diff options
| author | ST-DDT <[email protected]> | 2022-03-23 14:41:33 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-03-23 13:41:33 +0000 |
| commit | 1b08de821588a1d5a2436c177c20d60a66e8a977 (patch) | |
| tree | 3c6f2d1696e7001e142515332b6f245cad1ec637 /scripts | |
| parent | e6438353dbcb89055ef4ddb5c7cc8318d3f7a0f1 (diff) | |
| download | faker-1b08de821588a1d5a2436c177c20d60a66e8a977.tar.xz faker-1b08de821588a1d5a2436c177c20d60a66e8a977.zip | |
docs: read (complex) defaults from implementation signature (#656)
Co-authored-by: Shinigami <[email protected]>
Co-authored-by: Daniel Bannert <[email protected]>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/apidoc.ts | 15 | ||||
| -rw-r--r-- | scripts/apidoc/parameterDefaults.ts | 130 |
2 files changed, 145 insertions, 0 deletions
diff --git a/scripts/apidoc.ts b/scripts/apidoc.ts index cb4ed2a4..4ac4fbf9 100644 --- a/scripts/apidoc.ts +++ b/scripts/apidoc.ts @@ -3,6 +3,11 @@ import * as TypeDoc from 'typedoc'; import { writeApiPagesIndex } from './apidoc/apiDocsWriter'; import { processDirectMethods } from './apidoc/directMethods'; import { processModuleMethods } from './apidoc/moduleMethods'; +import { + DefaultParameterAwareSerializer, + parameterDefaultReader, + patchProjectParameterDefaults, +} from './apidoc/parameterDefaults'; import type { PageIndex } from './apidoc/utils'; import { pathOutputDir } from './apidoc/utils'; @@ -15,6 +20,14 @@ async function build(): Promise<void> { // 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 + ); + // Add to debug json output + app.serializer.addSerializer(new DefaultParameterAwareSerializer(undefined)); + app.bootstrap({ entryPoints: ['src/index.ts'], pretty: true, @@ -31,6 +44,8 @@ async function build(): Promise<void> { await app.generateJson(project, pathOutputJson); console.log(pathOutputDir); + patchProjectParameterDefaults(project); + const modulesPages: PageIndex = []; modulesPages.push({ text: 'Localization', link: '/api/localization.html' }); modulesPages.push(...processModuleMethods(project)); diff --git a/scripts/apidoc/parameterDefaults.ts b/scripts/apidoc/parameterDefaults.ts new file mode 100644 index 00000000..9342d7b2 --- /dev/null +++ b/scripts/apidoc/parameterDefaults.ts @@ -0,0 +1,130 @@ +import type { + Context, + DeclarationReflection, + EventCallback, + JSONOutput, + ProjectReflection, + SignatureReflection, +} from 'typedoc'; +import { + Reflection, + ReflectionKind, + SerializerComponent, + TypeScript, +} from 'typedoc'; + +const reflectionKindFunctionOrMethod = + ReflectionKind.Function | ReflectionKind.Method; + +interface ParameterDefaultsAware extends Reflection { + implementationDefaultParameters: string[]; +} + +/** + * TypeDoc EventCallback for EVENT_CREATE_DECLARATION events that reads the default parameters from the implementation. + */ +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[symbol.declarations.length - 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 { + 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 extends SerializerComponent<Reflection> { + serializeGroup(instance: unknown): boolean { + return instance instanceof Reflection; + } + + supports(item: unknown): boolean { + return true; + } + + toObject(item: Reflection, obj?: object): Partial<JSONOutput.Reflection> { + (obj 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 (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: string[] +): void { + const signatureParameters = signature.parameters; + if (signatureParameters.length !== parameterDefaults.length) { + throw new Error('Unexpected parameter length mismatch'); + } + signatureParameters.forEach( + (param, index) => + (param.defaultValue = parameterDefaults[index] || param.defaultValue) + ); +} |
