From 7f040a0afbeb64e05d20ddaeb812446f5431bd22 Mon Sep 17 00:00:00 2001 From: Eric Mika Date: Fri, 7 Jun 2024 12:18:29 -0400 Subject: [PATCH] Split monorepo. Removes remark-mdat. --- .eslintrc.cjs | 2 +- .mdatrc.ts | 14 +- .vscode/settings.json | 11 +- .../mdat-flow-63a3366c-dark.svg | 0 .../mdat-flow-63a3366c-light.svg | 0 .../mdat/assets => assets}/mdat-flow.tldr | 0 package.json | 75 +- packages/mdat/license.txt | 21 - packages/mdat/package.json | 95 -- packages/mdat/readme.md | 821 ------------------ packages/mdat/tsconfig.json | 11 - packages/remark-mdat/license.txt | 21 - packages/remark-mdat/package.json | 76 -- packages/remark-mdat/readme.md | 217 ----- packages/remark-mdat/src/index.ts | 34 - .../lib/mdast-utils/mdast-util-mdat-check.ts | 296 ------- .../lib/mdast-utils/mdast-util-mdat-clean.ts | 72 -- .../lib/mdast-utils/mdast-util-mdat-expand.ts | 119 --- .../lib/mdast-utils/mdast-util-mdat-split.ts | 104 --- .../src/lib/mdast-utils/mdast-util-mdat.ts | 44 - .../src/lib/mdat/deep-merge-defined.ts | 43 - packages/remark-mdat/src/lib/mdat/log.ts | 55 -- packages/remark-mdat/src/lib/mdat/mdat-log.ts | 186 ---- packages/remark-mdat/src/lib/mdat/parse.ts | 199 ----- packages/remark-mdat/src/lib/mdat/rules.ts | 347 -------- packages/remark-mdat/src/lib/remark-mdat.ts | 45 - .../test/__snapshots__/mdat.test.ts.snap | 530 ----------- .../remark-mdat/test/assets/test-document.md | 127 --- .../test/assets/test-rules-invalid.js | 5 - .../remark-mdat/test/assets/test-rules.ts | 56 -- packages/remark-mdat/test/check.test.ts | 244 ------ packages/remark-mdat/test/mdat.test.ts | 169 ---- packages/remark-mdat/test/merge.test.ts | 87 -- packages/remark-mdat/test/parse.test.ts | 524 ----------- packages/remark-mdat/test/split.test.ts | 391 --------- packages/remark-mdat/tsconfig.build.json | 10 - packages/remark-mdat/tsconfig.json | 5 - packages/remark-mdat/tsup.config.ts | 17 - pnpm-lock.yaml | 605 +++++-------- pnpm-workspace.yaml | 2 - readme.md | 793 ++++++++++++++++- {packages/mdat/src => src}/cli/cli.ts | 0 {packages/mdat/src => src}/cli/options.ts | 0 .../mdat/src => src}/cli/readme-options.ts | 0 {packages/mdat/src => src}/lib/api.ts | 0 {packages/mdat/src => src}/lib/config.ts | 0 {packages/mdat/src => src}/lib/index.ts | 0 .../mdat/src => src}/lib/mdat-json-loader.ts | 0 {packages/mdat/src => src}/lib/processors.ts | 0 {packages/mdat/src => src}/lib/readme/api.ts | 0 .../mdat/src => src}/lib/readme/config.ts | 0 {packages/mdat/src => src}/lib/readme/init.ts | 0 .../src => src}/lib/readme/rules/badges.ts | 0 .../src => src}/lib/readme/rules/banner.ts | 0 .../lib/readme/rules/cli-help/index.ts | 0 .../cli-help/utilities/get-help-markdown.ts | 0 .../utilities/help-object-to-markdown.ts | 0 .../utilities/help-string-to-object.ts | 0 .../rules/cli-help/utilities/infer-command.ts | 0 .../rules/cli-help/utilities/parsers/index.ts | 0 .../rules/cli-help/utilities/parsers/meow.ts | 0 .../rules/cli-help/utilities/parsers/yargs.ts | 0 .../mdat/src => src}/lib/readme/rules/cli.ts | 0 .../mdat/src => src}/lib/readme/rules/code.ts | 0 .../lib/readme/rules/contributing.ts | 0 .../lib/readme/rules/description.ts | 0 .../src => src}/lib/readme/rules/footer.ts | 0 .../src => src}/lib/readme/rules/header.ts | 0 .../src => src}/lib/readme/rules/index.ts | 0 .../src => src}/lib/readme/rules/license.ts | 0 .../lib/readme/rules/short-description.ts | 0 .../lib/readme/rules/table-of-contents.ts | 0 .../src => src}/lib/readme/rules/title.ts | 0 .../src => src}/lib/readme/rules/tldraw.ts | 0 .../mdat/src => src}/lib/readme/rules/toc.ts | 0 .../src => src}/lib/readme/templates/index.ts | 0 .../readme/templates/mdat-readme-compound.md | 0 .../lib/readme/templates/mdat-readme.md | 0 .../standard-readme-basic-compound.md | 0 .../readme/templates/standard-readme-basic.md | 0 .../standard-readme-full-compound.md | 0 .../readme/templates/standard-readme-full.md | 0 .../mdat/src => src}/lib/readme/utilities.ts | 0 {packages/mdat/src => src}/lib/utilities.ts | 0 {packages/mdat/src => src}/types/md.d.ts | 0 .../__snapshots__/api.test.ts.snap | 0 .../__snapshots__/cli.test.ts.snap | 0 .../__snapshots__/readme-api.test.ts.snap | 0 .../readme-cli-help-rule.test.ts.snap | 0 {packages/mdat/test => test}/api.test.ts | 0 .../mdat/test => test}/assets/extra-rules.js | 0 .../assets/help-supported/mdat --help.txt | 0 .../help-supported/mdat expand --help.txt | 0 .../help-supported/mdat readme --help.txt | 0 .../mdat readme init --help.txt | 0 .../help-supported/shared-config --help.txt | 0 .../help-supported/tldraw-cli --help.txt | 0 .../tldraw-cli export --help.txt | 0 .../help-supported/tldraw-cli open --help.txt | 0 .../assets/help-unsupported/snip --help.txt | 0 .../mdat/test => test}/assets/mdat.config.ts | 0 .../assets/readme-test-header-footer.md | 0 .../assets/readme-test-invalid.md | 0 .../mdat/test => test}/assets/readme-test.md | 0 .../assets/test-document-malformed.md | 0 .../test => test}/assets/test-document.md | 0 .../mdat/test => test}/assets/test-module.ts | 0 .../assets/test-rules-invalid.js | 0 .../test => test}/assets/test-rules-json.json | 0 .../assets/test-rules-throws-required.js | 0 .../mdat/test => test}/assets/test-rules.ts | 0 .../test => test}/assets/tldraw-sketch.tldr | 0 {packages/mdat/test => test}/cli.test.ts | 0 {packages/mdat/test => test}/config.test.ts | 7 +- .../mdat/test => test}/readme-api.test.ts | 0 .../readme-cli-help-rule.test.ts | 0 .../mdat/test => test}/readme-init.test.ts | 0 .../mdat/test => test}/readme-rules.test.ts | 0 ....build.bin.json => tsconfig.build.bin.json | 0 ....build.lib.json => tsconfig.build.lib.json | 0 tsconfig.json | 5 +- .../mdat/tsup.config.ts => tsup.config.ts | 0 122 files changed, 1062 insertions(+), 5423 deletions(-) rename {packages/mdat/assets => assets}/mdat-flow-63a3366c-dark.svg (100%) rename {packages/mdat/assets => assets}/mdat-flow-63a3366c-light.svg (100%) rename {packages/mdat/assets => assets}/mdat-flow.tldr (100%) delete mode 100644 packages/mdat/license.txt delete mode 100644 packages/mdat/package.json delete mode 100644 packages/mdat/readme.md delete mode 100644 packages/mdat/tsconfig.json delete mode 100644 packages/remark-mdat/license.txt delete mode 100644 packages/remark-mdat/package.json delete mode 100644 packages/remark-mdat/readme.md delete mode 100644 packages/remark-mdat/src/index.ts delete mode 100644 packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-check.ts delete mode 100644 packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-clean.ts delete mode 100644 packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-expand.ts delete mode 100644 packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-split.ts delete mode 100644 packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat.ts delete mode 100644 packages/remark-mdat/src/lib/mdat/deep-merge-defined.ts delete mode 100644 packages/remark-mdat/src/lib/mdat/log.ts delete mode 100644 packages/remark-mdat/src/lib/mdat/mdat-log.ts delete mode 100644 packages/remark-mdat/src/lib/mdat/parse.ts delete mode 100644 packages/remark-mdat/src/lib/mdat/rules.ts delete mode 100644 packages/remark-mdat/src/lib/remark-mdat.ts delete mode 100644 packages/remark-mdat/test/__snapshots__/mdat.test.ts.snap delete mode 100644 packages/remark-mdat/test/assets/test-document.md delete mode 100644 packages/remark-mdat/test/assets/test-rules-invalid.js delete mode 100644 packages/remark-mdat/test/assets/test-rules.ts delete mode 100644 packages/remark-mdat/test/check.test.ts delete mode 100644 packages/remark-mdat/test/mdat.test.ts delete mode 100644 packages/remark-mdat/test/merge.test.ts delete mode 100644 packages/remark-mdat/test/parse.test.ts delete mode 100644 packages/remark-mdat/test/split.test.ts delete mode 100644 packages/remark-mdat/tsconfig.build.json delete mode 100644 packages/remark-mdat/tsconfig.json delete mode 100644 packages/remark-mdat/tsup.config.ts delete mode 100644 pnpm-workspace.yaml rename {packages/mdat/src => src}/cli/cli.ts (100%) rename {packages/mdat/src => src}/cli/options.ts (100%) rename {packages/mdat/src => src}/cli/readme-options.ts (100%) rename {packages/mdat/src => src}/lib/api.ts (100%) rename {packages/mdat/src => src}/lib/config.ts (100%) rename {packages/mdat/src => src}/lib/index.ts (100%) rename {packages/mdat/src => src}/lib/mdat-json-loader.ts (100%) rename {packages/mdat/src => src}/lib/processors.ts (100%) rename {packages/mdat/src => src}/lib/readme/api.ts (100%) rename {packages/mdat/src => src}/lib/readme/config.ts (100%) rename {packages/mdat/src => src}/lib/readme/init.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/badges.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/banner.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/index.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/get-help-markdown.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/help-object-to-markdown.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/help-string-to-object.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/infer-command.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/parsers/index.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/parsers/meow.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli-help/utilities/parsers/yargs.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/cli.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/code.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/contributing.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/description.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/footer.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/header.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/index.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/license.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/short-description.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/table-of-contents.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/title.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/tldraw.ts (100%) rename {packages/mdat/src => src}/lib/readme/rules/toc.ts (100%) rename {packages/mdat/src => src}/lib/readme/templates/index.ts (100%) rename {packages/mdat/src => src}/lib/readme/templates/mdat-readme-compound.md (100%) rename {packages/mdat/src => src}/lib/readme/templates/mdat-readme.md (100%) rename {packages/mdat/src => src}/lib/readme/templates/standard-readme-basic-compound.md (100%) rename {packages/mdat/src => src}/lib/readme/templates/standard-readme-basic.md (100%) rename {packages/mdat/src => src}/lib/readme/templates/standard-readme-full-compound.md (100%) rename {packages/mdat/src => src}/lib/readme/templates/standard-readme-full.md (100%) rename {packages/mdat/src => src}/lib/readme/utilities.ts (100%) rename {packages/mdat/src => src}/lib/utilities.ts (100%) rename {packages/mdat/src => src}/types/md.d.ts (100%) rename {packages/mdat/test => test}/__snapshots__/api.test.ts.snap (100%) rename {packages/mdat/test => test}/__snapshots__/cli.test.ts.snap (100%) rename {packages/mdat/test => test}/__snapshots__/readme-api.test.ts.snap (100%) rename {packages/mdat/test => test}/__snapshots__/readme-cli-help-rule.test.ts.snap (100%) rename {packages/mdat/test => test}/api.test.ts (100%) rename {packages/mdat/test => test}/assets/extra-rules.js (100%) rename {packages/mdat/test => test}/assets/help-supported/mdat --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/mdat expand --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/mdat readme --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/mdat readme init --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/shared-config --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/tldraw-cli --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/tldraw-cli export --help.txt (100%) rename {packages/mdat/test => test}/assets/help-supported/tldraw-cli open --help.txt (100%) rename {packages/mdat/test => test}/assets/help-unsupported/snip --help.txt (100%) rename {packages/mdat/test => test}/assets/mdat.config.ts (100%) rename {packages/mdat/test => test}/assets/readme-test-header-footer.md (100%) rename {packages/mdat/test => test}/assets/readme-test-invalid.md (100%) rename {packages/mdat/test => test}/assets/readme-test.md (100%) rename {packages/mdat/test => test}/assets/test-document-malformed.md (100%) rename {packages/mdat/test => test}/assets/test-document.md (100%) rename {packages/mdat/test => test}/assets/test-module.ts (100%) rename {packages/mdat/test => test}/assets/test-rules-invalid.js (100%) rename {packages/mdat/test => test}/assets/test-rules-json.json (100%) rename {packages/mdat/test => test}/assets/test-rules-throws-required.js (100%) rename {packages/mdat/test => test}/assets/test-rules.ts (100%) rename {packages/mdat/test => test}/assets/tldraw-sketch.tldr (100%) rename {packages/mdat/test => test}/cli.test.ts (100%) rename {packages/mdat/test => test}/config.test.ts (86%) rename {packages/mdat/test => test}/readme-api.test.ts (100%) rename {packages/mdat/test => test}/readme-cli-help-rule.test.ts (100%) rename {packages/mdat/test => test}/readme-init.test.ts (100%) rename {packages/mdat/test => test}/readme-rules.test.ts (100%) rename packages/mdat/tsconfig.build.bin.json => tsconfig.build.bin.json (100%) rename packages/mdat/tsconfig.build.lib.json => tsconfig.build.lib.json (100%) rename packages/mdat/tsup.config.ts => tsup.config.ts (100%) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e1bdb66..fa149a0 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -13,7 +13,7 @@ module.exports = { }, }, { - files: ['packages/mdat/src/cli/**/*'], + files: ['src/cli/**/*'], rules: { 'n/shebang': 'off', }, diff --git a/.mdatrc.ts b/.mdatrc.ts index d209270..5b627b7 100644 --- a/.mdatrc.ts +++ b/.mdatrc.ts @@ -1,10 +1,6 @@ -import { type Config } from './packages/mdat/dist' -import mdatPackage from './packages/mdat/package.json' with { type: 'json' } -import remarkMdatPackage from './packages/remark-mdat/package.json' with { type: 'json' } +import mdatConfig from '@kitschpatrol/mdat-config' +import { mergeConfigs } from 'mdat' -export default { - rules: { - 'mdat-description': `_**${mdatPackage.description}**_`, - 'remark-mdat-description': `_**${remarkMdatPackage.description}**_`, - }, -} satisfies Config +export default mergeConfigs(mdatConfig, { + // Custom mdat config goes here +}) diff --git a/.vscode/settings.json b/.vscode/settings.json index 036107f..eaaee01 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,8 +3,8 @@ "explorer.fileNesting.expand": false, "explorer.fileNesting.patterns": { ".env": ".env.*", - "package.json": ".*.ts, .*.js, .*.json, .*.cjs, .*rc, .*ignore, pnpm-lock.yaml, pnpm-workspace.yaml", - "readme.md": "license*, changelog*" + "package.json": ".*.cjs, .*.js, .*.json, .*.mjs, .*.toml, .*.ts, .*.yaml, .*.yml, .*ignore, .*rc, *config.cjs, *config.js, *config.json, *config.mjs, *config.toml, *config.ts, *config.yaml, *config.yml, lerna.json, netlify.toml, package-lock.json, , pnpm*, turbo.json, vercel.json, workspace*, wrangler.toml, yarn.lock, yarn*", + "readme.md": "authors*, backers*, changelog*, citation*, code_of_conduct*, codeowners*, contributing*, contributors*, copying*, credits*, governance*, history*, license*, maintainers*, release_notes*, security*, sponsors*" }, "cSpell.enabled": true, "cSpell.workspaceRootPath": ".", @@ -22,7 +22,12 @@ }, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, - "prettier.documentSelectors": ["**/.prettierignore", "**/.npmrc", "**/.eslintignore"], + "prettier.documentSelectors": [ + "**/.eslintignore", + "**/.node-version", + "**/.npmrc", + "**/.prettierignore" + ], "prettier.enable": true, "stylelint.enable": true, "stylelint.validate": ["css", "html"] diff --git a/packages/mdat/assets/mdat-flow-63a3366c-dark.svg b/assets/mdat-flow-63a3366c-dark.svg similarity index 100% rename from packages/mdat/assets/mdat-flow-63a3366c-dark.svg rename to assets/mdat-flow-63a3366c-dark.svg diff --git a/packages/mdat/assets/mdat-flow-63a3366c-light.svg b/assets/mdat-flow-63a3366c-light.svg similarity index 100% rename from packages/mdat/assets/mdat-flow-63a3366c-light.svg rename to assets/mdat-flow-63a3366c-light.svg diff --git a/packages/mdat/assets/mdat-flow.tldr b/assets/mdat-flow.tldr similarity index 100% rename from packages/mdat/assets/mdat-flow.tldr rename to assets/mdat-flow.tldr diff --git a/package.json b/package.json index 0b1c4dd..91128d0 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { - "name": "mdat-monorepo", + "name": "mdat", "version": "0.6.16", "type": "module", - "description": "Use comments as dynamic content templates in Markdown files.", + "description": "CLI tool and library implementing the Markdown Autophagic Template (MDAT) system. MDAT lets you use comments as dynamic content templates in Markdown files, making it easy to generate and update readme boilerplate.", "repository": { "type": "git", - "url": "git+https://github.com/kitschpatrol/mdat.git" + "url": "git@github.com:kitschpatrol/mdat.git" }, "homepage": "https://github.com/kitschpatrol/mdat", "bugs": { @@ -18,12 +18,21 @@ "url": "https://ericmika.com" }, "license": "MIT", - "private": true, - "packageManager": "pnpm@9.1.4", + "packageManager": "pnpm@9.2.0+sha512.98a80fd11c2e7096747762304106432b3ddc67dcf54b5a8c01c93f68a2cd5e05e6821849522a06fb76284d41a2660d5e334f2ee3bbf29183bf2e739b1dafa771", "engines": { - "node": ">=16.0.0", + "node": ">=18.0.0", "pnpm": ">=8.0.0" }, + "bin": { + "mdat": "bin/cli.js" + }, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "bin/*", + "dist/*" + ], "keywords": [ "mdat", "markdown", @@ -36,17 +45,57 @@ "npm-package" ], "scripts": { - "build": "pnpm -r run build", + "build": "tsup && tsc -p tsconfig.build.lib.json", "clean": "git clean -fdX && rm ./pnpm-lock.yaml", + "dev": "pnpm run test", "fix": "pnpm shared-config --fix", "lint": "pnpm shared-config --lint", - "mdat": "packages/mdat/bin/cli.js readme && pnpm -r run mdat", - "prepublishOnly": "pnpm run build", - "release": "pnpm bumpp -r --commit 'Release: %s' --tag 'v%s' && pnpm -r build && pnpm -r publish --otp $(op read 'op://Personal/Npmjs/one-time password?attribute=otp')", - "test": "pnpm -r run test --watch=false" + "release": "pnpm bumpp --commit 'Release: %s' --tag 'v%s' && pnpm build && pnpm publish --otp $(op read 'op://Personal/Npmjs/one-time password?attribute=otp')", + "test": "vitest --no-file-parallelism" + }, + "dependencies": { + "@clack/prompts": "^0.7.0", + "@kitschpatrol/tldraw-cli": "^4.5.4", + "@types/mdast": "^4.0.4", + "@types/node": "^20.14.2", + "@types/unist": "^3.0.2", + "@types/which": "^3.0.4", + "@types/yargs": "^17.0.32", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^5.0.0", + "execa": "^9.2.0", + "globby": "^14.0.1", + "read-pkg": "^9.0.1", + "which": "^4.0.0" }, "devDependencies": { - "@kitschpatrol/shared-config": "^4.6.6", - "bumpp": "^9.4.1" + "@kitschpatrol/shared-config": "^4.6.7", + "bumpp": "^9.4.1", + "chalk": "^5.3.0", + "chevrotain": "^11.0.3", + "find-up": "^7.0.0", + "is-executable": "^2.0.1", + "mdast-util-toc": "^7.1.0", + "nanoid": "^5.0.7", + "package-up": "^5.0.0", + "path-type": "^5.0.0", + "pkg-dir": "^8.0.0", + "plur": "^5.1.0", + "pretty-ms": "^9.0.0", + "remark": "^15.0.1", + "remark-gfm": "^4.0.0", + "remark-mdat": "^0.7.0", + "to-vfile": "^8.0.0", + "tsup": "^8.1.0", + "type-fest": "^4.20.0", + "typescript": "^5.4.5", + "untildify": "^5.0.0", + "vfile": "^6.0.1", + "vitest": "^1.6.0", + "yargs": "^17.7.2", + "zod": "^3.23.8" + }, + "publishConfig": { + "access": "public" } } diff --git a/packages/mdat/license.txt b/packages/mdat/license.txt deleted file mode 100644 index f4944a6..0000000 --- a/packages/mdat/license.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 Eric Mika - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/mdat/package.json b/packages/mdat/package.json deleted file mode 100644 index e2a4c83..0000000 --- a/packages/mdat/package.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "name": "mdat", - "version": "0.6.16", - "type": "module", - "description": "CLI tool and library implementing the Markdown Autophagic Template (MDAT) system. MDAT lets you use comments as dynamic content templates in Markdown files, making it easy to generate and update readme boilerplate.", - "repository": { - "type": "git", - "url": "git@github.com:kitschpatrol/mdat.git", - "directory": "packages/mdat" - }, - "bugs": { - "url": "https://github.com/kitschpatrol/mdat/issues", - "email": "eric@ericmika.com" - }, - "author": { - "name": "Eric Mika", - "email": "eric@ericmika.com", - "url": "https://ericmika.com" - }, - "license": "MIT", - "engines": { - "node": ">=18.0.0", - "pnpm": ">=8.0.0" - }, - "bin": { - "mdat": "bin/cli.js" - }, - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "bin/*", - "dist/*" - ], - "keywords": [ - "mdat", - "markdown", - "template", - "comments", - "docs-generator", - "docs", - "cli" - ], - "scripts": { - "build": "tsup && tsc -p tsconfig.build.lib.json", - "dev": "pnpm run test", - "mdat": "./bin/cli.js readme --config ../../.mdatrc.ts", - "prepublishOnly": "pnpm run build", - "pretest": "pnpm run build", - "test": "vitest --no-file-parallelism" - }, - "dependencies": { - "@clack/prompts": "^0.7.0", - "@kitschpatrol/tldraw-cli": "^4.5.4", - "@types/mdast": "^4.0.4", - "@types/node": "^20.14.1", - "@types/unist": "^3.0.2", - "@types/which": "^3.0.4", - "@types/yargs": "^17.0.32", - "cosmiconfig": "^9.0.0", - "cosmiconfig-typescript-loader": "^5.0.0", - "execa": "^9.1.0", - "globby": "^14.0.1", - "read-pkg": "^9.0.1", - "which": "^4.0.0" - }, - "devDependencies": { - "chalk": "^5.3.0", - "chevrotain": "^11.0.3", - "find-up": "^7.0.0", - "is-executable": "^2.0.1", - "mdast-util-toc": "^7.1.0", - "nanoid": "^5.0.7", - "package-up": "^5.0.0", - "path-type": "^5.0.0", - "pkg-dir": "^8.0.0", - "plur": "^5.1.0", - "pretty-ms": "^9.0.0", - "remark": "^15.0.1", - "remark-gfm": "^4.0.0", - "remark-mdat": "workspace:*", - "to-vfile": "^8.0.0", - "tsup": "^8.1.0", - "type-fest": "^4.19.0", - "typescript": "^5.4.5", - "untildify": "^5.0.0", - "vfile": "^6.0.1", - "vitest": "^1.6.0", - "yargs": "^17.7.2", - "zod": "^3.23.8" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/mdat/readme.md b/packages/mdat/readme.md deleted file mode 100644 index 9bbe004..0000000 --- a/packages/mdat/readme.md +++ /dev/null @@ -1,821 +0,0 @@ - - - - -# mdat - -[![NPM Package mdat](https://img.shields.io/npm/v/mdat.svg)](https://npmjs.com/package/mdat) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - -**CLI tool and library implementing the Markdown Autophagic Template (MDAT) system. MDAT lets you use comments as dynamic content templates in Markdown files, making it easy to generate and update readme boilerplate.** - - - - - -## Table of contents - -- [Overview](#overview) -- [Getting started](#getting-started) - - [Dependencies](#dependencies) - - [Installation](#installation) -- [Features](#features) -- [Usage](#usage) - - [CLI](#cli) - - [API](#api) - - [Configuration](#configuration) - - [Creating custom rules](#creating-custom-rules) - - [The `mdat readme` subcommand](#the-mdat-readme-subcommand) -- [Background](#background) - - [Motivation](#motivation) - - [Similar projects](#similar-projects) -- [The future](#the-future) -- [Maintainers](#maintainers) -- [Acknowledgments](#acknowledgments) -- [Contributing](#contributing) -- [License](#license) - - - -## Overview - -This is a CLI tool and library implementing the Markdown Autophagic Template (MDAT) system, which makes it easy to automate the replacement of placeholder comments in Markdown documents with dynamic content from a variety of sources. The `mdat` command can also validate the structure and content of the Markdown document based on constraints specified in the expansion rules, and bundles numerous convenient expansion rules for working with `readme.md` files under the `mdat readme` subcommand. - - - - - - - tldraw diagram - - - - -A trivial example... - -Given placeholder comments in a Markdown file like this: - -`some-file.md` - -```md - -``` - -Run your file through the tool: - -```sh -mdat readme some-file.md -``` - -To turn it into: - -`some-file.md` - -```md - - -# mdat - - -``` - -In this case, according to a set of rules defined in an external configuration file, `` was replaced with date from `package.json`. The rule system behind these expansions is simple to define and readily extensible beyond the trivial example above. - -## Getting started - -### Dependencies - -The `mdat` CLI tool requires Node 16+. The exported APIs for expanding Markdown text and documents are ESM-only and share the Node 16+ requirement. `mdat` is implemented in TypeScript and bundles a complete set of type definitions. - -### Installation - -Install locally to access the CLI commands in a single project or to import the provided APIs: - -```sh -npm install remark-mdat -``` - -Or, install globally for access across your system: - -```sh -npm install --global remark-mdat -``` - -## Features - -As [noted below](#similar-projects), there are several similar projects out there. This overlap is mostly the result of my mediocre due diligence before starting development, but there remain a few distinguishing aspects of this particular implementation of the idea: - -1. **Minimalist syntax** - - No screaming caps or wordy opening and closing tag keywords, just a minimal HTML-esque syntax: - - ```md - - - # mdat - - - ``` - - (Optionally, you can specify a prefix if you want to mix "true" comments with MDAT content placeholder comments.) - -2. **Single-comment placeholders** - - When you're roughing out a readme, you can drop in a single opening comment, and `mdat` will take care of expanding it and adding the closing tag the next time it's run. To generate the block shown above, you'd need only to add: - - ```md - - ``` - -3. **Familiar JSON arguments** - - In the rare instances when you want to pass extra data or configuration into a comment template, you just use a bit of JSON. No need to grok a custom syntax: - - ```md - - ``` - - Internally, comment option arguments are parsed with [JSON5](https://json5.org), so you can skip quoting keys if you like. A pre-parsing step adds another layer of leniency if you want to skip the brackets or include parentheses to pretend your keyword is a function. The expansion rules included with the `mdat readme` subcommand use [Zod](https://zod.dev) to validate the option arguments and provide helpful errors at runtime. - -4. **Flexible rule system** - - Comment expansions definitions are referred to as "rules". - - An expansion rule can be as minimal as a file exporting a record: - - ```ts - { keyword: "content"}` - ``` - - Which will turn: - - ```md - - ``` - - Into: - - ```md - - - content - - - ``` - - Or, make things a bit more dynamic by returning a function instead of a string. Async functions are welcome. - - ```ts - { date: () => `${new Date().toISOString()}` } }" - ``` - - Or enforce validation by adding some metadata: - - ```ts - { - date: { - content: () => `${new Date().toISOString()}`, - order: 1, - required: true, - }, - } - ``` - - This scales all the way up to some of the [more](./src/lib/readme/rules/table-of-contents.ts) [elaborate](./src/lib/readme/rules/cli-help) rules found in the `mdat readme` subcommand. - - You can also treat any JSON file as a rule set. MDAT will flatten it to allow any dot-notated key path to become a placeholder comment keyword. - -5. **TypeScript native** - - MDAT exports definitions for rule types, and configuration / rule sets may be written directly in TypeScript. - -6. **Validation** - - In addition to content replacement, individual rules can define validation constraints. `mdat` includes a `--check` option which runs your expanded Markdown through a validator to enforce the presence and order of appearance of your comment placeholders. - -7. **Compound rules** - - It's easy to create "compound" expansion rules that encapsulate a number of other individual rules into a single Markdown comment to keep the quantity of template comments in check. - - See the [``](./src/lib/readme/rules/header.ts) rule in the `mdat readme` subcommand for an example. - -8. **Single-command readme workflow** - - MDAT's most typical use case is streamlined with the `mdat readme` subcommand. Invoking this CLI command in your repo will automatically find your readme and your package.json and provide access to a collection of bundled expansion rules. - - It also provides the `mdat readme init` subcommand with a selection of templates to kick off a fresh readme from scratch in a new project. - -## Usage - -> \[!WARNING]\ -> **The MDAT CLI tool directly manipulates the contents of readme files, in close (and perhaps dangerous) proximity to your painstakingly crafted words.** -> -> Please make sure any text you care about is committed before running `mdat`, and never directly modify content inside of the comment expansion blocks. -> -> Set the `--meta` flag on the command to add a warning comment to the top of your file explaining the extra caution demanded around the volatile automated sections of your readme.md. - -### CLI - - - -#### Command: `mdat` - -Work with MDAT placeholder comments in any Markdown file. - -This section lists top-level commands for `mdat`. - -If no command is provided, `mdat expand` is run by default. - -Usage: - -```txt -mdat [command] -``` - -| Command | Argument | Description | -| ---------- | ----------------------- | -------------------------------------------------------------- | -| `expand` | `` `[options]` | Expand MDAT placeholder comments. _(Default command.)_ | -| `check` | `` `[options]` | Validate a Markdown file containing MDAT placeholder comments. | -| `collapse` | `` `[options]` | Collapse MDAT placeholder comments. | -| `readme` | `[command]` | Work with MDAT comments in your readme.md. | - -_See the sections below for more information on each subcommand._ - -#### Subcommand: `mdat expand` - -Expand MDAT placeholder comments. - -Usage: - -```txt -mdat expand [options] -``` - -| Positional Argument | Description | Type | -| ------------------- | -------------------------------------------------------------- | -------- | -| `files` | Markdown file(s) with MDAT placeholder comments. _(Required.)_ | `string` | - -| Option | Alias | Description | Type | Default | -| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | -| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | -| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | -| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | -| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | -| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | -| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | -| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - -#### Subcommand: `mdat check` - -Validate a Markdown file containing MDAT placeholder comments. - -Usage: - -```txt -mdat check [options] -``` - -| Positional Argument | Description | Type | -| ------------------- | -------------------------------------------------------------- | -------- | -| `files` | Markdown file(s) with MDAT placeholder comments. _(Required.)_ | `string` | - -| Option | Alias | Description | Type | Default | -| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | -| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | -| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | -| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | -| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - -#### Subcommand: `mdat collapse` - -Collapse MDAT placeholder comments. - -Usage: - -```txt -mdat collapse [options] -``` - -| Positional Argument | Description | Type | -| ------------------- | -------------------------------------------------------------- | -------- | -| `files` | Markdown file(s) with MDAT placeholder comments. _(Required.)_ | `string` | - -| Option | Alias | Description | Type | Default | -| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | -| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | -| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | -| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | -| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | -| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - -#### Subcommand: `mdat readme` - -Work with MDAT comments in your readme.md. - -This section lists top-level commands for `mdat readme`. - -If no command is provided, `mdat readme expand` is run by default. - -Usage: - -```txt -mdat readme [command] -``` - -| Command | Argument | Description | -| ----------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| `readme expand` | `[files..]` `[options]` | Expand MDAT comment placeholders in your readme.md using a collection of helpful built-in expansion rules. _(Default command.)_ | -| `readme check` | `[files..]` `[options]` | Validate MDAT placeholder comments in your readme.md. | -| `readme collapse` | `[files..]` `[options]` | Collapse MDAT placeholder comments in your readme.md. | -| `readme init` | `[options]` | Interactively create a new readme.md file with sensible default MDAT comment placeholders. | - -_See the sections below for more information on each subcommand._ - -#### Subcommand: `mdat readme expand` - -Expand MDAT comment placeholders in your readme.md using a collection of helpful built-in expansion rules. - -Usage: - -```txt -mdat readme expand [files..] [options] -``` - -| Positional Argument | Description | Type | -| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | -| `files` | Readme file(s) with MDAT placeholder comments. If not provided, the closest readme.md file is used. _(Optional.)_ | `string` | - -| Option | Alias | Description | Type | Default | -| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | -| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | -| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | -| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | -| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | -| `--package` | | Path to the package.json file to use to populate the readme. | `string` | The closest package.json file is used by default. | -| `--assets` | | Path to find and save readme-related assets. | `string` | `./assets` | -| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | -| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | -| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - -#### Subcommand: `mdat readme check` - -Validate MDAT placeholder comments in your readme.md. - -Usage: - -```txt -mdat readme check [files..] [options] -``` - -| Positional Argument | Description | Type | -| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | -| `files` | Readme file(s) with MDAT placeholder comments. If not provided, the closest readme.md file is used. _(Optional.)_ | `string` | - -| Option | Alias | Description | Type | Default | -| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | -| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | -| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | -| `--package` | | Path to the package.json file to use to populate the readme. | `string` | The closest package.json file is used by default. | -| `--assets` | | Path to find and save readme-related assets. | `string` | `./assets` | -| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | -| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - -#### Subcommand: `mdat readme collapse` - -Collapse MDAT placeholder comments in your readme.md. - -Usage: - -```txt -mdat readme collapse [files..] [options] -``` - -| Positional Argument | Description | Type | -| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | -| `files` | Readme file(s) with MDAT placeholder comments. If not provided, the closest readme.md file is used. _(Optional.)_ | `string` | - -| Option | Alias | Description | Type | Default | -| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | -| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | -| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | -| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | -| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | -| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - -#### Subcommand: `mdat readme init` - -Interactively create a new readme.md file with sensible default MDAT comment placeholders. - -Usage: - -```txt -mdat readme init [options] -``` - -| Option | Alias | Description | Type | Default | -| --------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------------- | -| `--interactive` | `-i` | Run the guided interactive `init` process. Set explicitly to `false` to use default values and skip the prompt. | `boolean` | `true` | -| `--overwrite` | | Replace an existing readme file if one is found. | `boolean` | `false`, if an existing readme is found, don't touch it. | -| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | -| `--expand` | `-e` | Automatically run `mdat readme` immediately after creating the readme template. | `boolean` | `true` | -| `--template` | `-t` | Specify a template to use for the new readme. | `string` | "MDAT Readme" | -| `--compound` | `-c` | Use compound comment version of the template to replace several individual comment placeholders where possible. This combines things like ``, ``, etc. in a single `` comment. It's less clutter when you're editing, but it's also less explicit. The final readme.md output is identical. | `boolean` | `true` | -| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | -| `--help` | `-h` | Show help | `boolean` | | -| `--version` | `-v` | Show version number | `boolean` | | - - - -_Meta note: The entire section above was generated automatically by the [``](./src/lib/readme/rules/cli-help/index.ts) mdat expansion rule provided in `mdat readme` subcommand. It dynamically parses the output from `mdat --help` into a Markdown table, recursively calling `--help` on subcommands to build a tidy representation of the help output._ - -#### Examples - -##### Basic - -Expand comments in a single Markdown file in-place: - -```sh -mdat your-file.md -``` - -##### Multi-file - -Expand comments in multiple Markdown files: - -```sh -mdat *.md -``` - -##### Custom configuration - -A number of option flags are exposed on the CLI. Any values set here will override both ambient configuration files and any configuration file referenced passed as options: - -```sh -mdat --prefix 'mm- -``` - -##### Custom configuration file - -```sh -mdat --config 'custom-config.ts" -``` - -##### Rule sets - -```sh -mdat --rules 'rules.ts' 'more-rules.js' 'yet-more-rules.json' -``` - -##### Readme expansion - -Expand MDAT comments in your readme.md: - -```sh -mdat readme -``` - -##### Validation - -Check your readme.md for validation errors, without modifying it: - -```sh -mdat readme check -``` - -##### Additional rules - -Additional rules may be defined in a configuration file, or passed explicitly to most `mdat` commands via the `--rules` flag: - -```sh -mdat readme --rules rules.ts more-rules.js yet-more-rules.json -``` - -#### Create a starter readme from scratch - -```sh -mdat readme init -``` - -### API - -`mdat` exports a collection of functions to abstract the process of expanding placeholder comments into a single call. Type aliases are also provided. - -Highlights include: - -#### Expand String - -```ts -function expandString(markdown: string, config?: ConfigToLoad, rules?: RulesToLoad): Promise -``` - -Takes a string of Markdown and returns. Note that the returned object is a [VFile](https://github.com/vfile), which includes both the post-conversion Markdown content and additional metadata about the conversion. - -To get the Markdown content, simply call `.toString()` on the returned VFile object. - -#### Expand File - -```ts -function expandFile( - file: string, - name?: string, - output?: string, - config?: ConfigToLoad, - rules?: RulesToLoad, -): Promise -``` - -Similar to `expandString()`, but takes a file path and handles setting an optional destination path and file name. - -It's up to the caller to actually save the returned VFile object. The [to-vfile](https://www.npmjs.com/package/to-vfile) library can make this particularly painless: - -```ts -import { expandFile } from 'mdat' -import { write } from 'to-vfile' - -const file = await expandFiles(...) -await write(file) -``` - -#### Expand Files - -```ts -function expandFiles( - files: string[], - name?: string, - output?: string, - config?: ConfigToLoad, - rules?: RulesToLoad, -): Promise -``` - -Like `expandFile()`, but accepts an array of inputs. If an output name is specified, the output files are suffixed with a number to prevent name collisions. - -#### Load Config - -```ts -function loadConfig(options?: { - additionalConfig?: ConfigToLoad // file paths or config objects - additionalRules?: RulesToLoad // file paths or rule objects - searchFrom?: string -}): Promise // returns a single merged config object -``` - -This is provided for more advanced use cases. It assists in discovering and loading ambient configuration in your project (e.g. fields in your package.json, or dedicated `mdat` config files). It also dynamically loads, validates, and merges additional `mdat` configuration and rule files into a final `ConfigLoaded` object ready to be passed into the [`remark-mdat`](../remark-mdat/readme.md) plugin or one of the API functions like `expandFile()`. - -#### Examples - -### Configuration - -Expansion rules and certain aspects of global configuration are defined in configuration files which may be discovered automatically by `mdat`, or explicitly provided via command line options or library function arguments as shown above. - -`mdat` implements configuration loading via [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig), which means a variety of configuration [locations](https://github.com/cosmiconfig/cosmiconfig?tab=readme-ov-file#searchplaces) and file formats are supported. Configuration may be defined directly in your package.json, or in addition to stand-alone TypeScript files, JavaScript files, YAML, JSON, etc. - -TypeScript or JavaScript with JSDoc annotations are recommended for the most flexibility and ease of implementing more advanced rules. - -`mdat` also allows arbitrary JSON files to be loaded as rule sets, flattening them so any value may be accessed by using a dot-notation key path as a comment keyword. - -#### Configuration file format - -The `mdat` configuration file is a record object allowing you to customize aspects of the comment expansion process, and also optionally define expansion rules as well under the `rules` key: - -```ts -type Config = { - assetsPath?: string // where asset-generating rules should store their output, defaults to './assets' - packageFile?: string // used by readme rules, found dynamically if undefined - addMetaComment?: boolean // defaults to true - closingPrefix?: string // defaults to '/' - keywordPrefix?: string // defaults to '' - metaCommentIdentifier?: string // defaults to '+' - rules?: Rules -} -``` - -A valid configuration file default-exports an object conforming to the above type. - -The configuration file may be located in any location supported by [cosmicconfig](https://github.com/cosmiconfig/cosmiconfig?tab=readme-ov-file#searchplaces). I use an `.mdatrc.ts` file in the root of my projects. - -#### Rule file format - -Rules may also be defined in separate files that default-export a record of rules. The record keys become the keywords used to reference a rule from your comments in Markdown. - -```ts -type Rules = Record - -type Rule = - | string - | ((options: JsonValue, tree: Root) => Promise | string) - | Rule[] - | { - content: string | Rule[] | ((options: JsonValue, tree: Root) => Promise | string) - applicationOrder?: number | undefined - order?: number | undefined - required?: boolean | undefined - } -``` - -This is a bit complex, but it's intended to make defining simple rules simple, while still accommodating more demanding use cases. - -Some notes on the type: - -- Simple rules can be defined directly on the key, either as strings to replace the comment placeholder, or as sync or async functions returning a string. - -- If you need more advanced rules, or wish to define conditions for the validation process, you break the top-level keyword key's value out into an object, where a `content` key on the object is responsible for returning the replacement string, and additional fields are available to define validation constraints. - -- Note that `content` can itself take an array of Rule objects, which is useful for creating "compound" rules that combine several others into a single comment keyword. - -Since it's a record, multiple rules may be combined in single rules file. - -If multiple configuration and rule files are loaded, they are merged. CLI options take precedence over ambient configuration discovered by cosmicconfig, and where multiple configuration or rule files are provided, with the "last" rule of a particular key takes precedence. - -### Creating custom rules - -The underlying rule expansion system is flexible and easy to extend. - -See the [Examples section](../remark-mdat/readme.md#examples) of the `remark-mdat` readme, or take a look at the implementation of the [rules provided through the `mdat readme` subcommand](./src/lib/readme/rules/) for more complex examples. - -### The `mdat readme` subcommand - -#### Bundled rules - -##### Stand-alone: - -- ###### `` - - The `name` field from `package.json`. - -- ###### `` - - Looks for an image in the `/assets` folder for use as a banner image. Searches for a number of typical names and formats. (The assets path may be specified through configuration files or command line flags.) - -- ###### `` - - Generates badges based on `package.json`. Currently only supports license and NPM version badges. - -- ###### `` - - The `description` field from `package.json`. - - This rule is also aliased under the `` keyword, for consistency with the [standard-readme](https://github.com/RichardLitt/standard-readme/blob/main/spec.md#short-description) spec. - -- ###### `` - - A table of contents automatically generated by [mdast-util-toc](https://github.com/syntax-tree/mdast-util-toc). - - This rule is also aliased under the `` keyword, if you're into the brevity thing. - -- ###### `` - - Invites issues and pull request, generating links based on `package.json`. - -- ###### `` - - Documents the project's license, based on the `license` field from `package.json`. - -- ###### `` - - A quick way to embed a code block from elsewhere in your repository. Useful for examples. - -- ###### `` - - Automatically transform a CLI command's `--help` output into nicely formatted Markdown tables. The rule also recursively calls `--help` on any subcommands found for inclusion in the output. - - Currently, the rule can only parse help output in the format provided by [Yargs](https://yargs.js.org)- and [Meow](https://github.com/sindresorhus/meow)-based tools. If parsing fails, the rule will fall back to show the raw help output in a regular code block. - - ([Parsing help output](https://github.com/kitschpatrol/mdat/tree/main/packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers) is a bit tricky. The [jc](https://github.com/kellyjonbrazil/jc) project is a heroic collection of output parsers, but does not currently implement help output parsing. It might be interesting to try to contribute mdat's help parsing implementations to jc.) - - This rule is also aliased under the `` keyword. - -- ###### `` - - Allows embedding [tldraw](https://www.tldraw.com) files in your readme. Accepts either a path to a local `.tldr` file, or remote tldraw URLs. - - Automatically generates both "light" and "dark" SVG variations of the sketch, and emits a `` element per [GitHub's guidelines](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#specifying-the-theme-an-image-is-shown-to) to present the correctly themed image based on the viewer's preferences. - - Generated assets are intelligently hashed to aide in cache busting. For locally referenced files, the image will only be regenerated when the content in the source file changes. - - The implementation is based on [@kitschpatrol/tldraw-cli](https://github.com/kitschpatrol/tldraw-cli), and depends on Puppeteer to generate the assets, so it can be a bit slow. Referencing local files instead of remote URLs is recommended for improved performance. - - This rule is used to embed the diagram at the top of this readme. - -##### Compound - -Compound rules combine several stand-alone rules under a single keyword, which can help reduce comment clutter in your readme's Markdown. - -- ###### `` - - Combines a number of rules often applied at the top of a readme into a single keyword. This rule is the equivalent of: - - ```md - - - - - ``` - -- ###### `` - - Bundles together rules often applied at the end of a readme. Just two rules at the moment: - - ```md - - - ``` - -#### Bundled templates - -The `init` command provides a number of "starter readme" templates incorporating MDAT comment placeholders: - -- ##### MDAT Readme - - The house style. An expansive starting point. Prune to your context and taste. The readme files in this monorepo started from this template. - -- ##### Standard Readme basic - - Includes only the "required" sections from the [Standard Readme](https://github.com/RichardLitt/standard-readme/blob/main/spec.md) specification. [See an example](https://github.com/RichardLitt/standard-readme/blob/main/example-readmes/minimal-readme.md). - -- ##### Standard Readme full - - Includes all sections from the [Standard Readme](https://github.com/RichardLitt/standard-readme/blob/main/spec.md) specification. [See an example](https://github.com/RichardLitt/standard-readme/blob/main/example-readmes/maximal-readme.md). - -## Background - -### Motivation - -A package definition file like `package.json` is the canonical "single source of truth" for a project's metadata. Yet fragments of this metadata end up duplicated elsewhere, most prominently in the readme. Keeping them in sync is a pain. - -You could set up a separate readme template file and use one of a to generate your readme, but then you'd still have to wire up data ingestion and deal with and the cognitive clutter of a second half-baked readme in your repo. - -MDAT solves this tedium by committing a minor sacrilege: It allows comments in Markdown files to become placeholders for dynamic content, overwriting themselves in place with content pulled from around your repo. When `mdat` is run against the file, specific comments are expanded with content from elsewhere, the file is updated in-situ. - -I wrote it for use in my own projects, but if someone else finds it useful, that's great. - -### Similar projects - -This has been done several times before: - -- Benjamin Lupton's [projectz](https://github.com/bevry/projectz)\ - Goes way back. - -- David Wells' [Markdown Magic](https://github.com/DavidWells/markdown-magic)\ - I somehow missed the existence of this one until after building out MDAT. It's very similar conceptually, and has a nice ecosystem of plugins. - -- Titus Wormer's [mdast-zone](https://github.com/syntax-tree/mdast-zone)\ - Allows comments to be used as ranges or markers in Markdown files. Similar tree parsing and walking strategy to MDAT. Mdast-zone uses different syntax for arguments, and requires both opening and closing tags to be present for expansion to occur. - -- lillallol's [md-in-place](https://www.npmjs.com/package/md-in-place) - -## The future - -Additional rules: - -- Support embedding code documentation snippets via [typedoc](https://github.com/TypeStrong/typedoc) + [typedoc-plugin-markdown](https://github.com/tgreyuk/typedoc-plugin-markdown). -- Support line ranges i the `` rule. - -Improved documentation: - -- Describe available rule options. -- More details on defining custom rules. - -Recommended workflow integration approach: - -- Invoke via hooks / GitHub actions? - -## Maintainers - -[@kitschpatrol](https://github.com/kitschpatrol) - -## Acknowledgments - -- The [unified](https://unifiedjs.com), [remark](https://remark.js.org), and [unist](https://github.com/syntax-tree/unist) / [mdast](https://github.com/syntax-tree/mdast) ecosystem is powerful and well-architected. MDAT relies on it to do the the heavy lifting in of parsing, transforming, and restoring the Markdown to string form. - -- Richard Litt's [Standard Readme](https://github.com/RichardLitt/standard-readme) specification inspired some of the templates available in `mdat readme init`. - - - -## Contributing - -[Issues](https://github.com/kitschpatrol/mdat/issues) and pull requests are welcome. - -## License - -[MIT](license.txt) © Eric Mika - - diff --git a/packages/mdat/tsconfig.json b/packages/mdat/tsconfig.json deleted file mode 100644 index b52cdd9..0000000 --- a/packages/mdat/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../tsconfig.json", - - "compilerOptions": { - /* Markdown */ - "types": ["./src/types/md.d.ts"] - }, - - "include": ["**/*", "**.*"], - "exclude": ["dist"] -} diff --git a/packages/remark-mdat/license.txt b/packages/remark-mdat/license.txt deleted file mode 100644 index f4944a6..0000000 --- a/packages/remark-mdat/license.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 Eric Mika - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/remark-mdat/package.json b/packages/remark-mdat/package.json deleted file mode 100644 index e82149c..0000000 --- a/packages/remark-mdat/package.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "name": "remark-mdat", - "version": "0.6.16", - "type": "module", - "description": "A remark plugin implementing the Markdown Autophagic Template (MDAT) system.", - "repository": { - "type": "git", - "url": "git@github.com:kitschpatrol/mdat.git", - "directory": "packages/remark-mdat" - }, - "bugs": { - "url": "https://github.com/kitschpatrol/mdat/issues", - "email": "eric@ericmika.com" - }, - "author": { - "name": "Eric Mika", - "email": "eric@ericmika.com", - "url": "https://ericmika.com" - }, - "license": "MIT", - "engines": { - "node": ">=16.0.0", - "pnpm": ">=8.0.0" - }, - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "dist/*" - ], - "keywords": [ - "mdat", - "markdown", - "template", - "comments", - "unist", - "mdast", - "mdast-util", - "syntax-tree", - "remark", - "remark-plugin" - ], - "scripts": { - "build": "tsup && tsc -p tsconfig.build.json", - "dev": "pnpm run test", - "mdat": "../mdat/bin/cli.js readme --config ../../.mdatrc.ts", - "prepublishOnly": "pnpm run build", - "test": "vitest" - }, - "dependencies": { - "@types/mdast": "^4.0.4", - "@types/node": "^20.14.1", - "@types/unist": "^3.0.2" - }, - "devDependencies": { - "chalk": "^5.3.0", - "cli-table3": "^0.6.5", - "deepmerge-ts": "^7.0.2", - "hast-util-from-html": "^2.0.1", - "json5": "^2.2.3", - "remark": "^15.0.1", - "remark-gfm": "^4.0.0", - "tsup": "^8.1.0", - "type-fest": "^4.19.0", - "typescript": "^5.4.5", - "unified": "^11.0.4", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.1", - "vfile-message": "^4.0.2", - "vitest": "^1.6.0", - "zod": "^3.23.8" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/remark-mdat/readme.md b/packages/remark-mdat/readme.md deleted file mode 100644 index 857f16b..0000000 --- a/packages/remark-mdat/readme.md +++ /dev/null @@ -1,217 +0,0 @@ - - - - -# remark-mdat - -[![NPM Package remark-mdat](https://img.shields.io/npm/v/remark-mdat.svg)](https://npmjs.com/package/remark-mdat) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - -**A remark plugin implementing the Markdown Autophagic Template (MDAT) system.** - - - -> \[!NOTE]\ -> **Please see The [`mdat` package](http://github.com/kitschpatrol/mdat) for a higher-level CLI tool and library with a collection of built-in expansion rules.** - - - -## Table of contents - -- [Overview](#overview) -- [Getting started](#getting-started) - - [Dependencies](#dependencies) - - [Installation](#installation) -- [Usage](#usage) - - [API](#api) - - [Examples](#examples) -- [Utilities](#utilities) -- [The future](#the-future) -- [Maintainers](#maintainers) -- [Acknowledgements](#acknowledgements) -- [Contributing](#contributing) -- [License](#license) - - - -## Overview - -This is a [remark](https://remark.js.org) plugin that automates the inline expansion of placeholder HTML comments with dynamic content in Markdown, making it easy to keep readme files and other documentation in sync with an external single source of truth. - -The plugin can take placeholder comments in a Markdown file like this: - -```md - -``` - -And replace it with dynamic data. In this case, from `package.json`: - -```md - - -# remark-mdat - - -``` - -This plugin powers the higher-level [`mdat` package](../mdat) in this monorepo. [`mdat`](../mdat) is a better better place to start if you just want to expand some comments and aren't working directly with remark processing pipelines. - -## Getting started - -### Dependencies - -This library is ESM only and requires Node 16 or newer. It's designed to work with Remark 15. `remark-mdat` is implemented in TypeScript and bundles a complete set of type definitions. - -### Installation - -```sh -npm install remark-mdat -``` - -## Usage - -### API - -#### Core plugin - -This package's default export implements the unified [Plugin](https://github.com/unifiedjs/unified#plugin) type. - -The plugin is integrated into a remark process chain via the `.use()` method: - -```ts -import { remark } from 'remark' -import remarkMdat from 'remark-mdat' - -remark().use(remarkMdat) -``` - -#### Options - -The plugin accepts an optional options object which exposes some configuration options and, most importantly, determines how comments in the source Markdown file will be expanded via the `rules` field: - -```ts -export type Options = { - addMetaComment?: Boolean // default: false - closingPrefix?: String // default: '/', - keywordPrefix?: String // default: '', - metaCommentIdentifier?: String // default: '+', - rules?: Rules // default: a single test rule for the 'mdat' keyword -} -``` - -### Examples - -#### Basic - -`remark-mdat` includes one test rule by default, ``. - -```ts -import { remark } from 'remark' -import remarkMdat from 'remark-mdat' - -const markdownInput = '' -const markdownOutput = await remark().use(remarkMdat).process(markdown) - -console.log(markdownOutput.toString()) - -// Logs: -// -// -// Powered by the Markdown Autophagic Template system: [mdat](https://github.com/kitschpatrol/mdat). -// -// -``` - -#### With options - -If you wanted to replace `` comments in your Markdown file with the current time, you could pass in a rule: - -```ts -import { remark } from 'remark' -import { type Rules, default as remarkMdat } from 'remark-mdat' - -// Create the rule -const rules: Rules = { - time: () => new Date().toDateString(), -} - -const markdownInput = '' - -// Pass the time rule to remarkMdat -const markdownOutput = await remark().use(remarkMdat, { rules }).process(markdown) - -console.log(markdownOutput.toString()) - -// Logs: -// -// -// Mon Feb 05 2024 -// -// -``` - -See the [`mdat`](../mdat) package for a higher-level API and CLI that can operate directly on files or strings. It also provides dynamic rule loading and configuration resolution, and bundles a collection of rules convenient for use in readme files. - -## Utilities - -The plugin bundles a number of [mdast](https://github.com/syntax-tree/mdast) utilities designed to operate directly on syntax trees. These are exported to support customized Unified.js processors and enforce modularity and separation of concerns in mdat's internal implementation, but you do not need to use them directly — all functionality is encapsulated in the single `remarkMdat` plugin export. - -The remark-mdat plugin chains these utilities together to accommodate the typical use case of end-to-end expansion and validation of mdat comments. For now, the individual utility transformers are not published individually to NPM, and are instead bundled with `remark-mdat`. - -- [**`mdast-util-mdat`**](./src/lib/mdast-utils/mdast-util-mdat.ts) - - Composite transformer function performing end-to-end mdat comment expansion and validation on Markdown ASTs by chaining the other utility functions described below. - - _Exported as `mdat`_ - - Utilities wrapped by `mdast-util-mdat`: - - - [**`mdast-util-mdat-split`**](./src/lib/mdast-utils/mdast-util-mdat-split.ts) - - Transformer function that allows inline mdat expansion comments. - - _Exported as `mdatSplit`_ - - - [**`mdast-util-mdat-clean`**](./src/lib/mdast-utils/mdast-util-mdat-clean.ts) - - Transformer function that "resets" all mdat comment expansions in a file, collapsing expanded comments back into single-line placeholders. - - _Exported as `mdatClean`_ - - - [**`mdast-util-mdat-expand`**](./src/lib/mdast-utils/mdast-util-mdat-expand.ts) - - Transformer function that expands mdat comments (e.g. ``) in a Markdown file according to the rule set passed in to the `MdatExpandOptions` argument. - - _Exported as `mdatExpand`_ - - - [**`mdast-util-mdat-check`**](./src/lib/mdast-utils/mdast-util-mdat-check.ts) - - Transformer function that validates an expanded Markdown document against the requirements defined in the rules passed in to the `MdatCheckOptions` argument. - - See `reporterMdat` to extract, format, and log results from VFile messages written by `mdatCheck`. This function does not modify the tree, it only appends messages to the VFiles passed through it. - - _Exported as `mdatCheck`_ - -## The future - -- Consider making remark a peer dependency? Though perhaps not [strip-markdown/issues/24](https://github.com/remarkjs/strip-markdown/issues/24)... - -## Maintainers - -[@kitschpatrol](https://github.com/kitschpatrol) - -## Acknowledgements - -Please see the [mdat readme](../mdat/readme.md#acknowledgments). - - - -## Contributing - -[Issues](https://github.com/kitschpatrol/mdat/issues) and pull requests are welcome. - -## License - -[MIT](license.txt) © Eric Mika - - diff --git a/packages/remark-mdat/src/index.ts b/packages/remark-mdat/src/index.ts deleted file mode 100644 index 954446e..0000000 --- a/packages/remark-mdat/src/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Export utilities for advanced use cases -export { type Options as MdatOptions, mdat } from './lib/mdast-utils/mdast-util-mdat' -export { - type Options as MdatCheckOptions, - mdatCheck, -} from './lib/mdast-utils/mdast-util-mdat-check' -export { - type Options as MdatCleanOptions, - mdatClean, -} from './lib/mdast-utils/mdast-util-mdat-clean' -export { - type Options as MdatExpandOptions, - mdatExpand, -} from './lib/mdast-utils/mdast-util-mdat-expand' -export { mdatSplit } from './lib/mdast-utils/mdast-util-mdat-split' -export { deepMergeDefined } from './lib/mdat/deep-merge-defined' -export { default as log } from './lib/mdat/log' -export { - type MdatFileReport, - type MdatMessage, - getMdatReports, - reporterMdat, -} from './lib/mdat/mdat-log' -export { - type NormalizedRule, - type NormalizedRules, - type Rule, - type Rules, - type SimplifyDeep, - getSoleRule, - getSoleRuleKey, - rulesSchema, -} from './lib/mdat/rules' -export { type Options, default, optionsSchema } from './lib/remark-mdat' diff --git a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-check.ts b/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-check.ts deleted file mode 100644 index a6aa41c..0000000 --- a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-check.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { saveLog } from '../mdat/mdat-log' -import { type CommentMarkerNode, parseCommentNode } from '../mdat/parse' -import { - type NormalizedRule, - type NormalizedRules, - type Rules, - getRuleContent, - normalizeRules, - validateRules, -} from '../mdat/rules' -import chalk from 'chalk' -import Table from 'cli-table3' -import type { Root } from 'mdast' -import { CONTINUE, visit } from 'unist-util-visit' -import type { VFile } from 'vfile' - -export type Options = { - addMetaComment: boolean - closingPrefix: string - keywordPrefix: string - metaCommentIdentifier: string - /** Enable extra checks, too noisy for real life. */ - paranoid: boolean - rules: Rules -} - -type CommentMarkerWithRule = { - rule: NormalizedRule | undefined -} & CommentMarkerNode - -/** - * Mdast utility function to check mdat source document, and output. - */ -export async function mdatCheck(tree: Root, file: VFile, options: Options) { - const { - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - paranoid = false, - rules: rawRules, - } = options - - validateRules(rawRules) - const rules = normalizeRules(rawRules) - - // Collect all comment markers from the tree, including invalid ones - // Order will be that of appearance in the document - const commentMarkers: CommentMarkerWithRule[] = [] - visit(tree, 'html', (node, index, parent) => { - if (parent === undefined || index === undefined) return CONTINUE - // Find all comments - const commentMarker = parseCommentNode(node, parent, { - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - }) - - // Save the marker for validation functions - if (commentMarker !== undefined) { - // Pair the marker with its rule (if available) for ease of future use - const rule = - commentMarker.type === 'open' || commentMarker.type === 'close' - ? rules[commentMarker.keyword] - : undefined - - commentMarkers.push({ - ...commentMarker, - rule, - }) - } - }) - - // Now run some validations - - // Error level checks - checkMissingRequiredComments(file, commentMarkers, rules) - checkCommentOrder(file, commentMarkers) - checkMetaCommentPresence(file, commentMarkers, options) - await checkRulesReturnedContent(file, commentMarkers, tree) - - // Warning level checks - if (paranoid) { - checkMissingOptionalComments(file, commentMarkers, rules) // Too annoying - } - - checkMissingRules(file, commentMarkers) - checkMissingPrefix(file, commentMarkers, rules, options) -} - -// Validation functions - -/** - * Check that all the rules are working by getting their content - */ -async function checkRulesReturnedContent( - file: VFile, - comments: CommentMarkerWithRule[], - tree: Root, -) { - for (const comment of comments) { - if (comment.type === 'open' && comment.rule !== undefined) { - try { - const returnedContent = await getRuleContent(comment.rule, comment.options, tree, true) - - if (returnedContent.trim() === '') { - saveLog( - file, - comment.rule.required ? 'error' : 'warn', - 'check', - `${comment.html} returned an empty string.`, - comment.node, - ) - } - } catch (error) { - if (error instanceof Error) { - saveLog( - file, - comment.rule.required ? 'error' : 'warn', - 'check', - `Could not get content for ${comment.html}. ${error.message}`, - comment.node, - ) - } - } - } - } -} - -/** - * Check for comments with missing prefix (have an un-prefixed comment that matches a rule) - */ -function checkMissingPrefix( - file: VFile, - comments: CommentMarkerWithRule[], - rules: NormalizedRules, - options: Options, -): void { - if (options.keywordPrefix === '') return - const ruleKeywords = Object.keys(rules) - - for (const comment of comments) { - if (comment.type === 'native' && ruleKeywords.includes(comment.content)) { - saveLog(file, 'warn', 'check', `Missing prefix: ${comment.html}`, comment.node) - } - } -} - -/** - * Check for missing "optional" rules. These are instances where we have the comment, but not the rule - */ -function checkMissingRules(file: VFile, comments: CommentMarkerWithRule[]): void { - for (const comment of comments) { - if (comment.type === 'open' && comment.rule === undefined) { - saveLog(file, 'warn', 'check', `Missing rule for: ${comment.html}`, comment.node) - } - } -} - -/** - * Check for missing optional comments. We have defined the rule, but not written a matching comment. - */ -function checkMissingOptionalComments( - file: VFile, - comments: CommentMarkerWithRule[], - rules: NormalizedRules, -): void { - for (const [keyword, rule] of Object.entries(rules)) { - if ( - !rule.required && - !comments.some((comment) => comment.type === 'open' && comment.keyword === keyword) && - !satisfiedByCompoundRule(rule, comments) - ) { - saveLog(file, 'warn', 'check', `Missing optional: `) - } - } -} - -/** - * Check for missing required comments. - * The rule set includes a rule with `required: true`, but no matching comment was found in the document. - */ -function checkMissingRequiredComments( - file: VFile, - comments: CommentMarkerWithRule[], - rules: NormalizedRules, -): void { - for (const [keyword, rule] of Object.entries(rules)) { - // Compound rules don't get comments - if ( - rule.required && - !comments.some((comment) => comment.type === 'open' && comment.keyword === keyword) && - !satisfiedByCompoundRule(rule, comments) - ) { - saveLog(file, 'error', 'check', `Missing required: `) - } - } -} - -/** - * Helper to see if a required rule from the rule set was in fact called by a - * compound rule Tests equality of function string, not equality of output, so - * this only makes sense if the sub-rule was imported directly in the compound - * rule. - */ -function satisfiedByCompoundRule( - possiblyMissingRule: NormalizedRule, - comments: CommentMarkerWithRule[], -): boolean { - // Reduce down single rule on comments that meets a test - return comments.reduce((flag, comment) => { - if (Array.isArray(comment.rule?.content)) { - for (const rule of comment.rule.content) { - if (rule.content.toString() === possiblyMissingRule.content.toString()) { - flag = true - } - } - } - - return flag - }, false) -} - -/** - * Check if comment order in document is different from order specified in the rules - */ -function checkCommentOrder(file: VFile, comments: CommentMarkerWithRule[]): void { - const commentsInOrderOfAppearance = comments.filter( - (commentMarker) => commentMarker.type === 'open' && commentMarker.rule?.order !== undefined, - ) - - const commentsInCorrectOrder = [...commentsInOrderOfAppearance].sort((a, b) => { - const orderA = a.rule?.order - const orderB = b.rule?.order - - if (orderA === undefined || orderB === undefined) { - throw new Error('Unexpected undefined rule order') - } - - return orderA - orderB - }) - - const currentOrderList = commentOrderList(commentsInOrderOfAppearance) - const correctOrderList = commentOrderList(commentsInCorrectOrder) - - const table = new Table({ - head: [chalk.bold.red('Current Order'), chalk.bold.green('Required Order')], - style: { - compact: true, - }, - }) - - if (currentOrderList.join(',') !== correctOrderList.join(',')) { - table.push( - ...currentOrderList.map((currentOrder, index) => [currentOrder, correctOrderList[index]]), - ) - - saveLog(file, 'error', 'check', `Out of order:\n${table.toString()}`) - } -} - -/** - * Check that meta presence / absence comment matches options. - */ -function checkMetaCommentPresence( - file: VFile, - comments: CommentMarkerWithRule[], - options: Options, -): void { - const { addMetaComment } = options - - const metaCommentCount = comments.filter((comment) => comment.type === 'meta').length - - if (addMetaComment && metaCommentCount !== 1) { - saveLog(file, 'error', 'check', `Missing meta comment`) - } - - if (!addMetaComment && metaCommentCount !== 0) { - saveLog(file, 'error', 'check', `Unexpected meta comment`) - } - - if (metaCommentCount > 1) { - saveLog(file, 'error', 'check', `Multiple meta comments`) - } -} - -// Helpers - -function commentOrderList(comments: CommentMarkerWithRule[]): string[] { - return comments.map((comment, index) => { - if (comment.type === 'open' || comment.type === 'close') { - return `${index + 1}. ${comment.html}` - } - - throw new Error('Unexpected comment type') - }) -} diff --git a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-clean.ts b/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-clean.ts deleted file mode 100644 index dddb009..0000000 --- a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-clean.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { saveLog } from '../mdat/mdat-log' -import { type CommentMarkerNode, parseCommentNode } from '../mdat/parse' -import type { Root } from 'mdast' -import { CONTINUE, visit } from 'unist-util-visit' -import { type VFile } from 'vfile' - -export type Options = { - closingPrefix: string - keywordPrefix: string - metaCommentIdentifier: string -} - -/** - * Collapses any expanded mdat comments and removes meta comments, - * effectively resetting the document to its pre-expansion state. No-op if no - * mdat comments are found. - */ -export function mdatClean(tree: Root, file: VFile, options: Options): void { - // Collapse expanded tags - // Find closing tags, then go back to last opening tag - let lastOpenMarker: ({ type: 'close' | 'open' } & CommentMarkerNode) | undefined - visit(tree, 'html', (node, index, parent) => { - if (parent === undefined || index === undefined) return CONTINUE - - // Parse the marker to find probably mdat comments - const marker = parseCommentNode(node, parent, options) - - if (marker === undefined || marker.type === 'native') return CONTINUE - - // Remove meta comments generated by mdat - if (marker.type === 'meta') { - parent.children.splice(index, 1) - return [CONTINUE, index] - } - - if (marker.type === 'open') { - // Opening marker - lastOpenMarker = marker - return CONTINUE - } - - if (marker.type === 'close') { - // Check the match - if (lastOpenMarker === undefined) { - saveLog(file, 'error', 'clean', 'Found closing marker without opening marker', node) - return CONTINUE - } - - if (lastOpenMarker.parent !== marker.parent) { - saveLog(file, 'error', 'clean', "Opening marker doesn't share a parent", node) - return CONTINUE - } - - if (lastOpenMarker.keyword !== marker.keyword) { - saveLog(file, 'error', 'clean', "Opening marker doesn't share a keyword", node) - return CONTINUE - } - - // Remove everything between the opening and closing markers, and remove - // the closing marker as well - const openMarkerIndex = parent.children.indexOf(lastOpenMarker.node) - const closeMarkerIndex = parent.children.indexOf(marker.node) - const nodesToRemove = closeMarkerIndex - openMarkerIndex + 1 - - parent.children.splice(openMarkerIndex + 1, nodesToRemove - 1) - lastOpenMarker = undefined - - // Return revised index since we spliced out nodes - return [CONTINUE, index - nodesToRemove + 1] - } - }) -} diff --git a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-expand.ts b/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-expand.ts deleted file mode 100644 index a23ed10..0000000 --- a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-expand.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { saveLog } from '../mdat/mdat-log' -import { type CommentMarkerNode, parseCommentNode } from '../mdat/parse' -import { type Rules, getRuleContent, normalizeRules, validateRules } from '../mdat/rules' -import type { Html, Root } from 'mdast' -import { remark } from 'remark' -import remarkGfm from 'remark-gfm' -import { CONTINUE, visit } from 'unist-util-visit' -import { type VFile } from 'vfile' - -export type Options = { - addMetaComment: boolean - closingPrefix: string - keywordPrefix: string - metaCommentIdentifier: string - rules: Rules -} - -type ValidCommentMarker = { - type: 'close' | 'open' -} & CommentMarkerNode - -/* - * Mdast utility plugin to collapse mdat comments and strip generated meta - * comments, effectively resetting the document to its original state. - */ -export async function mdatExpand(tree: Root, file: VFile, options: Options) { - const { - addMetaComment, - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - rules: rawRules, - } = options - - // Make the rules easier to deal with by normalizing to consistent structure - validateRules(rawRules) - const rules = normalizeRules(rawRules) - - // Get all valid comment markers from the tree - const commentMarkers: ValidCommentMarker[] = [] - visit(tree, 'html', (node, index, parent) => { - if (parent === undefined || index === undefined) return CONTINUE - - // Find all comments - const commentMarker = parseCommentNode(node, parent, { - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - }) - - // Save the marker if it meets all criteria - if ( - commentMarker !== undefined && - commentMarker.type === 'open' && - rules[commentMarker.keyword] !== undefined - ) - commentMarkers.push(commentMarker) - }) - - // Sort by application order - commentMarkers.sort( - (a, b) => rules[a.keyword].applicationOrder - rules[b.keyword].applicationOrder, - ) - - // Expand the rules - for (const comment of commentMarkers) { - const { closingPrefix, html, keyword, keywordPrefix, node, options, parent } = comment - const rule = rules[keyword] - - let newMarkdownString = '' - try { - // Handle compound rules - newMarkdownString = await getRuleContent(rule, options, tree) - - // TODO just let check get this? - if (newMarkdownString.trim() === '') { - saveLog(file, 'error', 'expand', `Got empty content when expanding ${html}`, node) - } - } catch (error) { - if (error instanceof Error) { - saveLog( - file, - 'error', - 'expand', - `Caught error expanding ${html}, Error message: "${error.message}"`, - node, - ) - } - - continue - } - - // String to Markdown Nodes - // TODO Consider exposing this for more complex use cases? - const newNodes = remark().use(remarkGfm).parse(newMarkdownString).children - - // Add closing tag - const closingNode: Html = { - type: 'html', - value: ``, - } - - const openingCommentIndex = parent.children.indexOf(node) - parent.children.splice(openingCommentIndex + 1, 0, ...newNodes, closingNode) - - saveLog(file, 'info', 'expand', `Expanded: ${html}`, node) - } - - // Add meta comment - if (addMetaComment) { - const message = - 'Warning: Content inside HTML comment blocks was generated by mdat and may be overwritten.' - const metaComment: Html = { - type: 'html', - value: ``, - } - tree.children.unshift(metaComment) - } -} diff --git a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-split.ts b/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-split.ts deleted file mode 100644 index afc6d02..0000000 --- a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat-split.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { saveLog } from '../mdat/mdat-log' -import { fromHtml } from 'hast-util-from-html' -import { type Html, type Text } from 'mdast' -import type { Root } from 'mdast' -import { type Node, type Point, type Position } from 'unist' -import { CONTINUE, SKIP, visit } from 'unist-util-visit' -import { type VFile } from 'vfile' - -/** - * Mdast utility plugin to split any multi-comment nodes and their content into individual MDAST HTML - * nodes. They're wrapped in a paragraph so as not to introduce new breaks. - */ -export function mdatSplit(tree: Root, file: VFile) { - visit(tree, 'html', (node, index, parent) => { - if (parent === undefined || index === undefined) return CONTINUE - - const htmlNodes = splitHtmlIntoMdastNodes(node) - - if (htmlNodes.length > 1) { - // HtmlNodes[0].value = `${htmlNodes[0].value}\n` - saveLog(file, 'warn', 'split', 'Multiple comments in a single HTML node.', node) - - // TODO really vet this step - parent.children.splice(index, 1, { - children: htmlNodes, - type: 'paragraph', - }) - } - }) -} - -// Helpers -// Exported for testing -export function splitHtmlIntoMdastNodes(mdastNode: Html): Array { - const htmlTree = fromHtml(mdastNode.value, { fragment: true }) - - const mdastNodes: Array = [] - - visit(htmlTree, (hastNode) => { - // Ignore the root - if (hastNode.type === 'root') return CONTINUE - - // Return text as normal mdast node - if (hastNode.type === 'text') { - mdastNodes.push({ - position: addStartPoint(hastNode.position, mdastNode.position?.start), - type: 'text', - value: getOriginalMarkup(mdastNode, hastNode), - }) - return CONTINUE - } - - // Return everything else as mdast html node, but don't descend - // TODO support for comment in nested HTML elements, e.g. - // - mdastNodes.push({ - position: addStartPoint(hastNode.position, mdastNode.position?.start), - type: 'html', - value: getOriginalMarkup(mdastNode, hastNode), - }) - return SKIP - }) - - return mdastNodes -} - -// Helps us merge positions from hast nodes to mdast nodes for better logging -function addStartPoint( - position: Position | undefined, - start: Point | undefined, -): Position | undefined { - if (position === undefined || start === undefined) return undefined - - return { - end: { - column: position.end.column - 1 + start.column, - line: position.end.line - 1 + start.line, - offset: - position.end.offset !== undefined && start.offset !== undefined - ? position.end.offset + start.offset - : undefined, - }, - start: { - column: position.start.column - 1 + start.column, - line: position.start.line - 1 + start.line, - offset: - position.start.offset !== undefined && start.offset !== undefined - ? position.start.offset + start.offset - : undefined, - }, - } -} - -function getOriginalMarkup(mdastNode: Html, hastNode: Node): string { - // Alternate approach would use stringify the hast node: - // But could create issues where the HTML is not exactly the same as the original - // toHtml(hastNode) - - if (hastNode.position === undefined) { - throw new Error('Hast ElementContent node has no position!') - } - - return mdastNode.value.slice(hastNode.position.start.offset, hastNode.position.end.offset) -} diff --git a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat.ts b/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat.ts deleted file mode 100644 index 4d69ea7..0000000 --- a/packages/remark-mdat/src/lib/mdast-utils/mdast-util-mdat.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { type Rules } from '../mdat/rules' -import { mdatCheck } from './mdast-util-mdat-check' -import { mdatClean } from './mdast-util-mdat-clean' -import { mdatExpand } from './mdast-util-mdat-expand' -import { mdatSplit } from './mdast-util-mdat-split' -import type { Root } from 'mdast' -import { type VFile } from 'vfile' - -export type Options = { - addMetaComment: boolean - closingPrefix: string - keywordPrefix: string - metaCommentIdentifier: string - rules: Rules -} - -export async function mdat(tree: Root, file: VFile, options: Options): Promise { - const { addMetaComment, closingPrefix, keywordPrefix, metaCommentIdentifier, rules } = options - - mdatSplit(tree, file) - - mdatClean(tree, file, { - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - }) - - await mdatExpand(tree, file, { - addMetaComment, - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - rules, - }) - - await mdatCheck(tree, file, { - addMetaComment, - closingPrefix, - keywordPrefix, - metaCommentIdentifier, - paranoid: false, - rules, - }) -} diff --git a/packages/remark-mdat/src/lib/mdat/deep-merge-defined.ts b/packages/remark-mdat/src/lib/mdat/deep-merge-defined.ts deleted file mode 100644 index 1c5b205..0000000 --- a/packages/remark-mdat/src/lib/mdat/deep-merge-defined.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { deepmerge } from 'deepmerge-ts' - -// Discussion: -// https://github.com/RebeccaStevens/deepmerge-ts/discussions/25 -// https://github.com/voodoocreation/ts-deepmerge/issues/28 -// https://github.com/voodoocreation/ts-deepmerge/releases/tag/6.2.0 - -// Objects only -// export function stripUndefined>(object: T): T { -// return Object.entries(object) -// .map(([k, v]) => [ -// k, -// v && typeof v === 'object' ? stripUndefined(v as Record) : v, -// ]) -// .reduce( -// (acc: Record, [k, v]) => -// v === undefined ? acc : { ...acc, [k as string]: v }, -// {}, -// ) as T -// } - -// Objects + Arrays -export function stripUndefinedDeep(object: T | T[]): T | T[] { - if (Array.isArray(object)) { - return object - .map((v) => (v && typeof v === 'object' ? stripUndefinedDeep(v) : v)) - .filter((v) => v !== undefined) as T[] - } - - return Object.entries(object as Record) - .map(([k, v]) => [k, v && typeof v === 'object' ? stripUndefinedDeep(v) : v]) - .reduce( - (acc: Record, [k, v]) => - v === undefined ? acc : { ...acc, [k as string]: v }, - {}, - ) as T -} - -export function deepMergeDefined>(...objects: T[]): T { - // Maybe faster to skip stripping the first arg? - const stripped = objects.map((v, i) => (i === 0 ? v : stripUndefinedDeep(v))) - return deepmerge(...stripped) as T -} diff --git a/packages/remark-mdat/src/lib/mdat/log.ts b/packages/remark-mdat/src/lib/mdat/log.ts deleted file mode 100644 index 9441aa6..0000000 --- a/packages/remark-mdat/src/lib/mdat/log.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* eslint-disable perfectionist/sort-objects */ -// Staying basic, always log to stderr - -import chalk from 'chalk' - -const isNode = process?.versions?.node !== undefined - -const log = { - verbose: false, - - // Intended for temporary logging - log(...data: unknown[]): void { - if (!this.verbose) return - const levelPrefix = chalk.gray('[Log]') - if (isNode) { - // Log to stderr in node for ease of redirection - console.warn(levelPrefix, ...data) - } else { - console.log(levelPrefix, ...data) - } - }, - logPrefixed(prefix: string, ...data: unknown[]): void { - this.info(chalk.blue(`[${prefix}]`), ...data) - }, - - info(...data: unknown[]): void { - if (!this.verbose) return - const levelPrefix = chalk.green('[Info]') - if (isNode) { - // Log info to stderr in node for ease of redirection - console.warn(levelPrefix, ...data) - } else { - console.info(levelPrefix, ...data) - } - }, - infoPrefixed(prefix: string, ...data: unknown[]): void { - this.info(chalk.blue(`[${prefix}]`), ...data) - }, - - warn(...data: unknown[]): void { - console.warn(chalk.yellow('[Warning]'), ...data) - }, - warnPrefixed(prefix: string, ...data: unknown[]): void { - this.warn(chalk.blue(`[${prefix}]`), ...data) - }, - - error(...data: unknown[]): void { - console.error(chalk.red('[Error]'), ...data) - }, - errorPrefixed(prefix: string, ...data: unknown[]): void { - this.error(chalk.blue(`[${prefix}]`), ...data) - }, -} - -export default log diff --git a/packages/remark-mdat/src/lib/mdat/mdat-log.ts b/packages/remark-mdat/src/lib/mdat/mdat-log.ts deleted file mode 100644 index dfb7b89..0000000 --- a/packages/remark-mdat/src/lib/mdat/mdat-log.ts +++ /dev/null @@ -1,186 +0,0 @@ -import log from './log' -import chalk from 'chalk' -import path from 'node:path' -import type { Node } from 'unist' -import { type VFile } from 'vfile' -import { type Options, type VFileMessage } from 'vfile-message' - -// Tries to provide a simpler wrapper to vfile.message -export type MdatMessage = { - column?: number - level: 'error' | 'info' | 'warn' - line?: number - message: string - source?: string -} - -export type MdatFileReport = { - destinationPath?: string - errors: MdatMessage[] - infos: MdatMessage[] - sourcePath: string - warnings: MdatMessage[] -} - -// Official fields: -// ancestors (Array or undefined) — stack of (inclusive) ancestor nodes surrounding the message -// cause (Error or undefined) — original error cause of the message -// column (number or undefined) — starting column of message -// fatal (boolean or undefined) — state of problem; true: error, file not usable; false: warning, change may be needed; undefined: info, change likely not needed -// line (number or undefined) — starting line of message -// place (Point, Position or undefined) — place of message -// reason (string) — reason for message (should use Markdown) -// ruleId (string or undefined, example: 'my-rule') — category of message -// source (string or undefined, example: 'my-package') — namespace of message - -// Wrapper for file.message - -// Function Overloads -export function saveLog( - file: VFile, - level: 'error' | 'info' | 'warn', - source: string, - message: string, - line?: number, - column?: number, -): void -export function saveLog( - file: VFile, - level: 'error' | 'info' | 'warn', - source: string, - message: string, - node?: Node, -): void - -// Function Implementation -export function saveLog( - file: VFile, - level: 'error' | 'info' | 'warn', - source: string, - message: string, - lineOrNode?: Node | number, - maybeColumn?: number, -): void { - let line: number - let column: number - - if (lineOrNode === undefined || typeof lineOrNode === 'number') { - // Handle the case where lineOrNode is a number - line = lineOrNode ?? 0 - column = maybeColumn ?? 0 // Use the provided column or default to 0 - } else { - // Handle the case where lineOrNode is a Node - line = lineOrNode?.position?.start.line ?? 0 - column = lineOrNode?.position?.start.column ?? 0 - } - - const options: Options = { - place: { - end: { - column, - line, - }, - start: { - column, - line, - }, - }, - source, - } - - const vFileMessage = file.message(message, options) - vFileMessage.fatal = level === 'error' ? true : level === 'warn' ? false : undefined -} - -function vFileMessageToMdatMessage(vFileMessage: VFileMessage): MdatMessage { - return { - column: vFileMessage.column, - level: vFileMessage.fatal ? 'error' : vFileMessage.fatal === false ? 'warn' : 'info', - line: vFileMessage.line, - message: vFileMessage.reason, - source: vFileMessage.source, - } -} - -export function getMdatReports(files: VFile[]): MdatFileReport[] { - return files.map((file) => getMdatReport(file)) -} - -function getMdatReport(file: VFile): MdatFileReport { - const mdatFileReport: MdatFileReport = { - destinationPath: file.history.length > 0 ? file.history.at(-1) : undefined, - errors: [], - infos: [], - sourcePath: file.history.at(0) ?? file.path, - warnings: [], - } - - if (mdatFileReport.sourcePath?.startsWith('.')) { - mdatFileReport.sourcePath = path.relative( - process.cwd(), - path.join(process.cwd(), mdatFileReport.sourcePath), - ) - } - - for (const message of file.messages) { - const mdatMessage = vFileMessageToMdatMessage(message) - if (mdatMessage.level === 'error') { - mdatFileReport.errors.push(mdatMessage) - } else if (mdatMessage.level === 'warn') { - mdatFileReport.warnings.push(mdatMessage) - } else { - mdatFileReport.infos.push(mdatMessage) - } - } - - return mdatFileReport -} - -export function reporterMdat(files: VFile[]): void { - for (const file of files) { - const mdatFileReport = getMdatReport(file) - const { destinationPath, errors, infos, sourcePath, warnings } = mdatFileReport - - log.info(`${chalk.bold('MDAT Report:')}`) - log.info(`\tFrom: ${chalk.blue.bold(sourcePath)}`) - log.info(`\tTo: ${chalk.blue.bold(destinationPath)}`) - - for (const message of errors) { - log.error(mdatMessageToLogString(sourcePath, message)) - } - - for (const message of warnings) { - log.warn(mdatMessageToLogString(sourcePath, message)) - } - - for (const message of infos) { - log.info(mdatMessageToLogString(sourcePath, message)) - } - - if (errors.length === 0 && warnings.length === 0) { - log.info(`No issues found in ${sourcePath}`) - } else { - log.error(`${errors.length} errors, ${warnings.length} warnings found in ${sourcePath}`) - } - } -} - -function mdatMessageToLogString(sourcePath: string, mdatMessage: MdatMessage): string { - const { column, level, line, message, source } = mdatMessage - - const resolvedSource = source ? chalk.gray(`[${source}] `) : '' - const lineColumn = line && column ? `:${line}:${column}` : '' - const highlightedMessage = highlightComments(message, level) - - return `${resolvedSource}${highlightedMessage} ${chalk.whiteBright(sourcePath + lineColumn)}` -} - -function highlightComments(text: string, level: 'error' | 'info' | 'warn'): string { - return text.replaceAll(//g, (match) => - level === 'info' - ? chalk.green(match) - : level === 'warn' - ? chalk.yellow(match) - : chalk.red(match), - ) -} diff --git a/packages/remark-mdat/src/lib/mdat/parse.ts b/packages/remark-mdat/src/lib/mdat/parse.ts deleted file mode 100644 index bb3733c..0000000 --- a/packages/remark-mdat/src/lib/mdat/parse.ts +++ /dev/null @@ -1,199 +0,0 @@ -import json5 from 'json5' -import { type Html, type Parent } from 'mdast' -import type { JsonValue } from 'type-fest' -import { type Simplify } from 'type-fest' -import { VFileMessage } from 'vfile-message' - -/** - * Structured data about a parsed comment. - * Note that this is a discriminated union based on the `type` field. - */ -export type CommentMarker = Simplify< - { - // Shared field - /** The complete original comment, e.g. `` */ - html: string - } & ( - | { - /** Character used to delimit closing tags, e.g. the `/` in `` */ - closingPrefix: string - /** The first complete word in the comment */ - keyword: string - /** The unique keyword prefix */ - keywordPrefix: string - /** Parsed JSON object of argument string that followed the keyword, empty object if nothing passed */ - options: JsonValue - /** - * `open`: A mdat-style opening comment tag, e.g. `` \ - * `close`: A mdat-style closing comment tag, e.g. `` - */ - type: 'close' | 'open' - } - | { - /** The original text inside the comment, e.g. `` */ - content: string - /** - * `meta`: A mdat-style generated meta comment tag \ - * `native`: A normal comment that does not match the the `keywordPrefix` (if specified) - */ - type: 'meta' | 'native' - } - ) -> - -/** - * Parsed comment with additional information about the Mdast Node and its Parent. - */ -export type CommentMarkerNode = Simplify< - { - /** Original Mdast HTML Node where the comment was found. */ - node: Html - /** Parent of original Mdast HTML Node where the comment was found. */ - parent: Parent - } & CommentMarker -> - -export type CommentMarkerParseOptions = { - /** Character to identify closing tags, e.g. the `/` in `` */ - closingPrefix: string - /** Prefix to require on all mdat comments, e.g. `mm-` */ - keywordPrefix: string - /** Means of identifying mdat generated meta comments, e.g. `+` */ - metaCommentIdentifier: string -} - -/** - * Parse an Mdast HTML comment node into structured data. - * @returns A discriminated union of CommentMarkerNode based on comment type, or - * undefined if the node is not a comment. - */ -export function parseCommentNode( - node: Html, - parent: Parent, - options: CommentMarkerParseOptions, -): CommentMarkerNode | undefined { - try { - const result = parseComment(node.value, options) - - if (result === undefined) { - return undefined - } - - return { - ...result, - node, - parent, - } - } catch (error) { - if (error instanceof VFileMessage) { - error.line = node.position?.start.line - throw error - } else if (error instanceof Error) { - throw new VFileMessage(error.message, node) - } else { - throw new VFileMessage('Unknown error', node) - } - } -} - -/** - * Parse any comment string into structured data. - * @returns A discriminated union of CommentMarker based on comment type, or - * undefined if the node is not a comment. - */ -export function parseComment( - text: string, - options: CommentMarkerParseOptions, -): CommentMarker | undefined { - if (!isComment(text)) return - - const { closingPrefix, keywordPrefix, metaCommentIdentifier } = options - - const commentHtml = text.trim() - const commentBody = commentHtml.replace(/^\s*\s*$/, '') - - // Splits without capturing - const [rawKeyword, ...argumentParts] = commentBody.split(/(\s+|\(|{)/) - - const type = rawKeyword.startsWith(metaCommentIdentifier) - ? 'meta' - : keywordPrefix !== '' && - !rawKeyword.startsWith(keywordPrefix) && - !rawKeyword.startsWith(`${closingPrefix}${keywordPrefix}`) - ? 'native' - : rawKeyword.startsWith(closingPrefix) - ? 'close' - : 'open' - - if (type === 'meta') { - return { - content: trimMetaIdentifiers(commentBody, metaCommentIdentifier), - html: commentHtml, - type, - } - } - - if (type === 'native') { - return { - content: commentBody, - html: commentHtml, - type, - } - } - - // Must be open or closing tag, continue parsing - const keyword = rawKeyword - .replace(new RegExp(`^${closingPrefix}`), '') - .replace(new RegExp(`^${keywordPrefix}`), '') - const optionText = makeValidJson(argumentParts.join('')) - - if (type === 'open' || type === 'close') { - let options: JsonValue = {} - - try { - options = json5.parse(optionText) - } catch (error) { - if (error instanceof Error) { - throw new VFileMessage( - `Failed to parse comment options "${optionText}" for keyword "${keyword}": ${error.message}`, - ) - } - } - - return { - closingPrefix, - html: commentHtml, - keyword, - keywordPrefix, - options, - type, - } - } -} - -function isComment(text: string): boolean { - const trimmed = text.trim() - return trimmed.startsWith('') -} - -// Let the user pass the comment options inside parentheses if they want, like a function call -// Or let them skip the brackets if they want -function makeValidJson(text: string): string { - // Remove parentheses - text = text.trim() - text = text.startsWith('(') ? text.slice(1) : text - text = text.endsWith(')') ? text.slice(0, -1) : text - text = text.trim() - - // Make bare objects valid JSON - if (!text.startsWith('{') && !text.startsWith('[')) text = '{' + text - if (!text.endsWith('}') && !text.endsWith(']')) text += '}' - return text -} - -function trimMetaIdentifiers(text: string, metaCommentIdentifier: string): string { - text = text.trim() - text = text.startsWith(metaCommentIdentifier) ? text.slice(metaCommentIdentifier.length) : text - text = text.endsWith(metaCommentIdentifier) ? text.slice(0, -metaCommentIdentifier.length) : text - return text -} diff --git a/packages/remark-mdat/src/lib/mdat/rules.ts b/packages/remark-mdat/src/lib/mdat/rules.ts deleted file mode 100644 index b896cdc..0000000 --- a/packages/remark-mdat/src/lib/mdat/rules.ts +++ /dev/null @@ -1,347 +0,0 @@ -import { type Root } from 'mdast' -import { type JsonValue } from 'type-fest' -import type { Merge, MergeDeep, SetOptional, Simplify } from 'type-fest' -import { z } from 'zod' - -// Note that more advanced rule loading is implemented in `/packages/mdat` - -// Type-fest's internal SimplifyDeep implementation is not exported -// this isn't quite the same, but works for our purposes -export type SimplifyDeep = Simplify> - -// Basic interface for comment expanders - -/** - * Strict normalized rules used internally. - * Rules normalized to a form with async content functions and other default metadata - * Simplifies processing elsewhere, while retaining flexibility for rule authors - */ -export type NormalizedRule = { - /** - * The order in which the rule should be applied during processing - * Helpful if a rule depends on the presence of content generated by another rule - * Defaults to 0. - */ - applicationOrder: number - /** - * The function that generates the expanded Markdown string. - * For 'compound' rules, this can be an array of rules (without keywords). - */ - content: ((options: JsonValue, tree: Root) => Promise) | NormalizedRule[] - /** - * The expected order of the keyword in the document relative to other expander comments. - * Used for validation purposes. - * Leave undefined to order skip validation. - * Defaults to undefined, which means order is not enforced. - */ - order: number | undefined - /** - * Whether the presence of the keyword comment in the document is required. - * Used for validation purposes. - * Defaults to false. - */ - required: boolean -} - -// More flexible rules used in the public interface -export type Rule = - /** - * Function that returns the Markdown string to expand at the comment site. - */ - | ((options: JsonValue, tree: Root) => Promise | string) - /** - * Compound rules may be defined an array of rules, without keywords. - * Can be defined at the top level, if no validation metadata is required, or as the 'content' value - * of a rule object with validation metadata. - */ - | Rule[] - /** - * The Markdown string to expand at the comment site. - */ - | SetOptional< - Merge< - NormalizedRule, - { - /** - * Gets content to expand into the comment. - * Can be a simple string for direct replacement, a function that returns a string, or an async function that returns a string. - * - * If a function is provided, it will be passed the following arguments: - * - * @param options - * JSON value of options parsed immediately after the comment keyword in the comment, e.g.: - * `` or - * `` - * Sets options to {something: true} - * - * @param tree - * Markdown (mdast) abstract syntax tree containing the entire parsed document. Useful for expanders that need the entire document context, such as when generating a table of contents. Do not mutate the AST, instead return a new string. - * - * @returns A string with the generated content. The string will be parsed as Markdown and inserted into the document at the comment's location. - */ - content: ((options: JsonValue, tree: Root) => Promise | string) | Rule[] | string - } - >, - 'applicationOrder' | 'order' | 'required' - > - | string - -/** - * Rules are record objects whose keys match strings inside a Markdown comment, and values explain what should be expanded at the comment site. - * - * The record value may be a string, or an object containing additional metadata, possibly with a function to invoke to generate content. - * - * - * - * @example - * Most basic rule: - * ```ts - * { basic: 'content' } - * ``` - * - * Rule with dynamic content: - * ```ts - * { basic: () => `${new Date().toISOString()}` } - * ``` - * - * Rule with metadata: - * ```ts - * { basic-meta: { required: true, content: 'content'} } - * ``` - * - * Rule with dynamic content and metadata: - * { basic-date: { required: true, content: () => `${new Date().toISOString()}` } } - */ -export type Rules = SimplifyDeep> - -export type NormalizedRules = SimplifyDeep> - -// Helpers -export function normalizeRules(rules: Rules): NormalizedRules { - const normalizedRules: NormalizedRules = {} - - for (const [keyword, rule] of Object.entries(rules)) { - if (typeof rule === 'string') { - // Rule is just a simple string replacement, no metadata provided - normalizedRules[keyword] = { - applicationOrder: 0, - // eslint-disable-next-line @typescript-eslint/require-await - content: async () => rule, - order: undefined, - required: false, - } - } else if (typeof rule === 'function') { - // Rule is a function that returns a string - // Wrapped so it can be sync or async - normalizedRules[keyword] = { - applicationOrder: 0, - content: async (options: JsonValue, tree: Root) => rule(options, tree), - order: undefined, - required: false, - } - } else if (Array.isArray(rule)) { - // Top-level compound rule, gets wrapped in a normal rule - normalizedRules[keyword] = { - applicationOrder: 0, - content: Object.values(normalizeRules(Object.fromEntries(rule.entries()))), - order: undefined, - required: false, - } - } else if (typeof rule.content === 'string') { - // String replacement with metadata - // Merge any existing metadata, but turn content into a function - const ruleContent = rule.content // Needed for type narrowing - normalizedRules[keyword] = { - applicationOrder: rule.applicationOrder ?? 0, - // eslint-disable-next-line @typescript-eslint/require-await - content: async () => ruleContent, - order: rule.order ?? undefined, - required: rule.required ?? false, - } - } else if (Array.isArray(rule.content)) { - // Compound rule with metadata - // Normalize the array of rules - normalizedRules[keyword] = { - applicationOrder: rule.applicationOrder ?? 0, - content: Object.values(normalizeRules(Object.fromEntries(rule.content.entries()))), - order: rule.order ?? undefined, - required: rule.required ?? false, - } - } else { - // Rule with metadata - // Rule content returns a function, wrapped so it can be sync or async - const ruleContent = rule.content // Needed for type narrowing - normalizedRules[keyword] = { - applicationOrder: rule.applicationOrder ?? 0, - content: async (options: JsonValue, tree: Root) => ruleContent(options, tree), - order: rule.order ?? undefined, - required: rule.required ?? false, - } - } - } - - validateNormalizedRules(normalizedRules) - return normalizedRules -} - -export function validateRules(rules: Rules) { - // Check, throws on errors - try { - rulesSchema.parse(rules) - } catch (error) { - if (error instanceof Error) { - throw new TypeError(`Error validating rules: ${error.message}`) - } - } -} - -function validateNormalizedRules(rules: NormalizedRules) { - // Check, throws on errors - try { - normalizedRulesSchema.parse(rules) - } catch (error) { - if (error instanceof Error) { - throw new TypeError(`Error validating rules: ${error.message}`) - } - } -} - -// ---------------------------------------------------------- - -// Some duplication here, but less painful than inferring the TS types -// _from_ the Zod schemas because of the JsonValue and Root types. - -// TODO maybe narrow these, or use unknown... -const jsonValueSchema = z.any() -const rootSchema = z.any() - -// Declaration of normalizedRuleSchema for recursion within ruleSchema -const normalizedRuleSchema: z.ZodSchema = z.lazy(() => - z.object({ - applicationOrder: z.number(), - content: z.union([ - z - .function() - .args(jsonValueSchema.optional(), rootSchema.optional()) - .returns(z.promise(z.string())), - z.array(normalizedRuleSchema), - ]), - order: z.number().optional(), - required: z.boolean().default(false), - }), -) - -// Declaration of ruleSchema to include all possible types for Rule - -const ruleContentFunctionSchema = z - .function() - .args(jsonValueSchema.optional(), rootSchema.optional()) - .returns(z.union([z.string(), z.promise(z.string())])) - -const ruleSchema: z.ZodSchema = z.lazy(() => - z.union([ - // Extra top level options - ruleContentFunctionSchema, // Content function - z.array(ruleSchema), // Array of rules (compound rule) - z.string(), // Just a keyword - z.object({ - applicationOrder: z.number().optional(), - content: z.union([ - ruleContentFunctionSchema, // Content function - z.array(ruleSchema), // Array of rules (compound rule) - z.string(), // Just a keyword - ]), - order: z.number().optional(), - required: z.boolean().optional(), - }), - ]), -) -// Z.array(z.lazy(() => ruleSchema)), // Correctly handle recursive arrays of Rule - -export const rulesSchema = z.record(ruleSchema).describe('MDAT Rules') -export const normalizedRulesSchema = z.record(normalizedRuleSchema).describe('MDAT Rules') - -// ---------------------------------------------------------- - -// Compound rule helpers, used in both "expand" and "check" utilities -export async function getRuleContent( - rule: NormalizedRule, - options: JsonValue, - tree: Root, - check = false, -): Promise { - if (Array.isArray(rule.content)) { - const subruleContent = [] - for (const [index, subrule] of rule.content.entries()) { - const subruleOptions = Array.isArray(options) ? options.at(index) : undefined - - try { - subruleContent.push(await getRuleContent(subrule, subruleOptions ?? {}, tree)) - } catch (error) { - if (check) { - throw error - } - } - } - - return subruleContent.join('\n\n') - } - - try { - return await rule.content(options, tree) - } catch (error) { - if (check) { - throw error - } - } - - throw new Error('Failed to expand content') -} - -/** - * Returns the rule value from a single-rule record. - * Useful when aliasing rules or invoking them programmatically. - * - * Throws if there are no entries or more than one entry. - */ -export function getSoleRule(rules: T): T[keyof T] { - return getSoleRecord(rules as Record) -} - -/** - * Returns the rule key from a single-rule record. - * Useful for comment placeholder validation. - * - * Throws if there are no entries or more than one entry. - */ -export function getSoleRuleKey(rules: T): keyof T { - const keys = Object.keys(rules) - if (keys.length !== 1) { - throw new Error(`Expected exactly one rule, found ${keys.length}`) - } - - return keys[0] -} - -/** - * Get the sole entry in a record. - * - * Useful for working with Rules records - * that are only supposed to contain a single rule. - * - * @param record The record to get the sole entry from - * @returns The value of the sole entry in the record - * @throws If there are no entries or more than one entry - */ -function getSoleRecord(record: Record): V { - const recordValues = Object.values(record) - if (recordValues.length === 0) { - throw new Error('Found no entries in a "sole record" record. This should never happen') - } - - if (recordValues.length > 1) { - throw new Error('Found multiple entries in "sole record" record. This should never happen') - } - - return recordValues[0] -} diff --git a/packages/remark-mdat/src/lib/remark-mdat.ts b/packages/remark-mdat/src/lib/remark-mdat.ts deleted file mode 100644 index 93347c8..0000000 --- a/packages/remark-mdat/src/lib/remark-mdat.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { type Options as MdatOptions, mdat } from './mdast-utils/mdast-util-mdat' -import { deepMergeDefined } from './mdat/deep-merge-defined' -import { rulesSchema } from './mdat/rules' -import type { Root } from 'mdast' -import type { Plugin } from 'unified' -import { z } from 'zod' - -// Remark-mdat provides sensible default options -// for the lower-level mdat utility functions -export type Options = Partial - -const defaultOptions: Options = { - addMetaComment: false, - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - // One default rule out of the box - rules: { - mdat: `Powered by the Markdown Autophagic Template system: [mdat](https://github.com/kitschpatrol/mdat).`, - }, -} - -// Schema is exported for validation in other packages -export const optionsSchema = z - .object({ - addMetaComment: z.boolean().optional(), - closingPrefix: z.string().optional(), - keywordPrefix: z.string().optional(), - metaCommentIdentifier: z.string().optional(), - rules: rulesSchema.optional(), - }) - .describe('MDAT Options') - -/** - * A remark plugin that expands HTML comments in Markdown files. - */ -const remarkMdat: Plugin<[Options], Root> = function (options) { - const resolvedOptions = deepMergeDefined(defaultOptions, options) as Required - - return async function (tree, file) { - await mdat(tree, file, resolvedOptions) - } -} - -export default remarkMdat diff --git a/packages/remark-mdat/test/__snapshots__/mdat.test.ts.snap b/packages/remark-mdat/test/__snapshots__/mdat.test.ts.snap deleted file mode 100644 index 5893ab0..0000000 --- a/packages/remark-mdat/test/__snapshots__/mdat.test.ts.snap +++ /dev/null @@ -1,530 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`comment expansion > should expand comments 1`] = ` -"# The MDAT sample document - -## Basic comment expansion - - - -**A bold statement from test-rules.ts** - - - -## Basic comment clean up - - - -**A bold statement from test-rules.ts** - - - -## Prefixed comment - -Expansion only happens when \`--prefix mm-\` option is set: - - - -## Comment expansion with dynamic content - -Shows the name of the rules file: - - - -I was generated from test-rules.ts - - - -## Required expansion - -Inclusion is validated via \`--check\` option - - - -* I -* am -* a -* list -* that -* must -* be -* here - - - -## Expansions with options argument, canonical syntax - - - -🪴 I am between two ferns 🪴 - - - -## Same expansion with different options - - - -🌳 I am between two ferns 🌳 - - - -## Expansions with arguments, syntax forgiveness - - - -🪴 I am between two ferns 🪴 - - - -## Expansions via dot paths given arbitrary json files as rules - -Given e.g. \`--rules ./package.json\`, allow access to fields in the file: - - - - - -## Handling empty rule content - -This expansion rule always returns an empty string. The comment will not be expanded, MDAT will report the error. - - - - - -## Handling non-required rule errors - -This expansion rule always throws an error. The comment will not be expanded, and MDAT will report the error. - - - -## Ordered expansion - -Order in the document is validated via \`--check\` option - - - -I had to be last - - - - - -I had to be first - - - -## Inline expansions with paragraph elements - -This is a sentence with a "*test-rules.ts*" inside of it. - -## Multiple paragraphs - - - -I am a paragraph 1 - -I am a paragraph 2 - -I am a paragraph 3 - - - -## Multiple paragraphs blockquote - -> -> -> I am a paragraph 1 -> -> I am a paragraph 2 -> -> I am a paragraph 3 -> -> - -## Tags in code fence - -Should not expand - -\`\`\`html - -\`\`\` - -## Stacked expansions - - - -**A bold statement from test-rules.ts** - - - - - -**A bold statement from test-rules.ts** - - - -The following required an extra step to split html statements that were being interpreted as contiguous - -## Adjacent inline expansions - -A**A bold statement from test-rules.ts****A bold statement from test-rules.ts**Z - -## Adjacent top-level expansions - -**A bold statement from test-rules.ts****A bold statement from test-rules.ts**Z - -## Adjacent top-level expansions - -**A bold statement from test-rules.ts**Absolutely**A bold statement from test-rules.ts** - -## Adjacent top-level expansions with options - -🪴 I am between two ferns 🪴🪴 I am between two ferns 🪴 - -## Adjacent top-level expansions - -**A bold statement from test-rules.ts****A bold statement from test-rules.ts** - -## Adjacent top-level expansions with leading space - - **A bold statement from test-rules.ts****A bold statement from test-rules.ts** - -## Expansion with leading space - - **A bold statement from test-rules.ts** -" -`; - -exports[`comment expansion > should expand prefixed comments only 1`] = ` -"# The MDAT sample document - -## Basic comment expansion - - - -## Basic comment clean up - - - -Stale content that will be replaced - - - -## Prefixed comment - -Expansion only happens when \`--prefix mm-\` option is set: - - - -**A bold statement from test-rules.ts** - - - -## Comment expansion with dynamic content - -Shows the name of the rules file: - - - -## Required expansion - -Inclusion is validated via \`--check\` option - - - -## Expansions with options argument, canonical syntax - - - -## Same expansion with different options - - - -## Expansions with arguments, syntax forgiveness - - - -## Expansions via dot paths given arbitrary json files as rules - -Given e.g. \`--rules ./package.json\`, allow access to fields in the file: - - - - - -## Handling empty rule content - -This expansion rule always returns an empty string. The comment will not be expanded, MDAT will report the error. - - - -## Handling non-required rule errors - -This expansion rule always throws an error. The comment will not be expanded, and MDAT will report the error. - - - -## Ordered expansion - -Order in the document is validated via \`--check\` option - - - - - -## Inline expansions with paragraph elements - -This is a sentence with a "**" inside of it. - -## Multiple paragraphs - - - -## Multiple paragraphs blockquote - -> - -## Tags in code fence - -Should not expand - -\`\`\`html - -\`\`\` - -## Stacked expansions - - - - - -The following required an extra step to split html statements that were being interpreted as contiguous - -## Adjacent inline expansions - -AZ - -## Adjacent top-level expansions - -Z - -## Adjacent top-level expansions - -Absolutely - -## Adjacent top-level expansions with options - - - -## Adjacent top-level expansions - - - -## Adjacent top-level expansions with leading space - - - -## Expansion with leading space - - -" -`; - -exports[`comment expansion > should include the meta tag if asked 1`] = ` -" - -# The MDAT sample document - -## Basic comment expansion - - - -**A bold statement from test-rules.ts** - - - -## Basic comment clean up - - - -**A bold statement from test-rules.ts** - - - -## Prefixed comment - -Expansion only happens when \`--prefix mm-\` option is set: - - - -## Comment expansion with dynamic content - -Shows the name of the rules file: - - - -I was generated from test-rules.ts - - - -## Required expansion - -Inclusion is validated via \`--check\` option - - - -* I -* am -* a -* list -* that -* must -* be -* here - - - -## Expansions with options argument, canonical syntax - - - -🪴 I am between two ferns 🪴 - - - -## Same expansion with different options - - - -🌳 I am between two ferns 🌳 - - - -## Expansions with arguments, syntax forgiveness - - - -🪴 I am between two ferns 🪴 - - - -## Expansions via dot paths given arbitrary json files as rules - -Given e.g. \`--rules ./package.json\`, allow access to fields in the file: - - - - - -## Handling empty rule content - -This expansion rule always returns an empty string. The comment will not be expanded, MDAT will report the error. - - - - - -## Handling non-required rule errors - -This expansion rule always throws an error. The comment will not be expanded, and MDAT will report the error. - - - -## Ordered expansion - -Order in the document is validated via \`--check\` option - - - -I had to be last - - - - - -I had to be first - - - -## Inline expansions with paragraph elements - -This is a sentence with a "*test-rules.ts*" inside of it. - -## Multiple paragraphs - - - -I am a paragraph 1 - -I am a paragraph 2 - -I am a paragraph 3 - - - -## Multiple paragraphs blockquote - -> -> -> I am a paragraph 1 -> -> I am a paragraph 2 -> -> I am a paragraph 3 -> -> - -## Tags in code fence - -Should not expand - -\`\`\`html - -\`\`\` - -## Stacked expansions - - - -**A bold statement from test-rules.ts** - - - - - -**A bold statement from test-rules.ts** - - - -The following required an extra step to split html statements that were being interpreted as contiguous - -## Adjacent inline expansions - -A**A bold statement from test-rules.ts****A bold statement from test-rules.ts**Z - -## Adjacent top-level expansions - -**A bold statement from test-rules.ts****A bold statement from test-rules.ts**Z - -## Adjacent top-level expansions - -**A bold statement from test-rules.ts**Absolutely**A bold statement from test-rules.ts** - -## Adjacent top-level expansions with options - -🪴 I am between two ferns 🪴🪴 I am between two ferns 🪴 - -## Adjacent top-level expansions - -**A bold statement from test-rules.ts****A bold statement from test-rules.ts** - -## Adjacent top-level expansions with leading space - - **A bold statement from test-rules.ts****A bold statement from test-rules.ts** - -## Expansion with leading space - - **A bold statement from test-rules.ts** -" -`; diff --git a/packages/remark-mdat/test/assets/test-document.md b/packages/remark-mdat/test/assets/test-document.md deleted file mode 100644 index 73ac54c..0000000 --- a/packages/remark-mdat/test/assets/test-document.md +++ /dev/null @@ -1,127 +0,0 @@ -# The MDAT sample document - -## Basic comment expansion - - - -## Basic comment clean up - - - -Stale content that will be replaced - - - -## Prefixed comment - -Expansion only happens when `--prefix mm-` option is set: - - - -## Comment expansion with dynamic content - -Shows the name of the rules file: - - - -## Required expansion - -Inclusion is validated via `--check` option - - - -## Expansions with options argument, canonical syntax - - - -## Same expansion with different options - - - -## Expansions with arguments, syntax forgiveness - - - -## Expansions via dot paths given arbitrary json files as rules - -Given e.g. `--rules ./package.json`, allow access to fields in the file: - - - - - -## Handling empty rule content - -This expansion rule always returns an empty string. The comment will not be expanded, MDAT will report the error. - - - -## Handling non-required rule errors - -This expansion rule always throws an error. The comment will not be expanded, and MDAT will report the error. - - - -## Ordered expansion - -Order in the document is validated via `--check` option - - - - - -## Inline expansions with paragraph elements - -This is a sentence with a "__" inside of it. - -## Multiple paragraphs - - - -## Multiple paragraphs blockquote - -> - -## Tags in code fence - -Should not expand - -```html - -``` - -## Stacked expansions - - - - - -The following required an extra step to split html statements that were being interpreted as contiguous - -## Adjacent inline expansions - -AZ - -## Adjacent top-level expansions - -Z - -## Adjacent top-level expansions - -Absolutely - -## Adjacent top-level expansions with options - - - -## Adjacent top-level expansions - - - -## Adjacent top-level expansions with leading space - - - -## Expansion with leading space - - diff --git a/packages/remark-mdat/test/assets/test-rules-invalid.js b/packages/remark-mdat/test/assets/test-rules-invalid.js deleted file mode 100644 index e37171b..0000000 --- a/packages/remark-mdat/test/assets/test-rules-invalid.js +++ /dev/null @@ -1,5 +0,0 @@ -// This is a code sample for testing purposes -// It is intentionally malformed -export default { - basic: { rogue: "I don't conform to the Rules type" }, -} diff --git a/packages/remark-mdat/test/assets/test-rules.ts b/packages/remark-mdat/test/assets/test-rules.ts deleted file mode 100644 index 5176e2d..0000000 --- a/packages/remark-mdat/test/assets/test-rules.ts +++ /dev/null @@ -1,56 +0,0 @@ -// This is a code sample for testing purposes -import type { Rules } from '../../src/lib/mdat/rules' -import path from 'node:path' - -export default { - basic: '**A bold statement from test-rules.ts**', - 'basic-dynamic': { - content() { - return `I was generated from ${path.basename(import.meta.url)}` - }, - }, - 'basic-dynamic-no-metadata'() { - return `I was generated from ${path.basename(import.meta.url)}` - }, - 'basic-empty': '', - 'basic-inline': { - content() { - return `${path.basename(import.meta.url)}` - }, - }, - 'basic-list-required': { - applicationOrder: 1, - content: `- I\n- am\n- a\n- list\n- that\n- must\n- be\n- here`, - required: true, - }, - 'basic-multiple-paragraphs': 'I am a paragraph 1\n\nI am a paragraph 2\n\nI am a paragraph 3', - 'basic-options': { - content(options): string { - // Check if options is object - if (typeof options !== 'object') { - throw new TypeError('Options must be an object') - } - - const resolvedOptions = { - prefix: '', - suffix: '', - ...options, - } - - return `${resolvedOptions.prefix}I am between two ferns${resolvedOptions.suffix}` - }, - }, - 'basic-ordered-1': { - content: 'I had to be first', - order: 1, - }, - 'basic-ordered-2': { - content: 'I had to be last', - order: 2, - }, - 'basic-throws': { - content() { - throw new Error('I am a rule that always throws an error') - }, - }, -} satisfies Rules diff --git a/packages/remark-mdat/test/check.test.ts b/packages/remark-mdat/test/check.test.ts deleted file mode 100644 index 3d77046..0000000 --- a/packages/remark-mdat/test/check.test.ts +++ /dev/null @@ -1,244 +0,0 @@ -import remarkMdat, { type MdatCheckOptions, type Options, mdatCheck } from '../src' -import { type Root } from 'mdast' -import { remark } from 'remark' -import remarkGfm from 'remark-gfm' -import { type VFile } from 'vfile' -import { describe, expect, it } from 'vitest' - -async function expandStringToVfile(markdown: string, options: Options): Promise { - return remark().use(remarkGfm).use(remarkMdat, options).process(markdown) -} - -async function checkMarkdown(markdown: string, options: MdatCheckOptions): Promise { - return remark() - .use(remarkGfm) - .use( - () => - // eslint-disable-next-line unicorn/consistent-function-scoping - async function (tree, file) { - await mdatCheck(tree as Root, file, options) - }, - ) - .process(markdown) -} - -function stripAnsiEscapeCodes(text: string): string { - // This regex matches the escape sequences and removes them - // eslint-disable-next-line no-control-regex - const ansiEscapeRegex = /\u001B\[[\d;]*m/g - return text.replaceAll(ansiEscapeRegex, '') -} - -const options: Options = { - rules: { - 'optional-expansion': { - content: 'This is optional', - }, - 'required-first-expansion': { - content: 'This is required first', - order: 1, - required: true, - }, - 'required-second-expansion': { - content: 'This is required last', - order: 3, - required: true, - }, - }, -} - -describe('check validation', () => { - it('should not report errors when valid', async () => { - const markdown = `\n\n` - const result = await expandStringToVfile(markdown, options) - const foundError = result.messages.some((message) => message.fatal === true) - expect(foundError).toBeFalsy() - }) - - it('should report errors when required comments are missing', async () => { - const markdown = `\n` - const result = await expandStringToVfile(markdown, options) - const foundError = result.messages.some((message) => message.fatal === true) - expect(foundError).toBeTruthy() - }) - - it('should report errors when required comments are out of order', async () => { - const markdown = `\n\n\n` - const result = await expandStringToVfile(markdown, options) - const errorMessage = result.messages.find((message) => message.fatal === true) - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot(` - "Out of order: - ┌───────────────────────────────────────┬───────────────────────────────────────┐ - │ Current Order │ Required Order │ - ├───────────────────────────────────────┼───────────────────────────────────────┤ - │ 1. │ 1. │ - │ 2. │ 2. │ - └───────────────────────────────────────┴───────────────────────────────────────┘" - `) - }) - - it('should report errors when required comments are missing', async () => { - const markdown = `\n\n` - const result = await expandStringToVfile(markdown, options) - const errorMessage = result.messages.find((message) => message.fatal === true) - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Missing required: "`, - ) - }) - - it('should report errors when rules return nothing', async () => { - const badOptions: Options = { - ...options, - rules: { - ...options.rules, - 'rule-that-returns-nothing': '', - }, - } - const markdown = `\n\n\n` - const result = await expandStringToVfile(markdown, badOptions) - const errorMessage = result.messages.find((message) => message.fatal === true) - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Got empty content when expanding "`, - ) - }) - - it('should report errors when rules throw errors', async () => { - const badOptions: Options = { - ...options, - rules: { - ...options.rules, - 'rule-that-throws'() { - throw new Error('This rule throws') - }, - }, - } - const markdown = `\n\n\n` - const result = await expandStringToVfile(markdown, badOptions) - const errorMessage = result.messages.find((message) => message.fatal === true) - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Caught error expanding , Error message: "Failed to expand content""`, - ) - }) - - it('should report missing meta comments', async () => { - const metaOptions: MdatCheckOptions = { - addMetaComment: true, - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - paranoid: false, - rules: { placeholder: 'This is a placeholder' }, - } - const markdown = `\nThis is a placeholder\n\n` - const result = await checkMarkdown(markdown, metaOptions) - const errorMessage = result.messages.find((message) => message.fatal === true) - - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Missing meta comment"`, - ) - }) - - it('should report unwelcome meta comments', async () => { - const metaOptions: MdatCheckOptions = { - addMetaComment: false, - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - paranoid: false, - rules: { placeholder: 'This is a placeholder' }, - } - const markdown = `\n\nThis is a placeholder\n\n` - const result = await checkMarkdown(markdown, metaOptions) - const errorMessage = result.messages.find((message) => message.fatal === true) - - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Unexpected meta comment"`, - ) - }) - - it('should report multiple meta comments when none are wanted', async () => { - const metaOptions: MdatCheckOptions = { - addMetaComment: false, - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - paranoid: false, - rules: { placeholder: 'This is a placeholder' }, - } - const markdown = `\n\n\nThis is a placeholder\n\n` - const result = await checkMarkdown(markdown, metaOptions) - const errorMessage = result.messages.find( - (message) => message.message === 'Multiple meta comments', - ) - - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Multiple meta comments"`, - ) - }) - - it('should report multiple meta comments when a single one is wanted', async () => { - const metaOptions: MdatCheckOptions = { - addMetaComment: true, - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - paranoid: false, - rules: { placeholder: 'This is a placeholder' }, - } - const markdown = `\n\n\nThis is a placeholder\n\n` - const result = await checkMarkdown(markdown, metaOptions) - const errorMessage = result.messages.find( - (message) => message.message === 'Multiple meta comments', - ) - - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Multiple meta comments"`, - ) - }) - - it('should warn about missing rules', async () => { - const markdown = `\n\n\n` - const result = await expandStringToVfile(markdown, options) - const errorMessage = result.messages.find((message) => message.fatal === false) // "warn" level - - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Missing rule for: "`, - ) - }) - - it('should warn about missing prefixes', async () => { - const keywordOptions: Options = { - ...options, - keywordPrefix: 'mm-', - } - const markdown = `\n\n` - const result = await expandStringToVfile(markdown, keywordOptions) - const errorMessage = result.messages.find((message) => message.fatal === false) // "warn" level - - expect(errorMessage).toBeDefined() - expect(stripAnsiEscapeCodes(errorMessage!.message)).toMatchInlineSnapshot( - `"Missing prefix: "`, - ) - }) - - it('should not warn about missing prefixes in non-rules', async () => { - const keywordOptions: Options = { - ...options, - keywordPrefix: 'mm-', - } - const markdown = `\n\n` - const result = await expandStringToVfile(markdown, keywordOptions) - const errorMessage = result.messages.find((message) => message.fatal === false) // "warn" level - - expect(errorMessage).not.toBeDefined() - }) -}) diff --git a/packages/remark-mdat/test/mdat.test.ts b/packages/remark-mdat/test/mdat.test.ts deleted file mode 100644 index aef5d1c..0000000 --- a/packages/remark-mdat/test/mdat.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import remarkMdat, { type MdatCleanOptions, type Options, mdatClean, mdatSplit } from '../src' -import testRules from './assets/test-rules' -// @ts-expect-error - Intentionally invalid for testing purposes -import testRulesInvalid from './assets/test-rules-invalid' -import { type Root } from 'mdast' -import fs from 'node:fs/promises' -import { remark } from 'remark' -import remarkGfm from 'remark-gfm' -import { type VFile } from 'vfile' -import { describe, expect, it } from 'vitest' - -async function expandStringToString(markdown: string, options: Options): Promise { - const result = await remark().use(remarkGfm).use(remarkMdat, options).process(markdown) - return result.toString() -} - -// Export for linter -export async function cleanString(markdown: string, options: MdatCleanOptions): Promise { - const result = await remark() - .use(remarkGfm) - .use( - () => - // eslint-disable-next-line unicorn/consistent-function-scoping - function (tree: Root, file: VFile) { - mdatSplit(tree, file) - mdatClean(tree, file, options) - }, - ) - .process(markdown) - return result.toString() -} - -async function expandFileToString(file: string, options: Options): Promise { - const buffer = await fs.readFile(file) - const result = await remark().use(remarkGfm).use(remarkMdat, options).process(buffer) - return result.toString() -} - -describe('comment expansion', () => { - it('should expand comments', async () => { - const expandedString = await expandFileToString('./test/assets/test-document.md', { - rules: testRules, - }) - expect(expandedString.toString()).toMatchSnapshot() - }) - - it('should be idempotent', async () => { - const firstPass = await expandFileToString('./test/assets/test-document.md', { - rules: testRules, - }) - - const secondPass = await expandStringToString(firstPass, { - rules: testRules, - }) - - expect(firstPass.toString()).toEqual(secondPass.toString()) - }) - - it('should expand prefixed comments only', async () => { - const expandedString = await expandFileToString('./test/assets/test-document.md', { - keywordPrefix: 'mm-', - rules: testRules, - }) - - expect(expandedString.toString()).toMatchSnapshot() - }) - - it('should include the meta tag if asked', async () => { - const expandedString = await expandFileToString('./test/assets/test-document.md', { - addMetaComment: true, - rules: testRules, - }) - - expect(expandedString.toString()).toMatchSnapshot() - }) - - it('should throw an error if rule set is invalid', async () => { - await expect( - expandFileToString('./test/assets/test-document.md', { - rules: testRulesInvalid, - }), - ).rejects.toThrow() - }) -}) - -describe('keyword case sensitivity', () => { - it('should treat comment expansion keywords as case sensitive', async () => { - const markdown = `\n\n\n` - const options: Options = { - rules: { - // eslint-disable-next-line @typescript-eslint/naming-convention - KEYWORD: "I'm yelling", - kEyWoRd: "I'm emotional", - keyword: "I'm basic", - }, - } - const expandedString = await expandStringToString(markdown, options) - expect(expandedString.toString()).toMatchInlineSnapshot(` - " - - I'm yelling - - - - - - I'm emotional - - - - - - I'm basic - - - " - `) - }) -}) - -describe('compound rule handling', () => { - it('should expand compound rules', async () => { - const markdown = `\n` - const options: Options = { - rules: { - compoundKeyword: ['one', 'two', 'three'], - }, - } - const expandedString = await expandStringToString(markdown, options) - expect(expandedString.toString()).toMatchInlineSnapshot(` - " - - one - - two - - three - - - " - `) - }) - - it('should pass option arrays to compound rules', async () => { - const markdown = `\n` - const options: Options = { - rules: { - compound: [ - (options) => `My option is: ${(options as { option: string })?.option}`, - (options) => `My option is: ${(options as { option: string })?.option}`, - (options) => `My option is: ${(options as { option: string })?.option}`, - ], - }, - } - const expandedString = await expandStringToString(markdown, options) - expect(expandedString.toString()).toMatchInlineSnapshot(` - " - - My option is: yes - - My option is: it - - My option is: can - - - " - `) - }) -}) diff --git a/packages/remark-mdat/test/merge.test.ts b/packages/remark-mdat/test/merge.test.ts deleted file mode 100644 index cd707b0..0000000 --- a/packages/remark-mdat/test/merge.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { deepMergeDefined } from '../src/lib/mdat/deep-merge-defined' -import { type Options as MdatOptions } from '../src/lib/remark-mdat' -import { describe, expect, it } from 'vitest' - -describe('deep merge of defined values only', () => { - it('should not overwrite defined values with undefined in simple objects', () => { - type Test = { - baz: number | undefined - foo: string - } - - const a: Test = { - baz: 1, - foo: 'bar', - } - - const b: Test = { - baz: undefined, - foo: 'erm', - } - - const result = deepMergeDefined(a, b) - - expect(result).toEqual({ - baz: 1, - foo: 'erm', - }) - }) - - it('should not overwrite defined values in more complex mdat objects', () => { - const a: MdatOptions = { - addMetaComment: true, - rules: { - one: 'bla', - two: 'hmm', - }, - } - - const b: MdatOptions = { - addMetaComment: undefined, - rules: { - three: 'argh', - two: 'huh', - }, - } - - const result = deepMergeDefined(a, b) - - expect(result).toMatchInlineSnapshot(` - { - "addMetaComment": true, - "rules": { - "one": "bla", - "three": "argh", - "two": "huh", - }, - } - `) - }) - - it('should overwrite defined values with null', () => { - type Test = { - // eslint-disable-next-line @typescript-eslint/ban-types - baz: null | number - foo: string - } - - const a: Test = { - baz: 1, - foo: 'bar', - } - - const b: Test = { - // eslint-disable-next-line unicorn/no-null - baz: null, - foo: 'erm', - } - - const result = deepMergeDefined(a, b) - - expect(result).toEqual({ - // eslint-disable-next-line unicorn/no-null - baz: null, - foo: 'erm', - }) - }) -}) diff --git a/packages/remark-mdat/test/parse.test.ts b/packages/remark-mdat/test/parse.test.ts deleted file mode 100644 index 13ccc78..0000000 --- a/packages/remark-mdat/test/parse.test.ts +++ /dev/null @@ -1,524 +0,0 @@ -import { parseComment } from '../src/lib/mdat/parse' -import { describe, expect, it } from 'vitest' - -describe('basic comment keyword parsing', () => { - const basicOptions = { - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - } - - it('should not parse non-comments', () => { - expect(parseComment('', basicOptions)).toBeUndefined() - expect(parseComment('title() -->', basicOptions)).toBeUndefined() - }) - - it('should parse basic comments', () => { - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - }) - - it('should forgive spacing variations', () => { - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - }) - - it('should forgive extra garbage in basic comments', () => { - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - expect(parseComment('', basicOptions)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": {}, - "type": "open", - } - `) - }) - - const basicOptionsPrefixed = { - closingPrefix: '/', - keywordPrefix: 'tp.', - metaCommentIdentifier: '+', - } - - it('should parse prefixed comments', () => { - expect(parseComment('', basicOptionsPrefixed)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "tp.", - "options": {}, - "type": "open", - } - `) - }) -}) - -describe('keyword option argument parsing', () => { - const options = { - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - } - - it('should parse basic options', () => { - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": 1, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": true, - }, - "type": "open", - } - `) - }) - - it('should parse without parentheses', () => { - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": 1, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": true, - }, - "type": "open", - } - `) - }) - - it('should parse bare json into an object', () => { - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": 1, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": true, - }, - "type": "open", - } - `) - }) - - it('should parse bare json with wonky spacing', () => { - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": 1, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": true, - }, - "type": "open", - } - `) - }) - - it('should forgive spacing variations', () => { - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": 1, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": true, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": "😬", - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": 1, - }, - "type": "open", - } - `) - expect(parseComment('', options)).toMatchInlineSnapshot(` - { - "closingPrefix": "/", - "html": "", - "keyword": "title", - "keywordPrefix": "", - "options": { - "prefix": true, - }, - "type": "open", - } - `) - }) -}) - -describe('comment type detection', () => { - const options = { - closingPrefix: '/', - keywordPrefix: '', - metaCommentIdentifier: '+', - } - - it('should identify opening comments', () => { - expect(parseComment('', options)).toEqual({ - closingPrefix: '/', - html: '', - keyword: 'some-keyword', - keywordPrefix: '', - options: {}, - type: 'open', - }) - }) - - it('should identify snug opening comments', () => { - expect(parseComment('', options)).toEqual({ - closingPrefix: '/', - html: '', - keyword: 'some-keyword', - keywordPrefix: '', - options: {}, - type: 'open', - }) - }) - - it('should identify closing comments', () => { - expect(parseComment('', options)).toEqual({ - closingPrefix: '/', - html: '', - keyword: 'some-keyword', - keywordPrefix: '', - options: {}, - type: 'close', - }) - }) - - it('should identify snug closing comments', () => { - expect(parseComment('', options)).toEqual({ - closingPrefix: '/', - html: '', - keyword: 'some-keyword', - keywordPrefix: '', - options: {}, - type: 'close', - }) - }) - - it('should identify meta comments', () => { - expect(parseComment('', options)).toEqual({ - content: ' I am a meta comment ', - html: '', - type: 'meta', - }) - }) - - const nativeOptions = { - closingPrefix: '/', - keywordPrefix: 'tp.', - metaCommentIdentifier: '+', - } - - it('should identify native comments', () => { - expect(parseComment('', nativeOptions)).toEqual({ - content: 'I am a native comment', - html: '', - type: 'native', - }) - }) -}) diff --git a/packages/remark-mdat/test/split.test.ts b/packages/remark-mdat/test/split.test.ts deleted file mode 100644 index 5c6e4dd..0000000 --- a/packages/remark-mdat/test/split.test.ts +++ /dev/null @@ -1,391 +0,0 @@ -import { splitHtmlIntoMdastNodes } from '../src/lib/mdast-utils/mdast-util-mdat-split' -import { type Html } from 'mdast' -import { describe, expect, it } from 'vitest' - -function stringToMdastNode(value: string): Html { - return { - position: { - // Might be off by one... - end: { column: value.length + 1, line: 1, offset: value.length }, - start: { column: 1, line: 1, offset: 0 }, - }, - type: 'html', - value, - } -} - -describe('multi comment parsing', () => { - it('parse multi-comment html text', () => { - expect(splitHtmlIntoMdastNodes(stringToMdastNode(''))) - .toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 30, - "line": 1, - "offset": 29, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - expect(splitHtmlIntoMdastNodes(stringToMdastNode('Z'))) - .toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 15, - "line": 1, - "offset": 14, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 29, - "line": 1, - "offset": 28, - }, - "start": { - "column": 15, - "line": 1, - "offset": 14, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 30, - "line": 1, - "offset": 29, - }, - "start": { - "column": 29, - "line": 1, - "offset": 28, - }, - }, - "type": "text", - "value": "Z", - }, - ] - `) - expect( - splitHtmlIntoMdastNodes( - stringToMdastNode('Absolutely'), - ), - ).toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 35, - "line": 1, - "offset": 34, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 52, - "line": 1, - "offset": 51, - }, - "start": { - "column": 35, - "line": 1, - "offset": 34, - }, - }, - "type": "html", - "value": "Absolutely", - }, - { - "position": { - "end": { - "column": 66, - "line": 1, - "offset": 65, - }, - "start": { - "column": 52, - "line": 1, - "offset": 51, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - expect(splitHtmlIntoMdastNodes(stringToMdastNode(''))) - .toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 15, - "line": 1, - "offset": 14, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 29, - "line": 1, - "offset": 28, - }, - "start": { - "column": 15, - "line": 1, - "offset": 14, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - expect(splitHtmlIntoMdastNodes(stringToMdastNode(' '))) - .toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 2, - "line": 1, - "offset": 1, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "text", - "value": " ", - }, - { - "position": { - "end": { - "column": 16, - "line": 1, - "offset": 15, - }, - "start": { - "column": 2, - "line": 1, - "offset": 1, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 30, - "line": 1, - "offset": 29, - }, - "start": { - "column": 16, - "line": 1, - "offset": 15, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - expect(splitHtmlIntoMdastNodes(stringToMdastNode(' '))).toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 2, - "line": 1, - "offset": 1, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "text", - "value": " ", - }, - { - "position": { - "end": { - "column": 16, - "line": 1, - "offset": 15, - }, - "start": { - "column": 2, - "line": 1, - "offset": 1, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - expect(splitHtmlIntoMdastNodes(stringToMdastNode(' '))).toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 2, - "line": 1, - "offset": 1, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "text", - "value": " ", - }, - { - "position": { - "end": { - "column": 16, - "line": 1, - "offset": 15, - }, - "start": { - "column": 2, - "line": 1, - "offset": 1, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - // TODO Currently not supported! Separate pass for expansion inside HTML? - expect( - splitHtmlIntoMdastNodes( - stringToMdastNode(''), - ), - ).toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 15, - "line": 1, - "offset": 14, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 36, - "line": 1, - "offset": 35, - }, - "start": { - "column": 15, - "line": 1, - "offset": 14, - }, - }, - "type": "html", - "value": "", - }, - { - "position": { - "end": { - "column": 50, - "line": 1, - "offset": 49, - }, - "start": { - "column": 36, - "line": 1, - "offset": 35, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - // TODO Currently not supported! Separate pass for expansion inside HTML? - expect(splitHtmlIntoMdastNodes(stringToMdastNode(''))) - .toMatchInlineSnapshot(` - [ - { - "position": { - "end": { - "column": 22, - "line": 1, - "offset": 21, - }, - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "type": "html", - "value": "", - }, - ] - `) - }) -}) diff --git a/packages/remark-mdat/tsconfig.build.json b/packages/remark-mdat/tsconfig.build.json deleted file mode 100644 index 0a05ac3..0000000 --- a/packages/remark-mdat/tsconfig.build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "noEmit": false, - "declaration": true, - "outDir": "./dist", - "emitDeclarationOnly": true - }, - "include": ["src/**/*"] -} diff --git a/packages/remark-mdat/tsconfig.json b/packages/remark-mdat/tsconfig.json deleted file mode 100644 index 11f8076..0000000 --- a/packages/remark-mdat/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["**/*", "**.*"], - "exclude": ["dist"] -} diff --git a/packages/remark-mdat/tsup.config.ts b/packages/remark-mdat/tsup.config.ts deleted file mode 100644 index 3615578..0000000 --- a/packages/remark-mdat/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineConfig } from 'tsup' - -export default defineConfig({ - clean: true, - // This is a nice idea, to keep the direct dependencies thin, but it generates - // ugly names - // dts: { - // resolve: true, - // }, - dts: false, // Calling tsc directly gives cleaner output? - entry: ['src/index.ts'], - format: 'esm', - minify: true, - platform: 'node', - splitting: false, - target: 'node18', -}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b76be9..214db1a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,15 +7,6 @@ settings: importers: .: - devDependencies: - '@kitschpatrol/shared-config': - specifier: ^4.6.6 - version: 4.6.6(cspell@8.8.4)(eslint@8.57.0)(mdat@0.6.13(typescript@5.4.5))(postcss-html@1.7.0)(prettier@3.3.0)(stylelint@16.6.1(typescript@5.4.5))(svelte@4.2.17)(typescript@5.4.5) - bumpp: - specifier: ^9.4.1 - version: 9.4.1 - - packages/mdat: dependencies: '@clack/prompts': specifier: ^0.7.0 @@ -27,8 +18,8 @@ importers: specifier: ^4.0.4 version: 4.0.4 '@types/node': - specifier: ^20.14.1 - version: 20.14.1 + specifier: ^20.14.2 + version: 20.14.2 '@types/unist': specifier: ^3.0.2 version: 3.0.2 @@ -43,10 +34,10 @@ importers: version: 9.0.0(typescript@5.4.5) cosmiconfig-typescript-loader: specifier: ^5.0.0 - version: 5.0.0(@types/node@20.14.1)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5) + version: 5.0.0(@types/node@20.14.2)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5) execa: - specifier: ^9.1.0 - version: 9.1.0 + specifier: ^9.2.0 + version: 9.2.0 globby: specifier: ^14.0.1 version: 14.0.1 @@ -57,6 +48,12 @@ importers: specifier: ^4.0.0 version: 4.0.0 devDependencies: + '@kitschpatrol/shared-config': + specifier: ^4.6.7 + version: 4.6.7(cspell@8.8.4)(eslint@8.57.0)(mdat@0.6.16(typescript@5.4.5))(postcss-html@1.7.0)(prettier@3.3.1)(stylelint@16.6.1(typescript@5.4.5))(svelte@4.2.18)(typescript@5.4.5) + bumpp: + specifier: ^9.4.1 + version: 9.4.1 chalk: specifier: ^5.3.0 version: 5.3.0 @@ -97,8 +94,8 @@ importers: specifier: ^4.0.0 version: 4.0.0 remark-mdat: - specifier: workspace:* - version: link:../remark-mdat + specifier: ^0.7.0 + version: 0.7.0 to-vfile: specifier: ^8.0.0 version: 8.0.0 @@ -106,8 +103,8 @@ importers: specifier: ^8.1.0 version: 8.1.0(postcss@8.4.38)(typescript@5.4.5) type-fest: - specifier: ^4.19.0 - version: 4.19.0 + specifier: ^4.20.0 + version: 4.20.0 typescript: specifier: ^5.4.5 version: 5.4.5 @@ -119,7 +116,7 @@ importers: version: 6.0.1 vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.14.1) + version: 1.6.0(@types/node@20.14.2) yargs: specifier: ^17.7.2 version: 17.7.2 @@ -127,67 +124,6 @@ importers: specifier: ^3.23.8 version: 3.23.8 - packages/remark-mdat: - dependencies: - '@types/mdast': - specifier: ^4.0.4 - version: 4.0.4 - '@types/node': - specifier: ^20.14.1 - version: 20.14.1 - '@types/unist': - specifier: ^3.0.2 - version: 3.0.2 - devDependencies: - chalk: - specifier: ^5.3.0 - version: 5.3.0 - cli-table3: - specifier: ^0.6.5 - version: 0.6.5 - deepmerge-ts: - specifier: ^7.0.2 - version: 7.0.2 - hast-util-from-html: - specifier: ^2.0.1 - version: 2.0.1 - json5: - specifier: ^2.2.3 - version: 2.2.3 - remark: - specifier: ^15.0.1 - version: 15.0.1 - remark-gfm: - specifier: ^4.0.0 - version: 4.0.0 - tsup: - specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.38)(typescript@5.4.5) - type-fest: - specifier: ^4.19.0 - version: 4.19.0 - typescript: - specifier: ^5.4.5 - version: 5.4.5 - unified: - specifier: ^11.0.4 - version: 11.0.4 - unist-util-visit: - specifier: ^5.0.0 - version: 5.0.0 - vfile: - specifier: ^6.0.1 - version: 6.0.1 - vfile-message: - specifier: ^4.0.2 - version: 4.0.2 - vitest: - specifier: ^1.6.0 - version: 1.6.0(@types/node@20.14.1) - zod: - specifier: ^3.23.8 - version: 3.23.8 - packages: '@ampproject/remapping@2.3.0': @@ -200,20 +136,20 @@ packages: '@astrojs/compiler@2.8.0': resolution: {integrity: sha512-yrpD1WRGqsJwANaDIdtHo+YVjvIOFAjC83lu5qENIgrafwZcJgSXDuwVMXOgok4tFzpeKLsFQ6c3FoUdloLWBQ==} - '@babel/code-frame@7.24.6': - resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.6': - resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.6': - resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.24.6': - resolution: {integrity: sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==} + '@babel/runtime@7.24.7': + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} '@chevrotain/cst-dts-gen@11.0.3': @@ -239,10 +175,6 @@ packages: bundledDependencies: - is-unicode-supported - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - '@cspell/cspell-bundled-dicts@8.8.4': resolution: {integrity: sha512-k9ZMO2kayQFXB3B45b1xXze3MceAMNy9U+D7NTnWB1i3S0y8LhN53U9JWWgqHGPQaHaLHzizL7/w1aGHTA149Q==} engines: {node: '>=18'} @@ -294,8 +226,8 @@ packages: '@cspell/dict-dart@2.0.3': resolution: {integrity: sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw==} - '@cspell/dict-data-science@1.0.11': - resolution: {integrity: sha512-TaHAZRVe0Zlcc3C23StZqqbzC0NrodRwoSAc8dis+5qLeLLnOCtagYQeROQvDlcDg3X/VVEO9Whh4W/z4PAmYQ==} + '@cspell/dict-data-science@2.0.1': + resolution: {integrity: sha512-xeutkzK0eBe+LFXOFU2kJeAYO6IuFUc1g7iRLr7HeCmlC4rsdGclwGHh61KmttL3+YHQytYStxaRBdGAXWC8Lw==} '@cspell/dict-django@4.1.0': resolution: {integrity: sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w==} @@ -390,8 +322,8 @@ packages: '@cspell/dict-public-licenses@2.0.7': resolution: {integrity: sha512-KlBXuGcN3LE7tQi/GEqKiDewWGGuopiAD0zRK1QilOx5Co8XAvs044gk4MNIQftc8r0nHeUI+irJKLGcR36DIQ==} - '@cspell/dict-python@4.1.11': - resolution: {integrity: sha512-XG+v3PumfzUW38huSbfT15Vqt3ihNb462ulfXifpQllPok5OWynhszCLCRQjQReV+dgz784ST4ggRxW452/kVg==} + '@cspell/dict-python@4.2.1': + resolution: {integrity: sha512-9X2jRgyM0cxBoFQRo4Zc8oacyWnXi+0/bMI5FGibZNZV4y/o9UoFEr6agjU260/cXHTjIdkX233nN7eb7dtyRg==} '@cspell/dict-r@2.0.1': resolution: {integrity: sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA==} @@ -405,8 +337,8 @@ packages: '@cspell/dict-scala@5.0.2': resolution: {integrity: sha512-v97ClgidZt99JUm7OjhQugDHmhx4U8fcgunHvD/BsXWjXNj4cTr0m0YjofyZoL44WpICsNuFV9F/sv9OM5HUEw==} - '@cspell/dict-software-terms@3.4.1': - resolution: {integrity: sha512-JgNHVdWEUhZKCYBiAjsLojkw8WhvsTXyk/IfFby0Lzbl+/AoJvL/XZqr0pvqfpBjbv7pwtnjahrbGxPRCOV+gA==} + '@cspell/dict-software-terms@3.4.2': + resolution: {integrity: sha512-mdnTfWSWQVGdth7OTlX4WsNsHGBiBEzIEs8/rmmq//IDbjBYpIdbA4d/pZRhfUF0CpXkQdytccyg0EHtmN4+7w==} '@cspell/dict-sql@2.1.3': resolution: {integrity: sha512-SEyTNKJrjqD6PAzZ9WpdSu6P7wgdNtGV2RV8Kpuw1x6bV+YsSptuClYG+JSdRExBTE6LwIe1bTklejUp3ZP8TQ==} @@ -806,55 +738,55 @@ packages: resolution: {integrity: sha512-f5DRIOZf7wxogefH03RjMPMdBF7ADTWUMoOs9kaJo06EfwF+aFhMZMDZxHg/Xe12hptN9xoZjGso2fdjapBRIA==} engines: {node: '>=10'} - '@kitschpatrol/cspell-config@4.6.6': - resolution: {integrity: sha512-gztzEkBtXYbeL3eqOWiVK69/tUDh7z0b0NijEkiGnAQls2BwZXshY3lCfIUbchMNVY/Rk2pIoN1Je8xwcC/L3w==} + '@kitschpatrol/cspell-config@4.6.7': + resolution: {integrity: sha512-dtllXIR7ZmbY8MOQ8nWVHN3X5U4Uwz0uW5MSqQL8nb8SakivLMWo6p3D8XSPfuaOcXjd3p1/vhvyZzMC9GxZbA==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true peerDependencies: - cspell: ^8.8.1 + cspell: ^8.8.4 - '@kitschpatrol/eslint-config@4.6.6': - resolution: {integrity: sha512-UrLAymLbA6yNgyPIHJsr0Q1BfWpXijsNS25LWN/t2+/evBi1mx+OfJxqLxoWm2uIQONCCqlP4VD7PreyCrKZ4Q==} + '@kitschpatrol/eslint-config@4.6.7': + resolution: {integrity: sha512-MgiZvwWqaD5pgdMVlmwLyFXZU2P6LQhUxGVptocfw8L4j+J/sZI4OJPjUoIeWI1XtMjBtMQbUJk2OG47muK8jg==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true peerDependencies: eslint: ^8.57.0 - '@kitschpatrol/mdat-config@4.6.6': - resolution: {integrity: sha512-Z1rvWp4eexpA/uVheOi9KVd//d9eySQJPPfaPDqLAKavAqMpXzZYGaGiP3o28FqPYzcf7HmDEM8GeZvqgdDfFA==} + '@kitschpatrol/mdat-config@4.6.7': + resolution: {integrity: sha512-XVPxrL4MBXiE7kk8Mew2Wy6D2zsplLT6ZEp0OIL+oDynhLMPqucvo5K81d/5bkPUsRhN+y4AnV2uu5xzA9HRAA==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true peerDependencies: - mdat: ^0.6.12 + mdat: ^0.6.15 - '@kitschpatrol/prettier-config@4.6.6': - resolution: {integrity: sha512-yS8rYcZkResyd6hgfcGOkgeHXzO9JNq1OUM7kbLTTe2HjVJ9yOAYNElKrsCMveyoDnZX+wSuHNpjbmAIGwAO4A==} + '@kitschpatrol/prettier-config@4.6.7': + resolution: {integrity: sha512-iT3cYWeKVuNwaQjpFCtOxUCCzgDYs/4aFTauXZEjHWSHWzgJFbaAUS80q6HUcr9wYtG0hM+QwdNzTfeWBVE0Hg==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true peerDependencies: - prettier: ^3.2.5 + prettier: ^3.3.0 - '@kitschpatrol/remark-config@4.6.6': - resolution: {integrity: sha512-CK32JzcaTB0KVwfOKFu/ToYRRKbh9AJt+ELybN6KJwa8Ku4mbR6juOwFF5LfdYUQULROyNvBhTai2ms62ioenQ==} + '@kitschpatrol/remark-config@4.6.7': + resolution: {integrity: sha512-kdKH6G32W8E7RTAbF07qqYDSbxx2aZQWmo9D6VIFfO+k+LUBuR1NxSMtM/y7iYn4sRxh8UXZOlOyv5IOzJQM8A==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true - '@kitschpatrol/repo-config@4.6.6': - resolution: {integrity: sha512-9Vrf+5d4qx/s3hmjewRIWEYHK8D6lWClYd6Q8lMwQczV5/N/DVjvmlUuza7BuW+FqxJMaFNuBwHkk6h3u5UYqg==} + '@kitschpatrol/repo-config@4.6.7': + resolution: {integrity: sha512-tDO1TxajteQuQ2NZZJOQAKdKpjtFquFjejJbbV3y1QJI5C7EEKC0HIS9qUBebavvj/dTzCis8W3qXmnnQ8EG3Q==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true - '@kitschpatrol/shared-config@4.6.6': - resolution: {integrity: sha512-EEo/SdFr1n3F9b3W0nSPX4gLINeHNoGhMM1uoIpBYiFg9uLQFTIdxS7KxiGqVOQyLxu3RQHSi2X/tMAF7bN9cw==} + '@kitschpatrol/shared-config@4.6.7': + resolution: {integrity: sha512-YAuFq7MMWH8EPgoCOo0H3h1MAiJ7gaiJOypc6IMecDxChqY8QHcRAoQY89p6cT6k8JjBsYGx3HduYo+0yGQLJA==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true - '@kitschpatrol/stylelint-config@4.6.6': - resolution: {integrity: sha512-dW+aXIu0moyoq3tEoINCPFYOvFYKbkS1xCIMGL/rwtxA3DU+H4v01mKwhVBZKLdvyCJIE9DHYrIoxM9ygbkE3g==} + '@kitschpatrol/stylelint-config@4.6.7': + resolution: {integrity: sha512-5fx6osOvptbPZdwSZuqg9sUkwXvYfFnLeypkRQf3Cx+GskzR9ihN0K01Zj/pI5Owbe2thE3+skfn18M4uOMPQw==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true peerDependencies: - stylelint: ^16.5.0 + stylelint: ^16.6.1 '@kitschpatrol/tldraw-cli@4.5.4': resolution: {integrity: sha512-sYMjIReF453ELQT0wczRLzyN1PWqw6UJ2PQzHgqNkfa18U3Qvae78HrBhhiVN5/eBqS65sqT4GUQygQPPSp+4Q==} @@ -1052,8 +984,8 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@20.14.1': - resolution: {integrity: sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA==} + '@types/node@20.14.2': + resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1337,8 +1269,8 @@ packages: bare-path@2.1.3: resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} - bare-stream@2.0.1: - resolution: {integrity: sha512-ubLyoDqPnUf5o0kSFp709HC0WRZuxVuh4pbte5eY95Xvx5bdvz07c2JFmXBfqqe60q+9PJ8S4X5GRvmcNSKMxg==} + bare-stream@2.1.0: + resolution: {integrity: sha512-Wrsczv6c4ejfZBCyG+1lw1Fg7C0Ljkw6PCZbp3BieMBarvp7yi0NKwiEkSq6HsW0NcnO+N9ObYZgEm+gJT0mhg==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1423,8 +1355,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001627: - resolution: {integrity: sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==} + caniuse-lite@1.0.30001629: + resolution: {integrity: sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1507,10 +1439,6 @@ packages: resolution: {integrity: sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==} engines: {node: '>=8'} - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} - engines: {node: 10.* || >= 12.*} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -1717,17 +1645,13 @@ packages: decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} - deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge-ts@7.0.2: - resolution: {integrity: sha512-kt42SClSQ1DTvAdUtPlZfcCHQxiiLG0nIRu6KJEnhRUc1WJwo1ZQwWcUDRw4ZCHcOUk+HIiTBhohGS/lLtITqQ==} - engines: {node: '>=16.0.0'} - define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -1806,8 +1730,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.4.789: - resolution: {integrity: sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==} + electron-to-chromium@1.4.795: + resolution: {integrity: sha512-hHo4lK/8wb4NUa+NJYSFyJ0xedNHiR6ylilDtb8NUW9d4dmBFmGiecYEKCEbti1wTNzbKXLfl4hPWEkAFbHYlw==} emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} @@ -1953,8 +1877,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-es-x@7.6.0: - resolution: {integrity: sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==} + eslint-plugin-es-x@7.7.0: + resolution: {integrity: sha512-aP3qj8BwiEDPttxQkZdI221DLKq9sI/qHolE2YSQL1/9+xk7dTV+tB1Fz8/IaCA+lnLA1bDEnvaS2LKs0k2Uig==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' @@ -2080,9 +2004,9 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} - execa@9.1.0: - resolution: {integrity: sha512-lSgHc4Elo2m6bUDhc3Hl/VxvUDJdQWI40RZ4KMY9bKRc+hgMOT7II/JjbNDhI8VnMtrCb7U/fhpJIkLORZozWw==} - engines: {node: '>=18'} + execa@9.2.0: + resolution: {integrity: sha512-vpOyYg7UAVKLAWWtRS2gAdgkT7oJbCn0me3gmUmxZih4kd3MF/oo8kNTBTIbkO3yuuF5uB4ZCZfn8BOolITYhg==} + engines: {node: ^18.19.0 || >=20.5.0} express@4.19.2: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} @@ -2377,18 +2301,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hast-util-from-html@2.0.1: - resolution: {integrity: sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==} - - hast-util-from-parse5@8.0.1: - resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} - - hast-util-parse-selector@4.0.0: - resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - - hastscript@8.0.0: - resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} - hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -2680,12 +2592,12 @@ packages: iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} - jackspeak@3.3.0: - resolution: {integrity: sha512-glPiBfKguqA7v8JsXO3iLjJWZ9FV1vNpoI0I9hI9Mnk5yetO9uPLSpiCEmiVijAssv2f54HpvtzvAHfhPieiDQ==} + jackspeak@3.4.0: + resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} engines: {node: '>=14'} - jiti@1.21.1: - resolution: {integrity: sha512-KMXpzEJMsOFyRj6ZpDTnnlJrdr9umUY+eut5vlRvjVixohitnRFIRTFw9MEu9zPlBxTHZo6xD5ftKYiQZuJYQw==} + jiti@1.21.3: + resolution: {integrity: sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==} hasBin: true joycon@3.1.1: @@ -2920,8 +2832,8 @@ packages: mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - mdast-util-to-hast@13.1.0: - resolution: {integrity: sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==} + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} mdast-util-to-markdown@2.1.0: resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} @@ -2935,8 +2847,8 @@ packages: mdast-util-toc@7.1.0: resolution: {integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==} - mdat@0.6.13: - resolution: {integrity: sha512-nUJI59Rg7g8ljxoNCqjf3vTbVgzqeHbN66YN8vMSivHn+bc8KbH7gAxpRewcv97BgCaLOLfx75Kx8ivCyzdJlw==} + mdat@0.6.16: + resolution: {integrity: sha512-G4zoyc40daJeuPfuQjXDqHlCGIeHX1SFhj00iYMzVE1eoA1Q9atKjK1i1SvN1UDeent86LRDvS3xFa6jE8FJDg==} engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} hasBin: true @@ -3142,8 +3054,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.0: - resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} + mlly@1.7.1: + resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==} moo@0.5.2: resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} @@ -3361,9 +3273,6 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} - parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -3545,8 +3454,8 @@ packages: peerDependencies: prettier: ^3.0.3 - prettier-plugin-svelte@3.2.3: - resolution: {integrity: sha512-wJq8RunyFlWco6U0WJV5wNCM7zpBFakS76UBSbmzMGpncpK98NZABaE+s7n8/APDCEVNHXC5Mpq+MLebQtsRlg==} + prettier-plugin-svelte@3.2.4: + resolution: {integrity: sha512-tZv+ADfeOWFNQkXkRh6zUXE16w3Vla8x2Ug0B/EnSmjR4EnwdwZbGgL/liSwR1kcEALU5mAAyua98HBxheCxgg==} peerDependencies: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 @@ -3609,8 +3518,8 @@ packages: peerDependencies: prettier: ^3.0.3 - prettier@3.3.0: - resolution: {integrity: sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==} + prettier@3.3.1: + resolution: {integrity: sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==} engines: {node: '>=14'} hasBin: true @@ -3634,9 +3543,6 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - property-information@6.5.0: - resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} - propose@0.0.5: resolution: {integrity: sha512-Jary1vb+ap2DIwOGfyiadcK4x1Iu3pzpkDBy8tljFPmQvnc9ES3m1PMZOMiWOG50cfoAyYNtGeBzrp+Rlh4G9A==} @@ -3883,9 +3789,9 @@ packages: remark-lint@10.0.0: resolution: {integrity: sha512-E8yHHDOJ8b+qI0G49BRu24pe8t0fNNBWv8ENQJpCGNrVeTeyBIGEbaUe1yuF7OG8faA6PVpcN/pqWjzW9fcBWQ==} - remark-mdat@0.6.13: - resolution: {integrity: sha512-MxTuFUyIa7klU1i2glNIK58/eKcU4XHktgtEj0Sdf2AWBUO7B33Bv5xGP+RHc9sSfvGpTw++L4yu25sOV+ke/Q==} - engines: {node: '>=16.0.0', pnpm: '>=8.0.0'} + remark-mdat@0.7.0: + resolution: {integrity: sha512-3kF9KIhAg+cLFtZaNhhDZJvC3gVzQ0XCIf+iTU2Fi5l3Q+2C/MMHxiMQLoKm3pHWq/x1nvAOxY6dfE5oB/MpmA==} + engines: {node: '>=18.0.0', pnpm: '>=8.0.0'} remark-mdx@3.0.1: resolution: {integrity: sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==} @@ -4251,8 +4157,8 @@ packages: svelte: optional: true - svelte@4.2.17: - resolution: {integrity: sha512-N7m1YnoXtRf5wya5Gyx3TWuTddI4nAyayyIWFojiWV5IayDYNV5i2mRp/7qNGol4DtxEYxljmrbgp1HM6hUbmQ==} + svelte@4.2.18: + resolution: {integrity: sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==} engines: {node: '>=16'} svg-tags@1.0.0: @@ -4382,8 +4288,8 @@ packages: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} - type-fest@4.19.0: - resolution: {integrity: sha512-CN2l+hWACRiejlnr68vY0/7734Kzu+9+TOslUXbSCQ1ruY9XIHDBSceVXCcHm/oXrdzhtLMMdJEKfemf1yXiZQ==} + type-fest@4.20.0: + resolution: {integrity: sha512-MBh+PHUHHisjXf4tlx0CFWoMdjx8zCMLJHOjnV1prABYZFHqtFOyauCIK2/7w4oIfwkF8iNhLtnJEfVY2vn3iw==} engines: {node: '>=16'} type-is@1.6.18: @@ -4542,8 +4448,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.2.12: - resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} + vite@5.2.13: + resolution: {integrity: sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -4604,9 +4510,6 @@ packages: walk-up-path@3.0.1: resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} - web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} @@ -4741,21 +4644,21 @@ snapshots: '@astrojs/compiler@2.8.0': {} - '@babel/code-frame@7.24.6': + '@babel/code-frame@7.24.7': dependencies: - '@babel/highlight': 7.24.6 + '@babel/highlight': 7.24.7 picocolors: 1.0.1 - '@babel/helper-validator-identifier@7.24.6': {} + '@babel/helper-validator-identifier@7.24.7': {} - '@babel/highlight@7.24.6': + '@babel/highlight@7.24.7': dependencies: - '@babel/helper-validator-identifier': 7.24.6 + '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 - '@babel/runtime@7.24.6': + '@babel/runtime@7.24.7': dependencies: regenerator-runtime: 0.14.1 @@ -4787,9 +4690,6 @@ snapshots: picocolors: 1.0.1 sisteransi: 1.0.5 - '@colors/colors@1.5.0': - optional: true - '@cspell/cspell-bundled-dicts@8.8.4': dependencies: '@cspell/dict-ada': 4.0.2 @@ -4832,12 +4732,12 @@ snapshots: '@cspell/dict-php': 4.0.7 '@cspell/dict-powershell': 5.0.4 '@cspell/dict-public-licenses': 2.0.7 - '@cspell/dict-python': 4.1.11 + '@cspell/dict-python': 4.2.1 '@cspell/dict-r': 2.0.1 '@cspell/dict-ruby': 5.0.2 '@cspell/dict-rust': 4.0.3 '@cspell/dict-scala': 5.0.2 - '@cspell/dict-software-terms': 3.4.1 + '@cspell/dict-software-terms': 3.4.2 '@cspell/dict-sql': 2.1.3 '@cspell/dict-svelte': 1.0.2 '@cspell/dict-swift': 2.0.1 @@ -4877,7 +4777,7 @@ snapshots: '@cspell/dict-dart@2.0.3': {} - '@cspell/dict-data-science@1.0.11': {} + '@cspell/dict-data-science@2.0.1': {} '@cspell/dict-django@4.1.0': {} @@ -4941,9 +4841,9 @@ snapshots: '@cspell/dict-public-licenses@2.0.7': {} - '@cspell/dict-python@4.1.11': + '@cspell/dict-python@4.2.1': dependencies: - '@cspell/dict-data-science': 1.0.11 + '@cspell/dict-data-science': 2.0.1 '@cspell/dict-r@2.0.1': {} @@ -4953,7 +4853,7 @@ snapshots: '@cspell/dict-scala@5.0.2': {} - '@cspell/dict-software-terms@3.4.1': {} + '@cspell/dict-software-terms@3.4.2': {} '@cspell/dict-sql@2.1.3': {} @@ -5208,7 +5108,7 @@ snapshots: string-argv: 0.3.2 type-detect: 4.0.8 - '@kitschpatrol/cspell-config@4.6.6(cspell@8.8.4)(typescript@5.4.5)': + '@kitschpatrol/cspell-config@4.6.7(cspell@8.8.4)(typescript@5.4.5)': dependencies: '@pinojs/json-colorizer': 4.0.0 cosmiconfig: 9.0.0(typescript@5.4.5) @@ -5218,7 +5118,7 @@ snapshots: transitivePeerDependencies: - typescript - '@kitschpatrol/eslint-config@4.6.6(eslint@8.57.0)(svelte@4.2.17)(typescript@5.4.5)': + '@kitschpatrol/eslint-config@4.6.7(eslint@8.57.0)(svelte@4.2.18)(typescript@5.4.5)': dependencies: '@html-eslint/eslint-plugin': 0.24.1 '@html-eslint/parser': 0.24.1 @@ -5235,8 +5135,8 @@ snapshots: eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-mdx: 3.1.5(eslint@8.57.0) eslint-plugin-n: 16.6.2(eslint@8.57.0) - eslint-plugin-perfectionist: 2.10.0(astro-eslint-parser@0.16.3)(eslint@8.57.0)(svelte@4.2.17)(typescript@5.4.5) - eslint-plugin-svelte: 2.39.0(eslint@8.57.0)(svelte@4.2.17) + eslint-plugin-perfectionist: 2.10.0(astro-eslint-parser@0.16.3)(eslint@8.57.0)(svelte@4.2.18)(typescript@5.4.5) + eslint-plugin-svelte: 2.39.0(eslint@8.57.0)(svelte@4.2.18) eslint-plugin-unicorn: 51.0.1(eslint@8.57.0) execa: 8.0.1 fs-extra: 11.2.0 @@ -5248,33 +5148,33 @@ snapshots: - typescript - vue-eslint-parser - '@kitschpatrol/mdat-config@4.6.6(mdat@0.6.13(typescript@5.4.5))(typescript@5.4.5)': + '@kitschpatrol/mdat-config@4.6.7(mdat@0.6.16(typescript@5.4.5))(typescript@5.4.5)': dependencies: '@pinojs/json-colorizer': 4.0.0 cosmiconfig: 9.0.0(typescript@5.4.5) execa: 8.0.1 fs-extra: 11.2.0 - mdat: 0.6.13(typescript@5.4.5) + mdat: 0.6.16(typescript@5.4.5) transitivePeerDependencies: - typescript - '@kitschpatrol/prettier-config@4.6.6(prettier@3.3.0)(svelte@4.2.17)(typescript@5.4.5)': + '@kitschpatrol/prettier-config@4.6.7(prettier@3.3.1)(svelte@4.2.18)(typescript@5.4.5)': dependencies: '@pinojs/json-colorizer': 4.0.0 - '@prettier/plugin-php': 0.22.2(prettier@3.3.0) - '@prettier/plugin-ruby': 4.0.4(prettier@3.3.0) - '@prettier/plugin-xml': 3.4.1(prettier@3.3.0) + '@prettier/plugin-php': 0.22.2(prettier@3.3.1) + '@prettier/plugin-ruby': 4.0.4(prettier@3.3.1) + '@prettier/plugin-xml': 3.4.1(prettier@3.3.1) cosmiconfig: 9.0.0(typescript@5.4.5) execa: 8.0.1 fs-extra: 11.2.0 - prettier: 3.3.0 + prettier: 3.3.1 prettier-plugin-astro: 0.13.0 - prettier-plugin-pkg: 0.18.1(prettier@3.3.0) - prettier-plugin-sh: 0.14.0(prettier@3.3.0) - prettier-plugin-sql: 0.18.0(prettier@3.3.0) - prettier-plugin-svelte: 3.2.3(prettier@3.3.0)(svelte@4.2.17) - prettier-plugin-tailwindcss: 0.5.14(prettier-plugin-astro@0.13.0)(prettier-plugin-svelte@3.2.3(prettier@3.3.0)(svelte@4.2.17))(prettier@3.3.0) - prettier-plugin-toml: 2.0.1(prettier@3.3.0) + prettier-plugin-pkg: 0.18.1(prettier@3.3.1) + prettier-plugin-sh: 0.14.0(prettier@3.3.1) + prettier-plugin-sql: 0.18.0(prettier@3.3.1) + prettier-plugin-svelte: 3.2.4(prettier@3.3.1)(svelte@4.2.18) + prettier-plugin-tailwindcss: 0.5.14(prettier-plugin-astro@0.13.0)(prettier-plugin-svelte@3.2.4(prettier@3.3.1)(svelte@4.2.18))(prettier@3.3.1) + prettier-plugin-toml: 2.0.1(prettier@3.3.1) transitivePeerDependencies: - '@ianvs/prettier-plugin-sort-imports' - '@prettier/plugin-pug' @@ -5292,7 +5192,7 @@ snapshots: - svelte - typescript - '@kitschpatrol/remark-config@4.6.6(prettier@3.3.0)(typescript@5.4.5)': + '@kitschpatrol/remark-config@4.6.7(prettier@3.3.1)(typescript@5.4.5)': dependencies: '@pinojs/json-colorizer': 4.0.0 cosmiconfig: 9.0.0(typescript@5.4.5) @@ -5343,14 +5243,14 @@ snapshots: remark-lint-strong-marker: 4.0.0 remark-lint-table-cell-padding: 5.0.0 remark-lint-unordered-list-marker-style: 4.0.0 - remark-preset-prettier: 2.0.1(prettier@3.3.0) + remark-preset-prettier: 2.0.1(prettier@3.3.1) remark-validate-links: 13.0.1 transitivePeerDependencies: - prettier - supports-color - typescript - '@kitschpatrol/repo-config@4.6.6(typescript@5.4.5)': + '@kitschpatrol/repo-config@4.6.7(typescript@5.4.5)': dependencies: '@pinojs/json-colorizer': 4.0.0 cosmiconfig: 9.0.0(typescript@5.4.5) @@ -5359,15 +5259,15 @@ snapshots: transitivePeerDependencies: - typescript - '@kitschpatrol/shared-config@4.6.6(cspell@8.8.4)(eslint@8.57.0)(mdat@0.6.13(typescript@5.4.5))(postcss-html@1.7.0)(prettier@3.3.0)(stylelint@16.6.1(typescript@5.4.5))(svelte@4.2.17)(typescript@5.4.5)': + '@kitschpatrol/shared-config@4.6.7(cspell@8.8.4)(eslint@8.57.0)(mdat@0.6.16(typescript@5.4.5))(postcss-html@1.7.0)(prettier@3.3.1)(stylelint@16.6.1(typescript@5.4.5))(svelte@4.2.18)(typescript@5.4.5)': dependencies: - '@kitschpatrol/cspell-config': 4.6.6(cspell@8.8.4)(typescript@5.4.5) - '@kitschpatrol/eslint-config': 4.6.6(eslint@8.57.0)(svelte@4.2.17)(typescript@5.4.5) - '@kitschpatrol/mdat-config': 4.6.6(mdat@0.6.13(typescript@5.4.5))(typescript@5.4.5) - '@kitschpatrol/prettier-config': 4.6.6(prettier@3.3.0)(svelte@4.2.17)(typescript@5.4.5) - '@kitschpatrol/remark-config': 4.6.6(prettier@3.3.0)(typescript@5.4.5) - '@kitschpatrol/repo-config': 4.6.6(typescript@5.4.5) - '@kitschpatrol/stylelint-config': 4.6.6(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.4.5))(typescript@5.4.5) + '@kitschpatrol/cspell-config': 4.6.7(cspell@8.8.4)(typescript@5.4.5) + '@kitschpatrol/eslint-config': 4.6.7(eslint@8.57.0)(svelte@4.2.18)(typescript@5.4.5) + '@kitschpatrol/mdat-config': 4.6.7(mdat@0.6.16(typescript@5.4.5))(typescript@5.4.5) + '@kitschpatrol/prettier-config': 4.6.7(prettier@3.3.1)(svelte@4.2.18)(typescript@5.4.5) + '@kitschpatrol/remark-config': 4.6.7(prettier@3.3.1)(typescript@5.4.5) + '@kitschpatrol/repo-config': 4.6.7(typescript@5.4.5) + '@kitschpatrol/stylelint-config': 4.6.7(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.4.5))(typescript@5.4.5) '@pinojs/json-colorizer': 4.0.0 cosmiconfig: 9.0.0(typescript@5.4.5) execa: 8.0.1 @@ -5399,7 +5299,7 @@ snapshots: - typescript - vue-eslint-parser - '@kitschpatrol/stylelint-config@4.6.6(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.4.5))(typescript@5.4.5)': + '@kitschpatrol/stylelint-config@4.6.7(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.4.5))(typescript@5.4.5)': dependencies: '@pinojs/json-colorizer': 4.0.0 cosmiconfig: 9.0.0(typescript@5.4.5) @@ -5467,20 +5367,20 @@ snapshots: '@pkgr/core@0.1.1': {} - '@prettier/plugin-php@0.22.2(prettier@3.3.0)': + '@prettier/plugin-php@0.22.2(prettier@3.3.1)': dependencies: linguist-languages: 7.27.0 php-parser: 3.1.5 - prettier: 3.3.0 + prettier: 3.3.1 - '@prettier/plugin-ruby@4.0.4(prettier@3.3.0)': + '@prettier/plugin-ruby@4.0.4(prettier@3.3.1)': dependencies: - prettier: 3.3.0 + prettier: 3.3.1 - '@prettier/plugin-xml@3.4.1(prettier@3.3.0)': + '@prettier/plugin-xml@3.4.1(prettier@3.3.1)': dependencies: '@xml-tools/parser': 1.0.11 - prettier: 3.3.0 + prettier: 3.3.1 '@puppeteer/browsers@2.2.3': dependencies: @@ -5565,7 +5465,7 @@ snapshots: '@types/concat-stream@2.0.3': dependencies: - '@types/node': 20.14.1 + '@types/node': 20.14.2 '@types/debug@4.1.12': dependencies: @@ -5595,7 +5495,7 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@20.14.1': + '@types/node@20.14.2': dependencies: undici-types: 5.26.5 @@ -5621,7 +5521,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.14.1 + '@types/node': 20.14.2 optional: true '@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': @@ -5919,7 +5819,7 @@ snapshots: dependencies: bare-events: 2.3.1 bare-path: 2.1.3 - bare-stream: 2.0.1 + bare-stream: 2.1.0 optional: true bare-os@2.3.0: @@ -5930,7 +5830,7 @@ snapshots: bare-os: 2.3.0 optional: true - bare-stream@2.0.1: + bare-stream@2.1.0: dependencies: streamx: 2.18.0 optional: true @@ -5975,8 +5875,8 @@ snapshots: browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001627 - electron-to-chromium: 1.4.789 + caniuse-lite: 1.0.30001629 + electron-to-chromium: 1.4.795 node-releases: 2.0.14 update-browserslist-db: 1.0.16(browserslist@4.23.0) @@ -6020,8 +5920,8 @@ snapshots: defu: 6.1.4 dotenv: 16.4.5 giget: 1.2.3 - jiti: 1.21.1 - mlly: 1.7.0 + jiti: 1.21.3 + mlly: 1.7.1 ohash: 1.1.3 pathe: 1.1.2 perfect-debounce: 1.0.0 @@ -6042,7 +5942,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001627: {} + caniuse-lite@1.0.30001629: {} ccount@2.0.1: {} @@ -6050,7 +5950,7 @@ snapshots: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 - deep-eql: 4.1.3 + deep-eql: 4.1.4 get-func-name: 2.0.2 loupe: 2.3.7 pathval: 1.1.1 @@ -6140,12 +6040,6 @@ snapshots: parent-module: 2.0.0 resolve-from: 5.0.0 - cli-table3@0.6.5: - dependencies: - string-width: 4.2.3 - optionalDependencies: - '@colors/colors': 1.5.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -6225,11 +6119,11 @@ snapshots: core-util-is@1.0.3: {} - cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.1)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5): + cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.2)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5): dependencies: - '@types/node': 20.14.1 + '@types/node': 20.14.2 cosmiconfig: 9.0.0(typescript@5.4.5) - jiti: 1.21.1 + jiti: 1.21.3 typescript: 5.4.5 cosmiconfig@9.0.0(typescript@5.4.5): @@ -6378,14 +6272,12 @@ snapshots: dependencies: character-entities: 2.0.2 - deep-eql@4.1.3: + deep-eql@4.1.4: dependencies: type-detect: 4.0.8 deep-is@0.1.4: {} - deepmerge-ts@7.0.2: {} - define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 @@ -6458,7 +6350,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.4.789: {} + electron-to-chromium@1.4.795: {} emoji-regex@10.3.0: {} @@ -6705,7 +6597,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.6.0(eslint@8.57.0): + eslint-plugin-es-x@7.7.0(eslint@8.57.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.1 @@ -6718,7 +6610,7 @@ snapshots: eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0): dependencies: - '@babel/runtime': 7.24.6 + '@babel/runtime': 7.24.7 aria-query: 5.3.0 array-includes: 3.1.8 array.prototype.flatmap: 1.3.2 @@ -6762,7 +6654,7 @@ snapshots: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) builtins: 5.1.0 eslint: 8.57.0 - eslint-plugin-es-x: 7.6.0(eslint@8.57.0) + eslint-plugin-es-x: 7.7.0(eslint@8.57.0) get-tsconfig: 4.7.5 globals: 13.24.0 ignore: 5.3.1 @@ -6772,7 +6664,7 @@ snapshots: resolve: 1.22.8 semver: 7.6.2 - eslint-plugin-perfectionist@2.10.0(astro-eslint-parser@0.16.3)(eslint@8.57.0)(svelte@4.2.17)(typescript@5.4.5): + eslint-plugin-perfectionist@2.10.0(astro-eslint-parser@0.16.3)(eslint@8.57.0)(svelte@4.2.18)(typescript@5.4.5): dependencies: '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 @@ -6780,12 +6672,12 @@ snapshots: natural-compare-lite: 1.4.0 optionalDependencies: astro-eslint-parser: 0.16.3 - svelte: 4.2.17 + svelte: 4.2.18 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-svelte@2.39.0(eslint@8.57.0)(svelte@4.2.17): + eslint-plugin-svelte@2.39.0(eslint@8.57.0)(svelte@4.2.18): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@jridgewell/sourcemap-codec': 1.4.15 @@ -6799,16 +6691,16 @@ snapshots: postcss-safe-parser: 6.0.0(postcss@8.4.38) postcss-selector-parser: 6.1.0 semver: 7.6.2 - svelte-eslint-parser: 0.36.0(svelte@4.2.17) + svelte-eslint-parser: 0.36.0(svelte@4.2.18) optionalDependencies: - svelte: 4.2.17 + svelte: 4.2.18 transitivePeerDependencies: - supports-color - ts-node eslint-plugin-unicorn@51.0.1(eslint@8.57.0): dependencies: - '@babel/helper-validator-identifier': 7.24.6 + '@babel/helper-validator-identifier': 7.24.7 '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint/eslintrc': 2.1.4 ci-info: 4.0.0 @@ -6935,7 +6827,7 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 - execa@9.1.0: + execa@9.2.0: dependencies: '@sindresorhus/merge-streams': 4.0.0 cross-spawn: 7.0.3 @@ -7213,7 +7105,7 @@ snapshots: glob@10.4.1: dependencies: foreground-child: 3.1.1 - jackspeak: 3.3.0 + jackspeak: 3.4.0 minimatch: 9.0.4 minipass: 7.1.2 path-scurry: 1.11.1 @@ -7302,38 +7194,6 @@ snapshots: dependencies: function-bind: 1.1.2 - hast-util-from-html@2.0.1: - dependencies: - '@types/hast': 3.0.4 - devlop: 1.1.0 - hast-util-from-parse5: 8.0.1 - parse5: 7.1.2 - vfile: 6.0.1 - vfile-message: 4.0.2 - - hast-util-from-parse5@8.0.1: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.2 - devlop: 1.1.0 - hastscript: 8.0.0 - property-information: 6.5.0 - vfile: 6.0.1 - vfile-location: 5.0.2 - web-namespaces: 2.0.1 - - hast-util-parse-selector@4.0.0: - dependencies: - '@types/hast': 3.0.4 - - hastscript@8.0.0: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 6.5.0 - space-separated-tokens: 2.0.2 - hosted-git-info@2.8.9: {} hosted-git-info@7.0.2: @@ -7593,13 +7453,13 @@ snapshots: reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 - jackspeak@3.3.0: + jackspeak@3.4.0: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jiti@1.21.1: {} + jiti@1.21.3: {} joycon@3.1.1: {} @@ -7690,7 +7550,7 @@ snapshots: local-pkg@0.5.0: dependencies: - mlly: 1.7.0 + mlly: 1.7.1 pkg-types: 1.1.1 locate-character@3.0.0: {} @@ -7916,7 +7776,7 @@ snapshots: '@types/mdast': 4.0.4 unist-util-is: 6.0.0 - mdast-util-to-hast@13.1.0: + mdast-util-to-hast@13.2.0: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -7955,41 +7815,21 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit: 5.0.0 - mdat@0.6.13(typescript@5.4.5): + mdat@0.6.16(typescript@5.4.5): dependencies: '@clack/prompts': 0.7.0 '@kitschpatrol/tldraw-cli': 4.5.4(typescript@5.4.5) '@types/mdast': 4.0.4 - '@types/node': 20.14.1 + '@types/node': 20.14.2 '@types/unist': 3.0.2 '@types/which': 3.0.4 '@types/yargs': 17.0.32 - chalk: 5.3.0 - chevrotain: 11.0.3 cosmiconfig: 9.0.0(typescript@5.4.5) - cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.1)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5) - execa: 9.1.0 - find-up: 7.0.0 + cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.2)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5) + execa: 9.2.0 globby: 14.0.1 - is-executable: 2.0.1 - mdast-util-toc: 7.1.0 - nanoid: 5.0.7 - package-up: 5.0.0 - path-type: 5.0.0 - pkg-dir: 8.0.0 - plur: 5.1.0 - pretty-ms: 9.0.0 read-pkg: 9.0.1 - remark: 15.0.1 - remark-gfm: 4.0.0 - remark-mdat: 0.6.13 - to-vfile: 8.0.0 - type-fest: 4.19.0 - untildify: 5.0.0 - vfile: 6.0.1 which: 4.0.0 - yargs: 17.7.2 - zod: 3.23.8 transitivePeerDependencies: - bufferutil - supports-color @@ -8344,7 +8184,7 @@ snapshots: mkdirp@1.0.4: {} - mlly@1.7.0: + mlly@1.7.1: dependencies: acorn: 8.11.3 pathe: 1.1.2 @@ -8575,14 +8415,14 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.24.6 + '@babel/code-frame': 7.24.7 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 parse-json@7.1.1: dependencies: - '@babel/code-frame': 7.24.6 + '@babel/code-frame': 7.24.7 error-ex: 1.3.2 json-parse-even-better-errors: 3.0.2 lines-and-columns: 2.0.4 @@ -8590,16 +8430,12 @@ snapshots: parse-json@8.1.0: dependencies: - '@babel/code-frame': 7.24.6 + '@babel/code-frame': 7.24.7 index-to-position: 0.1.2 - type-fest: 4.19.0 + type-fest: 4.20.0 parse-ms@4.0.0: {} - parse5@7.1.2: - dependencies: - entities: 4.5.0 - parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -8654,7 +8490,7 @@ snapshots: pkg-types@1.1.1: dependencies: confbox: 0.1.7 - mlly: 1.7.0 + mlly: 1.7.1 pathe: 1.1.2 plur@5.1.0: @@ -8722,45 +8558,45 @@ snapshots: prettier-plugin-astro@0.13.0: dependencies: '@astrojs/compiler': 1.8.2 - prettier: 3.3.0 + prettier: 3.3.1 sass-formatter: 0.7.9 - prettier-plugin-pkg@0.18.1(prettier@3.3.0): + prettier-plugin-pkg@0.18.1(prettier@3.3.1): dependencies: - prettier: 3.3.0 + prettier: 3.3.1 - prettier-plugin-sh@0.14.0(prettier@3.3.0): + prettier-plugin-sh@0.14.0(prettier@3.3.1): dependencies: mvdan-sh: 0.10.1 - prettier: 3.3.0 + prettier: 3.3.1 sh-syntax: 0.4.2 - prettier-plugin-sql@0.18.0(prettier@3.3.0): + prettier-plugin-sql@0.18.0(prettier@3.3.1): dependencies: jsox: 1.2.119 node-sql-parser: 4.18.0 - prettier: 3.3.0 + prettier: 3.3.1 sql-formatter: 15.3.1 tslib: 2.6.3 - prettier-plugin-svelte@3.2.3(prettier@3.3.0)(svelte@4.2.17): + prettier-plugin-svelte@3.2.4(prettier@3.3.1)(svelte@4.2.18): dependencies: - prettier: 3.3.0 - svelte: 4.2.17 + prettier: 3.3.1 + svelte: 4.2.18 - prettier-plugin-tailwindcss@0.5.14(prettier-plugin-astro@0.13.0)(prettier-plugin-svelte@3.2.3(prettier@3.3.0)(svelte@4.2.17))(prettier@3.3.0): + prettier-plugin-tailwindcss@0.5.14(prettier-plugin-astro@0.13.0)(prettier-plugin-svelte@3.2.4(prettier@3.3.1)(svelte@4.2.18))(prettier@3.3.1): dependencies: - prettier: 3.3.0 + prettier: 3.3.1 optionalDependencies: prettier-plugin-astro: 0.13.0 - prettier-plugin-svelte: 3.2.3(prettier@3.3.0)(svelte@4.2.17) + prettier-plugin-svelte: 3.2.4(prettier@3.3.1)(svelte@4.2.18) - prettier-plugin-toml@2.0.1(prettier@3.3.0): + prettier-plugin-toml@2.0.1(prettier@3.3.1): dependencies: '@taplo/lib': 0.4.0-alpha.2 - prettier: 3.3.0 + prettier: 3.3.1 - prettier@3.3.0: {} + prettier@3.3.1: {} pretty-format@29.7.0: dependencies: @@ -8781,8 +8617,6 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - property-information@6.5.0: {} - propose@0.0.5: dependencies: levenshtein-edit-distance: 1.0.0 @@ -8894,7 +8728,7 @@ snapshots: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.1 parse-json: 8.1.0 - type-fest: 4.19.0 + type-fest: 4.20.0 unicorn-magic: 0.1.0 readable-stream@3.6.2: @@ -9327,26 +9161,11 @@ snapshots: transitivePeerDependencies: - supports-color - remark-mdat@0.6.13: + remark-mdat@0.7.0: dependencies: '@types/mdast': 4.0.4 - '@types/node': 20.14.1 + '@types/node': 20.14.2 '@types/unist': 3.0.2 - chalk: 5.3.0 - cli-table3: 0.6.5 - deepmerge-ts: 7.0.2 - hast-util-from-html: 2.0.1 - json5: 2.2.3 - remark: 15.0.1 - remark-gfm: 4.0.0 - type-fest: 4.19.0 - unified: 11.0.4 - unist-util-visit: 5.0.0 - vfile: 6.0.1 - vfile-message: 4.0.2 - zod: 3.23.8 - transitivePeerDependencies: - - supports-color remark-mdx@3.0.1: dependencies: @@ -9373,9 +9192,9 @@ snapshots: transitivePeerDependencies: - supports-color - remark-preset-prettier@2.0.1(prettier@3.3.0): + remark-preset-prettier@2.0.1(prettier@3.3.1): dependencies: - prettier: 3.3.0 + prettier: 3.3.1 remark-stringify@11.0.0: dependencies: @@ -9389,7 +9208,7 @@ snapshots: '@types/mdast': 4.0.4 github-slugger: 2.0.0 hosted-git-info: 7.0.2 - mdast-util-to-hast: 13.1.0 + mdast-util-to-hast: 13.2.0 mdast-util-to-string: 4.0.0 propose: 0.0.5 trough: 2.2.0 @@ -9810,7 +9629,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-eslint-parser@0.36.0(svelte@4.2.17): + svelte-eslint-parser@0.36.0(svelte@4.2.18): dependencies: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 @@ -9818,9 +9637,9 @@ snapshots: postcss: 8.4.38 postcss-scss: 4.0.9(postcss@8.4.38) optionalDependencies: - svelte: 4.2.17 + svelte: 4.2.18 - svelte@4.2.17: + svelte@4.2.18: dependencies: '@ampproject/remapping': 2.3.0 '@jridgewell/sourcemap-codec': 1.4.15 @@ -9962,7 +9781,7 @@ snapshots: type-fest@3.13.1: {} - type-fest@4.19.0: {} + type-fest@4.20.0: {} type-is@1.6.18: dependencies: @@ -10044,7 +9863,7 @@ snapshots: '@types/concat-stream': 2.0.3 '@types/debug': 4.1.12 '@types/is-empty': 1.2.3 - '@types/node': 20.14.1 + '@types/node': 20.14.2 '@types/unist': 3.0.2 concat-stream: 2.0.0 debug: 4.3.5 @@ -10206,13 +10025,13 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-node@1.6.0(@types/node@20.14.1): + vite-node@1.6.0(@types/node@20.14.2): dependencies: cac: 6.7.14 debug: 4.3.5 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.2.12(@types/node@20.14.1) + vite: 5.2.13(@types/node@20.14.2) transitivePeerDependencies: - '@types/node' - less @@ -10223,16 +10042,16 @@ snapshots: - supports-color - terser - vite@5.2.12(@types/node@20.14.1): + vite@5.2.13(@types/node@20.14.2): dependencies: esbuild: 0.20.2 postcss: 8.4.38 rollup: 4.18.0 optionalDependencies: - '@types/node': 20.14.1 + '@types/node': 20.14.2 fsevents: 2.3.3 - vitest@1.6.0(@types/node@20.14.1): + vitest@1.6.0(@types/node@20.14.2): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 @@ -10251,11 +10070,11 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.8.0 tinypool: 0.8.4 - vite: 5.2.12(@types/node@20.14.1) - vite-node: 1.6.0(@types/node@20.14.1) + vite: 5.2.13(@types/node@20.14.2) + vite-node: 1.6.0(@types/node@20.14.2) why-is-node-running: 2.2.2 optionalDependencies: - '@types/node': 20.14.1 + '@types/node': 20.14.2 transitivePeerDependencies: - less - lightningcss @@ -10271,8 +10090,6 @@ snapshots: walk-up-path@3.0.1: {} - web-namespaces@2.0.1: {} - webidl-conversions@4.0.2: {} whatwg-url@7.1.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 924b55f..0000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -packages: - - packages/* diff --git a/readme.md b/readme.md index a5bd1c0..1358ac5 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,12 @@ -# MDAT Monorepo + + +# mdat + + - + [![NPM Package mdat](https://img.shields.io/npm/v/mdat.svg)](https://npmjs.com/package/mdat) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) @@ -11,21 +15,70 @@ -**Use comments as dynamic content templates in Markdown files.** +**CLI tool and library implementing the Markdown Autophagic Template (MDAT) system. MDAT lets you use comments as dynamic content templates in Markdown files, making it easy to generate and update readme boilerplate.** + + +## Table of contents + +- [Overview](#overview) +- [Getting started](#getting-started) + - [Dependencies](#dependencies) + - [Installation](#installation) +- [Features](#features) +- [Usage](#usage) + - [CLI](#cli) + - [API](#api) + - [Configuration](#configuration) + - [Creating custom rules](#creating-custom-rules) + - [The `mdat readme` subcommand](#the-mdat-readme-subcommand) +- [Background](#background) + - [Motivation](#motivation) + - [Similar projects](#similar-projects) + - [Implementation notes](#implementation-notes) +- [The future](#the-future) +- [Maintainers](#maintainers) +- [Acknowledgments](#acknowledgments) +- [Contributing](#contributing) +- [License](#license) + + + ## Overview -MDAT stands for the **Markdown Autophagic Template** system. So-named because of its ouroboros-like approach to expanding comment placeholders in-place. +This is a CLI tool and library implementing the Markdown Autophagic Template (MDAT) system, which makes it easy to automate the replacement of placeholder comments in Markdown documents with dynamic content from a variety of sources. The `mdat` command can also validate the structure and content of the Markdown document based on constraints specified in the expansion rules, and bundles numerous convenient expansion rules for working with `readme.md` files under the `mdat readme` subcommand. + + + + + + + tldraw diagram + + + -It turns HTML comments in Markdown files like this: +A trivial example... + +Given placeholder comments in a Markdown file like this: + +`some-file.md` ```md ``` -Into this: +Run your file through the tool: + +```sh +mdat readme some-file.md +``` + +To turn it into: + +`some-file.md` ```md @@ -35,53 +88,739 @@ Into this: ``` -It uses sets of customizable rules to decide what to replace with what. The rule to generate the title above looks like this: +In this case, according to a set of rules defined in an external configuration file, `` was replaced with date from `package.json`. The rule system behind these expansions is simple to define and readily extensible beyond the trivial example above. + +## Getting started + +### Dependencies + +The `mdat` CLI tool requires Node 18+. The exported APIs for expanding Markdown text and documents are ESM-only and share the Node 18+ requirement. `mdat` is implemented in TypeScript and bundles a complete set of type definitions. + +### Installation + +Install locally to access the CLI commands in a single project or to import the provided APIs: + +```sh +npm install mdat +``` + +Or, install globally for access across your system: + +```sh +npm install --global mdat +``` + +## Features + +As [noted below](#similar-projects), there are several similar projects out there. This overlap is mostly the result of my mediocre due diligence before starting development, but there remain a few distinguishing aspects of this particular implementation of the idea: + +1. **Minimalist syntax** + + No screaming caps or wordy opening and closing tag keywords, just a minimal HTML-esque syntax: + + ```md + + + # mdat + + + ``` + + (Optionally, you can specify a prefix if you want to mix "true" comments with MDAT content placeholder comments.) + +2. **Single-comment placeholders** + + When you're roughing out a readme, you can drop in a single opening comment, and `mdat` will take care of expanding it and adding the closing tag the next time it's run. To generate the block shown above, you'd need only to add: + + ```md + + ``` + +3. **Familiar JSON arguments** + + In the rare instances when you want to pass extra data or configuration into a comment template, you just use a bit of JSON. No need to grok a custom syntax: + + ```md + + ``` + + Internally, comment option arguments are parsed with [JSON5](https://json5.org), so you can skip quoting keys if you like. A pre-parsing step adds another layer of leniency if you want to skip the brackets or include parentheses to pretend your keyword is a function. The expansion rules included with the `mdat readme` subcommand use [Zod](https://zod.dev) to validate the option arguments and provide helpful errors at runtime. + +4. **Flexible rule system** + + Comment expansions definitions are referred to as "rules". + + An expansion rule can be as minimal as a file exporting a record: + + ```ts + { keyword: "content"}` + ``` + + Which will turn: + + ```md + + ``` + + Into: + + ```md + + + content + + + ``` + + Or, make things a bit more dynamic by returning a function instead of a string. Async functions are welcome. + + ```ts + { date: () => `${new Date().toISOString()}` } }" + ``` + + Or enforce validation by adding some metadata: + + ```ts + { + date: { + content: () => `${new Date().toISOString()}`, + order: 1, + required: true, + }, + } + ``` + + This scales all the way up to some of the [more](./src/lib/readme/rules/table-of-contents.ts) [elaborate](./src/lib/readme/rules/cli-help) rules found in the `mdat readme` subcommand. + + You can also treat any JSON file as a rule set. MDAT will flatten it to allow any dot-notated key path to become a placeholder comment keyword. + +5. **TypeScript native** + + MDAT exports definitions for rule types, and configuration / rule sets may be written directly in TypeScript. + +6. **Validation** + + In addition to content replacement, individual rules can define validation constraints. `mdat` includes a `--check` option which runs your expanded Markdown through a validator to enforce the presence and order of appearance of your comment placeholders. + +7. **Compound rules** + + It's easy to create "compound" expansion rules that encapsulate a number of other individual rules into a single Markdown comment to keep the quantity of template comments in check. + + See the [``](./src/lib/readme/rules/header.ts) rule in the `mdat readme` subcommand for an example. + +8. **Single-command readme workflow** + + MDAT's most typical use case is streamlined with the `mdat readme` subcommand. Invoking this CLI command in your repo will automatically find your readme and your package.json and provide access to a collection of bundled expansion rules. + + It also provides the `mdat readme init` subcommand with a selection of templates to kick off a fresh readme from scratch in a new project. + +## Usage + +> \[!WARNING]\ +> **The MDAT CLI tool directly manipulates the contents of readme files, in close (and perhaps dangerous) proximity to your painstakingly crafted words.** +> +> Please make sure any text you care about is committed before running `mdat`, and never directly modify content inside of the comment expansion blocks. +> +> Set the `--meta` flag on the command to add a warning comment to the top of your file explaining the extra caution demanded around the volatile automated sections of your readme.md. + +### CLI + + + +#### Command: `mdat` + +Work with MDAT placeholder comments in any Markdown file. + +This section lists top-level commands for `mdat`. + +If no command is provided, `mdat expand` is run by default. + +Usage: + +```txt +mdat [command] +``` + +| Command | Argument | Description | +| ---------- | ----------------------- | -------------------------------------------------------------- | +| `expand` | `` `[options]` | Expand MDAT placeholder comments. _(Default command.)_ | +| `check` | `` `[options]` | Validate a Markdown file containing MDAT placeholder comments. | +| `collapse` | `` `[options]` | Collapse MDAT placeholder comments. | +| `readme` | `[command]` | Work with MDAT comments in your readme.md. | + +_See the sections below for more information on each subcommand._ + +#### Subcommand: `mdat expand` + +Expand MDAT placeholder comments. + +Usage: + +```txt +mdat expand [options] +``` + +| Positional Argument | Description | Type | +| ------------------- | -------------------------------------------------------------- | -------- | +| `files` | Markdown file(s) with MDAT placeholder comments. _(Required.)_ | `string` | + +| Option | Alias | Description | Type | Default | +| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | +| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | +| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | +| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | +| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | +| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | +| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + +#### Subcommand: `mdat check` + +Validate a Markdown file containing MDAT placeholder comments. + +Usage: + +```txt +mdat check [options] +``` + +| Positional Argument | Description | Type | +| ------------------- | -------------------------------------------------------------- | -------- | +| `files` | Markdown file(s) with MDAT placeholder comments. _(Required.)_ | `string` | + +| Option | Alias | Description | Type | Default | +| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | +| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | +| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | +| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + +#### Subcommand: `mdat collapse` + +Collapse MDAT placeholder comments. + +Usage: + +```txt +mdat collapse [options] +``` + +| Positional Argument | Description | Type | +| ------------------- | -------------------------------------------------------------- | -------- | +| `files` | Markdown file(s) with MDAT placeholder comments. _(Required.)_ | `string` | + +| Option | Alias | Description | Type | Default | +| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | +| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | +| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | +| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | +| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + +#### Subcommand: `mdat readme` + +Work with MDAT comments in your readme.md. + +This section lists top-level commands for `mdat readme`. + +If no command is provided, `mdat readme expand` is run by default. + +Usage: + +```txt +mdat readme [command] +``` + +| Command | Argument | Description | +| ----------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `readme expand` | `[files..]` `[options]` | Expand MDAT comment placeholders in your readme.md using a collection of helpful built-in expansion rules. _(Default command.)_ | +| `readme check` | `[files..]` `[options]` | Validate MDAT placeholder comments in your readme.md. | +| `readme collapse` | `[files..]` `[options]` | Collapse MDAT placeholder comments in your readme.md. | +| `readme init` | `[options]` | Interactively create a new readme.md file with sensible default MDAT comment placeholders. | + +_See the sections below for more information on each subcommand._ + +#### Subcommand: `mdat readme expand` + +Expand MDAT comment placeholders in your readme.md using a collection of helpful built-in expansion rules. + +Usage: + +```txt +mdat readme expand [files..] [options] +``` + +| Positional Argument | Description | Type | +| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | +| `files` | Readme file(s) with MDAT placeholder comments. If not provided, the closest readme.md file is used. _(Optional.)_ | `string` | + +| Option | Alias | Description | Type | Default | +| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | +| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | +| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | +| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | +| `--package` | | Path to the package.json file to use to populate the readme. | `string` | The closest package.json file is used by default. | +| `--assets` | | Path to find and save readme-related assets. | `string` | `./assets` | +| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | +| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | +| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + +#### Subcommand: `mdat readme check` + +Validate MDAT placeholder comments in your readme.md. + +Usage: + +```txt +mdat readme check [files..] [options] +``` + +| Positional Argument | Description | Type | +| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | +| `files` | Readme file(s) with MDAT placeholder comments. If not provided, the closest readme.md file is used. _(Optional.)_ | `string` | + +| Option | Alias | Description | Type | Default | +| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | +| `--rules` | `-r` | Path(s) to files containing MDAT comment expansion rules. | `array` | | +| `--package` | | Path to the package.json file to use to populate the readme. | `string` | The closest package.json file is used by default. | +| `--assets` | | Path to find and save readme-related assets. | `string` | `./assets` | +| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | +| `--meta` | `-m` | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically. | `boolean` | | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + +#### Subcommand: `mdat readme collapse` + +Collapse MDAT placeholder comments in your readme.md. + +Usage: + +```txt +mdat readme collapse [files..] [options] +``` + +| Positional Argument | Description | Type | +| ------------------- | ----------------------------------------------------------------------------------------------------------------- | -------- | +| `files` | Readme file(s) with MDAT placeholder comments. If not provided, the closest readme.md file is used. _(Optional.)_ | `string` | + +| Option | Alias | Description | Type | Default | +| ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | +| `--name` | `-n` | Output file name. | `string` | Same name as input file. Overwrites the input file. | +| `--print` | | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options. | `boolean` | | +| `--config` | | Path(s) to files containing MDAT configuration. | `array` | Configuration is loaded if found from the usual places, or defaults are used. | +| `--prefix` | | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string` | | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + +#### Subcommand: `mdat readme init` + +Interactively create a new readme.md file with sensible default MDAT comment placeholders. + +Usage: + +```txt +mdat readme init [options] +``` + +| Option | Alias | Description | Type | Default | +| --------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------------- | +| `--interactive` | `-i` | Run the guided interactive `init` process. Set explicitly to `false` to use default values and skip the prompt. | `boolean` | `true` | +| `--overwrite` | | Replace an existing readme file if one is found. | `boolean` | `false`, if an existing readme is found, don't touch it. | +| `--output` | `-o` | Output file directory. | `string` | Same directory as input file. | +| `--expand` | `-e` | Automatically run `mdat readme` immediately after creating the readme template. | `boolean` | `true` | +| `--template` | `-t` | Specify a template to use for the new readme. | `string` | "MDAT Readme" | +| `--compound` | `-c` | Use compound comment version of the template to replace several individual comment placeholders where possible. This combines things like ``, ``, etc. in a single `` comment. It's less clutter when you're editing, but it's also less explicit. The final readme.md output is identical. | `boolean` | `true` | +| `--verbose` | | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection. | `boolean` | | +| `--help` | `-h` | Show help | `boolean` | | +| `--version` | `-v` | Show version number | `boolean` | | + + + +_Meta note: The entire section above was generated automatically by the [``](./src/lib/readme/rules/cli-help/index.ts) mdat expansion rule provided in `mdat readme` subcommand. It dynamically parses the output from `mdat --help` into a Markdown table, recursively calling `--help` on subcommands to build a tidy representation of the help output._ + +#### Examples + +##### Basic + +Expand comments in a single Markdown file in-place: + +```sh +mdat your-file.md +``` + +##### Multi-file + +Expand comments in multiple Markdown files: + +```sh +mdat *.md +``` + +##### Custom configuration + +A number of option flags are exposed on the CLI. Any values set here will override both ambient configuration files and any configuration file referenced passed as options: + +```sh +mdat --prefix 'mm- +``` + +##### Custom configuration file + +```sh +mdat --config 'custom-config.ts" +``` + +##### Rule sets + +```sh +mdat --rules 'rules.ts' 'more-rules.js' 'yet-more-rules.json' +``` + +##### Readme expansion + +Expand MDAT comments in your readme.md: + +```sh +mdat readme +``` -`rules.ts` +##### Validation + +Check your readme.md for validation errors, without modifying it: + +```sh +mdat readme check +``` + +##### Additional rules + +Additional rules may be defined in a configuration file, or passed explicitly to most `mdat` commands via the `--rules` flag: + +```sh +mdat readme --rules rules.ts more-rules.js yet-more-rules.json +``` + +#### Create a starter readme from scratch + +```sh +mdat readme init +``` + +### API + +`mdat` exports a collection of functions to abstract the process of expanding placeholder comments into a single call. Type aliases are also provided. + +Highlights include: + +#### Expand String ```ts -import type { Rules } from 'remark-mdat' -import { readPackage } from 'read-pkg' +function expandString(markdown: string, config?: ConfigToLoad, rules?: RulesToLoad): Promise +``` + +Takes a string of Markdown and returns. Note that the returned object is a [VFile](https://github.com/vfile), which includes both the post-conversion Markdown content and additional metadata about the conversion. + +To get the Markdown content, simply call `.toString()` on the returned VFile object. + +#### Expand File + +```ts +function expandFile( + file: string, + name?: string, + output?: string, + config?: ConfigToLoad, + rules?: RulesToLoad, +): Promise +``` + +Similar to `expandString()`, but takes a file path and handles setting an optional destination path and file name. + +It's up to the caller to actually save the returned VFile object. The [to-vfile](https://www.npmjs.com/package/to-vfile) library can make this particularly painless: + +```ts +import { expandFile } from 'mdat' +import { write } from 'to-vfile' + +const file = await expandFiles(...) +await write(file) +``` + +#### Expand Files + +```ts +function expandFiles( + files: string[], + name?: string, + output?: string, + config?: ConfigToLoad, + rules?: RulesToLoad, +): Promise +``` + +Like `expandFile()`, but accepts an array of inputs. If an output name is specified, the output files are suffixed with a number to prevent name collisions. + +#### Load Config + +```ts +function loadConfig(options?: { + additionalConfig?: ConfigToLoad // file paths or config objects + additionalRules?: RulesToLoad // file paths or rule objects + searchFrom?: string +}): Promise // returns a single merged config object +``` + +This is provided for more advanced use cases. It assists in discovering and loading ambient configuration in your project (e.g. fields in your package.json, or dedicated `mdat` config files). It also dynamically loads, validates, and merges additional `mdat` configuration and rule files into a final `ConfigLoaded` object ready to be passed into the [`remark-mdat`](https://github.com/kitschpatorl/remark-mdat) plugin or one of the API functions like `expandFile()`. + +#### Examples + +### Configuration + +Expansion rules and certain aspects of global configuration are defined in configuration files which may be discovered automatically by `mdat`, or explicitly provided via command line options or library function arguments as shown above. + +`mdat` implements configuration loading via [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig), which means a variety of configuration [locations](https://github.com/cosmiconfig/cosmiconfig?tab=readme-ov-file#searchplaces) and file formats are supported. Configuration may be defined directly in your package.json, or in addition to stand-alone TypeScript files, JavaScript files, YAML, JSON, etc. + +TypeScript or JavaScript with JSDoc annotations are recommended for the most flexibility and ease of implementing more advanced rules. + +`mdat` also allows arbitrary JSON files to be loaded as rule sets, flattening them so any value may be accessed by using a dot-notation key path as a comment keyword. + +#### Configuration file format + +The `mdat` configuration file is a record object allowing you to customize aspects of the comment expansion process, and also optionally define expansion rules as well under the `rules` key: + +```ts +type Config = { + assetsPath?: string // where asset-generating rules should store their output, defaults to './assets' + packageFile?: string // used by readme rules, found dynamically if undefined + addMetaComment?: boolean // defaults to true + closingPrefix?: string // defaults to '/' + keywordPrefix?: string // defaults to '' + metaCommentIdentifier?: string // defaults to '+' + rules?: Rules +} +``` + +A valid configuration file default-exports an object conforming to the above type. + +The configuration file may be located in any location supported by [cosmicconfig](https://github.com/cosmiconfig/cosmiconfig?tab=readme-ov-file#searchplaces). I use an `.mdatrc.ts` file in the root of my projects. + +#### Rule file format -export default { - title: `# ${(await readPackage()).title}`, -} satisfies Rules +Rules may also be defined in separate files that default-export a record of rules. The record keys become the keywords used to reference a rule from your comments in Markdown. + +```ts +type Rules = Record + +type Rule = + | string + | ((options: JsonValue, tree: Root) => Promise | string) + | Rule[] + | { + content: string | Rule[] | ((options: JsonValue, tree: Root) => Promise | string) + applicationOrder?: number | undefined + order?: number | undefined + required?: boolean | undefined + } ``` -The `mdat readme` command bundles over a dozen useful rules for taking care of readme boilerplate, and adding more of your own is as easy as creating additional rules in an `.mdatrc.ts` file. +This is a bit complex, but it's intended to make defining simple rules simple, while still accommodating more demanding use cases. + +Some notes on the type: + +- Simple rules can be defined directly on the key, either as strings to replace the comment placeholder, or as sync or async functions returning a string. + +- If you need more advanced rules, or wish to define conditions for the validation process, you break the top-level keyword key's value out into an object, where a `content` key on the object is responsible for returning the replacement string, and additional fields are available to define validation constraints. + +- Note that `content` can itself take an array of Rule objects, which is useful for creating "compound" rules that combine several others into a single comment keyword. + +Since it's a record, multiple rules may be combined in single rules file. + +If multiple configuration and rule files are loaded, they are merged. CLI options take precedence over ambient configuration discovered by cosmicconfig, and where multiple configuration or rule files are provided, with the "last" rule of a particular key takes precedence. + +### Creating custom rules + +The underlying rule expansion system is flexible and easy to extend. + +See the [Examples section](https://github.com/kitschpatrol/remark-mdat/readme.md#examples) of the `remark-mdat` readme, or take a look at the implementation of the [rules provided through the `mdat readme` subcommand](./src/lib/readme/rules/) for more complex examples. + +### The `mdat readme` subcommand + +#### Bundled rules + +##### Stand-alone: + +- ###### `` + + The `name` field from `package.json`. + +- ###### `` + + Looks for an image in the `/assets` folder for use as a banner image. Searches for a number of typical names and formats. (The assets path may be specified through configuration files or command line flags.) + +- ###### `` + + Generates badges based on `package.json`. Currently only supports license and NPM version badges. + +- ###### `` + + The `description` field from `package.json`. + + This rule is also aliased under the `` keyword, for consistency with the [standard-readme](https://github.com/RichardLitt/standard-readme/blob/main/spec.md#short-description) spec. + +- ###### `` + + A table of contents automatically generated by [mdast-util-toc](https://github.com/syntax-tree/mdast-util-toc). + + This rule is also aliased under the `` keyword, if you're into the brevity thing. + +- ###### `` + + Invites issues and pull request, generating links based on `package.json`. + +- ###### `` + + Documents the project's license, based on the `license` field from `package.json`. + +- ###### `` + + A quick way to embed a code block from elsewhere in your repository. Useful for examples. + +- ###### `` + + Automatically transform a CLI command's `--help` output into nicely formatted Markdown tables. The rule also recursively calls `--help` on any subcommands found for inclusion in the output. + + Currently, the rule can only parse help output in the format provided by [Yargs](https://yargs.js.org)- and [Meow](https://github.com/sindresorhus/meow)-based tools. If parsing fails, the rule will fall back to show the raw help output in a regular code block. -## Packages + ([Parsing help output](https://github.com/kitschpatrol/mdat/tree/main/src/lib/readme/rules/cli-help/utilities/parsers) is a bit tricky. The [jc](https://github.com/kellyjonbrazil/jc) project is a heroic collection of output parsers, but does not currently implement help output parsing. It might be interesting to try to contribute mdat's help parsing implementations to jc.) -This repository includes two packages: + This rule is also aliased under the `` keyword. -### [mdat](./packages/mdat/readme.md) +- ###### `` - + Allows embedding [tldraw](https://www.tldraw.com) files in your readme. Accepts either a path to a local `.tldr` file, or remote tldraw URLs. -_**CLI tool and library implementing the Markdown Autophagic Template (MDAT) system. MDAT lets you use comments as dynamic content templates in Markdown files, making it easy to generate and update readme boilerplate.**_ + Automatically generates both "light" and "dark" SVG variations of the sketch, and emits a `` element per [GitHub's guidelines](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#specifying-the-theme-an-image-is-shown-to) to present the correctly themed image based on the viewer's preferences. - + Generated assets are intelligently hashed to aide in cache busting. For locally referenced files, the image will only be regenerated when the content in the source file changes. -This is the best place to get started. **See the [mdat readme file](./packages/mdat/readme.md) for much more information.** It explains how to use mdat comment templates with any Markdown file, how to create your own expansion rule sets, outlines available configuration options, and documents the `mdat readme` which bundles handy rules for expanding common content in readme.md files. + The implementation is based on [@kitschpatrol/tldraw-cli](https://github.com/kitschpatrol/tldraw-cli), and depends on Puppeteer to generate the assets, so it can be a bit slow. Referencing local files instead of remote URLs is recommended for improved performance. -### [remark-mdat](./packages/remark-mdat/readme.md) + This rule is used to embed the diagram at the top of this readme. - +##### Compound -_**A remark plugin implementing the Markdown Autophagic Template (MDAT) system.**_ +Compound rules combine several stand-alone rules under a single keyword, which can help reduce comment clutter in your readme's Markdown. - +- ###### `` -See the [remark-mdat readme file](./packages/remark-mdat/readme.md) for more. It demonstrates how to integrate an mdat template comment expansion step in more complex remark processing pipelines. Lower-level [unified](https://unifiedjs.com) [mdast](https://github.com/syntax-tree/mdast) utility functions are also available in the `remark-mdat` package for surgical work on Markdown ASTs. + Combines a number of rules often applied at the top of a readme into a single keyword. This rule is the equivalent of: + + ```md + + + + + ``` + +- ###### `` + + Bundles together rules often applied at the end of a readme. Just two rules at the moment: + + ```md + + + ``` + +#### Bundled templates + +The `init` command provides a number of "starter readme" templates incorporating MDAT comment placeholders: + +- ##### MDAT Readme + + The house style. An expansive starting point. Prune to your context and taste. The readme file in this repo was started from this template. + +- ##### Standard Readme basic + + Includes only the "required" sections from the [Standard Readme](https://github.com/RichardLitt/standard-readme/blob/main/spec.md) specification. [See an example](https://github.com/RichardLitt/standard-readme/blob/main/example-readmes/minimal-readme.md). + +- ##### Standard Readme full + + Includes all sections from the [Standard Readme](https://github.com/RichardLitt/standard-readme/blob/main/spec.md) specification. [See an example](https://github.com/RichardLitt/standard-readme/blob/main/example-readmes/maximal-readme.md). + +## Background + +### Motivation + +A package definition file like `package.json` is the canonical "single source of truth" for a project's metadata. Yet fragments of this metadata end up duplicated elsewhere, most prominently in the readme. Keeping them in sync is a pain. + +You could set up a separate readme template file and use one of a to generate your readme, but then you'd still have to wire up data ingestion and deal with and the cognitive clutter of a second half-baked readme in your repo. + +MDAT solves this tedium by committing a minor sacrilege: It allows comments in Markdown files to become placeholders for dynamic content, overwriting themselves in place with content pulled from around your repo. When `mdat` is run against the file, specific comments are expanded with content from elsewhere, the file is updated in-situ. + +I wrote it for use in my own projects, but if someone else finds it useful, that's great. + +### Similar projects + +This has been done several times before: + +- Benjamin Lupton's [projectz](https://github.com/bevry/projectz)\ + Goes way back. + +- David Wells' [Markdown Magic](https://github.com/DavidWells/markdown-magic)\ + I somehow missed the existence of this one until after building out MDAT. It's very similar conceptually, and has a nice ecosystem of plugins. + +- Titus Wormer's [mdast-zone](https://github.com/syntax-tree/mdast-zone)\ + Allows comments to be used as ranges or markers in Markdown files. Similar tree parsing and walking strategy to MDAT. Mdast-zone uses different syntax for arguments, and requires both opening and closing tags to be present for expansion to occur. + +- lillallol's [md-in-place](https://www.npmjs.com/package/md-in-place) + +### Implementation notes + +This project was split from a monorepo containing both `mdat` and `remark-mdat` into separate repos in July 2024. ## The future -This project will remain under major [version zero](https://semver.org/#spec-item-4) until it's clear that the rule structures and so forth make sense. Breaking changes may be introduced with any point release until 1.0. +Additional rules: + +- Support embedding code documentation snippets via [typedoc](https://github.com/TypeStrong/typedoc) + [typedoc-plugin-markdown](https://github.com/tgreyuk/typedoc-plugin-markdown). +- Support line ranges i the `` rule. + +Improved documentation: + +- Describe available rule options. +- More details on defining custom rules. + +Recommended workflow integration approach: + +- Invoke via hooks / GitHub actions? ## Maintainers [@kitschpatrol](https://github.com/kitschpatrol) +## Acknowledgments + +- The [unified](https://unifiedjs.com), [remark](https://remark.js.org), and [unist](https://github.com/syntax-tree/unist) / [mdast](https://github.com/syntax-tree/mdast) ecosystem is powerful and well-architected. MDAT relies on it to do the the heavy lifting in of parsing, transforming, and restoring the Markdown to string form. + +- Richard Litt's [Standard Readme](https://github.com/RichardLitt/standard-readme) specification inspired some of the templates available in `mdat readme init`. + ## Contributing diff --git a/packages/mdat/src/cli/cli.ts b/src/cli/cli.ts similarity index 100% rename from packages/mdat/src/cli/cli.ts rename to src/cli/cli.ts diff --git a/packages/mdat/src/cli/options.ts b/src/cli/options.ts similarity index 100% rename from packages/mdat/src/cli/options.ts rename to src/cli/options.ts diff --git a/packages/mdat/src/cli/readme-options.ts b/src/cli/readme-options.ts similarity index 100% rename from packages/mdat/src/cli/readme-options.ts rename to src/cli/readme-options.ts diff --git a/packages/mdat/src/lib/api.ts b/src/lib/api.ts similarity index 100% rename from packages/mdat/src/lib/api.ts rename to src/lib/api.ts diff --git a/packages/mdat/src/lib/config.ts b/src/lib/config.ts similarity index 100% rename from packages/mdat/src/lib/config.ts rename to src/lib/config.ts diff --git a/packages/mdat/src/lib/index.ts b/src/lib/index.ts similarity index 100% rename from packages/mdat/src/lib/index.ts rename to src/lib/index.ts diff --git a/packages/mdat/src/lib/mdat-json-loader.ts b/src/lib/mdat-json-loader.ts similarity index 100% rename from packages/mdat/src/lib/mdat-json-loader.ts rename to src/lib/mdat-json-loader.ts diff --git a/packages/mdat/src/lib/processors.ts b/src/lib/processors.ts similarity index 100% rename from packages/mdat/src/lib/processors.ts rename to src/lib/processors.ts diff --git a/packages/mdat/src/lib/readme/api.ts b/src/lib/readme/api.ts similarity index 100% rename from packages/mdat/src/lib/readme/api.ts rename to src/lib/readme/api.ts diff --git a/packages/mdat/src/lib/readme/config.ts b/src/lib/readme/config.ts similarity index 100% rename from packages/mdat/src/lib/readme/config.ts rename to src/lib/readme/config.ts diff --git a/packages/mdat/src/lib/readme/init.ts b/src/lib/readme/init.ts similarity index 100% rename from packages/mdat/src/lib/readme/init.ts rename to src/lib/readme/init.ts diff --git a/packages/mdat/src/lib/readme/rules/badges.ts b/src/lib/readme/rules/badges.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/badges.ts rename to src/lib/readme/rules/badges.ts diff --git a/packages/mdat/src/lib/readme/rules/banner.ts b/src/lib/readme/rules/banner.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/banner.ts rename to src/lib/readme/rules/banner.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/index.ts b/src/lib/readme/rules/cli-help/index.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/index.ts rename to src/lib/readme/rules/cli-help/index.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/get-help-markdown.ts b/src/lib/readme/rules/cli-help/utilities/get-help-markdown.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/get-help-markdown.ts rename to src/lib/readme/rules/cli-help/utilities/get-help-markdown.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/help-object-to-markdown.ts b/src/lib/readme/rules/cli-help/utilities/help-object-to-markdown.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/help-object-to-markdown.ts rename to src/lib/readme/rules/cli-help/utilities/help-object-to-markdown.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/help-string-to-object.ts b/src/lib/readme/rules/cli-help/utilities/help-string-to-object.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/help-string-to-object.ts rename to src/lib/readme/rules/cli-help/utilities/help-string-to-object.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/infer-command.ts b/src/lib/readme/rules/cli-help/utilities/infer-command.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/infer-command.ts rename to src/lib/readme/rules/cli-help/utilities/infer-command.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers/index.ts b/src/lib/readme/rules/cli-help/utilities/parsers/index.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers/index.ts rename to src/lib/readme/rules/cli-help/utilities/parsers/index.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers/meow.ts b/src/lib/readme/rules/cli-help/utilities/parsers/meow.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers/meow.ts rename to src/lib/readme/rules/cli-help/utilities/parsers/meow.ts diff --git a/packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers/yargs.ts b/src/lib/readme/rules/cli-help/utilities/parsers/yargs.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli-help/utilities/parsers/yargs.ts rename to src/lib/readme/rules/cli-help/utilities/parsers/yargs.ts diff --git a/packages/mdat/src/lib/readme/rules/cli.ts b/src/lib/readme/rules/cli.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/cli.ts rename to src/lib/readme/rules/cli.ts diff --git a/packages/mdat/src/lib/readme/rules/code.ts b/src/lib/readme/rules/code.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/code.ts rename to src/lib/readme/rules/code.ts diff --git a/packages/mdat/src/lib/readme/rules/contributing.ts b/src/lib/readme/rules/contributing.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/contributing.ts rename to src/lib/readme/rules/contributing.ts diff --git a/packages/mdat/src/lib/readme/rules/description.ts b/src/lib/readme/rules/description.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/description.ts rename to src/lib/readme/rules/description.ts diff --git a/packages/mdat/src/lib/readme/rules/footer.ts b/src/lib/readme/rules/footer.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/footer.ts rename to src/lib/readme/rules/footer.ts diff --git a/packages/mdat/src/lib/readme/rules/header.ts b/src/lib/readme/rules/header.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/header.ts rename to src/lib/readme/rules/header.ts diff --git a/packages/mdat/src/lib/readme/rules/index.ts b/src/lib/readme/rules/index.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/index.ts rename to src/lib/readme/rules/index.ts diff --git a/packages/mdat/src/lib/readme/rules/license.ts b/src/lib/readme/rules/license.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/license.ts rename to src/lib/readme/rules/license.ts diff --git a/packages/mdat/src/lib/readme/rules/short-description.ts b/src/lib/readme/rules/short-description.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/short-description.ts rename to src/lib/readme/rules/short-description.ts diff --git a/packages/mdat/src/lib/readme/rules/table-of-contents.ts b/src/lib/readme/rules/table-of-contents.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/table-of-contents.ts rename to src/lib/readme/rules/table-of-contents.ts diff --git a/packages/mdat/src/lib/readme/rules/title.ts b/src/lib/readme/rules/title.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/title.ts rename to src/lib/readme/rules/title.ts diff --git a/packages/mdat/src/lib/readme/rules/tldraw.ts b/src/lib/readme/rules/tldraw.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/tldraw.ts rename to src/lib/readme/rules/tldraw.ts diff --git a/packages/mdat/src/lib/readme/rules/toc.ts b/src/lib/readme/rules/toc.ts similarity index 100% rename from packages/mdat/src/lib/readme/rules/toc.ts rename to src/lib/readme/rules/toc.ts diff --git a/packages/mdat/src/lib/readme/templates/index.ts b/src/lib/readme/templates/index.ts similarity index 100% rename from packages/mdat/src/lib/readme/templates/index.ts rename to src/lib/readme/templates/index.ts diff --git a/packages/mdat/src/lib/readme/templates/mdat-readme-compound.md b/src/lib/readme/templates/mdat-readme-compound.md similarity index 100% rename from packages/mdat/src/lib/readme/templates/mdat-readme-compound.md rename to src/lib/readme/templates/mdat-readme-compound.md diff --git a/packages/mdat/src/lib/readme/templates/mdat-readme.md b/src/lib/readme/templates/mdat-readme.md similarity index 100% rename from packages/mdat/src/lib/readme/templates/mdat-readme.md rename to src/lib/readme/templates/mdat-readme.md diff --git a/packages/mdat/src/lib/readme/templates/standard-readme-basic-compound.md b/src/lib/readme/templates/standard-readme-basic-compound.md similarity index 100% rename from packages/mdat/src/lib/readme/templates/standard-readme-basic-compound.md rename to src/lib/readme/templates/standard-readme-basic-compound.md diff --git a/packages/mdat/src/lib/readme/templates/standard-readme-basic.md b/src/lib/readme/templates/standard-readme-basic.md similarity index 100% rename from packages/mdat/src/lib/readme/templates/standard-readme-basic.md rename to src/lib/readme/templates/standard-readme-basic.md diff --git a/packages/mdat/src/lib/readme/templates/standard-readme-full-compound.md b/src/lib/readme/templates/standard-readme-full-compound.md similarity index 100% rename from packages/mdat/src/lib/readme/templates/standard-readme-full-compound.md rename to src/lib/readme/templates/standard-readme-full-compound.md diff --git a/packages/mdat/src/lib/readme/templates/standard-readme-full.md b/src/lib/readme/templates/standard-readme-full.md similarity index 100% rename from packages/mdat/src/lib/readme/templates/standard-readme-full.md rename to src/lib/readme/templates/standard-readme-full.md diff --git a/packages/mdat/src/lib/readme/utilities.ts b/src/lib/readme/utilities.ts similarity index 100% rename from packages/mdat/src/lib/readme/utilities.ts rename to src/lib/readme/utilities.ts diff --git a/packages/mdat/src/lib/utilities.ts b/src/lib/utilities.ts similarity index 100% rename from packages/mdat/src/lib/utilities.ts rename to src/lib/utilities.ts diff --git a/packages/mdat/src/types/md.d.ts b/src/types/md.d.ts similarity index 100% rename from packages/mdat/src/types/md.d.ts rename to src/types/md.d.ts diff --git a/packages/mdat/test/__snapshots__/api.test.ts.snap b/test/__snapshots__/api.test.ts.snap similarity index 100% rename from packages/mdat/test/__snapshots__/api.test.ts.snap rename to test/__snapshots__/api.test.ts.snap diff --git a/packages/mdat/test/__snapshots__/cli.test.ts.snap b/test/__snapshots__/cli.test.ts.snap similarity index 100% rename from packages/mdat/test/__snapshots__/cli.test.ts.snap rename to test/__snapshots__/cli.test.ts.snap diff --git a/packages/mdat/test/__snapshots__/readme-api.test.ts.snap b/test/__snapshots__/readme-api.test.ts.snap similarity index 100% rename from packages/mdat/test/__snapshots__/readme-api.test.ts.snap rename to test/__snapshots__/readme-api.test.ts.snap diff --git a/packages/mdat/test/__snapshots__/readme-cli-help-rule.test.ts.snap b/test/__snapshots__/readme-cli-help-rule.test.ts.snap similarity index 100% rename from packages/mdat/test/__snapshots__/readme-cli-help-rule.test.ts.snap rename to test/__snapshots__/readme-cli-help-rule.test.ts.snap diff --git a/packages/mdat/test/api.test.ts b/test/api.test.ts similarity index 100% rename from packages/mdat/test/api.test.ts rename to test/api.test.ts diff --git a/packages/mdat/test/assets/extra-rules.js b/test/assets/extra-rules.js similarity index 100% rename from packages/mdat/test/assets/extra-rules.js rename to test/assets/extra-rules.js diff --git a/packages/mdat/test/assets/help-supported/mdat --help.txt b/test/assets/help-supported/mdat --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/mdat --help.txt rename to test/assets/help-supported/mdat --help.txt diff --git a/packages/mdat/test/assets/help-supported/mdat expand --help.txt b/test/assets/help-supported/mdat expand --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/mdat expand --help.txt rename to test/assets/help-supported/mdat expand --help.txt diff --git a/packages/mdat/test/assets/help-supported/mdat readme --help.txt b/test/assets/help-supported/mdat readme --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/mdat readme --help.txt rename to test/assets/help-supported/mdat readme --help.txt diff --git a/packages/mdat/test/assets/help-supported/mdat readme init --help.txt b/test/assets/help-supported/mdat readme init --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/mdat readme init --help.txt rename to test/assets/help-supported/mdat readme init --help.txt diff --git a/packages/mdat/test/assets/help-supported/shared-config --help.txt b/test/assets/help-supported/shared-config --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/shared-config --help.txt rename to test/assets/help-supported/shared-config --help.txt diff --git a/packages/mdat/test/assets/help-supported/tldraw-cli --help.txt b/test/assets/help-supported/tldraw-cli --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/tldraw-cli --help.txt rename to test/assets/help-supported/tldraw-cli --help.txt diff --git a/packages/mdat/test/assets/help-supported/tldraw-cli export --help.txt b/test/assets/help-supported/tldraw-cli export --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/tldraw-cli export --help.txt rename to test/assets/help-supported/tldraw-cli export --help.txt diff --git a/packages/mdat/test/assets/help-supported/tldraw-cli open --help.txt b/test/assets/help-supported/tldraw-cli open --help.txt similarity index 100% rename from packages/mdat/test/assets/help-supported/tldraw-cli open --help.txt rename to test/assets/help-supported/tldraw-cli open --help.txt diff --git a/packages/mdat/test/assets/help-unsupported/snip --help.txt b/test/assets/help-unsupported/snip --help.txt similarity index 100% rename from packages/mdat/test/assets/help-unsupported/snip --help.txt rename to test/assets/help-unsupported/snip --help.txt diff --git a/packages/mdat/test/assets/mdat.config.ts b/test/assets/mdat.config.ts similarity index 100% rename from packages/mdat/test/assets/mdat.config.ts rename to test/assets/mdat.config.ts diff --git a/packages/mdat/test/assets/readme-test-header-footer.md b/test/assets/readme-test-header-footer.md similarity index 100% rename from packages/mdat/test/assets/readme-test-header-footer.md rename to test/assets/readme-test-header-footer.md diff --git a/packages/mdat/test/assets/readme-test-invalid.md b/test/assets/readme-test-invalid.md similarity index 100% rename from packages/mdat/test/assets/readme-test-invalid.md rename to test/assets/readme-test-invalid.md diff --git a/packages/mdat/test/assets/readme-test.md b/test/assets/readme-test.md similarity index 100% rename from packages/mdat/test/assets/readme-test.md rename to test/assets/readme-test.md diff --git a/packages/mdat/test/assets/test-document-malformed.md b/test/assets/test-document-malformed.md similarity index 100% rename from packages/mdat/test/assets/test-document-malformed.md rename to test/assets/test-document-malformed.md diff --git a/packages/mdat/test/assets/test-document.md b/test/assets/test-document.md similarity index 100% rename from packages/mdat/test/assets/test-document.md rename to test/assets/test-document.md diff --git a/packages/mdat/test/assets/test-module.ts b/test/assets/test-module.ts similarity index 100% rename from packages/mdat/test/assets/test-module.ts rename to test/assets/test-module.ts diff --git a/packages/mdat/test/assets/test-rules-invalid.js b/test/assets/test-rules-invalid.js similarity index 100% rename from packages/mdat/test/assets/test-rules-invalid.js rename to test/assets/test-rules-invalid.js diff --git a/packages/mdat/test/assets/test-rules-json.json b/test/assets/test-rules-json.json similarity index 100% rename from packages/mdat/test/assets/test-rules-json.json rename to test/assets/test-rules-json.json diff --git a/packages/mdat/test/assets/test-rules-throws-required.js b/test/assets/test-rules-throws-required.js similarity index 100% rename from packages/mdat/test/assets/test-rules-throws-required.js rename to test/assets/test-rules-throws-required.js diff --git a/packages/mdat/test/assets/test-rules.ts b/test/assets/test-rules.ts similarity index 100% rename from packages/mdat/test/assets/test-rules.ts rename to test/assets/test-rules.ts diff --git a/packages/mdat/test/assets/tldraw-sketch.tldr b/test/assets/tldraw-sketch.tldr similarity index 100% rename from packages/mdat/test/assets/tldraw-sketch.tldr rename to test/assets/tldraw-sketch.tldr diff --git a/packages/mdat/test/cli.test.ts b/test/cli.test.ts similarity index 100% rename from packages/mdat/test/cli.test.ts rename to test/cli.test.ts diff --git a/packages/mdat/test/config.test.ts b/test/config.test.ts similarity index 86% rename from packages/mdat/test/config.test.ts rename to test/config.test.ts index fadabea..4eb849a 100644 --- a/packages/mdat/test/config.test.ts +++ b/test/config.test.ts @@ -13,7 +13,7 @@ describe('configuration loading', () => { "closingPrefix": "/", "keywordPrefix": "", "metaCommentIdentifier": "+", - "packageFile": "/Users/mika/Code/mdat/packages/mdat/package.json", + "packageFile": "/Users/mika/Code/mdat/package.json", "rules": { "cosmiconfig": "# I was loaded by Cosmiconfig", "dynamic-rule": { @@ -48,7 +48,7 @@ describe('configuration loading', () => { "closingPrefix": "/", "keywordPrefix": "", "metaCommentIdentifier": "+", - "packageFile": "/Users/mika/Code/mdat/packages/mdat/package.json", + "packageFile": "/Users/mika/Code/mdat/package.json", "rules": { "basic": "**A bold statement from test-rules-json.json**", "basic-list-required": "- I @@ -89,6 +89,9 @@ describe('configuration loading', () => { expect(config.rules).toMatchInlineSnapshot(` { "mdat": "Powered by the Markdown Autophagic Template system: [mdat](https://github.com/kitschpatrol/mdat).", + "shared-config": "## Project configuration + + This project uses [@kitschpatrol/shared-config](https://github.com/kitschpatrol/shared-config) to consolidate various linting and formatting tool configurations under a single dependency and command. (ESLint, Prettier, CSpell, etc.)", } `) }) diff --git a/packages/mdat/test/readme-api.test.ts b/test/readme-api.test.ts similarity index 100% rename from packages/mdat/test/readme-api.test.ts rename to test/readme-api.test.ts diff --git a/packages/mdat/test/readme-cli-help-rule.test.ts b/test/readme-cli-help-rule.test.ts similarity index 100% rename from packages/mdat/test/readme-cli-help-rule.test.ts rename to test/readme-cli-help-rule.test.ts diff --git a/packages/mdat/test/readme-init.test.ts b/test/readme-init.test.ts similarity index 100% rename from packages/mdat/test/readme-init.test.ts rename to test/readme-init.test.ts diff --git a/packages/mdat/test/readme-rules.test.ts b/test/readme-rules.test.ts similarity index 100% rename from packages/mdat/test/readme-rules.test.ts rename to test/readme-rules.test.ts diff --git a/packages/mdat/tsconfig.build.bin.json b/tsconfig.build.bin.json similarity index 100% rename from packages/mdat/tsconfig.build.bin.json rename to tsconfig.build.bin.json diff --git a/packages/mdat/tsconfig.build.lib.json b/tsconfig.build.lib.json similarity index 100% rename from packages/mdat/tsconfig.build.lib.json rename to tsconfig.build.lib.json diff --git a/tsconfig.json b/tsconfig.json index b443a39..9e683b5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,9 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + + /* Markdown */ + "types": ["./src/types/md.d.ts"] } } diff --git a/packages/mdat/tsup.config.ts b/tsup.config.ts similarity index 100% rename from packages/mdat/tsup.config.ts rename to tsup.config.ts