@sfmc-bds/cli 0.2.0-beta.11 → 0.2.0-beta.13
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/commands.d.ts +57 -4
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +1 -1
- package/dist/i18n/locales/zh-CN.js.map +1 -1
- package/dist/log-filter.d.ts +18 -2
- package/dist/log-filter.d.ts.map +1 -1
- package/dist/log-filter.js +54 -4
- package/dist/log-filter.js.map +2 -2
- package/dist/log-filter.test.js +62 -0
- package/dist/log-filter.test.js.map +2 -2
- package/dist/log-translator.d.ts +36 -0
- package/dist/log-translator.d.ts.map +1 -0
- package/dist/log-translator.js +279 -0
- package/dist/log-translator.js.map +7 -0
- package/dist/log-translator.test.js +120 -0
- package/dist/log-translator.test.js.map +7 -0
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +13 -7
- package/dist/logs.js.map +2 -2
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +21 -7
- package/dist/module-commands.js.map +2 -2
- package/dist/module-fingerprint.d.ts.map +1 -1
- package/dist/module-fingerprint.js +1 -0
- package/dist/module-fingerprint.js.map +2 -2
- package/dist/module-pack-build.d.ts.map +1 -1
- package/dist/module-pack-build.js +6 -1
- package/dist/module-pack-build.js.map +2 -2
- package/dist/module-toggle.d.ts +1 -1
- package/dist/module-toggle.d.ts.map +1 -1
- package/dist/module-toggle.js.map +1 -1
- package/dist/pack-lifecycle.d.ts.map +1 -1
- package/dist/pack-lifecycle.js +7 -2
- package/dist/pack-lifecycle.js.map +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -1
- package/dist/registry.js.map +2 -2
- package/dist/repl-windows/format-display.d.ts.map +1 -1
- package/dist/repl-windows/format-display.js +5 -1
- package/dist/repl-windows/format-display.js.map +2 -2
- package/dist/services.d.ts +14 -0
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js.map +2 -2
- package/dist/sfmc-modules-root.d.ts.map +1 -1
- package/dist/sfmc-modules-root.js +6 -2
- package/dist/sfmc-modules-root.js.map +2 -2
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +20 -22
- package/dist/wizard.js.map +2 -2
- package/package.json +5 -4
- package/scripts/module-install/check-modules.mjs +10 -76
- package/scripts/module-install/lib/catalog.mjs +1 -1
- package/scripts/module-install/lib/lock.mjs +2 -2
- package/scripts/module-install/lib/packages.mjs +16 -22
package/dist/log-filter.js
CHANGED
|
@@ -2,10 +2,13 @@ import { ensureSchemaConfig, readJson, stripConfigMeta } from "@sfmc-bds/sdk/nod
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { ROOT } from "./runtime.js";
|
|
5
|
+
import { applyRuleReplacement, translateBdsLog } from "./log-translator.js";
|
|
6
|
+
import { getLocale } from "./i18n/index.js";
|
|
5
7
|
const DEFAULTS = {
|
|
6
8
|
enabled: false,
|
|
7
9
|
mode: "drop",
|
|
8
10
|
applyTo: "display",
|
|
11
|
+
translate: true,
|
|
9
12
|
rules: []
|
|
10
13
|
};
|
|
11
14
|
function logFilterConfigPath() {
|
|
@@ -33,7 +36,7 @@ function compileRules(rules, onBadRegex) {
|
|
|
33
36
|
const out = [];
|
|
34
37
|
for (const r of rules) {
|
|
35
38
|
if (r.enabled === false) continue;
|
|
36
|
-
const hasAny = r.sources && r.sources.length > 0 || r.levels && r.levels.length > 0 || typeof r.contains === "string" && r.contains.length > 0 || typeof r.regex === "string" && r.regex.length > 0;
|
|
39
|
+
const hasAny = r.sources && r.sources.length > 0 || r.levels && r.levels.length > 0 || typeof r.contains === "string" && r.contains.length > 0 || typeof r.regex === "string" && r.regex.length > 0 || typeof r.replace === "string" && r.replace.length > 0;
|
|
37
40
|
if (!hasAny) continue;
|
|
38
41
|
const compiled = {};
|
|
39
42
|
if (r.sources && r.sources.length > 0) {
|
|
@@ -53,6 +56,9 @@ function compileRules(rules, onBadRegex) {
|
|
|
53
56
|
}
|
|
54
57
|
compiled.regex = re;
|
|
55
58
|
}
|
|
59
|
+
if (typeof r.replace === "string") {
|
|
60
|
+
compiled.replace = r.replace;
|
|
61
|
+
}
|
|
56
62
|
out.push(compiled);
|
|
57
63
|
}
|
|
58
64
|
return out;
|
|
@@ -61,11 +67,13 @@ function normalizeConfig(raw) {
|
|
|
61
67
|
const stripped = stripConfigMeta(raw);
|
|
62
68
|
const mode = stripped.mode === "keep" ? "keep" : "drop";
|
|
63
69
|
const applyTo = stripped.applyTo === "all" ? "all" : "display";
|
|
70
|
+
const translate = stripped.translate !== void 0 ? Boolean(stripped.translate) : true;
|
|
64
71
|
const rules = Array.isArray(stripped.rules) ? stripped.rules : [];
|
|
65
72
|
return {
|
|
66
73
|
enabled: Boolean(stripped.enabled),
|
|
67
74
|
mode,
|
|
68
75
|
applyTo,
|
|
76
|
+
translate,
|
|
69
77
|
rules
|
|
70
78
|
};
|
|
71
79
|
}
|
|
@@ -92,6 +100,7 @@ function getCompiledLogFilter(onBadRegex) {
|
|
|
92
100
|
enabled: cfg.enabled,
|
|
93
101
|
mode: cfg.mode,
|
|
94
102
|
applyTo: cfg.applyTo,
|
|
103
|
+
translate: cfg.translate ?? true,
|
|
95
104
|
rules,
|
|
96
105
|
mtimeMs
|
|
97
106
|
};
|
|
@@ -118,21 +127,61 @@ function shouldDropForDisk(entry, filter) {
|
|
|
118
127
|
if (filter.applyTo !== "all") return false;
|
|
119
128
|
return shouldDropForDisplay(entry, filter);
|
|
120
129
|
}
|
|
130
|
+
function transformLogEntry(entry, filter, locale) {
|
|
131
|
+
if (filter && filter.rules.length > 0) {
|
|
132
|
+
for (const rule of filter.rules) {
|
|
133
|
+
if (rule.replace && ruleMatchesEntry(rule, entry)) {
|
|
134
|
+
let newText = entry.text;
|
|
135
|
+
if (rule.regex) {
|
|
136
|
+
newText = applyRuleReplacement(entry.text, rule.regex, rule.replace);
|
|
137
|
+
} else if (rule.contains) {
|
|
138
|
+
newText = entry.text.replaceAll(rule.contains, rule.replace);
|
|
139
|
+
} else {
|
|
140
|
+
newText = rule.replace;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
entry: { ...entry, text: newText },
|
|
144
|
+
transformed: true
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const translateEnabled = filter ? filter.translate : true;
|
|
150
|
+
if (translateEnabled && entry.source.toLowerCase() === "bds") {
|
|
151
|
+
let loc;
|
|
152
|
+
try {
|
|
153
|
+
loc = locale ?? getLocale();
|
|
154
|
+
} catch {
|
|
155
|
+
loc = locale ?? "zh-CN";
|
|
156
|
+
}
|
|
157
|
+
const res = translateBdsLog(entry.text, loc);
|
|
158
|
+
if (res.translated) {
|
|
159
|
+
return {
|
|
160
|
+
entry: { ...entry, text: res.text },
|
|
161
|
+
transformed: true
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { entry, transformed: false };
|
|
166
|
+
}
|
|
121
167
|
function resetLogFilterCacheForTests() {
|
|
122
168
|
cache = null;
|
|
123
169
|
}
|
|
124
|
-
function evaluateLogFilter(entry, cfg) {
|
|
170
|
+
function evaluateLogFilter(entry, cfg, locale) {
|
|
125
171
|
const compiled = {
|
|
126
172
|
enabled: cfg.enabled,
|
|
127
173
|
mode: cfg.mode,
|
|
128
174
|
applyTo: cfg.applyTo,
|
|
175
|
+
translate: cfg.translate ?? true,
|
|
129
176
|
rules: compileRules(cfg.rules),
|
|
130
177
|
mtimeMs: 0
|
|
131
178
|
};
|
|
179
|
+
const transformRes = transformLogEntry(entry, compiled, locale);
|
|
132
180
|
return {
|
|
133
181
|
matched: entryMatchesAnyRule(entry, compiled.rules),
|
|
134
182
|
dropDisplay: shouldDropForDisplay(entry, compiled),
|
|
135
|
-
dropDisk: shouldDropForDisk(entry, compiled)
|
|
183
|
+
dropDisk: shouldDropForDisk(entry, compiled),
|
|
184
|
+
transformedEntry: transformRes.entry
|
|
136
185
|
};
|
|
137
186
|
}
|
|
138
187
|
export {
|
|
@@ -145,6 +194,7 @@ export {
|
|
|
145
194
|
resetLogFilterCacheForTests,
|
|
146
195
|
ruleMatchesEntry,
|
|
147
196
|
shouldDropForDisk,
|
|
148
|
-
shouldDropForDisplay
|
|
197
|
+
shouldDropForDisplay,
|
|
198
|
+
transformLogEntry
|
|
149
199
|
};
|
|
150
200
|
//# sourceMappingURL=log-filter.js.map
|
package/dist/log-filter.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/log-filter.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * log-filter.ts \u2014 configs/log-filter.json \u52A0\u8F7D\u4E0E\u5339\u914D\uFF08\u7EAF\u5224\u5B9A + \u70ED\u8BFB\u7F13\u5B58\uFF09\n */\nimport { ensureSchemaConfig, readJson, stripConfigMeta } from \"@sfmc-bds/sdk/node/config\";\nimport type { LogLevel } from \"@sfmc-bds/sdk/logs\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { ROOT } from \"./runtime.js\";\n\nexport type LogFilterMode = \"drop\" | \"keep\";\nexport type LogFilterApplyTo = \"display\" | \"all\";\n\nexport interface LogFilterRule {\n enabled?: boolean;\n sources?: string[];\n levels?: LogLevel[];\n contains?: string;\n /** JS RegExp \u6E90\uFF1B\u652F\u6301\u524D\u7F00 (?i) \u8868\u793A\u5FFD\u7565\u5927\u5C0F\u5199 */\n regex?: string;\n}\n\nexport interface LogFilterConfig {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n rules: LogFilterRule[];\n}\n\nexport type LogFilterEntry = {\n text: string;\n source: string;\n level: LogLevel;\n};\n\nconst DEFAULTS: LogFilterConfig = {\n enabled: false,\n mode: \"drop\",\n applyTo: \"display\",\n rules: [],\n};\n\nexport function logFilterConfigPath(): string {\n return path.join(ROOT, \"configs\", \"log-filter.json\");\n}\n\n/** \u786E\u4FDD configs/log-filter.json \u5B58\u5728\uFF08\u59D4\u6258 SDK ensureSchemaConfig\uFF0C\u7981\u6B62\u624B\u5199 withConfigSchema\uFF09 */\nexport function ensureLogFilterConfigFile(): string {\n ensureSchemaConfig(ROOT, \"log-filter.json\", \"log_filter\", { ...DEFAULTS } as Record<string, unknown>);\n return logFilterConfigPath();\n}\n\ntype CompiledRule = {\n sources?: Set<string>;\n levels?: Set<string>;\n contains?: string;\n regex?: RegExp;\n};\n\ntype CompiledFilter = {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n rules: CompiledRule[];\n mtimeMs: number;\n};\n\nlet cache: CompiledFilter | null = null;\n\n/** \u5C06 (?i) \u524D\u7F00\u8F6C\u4E3A RegExp i \u65D7\u6807\uFF08JS \u65E0\u5185\u8054 (?i)\uFF09 */\nexport function compileLogFilterRegex(src: string): RegExp | null {\n let pattern = String(src ?? \"\");\n let flags = \"\";\n if (pattern.startsWith(\"(?i)\")) {\n pattern = pattern.slice(4);\n flags = \"i\";\n }\n try {\n return new RegExp(pattern, flags);\n } catch {\n return null;\n }\n}\n\nfunction compileRules(rules: LogFilterRule[], onBadRegex?: (src: string) => void): CompiledRule[] {\n const out: CompiledRule[] = [];\n for (const r of rules) {\n if (r.enabled === false) continue;\n const hasAny =\n (r.sources && r.sources.length > 0) ||\n (r.levels && r.levels.length > 0) ||\n (typeof r.contains === \"string\" && r.contains.length > 0) ||\n (typeof r.regex === \"string\" && r.regex.length > 0);\n if (!hasAny) continue;\n\n const compiled: CompiledRule = {};\n if (r.sources && r.sources.length > 0) {\n compiled.sources = new Set(r.sources.map((s) => s.toLowerCase()));\n }\n if (r.levels && r.levels.length > 0) {\n compiled.levels = new Set(r.levels.map((l) => l.toLowerCase()));\n }\n if (typeof r.contains === \"string\" && r.contains.length > 0) {\n compiled.contains = r.contains;\n }\n if (typeof r.regex === \"string\" && r.regex.length > 0) {\n const re = compileLogFilterRegex(r.regex);\n if (!re) {\n onBadRegex?.(r.regex);\n continue;\n }\n compiled.regex = re;\n }\n out.push(compiled);\n }\n return out;\n}\n\nfunction normalizeConfig(raw: Record<string, unknown>): LogFilterConfig {\n const stripped = stripConfigMeta(raw);\n const mode = stripped.mode === \"keep\" ? \"keep\" : \"drop\";\n const applyTo = stripped.applyTo === \"all\" ? \"all\" : \"display\";\n const rules = Array.isArray(stripped.rules) ? (stripped.rules as LogFilterRule[]) : [];\n return {\n enabled: Boolean(stripped.enabled),\n mode,\n applyTo,\n rules,\n };\n}\n\n/**\n * \u52A0\u8F7D\u5E76\u7F16\u8BD1\u8FC7\u6EE4\u914D\u7F6E\uFF08\u6309\u6587\u4EF6 mtime \u70ED\u8BFB\uFF09\u3002\n * onBadRegex\uFF1A\u6B63\u5219\u975E\u6CD5\u65F6\u56DE\u8C03\uFF08\u7531 logs \u5C42\u6253 warn\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\uFF09\u3002\n */\nexport function getCompiledLogFilter(onBadRegex?: (src: string) => void): CompiledFilter {\n const p = ensureLogFilterConfigFile();\n let mtimeMs = 0;\n try {\n mtimeMs = fs.statSync(p).mtimeMs;\n } catch {\n mtimeMs = 0;\n }\n if (cache && cache.mtimeMs === mtimeMs) return cache;\n\n let cfg = { ...DEFAULTS };\n const raw = readJson<Record<string, unknown>>(p);\n if (raw) {\n try {\n cfg = normalizeConfig(raw);\n } catch {\n cfg = { ...DEFAULTS };\n }\n }\n\n const rules = compileRules(cfg.rules, onBadRegex);\n\n cache = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n rules,\n mtimeMs,\n };\n return cache;\n}\n\n/** \u5355\u6761\u89C4\u5219\u662F\u5426\u547D\u4E2D\uFF08\u540C\u6761 AND\uFF09 */\nexport function ruleMatchesEntry(rule: CompiledRule, entry: LogFilterEntry): boolean {\n if (rule.sources && !rule.sources.has(entry.source.toLowerCase())) return false;\n if (rule.levels && !rule.levels.has(entry.level.toLowerCase())) return false;\n if (rule.contains != null && !entry.text.includes(rule.contains)) return false;\n if (rule.regex && !rule.regex.test(entry.text)) return false;\n return true;\n}\n\n/** \u4EFB\u4E00\u89C4\u5219\u547D\u4E2D\u5373\u4E3A matched */\nexport function entryMatchesAnyRule(entry: LogFilterEntry, rules: CompiledRule[]): boolean {\n if (rules.length === 0) return false;\n return rules.some((r) => ruleMatchesEntry(r, entry));\n}\n\n/**\n * \u662F\u5426\u5E94\u4E22\u5F03\u8BE5\u6761\uFF08\u5BF9\u5C55\u793A/\u5185\u5B58\u800C\u8A00\uFF09\u3002\n * enabled=false \u2192 \u4E0D\u4E22\uFF1Bkeep \u6A21\u5F0F\u672A\u5339\u914D \u2192 \u4E22\uFF1Bdrop \u6A21\u5F0F\u5339\u914D \u2192 \u4E22\u3002\n */\nexport function shouldDropForDisplay(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (!filter.enabled) return false;\n const matched = entryMatchesAnyRule(entry, filter.rules);\n if (filter.mode === \"keep\") return !matched;\n return matched;\n}\n\n/** \u662F\u5426\u5E94\u8DF3\u8FC7\u843D\u76D8\uFF08\u4EC5 applyTo=all \u65F6\u4E0E display \u4E00\u81F4\uFF09 */\nexport function shouldDropForDisk(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (filter.applyTo !== \"all\") return false;\n return shouldDropForDisplay(entry, filter);\n}\n\n/** \u6D4B\u8BD5\u7528\uFF1A\u6E05\u7A7A\u7F13\u5B58 */\nexport function resetLogFilterCacheForTests(): void {\n cache = null;\n}\n\n/**\n * \u7EAF\u51FD\u6570\u5224\u5B9A\uFF08\u4E0D\u8BFB\u76D8\uFF09\uFF1A\u4F9B\u5355\u6D4B\u4E0E\u8C03\u7528\u65B9\u8868\u9A71\u52A8\u3002\n * dropDisplay / dropDisk \u8BED\u4E49\u4E0E pushLog \u4E00\u81F4\u3002\n */\nexport function evaluateLogFilter(\n entry: LogFilterEntry,\n cfg: LogFilterConfig\n): { dropDisplay: boolean; dropDisk: boolean; matched: boolean } {\n const compiled = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n rules: compileRules(cfg.rules),\n mtimeMs: 0,\n };\n return {\n matched: entryMatchesAnyRule(entry, compiled.rules),\n dropDisplay: shouldDropForDisplay(entry, compiled),\n dropDisk: shouldDropForDisk(entry, compiled),\n };\n}\n"],
|
|
5
|
-
"mappings": "AAGA,SAAS,oBAAoB,UAAU,uBAAuB;AAE9D,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,YAAY;
|
|
4
|
+
"sourcesContent": ["/**\n * log-filter.ts \u2014 configs/log-filter.json \u52A0\u8F7D\u4E0E\u5339\u914D\uFF08\u7EAF\u5224\u5B9A + \u70ED\u8BFB\u7F13\u5B58\uFF09\n */\nimport { ensureSchemaConfig, readJson, stripConfigMeta } from \"@sfmc-bds/sdk/node/config\";\nimport type { LogLevel } from \"@sfmc-bds/sdk/logs\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { ROOT } from \"./runtime.js\";\nimport { applyRuleReplacement, translateBdsLog } from \"./log-translator.js\";\nimport { getLocale } from \"./i18n/index.js\";\n\nexport type LogFilterMode = \"drop\" | \"keep\";\nexport type LogFilterApplyTo = \"display\" | \"all\";\n\nexport interface LogFilterRule {\n enabled?: boolean;\n sources?: string[];\n levels?: LogLevel[];\n contains?: string;\n /** JS RegExp \u6E90\uFF1B\u652F\u6301\u524D\u7F00 (?i) \u8868\u793A\u5FFD\u7565\u5927\u5C0F\u5199 */\n regex?: string;\n /** \u547D\u4E2D\u89C4\u5219\u65F6\u7684\u66FF\u6362/\u7FFB\u8BD1\u6587\u672C\u6A21\u677F\uFF0C\u652F\u6301 $1, $2 \u7B49\u6B63\u5219\u6355\u83B7\u53D8\u91CF */\n replace?: string;\n}\n\nexport interface LogFilterConfig {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n /** \u662F\u5426\u5F00\u542F BDS \u539F\u7248\u4E0E\u5E38\u7528\u65E5\u5FD7\u672C\u5730\u5316\u7FFB\u8BD1\uFF08\u7F3A\u7701\u4E3A true\uFF09 */\n translate?: boolean;\n rules: LogFilterRule[];\n}\n\nexport type LogFilterEntry = {\n text: string;\n source: string;\n level: LogLevel;\n};\n\nconst DEFAULTS: LogFilterConfig = {\n enabled: false,\n mode: \"drop\",\n applyTo: \"display\",\n translate: true,\n rules: [],\n};\n\nexport function logFilterConfigPath(): string {\n return path.join(ROOT, \"configs\", \"log-filter.json\");\n}\n\n/** \u786E\u4FDD configs/log-filter.json \u5B58\u5728\uFF08\u59D4\u6258 SDK ensureSchemaConfig\uFF0C\u7981\u6B62\u624B\u5199 withConfigSchema\uFF09 */\nexport function ensureLogFilterConfigFile(): string {\n ensureSchemaConfig(ROOT, \"log-filter.json\", \"log_filter\", { ...DEFAULTS } as Record<string, unknown>);\n return logFilterConfigPath();\n}\n\ntype CompiledRule = {\n sources?: Set<string>;\n levels?: Set<string>;\n contains?: string;\n regex?: RegExp;\n replace?: string;\n};\n\nexport type CompiledFilter = {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n translate: boolean;\n rules: CompiledRule[];\n mtimeMs: number;\n};\n\nlet cache: CompiledFilter | null = null;\n\n/** \u5C06 (?i) \u524D\u7F00\u8F6C\u4E3A RegExp i \u65D7\u6807\uFF08JS \u65E0\u5185\u8054 (?i)\uFF09 */\nexport function compileLogFilterRegex(src: string): RegExp | null {\n let pattern = String(src ?? \"\");\n let flags = \"\";\n if (pattern.startsWith(\"(?i)\")) {\n pattern = pattern.slice(4);\n flags = \"i\";\n }\n try {\n return new RegExp(pattern, flags);\n } catch {\n return null;\n }\n}\n\nfunction compileRules(rules: LogFilterRule[], onBadRegex?: (src: string) => void): CompiledRule[] {\n const out: CompiledRule[] = [];\n for (const r of rules) {\n if (r.enabled === false) continue;\n const hasAny =\n (r.sources && r.sources.length > 0) ||\n (r.levels && r.levels.length > 0) ||\n (typeof r.contains === \"string\" && r.contains.length > 0) ||\n (typeof r.regex === \"string\" && r.regex.length > 0) ||\n (typeof r.replace === \"string\" && r.replace.length > 0);\n if (!hasAny) continue;\n\n const compiled: CompiledRule = {};\n if (r.sources && r.sources.length > 0) {\n compiled.sources = new Set(r.sources.map((s) => s.toLowerCase()));\n }\n if (r.levels && r.levels.length > 0) {\n compiled.levels = new Set(r.levels.map((l) => l.toLowerCase()));\n }\n if (typeof r.contains === \"string\" && r.contains.length > 0) {\n compiled.contains = r.contains;\n }\n if (typeof r.regex === \"string\" && r.regex.length > 0) {\n const re = compileLogFilterRegex(r.regex);\n if (!re) {\n onBadRegex?.(r.regex);\n continue;\n }\n compiled.regex = re;\n }\n if (typeof r.replace === \"string\") {\n compiled.replace = r.replace;\n }\n out.push(compiled);\n }\n return out;\n}\n\nfunction normalizeConfig(raw: Record<string, unknown>): LogFilterConfig {\n const stripped = stripConfigMeta(raw);\n const mode = stripped.mode === \"keep\" ? \"keep\" : \"drop\";\n const applyTo = stripped.applyTo === \"all\" ? \"all\" : \"display\";\n const translate = stripped.translate !== undefined ? Boolean(stripped.translate) : true;\n const rules = Array.isArray(stripped.rules) ? (stripped.rules as LogFilterRule[]) : [];\n return {\n enabled: Boolean(stripped.enabled),\n mode,\n applyTo,\n translate,\n rules,\n };\n}\n\n/**\n * \u52A0\u8F7D\u5E76\u7F16\u8BD1\u8FC7\u6EE4\u914D\u7F6E\uFF08\u6309\u6587\u4EF6 mtime \u70ED\u8BFB\uFF09\u3002\n * onBadRegex\uFF1A\u6B63\u5219\u975E\u6CD5\u65F6\u56DE\u8C03\uFF08\u7531 logs \u5C42\u6253 warn\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\uFF09\u3002\n */\nexport function getCompiledLogFilter(onBadRegex?: (src: string) => void): CompiledFilter {\n const p = ensureLogFilterConfigFile();\n let mtimeMs = 0;\n try {\n mtimeMs = fs.statSync(p).mtimeMs;\n } catch {\n mtimeMs = 0;\n }\n if (cache && cache.mtimeMs === mtimeMs) return cache;\n\n let cfg = { ...DEFAULTS };\n const raw = readJson<Record<string, unknown>>(p);\n if (raw) {\n try {\n cfg = normalizeConfig(raw);\n } catch {\n cfg = { ...DEFAULTS };\n }\n }\n\n const rules = compileRules(cfg.rules, onBadRegex);\n\n cache = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n translate: cfg.translate ?? true,\n rules,\n mtimeMs,\n };\n return cache;\n}\n\n/** \u5355\u6761\u89C4\u5219\u662F\u5426\u547D\u4E2D\uFF08\u540C\u6761 AND\uFF09 */\nexport function ruleMatchesEntry(rule: CompiledRule, entry: LogFilterEntry): boolean {\n if (rule.sources && !rule.sources.has(entry.source.toLowerCase())) return false;\n if (rule.levels && !rule.levels.has(entry.level.toLowerCase())) return false;\n if (rule.contains != null && !entry.text.includes(rule.contains)) return false;\n if (rule.regex && !rule.regex.test(entry.text)) return false;\n return true;\n}\n\n/** \u4EFB\u4E00\u89C4\u5219\u547D\u4E2D\u5373\u4E3A matched */\nexport function entryMatchesAnyRule(entry: LogFilterEntry, rules: CompiledRule[]): boolean {\n if (rules.length === 0) return false;\n return rules.some((r) => ruleMatchesEntry(r, entry));\n}\n\n/**\n * \u662F\u5426\u5E94\u4E22\u5F03\u8BE5\u6761\uFF08\u5BF9\u5C55\u793A/\u5185\u5B58\u800C\u8A00\uFF09\u3002\n * enabled=false \u2192 \u4E0D\u4E22\uFF1Bkeep \u6A21\u5F0F\u672A\u5339\u914D \u2192 \u4E22\uFF1Bdrop \u6A21\u5F0F\u5339\u914D \u2192 \u4E22\u3002\n */\nexport function shouldDropForDisplay(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (!filter.enabled) return false;\n const matched = entryMatchesAnyRule(entry, filter.rules);\n if (filter.mode === \"keep\") return !matched;\n return matched;\n}\n\n/** \u662F\u5426\u5E94\u8DF3\u8FC7\u843D\u76D8\uFF08\u4EC5 applyTo=all \u65F6\u4E0E display \u4E00\u81F4\uFF09 */\nexport function shouldDropForDisk(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (filter.applyTo !== \"all\") return false;\n return shouldDropForDisplay(entry, filter);\n}\n\n/**\n * \u5BF9\u65E5\u5FD7\u6761\u76EE\u5E94\u7528\u8F6C\u6362/\u672C\u5730\u5316\u7FFB\u8BD1\uFF1A\n * 1. \u4F18\u5148\u5339\u914D rules \u4E2D\u5E26\u6709 replace \u7684\u81EA\u5B9A\u4E49\u89C4\u5219\uFF08\u652F\u6301 $1, $2 \u6355\u83B7\u7EC4\uFF09\n * 2. \u82E5\u672A\u88AB\u81EA\u5B9A\u4E49\u89C4\u5219\u66FF\u6362\u4E14\u542F\u7528\u4E86 translate\uFF08\u4E14 source \u4E3A bds\uFF09\uFF0C\u8C03\u7528\u5185\u5EFA BDS \u7FFB\u8BD1\u5F15\u64CE\n */\nexport function transformLogEntry(\n entry: LogFilterEntry,\n filter?: CompiledFilter,\n locale?: string\n): { entry: LogFilterEntry; transformed: boolean } {\n // 1. \u81EA\u5B9A\u4E49\u89C4\u5219 replace \u66FF\u6362\u4F18\u5148\n if (filter && filter.rules.length > 0) {\n for (const rule of filter.rules) {\n if (rule.replace && ruleMatchesEntry(rule, entry)) {\n let newText = entry.text;\n if (rule.regex) {\n newText = applyRuleReplacement(entry.text, rule.regex, rule.replace);\n } else if (rule.contains) {\n newText = entry.text.replaceAll(rule.contains, rule.replace);\n } else {\n newText = rule.replace;\n }\n return {\n entry: { ...entry, text: newText },\n transformed: true,\n };\n }\n }\n }\n\n // 2. \u5185\u7F6E BDS \u539F\u7248\u65E5\u5FD7\u672C\u5730\u5316\u7FFB\u8BD1\n const translateEnabled = filter ? filter.translate : true;\n if (translateEnabled && entry.source.toLowerCase() === \"bds\") {\n let loc: string;\n try {\n loc = locale ?? getLocale();\n } catch {\n loc = locale ?? \"zh-CN\";\n }\n const res = translateBdsLog(entry.text, loc);\n if (res.translated) {\n return {\n entry: { ...entry, text: res.text },\n transformed: true,\n };\n }\n }\n\n return { entry, transformed: false };\n}\n\n/** \u6D4B\u8BD5\u7528\uFF1A\u6E05\u7A7A\u7F13\u5B58 */\nexport function resetLogFilterCacheForTests(): void {\n cache = null;\n}\n\n/**\n * \u7EAF\u51FD\u6570\u5224\u5B9A\uFF08\u4E0D\u8BFB\u76D8\uFF09\uFF1A\u4F9B\u5355\u6D4B\u4E0E\u8C03\u7528\u65B9\u8868\u9A71\u52A8\u3002\n * dropDisplay / dropDisk \u8BED\u4E49\u4E0E pushLog \u4E00\u81F4\u3002\n */\nexport function evaluateLogFilter(\n entry: LogFilterEntry,\n cfg: LogFilterConfig,\n locale?: string\n): {\n dropDisplay: boolean;\n dropDisk: boolean;\n matched: boolean;\n transformedEntry: LogFilterEntry;\n} {\n const compiled: CompiledFilter = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n translate: cfg.translate ?? true,\n rules: compileRules(cfg.rules),\n mtimeMs: 0,\n };\n const transformRes = transformLogEntry(entry, compiled, locale);\n return {\n matched: entryMatchesAnyRule(entry, compiled.rules),\n dropDisplay: shouldDropForDisplay(entry, compiled),\n dropDisk: shouldDropForDisk(entry, compiled),\n transformedEntry: transformRes.entry,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/log-filter.test.js
CHANGED
|
@@ -116,4 +116,66 @@ test("applyTo=display \u65F6\u4EC5\u5F71\u54CD\u5C55\u793A", () => {
|
|
|
116
116
|
assert.equal(r.dropDisplay, true);
|
|
117
117
|
assert.equal(r.dropDisk, false);
|
|
118
118
|
});
|
|
119
|
+
test("evaluateLogFilter: \u5185\u7F6E BDS \u7FFB\u8BD1\u81EA\u52A8\u751F\u6548", () => {
|
|
120
|
+
const r = evaluateLogFilter(
|
|
121
|
+
entry({
|
|
122
|
+
source: "bds",
|
|
123
|
+
text: "Server started."
|
|
124
|
+
}),
|
|
125
|
+
baseCfg({
|
|
126
|
+
enabled: false,
|
|
127
|
+
translate: true
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
assert.equal(r.transformedEntry.text, "[\u670D\u52A1\u7AEF] BDS \u670D\u52A1\u7AEF\u5DF2\u6210\u529F\u542F\u52A8\uFF0C\u51C6\u5907\u5C31\u7EEA\u3002");
|
|
131
|
+
});
|
|
132
|
+
test("evaluateLogFilter: \u81EA\u5B9A\u4E49 rule.replace \u4F18\u5148\u4E8E\u5185\u7F6E\u7FFB\u8BD1", () => {
|
|
133
|
+
const r = evaluateLogFilter(
|
|
134
|
+
entry({
|
|
135
|
+
source: "bds",
|
|
136
|
+
text: "Server started."
|
|
137
|
+
}),
|
|
138
|
+
baseCfg({
|
|
139
|
+
enabled: true,
|
|
140
|
+
rules: [
|
|
141
|
+
{
|
|
142
|
+
sources: ["bds"],
|
|
143
|
+
contains: "Server started.",
|
|
144
|
+
replace: ">> \u670D\u52A1\u5668\u51C6\u5907\u5B8C\u6BD5 <<"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
assert.equal(r.transformedEntry.text, ">> \u670D\u52A1\u5668\u51C6\u5907\u5B8C\u6BD5 <<");
|
|
150
|
+
});
|
|
151
|
+
test("evaluateLogFilter: \u81EA\u5B9A\u4E49 rule.replace \u652F\u6301\u6B63\u5219\u6355\u83B7\u7EC4", () => {
|
|
152
|
+
const r = evaluateLogFilter(
|
|
153
|
+
entry({
|
|
154
|
+
source: "system",
|
|
155
|
+
text: "Job backup_world completed in 42ms"
|
|
156
|
+
}),
|
|
157
|
+
baseCfg({
|
|
158
|
+
enabled: true,
|
|
159
|
+
rules: [
|
|
160
|
+
{
|
|
161
|
+
regex: "Job (\\w+) completed in (\\d+)ms",
|
|
162
|
+
replace: "\u4EFB\u52A1 $1 \u5B8C\u6210 (\u8017\u65F6: $2\u6BEB\u79D2)"
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
assert.equal(r.transformedEntry.text, "\u4EFB\u52A1 backup_world \u5B8C\u6210 (\u8017\u65F6: 42\u6BEB\u79D2)");
|
|
168
|
+
});
|
|
169
|
+
test("evaluateLogFilter: translate=false \u65F6\u4E0D\u89E6\u53D1\u5185\u7F6E\u7FFB\u8BD1", () => {
|
|
170
|
+
const r = evaluateLogFilter(
|
|
171
|
+
entry({
|
|
172
|
+
source: "bds",
|
|
173
|
+
text: "Server started."
|
|
174
|
+
}),
|
|
175
|
+
baseCfg({
|
|
176
|
+
translate: false
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
assert.equal(r.transformedEntry.text, "Server started.");
|
|
180
|
+
});
|
|
119
181
|
//# sourceMappingURL=log-filter.test.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/log-filter.test.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * log-filter \u7EAF\u51FD\u6570\u8868\u9A71\u52A8\uFF08\u4E0D\u6D4B IO\uFF09\n */\nimport assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport { compileLogFilterRegex, evaluateLogFilter } from \"./log-filter.js\";\n\nconst entry = (over: Record<string, unknown> = {}) => ({\n text: \"Player connected: Steve\",\n source: \"bds\",\n level: \"info\",\n ...over,\n});\n\nconst baseCfg = (over: Record<string, unknown> = {}) => ({\n enabled: true,\n mode: \"drop\",\n applyTo: \"display\",\n rules: [],\n ...over,\n});\n\ntest(\"enabled=false \u6C38\u4E0D\u4E22\u5F03\", () => {\n const r = evaluateLogFilter(\n entry(),\n baseCfg({\n enabled: false,\n mode: \"keep\",\n rules: [{ sources: [\"bds\"] }],\n })\n );\n assert.equal(r.dropDisplay, false);\n assert.equal(r.dropDisk, false);\n});\n\ntest(\"drop \u00D7 sources \u547D\u4E2D\u5219\u4E22\u5F03\u5C55\u793A\", () => {\n const r = evaluateLogFilter(entry(), baseCfg({ rules: [{ sources: [\"bds\", \"pack\"] }] }));\n assert.equal(r.matched, true);\n assert.equal(r.dropDisplay, true);\n assert.equal(r.dropDisk, false);\n});\n\ntest(\"drop \u00D7 sources \u672A\u547D\u4E2D\u5219\u4FDD\u7559\", () => {\n const r = evaluateLogFilter(entry({ source: \"system\" }), baseCfg({ rules: [{ sources: [\"bds\"] }] }));\n assert.equal(r.matched, false);\n assert.equal(r.dropDisplay, false);\n});\n\ntest(\"drop \u00D7 levels\", () => {\n const hit = evaluateLogFilter(entry({ level: \"debug\" }), baseCfg({ rules: [{ levels: [\"debug\", \"info\"] }] }));\n const miss = evaluateLogFilter(entry({ level: \"error\" }), baseCfg({ rules: [{ levels: [\"debug\"] }] }));\n assert.equal(hit.dropDisplay, true);\n assert.equal(miss.dropDisplay, false);\n});\n\ntest(\"drop \u00D7 contains\uFF08\u5927\u5C0F\u5199\u654F\u611F\uFF09\", () => {\n const hit = evaluateLogFilter(entry(), baseCfg({ rules: [{ contains: \"Player connected\" }] }));\n const miss = evaluateLogFilter(entry(), baseCfg({ rules: [{ contains: \"player connected\" }] }));\n assert.equal(hit.dropDisplay, true);\n assert.equal(miss.dropDisplay, false);\n});\n\ntest(\"drop \u00D7 regex \u4E0E (?i) \u65D7\u6807\", () => {\n const hit = evaluateLogFilter(\n entry({ text: \"GAMERULE keepInventory\" }),\n baseCfg({ rules: [{ regex: \"(?i)gamerule|syntax error\" }] })\n );\n const miss = evaluateLogFilter(entry({ text: \"hello\" }), baseCfg({ rules: [{ regex: \"(?i)gamerule\" }] }));\n assert.equal(hit.dropDisplay, true);\n assert.equal(miss.dropDisplay, false);\n assert.ok(compileLogFilterRegex(\"(?i)ABC\")?.test(\"abc\"));\n assert.equal(compileLogFilterRegex(\"(\"), null);\n});\n\ntest(\"\u540C\u6761 AND\uFF1Asources + contains \u987B\u540C\u65F6\u6EE1\u8DB3\", () => {\n const both = evaluateLogFilter(entry(), baseCfg({ rules: [{ sources: [\"bds\"], contains: \"Player\" }] }));\n const onlySource = evaluateLogFilter(\n entry({ text: \"nope\" }),\n baseCfg({ rules: [{ sources: [\"bds\"], contains: \"Player\" }] })\n );\n assert.equal(both.dropDisplay, true);\n assert.equal(onlySource.dropDisplay, false);\n});\n\ntest(\"\u591A\u6761 OR\uFF1A\u4EFB\u4E00\u547D\u4E2D\u5373\u53EF\", () => {\n const r = evaluateLogFilter(\n entry({ source: \"pack\", text: \"done\" }),\n baseCfg({\n rules: [{ sources: [\"bds\"] }, { sources: [\"pack\"], contains: \"done\" }],\n })\n );\n assert.equal(r.matched, true);\n assert.equal(r.dropDisplay, true);\n});\n\ntest(\"rule.enabled=false \u8DF3\u8FC7\", () => {\n const r = evaluateLogFilter(entry(), baseCfg({ rules: [{ enabled: false, sources: [\"bds\"] }] }));\n assert.equal(r.matched, false);\n assert.equal(r.dropDisplay, false);\n});\n\ntest(\"keep \u6A21\u5F0F\uFF1A\u4EC5\u4FDD\u7559\u5339\u914D\uFF0C\u672A\u5339\u914D\u4E22\u5F03\", () => {\n const cfg = baseCfg({\n mode: \"keep\",\n rules: [{ levels: [\"error\"] }],\n });\n const keep = evaluateLogFilter(entry({ level: \"error\" }), cfg);\n const drop = evaluateLogFilter(entry({ level: \"info\" }), cfg);\n assert.equal(keep.dropDisplay, false);\n assert.equal(drop.dropDisplay, true);\n});\n\ntest(\"applyTo=all \u65F6\u843D\u76D8\u4E0E\u5C55\u793A\u4E00\u5E76\u8FC7\u6EE4\", () => {\n const r = evaluateLogFilter(\n entry(),\n baseCfg({\n applyTo: \"all\",\n rules: [{ sources: [\"bds\"] }],\n })\n );\n assert.equal(r.dropDisplay, true);\n assert.equal(r.dropDisk, true);\n});\n\ntest(\"applyTo=display \u65F6\u4EC5\u5F71\u54CD\u5C55\u793A\", () => {\n const r = evaluateLogFilter(\n entry(),\n baseCfg({\n applyTo: \"display\",\n rules: [{ sources: [\"bds\"] }],\n })\n );\n assert.equal(r.dropDisplay, true);\n assert.equal(r.dropDisk, false);\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * log-filter \u7EAF\u51FD\u6570\u8868\u9A71\u52A8\uFF08\u4E0D\u6D4B IO\uFF09\n */\nimport assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport { compileLogFilterRegex, evaluateLogFilter } from \"./log-filter.js\";\n\nconst entry = (over: Record<string, unknown> = {}) => ({\n text: \"Player connected: Steve\",\n source: \"bds\",\n level: \"info\",\n ...over,\n});\n\nconst baseCfg = (over: Record<string, unknown> = {}) => ({\n enabled: true,\n mode: \"drop\",\n applyTo: \"display\",\n rules: [],\n ...over,\n});\n\ntest(\"enabled=false \u6C38\u4E0D\u4E22\u5F03\", () => {\n const r = evaluateLogFilter(\n entry(),\n baseCfg({\n enabled: false,\n mode: \"keep\",\n rules: [{ sources: [\"bds\"] }],\n })\n );\n assert.equal(r.dropDisplay, false);\n assert.equal(r.dropDisk, false);\n});\n\ntest(\"drop \u00D7 sources \u547D\u4E2D\u5219\u4E22\u5F03\u5C55\u793A\", () => {\n const r = evaluateLogFilter(entry(), baseCfg({ rules: [{ sources: [\"bds\", \"pack\"] }] }));\n assert.equal(r.matched, true);\n assert.equal(r.dropDisplay, true);\n assert.equal(r.dropDisk, false);\n});\n\ntest(\"drop \u00D7 sources \u672A\u547D\u4E2D\u5219\u4FDD\u7559\", () => {\n const r = evaluateLogFilter(entry({ source: \"system\" }), baseCfg({ rules: [{ sources: [\"bds\"] }] }));\n assert.equal(r.matched, false);\n assert.equal(r.dropDisplay, false);\n});\n\ntest(\"drop \u00D7 levels\", () => {\n const hit = evaluateLogFilter(entry({ level: \"debug\" }), baseCfg({ rules: [{ levels: [\"debug\", \"info\"] }] }));\n const miss = evaluateLogFilter(entry({ level: \"error\" }), baseCfg({ rules: [{ levels: [\"debug\"] }] }));\n assert.equal(hit.dropDisplay, true);\n assert.equal(miss.dropDisplay, false);\n});\n\ntest(\"drop \u00D7 contains\uFF08\u5927\u5C0F\u5199\u654F\u611F\uFF09\", () => {\n const hit = evaluateLogFilter(entry(), baseCfg({ rules: [{ contains: \"Player connected\" }] }));\n const miss = evaluateLogFilter(entry(), baseCfg({ rules: [{ contains: \"player connected\" }] }));\n assert.equal(hit.dropDisplay, true);\n assert.equal(miss.dropDisplay, false);\n});\n\ntest(\"drop \u00D7 regex \u4E0E (?i) \u65D7\u6807\", () => {\n const hit = evaluateLogFilter(\n entry({ text: \"GAMERULE keepInventory\" }),\n baseCfg({ rules: [{ regex: \"(?i)gamerule|syntax error\" }] })\n );\n const miss = evaluateLogFilter(entry({ text: \"hello\" }), baseCfg({ rules: [{ regex: \"(?i)gamerule\" }] }));\n assert.equal(hit.dropDisplay, true);\n assert.equal(miss.dropDisplay, false);\n assert.ok(compileLogFilterRegex(\"(?i)ABC\")?.test(\"abc\"));\n assert.equal(compileLogFilterRegex(\"(\"), null);\n});\n\ntest(\"\u540C\u6761 AND\uFF1Asources + contains \u987B\u540C\u65F6\u6EE1\u8DB3\", () => {\n const both = evaluateLogFilter(entry(), baseCfg({ rules: [{ sources: [\"bds\"], contains: \"Player\" }] }));\n const onlySource = evaluateLogFilter(\n entry({ text: \"nope\" }),\n baseCfg({ rules: [{ sources: [\"bds\"], contains: \"Player\" }] })\n );\n assert.equal(both.dropDisplay, true);\n assert.equal(onlySource.dropDisplay, false);\n});\n\ntest(\"\u591A\u6761 OR\uFF1A\u4EFB\u4E00\u547D\u4E2D\u5373\u53EF\", () => {\n const r = evaluateLogFilter(\n entry({ source: \"pack\", text: \"done\" }),\n baseCfg({\n rules: [{ sources: [\"bds\"] }, { sources: [\"pack\"], contains: \"done\" }],\n })\n );\n assert.equal(r.matched, true);\n assert.equal(r.dropDisplay, true);\n});\n\ntest(\"rule.enabled=false \u8DF3\u8FC7\", () => {\n const r = evaluateLogFilter(entry(), baseCfg({ rules: [{ enabled: false, sources: [\"bds\"] }] }));\n assert.equal(r.matched, false);\n assert.equal(r.dropDisplay, false);\n});\n\ntest(\"keep \u6A21\u5F0F\uFF1A\u4EC5\u4FDD\u7559\u5339\u914D\uFF0C\u672A\u5339\u914D\u4E22\u5F03\", () => {\n const cfg = baseCfg({\n mode: \"keep\",\n rules: [{ levels: [\"error\"] }],\n });\n const keep = evaluateLogFilter(entry({ level: \"error\" }), cfg);\n const drop = evaluateLogFilter(entry({ level: \"info\" }), cfg);\n assert.equal(keep.dropDisplay, false);\n assert.equal(drop.dropDisplay, true);\n});\n\ntest(\"applyTo=all \u65F6\u843D\u76D8\u4E0E\u5C55\u793A\u4E00\u5E76\u8FC7\u6EE4\", () => {\n const r = evaluateLogFilter(\n entry(),\n baseCfg({\n applyTo: \"all\",\n rules: [{ sources: [\"bds\"] }],\n })\n );\n assert.equal(r.dropDisplay, true);\n assert.equal(r.dropDisk, true);\n});\n\ntest(\"applyTo=display \u65F6\u4EC5\u5F71\u54CD\u5C55\u793A\", () => {\n const r = evaluateLogFilter(\n entry(),\n baseCfg({\n applyTo: \"display\",\n rules: [{ sources: [\"bds\"] }],\n })\n );\n assert.equal(r.dropDisplay, true);\n assert.equal(r.dropDisk, false);\n});\n\ntest(\"evaluateLogFilter: \u5185\u7F6E BDS \u7FFB\u8BD1\u81EA\u52A8\u751F\u6548\", () => {\n const r = evaluateLogFilter(\n entry({\n source: \"bds\",\n text: \"Server started.\",\n }),\n baseCfg({\n enabled: false,\n translate: true,\n })\n );\n assert.equal(r.transformedEntry.text, \"[\u670D\u52A1\u7AEF] BDS \u670D\u52A1\u7AEF\u5DF2\u6210\u529F\u542F\u52A8\uFF0C\u51C6\u5907\u5C31\u7EEA\u3002\");\n});\n\ntest(\"evaluateLogFilter: \u81EA\u5B9A\u4E49 rule.replace \u4F18\u5148\u4E8E\u5185\u7F6E\u7FFB\u8BD1\", () => {\n const r = evaluateLogFilter(\n entry({\n source: \"bds\",\n text: \"Server started.\",\n }),\n baseCfg({\n enabled: true,\n rules: [\n {\n sources: [\"bds\"],\n contains: \"Server started.\",\n replace: \">> \u670D\u52A1\u5668\u51C6\u5907\u5B8C\u6BD5 <<\",\n },\n ],\n })\n );\n assert.equal(r.transformedEntry.text, \">> \u670D\u52A1\u5668\u51C6\u5907\u5B8C\u6BD5 <<\");\n});\n\ntest(\"evaluateLogFilter: \u81EA\u5B9A\u4E49 rule.replace \u652F\u6301\u6B63\u5219\u6355\u83B7\u7EC4\", () => {\n const r = evaluateLogFilter(\n entry({\n source: \"system\",\n text: \"Job backup_world completed in 42ms\",\n }),\n baseCfg({\n enabled: true,\n rules: [\n {\n regex: \"Job (\\\\w+) completed in (\\\\d+)ms\",\n replace: \"\u4EFB\u52A1 $1 \u5B8C\u6210 (\u8017\u65F6: $2\u6BEB\u79D2)\",\n },\n ],\n })\n );\n assert.equal(r.transformedEntry.text, \"\u4EFB\u52A1 backup_world \u5B8C\u6210 (\u8017\u65F6: 42\u6BEB\u79D2)\");\n});\n\ntest(\"evaluateLogFilter: translate=false \u65F6\u4E0D\u89E6\u53D1\u5185\u7F6E\u7FFB\u8BD1\", () => {\n const r = evaluateLogFilter(\n entry({\n source: \"bds\",\n text: \"Server started.\",\n }),\n baseCfg({\n translate: false,\n })\n );\n assert.equal(r.transformedEntry.text, \"Server started.\");\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log-translator.ts — BDS 原版日志本地化翻译与友好转换引擎
|
|
3
|
+
*
|
|
4
|
+
* 将 Minecraft 基岩版专用服务端 (BDS) 引擎输出的晦涩英文日志
|
|
5
|
+
* (如 Beta APIs 阻断、方块形态超限、包缺失、配方失效、语法错误等)
|
|
6
|
+
* 转换为服主与开发者易懂的本地化语言日志。
|
|
7
|
+
*/
|
|
8
|
+
export interface TranslationRule {
|
|
9
|
+
id: string;
|
|
10
|
+
pattern: RegExp;
|
|
11
|
+
translations: {
|
|
12
|
+
"zh-CN": string;
|
|
13
|
+
[locale: string]: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 内置常见 BDS 原版日志翻译字典
|
|
18
|
+
*/
|
|
19
|
+
export declare const BUILTIN_BDS_TRANSLATIONS: TranslationRule[];
|
|
20
|
+
/**
|
|
21
|
+
* 将正则匹配结果套入含 $1, $2 等占位符的模板字符串
|
|
22
|
+
*/
|
|
23
|
+
export declare function interpolateRegexTemplate(match: RegExpMatchArray, template: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* 应用规则正则替换模板
|
|
26
|
+
*/
|
|
27
|
+
export declare function applyRuleReplacement(text: string, regex: RegExp, replaceTemplate: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* 翻译单条 BDS 日志文本(纯函数)
|
|
30
|
+
*/
|
|
31
|
+
export declare function translateBdsLog(text: string, locale?: string): {
|
|
32
|
+
translated: boolean;
|
|
33
|
+
text: string;
|
|
34
|
+
ruleId?: string;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=log-translator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-translator.d.ts","sourceRoot":"","sources":["../src/log-translator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;KAC1B,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAAe,EA+OrD,CAAC;AAEF;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ1F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAIjG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,MAAgB,GACvB;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAqBxD"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
const BUILTIN_BDS_TRANSLATIONS = [
|
|
2
|
+
// 1. 实验性 / 测试版 API 未开启导致脚本阻断加载
|
|
3
|
+
{
|
|
4
|
+
id: "beta-apis-missing",
|
|
5
|
+
pattern: /(?:Plugin|Script)\s+\[(.+?)\]\s*-\s*requesting dependency on beta APIs\s*\[(.+?)\],\s*but the Beta APIs experiment is not enabled\./i,
|
|
6
|
+
translations: {
|
|
7
|
+
"zh-CN": "[\u811A\u672C\u963B\u65AD] \u63D2\u4EF6\u300C$1\u300D\u4F9D\u8D56\u6D4B\u8BD5\u7248 API ($2)\uFF0C\u4F46\u5F53\u524D\u4E16\u754C\u672A\u5F00\u542F\u300C\u6D4B\u8BD5\u7248 API (Beta APIs)\u300D\u5B9E\u9A8C\u5F00\u5173\uFF0C\u5DF2\u88AB BDS \u62D2\u7EDD\u8FD0\u884C\u3002\u8BF7\u5728\u4E16\u754C\u914D\u7F6E\u4E2D\u5F00\u542F\u8BE5\u5B9E\u9A8C\u5F00\u5173\u3002"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
// 2. 脚本语法错误 / 符号缺失
|
|
11
|
+
{
|
|
12
|
+
id: "script-syntax-missing-export",
|
|
13
|
+
pattern: /SyntaxError:\s*Could not find export '(.+?)' in module '(.+?)'/i,
|
|
14
|
+
translations: {
|
|
15
|
+
"zh-CN": "[\u811A\u672C\u8BED\u6CD5\u9519\u8BEF] \u6A21\u7EC4\u5C1D\u8BD5\u4ECE\u300C$2\u300D\u5BFC\u5165\u4E0D\u5B58\u5728\u7684\u7B26\u53F7\u300C$1\u300D\uFF0C\u811A\u672C\u52A0\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u6A21\u7EC4\u811A\u672C\u8BED\u6CD5\u6216 API \u7248\u672C\u517C\u5BB9\u6027\u3002"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
// 3. 世界配置清单中的包在磁盘上不存在
|
|
19
|
+
{
|
|
20
|
+
id: "configured-pack-missing",
|
|
21
|
+
pattern: /Configured pack \(id:\s*([0-9a-fA-F-]+),\s*version:\s*([^)]+)\)\s*was not found and was ignored/i,
|
|
22
|
+
translations: {
|
|
23
|
+
"zh-CN": "[\u5305\u7F3A\u5931] \u4E16\u754C\u6FC0\u6D3B\u6E05\u5355\u4E2D\u7684\u5305 (UUID: $1, \u7248\u672C: $2) \u5728\u672C\u5730\u672A\u627E\u5230\uFF0C\u5DF2\u88AB BDS \u81EA\u52A8\u5FFD\u7565\u3002"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
// 4. 自定义方块形态数量超限警告
|
|
27
|
+
{
|
|
28
|
+
id: "block-permutations-limit",
|
|
29
|
+
pattern: /World with over 65536 block permutations may degrade performance\.\s*Current world has (\d+) permutations\./i,
|
|
30
|
+
translations: {
|
|
31
|
+
"zh-CN": "[\u6027\u80FD\u63D0\u793A] \u81EA\u5B9A\u4E49\u65B9\u5757\u5F62\u6001\u6570\u91CF\u8FBE $1 \u4E2A (\u8D85\u51FA\u63A8\u8350\u4E0A\u9650 65,536)\uFF0C\u53EF\u80FD\u5F71\u54CD\u670D\u52A1\u7AEF\u53CA\u5BA2\u6237\u7AEF\u52A0\u8F7D\u6027\u80FD\u3002"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
// 5. 配方物品不存在或无效
|
|
35
|
+
{
|
|
36
|
+
id: "recipe-item-missing",
|
|
37
|
+
pattern: /(?:\[Recipes\]\s+)?(.+?)\s+\|\s+(.+?)\s+\|\s+The Item:\s*(\S+)\s+is missing or invalid,\s*can't make the recipe/i,
|
|
38
|
+
translations: {
|
|
39
|
+
"zh-CN": "[\u914D\u65B9\u9519\u8BEF] \u914D\u65B9\u6587\u4EF6\u300C$1\u300D(\u914D\u65B9\u6807\u8BC6: $2) \u5F15\u7528\u7684\u7269\u54C1\u300C$3\u300D\u4E0D\u5B58\u5728\u6216\u65E0\u6548\uFF0C\u65E0\u6CD5\u751F\u6210\u5408\u6210\u914D\u65B9\u3002"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
// 6. 配方缺少有效原料
|
|
43
|
+
{
|
|
44
|
+
id: "recipe-ingredient-missing",
|
|
45
|
+
pattern: /(?:\[Recipes\]\s+)?(.+?)\s+\|\s+(.+?)\s+\|\s+Recipe for:\s*(\S+)\s+is missing \(unknown\) ingredient/i,
|
|
46
|
+
translations: {
|
|
47
|
+
"zh-CN": "[\u914D\u65B9\u9519\u8BEF] \u914D\u65B9\u6587\u4EF6\u300C$1\u300D(\u4EA7\u7269: $2) \u7F3A\u5C11\u6709\u6548\u539F\u6599\uFF08\u5305\u542B\u672A\u8BC6\u522B\u7684\u539F\u6599\uFF09\uFF0C\u65E0\u6CD5\u6CE8\u518C\u3002"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
// 7. 配方产物格式错误
|
|
51
|
+
{
|
|
52
|
+
id: "recipe-result-malformed",
|
|
53
|
+
pattern: /(?:\[Recipes\]\s+)?(.+?)\s+\|\s+(.+?)\s+\|\s+Recipe result malformed/i,
|
|
54
|
+
translations: {
|
|
55
|
+
"zh-CN": "[\u914D\u65B9\u9519\u8BEF] \u914D\u65B9\u6587\u4EF6\u300C$1\u300D(\u914D\u65B9\u6807\u8BC6: $2) \u7684\u4EA7\u7269\u7ED3\u679C\u5B9A\u4E49\u683C\u5F0F\u9519\u8BEF (Malformed result)\u3002"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
// 8. 方块定义组件未在 Schema 中声明
|
|
59
|
+
{
|
|
60
|
+
id: "block-component-schema-unknown",
|
|
61
|
+
pattern: /(?:\[Blocks\]\s+)?block_definitions\s*\|.*?\|\s*([^|\r\n]+?)\.json\s*\|\s*(?:->\s*)?(.+?):\s*this component was found in the input,\s*but is not present in the Schema/i,
|
|
62
|
+
translations: {
|
|
63
|
+
"zh-CN": "[\u65B9\u5757\u89C4\u8303\u9519\u8BEF] \u65B9\u5757\u5B9A\u4E49\u300C$1.json\u300D\u5305\u542B\u672A\u5728\u5F53\u524D\u7248\u672C Schema \u4E2D\u5B9A\u4E49\u7684\u672A\u77E5\u7EC4\u4EF6: $2"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
// 9. 方块组件子项在此处无效
|
|
67
|
+
{
|
|
68
|
+
id: "block-child-component-invalid",
|
|
69
|
+
pattern: /(?:\[Blocks\]\s+)?block_definitions\s*\|.*?\|\s*([^|\r\n]+?)\.json\s*\|.*?\|\s*components\s*\|\s*([^|\r\n]+?)\s*\|\s*child '(.+?)' not valid here\./i,
|
|
70
|
+
translations: {
|
|
71
|
+
"zh-CN": "[\u65B9\u5757\u914D\u7F6E\u9519\u8BEF] \u65B9\u5757\u5B9A\u4E49\u300C$1.json\u300D\u7EC4\u4EF6\u300C$2\u300D\u7684\u5B50\u5C5E\u6027\u300C$3\u300D\u5728\u6B64\u5904\u65E0\u6548\u3002"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
// 10. 方块定义解析失败
|
|
75
|
+
{
|
|
76
|
+
id: "block-definition-parse-failed",
|
|
77
|
+
pattern: /(?:\[Blocks\]\s+)?block_definitions\s*\|.*?\|\s*([^|\r\n]+?)\.json\s*\|\s*Block definition parsing failed/i,
|
|
78
|
+
translations: {
|
|
79
|
+
"zh-CN": "[\u65B9\u5757\u89E3\u6790\u5931\u8D25] \u65E0\u6CD5\u89E3\u6790\u65B9\u5757\u5B9A\u4E49\u6587\u4EF6\u300C$1.json\u300D\u3002"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
// 11. 脚本组件未在脚本中注册但被物品使用
|
|
83
|
+
{
|
|
84
|
+
id: "script-component-not-registered",
|
|
85
|
+
pattern: /(?:\[Scripting\]\s+)?Component '(.+?)' was not registered in script but used on an item/i,
|
|
86
|
+
translations: {
|
|
87
|
+
"zh-CN": "[\u811A\u672C\u7EC4\u4EF6\u672A\u6CE8\u518C] \u7269\u54C1\u5F15\u7528\u4E86\u672A\u5728\u811A\u672C\u4E2D\u6CE8\u518C\u7684\u81EA\u5B9A\u4E49\u7EC4\u4EF6\u300C$1\u300D\u3002"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
// 12. 脚本注册的方块组件未被任何方块使用
|
|
91
|
+
{
|
|
92
|
+
id: "block-component-unused",
|
|
93
|
+
pattern: /(?:\[Scripting\]\s+)?Block custom component '(.+?)' is not being used by a block/i,
|
|
94
|
+
translations: {
|
|
95
|
+
"zh-CN": "[\u7EC4\u4EF6\u63D0\u793A] \u811A\u672C\u6CE8\u518C\u7684\u65B9\u5757\u81EA\u5B9A\u4E49\u7EC4\u4EF6\u300C$1\u300D\u672A\u88AB\u4EFB\u4F55\u65B9\u5757\u4F7F\u7528\u3002"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
// 13. 脚本注册的物品组件未被任何物品使用
|
|
99
|
+
{
|
|
100
|
+
id: "item-component-unused",
|
|
101
|
+
pattern: /(?:\[Scripting\]\s+)?Item custom component '(.+?)' is not being used by an item/i,
|
|
102
|
+
translations: {
|
|
103
|
+
"zh-CN": "[\u7EC4\u4EF6\u63D0\u793A] \u811A\u672C\u6CE8\u518C\u7684\u7269\u54C1\u81EA\u5B9A\u4E49\u7EC4\u4EF6\u300C$1\u300D\u672A\u88AB\u4EFB\u4F55\u7269\u54C1\u4F7F\u7528\u3002"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
// 14. 服务端启动就绪
|
|
107
|
+
{
|
|
108
|
+
id: "server-started",
|
|
109
|
+
pattern: /^Server started\./i,
|
|
110
|
+
translations: {
|
|
111
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] BDS \u670D\u52A1\u7AEF\u5DF2\u6210\u529F\u542F\u52A8\uFF0C\u51C6\u5907\u5C31\u7EEA\u3002"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
// 15. 服务端停机流程
|
|
115
|
+
{
|
|
116
|
+
id: "server-stop-requested",
|
|
117
|
+
pattern: /^Server stop requested\./i,
|
|
118
|
+
translations: {
|
|
119
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] \u6536\u5230\u505C\u670D\u8BF7\u6C42\uFF0C\u6B63\u5728\u901A\u77E5\u5E76\u4FDD\u5B58\u4E16\u754C\u6570\u636E..."
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: "server-stopping",
|
|
124
|
+
pattern: /^Stopping server\.\.\./i,
|
|
125
|
+
translations: {
|
|
126
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] \u6B63\u5728\u5173\u95ED\u670D\u52A1\u7AEF..."
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "server-quit-correctly",
|
|
131
|
+
pattern: /^Quit correctly/i,
|
|
132
|
+
translations: {
|
|
133
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] \u670D\u52A1\u7AEF\u5DF2\u6B63\u5E38\u5B89\u5168\u9000\u51FA\u3002"
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "server-starting",
|
|
138
|
+
pattern: /^Starting Server/i,
|
|
139
|
+
translations: {
|
|
140
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] \u6B63\u5728\u542F\u52A8 BDS \u670D\u52A1\u7AEF..."
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "server-setting-up-logging",
|
|
145
|
+
pattern: /^NO LOG FILE! - setting up server logging\.\.\./i,
|
|
146
|
+
translations: {
|
|
147
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] \u6B63\u5728\u521D\u59CB\u5316\u670D\u52A1\u7AEF\u65E5\u5FD7\u7CFB\u7EDF..."
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
// 16. 打开世界数据
|
|
151
|
+
{
|
|
152
|
+
id: "opening-level",
|
|
153
|
+
pattern: /^Opening level '(.+?)'/i,
|
|
154
|
+
translations: {
|
|
155
|
+
"zh-CN": "[\u4E16\u754C] \u6B63\u5728\u6253\u5F00\u4E16\u754C\u6570\u636E: $1"
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
// 17. 网络端口与信令服务
|
|
159
|
+
{
|
|
160
|
+
id: "ipv4-port",
|
|
161
|
+
pattern: /^IPv4 supported, port: (\d+): Used for gameplay and LAN discovery/i,
|
|
162
|
+
translations: {
|
|
163
|
+
"zh-CN": "[\u7F51\u7EDC] IPv4 \u6E38\u620F\u4E0E\u5C40\u57DF\u7F51\u53D1\u73B0\u7AEF\u53E3: $1 (UDP)"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: "ipv6-port",
|
|
168
|
+
pattern: /^IPv6 supported, port: (\d+): Used for gameplay/i,
|
|
169
|
+
translations: {
|
|
170
|
+
"zh-CN": "[\u7F51\u7EDC] IPv6 \u6E38\u620F\u7AEF\u53E3: $1 (UDP)"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: "signaling-signed-in",
|
|
175
|
+
pattern: /^Signed in to signaling service successfully/i,
|
|
176
|
+
translations: {
|
|
177
|
+
"zh-CN": "[\u7F51\u7EDC] \u5DF2\u6210\u529F\u767B\u5F55\u5FAE\u8F6F\u8054\u673A\u4FE1\u4EE4\u670D\u52A1\u3002"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: "waiting-minecraft-services",
|
|
182
|
+
pattern: /^Waiting for Minecraft services\.\.\./i,
|
|
183
|
+
translations: {
|
|
184
|
+
"zh-CN": "[\u670D\u52A1\u7AEF] \u6B63\u5728\u7B49\u5F85 Minecraft \u57FA\u7840\u670D\u52A1\u8FDE\u63A5..."
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
// 18. 白名单警告与提示
|
|
188
|
+
{
|
|
189
|
+
id: "allowlist-empty-warning",
|
|
190
|
+
pattern: /^Allow list is enabled but contains no entries\./i,
|
|
191
|
+
translations: {
|
|
192
|
+
"zh-CN": "[\u767D\u540D\u5355\u8B66\u544A] \u767D\u540D\u5355\u529F\u80FD\u5DF2\u5F00\u542F\u4F46\u540D\u5355\u4E3A\u7A7A\uFF01\u9664\u7BA1\u7406\u5458\u5916\u5176\u4ED6\u73A9\u5BB6\u5C06\u65E0\u6CD5\u52A0\u5165\u670D\u52A1\u5668\u3002"
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: "allowlist-add-hint",
|
|
197
|
+
pattern: /^Use allowlist add <playername> for you and your friends so that they can access the server, or modify allowlist\.json manually\./i,
|
|
198
|
+
translations: {
|
|
199
|
+
"zh-CN": "[\u767D\u540D\u5355\u63D0\u793A] \u8BF7\u4F7F\u7528\u300Callowlist add <\u73A9\u5BB6\u540D>\u300D\u6DFB\u52A0\u5141\u8BB8\u8FDB\u5165\u7684\u73A9\u5BB6\uFF0C\u6216\u624B\u52A8\u7F16\u8F91 allowlist.json\u3002"
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: "allowlist-toggle-hint",
|
|
204
|
+
pattern: /^Alternatively, the allow list can be turned off by typing allowlist off or manually toggled in the server\.properties file\./i,
|
|
205
|
+
translations: {
|
|
206
|
+
"zh-CN": "[\u767D\u540D\u5355\u63D0\u793A] \u53EF\u901A\u8FC7\u8F93\u5165\u300Callowlist off\u300D\u6216\u5728 server.properties \u4E2D\u5173\u95ED\u767D\u540D\u5355\u63A7\u5236\u3002"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
// 19. 控制台内容日志已禁用
|
|
210
|
+
{
|
|
211
|
+
id: "content-log-disabled",
|
|
212
|
+
pattern: /^Content logging to console is disabled\.\s*Enable it with content-log-console-output-enabled=true in server\.properties/i,
|
|
213
|
+
translations: {
|
|
214
|
+
"zh-CN": "[\u63D0\u793A] \u6A21\u7EC4\u5185\u5BB9\u65E5\u5FD7\u8F93\u51FA\u81F3\u63A7\u5236\u53F0\u5F53\u524D\u5DF2\u5173\u95ED\uFF08\u53EF\u901A\u8FC7 server.properties \u4E2D\u7684 content-log-console-output-enabled=true \u5F00\u542F\uFF09\u3002"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
// 20. 未知指令提示
|
|
218
|
+
{
|
|
219
|
+
id: "unknown-command",
|
|
220
|
+
pattern: /^Unknown command:\s*(.+?)\.\s*Please check that the command exists and that you have permission to use it\./i,
|
|
221
|
+
translations: {
|
|
222
|
+
"zh-CN": "[\u6307\u4EE4\u9519\u8BEF] \u672A\u77E5\u6307\u4EE4\u300C$1\u300D\u3002\u8BF7\u68C0\u67E5\u6307\u4EE4\u662F\u5426\u5B58\u5728\u6216\u60A8\u662F\u5426\u5177\u5907\u6267\u884C\u6743\u9650\u3002"
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
// 21. 玩家连接与断开
|
|
226
|
+
{
|
|
227
|
+
id: "player-connected",
|
|
228
|
+
pattern: /^Player connected:\s*([^,]+),\s*xuid:\s*(\S+)/i,
|
|
229
|
+
translations: {
|
|
230
|
+
"zh-CN": "[\u73A9\u5BB6\u8FDE\u63A5] \u73A9\u5BB6 $1 \u5DF2\u52A0\u5165\u4E16\u754C (XUID: $2)"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: "player-disconnected",
|
|
235
|
+
pattern: /^Player disconnected:\s*([^,]+),\s*xuid:\s*(\S+)/i,
|
|
236
|
+
translations: {
|
|
237
|
+
"zh-CN": "[\u73A9\u5BB6\u65AD\u5F00] \u73A9\u5BB6 $1 \u5DF2\u79BB\u5F00\u4E16\u754C (XUID: $2)"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
];
|
|
241
|
+
function interpolateRegexTemplate(match, template) {
|
|
242
|
+
return template.replace(/\$(\d+)/g, (full, indexStr) => {
|
|
243
|
+
const idx = parseInt(indexStr, 10);
|
|
244
|
+
if (!isNaN(idx) && idx < match.length) {
|
|
245
|
+
return match[idx] ?? "";
|
|
246
|
+
}
|
|
247
|
+
return full;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function applyRuleReplacement(text, regex, replaceTemplate) {
|
|
251
|
+
const m = text.match(regex);
|
|
252
|
+
if (!m) return text;
|
|
253
|
+
return interpolateRegexTemplate(m, replaceTemplate);
|
|
254
|
+
}
|
|
255
|
+
function translateBdsLog(text, locale = "zh-CN") {
|
|
256
|
+
const trimmed = text.trim();
|
|
257
|
+
if (!trimmed) {
|
|
258
|
+
return { translated: false, text };
|
|
259
|
+
}
|
|
260
|
+
const targetLocale = locale === "zh" ? "zh-CN" : locale;
|
|
261
|
+
for (const rule of BUILTIN_BDS_TRANSLATIONS) {
|
|
262
|
+
const m = trimmed.match(rule.pattern);
|
|
263
|
+
if (m) {
|
|
264
|
+
const template = rule.translations[targetLocale];
|
|
265
|
+
if (template) {
|
|
266
|
+
const translatedText = interpolateRegexTemplate(m, template);
|
|
267
|
+
return { translated: true, text: translatedText, ruleId: rule.id };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return { translated: false, text };
|
|
272
|
+
}
|
|
273
|
+
export {
|
|
274
|
+
BUILTIN_BDS_TRANSLATIONS,
|
|
275
|
+
applyRuleReplacement,
|
|
276
|
+
interpolateRegexTemplate,
|
|
277
|
+
translateBdsLog
|
|
278
|
+
};
|
|
279
|
+
//# sourceMappingURL=log-translator.js.map
|