diff --git a/packages/core/package.json b/packages/core/package.json index b9f8b54..e1a7a19 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -49,6 +49,7 @@ "jiti": "2.3.3", "js-yaml": "^4.1.0", "neotraverse": "^0.6.18", + "p-all": "^5.0.0", "path-to-regexp": "6.3.0", "picomatch": "^4.0.2", "simple-git": "^3.27.0", diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8a06632..8edf449 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,6 @@ import { resolve } from 'node:path'; import { type ConsolaInstance, createConsola } from 'consola'; +import pAll from 'p-all'; import picomatch from 'picomatch'; import { glob } from 'tinyglobby'; import { loadConfig, validateInitialConfig } from './config/config.js'; @@ -91,17 +92,27 @@ class Lunaria { ); } - /** We use `Promise.all` to allow the promises to run in parallel, increasing the performance considerably. */ - const entries = ( - await Promise.all( - sourceFilePaths.map(async (path) => { - return await this.#getFileStatus(path, false); - }), - ) - ).sort((a, b) => (a?.source.path ?? '').localeCompare(b?.source.path ?? '')); - - for (const entry of entries) { - if (entry) status.push(entry); + const entries: LunariaStatus = new Array(sourceFilePaths.length); + + await pAll( + sourceFilePaths.map((path) => { + return async () => { + const entry = await this.getFileStatus(path); + if (entry) entries.push(entry); + }; + }), + { + concurrency: 10, + }, + ); + + // We sort the entries by source path to make the resulting status consistent. + // That is, entries will be laid out by precedence in the `files` array, and then + // sorted internally. + const sortedEntries = entries.sort((a, b) => a.source.path.localeCompare(b.source.path)); + + for (const entry of sortedEntries) { + status.push(entry); } } @@ -170,23 +181,20 @@ class Lunaria { await cache.write(this.#git.cache); } - return { - ...file, - source: { - lang: this.config.sourceLocale.lang, - path: sourcePath, - git: latestSourceChanges, - }, - localizations: await Promise.all( - this.config.locales.map(async ({ lang }): Promise => { + const localizations: StatusLocalizationEntry[] = new Array(this.config.locales.length); + + const tasks = this.config.locales.map(({ lang }) => { + return async () => { + { const localizedPath = toPath(sourcePath, lang); if (!(await exists(resolve(externalSafePath(external, this.#cwd, localizedPath))))) { - return { + localizations.push({ lang: lang, path: localizedPath, status: 'missing', - }; + }); + return; } const latestLocaleChanges = await this.#git.getFileLatestChanges(localizedPath); @@ -221,15 +229,27 @@ class Lunaria { return {}; }; - return { + localizations.push({ lang: lang, path: localizedPath, git: latestLocaleChanges, status: isOutdated ? 'outdated' : 'up-to-date', ...(await entryTypeData()), - }; - }), - ), + }); + } + }; + }); + + await pAll(tasks, { concurrency: 5 }); + + return { + ...file, + source: { + lang: this.config.sourceLocale.lang, + path: sourcePath, + git: latestSourceChanges, + }, + localizations, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index befbd2e..99a4f6d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,9 @@ importers: neotraverse: specifier: ^0.6.18 version: 0.6.18 + p-all: + specifier: ^5.0.0 + version: 5.0.0 path-to-regexp: specifier: 6.3.0 version: 6.3.0 @@ -2628,6 +2631,10 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + p-all@5.0.0: + resolution: {integrity: sha512-pofqu/1FhCVa+78xNAptCGc9V45exFz2pvBRyIvgXkNM0Rh18Py7j8pQuSjA+zpabI46v9hRjNWmL9EAFcEbpw==} + engines: {node: '>=16'} + p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} @@ -2656,6 +2663,10 @@ packages: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} + p-map@6.0.0: + resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} + engines: {node: '>=16'} + p-queue@8.0.1: resolution: {integrity: sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==} engines: {node: '>=18'} @@ -6882,6 +6893,10 @@ snapshots: outdent@0.5.0: {} + p-all@5.0.0: + dependencies: + p-map: 6.0.0 + p-filter@2.1.0: dependencies: p-map: 2.1.0 @@ -6908,6 +6923,8 @@ snapshots: p-map@2.1.0: {} + p-map@6.0.0: {} + p-queue@8.0.1: dependencies: eventemitter3: 5.0.1