Skip to content

Commit 984fbb4

Browse files
ST-DDTpkuczynski
andauthored
fix(generate:locale): make the definition types extendible (#915)
Co-authored-by: Piotr Kuczynski <piotr.kuczynski@gmail.com>
1 parent f1dba1b commit 984fbb4

239 files changed

Lines changed: 443 additions & 407 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

scripts/generateLocales.ts

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ import { resolve } from 'node:path';
1717
import type { Options } from 'prettier';
1818
import { format } from 'prettier';
1919
import options from '../.prettierrc.cjs';
20-
import type { LocaleDefinition } from '../src/definitions';
21-
import { DEFINITIONS } from '../src/definitions';
20+
import type { Definitions, LocaleDefinition } from '../src/definitions';
2221

2322
// Constants
2423

@@ -33,6 +32,37 @@ const pathDocsApiLocalization = resolve(
3332
'localization.md'
3433
);
3534

35+
// Workaround for nameOf<T>
36+
type PascalCase<S extends string> = S extends `${infer P1}_${infer P2}`
37+
? `${Capitalize<P1>}${PascalCase<P2>}`
38+
: Capitalize<S>;
39+
40+
type DefinitionsType = {
41+
[key in keyof Definitions]: PascalCase<`${key}Definitions`>;
42+
};
43+
44+
/**
45+
* The types of the definitions.
46+
*/
47+
const definitionsTypes: DefinitionsType = {
48+
address: 'AddressDefinitions',
49+
animal: 'AnimalDefinitions',
50+
commerce: 'CommerceDefinitions',
51+
company: 'CompanyDefinitions',
52+
database: 'DatabaseDefinitions',
53+
date: 'DateDefinitions',
54+
finance: 'FinanceDefinitions',
55+
hacker: 'HackerDefinitions',
56+
internet: 'InternetDefinitions',
57+
lorem: 'LoremDefinitions',
58+
music: 'MusicDefinitions',
59+
name: 'NameDefinitions',
60+
phone_number: 'PhoneNumberDefinitions',
61+
system: 'SystemDefinitions',
62+
vehicle: 'VehicleDefinitions',
63+
word: 'WordDefinitions',
64+
};
65+
3666
const prettierTsOptions: Options = { ...options, parser: 'typescript' };
3767
const prettierMdOptions: Options = { ...options, parser: 'markdown' };
3868

@@ -73,13 +103,6 @@ function escapeField(module: string): string {
73103
}
74104
}
75105

76-
function containsAll(checked?: string[], expected?: string[]): boolean {
77-
if (expected == null || checked == null) {
78-
return true;
79-
}
80-
return expected.every((c) => checked.includes(c));
81-
}
82-
83106
function generateLocaleFile(locale: string): void {
84107
let content = `
85108
${autoGeneratedCommentHeader}
@@ -135,54 +158,47 @@ function generateLocalesIndexFile(
135158
name: string,
136159
type: string,
137160
depth: number,
138-
extra: string = '',
139-
expected?: string[]
161+
extra: string = ''
140162
): void {
141163
let modules = readdirSync(path);
142164
modules = removeIndexTs(modules);
143165
modules = removeTsSuffix(modules);
144-
const importType = type;
145-
if (!containsAll(modules, expected)) {
146-
type = `Partial<${type}>`;
147-
}
166+
167+
const content = [autoGeneratedCommentHeader];
148168
let fieldType = '';
149-
let asType = '';
150-
if (!containsAll(expected, modules)) {
151-
asType = ` as ${type}`;
152-
} else if (type !== 'any') {
153-
fieldType = `: ${type}`;
154-
}
155-
let content = `${autoGeneratedCommentHeader}\n`;
156169
if (type !== 'any') {
157-
content += ` import type { ${importType.replace(
158-
/\[.*/,
159-
''
160-
)} } from '..${'/..'.repeat(depth)}';\n`;
170+
fieldType = `: ${type}`;
171+
content.push(
172+
`import type { ${type.replace(/\[.*/, '')} } from '..${'/..'.repeat(
173+
depth
174+
)}';\n`
175+
);
161176
}
162-
content += ` ${modules
163-
.map((module) => `import ${escapeImport(module)} from './${module}';`)
164-
.join('\n')}
177+
content.push(
178+
...modules.map((m) => `import ${escapeImport(m)} from './${m}';`)
179+
);
165180

166-
const ${name}${fieldType} = {
181+
content.push(`\nconst ${name}${fieldType} = {
167182
${extra}
168183
${modules.map((module) => `${escapeField(module)},`).join('\n')}
169-
}${asType};
184+
};\n`);
170185

171-
export default ${name};
172-
`;
173-
content = format(content, prettierTsOptions);
174-
writeFileSync(resolve(path, 'index.ts'), content);
186+
content.push(`export default ${name};`);
187+
188+
writeFileSync(
189+
resolve(path, 'index.ts'),
190+
format(content.join('\n'), prettierTsOptions)
191+
);
175192
}
176193

177194
function generateRecursiveModuleIndexes(
178195
path: string,
179196
name: string,
180197
definition: string,
181198
depth: number,
182-
extra?: string,
183-
moduleFiles?: string[]
199+
extra?: string
184200
): void {
185-
generateLocalesIndexFile(path, name, definition, depth, extra, moduleFiles);
201+
generateLocalesIndexFile(path, name, definition, depth, extra);
186202

187203
let submodules = readdirSync(path);
188204
submodules = removeIndexTs(submodules);
@@ -193,18 +209,10 @@ function generateRecursiveModuleIndexes(
193209
if (lstatSync(pathModule).isDirectory()) {
194210
let moduleDefinition =
195211
definition === 'any' ? 'any' : `${definition}['${submodule}']`;
196-
let moduleFiles: string[];
197212

198-
// Overwrite types of src/locales/<locale>/<module>/index.ts for known DEFINITIONS
213+
// Overwrite types of src/locales/<locale>/<module>/index.ts for known definition types
199214
if (depth === 1) {
200-
moduleFiles = DEFINITIONS[submodule];
201-
if (moduleFiles == null) {
202-
moduleDefinition = 'any';
203-
} else {
204-
moduleDefinition = `${submodule.replace(/(^|_)([a-z])/g, (s) =>
205-
s.replace('_', '').toUpperCase()
206-
)}Definitions`;
207-
}
215+
moduleDefinition = definitionsTypes[submodule] ?? 'any';
208216
}
209217

210218
// Recursive
@@ -213,8 +221,7 @@ function generateRecursiveModuleIndexes(
213221
submodule,
214222
moduleDefinition,
215223
depth + 1,
216-
undefined,
217-
moduleFiles
224+
undefined
218225
);
219226
}
220227
}

src/definitions/address.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to addresses.
35
*/
4-
export interface AddressDefinitions {
6+
export type AddressDefinitions = LocaleEntry<{
57
/**
68
* Postcodes patterns by state
79
*/
@@ -14,7 +16,7 @@ export interface AddressDefinitions {
1416
/**
1517
* Names of actual cities
1618
*/
17-
city_name?: string[];
19+
city_name: string[];
1820
/**
1921
* Common city prefixes
2022
*/
@@ -96,4 +98,4 @@ export interface AddressDefinitions {
9698

9799
// A list of timezones names.
98100
time_zone: string[];
99-
}
101+
}>;

src/definitions/animal.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to animals.
35
*/
4-
export interface AnimalDefinitions {
6+
export type AnimalDefinitions = LocaleEntry<{
57
bear: string[];
68
bird: string[];
79
cat: string[];
@@ -16,4 +18,4 @@ export interface AnimalDefinitions {
1618
rabbit: string[];
1719
snake: string[];
1820
type: string[];
19-
}
21+
}>;

src/definitions/commerce.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to commerce.
35
*/
4-
export interface CommerceDefinitions {
6+
export type CommerceDefinitions = LocaleEntry<{
57
/**
68
* Human readable color names
79
*/
@@ -18,7 +20,7 @@ export interface CommerceDefinitions {
1820
* Descriptions for products.
1921
*/
2022
product_description: string[];
21-
}
23+
}>;
2224

2325
/**
2426
* The possible definitions related to product name generation.

src/definitions/company.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to companies.
35
*/
4-
export interface CompanyDefinitions {
6+
export type CompanyDefinitions = LocaleEntry<{
57
/**
68
* Business/products related adjectives.
79
*/
@@ -30,4 +32,4 @@ export interface CompanyDefinitions {
3032
* Company suffixes
3133
*/
3234
suffix: string[];
33-
}
35+
}>;

src/definitions/database.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to databases.
35
*/
4-
export interface DatabaseDefinitions {
6+
export type DatabaseDefinitions = LocaleEntry<{
57
/**
68
* Database Engine
79
*/
@@ -18,4 +20,4 @@ export interface DatabaseDefinitions {
1820
* Column types
1921
*/
2022
type: string[];
21-
}
23+
}>;

src/definitions/date.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to dates.
35
*/
4-
export interface DateDefinitions {
6+
export type DateDefinitions = LocaleEntry<{
57
/**
68
* The translations for months (January - December).
79
*/
@@ -10,7 +12,7 @@ export interface DateDefinitions {
1012
* The translations for weekdays (Sunday - Saturday).
1113
*/
1214
weekday: DateEntryDefinition;
13-
}
15+
}>;
1416

1517
/**
1618
* The possible definitions related to date entries.

src/definitions/definitions.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@ import type { SystemDefinitions } from './system';
1515
import type { VehicleDefinitions } from './vehicle';
1616
import type { WordDefinitions } from './word';
1717

18+
export type LocaleEntry<T> = Partial<T> &
19+
// Unsupported & custom modules
20+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21+
Record<string, any>;
22+
1823
/**
1924
* The definitions as used by the Faker modules.
2025
*/
21-
interface Definitions {
26+
export interface Definitions {
2227
address: AddressDefinitions;
2328
animal: AnimalDefinitions;
2429
commerce: CommerceDefinitions;
@@ -48,11 +53,4 @@ export type LocaleDefinition = {
4853
*/
4954
title: string;
5055
separator?: string;
51-
} & {
52-
// Known modules
53-
[module in keyof Definitions]?: Partial<Definitions[module]>;
54-
} & {
55-
// Unsupported & custom modules
56-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
57-
[group: string]: any;
58-
};
56+
} & LocaleEntry<Definitions>;

src/definitions/finance.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to finances.
35
*/
4-
export interface FinanceDefinitions {
6+
export type FinanceDefinitions = LocaleEntry<{
57
/**
68
* The types of accounts/purposes of an account (e.g. `Savings` account).
79
*/
@@ -21,7 +23,7 @@ export interface FinanceDefinitions {
2123
* Types of transactions (e.g. `deposit`).
2224
*/
2325
transaction_type: string[];
24-
}
26+
}>;
2527

2628
/**
2729
* The possible definitions related to currency entries.

src/definitions/hacker.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { LocaleEntry } from './definitions';
2+
13
/**
24
* The possible definitions related to computers.
35
*/
4-
export interface HackerDefinitions {
6+
export type HackerDefinitions = LocaleEntry<{
57
/**
68
* Generic computer related abbreviations (e.g. `RAM`, `EXE`).
79
*/
@@ -30,4 +32,4 @@ export interface HackerDefinitions {
3032
* Some computer related verbs (e.g. `hack`).
3133
*/
3234
verb: string[];
33-
}
35+
}>;

0 commit comments

Comments
 (0)