@x18n/ui 0.0.2 → 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.d.mts +255 -0
- package/dist/index.mjs +628 -0
- package/dist/nitro.json +15 -0
- package/dist/public/200.html +1 -0
- package/dist/public/404.html +1 -0
- package/dist/public/_nuxt/2T7o9vZw.js +1 -0
- package/dist/public/_nuxt/6U3VBVNw.js +3 -0
- package/dist/public/_nuxt/B2lY2QM5.js +1 -0
- package/dist/public/_nuxt/B3c8VNtz.js +1 -0
- package/dist/public/_nuxt/B_NBUgT3.js +1 -0
- package/dist/public/_nuxt/C-abT7Ra.js +1 -0
- package/dist/public/_nuxt/CKRUbA4H.js +1 -0
- package/dist/public/_nuxt/CUAtu6-x.js +1 -0
- package/dist/public/_nuxt/CuHl-Wxz.js +1 -0
- package/dist/public/_nuxt/CvRF2CKC.js +1 -0
- package/dist/public/_nuxt/D6gh7el6.js +1 -0
- package/dist/public/_nuxt/DCQwHjae.js +4 -0
- package/dist/public/_nuxt/DgJ_0G3r.js +1 -0
- package/dist/public/_nuxt/DgTv_6EB.js +1 -0
- package/dist/public/_nuxt/DvXI0X_5.js +1 -0
- package/dist/public/_nuxt/UAC6JKNO.js +1 -0
- package/dist/public/_nuxt/builds/latest.json +1 -0
- package/dist/public/_nuxt/builds/meta/45c30525-030d-44d4-bb10-65a4ca3668c9.json +1 -0
- package/dist/public/_nuxt/entry.puki6KUo.css +1 -0
- package/dist/public/_nuxt/error-404.BJfOvlY_.css +1 -0
- package/dist/public/_nuxt/error-500.DRhgjSut.css +1 -0
- package/dist/public/_nuxt/kCfYtaXI.js +1 -0
- package/dist/public/_nuxt/qB8tKtt1.js +2 -0
- package/dist/public/_nuxt/xg14vwJh.js +1 -0
- package/dist/public/index.html +1 -0
- package/package.json +4 -4
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { defineDevframe, defineRpcFunction } from "devframe";
|
|
3
|
+
import { toJsonSchema } from "@valibot/to-json-schema";
|
|
4
|
+
import { extractItems, findCandidates, toPlanFile } from "@x18n/builtins/extractors";
|
|
5
|
+
import { X18nError, createLineIndex, parseMessageBatch, placeholderProblems, renderPrompt, toWireDiagnostic } from "@x18n/core";
|
|
6
|
+
import * as v from "valibot";
|
|
7
|
+
//#region package.json
|
|
8
|
+
var name = "@x18n/ui";
|
|
9
|
+
var version = "0.0.3";
|
|
10
|
+
var description = "x18n UI as a devframe: dev server, static report, in-browser workspace and VS Code panel";
|
|
11
|
+
var homepage = "https://github.com/antfu/x18n#readme";
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/node/schemas.ts
|
|
14
|
+
function text(description) {
|
|
15
|
+
return v.pipe(v.string(), v.description(description));
|
|
16
|
+
}
|
|
17
|
+
const project = v.optional(text("Project name from `x18n_status`. Required only in a monorepo with several projects."));
|
|
18
|
+
const leaf = v.union([
|
|
19
|
+
v.string(),
|
|
20
|
+
v.number(),
|
|
21
|
+
v.boolean(),
|
|
22
|
+
v.null()
|
|
23
|
+
]);
|
|
24
|
+
const textRange = v.object({
|
|
25
|
+
start: v.number(),
|
|
26
|
+
end: v.number()
|
|
27
|
+
});
|
|
28
|
+
const ProjectQuerySchema = v.object({ project });
|
|
29
|
+
const KeyQuerySchema = v.object({
|
|
30
|
+
project,
|
|
31
|
+
key: text("Full key, for example `nav.home` or `common:save`.")
|
|
32
|
+
});
|
|
33
|
+
const UsageQuerySchema = v.object({
|
|
34
|
+
project,
|
|
35
|
+
key: v.optional(text("Only usages of this key.")),
|
|
36
|
+
path: v.optional(text("Only usages in this file (path relative to the project root)."))
|
|
37
|
+
});
|
|
38
|
+
const PromptQuerySchema = v.object({
|
|
39
|
+
project,
|
|
40
|
+
locale: text("Target locale code, as listed by `x18n_status`."),
|
|
41
|
+
keys: v.optional(v.union([text("Key glob: `*` inside a segment, `**` across segments."), v.array(v.string())])),
|
|
42
|
+
namespace: v.optional(v.string()),
|
|
43
|
+
limit: v.optional(v.pipe(v.number(), v.description("Messages per prompt. Default 50."))),
|
|
44
|
+
cursor: v.optional(text("`nextCursor` of the previous prompt."))
|
|
45
|
+
});
|
|
46
|
+
const EditOpSchema = v.variant("type", [
|
|
47
|
+
v.object({
|
|
48
|
+
type: v.literal("set"),
|
|
49
|
+
key: v.string(),
|
|
50
|
+
locale: v.string(),
|
|
51
|
+
value: leaf
|
|
52
|
+
}),
|
|
53
|
+
v.object({
|
|
54
|
+
type: v.literal("rename"),
|
|
55
|
+
from: v.string(),
|
|
56
|
+
to: v.string(),
|
|
57
|
+
usages: v.exactOptional(v.boolean())
|
|
58
|
+
}),
|
|
59
|
+
v.object({
|
|
60
|
+
type: v.literal("rename-prefix"),
|
|
61
|
+
from: v.string(),
|
|
62
|
+
to: v.string(),
|
|
63
|
+
usages: v.exactOptional(v.boolean())
|
|
64
|
+
}),
|
|
65
|
+
v.object({
|
|
66
|
+
type: v.literal("delete"),
|
|
67
|
+
key: v.string(),
|
|
68
|
+
locales: v.exactOptional(v.union([v.literal("all"), v.array(v.string())]))
|
|
69
|
+
})
|
|
70
|
+
]);
|
|
71
|
+
const PlanQuerySchema = v.object({
|
|
72
|
+
project,
|
|
73
|
+
ops: v.array(EditOpSchema)
|
|
74
|
+
});
|
|
75
|
+
const ApplyQuerySchema = v.object({
|
|
76
|
+
project,
|
|
77
|
+
ops: v.array(EditOpSchema),
|
|
78
|
+
answers: v.optional(v.record(v.string(), v.string())),
|
|
79
|
+
force: v.optional(v.boolean())
|
|
80
|
+
});
|
|
81
|
+
const ExtractQuerySchema = v.object({
|
|
82
|
+
project,
|
|
83
|
+
files: v.optional(v.pipe(v.array(v.string()), v.description("Only these files (globs relative to the project root). Default: every scanned file.")))
|
|
84
|
+
});
|
|
85
|
+
const ExtractItemSchema = v.object({
|
|
86
|
+
path: v.string(),
|
|
87
|
+
range: textRange,
|
|
88
|
+
original: v.string(),
|
|
89
|
+
key: v.string(),
|
|
90
|
+
value: v.string(),
|
|
91
|
+
replacement: v.string(),
|
|
92
|
+
imports: v.array(v.string())
|
|
93
|
+
});
|
|
94
|
+
const ExtractApplySchema = v.object({
|
|
95
|
+
project,
|
|
96
|
+
items: v.pipe(v.array(ExtractItemSchema), v.description("Items from `x18n_extract_plan`, keys and replacements edited as needed; drop items to skip them."))
|
|
97
|
+
});
|
|
98
|
+
const OpenQuerySchema = v.object({
|
|
99
|
+
project,
|
|
100
|
+
path: v.string(),
|
|
101
|
+
line: v.number(),
|
|
102
|
+
column: v.number()
|
|
103
|
+
});
|
|
104
|
+
/** Agent tools only. */
|
|
105
|
+
const AgentKeysSchema = v.object({
|
|
106
|
+
project,
|
|
107
|
+
glob: v.optional(text("Key glob: `*` inside a segment, `**` across segments.")),
|
|
108
|
+
missing: v.optional(text("Only keys missing or empty in this locale.")),
|
|
109
|
+
unused: v.optional(v.pipe(v.boolean(), v.description("Only keys without usages in code."))),
|
|
110
|
+
namespace: v.optional(v.string()),
|
|
111
|
+
values: v.optional(v.pipe(v.boolean(), v.description("Include the value per locale."))),
|
|
112
|
+
limit: v.optional(v.pipe(v.number(), v.description("Page size. Default 100."))),
|
|
113
|
+
cursor: v.optional(text("`nextCursor` of the previous page."))
|
|
114
|
+
});
|
|
115
|
+
const AgentUsagesSchema = v.object({
|
|
116
|
+
project,
|
|
117
|
+
key: v.optional(text("Only usages of this key.")),
|
|
118
|
+
path: v.optional(text("Only usages in this file (path relative to the project root).")),
|
|
119
|
+
limit: v.optional(v.pipe(v.number(), v.description("Page size. Default 100."))),
|
|
120
|
+
cursor: v.optional(text("`nextCursor` of the previous page."))
|
|
121
|
+
});
|
|
122
|
+
const AgentCheckSchema = v.object({
|
|
123
|
+
project,
|
|
124
|
+
only: v.optional(v.pipe(v.array(v.string()), v.description("Only these check ids, for example `placeholder-mismatch`, `invalid-syntax`, `missing-translation`."))),
|
|
125
|
+
locale: v.optional(v.pipe(v.array(v.string()), v.description("Only diagnostics for these locales."))),
|
|
126
|
+
limit: v.optional(v.pipe(v.number(), v.description("Page size. Default 100."))),
|
|
127
|
+
cursor: v.optional(text("`nextCursor` of the previous page."))
|
|
128
|
+
});
|
|
129
|
+
const AgentSetSchema = v.object({
|
|
130
|
+
project,
|
|
131
|
+
messages: v.pipe(v.record(v.string(), v.record(v.string(), leaf)), v.description("`{ \"<locale>\": { \"<key>\": \"<value>\" } }`, the same shape as `x18n apply`.")),
|
|
132
|
+
force: v.optional(v.pipe(v.boolean(), v.description("Write values even when their placeholders differ from the source value.")))
|
|
133
|
+
});
|
|
134
|
+
const confirm = v.optional(v.pipe(v.boolean(), v.description("Apply the plan. Without it, the tool only returns the plan.")));
|
|
135
|
+
const answers = v.optional(v.pipe(v.record(v.string(), v.string()), v.description("Decision id to option id, for decisions in the plan. Default: each decision's `default`.")));
|
|
136
|
+
const AgentRenameSchema = v.object({
|
|
137
|
+
project,
|
|
138
|
+
from: text("Key (or parent of keys) to rename."),
|
|
139
|
+
to: text("New key."),
|
|
140
|
+
usages: v.optional(v.pipe(v.boolean(), v.description("Also rewrite usages in code. Default true."))),
|
|
141
|
+
confirm,
|
|
142
|
+
answers
|
|
143
|
+
});
|
|
144
|
+
const AgentDeleteSchema = v.object({
|
|
145
|
+
project,
|
|
146
|
+
key: text("Key (or parent of keys) to delete."),
|
|
147
|
+
locales: v.optional(v.pipe(v.array(v.string()), v.description("Only in these locales. Default: all."))),
|
|
148
|
+
confirm,
|
|
149
|
+
answers
|
|
150
|
+
});
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/node/views.ts
|
|
153
|
+
/** The named project, or the only one. */
|
|
154
|
+
function pickProject(projects, name) {
|
|
155
|
+
const found = name === void 0 ? projects.length === 1 ? projects[0] : void 0 : projects.find((p) => p.name === name);
|
|
156
|
+
if (!found) throw new X18nError("X18N0003", name === void 0 ? `pass a project (${projects.map((p) => p.name).join(", ")})` : `"${name}" (${projects.map((p) => p.name).join(", ")})`);
|
|
157
|
+
return found;
|
|
158
|
+
}
|
|
159
|
+
function percent(coverage) {
|
|
160
|
+
return coverage.total === 0 ? 100 : Math.floor(coverage.translated / coverage.total * 1e3) / 10;
|
|
161
|
+
}
|
|
162
|
+
function summarize({ name, project }) {
|
|
163
|
+
const analysis = project.analyze();
|
|
164
|
+
const byCode = /* @__PURE__ */ new Map();
|
|
165
|
+
for (const d of analysis.diagnostics) {
|
|
166
|
+
const entry = byCode.get(d.code);
|
|
167
|
+
byCode.set(d.code, {
|
|
168
|
+
code: d.code,
|
|
169
|
+
severity: d.severity,
|
|
170
|
+
count: (entry?.count ?? 0) + 1
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const count = (severities) => analysis.diagnostics.filter((d) => severities.includes(d.severity)).length;
|
|
174
|
+
return {
|
|
175
|
+
name,
|
|
176
|
+
sourceLocale: project.sourceLocale,
|
|
177
|
+
namespaced: project.namespaced,
|
|
178
|
+
locales: analysis.coverage.map((c) => {
|
|
179
|
+
const info = project.localeInfo(c.locale);
|
|
180
|
+
return {
|
|
181
|
+
code: c.locale,
|
|
182
|
+
displayName: info.displayName,
|
|
183
|
+
flag: info.flag,
|
|
184
|
+
total: c.total,
|
|
185
|
+
translated: c.translated,
|
|
186
|
+
missing: c.missing.length,
|
|
187
|
+
empty: c.empty.length,
|
|
188
|
+
percent: percent(c)
|
|
189
|
+
};
|
|
190
|
+
}),
|
|
191
|
+
resources: project.resources.length,
|
|
192
|
+
keys: project.keys().length,
|
|
193
|
+
usages: project.usages().length,
|
|
194
|
+
diagnostics: {
|
|
195
|
+
errors: count(["error"]),
|
|
196
|
+
warnings: count(["warning"]),
|
|
197
|
+
infos: count(["info", "hint"]),
|
|
198
|
+
byCode: [...byCode.values()].sort((a, b) => b.count - a.count || a.code.localeCompare(b.code))
|
|
199
|
+
},
|
|
200
|
+
presets: project.explain().presets.filter((p) => p.reason === "listed" || p.reason === "detected").map((p) => p.name)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function keyTable({ name, project }) {
|
|
204
|
+
const analysis = project.analyze();
|
|
205
|
+
const unused = new Set(analysis.unused);
|
|
206
|
+
const diagnostics = /* @__PURE__ */ new Map();
|
|
207
|
+
for (const d of analysis.diagnostics) if (d.key !== void 0) diagnostics.set(d.key, (diagnostics.get(d.key) ?? 0) + 1);
|
|
208
|
+
const missing = /* @__PURE__ */ new Map();
|
|
209
|
+
for (const c of analysis.coverage) for (const key of [...c.missing, ...c.empty]) {
|
|
210
|
+
const list = missing.get(key) ?? [];
|
|
211
|
+
missing.set(key, list);
|
|
212
|
+
list.push(c.locale);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
project: name,
|
|
216
|
+
sourceLocale: project.sourceLocale,
|
|
217
|
+
locales: project.locales,
|
|
218
|
+
rows: project.keys().map((key) => {
|
|
219
|
+
const info = project.get(key);
|
|
220
|
+
return {
|
|
221
|
+
key,
|
|
222
|
+
namespace: info?.namespace,
|
|
223
|
+
values: Object.fromEntries((info?.messages ?? []).map((m) => [m.locale, m.value])),
|
|
224
|
+
missing: missing.get(key) ?? [],
|
|
225
|
+
unused: unused.has(key),
|
|
226
|
+
diagnostics: diagnostics.get(key) ?? 0
|
|
227
|
+
};
|
|
228
|
+
})
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const indexes = /* @__PURE__ */ new WeakMap();
|
|
232
|
+
/** Line index of a file, rebuilt only when its text changed. */
|
|
233
|
+
function lineIndex(p, path) {
|
|
234
|
+
const text = p.project.text(path) ?? "";
|
|
235
|
+
const cache = indexes.get(p) ?? /* @__PURE__ */ new Map();
|
|
236
|
+
indexes.set(p, cache);
|
|
237
|
+
const cached = cache.get(path);
|
|
238
|
+
if (cached?.text === text) return cached.index;
|
|
239
|
+
const index = createLineIndex(text);
|
|
240
|
+
cache.set(path, {
|
|
241
|
+
text,
|
|
242
|
+
index
|
|
243
|
+
});
|
|
244
|
+
return index;
|
|
245
|
+
}
|
|
246
|
+
function snippet(index, line, around = 2) {
|
|
247
|
+
const first = Math.max(0, line - around);
|
|
248
|
+
const last = Math.min(index.lineCount - 1, line + around);
|
|
249
|
+
return {
|
|
250
|
+
line: first + 1,
|
|
251
|
+
lines: Array.from({ length: last - first + 1 }, (_, i) => index.line(first + i))
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function usageView(p, usage, possible = false) {
|
|
255
|
+
const index = lineIndex(p, usage.path);
|
|
256
|
+
const position = index.position(usage.range.start);
|
|
257
|
+
return {
|
|
258
|
+
key: usage.key,
|
|
259
|
+
raw: usage.raw,
|
|
260
|
+
path: usage.path,
|
|
261
|
+
line: position.line + 1,
|
|
262
|
+
column: position.character + 1,
|
|
263
|
+
kind: usage.kind,
|
|
264
|
+
dynamic: usage.dynamic,
|
|
265
|
+
possible,
|
|
266
|
+
snippet: snippet(index, position.line)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function usageViews(p, matches) {
|
|
270
|
+
return matches.map((m) => usageView(p, m.usage, m.possible));
|
|
271
|
+
}
|
|
272
|
+
function wire(p, diagnostics) {
|
|
273
|
+
return diagnostics.map((d) => toWireDiagnostic(p.name, d, (path) => p.project.text(path)));
|
|
274
|
+
}
|
|
275
|
+
function keyDetail(p, key) {
|
|
276
|
+
const { project } = p;
|
|
277
|
+
const info = project.get(project.parseKey(key));
|
|
278
|
+
if (!info) return null;
|
|
279
|
+
const syntaxes = project.placeholderSyntaxes;
|
|
280
|
+
return {
|
|
281
|
+
project: p.name,
|
|
282
|
+
key: info.key,
|
|
283
|
+
namespace: info.namespace,
|
|
284
|
+
messages: info.messages.map((m) => {
|
|
285
|
+
const path = project.resources.find((r) => r.id === m.resource)?.path ?? m.resource;
|
|
286
|
+
return {
|
|
287
|
+
locale: m.locale,
|
|
288
|
+
value: m.value,
|
|
289
|
+
path,
|
|
290
|
+
line: lineIndex(p, path).position(m.range?.key.start ?? 0).line + 1,
|
|
291
|
+
placeholders: typeof m.value === "string" ? syntaxes.flatMap((s) => s.find(String(m.value))).map((ph) => ({
|
|
292
|
+
text: ph.text,
|
|
293
|
+
start: ph.range.start,
|
|
294
|
+
end: ph.range.end
|
|
295
|
+
})).sort((a, b) => a.start - b.start) : []
|
|
296
|
+
};
|
|
297
|
+
}),
|
|
298
|
+
missing: info.missing,
|
|
299
|
+
usages: usageViews(p, info.usages),
|
|
300
|
+
diagnostics: wire(p, info.diagnostics)
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function analysisView(p) {
|
|
304
|
+
const analysis = p.project.analyze();
|
|
305
|
+
return {
|
|
306
|
+
project: p.name,
|
|
307
|
+
diagnostics: wire(p, analysis.diagnostics),
|
|
308
|
+
unused: analysis.unused,
|
|
309
|
+
undefinedUsages: analysis.undefinedUsages.map((u) => usageView(p, u))
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function explainView(p) {
|
|
313
|
+
const { root: _root, ...rest } = p.project.explain();
|
|
314
|
+
return rest;
|
|
315
|
+
}
|
|
316
|
+
function planView(plan, problems) {
|
|
317
|
+
return {
|
|
318
|
+
keys: plan.keys,
|
|
319
|
+
warnings: plan.warnings,
|
|
320
|
+
decisions: plan.decisions,
|
|
321
|
+
changes: plan.changes.map((c) => ({
|
|
322
|
+
type: c.type,
|
|
323
|
+
path: c.path
|
|
324
|
+
})),
|
|
325
|
+
problems
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function previewOps(p, ops) {
|
|
329
|
+
return planView(p.project.plan(ops), placeholderProblems(p.project, ops));
|
|
330
|
+
}
|
|
331
|
+
/** Plans and applies ops; placeholder problems block the write unless `force`. */
|
|
332
|
+
async function applyOps(p, ops, options = {}) {
|
|
333
|
+
const plan = p.project.plan(ops);
|
|
334
|
+
const problems = placeholderProblems(p.project, ops);
|
|
335
|
+
if (problems.length > 0 && !options.force) return {
|
|
336
|
+
...planView(plan, problems),
|
|
337
|
+
applied: false,
|
|
338
|
+
revision: p.project.revision
|
|
339
|
+
};
|
|
340
|
+
const answers = Object.fromEntries(plan.decisions.map((d) => [d.id, options.answers?.[d.id] ?? d.default]));
|
|
341
|
+
const result = await p.project.apply(plan, { answers });
|
|
342
|
+
return {
|
|
343
|
+
...planView(plan, problems),
|
|
344
|
+
applied: true,
|
|
345
|
+
revision: result.revision
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/node/agent.ts
|
|
350
|
+
function page(items, query) {
|
|
351
|
+
const start = Number(query.cursor ?? 0) || 0;
|
|
352
|
+
const end = start + (query.limit ?? 100);
|
|
353
|
+
return {
|
|
354
|
+
total: items.length,
|
|
355
|
+
nextCursor: end < items.length ? String(end) : void 0,
|
|
356
|
+
items: items.slice(start, end)
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Registers the MCP tools (`x18n_*` on the wire). Descriptions are written for agents.
|
|
361
|
+
* Tools take one flat object, validated here, so agents see named fields instead of positional args.
|
|
362
|
+
*/
|
|
363
|
+
function registerAgentTools(ctx, projects) {
|
|
364
|
+
function tool(id, safety, description, schema, run) {
|
|
365
|
+
ctx.agent.registerTool({
|
|
366
|
+
id: `x18n:${id}`,
|
|
367
|
+
safety,
|
|
368
|
+
description,
|
|
369
|
+
inputSchema: toJsonSchema(schema),
|
|
370
|
+
handler: (input) => run(v.parse(schema, input ?? {}))
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
const pick = (name) => pickProject(projects, name);
|
|
374
|
+
/** Plans the ops, and applies them only with `confirm`. */
|
|
375
|
+
const confirmable = (p, ops, query) => query.confirm ? applyOps(p, ops, { answers: query.answers }) : {
|
|
376
|
+
...previewOps(p, ops),
|
|
377
|
+
applied: false,
|
|
378
|
+
revision: p.project.revision
|
|
379
|
+
};
|
|
380
|
+
tool("status", "read", "Overview of the i18n project: locales with translation coverage, counts of keys, resources and usages, diagnostics by check, and detected presets. Call it first to learn project names, the source locale and locale codes.", ProjectQuerySchema, (query) => ({ projects: (query.project === void 0 ? projects : [pick(query.project)]).map(summarize) }));
|
|
381
|
+
tool("keys", "read", "List message keys, paged. Filter by `missing` locale (keys to translate), `unused` (keys no code uses), `namespace` or a key `glob`. Pass `values: true` to get the value per locale. Continue with `cursor: nextCursor`.", AgentKeysSchema, (query) => {
|
|
382
|
+
const { project } = pick(query.project);
|
|
383
|
+
const { items, ...rest } = page(project.keys({
|
|
384
|
+
glob: query.glob,
|
|
385
|
+
missing: query.missing,
|
|
386
|
+
unused: query.unused,
|
|
387
|
+
namespace: query.namespace
|
|
388
|
+
}), query);
|
|
389
|
+
return {
|
|
390
|
+
...rest,
|
|
391
|
+
keys: items.map((key) => query.values ? {
|
|
392
|
+
key,
|
|
393
|
+
values: Object.fromEntries((project.get(key)?.messages ?? []).map((m) => [m.locale, m.value]))
|
|
394
|
+
} : { key })
|
|
395
|
+
};
|
|
396
|
+
});
|
|
397
|
+
tool("get", "read", "One key: its value in every locale with file and line, locales where it is missing, usages in code with a few lines of context, and diagnostics. Check a key with it before creating or renaming one.", KeyQuerySchema, (query) => {
|
|
398
|
+
const detail = keyDetail(pick(query.project), query.key);
|
|
399
|
+
if (!detail) throw new X18nError("X18N4006", `"${query.key}"; find keys with x18n_keys`);
|
|
400
|
+
return detail;
|
|
401
|
+
});
|
|
402
|
+
tool("usages", "read", "Usages in code, paged: of one `key` (usages with a computed key under a prefix of it are marked `possible`), of one file (`path`), or all. Each usage has file, line, column and a code snippet.", AgentUsagesSchema, (query) => {
|
|
403
|
+
const p = pick(query.project);
|
|
404
|
+
const { items, ...rest } = page(p.project.usages({
|
|
405
|
+
key: query.key,
|
|
406
|
+
path: query.path
|
|
407
|
+
}), query);
|
|
408
|
+
return {
|
|
409
|
+
...rest,
|
|
410
|
+
usages: usageViews(p, items)
|
|
411
|
+
};
|
|
412
|
+
});
|
|
413
|
+
tool("check", "read", "Run the checks (missing translations, placeholder mismatches, invalid syntax, unused and undefined keys, ...) and return diagnostics, paged. After writing messages, call it with `only: [\"placeholder-mismatch\", \"invalid-syntax\"]` and fix what it reports.", AgentCheckSchema, (query) => {
|
|
414
|
+
const p = pick(query.project);
|
|
415
|
+
const diagnostics = p.project.analyze().diagnostics.filter((d) => (!query.only || query.only.includes(d.code)) && (!query.locale || d.locale !== void 0 && query.locale.includes(d.locale)));
|
|
416
|
+
const { items, ...rest } = page(diagnostics, query);
|
|
417
|
+
return {
|
|
418
|
+
...rest,
|
|
419
|
+
summary: {
|
|
420
|
+
errors: diagnostics.filter((d) => d.severity === "error").length,
|
|
421
|
+
warnings: diagnostics.filter((d) => d.severity === "warning").length
|
|
422
|
+
},
|
|
423
|
+
diagnostics: items.map((d) => toWireDiagnostic(p.name, d, (path) => p.project.text(path)))
|
|
424
|
+
};
|
|
425
|
+
});
|
|
426
|
+
tool("translate_prompt", "read", "Instructions for translating missing messages into a locale: rules, glossary, style examples and the items with usage context, as markdown. Follow it, then write the results with x18n_set_messages. It says how many items remain and the cursor for the next batch.", PromptQuerySchema, (query) => {
|
|
427
|
+
const { project, locale, ...options } = query;
|
|
428
|
+
return renderPrompt(pick(project).project.prompt("translate", locale, options));
|
|
429
|
+
});
|
|
430
|
+
tool("set_messages", "action", "Set many messages at once: `messages` is `{ \"<locale>\": { \"<key>\": \"<value>\" } }`, the same shape as `x18n apply`. Files keep their format, key style and order. When a value drops or adds placeholders compared to the source value, nothing is written and `problems` lists them (`applied: false`); fix the values, or pass `force: true`.", AgentSetSchema, (query) => {
|
|
431
|
+
const p = pick(query.project);
|
|
432
|
+
return applyOps(p, parseMessageBatch(p.project, query.messages), { force: query.force });
|
|
433
|
+
});
|
|
434
|
+
tool("rename_key", "destructive", "Rename a key (or every key under a parent) in all locales, and its usages in code unless `usages: false`. Without `confirm` it returns the plan (files to change, decisions, warnings); call again with `confirm: true` to apply it.", AgentRenameSchema, (query) => {
|
|
435
|
+
const p = pick(query.project);
|
|
436
|
+
return confirmable(p, [{
|
|
437
|
+
type: "rename",
|
|
438
|
+
from: p.project.parseKey(query.from),
|
|
439
|
+
to: p.project.parseKey(query.to),
|
|
440
|
+
usages: query.usages !== false
|
|
441
|
+
}], query);
|
|
442
|
+
});
|
|
443
|
+
tool("delete_key", "destructive", "Delete a key (or every key under a parent) in all locales, or only in `locales`. Code is not changed. Without `confirm` it returns the plan; call again with `confirm: true` to apply it.", AgentDeleteSchema, (query) => {
|
|
444
|
+
const p = pick(query.project);
|
|
445
|
+
return confirmable(p, [{
|
|
446
|
+
type: "delete",
|
|
447
|
+
key: p.project.parseKey(query.key),
|
|
448
|
+
locales: query.locales ?? "all"
|
|
449
|
+
}], query);
|
|
450
|
+
});
|
|
451
|
+
tool("extract_plan", "read", "Find hard-coded strings in source files and propose a key, a message and a code replacement for each. Review the items (edit keys, drop items you do not want), then pass them to x18n_extract_apply.", ExtractQuerySchema, (query) => {
|
|
452
|
+
const { project } = pick(query.project);
|
|
453
|
+
return toPlanFile(project, findCandidates(project, { files: query.files }));
|
|
454
|
+
});
|
|
455
|
+
tool("extract_apply", "action", "Apply extraction items from x18n_extract_plan: adds the messages to the source locale and rewrites the code. Fails when a file changed since the plan was made; plan again then.", ExtractApplySchema, (query) => {
|
|
456
|
+
const p = pick(query.project);
|
|
457
|
+
return applyOps(p, [{
|
|
458
|
+
type: "extract",
|
|
459
|
+
items: extractItems(p.project, query.items)
|
|
460
|
+
}]);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/node/rpc.ts
|
|
465
|
+
/** Registers the `x18n:*` functions the SPA calls. Queries dump one record per project (and per key) for the static build. */
|
|
466
|
+
function registerRpc(ctx, projects, options) {
|
|
467
|
+
const rpc = ctx.scope("x18n").rpc;
|
|
468
|
+
const perProject = () => projects.map((p) => [{ project: p.name }]);
|
|
469
|
+
rpc.register(defineRpcFunction({
|
|
470
|
+
name: "project",
|
|
471
|
+
type: "static",
|
|
472
|
+
jsonSerializable: true,
|
|
473
|
+
handler: () => ({
|
|
474
|
+
projects: projects.map(summarize),
|
|
475
|
+
openInEditor: options.openInEditor !== void 0
|
|
476
|
+
})
|
|
477
|
+
}));
|
|
478
|
+
rpc.register(defineRpcFunction({
|
|
479
|
+
name: "keys",
|
|
480
|
+
type: "query",
|
|
481
|
+
jsonSerializable: true,
|
|
482
|
+
handler: (query) => keyTable(pickProject(projects, v.parse(ProjectQuerySchema, query).project)),
|
|
483
|
+
dump: () => ({ inputs: perProject() })
|
|
484
|
+
}));
|
|
485
|
+
rpc.register(defineRpcFunction({
|
|
486
|
+
name: "key",
|
|
487
|
+
type: "query",
|
|
488
|
+
jsonSerializable: true,
|
|
489
|
+
handler: (query) => {
|
|
490
|
+
const { project, key } = v.parse(KeyQuerySchema, query);
|
|
491
|
+
return keyDetail(pickProject(projects, project), key);
|
|
492
|
+
},
|
|
493
|
+
dump: () => ({
|
|
494
|
+
inputs: projects.flatMap((p) => p.project.keys().map((key) => [{
|
|
495
|
+
project: p.name,
|
|
496
|
+
key
|
|
497
|
+
}])),
|
|
498
|
+
fallback: null
|
|
499
|
+
})
|
|
500
|
+
}));
|
|
501
|
+
rpc.register(defineRpcFunction({
|
|
502
|
+
name: "usages",
|
|
503
|
+
type: "query",
|
|
504
|
+
jsonSerializable: true,
|
|
505
|
+
handler: (query) => {
|
|
506
|
+
const { project, key, path } = v.parse(UsageQuerySchema, query);
|
|
507
|
+
const p = pickProject(projects, project);
|
|
508
|
+
return usageViews(p, p.project.usages({
|
|
509
|
+
key,
|
|
510
|
+
path
|
|
511
|
+
}));
|
|
512
|
+
},
|
|
513
|
+
dump: () => ({ inputs: perProject() })
|
|
514
|
+
}));
|
|
515
|
+
rpc.register(defineRpcFunction({
|
|
516
|
+
name: "analysis",
|
|
517
|
+
type: "query",
|
|
518
|
+
jsonSerializable: true,
|
|
519
|
+
handler: (query) => analysisView(pickProject(projects, v.parse(ProjectQuerySchema, query).project)),
|
|
520
|
+
dump: () => ({ inputs: perProject() })
|
|
521
|
+
}));
|
|
522
|
+
rpc.register(defineRpcFunction({
|
|
523
|
+
name: "explain",
|
|
524
|
+
type: "static",
|
|
525
|
+
jsonSerializable: true,
|
|
526
|
+
handler: () => ({ projects: projects.map(explainView) })
|
|
527
|
+
}));
|
|
528
|
+
rpc.register(defineRpcFunction({
|
|
529
|
+
name: "translate-prompt",
|
|
530
|
+
type: "query",
|
|
531
|
+
jsonSerializable: true,
|
|
532
|
+
handler: (query) => {
|
|
533
|
+
const { project, locale, ...options } = v.parse(PromptQuerySchema, query);
|
|
534
|
+
return renderPrompt(pickProject(projects, project).project.prompt("translate", locale, options));
|
|
535
|
+
}
|
|
536
|
+
}));
|
|
537
|
+
rpc.register(defineRpcFunction({
|
|
538
|
+
name: "extract-candidates",
|
|
539
|
+
type: "query",
|
|
540
|
+
jsonSerializable: true,
|
|
541
|
+
handler: (query) => {
|
|
542
|
+
const { project, files } = v.parse(ExtractQuerySchema, query);
|
|
543
|
+
return findCandidates(pickProject(projects, project).project, { files });
|
|
544
|
+
},
|
|
545
|
+
dump: () => ({ inputs: perProject() })
|
|
546
|
+
}));
|
|
547
|
+
if (ctx.mode !== "dev") return;
|
|
548
|
+
rpc.register(defineRpcFunction({
|
|
549
|
+
name: "plan",
|
|
550
|
+
type: "action",
|
|
551
|
+
jsonSerializable: true,
|
|
552
|
+
handler: (query) => {
|
|
553
|
+
const { project, ops } = v.parse(PlanQuerySchema, query);
|
|
554
|
+
return previewOps(pickProject(projects, project), ops);
|
|
555
|
+
}
|
|
556
|
+
}));
|
|
557
|
+
rpc.register(defineRpcFunction({
|
|
558
|
+
name: "apply",
|
|
559
|
+
type: "action",
|
|
560
|
+
jsonSerializable: true,
|
|
561
|
+
handler: (query) => {
|
|
562
|
+
const { project, ops, answers, force } = v.parse(ApplyQuerySchema, query);
|
|
563
|
+
return applyOps(pickProject(projects, project), ops, {
|
|
564
|
+
answers,
|
|
565
|
+
force
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}));
|
|
569
|
+
rpc.register(defineRpcFunction({
|
|
570
|
+
name: "extract-apply",
|
|
571
|
+
type: "action",
|
|
572
|
+
jsonSerializable: true,
|
|
573
|
+
handler: (query) => {
|
|
574
|
+
const { project, items } = v.parse(ExtractApplySchema, query);
|
|
575
|
+
const p = pickProject(projects, project);
|
|
576
|
+
return applyOps(p, [{
|
|
577
|
+
type: "extract",
|
|
578
|
+
items: extractItems(p.project, items)
|
|
579
|
+
}]);
|
|
580
|
+
}
|
|
581
|
+
}));
|
|
582
|
+
const open = options.openInEditor;
|
|
583
|
+
if (open) rpc.register(defineRpcFunction({
|
|
584
|
+
name: "open-in-editor",
|
|
585
|
+
type: "action",
|
|
586
|
+
jsonSerializable: true,
|
|
587
|
+
handler: (query) => {
|
|
588
|
+
const { project, ...location } = v.parse(OpenQuerySchema, query);
|
|
589
|
+
return open({
|
|
590
|
+
project: pickProject(projects, project),
|
|
591
|
+
...location
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}));
|
|
595
|
+
}
|
|
596
|
+
//#endregion
|
|
597
|
+
//#region src/node/index.ts
|
|
598
|
+
/** The x18n UI, RPC functions and MCP tools over loaded projects, as a devframe definition. */
|
|
599
|
+
function createX18nDevframe(projects, options = {}) {
|
|
600
|
+
return defineDevframe({
|
|
601
|
+
id: "x18n",
|
|
602
|
+
name: "x18n",
|
|
603
|
+
version,
|
|
604
|
+
packageName: name,
|
|
605
|
+
homepage,
|
|
606
|
+
description,
|
|
607
|
+
icon: "ph:translate-duotone",
|
|
608
|
+
importMetaUrl: import.meta.url,
|
|
609
|
+
clientAssets: fileURLToPath(new URL("./public", import.meta.url)),
|
|
610
|
+
async setup(ctx) {
|
|
611
|
+
registerRpc(ctx, projects, options);
|
|
612
|
+
if (ctx.mode !== "dev") return;
|
|
613
|
+
registerAgentTools(ctx, projects);
|
|
614
|
+
const state = await ctx.scope("x18n").rpc.sharedState("state", { initialValue: {
|
|
615
|
+
revision: 0,
|
|
616
|
+
changedKeys: []
|
|
617
|
+
} });
|
|
618
|
+
for (const p of projects) p.project.onChange((change) => {
|
|
619
|
+
state.mutate((draft) => {
|
|
620
|
+
draft.revision += 1;
|
|
621
|
+
draft.changedKeys = [...change.keys];
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
//#endregion
|
|
628
|
+
export { createX18nDevframe };
|
package/dist/nitro.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>x18n</title><script type="importmap">{"imports":{"#entry":"/_nuxt/DCQwHjae.js"}}</script><script>{const p=new URLSearchParams(location.hash.slice(1)),c=p.get('devframe_otp');if(c){sessionStorage.setItem('x18n:otp',c);history.replaceState(null,'',location.pathname+location.search+'#'+(p.get('route')||'/'))}}</script><link rel="stylesheet" href="/_nuxt/entry.puki6KUo.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DCQwHjae.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/2T7o9vZw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/6U3VBVNw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/qB8tKtt1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B3c8VNtz.js"><script type="module" src="/_nuxt/DCQwHjae.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/B2lY2QM5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BJfOvlY_.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/D6gh7el6.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/xg14vwJh.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.DRhgjSut.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CKRUbA4H.js"></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"45c30525-030d-44d4-bb10-65a4ca3668c9",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792470018315,false]</script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>x18n</title><script type="importmap">{"imports":{"#entry":"/_nuxt/DCQwHjae.js"}}</script><script>{const p=new URLSearchParams(location.hash.slice(1)),c=p.get('devframe_otp');if(c){sessionStorage.setItem('x18n:otp',c);history.replaceState(null,'',location.pathname+location.search+'#'+(p.get('route')||'/'))}}</script><link rel="stylesheet" href="/_nuxt/entry.puki6KUo.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DCQwHjae.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/2T7o9vZw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/6U3VBVNw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/qB8tKtt1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B3c8VNtz.js"><script type="module" src="/_nuxt/DCQwHjae.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/B2lY2QM5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BJfOvlY_.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/D6gh7el6.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/xg14vwJh.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.DRhgjSut.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CKRUbA4H.js"></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"45c30525-030d-44d4-bb10-65a4ca3668c9",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792470018316,false]</script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{H as e,J as t,K as n,V as r,v as i,x as a}from"./6U3VBVNw.js";function o(e,...t){return typeof e==`function`?e(...t):e}var s=Error.captureStackTrace,c=class e extends Error{name;code;docs;fix;sources;data;get why(){return this.message}constructor(t,n=e){super(t.why,{cause:t.cause}),this.code=this.name=t.code,this.fix=t.fix,this.docs=t.docs,this.sources=t.sources,this.data=t.data,s?.(this,n)}toJSON(){return{name:this.name,why:this.why,fix:this.fix,docs:this.docs,sources:this.sources,cause:this.cause,data:this.data,stack:this.stack}}};function l(e,t){return typeof e==`string`?`${e}/${t.toLowerCase()}`:e?.(t)}function u(e){let t=e.reporters??[],n={},{docsBase:r}=e;for(let i of Object.keys(e.codes)){let a=e.codes[i],s=a.docs===!1?void 0:a.docs||l(r,i),u=(e={},n={})=>{let r=new c({code:i,why:o(a.why,e),fix:o(a.fix,e),docs:s,cause:e.cause,sources:e.sources,data:o(a.data,e)},u);for(let e of t)e(r,n);return r};n[i]=u}return n}function d(e={}){let{docsBase:t,reporters:n=[]}=e;return new Proxy({},{get(e,r){if(typeof r!=`string`)return;let i=(e={},a={})=>{let o=l(t,r),s=new c({code:r,why:o??``,docs:o,cause:e.cause,sources:e.sources},i);for(let e of n)e(s,a);return s};return i}})}function f(e){return`https://nuxt.com/docs/4.x/errors/${e.replace(`NUXT_`,``).toLowerCase()}`}var p=[e=>{console.error(`[${e.name}]`)}],m=d({docsBase:f,reporters:p}),h=globalThis.__nuxt_app_ctx__||={};function g(e){return h[e]||=(()=>{let e;return{use:()=>{if(e===void 0)throw Error(`Context is not available`);return e},tryUse:()=>e??null,set:t=>{e=t},unset:()=>{e=void 0},call:(t,n)=>(e=t,n()),callAsync:(t,n)=>(e=t,Promise.resolve(n()))}})()}function _(e,t){return g(e)}function v(e,t={},n){for(let r in e){let i=e[r],a=n?`${n}:${r}`:r;typeof i==`object`&&i?v(i,t,a):typeof i==`function`&&(t[a]=i)}return t}var y=(()=>{if(console.createTask)return console.createTask;let e={run:e=>e()};return()=>e})();function b(e,t,n,r){for(let i=n;i<e.length;i+=1)try{let n=r?r.run(()=>e[i](...t)):e[i](...t);if(n&&typeof n.then==`function`)return Promise.resolve(n).then(()=>b(e,t,i+1,r))}catch(e){return Promise.reject(e)}}function x(e,t,n){if(e.length>0)return b(e,t,0,y(n))}function S(e,t,n){if(e.length>0){let r=y(n);return Promise.all(e.map(e=>r.run(()=>e(...t))))}}function C(e,t){for(let n of[...e])n(t)}var w=class{_hooks;_before;_after;_deprecatedHooks;_deprecatedMessages;constructor(){this._hooks={},this._before=void 0,this._after=void 0,this._deprecatedMessages=void 0,this._deprecatedHooks={},this.hook=this.hook.bind(this),this.callHook=this.callHook.bind(this),this.callHookWith=this.callHookWith.bind(this)}hook(e,t,n={}){if(!e||typeof t!=`function`)return()=>{};let r=e,i;for(;this._deprecatedHooks[e];)i=this._deprecatedHooks[e],e=i.to;if(i&&!n.allowDeprecated){let e=i.message;e||=`${r} hook has been deprecated`+(i.to?`, please use ${i.to}`:``),this._deprecatedMessages||=new Set,this._deprecatedMessages.has(e)||(console.warn(e),this._deprecatedMessages.add(e))}if(!t.name)try{Object.defineProperty(t,"name",{get:()=>`_`+e.replace(/\W+/g,`_`)+`_hook_cb`,configurable:!0})}catch{}return this._hooks[e]=this._hooks[e]||[],this._hooks[e].push(t),()=>{t&&=(this.removeHook(e,t),void 0)}}hookOnce(e,t){let n,r=(...e)=>(typeof n==`function`&&n(),n=void 0,r=void 0,t(...e));return n=this.hook(e,r),n}removeHook(e,t){let n=this._hooks[e];if(n){let r=n.indexOf(t);r!==-1&&n.splice(r,1),n.length===0&&(this._hooks[e]=void 0)}}clearHook(e){this._hooks[e]=void 0}deprecateHook(e,t){this._deprecatedHooks[e]=typeof t==`string`?{to:t}:t;let n=this._hooks[e]||[];this._hooks[e]=void 0;for(let t of n)this.hook(e,t)}deprecateHooks(e){for(let t in e)this.deprecateHook(t,e[t])}addHooks(e){let t=v(e),n=Object.keys(t).map(e=>this.hook(e,t[e]));return()=>{for(let e of n)e();n.length=0}}removeHooks(e){let t=v(e);for(let e in t)this.removeHook(e,t[e])}removeAllHooks(){this._hooks={}}callHook(e,...t){return this.callHookWith(x,e,t)}callHookParallel(e,...t){return this.callHookWith(S,e,t)}callHookWith(e,t,n){let r=this._before||this._after?{name:t,args:n,context:{}}:void 0;this._before&&C(this._before,r);let i=e(this._hooks[t]?[...this._hooks[t]]:[],n,t);return i instanceof Promise?i.finally(()=>{this._after&&r&&C(this._after,r)}):(this._after&&r&&C(this._after,r),i)}beforeEach(e){return this._before=this._before||[],this._before.push(e),()=>{if(this._before!==void 0){let t=this._before.indexOf(e);t!==-1&&this._before.splice(t,1)}}}afterEach(e){return this._after=this._after||[],this._after.push(e),()=>{if(this._after!==void 0){let t=this._after.indexOf(e);t!==-1&&this._after.splice(t,1)}}}};function T(){return new w}var E=class{_hooks;constructor(){this._hooks={}}hook(e,t){return!e||typeof t!=`function`?()=>{}:(this._hooks[e]=this._hooks[e]||[],this._hooks[e].push(t),()=>{t&&=(this.removeHook(e,t),void 0)})}removeHook(e,t){let n=this._hooks[e];if(n){let r=n.indexOf(t);r!==-1&&n.splice(r,1),n.length===0&&(this._hooks[e]=void 0)}}callHook(e,...t){let n=this._hooks[e];if(n&&n.length!==0)return b(n.slice(),t,0)}},D={meta:[{name:`viewport`,content:`width=device-width,initial-scale=1`},{charset:`utf-8`}],link:[],style:[],script:[{innerHTML:`{const p=new URLSearchParams(location.hash.slice(1)),c=p.get('devframe_otp');if(c){sessionStorage.setItem('x18n:otp',c);history.replaceState(null,'',location.pathname+location.search+'#'+(p.get('route')||'/'))}}`}],noscript:[],title:`x18n`,viewport:`width=device-width,initial-scale=1`},O={id:`__nuxt-loader`},k={componentName:`NuxtLink`,prefetch:!0,prefetchOn:{visibility:!0}},A=`#__nuxt`,j=`nuxt-app`,M=36e5,N=`vite:preloadError`;function P(e=`nuxt-app`){return _(e,{asyncContext:!1})}var F=`__nuxt_plugin`;function I(i){let a=0,o={_id:i.id||`nuxt-app`,_scope:r(),provide:void 0,versions:{get nuxt(){return`4.6.1`},get vue(){return o.vueApp.version}},payload:t({...i.ssrContext?.payload||{},data:t({}),state:n({}),once:new Set,_errors:t({})}),static:{data:{}},runWithContext(t){return o._scope.active&&!e()?o._scope.run(()=>B(o,t)):B(o,t)},isHydrating:!0,deferHydration(){if(!o.isHydrating)return()=>{};a++;let e=!1;return()=>{if(!e&&(e=!0,a--,a===0))return o.isHydrating=!1,o.callHook(`app:suspense:resolve`)}},_asyncDataPromises:{},_asyncData:t({}),_state:t({}),_payloadRevivers:{},...i};{let e=window.__NUXT__;if(e)for(let t in e)switch(t){case`data`:case`state`:case`_errors`:Object.assign(o.payload[t],e[t]);break;default:o.payload[t]=e[t]}}o.hooks=T(),o.hook=o.hooks.hook;{let e=o.hooks.callHook;o.hooks.callHook=(t,...n)=>Promise.resolve().then(()=>e(t,...n))}o.callHook=o.hooks.callHook,o.provide=(e,t)=>{let n=`$`+e;W(o,n,t),W(o.vueApp.config.globalProperties,n,t)},W(o.vueApp,`$nuxt`,o),W(o.vueApp.config.globalProperties,`$nuxt`,o);{window.addEventListener(N,e=>{o.callHook(`app:chunkError`,{error:e.payload}),e.payload?.message?.includes(`Unable to preload CSS`)&&e.preventDefault()}),window.useNuxtApp||=H;let e=o.hook(`app:error`,(...e)=>{m.NUXT_E1005({cause:e.length>1?e:e[0]})});o.hook(`app:mounted`,e)}let s=o.payload.config;return o.provide(`config`,s),o}async function L(e,t){if(typeof t==`function`){let{provide:n}=await e.runWithContext(()=>t(e))||{};if(n&&typeof n==`object`)for(let t in n)e.provide(t,n[t])}}async function R(e,t){let n;for(let r of t)try{await L(e,r)}catch(t){if(!e.payload.error)throw t;n||=t}if(n)throw e.payload.error||n}function z(e){if(typeof e==`function`)return e;let t=e._name||e.name;return delete e.name,Object.assign(e.setup||(()=>{}),e,{[F]:!0,_name:t})}function B(e,t,n){return P(e._id).set(e),e.vueApp.runWithContext(()=>n?t(...n):t())}function V(e){let t;return a()&&(t=i()?.appContext.app.$nuxt),t||=P(e).tryUse(),t||null}function H(e){let t=V(e);if(!t)throw m.NUXT_E1001();return t}function U(e){return H().$config}function W(e,t,n){Object.defineProperty(e,t,{get:()=>n})}export{u as _,H as a,j as c,M as d,A as f,p as g,f as h,V as i,O as l,m,I as n,U as o,E as p,z as r,D as s,R as t,k as u,d as v};
|