aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2023-01-23 18:47:09 +0100
committerGitHub <[email protected]>2023-01-23 17:47:09 +0000
commit23aa08800ac66a5b16e405d04d07ea538d16dd6b (patch)
treed031ddeff74354b9064b4b32ceb5f5e2bf5f0ac4
parent826cb0b2db247fde4d0ee93933dfecd4f3a656dd (diff)
downloadfaker-23aa08800ac66a5b16e405d04d07ea538d16dd6b.tar.xz
faker-23aa08800ac66a5b16e405d04d07ea538d16dd6b.zip
refactor: reorganize apidoc scripts and reuse them for tests (#1759)
-rw-r--r--scripts/apidoc.ts3
-rw-r--r--scripts/apidoc/apiDocsWriter.ts40
-rw-r--r--scripts/apidoc/format.ts31
-rw-r--r--scripts/apidoc/moduleMethods.ts47
-rw-r--r--scripts/apidoc/signature.ts6
-rw-r--r--scripts/apidoc/typedoc.ts210
-rw-r--r--scripts/apidoc/utils.ts165
-rw-r--r--test/scripts/apidoc/examplesAndDeprecations.spec.ts146
-rw-r--r--test/scripts/apidoc/signature.debug.ts2
-rw-r--r--test/scripts/apidoc/signature.spec.ts8
-rw-r--r--test/scripts/apidoc/utils.ts58
11 files changed, 379 insertions, 337 deletions
diff --git a/scripts/apidoc.ts b/scripts/apidoc.ts
index 921859e7..3e11572e 100644
--- a/scripts/apidoc.ts
+++ b/scripts/apidoc.ts
@@ -5,8 +5,9 @@ import {
} from './apidoc/apiDocsWriter';
import { processModuleMethods } from './apidoc/moduleMethods';
import { initMarkdownRenderer } from './apidoc/signature';
+import { newTypeDocApp, patchProject } from './apidoc/typedoc';
import type { PageIndex } from './apidoc/utils';
-import { newTypeDocApp, patchProject, pathOutputDir } from './apidoc/utils';
+import { pathOutputDir } from './apidoc/utils';
const pathOutputJson = resolve(pathOutputDir, 'typedoc.json');
diff --git a/scripts/apidoc/apiDocsWriter.ts b/scripts/apidoc/apiDocsWriter.ts
index cd8dd2e5..f18b7cd9 100644
--- a/scripts/apidoc/apiDocsWriter.ts
+++ b/scripts/apidoc/apiDocsWriter.ts
@@ -1,17 +1,16 @@
import { writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import type { ProjectReflection } from 'typedoc';
-import { ReflectionKind } from 'typedoc';
import type { Method } from '../../docs/.vitepress/components/api-docs/method';
import type { APIGroup, APIItem } from '../../docs/api/api-types';
-import { extractModuleName, selectApiModules } from './moduleMethods';
-import type { PageIndex } from './utils';
+import { formatMarkdown, formatTypescript } from './format';
import {
- formatMarkdown,
- formatTypescript,
- pathDocsDir,
- pathOutputDir,
-} from './utils';
+ extractModuleName,
+ selectApiMethods,
+ selectApiModules,
+} from './typedoc';
+import type { PageIndex } from './utils';
+import { pathDocsDir, pathOutputDir } from './utils';
const pathDocsApiPages = resolve(pathDocsDir, '.vitepress', 'api-pages.ts');
const pathDocsApiSearchIndex = resolve(
@@ -139,28 +138,11 @@ export function writeApiSearchIndex(project: ProjectReflection): void {
const apiSection: APIItem = {
text: moduleName,
link: moduleName.toLowerCase(),
- headers: [],
+ headers: selectApiMethods(module).map((child) => ({
+ anchor: child.name,
+ text: child.name,
+ })),
};
- if (module.kind !== ReflectionKind.Property) {
- apiSection.headers = module
- .getChildrenByKind(ReflectionKind.Method)
- .map((child) => ({
- anchor: child.name,
- text: child.name,
- }));
- } else {
- // TODO @Shinigami92 2022-08-17: Extract capitalization into own function
- apiSection.text =
- apiSection.text.substring(0, 1).toUpperCase() +
- apiSection.text.substring(1);
-
- apiSection.headers = [
- {
- anchor: module.name,
- text: module.name,
- },
- ];
- }
return apiSection;
})
diff --git a/scripts/apidoc/format.ts b/scripts/apidoc/format.ts
new file mode 100644
index 00000000..0a502c5f
--- /dev/null
+++ b/scripts/apidoc/format.ts
@@ -0,0 +1,31 @@
+import type { Options } from 'prettier';
+import { format } from 'prettier';
+import prettierConfig from '../../.prettierrc.cjs';
+
+/**
+ * Formats markdown contents.
+ *
+ * @param text The text to format.
+ */
+export function formatMarkdown(text: string): string {
+ return format(text, prettierMarkdown);
+}
+
+/**
+ * Formats typedoc contents.
+ *
+ * @param text The text to format.
+ */
+export function formatTypescript(text: string): string {
+ return format(text, prettierTypescript);
+}
+
+const prettierMarkdown: Options = {
+ ...prettierConfig,
+ parser: 'markdown',
+};
+
+const prettierTypescript: Options = {
+ ...prettierConfig,
+ parser: 'typescript',
+};
diff --git a/scripts/apidoc/moduleMethods.ts b/scripts/apidoc/moduleMethods.ts
index dd4f528a..b52d4780 100644
--- a/scripts/apidoc/moduleMethods.ts
+++ b/scripts/apidoc/moduleMethods.ts
@@ -1,26 +1,16 @@
import type { DeclarationReflection, ProjectReflection } from 'typedoc';
-import { ReflectionKind } from 'typedoc';
import type { Method } from '../../docs/.vitepress/components/api-docs/method';
-import { faker } from '../../src';
import { writeApiDocsData, writeApiDocsModulePage } from './apiDocsWriter';
import { analyzeSignature, toBlock } from './signature';
+import {
+ extractModuleFieldName,
+ extractModuleName,
+ selectApiMethodSignatures,
+ selectApiModules,
+} from './typedoc';
import type { PageIndex } from './utils';
/**
- * Selects the modules from the project that needs to be documented.
- *
- * @param project The project used to extract the modules.
- * @returns The modules to document.
- */
-export function selectApiModules(
- project: ProjectReflection
-): DeclarationReflection[] {
- return project
- .getChildrenByKind(ReflectionKind.Class)
- .filter((module) => faker[extractModuleFieldName(module)] != null);
-}
-
-/**
* Analyzes and writes the documentation for modules and their methods such as `faker.animal.cat()`.
*
* @param project The project used to extract the modules.
@@ -37,24 +27,6 @@ export function processModuleMethods(project: ProjectReflection): PageIndex {
return pages;
}
-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$/, '');
-}
-
-function extractModuleFieldName(module: DeclarationReflection): string {
- const moduleName = extractModuleName(module);
- return moduleName.substring(0, 1).toLowerCase() + moduleName.substring(1);
-}
-
/**
* Analyzes and writes the documentation for a module and its methods such as `faker.animal.cat()`.
*
@@ -69,11 +41,10 @@ function processModuleMethod(module: DeclarationReflection): PageIndex {
const methods: Method[] = [];
// Generate method section
- for (const method of module.getChildrenByKind(ReflectionKind.Method)) {
- const methodName = method.name;
+ for (const [methodName, signature] of Object.entries(
+ selectApiMethodSignatures(module)
+ )) {
console.debug(`- ${methodName}`);
- const signatures = method.signatures;
- const signature = signatures[signatures.length - 1];
methods.push(analyzeSignature(signature, moduleFieldName, methodName));
}
diff --git a/scripts/apidoc/signature.ts b/scripts/apidoc/signature.ts
index f2a4bd85..d34abf18 100644
--- a/scripts/apidoc/signature.ts
+++ b/scripts/apidoc/signature.ts
@@ -18,15 +18,15 @@ import type {
} from '../../docs/.vitepress/components/api-docs/method';
import vitepressConfig from '../../docs/.vitepress/config';
import { faker } from '../../src';
+import { formatTypescript } from './format';
import {
extractRawExamples,
extractSeeAlsos,
extractSince,
- formatTypescript,
isDeprecated,
joinTagParts,
- pathOutputDir,
-} from './utils';
+} from './typedoc';
+import { pathOutputDir } from './utils';
export function prettifyMethodName(method: string): string {
return (
diff --git a/scripts/apidoc/typedoc.ts b/scripts/apidoc/typedoc.ts
new file mode 100644
index 00000000..d9b34a0b
--- /dev/null
+++ b/scripts/apidoc/typedoc.ts
@@ -0,0 +1,210 @@
+import type {
+ CommentDisplayPart,
+ CommentTag,
+ DeclarationReflection,
+ ProjectReflection,
+ SignatureReflection,
+} from 'typedoc';
+import {
+ Application,
+ Converter,
+ ReflectionKind,
+ TSConfigReader,
+} from 'typedoc';
+import { faker } from '../../src';
+import {
+ DefaultParameterAwareSerializer,
+ parameterDefaultReader,
+ patchProjectParameterDefaults,
+} from './parameterDefaults';
+import { mapByName } from './utils';
+
+/**
+ * Creates and configures a new typedoc application.
+ */
+export function newTypeDocApp(): Application {
+ const app = new Application();
+
+ app.options.addReader(new TSConfigReader());
+ // If you want TypeDoc to load typedoc.json files
+ //app.options.addReader(new TypeDoc.TypeDocReader());
+
+ // Read parameter defaults
+ app.converter.on(Converter.EVENT_CREATE_DECLARATION, parameterDefaultReader);
+ // Add to debug json output
+ app.serializer.addSerializer(new DefaultParameterAwareSerializer());
+
+ return app;
+}
+
+/**
+ * Apply our patches to the generated typedoc data.
+ *
+ * This is moved to a separate method to allow printing/saving the original content before patching it.
+ *
+ * @param project The project to patch.
+ */
+export function patchProject(project: ProjectReflection): void {
+ patchProjectParameterDefaults(project);
+}
+
+/**
+ * Selects the modules from the project that needs to be documented.
+ *
+ * @param project The project to extract the modules from.
+ * @returns The modules to document.
+ */
+export function selectApiModules(
+ project: ProjectReflection,
+ includeTestModules = false
+): DeclarationReflection[] {
+ return project
+ .getChildrenByKind(ReflectionKind.Class)
+ .filter(
+ (module) =>
+ faker[extractModuleFieldName(module)] != 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);
+}
+
+/**
+ * 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.`);
+ }
+
+ return signatures[signatures.length - 1];
+}
+
+/**
+ * Selects the method signatures from the module that needs to be documented.
+ * Method-Name -> Method-Signature
+ *
+ * @param method 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.substring(0, 1).toLowerCase() + moduleName.substring(1);
+}
+
+/**
+ * Extracts the text (md) from a jsdoc tag.
+ *
+ * @param tag The tag to extract the text from.
+ * @param signature The signature to extract the text from.
+ */
+export function extractTagContent(
+ tag: `@${string}`,
+ signature?: SignatureReflection,
+ tagProcessor: (tag: CommentTag) => string[] = joinTagContent
+): string[] {
+ return signature?.comment?.getTags(tag).flatMap(tagProcessor) ?? [];
+}
+
+/**
+ * Extracts the examples from the jsdocs without the surrounding md code block.
+ *
+ * @param signature The signature to extract the examples from.
+ */
+export function extractRawExamples(signature?: SignatureReflection): string[] {
+ return extractTagContent('@example', signature).map((tag) =>
+ tag.replace(/^```ts\n/, '').replace(/\n```$/, '')
+ );
+}
+
+/**
+ * Extracts all the `@see` references from the jsdocs separately.
+ *
+ * @param signature The signature to extract the see also references from.
+ */
+export function extractSeeAlsos(signature?: SignatureReflection): string[] {
+ return extractTagContent('@see', signature, (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).trim();
+ }
+
+ return link;
+ })
+ .filter((link) => link)
+ );
+}
+
+/**
+ * Joins the parts of the given jsdocs tag.
+ */
+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 signature is deprecated.
+ *
+ * @param signature The signature to check.
+ *
+ * @returns `true` if it is deprecated, otherwise `false`.
+ */
+export function isDeprecated(signature: SignatureReflection): boolean {
+ return extractTagContent('@deprecated', signature).length > 0;
+}
+
+/**
+ * Extracts the "since" tag from the provided signature.
+ *
+ * @param signature The signature to check.
+ *
+ * @returns the contents of the @since tag
+ */
+export function extractSince(signature: SignatureReflection): string {
+ return extractTagContent('@since', signature).join().trim();
+}
diff --git a/scripts/apidoc/utils.ts b/scripts/apidoc/utils.ts
index 9dad1b14..7939adb1 100644
--- a/scripts/apidoc/utils.ts
+++ b/scripts/apidoc/utils.ts
@@ -1,165 +1,24 @@
import { resolve } from 'node:path';
-import type { Options } from 'prettier';
-import { format } from 'prettier';
-import type {
- CommentDisplayPart,
- CommentTag,
- SignatureReflection,
-} from 'typedoc';
-import * as TypeDoc from 'typedoc';
-import prettierConfig from '../../.prettierrc.cjs';
-import {
- DefaultParameterAwareSerializer,
- parameterDefaultReader,
- patchProjectParameterDefaults,
-} from './parameterDefaults';
+
+// Types
export type Page = { text: string; link: string };
export type PageIndex = Array<Page>;
+// Paths
+
const pathRoot = resolve(__dirname, '..', '..');
export const pathDocsDir = resolve(pathRoot, 'docs');
export const pathOutputDir = resolve(pathDocsDir, 'api');
-/**
- * Creates and configures a new typedoc application.
- */
-export function newTypeDocApp(): TypeDoc.Application {
- const app = new TypeDoc.Application();
+// Functions
- app.options.addReader(new TypeDoc.TSConfigReader());
- // 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
+export function mapByName<T extends { name: string }, V>(
+ input: Array<T>,
+ valueExtractor: (item: T) => V
+): Record<string, V> {
+ return input.reduce(
+ (acc, item) => ({ ...acc, [item.name]: valueExtractor(item) }),
+ {}
);
- // Add to debug json output
- app.serializer.addSerializer(new DefaultParameterAwareSerializer());
-
- return app;
-}
-
-/**
- * Apply our patches to the generated typedoc data.
- *
- * This is moved to a separate method to allow printing/saving the original content before patching it.
- *
- * @param project The project to patch.
- */
-export function patchProject(project: TypeDoc.ProjectReflection): void {
- patchProjectParameterDefaults(project);
-}
-
-/**
- * Formats markdown contents.
- *
- * @param text The text to format.
- */
-export function formatMarkdown(text: string): string {
- return format(text, prettierMarkdown);
-}
-
-/**
- * Formats typedoc contents.
- *
- * @param text The text to format.
- */
-export function formatTypescript(text: string): string {
- return format(text, prettierTypescript);
-}
-
-const prettierMarkdown: Options = {
- ...prettierConfig,
- parser: 'markdown',
-};
-
-const prettierTypescript: Options = {
- ...prettierConfig,
- parser: 'typescript',
-};
-
-/**
- * Extracts the text (md) from a jsdoc tag.
- *
- * @param tag The tag to extract the text from.
- * @param signature The signature to extract the text from.
- */
-export function extractTagContent(
- tag: `@${string}`,
- signature?: SignatureReflection,
- tagProcessor: (tag: CommentTag) => string[] = joinTagContent
-): string[] {
- return signature?.comment?.getTags(tag).flatMap(tagProcessor) ?? [];
-}
-
-/**
- * Extracts the examples from the jsdocs without the surrounding md code block.
- *
- * @param signature The signature to extract the examples from.
- */
-export function extractRawExamples(signature?: SignatureReflection): string[] {
- return extractTagContent('@example', signature).map((tag) =>
- tag.replace(/^```ts\n/, '').replace(/\n```$/, '')
- );
-}
-
-/**
- * Extracts all the `@see` references from the jsdocs separately.
- *
- * @param signature The signature to extract the see also references from.
- */
-export function extractSeeAlsos(signature?: SignatureReflection): string[] {
- return extractTagContent('@see', signature, (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).trim();
- }
-
- return link;
- })
- .filter((link) => link)
- );
-}
-
-/**
- * Joins the parts of the given jsdocs tag.
- */
-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 signature is deprecated.
- *
- * @param signature The signature to check.
- *
- * @returns `true` if it is deprecated, otherwise `false`.
- */
-export function isDeprecated(signature: SignatureReflection): boolean {
- return extractTagContent('@deprecated', signature).length > 0;
-}
-
-/**
- * Extracts the "since" tag from the provided signature.
- *
- * @param signature The signature to check.
- *
- * @returns the contents of the @since tag
- */
-export function extractSince(signature: SignatureReflection): string {
- return extractTagContent('@since', signature).join().trim();
}
diff --git a/test/scripts/apidoc/examplesAndDeprecations.spec.ts b/test/scripts/apidoc/examplesAndDeprecations.spec.ts
index df1769b4..ac73244c 100644
--- a/test/scripts/apidoc/examplesAndDeprecations.spec.ts
+++ b/test/scripts/apidoc/examplesAndDeprecations.spec.ts
@@ -1,7 +1,5 @@
import { mkdirSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
-import type { DeclarationReflection, SignatureReflection } from 'typedoc';
-import { ReflectionKind } from 'typedoc';
import type { SpyInstance } from 'vitest';
import {
afterAll,
@@ -12,7 +10,6 @@ import {
it,
vi,
} from 'vitest';
-import { selectApiModules } from '../../../scripts/apidoc/moduleMethods';
import {
analyzeSignature,
initMarkdownRenderer,
@@ -23,9 +20,9 @@ import {
extractSince,
extractTagContent,
isDeprecated,
-} from '../../../scripts/apidoc/utils';
+} from '../../../scripts/apidoc/typedoc';
import { faker } from '../../../src';
-import { loadProject } from './utils';
+import { loadProjectModules } from './utils';
/*
* This test ensures, that every method
@@ -42,17 +39,7 @@ const locales: Record<string, string> = {
beforeAll(initMarkdownRenderer);
describe('examples and deprecations', () => {
- const project = loadProject();
-
- const modules: Record<string, DeclarationReflection[]> = selectApiModules(
- project
- ).reduce(
- (a, v) => ({
- ...a,
- [v.name]: v.getChildrenByKind(ReflectionKind.Method),
- }),
- {}
- );
+ const modules = loadProjectModules();
const consoleSpies: Array<SpyInstance> = Object.keys(console)
.filter((key) => typeof console[key] === 'function')
@@ -65,12 +52,7 @@ describe('examples and deprecations', () => {
}
});
- describe.each(Object.entries(modules))('%s', (moduleName, methods) => {
- const methodsByName: Record<string, DeclarationReflection> = methods.reduce(
- (a, v) => ({ ...a, [v.name]: v }),
- {}
- );
-
+ describe.each(Object.entries(modules))('%s', (moduleName, methodsByName) => {
beforeEach(() => {
faker.locale = 'en';
for (const spy of consoleSpies) {
@@ -79,70 +61,74 @@ describe('examples and deprecations', () => {
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
- it.each(Object.entries(methodsByName))('%s', async (methodName, method) => {
- const signatures: SignatureReflection[] =
- method.signatures || method.type?.['declaration'].signatures;
- const signature = signatures[signatures.length - 1];
-
- // Extract examples and make them runnable
- let examples = extractRawExamples(signature).join('').trim() ?? '';
- examples = examples.replace(
- /faker([A-Z]{2})\./g,
- (_, locale: string) => `faker.locale = '${locales[locale]}';\nfaker.`
- );
-
- expect(examples, `${moduleName}.${methodName} to have examples`).not.toBe(
- ''
- );
-
- // Save examples to a file to run it
- const dir = resolve(__dirname, 'temp', moduleName);
- mkdirSync(dir, { recursive: true });
- const path = resolve(dir, `${methodName}.ts`);
- writeFileSync(
- path,
- `import { faker } from '../../../../../src';\n${examples}`
- );
-
- // Run the examples
- await import(path);
+ it.each(Object.entries(methodsByName))(
+ '%s',
+ async (methodName, signature) => {
+ // Extract examples and make them runnable
+ let examples = extractRawExamples(signature).join('').trim();
+ examples = examples.replace(
+ /faker([A-Z]{2})\./g,
+ (_, locale: string) => `faker.locale = '${locales[locale]}';\nfaker.`
+ );
- // Verify logging
- const deprecatedFlag = isDeprecated(signature);
- if (deprecatedFlag) {
- expect(consoleSpies[1]).toHaveBeenCalled();
expect(
- extractTagContent('@deprecated', signature).join(''),
- '@deprecated tag without message'
+ examples,
+ `${moduleName}.${methodName} to have examples`
).not.toBe('');
- } else {
- for (const spy of consoleSpies) {
- expect(spy).not.toHaveBeenCalled();
- }
- }
- // Verify @param tags
- analyzeSignature(signature, moduleName, methodName).parameters.forEach(
- (param) => {
- const { name, description } = param;
- const plainDescription = description.replace(/<[^>]+>/g, '').trim();
+ // Save examples to a file to run it
+ const dir = resolve(__dirname, 'temp', moduleName);
+ mkdirSync(dir, { recursive: true });
+ const path = resolve(dir, `${methodName}.ts`);
+ writeFileSync(
+ path,
+ `import { faker } from '../../../../../src';\n${examples}`
+ );
+
+ // Run the examples
+ await import(path);
+
+ // Verify logging
+ const deprecatedFlag = isDeprecated(signature);
+ if (deprecatedFlag) {
+ expect(consoleSpies[1]).toHaveBeenCalled();
expect(
- plainDescription,
- `Expect param ${name} to have a description`
- ).not.toBe('Missing');
- }
- );
-
- // Verify @see tag
- extractSeeAlsos(signature).forEach((link) => {
- if (link.startsWith('faker.')) {
- // Expected @see faker.xxx.yyy()
- expect(link, 'Expect method reference to contain ()').toContain('(');
- expect(link, 'Expect method reference to contain ()').toContain(')');
+ extractTagContent('@deprecated', signature).join(''),
+ '@deprecated tag without message'
+ ).not.toBe('');
+ } else {
+ for (const spy of consoleSpies) {
+ expect(spy).not.toHaveBeenCalled();
+ }
}
- });
- expect(extractSince(signature), '@since to be present').toBeTruthy();
- });
+ // Verify @param tags
+ analyzeSignature(signature, moduleName, methodName).parameters.forEach(
+ (param) => {
+ const { name, description } = param;
+ const plainDescription = description.replace(/<[^>]+>/g, '').trim();
+ expect(
+ plainDescription,
+ `Expect param ${name} to have a description`
+ ).not.toBe('Missing');
+ }
+ );
+
+ // Verify @see tag
+ extractSeeAlsos(signature).forEach((link) => {
+ if (link.startsWith('faker.')) {
+ // Expected @see faker.xxx.yyy()
+ expect(link, 'Expect method reference to contain ()').toContain(
+ '('
+ );
+ expect(link, 'Expect method reference to contain ()').toContain(
+ ')'
+ );
+ }
+ });
+
+ expect(extractSince(signature), '@since to be present').toBeTruthy();
+ }
+ );
});
});
diff --git a/test/scripts/apidoc/signature.debug.ts b/test/scripts/apidoc/signature.debug.ts
index f805ca54..6be0e49f 100644
--- a/test/scripts/apidoc/signature.debug.ts
+++ b/test/scripts/apidoc/signature.debug.ts
@@ -16,7 +16,7 @@ initMarkdownRenderer()
.then(() => {
Object.entries(methods).forEach(([name, method]) => {
console.log('Analyzing: ', name);
- const result = analyzeSignature(method.signatures[0], null, method.name);
+ const result = analyzeSignature(method, null, method.name);
console.log('Result: ', result);
});
})
diff --git a/test/scripts/apidoc/signature.spec.ts b/test/scripts/apidoc/signature.spec.ts
index 43ab00e7..d90370a2 100644
--- a/test/scripts/apidoc/signature.spec.ts
+++ b/test/scripts/apidoc/signature.spec.ts
@@ -19,13 +19,11 @@ describe('signature', () => {
});
it('expected and actual methods are equal', () => {
- expect(Object.keys(methods).sort()).toMatchSnapshot();
+ expect(Object.keys(methods)).toMatchSnapshot();
});
- it.each(Object.keys(methods).sort())('%s', (name) => {
- const method = methods[name];
- expect(method, `Method ${name} to be defined`).toBeDefined();
- const actual = analyzeSignature(method.signatures[0], null, method.name);
+ it.each(Object.entries(methods))('%s', (name, signature) => {
+ const actual = analyzeSignature(signature, null, name);
expect(actual).toMatchSnapshot();
});
diff --git a/test/scripts/apidoc/utils.ts b/test/scripts/apidoc/utils.ts
index 19c4b4ea..61f3b848 100644
--- a/test/scripts/apidoc/utils.ts
+++ b/test/scripts/apidoc/utils.ts
@@ -1,43 +1,47 @@
-import type { DeclarationReflection, ProjectReflection } from 'typedoc';
-import { ReflectionKind } from 'typedoc';
-import { newTypeDocApp, patchProject } from '../../../scripts/apidoc/utils';
+import type { SignatureReflection, TypeDocOptions } from 'typedoc';
+import {
+ newTypeDocApp,
+ patchProject,
+ selectApiMethodSignatures,
+ selectApiModules,
+} from '../../../scripts/apidoc/typedoc';
+import { mapByName } from '../../../scripts/apidoc/utils';
/**
- * Loads the example methods using TypeDoc.
+ * Returns a record with the (Module-Name -> (Method-Name -> Method-Signature)) for the project.
*/
-export function loadExampleMethods(): Record<string, DeclarationReflection> {
+export function loadProjectModules(
+ options: Partial<TypeDocOptions> = {
+ entryPoints: ['src/index.ts'],
+ },
+ includeTestModules = false
+): Record<string, Record<string, SignatureReflection>> {
const app = newTypeDocApp();
- app.bootstrap({
- entryPoints: ['test/scripts/apidoc/signature.example.ts'],
- tsconfig: 'test/scripts/apidoc/tsconfig.json',
- });
+ app.bootstrap(options);
const project = app.convert();
+ if (project == null) {
+ throw new Error('Failed to convert project');
+ }
+
patchProject(project);
- const methods: Record<string, DeclarationReflection> = project
- .getChildrenByKind(ReflectionKind.Class)[0]
- .getChildrenByKind(ReflectionKind.Method)
- .reduce((a, v) => ({ ...a, [v.name]: v }), {});
+ const modules = selectApiModules(project, includeTestModules);
- return methods;
+ return mapByName(modules, selectApiMethodSignatures);
}
/**
- * Loads the project using TypeDoc.
+ * Loads the example methods using TypeDoc.
*/
-export function loadProject(): ProjectReflection {
- const app = newTypeDocApp();
-
- app.bootstrap({
- entryPoints: ['src/index.ts'],
- });
-
- const project = app.convert();
-
- patchProject(project);
-
- return project;
+export function loadExampleMethods(): Record<string, SignatureReflection> {
+ return loadProjectModules(
+ {
+ entryPoints: ['test/scripts/apidoc/signature.example.ts'],
+ tsconfig: 'test/scripts/apidoc/tsconfig.json',
+ },
+ true
+ )['SignatureTest'];
}