aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2022-03-23 14:41:33 +0100
committerGitHub <[email protected]>2022-03-23 13:41:33 +0000
commit1b08de821588a1d5a2436c177c20d60a66e8a977 (patch)
tree3c6f2d1696e7001e142515332b6f245cad1ec637 /scripts
parente6438353dbcb89055ef4ddb5c7cc8318d3f7a0f1 (diff)
downloadfaker-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.ts15
-rw-r--r--scripts/apidoc/parameterDefaults.ts130
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)
+ );
+}