finish path refactoring, add sourcemap + better trace support
1 files deleted
1 files added
34 files modified
| | |
| | | .gitignore |
| | | node_modules |
| | | public |
| | | tsconfig.tsbuildinfo |
| | | .obsidian |
| | | .quartz-cache |
| | |
| | | - `dark`: header text and icons |
| | | - `secondary`: link colour, current [[graph view|graph]] node |
| | | - `tertiary`: hover states and visited [[graph view|graph]] nodes |
| | | - `highlight`: internal link background, highlighted text, highlighted [[syntax highlighting|lines of code]] |
| | | - `highlight`: internal link background, highlighted text, [[syntax highlighting|highlighted lines of code]] |
| | | |
| | | ## Plugins |
| | | You can think of Quartz plugins as a series of transformations over content. |
| | |
| | | By adding, removing, and reordering plugins from the `tranformers`, `filters`, and `emitters` fields, you can customize the behaviour of Quartz. |
| | | |
| | | > [!note] |
| | | > Note that each node is modified by every transformer *in order*. Some transformers are position-sensitive so you may need to take special note of whether it needs come before or after any other particular plugins. |
| | | > Each node is modified by every transformer *in order*. Some transformers are position-sensitive so you may need to take special note of whether it needs come before or after any other particular plugins. |
| | | |
| | | Additionally, plugins may also have their own configuration settings that you can pass in. For example, the [[Latex]] plugin allows you to pass in a field specifying the `renderEngine` to choose between Katex and MathJax. |
| | | |
| | |
| | | --- |
| | | tags: |
| | | - plugins/transformer |
| | | --- |
| | | |
| | | Quartz uses [Katex](https://katex.org/) by default to typeset both inline and block math expressions at build time. |
| | | |
| | | ## Formatting |
| | |
| | | --- |
| | | title: Syntax Highlighting |
| | | tags: |
| | | - plugins/transformer |
| | | --- |
| | | |
| | | Syntax highlighting in Quartz is completely done at build-time. This means that Quartz only ships pre-calculated CSS to highlight the right words so there is no heavy client-side bundle that does the syntax highlighting. |
| | |
| | | --- |
| | | title: "Table of Contents" |
| | | tags: |
| | | - component |
| | | --- |
| | |
| | | |
| | | - fixes |
| | | - changing `_index` files |
| | | - typography |
| | | - CLI |
| | | - update |
| | | - push |
| | |
| | | - mermaid styling: [https://mermaid.js.org/config/theming.html#theme-variables-reference-table](https://mermaid.js.org/config/theming.html#theme-variables-reference-table) |
| | | - [https://github.com/jackyzha0/quartz/issues/331](https://github.com/jackyzha0/quartz/issues/331) |
| | | - block links: [https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note](https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note) |
| | | - note/header/block transcludes: [https://help.obsidian.md/Linking+notes+and+files/Embedding+files](https://help.obsidian.md/Linking+notes+and+files/Embedding+files) |
| | | - note/header/block transcludes: [https://help.obsidian.md/Linking+notes+and+files/Embedding+files](https://help.obsidian.md/Linking+notes+and+files/Embedding+files) |
| | | - parse all images in page |
| | | - use this for page lists if applicable? |
| | | - CV mode? |
| | | - with print stylesheet |
| | |
| | | "plausible-tracker": "^0.3.8", |
| | | "preact": "^10.14.1", |
| | | "preact-render-to-string": "^6.0.3", |
| | | "pretty-bytes": "^6.1.0", |
| | | "pretty-time": "^1.1.0", |
| | | "reading-time": "^1.5.0", |
| | | "rehype-autolink-headings": "^6.1.1", |
| | |
| | | "remark-smartypants": "^2.0.0", |
| | | "rimraf": "^5.0.1", |
| | | "serve-handler": "^6.1.5", |
| | | "source-map-support": "^0.5.21", |
| | | "to-vfile": "^7.2.4", |
| | | "unified": "^10.1.2", |
| | | "unist-util-visit": "^4.1.2", |
| | |
| | | "@types/serve-handler": "^6.1.1", |
| | | "@types/workerpool": "^6.4.0", |
| | | "@types/yargs": "^17.0.24", |
| | | "ava": "^5.3.1", |
| | | "esbuild": "^0.18.11", |
| | | "tsx": "^3.12.7", |
| | | "typescript": "^5.0.4" |
| | |
| | | "node": ">= 6.0.0" |
| | | } |
| | | }, |
| | | "node_modules/aggregate-error": { |
| | | "version": "4.0.1", |
| | | "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", |
| | | "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "clean-stack": "^4.0.0", |
| | | "indent-string": "^5.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/ansi-regex": { |
| | | "version": "6.0.1", |
| | | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", |
| | |
| | | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", |
| | | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" |
| | | }, |
| | | "node_modules/array-find-index": { |
| | | "version": "1.0.2", |
| | | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", |
| | | "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=0.10.0" |
| | | } |
| | | }, |
| | | "node_modules/array-iterate": { |
| | | "version": "2.0.1", |
| | | "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", |
| | |
| | | "url": "https://github.com/sponsors/wooorm" |
| | | } |
| | | }, |
| | | "node_modules/arrgv": { |
| | | "version": "1.0.2", |
| | | "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", |
| | | "integrity": "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=8.0.0" |
| | | } |
| | | }, |
| | | "node_modules/arrify": { |
| | | "version": "3.0.0", |
| | | "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", |
| | | "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/asynckit": { |
| | | "version": "0.4.0", |
| | | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", |
| | | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" |
| | | }, |
| | | "node_modules/ava": { |
| | | "version": "5.3.1", |
| | | "resolved": "https://registry.npmjs.org/ava/-/ava-5.3.1.tgz", |
| | | "integrity": "sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "acorn": "^8.8.2", |
| | | "acorn-walk": "^8.2.0", |
| | | "ansi-styles": "^6.2.1", |
| | | "arrgv": "^1.0.2", |
| | | "arrify": "^3.0.0", |
| | | "callsites": "^4.0.0", |
| | | "cbor": "^8.1.0", |
| | | "chalk": "^5.2.0", |
| | | "chokidar": "^3.5.3", |
| | | "chunkd": "^2.0.1", |
| | | "ci-info": "^3.8.0", |
| | | "ci-parallel-vars": "^1.0.1", |
| | | "clean-yaml-object": "^0.1.0", |
| | | "cli-truncate": "^3.1.0", |
| | | "code-excerpt": "^4.0.0", |
| | | "common-path-prefix": "^3.0.0", |
| | | "concordance": "^5.0.4", |
| | | "currently-unhandled": "^0.4.1", |
| | | "debug": "^4.3.4", |
| | | "emittery": "^1.0.1", |
| | | "figures": "^5.0.0", |
| | | "globby": "^13.1.4", |
| | | "ignore-by-default": "^2.1.0", |
| | | "indent-string": "^5.0.0", |
| | | "is-error": "^2.2.2", |
| | | "is-plain-object": "^5.0.0", |
| | | "is-promise": "^4.0.0", |
| | | "matcher": "^5.0.0", |
| | | "mem": "^9.0.2", |
| | | "ms": "^2.1.3", |
| | | "p-event": "^5.0.1", |
| | | "p-map": "^5.5.0", |
| | | "picomatch": "^2.3.1", |
| | | "pkg-conf": "^4.0.0", |
| | | "plur": "^5.1.0", |
| | | "pretty-ms": "^8.0.0", |
| | | "resolve-cwd": "^3.0.0", |
| | | "stack-utils": "^2.0.6", |
| | | "strip-ansi": "^7.0.1", |
| | | "supertap": "^3.0.1", |
| | | "temp-dir": "^3.0.0", |
| | | "write-file-atomic": "^5.0.1", |
| | | "yargs": "^17.7.2" |
| | | }, |
| | | "bin": { |
| | | "ava": "entrypoints/cli.mjs" |
| | | }, |
| | | "engines": { |
| | | "node": ">=14.19 <15 || >=16.15 <17 || >=18" |
| | | }, |
| | | "peerDependencies": { |
| | | "@ava/typescript": "*" |
| | | }, |
| | | "peerDependenciesMeta": { |
| | | "@ava/typescript": { |
| | | "optional": true |
| | | } |
| | | } |
| | | }, |
| | | "node_modules/ava/node_modules/acorn-walk": { |
| | | "version": "8.2.0", |
| | | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", |
| | | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=0.4.0" |
| | | } |
| | | }, |
| | | "node_modules/ava/node_modules/ansi-styles": { |
| | | "version": "6.2.1", |
| | | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", |
| | | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/chalk/ansi-styles?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/ava/node_modules/chalk": { |
| | | "version": "5.3.0", |
| | | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", |
| | | "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": "^12.17.0 || ^14.13 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/chalk/chalk?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/ava/node_modules/ms": { |
| | | "version": "2.1.3", |
| | | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", |
| | | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/bail": { |
| | | "version": "2.0.2", |
| | | "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", |
| | |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/blueimp-md5": { |
| | | "version": "2.19.0", |
| | | "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", |
| | | "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/brace-expansion": { |
| | | "version": "2.0.1", |
| | | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", |
| | |
| | | "node_modules/buffer-from": { |
| | | "version": "1.1.2", |
| | | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", |
| | | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", |
| | | "dev": true |
| | | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" |
| | | }, |
| | | "node_modules/bytes": { |
| | | "version": "3.0.0", |
| | |
| | | "node": ">= 0.8" |
| | | } |
| | | }, |
| | | "node_modules/callsites": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.0.0.tgz", |
| | | "integrity": "sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12.20" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/cbor": { |
| | | "version": "8.1.0", |
| | | "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", |
| | | "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "nofilter": "^3.1.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12.19" |
| | | } |
| | | }, |
| | | "node_modules/ccount": { |
| | | "version": "2.0.1", |
| | | "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", |
| | |
| | | "fsevents": "~2.3.2" |
| | | } |
| | | }, |
| | | "node_modules/chunkd": { |
| | | "version": "2.0.1", |
| | | "resolved": "https://registry.npmjs.org/chunkd/-/chunkd-2.0.1.tgz", |
| | | "integrity": "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/ci-info": { |
| | | "version": "3.8.0", |
| | | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", |
| | | "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", |
| | | "dev": true, |
| | | "funding": [ |
| | | { |
| | | "type": "github", |
| | | "url": "https://github.com/sponsors/sibiraj-s" |
| | | } |
| | | ], |
| | | "engines": { |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/ci-parallel-vars": { |
| | | "version": "1.0.1", |
| | | "resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.1.tgz", |
| | | "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/clean-stack": { |
| | | "version": "4.2.0", |
| | | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", |
| | | "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "escape-string-regexp": "5.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/clean-yaml-object": { |
| | | "version": "0.1.0", |
| | | "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", |
| | | "integrity": "sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=0.10.0" |
| | | } |
| | | }, |
| | | "node_modules/cli-spinner": { |
| | | "version": "0.2.10", |
| | | "resolved": "https://registry.npmjs.org/cli-spinner/-/cli-spinner-0.2.10.tgz", |
| | |
| | | "node": ">=0.10" |
| | | } |
| | | }, |
| | | "node_modules/cli-truncate": { |
| | | "version": "3.1.0", |
| | | "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", |
| | | "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "slice-ansi": "^5.0.0", |
| | | "string-width": "^5.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/cliui": { |
| | | "version": "8.0.1", |
| | | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", |
| | |
| | | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/code-excerpt": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", |
| | | "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "convert-to-spaces": "^2.0.1" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | } |
| | | }, |
| | | "node_modules/color-convert": { |
| | | "version": "2.0.1", |
| | | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", |
| | |
| | | "node": ">= 10" |
| | | } |
| | | }, |
| | | "node_modules/common-path-prefix": { |
| | | "version": "3.0.0", |
| | | "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", |
| | | "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/concat-map": { |
| | | "version": "0.0.1", |
| | | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", |
| | | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" |
| | | }, |
| | | "node_modules/concordance": { |
| | | "version": "5.0.4", |
| | | "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", |
| | | "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "date-time": "^3.1.0", |
| | | "esutils": "^2.0.3", |
| | | "fast-diff": "^1.2.0", |
| | | "js-string-escape": "^1.0.1", |
| | | "lodash": "^4.17.15", |
| | | "md5-hex": "^3.0.1", |
| | | "semver": "^7.3.2", |
| | | "well-known-symbols": "^2.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" |
| | | } |
| | | }, |
| | | "node_modules/content-disposition": { |
| | | "version": "0.5.2", |
| | | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", |
| | |
| | | "node": ">= 0.6" |
| | | } |
| | | }, |
| | | "node_modules/convert-to-spaces": { |
| | | "version": "2.0.1", |
| | | "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", |
| | | "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | } |
| | | }, |
| | | "node_modules/cross-spawn": { |
| | | "version": "7.0.3", |
| | | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", |
| | |
| | | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", |
| | | "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" |
| | | }, |
| | | "node_modules/currently-unhandled": { |
| | | "version": "0.4.1", |
| | | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", |
| | | "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "array-find-index": "^1.0.1" |
| | | }, |
| | | "engines": { |
| | | "node": ">=0.10.0" |
| | | } |
| | | }, |
| | | "node_modules/d3": { |
| | | "version": "7.8.5", |
| | | "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", |
| | |
| | | "node": ">=12" |
| | | } |
| | | }, |
| | | "node_modules/date-time": { |
| | | "version": "3.1.0", |
| | | "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", |
| | | "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "time-zone": "^1.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=6" |
| | | } |
| | | }, |
| | | "node_modules/debug": { |
| | | "version": "4.3.4", |
| | | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", |
| | |
| | | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", |
| | | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" |
| | | }, |
| | | "node_modules/emittery": { |
| | | "version": "1.0.1", |
| | | "resolved": "https://registry.npmjs.org/emittery/-/emittery-1.0.1.tgz", |
| | | "integrity": "sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=14.16" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sindresorhus/emittery?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/emoji-regex": { |
| | | "version": "9.2.2", |
| | | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", |
| | |
| | | "node": ">=0.10.0" |
| | | } |
| | | }, |
| | | "node_modules/fast-diff": { |
| | | "version": "1.3.0", |
| | | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", |
| | | "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/fast-glob": { |
| | | "version": "3.3.0", |
| | | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", |
| | |
| | | "url": "https://github.com/sponsors/wooorm" |
| | | } |
| | | }, |
| | | "node_modules/figures": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", |
| | | "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "escape-string-regexp": "^5.0.0", |
| | | "is-unicode-supported": "^1.2.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=14" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/fill-range": { |
| | | "version": "7.0.1", |
| | | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", |
| | |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/find-up": { |
| | | "version": "6.3.0", |
| | | "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", |
| | | "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "locate-path": "^7.1.0", |
| | | "path-exists": "^5.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/flexsearch": { |
| | | "version": "0.7.21", |
| | | "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.21.tgz", |
| | |
| | | "node": ">= 4" |
| | | } |
| | | }, |
| | | "node_modules/ignore-by-default": { |
| | | "version": "2.1.0", |
| | | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz", |
| | | "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=10 <11 || >=12 <13 || >=14" |
| | | } |
| | | }, |
| | | "node_modules/immutable": { |
| | | "version": "4.3.0", |
| | | "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", |
| | | "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==" |
| | | }, |
| | | "node_modules/imurmurhash": { |
| | | "version": "0.1.4", |
| | | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", |
| | | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=0.8.19" |
| | | } |
| | | }, |
| | | "node_modules/indent-string": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", |
| | | "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/inline-style-parser": { |
| | | "version": "0.1.1", |
| | | "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", |
| | |
| | | "node": ">=12" |
| | | } |
| | | }, |
| | | "node_modules/irregular-plurals": { |
| | | "version": "3.5.0", |
| | | "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", |
| | | "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/is-absolute-url": { |
| | | "version": "4.0.1", |
| | | "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", |
| | |
| | | "url": "https://github.com/sponsors/ljharb" |
| | | } |
| | | }, |
| | | "node_modules/is-error": { |
| | | "version": "2.2.2", |
| | | "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", |
| | | "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/is-extendable": { |
| | | "version": "0.1.1", |
| | | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", |
| | |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/is-plain-object": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", |
| | | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=0.10.0" |
| | | } |
| | | }, |
| | | "node_modules/is-potential-custom-element-name": { |
| | | "version": "1.0.1", |
| | | "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", |
| | | "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" |
| | | }, |
| | | "node_modules/is-promise": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", |
| | | "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/is-unicode-supported": { |
| | | "version": "1.3.0", |
| | | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", |
| | | "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/isexe": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", |
| | |
| | | "@pkgjs/parseargs": "^0.11.0" |
| | | } |
| | | }, |
| | | "node_modules/js-string-escape": { |
| | | "version": "1.0.1", |
| | | "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", |
| | | "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">= 0.8" |
| | | } |
| | | }, |
| | | "node_modules/js-yaml": { |
| | | "version": "4.1.0", |
| | | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", |
| | |
| | | "node": ">=6" |
| | | } |
| | | }, |
| | | "node_modules/load-json-file": { |
| | | "version": "7.0.1", |
| | | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", |
| | | "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/locate-path": { |
| | | "version": "7.2.0", |
| | | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", |
| | | "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "p-locate": "^6.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/lodash": { |
| | | "version": "4.17.21", |
| | | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", |
| | | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/longest-streak": { |
| | | "version": "3.1.0", |
| | | "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", |
| | |
| | | "node": "14 || >=16.14" |
| | | } |
| | | }, |
| | | "node_modules/map-age-cleaner": { |
| | | "version": "0.1.3", |
| | | "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", |
| | | "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "p-defer": "^1.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=6" |
| | | } |
| | | }, |
| | | "node_modules/markdown-table": { |
| | | "version": "3.0.3", |
| | | "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", |
| | |
| | | "url": "https://github.com/sponsors/wooorm" |
| | | } |
| | | }, |
| | | "node_modules/matcher": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", |
| | | "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "escape-string-regexp": "^5.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/mathjax-full": { |
| | | "version": "3.2.2", |
| | | "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz", |
| | |
| | | "speech-rule-engine": "^4.0.6" |
| | | } |
| | | }, |
| | | "node_modules/md5-hex": { |
| | | "version": "3.0.1", |
| | | "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", |
| | | "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "blueimp-md5": "^2.10.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/mdast-util-definitions": { |
| | | "version": "5.1.2", |
| | | "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", |
| | |
| | | "url": "https://opencollective.com/unified" |
| | | } |
| | | }, |
| | | "node_modules/mem": { |
| | | "version": "9.0.2", |
| | | "resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz", |
| | | "integrity": "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "map-age-cleaner": "^0.1.3", |
| | | "mimic-fn": "^4.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12.20" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sindresorhus/mem?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/merge2": { |
| | | "version": "1.4.1", |
| | | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", |
| | |
| | | "node": ">= 0.6" |
| | | } |
| | | }, |
| | | "node_modules/mimic-fn": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", |
| | | "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/minimatch": { |
| | | "version": "9.0.2", |
| | | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz", |
| | |
| | | "url": "https://opencollective.com/unified" |
| | | } |
| | | }, |
| | | "node_modules/nofilter": { |
| | | "version": "3.1.0", |
| | | "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", |
| | | "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12.19" |
| | | } |
| | | }, |
| | | "node_modules/normalize-path": { |
| | | "version": "3.0.0", |
| | | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", |
| | |
| | | "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", |
| | | "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" |
| | | }, |
| | | "node_modules/p-defer": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", |
| | | "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=4" |
| | | } |
| | | }, |
| | | "node_modules/p-event": { |
| | | "version": "5.0.1", |
| | | "resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz", |
| | | "integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "p-timeout": "^5.0.2" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/p-limit": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", |
| | | "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "yocto-queue": "^1.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/p-locate": { |
| | | "version": "6.0.0", |
| | | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", |
| | | "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "p-limit": "^4.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/p-map": { |
| | | "version": "5.5.0", |
| | | "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", |
| | | "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "aggregate-error": "^4.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/p-timeout": { |
| | | "version": "5.1.0", |
| | | "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", |
| | | "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/parse-latin": { |
| | | "version": "5.0.1", |
| | | "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.1.tgz", |
| | |
| | | "url": "https://github.com/sponsors/wooorm" |
| | | } |
| | | }, |
| | | "node_modules/parse-ms": { |
| | | "version": "3.0.0", |
| | | "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", |
| | | "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/parse-numeric-range": { |
| | | "version": "1.3.0", |
| | | "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", |
| | |
| | | "url": "https://github.com/inikulin/parse5?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/path-exists": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", |
| | | "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | } |
| | | }, |
| | | "node_modules/path-is-inside": { |
| | | "version": "1.0.2", |
| | | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", |
| | |
| | | "url": "https://github.com/sponsors/jonschlinkert" |
| | | } |
| | | }, |
| | | "node_modules/pkg-conf": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", |
| | | "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "find-up": "^6.0.0", |
| | | "load-json-file": "^7.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/plausible-tracker": { |
| | | "version": "0.3.8", |
| | | "resolved": "https://registry.npmjs.org/plausible-tracker/-/plausible-tracker-0.3.8.tgz", |
| | |
| | | "node": ">=10" |
| | | } |
| | | }, |
| | | "node_modules/plur": { |
| | | "version": "5.1.0", |
| | | "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", |
| | | "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "irregular-plurals": "^3.3.0" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/preact": { |
| | | "version": "10.15.1", |
| | | "resolved": "https://registry.npmjs.org/preact/-/preact-10.15.1.tgz", |
| | |
| | | "preact": ">=10" |
| | | } |
| | | }, |
| | | "node_modules/pretty-format": { |
| | | "version": "3.8.0", |
| | | "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", |
| | | "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" |
| | | }, |
| | | "node_modules/pretty-ms": { |
| | | "version": "8.0.0", |
| | | "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-8.0.0.tgz", |
| | | "integrity": "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "parse-ms": "^3.0.0" |
| | | }, |
| | | "node_modules/pretty-bytes": { |
| | | "version": "6.1.0", |
| | | "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.0.tgz", |
| | | "integrity": "sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==", |
| | | "engines": { |
| | | "node": ">=14.16" |
| | | "node": "^14.13.1 || >=16.0.0" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/pretty-format": { |
| | | "version": "3.8.0", |
| | | "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", |
| | | "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" |
| | | }, |
| | | "node_modules/pretty-time": { |
| | | "version": "1.1.0", |
| | | "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", |
| | |
| | | "url": "https://github.com/sponsors/ljharb" |
| | | } |
| | | }, |
| | | "node_modules/resolve-cwd": { |
| | | "version": "3.0.0", |
| | | "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", |
| | | "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "resolve-from": "^5.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/resolve-from": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", |
| | | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/resolve-pkg-maps": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", |
| | |
| | | "node": ">=4" |
| | | } |
| | | }, |
| | | "node_modules/semver": { |
| | | "version": "7.5.4", |
| | | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", |
| | | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "lru-cache": "^6.0.0" |
| | | }, |
| | | "bin": { |
| | | "semver": "bin/semver.js" |
| | | }, |
| | | "engines": { |
| | | "node": ">=10" |
| | | } |
| | | }, |
| | | "node_modules/semver/node_modules/lru-cache": { |
| | | "version": "6.0.0", |
| | | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", |
| | | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "yallist": "^4.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=10" |
| | | } |
| | | }, |
| | | "node_modules/serialize-error": { |
| | | "version": "7.0.1", |
| | | "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", |
| | | "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "type-fest": "^0.13.1" |
| | | }, |
| | | "engines": { |
| | | "node": ">=10" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/serialize-error/node_modules/type-fest": { |
| | | "version": "0.13.1", |
| | | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", |
| | | "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=10" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/serve-handler": { |
| | | "version": "6.1.5", |
| | | "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", |
| | |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/slice-ansi": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", |
| | | "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "ansi-styles": "^6.0.0", |
| | | "is-fullwidth-code-point": "^4.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/chalk/slice-ansi?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/slice-ansi/node_modules/ansi-styles": { |
| | | "version": "6.2.1", |
| | | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", |
| | | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/chalk/ansi-styles?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", |
| | | "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/sort-keys": { |
| | | "version": "5.0.0", |
| | | "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-5.0.0.tgz", |
| | |
| | | "version": "0.6.1", |
| | | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", |
| | | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", |
| | | "devOptional": true, |
| | | "engines": { |
| | | "node": ">=0.10.0" |
| | | } |
| | |
| | | "version": "0.5.21", |
| | | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", |
| | | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "buffer-from": "^1.0.0", |
| | | "source-map": "^0.6.0" |
| | |
| | | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", |
| | | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" |
| | | }, |
| | | "node_modules/stack-utils": { |
| | | "version": "2.0.6", |
| | | "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", |
| | | "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "escape-string-regexp": "^2.0.0" |
| | | }, |
| | | "engines": { |
| | | "node": ">=10" |
| | | } |
| | | }, |
| | | "node_modules/stack-utils/node_modules/escape-string-regexp": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", |
| | | "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/string-width": { |
| | | "version": "5.1.2", |
| | | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", |
| | |
| | | "inline-style-parser": "0.1.1" |
| | | } |
| | | }, |
| | | "node_modules/supertap": { |
| | | "version": "3.0.1", |
| | | "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", |
| | | "integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "indent-string": "^5.0.0", |
| | | "js-yaml": "^3.14.1", |
| | | "serialize-error": "^7.0.1", |
| | | "strip-ansi": "^7.0.1" |
| | | }, |
| | | "engines": { |
| | | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" |
| | | } |
| | | }, |
| | | "node_modules/supertap/node_modules/argparse": { |
| | | "version": "1.0.10", |
| | | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", |
| | | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "sprintf-js": "~1.0.2" |
| | | } |
| | | }, |
| | | "node_modules/supertap/node_modules/js-yaml": { |
| | | "version": "3.14.1", |
| | | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", |
| | | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "argparse": "^1.0.7", |
| | | "esprima": "^4.0.0" |
| | | }, |
| | | "bin": { |
| | | "js-yaml": "bin/js-yaml.js" |
| | | } |
| | | }, |
| | | "node_modules/supports-color": { |
| | | "version": "7.2.0", |
| | | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", |
| | |
| | | "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", |
| | | "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" |
| | | }, |
| | | "node_modules/temp-dir": { |
| | | "version": "3.0.0", |
| | | "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", |
| | | "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=14.16" |
| | | } |
| | | }, |
| | | "node_modules/time-zone": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", |
| | | "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=4" |
| | | } |
| | | }, |
| | | "node_modules/to-regex-range": { |
| | | "version": "5.0.1", |
| | | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", |
| | |
| | | "node": ">=12" |
| | | } |
| | | }, |
| | | "node_modules/well-known-symbols": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", |
| | | "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=6" |
| | | } |
| | | }, |
| | | "node_modules/whatwg-encoding": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", |
| | |
| | | "url": "https://github.com/chalk/ansi-styles?sponsor=1" |
| | | } |
| | | }, |
| | | "node_modules/write-file-atomic": { |
| | | "version": "5.0.1", |
| | | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", |
| | | "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", |
| | | "dev": true, |
| | | "dependencies": { |
| | | "imurmurhash": "^0.1.4", |
| | | "signal-exit": "^4.0.1" |
| | | }, |
| | | "engines": { |
| | | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" |
| | | } |
| | | }, |
| | | "node_modules/ws": { |
| | | "version": "8.13.0", |
| | | "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", |
| | |
| | | "node": ">=10" |
| | | } |
| | | }, |
| | | "node_modules/yallist": { |
| | | "version": "4.0.0", |
| | | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", |
| | | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", |
| | | "dev": true |
| | | }, |
| | | "node_modules/yargs": { |
| | | "version": "17.7.2", |
| | | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", |
| | |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/yocto-queue": { |
| | | "version": "1.0.0", |
| | | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", |
| | | "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", |
| | | "dev": true, |
| | | "engines": { |
| | | "node": ">=12.20" |
| | | }, |
| | | "funding": { |
| | | "url": "https://github.com/sponsors/sindresorhus" |
| | | } |
| | | }, |
| | | "node_modules/zwitch": { |
| | | "version": "2.0.4", |
| | | "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", |
| | |
| | | "name": "@jackyzha0/quartz", |
| | | "description": "🌱 publish your digital garden and notes as a website", |
| | | "private": true, |
| | | "version": "4.0.4", |
| | | "version": "4.0.5", |
| | | "type": "module", |
| | | "author": "jackyzha0 <j.zhao2k19@gmail.com>", |
| | | "license": "MIT", |
| | |
| | | "plausible-tracker": "^0.3.8", |
| | | "preact": "^10.14.1", |
| | | "preact-render-to-string": "^6.0.3", |
| | | "pretty-bytes": "^6.1.0", |
| | | "pretty-time": "^1.1.0", |
| | | "reading-time": "^1.5.0", |
| | | "rehype-autolink-headings": "^6.1.1", |
| | |
| | | "remark-smartypants": "^2.0.0", |
| | | "rimraf": "^5.0.1", |
| | | "serve-handler": "^6.1.5", |
| | | "source-map-support": "^0.5.21", |
| | | "to-vfile": "^7.2.4", |
| | | "unified": "^10.1.2", |
| | | "unist-util-visit": "^4.1.2", |
| | |
| | | import fs from 'fs' |
| | | import { intro, isCancel, outro, select, text } from '@clack/prompts' |
| | | import { rimraf } from 'rimraf' |
| | | import prettyBytes from 'pretty-bytes' |
| | | |
| | | const cacheFile = "./.quartz-cache/transpiled-build.mjs" |
| | | const fp = "./quartz/build.ts" |
| | |
| | | `) |
| | | }) |
| | | .command('build', 'Build Quartz into a bundle of static HTML files', BuildArgv, async (argv) => { |
| | | await esbuild.build({ |
| | | const result = await esbuild.build({ |
| | | entryPoints: [fp], |
| | | outfile: path.join("quartz", cacheFile), |
| | | bundle: true, |
| | |
| | | jsx: "automatic", |
| | | jsxImportSource: "preact", |
| | | packages: "external", |
| | | metafile: true, |
| | | sourcemap: true, |
| | | plugins: [ |
| | | sassPlugin({ |
| | | type: 'css-text', |
| | |
| | | process.exit(1) |
| | | }) |
| | | |
| | | if (argv.verbose) { |
| | | const outputFileName = 'quartz/.quartz-cache/transpiled-build.mjs' |
| | | const meta = result.metafile.outputs[outputFileName] |
| | | console.log(chalk.gray(`[debug] Successfully transpiled ${Object.keys(meta.inputs).length} files (${prettyBytes(meta.bytes)})`)) |
| | | } |
| | | |
| | | const { default: init } = await import(cacheFile) |
| | | init(argv, version) |
| | | }) |
| | |
| | | import 'source-map-support/register.js' |
| | | import path from "path" |
| | | import { PerfTimer } from "./perf" |
| | | import { rimraf } from "rimraf" |
| | |
| | | import { filterContent } from "./processors/filter" |
| | | import { emitContent } from "./processors/emit" |
| | | import cfg from "../quartz.config" |
| | | import { FilePath } from "./path" |
| | | |
| | | interface Argv { |
| | | directory: string |
| | |
| | | }) |
| | | console.log(`Found ${fps.length} input files from \`${argv.directory}\` in ${perf.timeSince('glob')}`) |
| | | |
| | | const filePaths = fps.map(fp => `${argv.directory}${path.sep}${fp}`) |
| | | const filePaths = fps.map(fp => `${argv.directory}${path.sep}${fp}` as FilePath) |
| | | const parsedFiles = await parseMarkdown(cfg.plugins.transformers, argv.directory, filePaths, argv.verbose) |
| | | const filteredContent = filterContent(cfg.plugins.filters, parsedFiles, argv.verbose) |
| | | await emitContent(argv.directory, output, cfg, filteredContent, argv.verbose) |
| | |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | import style from "./styles/backlinks.scss" |
| | | import { relativeToRoot } from "../path" |
| | | import { clientSideSlug } from "./scripts/util" |
| | | import { canonicalizeServer, resolveRelative } from "../path" |
| | | |
| | | function Backlinks({ fileData, allFiles }: QuartzComponentProps) { |
| | | const slug = fileData.slug! |
| | | const slug = canonicalizeServer(fileData.slug!) |
| | | const backlinkFiles = allFiles.filter(file => file.links?.includes(slug)) |
| | | return <div class="backlinks"> |
| | | <h3>Backlinks</h3> |
| | | <ul class="overflow"> |
| | | {backlinkFiles.length > 0 ? |
| | | backlinkFiles.map(f => <li><a href={clientSideSlug(relativeToRoot(slug, f.slug!))} class="internal">{f.frontmatter?.title}</a></li>) |
| | | backlinkFiles.map(f => <li><a href={resolveRelative(slug, canonicalizeServer(f.slug!))} class="internal">{f.frontmatter?.title}</a></li>) |
| | | : <li>No backlinks found</li>} |
| | | </ul> |
| | | </div> |
| | | </div> |
| | | } |
| | | |
| | | Backlinks.css = style |
| | | Backlinks.css = style |
| | | export default (() => Backlinks) satisfies QuartzComponentConstructor |
| | |
| | | import { toServerSlug, pathToRoot } from "../path" |
| | | import { canonicalizeServer, pathToRoot } from "../path" |
| | | import { JSResourceToScriptElement } from "../resources" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | export default (() => { |
| | | function Head({ fileData, externalResources }: QuartzComponentProps) { |
| | | const slug = toServerSlug(fileData.slug!) |
| | | const slug = canonicalizeServer(fileData.slug!) |
| | | const title = fileData.frontmatter?.title ?? "Untitled" |
| | | const description = fileData.description ?? "No description provided" |
| | | const { css, js } = externalResources |
| | |
| | | import { relativeToRoot } from "../path" |
| | | import { CanonicalSlug, canonicalizeServer, resolveRelative } from "../path" |
| | | import { QuartzPluginData } from "../plugins/vfile" |
| | | import { Date } from "./Date" |
| | | import { clientSideSlug } from "./scripts/util" |
| | | import { QuartzComponentProps } from "./types" |
| | | |
| | | function byDateAndAlphabetical(f1: QuartzPluginData, f2: QuartzPluginData): number { |
| | |
| | | } |
| | | |
| | | export function PageList({ fileData, allFiles }: QuartzComponentProps) { |
| | | const slug = fileData.slug! |
| | | const slug = canonicalizeServer(fileData.slug!) |
| | | return <ul class="section-ul"> |
| | | {allFiles.sort(byDateAndAlphabetical).map(page => { |
| | | const title = page.frontmatter?.title |
| | | const pageSlug = page.slug! |
| | | const pageSlug = canonicalizeServer(page.slug!) |
| | | const tags = page.frontmatter?.tags ?? [] |
| | | |
| | | return <li class="section-li"> |
| | | <div class="section"> |
| | | {page.dates && <p class="meta"> |
| | | <Date date={page.dates.modified} /> |
| | | </p>} |
| | | <div class="desc"> |
| | | <h3><a href={clientSideSlug(relativeToRoot(slug, pageSlug))} class="internal">{title}</a></h3> |
| | | <h3><a href={resolveRelative(slug, pageSlug)} class="internal">{title}</a></h3> |
| | | </div> |
| | | <ul class="tags"> |
| | | {tags.map(tag => <li><a class="internal" href={relativeToRoot(slug, `tags/${tag}`)}>#{tag}</a></li>)} |
| | | {tags.map(tag => <li><a class="internal" href={resolveRelative(slug, `tags/${tag}` as CanonicalSlug)}>#{tag}</a></li>)} |
| | | </ul> |
| | | </div> |
| | | </li> |
| | |
| | | import { pathToRoot } from "../path" |
| | | import { canonicalizeServer, pathToRoot } from "../path" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | function PageTitle({ fileData, cfg }: QuartzComponentProps) { |
| | | const title = cfg?.pageTitle ?? "Untitled Quartz" |
| | | const slug = fileData.slug! |
| | | const slug = canonicalizeServer(fileData.slug!) |
| | | const baseDir = pathToRoot(slug) |
| | | return <h1 class="page-title"><a href={baseDir}>{title}</a></h1> |
| | | } |
| | |
| | | import { pathToRoot } from "../path" |
| | | import { canonicalizeServer, pathToRoot } from "../path" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | import { slug as slugAnchor } from 'github-slugger' |
| | | |
| | | function TagList({ fileData }: QuartzComponentProps) { |
| | | const tags = fileData.frontmatter?.tags |
| | | const slug = fileData.slug! |
| | | const slug = canonicalizeServer(fileData.slug!) |
| | | const baseDir = pathToRoot(slug) |
| | | if (tags && tags.length > 0) { |
| | | return <ul class="tags">{tags.map(tag => { |
| | |
| | | |
| | | import style from '../styles/listPage.scss' |
| | | import { PageList } from "../PageList" |
| | | import { toServerSlug } from "../../path" |
| | | import { canonicalizeServer } from "../../path" |
| | | |
| | | function FolderContent(props: QuartzComponentProps) { |
| | | const { tree, fileData, allFiles } = props |
| | | const folderSlug = toServerSlug(fileData.slug!) |
| | | const folderSlug = canonicalizeServer(fileData.slug!) |
| | | const allPagesInFolder = allFiles.filter(file => { |
| | | const fileSlug = file.slug ?? "" |
| | | const prefixed = fileSlug.startsWith(folderSlug) |
| | |
| | | ...props, |
| | | allFiles: allPagesInFolder |
| | | } |
| | | |
| | | |
| | | // @ts-ignore |
| | | const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' }) |
| | | return <div class="popover-hint"> |
| | |
| | | import { toJsxRuntime } from "hast-util-to-jsx-runtime" |
| | | import style from '../styles/listPage.scss' |
| | | import { PageList } from "../PageList" |
| | | import { toServerSlug } from "../../path" |
| | | import { ServerSlug, canonicalizeServer } from "../../path" |
| | | |
| | | function TagContent(props: QuartzComponentProps) { |
| | | const { tree, fileData, allFiles } = props |
| | | const slug = fileData.slug |
| | | |
| | | if (slug?.startsWith("tags/")) { |
| | | const tag = toServerSlug(slug.slice("tags/".length)) |
| | | const tag = canonicalizeServer(slug.slice("tags/".length) as ServerSlug) |
| | | const allPagesWithTag = allFiles.filter(file => (file.frontmatter?.tags ?? []).includes(tag)) |
| | | const listProps = { |
| | | ...props, |
| | |
| | | </div> |
| | | </div> |
| | | } else { |
| | | throw `Component "TagContent" tried to render a non-tag page: ${slug}` |
| | | throw new Error(`Component "TagContent" tried to render a non-tag page: ${slug}`) |
| | | } |
| | | } |
| | | |
| | |
| | | import { ContentDetails } from "../../plugins/emitters/contentIndex" |
| | | import * as d3 from 'd3' |
| | | import { registerEscapeHandler, clientSideRelativePath, removeAllChildren } from "./util" |
| | | import { CanonicalSlug } from "../../path" |
| | | import { registerEscapeHandler, removeAllChildren } from "./util" |
| | | import { CanonicalSlug, getCanonicalSlug, getClientSlug, resolveRelative } from "../../path" |
| | | |
| | | type NodeData = { |
| | | id: CanonicalSlug, |
| | |
| | | localStorage.setItem(localStorageKey, JSON.stringify([...visited])) |
| | | } |
| | | |
| | | async function renderGraph(container: string, slug: string) { |
| | | async function renderGraph(container: string, slug: CanonicalSlug) { |
| | | const visited = getVisited() |
| | | const graph = document.getElementById(container) |
| | | if (!graph) return |
| | |
| | | const outgoing = details.links ?? [] |
| | | for (const dest of outgoing) { |
| | | if (src in data && dest in data) { |
| | | links.push({ source: src, target: dest }) |
| | | links.push({ source: src as CanonicalSlug, target: dest }) |
| | | } |
| | | } |
| | | } |
| | | |
| | | const neighbourhood = new Set() |
| | | |
| | | const wl = [slug, "__SENTINEL"] |
| | | const neighbourhood = new Set<CanonicalSlug>() |
| | | const wl: (CanonicalSlug | "__SENTINEL")[] = [slug, "__SENTINEL"] |
| | | if (depth >= 0) { |
| | | while (depth >= 0 && wl.length > 0) { |
| | | // compute neighbours |
| | | const cur = wl.shift() |
| | | const cur = wl.shift()! |
| | | if (cur === "__SENTINEL") { |
| | | depth-- |
| | | wl.push("__SENTINEL") |
| | |
| | | } |
| | | } |
| | | } else { |
| | | Object.keys(data).forEach(id => neighbourhood.add(id)) |
| | | Object.keys(data).forEach(id => neighbourhood.add(id as CanonicalSlug)) |
| | | } |
| | | |
| | | const graphData: { nodes: NodeData[], links: LinkData[] } = { |
| | | nodes: Object.keys(data).filter(id => neighbourhood.has(id)).map(url => ({ id: url, text: data[url]?.title ?? url, tags: data[url]?.tags ?? [] })), |
| | | nodes: [...neighbourhood].map(url => ({ id: url, text: data[url]?.title ?? url, tags: data[url]?.tags ?? [] })), |
| | | links: links.filter((l) => neighbourhood.has(l.source) && neighbourhood.has(l.target)) |
| | | } |
| | | |
| | |
| | | .attr("fill", color) |
| | | .style("cursor", "pointer") |
| | | .on("click", (_, d) => { |
| | | const targ = clientSideRelativePath(slug, d.id) |
| | | window.spaNavigate(new URL(targ)) |
| | | const targ = resolveRelative(slug, d.id) |
| | | window.spaNavigate(new URL(targ, getClientSlug(window))) |
| | | }) |
| | | .on("mouseover", function(_, d) { |
| | | const neighbours: string[] = data[slug].links ?? [] |
| | | const neighbours: CanonicalSlug[] = data[slug].links ?? [] |
| | | const neighbourNodes = d3.selectAll<HTMLElement, NodeData>(".node").filter((d) => neighbours.includes(d.id)) |
| | | console.log(neighbourNodes) |
| | | const currentId = d.id |
| | | const linkNodes = d3 |
| | | .selectAll(".link") |
| | |
| | | } |
| | | |
| | | function renderGlobalGraph() { |
| | | const slug = document.body.dataset["slug"]! |
| | | const slug = getCanonicalSlug(window) |
| | | const container = document.getElementById("global-graph-outer") |
| | | const sidebar = container?.closest(".sidebar") as HTMLElement |
| | | container?.classList.add("active") |
| | |
| | | import { Document } from "flexsearch" |
| | | import { ContentDetails } from "../../plugins/emitters/contentIndex" |
| | | import { registerEscapeHandler, clientSideRelativePath, removeAllChildren } from "./util" |
| | | import { CanonicalSlug } from "../../path" |
| | | import { registerEscapeHandler, removeAllChildren } from "./util" |
| | | import { CanonicalSlug, getClientSlug, resolveRelative } from "../../path" |
| | | |
| | | interface Item { |
| | | slug: CanonicalSlug, |
| | | title: string, |
| | | content: string, |
| | | } |
| | | |
| | | let index: Document<Item> | undefined = undefined |
| | | |
| | | const contextWindowWords = 30 |
| | |
| | | button.id = slug |
| | | button.innerHTML = `<h3>${title}</h3><p>${content}</p>` |
| | | button.addEventListener('click', () => { |
| | | const targ = clientSideRelativePath(currentSlug, slug) |
| | | window.spaNavigate(new URL(targ)) |
| | | const targ = resolveRelative(currentSlug, slug) |
| | | window.spaNavigate(new URL(targ, getClientSlug(window))) |
| | | }) |
| | | return button |
| | | } |
| | |
| | | function onType(e: HTMLElementEventMap["input"]) { |
| | | const term = (e.target as HTMLInputElement).value |
| | | const searchResults = index?.search(term, numSearchResults) ?? [] |
| | | const getByField = (field: string): string[] => { |
| | | const getByField = (field: string): CanonicalSlug[] => { |
| | | const results = searchResults.filter((x) => x.field === field) |
| | | return results.length === 0 ? [] : [...results[0].result] as string[] |
| | | return results.length === 0 ? [] : [...results[0].result] as CanonicalSlug[] |
| | | } |
| | | |
| | | // order titles ahead of content |
| | |
| | | import micromorph from "micromorph" |
| | | import { CanonicalSlug, RelativeURL } from "../../path" |
| | | import { CanonicalSlug, RelativeURL, getCanonicalSlug } from "../../path" |
| | | |
| | | // adapted from `micromorph` |
| | | // https://github.com/natemoo-re/micromorph |
| | |
| | | .catch(() => { |
| | | window.location.assign(url) |
| | | }) |
| | | |
| | | if (!contents) return; |
| | | if (!isBack) { |
| | | history.pushState({}, "", url) |
| | |
| | | const elementsToAdd = html.head.querySelectorAll(':not([spa-preserve])') |
| | | elementsToAdd.forEach(el => document.head.appendChild(el)) |
| | | |
| | | notifyNav(document.body.dataset.slug!) |
| | | notifyNav(getCanonicalSlug(window)) |
| | | delete announcer.dataset.persist |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | createRouter() |
| | | notifyNav(document.body.dataset.slug!) |
| | | notifyNav(getCanonicalSlug(window)) |
| | | |
| | | if (!customElements.get('route-announcer')) { |
| | | const attrs = { |
| | |
| | | }) |
| | | |
| | | test('isCanonicalSlug', () => { |
| | | assert(path.isCanonicalSlug("/")) |
| | | assert(path.isCanonicalSlug("/abc")) |
| | | assert(path.isCanonicalSlug("/notindex")) |
| | | assert(path.isCanonicalSlug("/notindex/def")) |
| | | assert(path.isCanonicalSlug("")) |
| | | assert(path.isCanonicalSlug("abc")) |
| | | assert(path.isCanonicalSlug("notindex")) |
| | | assert(path.isCanonicalSlug("notindex/def")) |
| | | |
| | | assert(!path.isCanonicalSlug("//")) |
| | | assert(!path.isCanonicalSlug("/index")) |
| | | assert(!path.isCanonicalSlug("")) |
| | | assert(!path.isCanonicalSlug("index")) |
| | | assert(!path.isCanonicalSlug("index/abc")) |
| | | assert(!path.isCanonicalSlug("https://example.com")) |
| | | assert(!path.isCanonicalSlug("/abc/")) |
| | | assert(!path.isCanonicalSlug("/abc/index")) |
| | | assert(!path.isCanonicalSlug("/abc#anchor")) |
| | | assert(!path.isCanonicalSlug("/abc?query=1")) |
| | | assert(!path.isCanonicalSlug("/index.md")) |
| | | assert(!path.isCanonicalSlug("/index.html")) |
| | | assert(!path.isCanonicalSlug("/abc")) |
| | | assert(!path.isCanonicalSlug("abc/")) |
| | | assert(!path.isCanonicalSlug("abc/index")) |
| | | assert(!path.isCanonicalSlug("abc#anchor")) |
| | | assert(!path.isCanonicalSlug("abc?query=1")) |
| | | assert(!path.isCanonicalSlug("index.md")) |
| | | assert(!path.isCanonicalSlug("index.html")) |
| | | }) |
| | | |
| | | test('isRelativeURL', () => { |
| | |
| | | assert(path.isRelativeURL("../abc/def")) |
| | | |
| | | assert(!path.isRelativeURL("abc")) |
| | | assert(!path.isRelativeURL("/abc/def")) |
| | | assert(!path.isRelativeURL("")) |
| | | assert(!path.isRelativeURL("../")) |
| | | assert(!path.isRelativeURL("./")) |
| | |
| | | }) |
| | | |
| | | test('isServerSlug', () => { |
| | | assert(path.isServerSlug("/index")) |
| | | assert(path.isServerSlug("/abc/def")) |
| | | assert(path.isServerSlug("index")) |
| | | assert(path.isServerSlug("abc/def")) |
| | | |
| | | assert(!path.isServerSlug("/")) |
| | | assert(!path.isServerSlug(".")) |
| | | assert(!path.isServerSlug("./abc/def")) |
| | | assert(!path.isServerSlug("../abc/def")) |
| | | assert(!path.isServerSlug("/index.html")) |
| | | assert(!path.isServerSlug("/abc/def.html")) |
| | | assert(!path.isServerSlug("/abc/def#anchor")) |
| | | assert(!path.isServerSlug("/abc/def?query=1")) |
| | | assert(!path.isServerSlug("/note with spaces")) |
| | | assert(!path.isServerSlug("index.html")) |
| | | assert(!path.isServerSlug("abc/def.html")) |
| | | assert(!path.isServerSlug("abc/def#anchor")) |
| | | assert(!path.isServerSlug("abc/def?query=1")) |
| | | assert(!path.isServerSlug("note with spaces")) |
| | | }) |
| | | |
| | | test('isFilePath', () => { |
| | | assert(path.isFilePath("/content/index.md")) |
| | | assert(path.isFilePath("/content/test.png")) |
| | | assert(path.isFilePath("content/index.md")) |
| | | assert(path.isFilePath("content/test.png")) |
| | | assert(!path.isFilePath("../test.pdf")) |
| | | assert(!path.isFilePath("content/test.png")) |
| | | assert(!path.isFilePath("content/test")) |
| | | assert(!path.isFilePath("./content/test")) |
| | | }) |
| | |
| | | for (const [inp, expected] of pairs) { |
| | | assert(checkPre(inp), `${inp} wasn't the expected input type`) |
| | | const actual = transform(inp) |
| | | assert.strictEqual(actual, expected, `after transforming ${inp}, ${actual} was not ${expected}`) |
| | | assert.strictEqual(actual, expected, `after transforming ${inp}, '${actual}' was not '${expected}'`) |
| | | assert(checkPost(actual), `${actual} wasn't the expected output type`) |
| | | } |
| | | } |
| | | |
| | | test('canonicalizeServer', () => { |
| | | asserts([ |
| | | ["/index", "/"], |
| | | ["/abc/def", "/abc/def"], |
| | | ["index", ""], |
| | | ["abc/index", "abc"], |
| | | ["abc/def", "abc/def"], |
| | | ], path.canonicalizeServer, path.isServerSlug, path.isCanonicalSlug) |
| | | }) |
| | | |
| | | test('canonicalizeClient', () => { |
| | | asserts([ |
| | | ["http://localhost:3000", "/"], |
| | | ["http://localhost:3000/index", "/"], |
| | | ["http://localhost:3000/test", "/test"], |
| | | ["http://example.com", "/"], |
| | | ["http://example.com/index", "/"], |
| | | ["http://example.com/index.html", "/"], |
| | | ["http://example.com/", "/"], |
| | | ["https://example.com", "/"], |
| | | ["https://example.com/abc/def", "/abc/def"], |
| | | ["https://example.com/abc/def/", "/abc/def"], |
| | | ["https://example.com/abc/def#cool", "/abc/def"], |
| | | ["https://example.com/abc/def?field=1&another=2", "/abc/def"], |
| | | ["https://example.com/abc/def?field=1&another=2#cool", "/abc/def"], |
| | | ["https://example.com/abc/def.html?field=1&another=2#cool", "/abc/def"], |
| | | ["http://localhost:3000", ""], |
| | | ["http://localhost:3000/index", ""], |
| | | ["http://localhost:3000/test", "test"], |
| | | ["http://example.com", ""], |
| | | ["http://example.com/index", ""], |
| | | ["http://example.com/index.html", ""], |
| | | ["http://example.com/", ""], |
| | | ["https://example.com", ""], |
| | | ["https://example.com/abc/def", "abc/def"], |
| | | ["https://example.com/abc/def/", "abc/def"], |
| | | ["https://example.com/abc/def#cool", "abc/def"], |
| | | ["https://example.com/abc/def?field=1&another=2", "abc/def"], |
| | | ["https://example.com/abc/def?field=1&another=2#cool", "abc/def"], |
| | | ["https://example.com/abc/def.html?field=1&another=2#cool", "abc/def"], |
| | | ], path.canonicalizeClient, path.isClientSlug, path.isCanonicalSlug) |
| | | }) |
| | | |
| | | describe('slugifyFilePath', () => { |
| | | asserts([ |
| | | ["/content/index.md", "/content/index"], |
| | | ["/content/cool.png", "/content/cool"], |
| | | ["/index.md", "/index"], |
| | | ["/note with spaces.md", "/note-with-spaces"], |
| | | ["content/index.md", "content/index"], |
| | | ["/content/index.md", "content/index"], |
| | | ["content/cool.png", "content/cool"], |
| | | ["index.md", "index"], |
| | | ["note with spaces.md", "note-with-spaces"], |
| | | ], path.slugifyFilePath, path.isFilePath, path.isServerSlug) |
| | | }) |
| | | |
| | |
| | | ["/tags/", "./tags"], |
| | | ["content/with spaces", "./content/with-spaces"], |
| | | ["content/with spaces#and Anchor!", "./content/with-spaces#and-anchor"], |
| | | ], path.transformInternalLink, (x: string): x is string => true, path.isRelativeURL) |
| | | ], path.transformInternalLink, (_x: string): _x is string => true, path.isRelativeURL) |
| | | }) |
| | | |
| | | describe('pathToRoot', () => { |
| | | asserts([ |
| | | ["/", "."], |
| | | ["/abc/def", "../.."], |
| | | ["", "."], |
| | | ["abc", ".."], |
| | | ["abc/def", "../.."], |
| | | ], path.pathToRoot, path.isCanonicalSlug, path.isRelativeURL) |
| | | }) |
| | | }) |
| | |
| | | import path from 'path' |
| | | import { slug as slugAnchor } from 'github-slugger' |
| | | import { trace } from './trace' |
| | | |
| | | // Quartz Paths |
| | | // Things in boxes are not actual types but rather sources which these types can be acquired from |
| | |
| | | // │ │ │ |
| | | // │ getClientSlug() │ .href │ |
| | | // │ ▼ ▼ |
| | | // │ |
| | | // │ Client Slug Relative URL |
| | | // getCanonicalSlug() │ https://test.ca/note/abc#anchor?query=123 ../note/def#anchor |
| | | // │ |
| | | // │ canonicalizeClient() │ ▲ |
| | | // │ ▼ │ |
| | | // │ │ |
| | | // └───────────────► Canonical Slug │ |
| | | // /note/abc │ |
| | | // │ |
| | | // ▲ │ |
| | | // │ Client Slug ┌───► Relative URL |
| | | // getCanonicalSlug() │ https://test.ca/note/abc#anchor?query=123 │ ../note/def#anchor |
| | | // │ │ |
| | | // │ canonicalizeClient() │ │ ▲ ▲ |
| | | // │ ▼ │ │ │ |
| | | // │ pathToRoot() │ │ │ |
| | | // └───────────────► Canonical Slug ────────────────┘ │ │ |
| | | // note/abc │ │ |
| | | // ──────────────────────────┘ │ |
| | | // ▲ resolveRelative() │ |
| | | // canonicalizeServer() │ │ |
| | | // │ |
| | | // HTML File Server Slug │ |
| | | // /note/abc/index.html ◄───────────── /note/abc/index │ |
| | | // note/abc/index.html ◄───────────── note/abc/index │ |
| | | // │ |
| | | // ▲ ┌────────┴────────┐ |
| | | // slugifyFilePath() │ transformInternalLink() │ │ |
| | | // slugifyFilePath() │ transformLink() │ │ |
| | | // │ │ │ |
| | | // ┌─────────┴──────────┐ ┌─────┴─────┐ ┌────────┴──────┐ |
| | | // │ File Path │ │ Wikilinks │ │ Markdown Link │ |
| | | // │ /note/abc/index.md │ └───────────┘ └───────────────┘ |
| | | // │ note/abc/index.md │ └───────────┘ └───────────────┘ |
| | | // └────────────────────┘ ▲ ▲ |
| | | // ▲ │ │ |
| | | // │ ┌─────────┐ │ │ |
| | | // └────────────┤ MD File ├─────┴─────────────────┘ |
| | | // └─────────┘ |
| | | |
| | | const STRICT_TYPE_CHECKS = true |
| | | const HARD_EXIT_ON_FAIL = true |
| | | |
| | | function conditionCheck<T>(name: string, label: 'pre' | 'post', s: T, chk: (x: any) => x is T) { |
| | | if (STRICT_TYPE_CHECKS && !chk(s)) { |
| | | trace(`${name} failed ${label}-condition check: ${s} does not pass ${chk.name}`, new Error()) |
| | | if (HARD_EXIT_ON_FAIL) { |
| | | process.exit(1) |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// Utility type to simulate nominal types in TypeScript |
| | | type SlugLike<T> = string & { __brand: T } |
| | | |
| | | /** Client-side slug, usually obtained through `window.location` */ |
| | | export type ClientSlug = SlugLike<"client"> |
| | | export function isClientSlug(s: string): s is ClientSlug { |
| | | return /^https?:\/\/.+/.test(s) |
| | | const res = /^https?:\/\/.+/.test(s) |
| | | return res |
| | | } |
| | | |
| | | /** Canonical slug, should be used whenever you need to refer to the location of a file/note. |
| | |
| | | */ |
| | | export type CanonicalSlug = SlugLike<"canonical"> |
| | | export function isCanonicalSlug(s: string): s is CanonicalSlug { |
| | | const validStart = s.startsWith("/") |
| | | const validEnding = s.length === 1 || (!s.endsWith("/") && !s.endsWith("/index")) |
| | | return !_containsForbiddenCharacters(s) && validStart && validEnding && !_hasFileExtension(s) |
| | | const validStart = !(s.startsWith(".") || s.startsWith("/")) |
| | | const validEnding = !(s.endsWith("/") || s.endsWith("/index") || s === "index") |
| | | return validStart && !_containsForbiddenCharacters(s) && validEnding && !_hasFileExtension(s) |
| | | } |
| | | |
| | | /** A relative link, can be found on `href`s but can also be constructed for |
| | |
| | | export type RelativeURL = SlugLike<"relative"> |
| | | export function isRelativeURL(s: string): s is RelativeURL { |
| | | const validStart = /^\.{1,2}/.test(s) |
| | | const validEnding = !s.endsWith("/") && !s.endsWith("/index") |
| | | const validEnding = !(s.endsWith("/") || s.endsWith("/index") || s === "index") |
| | | return validStart && validEnding && !_hasFileExtension(s) |
| | | } |
| | | |
| | | /** A server side slug. This is what Quartz uses to emit files so uses index suffixes */ |
| | | export type ServerSlug = SlugLike<"server"> |
| | | export function isServerSlug(s: string): s is ServerSlug { |
| | | // must start with forward slash |
| | | const validStart = s.startsWith("/") |
| | | const validStart = !(s.startsWith(".") || s.startsWith("/")) |
| | | const validEnding = !s.endsWith("/") |
| | | return validStart && validEnding && !_containsForbiddenCharacters(s) && !_hasFileExtension(s) |
| | | } |
| | |
| | | /** The real file path to a file on disk */ |
| | | export type FilePath = SlugLike<"filepath"> |
| | | export function isFilePath(s: string): s is FilePath { |
| | | return s.startsWith("/") && _hasFileExtension(s) |
| | | const validStart = !s.startsWith(".") |
| | | return validStart && _hasFileExtension(s) |
| | | } |
| | | |
| | | export function getClientSlug(window: Window): ClientSlug { |
| | | return window.location.href as ClientSlug |
| | | const res = window.location.href as ClientSlug |
| | | conditionCheck(getClientSlug.name, 'post', res, isClientSlug) |
| | | return res |
| | | } |
| | | |
| | | export function getCanonicalSlug(window: Window): CanonicalSlug { |
| | | return window.document.body.dataset.slug! as CanonicalSlug |
| | | const res = window.document.body.dataset.slug! as CanonicalSlug |
| | | conditionCheck(getCanonicalSlug.name, 'post', res, isCanonicalSlug) |
| | | return res |
| | | } |
| | | |
| | | export function canonicalizeClient(slug: ClientSlug): CanonicalSlug { |
| | | conditionCheck(canonicalizeClient.name, 'pre', slug, isClientSlug) |
| | | const { pathname } = new URL(slug) |
| | | let fp = pathname |
| | | fp = fp.replace(new RegExp(path.extname(fp) + '$'), '') |
| | | return _canonicalize(fp) as CanonicalSlug |
| | | let fp = pathname.slice(1) |
| | | fp = fp.replace(new RegExp(_getFileExtension(fp) + '$'), '') |
| | | const res = _canonicalize(fp) as CanonicalSlug |
| | | conditionCheck(canonicalizeClient.name, 'post', res, isCanonicalSlug) |
| | | return res |
| | | } |
| | | |
| | | export function canonicalizeServer(slug: ServerSlug): CanonicalSlug { |
| | | conditionCheck(canonicalizeServer.name, 'pre', slug, isServerSlug) |
| | | let fp = slug as string |
| | | return _canonicalize(fp) as CanonicalSlug |
| | | const res = _canonicalize(fp) as CanonicalSlug |
| | | conditionCheck(canonicalizeServer.name, 'post', res, isCanonicalSlug) |
| | | return res |
| | | } |
| | | |
| | | export function slugifyFilePath(fp: FilePath): ServerSlug { |
| | | // strip file extension |
| | | const withoutFileExt = fp.replace(new RegExp(path.extname(fp) + '$'), '') |
| | | conditionCheck(slugifyFilePath.name, 'pre', fp, isFilePath) |
| | | fp = _stripSlashes(fp) as FilePath |
| | | const withoutFileExt = fp.replace(new RegExp(_getFileExtension(fp) + '$'), '') |
| | | const slug = withoutFileExt |
| | | .split(path.sep) // fs can have diff interpretations of / |
| | | .split('/') |
| | | .map((segment) => segment.replace(/\s/g, '-')) // slugify all segments |
| | | .join('/') // always use / as sep |
| | | .replace(/\/$/, '') // remove trailing slash |
| | | |
| | | conditionCheck(slugifyFilePath.name, 'post', slug, isServerSlug) |
| | | return slug as ServerSlug |
| | | } |
| | | |
| | | export function transformInternalLink(link: string): RelativeURL { |
| | | let [fplike, anchor] = link.split("#", 2) |
| | | let [fplike, anchor] = splitAnchor(decodeURI(link)) |
| | | let segments = fplike.split("/").filter(x => x.length > 0) |
| | | let prefix = segments.filter(_isRelativeSegment).join("/") |
| | | let fp = "/" + segments.filter(seg => !_isRelativeSegment(seg)).join("/") |
| | | let fp = segments.filter(seg => !_isRelativeSegment(seg)).join("/") |
| | | |
| | | // implicit markdown |
| | | if (!_hasFileExtension(fp)) { |
| | | fp += ".md" |
| | | } |
| | | |
| | | fp = canonicalizeServer(slugifyFilePath(fp as FilePath)) |
| | | |
| | | if (fp.endsWith("index")) { |
| | | fp = fp.slice(0, -"index".length) |
| | | } |
| | | |
| | | let joined = [_stripSlashes(prefix), _stripSlashes(fp)].filter(x => x !== "").join("/") |
| | | anchor = anchor === undefined ? "" : '#' + slugAnchor(anchor) |
| | | return _addRelativeToStart(joined) + anchor as RelativeURL |
| | | let joined = joinSegments(_stripSlashes(prefix), _stripSlashes(fp)) |
| | | const res = _addRelativeToStart(joined) + anchor as RelativeURL |
| | | conditionCheck(transformInternalLink.name, 'post', res, isRelativeURL) |
| | | return res |
| | | } |
| | | |
| | | // resolve /a/b/c to ../../ |
| | | export function pathToRoot(slug: CanonicalSlug): RelativeURL { |
| | | conditionCheck(pathToRoot.name, 'pre', slug, isCanonicalSlug) |
| | | let rootPath = slug |
| | | .split('/') |
| | | .filter(x => x !== '') |
| | | .map(_ => '..') |
| | | .join('/') |
| | | |
| | | return _addRelativeToStart(rootPath) as RelativeURL |
| | | const res = _addRelativeToStart(rootPath) as RelativeURL |
| | | conditionCheck(pathToRoot.name, 'post', res, isRelativeURL) |
| | | return res |
| | | } |
| | | |
| | | export function resolveRelative(current: CanonicalSlug, target: CanonicalSlug): RelativeURL { |
| | | conditionCheck(resolveRelative.name, 'pre', current, isCanonicalSlug) |
| | | conditionCheck(resolveRelative.name, 'pre', target, isCanonicalSlug) |
| | | const res = joinSegments(pathToRoot(current), target) as RelativeURL |
| | | conditionCheck(resolveRelative.name, 'post', res, isRelativeURL) |
| | | return res |
| | | } |
| | | |
| | | export function splitAnchor(link: string): [string, string] { |
| | | let [fp, anchor] = link.split("#", 2) |
| | | anchor = anchor === undefined ? "" : '#' + slugAnchor(anchor) |
| | | return [fp, anchor] |
| | | } |
| | | |
| | | export function joinSegments(...args: string[]): string { |
| | | return args.filter(segment => segment !== "").join('/') |
| | | } |
| | | |
| | | export const QUARTZ = "quartz" |
| | |
| | | fp = fp.slice(0, -"index".length) |
| | | } |
| | | |
| | | // remove trailing slash |
| | | if (fp.endsWith("/")) { |
| | | fp = fp.slice(0, -1) |
| | | } |
| | | |
| | | if (fp.length === 0) { |
| | | return "/" as CanonicalSlug |
| | | } |
| | | |
| | | return fp |
| | | return _stripSlashes(fp) |
| | | } |
| | | |
| | | function _containsForbiddenCharacters(s: string): boolean { |
| | |
| | | } |
| | | |
| | | function _hasFileExtension(s: string): boolean { |
| | | return /\.[A-Za-z]+$/.test(s) |
| | | return _getFileExtension(s) !== undefined |
| | | } |
| | | |
| | | function _getFileExtension(s: string): string | undefined { |
| | | return s.match(/\.[A-Za-z]+$/)?.[0] |
| | | } |
| | | |
| | | function _isRelativeSegment(s: string): boolean { |
| | |
| | | } |
| | | |
| | | if (!s.startsWith(".")) { |
| | | s = "./" + s |
| | | s = joinSegments(".", s) |
| | | } |
| | | |
| | | return s |
| | |
| | | import { CanonicalSlug, FilePath, ServerSlug, relativeToRoot } from "../../path" |
| | | import { CanonicalSlug, FilePath, ServerSlug, canonicalizeServer, resolveRelative } from "../../path" |
| | | import { QuartzEmitterPlugin } from "../types" |
| | | import path from 'path' |
| | | |
| | |
| | | const fps: FilePath[] = [] |
| | | |
| | | for (const [_tree, file] of content) { |
| | | const ogSlug = file.data.slug! |
| | | const ogSlug = canonicalizeServer(file.data.slug!) |
| | | const dir = path.relative(contentFolder, file.dirname ?? contentFolder) |
| | | |
| | | let aliases: CanonicalSlug[] = [] |
| | |
| | | } |
| | | |
| | | for (const alias of aliases) { |
| | | const slug = (alias.startsWith("/") |
| | | ? alias |
| | | : path.posix.join(dir, alias)) as ServerSlug |
| | | const slug = path.posix.join(dir, alias) as ServerSlug |
| | | |
| | | const fp = slug + ".html" as FilePath |
| | | const redirUrl = relativeToRoot(slug, ogSlug) |
| | | const redirUrl = resolveRelative(canonicalizeServer(slug), ogSlug) |
| | | await emit({ |
| | | content: ` |
| | | <!DOCTYPE html> |
| | |
| | | import { GlobalConfiguration } from "../../cfg" |
| | | import { CanonicalSlug, ClientSlug } from "../../path" |
| | | import { CanonicalSlug, ClientSlug, FilePath, ServerSlug, canonicalizeServer } from "../../path" |
| | | import { QuartzEmitterPlugin } from "../types" |
| | | import path from "path" |
| | | |
| | |
| | | return { |
| | | name: "ContentIndex", |
| | | async emit(_contentDir, cfg, content, _resources, emit) { |
| | | const emitted: string[] = [] |
| | | const emitted: FilePath[] = [] |
| | | const linkIndex: ContentIndex = new Map() |
| | | for (const [_tree, file] of content) { |
| | | const slug = file.data.slug! |
| | | const slug = canonicalizeServer(file.data.slug!) |
| | | const date = file.data.dates?.modified ?? new Date() |
| | | if (opts?.includeEmptyFiles || (file.data.text && file.data.text !== "")) { |
| | | linkIndex.set(slug, { |
| | |
| | | if (opts?.enableSiteMap) { |
| | | await emit({ |
| | | content: generateSiteMap(cfg, linkIndex), |
| | | slug: "sitemap", |
| | | slug: "sitemap" as ServerSlug, |
| | | ext: ".xml" |
| | | }) |
| | | emitted.push("sitemap.xml") |
| | | emitted.push("sitemap.xml" as FilePath) |
| | | } |
| | | |
| | | if (opts?.enableRSS) { |
| | | await emit({ |
| | | content: generateRSSFeed(cfg, linkIndex), |
| | | slug: "index", |
| | | slug: "index" as ServerSlug, |
| | | ext: ".xml" |
| | | }) |
| | | emitted.push("index.xml") |
| | | emitted.push("index.xml" as FilePath) |
| | | } |
| | | |
| | | const fp = path.join("static", "contentIndex") |
| | | const fp = path.join("static", "contentIndex") as ServerSlug |
| | | const simplifiedIndex = Object.fromEntries( |
| | | Array.from(linkIndex).map(([slug, content]) => { |
| | | // remove description and from content index as nothing downstream |
| | |
| | | slug: fp, |
| | | ext: ".json", |
| | | }) |
| | | emitted.push(`${fp}.json`) |
| | | emitted.push(`${fp}.json` as FilePath) |
| | | |
| | | return emitted |
| | | }, |
| | |
| | | import BodyConstructor from "../../components/Body" |
| | | import { pageResources, renderPage } from "../../components/renderPage" |
| | | import { FullPageLayout } from "../../cfg" |
| | | import { FilePath } from "../../path" |
| | | import { FilePath, canonicalizeServer } from "../../path" |
| | | |
| | | export const ContentPage: QuartzEmitterPlugin<FullPageLayout> = (opts) => { |
| | | if (!opts) { |
| | |
| | | const fps: FilePath[] = [] |
| | | const allFiles = content.map(c => c[1].data) |
| | | for (const [tree, file] of content) { |
| | | const slug = file.data.slug! |
| | | const slug = canonicalizeServer(file.data.slug!) |
| | | const externalResources = pageResources(slug, resources) |
| | | const componentData: QuartzComponentProps = { |
| | | fileData: file.data, |
| | |
| | | import { ProcessedContent, defaultProcessedContent } from "../vfile" |
| | | import { FullPageLayout } from "../../cfg" |
| | | import path from "path" |
| | | import { FilePath, toServerSlug } from "../../path" |
| | | import { CanonicalSlug, FilePath, ServerSlug, canonicalizeServer, joinSegments } from "../../path" |
| | | |
| | | export const FolderPage: QuartzEmitterPlugin<FullPageLayout> = (opts) => { |
| | | if (!opts) { |
| | |
| | | return [Head, Header, Body, ...header, ...beforeBody, Content, ...left, ...right, Footer] |
| | | }, |
| | | async emit(_contentDir, cfg, content, resources, emit): Promise<FilePath[]> { |
| | | const fps: string[] = [] |
| | | const fps: FilePath[] = [] |
| | | const allFiles = content.map(c => c[1].data) |
| | | |
| | | const folders: Set<string> = new Set(allFiles.flatMap(data => data.slug ? [path.dirname(data.slug)] : [])) |
| | | const folders: Set<CanonicalSlug> = new Set(allFiles.flatMap(data => { |
| | | const slug = data.slug |
| | | const folderName = path.dirname(slug ?? "") as CanonicalSlug |
| | | if (slug && folderName !== ".") { |
| | | return [folderName] |
| | | } |
| | | return [] |
| | | })) |
| | | |
| | | // remove special prefixes |
| | | folders.delete(".") |
| | | folders.delete("tags") |
| | | folders.delete("tags" as CanonicalSlug) |
| | | |
| | | const folderDescriptions: Record<string, ProcessedContent> = Object.fromEntries([...folders].map(folder => ([ |
| | | folder, defaultProcessedContent({ slug: folder, frontmatter: { title: `Folder: ${folder}`, tags: [] } }) |
| | | folder, defaultProcessedContent({ slug: joinSegments(folder, "index") as ServerSlug, frontmatter: { title: `Folder: ${folder}`, tags: [] } }) |
| | | ]))) |
| | | |
| | | for (const [tree, file] of content) { |
| | | const slug = toServerSlug(file.data.slug!) |
| | | const slug = canonicalizeServer(file.data.slug!) |
| | | if (folders.has(slug)) { |
| | | folderDescriptions[slug] = [tree, file] |
| | | } |
| | | } |
| | | |
| | | for (const folder of folders) { |
| | | const slug = folder |
| | | const slug = folder |
| | | const externalResources = pageResources(slug, resources) |
| | | const [tree, file] = folderDescriptions[folder] |
| | | const componentData: QuartzComponentProps = { |
| | |
| | | externalResources |
| | | ) |
| | | |
| | | const fp = file.data.slug + ".html" |
| | | const fp = file.data.slug! + ".html" as FilePath |
| | | await emit({ |
| | | content, |
| | | slug: file.data.slug!, |
| | |
| | | import { pageResources, renderPage } from "../../components/renderPage" |
| | | import { ProcessedContent, defaultProcessedContent } from "../vfile" |
| | | import { FullPageLayout } from "../../cfg" |
| | | import { FilePath, ServerSlug, toServerSlug } from "../../path" |
| | | import { CanonicalSlug, FilePath, ServerSlug } from "../../path" |
| | | |
| | | export const TagPage: QuartzEmitterPlugin<FullPageLayout> = (opts) => { |
| | | if (!opts) { |
| | |
| | | ]))) |
| | | |
| | | for (const [tree, file] of content) { |
| | | const slug = toServerSlug(file.data.slug!) |
| | | const slug = file.data.slug! |
| | | if (slug.startsWith("tags/")) { |
| | | const tag = slug.slice("tags/".length) |
| | | if (tags.has(tag)) { |
| | |
| | | } |
| | | |
| | | for (const tag of tags) { |
| | | const slug = `tags/${tag}` |
| | | const slug = `tags/${tag}` as CanonicalSlug |
| | | const externalResources = pageResources(slug, resources) |
| | | const [tree, file] = tagDescriptions[tag] |
| | | const componentData: QuartzComponentProps = { |
| | |
| | | export async function emitComponentResources(cfg: GlobalConfiguration, res: ComponentResources, emit: EmitCallback): Promise<FilePath[]> { |
| | | const fps = await Promise.all([ |
| | | emit({ |
| | | slug: "index", |
| | | slug: "index" as ServerSlug, |
| | | ext: ".css", |
| | | content: joinStyles(cfg.theme, styles, ...res.css) |
| | | }), |
| | | emit({ |
| | | slug: "prescript", |
| | | slug: "prescript" as ServerSlug, |
| | | ext: ".js", |
| | | content: joinScripts(res.beforeDOMLoaded) |
| | | }), |
| | | emit({ |
| | | slug: "postscript", |
| | | slug: "postscript" as ServerSlug, |
| | | ext: ".js", |
| | | content: joinScripts(res.afterDOMLoaded) |
| | | }) |
| | |
| | | import { QuartzTransformerPlugin } from "../types" |
| | | import { CanonicalSlug, transformInternalLink } from "../../path" |
| | | import { CanonicalSlug, RelativeURL, canonicalizeServer, joinSegments, pathToRoot, resolveRelative, splitAnchor, transformInternalLink } from "../../path" |
| | | import path from "path" |
| | | import { visit } from 'unist-util-visit' |
| | | import isAbsoluteUrl from "is-absolute-url" |
| | |
| | | markdownLinkResolution: 'absolute' | 'relative' | 'shortest' |
| | | /** Strips folders from a link so that it looks nice */ |
| | | prettyLinks: boolean |
| | | indexAnchorLinks: boolean |
| | | indexExternalLinks: boolean |
| | | } |
| | | |
| | | const defaultOptions: Options = { |
| | | markdownLinkResolution: 'absolute', |
| | | prettyLinks: true, |
| | | indexAnchorLinks: false, |
| | | indexExternalLinks: false, |
| | | } |
| | | |
| | | export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => { |
| | |
| | | htmlPlugins() { |
| | | return [() => { |
| | | return (tree, file) => { |
| | | const curSlug = file.data.slug! |
| | | const transformLink = (target: string) => { |
| | | const targetSlug = transformInternalLink(target) |
| | | if (opts.markdownLinkResolution === 'relative' && !path.isAbsolute(targetSlug)) { |
| | | return './' + relative(curSlug, targetSlug) |
| | | const curSlug = canonicalizeServer(file.data.slug!) |
| | | const transformLink = (target: string): RelativeURL => { |
| | | const targetSlug = transformInternalLink(target).slice("./".length) |
| | | let [targetCanonical, targetAnchor] = splitAnchor(targetSlug) |
| | | if (opts.markdownLinkResolution === 'relative') { |
| | | return targetSlug as RelativeURL |
| | | } else if (opts.markdownLinkResolution === 'shortest') { |
| | | // https://forum.obsidian.md/t/settings-new-link-format-what-is-shortest-path-when-possible/6748/5 |
| | | const allSlugs = file.data.allSlugs! |
| | | |
| | | // if the file name is unique, then it's just the filename |
| | | const matchingFileNames = allSlugs.filter(slug => { |
| | | const parts = toServerSlug(slug).split(path.posix.sep) |
| | | const parts = slug.split(path.posix.sep) |
| | | const fileName = parts.at(-1) |
| | | return targetSlug === fileName |
| | | return targetCanonical === fileName |
| | | }) |
| | | |
| | | if (matchingFileNames.length === 1) { |
| | | const targetSlug = toServerSlug(matchingFileNames[0]) |
| | | return './' + relativeToRoot(curSlug, targetSlug) |
| | | const targetSlug = canonicalizeServer(matchingFileNames[0]) |
| | | return resolveRelative(curSlug, targetSlug) + targetAnchor as RelativeURL |
| | | } |
| | | |
| | | // if it's not unique, then it's the absolute path from the vault root |
| | | // (fall-through case) |
| | | } |
| | | |
| | | // treat as absolute |
| | | return './' + relativeToRoot(curSlug, targetSlug) |
| | | return joinSegments(pathToRoot(curSlug), targetSlug) as RelativeURL |
| | | } |
| | | |
| | | const outgoing: Set<CanonicalSlug> = new Set() |
| | |
| | | node.properties && |
| | | typeof node.properties.href === 'string' |
| | | ) { |
| | | let dest = node.properties.href |
| | | let dest = node.properties.href as RelativeURL |
| | | node.properties.className = isAbsoluteUrl(dest) ? "external" : "internal" |
| | | |
| | | // don't process external links or intra-document anchors |
| | | if (!(isAbsoluteUrl(dest) || dest.startsWith("#"))) { |
| | | node.properties.href = transformLink(dest) |
| | | } |
| | | |
| | | dest = node.properties.href |
| | | if (dest.startsWith(".")) { |
| | | const normalizedPath = path.normalize(path.join(curSlug, dest)) |
| | | outgoing.add(trimPathSuffix(normalizedPath)) |
| | | } else if (dest.startsWith("#")) { |
| | | if (opts.indexAnchorLinks) { |
| | | outgoing.add(dest) |
| | | } |
| | | } else { |
| | | if (opts.indexExternalLinks) { |
| | | outgoing.add(dest) |
| | | } |
| | | dest = node.properties.href = transformLink(dest) |
| | | const canonicalDest = path.normalize(joinSegments(curSlug, dest)) |
| | | const [destCanonical, _destAnchor] = splitAnchor(canonicalDest) |
| | | outgoing.add(destCanonical as CanonicalSlug) |
| | | } |
| | | |
| | | // rewrite link internals if prettylinks is on |
| | |
| | | import { QuartzTransformerPlugin } from "../types" |
| | | import { Root, HTML, BlockContent, DefinitionContent, Code } from 'mdast' |
| | | import { findAndReplace } from "mdast-util-find-and-replace" |
| | | import { slugify } from "../../path" |
| | | import { slug as slugAnchor } from 'github-slugger' |
| | | import rehypeRaw from "rehype-raw" |
| | | import { visit } from "unist-util-visit" |
| | |
| | | import { JSResource } from "../../resources" |
| | | // @ts-ignore |
| | | import calloutScript from "../../components/scripts/callout.inline.ts" |
| | | import { FilePath, slugifyFilePath, transformInternalLink } from "../../path" |
| | | |
| | | export interface Options { |
| | | comments: boolean |
| | |
| | | plugins.push(() => { |
| | | return (tree: Root, _file) => { |
| | | findAndReplace(tree, wikilinkRegex, (value: string, ...capture: string[]) => { |
| | | const [fp, rawHeader, rawAlias] = capture |
| | | let [fp, rawHeader, rawAlias] = capture |
| | | fp = fp.trim() |
| | | const anchor = rawHeader?.trim() ?? "" |
| | | const alias = rawAlias?.slice(1).trim() |
| | | |
| | | // embed cases |
| | | if (value.startsWith("!")) { |
| | | const ext = path.extname(fp).toLowerCase() |
| | | const url = slugify(fp.trim()) + ext |
| | | const ext: string | undefined = path.extname(fp).toLowerCase() |
| | | const url = slugifyFilePath(fp as FilePath) + ext |
| | | if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg"].includes(ext)) { |
| | | const dims = alias ?? "" |
| | | let [width, height] = dims.split("x", 2) |
| | |
| | | type: 'html', |
| | | value: `<iframe src="${url}"></iframe>` |
| | | } |
| | | } else { |
| | | // TODO: this is the node embed case |
| | | } |
| | | // otherwise, fall through to regular link |
| | | } |
| | | |
| | | // internal link |
| | | const url = slugify(fp.trim() + anchor) |
| | | // const url = transformInternalLink(fp + anchor) |
| | | const url = fp + anchor |
| | | return { |
| | | type: 'link', |
| | | url, |
| | |
| | | import { visit } from "unist-util-visit" |
| | | import { toString } from "mdast-util-to-string" |
| | | import { slug as slugAnchor } from 'github-slugger' |
| | | import { CanonicalSlug } from "../../path" |
| | | |
| | | export interface Options { |
| | | maxDepth: 1 | 2 | 3 | 4 | 5 | 6, |
| | |
| | | interface TocEntry { |
| | | depth: number, |
| | | text: string, |
| | | slug: CanonicalSlug |
| | | slug: string // this is just the anchor (#some-slug), not the canonical slug |
| | | } |
| | | |
| | | export const TableOfContents: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => { |
| | |
| | | import { StaticResources } from "../resources" |
| | | import { QuartzLogger } from "../log" |
| | | import { googleFontHref } from "../theme" |
| | | import { trace } from "../trace" |
| | | |
| | | function addGlobalPageResources(cfg: GlobalConfiguration, staticResources: StaticResources, componentResources: ComponentResources) { |
| | | staticResources.css.push(googleFontHref(cfg.theme)) |
| | |
| | | } |
| | | } |
| | | } catch (err) { |
| | | console.log(chalk.red(`Failed to emit from plugin \`${emitter.name}\`: `) + err) |
| | | trace(`Failed to emit from plugin \`${emitter.name}\``, err as Error) |
| | | process.exit(1) |
| | | } |
| | | } |
| | |
| | | import { QuartzTransformerPluginInstance } from '../plugins/types' |
| | | import { QuartzLogger } from '../log' |
| | | import chalk from 'chalk' |
| | | import { trace } from '../trace' |
| | | |
| | | export type QuartzProcessor = Processor<MDRoot, HTMLRoot, void> |
| | | export function createProcessor(transformers: QuartzTransformerPluginInstance[]): QuartzProcessor { |
| | |
| | | console.log(`[process] ${fp} -> ${file.data.slug}`) |
| | | } |
| | | } catch (err) { |
| | | console.log(chalk.red(`\nFailed to process \`${fp}\`: `) + err) |
| | | trace(`\nFailed to process \`${fp}\``, err as Error) |
| | | process.exit(1) |
| | | } |
| | | } |
| New file |
| | |
| | | import chalk from "chalk" |
| | | |
| | | const rootFile = /.*at file:/ |
| | | export function trace(msg: string, err: Error) { |
| | | const stack = err.stack |
| | | console.log() |
| | | console.log(chalk.bgRed.white.bold(" ERROR ") + chalk.red(` ${msg}`) + (err.message.length > 0 ? `: ${err.message}` : "")) |
| | | if (!stack) { |
| | | return |
| | | } |
| | | |
| | | let reachedEndOfLegibleTrace = false |
| | | for (const line of stack.split('\n').slice(1)) { |
| | | if (reachedEndOfLegibleTrace) { |
| | | break |
| | | } |
| | | |
| | | if (!line.includes("node_modules")) { |
| | | console.log(` ${line}`) |
| | | if (rootFile.test(line)) { |
| | | reachedEndOfLegibleTrace = true |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | "DOM", |
| | | "DOM.Iterable" |
| | | ], |
| | | "experimentalDecorators": true, |
| | | "module": "esnext", |
| | | "target": "esnext", |
| | | "moduleResolution": "node", |