Skip to content

Commit

Permalink
fix(generate:locale): make the definition types extendible (#915)
Browse files Browse the repository at this point in the history
Co-authored-by: Piotr Kuczynski <piotr.kuczynski@gmail.com>
  • Loading branch information
ST-DDT and pkuczynski committed May 4, 2022
1 parent f1dba1b commit 984fbb4
Show file tree
Hide file tree
Showing 239 changed files with 443 additions and 407 deletions.
107 changes: 57 additions & 50 deletions scripts/generateLocales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import { resolve } from 'node:path';
import type { Options } from 'prettier';
import { format } from 'prettier';
import options from '../.prettierrc.cjs';
import type { LocaleDefinition } from '../src/definitions';
import { DEFINITIONS } from '../src/definitions';
import type { Definitions, LocaleDefinition } from '../src/definitions';

// Constants

Expand All @@ -33,6 +32,37 @@ const pathDocsApiLocalization = resolve(
'localization.md'
);

// Workaround for nameOf<T>
type PascalCase<S extends string> = S extends `${infer P1}_${infer P2}`
? `${Capitalize<P1>}${PascalCase<P2>}`
: Capitalize<S>;

type DefinitionsType = {
[key in keyof Definitions]: PascalCase<`${key}Definitions`>;
};

/**
* The types of the definitions.
*/
const definitionsTypes: DefinitionsType = {
address: 'AddressDefinitions',
animal: 'AnimalDefinitions',
commerce: 'CommerceDefinitions',
company: 'CompanyDefinitions',
database: 'DatabaseDefinitions',
date: 'DateDefinitions',
finance: 'FinanceDefinitions',
hacker: 'HackerDefinitions',
internet: 'InternetDefinitions',
lorem: 'LoremDefinitions',
music: 'MusicDefinitions',
name: 'NameDefinitions',
phone_number: 'PhoneNumberDefinitions',
system: 'SystemDefinitions',
vehicle: 'VehicleDefinitions',
word: 'WordDefinitions',
};

const prettierTsOptions: Options = { ...options, parser: 'typescript' };
const prettierMdOptions: Options = { ...options, parser: 'markdown' };

Expand Down Expand Up @@ -73,13 +103,6 @@ function escapeField(module: string): string {
}
}

function containsAll(checked?: string[], expected?: string[]): boolean {
if (expected == null || checked == null) {
return true;
}
return expected.every((c) => checked.includes(c));
}

function generateLocaleFile(locale: string): void {
let content = `
${autoGeneratedCommentHeader}
Expand Down Expand Up @@ -135,54 +158,47 @@ function generateLocalesIndexFile(
name: string,
type: string,
depth: number,
extra: string = '',
expected?: string[]
extra: string = ''
): void {
let modules = readdirSync(path);
modules = removeIndexTs(modules);
modules = removeTsSuffix(modules);
const importType = type;
if (!containsAll(modules, expected)) {
type = `Partial<${type}>`;
}

const content = [autoGeneratedCommentHeader];
let fieldType = '';
let asType = '';
if (!containsAll(expected, modules)) {
asType = ` as ${type}`;
} else if (type !== 'any') {
fieldType = `: ${type}`;
}
let content = `${autoGeneratedCommentHeader}\n`;
if (type !== 'any') {
content += ` import type { ${importType.replace(
/\[.*/,
''
)} } from '..${'/..'.repeat(depth)}';\n`;
fieldType = `: ${type}`;
content.push(
`import type { ${type.replace(/\[.*/, '')} } from '..${'/..'.repeat(
depth
)}';\n`
);
}
content += ` ${modules
.map((module) => `import ${escapeImport(module)} from './${module}';`)
.join('\n')}
content.push(
...modules.map((m) => `import ${escapeImport(m)} from './${m}';`)
);

const ${name}${fieldType} = {
content.push(`\nconst ${name}${fieldType} = {
${extra}
${modules.map((module) => `${escapeField(module)},`).join('\n')}
}${asType};
};\n`);

export default ${name};
`;
content = format(content, prettierTsOptions);
writeFileSync(resolve(path, 'index.ts'), content);
content.push(`export default ${name};`);

writeFileSync(
resolve(path, 'index.ts'),
format(content.join('\n'), prettierTsOptions)
);
}

function generateRecursiveModuleIndexes(
path: string,
name: string,
definition: string,
depth: number,
extra?: string,
moduleFiles?: string[]
extra?: string
): void {
generateLocalesIndexFile(path, name, definition, depth, extra, moduleFiles);
generateLocalesIndexFile(path, name, definition, depth, extra);

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

// Overwrite types of src/locales/<locale>/<module>/index.ts for known DEFINITIONS
// Overwrite types of src/locales/<locale>/<module>/index.ts for known definition types
if (depth === 1) {
moduleFiles = DEFINITIONS[submodule];
if (moduleFiles == null) {
moduleDefinition = 'any';
} else {
moduleDefinition = `${submodule.replace(/(^|_)([a-z])/g, (s) =>
s.replace('_', '').toUpperCase()
)}Definitions`;
}
moduleDefinition = definitionsTypes[submodule] ?? 'any';
}

// Recursive
Expand All @@ -213,8 +221,7 @@ function generateRecursiveModuleIndexes(
submodule,
moduleDefinition,
depth + 1,
undefined,
moduleFiles
undefined
);
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/definitions/address.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to addresses.
*/
export interface AddressDefinitions {
export type AddressDefinitions = LocaleEntry<{
/**
* Postcodes patterns by state
*/
Expand All @@ -14,7 +16,7 @@ export interface AddressDefinitions {
/**
* Names of actual cities
*/
city_name?: string[];
city_name: string[];
/**
* Common city prefixes
*/
Expand Down Expand Up @@ -96,4 +98,4 @@ export interface AddressDefinitions {

// A list of timezones names.
time_zone: string[];
}
}>;
6 changes: 4 additions & 2 deletions src/definitions/animal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to animals.
*/
export interface AnimalDefinitions {
export type AnimalDefinitions = LocaleEntry<{
bear: string[];
bird: string[];
cat: string[];
Expand All @@ -16,4 +18,4 @@ export interface AnimalDefinitions {
rabbit: string[];
snake: string[];
type: string[];
}
}>;
6 changes: 4 additions & 2 deletions src/definitions/commerce.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to commerce.
*/
export interface CommerceDefinitions {
export type CommerceDefinitions = LocaleEntry<{
/**
* Human readable color names
*/
Expand All @@ -18,7 +20,7 @@ export interface CommerceDefinitions {
* Descriptions for products.
*/
product_description: string[];
}
}>;

/**
* The possible definitions related to product name generation.
Expand Down
6 changes: 4 additions & 2 deletions src/definitions/company.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to companies.
*/
export interface CompanyDefinitions {
export type CompanyDefinitions = LocaleEntry<{
/**
* Business/products related adjectives.
*/
Expand Down Expand Up @@ -30,4 +32,4 @@ export interface CompanyDefinitions {
* Company suffixes
*/
suffix: string[];
}
}>;
6 changes: 4 additions & 2 deletions src/definitions/database.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to databases.
*/
export interface DatabaseDefinitions {
export type DatabaseDefinitions = LocaleEntry<{
/**
* Database Engine
*/
Expand All @@ -18,4 +20,4 @@ export interface DatabaseDefinitions {
* Column types
*/
type: string[];
}
}>;
6 changes: 4 additions & 2 deletions src/definitions/date.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to dates.
*/
export interface DateDefinitions {
export type DateDefinitions = LocaleEntry<{
/**
* The translations for months (January - December).
*/
Expand All @@ -10,7 +12,7 @@ export interface DateDefinitions {
* The translations for weekdays (Sunday - Saturday).
*/
weekday: DateEntryDefinition;
}
}>;

/**
* The possible definitions related to date entries.
Expand Down
16 changes: 7 additions & 9 deletions src/definitions/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ import type { SystemDefinitions } from './system';
import type { VehicleDefinitions } from './vehicle';
import type { WordDefinitions } from './word';

export type LocaleEntry<T> = Partial<T> &
// Unsupported & custom modules
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Record<string, any>;

/**
* The definitions as used by the Faker modules.
*/
interface Definitions {
export interface Definitions {
address: AddressDefinitions;
animal: AnimalDefinitions;
commerce: CommerceDefinitions;
Expand Down Expand Up @@ -48,11 +53,4 @@ export type LocaleDefinition = {
*/
title: string;
separator?: string;
} & {
// Known modules
[module in keyof Definitions]?: Partial<Definitions[module]>;
} & {
// Unsupported & custom modules
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[group: string]: any;
};
} & LocaleEntry<Definitions>;
6 changes: 4 additions & 2 deletions src/definitions/finance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to finances.
*/
export interface FinanceDefinitions {
export type FinanceDefinitions = LocaleEntry<{
/**
* The types of accounts/purposes of an account (e.g. `Savings` account).
*/
Expand All @@ -21,7 +23,7 @@ export interface FinanceDefinitions {
* Types of transactions (e.g. `deposit`).
*/
transaction_type: string[];
}
}>;

/**
* The possible definitions related to currency entries.
Expand Down
6 changes: 4 additions & 2 deletions src/definitions/hacker.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to computers.
*/
export interface HackerDefinitions {
export type HackerDefinitions = LocaleEntry<{
/**
* Generic computer related abbreviations (e.g. `RAM`, `EXE`).
*/
Expand Down Expand Up @@ -30,4 +32,4 @@ export interface HackerDefinitions {
* Some computer related verbs (e.g. `hack`).
*/
verb: string[];
}
}>;
2 changes: 1 addition & 1 deletion src/definitions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type {
export type { CompanyDefinitions } from './company';
export type { DatabaseDefinitions } from './database';
export type { DateDefinitions, DateEntryDefinition } from './date';
export type { LocaleDefinition } from './definitions';
export type { Definitions, LocaleDefinition } from './definitions';
export type {
FinanceCurrencyEntryDefinitions,
FinanceDefinitions,
Expand Down
5 changes: 3 additions & 2 deletions src/definitions/internet.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { EmojiType } from '../modules/internet';
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to internet stuff.
*/
export interface InternetDefinitions {
export type InternetDefinitions = LocaleEntry<{
/**
* Common top level and similar domains (e.g `de`, `co.uk`).
*/
Expand All @@ -20,4 +21,4 @@ export interface InternetDefinitions {
* List of all fully-qualified emojis.
*/
emoji: Record<EmojiType, string[]>;
}
}>;
6 changes: 4 additions & 2 deletions src/definitions/lorem.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to lorem texts.
*/
export interface LoremDefinitions {
export type LoremDefinitions = LocaleEntry<{
/**
* Lorem words used to generate dummy texts.
*/
words: string[];
}
}>;

0 comments on commit 984fbb4

Please sign in to comment.