├── .env
├── .github
├── node_modules
│ ├── data-uri-to-buffer
│ │ ├── README.md
│ │ ├── dist
│ │ │ └── src
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── index.js
│ │ │ │ └── index.js.map
│ │ └── package.json
│ ├── fetch-blob
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── file.d.ts
│ │ ├── file.js
│ │ ├── from.d.ts
│ │ ├── from.js
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ ├── package.json
│ │ └── streams.cjs
│ ├── node-fetch
│ │ ├── @types
│ │ │ └── index.d.ts
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── package.json
│ │ └── src
│ │ │ ├── body.js
│ │ │ ├── errors
│ │ │ ├── abort-error.js
│ │ │ ├── base.js
│ │ │ └── fetch-error.js
│ │ │ ├── headers.js
│ │ │ ├── index.js
│ │ │ ├── request.js
│ │ │ ├── response.js
│ │ │ └── utils
│ │ │ ├── form-data.js
│ │ │ ├── get-search.js
│ │ │ ├── is-redirect.js
│ │ │ └── is.js
│ └── web-streams-polyfill
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── dist
│ │ ├── polyfill.es2018.js
│ │ ├── polyfill.es2018.js.map
│ │ ├── polyfill.es2018.min.js
│ │ ├── polyfill.es2018.min.js.map
│ │ ├── polyfill.es2018.mjs
│ │ ├── polyfill.es2018.mjs.map
│ │ ├── polyfill.es6.js
│ │ ├── polyfill.es6.js.map
│ │ ├── polyfill.es6.min.js
│ │ ├── polyfill.es6.min.js.map
│ │ ├── polyfill.es6.mjs
│ │ ├── polyfill.es6.mjs.map
│ │ ├── polyfill.js
│ │ ├── polyfill.js.map
│ │ ├── polyfill.min.js
│ │ ├── polyfill.min.js.map
│ │ ├── polyfill.mjs
│ │ ├── polyfill.mjs.map
│ │ ├── ponyfill.es2018.js
│ │ ├── ponyfill.es2018.js.map
│ │ ├── ponyfill.es2018.mjs
│ │ ├── ponyfill.es2018.mjs.map
│ │ ├── ponyfill.es6.js
│ │ ├── ponyfill.es6.js.map
│ │ ├── ponyfill.es6.mjs
│ │ ├── ponyfill.es6.mjs.map
│ │ ├── ponyfill.js
│ │ ├── ponyfill.js.map
│ │ ├── ponyfill.mjs
│ │ ├── ponyfill.mjs.map
│ │ └── types
│ │ │ ├── polyfill.d.ts
│ │ │ ├── ts3.6
│ │ │ └── polyfill.d.ts
│ │ │ └── tsdoc-metadata.json
│ │ ├── es2018
│ │ └── package.json
│ │ ├── es6
│ │ └── package.json
│ │ ├── package.json
│ │ └── ponyfill
│ │ ├── es2018
│ │ └── package.json
│ │ ├── es6
│ │ └── package.json
│ │ └── package.json
├── update-sponsors
│ ├── fetch-sponsors.mjs
│ └── index.mjs
└── workflows
│ └── update-sponsors.yml
├── .gitignore
├── .gitpod.yml
├── .prettierrc
├── data
├── demos
│ ├── code.mdx
│ ├── comment-annotations.mdx
│ ├── custom-annotations.mdx
│ ├── custom-annotations
│ │ └── MyThing.jsx
│ ├── filenames.mdx
│ ├── index.json
│ ├── meta-annotations.mdx
│ ├── old-show.mdx
│ ├── scrollycoding-preview.mdx
│ ├── scrollycoding.mdx
│ ├── sections.mdx
│ ├── show.mdx
│ ├── slideshow-preview.mdx
│ ├── slideshow.mdx
│ ├── spotlight-preview.mdx
│ └── spotlight.mdx
└── sponsors.json
├── docs
├── annotations.mdx
├── ch-code.mdx
├── ch-scrollycoding.mdx
├── ch-section.mdx
├── ch-slideshow.mdx
├── ch-spotlight.mdx
├── codeblocks.mdx
├── configuration.mdx
├── configuration
│ ├── line-numbers.mdx
│ └── theme.mdx
├── installation-astro.mdx
├── installation-contentlayer.mdx
├── installation-cra.mdx
├── installation-docspage.mdx
├── installation-docusaurus.mdx
├── installation-eleventy.mdx
├── installation-gatsby.mdx
├── installation-mdx-bundler.mdx
├── installation-motif.mdx
├── installation-next-mdx-remote.mdx
├── installation-nextjs.mdx
├── installation-nextra.mdx
├── installation-parcel.mdx
├── installation-remix.mdx
├── installation-vite.mdx
├── installation.mdx
├── introduction.mdx
├── preview
│ ├── ch-code-1.mdx
│ ├── ch-code-2.mdx
│ ├── ch-code-3.mdx
│ ├── ch-code-4.mdx
│ ├── ch-code-5.mdx
│ ├── ch-code-6.mdx
│ ├── ch-section-1.mdx
│ ├── ch-section-2.mdx
│ ├── ch-section-3.mdx
│ ├── codeblocks-1.mdx
│ ├── codeblocks-2.mdx
│ ├── installation-1.mdx
│ ├── mark-1.mdx
│ ├── mark-2.mdx
│ ├── mark-3.mdx
│ └── with-class.mdx
├── styling.mdx
├── themes.mdx
└── troubleshooting.mdx
├── global.css
├── next.config.js
├── package.json
├── pages
├── _app.js
├── _document.js
├── api
│ ├── auth
│ │ └── [...nextauth].js
│ └── update-sponsors.js
├── card.js
├── demo
│ └── [...slug].js
├── docs
│ ├── [slug].js
│ ├── configuration.js
│ ├── installation
│ │ └── [fwk].js
│ ├── preview
│ │ └── [preview].js
│ └── themes.js
├── index.js
├── logo.js
└── show.js
├── postcss.config.js
├── public
├── card.png
├── cards
│ ├── card.png
│ ├── contentlayer.png
│ ├── docusaurus.png
│ ├── gatsby.png
│ └── nextjs.png
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── logo
│ ├── astro.svg
│ ├── contentlayer.svg
│ ├── cra.svg
│ ├── docspage.svg
│ ├── docusaurus.svg
│ ├── eleventy.svg
│ ├── gatsby.svg
│ ├── github.svg
│ ├── mdx-bundler.svg
│ ├── motif.svg
│ ├── next-mdx-remote.svg
│ ├── nextjs.svg
│ ├── nextra.svg
│ ├── parcel.svg
│ ├── remix.svg
│ ├── vite.svg
│ └── webpack.svg
├── not-stripe.png
├── not-tailwind.png
└── show1.mp4
├── readme.md
├── src
├── ch-theme.js
├── collapsable.js
├── demo-grid.js
├── docs-layout.js
├── docs-mdx.js
├── footer.js
├── frameworks.js
├── home-demo-server.js
├── home-demo.js
├── logo.js
└── seo.js
├── tailwind.config.js
├── themes.css
└── yarn.lock
/.env:
--------------------------------------------------------------------------------
1 | GITHUB_TOKEN= used to get the list of sponsors (deprecated, this is done by a GH action now)
2 | GITHUB_ID= used to authenticate website visitors
3 | GITHUB_SECRET= used to authenticate website visitors
4 | TRIGGER_ACTION_PAT= GH PAT used to trigger update sponsors workflow on ch-site
5 | NEXTAUTH_URL= NextAuth.js url (https://next-auth.js.org/warnings#nextauth_url)
6 | JWT_SIGNING_PRIVATE_KEY= NextAuth.js JWT key (https://next-auth.js.org/warnings#jwt_auto_generated_signing_key)
--------------------------------------------------------------------------------
/.github/node_modules/data-uri-to-buffer/README.md:
--------------------------------------------------------------------------------
1 | data-uri-to-buffer
2 | ==================
3 | ### Generate a Buffer instance from a [Data URI][rfc] string
4 | [](https://travis-ci.org/TooTallNate/node-data-uri-to-buffer)
5 |
6 | This module accepts a ["data" URI][rfc] String of data, and returns a
7 | node.js `Buffer` instance with the decoded data.
8 |
9 |
10 | Installation
11 | ------------
12 |
13 | Install with `npm`:
14 |
15 | ``` bash
16 | $ npm install data-uri-to-buffer
17 | ```
18 |
19 |
20 | Example
21 | -------
22 |
23 | ``` js
24 | var dataUriToBuffer = require('data-uri-to-buffer');
25 |
26 | // plain-text data is supported
27 | var uri = 'data:,Hello%2C%20World!';
28 | var decoded = dataUriToBuffer(uri);
29 | console.log(decoded.toString());
30 | // 'Hello, World!'
31 |
32 | // base64-encoded data is supported
33 | uri = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D';
34 | decoded = dataUriToBuffer(uri);
35 | console.log(decoded.toString());
36 | // 'Hello, World!'
37 | ```
38 |
39 |
40 | API
41 | ---
42 |
43 | ### dataUriToBuffer(String uri) → Buffer
44 |
45 | The `type` property on the Buffer instance gets set to the main type portion of
46 | the "mediatype" portion of the "data" URI, or defaults to `"text/plain"` if not
47 | specified.
48 |
49 | The `typeFull` property on the Buffer instance gets set to the entire
50 | "mediatype" portion of the "data" URI (including all parameters), or defaults
51 | to `"text/plain;charset=US-ASCII"` if not specified.
52 |
53 | The `charset` property on the Buffer instance gets set to the Charset portion of
54 | the "mediatype" portion of the "data" URI, or defaults to `"US-ASCII"` if the
55 | entire type is not specified, or defaults to `""` otherwise.
56 |
57 | *Note*: If the only the main type is specified but not the charset, e.g.
58 | `"data:text/plain,abc"`, the charset is set to the empty string. The spec only
59 | defaults to US-ASCII as charset if the entire type is not specified.
60 |
61 |
62 | License
63 | -------
64 |
65 | (The MIT License)
66 |
67 | Copyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>
68 |
69 | Permission is hereby granted, free of charge, to any person obtaining
70 | a copy of this software and associated documentation files (the
71 | 'Software'), to deal in the Software without restriction, including
72 | without limitation the rights to use, copy, modify, merge, publish,
73 | distribute, sublicense, and/or sell copies of the Software, and to
74 | permit persons to whom the Software is furnished to do so, subject to
75 | the following conditions:
76 |
77 | The above copyright notice and this permission notice shall be
78 | included in all copies or substantial portions of the Software.
79 |
80 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
81 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
82 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
83 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
84 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
85 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
86 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
87 |
88 | [rfc]: http://tools.ietf.org/html/rfc2397
89 |
--------------------------------------------------------------------------------
/.github/node_modules/data-uri-to-buffer/dist/src/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Returns a `Buffer` instance from the given data URI `uri`.
3 | *
4 | * @param {String} uri Data URI to turn into a Buffer instance
5 | * @return {Buffer} Buffer instance from Data URI
6 | * @api public
7 | */
8 | ///
9 | declare function dataUriToBuffer(uri: string): dataUriToBuffer.MimeBuffer;
10 | declare namespace dataUriToBuffer {
11 | interface MimeBuffer extends Buffer {
12 | type: string;
13 | typeFull: string;
14 | charset: string;
15 | }
16 | }
17 | export = dataUriToBuffer;
18 |
--------------------------------------------------------------------------------
/.github/node_modules/data-uri-to-buffer/dist/src/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * Returns a `Buffer` instance from the given data URI `uri`.
4 | *
5 | * @param {String} uri Data URI to turn into a Buffer instance
6 | * @return {Buffer} Buffer instance from Data URI
7 | * @api public
8 | */
9 | function dataUriToBuffer(uri) {
10 | if (!/^data:/i.test(uri)) {
11 | throw new TypeError('`uri` does not appear to be a Data URI (must begin with "data:")');
12 | }
13 | // strip newlines
14 | uri = uri.replace(/\r?\n/g, '');
15 | // split the URI up into the "metadata" and the "data" portions
16 | const firstComma = uri.indexOf(',');
17 | if (firstComma === -1 || firstComma <= 4) {
18 | throw new TypeError('malformed data: URI');
19 | }
20 | // remove the "data:" scheme and parse the metadata
21 | const meta = uri.substring(5, firstComma).split(';');
22 | let charset = '';
23 | let base64 = false;
24 | const type = meta[0] || 'text/plain';
25 | let typeFull = type;
26 | for (let i = 1; i < meta.length; i++) {
27 | if (meta[i] === 'base64') {
28 | base64 = true;
29 | }
30 | else {
31 | typeFull += `;${meta[i]}`;
32 | if (meta[i].indexOf('charset=') === 0) {
33 | charset = meta[i].substring(8);
34 | }
35 | }
36 | }
37 | // defaults to US-ASCII only if type is not provided
38 | if (!meta[0] && !charset.length) {
39 | typeFull += ';charset=US-ASCII';
40 | charset = 'US-ASCII';
41 | }
42 | // get the encoded data portion and decode URI-encoded chars
43 | const encoding = base64 ? 'base64' : 'ascii';
44 | const data = unescape(uri.substring(firstComma + 1));
45 | const buffer = Buffer.from(data, encoding);
46 | // set `.type` and `.typeFull` properties to MIME type
47 | buffer.type = type;
48 | buffer.typeFull = typeFull;
49 | // set the `.charset` property
50 | buffer.charset = charset;
51 | return buffer;
52 | }
53 | module.exports = dataUriToBuffer;
54 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/.github/node_modules/data-uri-to-buffer/dist/src/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;AAEH,SAAS,eAAe,CAAC,GAAW;IACnC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACzB,MAAM,IAAI,SAAS,CAClB,kEAAkE,CAClE,CAAC;KACF;IAED,iBAAiB;IACjB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEhC,+DAA+D;IAC/D,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE;QACzC,MAAM,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAAC;KAC3C;IAED,mDAAmD;IACnD,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAErD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC;IACrC,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;YACzB,MAAM,GAAG,IAAI,CAAC;SACd;aAAM;YACN,QAAQ,IAAI,IAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;gBACtC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;aAC/B;SACD;KACD;IACD,oDAAoD;IACpD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;QAChC,QAAQ,IAAI,mBAAmB,CAAC;QAChC,OAAO,GAAG,UAAU,CAAC;KACrB;IAED,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAA+B,CAAC;IAEzE,sDAAsD;IACtD,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAE3B,8BAA8B;IAC9B,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAEzB,OAAO,MAAM,CAAC;AACf,CAAC;AAUD,iBAAS,eAAe,CAAC"}
--------------------------------------------------------------------------------
/.github/node_modules/data-uri-to-buffer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "data-uri-to-buffer@^3.0.1",
3 | "_id": "data-uri-to-buffer@3.0.1",
4 | "_inBundle": false,
5 | "_integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
6 | "_location": "/data-uri-to-buffer",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "range",
10 | "registry": true,
11 | "raw": "data-uri-to-buffer@^3.0.1",
12 | "name": "data-uri-to-buffer",
13 | "escapedName": "data-uri-to-buffer",
14 | "rawSpec": "^3.0.1",
15 | "saveSpec": null,
16 | "fetchSpec": "^3.0.1"
17 | },
18 | "_requiredBy": [
19 | "/node-fetch"
20 | ],
21 | "_resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
22 | "_shasum": "594b8973938c5bc2c33046535785341abc4f3636",
23 | "_spec": "data-uri-to-buffer@^3.0.1",
24 | "_where": "/home/pomber/p/temp/x/node_modules/node-fetch",
25 | "author": {
26 | "name": "Nathan Rajlich",
27 | "email": "nathan@tootallnate.net",
28 | "url": "http://n8.io/"
29 | },
30 | "bugs": {
31 | "url": "https://github.com/TooTallNate/node-data-uri-to-buffer/issues"
32 | },
33 | "bundleDependencies": false,
34 | "deprecated": false,
35 | "description": "Generate a Buffer instance from a Data URI string",
36 | "devDependencies": {
37 | "@types/es6-promisify": "^5.0.0",
38 | "@types/mocha": "^5.2.7",
39 | "@types/node": "^10.5.3",
40 | "@typescript-eslint/eslint-plugin": "1.6.0",
41 | "@typescript-eslint/parser": "1.1.0",
42 | "eslint": "5.16.0",
43 | "eslint-config-airbnb": "17.1.0",
44 | "eslint-config-prettier": "4.1.0",
45 | "eslint-import-resolver-typescript": "1.1.1",
46 | "eslint-plugin-import": "2.16.0",
47 | "eslint-plugin-jsx-a11y": "6.2.1",
48 | "eslint-plugin-react": "7.12.4",
49 | "mocha": "^6.2.0",
50 | "typescript": "^3.5.3"
51 | },
52 | "engines": {
53 | "node": ">= 6"
54 | },
55 | "files": [
56 | "dist/src"
57 | ],
58 | "homepage": "https://github.com/TooTallNate/node-data-uri-to-buffer",
59 | "keywords": [
60 | "data",
61 | "uri",
62 | "datauri",
63 | "data-uri",
64 | "buffer",
65 | "convert",
66 | "rfc2397",
67 | "2397"
68 | ],
69 | "license": "MIT",
70 | "main": "dist/src/index.js",
71 | "name": "data-uri-to-buffer",
72 | "repository": {
73 | "type": "git",
74 | "url": "git://github.com/TooTallNate/node-data-uri-to-buffer.git"
75 | },
76 | "scripts": {
77 | "build": "tsc",
78 | "prepublishOnly": "npm run build",
79 | "test": "mocha --reporter spec dist/test/*.js",
80 | "test-lint": "eslint src --ext .js,.ts"
81 | },
82 | "types": "dist/src/index.d.ts",
83 | "version": "3.0.1"
84 | }
85 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 David Frank
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/README.md:
--------------------------------------------------------------------------------
1 | # fetch-blob
2 |
3 | [![npm version][npm-image]][npm-url]
4 | [![build status][ci-image]][ci-url]
5 | [![coverage status][codecov-image]][codecov-url]
6 | [![install size][install-size-image]][install-size-url]
7 |
8 | A Blob implementation in Node.js, originally from [node-fetch](https://github.com/node-fetch/node-fetch).
9 |
10 | ## Installation
11 |
12 | ```sh
13 | npm install fetch-blob
14 | ```
15 |
16 |
17 | Upgrading from 2x to 3x
18 |
19 | Updating from 2 to 3 should be a breeze since there is not many changes to the blob specification.
20 | The major cause of a major release is coding standards.
21 | - internal WeakMaps was replaced with private fields
22 | - internal Buffer.from was replaced with TextEncoder/Decoder
23 | - internal buffers was replaced with Uint8Arrays
24 | - CommonJS was replaced with ESM
25 | - The node stream returned by calling `blob.stream()` was replaced with whatwg streams
26 | - (Read "Differences from other blobs" for more info.)
27 |
28 |
29 |
30 |
31 | Differences from other Blobs
32 |
33 | - Unlike NodeJS `buffer.Blob` (Added in: v15.7.0) and browser native Blob this polyfilled version can't be sent via PostMessage
34 | - This blob version is more arbitrary, it can be constructed with blob parts that isn't a instance of itself
35 | it has to look and behave as a blob to be accepted as a blob part.
36 | - The benefit of this is that you can create other types of blobs that don't contain any internal data that has to be read in other ways, such as the `BlobDataItem` created in `from.js` that wraps a file path into a blob-like item and read lazily (nodejs plans to [implement this][fs-blobs] as well)
37 | - The `blob.stream()` is the most noticeable differences. It returns a WHATWG stream now. to keep it as a node stream you would have to do:
38 |
39 | ```js
40 | import {Readable} from 'stream'
41 | const stream = Readable.from(blob.stream())
42 | ```
43 |
44 |
45 | ## Usage
46 |
47 | ```js
48 | // Ways to import
49 | // (PS it's dependency free ESM package so regular http-import from CDN works too)
50 | import Blob from 'fetch-blob'
51 | import File from 'fetch-blob/file.js'
52 |
53 | import {Blob} from 'fetch-blob'
54 | import {File} from 'fetch-blob/file.js'
55 |
56 | const {Blob} = await import('fetch-blob')
57 |
58 |
59 | // Ways to read the blob:
60 | const blob = new Blob(['hello, world'])
61 |
62 | await blob.text()
63 | await blob.arrayBuffer()
64 | for await (let chunk of blob.stream()) { ... }
65 | blob.stream().getReader().read()
66 | blob.stream().getReader({mode: 'byob'}).read(view)
67 | ```
68 |
69 | ### Blob part backed up by filesystem
70 |
71 | `fetch-blob/from.js` comes packed with tools to convert any filepath into either a Blob or a File
72 | It will not read the content into memory. It will only stat the file for last modified date and file size.
73 |
74 | ```js
75 | // The default export is sync and use fs.stat to retrieve size & last modified as a blob
76 | import blobFromSync from 'fetch-blob/from.js'
77 | import {File, Blob, blobFrom, blobFromSync, fileFrom, fileFromSync} from 'fetch-blob/from.js'
78 |
79 | const fsFile = fileFromSync('./2-GiB-file.bin', 'application/octet-stream')
80 | const fsBlob = await blobFrom('./2-GiB-file.mp4')
81 |
82 | // Not a 4 GiB memory snapshot, just holds references
83 | // points to where data is located on the disk
84 | const blob = new Blob([fsFile, fsBlob, 'memory', new Uint8Array(10)])
85 | console.log(blob.size) // ~4 GiB
86 | ```
87 |
88 | `blobFrom|blobFromSync|fileFrom|fileFromSync(path, [mimetype])`
89 |
90 | ### Creating Blobs backed up by other async sources
91 | Our Blob & File class are more generic then any other polyfills in the way that it can accept any blob look-a-like item
92 | An example of this is that our blob implementation can be constructed with parts coming from [BlobDataItem](https://github.com/node-fetch/fetch-blob/blob/8ef89adad40d255a3bbd55cf38b88597c1cd5480/from.js#L32) (aka a filepath) or from [buffer.Blob](https://nodejs.org/api/buffer.html#buffer_new_buffer_blob_sources_options), It dose not have to implement all the methods - just enough that it can be read/understood by our Blob implementation. The minium requirements is that it has `Symbol.toStringTag`, `size`, `slice()` and either a `stream()` or a `arrayBuffer()` method. If you then wrap it in our Blob or File `new Blob([blobDataItem])` then you get all of the other methods that should be implemented in a blob or file
93 |
94 | An example of this could be to create a file or blob like item coming from a remote HTTP request. Or from a DataBase
95 |
96 | See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [tests](https://github.com/node-fetch/fetch-blob/blob/master/test.js) for more details of how to use the Blob.
97 |
98 | [npm-image]: https://flat.badgen.net/npm/v/fetch-blob
99 | [npm-url]: https://www.npmjs.com/package/fetch-blob
100 | [ci-image]: https://github.com/node-fetch/fetch-blob/workflows/CI/badge.svg
101 | [ci-url]: https://github.com/node-fetch/fetch-blob/actions
102 | [codecov-image]: https://flat.badgen.net/codecov/c/github/node-fetch/fetch-blob/master
103 | [codecov-url]: https://codecov.io/gh/node-fetch/fetch-blob
104 | [install-size-image]: https://flat.badgen.net/packagephobia/install/fetch-blob
105 | [install-size-url]: https://packagephobia.now.sh/result?p=fetch-blob
106 | [fs-blobs]: https://github.com/nodejs/node/issues/37340
107 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/file.d.ts:
--------------------------------------------------------------------------------
1 | /** @type {typeof globalThis.File} */ export const File: typeof globalThis.File;
2 | export default File;
3 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/file.js:
--------------------------------------------------------------------------------
1 | import Blob from './index.js'
2 |
3 | const _File = class File extends Blob {
4 | #lastModified = 0
5 | #name = ''
6 |
7 | /**
8 | * @param {*[]} fileBits
9 | * @param {string} fileName
10 | * @param {{lastModified?: number, type?: string}} options
11 | */// @ts-ignore
12 | constructor (fileBits, fileName, options = {}) {
13 | if (arguments.length < 2) {
14 | throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`)
15 | }
16 | super(fileBits, options)
17 |
18 | if (options === null) options = {}
19 |
20 | // Simulate WebIDL type casting for NaN value in lastModified option.
21 | const lastModified = options.lastModified === undefined ? Date.now() : Number(options.lastModified)
22 | if (!Number.isNaN(lastModified)) {
23 | this.#lastModified = lastModified
24 | }
25 |
26 | this.#name = String(fileName)
27 | }
28 |
29 | get name () {
30 | return this.#name
31 | }
32 |
33 | get lastModified () {
34 | return this.#lastModified
35 | }
36 |
37 | get [Symbol.toStringTag] () {
38 | return 'File'
39 | }
40 | }
41 |
42 | /** @type {typeof globalThis.File} */// @ts-ignore
43 | export const File = _File
44 | export default File
45 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/from.d.ts:
--------------------------------------------------------------------------------
1 | export default blobFromSync;
2 | /**
3 | * @param {string} path filepath on the disk
4 | * @param {string} [type] mimetype to use
5 | */
6 | export function blobFromSync(path: string, type?: string): Blob;
7 | import File from "./file.js";
8 | import Blob from "./index.js";
9 | /**
10 | * @param {string} path filepath on the disk
11 | * @param {string} [type] mimetype to use
12 | */
13 | export function blobFrom(path: string, type?: string): any;
14 | /**
15 | * @param {string} path filepath on the disk
16 | * @param {string} [type] mimetype to use
17 | */
18 | export function fileFrom(path: string, type?: string): any;
19 | /**
20 | * @param {string} path filepath on the disk
21 | * @param {string} [type] mimetype to use
22 | */
23 | export function fileFromSync(path: string, type?: string): File;
24 | export { File, Blob };
25 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/from.js:
--------------------------------------------------------------------------------
1 | import { statSync, createReadStream, promises as fs } from 'node:fs'
2 | import { basename } from 'node:path'
3 | import { MessageChannel } from 'node:worker_threads'
4 |
5 | import File from './file.js'
6 | import Blob from './index.js'
7 |
8 | const { stat } = fs
9 |
10 | const DOMException = globalThis.DOMException || (() => {
11 | const port = new MessageChannel().port1
12 | const ab = new ArrayBuffer(0)
13 | try { port.postMessage(ab, [ab, ab]) } catch (err) { return err.constructor }
14 | })()
15 |
16 | /**
17 | * @param {string} path filepath on the disk
18 | * @param {string} [type] mimetype to use
19 | */
20 | const blobFromSync = (path, type) => fromBlob(statSync(path), path, type)
21 |
22 | /**
23 | * @param {string} path filepath on the disk
24 | * @param {string} [type] mimetype to use
25 | */
26 | const blobFrom = (path, type) => stat(path).then(stat => fromBlob(stat, path, type))
27 |
28 | /**
29 | * @param {string} path filepath on the disk
30 | * @param {string} [type] mimetype to use
31 | */
32 | const fileFrom = (path, type) => stat(path).then(stat => fromFile(stat, path, type))
33 |
34 | /**
35 | * @param {string} path filepath on the disk
36 | * @param {string} [type] mimetype to use
37 | */
38 | const fileFromSync = (path, type) => fromFile(statSync(path), path, type)
39 |
40 | // @ts-ignore
41 | const fromBlob = (stat, path, type = '') => new Blob([new BlobDataItem({
42 | path,
43 | size: stat.size,
44 | lastModified: stat.mtimeMs,
45 | start: 0
46 | })], { type })
47 |
48 | // @ts-ignore
49 | const fromFile = (stat, path, type = '') => new File([new BlobDataItem({
50 | path,
51 | size: stat.size,
52 | lastModified: stat.mtimeMs,
53 | start: 0
54 | })], basename(path), { type, lastModified: stat.mtimeMs })
55 |
56 | /**
57 | * This is a blob backed up by a file on the disk
58 | * with minium requirement. Its wrapped around a Blob as a blobPart
59 | * so you have no direct access to this.
60 | *
61 | * @private
62 | */
63 | class BlobDataItem {
64 | #path
65 | #start
66 |
67 | constructor (options) {
68 | this.#path = options.path
69 | this.#start = options.start
70 | this.size = options.size
71 | this.lastModified = options.lastModified
72 | }
73 |
74 | /**
75 | * Slicing arguments is first validated and formatted
76 | * to not be out of range by Blob.prototype.slice
77 | */
78 | slice (start, end) {
79 | return new BlobDataItem({
80 | path: this.#path,
81 | lastModified: this.lastModified,
82 | size: end - start,
83 | start
84 | })
85 | }
86 |
87 | async * stream () {
88 | const { mtimeMs } = await stat(this.#path)
89 | if (mtimeMs > this.lastModified) {
90 | throw new DOMException('The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.', 'NotReadableError')
91 | }
92 | yield * createReadStream(this.#path, {
93 | start: this.#start,
94 | end: this.#start + this.size - 1
95 | })
96 | }
97 |
98 | get [Symbol.toStringTag] () {
99 | return 'Blob'
100 | }
101 | }
102 |
103 | export default blobFromSync
104 | export { File, Blob, blobFrom, blobFromSync, fileFrom, fileFromSync }
105 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/index.d.ts:
--------------------------------------------------------------------------------
1 | /** @type {typeof globalThis.Blob} */
2 | export const Blob: typeof globalThis.Blob;
3 | export default Blob;
4 | /**
5 | * }
6 | */
7 | export type NodeBlob = import('buffer').Blob;
8 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "fetch-blob@^3.1.2",
3 | "_id": "fetch-blob@3.1.3",
4 | "_inBundle": false,
5 | "_integrity": "sha512-ax1Y5I9w+9+JiM+wdHkhBoxew+zG4AJ2SvAD1v1szpddUIiPERVGBxrMcB2ZqW0Y3PP8bOWYv2zqQq1Jp2kqUQ==",
6 | "_location": "/fetch-blob",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "range",
10 | "registry": true,
11 | "raw": "fetch-blob@^3.1.2",
12 | "name": "fetch-blob",
13 | "escapedName": "fetch-blob",
14 | "rawSpec": "^3.1.2",
15 | "saveSpec": null,
16 | "fetchSpec": "^3.1.2"
17 | },
18 | "_requiredBy": [
19 | "/node-fetch"
20 | ],
21 | "_resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.3.tgz",
22 | "_shasum": "a7dca4855e39d3e3c5a1da62d4ee335c37d26012",
23 | "_spec": "fetch-blob@^3.1.2",
24 | "_where": "/home/pomber/p/temp/x/node_modules/node-fetch",
25 | "author": {
26 | "name": "Jimmy Wärting",
27 | "email": "jimmy@warting.se",
28 | "url": "https://jimmy.warting.se"
29 | },
30 | "bugs": {
31 | "url": "https://github.com/node-fetch/fetch-blob/issues"
32 | },
33 | "bundleDependencies": false,
34 | "dependencies": {
35 | "web-streams-polyfill": "^3.0.3"
36 | },
37 | "deprecated": false,
38 | "description": "Blob & File implementation in Node.js, originally from node-fetch.",
39 | "devDependencies": {
40 | "ava": "^3.15.0",
41 | "c8": "^7.7.2",
42 | "codecov": "^3.8.2",
43 | "node-fetch": "^3.0.0-beta.9",
44 | "typescript": "^4.3.2"
45 | },
46 | "engines": {
47 | "node": "^12.20 || >= 14.13"
48 | },
49 | "files": [
50 | "from.js",
51 | "file.js",
52 | "file.d.ts",
53 | "index.js",
54 | "index.d.ts",
55 | "from.d.ts",
56 | "streams.cjs"
57 | ],
58 | "funding": [
59 | {
60 | "type": "github",
61 | "url": "https://github.com/sponsors/jimmywarting"
62 | },
63 | {
64 | "type": "paypal",
65 | "url": "https://paypal.me/jimmywarting"
66 | }
67 | ],
68 | "homepage": "https://github.com/node-fetch/fetch-blob#readme",
69 | "keywords": [
70 | "blob",
71 | "file",
72 | "node-fetch"
73 | ],
74 | "license": "MIT",
75 | "main": "index.js",
76 | "name": "fetch-blob",
77 | "repository": {
78 | "type": "git",
79 | "url": "git+https://github.com/node-fetch/fetch-blob.git"
80 | },
81 | "scripts": {
82 | "coverage": "c8 --reporter json --reporter text ava test.js && codecov -f coverage/coverage-final.json",
83 | "prepublishOnly": "tsc --declaration --emitDeclarationOnly --allowJs index.js from.js",
84 | "report": "c8 --reporter json --reporter text ava test.js",
85 | "test": "ava test.js",
86 | "test-wpt": "node --experimental-loader ./test/http-loader.js ./test/test-wpt-in-node.js"
87 | },
88 | "type": "module",
89 | "version": "3.1.3"
90 | }
91 |
--------------------------------------------------------------------------------
/.github/node_modules/fetch-blob/streams.cjs:
--------------------------------------------------------------------------------
1 | /* c8 ignore start */
2 | // 64 KiB (same size chrome slice theirs blob into Uint8array's)
3 | const POOL_SIZE = 65536
4 |
5 | if (!globalThis.ReadableStream) {
6 | // `node:stream/web` got introduced in v16.5.0 as experimental
7 | // and it's preferred over the polyfilled version. So we also
8 | // suppress the warning that gets emitted by NodeJS for using it.
9 | try {
10 | const process = require('node:process')
11 | const { emitWarning } = process
12 | try {
13 | process.emitWarning = () => {}
14 | Object.assign(globalThis, require('node:stream/web'))
15 | process.emitWarning = emitWarning
16 | } catch (error) {
17 | process.emitWarning = emitWarning
18 | throw error
19 | }
20 | } catch (error) {
21 | // fallback to polyfill implementation
22 | Object.assign(globalThis, require('web-streams-polyfill/dist/ponyfill.es2018.js'))
23 | }
24 | }
25 |
26 | try {
27 | // Don't use node: prefix for this, require+node: is not supported until node v14.14
28 | // Only `import()` can use prefix in 12.20 and later
29 | const { Blob } = require('buffer')
30 | if (Blob && !Blob.prototype.stream) {
31 | Blob.prototype.stream = function name (params) {
32 | let position = 0
33 | const blob = this
34 |
35 | return new ReadableStream({
36 | type: 'bytes',
37 | async pull (ctrl) {
38 | const chunk = blob.slice(position, Math.min(blob.size, position + POOL_SIZE))
39 | const buffer = await chunk.arrayBuffer()
40 | position += buffer.byteLength
41 | ctrl.enqueue(new Uint8Array(buffer))
42 |
43 | if (position === blob.size) {
44 | ctrl.close()
45 | }
46 | }
47 | })
48 | }
49 | }
50 | } catch (error) {}
51 | /* c8 ignore end */
52 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/@types/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | import {Agent} from 'http';
5 |
6 | type AbortSignal = {
7 | readonly aborted: boolean;
8 |
9 | addEventListener: (type: 'abort', listener: (this: AbortSignal) => void) => void;
10 | removeEventListener: (type: 'abort', listener: (this: AbortSignal) => void) => void;
11 | };
12 |
13 | export type HeadersInit = Headers | Record | Iterable | Iterable>;
14 |
15 | /**
16 | * This Fetch API interface allows you to perform various actions on HTTP request and response headers.
17 | * These actions include retrieving, setting, adding to, and removing.
18 | * A Headers object has an associated header list, which is initially empty and consists of zero or more name and value pairs.
19 | * You can add to this using methods like append() (see Examples.)
20 | * In all methods of this interface, header names are matched by case-insensitive byte sequence.
21 | * */
22 | export class Headers {
23 | constructor(init?: HeadersInit);
24 |
25 | append(name: string, value: string): void;
26 | delete(name: string): void;
27 | get(name: string): string | null;
28 | has(name: string): boolean;
29 | set(name: string, value: string): void;
30 | forEach(
31 | callbackfn: (value: string, key: string, parent: Headers) => void,
32 | thisArg?: any
33 | ): void;
34 |
35 | [Symbol.iterator](): IterableIterator<[string, string]>;
36 | /**
37 | * Returns an iterator allowing to go through all key/value pairs contained in this object.
38 | */
39 | entries(): IterableIterator<[string, string]>;
40 | /**
41 | * Returns an iterator allowing to go through all keys of the key/value pairs contained in this object.
42 | */
43 | keys(): IterableIterator;
44 | /**
45 | * Returns an iterator allowing to go through all values of the key/value pairs contained in this object.
46 | */
47 | values(): IterableIterator;
48 |
49 | /** Node-fetch extension */
50 | raw(): Record;
51 | }
52 |
53 | export interface RequestInit {
54 | /**
55 | * A BodyInit object or null to set request's body.
56 | */
57 | body?: BodyInit | null;
58 | /**
59 | * A Headers object, an object literal, or an array of two-item arrays to set request's headers.
60 | */
61 | headers?: HeadersInit;
62 | /**
63 | * A string to set request's method.
64 | */
65 | method?: string;
66 | /**
67 | * A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect.
68 | */
69 | redirect?: RequestRedirect;
70 | /**
71 | * An AbortSignal to set request's signal.
72 | */
73 | signal?: AbortSignal | null;
74 |
75 | // Node-fetch extensions to the whatwg/fetch spec
76 | agent?: Agent | ((parsedUrl: URL) => Agent);
77 | compress?: boolean;
78 | counter?: number;
79 | follow?: number;
80 | hostname?: string;
81 | port?: number;
82 | protocol?: string;
83 | size?: number;
84 | highWaterMark?: number;
85 | insecureHTTPParser?: boolean;
86 | }
87 |
88 | export interface ResponseInit {
89 | headers?: HeadersInit;
90 | status?: number;
91 | statusText?: string;
92 | }
93 |
94 | export type BodyInit =
95 | | Blob
96 | | Buffer
97 | | URLSearchParams
98 | | NodeJS.ReadableStream
99 | | string;
100 | declare class BodyMixin {
101 | constructor(body?: BodyInit, options?: {size?: number});
102 |
103 | readonly body: NodeJS.ReadableStream | null;
104 | readonly bodyUsed: boolean;
105 | readonly size: number;
106 |
107 | buffer(): Promise;
108 | arrayBuffer(): Promise;
109 | blob(): Promise;
110 | json(): Promise;
111 | text(): Promise;
112 | }
113 |
114 | // `Body` must not be exported as a class since it's not exported from the JavaScript code.
115 | export interface Body extends Pick {}
116 |
117 | export type RequestRedirect = 'error' | 'follow' | 'manual';
118 | export type RequestInfo = string | Request;
119 | export class Request extends BodyMixin {
120 | constructor(input: RequestInfo, init?: RequestInit);
121 |
122 | /**
123 | * Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header.
124 | */
125 | readonly headers: Headers;
126 | /**
127 | * Returns request's HTTP method, which is "GET" by default.
128 | */
129 | readonly method: string;
130 | /**
131 | * Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default.
132 | */
133 | readonly redirect: RequestRedirect;
134 | /**
135 | * Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler.
136 | */
137 | readonly signal: AbortSignal;
138 | /**
139 | * Returns the URL of request as a string.
140 | */
141 | readonly url: string;
142 | clone(): Request;
143 | }
144 |
145 | type ResponseType = 'basic' | 'cors' | 'default' | 'error' | 'opaque' | 'opaqueredirect';
146 |
147 | export class Response extends BodyMixin {
148 | constructor(body?: BodyInit | null, init?: ResponseInit);
149 |
150 | readonly headers: Headers;
151 | readonly ok: boolean;
152 | readonly redirected: boolean;
153 | readonly status: number;
154 | readonly statusText: string;
155 | readonly type: ResponseType;
156 | readonly url: string;
157 | clone(): Response;
158 |
159 | static error(): Response;
160 | }
161 |
162 | export class FetchError extends Error {
163 | constructor(message: string, type: string, systemError?: Record);
164 |
165 | name: 'FetchError';
166 | [Symbol.toStringTag]: 'FetchError';
167 | type: string;
168 | code?: string;
169 | errno?: string;
170 | }
171 |
172 | export class AbortError extends Error {
173 | type: string;
174 | name: 'AbortError';
175 | [Symbol.toStringTag]: 'AbortError';
176 | }
177 |
178 | export function isRedirect(code: number): boolean;
179 | export default function fetch(url: RequestInfo, init?: RequestInit): Promise;
180 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 - 2020 Node Fetch Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "node-fetch",
3 | "_id": "node-fetch@3.0.0",
4 | "_inBundle": false,
5 | "_integrity": "sha512-bKMI+C7/T/SPU1lKnbQbwxptpCrG9ashG+VkytmXCPZyuM9jB6VU+hY0oi4lC8LxTtAeWdckNCTa3nrGsAdA3Q==",
6 | "_location": "/node-fetch",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "tag",
10 | "registry": true,
11 | "raw": "node-fetch",
12 | "name": "node-fetch",
13 | "escapedName": "node-fetch",
14 | "rawSpec": "",
15 | "saveSpec": null,
16 | "fetchSpec": "latest"
17 | },
18 | "_requiredBy": [
19 | "#USER",
20 | "/"
21 | ],
22 | "_resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0.tgz",
23 | "_shasum": "79da7146a520036f2c5f644e4a26095f17e411ea",
24 | "_spec": "node-fetch",
25 | "_where": "/home/pomber/p/temp/x",
26 | "author": {
27 | "name": "David Frank"
28 | },
29 | "bugs": {
30 | "url": "https://github.com/node-fetch/node-fetch/issues"
31 | },
32 | "bundleDependencies": false,
33 | "dependencies": {
34 | "data-uri-to-buffer": "^3.0.1",
35 | "fetch-blob": "^3.1.2"
36 | },
37 | "deprecated": false,
38 | "description": "A light-weight module that brings Fetch API to node.js",
39 | "devDependencies": {
40 | "abort-controller": "^3.0.0",
41 | "abortcontroller-polyfill": "^1.7.1",
42 | "busboy": "^0.3.1",
43 | "c8": "^7.7.2",
44 | "chai": "^4.3.4",
45 | "chai-as-promised": "^7.1.1",
46 | "chai-iterator": "^3.0.2",
47 | "chai-string": "^1.5.0",
48 | "coveralls": "^3.1.0",
49 | "delay": "^5.0.0",
50 | "form-data": "^4.0.0",
51 | "formdata-node": "^3.5.4",
52 | "mocha": "^8.3.2",
53 | "p-timeout": "^5.0.0",
54 | "tsd": "^0.14.0",
55 | "xo": "^0.39.1"
56 | },
57 | "engines": {
58 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
59 | },
60 | "files": [
61 | "src",
62 | "@types/index.d.ts"
63 | ],
64 | "funding": {
65 | "type": "opencollective",
66 | "url": "https://opencollective.com/node-fetch"
67 | },
68 | "homepage": "https://github.com/node-fetch/node-fetch",
69 | "keywords": [
70 | "fetch",
71 | "http",
72 | "promise",
73 | "request",
74 | "curl",
75 | "wget",
76 | "xhr",
77 | "whatwg"
78 | ],
79 | "license": "MIT",
80 | "main": "./src/index.js",
81 | "name": "node-fetch",
82 | "repository": {
83 | "type": "git",
84 | "url": "git+https://github.com/node-fetch/node-fetch.git"
85 | },
86 | "runkitExampleFilename": "example.js",
87 | "scripts": {
88 | "coverage": "c8 report --reporter=text-lcov | coveralls",
89 | "lint": "xo",
90 | "test": "mocha",
91 | "test-types": "tsd"
92 | },
93 | "sideEffects": false,
94 | "tsd": {
95 | "cwd": "@types",
96 | "compilerOptions": {
97 | "esModuleInterop": true
98 | }
99 | },
100 | "type": "module",
101 | "types": "./@types/index.d.ts",
102 | "version": "3.0.0",
103 | "xo": {
104 | "envs": [
105 | "node",
106 | "browser"
107 | ],
108 | "ignores": [
109 | "example.js"
110 | ],
111 | "rules": {
112 | "complexity": 0,
113 | "import/extensions": 0,
114 | "import/no-useless-path-segments": 0,
115 | "import/no-anonymous-default-export": 0,
116 | "import/no-named-as-default": 0,
117 | "unicorn/import-index": 0,
118 | "unicorn/no-array-reduce": 0,
119 | "unicorn/prefer-node-protocol": 0,
120 | "unicorn/numeric-separators-style": 0,
121 | "unicorn/explicit-length-check": 0,
122 | "capitalized-comments": 0,
123 | "@typescript-eslint/member-ordering": 0
124 | },
125 | "overrides": [
126 | {
127 | "files": "test/**/*.js",
128 | "envs": [
129 | "node",
130 | "mocha"
131 | ],
132 | "rules": {
133 | "max-nested-callbacks": 0,
134 | "no-unused-expressions": 0,
135 | "no-warning-comments": 0,
136 | "new-cap": 0,
137 | "guard-for-in": 0,
138 | "unicorn/no-array-for-each": 0,
139 | "unicorn/prevent-abbreviations": 0,
140 | "promise/prefer-await-to-then": 0,
141 | "ava/no-import-test-files": 0
142 | }
143 | }
144 | ]
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/errors/abort-error.js:
--------------------------------------------------------------------------------
1 | import {FetchBaseError} from './base.js';
2 |
3 | /**
4 | * AbortError interface for cancelled requests
5 | */
6 | export class AbortError extends FetchBaseError {
7 | constructor(message, type = 'aborted') {
8 | super(message, type);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/errors/base.js:
--------------------------------------------------------------------------------
1 | export class FetchBaseError extends Error {
2 | constructor(message, type) {
3 | super(message);
4 | // Hide custom error implementation details from end-users
5 | Error.captureStackTrace(this, this.constructor);
6 |
7 | this.type = type;
8 | }
9 |
10 | get name() {
11 | return this.constructor.name;
12 | }
13 |
14 | get [Symbol.toStringTag]() {
15 | return this.constructor.name;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/errors/fetch-error.js:
--------------------------------------------------------------------------------
1 |
2 | import {FetchBaseError} from './base.js';
3 |
4 | /**
5 | * @typedef {{ address?: string, code: string, dest?: string, errno: number, info?: object, message: string, path?: string, port?: number, syscall: string}} SystemError
6 | */
7 |
8 | /**
9 | * FetchError interface for operational errors
10 | */
11 | export class FetchError extends FetchBaseError {
12 | /**
13 | * @param {string} message - Error message for human
14 | * @param {string} [type] - Error type for machine
15 | * @param {SystemError} [systemError] - For Node.js system error
16 | */
17 | constructor(message, type, systemError) {
18 | super(message, type);
19 | // When err.type is `system`, err.erroredSysCall contains system error and err.code contains system error code
20 | if (systemError) {
21 | // eslint-disable-next-line no-multi-assign
22 | this.code = this.errno = systemError.code;
23 | this.erroredSysCall = systemError.syscall;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/response.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Response.js
3 | *
4 | * Response class provides content decoding
5 | */
6 |
7 | import Headers from './headers.js';
8 | import Body, {clone, extractContentType} from './body.js';
9 | import {isRedirect} from './utils/is-redirect.js';
10 |
11 | const INTERNALS = Symbol('Response internals');
12 |
13 | /**
14 | * Response class
15 | *
16 | * Ref: https://fetch.spec.whatwg.org/#response-class
17 | *
18 | * @param Stream body Readable stream
19 | * @param Object opts Response options
20 | * @return Void
21 | */
22 | export default class Response extends Body {
23 | constructor(body = null, options = {}) {
24 | super(body, options);
25 |
26 | // eslint-disable-next-line no-eq-null, eqeqeq, no-negated-condition
27 | const status = options.status != null ? options.status : 200;
28 |
29 | const headers = new Headers(options.headers);
30 |
31 | if (body !== null && !headers.has('Content-Type')) {
32 | const contentType = extractContentType(body);
33 | if (contentType) {
34 | headers.append('Content-Type', contentType);
35 | }
36 | }
37 |
38 | this[INTERNALS] = {
39 | type: 'default',
40 | url: options.url,
41 | status,
42 | statusText: options.statusText || '',
43 | headers,
44 | counter: options.counter,
45 | highWaterMark: options.highWaterMark
46 | };
47 | }
48 |
49 | get type() {
50 | return this[INTERNALS].type;
51 | }
52 |
53 | get url() {
54 | return this[INTERNALS].url || '';
55 | }
56 |
57 | get status() {
58 | return this[INTERNALS].status;
59 | }
60 |
61 | /**
62 | * Convenience property representing if the request ended normally
63 | */
64 | get ok() {
65 | return this[INTERNALS].status >= 200 && this[INTERNALS].status < 300;
66 | }
67 |
68 | get redirected() {
69 | return this[INTERNALS].counter > 0;
70 | }
71 |
72 | get statusText() {
73 | return this[INTERNALS].statusText;
74 | }
75 |
76 | get headers() {
77 | return this[INTERNALS].headers;
78 | }
79 |
80 | get highWaterMark() {
81 | return this[INTERNALS].highWaterMark;
82 | }
83 |
84 | /**
85 | * Clone this response
86 | *
87 | * @return Response
88 | */
89 | clone() {
90 | return new Response(clone(this, this.highWaterMark), {
91 | type: this.type,
92 | url: this.url,
93 | status: this.status,
94 | statusText: this.statusText,
95 | headers: this.headers,
96 | ok: this.ok,
97 | redirected: this.redirected,
98 | size: this.size
99 | });
100 | }
101 |
102 | /**
103 | * @param {string} url The URL that the new response is to originate from.
104 | * @param {number} status An optional status code for the response (e.g., 302.)
105 | * @returns {Response} A Response object.
106 | */
107 | static redirect(url, status = 302) {
108 | if (!isRedirect(status)) {
109 | throw new RangeError('Failed to execute "redirect" on "response": Invalid status code');
110 | }
111 |
112 | return new Response(null, {
113 | headers: {
114 | location: new URL(url).toString()
115 | },
116 | status
117 | });
118 | }
119 |
120 | static error() {
121 | const response = new Response(null, {status: 0, statusText: ''});
122 | response[INTERNALS].type = 'error';
123 | return response;
124 | }
125 |
126 | get [Symbol.toStringTag]() {
127 | return 'Response';
128 | }
129 | }
130 |
131 | Object.defineProperties(Response.prototype, {
132 | type: {enumerable: true},
133 | url: {enumerable: true},
134 | status: {enumerable: true},
135 | ok: {enumerable: true},
136 | redirected: {enumerable: true},
137 | statusText: {enumerable: true},
138 | headers: {enumerable: true},
139 | clone: {enumerable: true}
140 | });
141 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/utils/form-data.js:
--------------------------------------------------------------------------------
1 | import {randomBytes} from 'crypto';
2 |
3 | import {isBlob} from './is.js';
4 |
5 | const carriage = '\r\n';
6 | const dashes = '-'.repeat(2);
7 | const carriageLength = Buffer.byteLength(carriage);
8 |
9 | /**
10 | * @param {string} boundary
11 | */
12 | const getFooter = boundary => `${dashes}${boundary}${dashes}${carriage.repeat(2)}`;
13 |
14 | /**
15 | * @param {string} boundary
16 | * @param {string} name
17 | * @param {*} field
18 | *
19 | * @return {string}
20 | */
21 | function getHeader(boundary, name, field) {
22 | let header = '';
23 |
24 | header += `${dashes}${boundary}${carriage}`;
25 | header += `Content-Disposition: form-data; name="${name}"`;
26 |
27 | if (isBlob(field)) {
28 | header += `; filename="${field.name}"${carriage}`;
29 | header += `Content-Type: ${field.type || 'application/octet-stream'}`;
30 | }
31 |
32 | return `${header}${carriage.repeat(2)}`;
33 | }
34 |
35 | /**
36 | * @return {string}
37 | */
38 | export const getBoundary = () => randomBytes(8).toString('hex');
39 |
40 | /**
41 | * @param {FormData} form
42 | * @param {string} boundary
43 | */
44 | export async function * formDataIterator(form, boundary) {
45 | for (const [name, value] of form) {
46 | yield getHeader(boundary, name, value);
47 |
48 | if (isBlob(value)) {
49 | yield * value.stream();
50 | } else {
51 | yield value;
52 | }
53 |
54 | yield carriage;
55 | }
56 |
57 | yield getFooter(boundary);
58 | }
59 |
60 | /**
61 | * @param {FormData} form
62 | * @param {string} boundary
63 | */
64 | export function getFormDataLength(form, boundary) {
65 | let length = 0;
66 |
67 | for (const [name, value] of form) {
68 | length += Buffer.byteLength(getHeader(boundary, name, value));
69 |
70 | length += isBlob(value) ? value.size : Buffer.byteLength(String(value));
71 |
72 | length += carriageLength;
73 | }
74 |
75 | length += Buffer.byteLength(getFooter(boundary));
76 |
77 | return length;
78 | }
79 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/utils/get-search.js:
--------------------------------------------------------------------------------
1 | export const getSearch = parsedURL => {
2 | if (parsedURL.search) {
3 | return parsedURL.search;
4 | }
5 |
6 | const lastOffset = parsedURL.href.length - 1;
7 | const hash = parsedURL.hash || (parsedURL.href[lastOffset] === '#' ? '#' : '');
8 | return parsedURL.href[lastOffset - hash.length] === '?' ? '?' : '';
9 | };
10 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/utils/is-redirect.js:
--------------------------------------------------------------------------------
1 | const redirectStatus = new Set([301, 302, 303, 307, 308]);
2 |
3 | /**
4 | * Redirect code matching
5 | *
6 | * @param {number} code - Status code
7 | * @return {boolean}
8 | */
9 | export const isRedirect = code => {
10 | return redirectStatus.has(code);
11 | };
12 |
--------------------------------------------------------------------------------
/.github/node_modules/node-fetch/src/utils/is.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Is.js
3 | *
4 | * Object type checks.
5 | */
6 |
7 | const NAME = Symbol.toStringTag;
8 |
9 | /**
10 | * Check if `obj` is a URLSearchParams object
11 | * ref: https://github.com/node-fetch/node-fetch/issues/296#issuecomment-307598143
12 | *
13 | * @param {*} obj
14 | * @return {boolean}
15 | */
16 | export const isURLSearchParameters = object => {
17 | return (
18 | typeof object === 'object' &&
19 | typeof object.append === 'function' &&
20 | typeof object.delete === 'function' &&
21 | typeof object.get === 'function' &&
22 | typeof object.getAll === 'function' &&
23 | typeof object.has === 'function' &&
24 | typeof object.set === 'function' &&
25 | typeof object.sort === 'function' &&
26 | object[NAME] === 'URLSearchParams'
27 | );
28 | };
29 |
30 | /**
31 | * Check if `object` is a W3C `Blob` object (which `File` inherits from)
32 | *
33 | * @param {*} obj
34 | * @return {boolean}
35 | */
36 | export const isBlob = object => {
37 | return (
38 | typeof object === 'object' &&
39 | typeof object.arrayBuffer === 'function' &&
40 | typeof object.type === 'string' &&
41 | typeof object.stream === 'function' &&
42 | typeof object.constructor === 'function' &&
43 | /^(Blob|File)$/.test(object[NAME])
44 | );
45 | };
46 |
47 | /**
48 | * Check if `obj` is a spec-compliant `FormData` object
49 | *
50 | * @param {*} object
51 | * @return {boolean}
52 | */
53 | export function isFormData(object) {
54 | return (
55 | typeof object === 'object' &&
56 | typeof object.append === 'function' &&
57 | typeof object.set === 'function' &&
58 | typeof object.get === 'function' &&
59 | typeof object.getAll === 'function' &&
60 | typeof object.delete === 'function' &&
61 | typeof object.keys === 'function' &&
62 | typeof object.values === 'function' &&
63 | typeof object.entries === 'function' &&
64 | typeof object.constructor === 'function' &&
65 | object[NAME] === 'FormData'
66 | );
67 | }
68 |
69 | /**
70 | * Check if `obj` is an instance of AbortSignal.
71 | *
72 | * @param {*} obj
73 | * @return {boolean}
74 | */
75 | export const isAbortSignal = object => {
76 | return (
77 | typeof object === 'object' && (
78 | object[NAME] === 'AbortSignal' ||
79 | object[NAME] === 'EventTarget'
80 | )
81 | );
82 | };
83 |
84 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Mattias Buelens
4 | Copyright (c) 2016 Diwank Singh Tomer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/dist/types/tsdoc-metadata.json:
--------------------------------------------------------------------------------
1 | // This file is read by tools that parse documentation comments conforming to the TSDoc standard.
2 | // It should be published with your NPM package. It should not be tracked by Git.
3 | {
4 | "tsdocVersion": "0.12",
5 | "toolPackages": [
6 | {
7 | "packageName": "@microsoft/api-extractor",
8 | "packageVersion": "7.13.4"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/es2018/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-streams-polyfill-es2018",
3 | "main": "../dist/polyfill.es2018",
4 | "browser": "../dist/polyfill.es2018.min.js",
5 | "module": "../dist/polyfill.es2018.mjs",
6 | "types": "../dist/types/polyfill.d.ts"
7 | }
8 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/es6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-streams-polyfill-es6",
3 | "main": "../dist/polyfill.es6",
4 | "browser": "../dist/polyfill.es6.min.js",
5 | "module": "../dist/polyfill.es6.mjs",
6 | "types": "../dist/types/polyfill.d.ts"
7 | }
8 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "web-streams-polyfill@^3.0.3",
3 | "_id": "web-streams-polyfill@3.1.1",
4 | "_inBundle": false,
5 | "_integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q==",
6 | "_location": "/web-streams-polyfill",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "range",
10 | "registry": true,
11 | "raw": "web-streams-polyfill@^3.0.3",
12 | "name": "web-streams-polyfill",
13 | "escapedName": "web-streams-polyfill",
14 | "rawSpec": "^3.0.3",
15 | "saveSpec": null,
16 | "fetchSpec": "^3.0.3"
17 | },
18 | "_requiredBy": [
19 | "/fetch-blob"
20 | ],
21 | "_resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz",
22 | "_shasum": "1516f2d4ea8f1bdbfed15eb65cb2df87098c8364",
23 | "_spec": "web-streams-polyfill@^3.0.3",
24 | "_where": "/home/pomber/p/temp/x/node_modules/fetch-blob",
25 | "author": {
26 | "name": "Mattias Buelens",
27 | "email": "mattias@buelens.com"
28 | },
29 | "browser": "dist/polyfill.min.js",
30 | "bugs": {
31 | "url": "https://github.com/MattiasBuelens/web-streams-polyfill/issues"
32 | },
33 | "bundleDependencies": false,
34 | "contributors": [
35 | {
36 | "name": "Diwank Singh",
37 | "email": "diwank.singh@gmail.com"
38 | }
39 | ],
40 | "deprecated": false,
41 | "description": "Web Streams, based on the WHATWG spec reference implementation",
42 | "devDependencies": {
43 | "@microsoft/api-extractor": "^7.13.4",
44 | "@rollup/plugin-inject": "^4.0.2",
45 | "@rollup/plugin-replace": "^2.4.2",
46 | "@rollup/plugin-strip": "^2.0.0",
47 | "@rollup/plugin-typescript": "^8.2.1",
48 | "@types/node": "^14.14.37",
49 | "@typescript-eslint/eslint-plugin": "^4.21.0",
50 | "@typescript-eslint/parser": "^4.21.0",
51 | "@ungap/promise-all-settled": "^1.1.2",
52 | "eslint": "^7.23.0",
53 | "jasmine": "^3.7.0",
54 | "micromatch": "^4.0.2",
55 | "rollup": "^2.44.0",
56 | "rollup-plugin-terser": "^7.0.2",
57 | "ts-morph": "^10.0.2",
58 | "tslib": "^2.2.0",
59 | "typescript": "^4.2.4",
60 | "wpt-runner": "^3.2.1"
61 | },
62 | "engines": {
63 | "node": ">= 8"
64 | },
65 | "files": [
66 | "dist",
67 | "es6",
68 | "es2018",
69 | "ponyfill"
70 | ],
71 | "homepage": "https://github.com/MattiasBuelens/web-streams-polyfill#readme",
72 | "keywords": [
73 | "streams",
74 | "whatwg",
75 | "polyfill"
76 | ],
77 | "license": "MIT",
78 | "main": "dist/polyfill",
79 | "module": "dist/polyfill.mjs",
80 | "name": "web-streams-polyfill",
81 | "repository": {
82 | "type": "git",
83 | "url": "git+https://github.com/MattiasBuelens/web-streams-polyfill.git"
84 | },
85 | "scripts": {
86 | "accept:types": "tsc --project . --emitDeclarationOnly --declarationDir ./lib && api-extractor run --local && node ./build/downlevel-dts.js",
87 | "build": "npm run build:bundle && npm run build:types",
88 | "build:bundle": "rollup -c",
89 | "build:types": "tsc --project . --emitDeclarationOnly --declarationDir ./lib && api-extractor run && node ./build/downlevel-dts.js",
90 | "lint": "eslint \"src/**/*.ts\"",
91 | "prepare": "npm run build",
92 | "pretest:wpt": "git submodule update --init --recursive",
93 | "test": "npm run test:types && npm run test:unit && npm run test:wpt",
94 | "test:types": "tsc -p ./test/types/tsconfig.json",
95 | "test:unit": "jasmine --config=test/unit/jasmine.json",
96 | "test:wpt": "node --expose_gc ./test/run-web-platform-tests.js"
97 | },
98 | "types": "dist/types/polyfill.d.ts",
99 | "typesVersions": {
100 | ">=3.6": {
101 | "dist/types/*": [
102 | "dist/types/ts3.6/*"
103 | ]
104 | }
105 | },
106 | "version": "3.1.1"
107 | }
108 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/ponyfill/es2018/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-streams-ponyfill-es2018",
3 | "main": "../../dist/ponyfill.es2018",
4 | "module": "../../dist/ponyfill.es2018.mjs",
5 | "types": "../../dist/types/polyfill.d.ts"
6 | }
7 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/ponyfill/es6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-streams-ponyfill-es6",
3 | "main": "../../dist/ponyfill.es6",
4 | "module": "../../dist/ponyfill.es6.mjs",
5 | "types": "../../dist/types/polyfill.d.ts"
6 | }
7 |
--------------------------------------------------------------------------------
/.github/node_modules/web-streams-polyfill/ponyfill/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-streams-ponyfill",
3 | "main": "../dist/ponyfill",
4 | "module": "../dist/ponyfill.mjs",
5 | "types": "../dist/types/polyfill.d.ts"
6 | }
7 |
--------------------------------------------------------------------------------
/.github/update-sponsors/fetch-sponsors.mjs:
--------------------------------------------------------------------------------
1 | import fetch from "node-fetch";
2 |
3 | export async function fetchSponsors() {
4 | const githubUrl = "https://api.github.com/graphql";
5 | const token = process.env.GITHUB_TOKEN;
6 | const oauth = { Authorization: "bearer " + token };
7 |
8 | if (!token) {
9 | console.log("Missing process.env.GITHUB_TOKEN");
10 | return [];
11 | }
12 |
13 | return await fetch(githubUrl, {
14 | method: "POST",
15 | body: JSON.stringify({ query }),
16 | headers: oauth,
17 | })
18 | .then(function (response) {
19 | return response.json();
20 | })
21 | .then(({ data, errors }) => {
22 | if (errors) {
23 | console.error(JSON.stringify(errors));
24 | return;
25 | }
26 | // console.log(JSON.stringify(data.organization, null, 2));
27 | const ghSponsors = data.organization.sponsorshipsAsMaintainer.nodes
28 | .filter((node) => node.tier.monthlyPriceInDollars >= 9)
29 | .map((node) => {
30 | const { __typename, ...sponsor } = node.sponsorEntity;
31 | return {
32 | ...sponsor,
33 | isOrg: __typename === "Organization",
34 | };
35 | });
36 | return [...otherSponsors, ...ghSponsors.reverse()];
37 | })
38 | .catch((error) => {
39 | console.error("Error fetching sponsors", error);
40 | });
41 | }
42 |
43 | const query = `
44 | {
45 | organization(login: "code-hike") {
46 | sponsorshipsAsMaintainer(last: 100, orderBy: {field: CREATED_AT, direction: DESC}) {
47 | nodes {
48 | tier {
49 | monthlyPriceInDollars
50 | isCustomAmount
51 | isOneTime
52 | }
53 | sponsorEntity {
54 | __typename
55 | ... on User {
56 | name
57 | login
58 | avatarUrl(size: 128)
59 | location
60 | url
61 | }
62 | ... on Organization {
63 | avatarUrl(size: 128)
64 | login
65 | name
66 | location
67 | url
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
74 | `;
75 |
76 | const otherSponsors = [
77 | {
78 | name: "Meta",
79 | login: "facebook",
80 | avatarUrl: "https://avatars.githubusercontent.com/u/69631?v=4",
81 | location: "Menlo Park, California",
82 | url: "https://github.com/facebook",
83 | isOrg: true,
84 | },
85 | {
86 | name: "Outerbounds",
87 | login: "outerbounds",
88 | avatarUrl: "https://avatars.githubusercontent.com/u/82194325?v=4",
89 | location: "",
90 | url: "https://github.com/outerbounds",
91 | isOrg: true,
92 | },
93 | {
94 | name: "Fran Méndez",
95 | login: "fmvilas",
96 | avatarUrl: "https://avatars.githubusercontent.com/u/242119?s=128&v=4",
97 | location: "Spain",
98 | url: "https://github.com/fmvilas",
99 | isOrg: false,
100 | },
101 | {
102 | name: "Matthias Zepper",
103 | login: "MatthiasZepper",
104 | avatarUrl: "https://avatars.githubusercontent.com/u/6963520?s=128&v=4",
105 | location: "Germany",
106 | url: "https://github.com/matthiaszepper",
107 | isOrg: false,
108 | },
109 | ];
110 |
--------------------------------------------------------------------------------
/.github/update-sponsors/index.mjs:
--------------------------------------------------------------------------------
1 | import { fetchSponsors } from "./fetch-sponsors.mjs";
2 | import { promises as fs } from "fs";
3 | const sponsorsFilePath = "./data/sponsors.json";
4 | const demosFilePath = "./data/demos/index.json";
5 |
6 | async function main() {
7 | const sponsors = await fetchSponsors();
8 |
9 | updateSponsors(sponsors);
10 | updateDemos(sponsors);
11 | }
12 |
13 | main();
14 |
15 | process.on("unhandledRejection", (up) => {
16 | throw up;
17 | });
18 |
19 | async function updateSponsors(sponsors) {
20 | const sponsorsData = JSON.parse(await fs.readFile(sponsorsFilePath, "utf8"));
21 | sponsorsData.sponsors = sponsors;
22 | console.table(sponsors.map(({ url, avatarUrl, ...x }) => x));
23 | await fs.writeFile(sponsorsFilePath, JSON.stringify(sponsorsData, null, 2));
24 | }
25 |
26 | async function updateDemos(sponsors) {
27 | const demos = JSON.parse(await fs.readFile(demosFilePath, "utf8"));
28 | const logins = sponsors.map(({ login }) => login);
29 |
30 | demos.forEach((demo) => {
31 | demo.sponsors.forEach((sponsor) => {
32 | if (!logins.includes(sponsor)) {
33 | // remove old sponsor for demo sponsors
34 | removeItem(demo.sponsors, sponsor);
35 | } else {
36 | // remove used sponsors from login list
37 | removeItem(logins, sponsor);
38 | }
39 | });
40 | });
41 |
42 | // add new logins
43 | demos.forEach((demo) => {
44 | while (demo.sponsors.length < 5 && logins.length > 0) {
45 | demo.sponsors.push(logins.pop());
46 | }
47 | demo.locked = demo.sponsors.length < 5;
48 | });
49 |
50 | await fs.writeFile(demosFilePath, JSON.stringify(demos, null, 2));
51 | }
52 |
53 | function removeItem(list, item) {
54 | const index = list.indexOf(item);
55 | if (index > -1) {
56 | list.splice(index, 1);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/.github/workflows/update-sponsors.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch:
3 | name: Update Sponsors
4 | jobs:
5 | render:
6 | name: Update Sponsors
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@main
10 | - uses: actions/setup-node@main
11 | - name: Update sponsors files
12 | run: node .github/update-sponsors/index.mjs
13 | env:
14 | GITHUB_TOKEN: ${{ secrets.CH_GITHUB_TOKEN }}
15 | - name: Commit files
16 | run: |
17 | git config --local user.email "action@github.com"
18 | git config --local user.name "GitHub Action"
19 | git add .
20 | git diff-index --quiet HEAD || git commit -m "Update sponsors" -a
21 | - name: Push changes
22 | uses: ad-m/github-push-action@v0.6.0
23 | with:
24 | github_token: ${{ secrets.GITHUB_TOKEN }}
25 | branch: ${{ github.ref }}
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
36 | todo.md
37 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | # This configuration file was automatically generated by Gitpod.
2 | # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
3 | # and commit this file to your remote git repository to share the goodness with others.
4 |
5 | tasks:
6 | - init: yarn install
7 | command: yarn run dev
8 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [
3 | {
4 | "files": ["*.mdx"],
5 | "options": {
6 | "semi": false,
7 | "printWidth": 40
8 | }
9 | },
10 | {
11 | "files": ["show.mdx", "old-show.mdx"],
12 | "options": {
13 | "printWidth": 54,
14 | "semi": false
15 | }
16 | },
17 | {
18 | "files": ["slideshow-preview.mdx"],
19 | "options": {
20 | "printWidth": 60,
21 | "semi": false
22 | }
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/data/demos/code.mdx:
--------------------------------------------------------------------------------
1 | # Code and Focus
2 |
3 | Code Hike will apply syntax highlighting to any code block
4 |
5 | ```js
6 | function lorem(ipsum, dolor = 1) {
7 | const sit = ipsum == null ? 0 : ipsum.sit;
8 | dolor = sit - amet(dolor);
9 | return sit ? consectetur(ipsum) : [];
10 | }
11 | ```
12 |
13 | It works by default with many languages
14 |
15 | ```groovy
16 | def f() {
17 | return [2, 3]
18 | }
19 |
20 | (a, b) = f()
21 | println a
22 | println b
23 | ```
24 |
25 | Use `focus` to show the code that's important to the reader
26 |
27 | ```js focus=4
28 | function lorem(ipsum, dolor = 1) {
29 | const sit = ipsum == null ? 0 : ipsum.sit;
30 | dolor = sit - amet(dolor);
31 | return sit ? consectetur(ipsum) : [];
32 | }
33 | ```
34 |
35 | You can specify a list of line numbers
36 |
37 | ```js focus=1,3:4
38 | function lorem(ipsum, dolor = 1) {
39 | const sit = ipsum == null ? 0 : ipsum.sit;
40 | dolor = sit - amet(dolor);
41 | return sit ? consectetur(ipsum) : [];
42 | }
43 | ```
44 |
45 | And also columns
46 |
47 | ```js focus=2,4[10:13]
48 | function lorem(ipsum, dolor = 1) {
49 | const sit = ipsum == null ? 0 : ipsum.sit;
50 | dolor = sit - amet(dolor);
51 | return sit ? consectetur(ipsum) : [];
52 | }
53 | ```
54 |
--------------------------------------------------------------------------------
/data/demos/comment-annotations.mdx:
--------------------------------------------------------------------------------
1 | # Comment annotations
2 |
3 | You can use comments inside the code to make the focus relative.
4 |
5 | ```js
6 | function lorem(ipsum, dolor = 1) {
7 | const sit = ipsum == null && 0
8 | dolor = sit - amet(dolor)
9 | // focus
10 | return sit ? consectetur(ipsum) : []
11 | }
12 |
13 | // focus(1:4)
14 | function adipiscing(...elit) {
15 | console.log(elit)
16 | return elit.map((ipsum) => ipsum.sit)
17 | }
18 |
19 | // focus[13:17]
20 | console.log("hey")
21 | ```
22 |
23 | Same with other annotations like `mark`.
24 |
25 | ```js
26 | function foo() {
27 | // mark
28 | console.log("lorem ipsum")
29 | return 8
30 | }
31 | ```
32 |
33 | You can pass a string parameter to comment annotations
34 |
35 | ```js index.js
36 | function lorem(ipsum, dolor = 1) {
37 | // mark(1:3) line-through
38 | const sit = ipsum == null && 0
39 | dolor = sit - amet(dolor)
40 | return sit ? consectetur(ipsum) : []
41 | }
42 |
43 | function adipiscing(...elit) {
44 | console.log(elit)
45 | // withClass[19:38] line-through
46 | return elit.map((ipsum) => ipsum.sit)
47 | }
48 | ```
49 |
50 | ## Links and labels
51 |
52 | And now we introduce two more annotations: `link` and `label`
53 |
54 | ```js focus=4,8
55 | function lorem(ipsum, dolor = 1) {
56 | const sit = ipsum == null && 0
57 | dolor = sit - amet(dolor)
58 | // link[16:26] https://github.com/code-hike/codehike
59 | return sit ? consectetur(ipsum) : []
60 | }
61 |
62 | function adipiscing(...elit) {
63 | // label something something
64 | console.log("hover me")
65 | return elit.map((ipsum) => ipsum.sit)
66 | }
67 | ```
68 |
--------------------------------------------------------------------------------
/data/demos/custom-annotations.mdx:
--------------------------------------------------------------------------------
1 | import MyThing from "./MyThing";
2 |
3 | # Custom Annotations
4 |
5 | ```js app.js
6 | function lorem(ipsum, dolor = 1) {
7 | const sit = ipsum == null && 0;
8 | dolor = sit - amet(dolor);
9 | return sit ? consectetur(ipsum) : [];
10 | }
11 |
12 | function adipiscing(...elit) {
13 | const sit = ipsum == null && 0;
14 | dolor = sit - amet(dolor);
15 | console.log(2);
16 | return elit.map((ipsum) => ipsum.sit);
17 | }
18 | ```
19 |
20 |
21 |
22 | ### Something
23 |
24 | Lorem ipsum dolor sit amet, consectetur adipiscing elit.
25 |
26 |
27 |
--------------------------------------------------------------------------------
/data/demos/custom-annotations/MyThing.jsx:
--------------------------------------------------------------------------------
1 | import * as HoverCard from "@radix-ui/react-hover-card";
2 |
3 | export default function MyTooltipAnnotation({ children, data, theme }) {
4 | const border =
5 | typeof data === "string"
6 | ? data
7 | : theme.tokenColors.find((tc) => tc.scope?.includes("string"))?.settings
8 | ?.foreground || "yellow";
9 |
10 | return (
11 |
12 |
13 | {children}
14 |
15 |
19 |
20 | {data?.children || "Hey"}
21 |
22 |
23 | );
24 | return;
25 | }
26 |
--------------------------------------------------------------------------------
/data/demos/filenames.mdx:
--------------------------------------------------------------------------------
1 | # Filenames
2 |
3 | Adding a filename to the codeblock
4 |
5 | ```js app.js
6 | function lorem(ipsum, dolor = 1) {
7 | const sit = ipsum == null ? 0 : ipsum.sit;
8 | dolor = sit - amet(dolor);
9 | return sit ? consectetur(ipsum) : [];
10 | }
11 | ```
12 |
13 | ## Tabs
14 |
15 | To add more tabs, wrap multiple codeblocks with ``:
16 |
17 |
18 |
19 | ```js app.js
20 | function lorem(ipsum, dolor = 1) {
21 | const sit = ipsum == null ? 0 : ipsum.sit;
22 | dolor = sit - amet(dolor);
23 | return sit ? consectetur(ipsum) : [];
24 | }
25 | ```
26 |
27 | ```css styles.css
28 | .lorem {
29 | color: #fff;
30 | padding: 10px;
31 | background: #000;
32 | }
33 | ```
34 |
35 |
36 |
37 | ## Panels
38 |
39 | The _editor_ can be splitted vertically in two panels using `---`
40 |
41 |
42 |
43 | ```js app.js
44 | function lorem(ipsum, dolor = 1) {
45 | const sit = ipsum == null ? 0 : ipsum.sit;
46 | dolor = sit - amet(dolor);
47 | return sit ? consectetur(ipsum) : [];
48 | }
49 | ```
50 |
51 | ---
52 |
53 | ```css styles.css
54 | .lorem {
55 | color: #fff;
56 | padding: 10px;
57 | background: #000;
58 | }
59 | ```
60 |
61 |
62 |
--------------------------------------------------------------------------------
/data/demos/index.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "code",
4 | "title": "Code and focus",
5 | "sponsors": [
6 | "facebook",
7 | "fmvilas",
8 | "MatthiasZepper",
9 | "speakeasybot",
10 | "kickstartDS"
11 | ],
12 | "locked": false
13 | },
14 | {
15 | "id": "filenames",
16 | "title": "Filenames and tabs",
17 | "sponsors": [
18 | "yacinelakel",
19 | "molebox",
20 | "codecrafters-io",
21 | "kiliman",
22 | "zmzlois"
23 | ],
24 | "locked": false
25 | },
26 | {
27 | "id": "meta-annotations",
28 | "title": "Annotations",
29 | "sponsors": [
30 | "codeSTACKr",
31 | "hunterbecton",
32 | "n0lawz"
33 | ],
34 | "locked": true
35 | },
36 | {
37 | "id": "comment-annotations",
38 | "title": "Comment annotations",
39 | "sponsors": [],
40 | "locked": true
41 | },
42 | {
43 | "id": "sections",
44 | "title": "Code links",
45 | "sponsors": [
46 | "traviscooper",
47 | "arosenkranz",
48 | "Naturalclar",
49 | "outerbounds",
50 | "ndimares"
51 | ],
52 | "locked": false
53 | },
54 | {
55 | "id": "spotlight",
56 | "title": "Spotlight",
57 | "sponsors": [
58 | "obgibson"
59 | ],
60 | "locked": true
61 | },
62 | {
63 | "id": "spotlight-preview",
64 | "title": "Spotlight & preview",
65 | "sponsors": [
66 | "brianespinosa",
67 | "drivly",
68 | "nathanclevenger"
69 | ],
70 | "locked": true
71 | },
72 | {
73 | "id": "scrollycoding",
74 | "title": "Scrollycoding",
75 | "sponsors": [],
76 | "locked": true
77 | },
78 | {
79 | "id": "scrollycoding-preview",
80 | "title": "Scrollycoding & preview",
81 | "sponsors": [],
82 | "locked": true
83 | },
84 | {
85 | "id": "slideshow",
86 | "title": "Slideshow",
87 | "sponsors": [],
88 | "locked": true
89 | },
90 | {
91 | "id": "slideshow-preview",
92 | "title": "Slideshow & preview",
93 | "sponsors": [],
94 | "locked": true
95 | }
96 | ]
--------------------------------------------------------------------------------
/data/demos/meta-annotations.mdx:
--------------------------------------------------------------------------------
1 | # Annotations
2 |
3 | There are a few more annotations that can be used to highlight code.
4 |
5 | ### `mark` annotation
6 |
7 | ```js mark=1[10:14]
8 | function lorem(ipsum, dolor = 1) {
9 | const sit =
10 | ipsum == null ? 0 : ipsum.sit
11 | dolor = sit - amet(dolor)
12 | return dolor
13 | }
14 | ```
15 |
16 | ```js mark=2:4
17 | function lorem(ipsum, dolor = 1) {
18 | const sit =
19 | ipsum == null ? 0 : ipsum.sit
20 | dolor = sit - amet(dolor)
21 | return dolor
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/data/demos/scrollycoding.mdx:
--------------------------------------------------------------------------------
1 | # Scrollycoding
2 |
3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
4 |
5 | Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
6 |
7 |
8 |
9 | ## Step 1
10 |
11 | Lorem ipsum dolor sit amet, consectetur adipiscing something about points, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
12 |
13 | > Nova in illis at dabat legi harundine non, ova miratur? _Quid in_ sole aer
14 | > ad diffusa illis voluisti fidensque coniugiale laniata curam. Aras rivus
15 | > eripuit, qua fistula haec partus; serpens, negat.
16 |
17 | Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.
18 |
19 | ```js app.js focus=3:10
20 | const { lorem, ipsum } = dolor({
21 | sit: {
22 | amet: 1,
23 | consectetur: 2,
24 | adipiscing: (elit) => ({
25 | sed: elit,
26 | }),
27 | eiusmod: (tempor) => ({
28 | incididunt: tempor,
29 | }),
30 | ut: (labore) => ({
31 | et: labore,
32 | dolore: labore + 1,
33 | }),
34 | magna: (aliqua) => ({
35 | ut: aliqua,
36 | }),
37 | nostrud: (elit) => ({
38 | exercitation: elit,
39 | ullamco: elit,
40 | }),
41 | laboris: (elit) => ({
42 | nisi: elit,
43 | }),
44 | },
45 | });
46 | ```
47 |
48 | ---
49 |
50 | ## Step 2
51 |
52 | Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in.
53 |
54 | Praesent elementum facilisis leo vel fringilla est ullamcorper eget.
55 |
56 | Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
57 |
58 | Morbi quis commodo.
59 |
60 | ```js app.js focus=11:17
61 |
62 | ```
63 |
64 | ---
65 |
66 | ## Step 3
67 |
68 | Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu.
69 |
70 | - Nisi lacus sed viverra tellus in
71 | - Nibh cras pulvinar mattis nunc sed
72 | - Luctus accumsan tortor posuere ac
73 |
74 | Ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
75 |
76 | ```js app.js focus=11:14
77 | const { lorem, ipsum } = dolor({
78 | sit: {
79 | amet: 1,
80 | consectetur: 2,
81 | adipiscing: (elit) => ({
82 | sed: elit,
83 | }),
84 | eiusmod: (tempor) => ({
85 | incididunt: tempor,
86 | }),
87 | ut: (labore) => ({
88 | et: lorem(labore * ipsum),
89 | dolore: lorem(labore + 1),
90 | }),
91 | nostrud: (elit) => ({
92 | exercitation: elit,
93 | ullamco: elit,
94 | }),
95 | laboris: (elit) => ({
96 | nisi: elit,
97 | }),
98 | },
99 | });
100 | ```
101 |
102 | ---
103 |
104 | ## Step 4
105 |
106 | Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt.
107 |
108 | Sed blandit libero volutpat sed cras.
109 |
110 | - Nisi lacus sed viverra tellus in
111 | - Nibh cras pulvinar mattis nunc sed
112 |
113 | Gravida in fermentum et sollicitudin ac orci phasellus egestas tellus. Volutpat consequat mauris nunc congue nisi vitae.
114 |
115 | ```js app.js focus=15:21
116 |
117 | ```
118 |
119 | ---
120 |
121 | ## Step 5
122 |
123 | Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in.
124 |
125 | Praesent elementum facilisis leo vel fringilla est ullamcorper eget.
126 |
127 | Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat.
128 |
129 | Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra.
130 |
131 | - Fringilla ut morbi tincidunt augue interdum velit euismod.
132 | - Luctus accumsan tortor posuere ac ut consequat semper viverra.
133 |
134 | Morbi quis commodo.
135 |
136 | ```js app.js
137 |
138 | ```
139 |
140 |
141 |
142 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
143 |
144 | Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
145 |
--------------------------------------------------------------------------------
/data/demos/sections.mdx:
--------------------------------------------------------------------------------
1 | # Code Links
2 |
3 | Lorem ipsum dolor sit amet.
4 |
5 |
6 |
7 | Consectetur adipiscing elit, sed do eiusmod tempor [incididunt](focus://4:7) ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget.
8 |
9 | ```js
10 | function lorem(ipsum, dolor) {
11 | const sit = "lorem ipsum";
12 | dolor = elit(dolor, 3);
13 | while (++consectetur < amet) {
14 | sit.eiusmod(150);
15 | tempor(ipsum, adipiscing);
16 | }
17 | }
18 | ```
19 |
20 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum [dolore](focus://1[23:27],3) eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.
21 |
22 |
23 |
24 | ## With multiple files
25 |
26 |
27 |
28 | Lorem dolor sit amet, [javascript](focus://index.js#2:3) adipiscing elit, sed do eiusmod [styles](focus://styles.css#2:3) incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
29 |
30 |
31 |
32 | ```js index.js
33 | function lorem(ipsum, dolor) {
34 | const sit = ipsum - amet(dolor);
35 | return sit + "lorem ipsum";
36 | }
37 | ```
38 |
39 | ```css styles.css
40 | .lorem-ipsum > .dolor pre {
41 | background-color: var(--color-bg);
42 | padding: 1em 0px 10vh 300px;
43 | }
44 | ```
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/data/demos/slideshow.mdx:
--------------------------------------------------------------------------------
1 | # Slideshow
2 |
3 | This is how to use the `` component. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quia! Quidem, quisquam.
4 |
5 |
6 |
7 | ```rust
8 | pub fn add(a: i32, b: i32) -> i32 {
9 | a + b
10 | }
11 |
12 | #[allow(dead_code)]
13 | fn bad_add(a: i32, b: i32) -> i32 {
14 | a - b
15 | }
16 | ```
17 |
18 | ---
19 |
20 | ```rust
21 | pub fn add(a: i32, b: i32) -> i32 {
22 | a + b
23 | }
24 |
25 | #[allow(dead_code)]
26 | fn bad_add(a: i32, b: i32) -> i32 {
27 | a - b
28 | }
29 |
30 | // focus(1:4)
31 | #[cfg(test)]
32 | mod tests {
33 | use super::*;
34 | }
35 | ```
36 |
37 | ---
38 |
39 | ```rust
40 | // focus(1:3)
41 | pub fn add(a: i32, b: i32) -> i32 {
42 | a + b
43 | }
44 |
45 | #[allow(dead_code)]
46 | fn bad_add(a: i32, b: i32) -> i32 {
47 | a - b
48 | }
49 |
50 | #[cfg(test)]
51 | mod tests {
52 | use super::*;
53 | // focus(1:4)
54 | #[test]
55 | fn test_add() {
56 | assert_eq!(add(1, 2), 3);
57 | }
58 | }
59 | ```
60 |
61 | ---
62 |
63 | ```rust
64 | pub fn add(a: i32, b: i32) -> i32 {
65 | a + b
66 | }
67 |
68 | // focus(1:4)
69 | #[allow(dead_code)]
70 | fn bad_add(a: i32, b: i32) -> i32 {
71 | a - b
72 | }
73 |
74 | #[cfg(test)]
75 | mod tests {
76 | use super::*;
77 | #[test]
78 | fn test_add() {
79 | assert_eq!(add(1, 2), 3);
80 | }
81 | // focus(1:4)
82 | #[test]
83 | fn test_bad_add() {
84 | assert_eq!(bad_add(1, 2), 3);
85 | }
86 | }
87 | ```
88 |
89 |
90 |
--------------------------------------------------------------------------------
/data/demos/spotlight-preview.mdx:
--------------------------------------------------------------------------------
1 | # Spotlight with preview
2 |
3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
4 |
5 |
6 |
7 | ```jsx app.js
8 | import Circle from "./circle";
9 | const red = "hsl(0 85% 60%)";
10 | export default function App() {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 | ```
18 |
19 | ---
20 |
21 | ## Lorem
22 |
23 | Lorem ipsum dolor sit amet, consectetur adipiscing something about points, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
24 |
25 | ```jsx app.js
26 |
27 | ```
28 |
29 | ---
30 |
31 | ## Ipsum
32 |
33 | Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in.
34 |
35 | ```jsx app.js focus=5:9
36 | import Circle from "./circle";
37 | const red = "hsl(0 85% 60%)";
38 | export default function App() {
39 | return (
40 |
41 |
42 |
43 |
44 |
45 | );
46 | }
47 | ```
48 |
49 | ---
50 |
51 | ## Dolor sit
52 |
53 | Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu.
54 |
55 | ```jsx app.js focus=2,6:8
56 | import Circle from "./circle";
57 | const red = "hsl(0 85% 60%)";
58 | export default function App() {
59 | return (
60 |
61 |
62 |
63 |
64 |
65 | );
66 | }
67 | ```
68 |
69 | ---
70 |
71 | ## Amet
72 |
73 | Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt.
74 |
75 | ```jsx app.js focus=8:10
76 | import Circle from "./circle";
77 | const red = "hsl(0 85% 60%)";
78 | const blue = "hsl(240 50% 60%)";
79 | const gold = "hsl(60 60% 60%)";
80 | export default function App() {
81 | return (
82 |
83 |
84 |
85 |
86 |
87 | );
88 | }
89 | ```
90 |
91 |
92 |
93 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
94 |
95 | Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
96 |
--------------------------------------------------------------------------------
/data/demos/spotlight.mdx:
--------------------------------------------------------------------------------
1 | # Spotlight
2 |
3 | This is how to use the `` component. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quia! Quidem, quisquam.
4 |
5 |
6 |
7 | ```js app.js
8 | function lorem(ipsum, dolor = 1) {
9 | const sit = ipsum == null && 0;
10 | dolor = sit - amet(dolor);
11 | return sit ? consectetur(ipsum) : [];
12 | }
13 | ```
14 |
15 | ---
16 |
17 | Change focus
18 |
19 | ```js app.js focus=2:4
20 |
21 | ```
22 |
23 | ---
24 |
25 | Or change the code
26 |
27 | ```js app.js focus=6:10
28 | function lorem(ipsum, dolor = 1) {
29 | const sit = ipsum == null && 0;
30 | dolor = sit - amet(dolor);
31 | return sit ? consectetur(ipsum) : [];
32 | }
33 |
34 | function adipiscing(...elit) {
35 | console.log(elit);
36 | return elit.map((ipsum) => ipsum.sit);
37 | }
38 | ```
39 |
40 | ---
41 |
42 | Or change the file
43 |
44 |
45 |
46 | ```js app.js focus=1:4
47 | function adipiscing(...elit) {
48 | console.log(elit);
49 | return elit.map((ipsum) => ipsum.sit);
50 | }
51 | ```
52 |
53 | ---
54 |
55 | ```css styles.css
56 | .lorem {
57 | color: #fff;
58 | padding: 10px;
59 | background: #000;
60 | }
61 | ```
62 |
63 |
64 |
65 | ---
66 |
67 | ### By the way
68 |
69 | - you can
70 | - put any
71 | - markdown
72 | - here
73 |
74 | 👍
75 |
76 | ```js app.js
77 |
78 | ```
79 |
80 |
81 |
--------------------------------------------------------------------------------
/docs/ch-code.mdx:
--------------------------------------------------------------------------------
1 | With _``_ you can show code files in [tabs](#tabs) or [panels](#panels). You can also pass props to [override configuration](#override-configuration) or [customize styling](#styling-props).
2 |
3 | ## Tabs
4 |
5 | When you include more than one code blocks inside a _``_, Code Hike will show them as tabs.
6 |
7 |
8 |
9 | ```mdx your.mdx
10 | // from ../docs/preview/ch-code-1.mdx
11 | ```
12 |
13 |
20 |
21 |
22 |
23 | ## Panels
24 |
25 | You can also show two files at the same time in two panels. Use a divider _`---`_ to separate the top tabs from the bottom tabs.
26 |
27 |
28 |
29 | ```mdx your.mdx focus=1,7,13
30 | // from ../docs/preview/ch-code-2.mdx
31 | ```
32 |
33 |
40 |
41 |
42 |
43 | ## Override configuration
44 |
45 | You can override some of the [configuration](configuration) options by passing props to _``_.
46 |
47 |
48 |
49 | ```mdx your.mdx focus=1,9 mark=1[10:27]
50 | // from ../docs/preview/ch-code-3.mdx
51 | ```
52 |
53 |
60 |
61 |
62 |
63 | ## Styling props
64 |
65 | Then there are the _`style`_ and _`className`_ props. You can use them to customize the styles of the component.
66 |
67 |
68 |
69 | ```mdx your.mdx focus=1,9 mark=1[10:30]
70 | // from ../docs/preview/ch-code-4.mdx
71 | ```
72 |
73 |
80 |
81 |
82 |
83 | ## Height
84 |
85 |
86 |
87 | By default, `` will take the height needed to fit all the lines of the given code. As we saw in the previous example, you can use CSS to set a fixed height.
88 |
89 | Instead of setting the height with CSS, you can also use the _`rows`_ prop. You pass the number of lines you want to show, and Code Hike will set the height accordingly.
90 |
91 |
92 |
93 | ```mdx your.mdx focus=1 mark=1[10:17]
94 | // from ../docs/preview/ch-code-5.mdx
95 | ```
96 |
97 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | In addition to the number of lines, you can also pass _`"focus"`_, then the height of the code will match the height of the focused lines.
112 |
113 |
114 |
115 | ```mdx your.mdx focus=1 mark=1[10:21]
116 | // from ../docs/preview/ch-code-6.mdx
117 | ```
118 |
119 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/ch-scrollycoding.mdx:
--------------------------------------------------------------------------------
1 | **This feature is experimental.**
2 |
3 | For a sneak peek, see the demos:
4 |
5 | - [Scrollycoding demo](/demo/scrollycoding)
6 | - [Scrollycoding with preview demo](/demo/scrollycoding-preview)
7 |
--------------------------------------------------------------------------------
/docs/ch-section.mdx:
--------------------------------------------------------------------------------
1 | Sometimes it is useful to reference code from a section of text. Since the code may be below or above the text, we need to wrap the text and the code inside an element: _``_.
2 |
3 | With the `` component you can reference code in two ways:
4 |
5 | - [Inline code](#inline-code)
6 | - [Code mentions](#code-mentions)
7 |
8 | ## Inline code
9 |
10 | With Code Hike, you have two options to render inline code:
11 |
12 | - You can use the standard markdown syntax where you wrap the code in backticks: `` `var x = 10` ``, which won't be syntax-highlighted.
13 | - Or use a special syntax where you wrap the code with underscores and backticks: _`` _`var x = 10`_ ``_, which will be syntax-highlighted as _`var x = 10`_.
14 |
15 | Usually, the syntax depends on the context and the language. If you use the special inline code inside a `` component, Code Hike will copy the highlighting from the code to the text:
16 |
17 |
18 |
19 | ```mdx your.mdx mark=8[11:30]
20 | // from ../docs/preview/ch-section-1.mdx
21 | ```
22 |
23 |
30 |
31 |
32 |
33 | ## Code mentions
34 |
35 | Code mentions are a way to link code and text. We borrow the link syntax from markdown to create hoverable links to the code. It's easier to show than to explain:
36 |
37 |
38 |
39 | ```mdx your.mdx focus=1,8[8:34],10
40 | // from ../docs/preview/ch-section-2.mdx
41 | ```
42 |
43 |
50 |
51 |
52 |
53 | The syntax is the same as a markdown link, but instead of an URL, you use `focus://` as the protocol, and then pass a [focus string](annotations#metastring-syntax).
54 |
55 | Code mentions are useful when you have more than one file. To specify the file, you prepend the name before the focus string and separate them with a `#`:
56 |
57 |
58 |
59 | ```mdx your.mdx focus=1,3,4,21 mark=3[20:34],4[20:33]
60 | // from ../docs/preview/ch-section-3.mdx
61 | ```
62 |
63 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/docs/ch-slideshow.mdx:
--------------------------------------------------------------------------------
1 | **This feature is experimental.**
2 |
3 | For a sneak peek, see the demos:
4 |
5 | - [Slideshow demo](/demo/slideshow)
6 | - [Slideshow with preview demo](/demo/slideshow-preview)
7 |
--------------------------------------------------------------------------------
/docs/ch-spotlight.mdx:
--------------------------------------------------------------------------------
1 | **This feature is experimental.**
2 |
3 | For a sneak peek, see the demos:
4 |
5 | - [Spotlight demo](/demo/spotlight)
6 | - [Spotlight with preview demo](/demo/spotlight-preview)
7 |
--------------------------------------------------------------------------------
/docs/codeblocks.mdx:
--------------------------------------------------------------------------------
1 | The fundamental building block of Code Hike is the code block. There are several ways to write code blocks inside markdown. The most common way is to wrap the code using triple backticks:
2 |
3 | {/* prettier-ignore */}
4 | ````mdx lorem.mdx focus=3:5
5 | ## Lorem ipsum
6 |
7 | ```
8 | print("Hello, world!")
9 | ```
10 |
11 | dolor **sit** amet
12 | ````
13 |
14 | ### Syntax highlighting
15 |
16 | If you specify a language after the ``` Code Hike will apply syntax highlighting to the code.
17 |
18 |
19 |
20 | {/* prettier-ignore */}
21 | ````mdx lorem.mdx focus=3:5 mark=3[4:9]
22 | ### Lorem ipsum
23 |
24 | ```python
25 | print("Hello, world!")
26 | ```
27 |
28 | dolor **sit** amet
29 | ````
30 |
31 |
39 |
40 |
41 |
42 | ### Languages
43 |
44 |
45 |
46 | ### Filename
47 |
48 | If you add a title after the language, Code Hike will show a different UI featuring the filename:
49 |
50 |
51 |
52 | {/* prettier-ignore */}
53 | ````mdx lorem.mdx focus=3:5 mark=3[11:18]
54 | ### Lorem ipsum
55 |
56 | ```python hello.py
57 | print("Hello, world!")
58 | ```
59 |
60 | dolor **sit** amet
61 | ````
62 |
63 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/docs/configuration.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | Somewhere in your code, you'll have a _`remarkPlugins`_ array, there you'll find Code Hike's [config object](focus://9:13). If you haven't already set Code Hike up, see the [installation docs](installation) first.
4 |
5 | {/* prettier-ignore */}
6 | ```js your.config.js
7 | const remarkSomething = require("remark-something")
8 | // focus
9 | const { remarkCodeHike } = require("@code-hike/mdx")
10 |
11 | mdxOptions = {
12 | remarkPlugins: [
13 | // focus(1:12)
14 | [
15 | remarkCodeHike,
16 | {
17 | // link[9:19] #line-numbers
18 | lineNumbers: false,
19 | // link[9:22] #copy-button
20 | showCopyButton: false,
21 | // link[9:13] #theme
22 | theme: "dark-plus",
23 | // link[9:21] #skip-languages
24 | skipLanguages: ["mermaid"],
25 | // link[9:24] #static-components
26 | staticMediaQuery: "not screen, (max-width: 768px)",
27 | // link[9:18] #auto-import
28 | autoImport: true,
29 | // link[9:16] #auto-link
30 | autoLink: false,
31 | },
32 | ],
33 | remarkSomething,
34 | remarkSomethingElse,
35 | ],
36 | }
37 | ```
38 |
39 |
40 |
41 | ## Line Numbers
42 |
43 |
44 |
45 | ## Copy Button
46 |
47 | To add a copy button to your code, set _`showCopyButton`_ to _`true`_.
48 |
49 |
50 |
51 | ```js your.config.js
52 | mdxOptions = {
53 | remarkPlugins: [
54 | [
55 | remarkCodeHike,
56 | {
57 | theme: someTheme,
58 | // focus
59 | // mark[25:28]
60 | showCopyButton: true,
61 | },
62 | ],
63 | ],
64 | }
65 | ```
66 |
67 |
68 |
69 | A common pattern is to have the copy button hidden by default, but show it when the user hovers over the code. You can do it with this CSS:
70 |
71 |
72 |
73 | ```css
74 | .ch-codeblock .ch-code-button {
75 | display: none;
76 | }
77 |
78 | .ch-codeblock:hover .ch-code-button {
79 | display: block;
80 | }
81 | ```
82 |
83 |
84 |
85 | ## Theme
86 |
87 | See the [themes docs](themes) for more info.
88 |
89 | ## Skip Languages
90 |
91 |
92 |
93 | If you want Code Hike to skip certain languages, you can set _`skipLanguages`_. This is useful when you have other plugins that handle those languages, like [mermaid](https://github.com/mermaid-js/mermaid).
94 |
95 | ```js
96 | mdxOptions = {
97 | remarkPlugins: [
98 | [
99 | remarkCodeHike,
100 | {
101 | theme: someTheme,
102 | // focus
103 | skipLanguages: ["", "mermaid"],
104 | },
105 | ],
106 | ],
107 | }
108 | ```
109 |
110 |
111 |
112 | ## Static Components
113 |
114 | Some components, like `` have static versions more suitable for small screens or printing. You can choose the media query that triggers the static version.
115 |
116 | {/* prettier-ignore */}
117 | ```js
118 | mdxOptions = {
119 | remarkPlugins: [
120 | [
121 | remarkCodeHike,
122 | {
123 | theme: someTheme,
124 | // focus
125 | // mark[28:57]
126 | staticMediaQuery: "not screen, (max-width: 768px)",
127 | },
128 | ],
129 | ],
130 | }
131 | ```
132 |
133 | ## Auto Import
134 |
135 |
136 |
137 | By default, any Code Hike component used in your mdx files will be automatically imported. But some tools don't work well with imports in mdx files, so you can disable this feature by setting _`autoImport: false`_.
138 |
139 | ```js
140 | mdxOptions = {
141 | remarkPlugins: [
142 | [
143 | remarkCodeHike,
144 | {
145 | theme: someTheme,
146 | // focus
147 | // mark[21:25]
148 | autoImport: false,
149 | },
150 | ],
151 | ],
152 | }
153 | ```
154 |
155 |
156 |
157 | Then you'll need to pass Code Hike components as a prop like this:
158 |
159 | ```js
160 | import Example from "./example.mdx"
161 | import { CH } from "@code-hike/mdx/components"
162 |
163 | function App() {
164 | // mark[19:37]
165 | return
166 | }
167 | ```
168 |
169 | ## Auto Link
170 |
171 |
172 |
173 | You can set _`autoLink: true`_ to automatically turn any URL in your code into a link.
174 |
175 | ```js
176 | mdxOptions = {
177 | remarkPlugins: [
178 | [
179 | remarkCodeHike,
180 | {
181 | // focus
182 | // mark[19:22]
183 | autoLink: true,
184 | },
185 | ],
186 | ],
187 | }
188 | ```
189 |
190 |
191 |
--------------------------------------------------------------------------------
/docs/configuration/line-numbers.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | Line numbers are turned off by default (I'm not a fan of line numbers). You can turn them on by setting _`lineNumbers: true`_.
4 |
5 | ```js
6 | mdxOptions = {
7 | remarkPlugins: [
8 | [
9 | remarkCodeHike,
10 | {
11 | theme: someTheme,
12 | // focus
13 | // mark[22:25]
14 | // label but do you really need line numbers?
15 | lineNumbers: true,
16 | },
17 | ],
18 | ],
19 | }
20 | ```
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/configuration/theme.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```js lorem.js
4 | // lorem ipsum dolor sit
5 | function lorem(ipsum, dolor = 1) {
6 | const sit = ipsum == null
7 | // mark
8 | dolor = sit - amet(dolor)
9 | return "consectetur"
10 | }
11 | ```
12 |
13 | ```css styles/ipsum.css
14 | html,
15 | body {
16 | margin: 0;
17 | font-size: 16px;
18 | font-family: sans-serif;
19 | }
20 | ```
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/installation-astro.mdx:
--------------------------------------------------------------------------------
1 | Not sure what's the state of MDX v2 support with Astro. But I guess it's possible to [build a custom renderer](https://docs.astro.build/en/reference/renderer-reference/#building-your-own-renderer) for MDX v2. Contributions to [the examples repo](https://github.com/code-hike/examples) are welcome.
2 |
--------------------------------------------------------------------------------
/docs/installation-cra.mdx:
--------------------------------------------------------------------------------
1 | Not working. See this [pull request](https://github.com/code-hike/examples/pull/2).
2 |
--------------------------------------------------------------------------------
/docs/installation-docspage.mdx:
--------------------------------------------------------------------------------
1 | ## docs.page + Code Hike
2 |
3 | [Docs.page](https://docs.page/) generates docs directly from your GitHub repository.
4 |
5 | You can [use it together with Code Hike](https://twitter.com/pomber/status/1501972442432122880) using an [experimental flag](https://github.com/pomber/docs-page-demo/blob/main/docs.json#L7).
6 |
7 | Guide coming soon.
8 |
--------------------------------------------------------------------------------
/docs/installation-eleventy.mdx:
--------------------------------------------------------------------------------
1 | See this [pull request](https://github.com/code-hike/examples/pull/1).
2 |
--------------------------------------------------------------------------------
/docs/installation-gatsby.mdx:
--------------------------------------------------------------------------------
1 | ## Gatsby + Code Hike
2 |
3 | See [this example](https://github.com/code-hike/codehike/tree/next/examples/gatsby) or try it on [CodeSandbox](https://codesandbox.io/s/github/code-hike/codehike/tree/main/examples/gatsby?file=/src/pages/index.mdx).
4 |
5 | Gatsby + MDX docs: [https://www.gatsbyjs.com/docs/how-to/routing/mdx/](https://www.gatsbyjs.com/docs/how-to/routing/mdx/)
6 |
--------------------------------------------------------------------------------
/docs/installation-mdx-bundler.mdx:
--------------------------------------------------------------------------------
1 | ## Next.js + MDX Bundler + Code Hike
2 |
3 | See this [example](https://github.com/code-hike/codehike/tree/next/examples/mdx-bundler). Guide coming soon.
4 |
--------------------------------------------------------------------------------
/docs/installation-motif.mdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pomber/code-hike-site/eb211f21fb0aecab2596eb78247b26dd026e038a/docs/installation-motif.mdx
--------------------------------------------------------------------------------
/docs/installation-next-mdx-remote.mdx:
--------------------------------------------------------------------------------
1 | ## Next MDX Remote + Code Hike
2 |
3 | _Based on [Next.js official docs](https://nextjs.org/docs/advanced-features/using-mdx) and [next-mdx-remote](https://github.com/hashicorp/next-mdx-remote)._
4 |
5 | Start by installing next and react on an empty directory:
6 |
7 |
8 |
9 | ```bash
10 | npm install next react react-dom
11 | ```
12 |
13 |
14 |
15 |
16 |
17 | Then also install the [next-mdx-remote](focus://1[7:21]) plugin.
18 |
19 |
20 |
21 | ```bash
22 | npm i next-mdx-remote
23 | ```
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | First, you need to create a `pages/_app.js` file if you don't have one.
34 |
35 | The _`MyApp`_ component is where you put global stuff that applies to all pages.
36 |
37 | You can find more information about the `_app.js` file in the [Next.js official docs](https://nextjs.org/docs/advanced-features/custom-app).
38 |
39 | {/* prettier-ignore */}
40 | ```js pages/_app.js
41 | function MyApp({ Component, pageProps }) {
42 | return
43 | }
44 |
45 | export default MyApp
46 | ```
47 |
48 | ---
49 |
50 | We use `pages/_app.js` file to import Code Hike's stylesheet.
51 |
52 | If you want to customize Code Hike's styles with a global stylesheet make sure to import it after this import to avoid specificity issues.
53 |
54 | You can learn more about customizing Code Hike styles in the [styling docs](/docs/styling).
55 |
56 | {/* prettier-ignore */}
57 | ```js pages/_app.js focus=1
58 | import "@code-hike/mdx/dist/index.css"
59 |
60 | function MyApp({ Component, pageProps }) {
61 | return
62 | }
63 |
64 | export default MyApp
65 | ```
66 |
67 | ---
68 |
69 | Next, create a page for rendering your MDX content.
70 |
71 | You can learn more about parsing MDX content from remote locations in the [next-mdx-remote docs](https://github.com/hashicorp/next-mdx-remote);
72 |
73 | ```js pages/content.js
74 | import { serialize } from "next-mdx-remote/serialize"
75 | import { MDXRemote } from "next-mdx-remote"
76 |
77 | import Test from "../components/test"
78 |
79 | const components = {}
80 |
81 | export default function TestPage({
82 | source,
83 | }) {
84 | return (
85 |
86 |
90 |
91 | )
92 | }
93 |
94 | export async function getStaticProps() {
95 | // MDX text - can be from a local file, database, anywhere
96 | const source =
97 | "Some **mdx** text,
using an HTML element
"
98 | const mdxSource = await serialize(
99 | source
100 | )
101 | return {
102 | props: { source: mdxSource },
103 | }
104 | }
105 | ```
106 |
107 | ---
108 |
109 | To set up Code Hike you need to import the ` @code-hike/mdx`` plugin, and add it to the `remarkPlugins``array in the`serialize` function.
110 |
111 | Next to the plugin you can pass [a config object](focus://10[24:32]). Almost always you'll want to pass a `theme` there. For more information about themes, see the [themes docs](/docs/themes).
112 |
113 | You can also pass more options, like `lineNumbers` for example. See the [configuration docs](/docs/configuration) for more information.
114 |
115 | ```js pages/content.js focus=3:4,6,19:24
116 | import { serialize } from "next-mdx-remote/serialize"
117 | import { MDXRemote } from "next-mdx-remote"
118 | import { remarkCodeHike } from "@code-hike/mdx"
119 | import { CH } from "@code-hike/mdx/components"
120 |
121 | const components = { CH }
122 |
123 | export default function TestPage({
124 | source,
125 | }) {
126 | return (
127 |
128 |
132 |
133 | )
134 | }
135 |
136 | export async function getStaticProps() {
137 | // MDX text - can be from a local file, database, anywhere
138 | const source =
139 | "Some **mdx** text,
using an HTML element
"
140 | const mdxSource = await serialize(
141 | source,
142 | {
143 | mdxOptions: {
144 | remarkPlugins: [
145 | [
146 | remarkCodeHike,
147 | {
148 | autoImport: false,
149 | theme: "material-default",
150 | },
151 | ],
152 | ],
153 | useDynamicImport: true,
154 | },
155 | }
156 | )
157 | return {
158 | props: { source: mdxSource },
159 | }
160 | }
161 | ```
162 |
163 | ---
164 |
165 | And now you can import mdx files from anywhere.
166 |
167 | For examples on importing files from your local file system or a database, refer to the `next-mdx-remote` [docs](https://github.com/hashicorp/next-mdx-remote).
168 |
169 |
170 |
171 |
172 |
173 | A demo of Code Hike + NextJS is available on [GitHub](https://github.com/code-hike/codehike/tree/next/examples/next-mdx-remote). You can also try it out from your browser on [StackBlitz](https://github.com/code-hike/codehike/tree/next/examples/next-mdx-remote?file=pages%2Findex.mdx).
174 |
175 |
176 |
--------------------------------------------------------------------------------
/docs/installation-nextjs.mdx:
--------------------------------------------------------------------------------
1 | ## Next.js + Code Hike
2 |
3 | _Based on [Next.js official docs](https://nextjs.org/docs/advanced-features/using-mdx)._
4 |
5 | Start by installing next and react on an empty directory:
6 |
7 |
8 |
9 | ```bash
10 | npm install next react react-dom
11 | ```
12 |
13 |
14 |
15 |
16 |
17 | Then also install the [mdx plugin for next](focus://1[13:21]), the [mdx loader](focus://1[23:36]), and [Code Hike](focus://1[38:56]).
18 |
19 |
20 |
21 | ```bash
22 | npm install @next/mdx @mdx-js/loader @code-hike/mdx
23 | ```
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Create a `next.config.js` file at the root of your project.
34 |
35 | We use the _`@next/mdx`_ plugin to [set up MDX imports](focus://1:6,8,13).
36 |
37 | Inside the _`withMDX`_ function we pass the Next JS config. Make sure to [include `"md"` and `"mdx"`](focus://9,11[12:22],12) on the _`pageExtensions`_ setting if you want to write MDX files directly in your `pages` directory.
38 |
39 | After this step, you can use MDX files in your project, but you can't use Code Hike yet.
40 |
41 | {/* prettier-ignore */}
42 | ```js next.config.js
43 | const withMDX = require("@next/mdx")({
44 | extension: /\.mdx?$/,
45 | options: {
46 | remarkPlugins: [],
47 | },
48 | })
49 |
50 | module.exports = withMDX({
51 | pageExtensions: [
52 | "ts", "tsx", "js",
53 | "jsx", "md", "mdx"
54 | ],
55 | })
56 | ```
57 |
58 | ---
59 |
60 | To set up Code Hike you need to import the _`@code-hike/mdx`_ plugin, and add it to the _`remarkPlugins`_ array in the `next.config.js` file.
61 |
62 | Next to the plugin you can pass [a config object](focus://10[24:32]). Almost always you'll want to pass a `theme` there. For more information about themes, see the [themes docs](/docs/themes).
63 |
64 | You can also pass more options, like `lineNumbers` for example. See the [configuration docs](/docs/configuration) for more information.
65 |
66 | {/* prettier-ignore */}
67 | ```js next.config.js focus=1:3,8:10
68 | const {
69 | remarkCodeHike,
70 | } = require("@code-hike/mdx")
71 |
72 | const withMDX = require("@next/mdx")({
73 | extension: /\.mdx?$/,
74 | options: {
75 | remarkPlugins: [
76 | [remarkCodeHike, { theme: "nord" }]
77 | ],
78 | },
79 | })
80 |
81 | module.exports = withMDX({
82 | pageExtensions: [
83 | "ts", "tsx", "js",
84 | "jsx", "md", "mdx"
85 | ],
86 | })
87 | ```
88 |
89 | ---
90 |
91 | Then you need to create a `pages/_app.js` file if you don't have one.
92 |
93 | The _`MyApp`_ component is where you put global stuff that applies to all pages.
94 |
95 | You can find more information about the `_app.js` file in the [Next.js official docs](https://nextjs.org/docs/advanced-features/custom-app).
96 |
97 | {/* prettier-ignore */}
98 | ```js pages/_app.js
99 | function MyApp({ Component, pageProps }) {
100 | return
101 | }
102 |
103 | export default MyApp
104 | ```
105 |
106 | ---
107 |
108 | We use `pages/_app.js` file to import Code Hike's stylesheet.
109 |
110 | If you want to customize Code Hike's styles with a global stylesheet make sure to import it after this import to avoid specificity issues.
111 |
112 | You can learn more about customizing Code Hike styles in the [styling docs](/docs/styling).
113 |
114 | {/* prettier-ignore */}
115 | ```js pages/_app.js focus=1
116 | import "@code-hike/mdx/dist/index.css"
117 |
118 | function MyApp({ Component, pageProps }) {
119 | return
120 | }
121 |
122 | export default MyApp
123 | ```
124 |
125 | ---
126 |
127 | And now you should be able to use Code Hike inside your mdx files.
128 |
129 | For example, create an `index.mdx` file in your `pages` directory, and run Next with `npx next`.
130 |
131 | If you open _`localhost:3000`_ on your browser you should see Code Hike's syntax highlighting.
132 |
133 | Markdown (.md) files should also work.
134 |
135 | {/* prettier-ignore */}
136 | ~~~md pages/index.mdx
137 | # Hello
138 |
139 | Lorem ipsum dolor sit amet.
140 |
141 | ```python hello.py
142 | print("Rendered with Code Hike")
143 | ```
144 |
145 | Lorem ipsum dolor sit amet.
146 | ~~~
147 |
148 |
149 |
150 |
151 |
152 | A demo of Code Hike + NextJS is available on [GitHub](https://github.com/code-hike/codehike/tree/main/examples/nextjs). You can also try it out from your browser on [StackBlitz](https://stackblitz.com/github/code-hike/codehike/tree/main/examples/nextjs?file=pages%2Findex.mdx).
153 |
154 |
155 |
--------------------------------------------------------------------------------
/docs/installation-nextra.mdx:
--------------------------------------------------------------------------------
1 | ## Nextra + Code Hike
2 |
3 | See this [example](https://github.com/code-hike/codehike/tree/next/examples/nextra). Guide coming soon.
4 |
--------------------------------------------------------------------------------
/docs/installation-parcel.mdx:
--------------------------------------------------------------------------------
1 | See this [pull request](https://github.com/code-hike/examples/pull/3).
2 |
--------------------------------------------------------------------------------
/docs/installation-remix.mdx:
--------------------------------------------------------------------------------
1 | ## Remix + Code Hike
2 |
3 | See this [example](https://github.com/code-hike/codehike/tree/next/examples/remix). Guide coming soon.
4 |
--------------------------------------------------------------------------------
/docs/installation-vite.mdx:
--------------------------------------------------------------------------------
1 | ## Vite + Code Hike
2 |
3 | See this [example](https://github.com/code-hike/codehike/tree/next/examples/vite). Guide coming soon.
4 |
--------------------------------------------------------------------------------
/docs/installation.mdx:
--------------------------------------------------------------------------------
1 | Code Hike is a remark plugin for [MDX v2](https://mdxjs.com/). The specific set up will depend on [your stack](#frameworks), it usually involves five steps:
2 |
3 |
4 |
5 | **1.** Set up MDX v2
6 |
7 | See the [MDX v2 documentation](https://mdxjs.com/docs/getting-started/).
8 |
9 |
10 |
11 |
12 | **2.** Install the Code Hike plugin
13 |
14 |
15 |
16 | ```bash
17 | npm install @code-hike/mdx
18 | ```
19 |
20 |
21 |
22 | or
23 |
24 |
25 |
26 | ```bash
27 | yarn add @code-hike/mdx
28 | ```
29 |
30 |
31 |
32 |
33 |
34 |
35 | **3.** Include Code Hike's CSS
36 |
37 | Depending on your stack, it could be:
38 |
39 |
40 |
41 | ```js your.js
42 | import "@code-hike/mdx/dist/index.css"
43 | ```
44 |
45 |
46 |
47 |
48 |
49 |
50 | **4.** Add the remark plugin to your MDX configuration
51 |
52 | Also depends on your stack. Find the right place to pass `remarkPlugins`.
53 |
54 | {/* prettier-ignore */}
55 | ```js your.config.js focus=2,5,6,9
56 | const remarkSomething = require("remark-something");
57 | const { remarkCodeHike } = require("@code-hike/mdx");
58 |
59 | mdxOptions = {
60 | remarkPlugins: [
61 | [remarkCodeHike, { theme: "github-dark", lineNumbers: false }],
62 | remarkSomething,
63 | remarkSomethingElse,
64 | ],
65 | };
66 | ```
67 |
68 |
69 |
70 |
71 | **5.** Copy and try one of the [demos](https://codehike.org/#demos) to test the set up.
72 |
73 | For example:
74 |
75 | {/* prettier-ignore */}
76 | ````mdx your.mdx
77 | # Hello, world!
78 |
79 |
80 |
81 | ```js app.js focus=2:4
82 | function lorem(ipsum, dolor = 1) {
83 | const sit = ipsum == null ? 0 : ipsum.sit;
84 | dolor = sit - amet(dolor);
85 | return sit ? consectetur(ipsum) : [];
86 | }
87 | ```
88 |
89 | ```python hello.py
90 | print("Hello, world!")
91 | ```
92 |
93 | ---
94 |
95 | ```css styles.css
96 | .lorem {
97 | color: #fff;
98 | padding: 10px;
99 | background: #000;
100 | }
101 | ```
102 |
103 |
104 | ````
105 |
106 |
107 |
108 | ## Frameworks
109 |
110 | Installation guides for specific frameworks. Pick one:
111 |
--------------------------------------------------------------------------------
/docs/introduction.mdx:
--------------------------------------------------------------------------------
1 | Code Hike is a remark plugin for MDX. It will help you display code on your websites.
2 |
3 | - Display code blocks, using **VS Code themes** for syntax highlighting and support for [ programming languages](codeblocks#languages).
4 | - Use Code Hike **components and annotations** to enhance the **code-reading experience** and embrace the web as the interactive medium it is.
5 | - Good-looking **default styles**. Customizable using CSS.
6 | - And always keeping the MDX syntax as close to markdown as possible for a better **authoring experience**.
7 |
8 | ## Limitations
9 |
10 | - It only works with MDX v2.
11 | - Even when you can use MDX with frameworks like Vue or Svelte, Code Hike can only be used with React.
12 | - Code Hike components are meant to be used from MDX files. It's a bad idea to import them directly from React code.
13 |
--------------------------------------------------------------------------------
/docs/preview/ch-code-1.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python one.py
4 | print("Hello, one!")
5 | ```
6 |
7 | ```python two.py
8 | print("Hello, two!")
9 | ```
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/preview/ch-code-2.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python one.py
4 | print("Hello, one!")
5 | ```
6 |
7 | ---
8 |
9 | ```python two.py
10 | print("Hello, two!")
11 | ```
12 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/preview/ch-code-3.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python one.py
4 | print("Hello, world!")
5 | print("Hello, world!")
6 | print("Hello, world!")
7 | ```
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/preview/ch-code-4.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python one.py
4 | print("Hello, world!")
5 | print("Hello, world!")
6 | print("Hello, world!")
7 | ```
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/preview/ch-code-5.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python one.py focus=2
4 | print("Hello, world 1!")
5 | print("Hello, world 2!")
6 | print("Hello, world 3!")
7 | print("Hello, world 4!")
8 | print("Hello, world 5!")
9 | ```
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/preview/ch-code-6.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python one.py focus=2:3
4 | print("Hello, world 1!")
5 | print("Hello, world 2!")
6 | print("Hello, world 3!")
7 | print("Hello, world 4!")
8 | print("Hello, world 5!")
9 | ```
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/preview/ch-section-1.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python
4 | def lorem(ipsum):
5 | ipsum + 1
6 | ```
7 |
8 | Something _`def lorem(ipsum)`_
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/preview/ch-section-2.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ```python
4 | def lorem(ipsum):
5 | ipsum + 1
6 | ```
7 |
8 | Hello, [hover me](focus://1[5:16])
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/preview/ch-section-3.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | [lorem js](focus://two.js#1[10:21])
4 | [lorem py](focus://one.py#1[5:16])
5 |
6 |
7 |
8 | ```python one.py
9 | def lorem(ipsum):
10 | ipsum + 1
11 | ```
12 |
13 | ```js two.js
14 | function lorem(ipsum) {
15 | return ipsum + 1
16 | }
17 | ```
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/preview/codeblocks-1.mdx:
--------------------------------------------------------------------------------
1 | ### Lorem ipsum
2 |
3 | ```python
4 | print("Hello, world!")
5 | ```
6 |
7 | dolor **sit** amet
8 |
--------------------------------------------------------------------------------
/docs/preview/codeblocks-2.mdx:
--------------------------------------------------------------------------------
1 | ### Lorem ipsum
2 |
3 | ```python hello.py
4 | print("Hello, world!")
5 | ```
6 |
7 | dolor **sit** amet
8 |
--------------------------------------------------------------------------------
/docs/preview/installation-1.mdx:
--------------------------------------------------------------------------------
1 | ### Lorem ipsum
2 |
3 | ```python hello.py
4 | # mark[16:24]
5 | print("This is Code Hike")
6 | ```
7 |
8 | Lorem ipsum dolor sit amet.
9 |
--------------------------------------------------------------------------------
/docs/preview/mark-1.mdx:
--------------------------------------------------------------------------------
1 | ```py
2 | print("This is line 1")
3 | # mark
4 | print("This is line 2")
5 | print("This is line 3")
6 | ```
7 |
--------------------------------------------------------------------------------
/docs/preview/mark-2.mdx:
--------------------------------------------------------------------------------
1 | ```py
2 | # mark[7:11]
3 | class Lorem:
4 | def dolor(self):
5 | # mark[5:10]
6 | return "sit"
7 | ```
8 |
--------------------------------------------------------------------------------
/docs/preview/mark-3.mdx:
--------------------------------------------------------------------------------
1 | ```py
2 | # mark[16:24] my-colors
3 | print("This is Code Hike")
4 | ```
5 |
--------------------------------------------------------------------------------
/docs/preview/with-class.mdx:
--------------------------------------------------------------------------------
1 | ```py
2 | # withClass[7:16] my-class
3 | print("hover me")
4 | ```
5 |
--------------------------------------------------------------------------------
/docs/styling.mdx:
--------------------------------------------------------------------------------
1 | Styling docs are coming soon.
2 |
3 | In the meantime, here are two examples of styling Code Hike components to look very different:
4 |
5 |
6 |
7 | [](https://not-stripe.vercel.app/)
8 |
9 |
21 | Everyone can see all the demos, but only sponsors can see the code for
22 | demos marked with .
23 | Locked demos are unlocked for everyone after being sponsored by five
24 | sponsors.
25 |