From edc50b69197260f9d3e8ac22f2bf062c9a71c390 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Mon, 3 Apr 2023 17:39:43 +0200 Subject: docs: Faker and utility pages (#1940) --- scripts/apidoc.ts | 2 - scripts/apidoc/apiDocsWriter.ts | 109 +++++++++++++++++++++++++-------------- scripts/apidoc/fakerClass.ts | 48 +++++++++++++++++ scripts/apidoc/fakerUtilities.ts | 32 ++++++++++++ scripts/apidoc/generate.ts | 16 ++++-- scripts/apidoc/moduleMethods.ts | 92 ++++++++++++++++----------------- scripts/apidoc/signature.ts | 34 +----------- scripts/apidoc/utils.ts | 5 +- 8 files changed, 212 insertions(+), 126 deletions(-) create mode 100644 scripts/apidoc/fakerClass.ts create mode 100644 scripts/apidoc/fakerUtilities.ts (limited to 'scripts') diff --git a/scripts/apidoc.ts b/scripts/apidoc.ts index 3c448f8b..ecb1f8fe 100644 --- a/scripts/apidoc.ts +++ b/scripts/apidoc.ts @@ -1,10 +1,8 @@ -import { faker } from '../src'; import { generate } from './apidoc/generate'; import { initMarkdownRenderer } from './apidoc/signature'; async function build(): Promise { await initMarkdownRenderer(); - faker.setDefaultRefDate(Date.UTC(2023, 0, 1)); await generate(); } diff --git a/scripts/apidoc/apiDocsWriter.ts b/scripts/apidoc/apiDocsWriter.ts index 6f00f64a..ba1e4367 100644 --- a/scripts/apidoc/apiDocsWriter.ts +++ b/scripts/apidoc/apiDocsWriter.ts @@ -2,16 +2,17 @@ import { writeFileSync } from 'node:fs'; import { resolve } from 'node:path'; import type { ProjectReflection } from 'typedoc'; import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import type { APIGroup, APIItem } from '../../docs/api/api-types'; +import type { APIGroup } from '../../docs/api/api-types'; import { formatMarkdown, formatTypescript } from './format'; +import { extractSourceBaseUrl } from './typedoc'; +import type { DocsApiDiffIndex, ModuleSummary, Page } from './utils'; import { - extractModuleName, - extractSourceBaseUrl, - selectApiMethods, - selectApiModules, -} from './typedoc'; -import type { DocsApiDiffIndex, PageIndex } from './utils'; -import { pathDocsDiffIndexFile, pathDocsDir, pathOutputDir } from './utils'; + diffHash, + methodDiffHash, + pathDocsDiffIndexFile, + pathDocsDir, + pathOutputDir, +} from './utils'; const pathDocsApiPages = resolve(pathDocsDir, '.vitepress', 'api-pages.ts'); const pathDocsApiSearchIndex = resolve( @@ -29,6 +30,52 @@ editLink: false `; +/** + * Writes the api docs for the given modules. + * + * @param moduleName The name of the module to write the docs for. + * @param lowerModuleName The lowercase name of the module. + * @param comment The module comments. + * @param deprecated The deprecation message. + * @param methods The methods of the module. + */ +export function writeApiDocsModule( + moduleName: string, + lowerModuleName: string, + comment: string, + deprecated: string | undefined, + methods: Method[] +): ModuleSummary { + writeApiDocsModulePage( + moduleName, + lowerModuleName, + comment, + deprecated, + methods + ); + writeApiDocsModuleData(lowerModuleName, methods); + + return { + text: moduleName, + link: `/api/${lowerModuleName}.html`, + methods, + diff: methods.reduce( + (data, method) => ({ + ...data, + [method.name]: methodDiffHash(method), + }), + { + moduleHash: diffHash({ + name: moduleName, + field: lowerModuleName, + deprecated, + comment, + }), + } + ), + }; +} + /** * Writes the api page for the given module to the correct location. * @@ -37,7 +84,7 @@ editLink: false * @param comment The module comments. * @param methods The methods of the module. */ -export function writeApiDocsModulePage( +function writeApiDocsModulePage( moduleName: string, lowerModuleName: string, comment: string, @@ -94,7 +141,7 @@ export function writeApiDocsModulePage( * @param lowerModuleName The lowercase name of the module. * @param methods The methods data to save. */ -export function writeApiDocsData( +function writeApiDocsModuleData( lowerModuleName: string, methods: Method[] ): void { @@ -116,10 +163,9 @@ export function writeApiDocsData( * * @param pages The pages to write into the index. */ -export function writeApiPagesIndex(pages: PageIndex): void { +export function writeApiPagesIndex(pages: Page[]): void { // Write api-pages.ts console.log('Updating api-pages.ts'); - pages.sort((a, b) => a.text.localeCompare(b.text)); pages.splice(0, 0, { text: 'Overview', link: '/api/' }); let apiPagesContent = ` // This file is automatically generated. @@ -146,33 +192,20 @@ export function writeApiDiffIndex(diffIndex: DocsApiDiffIndex): void { * * @param project The typedoc project. */ -export function writeApiSearchIndex(project: ProjectReflection): void { - const apiIndex: APIGroup[] = []; - - const moduleApiSection: APIGroup = { - text: 'Module API', - items: [], - }; - - apiIndex.push(moduleApiSection); - - const apiModules = selectApiModules(project); - - moduleApiSection.items = apiModules - .map((module) => { - const moduleName = extractModuleName(module); - const apiSection: APIItem = { - text: moduleName, - link: moduleName.toLowerCase(), - headers: selectApiMethods(module).map((child) => ({ - anchor: child.name, - text: child.name, +export function writeApiSearchIndex(pages: ModuleSummary[]): void { + const apiIndex: APIGroup[] = [ + { + text: 'Module API', + items: pages.map((module) => ({ + text: module.text, + link: module.link, + headers: module.methods.map((method) => ({ + anchor: method.name, + text: method.name, })), - }; - - return apiSection; - }) - .sort((a, b) => a.text.localeCompare(b.text)); + })), + }, + ]; writeFileSync(pathDocsApiSearchIndex, JSON.stringify(apiIndex)); } diff --git a/scripts/apidoc/fakerClass.ts b/scripts/apidoc/fakerClass.ts new file mode 100644 index 00000000..9d11815f --- /dev/null +++ b/scripts/apidoc/fakerClass.ts @@ -0,0 +1,48 @@ +import type { DeclarationReflection, ProjectReflection } from 'typedoc'; +import { ReflectionKind } from 'typedoc'; +import type { Method } from '../../docs/.vitepress/components/api-docs/method'; +import { writeApiDocsModule } from './apiDocsWriter'; +import { processModuleMethods } from './moduleMethods'; +import { analyzeSignature, toBlock } from './signature'; +import { selectApiSignature } from './typedoc'; +import type { ModuleSummary } from './utils'; + +export function processFakerClass(project: ProjectReflection): ModuleSummary { + const fakerClass = project + .getChildrenByKind(ReflectionKind.Class) + .filter((clazz) => clazz.name === 'Faker')[0]; + + if (!fakerClass) { + throw new Error('Faker class not found'); + } + + return processClass(fakerClass); +} + +function processClass(fakerClass: DeclarationReflection): ModuleSummary { + console.log(`Processing Faker class`); + const comment = toBlock(fakerClass.comment); + const methods: Method[] = []; + + console.debug(`- constructor`); + methods.push(processConstructor(fakerClass)); + + methods.push(...processModuleMethods(fakerClass, 'faker.')); + + return writeApiDocsModule('Faker', 'faker', comment, undefined, methods); +} + +function processConstructor(fakerClass: DeclarationReflection): Method { + const constructor = fakerClass.getChildrenByKind( + ReflectionKind.Constructor + )[0]; + + const signature = selectApiSignature(constructor); + + const method = analyzeSignature(signature, '', 'new Faker'); + + return { + ...method, + name: 'constructor', + }; +} diff --git a/scripts/apidoc/fakerUtilities.ts b/scripts/apidoc/fakerUtilities.ts new file mode 100644 index 00000000..f033eadc --- /dev/null +++ b/scripts/apidoc/fakerUtilities.ts @@ -0,0 +1,32 @@ +import type { DeclarationReflection, ProjectReflection } from 'typedoc'; +import { ReflectionKind } from 'typedoc'; +import type { Method } from '../../docs/.vitepress/components/api-docs/method'; +import { writeApiDocsModule } from './apiDocsWriter'; +import { processMethods } from './moduleMethods'; +import { selectApiSignature } from './typedoc'; +import type { ModuleSummary } from './utils'; + +export function processFakerUtilities( + project: ProjectReflection +): ModuleSummary { + const fakerUtilities = project + .getChildrenByKind(ReflectionKind.Function) + .filter((method) => !method.flags.isPrivate); + + return processUtilities(fakerUtilities); +} + +function processUtilities( + fakerUtilities: DeclarationReflection[] +): ModuleSummary { + console.log(`Processing Faker Utilities`); + const comment = 'A list of all the utilities available in Faker.js.'; + + const methods: Method[] = processMethods( + Object.fromEntries( + fakerUtilities.map((method) => [method.name, selectApiSignature(method)]) + ) + ); + + return writeApiDocsModule('Utilities', 'utils', comment, undefined, methods); +} diff --git a/scripts/apidoc/generate.ts b/scripts/apidoc/generate.ts index b5ccb3f3..408ab76a 100644 --- a/scripts/apidoc/generate.ts +++ b/scripts/apidoc/generate.ts @@ -5,7 +5,9 @@ import { writeApiSearchIndex, writeSourceBaseUrl, } from './apiDocsWriter'; -import { processModuleMethods } from './moduleMethods'; +import { processFakerClass } from './fakerClass'; +import { processFakerUtilities } from './fakerUtilities'; +import { processModules } from './moduleMethods'; import { loadProject } from './typedoc'; import { pathOutputDir } from './utils'; @@ -20,12 +22,16 @@ export async function generate(): Promise { // Useful for manually analyzing the content await app.generateJson(project, pathOutputJson); - const modules = processModuleMethods(project); - writeApiPagesIndex(modules.map(({ text, link }) => ({ text, link }))); + const pages = [ + processFakerClass(project), + ...processModules(project).sort((a, b) => a.text.localeCompare(b.text)), + processFakerUtilities(project), + ]; + writeApiPagesIndex(pages.map(({ text, link }) => ({ text, link }))); writeApiDiffIndex( - modules.reduce((data, { text, diff }) => ({ ...data, [text]: diff }), {}) + pages.reduce((data, { text, diff }) => ({ ...data, [text]: diff }), {}) ); + writeApiSearchIndex(pages); - writeApiSearchIndex(project); writeSourceBaseUrl(project); } diff --git a/scripts/apidoc/moduleMethods.ts b/scripts/apidoc/moduleMethods.ts index 20cbc2b8..9c902dd7 100644 --- a/scripts/apidoc/moduleMethods.ts +++ b/scripts/apidoc/moduleMethods.ts @@ -1,6 +1,10 @@ -import type { DeclarationReflection, ProjectReflection } from 'typedoc'; +import type { + DeclarationReflection, + ProjectReflection, + SignatureReflection, +} from 'typedoc'; import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import { writeApiDocsData, writeApiDocsModulePage } from './apiDocsWriter'; +import { writeApiDocsModule } from './apiDocsWriter'; import { analyzeSignature, stripAbsoluteFakerUrls, toBlock } from './signature'; import { extractDeprecated, @@ -9,8 +13,7 @@ import { selectApiMethodSignatures, selectApiModules, } from './typedoc'; -import type { PageAndDiffIndex } from './utils'; -import { diffHash, methodDiffHash } from './utils'; +import type { ModuleSummary } from './utils'; /** * Analyzes and writes the documentation for modules and their methods such as `faker.animal.cat()`. @@ -18,17 +21,8 @@ import { diffHash, methodDiffHash } from './utils'; * @param project The project used to extract the modules. * @returns The generated pages. */ -export function processModuleMethods( - project: ProjectReflection -): PageAndDiffIndex { - const pages: PageAndDiffIndex = []; - - // Generate module files - for (const module of selectApiModules(project)) { - pages.push(...processModuleMethod(module)); - } - - return pages; +export function processModules(project: ProjectReflection): ModuleSummary[] { + return selectApiModules(project).map(processModule); } /** @@ -37,48 +31,54 @@ export function processModuleMethods( * @param module The module to process. * @returns The generated pages. */ -function processModuleMethod(module: DeclarationReflection): PageAndDiffIndex { +function processModule(module: DeclarationReflection): ModuleSummary { const moduleName = extractModuleName(module); const moduleFieldName = extractModuleFieldName(module); console.log(`Processing Module ${moduleName}`); const comment = stripAbsoluteFakerUrls(toBlock(module.comment)); const deprecated = extractDeprecated(module); - const methods: Method[] = []; - - // Generate method section - for (const [methodName, signature] of Object.entries( - selectApiMethodSignatures(module) - )) { - console.debug(`- ${methodName}`); - methods.push(analyzeSignature(signature, moduleFieldName, methodName)); - } + const methods = processModuleMethods(module, `faker.${moduleFieldName}.`); - writeApiDocsModulePage( + return writeApiDocsModule( moduleName, moduleFieldName, comment, deprecated, methods ); - writeApiDocsData(moduleFieldName, methods); +} + +/** + * Processes all api methods of the given class. This does not include the constructor. + * + * @param module The module to process. + * @param accessor The code used to access the methods within the module. + * @returns A list containing the documentation for the api methods in the given module. + */ +export function processModuleMethods( + module: DeclarationReflection, + accessor: string +): Method[] { + return processMethods(selectApiMethodSignatures(module), accessor); +} + +/** + * Processes all api methods. + * + * @param signatures The signatures to process. + * @param accessor The code used to access the methods. + * @returns A list containing the documentation for the api methods. + */ +export function processMethods( + signatures: Record, + accessor: string = '' +): Method[] { + const methods: Method[] = []; + + for (const [methodName, signature] of Object.entries(signatures)) { + console.debug(`- ${methodName}`); + methods.push(analyzeSignature(signature, accessor, methodName)); + } - return [ - { - text: moduleName, - link: `/api/${moduleFieldName}.html`, - diff: methods.reduce( - (data, method) => ({ - ...data, - [method.name]: methodDiffHash(method), - }), - { - moduleHash: diffHash({ - name: moduleName, - field: moduleFieldName, - comment, - }), - } - ), - }, - ]; + return methods; } diff --git a/scripts/apidoc/signature.ts b/scripts/apidoc/signature.ts index f9364a04..113aba1d 100644 --- a/scripts/apidoc/signature.ts +++ b/scripts/apidoc/signature.ts @@ -17,7 +17,6 @@ import type { MethodParameter, } from '../../docs/.vitepress/components/api-docs/method'; import vitepressConfig from '../../docs/.vitepress/config'; -import { faker } from '../../src'; import { formatTypescript } from './format'; import { extractDeprecated, @@ -32,14 +31,6 @@ import { pathOutputDir } from './utils'; const code = '```'; -function prettifyMethodName(method: string): string { - return ( - // Capitalize and insert space before upper case characters - method.substring(0, 1).toUpperCase() + - method.substring(1).replace(/([A-Z]+)/g, ' $1') - ); -} - export const MISSING_DESCRIPTION = 'Missing'; export function toBlock(comment?: Comment): string { @@ -115,7 +106,7 @@ function mdToHtml(md: string, inline: boolean = false): string { export function analyzeSignature( signature: SignatureReflection, - moduleName: string | null, + accessor: string, methodName: string ): Method { const parameters: MethodParameter[] = []; @@ -155,27 +146,7 @@ export function analyzeSignature( const signatureParametersString = signatureParameters.join(', '); - let examples: string; - if (moduleName) { - examples = `faker.${moduleName}.${methodName}${signatureTypeParametersString}(${signatureParametersString}): ${signature.type?.toString()}\n`; - } else { - examples = `faker.${methodName}${signatureTypeParametersString}(${signatureParametersString}): ${signature.type?.toString()}\n`; - } - - faker.seed(0); - if (moduleName) { - try { - let example = JSON.stringify(faker[moduleName][methodName]()); - if (example.length > 50) { - example = `${example.substring(0, 47)}...`; - } - - examples += `faker.${moduleName}.${methodName}()`; - examples += `${example ? ` // => ${example}` : ''}\n`; - } catch (error) { - // Ignore the error => hide the example call + result. - } - } + let examples = `${accessor}${methodName}${signatureTypeParametersString}(${signatureParametersString}): ${signature.type?.toString()}\n`; const exampleTags = extractRawExamples(signature); if (exampleTags.length > 0) { @@ -191,7 +162,6 @@ export function analyzeSignature( : undefined; return { name: methodName, - title: prettifyMethodName(methodName), description: mdToHtml(toBlock(signature.comment)), parameters: parameters, since: extractSince(signature), diff --git a/scripts/apidoc/utils.ts b/scripts/apidoc/utils.ts index 4c9c322d..79e47507 100644 --- a/scripts/apidoc/utils.ts +++ b/scripts/apidoc/utils.ts @@ -5,12 +5,11 @@ import type { Method } from '../../docs/.vitepress/components/api-docs/method'; // Types export type Page = { text: string; link: string }; -export type PageIndex = Page[]; -export type PageAndDiff = Page & { +export type ModuleSummary = Page & { + methods: Method[]; diff: DocsApiDiff; }; -export type PageAndDiffIndex = PageAndDiff[]; export interface DocsApiDiffIndex { /** -- cgit v1.2.3