Skip to content

Commit

Permalink
feat(types): provide strong typing for locales 2 (#398)
Browse files Browse the repository at this point in the history
  • Loading branch information
ST-DDT committed Feb 11, 2022
1 parent 6afa92b commit 419e9e2
Show file tree
Hide file tree
Showing 382 changed files with 2,572 additions and 641 deletions.
164 changes: 144 additions & 20 deletions scripts/generateLocales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import type { Options } from 'prettier';
import { format } from 'prettier';
import options from '../.prettierrc.cjs';
import type { LocaleDefinition } from '../src';
import { DEFINITIONS } from '../src/definitions';

// Constants

const pathRoot = resolve(__dirname, '..');
const pathLocale = resolve(pathRoot, 'src', 'locale');
Expand All @@ -16,36 +19,58 @@ const pathDocsApiLocalization = resolve(
'localization.md'
);

const scriptCommand = 'pnpm run generate:locales';
const prettierTsOptions: Options = { ...options, parser: 'typescript' };
const prettierMdOptions: Options = { ...options, parser: 'markdown' };

const locales = readdirSync(pathLocales);
locales.splice(locales.indexOf('index.ts'), 1);

let localeIndexImports = "import type { LocaleDefinition } from '..';\n";
let localeIndexType = 'export type KnownLocale =\n';
let localeIndexLocales = 'const locales: KnownLocales = {\n';

let localizationLocales = '| Locale | Name |\n| :--- | :--- |\n';
const scriptCommand = 'pnpm run generate:locales';

const autoGeneratedCommentHeader = `/*
* This file is automatically generated.
* Run '${scriptCommand}' to update.
*/`;

for (const locale of locales) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localeDef: LocaleDefinition = require('../src/locales/' +
locale).default;
const localeTitle = localeDef.title;
// Helper functions

localeIndexImports += `import ${locale} from './${locale}';\n`;
localeIndexType += ` | '${locale}'\n`;
localeIndexLocales += ` ${locale},\n`;
localizationLocales += `| ${locale} | ${localeTitle} |\n`;
function removeIndexTs(files: string[]): string[] {
const index = files.indexOf('index.ts');
if (index !== -1) {
files.splice(index, 1);
}
return files;
}

// src/locale/<locale>.ts
function removeTsSuffix(files: string[]): string[] {
return files.map((file) => file.replace('.ts', ''));
}

function escapeImport(module: string): string {
if (module === 'name') {
return 'name_';
} else if (module === 'type') {
return 'type_';
} else {
return module;
}
}

function escapeField(module: string): string {
if (module === 'name') {
return 'name: name_';
} else if (module === 'type') {
return 'type: type_';
} else {
return module;
}
}

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

function generateLocaleFile(locale: string) {
let content = `
${autoGeneratedCommentHeader}
Expand All @@ -69,6 +94,106 @@ for (const locale of locales) {
writeFileSync(resolve(pathLocale, locale + '.ts'), content);
}

function generateLocalesIndexFile(
path: string,
name: string,
type: string,
depth: number,
extra: string = '',
expected?: string[]
) {
let modules = readdirSync(path);
modules = removeIndexTs(modules);
modules = removeTsSuffix(modules);
const importType = type;
if (!containsAll(modules, expected)) {
type = `Partial<${type}>`;
}
let fieldType = '';
let asType = '';
if (!containsAll(expected, modules)) {
asType = ` as ${type}`;
} else {
fieldType = `: ${type}`;
}
let content = `${autoGeneratedCommentHeader}
import type { ${importType} } from '..${'/..'.repeat(depth)}';
${modules
.map((module) => `import ${escapeImport(module)} from './${module}';`)
.join('\n')}
const ${name}${fieldType} = {
${extra}
${modules.map((module) => `${escapeField(module)},`).join('\n')}
}${asType};
export default ${name};
`;
content = format(content, prettierTsOptions);
writeFileSync(resolve(path, 'index.ts'), content);
}

// Start of actual logic

const locales = readdirSync(pathLocales);
removeIndexTs(locales);

let localeIndexImports = "import type { LocaleDefinition } from '..';\n";
let localeIndexType = 'export type KnownLocale =\n';
let localeIndexLocales = 'const locales: KnownLocales = {\n';

let localizationLocales = '| Locale | Name |\n| :--- | :--- |\n';

for (const locale of locales) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localeDef: LocaleDefinition = require('../src/locales/' +
locale).default;
const localeTitle = localeDef.title;
const localeSeparator = localeDef.separator;

localeIndexImports += `import ${locale} from './${locale}';\n`;
localeIndexType += ` | '${locale}'\n`;
localeIndexLocales += ` ${locale},\n`;
localizationLocales += `| ${locale} | ${localeTitle} |\n`;

// src/locale/<locale>.ts
generateLocaleFile(locale);

// src/locales/<locale>/index.ts
const pathModules = resolve(pathLocales, locale);
generateLocalesIndexFile(
pathModules,
locale,
'LocaleDefinition',
1,
`title: '${localeTitle}',` +
(localeSeparator ? `\nseparator: '${localeSeparator}',` : ''),
undefined
);

let modules = readdirSync(pathModules);
modules = removeIndexTs(modules);
modules = removeTsSuffix(modules);
for (const module of modules) {
// src/locales/<locale>/<module>/index.ts
const pathModule = resolve(pathModules, module);
const moduleFiles: string[] = DEFINITIONS[module];
if (typeof moduleFiles === 'undefined') {
continue;
}
generateLocalesIndexFile(
pathModule,
module,
`${module.replace(/(^|_)([a-z])/g, (s) =>
s.replace('_', '').toUpperCase()
)}Definitions`,
2,
'',
moduleFiles
);
}
}

// src/locales/index.ts

let indexContent = `
Expand All @@ -86,7 +211,6 @@ let indexContent = `
`;

indexContent = format(indexContent, prettierTsOptions);

writeFileSync(pathLocalesIndex, indexContent);

// docs/api/localization.md
Expand Down
27 changes: 25 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@ import { Database } from './database';
import { Datatype } from './datatype';
import { _Date } from './date';
import type { LocaleDefinition } from './definitions';
export type {
AddressDefinitions,
AnimalDefinitions,
CommerceDefinitions,
CommerceProductNameDefinitions,
CompanyDefinitions,
DatabaseDefinitions,
DateDefinitions,
DateEntryDefinition,
DefinitionTypes,
FinanceCurrencyEntryDefinitions,
FinanceDefinitions,
HackerDefinitions,
InternetDefinitions,
LocaleDefinition,
LoremDefinitions,
MusicDefinitions,
NameDefinitions,
NameTitleDefinitions,
PhoneNumberDefinitions,
SystemDefinitions,
SystemMimeTypeEntryDefinitions,
VehicleDefinitions,
WordDefinitions,
} from './definitions';
import { DEFINITIONS } from './definitions';
import { Fake } from './fake';
import { Finance } from './finance';
Expand Down Expand Up @@ -34,8 +59,6 @@ type LiteralUnion<T extends U, U = string> = T | (U & { zz_IGNORE_ME?: never });
export type UsableLocale = LiteralUnion<KnownLocale>;
export type UsedLocales = Partial<Record<UsableLocale, LocaleDefinition>>;

export type { LocaleDefinition };

export interface FakerOptions {
locales?: UsedLocales;
locale?: UsableLocale;
Expand Down
9 changes: 7 additions & 2 deletions src/locales/af_ZA/address/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { AddressDefinitions } from '../../..';
import default_country from './default_country';
import postcode from './postcode';

const address: any = {
const address = {
default_country,
postcode,
};
} as Partial<AddressDefinitions>;

export default address;
7 changes: 6 additions & 1 deletion src/locales/af_ZA/company/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { CompanyDefinitions } from '../../..';
import suffix from './suffix';

const company: any = {
const company: Partial<CompanyDefinitions> = {
suffix,
};

Expand Down
8 changes: 6 additions & 2 deletions src/locales/af_ZA/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { LocaleDefinition } from '../..';
import address from './address';
import cell_phone from './cell_phone';
import company from './company';
import internet from './internet';
import name from './name';
import name_ from './name';
import phone_number from './phone_number';

const af_ZA: LocaleDefinition = {
Expand All @@ -12,7 +16,7 @@ const af_ZA: LocaleDefinition = {
cell_phone,
company,
internet,
name,
name: name_,
phone_number,
};

Expand Down
7 changes: 6 additions & 1 deletion src/locales/af_ZA/internet/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { InternetDefinitions } from '../../..';
import domain_suffix from './domain_suffix';

const internet: any = {
const internet: Partial<InternetDefinitions> = {
domain_suffix,
};

Expand Down
7 changes: 6 additions & 1 deletion src/locales/af_ZA/name/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { NameDefinitions } from '../../..';
import female_first_name from './female_first_name';
import first_name from './first_name';
import last_name from './last_name';
import male_first_name from './male_first_name';

const name: any = {
const name: Partial<NameDefinitions> = {
female_first_name,
first_name,
last_name,
Expand Down
7 changes: 6 additions & 1 deletion src/locales/af_ZA/phone_number/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { PhoneNumberDefinitions } from '../../..';
import formats from './formats';

const phone_number: any = {
const phone_number: PhoneNumberDefinitions = {
formats,
};

Expand Down
9 changes: 7 additions & 2 deletions src/locales/ar/address/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { AddressDefinitions } from '../../..';
import building_number from './building_number';
import city from './city';
import city_name from './city_name';
Expand All @@ -11,7 +16,7 @@ import street_address from './street_address';
import street_name from './street_name';
import street_prefix from './street_prefix';

const address: any = {
const address = {
building_number,
city,
city_name,
Expand All @@ -24,6 +29,6 @@ const address: any = {
street_address,
street_name,
street_prefix,
};
} as Partial<AddressDefinitions>;

export default address;
7 changes: 6 additions & 1 deletion src/locales/ar/commerce/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { CommerceDefinitions } from '../../..';
import color from './color';
import department from './department';
import product_name from './product_name';

const commerce: any = {
const commerce: Partial<CommerceDefinitions> = {
color,
department,
product_name,
Expand Down
7 changes: 6 additions & 1 deletion src/locales/ar/date/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/*
* This file is automatically generated.
* Run 'pnpm run generate:locales' to update.
*/
import type { DateDefinitions } from '../../..';
import month from './month';
import weekday from './weekday';

const date: any = {
const date: DateDefinitions = {
month,
weekday,
};
Expand Down
Loading

0 comments on commit 419e9e2

Please sign in to comment.