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');