Skip to content

Commit

Permalink
Merge branch 'next' into infra/unicorn/prefer-number-properties
Browse files Browse the repository at this point in the history
  • Loading branch information
ST-DDT authored Oct 19, 2023
2 parents eca7150 + a882244 commit 9132cf7
Showing 1 changed file with 113 additions and 11 deletions.
124 changes: 113 additions & 11 deletions scripts/generateLocales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ async function generateRecursiveModuleIndexes(
submodules = removeIndexTs(submodules);
for (const submodule of submodules) {
const pathModule = resolve(path, submodule);
updateLocaleFile(pathModule);
await updateLocaleFile(pathModule);
// Only process sub folders recursively
if (lstatSync(pathModule).isDirectory()) {
let moduleDefinition =
Expand Down Expand Up @@ -238,14 +238,12 @@ async function generateRecursiveModuleIndexes(
*
* @param filePath The full file path to the file.
*/
function updateLocaleFile(filePath: string): void {
async function updateLocaleFile(filePath: string): Promise<void> {
if (lstatSync(filePath).isFile()) {
const pathParts = filePath
const [locale, moduleKey, entryKey] = filePath
.substring(pathLocales.length + 1, filePath.length - 3)
.split(/[\\/]/);
const locale = pathParts[0];
pathParts.splice(0, 1);
updateLocaleFileHook(filePath, locale, pathParts);
await updateLocaleFileHook(filePath, locale, moduleKey, entryKey);
}
}

Expand All @@ -255,16 +253,120 @@ function updateLocaleFile(filePath: string): void {
*
* @param filePath The full file path to the file.
* @param locale The locale for that file.
* @param localePath The locale path parts (after the locale).
* @param definitionKey The definition key of the current file (ex. 'location').
* @param entryName The entry key of the current file (ex. 'state'). Is `undefined` if `definitionKey` is `'metadata'`.
*/
function updateLocaleFileHook(
async function updateLocaleFileHook(
filePath: string,
locale: string,
localePath: string[]
): void {
definitionKey: string,
entryName: string | undefined
): Promise<void> {
// this needs to stay so all arguments are "used"
if (filePath === 'never') {
console.log(`${filePath} <-> ${locale} @ ${localePath.join(' -> ')}`);
console.log(`${filePath} <-> ${locale} @ ${definitionKey} -> ${entryName}`);
}

await normalizeLocaleFile(filePath, definitionKey);
}

/**
* Normalizes the data of a locale file based on a set of rules.
* Those include:
* - filter the entry list for duplicates
* - limiting the maximum entries of a file to 1000
* - sorting the entries alphabetically
*
* This function mutates the file by reading and writing to it!
*
* @param filePath The full file path to the file.
* @param definitionKey The definition key of the current file (ex. 'location').
*/
async function normalizeLocaleFile(filePath: string, definitionKey: string) {
function normalizeDataRecursive<T>(localeData: T): T {
if (typeof localeData !== 'object' || localeData === null) {
// we can only traverse object-like structs
return localeData;
}

if (Array.isArray(localeData)) {
return (
[...new Set(localeData)]
// limit entries to 1k
.slice(0, 1000)
// sort entries alphabetically
.sort() as T
);
}

const result = {} as T;
for (const key of Object.keys(localeData)) {
result[key] = normalizeDataRecursive(localeData[key]);
}

return result;
}

const legacyDefinitions = ['app', 'cell_phone', 'team'];
const definitionsToSkip = [
'airline',
'animal',
'color',
'commerce',
'company',
'database',
'date',
'finance',
'hacker',
'internet',
'location',
'lorem',
'metadata',
'music',
'person',
'phone_number',
'science',
'system',
'vehicle',
'word',
...legacyDefinitions,
];
if (definitionsToSkip.includes(definitionKey)) {
return;
}

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

const fileContent = readFileSync(filePath).toString();
const searchString = 'export default ';
const compareIndex = fileContent.indexOf(searchString) + searchString.length;
const compareString = fileContent.substring(compareIndex);

const isDynamicFile = compareString.startsWith('mergeArrays');
const isNonApplicable = compareString.startsWith('null');
const isFrozenData = compareString.startsWith('Object.freeze');
if (isDynamicFile || isNonApplicable || isFrozenData) {
return;
}

const validEntryListStartCharacters = ['[', '{'];
const staticFileOpenSyntax = validEntryListStartCharacters.find(
(validStart) => compareString.startsWith(validStart)
);
if (staticFileOpenSyntax === undefined) {
console.log('Found an unhandled dynamic file:', filePath);
return;
}

const fileContentPreData = fileContent.substring(0, compareIndex);
// eslint-disable-next-line @typescript-eslint/no-var-requires
const localeData = normalizeDataRecursive(require(filePath).default);

// We reattach the content before the actual data implementation to keep stuff like comments.
// 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 format(newContent, prettierTsOptions));
}

// Start of actual logic
Expand Down

0 comments on commit 9132cf7

Please sign in to comment.