diff --git a/scripts/apidoc.ts b/scripts/apidoc.ts index 921859e7a77..3e11572e1d6 100644 --- a/scripts/apidoc.ts +++ b/scripts/apidoc.ts @@ -5,8 +5,9 @@ import { } from './apidoc/apiDocsWriter'; import { processModuleMethods } from './apidoc/moduleMethods'; import { initMarkdownRenderer } from './apidoc/signature'; +import { newTypeDocApp, patchProject } from './apidoc/typedoc'; import type { PageIndex } from './apidoc/utils'; -import { newTypeDocApp, patchProject, pathOutputDir } from './apidoc/utils'; +import { pathOutputDir } from './apidoc/utils'; const pathOutputJson = resolve(pathOutputDir, 'typedoc.json'); diff --git a/scripts/apidoc/apiDocsWriter.ts b/scripts/apidoc/apiDocsWriter.ts index cd8dd2e5936..f18b7cd97e1 100644 --- a/scripts/apidoc/apiDocsWriter.ts +++ b/scripts/apidoc/apiDocsWriter.ts @@ -1,17 +1,16 @@ import { writeFileSync } from 'node:fs'; import { resolve } from 'node:path'; import type { ProjectReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; import type { Method } from '../../docs/.vitepress/components/api-docs/method'; import type { APIGroup, APIItem } from '../../docs/api/api-types'; -import { extractModuleName, selectApiModules } from './moduleMethods'; -import type { PageIndex } from './utils'; +import { formatMarkdown, formatTypescript } from './format'; import { - formatMarkdown, - formatTypescript, - pathDocsDir, - pathOutputDir, -} from './utils'; + extractModuleName, + selectApiMethods, + selectApiModules, +} from './typedoc'; +import type { PageIndex } from './utils'; +import { pathDocsDir, pathOutputDir } from './utils'; const pathDocsApiPages = resolve(pathDocsDir, '.vitepress', 'api-pages.ts'); const pathDocsApiSearchIndex = resolve( @@ -139,28 +138,11 @@ export function writeApiSearchIndex(project: ProjectReflection): void { const apiSection: APIItem = { text: moduleName, link: moduleName.toLowerCase(), - headers: [], + headers: selectApiMethods(module).map((child) => ({ + anchor: child.name, + text: child.name, + })), }; - if (module.kind !== ReflectionKind.Property) { - apiSection.headers = module - .getChildrenByKind(ReflectionKind.Method) - .map((child) => ({ - anchor: child.name, - text: child.name, - })); - } else { - // TODO @Shinigami92 2022-08-17: Extract capitalization into own function - apiSection.text = - apiSection.text.substring(0, 1).toUpperCase() + - apiSection.text.substring(1); - - apiSection.headers = [ - { - anchor: module.name, - text: module.name, - }, - ]; - } return apiSection; }) diff --git a/scripts/apidoc/format.ts b/scripts/apidoc/format.ts new file mode 100644 index 00000000000..0a502c5fc2a --- /dev/null +++ b/scripts/apidoc/format.ts @@ -0,0 +1,31 @@ +import type { Options } from 'prettier'; +import { format } from 'prettier'; +import prettierConfig from '../../.prettierrc.cjs'; + +/** + * Formats markdown contents. + * + * @param text The text to format. + */ +export function formatMarkdown(text: string): string { + return format(text, prettierMarkdown); +} + +/** + * Formats typedoc contents. + * + * @param text The text to format. + */ +export function formatTypescript(text: string): string { + return format(text, prettierTypescript); +} + +const prettierMarkdown: Options = { + ...prettierConfig, + parser: 'markdown', +}; + +const prettierTypescript: Options = { + ...prettierConfig, + parser: 'typescript', +}; diff --git a/scripts/apidoc/moduleMethods.ts b/scripts/apidoc/moduleMethods.ts index dd4f528a42b..b52d47806ec 100644 --- a/scripts/apidoc/moduleMethods.ts +++ b/scripts/apidoc/moduleMethods.ts @@ -1,25 +1,15 @@ import type { DeclarationReflection, ProjectReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import { faker } from '../../src'; import { writeApiDocsData, writeApiDocsModulePage } from './apiDocsWriter'; import { analyzeSignature, toBlock } from './signature'; +import { + extractModuleFieldName, + extractModuleName, + selectApiMethodSignatures, + selectApiModules, +} from './typedoc'; import type { PageIndex } from './utils'; -/** - * Selects the modules from the project that needs to be documented. - * - * @param project The project used to extract the modules. - * @returns The modules to document. - */ -export function selectApiModules( - project: ProjectReflection -): DeclarationReflection[] { - return project - .getChildrenByKind(ReflectionKind.Class) - .filter((module) => faker[extractModuleFieldName(module)] != null); -} - /** * Analyzes and writes the documentation for modules and their methods such as `faker.animal.cat()`. * @@ -37,24 +27,6 @@ export function processModuleMethods(project: ProjectReflection): PageIndex { return pages; } -export function extractModuleName(module: DeclarationReflection): string { - const { name } = module; - // TODO @ST-DDT 2022-10-16: Remove in v10. - // Typedoc prefers the name of the module that is exported first. - if (name === 'AddressModule') { - return 'Location'; - } else if (name === 'NameModule') { - return 'Person'; - } - - return name.replace(/Module$/, ''); -} - -function extractModuleFieldName(module: DeclarationReflection): string { - const moduleName = extractModuleName(module); - return moduleName.substring(0, 1).toLowerCase() + moduleName.substring(1); -} - /** * Analyzes and writes the documentation for a module and its methods such as `faker.animal.cat()`. * @@ -69,11 +41,10 @@ function processModuleMethod(module: DeclarationReflection): PageIndex { const methods: Method[] = []; // Generate method section - for (const method of module.getChildrenByKind(ReflectionKind.Method)) { - const methodName = method.name; + for (const [methodName, signature] of Object.entries( + selectApiMethodSignatures(module) + )) { console.debug(`- ${methodName}`); - const signatures = method.signatures; - const signature = signatures[signatures.length - 1]; methods.push(analyzeSignature(signature, moduleFieldName, methodName)); } diff --git a/scripts/apidoc/signature.ts b/scripts/apidoc/signature.ts index f2a4bd85130..d34abf188d4 100644 --- a/scripts/apidoc/signature.ts +++ b/scripts/apidoc/signature.ts @@ -18,15 +18,15 @@ import type { } from '../../docs/.vitepress/components/api-docs/method'; import vitepressConfig from '../../docs/.vitepress/config'; import { faker } from '../../src'; +import { formatTypescript } from './format'; import { extractRawExamples, extractSeeAlsos, extractSince, - formatTypescript, isDeprecated, joinTagParts, - pathOutputDir, -} from './utils'; +} from './typedoc'; +import { pathOutputDir } from './utils'; export function prettifyMethodName(method: string): string { return ( diff --git a/scripts/apidoc/typedoc.ts b/scripts/apidoc/typedoc.ts new file mode 100644 index 00000000000..d9b34a0b11e --- /dev/null +++ b/scripts/apidoc/typedoc.ts @@ -0,0 +1,210 @@ +import type { + CommentDisplayPart, + CommentTag, + DeclarationReflection, + ProjectReflection, + SignatureReflection, +} from 'typedoc'; +import { + Application, + Converter, + ReflectionKind, + TSConfigReader, +} from 'typedoc'; +import { faker } from '../../src'; +import { + DefaultParameterAwareSerializer, + parameterDefaultReader, + patchProjectParameterDefaults, +} from './parameterDefaults'; +import { mapByName } from './utils'; + +/** + * Creates and configures a new typedoc application. + */ +export function newTypeDocApp(): Application { + const app = new Application(); + + app.options.addReader(new TSConfigReader()); + // If you want TypeDoc to load typedoc.json files + //app.options.addReader(new TypeDoc.TypeDocReader()); + + // Read parameter defaults + app.converter.on(Converter.EVENT_CREATE_DECLARATION, parameterDefaultReader); + // Add to debug json output + app.serializer.addSerializer(new DefaultParameterAwareSerializer()); + + return app; +} + +/** + * Apply our patches to the generated typedoc data. + * + * This is moved to a separate method to allow printing/saving the original content before patching it. + * + * @param project The project to patch. + */ +export function patchProject(project: ProjectReflection): void { + patchProjectParameterDefaults(project); +} + +/** + * Selects the modules from the project that needs to be documented. + * + * @param project The project to extract the modules from. + * @returns The modules to document. + */ +export function selectApiModules( + project: ProjectReflection, + includeTestModules = false +): DeclarationReflection[] { + return project + .getChildrenByKind(ReflectionKind.Class) + .filter( + (module) => + faker[extractModuleFieldName(module)] != null || includeTestModules + ); +} + +/** + * Selects the methods from the module that needs to be documented. + * + * @param module The module to extract the methods from. + * @returns The methods to document. + */ +export function selectApiMethods( + module: DeclarationReflection +): DeclarationReflection[] { + return module.getChildrenByKind(ReflectionKind.Method); +} + +/** + * Selects the signature from the method that needs to be documented. + * + * @param method The method to extract the signature from. + * @returns The signature to document. + */ +export function selectApiSignature( + method: DeclarationReflection +): SignatureReflection { + const signatures = method.signatures; + if (signatures == null || signatures.length === 0) { + throw new Error(`Method ${method.name} has no signature.`); + } + + return signatures[signatures.length - 1]; +} + +/** + * Selects the method signatures from the module that needs to be documented. + * Method-Name -> Method-Signature + * + * @param method The module to extract the method signatures from. + * @returns The method signatures to document. + */ +export function selectApiMethodSignatures( + module: DeclarationReflection +): Record { + return mapByName(selectApiMethods(module), selectApiSignature); +} + +export function extractModuleName(module: DeclarationReflection): string { + const { name } = module; + // TODO @ST-DDT 2022-10-16: Remove in v10. + // Typedoc prefers the name of the module that is exported first. + if (name === 'AddressModule') { + return 'Location'; + } else if (name === 'NameModule') { + return 'Person'; + } + + return name.replace(/Module$/, ''); +} + +export function extractModuleFieldName(module: DeclarationReflection): string { + const moduleName = extractModuleName(module); + return moduleName.substring(0, 1).toLowerCase() + moduleName.substring(1); +} + +/** + * Extracts the text (md) from a jsdoc tag. + * + * @param tag The tag to extract the text from. + * @param signature The signature to extract the text from. + */ +export function extractTagContent( + tag: `@${string}`, + signature?: SignatureReflection, + tagProcessor: (tag: CommentTag) => string[] = joinTagContent +): string[] { + return signature?.comment?.getTags(tag).flatMap(tagProcessor) ?? []; +} + +/** + * Extracts the examples from the jsdocs without the surrounding md code block. + * + * @param signature The signature to extract the examples from. + */ +export function extractRawExamples(signature?: SignatureReflection): string[] { + return extractTagContent('@example', signature).map((tag) => + tag.replace(/^```ts\n/, '').replace(/\n```$/, '') + ); +} + +/** + * Extracts all the `@see` references from the jsdocs separately. + * + * @param signature The signature to extract the see also references from. + */ +export function extractSeeAlsos(signature?: SignatureReflection): string[] { + return extractTagContent('@see', signature, (tag) => + // If the @see tag contains code in backticks, the content is split into multiple parts. + // So we join together, split on newlines and filter out empty tags. + joinTagParts(tag.content) + .split('\n') + .map((link) => { + link = link.trim(); + if (link.startsWith('-')) { + link = link.slice(1).trim(); + } + + return link; + }) + .filter((link) => link) + ); +} + +/** + * Joins the parts of the given jsdocs tag. + */ +export function joinTagContent(tag: CommentTag): string[] { + return [joinTagParts(tag?.content)]; +} + +export function joinTagParts(parts: CommentDisplayPart[]): string; +export function joinTagParts(parts?: CommentDisplayPart[]): string | undefined; +export function joinTagParts(parts?: CommentDisplayPart[]): string | undefined { + return parts?.map((part) => part.text).join(''); +} + +/** + * Checks if the given signature is deprecated. + * + * @param signature The signature to check. + * + * @returns `true` if it is deprecated, otherwise `false`. + */ +export function isDeprecated(signature: SignatureReflection): boolean { + return extractTagContent('@deprecated', signature).length > 0; +} + +/** + * Extracts the "since" tag from the provided signature. + * + * @param signature The signature to check. + * + * @returns the contents of the @since tag + */ +export function extractSince(signature: SignatureReflection): string { + return extractTagContent('@since', signature).join().trim(); +} diff --git a/scripts/apidoc/utils.ts b/scripts/apidoc/utils.ts index 9dad1b1457a..7939adb1106 100644 --- a/scripts/apidoc/utils.ts +++ b/scripts/apidoc/utils.ts @@ -1,165 +1,24 @@ import { resolve } from 'node:path'; -import type { Options } from 'prettier'; -import { format } from 'prettier'; -import type { - CommentDisplayPart, - CommentTag, - SignatureReflection, -} from 'typedoc'; -import * as TypeDoc from 'typedoc'; -import prettierConfig from '../../.prettierrc.cjs'; -import { - DefaultParameterAwareSerializer, - parameterDefaultReader, - patchProjectParameterDefaults, -} from './parameterDefaults'; + +// Types export type Page = { text: string; link: string }; export type PageIndex = Array; +// Paths + const pathRoot = resolve(__dirname, '..', '..'); export const pathDocsDir = resolve(pathRoot, 'docs'); export const pathOutputDir = resolve(pathDocsDir, 'api'); -/** - * Creates and configures a new typedoc application. - */ -export function newTypeDocApp(): TypeDoc.Application { - const app = new TypeDoc.Application(); +// Functions - app.options.addReader(new TypeDoc.TSConfigReader()); - // If you want TypeDoc to load typedoc.json files - //app.options.addReader(new TypeDoc.TypeDocReader()); - - // Read parameter defaults - app.converter.on( - TypeDoc.Converter.EVENT_CREATE_DECLARATION, - parameterDefaultReader +export function mapByName( + input: Array, + valueExtractor: (item: T) => V +): Record { + return input.reduce( + (acc, item) => ({ ...acc, [item.name]: valueExtractor(item) }), + {} ); - // Add to debug json output - app.serializer.addSerializer(new DefaultParameterAwareSerializer()); - - return app; -} - -/** - * Apply our patches to the generated typedoc data. - * - * This is moved to a separate method to allow printing/saving the original content before patching it. - * - * @param project The project to patch. - */ -export function patchProject(project: TypeDoc.ProjectReflection): void { - patchProjectParameterDefaults(project); -} - -/** - * Formats markdown contents. - * - * @param text The text to format. - */ -export function formatMarkdown(text: string): string { - return format(text, prettierMarkdown); -} - -/** - * Formats typedoc contents. - * - * @param text The text to format. - */ -export function formatTypescript(text: string): string { - return format(text, prettierTypescript); -} - -const prettierMarkdown: Options = { - ...prettierConfig, - parser: 'markdown', -}; - -const prettierTypescript: Options = { - ...prettierConfig, - parser: 'typescript', -}; - -/** - * Extracts the text (md) from a jsdoc tag. - * - * @param tag The tag to extract the text from. - * @param signature The signature to extract the text from. - */ -export function extractTagContent( - tag: `@${string}`, - signature?: SignatureReflection, - tagProcessor: (tag: CommentTag) => string[] = joinTagContent -): string[] { - return signature?.comment?.getTags(tag).flatMap(tagProcessor) ?? []; -} - -/** - * Extracts the examples from the jsdocs without the surrounding md code block. - * - * @param signature The signature to extract the examples from. - */ -export function extractRawExamples(signature?: SignatureReflection): string[] { - return extractTagContent('@example', signature).map((tag) => - tag.replace(/^```ts\n/, '').replace(/\n```$/, '') - ); -} - -/** - * Extracts all the `@see` references from the jsdocs separately. - * - * @param signature The signature to extract the see also references from. - */ -export function extractSeeAlsos(signature?: SignatureReflection): string[] { - return extractTagContent('@see', signature, (tag) => - // If the @see tag contains code in backticks, the content is split into multiple parts. - // So we join together, split on newlines and filter out empty tags. - joinTagParts(tag.content) - .split('\n') - .map((link) => { - link = link.trim(); - if (link.startsWith('-')) { - link = link.slice(1).trim(); - } - - return link; - }) - .filter((link) => link) - ); -} - -/** - * Joins the parts of the given jsdocs tag. - */ -export function joinTagContent(tag: CommentTag): string[] { - return [joinTagParts(tag?.content)]; -} - -export function joinTagParts(parts: CommentDisplayPart[]): string; -export function joinTagParts(parts?: CommentDisplayPart[]): string | undefined; -export function joinTagParts(parts?: CommentDisplayPart[]): string | undefined { - return parts?.map((part) => part.text).join(''); -} - -/** - * Checks if the given signature is deprecated. - * - * @param signature The signature to check. - * - * @returns `true` if it is deprecated, otherwise `false`. - */ -export function isDeprecated(signature: SignatureReflection): boolean { - return extractTagContent('@deprecated', signature).length > 0; -} - -/** - * Extracts the "since" tag from the provided signature. - * - * @param signature The signature to check. - * - * @returns the contents of the @since tag - */ -export function extractSince(signature: SignatureReflection): string { - return extractTagContent('@since', signature).join().trim(); } diff --git a/test/scripts/apidoc/examplesAndDeprecations.spec.ts b/test/scripts/apidoc/examplesAndDeprecations.spec.ts index df1769b4364..ac73244c1ac 100644 --- a/test/scripts/apidoc/examplesAndDeprecations.spec.ts +++ b/test/scripts/apidoc/examplesAndDeprecations.spec.ts @@ -1,7 +1,5 @@ import { mkdirSync, writeFileSync } from 'node:fs'; import { resolve } from 'node:path'; -import type { DeclarationReflection, SignatureReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; import type { SpyInstance } from 'vitest'; import { afterAll, @@ -12,7 +10,6 @@ import { it, vi, } from 'vitest'; -import { selectApiModules } from '../../../scripts/apidoc/moduleMethods'; import { analyzeSignature, initMarkdownRenderer, @@ -23,9 +20,9 @@ import { extractSince, extractTagContent, isDeprecated, -} from '../../../scripts/apidoc/utils'; +} from '../../../scripts/apidoc/typedoc'; import { faker } from '../../../src'; -import { loadProject } from './utils'; +import { loadProjectModules } from './utils'; /* * This test ensures, that every method @@ -42,17 +39,7 @@ const locales: Record = { beforeAll(initMarkdownRenderer); describe('examples and deprecations', () => { - const project = loadProject(); - - const modules: Record = selectApiModules( - project - ).reduce( - (a, v) => ({ - ...a, - [v.name]: v.getChildrenByKind(ReflectionKind.Method), - }), - {} - ); + const modules = loadProjectModules(); const consoleSpies: Array = Object.keys(console) .filter((key) => typeof console[key] === 'function') @@ -65,12 +52,7 @@ describe('examples and deprecations', () => { } }); - describe.each(Object.entries(modules))('%s', (moduleName, methods) => { - const methodsByName: Record = methods.reduce( - (a, v) => ({ ...a, [v.name]: v }), - {} - ); - + describe.each(Object.entries(modules))('%s', (moduleName, methodsByName) => { beforeEach(() => { faker.locale = 'en'; for (const spy of consoleSpies) { @@ -79,70 +61,74 @@ describe('examples and deprecations', () => { }); // eslint-disable-next-line @typescript-eslint/no-misused-promises - it.each(Object.entries(methodsByName))('%s', async (methodName, method) => { - const signatures: SignatureReflection[] = - method.signatures || method.type?.['declaration'].signatures; - const signature = signatures[signatures.length - 1]; - - // Extract examples and make them runnable - let examples = extractRawExamples(signature).join('').trim() ?? ''; - examples = examples.replace( - /faker([A-Z]{2})\./g, - (_, locale: string) => `faker.locale = '${locales[locale]}';\nfaker.` - ); - - expect(examples, `${moduleName}.${methodName} to have examples`).not.toBe( - '' - ); - - // Save examples to a file to run it - const dir = resolve(__dirname, 'temp', moduleName); - mkdirSync(dir, { recursive: true }); - const path = resolve(dir, `${methodName}.ts`); - writeFileSync( - path, - `import { faker } from '../../../../../src';\n${examples}` - ); - - // Run the examples - await import(path); + it.each(Object.entries(methodsByName))( + '%s', + async (methodName, signature) => { + // Extract examples and make them runnable + let examples = extractRawExamples(signature).join('').trim(); + examples = examples.replace( + /faker([A-Z]{2})\./g, + (_, locale: string) => `faker.locale = '${locales[locale]}';\nfaker.` + ); - // Verify logging - const deprecatedFlag = isDeprecated(signature); - if (deprecatedFlag) { - expect(consoleSpies[1]).toHaveBeenCalled(); expect( - extractTagContent('@deprecated', signature).join(''), - '@deprecated tag without message' + examples, + `${moduleName}.${methodName} to have examples` ).not.toBe(''); - } else { - for (const spy of consoleSpies) { - expect(spy).not.toHaveBeenCalled(); - } - } - // Verify @param tags - analyzeSignature(signature, moduleName, methodName).parameters.forEach( - (param) => { - const { name, description } = param; - const plainDescription = description.replace(/<[^>]+>/g, '').trim(); + // Save examples to a file to run it + const dir = resolve(__dirname, 'temp', moduleName); + mkdirSync(dir, { recursive: true }); + const path = resolve(dir, `${methodName}.ts`); + writeFileSync( + path, + `import { faker } from '../../../../../src';\n${examples}` + ); + + // Run the examples + await import(path); + + // Verify logging + const deprecatedFlag = isDeprecated(signature); + if (deprecatedFlag) { + expect(consoleSpies[1]).toHaveBeenCalled(); expect( - plainDescription, - `Expect param ${name} to have a description` - ).not.toBe('Missing'); - } - ); - - // Verify @see tag - extractSeeAlsos(signature).forEach((link) => { - if (link.startsWith('faker.')) { - // Expected @see faker.xxx.yyy() - expect(link, 'Expect method reference to contain ()').toContain('('); - expect(link, 'Expect method reference to contain ()').toContain(')'); + extractTagContent('@deprecated', signature).join(''), + '@deprecated tag without message' + ).not.toBe(''); + } else { + for (const spy of consoleSpies) { + expect(spy).not.toHaveBeenCalled(); + } } - }); - expect(extractSince(signature), '@since to be present').toBeTruthy(); - }); + // Verify @param tags + analyzeSignature(signature, moduleName, methodName).parameters.forEach( + (param) => { + const { name, description } = param; + const plainDescription = description.replace(/<[^>]+>/g, '').trim(); + expect( + plainDescription, + `Expect param ${name} to have a description` + ).not.toBe('Missing'); + } + ); + + // Verify @see tag + extractSeeAlsos(signature).forEach((link) => { + if (link.startsWith('faker.')) { + // Expected @see faker.xxx.yyy() + expect(link, 'Expect method reference to contain ()').toContain( + '(' + ); + expect(link, 'Expect method reference to contain ()').toContain( + ')' + ); + } + }); + + expect(extractSince(signature), '@since to be present').toBeTruthy(); + } + ); }); }); diff --git a/test/scripts/apidoc/signature.debug.ts b/test/scripts/apidoc/signature.debug.ts index f805ca547e3..6be0e49fd0c 100644 --- a/test/scripts/apidoc/signature.debug.ts +++ b/test/scripts/apidoc/signature.debug.ts @@ -16,7 +16,7 @@ initMarkdownRenderer() .then(() => { Object.entries(methods).forEach(([name, method]) => { console.log('Analyzing: ', name); - const result = analyzeSignature(method.signatures[0], null, method.name); + const result = analyzeSignature(method, null, method.name); console.log('Result: ', result); }); }) diff --git a/test/scripts/apidoc/signature.spec.ts b/test/scripts/apidoc/signature.spec.ts index 43ab00e7b27..d90370a27c2 100644 --- a/test/scripts/apidoc/signature.spec.ts +++ b/test/scripts/apidoc/signature.spec.ts @@ -19,13 +19,11 @@ describe('signature', () => { }); it('expected and actual methods are equal', () => { - expect(Object.keys(methods).sort()).toMatchSnapshot(); + expect(Object.keys(methods)).toMatchSnapshot(); }); - it.each(Object.keys(methods).sort())('%s', (name) => { - const method = methods[name]; - expect(method, `Method ${name} to be defined`).toBeDefined(); - const actual = analyzeSignature(method.signatures[0], null, method.name); + it.each(Object.entries(methods))('%s', (name, signature) => { + const actual = analyzeSignature(signature, null, name); expect(actual).toMatchSnapshot(); }); diff --git a/test/scripts/apidoc/utils.ts b/test/scripts/apidoc/utils.ts index 19c4b4eabf6..61f3b848d32 100644 --- a/test/scripts/apidoc/utils.ts +++ b/test/scripts/apidoc/utils.ts @@ -1,43 +1,47 @@ -import type { DeclarationReflection, ProjectReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; -import { newTypeDocApp, patchProject } from '../../../scripts/apidoc/utils'; +import type { SignatureReflection, TypeDocOptions } from 'typedoc'; +import { + newTypeDocApp, + patchProject, + selectApiMethodSignatures, + selectApiModules, +} from '../../../scripts/apidoc/typedoc'; +import { mapByName } from '../../../scripts/apidoc/utils'; /** - * Loads the example methods using TypeDoc. + * Returns a record with the (Module-Name -> (Method-Name -> Method-Signature)) for the project. */ -export function loadExampleMethods(): Record { +export function loadProjectModules( + options: Partial = { + entryPoints: ['src/index.ts'], + }, + includeTestModules = false +): Record> { const app = newTypeDocApp(); - app.bootstrap({ - entryPoints: ['test/scripts/apidoc/signature.example.ts'], - tsconfig: 'test/scripts/apidoc/tsconfig.json', - }); + app.bootstrap(options); const project = app.convert(); + if (project == null) { + throw new Error('Failed to convert project'); + } + patchProject(project); - const methods: Record = project - .getChildrenByKind(ReflectionKind.Class)[0] - .getChildrenByKind(ReflectionKind.Method) - .reduce((a, v) => ({ ...a, [v.name]: v }), {}); + const modules = selectApiModules(project, includeTestModules); - return methods; + return mapByName(modules, selectApiMethodSignatures); } /** - * Loads the project using TypeDoc. + * Loads the example methods using TypeDoc. */ -export function loadProject(): ProjectReflection { - const app = newTypeDocApp(); - - app.bootstrap({ - entryPoints: ['src/index.ts'], - }); - - const project = app.convert(); - - patchProject(project); - - return project; +export function loadExampleMethods(): Record { + return loadProjectModules( + { + entryPoints: ['test/scripts/apidoc/signature.example.ts'], + tsconfig: 'test/scripts/apidoc/tsconfig.json', + }, + true + )['SignatureTest']; }