From 5f65e52ec6d6022873c89bc7f07d578f344c52d3 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Mon, 27 May 2024 10:36:33 +0200 Subject: [PATCH 1/9] Add link checker --- package-lock.json | 554 ++++++++++++++++++++++++++++++++++++++++- package.json | 8 +- scripts/check-links.ts | 106 ++++++++ 3 files changed, 655 insertions(+), 13 deletions(-) create mode 100644 scripts/check-links.ts diff --git a/package-lock.json b/package-lock.json index 6abb9bfd..dc558775 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,10 @@ "devDependencies": { "concurrently": "~8.2.1", "cross-env": "~7.0.3", - "shx": "~0.3.4" + "front-matter": "^4.0.2", + "glob": "^10.4.1", + "shx": "~0.3.4", + "ts-node": "^10.9.2" } }, "core": { @@ -315,6 +318,26 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/cli/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -1047,6 +1070,28 @@ "vscode": "npm:@codingame/monaco-vscode-api@1.83.2" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.19.4", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.4.tgz", @@ -1399,6 +1444,102 @@ "node": ">=12" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -1498,6 +1639,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-inject": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.4.tgz", @@ -1573,6 +1724,30 @@ "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@typefox/monaco-editor-react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@typefox/monaco-editor-react/-/monaco-editor-react-2.3.0.tgz", @@ -2010,6 +2185,15 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2473,6 +2657,12 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -3187,6 +3377,15 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "dev": true }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3204,6 +3403,12 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/electron-to-chromium": { "version": "1.4.479", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.479.tgz", @@ -3604,6 +3809,19 @@ "node": ">=0.8.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -3675,6 +3893,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -3688,6 +3922,15 @@ "url": "https://www.patreon.com/infusion" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, + "dependencies": { + "js-yaml": "^3.13.1" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -3768,19 +4011,22 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3797,6 +4043,30 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3982,6 +4252,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4127,11 +4398,42 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jackspeak": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", + "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4765,6 +5067,12 @@ "semver": "bin/semver" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4813,6 +5121,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/monaco-editor": { "version": "0.44.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", @@ -5414,6 +5731,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5829,6 +6171,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -5990,6 +6352,27 @@ "node": ">=4" } }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/shx": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", @@ -6006,6 +6389,18 @@ "node": ">=6" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -6057,6 +6452,12 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6084,6 +6485,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6096,6 +6512,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", @@ -6276,6 +6705,76 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/tslib": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", @@ -6371,6 +6870,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -6581,6 +7086,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6653,6 +7176,15 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", diff --git a/package.json b/package.json index cb45657c..f2a0f256 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,16 @@ "watch": "npm run build --workspace core && concurrently -c gray,blue -k -n hugo,tailwind \"npm run watch --workspace hugo\" \"npm run watch --workspace tailwind\"", "watch:gitpod": "npm run build --workspace core && concurrently -c gray,blue -k -n hugo,tailwind \"npm run watch:gitpod --workspace hugo\" \"npm run watch --workspace tailwind\"", "build": "npm run clean && npm run build --workspace core --workspace=tailwind --workspace=hugo", - "clean": "shx rm -rf public && npm run clean --workspace core --workspace=tailwind" + "clean": "shx rm -rf public && npm run clean --workspace core --workspace=tailwind", + "check:links": "ts-node scripts/check-links.ts" }, "devDependencies": { "concurrently": "~8.2.1", "cross-env": "~7.0.3", - "shx": "~0.3.4" + "front-matter": "^4.0.2", + "glob": "^10.4.1", + "shx": "~0.3.4", + "ts-node": "^10.9.2" }, "workspaces": [ "core", diff --git a/scripts/check-links.ts b/scripts/check-links.ts new file mode 100644 index 00000000..8d06d433 --- /dev/null +++ b/scripts/check-links.ts @@ -0,0 +1,106 @@ +import { glob } from "glob"; +import { mkdir, readFile } from "node:fs/promises"; +import { basename, dirname, resolve, relative } from 'node:path'; +import fm from "front-matter"; + +type Attributes = { + aliases?: string[]; + url?: string; + slug?: string; +} + +type MarkdownFile = { + localPath: string; + aliases: string[]; + links: string[]; +} + +const projectDir = dirname(__dirname); +const contentDir = resolve(projectDir, "hugo", "content"); + +async function main() { + let success = true; + const markdownFiles: MarkdownFile[] = await readMarkdownFiles(); + //collect what is there + const setOfUrls = new Set([ + urlToString('http://langium.org/') + ]); + for (const file of markdownFiles) { + for (const url of file.aliases) { + setOfUrls.add(urlToString(url)); + } + } + //check what is missing + for (const file of markdownFiles) { + console.log(`${relative(contentDir, file.localPath)}:`); + for (const link of file.links) { + if(link.startsWith("http")) { + continue; + } + const url = urlToString(link); + if(!setOfUrls.has(url)) { + console.log(`- MISSING LINK: ${url.toString()}`); + success = false; + } + } + } + return success; +} + +async function readMarkdownFiles() { + const markdownFiles: MarkdownFile[] = []; + const mdfiles = await glob(`${contentDir}/**/*.md`); + for (const mdFile of mdfiles) { + const content = await readFile(mdFile, 'utf-8'); + + //urls + const { attributes: { url, aliases, slug }, body } = fm(content); + let urls: string[] = []; + if (aliases) { + urls = [...urls, ...aliases]; + } + if (url) { + urls.push(url); + } else if (slug) { + urls.push(relative(contentDir, resolve(mdFile, '..', slug))); + } else { + const base = basename(mdFile, '.md'); + if (["index.md", "_index.md", '_index'].includes(base)) { + urls.push(relative(contentDir, resolve(mdFile, '..'))); + } else { + urls.push(relative(contentDir, resolve(mdFile, '..', base))); + } + } + + //links + const links = getAllLinks(content); + + //new file + markdownFiles.push({ + localPath: mdFile, + aliases: urls, + links + }); + } + return markdownFiles; +} + +function getAllLinks(content: string) { + const regexMdLinks = /\[([^\[]+)\](\(.*\))/gm + const matches = content.match(regexMdLinks) + const singleMatch = /\[([^\[]+)\]\((.*)\)/; + const result: string[] = []; + for (var i = 0; i < matches?.length ?? 0; i++) { + var text = singleMatch.exec(matches[i]) + result.push(text[2]); + } + return result; +} + +function urlToString(link: string): string { + const url = new URL(link, 'http://langium.org'); + url.hash = ""; + return url.toString(); +} + +main().then(success => process.exit(success ? 0 : 1)); \ No newline at end of file From 7ce426826c12c5bea30c40e057244cf59776b845 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Mon, 27 May 2024 10:56:57 +0200 Subject: [PATCH 2/9] Add aliases --- .../minilogo/building_an_extension/index.md | 2 ++ .../docs/learn/minilogo/customizing_cli.md | 2 ++ .../content/docs/learn/minilogo/generation.md | 2 ++ .../learn/minilogo/generation_in_the_web.md | 2 ++ .../docs/learn/minilogo/langium_and_monaco.md | 2 ++ .../content/docs/learn/minilogo/validation.md | 2 ++ .../docs/learn/minilogo/writing_a_grammar.md | 3 +++ hugo/content/docs/learn/workflow/_index.md | 2 ++ hugo/content/docs/recipes/code-bundling.md | 2 ++ .../docs/recipes/scoping/class-member.md | 2 ++ .../docs/recipes/scoping/qualified-name.md | 2 ++ .../docs/reference/document-lifecycle.md | 2 ++ .../docs/reference/grammar-language.md | 3 +++ hugo/content/docs/reference/semantic-model.md | 3 +++ scripts/check-links.ts | 21 +++++++++++++------ 15 files changed, 46 insertions(+), 6 deletions(-) diff --git a/hugo/content/docs/learn/minilogo/building_an_extension/index.md b/hugo/content/docs/learn/minilogo/building_an_extension/index.md index f8ace5a1..b50c7a1c 100644 --- a/hugo/content/docs/learn/minilogo/building_an_extension/index.md +++ b/hugo/content/docs/learn/minilogo/building_an_extension/index.md @@ -1,6 +1,8 @@ --- title: "Building an Extension" weight: 5 +aliases: + - /tutorials/building_an_extension --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/customizing_cli.md b/hugo/content/docs/learn/minilogo/customizing_cli.md index 836ac8ea..d2894308 100644 --- a/hugo/content/docs/learn/minilogo/customizing_cli.md +++ b/hugo/content/docs/learn/minilogo/customizing_cli.md @@ -1,6 +1,8 @@ --- title: "Customizing the CLI" weight: 2 +aliases: + - /tutorials/customizing_cli --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/generation.md b/hugo/content/docs/learn/minilogo/generation.md index 5898cd0a..7b47d670 100644 --- a/hugo/content/docs/learn/minilogo/generation.md +++ b/hugo/content/docs/learn/minilogo/generation.md @@ -1,6 +1,8 @@ --- title: "Generation" weight: 3 +aliases: + - /tutorials/generation --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/generation_in_the_web.md b/hugo/content/docs/learn/minilogo/generation_in_the_web.md index 4dc9bceb..c8db7cdb 100644 --- a/hugo/content/docs/learn/minilogo/generation_in_the_web.md +++ b/hugo/content/docs/learn/minilogo/generation_in_the_web.md @@ -1,6 +1,8 @@ --- title: "Generation in the Web" weight: 7 +aliases: + - /tutorials/generation_in_the_web --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/langium_and_monaco.md b/hugo/content/docs/learn/minilogo/langium_and_monaco.md index 573ae304..4dcee7b3 100644 --- a/hugo/content/docs/learn/minilogo/langium_and_monaco.md +++ b/hugo/content/docs/learn/minilogo/langium_and_monaco.md @@ -1,6 +1,8 @@ --- title: "Langium + Monaco Editor" weight: 6 +aliases: + - /tutorials/langium_and_monaco --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/validation.md b/hugo/content/docs/learn/minilogo/validation.md index 805f11ab..c37a5189 100644 --- a/hugo/content/docs/learn/minilogo/validation.md +++ b/hugo/content/docs/learn/minilogo/validation.md @@ -1,6 +1,8 @@ --- title: "Validation" weight: 1 +aliases: + - /tutorials/validation --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/writing_a_grammar.md b/hugo/content/docs/learn/minilogo/writing_a_grammar.md index b9f02a6a..84b50b0b 100644 --- a/hugo/content/docs/learn/minilogo/writing_a_grammar.md +++ b/hugo/content/docs/learn/minilogo/writing_a_grammar.md @@ -1,6 +1,9 @@ --- title: "Writing a Grammar" weight: 0 +aliases: + - /tutorials/writing_a_grammar + - /writing_a_grammar --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/workflow/_index.md b/hugo/content/docs/learn/workflow/_index.md index b829400a..b5b35caa 100644 --- a/hugo/content/docs/learn/workflow/_index.md +++ b/hugo/content/docs/learn/workflow/_index.md @@ -2,6 +2,8 @@ title: "Langium's workflow" weight: 0 url: /docs/learn/workflow/ +aliases: + - /docs/getting-started --- Langium's workflow can be expressed as a flow chart diagram, which boils down to the following steps in the diagram. diff --git a/hugo/content/docs/recipes/code-bundling.md b/hugo/content/docs/recipes/code-bundling.md index f0fb6f78..9dcf91a6 100644 --- a/hugo/content/docs/recipes/code-bundling.md +++ b/hugo/content/docs/recipes/code-bundling.md @@ -1,6 +1,8 @@ --- title: "Code Bundling" weight: 900 +aliases: + - /guides/code-bundling --- When you first create a Langium project using the [Yeoman generator](/docs/learn/workflow/install), it will only contain a plain TypeScript configuration, without any additional build processes. diff --git a/hugo/content/docs/recipes/scoping/class-member.md b/hugo/content/docs/recipes/scoping/class-member.md index d6ef7ca1..2051ceb8 100644 --- a/hugo/content/docs/recipes/scoping/class-member.md +++ b/hugo/content/docs/recipes/scoping/class-member.md @@ -1,6 +1,8 @@ --- title: "Class Member Scoping" weight: 200 +aliases: + - /class-member --- In this guide we will take a look at member based scoping. It's a mechanism you are likely familiar with from object oriented languages such as Java, C# and JavaScript: diff --git a/hugo/content/docs/recipes/scoping/qualified-name.md b/hugo/content/docs/recipes/scoping/qualified-name.md index d79e968a..8f9ffbb1 100644 --- a/hugo/content/docs/recipes/scoping/qualified-name.md +++ b/hugo/content/docs/recipes/scoping/qualified-name.md @@ -1,6 +1,8 @@ --- title: "Qualified Name Scoping" weight: 100 +aliases: + - /qualified-name --- Qualified name scoping refers to a style of referencing elements using a fully qualified name. diff --git a/hugo/content/docs/reference/document-lifecycle.md b/hugo/content/docs/reference/document-lifecycle.md index 1a99770e..bc2a8247 100644 --- a/hugo/content/docs/reference/document-lifecycle.md +++ b/hugo/content/docs/reference/document-lifecycle.md @@ -1,6 +1,8 @@ --- title: 'Document Lifecycle' weight: 300 +aliases: + - /docs/document-lifecycle --- `LangiumDocument` is the central data structure in Langium that represents a text file of your DSL. Its main purpose is to hold the parsed Abstract Syntax Tree (AST) plus additional information derived from it. After its creation, a `LangiumDocument` must be "built" before it can be used in any way. The service responsible for building documents is called `DocumentBuilder`. diff --git a/hugo/content/docs/reference/grammar-language.md b/hugo/content/docs/reference/grammar-language.md index 2def1c3f..e0d732b6 100644 --- a/hugo/content/docs/reference/grammar-language.md +++ b/hugo/content/docs/reference/grammar-language.md @@ -1,6 +1,9 @@ --- title: "Grammar Language" weight: 100 +aliases: + - /grammar-language + - /docs/grammar-language --- {{< toc format=html >}} diff --git a/hugo/content/docs/reference/semantic-model.md b/hugo/content/docs/reference/semantic-model.md index 56df2bca..ac5f9a02 100644 --- a/hugo/content/docs/reference/semantic-model.md +++ b/hugo/content/docs/reference/semantic-model.md @@ -1,6 +1,9 @@ --- title: "Semantic Model Inference" weight: 400 +aliases: + - /sematic-model + - /semantic-model --- When AST nodes are created during the parsing of a document, they are given a type. The language grammar dictates the shape of those types and how they might be related to each other. All types form the *semantic model* of your language. There are two ways by which Langium derives semantic model types from the grammar, by **[inference](#inferred-types)** and by **[declaration](#declared-types)**. diff --git a/scripts/check-links.ts b/scripts/check-links.ts index 8d06d433..f01378b9 100644 --- a/scripts/check-links.ts +++ b/scripts/check-links.ts @@ -23,8 +23,10 @@ async function main() { const markdownFiles: MarkdownFile[] = await readMarkdownFiles(); //collect what is there const setOfUrls = new Set([ - urlToString('http://langium.org/') - ]); + 'http://langium.org/', + "/showcase", + "/playground" + ].map(urlToString)); for (const file of markdownFiles) { for (const url of file.aliases) { setOfUrls.add(urlToString(url)); @@ -32,13 +34,17 @@ async function main() { } //check what is missing for (const file of markdownFiles) { - console.log(`${relative(contentDir, file.localPath)}:`); + let out = false; for (const link of file.links) { - if(link.startsWith("http")) { + if(link.startsWith("http") || link.endsWith(".png") || link.endsWith(".jpg")) { continue; } const url = urlToString(link); if(!setOfUrls.has(url)) { + if(!out) { + console.log(`${relative(contentDir, file.localPath)}:`); + out = true; + } console.log(`- MISSING LINK: ${url.toString()}`); success = false; } @@ -86,9 +92,9 @@ async function readMarkdownFiles() { } function getAllLinks(content: string) { - const regexMdLinks = /\[([^\[]+)\](\(.*\))/gm + const regexMdLinks = /\[([^\[]+)\](\(.*?\))/gm const matches = content.match(regexMdLinks) - const singleMatch = /\[([^\[]+)\]\((.*)\)/; + const singleMatch = /\[([^\[]+)\]\((.*?)\)/; const result: string[] = []; for (var i = 0; i < matches?.length ?? 0; i++) { var text = singleMatch.exec(matches[i]) @@ -100,6 +106,9 @@ function getAllLinks(content: string) { function urlToString(link: string): string { const url = new URL(link, 'http://langium.org'); url.hash = ""; + if(url.pathname.endsWith("/")) { + url.pathname = url.pathname.substring(0, url.pathname.length-1) + } return url.toString(); } From bd16a91b008f576373facac79c3b7b9b63348b8b Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 15:06:07 +0200 Subject: [PATCH 3/9] Fix the remaining links pointing to (old) alias links --- hugo/content/docs/introduction/features.md | 6 +- .../{index.md => _index.md} | 0 hugo/content/docs/learn/workflow/_index.md | 2 +- hugo/content/docs/recipes/builtin-library.md | 2 +- hugo/content/docs/recipes/code-bundling.md | 2 +- .../docs/recipes/multiple-languages.md | 2 +- hugo/content/docs/recipes/scoping/_index.md | 4 +- .../docs/recipes/scoping/qualified-name.md | 2 +- .../docs/reference/grammar-language.md | 4 +- hugo/content/docs/reference/semantic-model.md | 2 +- package-lock.json | 12 ++++ package.json | 2 + scripts/check-links.ts | 58 ++++++++++++------- 13 files changed, 66 insertions(+), 32 deletions(-) rename hugo/content/docs/learn/minilogo/building_an_extension/{index.md => _index.md} (100%) diff --git a/hugo/content/docs/introduction/features.md b/hugo/content/docs/introduction/features.md index e6fa716e..0a00ac81 100644 --- a/hugo/content/docs/introduction/features.md +++ b/hugo/content/docs/introduction/features.md @@ -19,7 +19,7 @@ In this chapter, you'll get a closer look at the requirements developers usually - [Cross References and Linking](#cross-references-and-linking) - [Workspace Management](#workspace-management) - [Editing Support](#editing-support) -- [Try it out!](#try-it-out) +- [Try it out](#try-it-out) Langium provides out-of-the-box solutions for these problems, with the ability to fine-tune every part of it to fit your domain requirements. @@ -27,7 +27,7 @@ Langium provides out-of-the-box solutions for these problems, with the ability t ## Language Parsing -Programming languages and domain specific languages (DSLs) cannot be parsed using simple regular expressions (RegExp). Instead they require a more sophisticated parsing strategy. To define a custom language in Langium, you interact with a high level representation of your context-free grammar using the [Langium grammar language](/docs/grammar-language), in a similar fashion to EBNF. +Programming languages and domain specific languages (DSLs) cannot be parsed using simple regular expressions (RegExp). Instead they require a more sophisticated parsing strategy. To define a custom language in Langium, you interact with a high level representation of your context-free grammar using the [Langium grammar language](/docs/reference/grammar-language), in a similar fashion to EBNF. Based on the grammar, Langium is then able to construct a parser which transforms an input string into a semantic model representation. Just as the name suggests, this model captures the essential structure to describe your language. @@ -97,7 +97,7 @@ The Langium framework is deeply integrated with the [language server protocol](h The LSP includes commonly used language features, such as code completion, custom validations/diagnostics, finding references, formatting and many more. This allows for deep IDE integration without binding your language to a single IDE. Langium offers out-of-the-box support for most of these language features, with additional extension points for your domain specific requirements. -## Try it out! +## Try it out You can try out most of these features using our [showcase](/showcase/) and [playground](/playground/). The languages shown there are written using Langium and integrated in the monaco-editor. diff --git a/hugo/content/docs/learn/minilogo/building_an_extension/index.md b/hugo/content/docs/learn/minilogo/building_an_extension/_index.md similarity index 100% rename from hugo/content/docs/learn/minilogo/building_an_extension/index.md rename to hugo/content/docs/learn/minilogo/building_an_extension/_index.md diff --git a/hugo/content/docs/learn/workflow/_index.md b/hugo/content/docs/learn/workflow/_index.md index b5b35caa..ddec04f2 100644 --- a/hugo/content/docs/learn/workflow/_index.md +++ b/hugo/content/docs/learn/workflow/_index.md @@ -1,7 +1,7 @@ --- title: "Langium's workflow" weight: 0 -url: /docs/learn/workflow/ +url: /docs/learn/workflow aliases: - /docs/getting-started --- diff --git a/hugo/content/docs/recipes/builtin-library.md b/hugo/content/docs/recipes/builtin-library.md index 7e53a6c3..974047cd 100644 --- a/hugo/content/docs/recipes/builtin-library.md +++ b/hugo/content/docs/recipes/builtin-library.md @@ -8,7 +8,7 @@ For example, TypeScript provides users with typings for globally accessible vari They are part of the JavaScript runtime, and not defined by any user or a package they might import. Instead, these features are contributed through what we call builtin libraries. -Loading a builtin library in Langium is very simple. We first start off with defining the source code of the library using the *hello world* language from the [getting started guide](/docs/getting-started): +Loading a builtin library in Langium is very simple. We first start off with defining the source code of the library using the *hello world* language from the [getting started guide](/docs/learn/workflow): ```ts export const builtinHelloWorld = ` diff --git a/hugo/content/docs/recipes/code-bundling.md b/hugo/content/docs/recipes/code-bundling.md index 9dcf91a6..1f2d0183 100644 --- a/hugo/content/docs/recipes/code-bundling.md +++ b/hugo/content/docs/recipes/code-bundling.md @@ -5,7 +5,7 @@ aliases: - /guides/code-bundling --- -When you first create a Langium project using the [Yeoman generator](/docs/learn/workflow/install), it will only contain a plain TypeScript configuration, without any additional build processes. +When you first create a Langium project using the [Yeoman generator](/docs/learn/workflow/scaffold#your-first-example-language), it will only contain a plain TypeScript configuration, without any additional build processes. However, if you want to make your language available for consumption in a non-development context, you'll want to create a bundle. It is not absolutely necessary in a Node.js context, since you can always resolve local `node_modules` but it's still recommended [for vscode extensions](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). It improves performance and decreases file size by minifying your code and only including what you actually need. diff --git a/hugo/content/docs/recipes/multiple-languages.md b/hugo/content/docs/recipes/multiple-languages.md index d76d7065..112a20e9 100644 --- a/hugo/content/docs/recipes/multiple-languages.md +++ b/hugo/content/docs/recipes/multiple-languages.md @@ -25,7 +25,7 @@ The entire change touches several files. Let's summarize what needs to be done: ## Our scenario -To keep this guide easy, I will use the `hello-world` project from the [learning section](/docs/learn/workflow). +To keep this guide easy, I will use the [`hello-world` project](/docs/learn/workflow) of the learning section. Let’s imagine that we have three languages: diff --git a/hugo/content/docs/recipes/scoping/_index.md b/hugo/content/docs/recipes/scoping/_index.md index 9d683f4f..b97b2708 100644 --- a/hugo/content/docs/recipes/scoping/_index.md +++ b/hugo/content/docs/recipes/scoping/_index.md @@ -25,8 +25,8 @@ In general, the way we resolve references is split into three phases of the docu In this guide, we'll look at different scoping kinds and styles and see how we can achieve them using Langium: -1. [Qualified Name Scoping](./qualified-name) -2. [Class Member Scoping](./class-member) +1. [Qualified Name Scoping](/docs/recipes/scoping/qualified-name) +2. [Class Member Scoping](/docs/recipes/scoping/class-member) Note that these are just example implementations for commonly used scoping methods. The scoping API of Langium is designed to be flexible and extensible for any kind of use case. diff --git a/hugo/content/docs/recipes/scoping/qualified-name.md b/hugo/content/docs/recipes/scoping/qualified-name.md index 8f9ffbb1..715bcabd 100644 --- a/hugo/content/docs/recipes/scoping/qualified-name.md +++ b/hugo/content/docs/recipes/scoping/qualified-name.md @@ -23,7 +23,7 @@ void main() { As can be seen, using qualified name scoping is quite helpful in this case. It allows us to reference the `getDocumentation` function through the scope computed & made available by the `Langium` namespace, even though it's not directly accessible within the scope of `main` by itself. -Note that such behavior can also be accomplished using [class member scoping](./class-member). +Note that such behavior can also be accomplished using [class member scoping](/docs/recipes/scoping/class-member). However, there is one core advantage to using globally available elements: Compared to member scoping, this type of scoping requires few resources. The lookup required for qualified name scoping can be done in near constant time with just a bit of additional computation on a **per-document** basis, whereas member scoping needs to do a lot of computation on a **per-reference** basis. diff --git a/hugo/content/docs/reference/grammar-language.md b/hugo/content/docs/reference/grammar-language.md index e0d732b6..9bd6e7dd 100644 --- a/hugo/content/docs/reference/grammar-language.md +++ b/hugo/content/docs/reference/grammar-language.md @@ -11,7 +11,9 @@ aliases: The grammar language describes the syntax and structure of your language. The [Langium grammar language](https://github.com/eclipse-langium/langium/blob/main/packages/langium/src/grammar/langium-grammar.langium) is implemented using Langium itself and therefore follows the same syntactic rules as any language created with Langium. The grammar language will define the structure of the *abstract syntax tree* (AST) which in Langium is a collection of *TypeScript types* describing the content of a parsed document and organized hierarchically. The individual nodes of the tree are then represented with JavaScript objects at runtime. In the following, we describe the Langium syntax and document structure. + ## Language Declaration + An *entry* Langium grammar file (i.e. a grammar which contains an [entry rule](#the-entry-rule)) always starts with a header which declares the name of the language. For example, a language named `MyLanguage` would be declared with: ```langium @@ -80,7 +82,7 @@ Person: ``` In this example, the parser will create an object of type `Person`. This object will have a property `name` which value and type must match the terminal rule `ID` (i.e. the property `name` is of type `string` and cannot start with a digit or special character). -By default, the parser will create an object with an inferred type corresponding to the parser rule name. It is possible to override this behavior by explicitly defining the type of the object to be created. This is done by adding the keyword `returns` followed by a separately declared type, or the keyword `infers` followed by the name of the type to be inferred for this rule (more about this [in the next chapter](../sematic-model)): +By default, the parser will create an object with an inferred type corresponding to the parser rule name. It is possible to override this behavior by explicitly defining the type of the object to be created. This is done by adding the keyword `returns` followed by a separately declared type, or the keyword `infers` followed by the name of the type to be inferred for this rule (more about this [in the next chapter](/docs/reference/semantic-model)): ```langium Person infers OtherType: 'person' name=ID; diff --git a/hugo/content/docs/reference/semantic-model.md b/hugo/content/docs/reference/semantic-model.md index ac5f9a02..151bb111 100644 --- a/hugo/content/docs/reference/semantic-model.md +++ b/hugo/content/docs/reference/semantic-model.md @@ -92,7 +92,7 @@ interface X extends AstNode { ``` ### Assignments -There are three available kinds of [assignments](../grammar-language/#assignments) in a parser rule: +There are three available kinds of [assignments](/docs/reference/grammar-language/#assignments) in a parser rule: 1. `=` for assigning a **single value** to a property, resulting in the property's type to be derived from the right hand side of the assignment. 2. `+=` for assigning **multiple values** to a property, resulting in the property's type to be an array of the right hand side of the assignment. diff --git a/package-lock.json b/package-lock.json index dc558775..aeaa20cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "tailwind" ], "devDependencies": { + "@types/chalk": "^2.2.0", + "chalk": "^4.0.0", "concurrently": "~8.2.1", "cross-env": "~7.0.3", "front-matter": "^4.0.2", @@ -1770,6 +1772,16 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/chalk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", + "deprecated": "This is a stub types definition for chalk (https://github.com/chalk/chalk). chalk provides its own type definitions, so you don't need @types/chalk installed!", + "dev": true, + "dependencies": { + "chalk": "*" + } + }, "node_modules/@types/css-font-loading-module": { "version": "0.0.13", "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.13.tgz", diff --git a/package.json b/package.json index f2a0f256..51fdc8d5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "check:links": "ts-node scripts/check-links.ts" }, "devDependencies": { + "@types/chalk": "^2.2.0", + "chalk": "^4.0.0", "concurrently": "~8.2.1", "cross-env": "~7.0.3", "front-matter": "^4.0.2", diff --git a/scripts/check-links.ts b/scripts/check-links.ts index f01378b9..756429df 100644 --- a/scripts/check-links.ts +++ b/scripts/check-links.ts @@ -1,6 +1,7 @@ import { glob } from "glob"; -import { mkdir, readFile } from "node:fs/promises"; +import { readFile } from "node:fs/promises"; import { basename, dirname, resolve, relative } from 'node:path'; +import chalk from 'chalk'; import fm from "front-matter"; type Attributes = { @@ -11,41 +12,56 @@ type Attributes = { type MarkdownFile = { localPath: string; + documentLink: string; aliases: string[]; links: string[]; } +type LinkType = 'alias'|'document'; + const projectDir = dirname(__dirname); const contentDir = resolve(projectDir, "hugo", "content"); async function main() { - let success = true; - const markdownFiles: MarkdownFile[] = await readMarkdownFiles(); - //collect what is there - const setOfUrls = new Set([ + const markdownFiles = await readMarkdownFiles(); + const setOfUrls = classifyAsDocumentLinksOrAliases(markdownFiles); + //await writeFile("existingLinks.txt", JSON.stringify([...setOfUrls.entries()], null, 2)); + return printMissingLinks(markdownFiles, setOfUrls); +} + +function classifyAsDocumentLinksOrAliases(markdownFiles: MarkdownFile[]) { + const documentLinks = [ + ...markdownFiles.map(m => m.documentLink), 'http://langium.org/', "/showcase", "/playground" - ].map(urlToString)); - for (const file of markdownFiles) { - for (const url of file.aliases) { - setOfUrls.add(urlToString(url)); - } - } - //check what is missing + ].map(urlToString).map(s => [s, 'document'] as const); + const aliases = markdownFiles.flatMap(m => m.aliases).map(urlToString).map(s => [s, 'alias'] as const); + return new Map([...documentLinks, ...aliases]); +} + +function printMissingLinks(markdownFiles: MarkdownFile[], setOfUrls: Map) { + let success: boolean = true; for (const file of markdownFiles) { let out = false; for (const link of file.links) { - if(link.startsWith("http") || link.endsWith(".png") || link.endsWith(".jpg")) { + if (link.startsWith("http") || link.endsWith(".png") || link.endsWith(".jpg")) { continue; } const url = urlToString(link); - if(!setOfUrls.has(url)) { - if(!out) { + if (!setOfUrls.has(url)) { + if (!out) { + console.log(`${relative(contentDir, file.localPath)}:`); + out = true; + } + console.log(`- ${chalk.red("MISSING LINK")}: ${url.toString()}`); + success = false; + } else if(setOfUrls.get(url) === 'alias') { + if (!out) { console.log(`${relative(contentDir, file.localPath)}:`); out = true; } - console.log(`- MISSING LINK: ${url.toString()}`); + console.log(`- ${chalk.yellow("LINK TO ALIAS")}: ${url.toString()}`); success = false; } } @@ -65,16 +81,17 @@ async function readMarkdownFiles() { if (aliases) { urls = [...urls, ...aliases]; } + let documentLink: string = ''; if (url) { - urls.push(url); + documentLink = url; } else if (slug) { - urls.push(relative(contentDir, resolve(mdFile, '..', slug))); + documentLink = relative(contentDir, resolve(mdFile, '..', slug)); } else { const base = basename(mdFile, '.md'); if (["index.md", "_index.md", '_index'].includes(base)) { - urls.push(relative(contentDir, resolve(mdFile, '..'))); + documentLink = relative(contentDir, resolve(mdFile, '..')); } else { - urls.push(relative(contentDir, resolve(mdFile, '..', base))); + documentLink = relative(contentDir, resolve(mdFile, '..', base)); } } @@ -84,6 +101,7 @@ async function readMarkdownFiles() { //new file markdownFiles.push({ localPath: mdFile, + documentLink, aliases: urls, links }); From 934d7c03aea2b026d36576201334f20995096060 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 15:12:38 +0200 Subject: [PATCH 4/9] Add a GH action for the link checker --- .github/workflows/links.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/links.yml diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 00000000..a04e73cd --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,22 @@ +name: Check if all links are reachable +on: + push: + branches: main + pull_request: + branches: main + workflow_dispatch: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + - name: Checkout + uses: actions/checkout@v3 + - name: Install + run: npm install + - name: Check links + run: npm run check:links \ No newline at end of file From 18e888f358801162ce03d145816fdcc2725e39ad Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 15:35:18 +0200 Subject: [PATCH 5/9] Test link checker --- hugo/content/docs/introduction/features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugo/content/docs/introduction/features.md b/hugo/content/docs/introduction/features.md index 0a00ac81..35301c6e 100644 --- a/hugo/content/docs/introduction/features.md +++ b/hugo/content/docs/introduction/features.md @@ -101,4 +101,4 @@ The LSP includes commonly used language features, such as code completion, custo You can try out most of these features using our [showcase](/showcase/) and [playground](/playground/). The languages shown there are written using Langium and integrated in the monaco-editor. -If you're interested in Langium, you can check out our [learning](/docs/learn/workflow) page next. There you'll learn how to get started writing your first language, and to learn more about how Langium can help you achieve your language designing goals. +If you're interested in Langium, you can check out our [learning](/docs/learn/workflow123) page next. There you'll learn how to get started writing your first language, and to learn more about how Langium can help you achieve your language designing goals. From 1c73b6c40d83297a541d241a7705bf2448bbe543 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 15:36:56 +0200 Subject: [PATCH 6/9] Revert change --- hugo/content/docs/introduction/features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugo/content/docs/introduction/features.md b/hugo/content/docs/introduction/features.md index 35301c6e..0a00ac81 100644 --- a/hugo/content/docs/introduction/features.md +++ b/hugo/content/docs/introduction/features.md @@ -101,4 +101,4 @@ The LSP includes commonly used language features, such as code completion, custo You can try out most of these features using our [showcase](/showcase/) and [playground](/playground/). The languages shown there are written using Langium and integrated in the monaco-editor. -If you're interested in Langium, you can check out our [learning](/docs/learn/workflow123) page next. There you'll learn how to get started writing your first language, and to learn more about how Langium can help you achieve your language designing goals. +If you're interested in Langium, you can check out our [learning](/docs/learn/workflow) page next. There you'll learn how to get started writing your first language, and to learn more about how Langium can help you achieve your language designing goals. From 7f44c4f61169c2691f1ca5d412c401d52622d763 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 15:43:09 +0200 Subject: [PATCH 7/9] Update .github/workflows/links.yml Co-authored-by: Mark Sujew --- .github/workflows/links.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index a04e73cd..0758cbdb 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -17,6 +17,6 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Install - run: npm install + run: npm ci - name: Check links run: npm run check:links \ No newline at end of file From 855acc37a962bee6623dcb04dd40e50651843b08 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 15:49:47 +0200 Subject: [PATCH 8/9] Add a status line at the end of execution --- scripts/check-links.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/check-links.ts b/scripts/check-links.ts index 756429df..4a3595f9 100644 --- a/scripts/check-links.ts +++ b/scripts/check-links.ts @@ -26,7 +26,14 @@ async function main() { const markdownFiles = await readMarkdownFiles(); const setOfUrls = classifyAsDocumentLinksOrAliases(markdownFiles); //await writeFile("existingLinks.txt", JSON.stringify([...setOfUrls.entries()], null, 2)); - return printMissingLinks(markdownFiles, setOfUrls); + const success = printMissingLinks(markdownFiles, setOfUrls); + if(success) { + console.log(chalk.greenBright('Success!')); + process.exit(0); + } else { + console.log(chalk.redBright('Failed!')); + process.exit(1); + } } function classifyAsDocumentLinksOrAliases(markdownFiles: MarkdownFile[]) { @@ -130,4 +137,4 @@ function urlToString(link: string): string { return url.toString(); } -main().then(success => process.exit(success ? 0 : 1)); \ No newline at end of file +main(); \ No newline at end of file From fe405e11d3753d9e294e2c242ef7950f80ee0474 Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Wed, 29 May 2024 16:47:46 +0200 Subject: [PATCH 9/9] Remove strings that never match --- scripts/check-links.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check-links.ts b/scripts/check-links.ts index 4a3595f9..35bf3184 100644 --- a/scripts/check-links.ts +++ b/scripts/check-links.ts @@ -95,7 +95,7 @@ async function readMarkdownFiles() { documentLink = relative(contentDir, resolve(mdFile, '..', slug)); } else { const base = basename(mdFile, '.md'); - if (["index.md", "_index.md", '_index'].includes(base)) { + if (['index', '_index'].includes(base)) { documentLink = relative(contentDir, resolve(mdFile, '..')); } else { documentLink = relative(contentDir, resolve(mdFile, '..', base));