Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

infra(locales): use mostly async io for generate-locales #2826

Merged
merged 6 commits into from
Apr 17, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 46 additions & 37 deletions scripts/generate-locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@
*
* Run this script using `pnpm run generate:locales`
*/
import {
existsSync,
lstatSync,
readdirSync,
readFileSync,
writeFileSync,
} from 'node:fs';
import { constants } from 'node:fs';
import { access, readFile, readdir, stat, writeFile } from 'node:fs/promises';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { LocaleDefinition, MetadataDefinition } from '../src/definitions';
Expand Down Expand Up @@ -122,8 +117,11 @@ async function generateLocaleFile(locale: string): Promise<void> {

for (let i = parts.length - 1; i > 0; i--) {
const fallback = parts.slice(0, i).join('_');
if (existsSync(resolve(pathLocales, fallback))) {
try {
await access(resolve(pathLocales, fallback), constants.R_OK);
locales.push(fallback);
} catch {
// file is missing
}
}

Expand Down Expand Up @@ -152,7 +150,7 @@ async function generateLocaleFile(locale: string): Promise<void> {
`;

content = await formatTypescript(content);
writeFileSync(resolve(pathLocale, `${locale}.ts`), content);
return writeFile(resolve(pathLocale, `${locale}.ts`), content);
}

async function generateLocalesIndexFile(
Expand All @@ -161,7 +159,7 @@ async function generateLocalesIndexFile(
type: string,
depth: number
): Promise<void> {
let modules = readdirSync(path);
let modules = await readdir(path);
modules = modules.filter((file) => !file.startsWith('.'));
modules = removeIndexTs(modules);
modules = removeTsSuffix(modules);
Expand Down Expand Up @@ -190,7 +188,7 @@ async function generateLocalesIndexFile(
`export default ${name};`
);

writeFileSync(
return writeFile(
resolve(path, 'index.ts'),
await formatTypescript(content.join('\n'))
);
Expand All @@ -201,16 +199,18 @@ async function generateRecursiveModuleIndexes(
name: string,
definition: string,
depth: number
): Promise<void> {
): Promise<unknown> {
await generateLocalesIndexFile(path, name, definition, depth);
const promises: Array<Promise<unknown>> = [];

let submodules = readdirSync(path);
let submodules = await readdir(path);
submodules = removeIndexTs(submodules);
for (const submodule of submodules) {
const pathModule = resolve(path, submodule);
await updateLocaleFile(pathModule);
// Only process sub folders recursively
if (lstatSync(pathModule).isDirectory()) {
const moduleStat = await stat(pathModule);
if (moduleStat.isDirectory()) {
let moduleDefinition =
definition === 'any' ? 'any' : `${definition}['${submodule}']`;

Expand All @@ -220,14 +220,18 @@ async function generateRecursiveModuleIndexes(
}

// Recursive
await generateRecursiveModuleIndexes(
pathModule,
submodule,
moduleDefinition,
depth + 1
promises.push(
generateRecursiveModuleIndexes(
pathModule,
submodule,
moduleDefinition,
depth + 1
)
);
}
}

return Promise.all(promises);
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand All @@ -237,11 +241,12 @@ async function generateRecursiveModuleIndexes(
* @param filePath The full file path to the file.
*/
async function updateLocaleFile(filePath: string): Promise<void> {
if (lstatSync(filePath).isFile()) {
const fileStat = await stat(filePath);
if (fileStat.isFile()) {
const [locale, moduleKey, entryKey] = filePath
.substring(pathLocales.length + 1, filePath.length - 3)
.split(/[\\/]/);
await updateLocaleFileHook(filePath, locale, moduleKey, entryKey);
return updateLocaleFileHook(filePath, locale, moduleKey, entryKey);
}
}

Expand All @@ -265,7 +270,7 @@ async function updateLocaleFileHook(
console.log(`${filePath} <-> ${locale} @ ${definitionKey} -> ${entryName}`);
}

await normalizeLocaleFile(filePath, definitionKey);
return normalizeLocaleFile(filePath, definitionKey);
}

/**
Expand Down Expand Up @@ -334,7 +339,9 @@ async function normalizeLocaleFile(filePath: string, definitionKey: string) {

console.log(`Running data normalization for:`, filePath);

const fileContent = readFileSync(filePath).toString();
const fileContent = (
await readFile(filePath, { encoding: 'utf8' })
).toString();
const searchString = 'export default ';
const compareIndex = fileContent.indexOf(searchString) + searchString.length;
const compareString = fileContent.substring(compareIndex);
Expand Down Expand Up @@ -363,12 +370,12 @@ async function normalizeLocaleFile(filePath: string, definitionKey: string) {
// In the long term we should probably define a whether we want those in the files at all.
const newContent = fileContentPreData + JSON.stringify(localeData);

writeFileSync(filePath, await formatTypescript(newContent));
return writeFile(filePath, await formatTypescript(newContent));
}

// Start of actual logic

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

let localeIndexImports = '';
Expand All @@ -377,6 +384,7 @@ let localeIndexExportsGrouped = '';
let localesIndexImports = '';

let localizationLocales = '| Locale | Name | Faker |\n| :--- | :--- | :--- |\n';
const promises: Array<Promise<unknown>> = [];

for (const locale of locales) {
const pathModules = resolve(pathLocales, locale);
Expand Down Expand Up @@ -408,18 +416,19 @@ for (const locale of locales) {
localesIndexImports += `import { default as ${locale} } from './${locale}';\n`;
localizationLocales += `| \`${locale}\` | ${localeTitle} | \`${localizedFaker}\` |\n`;

// src/locale/<locale>.ts
await generateLocaleFile(locale);
promises.push(
// src/locale/<locale>.ts
// eslint-disable-next-line unicorn/prefer-top-level-await -- Disabled for performance
generateLocaleFile(locale),

// src/locales/**/index.ts
await generateRecursiveModuleIndexes(
pathModules,
locale,
'LocaleDefinition',
1
// src/locales/**/index.ts
// eslint-disable-next-line unicorn/prefer-top-level-await -- Disabled for performance
generateRecursiveModuleIndexes(pathModules, locale, 'LocaleDefinition', 1)
);
}

await Promise.all(promises);
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved

// src/locale/index.ts

let localeIndexContent = `
Expand All @@ -437,7 +446,7 @@ let localeIndexContent = `
`;

localeIndexContent = await formatTypescript(localeIndexContent);
writeFileSync(pathLocaleIndex, localeIndexContent);
await writeFile(pathLocaleIndex, localeIndexContent);

// src/locales/index.ts

Expand All @@ -452,15 +461,15 @@ let localesIndexContent = `
`;

localesIndexContent = await formatTypescript(localesIndexContent);
writeFileSync(pathLocalesIndex, localesIndexContent);
await writeFile(pathLocalesIndex, localesIndexContent);

// docs/guide/localization.md

localizationLocales = await formatMarkdown(localizationLocales);

let localizationContent = readFileSync(pathDocsGuideLocalization, 'utf8');
let localizationContent = await readFile(pathDocsGuideLocalization, 'utf8');
localizationContent = localizationContent.replaceAll(
/(^<!-- LOCALES-AUTO-GENERATED-START -->$).*(^<!-- LOCALES-AUTO-GENERATED-END -->$)/gms,
`$1\n\n<!-- Run '${scriptCommand}' to update. -->\n\n${localizationLocales}\n$2`
);
writeFileSync(pathDocsGuideLocalization, localizationContent);
await writeFile(pathDocsGuideLocalization, localizationContent);