diff --git a/scripts/apidoc/typedoc.ts b/scripts/apidoc/typedoc.ts index 12b474b0435..a795efa27c2 100644 --- a/scripts/apidoc/typedoc.ts +++ b/scripts/apidoc/typedoc.ts @@ -219,7 +219,40 @@ export function extractTagContent( reflection?: CommentHolder, tagProcessor: (tag: CommentTag) => string[] = joinTagContent ): string[] { - return reflection?.comment?.getTags(tag).flatMap(tagProcessor) ?? []; + const tags = + reflection?.comment + ?.getTags(tag) + .flatMap(tagProcessor) + .map((tag) => tag.trim()) ?? []; + if (tags.some((tag) => tag.length === 0)) { + throw new Error(`Expected non-empty ${tag} tag.`); + } + + return tags; +} + +/** + * Extracts the text (md) from a single jsdoc tag. + * + * @param tag The tag to extract the text from. + * @param reflection The reflection to extract the text from. + * @param tagProcessor The function used to extract the text from the tag. + * + * @throws If there are multiple tags of that type. + */ +function extractSingleTagContent( + tag: `@${string}`, + reflection?: CommentHolder, + tagProcessor: (tag: CommentTag) => string[] = joinTagContent +): string | undefined { + const tags = extractTagContent(tag, reflection, tagProcessor); + if (tags.length === 0) { + return undefined; + } else if (tags.length === 1) { + return tags[0]; + } + + throw new Error(`Expected 1 ${tag} tag, but got ${tags.length}.`); } /** @@ -358,8 +391,7 @@ export function joinTagParts(parts?: CommentDisplayPart[]): string | undefined { export function extractDeprecated( reflection?: CommentHolder ): string | undefined { - const deprecated = extractTagContent('@deprecated', reflection).join().trim(); - return deprecated.length === 0 ? undefined : deprecated; + return extractSingleTagContent('@deprecated', reflection); } /** @@ -370,8 +402,8 @@ export function extractDeprecated( * @returns The message explaining the conditions when this method throws. Or `undefined` if it does not throw. */ export function extractThrows(reflection?: CommentHolder): string | undefined { - const throws = extractTagContent('@throws', reflection).join().trim(); - return throws.length === 0 ? undefined : throws; + const content = extractTagContent('@throws', reflection).join('\n'); + return content.length === 0 ? undefined : content; } /** @@ -382,5 +414,5 @@ export function extractThrows(reflection?: CommentHolder): string | undefined { * @returns The contents of the `@since` tag. */ export function extractSince(reflection: CommentHolder): string { - return extractTagContent('@since', reflection).join().trim(); + return extractSingleTagContent('@since', reflection) || MISSING_DESCRIPTION; } diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 26de107dc2e..6e993c8412c 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -417,8 +417,8 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @param pattern The template string/RegExp to generate a matching string for. * - * @throws If min value is more than max value in quantifier. e.g. `#{10,5}` - * @throws If invalid quantifier symbol is passed in. + * @throws If min value is more than max value in quantifier, e.g. `#{10,5}`. + * @throws If an invalid quantifier symbol is passed in. * * @example * faker.helpers.fromRegExp('#{5}') // '#####' diff --git a/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap b/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap index 12e7df29bb5..84365003a9d 100644 --- a/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap +++ b/test/scripts/apidoc/__snapshots__/signature.spec.ts.snap @@ -42,8 +42,8 @@ exports[`signature > analyzeSignature() > complexArrayParameter 1`] = ` ], "returns": "T", "seeAlsos": [], - "since": "", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L367", + "since": "Missing", + "sourcePath": "test/scripts/apidoc/signature.example.ts#L377", "throws": undefined, } `; @@ -67,7 +67,7 @@ exports[`signature > analyzeSignature() > defaultBooleanParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L105", "throws": undefined, } @@ -84,6 +84,7 @@ exports[`signature > analyzeSignature() > expected and actual methods are equal "methodWithExample", "methodWithMultipleSeeMarkers", "methodWithMultipleSeeMarkersAndBackticks", + "methodWithMultipleThrows", "methodWithSinceMarker", "methodWithThrows", "multiParamMethod", @@ -118,7 +119,7 @@ exports[`signature > analyzeSignature() > functionParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L125", "throws": undefined, } @@ -178,7 +179,7 @@ exports[`signature > analyzeSignature() > literalUnionParamMethod 1`] = ` ], "returns": "string", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L159", "throws": undefined, } @@ -198,7 +199,7 @@ exports[`signature > analyzeSignature() > methodWithDeprecated 1`] = ` "seeAlsos": [ "test.apidoc.methodWithExample()", ], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L287", "throws": undefined, } @@ -250,8 +251,8 @@ exports[`signature > analyzeSignature() > methodWithDeprecatedOption 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L308", + "since": "Missing", + "sourcePath": "test/scripts/apidoc/signature.example.ts#L318", "throws": undefined, } `; @@ -268,7 +269,7 @@ exports[`signature > analyzeSignature() > methodWithExample 1`] = ` "parameters": [], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L276", "throws": undefined, } @@ -288,8 +289,8 @@ exports[`signature > analyzeSignature() > methodWithMultipleSeeMarkers 1`] = ` "test.apidoc.methodWithExample()", "test.apidoc.methodWithDeprecated()", ], - "since": "", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L335", + "since": "Missing", + "sourcePath": "test/scripts/apidoc/signature.example.ts#L345", "throws": undefined, } `; @@ -308,12 +309,30 @@ exports[`signature > analyzeSignature() > methodWithMultipleSeeMarkersAndBacktic "test.apidoc.methodWithExample() with parameter foo.", "test.apidoc.methodWithDeprecated() with parameter bar and baz.", ], - "since": "", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L345", + "since": "Missing", + "sourcePath": "test/scripts/apidoc/signature.example.ts#L355", "throws": undefined, } `; +exports[`signature > analyzeSignature() > methodWithMultipleThrows 1`] = ` +{ + "deprecated": undefined, + "description": "

Test with multiple throws.

+", + "examples": "
ts
methodWithMultipleThrows(): number
+
", + "name": "methodWithMultipleThrows", + "parameters": [], + "returns": "number", + "seeAlsos": [], + "since": "Missing", + "sourcePath": "test/scripts/apidoc/signature.example.ts#L306", + "throws": "First error case. +Another error case.", +} +`; + exports[`signature > analyzeSignature() > methodWithSinceMarker 1`] = ` { "deprecated": undefined, @@ -326,7 +345,7 @@ exports[`signature > analyzeSignature() > methodWithSinceMarker 1`] = ` "returns": "number", "seeAlsos": [], "since": "1.0.0", - "sourcePath": "test/scripts/apidoc/signature.example.ts#L354", + "sourcePath": "test/scripts/apidoc/signature.example.ts#L364", "throws": undefined, } `; @@ -334,7 +353,7 @@ exports[`signature > analyzeSignature() > methodWithSinceMarker 1`] = ` exports[`signature > analyzeSignature() > methodWithThrows 1`] = ` { "deprecated": undefined, - "description": "

Test with throws

+ "description": "

Test with throws.

", "examples": "
ts
methodWithThrows(): number
", @@ -342,9 +361,9 @@ exports[`signature > analyzeSignature() > methodWithThrows 1`] = ` "parameters": [], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L296", - "throws": "a Faker error", + "throws": "Everytime.", } `; @@ -381,7 +400,7 @@ exports[`signature > analyzeSignature() > multiParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L116", "throws": undefined, } @@ -398,7 +417,7 @@ exports[`signature > analyzeSignature() > noParamMethod 1`] = ` "parameters": [], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L78", "throws": undefined, } @@ -423,7 +442,7 @@ exports[`signature > analyzeSignature() > optionalStringParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L96", "throws": undefined, } @@ -491,7 +510,7 @@ It also has a more complex description.

], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L226", "throws": undefined, } @@ -530,7 +549,7 @@ exports[`signature > analyzeSignature() > optionsInterfaceParamMethodWithDefault ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L262", "throws": undefined, } @@ -596,7 +615,7 @@ exports[`signature > analyzeSignature() > optionsParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L196", "throws": undefined, } @@ -635,7 +654,7 @@ exports[`signature > analyzeSignature() > optionsTypeParamMethodWithDefaults 1`] ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L244", "throws": undefined, } @@ -660,7 +679,7 @@ exports[`signature > analyzeSignature() > recordParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L182", "throws": undefined, } @@ -685,7 +704,7 @@ exports[`signature > analyzeSignature() > requiredNumberParamMethod 1`] = ` ], "returns": "number", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L87", "throws": undefined, } @@ -742,7 +761,7 @@ exports[`signature > analyzeSignature() > stringUnionParamMethod 1`] = ` ], "returns": "string", "seeAlsos": [], - "since": "", + "since": "Missing", "sourcePath": "test/scripts/apidoc/signature.example.ts#L138", "throws": undefined, } diff --git a/test/scripts/apidoc/signature.example.ts b/test/scripts/apidoc/signature.example.ts index 724f687d3a6..2f62057bc01 100644 --- a/test/scripts/apidoc/signature.example.ts +++ b/test/scripts/apidoc/signature.example.ts @@ -289,14 +289,24 @@ export class SignatureTest { } /** - * Test with throws + * Test with throws. * - * @throws a Faker error + * @throws Everytime. */ methodWithThrows(): number { throw new FakerError('Test error'); } + /** + * Test with multiple throws. + * + * @throws First error case. + * @throws Another error case. + */ + methodWithMultipleThrows(): number { + throw new FakerError('Another test error'); + } + /** * Test with deprecated option. * diff --git a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts index efb1919bf35..76865c16e80 100644 --- a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts +++ b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts @@ -300,6 +300,7 @@ describe('verify JSDoc tags', () => { it('verify @since tag', () => { const since = extractSince(signature); expect(since, '@since to be present').toBeTruthy(); + expect(since).not.toBe(MISSING_DESCRIPTION); expect(since, '@since to be a valid semver').toSatisfy( validator.isSemVer );