diff --git a/README.md b/README.md index afbab0b..ebeb9d0 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,35 @@ [![NPM version](https://img.shields.io/npm/v/@diplodoc/file-extension.svg?style=flat)](https://www.npmjs.org/package/@diplodoc/file-extension) +```md +{% file src="path/to/file" name='readme.md' %} + +==> + +readme.md +``` + +## Attributes + +| Name | Required | Description | +| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `src` | yes | URL of the file. Will be mapped to [`href` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-href) | +| `name` | yes | Name of the file. Will be mapped to [`download` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download) | +| `lang` | - | Language of the file content. Will be mapped to [`hreflang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-hreflang) | +| `referrerpolicy` | - | [`referrerpolicy` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-referrerpolicy) | +| `rel` | - | [`rel` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-rel) | +| `target` | - | [`target` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-target) | +| `type` | - | [`type` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-type) | + +> _Note: other attributes will be ignored_ + +## Options + +| Name | Type | Description | +| ---------------- | -------------------- | ------------------------------------------------ | +| `fileExtraAttrs` | `[string, string][]` | Adds additional attributes to rendered hyperlink | + +## CSS public variables + +- `--yfm-file-icon` – sets custom file icon image +- `--yfm-file-icon-color` – sets custom file icon color diff --git a/esbuild/build.mjs b/esbuild/build.mjs index 2c71148..670d5d9 100755 --- a/esbuild/build.mjs +++ b/esbuild/build.mjs @@ -1,6 +1,7 @@ #!/usr/bin/env node import {build} from 'esbuild'; +import {sassPlugin} from 'esbuild-sass-plugin'; import tsConfig from '../tsconfig.json' assert {type: 'json'}; @@ -14,9 +15,34 @@ const common = { tsconfig: './tsconfig.publish.json', }; -build({ +/** @type {import('esbuild').BuildOptions}*/ +const plugin = { ...common, - entryPoints: ['src/index.ts'], - outfile: outDir + '/index.js', + entryPoints: ['src/plugin/index.ts'], + outfile: outDir + '/plugin/index.js', + platform: 'node', packages: 'external', -}); +}; + +/** @type {import('esbuild').BuildOptions}*/ +const pluginNode = { + ...common, + entryPoints: ['src/plugin/index-node.ts'], + outfile: outDir + '/plugin/index-node.js', + platform: 'node', + packages: 'external', +}; + +/** @type {import('esbuild').BuildOptions}*/ +const runtime = { + ...common, + entryPoints: ['src/runtime/index.ts'], + outfile: outDir + '/runtime/index.js', + minify: true, + platform: 'browser', + plugins: [sassPlugin()], +}; + +build(plugin); +build(pluginNode); +build(runtime); diff --git a/package-lock.json b/package-lock.json index c33e76d..c80afe0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,15 @@ "devDependencies": { "@diplodoc/lint": "^1.2.0", "@diplodoc/tsconfig": "^1.0.2", + "@types/markdown-it": "^13.0.9", + "@types/node": "^18.19.64", "esbuild": "^0.24.0", + "esbuild-sass-plugin": "^3.3.1", "npm-run-all": "^4.1.5", "typescript": "^5.6.3" + }, + "peerDependencies": { + "markdown-it": "^13.0.0" } }, "node_modules/@ampproject/remapping": { @@ -398,6 +404,13 @@ "node": ">=6.9.0" } }, + "node_modules/@bufbuild/protobuf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.2.tgz", + "integrity": "sha512-UNtPCbrwrenpmrXuRwn9jYpPoweNXj8X5sMvYgsqYyaH8jQ6LfUJSk3dJLnBK+6sfYPrF4iAIo5sd5HQ+tg75A==", + "dev": true, + "peer": true + }, "node_modules/@csstools/css-parser-algorithms": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz", @@ -1253,6 +1266,302 @@ "node": ">=12.4.0" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -1292,12 +1601,43 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.9.tgz", + "integrity": "sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==", + "dev": true, + "dependencies": { + "@types/linkify-it": "^3", + "@types/mdurl": "^1" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "dev": true + }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, + "node_modules/@types/node": { + "version": "18.19.64", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -1633,8 +1973,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { "version": "5.3.2", @@ -1926,6 +2265,13 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-builder": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", + "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", + "dev": true, + "peer": true + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2020,6 +2366,21 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -2081,6 +2442,13 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "dev": true, + "peer": true + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -2397,6 +2765,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2732,12 +3113,27 @@ "@esbuild/win32-x64": "0.24.0" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/esbuild-sass-plugin": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-3.3.1.tgz", + "integrity": "sha512-SnO1ls+d52n6j8gRRpjexXI8MsHEaumS0IdDHaYM29Y6gakzZYMls6i9ql9+AWMSQk/eryndmUpXEgT34QrX1A==", "dev": true, - "engines": { + "dependencies": { + "resolve": "^1.22.8", + "safe-identifier": "^0.4.2", + "sass": "^1.71.1" + }, + "peerDependencies": { + "esbuild": ">=0.20.1", + "sass-embedded": "^1.71.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { "node": ">=6" } }, @@ -3978,6 +4374,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz", + "integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4667,6 +5069,15 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "peer": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, "node_modules/lint-staged": { "version": "15.2.10", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz", @@ -4900,6 +5311,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-it": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", + "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==", + "peer": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", @@ -4916,6 +5355,12 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "peer": true + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -5086,6 +5531,13 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -5949,6 +6401,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/redent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", @@ -6143,6 +6608,16 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", @@ -6161,6 +6636,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "dev": true + }, "node_modules/safe-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", @@ -6187,6 +6668,427 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sass": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.7.tgz", + "integrity": "sha512-MVWvN0u5meytrSjsU7AWsbhoXi1sc58zADXFllfZzbsBT1GHjjar6JwBINYPRrkx/zqnQ6uqbQuHgE95O+C+eQ==", + "dev": true, + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-embedded": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.80.7.tgz", + "integrity": "sha512-OwF0QvpDUjW2udPCvxgaObU0tQHycpsIgCDtHBVHuOqZ2LN0OkkY+uxSO7bOaw9wD7vXtt+1V+jiIZDTxiSRVQ==", + "dev": true, + "peer": true, + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "buffer-builder": "^0.2.0", + "colorjs.io": "^0.5.0", + "immutable": "^5.0.2", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-android-arm": "1.80.7", + "sass-embedded-android-arm64": "1.80.7", + "sass-embedded-android-ia32": "1.80.7", + "sass-embedded-android-riscv64": "1.80.7", + "sass-embedded-android-x64": "1.80.7", + "sass-embedded-darwin-arm64": "1.80.7", + "sass-embedded-darwin-x64": "1.80.7", + "sass-embedded-linux-arm": "1.80.7", + "sass-embedded-linux-arm64": "1.80.7", + "sass-embedded-linux-ia32": "1.80.7", + "sass-embedded-linux-musl-arm": "1.80.7", + "sass-embedded-linux-musl-arm64": "1.80.7", + "sass-embedded-linux-musl-ia32": "1.80.7", + "sass-embedded-linux-musl-riscv64": "1.80.7", + "sass-embedded-linux-musl-x64": "1.80.7", + "sass-embedded-linux-riscv64": "1.80.7", + "sass-embedded-linux-x64": "1.80.7", + "sass-embedded-win32-arm64": "1.80.7", + "sass-embedded-win32-ia32": "1.80.7", + "sass-embedded-win32-x64": "1.80.7" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.80.7.tgz", + "integrity": "sha512-pMxJ70yOGXYGmfoGlAMKqnr/nuP/UgKV3jc7v5kpmWGpPPMF2u63DM2QkvTqM32FyfwyxSycVaNFNT+gPomTiw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.80.7.tgz", + "integrity": "sha512-Gwl/OY80uEA14MLm7efJvc1ErgGT51SvAv4/kIpTziOJpkk+999/nrEJHQ6YAJ7r5DuQcKvC3lHipcENUIpP9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-ia32": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.80.7.tgz", + "integrity": "sha512-CJccGPgBePPYiXhyQWvgHF8AqjIDSGf+mcC4Ac/f5upRd9Z/vhQVrJfsDxt4c4tV0HGEfbQpT9xOCYF1Z6luZQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.80.7.tgz", + "integrity": "sha512-kIGcyuhNes9NUDzJ9VHy/ZGKdADCCt7JAwiC7lFSc6/xs5rJtGRn6hZ+mcG7gQWAezb5oK/VMQl8ps7HBFUEXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.80.7.tgz", + "integrity": "sha512-oLMQiFpbSczOrGZSWlZvVJ1T9L6nDjS2u8PTxfT0MFX/FT3EhaxylHeiYKrmtY4epRufNCC/G96DMVqnSNa1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.80.7.tgz", + "integrity": "sha512-Vi5BbTWd9OO0tC60CPw5IY7w3Tccr1/Gy2DdkfE4qP6Rc368WmUis5ceG8ehAye0IT7aoRXpw8XTzWyXAZHbfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.80.7.tgz", + "integrity": "sha512-yeANclgSHJ7K/XLG4Lnk7aQ5dk7K+oqIOtoOP0bjXgWsdPbes9V7k1ZJ9mZGl+f/XAPaRRPqjKs4WHU9s8m8MA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.80.7.tgz", + "integrity": "sha512-ZttC6H2Z9YXUVFlprqZ0AgXuHdzqhvhUWsG7UUqkND9JSHvyFSwRij4h90aOK3gKg3PBGI4yG5tonLq2yV525A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.80.7.tgz", + "integrity": "sha512-Idb5K9LHHWklN7A/kqWUd6sktA36V70bSjZ/gvCDu/5CBJBkMsVNdrxcdpGzrZe7pYV4XUTkMZOwf91owEywtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-ia32": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.80.7.tgz", + "integrity": "sha512-xKnWWEFz1jFc9xDAG7nMcjPBCTuiJbqvTmEtwQoWj79hQrzVdkLM6SiUGVbGa1c2s2fJMS3Bg2fkDJBK6/BcuQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.80.7.tgz", + "integrity": "sha512-gJLfSFiiuGaqWjaj0bcuhOlQ+t1jS9StuzXnW1b9gy2I6Y0uCprgbbELgtRVPSZlCG2BBolR76YCGQTB85M43Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.80.7.tgz", + "integrity": "sha512-7+GCYIh+c1BG4ot/PbTvVXUxd2GxDWcMxV7i3sARStQBDpTZFfohWdjUytLyqGxQgJIrbq0Q60Ucrw6HUJtJ9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-ia32": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.80.7.tgz", + "integrity": "sha512-Iw2E6P1lha335C5tGNgPjLD7Oll7OdLBJ7uPKaU+I7KbiOPk7ELsxUL9AYIrKO0/MLtgxGqOWWfTo/5cvU8xSA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.80.7.tgz", + "integrity": "sha512-gd92dkDVpTh4xJb2hpX82E6el30h4MxCb7VJLwtbQSrQuxOlZgaDX4plMSZifsNTLvOsafdLCYyI+QsZRr8bkA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.80.7.tgz", + "integrity": "sha512-i5udU+i0LZrL3dhHAgIfK7LBaHtScwAceiykndNIHyRXc1TY2DX3lG0EolVUvPyWFUNnvGCgxZF8oUToPzJ+pw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.80.7.tgz", + "integrity": "sha512-DvnXvu019c6THNQnSWfy2eY/HFWZ2ogGUjRkdKAxj7U7i/YD+bsDIxdDQHZ48qzOguzx8n2aRa/clriM0HQPUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.80.7.tgz", + "integrity": "sha512-nQB+IZwCzVPpPkP5L9zV416/AGPLky7L2GGPWtvxG2CEeTV1Rzet+gkhzk2eYEdbh+3py/w9YVRTaQuZ3QV0vQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.80.7.tgz", + "integrity": "sha512-Q6Rh/CM30m8txoKK5SIVamnwPXs028Mvfq4Ol4saHgSYro9kY/HTrrWlG/RPd6sPvYBCYIm1mX8oBteDUMCajQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-ia32": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.80.7.tgz", + "integrity": "sha512-VZMRp81KWUZZDqNwkL3yTDT+VRxB7ScJKUJD1M8fq6P1nyJP35+r1byXLF4UQMoNgpC5B16txxMvqdkv43OqAA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.80.7.tgz", + "integrity": "sha512-4p+GzOJJ1KqxPKrkIkKisod4YAcC70fj4WMRLrQLLuUW+MzAvtKgX2+ZJf90D50CozSdgETGBvdPSj3VLjBzZw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -6847,6 +7749,29 @@ "node": ">= 10" } }, + "node_modules/sync-child-process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", + "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "dev": true, + "peer": true, + "dependencies": { + "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/sync-message-port": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz", + "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/synckit": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", @@ -7138,6 +8063,12 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "peer": true + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -7153,6 +8084,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -7208,6 +8145,13 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "dev": true, + "peer": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index e5a48bd..f89eeae 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,22 @@ "name": "@diplodoc/file-extension", "version": "0.0.0", "description": "Template package for Diplodoc platform development", - "main": "build/index.js", - "types": "build/index.d.ts", + "main": "build/plugin/index.js", + "types": "build/plugin/index.d.ts", + "exports": { + ".": { + "types": "./build/plugin/index.d.ts", + "node": "./build/plugin/index-node.js", + "default": "./build/plugin/index.js" + }, + "./runtime": { + "types": "./build/runtime/index.d.ts", + "style": "./build/runtime/index.css", + "default": "./build/runtime/index.js" + }, + "./runtime/styles": "./build/runtime/index.css", + "./runtime/styles.css": "./build/runtime/index.css" + }, "homepage": "https://diplodoc.com/", "repository": { "type": "git", @@ -28,8 +42,14 @@ "devDependencies": { "@diplodoc/lint": "^1.2.0", "@diplodoc/tsconfig": "^1.0.2", + "@types/markdown-it": "^13.0.9", + "@types/node": "^18.19.64", "esbuild": "^0.24.0", + "esbuild-sass-plugin": "^3.3.1", "npm-run-all": "^4.1.5", "typescript": "^5.6.3" + }, + "peerDependencies": { + "markdown-it": "^13.0.0" } } diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 59ad34f..0000000 --- a/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export const test = 'test'; diff --git a/src/plugin/const.ts b/src/plugin/const.ts new file mode 100644 index 0000000..e7f4a43 --- /dev/null +++ b/src/plugin/const.ts @@ -0,0 +1,48 @@ +export enum FileSpecialAttr { + Src = 'src', + Name = 'name', + Lang = 'lang', +} + +// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes +export enum LinkHtmlAttr { + Download = 'download', + Href = 'href', + HrefLang = 'hreflang', + Media = 'media', + Ping = 'ping', + ReferrerPolicy = 'referrerpolicy', + Rel = 'rel', + Target = 'target', + Type = 'type', +} + +export const FILE_TO_LINK_ATTRS_MAP: Record = { + [FileSpecialAttr.Src]: LinkHtmlAttr.Href, + [FileSpecialAttr.Name]: LinkHtmlAttr.Download, + [FileSpecialAttr.Lang]: LinkHtmlAttr.HrefLang, +}; + +export const RULE_NAME = 'yfm_file_inline'; +export const KNOWN_ATTRS: readonly string[] = [ + FileSpecialAttr.Src, + FileSpecialAttr.Name, + FileSpecialAttr.Lang, + LinkHtmlAttr.ReferrerPolicy, + LinkHtmlAttr.Rel, + LinkHtmlAttr.Target, + LinkHtmlAttr.Type, +]; +export const REQUIRED_ATTRS: readonly string[] = [FileSpecialAttr.Src, FileSpecialAttr.Name]; + +export const FILE_TOKEN = 'yfm_file'; + +export const PREFIX = '{% file '; +export const PREFIX_LENGTH = PREFIX.length; + +export enum FileClassName { + Link = 'yfm-file', + Icon = 'yfm-file__icon', +} + +export const ENV_FLAG_NAME = 'has-yfm-file'; diff --git a/src/plugin/index-node.ts b/src/plugin/index-node.ts new file mode 100644 index 0000000..bc190da --- /dev/null +++ b/src/plugin/index-node.ts @@ -0,0 +1,35 @@ +import {type RuntimeObj, type TransformOptions, transform as baseTransform} from './transform'; + +export * from './index'; + +const onBundle: TransformOptions['onBundle'] = (env, output, runtime) => { + copyRuntime({runtime, output}, env.bundled); +}; + +export const transform: typeof baseTransform = (opts) => { + return baseTransform({onBundle, ...opts}); +}; + +function copyRuntime({runtime, output}: {runtime: RuntimeObj; output: string}, cache: Set) { + const PATH_TO_RUNTIME = '../runtime'; + const {join, resolve} = require('node:path'); + const runtimeFiles = { + // 'index.js': runtime.script, + 'index.css': runtime.style, + }; + for (const [originFile, outputFile] of Object.entries(runtimeFiles)) { + const file = join(PATH_TO_RUNTIME, originFile); + if (!cache.has(file)) { + cache.add(file); + copy(resolve(__dirname, file), join(output, outputFile)); + } + } +} + +export function copy(from: string, to: string) { + const {mkdirSync, copyFileSync} = require('node:fs'); + const {dirname} = require('node:path'); + + mkdirSync(dirname(to), {recursive: true}); + copyFileSync(from, to); +} diff --git a/src/plugin/index.ts b/src/plugin/index.ts new file mode 100644 index 0000000..5e1ebdb --- /dev/null +++ b/src/plugin/index.ts @@ -0,0 +1,10 @@ +export type {PluginOptions, TransformOptions} from './transform'; +export {transform} from './transform'; +export { + FILE_TOKEN, + FILE_TO_LINK_ATTRS_MAP, + FileSpecialAttr, + FileClassName, + KNOWN_ATTRS as FILE_KNOWN_ATTRS, + REQUIRED_ATTRS as FILE_REQUIRED_ATTRS, +} from './const'; diff --git a/src/plugin/plugin.ts b/src/plugin/plugin.ts new file mode 100644 index 0000000..5fc30a4 --- /dev/null +++ b/src/plugin/plugin.ts @@ -0,0 +1,91 @@ +import type MarkdownIt from 'markdown-it'; + +import { + ENV_FLAG_NAME, + FILE_TOKEN, + FILE_TO_LINK_ATTRS_MAP, + FileClassName, + FileSpecialAttr, + KNOWN_ATTRS, + PREFIX, + PREFIX_LENGTH, + REQUIRED_ATTRS, + RULE_NAME, +} from './const'; + +export type FileOptions = { + fileExtraAttrs?: [string, string][]; +}; + +export const filePlugin: MarkdownIt.PluginWithOptions = (md, opts) => { + md.inline.ruler.push(RULE_NAME, (state, silent) => { + if (state.src.substring(state.pos, state.pos + PREFIX_LENGTH) !== PREFIX) { + return false; + } + + // the rest of line after '{% file ' + const searchStr = state.src.slice(state.pos + PREFIX_LENGTH, state.posMax); + // loking for pattern 'src="..." name="..." etc="value" %}' + const matchResult = searchStr.match(/^((?:\s*\w+=(?:"[^"]+"|'[^']+')\s)+)\s*%}/); + if (!matchResult) { + return false; + } + + const paramsGroupLength = matchResult[0].length; // '(src="..." name="...")'.length + const paramsStr = matchResult[1]; // 'src="..." name="..."' + + // find pairs of key="foo" or key='bar' + const params = paramsStr.match(/\w+=(?:"[^"]+"|'[^']+')/g); + if (!params) { + return false; + } + + const attrsObj: Record = {}; + params.forEach((param) => { + const indexKey = param.indexOf('='); + const key = param.slice(0, indexKey); + const value = param.slice(indexKey + 2, -1); + if (KNOWN_ATTRS.includes(key) && value) { + attrsObj[key] = value; + } + }); + + const hasAllRequiredAttrs = REQUIRED_ATTRS.every((attr) => attr in attrsObj); + if (!hasAllRequiredAttrs) { + return false; + } + + if (!silent) { + const token = state.push(FILE_TOKEN, '', 0); + token.block = false; + token.markup = PREFIX; + token.content = attrsObj[FileSpecialAttr.Name]; + token.attrs = Object.entries(attrsObj); + token.attrSet('class', FileClassName.Link); + + for (const attr of token.attrs) { + if (attr[0] in FILE_TO_LINK_ATTRS_MAP) { + attr[0] = FILE_TO_LINK_ATTRS_MAP[attr[0] as FileSpecialAttr]; + } + } + + if (Array.isArray(opts?.fileExtraAttrs)) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + token.attrs.push(...opts!.fileExtraAttrs); + } + } + + state.pos = state.pos + PREFIX_LENGTH + paramsGroupLength; + + state.env ??= {}; + state.env[ENV_FLAG_NAME] = true; + + return true; + }); + + md.renderer.rules[FILE_TOKEN] = (tokens, idx, _opts, _env, self) => { + const token = tokens[idx]; + const iconHtml = ``; + return `${iconHtml}${md.utils.escapeHtml(token.content)}`; + }; +}; diff --git a/src/plugin/transform.ts b/src/plugin/transform.ts new file mode 100644 index 0000000..2aca47e --- /dev/null +++ b/src/plugin/transform.ts @@ -0,0 +1,97 @@ +import MarkdownIt from 'markdown-it'; + +import {type FileOptions, filePlugin} from './plugin'; +import {ENV_FLAG_NAME} from './const'; +import {hidden} from './utils'; + +export type PluginOptions = { + output?: string; +}; + +export type RuntimeObj = {style: string}; + +export type TransformOptions = { + /** @default '' */ + runtime?: string | {style: string}; + bundle?: boolean; + extraAttrs?: FileOptions['fileExtraAttrs']; + onBundle?: (env: {bundled: Set}, output: string, runtime: RuntimeObj) => void; +}; + +const registerTransform = ( + md: MarkdownIt, + { + extraAttrs, + bundle, + onBundle, + runtime, + output, + }: Pick & { + bundle: boolean; + runtime: {style: string}; + output: string; + }, +) => { + filePlugin(md, {fileExtraAttrs: extraAttrs}); + + md.core.ruler.push('yfm_file_after', ({env}) => { + if (env?.[ENV_FLAG_NAME]) { + env.meta ||= {}; + env.meta.style ||= []; + env.meta.style.push(runtime.style); + + if (bundle && onBundle) { + hidden(env, 'bundled', new Set()); + onBundle(env, output, runtime); + } + } + }); +}; + +export const transform = (opts: TransformOptions = {}) => { + const {bundle = true} = opts; + + if (bundle && typeof opts.runtime === 'string') { + throw new TypeError('Option `runtime` should be record when `bundle` is enabled.'); + } + + const runtime: RuntimeObj = + typeof opts?.runtime === 'object' + ? opts.runtime + : {style: opts?.runtime ?? '_assets/file-extension.css'}; + + const plugin: MarkdownIt.PluginWithOptions = ( + md, + {output = '.', fileExtraAttrs} = {}, + ) => { + registerTransform(md, { + bundle, + runtime, + output, + onBundle: opts.onBundle, + extraAttrs: fileExtraAttrs ?? opts.extraAttrs, + }); + }; + + Object.assign(plugin, { + collect(input: string, {destRoot = '.'}: InputOptions) { + const md = new MarkdownIt().use((md: MarkdownIt) => { + registerTransform(md, { + bundle, + runtime, + output: destRoot, + onBundle: opts.onBundle, + extraAttrs: opts.extraAttrs, + }); + }); + + md.parse(input, {}); + }, + }); + + return plugin; +}; + +type InputOptions = { + destRoot: string; +}; diff --git a/src/plugin/utils.ts b/src/plugin/utils.ts new file mode 100644 index 0000000..a197fc1 --- /dev/null +++ b/src/plugin/utils.ts @@ -0,0 +1,14 @@ +export function hidden, F extends string | symbol, V>( + box: B, + field: F, + value: V, +) { + if (!(field in box)) { + Object.defineProperty(box, field, { + enumerable: false, + value: value, + }); + } + + return box as B & {[P in F]: V}; +} diff --git a/src/runtime/index.ts b/src/runtime/index.ts new file mode 100644 index 0000000..a00fab8 --- /dev/null +++ b/src/runtime/index.ts @@ -0,0 +1 @@ +import './styles/file.scss'; diff --git a/src/runtime/styles/file.scss b/src/runtime/styles/file.scss new file mode 100644 index 0000000..5233993 --- /dev/null +++ b/src/runtime/styles/file.scss @@ -0,0 +1,33 @@ +$defaultIcon: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzODQgNTEyIj48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik0zNjkuOSA5Ny45TDI4NiAxNEMyNzcgNSAyNjQuOC0uMSAyNTIuMS0uMUg0OEMyMS41IDAgMCAyMS41IDAgNDh2NDE2YzAgMjYuNSAyMS41IDQ4IDQ4IDQ4aDI4OGMyNi41IDAgNDgtMjEuNSA0OC00OFYxMzEuOWMwLTEyLjctNS4xLTI1LTE0LjEtMzR6bS0yMi42IDIyLjdjMi4xIDIuMSAzLjUgNC42IDQuMiA3LjRIMjU2VjMyLjVjMi44LjcgNS4zIDIuMSA3LjQgNC4ybDgzLjkgODMuOXpNMzM2IDQ4MEg0OGMtOC44IDAtMTYtNy4yLTE2LTE2VjQ4YzAtOC44IDcuMi0xNiAxNi0xNmgxNzZ2MTA0YzAgMTMuMyAxMC43IDI0IDI0IDI0aDEwNHYzMDRjMCA4LjgtNy4yIDE2LTE2IDE2em0tNDgtMjQ0djhjMCA2LjYtNS40IDEyLTEyIDEySDEwOGMtNi42IDAtMTItNS40LTEyLTEydi04YzAtNi42IDUuNC0xMiAxMi0xMmgxNjhjNi42IDAgMTIgNS40IDEyIDEyem0wIDY0djhjMCA2LjYtNS40IDEyLTEyIDEySDEwOGMtNi42IDAtMTItNS40LTEyLTEydi04YzAtNi42IDUuNC0xMiAxMi0xMmgxNjhjNi42IDAgMTIgNS40IDEyIDEyem0wIDY0djhjMCA2LjYtNS40IDEyLTEyIDEySDEwOGMtNi42IDAtMTItNS40LTEyLTEydi04YzAtNi42IDUuNC0xMiAxMi0xMmgxNjhjNi42IDAgMTIgNS40IDEyIDEyeiIvPjwvc3ZnPg=='); + +/** + Public CSS variables: + --yfm-file-icon sets file icon image + --yfm-file-icon-color sets file icon color +*/ + +.yfm-file { + &__icon { + ---yfm-file-icon-img: var(--yfm-file-icon, #{$defaultIcon}); + + display: inline-block; + user-select: none; + + width: 16px; + margin: 0 2px; + + color: var(--yfm-file-icon-color, --yfm-color-text); + background-color: currentColor; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100%; + + mask-image: var(---yfm-file-icon-img); + mask-position: center; + mask-repeat: no-repeat; + + &::before { + content: '\a0'; + } + } +} diff --git a/tests/src/index.test.ts b/tests/src/index.test.ts index 234ee46..8b6602b 100644 --- a/tests/src/index.test.ts +++ b/tests/src/index.test.ts @@ -1,5 +1,3 @@ -import {test} from '../../src'; - describe('test', () => { it('should be test', () => { expect(test).toBe('test');