@x18n/node 0.0.0 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +258 -127
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
|
-
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { compileYamlPlugin } from "@x18n/builtins/yaml-plugin";
|
|
7
7
|
import { PluginFileSchema, X18nError, createProject, hashText, isX18nError, resolveConfig, validate } from "@x18n/core";
|
|
8
8
|
import { createJiti } from "jiti";
|
|
9
|
+
import { glob } from "tinyglobby";
|
|
9
10
|
import { parse, stringify } from "yaml";
|
|
10
11
|
import process from "node:process";
|
|
11
12
|
import { watch } from "chokidar";
|
|
12
13
|
import ignore from "ignore";
|
|
13
|
-
import { glob } from "tinyglobby";
|
|
14
14
|
import { createBuiltins } from "@x18n/builtins";
|
|
15
15
|
import { applyEdits, modify, parse as parse$1 } from "jsonc-parser";
|
|
16
16
|
//#region src/config.ts
|
|
@@ -41,9 +41,17 @@ function findConfigUpward(cwd) {
|
|
|
41
41
|
dir = parent;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
const core = fileURLToPath(import.meta.resolve("@x18n/core"));
|
|
45
|
+
const presets = fileURLToPath(import.meta.resolve("@x18n/builtins/presets"));
|
|
44
46
|
const jiti = createJiti(import.meta.url, {
|
|
45
47
|
moduleCache: false,
|
|
46
|
-
interopDefault: true
|
|
48
|
+
interopDefault: true,
|
|
49
|
+
alias: {
|
|
50
|
+
"@x18n/core": core,
|
|
51
|
+
"@x18n/cli/presets": presets,
|
|
52
|
+
"@x18n/cli": core,
|
|
53
|
+
"@x18n/builtins/presets": presets
|
|
54
|
+
}
|
|
47
55
|
});
|
|
48
56
|
/** Imports a JS or TS module (config, plugin, executed resource). */
|
|
49
57
|
async function importModule(file) {
|
|
@@ -91,16 +99,36 @@ function createPluginLoader(dir) {
|
|
|
91
99
|
}
|
|
92
100
|
};
|
|
93
101
|
}
|
|
94
|
-
/**
|
|
95
|
-
function
|
|
102
|
+
/** Workspace package directories of `root`, from `pnpm-workspace.yaml` or the `workspaces` field of `package.json`. */
|
|
103
|
+
async function workspacePackages(root) {
|
|
104
|
+
const pnpm = parse(await readFile(join(root, "pnpm-workspace.yaml"), "utf8").catch(() => "") || "{}");
|
|
105
|
+
const manifest = JSON.parse(await readFile(join(root, "package.json"), "utf8").catch(() => "{}"));
|
|
106
|
+
const field = (value, key) => typeof value === "object" && value !== null && key in value ? new Map(Object.entries(value)).get(key) : void 0;
|
|
107
|
+
const workspaces = field(manifest, "workspaces");
|
|
108
|
+
const patterns = [
|
|
109
|
+
field(pnpm, "packages"),
|
|
110
|
+
workspaces,
|
|
111
|
+
field(workspaces, "packages")
|
|
112
|
+
].flatMap((list) => Array.isArray(list) ? list.filter((item) => typeof item === "string") : []);
|
|
113
|
+
if (patterns.length === 0) return [];
|
|
114
|
+
return (await glob(patterns.filter((p) => !p.startsWith("!")).map((p) => `${p.replace(/\/$/, "")}/package.json`), {
|
|
115
|
+
cwd: root,
|
|
116
|
+
ignore: ["**/node_modules/**", ...patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1))]
|
|
117
|
+
})).map((file) => dirname(file)).sort();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Directories, relative to `root`, whose manifests count for preset detection: the parents up to the
|
|
121
|
+
* git root (`..`, `../..`), and the workspace packages of a monorepo root, where the i18n library is often listed.
|
|
122
|
+
*/
|
|
123
|
+
async function manifestRootsOf(root, gitRoot) {
|
|
96
124
|
const out = [];
|
|
97
|
-
|
|
125
|
+
const top = gitRoot ?? resolve(root);
|
|
98
126
|
let dir = resolve(root);
|
|
99
|
-
while (dir !==
|
|
127
|
+
while (dir !== top && dir.startsWith(top)) {
|
|
100
128
|
dir = dirname(dir);
|
|
101
129
|
out.push(relative(root, dir).replace(/\\/g, "/"));
|
|
102
130
|
}
|
|
103
|
-
return out;
|
|
131
|
+
return [...out, ...await workspacePackages(root)];
|
|
104
132
|
}
|
|
105
133
|
//#endregion
|
|
106
134
|
//#region src/host.ts
|
|
@@ -256,90 +284,6 @@ function createNodeHost(root, options = {}) {
|
|
|
256
284
|
};
|
|
257
285
|
}
|
|
258
286
|
//#endregion
|
|
259
|
-
//#region src/load.ts
|
|
260
|
-
async function projectSpecs(rootConfigFile, cwd) {
|
|
261
|
-
const configDir = rootConfigFile ? dirname(rootConfigFile) : resolve(cwd);
|
|
262
|
-
const rootConfig = rootConfigFile ? await loadConfigFile(rootConfigFile) : {};
|
|
263
|
-
const root = resolve(configDir, rootConfig.root ?? ".");
|
|
264
|
-
if (!rootConfig.projects?.length) return {
|
|
265
|
-
root,
|
|
266
|
-
specs: [{
|
|
267
|
-
root,
|
|
268
|
-
config: rootConfig,
|
|
269
|
-
parent: void 0,
|
|
270
|
-
configFile: rootConfigFile
|
|
271
|
-
}]
|
|
272
|
-
};
|
|
273
|
-
const { projects, ...parent } = rootConfig;
|
|
274
|
-
const dirs = await glob([...projects], {
|
|
275
|
-
cwd: root,
|
|
276
|
-
onlyDirectories: true,
|
|
277
|
-
ignore: ["**/node_modules/**"]
|
|
278
|
-
});
|
|
279
|
-
const specs = [];
|
|
280
|
-
for (const dir of dirs.sort()) {
|
|
281
|
-
const projectRoot = resolve(root, dir);
|
|
282
|
-
const file = findConfigFile(projectRoot);
|
|
283
|
-
const config = file ? await loadConfigFile(file) : {};
|
|
284
|
-
specs.push({
|
|
285
|
-
root: resolve(projectRoot, config.root ?? "."),
|
|
286
|
-
config,
|
|
287
|
-
parent,
|
|
288
|
-
configFile: file
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
return {
|
|
292
|
-
root,
|
|
293
|
-
specs
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
/** Finds the config, resolves every project and waits until each is indexed. */
|
|
297
|
-
async function loadWorkspace(options) {
|
|
298
|
-
const configFile = options.configFile ? resolve(options.cwd, options.configFile) : options.upward === false ? findConfigFile(resolve(options.cwd)) : findConfigUpward(options.cwd);
|
|
299
|
-
const { root, specs } = await projectSpecs(configFile, options.cwd);
|
|
300
|
-
const builtins = options.builtins ?? createBuiltins();
|
|
301
|
-
const gitRoot = findGitRoot(root);
|
|
302
|
-
const loaded = [];
|
|
303
|
-
for (const spec of specs) {
|
|
304
|
-
const name = spec.config.name ?? (spec.root === root ? relative(dirname(root), root) : relative(root, spec.root)).replace(/\\/g, "/");
|
|
305
|
-
if (options.project !== void 0 && options.project !== name) continue;
|
|
306
|
-
const host = createNodeHost(spec.root, {
|
|
307
|
-
cacheDir: options.cache === false ? false : void 0,
|
|
308
|
-
logger: options.logger
|
|
309
|
-
});
|
|
310
|
-
const projectHost = options.wrapHost?.(host) ?? host;
|
|
311
|
-
const setup = await resolveConfig({
|
|
312
|
-
host: projectHost,
|
|
313
|
-
config: spec.config,
|
|
314
|
-
parent: spec.parent,
|
|
315
|
-
builtins,
|
|
316
|
-
name,
|
|
317
|
-
runtime: "node",
|
|
318
|
-
loadPlugin: createPluginLoader(spec.configFile ? dirname(spec.configFile) : spec.root),
|
|
319
|
-
manifestRoots: manifestRootsOf(spec.root, gitRoot)
|
|
320
|
-
});
|
|
321
|
-
const project = createProject({
|
|
322
|
-
host: projectHost,
|
|
323
|
-
setup
|
|
324
|
-
});
|
|
325
|
-
await project.ready;
|
|
326
|
-
await host.flush();
|
|
327
|
-
loaded.push({
|
|
328
|
-
name,
|
|
329
|
-
root: spec.root,
|
|
330
|
-
configFile: spec.configFile,
|
|
331
|
-
host,
|
|
332
|
-
project
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
if (options.project !== void 0 && loaded.length === 0) throw new X18nError("X18N0003", options.project);
|
|
336
|
-
return {
|
|
337
|
-
root,
|
|
338
|
-
configFile,
|
|
339
|
-
projects: loaded
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
//#endregion
|
|
343
287
|
//#region src/migrate.ts
|
|
344
288
|
const frameworkPresets = {
|
|
345
289
|
"vue": "vue-i18n",
|
|
@@ -427,13 +371,30 @@ const handledByDefaults = [
|
|
|
427
371
|
async function readText(path) {
|
|
428
372
|
return readFile(path, "utf8").catch(() => void 0);
|
|
429
373
|
}
|
|
374
|
+
/** The first of `paths` that exists; the i18n-ally-next name comes first. */
|
|
375
|
+
async function readFirst(root, paths) {
|
|
376
|
+
for (const path of paths) {
|
|
377
|
+
const text = await readText(join(root, path));
|
|
378
|
+
if (text !== void 0) return {
|
|
379
|
+
path,
|
|
380
|
+
text
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
430
384
|
function isRecord(value) {
|
|
431
385
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
432
386
|
}
|
|
433
387
|
const asStrings = (value) => (Array.isArray(value) ? value : value === void 0 ? [] : [value]).filter((v) => typeof v === "string");
|
|
434
|
-
/**
|
|
388
|
+
/** Setting prefixes by priority: the i18n-ally-next fork renames `i18n-ally.*` keys, so its value is the newest. */
|
|
389
|
+
const settingPrefixes = [
|
|
390
|
+
"i18n-ally-next",
|
|
391
|
+
"i18n-ally",
|
|
392
|
+
"vue-i18n-ally"
|
|
393
|
+
];
|
|
394
|
+
/** `i18n-ally-next.*`, `i18n-ally.*` and legacy `vue-i18n-ally.*` keys from `.vscode/settings.json` and `*.code-workspace` files. */
|
|
435
395
|
async function readSettings(root) {
|
|
436
396
|
const settings = /* @__PURE__ */ new Map();
|
|
397
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
437
398
|
const keys = [];
|
|
438
399
|
const sources = [];
|
|
439
400
|
const vscode = await readText(join(root, ".vscode/settings.json"));
|
|
@@ -445,10 +406,13 @@ async function readSettings(root) {
|
|
|
445
406
|
for (const source of sources) {
|
|
446
407
|
if (!isRecord(source)) continue;
|
|
447
408
|
for (const [key, value] of Object.entries(source)) {
|
|
448
|
-
const match = /^(
|
|
449
|
-
if (
|
|
450
|
-
|
|
451
|
-
|
|
409
|
+
const match = /^(i18n-ally-next|i18n-ally|vue-i18n-ally)\.(.+)$/.exec(key);
|
|
410
|
+
if (!match) continue;
|
|
411
|
+
keys.push(key);
|
|
412
|
+
const rank = settingPrefixes.indexOf(match[1]);
|
|
413
|
+
if (rank < (ranks.get(match[2]) ?? Infinity)) {
|
|
414
|
+
settings.set(match[2], value);
|
|
415
|
+
ranks.set(match[2], rank);
|
|
452
416
|
}
|
|
453
417
|
}
|
|
454
418
|
}
|
|
@@ -521,7 +485,7 @@ function configFile(config, format) {
|
|
|
521
485
|
};
|
|
522
486
|
return {
|
|
523
487
|
path: "x18n.config.ts",
|
|
524
|
-
content: `import { defineConfig } from 'x18n'\n\n// Migrated from i18n-ally by \`x18n migrate i18n-ally\`.\nexport default defineConfig(${JSON.stringify(config, null, 2).replace(/"([a-z_$][\w$]*)":/gi, "$1:").replace(/'/g, "\\'").replace(/"/g, "'")})\n`
|
|
488
|
+
content: `import { defineConfig } from '@x18n/core'\n\n// Migrated from i18n-ally by \`x18n migrate i18n-ally\`.\nexport default defineConfig(${JSON.stringify(config, null, 2).replace(/"([a-z_$][\w$]*)":/gi, "$1:").replace(/'/g, "\\'").replace(/"/g, "'")})\n`
|
|
525
489
|
};
|
|
526
490
|
}
|
|
527
491
|
function readerOf(settings) {
|
|
@@ -639,17 +603,16 @@ function mapConfig(settings, parts, notes) {
|
|
|
639
603
|
...Object.keys(extract).length ? { extract } : {}
|
|
640
604
|
};
|
|
641
605
|
}
|
|
642
|
-
/**
|
|
643
|
-
async function
|
|
606
|
+
/** The x18n config that a project's i18n-ally settings and custom framework mean, or undefined without any. */
|
|
607
|
+
async function readI18nAllyConfig(root) {
|
|
644
608
|
const { settings, keys } = await readSettings(root);
|
|
645
|
-
|
|
646
|
-
|
|
609
|
+
return configOf(root, settings, keys);
|
|
610
|
+
}
|
|
611
|
+
async function configOf(root, settings, keys) {
|
|
612
|
+
const custom = await readFirst(root, [".vscode/i18n-ally-next-custom-framework.yml", ".vscode/i18n-ally-custom-framework.yml"]);
|
|
613
|
+
const customText = custom?.text;
|
|
614
|
+
if (keys.length === 0 && customText === void 0) return void 0;
|
|
647
615
|
const notes = [];
|
|
648
|
-
if (keys.length === 0 && customText === void 0) return {
|
|
649
|
-
files: [],
|
|
650
|
-
notes: ["No i18n-ally settings found."],
|
|
651
|
-
removable: []
|
|
652
|
-
};
|
|
653
616
|
const parts = {
|
|
654
617
|
regex: [],
|
|
655
618
|
scopes: void 0,
|
|
@@ -659,28 +622,43 @@ async function migrateI18nAlly(root, options = {}) {
|
|
|
659
622
|
};
|
|
660
623
|
if (customText !== void 0) customFramework(parse(customText), parts);
|
|
661
624
|
const config = mapConfig(settings, parts, notes);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
625
|
+
if (parts.exclusive) notes.push("The custom framework was exclusive (`monopoly`), so built-in presets are turned off (`presets: []`).");
|
|
626
|
+
return {
|
|
627
|
+
config,
|
|
628
|
+
plugin: parts.regex.length > 0 || parts.scopes !== void 0 || parts.templates.length > 0 || Object.keys(parts.localeInfo).length > 0 ? {
|
|
629
|
+
name: "custom",
|
|
630
|
+
...parts.regex.length ? { scanners: { regex: parts.regex } } : {},
|
|
631
|
+
...parts.scopes ? { scopes: { regex: parts.scopes } } : {},
|
|
632
|
+
...parts.templates.length ? { extract: { templates: parts.templates } } : {},
|
|
633
|
+
...Object.keys(parts.localeInfo).length ? { localeInfo: parts.localeInfo } : {}
|
|
634
|
+
} : void 0,
|
|
635
|
+
notes,
|
|
636
|
+
keys,
|
|
637
|
+
customFramework: custom?.path
|
|
670
638
|
};
|
|
671
|
-
|
|
672
|
-
|
|
639
|
+
}
|
|
640
|
+
/** Converts i18n-ally settings, custom framework and reviews into x18n files. Never deletes i18n-ally files. */
|
|
641
|
+
async function migrateI18nAlly(root, options = {}) {
|
|
642
|
+
const { settings, keys } = await readSettings(root);
|
|
643
|
+
const found = await configOf(root, settings, keys);
|
|
644
|
+
if (!found) return {
|
|
645
|
+
files: [],
|
|
646
|
+
notes: ["No i18n-ally settings found."],
|
|
647
|
+
removable: []
|
|
648
|
+
};
|
|
649
|
+
const { config, plugin } = found;
|
|
650
|
+
const notes = [...found.notes];
|
|
651
|
+
const reviews = (await readFirst(root, [".vscode/i18n-ally-next-reviews.yml", ".vscode/i18n-ally-reviews.yml"]))?.text;
|
|
652
|
+
const files = [];
|
|
653
|
+
const finalConfig = plugin !== void 0 ? {
|
|
673
654
|
...config,
|
|
674
655
|
plugins: ["./x18n/custom.x18n-plugin.yml"]
|
|
675
656
|
} : config;
|
|
676
657
|
files.push(configFile(finalConfig, options.format ?? "ts"));
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
content: `# yaml-language-server: $schema=${$schema}\n${stringify(rest)}`
|
|
682
|
-
});
|
|
683
|
-
}
|
|
658
|
+
if (plugin) files.push({
|
|
659
|
+
path: "x18n/custom.x18n-plugin.yml",
|
|
660
|
+
content: `# yaml-language-server: $schema=../node_modules/@x18n/core/schema/plugin.json\n${stringify(plugin)}`
|
|
661
|
+
});
|
|
684
662
|
let vscodeText = await readText(join(root, ".vscode/settings.json"));
|
|
685
663
|
if (vscodeText !== void 0) {
|
|
686
664
|
let changed = false;
|
|
@@ -703,11 +681,164 @@ async function migrateI18nAlly(root, options = {}) {
|
|
|
703
681
|
});
|
|
704
682
|
notes.push("Reviews were copied to `.x18n/reviews.yml`; x18n reads them once reviews ship (1.x).");
|
|
705
683
|
}
|
|
706
|
-
if (parts.exclusive) notes.push("The custom framework was exclusive (`monopoly`), so built-in presets are turned off (`presets: []`).");
|
|
707
684
|
return {
|
|
708
685
|
files,
|
|
709
686
|
notes,
|
|
710
|
-
removable: [...keys, ...
|
|
687
|
+
removable: [...keys, ...found.customFramework ? [found.customFramework] : []]
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
//#endregion
|
|
691
|
+
//#region src/load.ts
|
|
692
|
+
/** The nearest directory at or above `cwd`, up to the git root, whose `.vscode/settings.json` has i18n-ally settings. */
|
|
693
|
+
function findI18nAllyRoot(cwd, upward) {
|
|
694
|
+
let dir = resolve(cwd);
|
|
695
|
+
while (true) {
|
|
696
|
+
const settings = join(dir, ".vscode/settings.json");
|
|
697
|
+
if (existsSync(settings) && /"(?:i18n-ally-next|i18n-ally|vue-i18n-ally)\./.test(readFileSync(settings, "utf8"))) return dir;
|
|
698
|
+
const parent = dirname(dir);
|
|
699
|
+
if (!upward || parent === dir || existsSync(join(dir, ".git"))) return void 0;
|
|
700
|
+
dir = parent;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Without an x18n config, the project's i18n-ally settings act as defaults, so an i18n-ally project
|
|
705
|
+
* works as it did in the editor. A plugin applies them, so detection and the locale guess still fill gaps.
|
|
706
|
+
*/
|
|
707
|
+
async function i18nAllyFallback(root) {
|
|
708
|
+
const found = await readI18nAllyConfig(root);
|
|
709
|
+
if (!found) return void 0;
|
|
710
|
+
const { presets, plugins: _plugins, ...defaults } = found.config;
|
|
711
|
+
const settingsPlugin = {
|
|
712
|
+
name: "x18n:i18n-ally-settings",
|
|
713
|
+
config: (draft) => applyDefaults(draft, defaults)
|
|
714
|
+
};
|
|
715
|
+
return {
|
|
716
|
+
...presets ? { presets } : {},
|
|
717
|
+
plugins: [settingsPlugin, ...found.plugin ? [compileYamlPlugin(found.plugin)] : []]
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function applyDefaults(draft, config) {
|
|
721
|
+
if (config.sourceLocale) draft.sourceLocale = config.sourceLocale;
|
|
722
|
+
if (config.ignoreLocales) draft.ignoreLocales = [...draft.ignoreLocales, ...config.ignoreLocales];
|
|
723
|
+
if (config.resources) draft.resources = [...draft.resources, ...config.resources];
|
|
724
|
+
if (config.formats) draft.formats = {
|
|
725
|
+
...draft.formats,
|
|
726
|
+
...config.formats
|
|
727
|
+
};
|
|
728
|
+
if (config.keyStyle) draft.keyStyle = config.keyStyle;
|
|
729
|
+
if (config.namespace?.default) draft.namespace = {
|
|
730
|
+
...draft.namespace,
|
|
731
|
+
default: config.namespace.default
|
|
732
|
+
};
|
|
733
|
+
if (config.usage) draft.usage = {
|
|
734
|
+
...draft.usage,
|
|
735
|
+
keysInUse: [...draft.usage.keysInUse, ...config.usage.keysInUse ?? []],
|
|
736
|
+
derivedKeys: [...draft.usage.derivedKeys, ...config.usage.derivedKeys ?? []],
|
|
737
|
+
exclude: [...draft.usage.exclude, ...config.usage.exclude ?? []]
|
|
738
|
+
};
|
|
739
|
+
if (config.write) draft.write = {
|
|
740
|
+
sort: config.write.sort ?? draft.write.sort,
|
|
741
|
+
indent: config.write.indent ?? draft.write.indent,
|
|
742
|
+
keepFilled: config.write.keepFilled ?? draft.write.keepFilled
|
|
743
|
+
};
|
|
744
|
+
if (config.extract) draft.extract = {
|
|
745
|
+
...draft.extract,
|
|
746
|
+
...config.extract
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
async function projectSpecs(rootConfigFile, cwd, upward) {
|
|
750
|
+
if (!rootConfigFile) {
|
|
751
|
+
const settingsRoot = findI18nAllyRoot(cwd, upward);
|
|
752
|
+
const fallback = settingsRoot && await i18nAllyFallback(settingsRoot);
|
|
753
|
+
if (settingsRoot && fallback) return {
|
|
754
|
+
root: settingsRoot,
|
|
755
|
+
specs: [{
|
|
756
|
+
root: settingsRoot,
|
|
757
|
+
config: fallback,
|
|
758
|
+
parent: void 0,
|
|
759
|
+
configFile: join(settingsRoot, ".vscode/settings.json")
|
|
760
|
+
}]
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
const configDir = rootConfigFile ? dirname(rootConfigFile) : resolve(cwd);
|
|
764
|
+
const rootConfig = rootConfigFile ? await loadConfigFile(rootConfigFile) : {};
|
|
765
|
+
const root = resolve(configDir, rootConfig.root ?? ".");
|
|
766
|
+
if (!rootConfig.projects?.length) return {
|
|
767
|
+
root,
|
|
768
|
+
specs: [{
|
|
769
|
+
root,
|
|
770
|
+
config: rootConfig,
|
|
771
|
+
parent: void 0,
|
|
772
|
+
configFile: rootConfigFile
|
|
773
|
+
}]
|
|
774
|
+
};
|
|
775
|
+
const { projects, ...parent } = rootConfig;
|
|
776
|
+
const dirs = await glob([...projects], {
|
|
777
|
+
cwd: root,
|
|
778
|
+
onlyDirectories: true,
|
|
779
|
+
ignore: ["**/node_modules/**"]
|
|
780
|
+
});
|
|
781
|
+
const specs = [];
|
|
782
|
+
for (const dir of dirs.sort()) {
|
|
783
|
+
const projectRoot = resolve(root, dir);
|
|
784
|
+
const file = findConfigFile(projectRoot);
|
|
785
|
+
const config = file ? await loadConfigFile(file) : {};
|
|
786
|
+
specs.push({
|
|
787
|
+
root: resolve(projectRoot, config.root ?? "."),
|
|
788
|
+
config,
|
|
789
|
+
parent,
|
|
790
|
+
configFile: file
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
return {
|
|
794
|
+
root,
|
|
795
|
+
specs
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
/** Finds the config, resolves every project and waits until each is indexed. */
|
|
799
|
+
async function loadWorkspace(options) {
|
|
800
|
+
const configFile = options.configFile ? resolve(options.cwd, options.configFile) : options.upward === false ? findConfigFile(resolve(options.cwd)) : findConfigUpward(options.cwd);
|
|
801
|
+
const { root, specs } = await projectSpecs(configFile, options.cwd, options.upward !== false);
|
|
802
|
+
const builtins = options.builtins ?? createBuiltins();
|
|
803
|
+
const gitRoot = findGitRoot(root);
|
|
804
|
+
const loaded = [];
|
|
805
|
+
for (const spec of specs) {
|
|
806
|
+
const name = spec.config.name ?? (spec.root === root ? relative(dirname(root), root) : relative(root, spec.root)).replace(/\\/g, "/");
|
|
807
|
+
if (options.project !== void 0 && options.project !== name) continue;
|
|
808
|
+
const host = createNodeHost(spec.root, {
|
|
809
|
+
cacheDir: options.cache === false ? false : void 0,
|
|
810
|
+
logger: options.logger
|
|
811
|
+
});
|
|
812
|
+
const projectHost = options.wrapHost?.(host) ?? host;
|
|
813
|
+
const setup = await resolveConfig({
|
|
814
|
+
host: projectHost,
|
|
815
|
+
config: spec.config,
|
|
816
|
+
parent: spec.parent,
|
|
817
|
+
builtins,
|
|
818
|
+
name,
|
|
819
|
+
runtime: "node",
|
|
820
|
+
loadPlugin: createPluginLoader(spec.configFile ? dirname(spec.configFile) : spec.root),
|
|
821
|
+
manifestRoots: await manifestRootsOf(spec.root, gitRoot)
|
|
822
|
+
});
|
|
823
|
+
const project = createProject({
|
|
824
|
+
host: projectHost,
|
|
825
|
+
setup
|
|
826
|
+
});
|
|
827
|
+
await project.ready;
|
|
828
|
+
await host.flush();
|
|
829
|
+
loaded.push({
|
|
830
|
+
name,
|
|
831
|
+
root: spec.root,
|
|
832
|
+
configFile: spec.configFile,
|
|
833
|
+
host,
|
|
834
|
+
project
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
if (options.project !== void 0 && loaded.length === 0) throw new X18nError("X18N0003", options.project);
|
|
838
|
+
return {
|
|
839
|
+
root,
|
|
840
|
+
configFile,
|
|
841
|
+
projects: loaded
|
|
711
842
|
};
|
|
712
843
|
}
|
|
713
844
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x18n/node",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"description": "Node.js host for x18n: file system access, config and plugin loading",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"node": ">=22"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@x18n/builtins": "0.0.
|
|
29
|
-
"@x18n/core": "0.0.
|
|
28
|
+
"@x18n/builtins": "0.0.3",
|
|
29
|
+
"@x18n/core": "0.0.3",
|
|
30
30
|
"chokidar": "^5.0.0",
|
|
31
31
|
"ignore": "^7.0.12",
|
|
32
32
|
"jiti": "^2.6.1",
|