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/apidocs/processing/parameter.ts | |
| parent | 7dae52bfcd93c41ec9d2c4dd4d96a07f31c3dfc1 (diff) | |
| download | faker-6191a5d883048b694404dbf42527caba395828ea.tar.xz faker-6191a5d883048b694404dbf42527caba395828ea.zip | |
docs: rewrite api-docs generation using ts-morph (#2628)
Diffstat (limited to 'scripts/apidocs/processing/parameter.ts')
| -rw-r--r-- | scripts/apidocs/processing/parameter.ts | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/scripts/apidocs/processing/parameter.ts b/scripts/apidocs/processing/parameter.ts new file mode 100644 index 00000000..7a6b67da --- /dev/null +++ b/scripts/apidocs/processing/parameter.ts @@ -0,0 +1,203 @@ +import type { + PropertySignature, + Type, + TypeParameterDeclaration, +} from 'ts-morph'; +import { type JSDoc, type JSDocTag, type ParameterDeclaration } from 'ts-morph'; +import { exactlyOne, valueForKey } from '../utils/value-checks'; +import { newProcessingError } from './error'; +import { + getDefault, + getDeprecated, + getDescription, + getJsDocs, + getParameterTags, + getTypeParameterTags, +} from './jsdocs'; +import type { RawApiDocsType } from './type'; +import { getNameSuffix, getTypeText, isOptionsLikeType } from './type'; + +/** + * Represents a parameter in the raw API docs. + */ +export interface RawApiDocsParameter { + /** + * The name of the parameter. + */ + name: string; + /** + * The type of the parameter. + */ + type: RawApiDocsType; + /** + * The default value or expression of the parameter, if it has one. + */ + default: string | undefined; + /** + * The description of the parameter. + */ + description: string; +} + +export function processTypeParameters( + parameters: TypeParameterDeclaration[], + jsdocs: JSDoc +): RawApiDocsParameter[] { + const paramTags = getTypeParameterTags(jsdocs); + + return parameters.flatMap((parameter) => { + try { + return processTypeParameterEntry(parameter, paramTags); + } catch (error) { + throw newProcessingError({ + type: 'type parameter', + name: parameter.getName(), + source: parameter, + cause: error, + }); + } + }); +} + +function processTypeParameterEntry( + parameter: TypeParameterDeclaration, + paramTags: Record<string, JSDocTag> +): RawApiDocsParameter { + return { + name: `<${parameter.getName()}>`, + type: getTypeText(parameter.getType(), { resolveAliases: true }), + default: parameter.getDefault()?.getText(), + description: getDescription(valueForKey(paramTags, parameter.getName())), + }; +} + +export function processParameters( + signatureParameters: ParameterDeclaration[], + implParameters: ParameterDeclaration[], + jsdocs: JSDoc +): RawApiDocsParameter[] { + const paramTags = getParameterTags(jsdocs); + const implParameterDefaults = Object.fromEntries( + implParameters.map((parameter) => [ + parameter.getName(), + getDefaultValue(parameter), + ]) + ); + + return signatureParameters.flatMap((parameter) => { + try { + return processParameter( + parameter, + paramTags, + implParameterDefaults[parameter.getName()] + ); + } catch (error) { + throw newProcessingError({ + type: 'parameter', + name: parameter.getName(), + source: parameter, + cause: error, + }); + } + }); +} + +function processParameter( + parameter: ParameterDeclaration, + paramTags: Record<string, JSDocTag>, + implementationDefault: string | undefined +): RawApiDocsParameter[] { + const name = parameter.getName(); + return [ + processSimpleParameter( + parameter, + valueForKey(paramTags, name), + implementationDefault + ), + ...processComplexParameter(name, parameter.getType()), + ]; +} + +type ParameterLikeDeclaration = Pick< + ParameterDeclaration, + 'getName' | 'getType' +> & + Partial<Pick<ParameterDeclaration, 'getInitializer'>>; + +function processSimpleParameter( + parameter: ParameterLikeDeclaration, + jsdocTag: JSDocTag, + implementationDefault: string | undefined +): RawApiDocsParameter { + const name = parameter.getName(); + const type = parameter.getType(); + return { + name: `${name}${getNameSuffix(type)}`, + type: getTypeText(type, { + abbreviate: true, + stripUndefined: true, + }), + default: getDefaultValue(parameter) ?? implementationDefault, + description: getDescription(jsdocTag), + }; +} + +function getDefaultValue( + parameter: ParameterLikeDeclaration +): string | undefined { + return parameter + .getInitializer?.() + ?.getText() + .replace(/ as .+$/, ''); +} + +function processComplexParameter( + name: string, + type: Type +): RawApiDocsParameter[] { + if (type.isNullable()) { + return processComplexParameter(name, type.getNonNullableType()); + } else if (type.isUnion()) { + return type + .getUnionTypes() + .flatMap((unionType) => processComplexParameter(name, unionType)); + } else if (type.isArray()) { + return processComplexParameter( + `${name}[]`, + type.getArrayElementTypeOrThrow() + ); + } else if (type.isObject()) { + if (!isOptionsLikeType(type)) { + return []; + } + + return type + .getApparentProperties() + .flatMap((parameter) => { + const declaration = exactlyOne( + parameter.getDeclarations(), + 'property declaration' + ) as PropertySignature; + const propertyType = declaration.getType(); + const jsdocs = getJsDocs(declaration); + const deprecated = getDeprecated(jsdocs); + + return [ + { + name: `${name}.${parameter.getName()}${getNameSuffix(propertyType)}`, + type: getTypeText(propertyType, { + abbreviate: false, + stripUndefined: true, + }), + default: getDefault(jsdocs), + description: + getDescription(jsdocs) + + (deprecated ? `\n\n**DEPRECATED:** ${deprecated}` : ''), + }, + ]; + }) + .sort((a, b) => a.name.localeCompare(b.name)); + } + + return []; +} |
