@x18n/node 0.0.13 → 0.0.14
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 +97 -4
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -3,11 +3,12 @@ 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
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
-
import { compileYamlPlugin } from "@x18n/builtins/yaml-plugin";
|
|
7
6
|
import { PluginFileSchema, createProject, errors, hashText, isX18nError, resolveConfig, validate } from "@x18n/core";
|
|
8
7
|
import { createJiti } from "jiti";
|
|
9
8
|
import { glob } from "tinyglobby";
|
|
10
9
|
import { parse, stringify } from "yaml";
|
|
10
|
+
import { placeholderFromShape } from "@x18n/builtins/placeholders";
|
|
11
|
+
import regexScopes from "@x18n/builtins/scanners/regex-scopes";
|
|
11
12
|
import process from "node:process";
|
|
12
13
|
import { watch } from "chokidar";
|
|
13
14
|
import ignore from "ignore";
|
|
@@ -15,6 +16,76 @@ import { createBuiltins } from "@x18n/builtins";
|
|
|
15
16
|
import { Buffer } from "node:buffer";
|
|
16
17
|
import { execFile, spawn } from "node:child_process";
|
|
17
18
|
import { applyEdits, modify, parse as parse$1 } from "jsonc-parser";
|
|
19
|
+
//#region src/yaml-plugin.ts
|
|
20
|
+
/**
|
|
21
|
+
* Compiles a validated YAML plugin into plugin objects. Each section maps to the
|
|
22
|
+
* options of a built-in factory, so moving to a TS plugin is a small change.
|
|
23
|
+
*/
|
|
24
|
+
function compileYamlPlugin(data) {
|
|
25
|
+
const replacements = (data.normalizeKey ?? []).map((rule) => ({
|
|
26
|
+
from: new RegExp(rule.replace.pattern, "g"),
|
|
27
|
+
to: rule.replace.with
|
|
28
|
+
}));
|
|
29
|
+
const localeInfo = data.localeInfo;
|
|
30
|
+
const plugin = {
|
|
31
|
+
name: data.name,
|
|
32
|
+
config(draft) {
|
|
33
|
+
const defaults = data.config;
|
|
34
|
+
if (defaults?.sourceLocale) draft.sourceLocale = defaults.sourceLocale;
|
|
35
|
+
if (defaults?.locales) draft.locales = defaults.locales;
|
|
36
|
+
if (defaults?.resources && draft.resources.length === 0) draft.resources = defaults.resources;
|
|
37
|
+
if (defaults?.keyStyle) draft.keyStyle = defaults.keyStyle;
|
|
38
|
+
if (defaults?.namespace) draft.namespace = {
|
|
39
|
+
separator: defaults.namespace.separator ?? draft.namespace.separator,
|
|
40
|
+
default: defaults.namespace.default ?? draft.namespace.default,
|
|
41
|
+
fallback: defaults.namespace.fallback ?? draft.namespace.fallback,
|
|
42
|
+
byFile: {
|
|
43
|
+
...draft.namespace.byFile,
|
|
44
|
+
...defaults.namespace.byFile
|
|
45
|
+
},
|
|
46
|
+
fromPath: defaults.namespace.fromPath ?? draft.namespace.fromPath
|
|
47
|
+
};
|
|
48
|
+
draft.usage = {
|
|
49
|
+
...draft.usage,
|
|
50
|
+
calls: [...draft.usage.calls, ...data.scanners?.calls ?? []],
|
|
51
|
+
regex: [...draft.usage.regex, ...data.scanners?.regex ?? []]
|
|
52
|
+
};
|
|
53
|
+
if (data.extract?.templates) draft.extract = {
|
|
54
|
+
...draft.extract,
|
|
55
|
+
templates: [...draft.extract.templates ?? [], ...data.extract.templates]
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
derivedKeys: data.derivedKeys,
|
|
59
|
+
placeholders: data.placeholders?.map(placeholderFromShape),
|
|
60
|
+
normalizeKey: replacements.length > 0 ? (raw) => replacements.reduce((text, rule) => text.replace(rule.from, rule.to), raw) : void 0,
|
|
61
|
+
localeInfo: localeInfo ? (code) => {
|
|
62
|
+
const info = localeInfo[code];
|
|
63
|
+
return info ? {
|
|
64
|
+
...info.flag ? { flag: info.flag } : {},
|
|
65
|
+
...info.displayName ? { displayName: info.displayName } : {}
|
|
66
|
+
} : void 0;
|
|
67
|
+
} : void 0
|
|
68
|
+
};
|
|
69
|
+
const plugins = [plugin, ...data.scopes ? [regexScopes(data.scopes.regex, `${data.name}-scopes`)] : []];
|
|
70
|
+
const detect = data.detect;
|
|
71
|
+
if (!detect) return plugins.length === 1 ? plugin : {
|
|
72
|
+
name: data.name,
|
|
73
|
+
plugins
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
name: data.name,
|
|
77
|
+
exclusive: data.exclusive,
|
|
78
|
+
plugins,
|
|
79
|
+
async detect(ctx) {
|
|
80
|
+
const deps = detect.dependencies;
|
|
81
|
+
if (deps?.any && !ctx.hasAnyDependency(deps.any)) return false;
|
|
82
|
+
if (deps?.all && !deps.all.every(ctx.hasDependency)) return false;
|
|
83
|
+
for (const pattern of detect.files ?? []) if (!await ctx.fileExists(pattern)) return false;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
18
89
|
//#region src/config.ts
|
|
19
90
|
const configFileNames = [
|
|
20
91
|
"x18n.config.ts",
|
|
@@ -43,6 +114,15 @@ function findConfigUpward(cwd) {
|
|
|
43
114
|
dir = parent;
|
|
44
115
|
}
|
|
45
116
|
}
|
|
117
|
+
/** One config file per directory below `dir`, shallowest first. */
|
|
118
|
+
async function findConfigsBelow(dir) {
|
|
119
|
+
const files = await glob(configFileNames.map((name) => `**/${name}`), {
|
|
120
|
+
cwd: dir,
|
|
121
|
+
absolute: true,
|
|
122
|
+
ignore: ["**/node_modules/**"]
|
|
123
|
+
});
|
|
124
|
+
return [...new Set(files.map((file) => dirname(file)))].sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b)).flatMap((found) => findConfigFile(found) ?? []);
|
|
125
|
+
}
|
|
46
126
|
function resolveOwn(specifier) {
|
|
47
127
|
try {
|
|
48
128
|
return fileURLToPath(import.meta.resolve(specifier));
|
|
@@ -153,7 +233,9 @@ async function manifestRootsOf(root, gitRoot) {
|
|
|
153
233
|
}
|
|
154
234
|
//#endregion
|
|
155
235
|
//#region src/host.ts
|
|
156
|
-
|
|
236
|
+
function toPosix(path) {
|
|
237
|
+
return sep === "\\" ? path.replace(/\\/g, "/") : path;
|
|
238
|
+
}
|
|
157
239
|
function isNotFound(error) {
|
|
158
240
|
return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "EISDIR");
|
|
159
241
|
}
|
|
@@ -759,7 +841,9 @@ async function readFirst(root, paths) {
|
|
|
759
841
|
function isRecord(value) {
|
|
760
842
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
761
843
|
}
|
|
762
|
-
|
|
844
|
+
function asStrings(value) {
|
|
845
|
+
return (Array.isArray(value) ? value : value === void 0 ? [] : [value]).filter((v) => typeof v === "string");
|
|
846
|
+
}
|
|
763
847
|
/** Setting prefixes by priority: the i18n-ally-next fork renames `i18n-ally.*` keys, so its value is the newest. */
|
|
764
848
|
const settingPrefixes = [
|
|
765
849
|
"i18n-ally-next",
|
|
@@ -1127,6 +1211,15 @@ function applyDefaults(draft, config) {
|
|
|
1127
1211
|
}
|
|
1128
1212
|
async function projectSpecs(rootConfigFile, cwd, upward) {
|
|
1129
1213
|
if (!rootConfigFile) {
|
|
1214
|
+
const nested = await findConfigsBelow(cwd);
|
|
1215
|
+
if (nested.length) {
|
|
1216
|
+
const specs = [];
|
|
1217
|
+
for (const file of nested) if (!specs.some((spec) => spec.configFile === file)) specs.push(...(await projectSpecs(file, cwd, false)).specs);
|
|
1218
|
+
return {
|
|
1219
|
+
root: resolve(cwd),
|
|
1220
|
+
specs
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1130
1223
|
const settingsRoot = findI18nAllyRoot(cwd, upward);
|
|
1131
1224
|
const fallback = settingsRoot && await i18nAllyFallback(settingsRoot);
|
|
1132
1225
|
if (settingsRoot && fallback) return {
|
|
@@ -1179,7 +1272,7 @@ async function loadWorkspace(options) {
|
|
|
1179
1272
|
const configFile = options.configFile ? resolve(options.cwd, options.configFile) : options.upward === false ? findConfigFile(resolve(options.cwd)) : findConfigUpward(options.cwd);
|
|
1180
1273
|
const { root, specs } = await projectSpecs(configFile, options.cwd, options.upward !== false);
|
|
1181
1274
|
const gitRoot = findGitRoot(root);
|
|
1182
|
-
const defaults = options.builtins ?? createBuiltins();
|
|
1275
|
+
const defaults = options.builtins ?? await createBuiltins();
|
|
1183
1276
|
const builtins = gitRoot ? {
|
|
1184
1277
|
...defaults,
|
|
1185
1278
|
plugins: [...defaults.plugins, gitHistory()]
|
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.14",
|
|
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.14",
|
|
29
|
+
"@x18n/core": "0.0.14",
|
|
30
30
|
"chokidar": "^6.0.0",
|
|
31
31
|
"ignore": "^7.0.13",
|
|
32
32
|
"jiti": "^2.7.0",
|