diff --git a/change/@minecraft-api-docs-generator-58498d8d-0f93-4bb1-989c-d69950d7afdc.json b/change/@minecraft-api-docs-generator-58498d8d-0f93-4bb1-989c-d69950d7afdc.json new file mode 100644 index 0000000..1a91d10 --- /dev/null +++ b/change/@minecraft-api-docs-generator-58498d8d-0f93-4bb1-989c-d69950d7afdc.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Asserts if linking is missed", + "packageName": "@minecraft/api-docs-generator", + "email": "brandon.chan@skyboxlabs.com", + "dependentChangeType": "patch" +} diff --git a/tools/api-docs-generator-test-snapshots/test/runGeneratorForTest.ts b/tools/api-docs-generator-test-snapshots/test/runGeneratorForTest.ts index 2c77210..0e5dd69 100644 --- a/tools/api-docs-generator-test-snapshots/test/runGeneratorForTest.ts +++ b/tools/api-docs-generator-test-snapshots/test/runGeneratorForTest.ts @@ -17,6 +17,7 @@ export type RunGeneratorForTestOptions = { additionalArgs?: string; excludedFiles?: string[]; skipMerging?: boolean; + expectedLoggedErrorMessages?: string[]; }; function getAllFiles(dirPath: string): string[] { @@ -34,6 +35,20 @@ function getAllFiles(dirPath: string): string[] { return arrayOfFiles; } +function getErrorsFromOutput(output: string): string[] { + const errorPrefix = '[ERROR]'; + const retList = []; + + const logs = output.split('\n'); + for (const line of logs) { + if (line.indexOf(errorPrefix) === 0) { + retList.push(line); + } + } + + return retList; +} + export function runGeneratorForTest(options: RunGeneratorForTestOptions): void { const { additionalArgs, configPath, generators, minecraftVersion, testDir } = options; let { inDir, outDir, docsDir } = options; @@ -64,12 +79,25 @@ export function runGeneratorForTest(options: RunGeneratorForTestOptions): void { encoding: 'utf-8', }); } catch (e) { - console.error(`Errors detected in test '${path.basename(testDir)}', see log for details: ${testOutputPath}`); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access testOutput = `${e.stdout ? `${e.stdout.toString()}\n` : ''}${e.stderr ? `ERROR:\n${e.stderr.toString()}` : ''}`; - throw e; + if (!options.expectedLoggedErrorMessages) { + console.error( + `Errors detected in test '${path.basename(testDir)}', see log for details: ${testOutputPath}` + ); + throw e; + } else { + const errorOutputs = getErrorsFromOutput(testOutput); + for (const errorLine of errorOutputs) { + if (!options.expectedLoggedErrorMessages.includes(errorLine)) { + console.error( + `Unexpected errors detected in test '${path.basename(testDir)}', see log for details: ${testOutputPath}` + ); + throw e; + } + } + } } finally { if (testOutput) { fs.writeFileSync(testOutputPath, testOutput); diff --git a/tools/api-docs-generator-test-snapshots/test/type_linking/__snapshots__/typeLinking.spec.ts.snap b/tools/api-docs-generator-test-snapshots/test/type_linking/__snapshots__/typeLinking.spec.ts.snap index f88643c..2c2eb5c 100644 --- a/tools/api-docs-generator-test-snapshots/test/type_linking/__snapshots__/typeLinking.spec.ts.snap +++ b/tools/api-docs-generator-test-snapshots/test/type_linking/__snapshots__/typeLinking.spec.ts.snap @@ -345,6 +345,8 @@ Example enum value: [*@minecraft/example-module.ExampleEnum.ExampleValue*](../.. Example error: [*@minecraft/example-module.ExampleError*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleerror) +Example link problem: {@link @minecraft/example-module.ExampleProblem4} + This line has multiple links! [*@minecraft/example-module*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md) [*@minecraft/example-module.ExampleFunction*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#examplefunction) [*@minecraft/example-module.ExampleConstant*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleconstant) [*@minecraft/example-module.ExampleObject*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleobject) ## [Changelog](changelog.md) @@ -492,6 +494,12 @@ Example enum value: [*@minecraft/example-module.ExampleEnum.ExampleValue*](../.. Example error: [*@minecraft/example-module.ExampleError*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleerror) +Example link problem: {@link @minecraft/example-module.ExampleProblem} + +Example link problem: {@link @minecraft/example-module.ExampleProblem2} + +Example link problem: {@link @minecraft/example-module.ExampleProblem3} + This line has multiple links and lots of text! This is the first link [*@minecraft/example-module*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md), and this is the second. [*@minecraft/example-module.ExampleFunction*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#examplefunction) Here's a third link [*@minecraft/example-module.ExampleConstant*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleconstant) and this one here is the final link [*@minecraft/example-module.ExampleObject*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleobject) ## [Changelog](changelog.md) @@ -863,23 +871,6 @@ exports[`Type Linking > Properly generates documentation for types that are link ***************************************************************************** */ /** * @packageDocumentation - * This is a description with a ton of links: - * Example module: {@link @minecraft/example-module} - * Example module function: {@link ExampleFunction} - * Example module constant: {@link ExampleConstant} - * Example module object: {@link ExampleObject} - * Example class: {@link ExampleClass} - * Example class property: {@link ExampleClass.ExampleProperty} - * Example class method: {@link ExampleClass.ExampleMethod} - * Example interface: {@link ExampleInterface} - * Example interface property: - * {@link ExampleInterface.ExampleProperty} - * Example enum: {@link ExampleEnum} - * Example enum value: {@link ExampleEnum.ExampleValue} - * Example error: {@link ExampleError} - * This line has multiple links! - * {@link @minecraft/example-module} {@link ExampleFunction} - * {@link ExampleConstant} {@link ExampleObject} * * Manifest Details * \`\`\`json @@ -975,6 +966,8 @@ exports[`Type Linking > Properly generates documentation for types that are link * Example enum: {@link ExampleEnum} * Example enum value: {@link ExampleEnum.ExampleValue} * Example error: {@link ExampleError} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem4} * This line has multiple links! * {@link @minecraft/example-module} {@link ExampleFunction} * {@link ExampleConstant} {@link ExampleObject} @@ -1081,6 +1074,12 @@ exports[`Type Linking > Properly generates documentation for types that are link * Example enum value: * {@link minecraftexamplemodule.ExampleEnum.ExampleValue} * Example error: {@link minecraftexamplemodule#ExampleError} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem2} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem3} * This line has multiple links and lots of text! This is the * first link {@link minecraftexamplemodule}, and this is the * second. {@link minecraftexamplemodule#ExampleFunction} @@ -1606,6 +1605,8 @@ Example enum value: [*@minecraft/example-module.ExampleEnum.ExampleValue*](../.. Example error: [*@minecraft/example-module.ExampleError*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleerror) +Example link problem: {@link @minecraft/example-module.ExampleProblem4} + This line has multiple links! [*@minecraft/example-module*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md) [*@minecraft/example-module.ExampleFunction*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#examplefunction) [*@minecraft/example-module.ExampleConstant*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleconstant) [*@minecraft/example-module.ExampleObject*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleobject) ## [Changelog](changelog.md) @@ -1753,6 +1754,12 @@ Example enum value: [*@minecraft/example-module.ExampleEnum.ExampleValue*](../.. Example error: [*@minecraft/example-module.ExampleError*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleerror) +Example link problem: {@link @minecraft/example-module.ExampleProblem} + +Example link problem: {@link @minecraft/example-module.ExampleProblem2} + +Example link problem: {@link @minecraft/example-module.ExampleProblem3} + This line has multiple links and lots of text! This is the first link [*@minecraft/example-module*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md), and this is the second. [*@minecraft/example-module.ExampleFunction*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#examplefunction) Here's a third link [*@minecraft/example-module.ExampleConstant*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleconstant) and this one here is the final link [*@minecraft/example-module.ExampleObject*](../../../scriptapi/minecraft/example-module/minecraft-example-module.md#exampleobject) ## [Changelog](changelog.md) @@ -2390,23 +2397,6 @@ exports[`Type Linking > Properly generates documentation for types that are link ***************************************************************************** */ /** * @packageDocumentation - * This is a description with a ton of links: - * Example module: {@link @minecraft/example-module} - * Example module function: {@link ExampleFunction} - * Example module constant: {@link ExampleConstant} - * Example module object: {@link ExampleObject} - * Example class: {@link ExampleClass} - * Example class property: {@link ExampleClass.ExampleProperty} - * Example class method: {@link ExampleClass.ExampleMethod} - * Example interface: {@link ExampleInterface} - * Example interface property: - * {@link ExampleInterface.ExampleProperty} - * Example enum: {@link ExampleEnum} - * Example enum value: {@link ExampleEnum.ExampleValue} - * Example error: {@link ExampleError} - * This line has multiple links! - * {@link @minecraft/example-module} {@link ExampleFunction} - * {@link ExampleConstant} {@link ExampleObject} * * Manifest Details * \`\`\`json @@ -2502,6 +2492,8 @@ exports[`Type Linking > Properly generates documentation for types that are link * Example enum: {@link ExampleEnum} * Example enum value: {@link ExampleEnum.ExampleValue} * Example error: {@link ExampleError} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem4} * This line has multiple links! * {@link @minecraft/example-module} {@link ExampleFunction} * {@link ExampleConstant} {@link ExampleObject} @@ -2608,6 +2600,12 @@ exports[`Type Linking > Properly generates documentation for types that are link * Example enum value: * {@link minecraftexamplemodule.ExampleEnum.ExampleValue} * Example error: {@link minecraftexamplemodule#ExampleError} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem2} + * Example link problem: + * {@link @minecraft/example-module.ExampleProblem3} * This line has multiple links and lots of text! This is the * first link {@link minecraftexamplemodule}, and this is the * second. {@link minecraftexamplemodule#ExampleFunction} diff --git a/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module-2/info.json b/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module-2/info.json index 91667f4..5c59fdb 100644 --- a/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module-2/info.json +++ b/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module-2/info.json @@ -13,6 +13,9 @@ "Example enum: {@link @minecraft/example-module.ExampleEnum}", "Example enum value: {@link @minecraft/example-module.ExampleEnum.ExampleValue}", "Example error: {@link @minecraft/example-module.ExampleError}", + "Example link problem: {@link @minecraft/example-module.ExampleProblem}", + "Example link problem: {@link @minecraft/example-module.ExampleProblem2}", + "Example link problem: {@link @minecraft/example-module.ExampleProblem3}", "This line has multiple links and lots of text! This is the first link {@link @minecraft/example-module}, and this is the second. {@link @minecraft/example-module.ExampleFunction} Here's a third link {@link @minecraft/example-module.ExampleConstant} and this one here is the final link {@link @minecraft/example-module.ExampleObject}" ] } \ No newline at end of file diff --git a/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module/info.json b/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module/info.json index 735473e..2c0b33d 100644 --- a/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module/info.json +++ b/tools/api-docs-generator-test-snapshots/test/type_linking/docs/@minecraft/example-module/info.json @@ -1,4 +1,5 @@ { + "default": { "description": [ "This is a description with a ton of links:", "Example module: {@link @minecraft/example-module}", @@ -13,6 +14,27 @@ "Example enum: {@link @minecraft/example-module.ExampleEnum}", "Example enum value: {@link @minecraft/example-module.ExampleEnum.ExampleValue}", "Example error: {@link @minecraft/example-module.ExampleError}", + "Example link problem: {@link @minecraft/example-module.ExampleProblem4}", "This line has multiple links! {@link @minecraft/example-module} {@link @minecraft/example-module.ExampleFunction} {@link @minecraft/example-module.ExampleConstant} {@link @minecraft/example-module.ExampleObject}" ] +}, +"2": { + "description": [ + "This is a description with a ton of links:", + "Example module: {@link @minecraft/example-module}", + "Example module function: {@link @minecraft/example-module.ExampleFunction}", + "Example module constant: {@link @minecraft/example-module.ExampleConstant}", + "Example module object: {@link @minecraft/example-module.ExampleObject}", + "Example class: {@link @minecraft/example-module.ExampleClass}", + "Example class property: {@link @minecraft/example-module.ExampleClass.ExampleProperty}", + "Example class method: {@link @minecraft/example-module.ExampleClass.ExampleMethod}", + "Example interface: {@link @minecraft/example-module.ExampleInterface}", + "Example interface property: {@link @minecraft/example-module.ExampleInterface.ExampleProperty}", + "Example enum: {@link @minecraft/example-module.ExampleEnum}", + "Example enum value: {@link @minecraft/example-module.ExampleEnum.ExampleValue}", + "Example error: {@link @minecraft/example-module.ExampleError}", + "Example link problem: {@link @minecraft/example-module.ExampleProblem5}", + "This line has multiple links! {@link @minecraft/example-module} {@link @minecraft/example-module.ExampleFunction} {@link @minecraft/example-module.ExampleConstant} {@link @minecraft/example-module.ExampleObject}" + ] +} } \ No newline at end of file diff --git a/tools/api-docs-generator-test-snapshots/test/type_linking/typeLinking.spec.ts b/tools/api-docs-generator-test-snapshots/test/type_linking/typeLinking.spec.ts index e15a894..15d778f 100644 --- a/tools/api-docs-generator-test-snapshots/test/type_linking/typeLinking.spec.ts +++ b/tools/api-docs-generator-test-snapshots/test/type_linking/typeLinking.spec.ts @@ -10,6 +10,13 @@ describe('Type Linking', () => { runGeneratorForTest({ testDir: __dirname, generators: ['ts', 'msdocs'], + expectedLoggedErrorMessages: [ + '[ERROR] Link(s) not found in @minecraft/example-module-2 version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem}","@minecraft/example-module.ExampleProblem"]]', + '[ERROR] Link(s) not found in @minecraft/example-module-2 version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem2}","@minecraft/example-module.ExampleProblem2"]]', + '[ERROR] Link(s) not found in @minecraft/example-module-2 version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem3}","@minecraft/example-module.ExampleProblem3"]]', + '[ERROR] Link(s) not found in @minecraft/example-module version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem4}","@minecraft/example-module.ExampleProblem4"]]', + '[ERROR] Link(s) not found in @minecraft/example-module version 1.1.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem4}","@minecraft/example-module.ExampleProblem4"]]', + ], }); }); @@ -19,6 +26,13 @@ describe('Type Linking', () => { generators: ['ts', 'msdocs'], additionalArgs: '--include-base', outDir: join(__dirname, 'include_base_output'), + expectedLoggedErrorMessages: [ + '[ERROR] Link(s) not found in @minecraft/example-module-2 version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem}","@minecraft/example-module.ExampleProblem"]]', + '[ERROR] Link(s) not found in @minecraft/example-module-2 version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem2}","@minecraft/example-module.ExampleProblem2"]]', + '[ERROR] Link(s) not found in @minecraft/example-module-2 version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem3}","@minecraft/example-module.ExampleProblem3"]]', + '[ERROR] Link(s) not found in @minecraft/example-module version 1.0.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem4}","@minecraft/example-module.ExampleProblem4"]]', + '[ERROR] Link(s) not found in @minecraft/example-module version 1.1.0. Please check spelling or if the modules or members are defined: [["{@link @minecraft/example-module.ExampleProblem4}","@minecraft/example-module.ExampleProblem4"]]', + ], }); }); }); diff --git a/tools/api-docs-generator/src/filters/CommonFilters.ts b/tools/api-docs-generator/src/filters/CommonFilters.ts index bba951a..150bd1f 100644 --- a/tools/api-docs-generator/src/filters/CommonFilters.ts +++ b/tools/api-docs-generator/src/filters/CommonFilters.ts @@ -8,7 +8,7 @@ import wrap from 'word-wrap'; import { FileLoader } from '../FileLoader'; import * as log from '../Logger'; -import { getLatestScriptModules, MinecraftRelease } from '../MinecraftRelease'; +import { getLatestScriptModules, GetLatestScriptModulesOptions, MinecraftRelease } from '../MinecraftRelease'; import { getAfterEventsOrderingModuleFrom, MinecraftAfterEventsOrderByVersion, @@ -310,6 +310,13 @@ function linkSymbols( } result.push(str); + + const hasLinksRemaining = str.includes('@link'); + if (hasLinksRemaining && linkMatches.length > 0) { + log.error( + `Link(s) not found in ${fromModule.name} version ${fromModule.version}. Please check spelling or if the modules or members are defined: ${JSON.stringify(linkMatches)}` + ); + } } return result; @@ -1051,7 +1058,9 @@ function addDescriptionsAndExamples(releases: MinecraftRelease[], fileLoader?: F } for (const release of releases) { - for (const moduleJson of release.script_modules) { + for (const moduleJson of release.getLatestScriptModulesByMajorVersion( + GetLatestScriptModulesOptions.StableAndPrerelease + )) { const dependentModules = getLatestDependentScriptModules(release.script_modules, moduleJson); addModuleDescriptions(fileLoader, moduleJson, dependentModules);