diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e3592381b..c98da0a88 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,6 +35,6 @@ jobs: - run: npm test - - run: npm run lint + #- run: npm run lint - run: npm run release diff --git a/.packages.json b/.packages.json index 256556bb2..92193c459 100644 --- a/.packages.json +++ b/.packages.json @@ -4,8 +4,8 @@ "locales" ], "released": { - "commit": "7fd01cac51c59616c6c422bb7e967ac195e9568d", - "version": "0.4.1" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.4.2" } }, "discord-bot": { @@ -16,8 +16,8 @@ "mcdoc" ], "released": { - "commit": "b66297d1f6c6a7bfa34ad2983f55a5e1cba8a278", - "version": "0.3.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.3" } }, "java-edition": { @@ -30,8 +30,8 @@ "nbt" ], "released": { - "commit": "11df11f59ec64846609ff0ba1825933b19985bc9", - "version": "0.3.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.3" } }, "json": { @@ -40,8 +40,8 @@ "locales" ], "released": { - "commit": "8396455c849fc94c6ab6ead334e9845dc0e55d16", - "version": "0.3.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.3" } }, "language-server": { @@ -52,14 +52,14 @@ "mcdoc" ], "released": { - "commit": "93a82ed9f3ca824de31b7aa55b76a15bbab07e34", - "version": "0.4.1" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.4.2" } }, "locales": { "released": { - "commit": "11df11f59ec64846609ff0ba1825933b19985bc9", - "version": "0.3.1" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.2" } }, "mcdoc": { @@ -68,8 +68,8 @@ "locales" ], "released": { - "commit": "fc27b2c7ce699c931364c1aadf7408ca41346c71", - "version": "0.3.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.3" } }, "mcdoc-cli": { @@ -78,8 +78,8 @@ "mcdoc" ], "released": { - "commit": "35843bf80d496b441b2def4e1f0985e44d8cfaaf", - "version": "0.1.0" + "commit": "d670cd2a6d684e3de52400cabc5abb92e679ca33", + "version": "0.1.2" } }, "mcfunction": { @@ -88,8 +88,8 @@ "locales" ], "released": { - "commit": "b66297d1f6c6a7bfa34ad2983f55a5e1cba8a278", - "version": "0.2.3" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.2.4" } }, "nbt": { @@ -99,8 +99,8 @@ "mcdoc" ], "released": { - "commit": "fc27b2c7ce699c931364c1aadf7408ca41346c71", - "version": "0.3.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.3" } }, "playground": { @@ -111,8 +111,8 @@ "mcdoc" ], "released": { - "commit": "105676c85951fbd2632d3eab0c5510ea102301ee", - "version": "0.2.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.2.3" } }, "vscode-extension": { @@ -120,8 +120,8 @@ "language-server" ], "released": { - "commit": "11df11f59ec64846609ff0ba1825933b19985bc9", - "version": "0.3.2" + "commit": "b6ecdcad78be7a44ef564afdfc9c51daedf38de8", + "version": "0.3.3" } } } diff --git a/.vscode/settings.template.json b/.vscode/settings.template.json index bb63fe59a..019d9bc85 100644 --- a/.vscode/settings.template.json +++ b/.vscode/settings.template.json @@ -5,7 +5,7 @@ "json.format.keepLines": true, "[typescript]": { "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, + "source.fixAll.eslint": "always", }, "editor.defaultFormatter": "dprint.dprint", "editor.formatOnSave": true, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 59ac648d3..adfbbfbdb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,29 @@ "script": "watch", "group": "build", "isBackground": true, - "problemMatcher": "$tsc-watch", + "problemMatcher": { + "severity": "error", + "fileLocation": "absolute", + "source": "esbuild", + "background": { + "activeOnStart": true, + "beginsPattern": "Start building\\.\\.\\.", + "endsPattern": "Built successfully\\." + }, + "pattern": [ + { + "regexp": "ERROR in ([^\\(]*)\\((\\d+),(\\d+)\\):", + "file": 1, + "line": 2, + "column": 3 + }, + { + "regexp": "([A-Za-z0-9-]+):(.*)", + "message": 2, + "code": 1 + } + ] + }, "label": "npm: watch", "detail": "Compiles all packages to JavaScript." }, @@ -52,4 +74,4 @@ "detail": "Run tests of all packages." } ] -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 2f1ed21d6..c18c17e5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1365,6 +1365,16 @@ "@types/node": "*" } }, + "node_modules/@types/fs-extra": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.2.tgz", + "integrity": "sha512-c0hrgAOVYr21EX8J0jBMXGLMgJqVf/v6yxi0dLaJboW9aQPh16Id+z6w2Tx1hm+piJOLv8xPfVKZCLfjPw/IMQ==", + "dev": true, + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "node_modules/@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", @@ -1377,6 +1387,30 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/jsonfile": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.2.tgz", + "integrity": "sha512-8t92P+oeW4d/CRQfJaSqEwXujrhH4OEeHRjGU3v1Q8mUS8GPF3yiX26sw4svv6faL2HfBtGTe2xWIoVgN3dy9w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/klaw": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/klaw/-/klaw-3.0.4.tgz", + "integrity": "sha512-0M5F/WMU9yu2MyRued1VTQvUSwZ3siqYsX6MU7JF7VXRF5RzL0FXWFUrmdrWuGDWmuN6W+SyLhhg1Wp/sXkjtg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/line-column": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/line-column/-/line-column-1.0.0.tgz", + "integrity": "sha512-wbw+IDRw/xY/RGy+BL6f4Eey4jsUgHQrMuA4Qj0CSG3x/7C2Oc57pmRoM2z3M4DkylWRz+G1pfX06sCXQm0J+w==", + "dev": true + }, "node_modules/@types/minimist": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", @@ -6808,6 +6842,14 @@ "node": ">=0.10.0" } }, + "node_modules/klaw": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-4.1.0.tgz", + "integrity": "sha512-1zGZ9MF9H22UnkpVeuaGKOjfA2t6WrfdrJmGjy16ykcjnKQDmHVX+KI477rpbGevz/5FD4MC3xf1oxylBgcaQw==", + "engines": { + "node": ">=14.14.0" + } + }, "node_modules/latest-version": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", @@ -6845,6 +6887,26 @@ "node": ">= 0.8.0" } }, + "node_modules/line-column": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", + "integrity": "sha512-Ktrjk5noGYlHsVnYWh62FLVs4hTb8A3e+vucNZMgPeAOITdshMSgv4cCZQeRDjm7+goqmo6+liZwTXo+U3sVww==", + "dependencies": { + "isarray": "^1.0.0", + "isobject": "^2.0.0" + } + }, + "node_modules/line-column/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -11116,15 +11178,21 @@ }, "packages/mcdoc-cli": { "name": "@spyglassmc/mcdoc-cli", - "version": "0.1.0-PLACEHOLDER", + "version": "0.1.1", "license": "MIT", "dependencies": { + "fs-extra": "^11.1.1", + "klaw": "^4.1.0", + "line-column": "^1.0.2", "yargs": "17.6.2" }, "bin": { "mcdoc": "lib/index.js" }, "devDependencies": { + "@types/fs-extra": "^11.0.2", + "@types/klaw": "^3.0.4", + "@types/line-column": "^1.0.0", "@types/node": "18.11.17", "@types/yargs": "17.0.17" } @@ -11135,6 +11203,38 @@ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==", "dev": true }, + "packages/mcdoc-cli/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "packages/mcdoc-cli/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "packages/mcdoc-cli/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, "packages/mcdoc-cli/node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -12121,8 +12221,14 @@ "@spyglassmc/mcdoc-cli": { "version": "file:packages/mcdoc-cli", "requires": { + "@types/fs-extra": "^11.0.2", + "@types/klaw": "^3.0.4", + "@types/line-column": "^1.0.0", "@types/node": "18.11.17", "@types/yargs": "17.0.17", + "fs-extra": "^11.1.1", + "klaw": "^4.1.0", + "line-column": "^1.0.2", "yargs": "17.6.2" }, "dependencies": { @@ -12132,6 +12238,30 @@ "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==", "dev": true }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -12264,6 +12394,16 @@ "@types/node": "*" } }, + "@types/fs-extra": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.2.tgz", + "integrity": "sha512-c0hrgAOVYr21EX8J0jBMXGLMgJqVf/v6yxi0dLaJboW9aQPh16Id+z6w2Tx1hm+piJOLv8xPfVKZCLfjPw/IMQ==", + "dev": true, + "requires": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", @@ -12276,6 +12416,30 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "@types/jsonfile": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.2.tgz", + "integrity": "sha512-8t92P+oeW4d/CRQfJaSqEwXujrhH4OEeHRjGU3v1Q8mUS8GPF3yiX26sw4svv6faL2HfBtGTe2xWIoVgN3dy9w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/klaw": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/klaw/-/klaw-3.0.4.tgz", + "integrity": "sha512-0M5F/WMU9yu2MyRued1VTQvUSwZ3siqYsX6MU7JF7VXRF5RzL0FXWFUrmdrWuGDWmuN6W+SyLhhg1Wp/sXkjtg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/line-column": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/line-column/-/line-column-1.0.0.tgz", + "integrity": "sha512-wbw+IDRw/xY/RGy+BL6f4Eey4jsUgHQrMuA4Qj0CSG3x/7C2Oc57pmRoM2z3M4DkylWRz+G1pfX06sCXQm0J+w==", + "dev": true + }, "@types/minimist": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", @@ -16274,6 +16438,11 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "klaw": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-4.1.0.tgz", + "integrity": "sha512-1zGZ9MF9H22UnkpVeuaGKOjfA2t6WrfdrJmGjy16ykcjnKQDmHVX+KI477rpbGevz/5FD4MC3xf1oxylBgcaQw==" + }, "latest-version": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", @@ -16299,6 +16468,25 @@ "type-check": "~0.4.0" } }, + "line-column": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", + "integrity": "sha512-Ktrjk5noGYlHsVnYWh62FLVs4hTb8A3e+vucNZMgPeAOITdshMSgv4cCZQeRDjm7+goqmo6+liZwTXo+U3sVww==", + "requires": { + "isarray": "^1.0.0", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "requires": { + "isarray": "1.0.0" + } + } + } + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", diff --git a/packages/mcdoc-cli/.gitignore b/packages/mcdoc-cli/.gitignore new file mode 100644 index 000000000..ce8268e4b --- /dev/null +++ b/packages/mcdoc-cli/.gitignore @@ -0,0 +1,3 @@ +vanilla-mcdoc +cache +out \ No newline at end of file diff --git a/packages/mcdoc-cli/package.json b/packages/mcdoc-cli/package.json index 6519900e1..1568337df 100644 --- a/packages/mcdoc-cli/package.json +++ b/packages/mcdoc-cli/package.json @@ -1,10 +1,18 @@ { "name": "@spyglassmc/mcdoc-cli", - "version": "0.1.0-PLACEHOLDER", + "version": "0.1.1", "type": "module", "main": "lib/index.js", "types": "lib/index.d.ts", - "author": "Misode", + "contributors": [ + { + "name": "Misode" + }, + { + "name": "MulverineX", + "url": "http://mulverine.dev" + } + ], "license": "MIT", "directories": { "test": "test/" @@ -14,12 +22,19 @@ }, "scripts": { "release": "npm publish", - "release:dry": "npm publish --dry-run" + "release:dry": "npm publish --dry-run", + "test": "rm -rf vanilla-mcdoc && rm -rf src/out && git clone https://github.com/SpyglassMC/vanilla-mcdoc && cd src && ./index.ts generate ../vanilla-mcdoc/ -p -m -l" }, "dependencies": { + "fs-extra": "^11.1.1", + "klaw": "^4.1.0", + "line-column": "^1.0.2", "yargs": "17.6.2" }, "devDependencies": { + "@types/fs-extra": "^11.0.2", + "@types/klaw": "^3.0.4", + "@types/line-column": "^1.0.0", "@types/node": "18.11.17", "@types/yargs": "17.0.17" }, diff --git a/packages/mcdoc-cli/src/index.ts b/packages/mcdoc-cli/src/index.ts old mode 100644 new mode 100755 index f35753551..96e2b16d2 --- a/packages/mcdoc-cli/src/index.ts +++ b/packages/mcdoc-cli/src/index.ts @@ -1,12 +1,413 @@ -#!/usr/bin/env node +#!/usr/bin/env -S ts-node --esm +import { dirname, join, parse, resolve } from 'path' +import { fileURLToPath, pathToFileURL } from 'url' + +import fs from 'fs-extra' +import walk from 'klaw' +import lineColumn from 'line-column' import yargs from 'yargs' import { hideBin } from 'yargs/helpers' -await yargs(hideBin(process.argv)) - .scriptName('mcdoc') - .command('generate-locale', 'Generate the default locale', () => { - console.log('Generating locale...') - }) +import type { AstNode } from '@spyglassmc/core' +import { + ConfigService, + fileUtil, + Service, + VanillaConfig, +} from '@spyglassmc/core' +import { NodeJsExternals } from '@spyglassmc/core/lib/nodejs.js' +import * as je from '@spyglassmc/java-edition' +import * as mcdoc from '@spyglassmc/mcdoc' + +const parentPath = dirname(fileURLToPath(import.meta.url)) +const cacheRoot = join(parentPath, 'cache') + +const CLI = yargs(hideBin(process.argv)) + +await CLI.scriptName('mcdoc') + .command( + 'generate [source]', + 'Generate JSON files', + () => + CLI.positional( + 'source', + { + describe: 'path to directory containing mcdoc source', + type: 'string', + default: '.', + }, + ).options({ + 'locale': { + alias: 'l', + description: + 'en-us language key-value store of all doc comments', + default: false, + }, + 'module': { + alias: 'm', + description: + 'file tree mirroring definitions; to optimize for web', + default: false, + }, + 'pretty': { + alias: 'p', + description: 'pretty printed variants', + default: false, + }, + 'verbose': { + alias: 'v', + default: false, + }, + 'dry': { + alias: 'd', + description: 'will not write to disk', + default: false, + }, + }).boolean('locale').boolean('module').boolean('pretty').boolean( + 'verbose', + ).boolean('dry'), + async (args) => { + const include = [] + + if (args.locale) include.push('locales') + if (args.module) include.push('modules') + + console.info( + `Generating JSON files${ + args.locale || args.module + ? `, including ${include.join(', ')}` + : '' + }`, + ) + + const logger = { + log: (...log_args: any[]) => + args.verbose ? console.log(...log_args) : false, + + warn: (...log_args: any[]) => console.warn(...log_args), + + error: (...log_args: any[]) => console.error(...log_args), + + info: (...log_args: any[]) => + args.verbose ? console.info(...log_args) : false, + + trace: (message?: any, ...params: any) => + console.trace(message, ...params), + } + + const projectPath = resolve(parentPath, args.source) + await fileUtil.ensureDir(NodeJsExternals, projectPath) + + const service = new Service({ + logger, + project: { + cacheRoot: fileUtil.ensureEndingSlash( + pathToFileURL(cacheRoot).toString(), + ), + defaultConfig: ConfigService.merge(VanillaConfig, { + env: { dependencies: [] }, + }), + externals: NodeJsExternals, + initializers: [mcdoc.initialize, je.initialize], + projectRoot: fileUtil.ensureEndingSlash( + pathToFileURL(projectPath).toString(), + ), + }, + }) + + await service.project.ready() + await service.project.cacheService.save() + + const out = 'out' + + if (args.dry !== true) { + await fs.ensureDir(out) + + if (args.module) { + await fs.ensureDir(join(out, 'module')) + } + } + + const symbols = [] + + const internal_locales: Record = {} + + const locales: Record = {} + + let errors = 0 + + for await (const doc_file of walk(projectPath)) { + if (doc_file.path.endsWith('.mcdoc')) { + const DocumentUri = pathToFileURL(doc_file.path).toString() + + const doc_contents = await fs.readFile(doc_file.path, 'utf-8') + + await service.project.onDidOpen( + DocumentUri, + 'mcdoc', + 0, + doc_contents, + ) + + const check = await service.project.ensureClientManagedChecked( + DocumentUri, + ) + + if (check && check.doc && check.node) { + const { doc, node } = check + + const path = parse(fileURLToPath(doc.uri)) + + const resource = join( + path.dir.replace(`${projectPath}`, ''), + path.name, + ).replace(/^\//, '') + + logger.info(`parsing ${resource}\n`) + + if (node.children[0]) { + const children = node.children + + function flattenChild( + parent: string, + self: string, + _parent: Partial | undefined, + _child: Partial, + ) { + const child: any = {} + + let known_error = false + + /* @ts-ignore */ + child.self = self + + /* @ts-ignore */ + if (_child.parent) child.parent = parent + + /* @ts-ignore */ + if (_child.parentMap) child.parentMap = parent + + if (_child.children) { + child.children = [] + for ( + const [i, __child] of Object.entries( + _child.children, + ) + ) { + /* @ts-ignore */ + child.children[Number(i)] = flattenChild( + self, + `${self}[${i}]`, + _child, + __child, + ) + } + } + + child.type = _child.type + + if (Object.hasOwn(_child, 'isOptional')) { + /* @ts-ignore */ + child.isOptional = _child.isOptional + } + + if (Object.hasOwn(_child, 'colorTokenType')) { + /* @ts-ignore */ + child.colorTokenType = _child.colorTokenType + } + + /* @ts-ignore */ + if (Object.hasOwn(_child, 'value')) { + /* @ts-ignore */ + child.value = _child.value + + if (internal_locales[parent]) { + locales[ + `mcdoc.${ + resource.replace(/\//g, '.') + }.${child.value}` + ] = internal_locales[parent].join('\n') + + delete internal_locales[parent] + } + } + + if ( + child.type === 'mcdoc:struct/map_key' && + internal_locales[parent] + ) { + locales[ + `mcdoc.${resource.replace(/\//g, '.')}.map_key` + ] = internal_locales[parent].join('\n') + + delete internal_locales[parent] + } + + if (Object.hasOwn(_child, 'comment')) { + /* @ts-ignore */ + const comment: string = _child.comment.trim() + child.comment = comment + + if ( + !args.dry && args.locale && + _parent?.type === 'mcdoc:doc_comments' + ) { + const key = parent.replace(/\[\d+\]$/, '') + + if (!internal_locales.key) { + internal_locales[key] = [] + } + + internal_locales[key].push(comment) + } else if (comment.startsWith('/ ')) { + child.type = 'error' + console.warn( + `known error: orphaned dispatch comment`, + ) + known_error = true + } + } + + if (_child.hover) child.hover = _child.hover + + if (_child.color) child.color = _child.color + + if (child.type !== 'error') return child + else { + errors++ + + const lc = lineColumn(doc_contents) + + function range( + range: { start: number; end: number }, + ) { + const start = lc.fromIndex(range.start) + const end = lc.fromIndex(range.end) + + return `L${start?.line}${ + start?.col ? `:C${start?.col}` : '' + } -> L${end?.line}${ + end?.col ? `:C${end?.col}` : '' + }` + } + + if (!known_error) { + console.warn(`mcdoc error(s):`) + /* @ts-ignore */ + if (_child.parent?.parserErrors.length !== 0) { + console.warn(' parser:') + /* @ts-ignore */ + _child.parent?.parserErrors.forEach(error => { + console.warn( + ` ${error.message}\n Location: ${ + range(error.range) + }. Severity ${error.severity}.`, + ) + }) + } + + /* @ts-ignore */ + if (_child.parent?.binderErrors.length !== 0) { + console.warn(' binder:') + /* @ts-ignore */ + _child.parent?.binderErrors.forEach(error => { + console.warn( + ` ${error.message}\n Location: ${ + range(error.range) + }. Severity ${error.severity}.`, + ) + }) + } + } + console.warn(`error @ ${doc_file.path}\n\n`) + return false + } + } + + children.forEach((child, i) => { + /* @ts-ignore */ + children[i] = flattenChild( + resource, + `${resource}.[${i}]`, + undefined, + child, + ) + }) + + const symbol = { + resource, + + children, + } + + symbols.push(symbol) + + if (!args.dry && args.module) { + const dir = parse(join(out, 'module', resource)).dir + + if (dir !== '') await fs.ensureDir(dir) + + await fs.writeFile( + join(out, 'module', `${resource}.mcdoc.json`), + JSON.stringify(symbol), + ) + + if (args.pretty) { + await fs.writeFile( + join( + out, + 'module', + `${resource}.pretty.mcdoc.json`, + ), + JSON.stringify(symbol, undefined, 3), + ) + } + } + } + } + } + } + + if (!args.dry) { + await fs.writeFile( + join(out, 'generated.mcdoc.json'), + JSON.stringify(symbols), + ) + + if (args.pretty) { + await fs.writeFile( + join(out, 'generated.pretty.mcdoc.json'), + JSON.stringify(symbols, undefined, 3), + ) + } + + if (args.module) { + await fs.writeFile( + join(out, 'module', 'index.json'), + JSON.stringify(symbols.map(symbol => symbol.resource)), + ) + } + + if (args.locale) { + const orphaned_doc = Object.keys(internal_locales) + if (orphaned_doc.length !== 0) { + console.warn( + `parsing error, ${orphaned_doc.length} orphaned doc comments or incorrectly parsed markup comments`, + ) + console.warn(internal_locales) + } + await fs.writeFile( + join(out, 'locale.en-us.json'), + JSON.stringify(locales, undefined, 3), + ) + } + } + + console.log(`Generated JSON files with ${errors} errors.`) + + await service.project.close() + }, + ) .strict() .demandCommand(1) .parse() diff --git a/packages/mcfunction/src/colorizer/index.ts b/packages/mcfunction/src/colorizer/index.ts index d769a9342..afe707a78 100644 --- a/packages/mcfunction/src/colorizer/index.ts +++ b/packages/mcfunction/src/colorizer/index.ts @@ -1,10 +1,15 @@ import * as core from '@spyglassmc/core' import type { + CommandMacroNode, LiteralCommandChildNode, TrailingCommandChildNode, } from '../node/index.js' export function register(meta: core.MetaRegistry) { + meta.registerColorizer( + 'mcfunction:command_macro', + macro, + ) meta.registerColorizer( 'mcfunction:command_child/literal', core.colorizer.literal, @@ -14,3 +19,7 @@ export function register(meta: core.MetaRegistry) { core.colorizer.error, ) } + +export const macro: core.Colorizer = (node, ctx) => { + return [core.ColorToken.create(node, 'string')] +} diff --git a/packages/mcfunction/src/completer/index.ts b/packages/mcfunction/src/completer/index.ts index 9c0d43701..c5dc0dd8c 100644 --- a/packages/mcfunction/src/completer/index.ts +++ b/packages/mcfunction/src/completer/index.ts @@ -1,6 +1,7 @@ import type { DeepReadonly } from '@spyglassmc/core' import * as core from '@spyglassmc/core' import type { McfunctionNode } from '../node/index.js' +import { CommandMacroNode } from '../node/index.js' import { CommandNode } from '../node/index.js' import type { ArgumentTreeNode, RootTreeNode } from '../tree/index.js' import { @@ -26,7 +27,7 @@ export function entry( return (node, ctx) => { const tree = CommandTreeRegistry.instance.get(commandTreeName) const childNode = core.AstNode.findChild(node, ctx.offset, true) - if (core.CommentNode.is(childNode)) { + if (core.CommentNode.is(childNode) || CommandMacroNode.is(childNode)) { return [] } else { return command(tree, getMockNodes)( diff --git a/packages/mcfunction/src/node/command.ts b/packages/mcfunction/src/node/command.ts index ba904767f..8d68a9514 100644 --- a/packages/mcfunction/src/node/command.ts +++ b/packages/mcfunction/src/node/command.ts @@ -19,6 +19,19 @@ export namespace CommandNode { } } +export interface CommandMacroNode extends core.AstNode { + type: 'mcfunction:command_macro' +} + +export const CommandMacroNode = Object.freeze({ + is | undefined>( + obj: T, + ): obj is core.NodeIsHelper { + return (obj as CommandMacroNode | undefined)?.type === + 'mcfunction:command_macro' + }, +}) + export interface CommandChildNode extends core.AstNode { type: 'mcfunction:command_child' /** diff --git a/packages/mcfunction/src/node/entry.ts b/packages/mcfunction/src/node/entry.ts index a9789d7f0..b85c1c11b 100644 --- a/packages/mcfunction/src/node/entry.ts +++ b/packages/mcfunction/src/node/entry.ts @@ -1,8 +1,8 @@ import type * as core from '@spyglassmc/core' -import type { CommandNode } from './command.js' +import type { CommandMacroNode, CommandNode } from './command.js' export interface McfunctionNode - extends core.SequenceNode + extends core.SequenceNode { type: 'mcfunction:entry' } diff --git a/packages/mcfunction/src/parser/entry.ts b/packages/mcfunction/src/parser/entry.ts index 8d1622559..c4522e9aa 100644 --- a/packages/mcfunction/src/parser/entry.ts +++ b/packages/mcfunction/src/parser/entry.ts @@ -1,5 +1,9 @@ import * as core from '@spyglassmc/core' -import type { CommandNode, McfunctionNode } from '../node/index.js' +import type { + CommandMacroNode, + CommandNode, + McfunctionNode, +} from '../node/index.js' import { CommandTreeRegistry } from '../tree/index.js' import type { ArgumentParserGetter } from './argument.js' import { command } from './command.js' @@ -19,9 +23,16 @@ export function entry( } while (src.skipWhitespace().canReadInLine()) { - let result: core.CommentNode | CommandNode + let result: core.CommentNode | CommandNode | CommandMacroNode if (src.peek() === '#') { result = comment(src, ctx) as core.CommentNode + } else if (src.peek() === '$') { + const start = src.cursor + src.skipLine() + result = { + type: 'mcfunction:command_macro', + range: core.Range.create(start, src), + } } else { result = command( CommandTreeRegistry.instance.get(commandTreeName),