@fluenti/cli 0.6.2 → 0.6.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/cli.js CHANGED
@@ -1,39 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as e, n as t, r as n, t as r } from "./compile-CZVpE5Md.js";
3
- import { t as i } from "./tsx-extractor-C-HZNobu.js";
4
- import { a, c as o, d as s, f as c, l, n as u, o as d, p as f, r as p, s as m, t as h, u as g } from "./doctor-BqXXxyST.js";
5
- import { parse as _, resolveLocaleCodes as v } from "@fluenti/core/compiler";
6
- import { existsSync as y, mkdirSync as b, readFileSync as x, statSync as S, writeFileSync as C } from "node:fs";
7
- import { dirname as w, extname as T, join as E, resolve as D } from "node:path";
8
- import { fileURLToPath as O } from "node:url";
9
- import k from "fast-glob";
10
- import { createHash as A } from "node:crypto";
11
- import j from "consola";
12
- import { defineCommand as M, runMain as ee } from "citty";
13
- import { execFile as N } from "node:child_process";
14
- import { promisify as P } from "node:util";
15
- import { setTimeout as F } from "node:timers/promises";
3
+ import { a as i, c as a, d as o, f as s, l as c, n as l, o as u, r as d, s as f, t as p, u as m } from "./doctor-CLfvuKpJ.js";
4
+ import { parse as h, resolveLocaleCodes as g } from "@fluenti/core/compiler";
5
+ import { existsSync as _, mkdirSync as v, readFileSync as y, statSync as b, writeFileSync as x } from "node:fs";
6
+ import { dirname as S, join as C, resolve as w } from "node:path";
7
+ import { fileURLToPath as T } from "node:url";
8
+ import E from "fast-glob";
9
+ import { createHash as D } from "node:crypto";
10
+ import O from "consola";
11
+ import { defineCommand as k, runMain as A } from "citty";
12
+ import { execFile as j } from "node:child_process";
13
+ import { promisify as M } from "node:util";
14
+ import { setTimeout as N } from "node:timers/promises";
16
15
  //#region src/stats-format.ts
17
- var te = "█", ne = "░";
18
- function re(e, t = 20) {
16
+ var ee = "█", te = "░";
17
+ function ne(e, t = 20) {
19
18
  let n = Math.round(Math.max(0, Math.min(100, e)) / 100 * t);
20
- return te.repeat(n) + ne.repeat(t - n);
19
+ return ee.repeat(n) + te.repeat(t - n);
21
20
  }
22
- function ie(e) {
21
+ function re(e) {
23
22
  let t = e.toFixed(1) + "%";
24
23
  return e >= 90 ? `\x1b[32m${t}\x1b[0m` : e >= 70 ? `\x1b[33m${t}\x1b[0m` : `\x1b[31m${t}\x1b[0m`;
25
24
  }
26
- function ae(e, t, n) {
27
- let r = t > 0 ? n / t * 100 : 0, i = t > 0 ? ie(r) : "—", a = t > 0 ? re(r) : "";
25
+ function P(e, t, n) {
26
+ let r = t > 0 ? n / t * 100 : 0, i = t > 0 ? re(r) : "—", a = t > 0 ? ne(r) : "";
28
27
  return ` ${e.padEnd(8)}│ ${String(t).padStart(5)} │ ${String(n).padStart(10)} │ ${a} ${i}`;
29
28
  }
30
29
  //#endregion
31
30
  //#region src/validation.ts
32
- var I = /\{(\w+),\s*(plural|select|selectordinal)\s*,/;
33
- function L(e) {
31
+ var F = /\{(\w+),\s*(plural|select|selectordinal)\s*,/;
32
+ function I(e) {
34
33
  try {
35
- let t = _(e), n = /* @__PURE__ */ new Set();
36
- return R(t, n), [...n].sort();
34
+ let t = h(e), n = /* @__PURE__ */ new Set();
35
+ return L(t, n), [...n].sort();
37
36
  } catch {
38
37
  let t = /* @__PURE__ */ new Set(), n = 0, r = 0;
39
38
  for (; r < e.length;) {
@@ -51,22 +50,22 @@ function L(e) {
51
50
  return [...t].sort();
52
51
  }
53
52
  }
54
- function R(e, t) {
53
+ function L(e, t) {
55
54
  for (let n of e) if (n.type === "variable" && n.name !== "#") t.add(n.name);
56
55
  else if (n.type === "plural" || n.type === "select") {
57
56
  t.add(n.variable);
58
- for (let e of Object.values(n.options)) R(e, t);
57
+ for (let e of Object.values(n.options)) L(e, t);
59
58
  } else n.type === "function" && t.add(n.variable);
60
59
  }
61
- function z(e) {
60
+ function R(e) {
62
61
  let t = /* @__PURE__ */ new Set(), n = /<\/?([a-zA-Z][\w-]*)[^>]*>/g, r;
63
62
  for (; (r = n.exec(e)) !== null;) t.add(r[1].toLowerCase());
64
63
  return [...t].sort();
65
64
  }
66
- function oe(e, t) {
67
- let n = L(e), r = L(t), i = z(e), a = z(t), o = n.filter((e) => !r.includes(e)), s = r.filter((e) => !n.includes(e)), c = i.filter((e) => !a.includes(e)), l = a.filter((e) => !i.includes(e)), u = [];
68
- if (I.test(t)) try {
69
- _(t);
65
+ function ie(e, t) {
66
+ let n = I(e), r = I(t), i = R(e), a = R(t), o = n.filter((e) => !r.includes(e)), s = r.filter((e) => !n.includes(e)), c = i.filter((e) => !a.includes(e)), l = a.filter((e) => !i.includes(e)), u = [];
67
+ if (F.test(t)) try {
68
+ h(t);
70
69
  } catch (e) {
71
70
  u.push(e.message);
72
71
  }
@@ -81,7 +80,7 @@ function oe(e, t) {
81
80
  }
82
81
  //#endregion
83
82
  //#region src/lint.ts
84
- function B(e, t) {
83
+ function z(e, t) {
85
84
  let n = [], { sourceLocale: r } = t, i = t.locales ?? Object.keys(e), a = e[r];
86
85
  if (!a) return n.push({
87
86
  rule: "missing-source",
@@ -113,7 +112,7 @@ function B(e, t) {
113
112
  });
114
113
  continue;
115
114
  }
116
- let s = L(r.message ?? e), c = L(o.translation), l = s.filter((e) => !c.includes(e)), u = c.filter((e) => !s.includes(e));
115
+ let s = I(r.message ?? e), c = I(o.translation), l = s.filter((e) => !c.includes(e)), u = c.filter((e) => !s.includes(e));
117
116
  l.length > 0 && n.push({
118
117
  rule: "inconsistent-placeholders",
119
118
  severity: "error",
@@ -156,9 +155,9 @@ function B(e, t) {
156
155
  });
157
156
  return n;
158
157
  }
159
- function se(e) {
158
+ function ae(e) {
160
159
  if (e.length === 0) return " ✓ All checks passed";
161
- let t = [], n = ce(e, (e) => e.rule);
160
+ let t = [], n = oe(e, (e) => e.rule);
162
161
  for (let [e, r] of Object.entries(n)) {
163
162
  t.push(` ${e} (${r.length}):`);
164
163
  for (let e of r) {
@@ -169,7 +168,7 @@ function se(e) {
169
168
  let r = e.filter((e) => e.severity === "error").length, i = e.filter((e) => e.severity === "warning").length, a = e.filter((e) => e.severity === "info").length;
170
169
  return t.push(""), t.push(` Summary: ${r} errors, ${i} warnings, ${a} info`), t.join("\n");
171
170
  }
172
- function ce(e, t) {
171
+ function oe(e, t) {
173
172
  let n = {};
174
173
  for (let r of e) {
175
174
  let e = t(r);
@@ -179,7 +178,7 @@ function ce(e, t) {
179
178
  }
180
179
  //#endregion
181
180
  //#region src/check.ts
182
- function le(e, t) {
181
+ function se(e, t) {
183
182
  let { sourceLocale: n, minCoverage: r, locale: i } = t, a = e[n];
184
183
  if (!a) return {
185
184
  results: [],
@@ -227,10 +226,10 @@ function le(e, t) {
227
226
  passed: p,
228
227
  minCoverage: r,
229
228
  actualCoverage: f,
230
- diagnostics: B(e, m)
229
+ diagnostics: z(e, m)
231
230
  };
232
231
  }
233
- function ue(e) {
232
+ function ce(e) {
234
233
  let t = [];
235
234
  for (let n of e.results) {
236
235
  let r = n.coverage >= e.minCoverage ? "✓" : "✗", i = n.coverage.toFixed(1), a = n.missing > 0 ? ` — ${n.missing} missing` : "", o = n.fuzzy > 0 ? `, ${n.fuzzy} fuzzy` : "";
@@ -240,7 +239,7 @@ function ue(e) {
240
239
  let n = e.actualCoverage.toFixed(1), r = e.passed ? "PASSED" : "FAILED";
241
240
  return t.push(`Coverage: ${n}% (min: ${e.minCoverage}%) — ${r}`), t.join("\n");
242
241
  }
243
- function de(e, t, n) {
242
+ function le(e, t, n) {
244
243
  let r = [], i = n === "json" ? ".json" : ".po";
245
244
  for (let n of e.results) if (n.coverage < e.minCoverage) {
246
245
  let a = `${t}/${n.locale}${i}`;
@@ -253,7 +252,7 @@ function de(e, t, n) {
253
252
  }
254
253
  return r.join("\n");
255
254
  }
256
- function fe(e) {
255
+ function B(e) {
257
256
  return JSON.stringify({
258
257
  results: e.results,
259
258
  passed: e.passed,
@@ -263,31 +262,31 @@ function fe(e) {
263
262
  }
264
263
  //#endregion
265
264
  //#region src/compile-cache.ts
266
- var V = "1", pe = class {
265
+ var V = "1", H = class {
267
266
  data;
268
267
  cachePath;
269
268
  dirty = !1;
270
269
  constructor(e, t) {
271
- this.cachePath = D(t ? D(e, ".cache", t) : D(e, ".cache"), "compile-cache.json"), this.data = this.load();
270
+ this.cachePath = w(t ? w(e, ".cache", t) : w(e, ".cache"), "compile-cache.json"), this.data = this.load();
272
271
  }
273
272
  isUpToDate(e, t) {
274
273
  let n = this.data.entries[e];
275
274
  if (!n) return !1;
276
- let r = H(t);
275
+ let r = U(t);
277
276
  return n.inputHash === r;
278
277
  }
279
278
  set(e, t) {
280
- this.data.entries[e] = { inputHash: H(t) }, this.dirty = !0;
279
+ this.data.entries[e] = { inputHash: U(t) }, this.dirty = !0;
281
280
  }
282
281
  save() {
283
282
  if (this.dirty) try {
284
- b(w(this.cachePath), { recursive: !0 }), C(this.cachePath, JSON.stringify(this.data), "utf-8"), this.dirty = !1;
283
+ v(S(this.cachePath), { recursive: !0 }), x(this.cachePath, JSON.stringify(this.data), "utf-8"), this.dirty = !1;
285
284
  } catch {}
286
285
  }
287
286
  load() {
288
287
  try {
289
- if (y(this.cachePath)) {
290
- let e = x(this.cachePath, "utf-8"), t = JSON.parse(e);
288
+ if (_(this.cachePath)) {
289
+ let e = y(this.cachePath, "utf-8"), t = JSON.parse(e);
291
290
  if (t.version === V) return t;
292
291
  }
293
292
  } catch {}
@@ -297,29 +296,29 @@ var V = "1", pe = class {
297
296
  };
298
297
  }
299
298
  };
300
- function H(e) {
301
- return A("md5").update(e).digest("hex");
299
+ function U(e) {
300
+ return D("md5").update(e).digest("hex");
302
301
  }
303
302
  //#endregion
304
303
  //#region src/ai-provider.ts
305
- var me = P(N), he = {
304
+ var W = M(j), ue = {
306
305
  claude: "npm install -g @anthropic-ai/claude-code",
307
306
  codex: "npm install -g @openai/codex"
308
307
  };
309
- function ge(e, t) {
308
+ function de(e, t) {
310
309
  return e === "claude" ? ["-p", t] : [
311
310
  "-p",
312
311
  t,
313
312
  "--full-auto"
314
313
  ];
315
314
  }
316
- function _e(e) {
315
+ function fe(e) {
317
316
  return e.code === "ENOENT";
318
317
  }
319
- async function ve(e) {
320
- let { provider: t, prompt: n, maxRetries: r = 3, initialDelayMs: i = 1e3, maxBuffer: a = 10 * 1024 * 1024, timeoutMs: o = 12e4 } = e, s = ge(t, n), c = t === "claude" ? "claude" : "codex", l;
318
+ async function pe(e) {
319
+ let { provider: t, prompt: n, maxRetries: r = 3, initialDelayMs: i = 1e3, maxBuffer: a = 10 * 1024 * 1024, timeoutMs: o = 12e4 } = e, s = de(t, n), c = t === "claude" ? "claude" : "codex", l;
321
320
  for (let e = 0; e <= r; e++) try {
322
- let t = me(c, [...s], { maxBuffer: a }), { stdout: n } = await Promise.race([t, F(o).then(() => {
321
+ let t = W(c, [...s], { maxBuffer: a }), { stdout: n } = await Promise.race([t, N(o).then(() => {
323
322
  throw Error(`AI provider timed out after ${o}ms`);
324
323
  })]);
325
324
  return {
@@ -327,22 +326,22 @@ async function ve(e) {
327
326
  attempts: e + 1
328
327
  };
329
328
  } catch (n) {
330
- if (_e(n)) throw Error(`"${t}" CLI not found. Please install it first:\n ${he[t]}`);
329
+ if (fe(n)) throw Error(`"${t}" CLI not found. Please install it first:\n ${ue[t]}`);
331
330
  if (n instanceof Error && n.message.includes("timed out")) throw n;
332
- l = n, e < r && await F(i * 2 ** e);
331
+ l = n, e < r && await N(i * 2 ** e);
333
332
  }
334
333
  throw l;
335
334
  }
336
335
  //#endregion
337
336
  //#region src/glossary.ts
338
- var U = 1048576;
339
- function ye(e) {
340
- if (!y(e)) return {};
341
- let t = S(e).size;
342
- if (t > U) throw Error(`Glossary file exceeds maximum size of ${U} bytes (got ${t} bytes)`);
337
+ var G = 1048576;
338
+ function me(e) {
339
+ if (!_(e)) return {};
340
+ let t = b(e).size;
341
+ if (t > G) throw Error(`Glossary file exceeds maximum size of ${G} bytes (got ${t} bytes)`);
343
342
  let n;
344
343
  try {
345
- let t = x(e, "utf-8");
344
+ let t = y(e, "utf-8");
346
345
  n = JSON.parse(t);
347
346
  } catch (e) {
348
347
  let t = e instanceof Error ? e.message : String(e);
@@ -355,21 +354,21 @@ function ye(e) {
355
354
  }
356
355
  return n;
357
356
  }
358
- function be(e, t) {
357
+ function he(e, t) {
359
358
  let n = {};
360
359
  for (let [r, i] of Object.entries(e)) t in i && (n[r] = i[t]);
361
360
  return n;
362
361
  }
363
- function W(e) {
362
+ function K(e) {
364
363
  return e.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/[\n\r]/g, " ").replace(/\t/g, " ");
365
364
  }
366
- function xe(e) {
365
+ function q(e) {
367
366
  let t = Object.entries(e);
368
- return t.length === 0 ? "" : `=== GLOSSARY (use these exact translations) ===\n${[...t].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => `"${W(e)}" → "${W(t)}"`).join("\n")}`;
367
+ return t.length === 0 ? "" : `=== GLOSSARY (use these exact translations) ===\n${[...t].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => `"${K(e)}" → "${K(t)}"`).join("\n")}`;
369
368
  }
370
369
  //#endregion
371
370
  //#region src/translate-prompt.ts
372
- function Se(e) {
371
+ function ge(e) {
373
372
  let { sourceLocale: t, targetLocale: n, messages: r, glossary: i, context: a } = e, o = JSON.stringify(r, null, 2), s = [
374
373
  `You are a professional translator. Translate the following messages from "${t}" to "${n}".`,
375
374
  "",
@@ -381,14 +380,14 @@ function Se(e) {
381
380
  "5. Do not add any explanation, markdown formatting, or code fences — output raw JSON only."
382
381
  ];
383
382
  if (i && Object.keys(i).length > 0) {
384
- let e = xe(i);
383
+ let e = q(i);
385
384
  e && s.push("", e);
386
385
  }
387
386
  return a && s.push("", "=== PROJECT CONTEXT ===", a), s.push("", "Input (JSON):", o), s.join("\n");
388
387
  }
389
388
  //#endregion
390
389
  //#region src/translate-parse.ts
391
- function Ce(e) {
390
+ function _e(e) {
392
391
  let t = e.indexOf("{");
393
392
  if (t === -1) throw Error("No JSON object found in AI response");
394
393
  let n = 0, r = !1, i = !1;
@@ -410,12 +409,12 @@ function Ce(e) {
410
409
  }
411
410
  throw Error("Unterminated JSON object in AI response");
412
411
  }
413
- function we(e) {
412
+ function ve(e) {
414
413
  let t = e.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
415
414
  return t ? t[1] : e;
416
415
  }
417
- function Te(e, t) {
418
- let n = [], r = Ce(we(e)), i;
416
+ function ye(e, t) {
417
+ let n = [], r = _e(ve(e)), i;
419
418
  try {
420
419
  i = JSON.parse(r);
421
420
  } catch {
@@ -433,7 +432,7 @@ function Te(e, t) {
433
432
  continue;
434
433
  }
435
434
  o[e] = r;
436
- let i = t[e], a = oe(i, r);
435
+ let i = t[e], a = ie(i, r);
437
436
  if (!a.valid) {
438
437
  let t = [];
439
438
  a.missingPlaceholders.length > 0 && t.push(`missing placeholders: ${a.missingPlaceholders.join(", ")}`), a.extraPlaceholders.length > 0 && t.push(`extra placeholders: ${a.extraPlaceholders.join(", ")}`), a.missingHtmlTags.length > 0 && t.push(`missing HTML tags: ${a.missingHtmlTags.join(", ")}`), a.extraHtmlTags.length > 0 && t.push(`extra HTML tags: ${a.extraHtmlTags.join(", ")}`), a.syntaxErrors.length > 0 && t.push(`ICU syntax errors: ${a.syntaxErrors.join("; ")}`), n.push(`QA issue for "${e}": ${t.join("; ")}`);
@@ -447,12 +446,12 @@ function Te(e, t) {
447
446
  }
448
447
  //#endregion
449
448
  //#region src/translate.ts
450
- function Ee(e) {
449
+ function be(e) {
451
450
  let t = {};
452
451
  for (let [n, r] of Object.entries(e)) r.obsolete || (!r.translation || r.translation.length === 0) && (t[n] = r.message ?? n);
453
452
  return t;
454
453
  }
455
- function G(e, t) {
454
+ function xe(e, t) {
456
455
  let n = Object.keys(e), r = [];
457
456
  for (let i = 0; i < n.length; i += t) {
458
457
  let a = {};
@@ -461,22 +460,22 @@ function G(e, t) {
461
460
  }
462
461
  return r;
463
462
  }
464
- async function De(e) {
465
- let { provider: t, sourceLocale: n, targetLocale: r, catalog: i, batchSize: a, context: o, glossary: s, timeoutMs: c } = e, l = Ee(i), u = Object.keys(l).length;
463
+ async function Se(e) {
464
+ let { provider: t, sourceLocale: n, targetLocale: r, catalog: i, batchSize: a, context: o, glossary: s, timeoutMs: c } = e, l = be(i), u = Object.keys(l).length;
466
465
  if (u === 0) return {
467
466
  catalog: { ...i },
468
467
  translated: 0,
469
468
  warnings: []
470
469
  };
471
- j.info(` ${u} untranslated messages, translating with ${t}...`);
472
- let d = { ...i }, f = G(l, a), p = 0, m = [];
470
+ O.info(` ${u} untranslated messages, translating with ${t}...`);
471
+ let d = { ...i }, f = xe(l, a), p = 0, m = [];
473
472
  for (let e = 0; e < f.length; e++) {
474
473
  let i = f[e], a = Object.keys(i);
475
- f.length > 1 && j.info(` Batch ${e + 1}/${f.length} (${a.length} messages)`);
474
+ f.length > 1 && O.info(` Batch ${e + 1}/${f.length} (${a.length} messages)`);
476
475
  try {
477
- let { stdout: e } = await ve({
476
+ let { stdout: e } = await pe({
478
477
  provider: t,
479
- prompt: Se({
478
+ prompt: ge({
480
479
  sourceLocale: n,
481
480
  targetLocale: r,
482
481
  messages: i,
@@ -484,15 +483,15 @@ async function De(e) {
484
483
  context: o
485
484
  }),
486
485
  timeoutMs: c
487
- }), { translations: l, warnings: u } = Te(e, i);
488
- for (let e of u) m.push(`[${r}] ${e}`), j.warn(` ${e}`);
486
+ }), { translations: l, warnings: u } = ye(e, i);
487
+ for (let e of u) m.push(`[${r}] ${e}`), O.warn(` ${e}`);
489
488
  for (let e of a) e in l && (d[e] = {
490
489
  ...d[e],
491
490
  translation: l[e]
492
491
  }, p++);
493
492
  } catch (t) {
494
493
  let n = t instanceof Error ? t.message : String(t);
495
- m.push(`[${r}] Batch ${e + 1} failed: ${n}`), j.error(` Batch ${e + 1} failed: ${n}`);
494
+ m.push(`[${r}] Batch ${e + 1} failed: ${n}`), O.error(` Batch ${e + 1} failed: ${n}`);
496
495
  }
497
496
  }
498
497
  return {
@@ -503,7 +502,7 @@ async function De(e) {
503
502
  }
504
503
  //#endregion
505
504
  //#region src/migrate.ts
506
- var K = P(N), q = {
505
+ var J = M(j), Y = {
507
506
  "vue-i18n": {
508
507
  name: "vue-i18n",
509
508
  framework: "Vue",
@@ -643,37 +642,37 @@ var K = P(N), q = {
643
642
  ],
644
643
  migrationGuide: "react/llms-migration.txt"
645
644
  }
646
- }, J = Object.keys(q);
647
- function Oe(e) {
645
+ }, X = Object.keys(Y);
646
+ function Ce(e) {
648
647
  let t = e.toLowerCase().replace(/^@nuxtjs\//, "nuxt-").replace(/^@/, "");
649
- return J.find((e) => e === t);
648
+ return X.find((e) => e === t);
650
649
  }
651
- async function ke(e) {
650
+ async function we(e) {
652
651
  let t = {
653
652
  configFiles: [],
654
653
  localeFiles: [],
655
654
  sampleSources: [],
656
655
  packageJson: void 0
657
- }, n = D("package.json");
658
- y(n) && (t.packageJson = x(n, "utf-8"));
656
+ }, n = w("package.json");
657
+ _(n) && (t.packageJson = y(n, "utf-8"));
659
658
  for (let n of e.configPatterns) {
660
- let e = D(n);
661
- y(e) && t.configFiles.push({
659
+ let e = w(n);
660
+ _(e) && t.configFiles.push({
662
661
  path: n,
663
- content: x(e, "utf-8")
662
+ content: y(e, "utf-8")
664
663
  });
665
664
  }
666
- let r = await k(e.localePatterns, { absolute: !1 });
665
+ let r = await E(e.localePatterns, { absolute: !1 });
667
666
  for (let e of r.slice(0, 10)) {
668
- let n = x(D(e), "utf-8");
667
+ let n = y(w(e), "utf-8");
669
668
  t.localeFiles.push({
670
669
  path: e,
671
670
  content: n.length > 5e3 ? n.slice(0, 5e3) + "\n... (truncated)" : n
672
671
  });
673
672
  }
674
- let i = await k(e.sourcePatterns, { absolute: !1 });
673
+ let i = await E(e.sourcePatterns, { absolute: !1 });
675
674
  for (let e of i.slice(0, 5)) {
676
- let n = x(D(e), "utf-8");
675
+ let n = y(w(e), "utf-8");
677
676
  t.sampleSources.push({
678
677
  path: e,
679
678
  content: n.length > 3e3 ? n.slice(0, 3e3) + "\n... (truncated)" : n
@@ -681,16 +680,16 @@ async function ke(e) {
681
680
  }
682
681
  return t;
683
682
  }
684
- function Ae(e) {
685
- let t = typeof __dirname < "u" ? __dirname : w(O(import.meta.url)), n = [
686
- D("node_modules", "@fluenti", "cli", "..", "..", e),
687
- E(t, "..", "..", "..", e),
688
- E(t, "..", "..", e)
683
+ function Te(e) {
684
+ let t = typeof __dirname < "u" ? __dirname : S(T(import.meta.url)), n = [
685
+ w("node_modules", "@fluenti", "cli", "..", "..", e),
686
+ C(t, "..", "..", "..", e),
687
+ C(t, "..", "..", e)
689
688
  ];
690
- for (let e of n) if (y(e)) return x(e, "utf-8");
689
+ for (let e of n) if (_(e)) return y(e, "utf-8");
691
690
  return "";
692
691
  }
693
- function je(e, t, n) {
692
+ function Ee(e, t, n) {
694
693
  let r = [];
695
694
  if (r.push(`You are a migration tool converting a ${e.framework} project from "${e.name}" to Fluenti (@fluenti).`, "", "Tasks:", "1. Generate a `fluenti.config.ts` based on the existing i18n configuration", "2. Convert each locale/translation file to standard gettext PO format", "3. Generate unified diff patches for every source file that needs changes", "4. Generate install/uninstall commands", "", "=== TRANSLATION API RULES ===", "Fluenti provides a compile-time `t` tagged template that does NOT require useI18n():", "", " import { t } from '@fluenti/react' // or @fluenti/vue, @fluenti/solid", " const name = \"World\"", " t`Hello, ${name}!`", "", "Use `import { t }` for ALL translation calls. Only use `useI18n()` when you need:", "- `d()` / `n()` for date/number formatting", "- `setLocale()` for locale switching", "- `locale` for reading the current locale reactively", "", "=== SOURCE CODE REWRITING RULES ===", "Imports:", `- ${e.name}: remove all imports from "${e.name}" (and related packages)`, `- Add: import { t } from '@fluenti/${e.framework === "Vue" ? "vue" : e.framework === "Next.js" ? "react" : e.framework.toLowerCase()}'`, "- Only add useI18n import if d()/n()/setLocale is needed in that file", "", "Translation calls:", "- t('key') → t`Source text` (tagged template with the actual source text, not the key)", "- t('key', { name }) → t`Hello, ${name}` (interpolate directly in template)", "- $t('key') → t`Source text` (Vue template)", "- Remove useI18n()/useTranslation()/useTranslations() destructuring if only t was used", "", "Components:", "- <i18n-t keypath=\"key\"> → <Trans>Source text</Trans>", "- <Trans i18nKey=\"key\"> → <Trans>Source text</Trans>", "", "ICU syntax conversion:", "- {{variable}} (double braces) → {variable} (single braces)", "- _one/_other suffixes → ICU {count, plural, one {...} other {...}}", "- @:key references → inline the referenced text directly", "- Pipe-separated plurals → ICU plural", "", "=== PO FORMAT RULES ===", "Each PO file must have a standard header:", " msgid \"\"", " msgstr \"\"", " \"Content-Type: text/plain; charset=UTF-8\\n\"", " \"Content-Transfer-Encoding: 8bit\\n\"", " \"Language: {locale}\\n\"", "", "Message entries: msgid is the source text (English), msgstr is the translation.", "Flatten nested JSON keys: \"home.title\" → use the actual source text as msgid.", ""), n && r.push("=== MIGRATION GUIDE ===", n, ""), t.packageJson && r.push("=== package.json ===", t.packageJson, ""), t.configFiles.length > 0) {
696
695
  r.push("=== EXISTING CONFIG FILES ===");
@@ -706,14 +705,14 @@ function je(e, t, n) {
706
705
  }
707
706
  return r.push("", "=== OUTPUT FORMAT ===", "Output ONLY the following sections. No explanations, no commentary.", "", "### FLUENTI_CONFIG", "```ts", "// Complete fluenti.config.ts", "```", "", "### LOCALE_FILES", "#### LOCALE: {locale_code}", "```po", "// Complete PO file with standard header", "```", "(repeat for each locale)", "", "### SOURCE_PATCHES", "#### FILE: {relative_file_path}", "```diff", "--- a/{file_path}", "+++ b/{file_path}", "@@ ... @@", " context line", "-removed line", "+added line", "```", "(repeat for each file that needs changes)", "", "### INSTALL_COMMANDS", "```bash", "// install + uninstall commands", "```"), r.join("\n");
708
707
  }
709
- async function Me(e, t) {
708
+ async function De(e, t) {
710
709
  let n = 10 * 1024 * 1024;
711
710
  try {
712
711
  if (e === "claude") {
713
- let { stdout: e } = await K("claude", ["-p", t], { maxBuffer: n });
712
+ let { stdout: e } = await J("claude", ["-p", t], { maxBuffer: n });
714
713
  return e;
715
714
  } else {
716
- let { stdout: e } = await K("codex", [
715
+ let { stdout: e } = await J("codex", [
717
716
  "-p",
718
717
  t,
719
718
  "--full-auto"
@@ -725,7 +724,7 @@ async function Me(e, t) {
725
724
  throw n.code === "ENOENT" || n.code === "EPERM" || n.code === "EACCES" ? Error(`"${e}" CLI not found or not executable. Please install it first:\n` + (e === "claude" ? " npm install -g @anthropic-ai/claude-code" : " npm install -g @openai/codex")) : t;
726
725
  }
727
726
  }
728
- function Ne(e) {
727
+ function Oe(e) {
729
728
  let t = 5e5, n = e.length > t ? e.slice(0, t) : e, r = {
730
729
  config: void 0,
731
730
  localeFiles: [],
@@ -755,83 +754,74 @@ function Ne(e) {
755
754
  let c = n.match(/### INSTALL_COMMANDS[\s\S]*?```(?:bash|sh)?\n([\s\S]*?)```/);
756
755
  return c && (r.installCommands = c[1].trim()), r;
757
756
  }
758
- async function Pe(e) {
759
- let { from: t, provider: n, write: r } = e, i = Oe(t);
757
+ async function ke(e) {
758
+ let { from: t, provider: n, write: r } = e, i = Ce(t);
760
759
  if (!i) {
761
- j.error(`Unsupported library "${t}". Supported libraries:`);
762
- for (let e of J) j.log(` - ${e}`);
760
+ O.error(`Unsupported library "${t}". Supported libraries:`);
761
+ for (let e of X) O.log(` - ${e}`);
763
762
  return;
764
763
  }
765
- let a = q[i];
766
- j.info(`Migrating from ${a.name} (${a.framework}) to Fluenti`), j.info("Scanning project for existing i18n files...");
767
- let o = await ke(a);
764
+ let a = Y[i];
765
+ O.info(`Migrating from ${a.name} (${a.framework}) to Fluenti`), O.info("Scanning project for existing i18n files...");
766
+ let o = await we(a);
768
767
  if (o.configFiles.length === 0 && o.localeFiles.length === 0) {
769
- j.warn(`No ${a.name} configuration or locale files found.`), j.info("Make sure you are running this command from the project root directory.");
768
+ O.warn(`No ${a.name} configuration or locale files found.`), O.info("Make sure you are running this command from the project root directory.");
770
769
  return;
771
770
  }
772
- j.info(`Found: ${o.configFiles.length} config file(s), ${o.localeFiles.length} locale file(s), ${o.sampleSources.length} source file(s)`);
773
- let s = Ae(a.migrationGuide);
774
- j.info(`Generating migration plan with ${n}...`);
775
- let c = Ne(await Me(n, je(a, o, s)));
776
- if (c.installCommands && (j.log(""), j.box({
771
+ O.info(`Found: ${o.configFiles.length} config file(s), ${o.localeFiles.length} locale file(s), ${o.sampleSources.length} source file(s)`);
772
+ let s = Te(a.migrationGuide);
773
+ O.info(`Generating migration plan with ${n}...`);
774
+ let c = Oe(await De(n, Ee(a, o, s)));
775
+ if (c.installCommands && (O.log(""), O.box({
777
776
  title: "Install Commands",
778
777
  message: c.installCommands
779
778
  })), c.config) if (r) {
780
- let { writeFileSync: e } = await import("node:fs"), t = D("fluenti.config.ts");
781
- e(t, c.config, "utf-8"), j.success(`Written: ${t}`);
782
- } else j.log(""), j.box({
779
+ let { writeFileSync: e } = await import("node:fs"), t = w("fluenti.config.ts");
780
+ e(t, c.config, "utf-8"), O.success(`Written: ${t}`);
781
+ } else O.log(""), O.box({
783
782
  title: "fluenti.config.ts",
784
783
  message: c.config
785
784
  });
786
785
  if (c.localeFiles.length > 0) if (r) {
787
786
  let { writeFileSync: e, mkdirSync: t } = await import("node:fs"), n = "./locales";
788
- t(D(n), { recursive: !0 });
787
+ t(w(n), { recursive: !0 });
789
788
  for (let t of c.localeFiles) {
790
- let r = D(n, `${t.locale}.po`);
791
- e(r, t.content, "utf-8"), j.success(`Written: ${r}`);
789
+ let r = w(n, `${t.locale}.po`);
790
+ e(r, t.content, "utf-8"), O.success(`Written: ${r}`);
792
791
  }
793
- } else for (let e of c.localeFiles) j.log(""), j.box({
792
+ } else for (let e of c.localeFiles) O.log(""), O.box({
794
793
  title: `locales/${e.locale}.po`,
795
794
  message: e.content.length > 500 ? e.content.slice(0, 500) + "\n... (use --write to save full file)" : e.content
796
795
  });
797
796
  if (c.sourcePatches.length > 0) if (r) {
798
- j.log(""), j.info(`Generated ${c.sourcePatches.length} source patch(es). Apply with:`);
797
+ O.log(""), O.info(`Generated ${c.sourcePatches.length} source patch(es). Apply with:`);
799
798
  for (let e of c.sourcePatches) {
800
- let t = D(`.fluenti-migrate-${e.file.replace(/[/\\]/g, "-")}.patch`), { writeFileSync: n } = await import("node:fs");
801
- n(t, e.patch, "utf-8"), j.success(`Patch written: ${t}`), j.log(` patch -p1 < ${t}`);
799
+ let t = w(`.fluenti-migrate-${e.file.replace(/[/\\]/g, "-")}.patch`), { writeFileSync: n } = await import("node:fs");
800
+ n(t, e.patch, "utf-8"), O.success(`Patch written: ${t}`), O.log(` patch -p1 < ${t}`);
802
801
  }
803
- } else for (let e of c.sourcePatches) j.log(""), j.box({
802
+ } else for (let e of c.sourcePatches) O.log(""), O.box({
804
803
  title: `Patch: ${e.file}`,
805
804
  message: e.patch.length > 800 ? e.patch.slice(0, 800) + "\n... (use --write to save full patch)" : e.patch
806
805
  });
807
- c.steps && c.sourcePatches.length === 0 && (j.log(""), j.box({
806
+ c.steps && c.sourcePatches.length === 0 && (O.log(""), O.box({
808
807
  title: "Migration Steps",
809
808
  message: c.steps
810
- })), !r && (c.config || c.localeFiles.length > 0 || c.sourcePatches.length > 0) && (j.log(""), j.info("Run with --write to save generated files and patches to disk:"), j.log(` fluenti migrate --from ${t} --write`));
809
+ })), !r && (c.config || c.localeFiles.length > 0 || c.sourcePatches.length > 0) && (O.log(""), O.info("Run with --write to save generated files and patches to disk:"), O.log(` fluenti migrate --from ${t} --write`));
811
810
  }
812
811
  //#endregion
813
812
  //#region src/cli.ts
814
- function Y(e) {
815
- return A("md5").update(e).digest("hex").slice(0, 8);
816
- }
817
- function X(e, t) {
818
- if (!y(e)) return {};
819
- let n = x(e, "utf-8");
820
- return t === "json" ? s(n) : l(n);
813
+ function Ae(e) {
814
+ return D("md5").update(e).digest("hex").slice(0, 8);
821
815
  }
822
- function Z(e, t, n) {
823
- b(w(e), { recursive: !0 }), C(e, n === "json" ? c(t) : g(t), "utf-8");
816
+ function Z(e, t) {
817
+ if (!_(e)) return {};
818
+ let n = y(e, "utf-8");
819
+ return t === "json" ? o(n) : c(n);
824
820
  }
825
- async function Fe(e, t, n) {
826
- if (T(e) === ".vue") try {
827
- let { extractFromVue: r } = await import("./vue-extractor.js");
828
- return r(t, e, n);
829
- } catch {
830
- return j.warn(`Skipping ${e}: install @vue/compiler-sfc to extract from .vue files`), [];
831
- }
832
- return i(t, e, n);
821
+ function je(e, t, n) {
822
+ v(S(e), { recursive: !0 }), x(e, n === "json" ? s(t) : m(t), "utf-8");
833
823
  }
834
- var Ie = M({
824
+ var Me = k({
835
825
  meta: {
836
826
  name: "extract",
837
827
  description: "Extract messages from source files"
@@ -858,46 +848,27 @@ var Ie = M({
858
848
  }
859
849
  },
860
850
  async run({ args: e }) {
861
- let t = await o(e.config), n = v(t.locales);
862
- j.info(`Extracting messages from ${t.include.join(", ")}`);
863
- let r = await k(t.include, {
864
- ignore: t.exclude ?? [],
865
- absolute: !1
866
- }), i = [], a = e["no-cache"] ?? !1 ? null : new d(t.catalogDir, Y(process.cwd())), s = 0;
867
- for (let e of r) {
868
- if (a) {
869
- let t = a.get(e);
870
- if (t) {
871
- i.push(...t), s++;
872
- continue;
873
- }
874
- }
875
- let n = await Fe(e, x(e, "utf-8"), t.idGenerator);
876
- i.push(...n), a && a.set(e, n);
877
- }
878
- a && (a.prune(new Set(r)), a.save()), s > 0 ? j.info(`Found ${i.length} messages in ${r.length} files (${s} cached)`) : j.info(`Found ${i.length} messages in ${r.length} files`);
879
- let c = t.format === "json" ? ".json" : ".po", l = e.clean ?? !1, u = e["no-fuzzy"] ?? !1;
880
- for (let e of n) {
881
- let n = D(t.catalogDir, `${e}${c}`), { catalog: r, result: a } = f(X(n, t.format), i, { stripFuzzy: u });
882
- Z(n, l ? Object.fromEntries(Object.entries(r).filter(([, e]) => !e.obsolete)) : r, t.format);
883
- let o = l ? `${a.obsolete} removed` : `${a.obsolete} obsolete`;
884
- j.success(`${e}: ${a.added} added, ${a.unchanged} unchanged, ${o}`);
885
- }
886
- for (let e of t.plugins ?? []) await e.onAfterExtract?.({
887
- messages: new Map(i.map((e) => [e.id, e])),
888
- sourceLocale: t.sourceLocale,
889
- targetLocales: n.filter((e) => e !== t.sourceLocale),
890
- config: t
851
+ let t = await a(e.config);
852
+ O.info(`Extracting messages from ${t.include.join(", ")}`);
853
+ let n = await u(process.cwd(), t, {
854
+ clean: e.clean ?? !1,
855
+ stripFuzzy: e["no-fuzzy"] ?? !1,
856
+ useCache: !(e["no-cache"] ?? !1)
891
857
  });
858
+ n.cacheHits > 0 ? O.info(`Found ${n.messageCount} messages in ${n.fileCount} files (${n.cacheHits} cached)`) : O.info(`Found ${n.messageCount} messages in ${n.fileCount} files`);
859
+ for (let t of n.localeResults) {
860
+ let n = e.clean ? `${t.result.obsolete} removed` : `${t.result.obsolete} obsolete`;
861
+ O.success(`${t.locale}: ${t.result.added} added, ${t.result.unchanged} unchanged, ${n}`);
862
+ }
892
863
  }
893
864
  });
894
- function Le(e) {
865
+ function Ne(e) {
895
866
  let t = {};
896
867
  for (let [n, r] of Object.entries(e)) r.translation && r.translation.length > 0 ? t[n] = r.translation : r.message && (t[n] = r.message);
897
868
  return t;
898
869
  }
899
870
  async function Q(e, t, n) {
900
- let r = Le(e);
871
+ let r = Ne(e);
901
872
  for (let e of n) e.transformMessages && (r = await e.transformMessages(r, t));
902
873
  let i = {};
903
874
  for (let [t, n] of Object.entries(e)) {
@@ -919,7 +890,7 @@ function $(e, t, n, r) {
919
890
  config: r
920
891
  };
921
892
  }
922
- var Re = M({
893
+ var Pe = k({
923
894
  meta: {
924
895
  name: "compile",
925
896
  description: "Compile message catalogs to JS modules"
@@ -950,70 +921,70 @@ var Re = M({
950
921
  }
951
922
  },
952
923
  async run({ args: i }) {
953
- let a = await o(i.config), c = v(a.locales), u = a.format === "json" ? ".json" : ".po";
954
- b(a.compileOutDir, { recursive: !0 });
955
- let d = {}, f = {};
956
- for (let e of c) {
957
- let t = D(a.catalogDir, `${e}${u}`);
958
- if (y(t)) {
959
- let n = x(t, "utf-8");
960
- f[e] = n, d[e] = a.format === "json" ? s(n) : l(n);
961
- } else f[e] = "", d[e] = {};
924
+ let s = await a(i.config), l = g(s.locales), u = s.format === "json" ? ".json" : ".po";
925
+ v(s.compileOutDir, { recursive: !0 });
926
+ let d = {}, p = {};
927
+ for (let e of l) {
928
+ let t = w(s.catalogDir, `${e}${u}`);
929
+ if (_(t)) {
930
+ let n = y(t, "utf-8");
931
+ p[e] = n, d[e] = s.format === "json" ? o(n) : c(n);
932
+ } else p[e] = "", d[e] = {};
962
933
  }
963
- let p = r(d);
964
- j.info(`Compiling ${p.length} messages across ${c.length} locales`);
965
- let h = i["skip-fuzzy"] ?? !1, g = i["no-cache"] ?? !1 ? null : new pe(a.catalogDir, Y(process.cwd())), _ = i.parallel ?? !1, S = i.concurrency ? parseInt(i.concurrency, 10) : void 0;
966
- if (S !== void 0 && (isNaN(S) || S < 1)) {
967
- j.error("Invalid --concurrency. Must be a positive integer."), process.exitCode = 1;
934
+ let m = r(d);
935
+ O.info(`Compiling ${m.length} messages across ${l.length} locales`);
936
+ let h = i["skip-fuzzy"] ?? !1, b = i["no-cache"] ?? !1 ? null : new H(s.catalogDir, Ae(process.cwd())), S = i.parallel ?? !1, C = i.concurrency ? parseInt(i.concurrency, 10) : void 0;
937
+ if (C !== void 0 && (isNaN(C) || C < 1)) {
938
+ O.error("Invalid --concurrency. Must be a positive integer."), process.exitCode = 1;
968
939
  return;
969
940
  }
970
- let w = 0, T = !1, E = [];
971
- for (let e of c) {
972
- if (g && g.isUpToDate(e, f[e]) && y(D(a.compileOutDir, `${e}.js`))) {
973
- w++;
941
+ let T = 0, E = !1, D = [];
942
+ for (let e of l) {
943
+ if (b && b.isUpToDate(e, p[e]) && _(w(s.compileOutDir, `${e}.js`))) {
944
+ T++;
974
945
  continue;
975
946
  }
976
- E.push(e);
947
+ D.push(e);
977
948
  }
978
- if (E.length > 0 && (T = !0), _ && E.length > 1) {
979
- let e = a.plugins ?? [], t = {};
980
- for (let n of E) {
981
- for (let t of e) await t.onBeforeCompile?.($(n, d[n], a.compileOutDir, a));
949
+ if (D.length > 0 && (E = !0), S && D.length > 1) {
950
+ let e = s.plugins ?? [], t = {};
951
+ for (let n of D) {
952
+ for (let t of e) await t.onBeforeCompile?.($(n, d[n], s.compileOutDir, s));
982
953
  t[n] = e.length > 0 ? await Q(d[n], n, e) : d[n];
983
954
  }
984
- let n = await m(E.map((e) => ({
955
+ let n = await f(D.map((e) => ({
985
956
  locale: e,
986
957
  catalog: t[e],
987
- allIds: p,
988
- sourceLocale: a.sourceLocale,
958
+ allIds: m,
959
+ sourceLocale: s.sourceLocale,
989
960
  options: { skipFuzzy: h }
990
- })), S);
961
+ })), C);
991
962
  for (let e of n) {
992
- let t = D(a.compileOutDir, `${e.locale}.js`);
993
- if (C(t, e.code, "utf-8"), g && g.set(e.locale, f[e.locale]), e.stats.missing.length > 0) {
994
- j.warn(`${e.locale}: ${e.stats.compiled} compiled, ${e.stats.missing.length} missing translations`);
995
- for (let t of e.stats.missing) j.warn(` ⤷ ${t}`);
996
- } else j.success(`Compiled ${e.locale}: ${e.stats.compiled} messages → ${t}`);
963
+ let t = w(s.compileOutDir, `${e.locale}.js`);
964
+ if (x(t, e.code, "utf-8"), b && b.set(e.locale, p[e.locale]), e.stats.missing.length > 0) {
965
+ O.warn(`${e.locale}: ${e.stats.compiled} compiled, ${e.stats.missing.length} missing translations`);
966
+ for (let t of e.stats.missing) O.warn(` ⤷ ${t}`);
967
+ } else O.success(`Compiled ${e.locale}: ${e.stats.compiled} messages → ${t}`);
997
968
  }
998
- for (let n of E) for (let r of e) await r.onAfterCompile?.($(n, t[n], a.compileOutDir, a));
969
+ for (let n of D) for (let r of e) await r.onAfterCompile?.($(n, t[n], s.compileOutDir, s));
999
970
  } else {
1000
- let e = a.plugins ?? [];
1001
- for (let n of E) {
1002
- let r = D(a.compileOutDir, `${n}.js`);
1003
- for (let t of e) await t.onBeforeCompile?.($(n, d[n], a.compileOutDir, a));
1004
- let i = e.length > 0 ? await Q(d[n], n, e) : d[n], { code: o, stats: s } = t(i, n, p, a.sourceLocale, { skipFuzzy: h });
1005
- if (C(r, o, "utf-8"), g && g.set(n, f[n]), s.missing.length > 0) {
1006
- j.warn(`${n}: ${s.compiled} compiled, ${s.missing.length} missing translations`);
1007
- for (let e of s.missing) j.warn(` ⤷ ${e}`);
1008
- } else j.success(`Compiled ${n}: ${s.compiled} messages → ${r}`);
1009
- for (let t of e) await t.onAfterCompile?.($(n, i, a.compileOutDir, a));
971
+ let e = s.plugins ?? [];
972
+ for (let n of D) {
973
+ let r = w(s.compileOutDir, `${n}.js`);
974
+ for (let t of e) await t.onBeforeCompile?.($(n, d[n], s.compileOutDir, s));
975
+ let i = e.length > 0 ? await Q(d[n], n, e) : d[n], { code: a, stats: o } = t(i, n, m, s.sourceLocale, { skipFuzzy: h });
976
+ if (x(r, a, "utf-8"), b && b.set(n, p[n]), o.missing.length > 0) {
977
+ O.warn(`${n}: ${o.compiled} compiled, ${o.missing.length} missing translations`);
978
+ for (let e of o.missing) O.warn(` ⤷ ${e}`);
979
+ } else O.success(`Compiled ${n}: ${o.compiled} messages → ${r}`);
980
+ for (let t of e) await t.onAfterCompile?.($(n, i, s.compileOutDir, s));
1010
981
  }
1011
982
  }
1012
- w > 0 && j.info(`${w} locale(s) unchanged — skipped`), g && g.save();
1013
- let O = D(a.compileOutDir, "index.js"), k = D(a.compileOutDir, "messages.d.ts");
1014
- (T || !y(O)) && (C(O, n(c, a.compileOutDir), "utf-8"), j.success(`Generated index → ${O}`)), (T || !y(k)) && (C(k, e(p, d, a.sourceLocale), "utf-8"), j.success(`Generated types → ${k}`));
983
+ T > 0 && O.info(`${T} locale(s) unchanged — skipped`), b && b.save();
984
+ let k = w(s.compileOutDir, "index.js"), A = w(s.compileOutDir, "messages.d.ts");
985
+ (E || !_(k)) && (x(k, n(l, s.compileOutDir), "utf-8"), O.success(`Generated index → ${k}`)), (E || !_(A)) && (x(A, e(m, d, s.sourceLocale), "utf-8"), O.success(`Generated types → ${A}`));
1015
986
  }
1016
- }), ze = M({
987
+ }), Fe = k({
1017
988
  meta: {
1018
989
  name: "stats",
1019
990
  description: "Show translation progress"
@@ -1023,9 +994,9 @@ var Re = M({
1023
994
  description: "Path to config file"
1024
995
  } },
1025
996
  async run({ args: e }) {
1026
- let t = await o(e.config), n = v(t.locales), r = t.format === "json" ? ".json" : ".po", i = [];
997
+ let t = await a(e.config), n = g(t.locales), r = t.format === "json" ? ".json" : ".po", i = [];
1027
998
  for (let e of n) {
1028
- let n = X(D(t.catalogDir, `${e}${r}`), t.format), a = Object.values(n).filter((e) => !e.obsolete), o = a.length, s = a.filter((e) => e.translation && e.translation.length > 0).length, c = o > 0 ? (s / o * 100).toFixed(1) + "%" : "—";
999
+ let n = Z(w(t.catalogDir, `${e}${r}`), t.format), a = Object.values(n).filter((e) => !e.obsolete), o = a.length, s = a.filter((e) => e.translation && e.translation.length > 0).length, c = o > 0 ? (s / o * 100).toFixed(1) + "%" : "—";
1029
1000
  i.push({
1030
1001
  locale: e,
1031
1002
  total: o,
@@ -1033,11 +1004,11 @@ var Re = M({
1033
1004
  pct: c
1034
1005
  });
1035
1006
  }
1036
- j.log(""), j.log(" Locale │ Total │ Translated │ Progress"), j.log(" ────────┼───────┼────────────┼─────────────────────────────");
1037
- for (let e of i) j.log(ae(e.locale, e.total, e.translated));
1038
- j.log("");
1007
+ O.log(""), O.log(" Locale │ Total │ Translated │ Progress"), O.log(" ────────┼───────┼────────────┼─────────────────────────────");
1008
+ for (let e of i) O.log(P(e.locale, e.total, e.translated));
1009
+ O.log("");
1039
1010
  }
1040
- }), Be = M({
1011
+ }), Ie = k({
1041
1012
  meta: {
1042
1013
  name: "lint",
1043
1014
  description: "Check translation quality (missing, inconsistent placeholders, fuzzy)"
@@ -1058,21 +1029,21 @@ var Re = M({
1058
1029
  }
1059
1030
  },
1060
1031
  async run({ args: e }) {
1061
- let t = await o(e.config), n = v(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
1062
- for (let e of n) i[e] = X(D(t.catalogDir, `${e}${r}`), t.format);
1063
- let a = e.locale ? [e.locale] : void 0;
1064
- j.info(`Linting ${a ? a.join(", ") : "all locales"} (source: ${t.sourceLocale})`);
1032
+ let t = await a(e.config), n = g(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
1033
+ for (let e of n) i[e] = Z(w(t.catalogDir, `${e}${r}`), t.format);
1034
+ let o = e.locale ? [e.locale] : void 0;
1035
+ O.info(`Linting ${o ? o.join(", ") : "all locales"} (source: ${t.sourceLocale})`);
1065
1036
  let s = {
1066
1037
  sourceLocale: t.sourceLocale,
1067
1038
  strict: e.strict ?? !1
1068
1039
  };
1069
- a && (s.locales = a);
1070
- let c = B(i, s);
1071
- j.log(""), j.log(se(c)), j.log("");
1040
+ o && (s.locales = o);
1041
+ let c = z(i, s);
1042
+ O.log(""), O.log(ae(c)), O.log("");
1072
1043
  let l = c.filter((e) => e.severity === "error"), u = c.filter((e) => e.severity === "warning");
1073
1044
  (l.length > 0 || e.strict && u.length > 0) && (process.exitCode = 1);
1074
1045
  }
1075
- }), Ve = M({
1046
+ }), Le = k({
1076
1047
  meta: {
1077
1048
  name: "check",
1078
1049
  description: "Check translation coverage for CI"
@@ -1102,35 +1073,35 @@ var Re = M({
1102
1073
  }
1103
1074
  },
1104
1075
  async run({ args: e }) {
1105
- let t = await o(e.config), n = v(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
1106
- for (let e of n) i[e] = X(D(t.catalogDir, `${e}${r}`), t.format);
1107
- let a = parseFloat(e["min-coverage"] ?? "100");
1108
- if (isNaN(a) || a < 0 || a > 100) {
1109
- j.error("Invalid --min-coverage. Must be a number between 0 and 100."), process.exitCode = 1;
1076
+ let t = await a(e.config), n = g(t.locales), r = t.format === "json" ? ".json" : ".po", i = {};
1077
+ for (let e of n) i[e] = Z(w(t.catalogDir, `${e}${r}`), t.format);
1078
+ let o = parseFloat(e["min-coverage"] ?? "100");
1079
+ if (isNaN(o) || o < 0 || o > 100) {
1080
+ O.error("Invalid --min-coverage. Must be a number between 0 and 100."), process.exitCode = 1;
1110
1081
  return;
1111
1082
  }
1112
1083
  let s = e.format ?? (e.ci ? "github" : "text"), c = {
1113
1084
  sourceLocale: t.sourceLocale,
1114
- minCoverage: a,
1085
+ minCoverage: o,
1115
1086
  format: s
1116
1087
  };
1117
1088
  e.locale && (c.locale = e.locale);
1118
- let l = le(i, c);
1089
+ let l = se(i, c);
1119
1090
  switch (s) {
1120
1091
  case "json":
1121
- j.log(fe(l));
1092
+ O.log(B(l));
1122
1093
  break;
1123
1094
  case "github":
1124
- j.log(de(l, t.catalogDir, t.format));
1095
+ O.log(le(l, t.catalogDir, t.format));
1125
1096
  break;
1126
1097
  default:
1127
- j.log(""), j.log(ue(l)), j.log("");
1098
+ O.log(""), O.log(ce(l)), O.log("");
1128
1099
  break;
1129
1100
  }
1130
1101
  l.passed || (process.exitCode = 1);
1131
1102
  }
1132
1103
  });
1133
- async function He(e, t, n) {
1104
+ async function Re(e, t, n) {
1134
1105
  let r = Array(e.length), i = 0, a = Array.from({ length: Math.min(n, e.length) }, async () => {
1135
1106
  for (; i < e.length;) {
1136
1107
  let n = i++;
@@ -1139,7 +1110,7 @@ async function He(e, t, n) {
1139
1110
  });
1140
1111
  return await Promise.all(a), r;
1141
1112
  }
1142
- var Ue = M({
1113
+ var ze = k({
1143
1114
  meta: {
1144
1115
  name: "translate",
1145
1116
  description: "Translate messages using AI (Claude Code or Codex CLI)"
@@ -1186,45 +1157,45 @@ var Ue = M({
1186
1157
  }
1187
1158
  },
1188
1159
  async run({ args: e }) {
1189
- let t = await o(e.config), n = v(t.locales), r = e.provider;
1160
+ let t = await a(e.config), n = g(t.locales), r = e.provider;
1190
1161
  if (r !== "claude" && r !== "codex") {
1191
- j.error(`Invalid provider "${r}". Use "claude" or "codex".`);
1162
+ O.error(`Invalid provider "${r}". Use "claude" or "codex".`);
1192
1163
  return;
1193
1164
  }
1194
1165
  let i = parseInt(e["batch-size"] ?? "50", 10);
1195
1166
  if (isNaN(i) || i < 1) {
1196
- j.error("Invalid batch-size. Must be a positive integer.");
1167
+ O.error("Invalid batch-size. Must be a positive integer.");
1197
1168
  return;
1198
1169
  }
1199
- let a = e.glossary ? ye(D(e.glossary)) : void 0, s = e.concurrency ? parseInt(e.concurrency, 10) : 3;
1170
+ let o = e.glossary ? me(w(e.glossary)) : void 0, s = e.concurrency ? parseInt(e.concurrency, 10) : 3;
1200
1171
  if (isNaN(s) || s < 1) {
1201
- j.error("Invalid concurrency. Must be a positive integer.");
1172
+ O.error("Invalid concurrency. Must be a positive integer.");
1202
1173
  return;
1203
1174
  }
1204
1175
  let c = e.timeout ? parseInt(e.timeout, 10) : 120;
1205
1176
  if (isNaN(c) || c < 1) {
1206
- j.error("Invalid timeout. Must be a positive integer (seconds).");
1177
+ O.error("Invalid timeout. Must be a positive integer (seconds).");
1207
1178
  return;
1208
1179
  }
1209
1180
  let l = c * 1e3, u = e.locale ? [e.locale] : n.filter((e) => e !== t.sourceLocale);
1210
1181
  if (u.length === 0) {
1211
- j.warn("No target locales to translate.");
1182
+ O.warn("No target locales to translate.");
1212
1183
  return;
1213
1184
  }
1214
- j.info(`Translating with ${r} (batch size: ${i})`);
1185
+ O.info(`Translating with ${r} (batch size: ${i})`);
1215
1186
  let d = t.format === "json" ? ".json" : ".po";
1216
- await He(u, async (n) => {
1217
- j.info(`\n[${n}]`);
1218
- let o = D(t.catalogDir, `${n}${d}`), s = X(o, t.format);
1187
+ await Re(u, async (n) => {
1188
+ O.info(`\n[${n}]`);
1189
+ let a = w(t.catalogDir, `${n}${d}`), s = Z(a, t.format);
1219
1190
  if (e["dry-run"]) {
1220
1191
  let e = Object.entries(s).filter(([, e]) => !e.obsolete && (!e.translation || e.translation.length === 0));
1221
1192
  if (e.length > 0) {
1222
- for (let [t, n] of e) j.log(` ${t}: ${n.message ?? t}`);
1223
- j.success(` ${n}: ${e.length} messages would be translated (dry-run)`);
1224
- } else j.success(` ${n}: already fully translated`);
1193
+ for (let [t, n] of e) O.log(` ${t}: ${n.message ?? t}`);
1194
+ O.success(` ${n}: ${e.length} messages would be translated (dry-run)`);
1195
+ } else O.success(` ${n}: already fully translated`);
1225
1196
  return;
1226
1197
  }
1227
- let c = a ? be(a, n) : void 0, { catalog: u, translated: f, warnings: p } = await De({
1198
+ let c = o ? he(o, n) : void 0, { catalog: u, translated: f, warnings: p } = await Se({
1228
1199
  provider: r,
1229
1200
  sourceLocale: t.sourceLocale,
1230
1201
  targetLocale: n,
@@ -1234,10 +1205,10 @@ var Ue = M({
1234
1205
  timeoutMs: l,
1235
1206
  ...e.context ? { context: e.context } : {}
1236
1207
  });
1237
- f > 0 ? (Z(o, u, t.format), j.success(` ${n}: ${f} messages translated`)) : j.success(` ${n}: already fully translated`), p.length > 0 && j.warn(` ${n}: ${p.length} QA warnings`);
1208
+ f > 0 ? (je(a, u, t.format), O.success(` ${n}: ${f} messages translated`)) : O.success(` ${n}: already fully translated`), p.length > 0 && O.warn(` ${n}: ${p.length} QA warnings`);
1238
1209
  }, s);
1239
1210
  }
1240
- }), We = M({
1211
+ }), Be = k({
1241
1212
  meta: {
1242
1213
  name: "migrate",
1243
1214
  description: "Migrate from another i18n library using AI"
@@ -1262,34 +1233,34 @@ var Ue = M({
1262
1233
  async run({ args: e }) {
1263
1234
  let t = e.provider;
1264
1235
  if (t !== "claude" && t !== "codex") {
1265
- j.error(`Invalid provider "${t}". Use "claude" or "codex".`);
1236
+ O.error(`Invalid provider "${t}". Use "claude" or "codex".`);
1266
1237
  return;
1267
1238
  }
1268
- await Pe({
1239
+ await ke({
1269
1240
  from: e.from,
1270
1241
  provider: t,
1271
1242
  write: e.write ?? !1
1272
1243
  });
1273
1244
  }
1274
1245
  });
1275
- ee(M({
1246
+ A(k({
1276
1247
  meta: {
1277
1248
  name: "fluenti",
1278
1249
  version: "0.0.1",
1279
1250
  description: "Compile-time i18n for modern frameworks"
1280
1251
  },
1281
1252
  subCommands: {
1282
- init: M({
1253
+ init: k({
1283
1254
  meta: {
1284
1255
  name: "init",
1285
1256
  description: "Initialize Fluenti in your project"
1286
1257
  },
1287
1258
  args: {},
1288
1259
  async run() {
1289
- await p({ cwd: process.cwd() });
1260
+ await d({ cwd: process.cwd() });
1290
1261
  }
1291
1262
  }),
1292
- doctor: M({
1263
+ doctor: k({
1293
1264
  meta: {
1294
1265
  name: "doctor",
1295
1266
  description: "Diagnose Fluenti setup and vNext import issues"
@@ -1306,16 +1277,16 @@ ee(M({
1306
1277
  }
1307
1278
  },
1308
1279
  async run({ args: e }) {
1309
- let t = await u({
1280
+ let t = await l({
1310
1281
  cwd: process.cwd(),
1311
1282
  ...e.config ? { config: e.config } : {}
1312
- }), n = h(t);
1313
- j.log(n);
1283
+ }), n = p(t);
1284
+ O.log(n);
1314
1285
  let r = t.findings.some((e) => e.severity === "error"), i = t.findings.some((e) => e.severity === "warning");
1315
1286
  (r || (e.strict ?? !1) && i) && (process.exitCode = 1);
1316
1287
  }
1317
1288
  }),
1318
- codemod: M({
1289
+ codemod: k({
1319
1290
  meta: {
1320
1291
  name: "codemod",
1321
1292
  description: "Rewrite imports to the vNext Fluenti entry layout"
@@ -1332,26 +1303,26 @@ ee(M({
1332
1303
  }
1333
1304
  },
1334
1305
  async run({ args: e }) {
1335
- let t = e.include ? e.include.split(",").map((e) => e.trim()).filter(Boolean) : void 0, n = await a({
1306
+ let t = e.include ? e.include.split(",").map((e) => e.trim()).filter(Boolean) : void 0, n = await i({
1336
1307
  cwd: process.cwd(),
1337
1308
  ...t ? { include: t } : {},
1338
1309
  write: e.write ?? !1
1339
1310
  });
1340
1311
  if (n.changedCount === 0) {
1341
- j.success("No files need import rewrites.");
1312
+ O.success("No files need import rewrites.");
1342
1313
  return;
1343
1314
  }
1344
- for (let t of n.changedFiles) j.log(`${e.write ? "updated" : "would update"} ${t.file}`);
1345
- j.success(`${e.write ? "Updated" : "Detected"} ${n.changedCount} file(s) with Fluenti import rewrites.`);
1315
+ for (let t of n.changedFiles) O.log(`${e.write ? "updated" : "would update"} ${t.file}`);
1316
+ O.success(`${e.write ? "Updated" : "Detected"} ${n.changedCount} file(s) with Fluenti import rewrites.`);
1346
1317
  }
1347
1318
  }),
1348
- extract: Ie,
1349
- compile: Re,
1350
- stats: ze,
1351
- lint: Be,
1352
- check: Ve,
1353
- translate: Ue,
1354
- migrate: We
1319
+ extract: Me,
1320
+ compile: Pe,
1321
+ stats: Fe,
1322
+ lint: Ie,
1323
+ check: Le,
1324
+ translate: ze,
1325
+ migrate: Be
1355
1326
  }
1356
1327
  }));
1357
1328
  //#endregion