diff options
| author | ST-DDT <[email protected]> | 2024-04-01 10:21:18 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-01 10:21:18 +0200 |
| commit | 6191a5d883048b694404dbf42527caba395828ea (patch) | |
| tree | d0f18f17789cb0bbdb5d6087f1a95772438dfe27 /scripts/apidoc | |
| parent | 7dae52bfcd93c41ec9d2c4dd4d96a07f31c3dfc1 (diff) | |
| download | faker-6191a5d883048b694404dbf42527caba395828ea.tar.xz faker-6191a5d883048b694404dbf42527caba395828ea.zip | |
docs: rewrite api-docs generation using ts-morph (#2628)
Diffstat (limited to 'scripts/apidoc')
| -rw-r--r-- | scripts/apidoc/diff.ts | 94 | ||||
| -rw-r--r-- | scripts/apidoc/faker-class.ts | 86 | ||||
| -rw-r--r-- | scripts/apidoc/faker-utilities.ts | 40 | ||||
| -rw-r--r-- | scripts/apidoc/format.ts | 31 | ||||
| -rw-r--r-- | scripts/apidoc/generate.ts | 42 | ||||
| -rw-r--r-- | scripts/apidoc/markdown.ts | 87 | ||||
| -rw-r--r-- | scripts/apidoc/module-methods.ts | 122 | ||||
| -rw-r--r-- | scripts/apidoc/parameter-defaults.ts | 136 | ||||
| -rw-r--r-- | scripts/apidoc/signature.ts | 365 | ||||
| -rw-r--r-- | scripts/apidoc/typedoc.ts | 421 | ||||
| -rw-r--r-- | scripts/apidoc/utils.ts | 79 | ||||
| -rw-r--r-- | scripts/apidoc/writer.ts | 249 |
12 files changed, 0 insertions, 1752 deletions
diff --git a/scripts/apidoc/diff.ts b/scripts/apidoc/diff.ts deleted file mode 100644 index 101200cd..00000000 --- a/scripts/apidoc/diff.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { DocsApiDiffIndex } from './utils'; -import { nameDocsDiffIndexFile, pathDocsDiffIndexFile } from './utils'; - -/** - * Loads the diff index from the given source url. - * - * @param url The url to load the diff index from. - */ -async function loadRemote(url: string): Promise<DocsApiDiffIndex> { - return fetch(url).then((res) => { - if (!res.ok) { - throw new Error( - `Failed to load remote diff index from ${url}: ${res.statusText}` - ); - } - - return res.json() as Promise<DocsApiDiffIndex>; - }); -} - -/** - * Loads the diff index from the given local path. - * - * @param path The path to load the diff index from. Should start with `file://` for cross platform compatibility. - */ -async function loadLocal(path: string): Promise<DocsApiDiffIndex> { - return import(path).then((imp) => imp.default as DocsApiDiffIndex); -} - -/** - * Loads the diff index from the given source. - * If the source starts with `https://` it will be loaded from the remote url. - * Otherwise it will be loaded from the local path. - * - * @param source The source to load the diff index from. - */ -async function load(source: string): Promise<DocsApiDiffIndex> { - return source.startsWith('https://') ? loadRemote(source) : loadLocal(source); -} - -/** - * Returns a set of all keys from the given entries. - * - * @param entries The entries to get the keys from. - */ -function allKeys( - ...entries: ReadonlyArray<Record<string, unknown>> -): Set<string> { - return new Set(entries.flatMap(Object.keys)); -} - -/** - * Compares the target (reference) and source (changed) diff index and returns the differences. - * The returned object contains the module names as keys and the method names as values. - * If the module name is `ADDED` or `REMOVED` it means that the module was added or removed in the local diff index. - * - * @param targetDiffIndex The url to the target (reference) diff index. Defaults to the next.fakerjs.dev diff index. - * @param sourceDiffIndex The path to the source (changed) index. Defaults to the local diff index. - */ -export async function diff( - targetDiffIndex = `https://next.fakerjs.dev/${nameDocsDiffIndexFile}`, - sourceDiffIndex = `file://${pathDocsDiffIndexFile}` -): Promise<Record<string, ['ADDED'] | ['REMOVED'] | string[]>> { - const target = await load(targetDiffIndex); - const source = await load(sourceDiffIndex); - - const diff: Record<string, string[]> = {}; - - for (const moduleName of allKeys(target, source)) { - const remoteModule = target[moduleName]; - const localModule = source[moduleName]; - - if (!remoteModule) { - diff[moduleName] = ['ADDED']; - continue; - } - - if (!localModule) { - diff[moduleName] = ['REMOVED']; - continue; - } - - for (const methodName of allKeys(remoteModule, localModule)) { - const remoteMethod = remoteModule[methodName]; - const localMethod = localModule[methodName]; - - if (remoteMethod !== localMethod) { - (diff[moduleName] ??= []).push(methodName); - } - } - } - - return diff; -} diff --git a/scripts/apidoc/faker-class.ts b/scripts/apidoc/faker-class.ts deleted file mode 100644 index a9acad3c..00000000 --- a/scripts/apidoc/faker-class.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { DeclarationReflection, ProjectReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; -import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import { analyzeModule, processModuleMethods } from './module-methods'; -import { analyzeSignature } from './signature'; -import { extractModuleFieldName, selectApiSignature } from './typedoc'; -import type { ModuleSummary } from './utils'; -import { writeApiDocsModule } from './writer'; - -export async function processFakerClasses( - project: ProjectReflection -): Promise<ModuleSummary[]> { - const fakerClasses = project - .getChildrenByKind(ReflectionKind.Class) - .filter((clazz) => clazz.name === 'Faker' || clazz.name === 'SimpleFaker'); - - if (fakerClasses.length !== 2) { - throw new Error('Faker classes not found'); - } - - return Promise.all(fakerClasses.map(processClass)); -} - -export async function processFakerRandomizer( - project: ProjectReflection -): Promise<ModuleSummary> { - const randomizerClass = project - .getChildrenByKind(ReflectionKind.Interface) - .find((clazz) => clazz.name === 'Randomizer'); - - if (randomizerClass == null) { - throw new Error('Randomizer class not found'); - } - - return processClass(randomizerClass); -} - -async function processClass( - clazz: DeclarationReflection -): Promise<ModuleSummary> { - const { name } = clazz; - const moduleFieldName = extractModuleFieldName(clazz); - - console.log(`Processing ${name} class`); - - const { comment, deprecated, examples } = analyzeModule(clazz); - const methods: Method[] = []; - - if (hasConstructor(clazz)) { - console.debug(`- constructor`); - methods.push(await processConstructor(clazz)); - } - - methods.push(...(await processModuleMethods(clazz, `${moduleFieldName}.`))); - - return writeApiDocsModule( - name, - moduleFieldName, - comment, - examples, - deprecated, - methods, - '' - ); -} - -function hasConstructor(clazz: DeclarationReflection): boolean { - return clazz - .getChildrenByKind(ReflectionKind.Constructor) - .some((constructor) => (constructor.signatures?.length ?? 0) > 0); -} - -async function processConstructor( - clazz: DeclarationReflection -): Promise<Method> { - const constructor = clazz.getChildrenByKind(ReflectionKind.Constructor)[0]; - - const signature = selectApiSignature(constructor); - - const method = await analyzeSignature(signature, '', `new ${clazz.name}`); - - return { - ...method, - name: 'constructor', - }; -} diff --git a/scripts/apidoc/faker-utilities.ts b/scripts/apidoc/faker-utilities.ts deleted file mode 100644 index ad1f74c3..00000000 --- a/scripts/apidoc/faker-utilities.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { DeclarationReflection, ProjectReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; -import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import { processMethods } from './module-methods'; -import { selectApiSignature } from './typedoc'; -import type { ModuleSummary } from './utils'; -import { writeApiDocsModule } from './writer'; - -export async function processFakerUtilities( - project: ProjectReflection -): Promise<ModuleSummary> { - const fakerUtilities = project - .getChildrenByKind(ReflectionKind.Function) - .filter((method) => !method.flags.isPrivate); - - return processUtilities(fakerUtilities); -} - -async function processUtilities( - fakerUtilities: DeclarationReflection[] -): Promise<ModuleSummary> { - console.log(`Processing Faker Utilities`); - const comment = 'A list of all the utilities available in Faker.js.'; - - const methods: Method[] = await processMethods( - Object.fromEntries( - fakerUtilities.map((method) => [method.name, selectApiSignature(method)]) - ) - ); - - return writeApiDocsModule( - 'Utilities', - 'utils', - comment, - undefined, - undefined, - methods, - '' - ); -} diff --git a/scripts/apidoc/format.ts b/scripts/apidoc/format.ts deleted file mode 100644 index a8f63ac0..00000000 --- a/scripts/apidoc/format.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Options } from 'prettier'; -import { format } from 'prettier'; -import prettierConfig from '../../.prettierrc.js'; - -/** - * Formats markdown contents. - * - * @param text The text to format. - */ -export async function formatMarkdown(text: string): Promise<string> { - return format(text, prettierMarkdown); -} - -/** - * Formats typedoc contents. - * - * @param text The text to format. - */ -export async function formatTypescript(text: string): Promise<string> { - return format(text, prettierTypescript); -} - -const prettierMarkdown: Options = { - ...prettierConfig, - parser: 'markdown', -}; - -const prettierTypescript: Options = { - ...prettierConfig, - parser: 'typescript', -}; diff --git a/scripts/apidoc/generate.ts b/scripts/apidoc/generate.ts deleted file mode 100644 index eb00cea4..00000000 --- a/scripts/apidoc/generate.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { resolve } from 'node:path'; -import { processFakerClasses, processFakerRandomizer } from './faker-class'; -import { processFakerUtilities } from './faker-utilities'; -import { processModules } from './module-methods'; -import { loadProject } from './typedoc'; -import { pathOutputDir } from './utils'; -import { - writeApiDiffIndex, - writeApiPagesIndex, - writeApiSearchIndex, - writeSourceBaseUrl, -} from './writer'; - -const pathOutputJson = resolve(pathOutputDir, 'typedoc.json'); - -/** - * Generates the API documentation. - */ -export async function generate(): Promise<void> { - const [app, project] = await loadProject(); - - // Useful for manually analyzing the content - await app.generateJson(project, pathOutputJson); - - const pages = [ - ...(await processFakerClasses(project)), - await processFakerRandomizer(project), - await processFakerUtilities(project), - ...(await processModules(project)).sort((a, b) => - a.text.localeCompare(b.text) - ), - ]; - await writeApiPagesIndex( - pages.map(({ text, link, category }) => ({ text, link, category })) - ); - writeApiDiffIndex( - Object.fromEntries(pages.map(({ text, diff }) => [text, diff])) - ); - writeApiSearchIndex(pages); - - await writeSourceBaseUrl(project); -} diff --git a/scripts/apidoc/markdown.ts b/scripts/apidoc/markdown.ts deleted file mode 100644 index 0b1e3b40..00000000 --- a/scripts/apidoc/markdown.ts +++ /dev/null @@ -1,87 +0,0 @@ -import sanitizeHtml from 'sanitize-html'; -import type { MarkdownRenderer } from 'vitepress'; -import { createMarkdownRenderer } from 'vitepress'; -import vitepressConfig from '../../docs/.vitepress/config'; -import { adjustUrls, pathOutputDir } from './utils'; - -let markdown: MarkdownRenderer; - -export async function initMarkdownRenderer(): Promise<void> { - markdown = await createMarkdownRenderer( - pathOutputDir, - vitepressConfig.markdown, - '/' - ); -} - -const htmlSanitizeOptions: sanitizeHtml.IOptions = { - allowedTags: [ - 'a', - 'button', - 'code', - 'div', - 'li', - 'p', - 'pre', - 'span', - 'strong', - 'ul', - ], - allowedAttributes: { - a: ['href', 'target', 'rel'], - button: ['class', 'title'], - div: ['class'], - pre: ['class', 'tabindex', 'v-pre'], - span: ['class', 'style'], - }, - selfClosing: [], -}; - -function comparableSanitizedHtml(html: string): string { - return html - .replaceAll(/&#x[0-9A-F]{2};/g, (x) => - String.fromCodePoint(Number.parseInt(x.slice(3, -1), 16)) - ) - .replaceAll('>', '>') - .replaceAll('<', '<') - .replaceAll('&', '&') - .replaceAll('"', '"') - .replaceAll('=""', '') - .replaceAll(' ', ''); -} - -/** - * Converts a Typescript code block to an HTML string and sanitizes it. - * - * @param code The code to convert. - * - * @returns The converted HTML string. - */ -export function codeToHtml(code: string): string { - const delimiter = '```'; - return mdToHtml(`${delimiter}ts\n${code}\n${delimiter}`); -} - -/** - * Converts Markdown to an HTML string and sanitizes it. - * - * @param md The markdown to convert. - * @param inline Whether to render the markdown as inline, without a wrapping `<p>` tag. Defaults to `false`. - * - * @returns The converted HTML string. - */ -export function mdToHtml(md: string, inline: boolean = false): string { - const rawHtml = inline ? markdown.renderInline(md) : markdown.render(md); - - const safeHtml: string = sanitizeHtml(rawHtml, htmlSanitizeOptions); - // Revert some escaped characters for comparison. - if (comparableSanitizedHtml(rawHtml) === comparableSanitizedHtml(safeHtml)) { - return adjustUrls(safeHtml); - } - - console.debug('Rejected unsafe md:', md); - console.error('Rejected unsafe html:', rawHtml); - console.error('Rejected unsafe html:', comparableSanitizedHtml(rawHtml)); - console.error('Expected safe html:', comparableSanitizedHtml(safeHtml)); - throw new Error('Found unsafe html'); -} diff --git a/scripts/apidoc/module-methods.ts b/scripts/apidoc/module-methods.ts deleted file mode 100644 index c21ccf97..00000000 --- a/scripts/apidoc/module-methods.ts +++ /dev/null @@ -1,122 +0,0 @@ -import type { - DeclarationReflection, - ProjectReflection, - SignatureReflection, -} from 'typedoc'; -import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import { codeToHtml } from './markdown'; -import { analyzeSignature } from './signature'; -import { - extractDeprecated, - extractDescription, - extractJoinedRawExamples, - extractModuleFieldName, - extractModuleName, - selectApiMethodSignatures, - selectApiModules, -} from './typedoc'; -import type { ModuleSummary } from './utils'; -import { adjustUrls } from './utils'; -import { writeApiDocsModule } from './writer'; - -/** - * Analyzes and writes the documentation for modules and their methods such as `faker.animal.cat()`. - * - * @param project The project used to extract the modules. - * - * @returns The generated pages. - */ -export async function processModules( - project: ProjectReflection -): Promise<ModuleSummary[]> { - return Promise.all(selectApiModules(project).map(processModule)); -} - -/** - * Analyzes and writes the documentation for a module and its methods such as `faker.animal.cat()`. - * - * @param module The module to process. - * - * @returns The generated pages. - */ -async function processModule( - module: DeclarationReflection -): Promise<ModuleSummary> { - const moduleName = extractModuleName(module); - console.log(`Processing Module ${moduleName}`); - const moduleFieldName = extractModuleFieldName(module); - const { comment, deprecated, examples } = analyzeModule(module); - const methods = await processModuleMethods( - module, - `faker.${moduleFieldName}.` - ); - - return writeApiDocsModule( - moduleName, - moduleFieldName, - comment, - examples, - deprecated, - methods, - 'Modules' - ); -} - -/** - * Analyzes the documentation for a class. - * - * @param module The class to process. - * - * @returns The class information. - */ -export function analyzeModule(module: DeclarationReflection): { - comment: string; - deprecated: string | undefined; - examples: string | undefined; -} { - const examplesRaw = extractJoinedRawExamples(module); - const examples = examplesRaw ? codeToHtml(examplesRaw) : undefined; - - return { - comment: adjustUrls(extractDescription(module)), - deprecated: extractDeprecated(module), - examples, - }; -} - -/** - * 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 async function processModuleMethods( - module: DeclarationReflection, - accessor: string -): Promise<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 async function processMethods( - signatures: Record<string, SignatureReflection>, - accessor: string = '' -): Promise<Method[]> { - const methods: Method[] = []; - - for (const [methodName, signature] of Object.entries(signatures)) { - console.debug(`- ${methodName}`); - methods.push(await analyzeSignature(signature, accessor, methodName)); - } - - return methods; -} diff --git a/scripts/apidoc/parameter-defaults.ts b/scripts/apidoc/parameter-defaults.ts deleted file mode 100644 index a7f53c2b..00000000 --- a/scripts/apidoc/parameter-defaults.ts +++ /dev/null @@ -1,136 +0,0 @@ -import type { - Context, - DeclarationReflection, - EventCallback, - JSONOutput, - ProjectReflection, - SerializerComponent, - SignatureReflection, -} from 'typedoc'; -import { Reflection, ReflectionKind, TypeScript } from 'typedoc'; - -const reflectionKindFunctionOrMethod = - ReflectionKind.Function | ReflectionKind.Method; - -interface ParameterDefaultsAware extends Reflection { - implementationDefaultParameters: Array<string | undefined>; -} - -/** - * TypeDoc EventCallback for EVENT_CREATE_DECLARATION events that reads the default parameters from the implementation. - * - * @param context The converter context. - * @param reflection The reflection to read the default parameters from. - */ -export const parameterDefaultReader: EventCallback = ( - context: Context, - reflection: Reflection -): void => { - const symbol = context.project.getSymbolFromReflection(reflection); - if (!symbol) return; - - if ( - reflection.kindOf(reflectionKindFunctionOrMethod) && - symbol.declarations?.length - ) { - const lastDeclaration = symbol.declarations.at(-1); - if (TypeScript.isFunctionLike(lastDeclaration)) { - (reflection as ParameterDefaultsAware).implementationDefaultParameters = - lastDeclaration.parameters.map((param) => - cleanParameterDefault(param.initializer?.getText()) - ); - } - } -}; - -/** - * Removes compile expressions that don't add any value for readers. - * - * @param value The default value to clean. - * - * @returns The cleaned default value. - */ -function cleanParameterDefault(value: string): string; -function cleanParameterDefault(value?: string): string | undefined; -function cleanParameterDefault(value?: string): string | undefined { - if (value == null) { - return undefined; - } - - // Strip type casts: "'foobar' as unknown as T" => "'foobar'" - return value.replace(/( as unknown)? as [A-Za-z<>]+/, ''); -} - -/** - * Serializer that adds the `implementationDefaultParameters` to the JSON output. - */ -export class DefaultParameterAwareSerializer - implements SerializerComponent<Reflection> -{ - readonly priority = 0; - - supports(item: unknown): item is Reflection { - return item instanceof Reflection; - } - - toObject( - item: Reflection, - obj: Partial<JSONOutput.Reflection> - ): Partial<JSONOutput.Reflection> { - (obj as unknown as ParameterDefaultsAware).implementationDefaultParameters = - (item as ParameterDefaultsAware).implementationDefaultParameters; - return obj; - } -} - -/** - * Replaces all methods' last signature's parameter's default value with the default value read from the implementation. - * - * @param project The project to patch. - */ -export function patchProjectParameterDefaults( - project: ProjectReflection -): void { - const functionOrMethods = project.getReflectionsByKind( - reflectionKindFunctionOrMethod - ) as DeclarationReflection[]; - for (const functionOrMethod of functionOrMethods) { - patchMethodParameterDefaults(functionOrMethod); - } -} - -/** - * Replaces the last signature's parameter's default value with the default value read from the implementation. - * - * @param method The method to patch. - */ -function patchMethodParameterDefaults(method: DeclarationReflection): void { - const signatures = method.signatures; - const signature = signatures?.[signatures.length - 1]; - const parameterDefaults = (method as unknown as ParameterDefaultsAware) - .implementationDefaultParameters; - if (signature && parameterDefaults) { - patchSignatureParameterDefaults(signature, parameterDefaults); - } -} - -/** - * Replaces the given signature's parameter's default value with the given default values. - * - * @param signature The signature to patch. - * @param parameterDefaults The defaults to add. - */ -function patchSignatureParameterDefaults( - signature: SignatureReflection, - parameterDefaults: Array<string | undefined> -): void { - const signatureParameters = - signature.parameters ?? Array.from({ length: parameterDefaults.length }); - if (signatureParameters.length !== parameterDefaults.length) { - throw new Error('Unexpected parameter length mismatch'); - } - - for (const [index, param] of signatureParameters.entries()) { - param.defaultValue = parameterDefaults[index] || param.defaultValue; - } -} diff --git a/scripts/apidoc/signature.ts b/scripts/apidoc/signature.ts deleted file mode 100644 index 64910534..00000000 --- a/scripts/apidoc/signature.ts +++ /dev/null @@ -1,365 +0,0 @@ -import type { - Comment, - DeclarationReflection, - ParameterReflection, - Reflection, - ReflectionType, - SignatureReflection, - SomeType, - Type, -} from 'typedoc'; -import { ReflectionFlag, ReflectionKind } from 'typedoc'; -import type { - Method, - MethodParameter, -} from '../../docs/.vitepress/components/api-docs/method'; -import { formatTypescript } from './format'; -import { codeToHtml, mdToHtml } from './markdown'; -import { - extractDeprecated, - extractDescription, - extractJoinedRawExamples, - extractRawDefault, - extractSeeAlsos, - extractSince, - extractSourcePath, - extractSummaryDefault, - extractThrows, - toBlock, -} from './typedoc'; - -export async function analyzeSignature( - signature: SignatureReflection, - accessor: string, - methodName: string -): Promise<Method> { - const parameters: MethodParameter[] = []; - - // Collect Type Parameters - const typeParameters = signature.typeParameters || []; - const signatureTypeParameters: string[] = []; - for (const parameter of typeParameters) { - signatureTypeParameters.push(parameter.name); - parameters.push({ - name: `<${parameter.name}>`, - type: parameter.type ? await typeToText(parameter.type) : undefined, - description: mdToHtml(extractDescription(parameter)), - }); - } - - // Collect Parameters - const signatureParameters: string[] = []; - for ( - let index = 0; - signature.parameters && index < signature.parameters.length; - index++ - ) { - const parameter = signature.parameters[index]; - - const aParam = await analyzeParameter(parameter); - signatureParameters.push(aParam.signature); - parameters.push(...aParam.parameters); - } - - // Generate usage section - - let signatureTypeParametersString = ''; - if (signatureTypeParameters.length > 0) { - signatureTypeParametersString = `<${signatureTypeParameters.join(', ')}>`; - } - - const signatureParametersString = signatureParameters.join(', '); - - let examples = `${accessor}${methodName}${signatureTypeParametersString}(${signatureParametersString}): ${signature.type?.toString()}\n`; - - const exampleTags = extractJoinedRawExamples(signature); - if (exampleTags) { - examples += exampleTags; - } - - const seeAlsos = extractSeeAlsos(signature).map((seeAlso) => - mdToHtml(seeAlso, true) - ); - const deprecatedMessage = extractDeprecated(signature); - const deprecated = deprecatedMessage - ? mdToHtml(deprecatedMessage) - : undefined; - const throwsMessage = extractThrows(signature); - const throws = throwsMessage ? mdToHtml(throwsMessage, true) : undefined; - - return { - name: methodName, - description: mdToHtml(extractDescription(signature)), - parameters: parameters, - since: extractSince(signature), - sourcePath: extractSourcePath(signature), - throws, - returns: await typeToText(signature.type), - examples: codeToHtml(examples), - deprecated, - seeAlsos, - }; -} - -async function analyzeParameter(parameter: ParameterReflection): Promise<{ - parameters: MethodParameter[]; - signature: string; -}> { - const name = parameter.name; - const declarationName = name + (isOptional(parameter) ? '?' : ''); - const type = parameter.type; - const defaultValue = extractDefaultFromParameter(parameter); - - let signatureText = ''; - if (defaultValue) { - signatureText = ` = ${defaultValue}`; - } - - const signature = `${declarationName}: ${await typeToText( - type - )}${signatureText}`; - - const parameters: MethodParameter[] = [ - { - name: declarationName, - type: await typeToText(type, true), - default: defaultValue, - description: mdToHtml(extractDescription(parameter)), - }, - ]; - parameters.push(...(await analyzeParameterOptions(name, type))); - - return { - parameters, - signature, - }; -} - -// keep in sync with assertNestedParameterDefault -async function analyzeParameterOptions( - name: string, - parameterType?: SomeType -): Promise<MethodParameter[]> { - if (!parameterType) { - return []; - } - - switch (parameterType.type) { - case 'array': { - return analyzeParameterOptions(`${name}[]`, parameterType.elementType); - } - - case 'union': { - return Promise.all( - parameterType.types.map((type) => analyzeParameterOptions(name, type)) - ).then((options) => options.flat()); - } - - case 'reflection': { - const properties = parameterType.declaration.children ?? []; - return Promise.all( - properties.map(async (property) => { - const reflection = property.comment - ? property - : (property.type as ReflectionType)?.declaration?.signatures?.[0]; - const comment = reflection?.comment; - const deprecated = extractDeprecated(reflection); - return { - name: `${name}.${property.name}${isOptional(property) ? '?' : ''}`, - type: await declarationTypeToText(property), - default: extractDefaultFromComment(comment), - description: mdToHtml( - toBlock(comment) + - (deprecated ? `\n\n**DEPRECATED:** ${deprecated}` : '') - ), - }; - }) - ); - } - - case 'typeOperator': { - return analyzeParameterOptions(name, parameterType.target); - } - - default: { - return []; - } - } -} - -function isOptional(parameter: Reflection): boolean { - return parameter.flags.hasFlag(ReflectionFlag.Optional); -} - -async function typeToText(type_?: Type, short = false): Promise<string> { - if (!type_) { - return '?'; - } - - const type = type_ as SomeType; - switch (type.type) { - case 'array': { - const text = await typeToText(type.elementType, short); - const isComplexType = text.includes('|') || text.includes('{'); - return isComplexType ? `Array<${text}>` : `${text}[]`; - } - - case 'union': { - return (await Promise.all(type.types.map((t) => typeToText(t, short)))) - .map((t) => (t.includes('=>') ? `(${t})` : t)) - .sort() - .join(' | '); - } - - case 'reference': { - if (!type.typeArguments || type.typeArguments.length === 0) { - const reflection = type.reflection as DeclarationReflection | undefined; - const reflectionType = reflection?.type; - if ( - (reflectionType?.type === 'literal' || - reflectionType?.type === 'union') && - !type.name.endsWith('Char') - ) { - return typeToText(reflectionType, short); - } - - return type.name; - } else if (type.name === 'LiteralUnion') { - return [ - await typeToText(type.typeArguments[0], short), - await typeToText(type.typeArguments[1], short), - ].join(' | '); - } - - return `${type.name}<${( - await Promise.all(type.typeArguments.map((t) => typeToText(t, short))) - ).join(', ')}>`; - } - - case 'reflection': { - return declarationTypeToText(type.declaration, short); - } - - case 'indexedAccess': { - return `${await typeToText(type.objectType, short)}[${await typeToText( - type.indexType, - short - )}]`; - } - - case 'literal': { - return (await formatTypescript(type.toString())).replace(/;\n$/, ''); - } - - case 'typeOperator': { - const text = await typeToText(type.target, short); - if (short && type.operator === 'readonly') { - return text; - } - - return `${type.operator} ${text}`; - } - - default: { - return type.toString(); - } - } -} - -async function declarationTypeToText( - declaration: DeclarationReflection, - short = false -): Promise<string> { - switch (declaration.kind) { - case ReflectionKind.Method: { - return signatureTypeToText(declaration.signatures?.[0]); - } - - case ReflectionKind.Property: { - return typeToText(declaration.type); - } - - case ReflectionKind.TypeLiteral: { - if (declaration.children?.length) { - if (short) { - // This is too long for the parameter table, thus we abbreviate this. - return '{ ... }'; - } - - const list = ( - await Promise.all( - declaration.children.map( - async (c) => ` ${c.name}: ${await declarationTypeToText(c)}` - ) - ) - ).join(',\n'); - - return `{\n${list}\n}`; - } else if (declaration.signatures?.length) { - return signatureTypeToText(declaration.signatures[0]); - } - - return declaration.toString(); - } - - default: { - return declaration.toString(); - } - } -} - -async function signatureTypeToText( - signature?: SignatureReflection -): Promise<string> { - if (!signature) { - return '(???) => ?'; - } - - return `(${( - await Promise.all( - signature.parameters?.map( - async (p) => `${p.name}: ${await typeToText(p.type)}` - ) ?? [] - ) - ).join(', ')}) => ${await typeToText(signature.type)}`; -} - -/** - * Extracts and optionally removes the parameter default from the parameter. - * - * @param parameter The parameter to extract the default from. - * @param eraseDefault Whether to erase the default text from the parameter comment. - * - * @returns The extracted default value. - */ -function extractDefaultFromParameter( - parameter: ParameterReflection, - eraseDefault = true -): string | undefined { - const commentDefault = extractDefaultFromComment( - parameter.comment, - eraseDefault - ); - return parameter.defaultValue ?? commentDefault; -} - -/** - * Extracts and optionally removes the parameter default from the comments. - * - * @param comment The comment to extract the default from. - * @param eraseDefault Whether to erase the default text from the comment. - * - * @returns The extracted default value. - */ -function extractDefaultFromComment( - comment?: Comment, - eraseDefault = true -): string | undefined { - if (!comment) { - return; - } - - const tagDefault = extractRawDefault({ comment }); - const summaryDefault = extractSummaryDefault(comment, eraseDefault); - return tagDefault || summaryDefault; -} diff --git a/scripts/apidoc/typedoc.ts b/scripts/apidoc/typedoc.ts deleted file mode 100644 index 1cdcf3e1..00000000 --- a/scripts/apidoc/typedoc.ts +++ /dev/null @@ -1,421 +0,0 @@ -import type { - Comment, - CommentDisplayPart, - CommentTag, - DeclarationReflection, - ProjectReflection, - Reflection, - SignatureReflection, - TypeDocOptions, -} from 'typedoc'; -import { - Application, - Converter, - ReflectionKind, - TSConfigReader, -} from 'typedoc'; -import { faker } from '../../src'; -import { - DefaultParameterAwareSerializer, - parameterDefaultReader, - patchProjectParameterDefaults, -} from './parameter-defaults'; -import { mapByName } from './utils'; - -type CommentHolder = Pick<Reflection, 'comment'>; - -/** - * Loads the project using TypeDoc. - * - * @param options The options to use for the project. - * - * @returns The TypeDoc application and the project reflection. - */ -export async function loadProject( - options: Partial<TypeDocOptions> = { - entryPoints: ['src/index.ts'], - pretty: true, - cleanOutputDir: true, - tsconfig: 'tsconfig.build.json', - } -): Promise<[Application, ProjectReflection]> { - const app = await newTypeDocApp(options); - - const project = await app.convert(); - - if (!project) { - throw new Error('Failed to convert project'); - } - - patchProjectParameterDefaults(project); - - return [app, project]; -} - -/** - * Creates and configures a new typedoc application. - * - * @param options The options to use for the project. - */ -async function newTypeDocApp( - options?: Partial<TypeDocOptions> -): Promise<Application> { - const app = await Application.bootstrapWithPlugins(options, [ - new TSConfigReader(), - ]); - - // Read parameter defaults - app.converter.on(Converter.EVENT_CREATE_DECLARATION, parameterDefaultReader); - // Add to debug json output - app.serializer.addSerializer(new DefaultParameterAwareSerializer()); - - return app; -} - -/** - * Selects the modules from the project that needs to be documented. - * - * @param project The project to extract the modules from. - * @param includeTestModules Whether to include test modules. - * - * @returns The modules to document. - */ -export function selectApiModules( - project: ProjectReflection, - includeTestModules = false -): DeclarationReflection[] { - return project - .getChildrenByKind(ReflectionKind.Class) - .filter( - (module) => - faker[extractModuleFieldName(module) as keyof typeof faker] != 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) - .filter((method) => !method.flags.isPrivate); -} - -/** - * 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.`); - } - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return signatures.at(-1)!; -} - -/** - * Selects the method signatures from the module that needs to be documented. - * Method-Name -> Method-Signature - * - * @param module The module to extract the method signatures from. - * - * @returns The method signatures to document. - */ -export function selectApiMethodSignatures( - module: DeclarationReflection -): Record<string, SignatureReflection> { - 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[0].toLowerCase() + moduleName.substring(1); -} - -export const MISSING_DESCRIPTION = 'Missing'; - -export function toBlock(comment?: Comment): string { - return joinTagParts(comment?.summary) || MISSING_DESCRIPTION; -} - -export function extractDescription(reflection: Reflection): string { - return toBlock(reflection.comment); -} - -/** - * Extracts the source url from the jsdocs. - * - * @param reflection The reflection instance to extract the source url from. - */ -function extractSourceUrl( - reflection: DeclarationReflection | SignatureReflection -): string { - const source = reflection.sources?.[0]; - return source?.url ?? ''; -} - -/** - * Extracts the source base url from the jsdocs. - * - * @param reflection The reflection instance to extract the source base url from. - */ -export function extractSourceBaseUrl( - reflection: DeclarationReflection | SignatureReflection -): string { - return extractSourceUrl(reflection).replace( - /^(.*\/blob\/[0-9a-f]+\/)(.*)$/, - '$1' - ); -} - -/** - * Extracts the relative source path from the jsdocs. - * - * @param reflection The reflection instance to extract the source path from. - */ -export function extractSourcePath( - reflection: DeclarationReflection | SignatureReflection -): string { - return extractSourceUrl(reflection).replace( - /^(.*\/blob\/[0-9a-f]+\/)(.*)$/, - '$2' - ); -} - -/** - * Extracts the text (md) from a 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. - */ -export function extractTagContent( - tag: `@${string}`, - reflection?: CommentHolder, - tagProcessor: (tag: CommentTag) => string[] = joinTagContent -): string[] { - 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}.`); -} - -/** - * Extracts the raw code from the jsdocs without the surrounding md code block. - * - * @param tag The tag to extract the code from. - * @param reflection The reflection to extract the code from. - */ -function extractRawCode( - tag: `@${string}`, - reflection?: CommentHolder -): string[] { - return extractTagContent(tag, reflection).map((tag) => - tag.replace(/^```ts\n/, '').replace(/\n```$/, '') - ); -} - -/** - * Extracts the default from the jsdocs without the surrounding md code block. - * - * @param reflection The reflection to extract the examples from. - */ -export function extractRawDefault(reflection?: CommentHolder): string { - return extractRawCode('@default', reflection)[0] ?? ''; -} - -/** - * Extracts and optionally removes the default from the comment summary. - * - * @param comment The comment to extract the default from. - * @param eraseDefault Whether to erase the default text from the comment. - * - * @returns The extracted default value. - */ -export function extractSummaryDefault( - comment?: Comment, - eraseDefault = true -): string | undefined { - if (!comment) { - return; - } - - const summary = comment.summary; - const text = joinTagParts(summary).trim(); - if (!text) { - return; - } - - const result = /^(.*)[ \n]Defaults to `([^`]+)`\.(.*)$/s.exec(text); - if (!result) { - return; - } - - if (result[3].trim()) { - throw new Error(`Found description text after the default value:\n${text}`); - } - - if (eraseDefault) { - summary.splice(-2, 2); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const lastSummaryPart = summary.at(-1)!; - lastSummaryPart.text = lastSummaryPart.text.replace( - /[ \n]Defaults to $/, - '' - ); - } - - return result[2]; -} - -/** - * Extracts the examples from the jsdocs without the surrounding md code block. - * - * @param reflection The reflection to extract the examples from. - */ -function extractRawExamples(reflection?: CommentHolder): string[] { - return extractRawCode('@example', reflection); -} - -/** - * Extracts the examples from the jsdocs without the surrounding md code block, then joins them with newlines and trims. - * - * @param reflection The reflection to extract the examples from. - */ -export function extractJoinedRawExamples( - reflection?: CommentHolder -): string | undefined { - const examples = extractRawExamples(reflection); - return examples.length === 0 ? undefined : examples.join('\n').trim(); -} - -/** - * Extracts all the `@see` references from the jsdocs separately. - * - * @param reflection The reflection to extract the see also references from. - */ -export function extractSeeAlsos(reflection?: CommentHolder): string[] { - return extractTagContent('@see', reflection, (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).trimStart(); - } - - return link; - }) - .filter((link) => link.length > 0) - ); -} - -/** - * Joins the parts of the given jsdocs tag. - * - * @param tag The tag to join the parts of. - */ -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 reflection is deprecated. - * - * @param reflection The reflection to check. - * - * @returns The message explaining the deprecation if deprecated, otherwise `undefined`. - */ -export function extractDeprecated( - reflection?: CommentHolder -): string | undefined { - return extractSingleTagContent('@deprecated', reflection); -} - -/** - * Extracts the "throws" tag from the provided signature. - * - * @param reflection The reflection to check. - * - * @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 content = extractTagContent('@throws', reflection).join('\n'); - return content.length === 0 ? undefined : content; -} - -/** - * Extracts the "since" tag from the provided signature. - * - * @param reflection The signature to check. - * - * @returns The contents of the `@since` tag. - */ -export function extractSince(reflection: CommentHolder): string { - return extractSingleTagContent('@since', reflection) || MISSING_DESCRIPTION; -} diff --git a/scripts/apidoc/utils.ts b/scripts/apidoc/utils.ts deleted file mode 100644 index b23f3568..00000000 --- a/scripts/apidoc/utils.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { createHash } from 'node:crypto'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import type { Method } from '../../docs/.vitepress/components/api-docs/method'; - -// Types - -export type Page = { text: string; link: string; category: string }; - -export type ModuleSummary = Page & { - methods: Method[]; - diff: DocsApiDiff; -}; - -export interface DocsApiDiffIndex { - /** - * The methods in the module by name. - */ - [module: string]: DocsApiDiff; -} - -export interface DocsApiDiff { - /** - * The checksum of the entire module. - */ - moduleHash: string; - /** - * The checksum of the method by name. - */ - [method: string]: string; -} - -// Paths - -const pathRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..'); -export const pathDocsDir = resolve(pathRoot, 'docs'); -const pathPublicDir = resolve(pathDocsDir, 'public'); -export const nameDocsDiffIndexFile = 'api-diff-index.json'; -export const pathDocsDiffIndexFile = resolve( - pathPublicDir, - nameDocsDiffIndexFile -); -export const pathOutputDir = resolve(pathDocsDir, 'api'); - -// Functions - -export function adjustUrls(description: string): string { - return description.replaceAll(/https:\/\/(next.)?fakerjs.dev\//g, '/'); -} - -export function mapByName<TInput extends { name: string }, TValue>( - input: TInput[], - valueExtractor: (item: TInput) => TValue -): Record<string, TValue> { - return Object.fromEntries( - input.map((item) => [item.name, valueExtractor(item)]) - ); -} - -/** - * Creates a diff hash for the given method by removing the line number from the source path. - * - * @param method The method to create a hash for. - */ -export function methodDiffHash(method: Method): string { - return diffHash({ - ...method, - sourcePath: method.sourcePath.replaceAll(/#.*/g, ''), - }); -} - -/** - * Creates a diff hash for the given object. - * - * @param object The object to create a hash for. - */ -export function diffHash(object: unknown): string { - return createHash('md5').update(JSON.stringify(object)).digest('hex'); -} diff --git a/scripts/apidoc/writer.ts b/scripts/apidoc/writer.ts deleted file mode 100644 index b03cfe85..00000000 --- a/scripts/apidoc/writer.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { writeFileSync } from 'node:fs'; -import { resolve } from 'node:path'; -import type { ProjectReflection } from 'typedoc'; -import { ReflectionKind } from 'typedoc'; -import type { DefaultTheme } from 'vitepress'; -import type { Method } from '../../docs/.vitepress/components/api-docs/method'; -import type { APIGroup } from '../../docs/api/api-types'; -import { groupBy } from '../../src/internal/group-by'; -import { formatMarkdown, formatTypescript } from './format'; -import { extractSourceBaseUrl } from './typedoc'; -import type { DocsApiDiffIndex, ModuleSummary, Page } from './utils'; -import { - diffHash, - methodDiffHash, - pathDocsDiffIndexFile, - pathDocsDir, - pathOutputDir, -} from './utils'; - -const pathDocsApiPages = resolve(pathDocsDir, '.vitepress', 'api-pages.ts'); -const pathDocsApiSearchIndex = resolve( - pathDocsDir, - 'api', - 'api-search-index.json' -); - -const scriptCommand = 'pnpm run generate:api-docs'; - -// Moved here because this must not be formatted by prettier -const vitePressInFileOptions = `--- -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 examples The example code. - * @param deprecated The deprecation message. - * @param methods The methods of the module. - * @param category The category of the module. - */ -export async function writeApiDocsModule( - moduleName: string, - lowerModuleName: string, - comment: string, - examples: string | undefined, - deprecated: string | undefined, - methods: Method[], - category: string -): Promise<ModuleSummary> { - await writeApiDocsModulePage( - moduleName, - lowerModuleName, - comment, - examples, - deprecated, - methods - ); - writeApiDocsModuleData(lowerModuleName, methods); - - return { - text: moduleName, - link: `/api/${lowerModuleName}.html`, - methods, - category, - diff: { - moduleHash: diffHash({ - name: moduleName, - field: lowerModuleName, - deprecated, - comment, - }), - ...Object.fromEntries( - methods.map((method) => [method.name, methodDiffHash(method)]) - ), - }, - }; -} - -/** - * Writes the api page for the given module to the correct location. - * - * @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 examples The example code. - * @param deprecated The deprecation message. - * @param methods The methods of the module. - */ -async function writeApiDocsModulePage( - moduleName: string, - lowerModuleName: string, - comment: string, - examples: string | undefined, - deprecated: string | undefined, - methods: Method[] -): Promise<void> { - // Write api docs page - let content = ` - <script setup> - import ApiDocsMethod from '../.vitepress/components/api-docs/method.vue'; - import ${lowerModuleName} from './${lowerModuleName}.json'; - </script> - - <!-- This file is automatically generated. --> - <!-- Run '${scriptCommand}' to update --> - - # ${moduleName} - - ::: v-pre - - ${ - deprecated == null - ? '' - : `<div class="warning custom-block"> - <p class="custom-block-title">Deprecated</p> - <p>This module is deprecated and will be removed in a future version.</p> - <span>${deprecated}</span> - </div>` - } - - ${comment} - - ${examples == null ? '' : `<div class="examples">${examples}</div>`} - - ::: - - ${methods - .map( - (method) => ` - ## ${method.name} - - <ApiDocsMethod :method="${lowerModuleName}.${method.name}" v-once /> - ` - ) - .join('')} - `.replaceAll(/\n +/g, '\n'); - - content = vitePressInFileOptions + (await formatMarkdown(content)); - - writeFileSync(resolve(pathOutputDir, `${lowerModuleName}.md`), content); -} - -/** - * Writes the api docs data to correct location. - * - * @param lowerModuleName The lowercase name of the module. - * @param methods The methods data to save. - */ -function writeApiDocsModuleData( - lowerModuleName: string, - methods: Method[] -): void { - const content = JSON.stringify( - Object.fromEntries(methods.map((method) => [method.name, method])) - ); - - writeFileSync(resolve(pathOutputDir, `${lowerModuleName}.json`), content); -} - -/** - * Writes the api docs index to correct location. - * - * @param pages The pages to write into the index. - */ -export async function writeApiPagesIndex(pages: Page[]): Promise<void> { - const pagesByCategory: Record<string, DefaultTheme.SidebarItem[]> = groupBy( - pages, - (page) => page.category, - ({ text, link }) => ({ text, link }) - ); - const pageTree = Object.entries(pagesByCategory).flatMap( - ([category, items]) => (category ? [{ text: category, items }] : items) - ); - - // Write api-pages.ts - console.log('Updating api-pages.ts'); - pageTree.splice(0, 0, { text: 'Overview', link: '/api/' }); - let apiPagesContent = ` - // This file is automatically generated. - // Run '${scriptCommand}' to update - export const apiPages = ${JSON.stringify(pageTree)}; - `.replace(/\n +/, '\n'); - - apiPagesContent = await formatTypescript(apiPagesContent); - - writeFileSync(pathDocsApiPages, apiPagesContent); -} - -/** - * Writes the api diff index to the correct location. - * - * @param diffIndex The diff index project to write. - */ -export function writeApiDiffIndex(diffIndex: DocsApiDiffIndex): void { - writeFileSync(pathDocsDiffIndexFile, JSON.stringify(diffIndex)); -} - -/** - * Writes the api search index to the correct location. - * - * @param pages The pages to write into the index. - */ -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, - deprecated: !!method.deprecated, - })), - })), - }, - ]; - - writeFileSync(pathDocsApiSearchIndex, JSON.stringify(apiIndex)); -} - -/** - * Writes the source base url to the correct location. - * - * @param project The typedoc project. - */ -export async function writeSourceBaseUrl( - project: ProjectReflection -): Promise<void> { - const baseUrl = extractSourceBaseUrl( - project.getChildrenByKind(ReflectionKind.Class)[0] - ); - - let content = ` - // This file is automatically generated. - // Run '${scriptCommand}' to update - export const sourceBaseUrl = '${baseUrl}'; - `.replace(/\n +/, '\n'); - - content = await formatTypescript(content); - - writeFileSync(resolve(pathOutputDir, 'source-base-url.ts'), content); -} |
