Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6dddc14
refactor: _prefix module helpers
ST-DDT Mar 3, 2026
310627f
feat: introduce standalone module functions (transform script)
ST-DDT Apr 9, 2026
8e55df6
chore: run transform script (dirty)
ST-DDT May 15, 2026
9bba089
refactor: transform aircraft
ST-DDT Mar 3, 2026
8071fd8
refactor: transform color
ST-DDT Mar 4, 2026
ac7e614
refactor: transform commerce
ST-DDT Mar 4, 2026
4a59985
refactor: transform date
ST-DDT Mar 4, 2026
7cbb402
refactor: transform finance
ST-DDT Mar 4, 2026
0e57834
refactor: transform food
ST-DDT Mar 4, 2026
7e08fe2
refactor: transform git
ST-DDT Mar 4, 2026
397222c
refactor: transform helpers
ST-DDT Mar 4, 2026
8617126
refactor: transform image
ST-DDT Mar 5, 2026
517875b
refactor: transform internet
ST-DDT Mar 5, 2026
88ea3e8
refactor: transform location
ST-DDT Mar 5, 2026
6401cb1
refactor: transform number
ST-DDT Mar 5, 2026
6975129
refactor: transform lorem
ST-DDT Mar 5, 2026
03d6468
refactor: transform internet
ST-DDT Mar 5, 2026
015b1f0
refactor: transform person
ST-DDT Mar 5, 2026
e883443
refactor: transform phone
ST-DDT Mar 6, 2026
b09eab0
refactor: transform science
ST-DDT Mar 5, 2026
d7c2fa1
refactor: transform string
ST-DDT Mar 6, 2026
4641b39
refactor: transform system
ST-DDT Mar 6, 2026
59ae230
refactor: transform word
ST-DDT Mar 6, 2026
8e1b673
infra: introduce generate-module-tree script
ST-DDT Mar 14, 2026
6ddd95b
chore: apply generate-module-tree script
ST-DDT May 15, 2026
5daaa57
chore: cleanup and final fixes
ST-DDT Mar 16, 2026
e68ac68
Merge branch 'next' into feat/standalone-module-functions
ST-DDT May 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
207 changes: 207 additions & 0 deletions scripts/generate-module-tree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { SyntaxKind } from 'ts-morph';
import { getDeprecated, getJsDocs } from './apidocs/processing/jsdocs';
import { getProject } from './apidocs/project';
import { toCamelCase, toKebabCase } from './shared/character-case';
import { formatTypescript } from './shared/format';
import { FILE_PATH_SRC } from './shared/paths';

const project = getProject();

const directories = project
.getDirectoryOrThrow('src')
.getDirectoryOrThrow('modules')
.getDirectories();

const moduleNames = new Set(directories.map((dir) => dir.getBaseName()));

//#region Module
for (const directory of directories) {
const moduleName = directory.getBaseName();

console.log(`Processing module: ${moduleName}`);
//#region Index
const indexFile = directory.getSourceFileOrThrow('index.ts');

const header = indexFile
.getStatements()[0]
?.getLeadingCommentRanges()
.map((c) => c.getText());

const imports = new Set([
`import { SimpleModuleBase } from '../../internal/module-base';`,
`import { ModuleBase } from '../../internal/module-base';`,
`import type { Faker } from '../../faker';`,
`import type { LiteralUnion } from '../../internal/types';`,
`import type { Distributor } from '../../distributors/distributor';`,
]);
if (moduleName === 'image') {
imports.add(`import type { SexType } from '../person';`);
}

const exports: string[] = indexFile
.getExportDeclarations()
.map((exp) => exp.getText());

const typesFile = directory.getSourceFile('_types.ts');
if (typesFile) {
const typesToImport = [
typesFile.getEnums(),
typesFile.getTypeAliases(),
typesFile.getInterfaces(),
]
.flat()
.filter((decl) => decl.isExported())
.map((decl) => decl.getName());

if (typesToImport.length > 0) {
imports.add(
`import type { ${typesToImport.join(', ')} } from './_types';`
);
}
}

const content: string[] = [];
const classes = indexFile?.getClasses() ?? [];

//#region Module Classes
for (const cls of classes) {
content.push(getJsDocs(cls).getText());
const methodNames = cls.getMethods().map((method) => method.getName());
for (const method of cls.getMethods()) {
if (method.getName() !== 'fake') {
method.remove();
}
}

for (const methodName of methodNames) {
if (methodName === 'fake') {
continue;
}

const methodFile = directory.getSourceFileOrThrow(
`${toKebabCase(methodName)}.ts`
);

const typesToImport = [
methodFile.getEnums(),
methodFile.getTypeAliases(),
methodFile.getInterfaces(),
]
.flat()
.filter((decl) => decl.isExported())
.map((decl) => decl.getName());

imports.add(
`import { ${methodName} as ${toCamelCase(moduleName, methodName)} } from './${toKebabCase(methodName)}';`
);
if (typesToImport.length > 0) {
imports.add(
`import type { ${typesToImport.join(', ')} } from './${toKebabCase(methodName)}';`
);
}

const functions = methodFile
.getChildrenOfKind(SyntaxKind.FunctionDeclaration)
.filter((fn) => fn.isExported())
.filter((fn) => fn.getName() === methodName);

const parts: string[] = [];

const restoreFakerTreeInvocations = (
_: string,
module: string,
method: string
): string =>
methodNames.includes(`${module}${method}`)
? `faker.${moduleName}.${module}${method}(`
: moduleNames.has(module)
? `faker.${module}.${toCamelCase(method)}(`
: `faker.${module}${method}(`;

for (const child of functions) {
//#region Module Functions
const jsDocs = child.getJsDocs()[0];

if (child.hasBody()) {
const params = child
.getSignature()
.getParameters()
.slice(1)
.map((param) => param.getName());

const isDeprecated = jsDocs && getDeprecated(jsDocs);

child.setBodyText(
`${
isDeprecated
? '// eslint-disable-next-line @typescript-eslint/no-deprecated -- Internal call\n'
: ''
}return ${toCamelCase(moduleName, methodName)}(this.faker.fakerCore, ${params.join(', ')});`
);
}

if (jsDocs) {
const description = jsDocs
.getFullText()
// Param
.replace(' * @param fakerCore The FakerCore to use.\n', '')
.replaceAll(/ +\*\n +\*\n/g, ' *\n')
// Examples
.replaceAll(
new RegExp(`${methodName}\\(fakerCore(?:, ?)?`, 'g'),
`faker.${moduleName}.${methodName}(`
)
// Method References
.replaceAll(
/\b([a-z]+)([A-Z][a-zA-Z]+)\(fakerCore(?:, ?)?/g,
restoreFakerTreeInvocations
)
.replaceAll(
/\b([a-zA-Z]+)\(fakerCore(?:, ?)?/g,
(_, method: string) =>
`faker.${moduleName}.${toCamelCase(method)}(`
);

parts.push(description);
}

const signature = child
.getSignature()
.getDeclaration()
.getText()
// Adapt signature
.replace('export function ', '')
.replace(/\((\n +)?fakerCore: FakerCore,?/, '(')
// Adapt nested options defaults
.replaceAll(
/(?<= +\* .*?)\bgetDefaultRefDate\(fakerCore(?:, ?)?/g,
'faker.defaultRefDate('
)
.replaceAll(
/(?<= +\* .*?)\b([a-z]+)([A-Z][a-zA-Z]+)\(fakerCore(?:, ?)?/g,
restoreFakerTreeInvocations
);

parts.push(signature);
//#endregion
}

cls.addMember(parts.join('\n'));
}
//#endregion

content.push(cls.getText(), '');
}

content.unshift(...header, ...imports, '', ...exports, '');

writeFileSync(
resolve(FILE_PATH_SRC, 'modules', moduleName, 'index.ts'),
await formatTypescript(content.join('\n')),
'utf8'
);
//#endregion
}
//#endregion
19 changes: 19 additions & 0 deletions scripts/shared/character-case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function toKebabCase(...values: string[]): string {
return values
.join('-')
.replaceAll(/([a-z])([A-Z])/g, '$1-$2')
.replaceAll(/[\s_]+/g, '-')
.toLowerCase();
}

export function toCamelCase(...values: string[]): string {
const text = values
.flatMap((value) => value.split(/[\s_-]+/))
.map(toPascalCase)
.join('');
return text.substring(0, 1).toLowerCase() + text.substring(1);
}

export function toPascalCase(value: string): string {
return value.substring(0, 1).toUpperCase() + value.substring(1);
}
2 changes: 1 addition & 1 deletion scripts/shared/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const FILE_PATH_DOCS_LOCALES = resolve(FILE_PATH_DOCS, 'locales');
/**
* The path to the src directory.
*/
const FILE_PATH_SRC = resolve(FILE_PATH_PROJECT, 'src');
export const FILE_PATH_SRC = resolve(FILE_PATH_PROJECT, 'src');
/**
* The path to the locale source files.
*/
Expand Down
Loading
Loading