@verbaly/compiler 0.15.0 → 0.17.0

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.
@@ -1,3 +1,4 @@
1
+ import { t as isModuleNotFound } from "./cli.js";
1
2
  //#region src/providers/claude.ts
2
3
  const DEFAULT_MODEL = "claude-sonnet-5";
3
4
  const SYSTEM = `You translate UI strings for the Verbaly i18n library.
@@ -44,10 +45,7 @@ async function loadSdk(load = () => import("@anthropic-ai/sdk")) {
44
45
  throw error;
45
46
  }
46
47
  }
47
- function isModuleNotFound(error, name) {
48
- return error instanceof Error && error.code === "ERR_MODULE_NOT_FOUND" && error.message.includes(name);
49
- }
50
48
  //#endregion
51
49
  export { claudeProvider };
52
50
 
53
- //# sourceMappingURL=claude-Bi_Ex2hm.js.map
51
+ //# sourceMappingURL=claude-mpjdqqnY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-mpjdqqnY.js","names":[],"sources":["../src/providers/claude.ts"],"sourcesContent":["import { isModuleNotFound } from '../config';\nimport type { TranslateProvider, TranslateRequest } from '../translate';\n\nexport interface ClaudeProviderOptions {\n model?: string;\n apiKey?: string;\n maxTokens?: number;\n}\n\n// balanced default for translation\nconst DEFAULT_MODEL = 'claude-sonnet-5';\n\nconst SYSTEM = `You translate UI strings for the Verbaly i18n library.\nRules:\n- Translate only the human-readable text, naturally for the target locale.\n- Preserve verbatim: placeholders like {name}, format specs like {price:currency/EUR}, variant blocks like {count | one: ... | other: # ...} (translate only the text inside each variant, keep keys and # as-is), ICU syntax, named tags like <em>...</em> and escapes {{ }} || ##.\n- Keys are opaque identifiers: return exactly the same keys, never translate or rename them.`;\n\nexport function claudeProvider(options: ClaudeProviderOptions = {}): TranslateProvider {\n return async (request: TranslateRequest) => {\n const Anthropic = await loadSdk();\n const client = new Anthropic(options.apiKey ? { apiKey: options.apiKey } : {});\n const response = await client.messages.create({\n model: options.model ?? DEFAULT_MODEL,\n max_tokens: options.maxTokens ?? 16000,\n thinking: { type: 'disabled' },\n system: SYSTEM,\n messages: [{ role: 'user', content: buildPrompt(request) }],\n output_config: { format: batchFormat(request) },\n });\n const text = response.content.find((block) => block.type === 'text')?.text ?? '{}';\n return JSON.parse(text) as Record<string, string>;\n };\n}\n\nexport function buildPrompt(request: TranslateRequest): string {\n return (\n `Translate each value from \"${request.sourceLocale}\" to \"${request.targetLocale}\". ` +\n `Return a JSON object with the same keys and translated values.\\n\\n` +\n JSON.stringify(request.messages, null, 2)\n );\n}\n\nexport function batchFormat(request: TranslateRequest) {\n const keys = Object.keys(request.messages);\n return {\n type: 'json_schema' as const,\n schema: {\n type: 'object',\n properties: Object.fromEntries(keys.map((key) => [key, { type: 'string' }])),\n required: keys,\n additionalProperties: false,\n },\n };\n}\n\ntype SdkModule = { default: typeof import('@anthropic-ai/sdk').default };\n\n// injectable for tests\nexport async function loadSdk(\n load: () => Promise<SdkModule> = () => import('@anthropic-ai/sdk'),\n): Promise<SdkModule['default']> {\n try {\n const mod = await load();\n return mod.default;\n } catch (error) {\n if (isModuleNotFound(error, '@anthropic-ai/sdk')) {\n throw new Error(\n '[verbaly] the claude translate provider needs @anthropic-ai/sdk — install it as a dev dependency (e.g. `pnpm add -D @anthropic-ai/sdk` / `npm i -D @anthropic-ai/sdk`) and set ANTHROPIC_API_KEY',\n { cause: error },\n );\n }\n throw error;\n }\n}\n\n"],"mappings":";;AAUA,MAAM,gBAAgB;AAEtB,MAAM,SAAS;;;;;AAMf,SAAgB,eAAe,UAAiC,CAAC,GAAsB;CACrF,OAAO,OAAO,YAA8B;EAW1C,MAAM,QAAO,MARU,KADJ,OADK,QAAQ,IACH,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC,CAChD,CAAC,CAAC,SAAS,OAAO;GAC5C,OAAO,QAAQ,SAAS;GACxB,YAAY,QAAQ,aAAa;GACjC,UAAU,EAAE,MAAM,WAAW;GAC7B,QAAQ;GACR,UAAU,CAAC;IAAE,MAAM;IAAQ,SAAS,YAAY,OAAO;GAAE,CAAC;GAC1D,eAAe,EAAE,QAAQ,YAAY,OAAO,EAAE;EAChD,CAAC,EAAA,CACqB,QAAQ,MAAM,UAAU,MAAM,SAAS,MAAM,CAAC,EAAE,QAAQ;EAC9E,OAAO,KAAK,MAAM,IAAI;CACxB;AACF;AAEA,SAAgB,YAAY,SAAmC;CAC7D,OACE,8BAA8B,QAAQ,aAAa,QAAQ,QAAQ,aAAa,yEAEhF,KAAK,UAAU,QAAQ,UAAU,MAAM,CAAC;AAE5C;AAEA,SAAgB,YAAY,SAA2B;CACrD,MAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ;CACzC,OAAO;EACL,MAAM;EACN,QAAQ;GACN,MAAM;GACN,YAAY,OAAO,YAAY,KAAK,KAAK,QAAQ,CAAC,KAAK,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC;GAC3E,UAAU;GACV,sBAAsB;EACxB;CACF;AACF;AAKA,eAAsB,QACpB,aAAuC,OAAO,sBACf;CAC/B,IAAI;EAEF,QAAO,MADW,KAAK,EAAA,CACZ;CACb,SAAS,OAAO;EACd,IAAI,iBAAiB,OAAO,mBAAmB,GAC7C,MAAM,IAAI,MACR,oMACA,EAAE,OAAO,MAAM,CACjB;EAEF,MAAM;CACR;AACF"}
package/dist/cli.js CHANGED
@@ -154,6 +154,15 @@ ${lines.join("\n")}
154
154
 
155
155
  export const verbaly: import('verbaly').Verbaly<VerbalyKey>;
156
156
 
157
+ export const sourceLocale: string;
158
+ export const locales: string[];
159
+ export function createInstance(
160
+ options?: import('verbaly').VerbalyOptions<VerbalyKey>,
161
+ ): import('verbaly').Verbaly<VerbalyKey>;
162
+ export function createRequestInstance(
163
+ locale: string,
164
+ ): Promise<import('verbaly').Verbaly<VerbalyKey>>;
165
+
157
166
  export function t<K extends VerbalyKey>(
158
167
  key: K,
159
168
  ...args: [VerbalyMessages[K]] extends [never] ? [] : [VerbalyMessages[K]]
@@ -180,6 +189,125 @@ function writeDts(cfg, entries) {
180
189
  writeFileSync(join(cfg.root, "verbaly.d.ts"), generateDts(entries));
181
190
  }
182
191
  //#endregion
192
+ //#region src/pseudo.ts
193
+ const PSEUDO_LOCALE = "en-XA";
194
+ const ACCENTS = {
195
+ a: "á",
196
+ b: "ƀ",
197
+ c: "ç",
198
+ d: "đ",
199
+ e: "é",
200
+ f: "ƒ",
201
+ g: "ğ",
202
+ h: "ĥ",
203
+ i: "í",
204
+ j: "ĵ",
205
+ k: "ķ",
206
+ l: "ĺ",
207
+ m: "ɱ",
208
+ n: "ñ",
209
+ o: "ó",
210
+ p: "þ",
211
+ q: "ǫ",
212
+ r: "ŕ",
213
+ s: "š",
214
+ t: "ţ",
215
+ u: "ú",
216
+ v: "ṽ",
217
+ w: "ŵ",
218
+ x: "ẋ",
219
+ y: "ý",
220
+ z: "ž",
221
+ A: "Á",
222
+ B: "Ɓ",
223
+ C: "Ç",
224
+ D: "Đ",
225
+ E: "É",
226
+ F: "Ƒ",
227
+ G: "Ğ",
228
+ H: "Ĥ",
229
+ I: "Í",
230
+ J: "Ĵ",
231
+ K: "Ķ",
232
+ L: "Ĺ",
233
+ M: "Ḿ",
234
+ N: "Ñ",
235
+ O: "Ó",
236
+ P: "Þ",
237
+ Q: "Ǫ",
238
+ R: "Ŕ",
239
+ S: "Š",
240
+ T: "Ţ",
241
+ U: "Ú",
242
+ V: "Ṽ",
243
+ W: "Ŵ",
244
+ X: "Ẍ",
245
+ Y: "Ý",
246
+ Z: "Ž"
247
+ };
248
+ const TAG_AT = /<\/?[a-zA-Z][\w-]*\/?>/y;
249
+ function pseudoLocalize(message) {
250
+ let out = "";
251
+ let letters = 0;
252
+ let i = 0;
253
+ while (i < message.length) {
254
+ const two = message.slice(i, i + 2);
255
+ if (two === "{{" || two === "}}" || two === "||" || two === "##") {
256
+ out += two;
257
+ i += 2;
258
+ continue;
259
+ }
260
+ const ch = message[i];
261
+ if (ch === "{") {
262
+ const end = matchBrace(message, i);
263
+ out += message.slice(i, end);
264
+ i = end;
265
+ continue;
266
+ }
267
+ if (ch === "<") {
268
+ TAG_AT.lastIndex = i;
269
+ const m = TAG_AT.exec(message);
270
+ if (m) {
271
+ out += m[0];
272
+ i += m[0].length;
273
+ continue;
274
+ }
275
+ }
276
+ const mapped = ACCENTS[ch];
277
+ if (mapped) {
278
+ out += mapped;
279
+ letters += 1;
280
+ } else out += ch;
281
+ i += 1;
282
+ }
283
+ const pad = "~".repeat(Math.ceil(letters / 3));
284
+ return `⟦${out}${pad ? " " + pad : ""}⟧`;
285
+ }
286
+ function matchBrace(message, start) {
287
+ let depth = 0;
288
+ for (let i = start; i < message.length; i++) {
289
+ const two = message.slice(i, i + 2);
290
+ if (two === "{{" || two === "}}") {
291
+ i += 1;
292
+ continue;
293
+ }
294
+ const ch = message[i];
295
+ if (ch === "{") depth += 1;
296
+ else if (ch === "}") {
297
+ depth -= 1;
298
+ if (depth === 0) return i + 1;
299
+ }
300
+ }
301
+ return message.length;
302
+ }
303
+ function pseudoCatalogs(cfg, catalogs, locale = PSEUDO_LOCALE) {
304
+ const source = catalogs[cfg.sourceLocale] ?? {};
305
+ const target = {};
306
+ for (const [key, msg] of Object.entries(source)) target[key] = msg ? pseudoLocalize(msg) : "";
307
+ catalogs[locale] = target;
308
+ return Object.keys(target).filter((key) => target[key]);
309
+ }
310
+ //#endregion
183
311
  //#region src/config.ts
184
312
  function resolveConfig(config = {}) {
185
313
  const root = resolve(config.root ?? process.cwd());
@@ -187,7 +315,7 @@ function resolveConfig(config = {}) {
187
315
  const sourceLocale = config.sourceLocale ?? "en";
188
316
  const locales = /* @__PURE__ */ new Set([sourceLocale, ...config.locales ?? []]);
189
317
  if (existsSync(dir)) {
190
- for (const file of readdirSync(dir)) if (file.endsWith(".json")) locales.add(file.slice(0, -5));
318
+ for (const file of readdirSync(dir)) if (file.endsWith(".json") && file !== `en-XA.json`) locales.add(file.slice(0, -5));
191
319
  }
192
320
  return {
193
321
  root,
@@ -236,6 +364,9 @@ async function loadTsConfig(path) {
236
364
  function isModuleNotFound(error, name) {
237
365
  return error instanceof Error && error.code === "ERR_MODULE_NOT_FOUND" && error.message.includes(name);
238
366
  }
367
+ function targetLocales(cfg, override) {
368
+ return (override ?? cfg.locales).filter((locale) => locale !== cfg.sourceLocale && cfg.locales.includes(locale));
369
+ }
239
370
  async function loadConfig(root, overrides = {}) {
240
371
  return resolveConfig({
241
372
  ...await loadConfigFile(root),
@@ -389,7 +520,7 @@ function buildTransMessage(code, children) {
389
520
  text += escapeText(expr.value);
390
521
  continue;
391
522
  }
392
- if (expr.type === "TaggedTemplateExpression") return void 0;
523
+ if (containsTaggedT(expr)) return void 0;
393
524
  const source = code.slice(expr.start, expr.end);
394
525
  const name = uniqueName(deriveName(expr, params.length), source, takenParams);
395
526
  params.push({
@@ -442,6 +573,15 @@ function selfClosedSource(code, opening) {
442
573
  const src = code.slice(opening.start, opening.end);
443
574
  return src.endsWith("/>") ? src : `${src.slice(0, -1).trimEnd()} />`;
444
575
  }
576
+ function containsTaggedT(node) {
577
+ let found = false;
578
+ walk(node, (n) => {
579
+ if (n.type !== "TaggedTemplateExpression") return;
580
+ const tag = n.tag;
581
+ if (isTReference(tag) || explicitId(tag)) found = true;
582
+ });
583
+ return found;
584
+ }
445
585
  function isTReference(node) {
446
586
  if (node.type === "Identifier") return node.name === "t";
447
587
  if (node.type === "MemberExpression" && !node.computed) {
@@ -459,6 +599,7 @@ function buildMessage(code, quasi) {
459
599
  for (let i = 0; i < expressions.length; i++) {
460
600
  const expr = expressions[i];
461
601
  if (!expr) return void 0;
602
+ if (containsTaggedT(expr)) return void 0;
462
603
  const source = code.slice(expr.start, expr.end);
463
604
  const name = uniqueName(deriveName(expr, i), source, taken);
464
605
  params.push({
@@ -762,7 +903,7 @@ function readDeps(root) {
762
903
  //#region src/translate.ts
763
904
  async function translateCatalogs(cfg, catalogs, provider, options = {}) {
764
905
  const batchSize = options.batchSize ?? 20;
765
- const targets = (options.locales ?? cfg.locales).filter((locale) => locale !== cfg.sourceLocale && cfg.locales.includes(locale));
906
+ const targets = targetLocales(cfg, options.locales);
766
907
  const source = catalogs[cfg.sourceLocale] ?? {};
767
908
  const result = {
768
909
  translated: {},
@@ -821,7 +962,7 @@ function exportCatalogs(cfg, catalogs, options = {}) {
821
962
  const format = options.format ?? "xliff";
822
963
  const dir = resolve(cfg.root, options.out ?? "verbaly-export");
823
964
  const source = catalogs[cfg.sourceLocale] ?? {};
824
- const targets = (options.locales ?? cfg.locales).filter((locale) => locale !== cfg.sourceLocale && cfg.locales.includes(locale));
965
+ const targets = targetLocales(cfg, options.locales);
825
966
  const files = [];
826
967
  mkdirSync(dir, { recursive: true });
827
968
  for (const locale of targets) {
@@ -1000,125 +1141,6 @@ function csvRows(content) {
1000
1141
  return rows;
1001
1142
  }
1002
1143
  //#endregion
1003
- //#region src/pseudo.ts
1004
- const PSEUDO_LOCALE = "en-XA";
1005
- const ACCENTS = {
1006
- a: "á",
1007
- b: "ƀ",
1008
- c: "ç",
1009
- d: "đ",
1010
- e: "é",
1011
- f: "ƒ",
1012
- g: "ğ",
1013
- h: "ĥ",
1014
- i: "í",
1015
- j: "ĵ",
1016
- k: "ķ",
1017
- l: "ĺ",
1018
- m: "ɱ",
1019
- n: "ñ",
1020
- o: "ó",
1021
- p: "þ",
1022
- q: "ǫ",
1023
- r: "ŕ",
1024
- s: "š",
1025
- t: "ţ",
1026
- u: "ú",
1027
- v: "ṽ",
1028
- w: "ŵ",
1029
- x: "ẋ",
1030
- y: "ý",
1031
- z: "ž",
1032
- A: "Á",
1033
- B: "Ɓ",
1034
- C: "Ç",
1035
- D: "Đ",
1036
- E: "É",
1037
- F: "Ƒ",
1038
- G: "Ğ",
1039
- H: "Ĥ",
1040
- I: "Í",
1041
- J: "Ĵ",
1042
- K: "Ķ",
1043
- L: "Ĺ",
1044
- M: "Ḿ",
1045
- N: "Ñ",
1046
- O: "Ó",
1047
- P: "Þ",
1048
- Q: "Ǫ",
1049
- R: "Ŕ",
1050
- S: "Š",
1051
- T: "Ţ",
1052
- U: "Ú",
1053
- V: "Ṽ",
1054
- W: "Ŵ",
1055
- X: "Ẍ",
1056
- Y: "Ý",
1057
- Z: "Ž"
1058
- };
1059
- const TAG_AT = /<\/?[a-zA-Z][\w-]*\/?>/y;
1060
- function pseudoLocalize(message) {
1061
- let out = "";
1062
- let letters = 0;
1063
- let i = 0;
1064
- while (i < message.length) {
1065
- const two = message.slice(i, i + 2);
1066
- if (two === "{{" || two === "}}" || two === "||" || two === "##") {
1067
- out += two;
1068
- i += 2;
1069
- continue;
1070
- }
1071
- const ch = message[i];
1072
- if (ch === "{") {
1073
- const end = matchBrace(message, i);
1074
- out += message.slice(i, end);
1075
- i = end;
1076
- continue;
1077
- }
1078
- if (ch === "<") {
1079
- TAG_AT.lastIndex = i;
1080
- const m = TAG_AT.exec(message);
1081
- if (m) {
1082
- out += m[0];
1083
- i += m[0].length;
1084
- continue;
1085
- }
1086
- }
1087
- const mapped = ACCENTS[ch];
1088
- if (mapped) {
1089
- out += mapped;
1090
- letters += 1;
1091
- } else out += ch;
1092
- i += 1;
1093
- }
1094
- const pad = "~".repeat(Math.ceil(letters / 3));
1095
- return `⟦${out}${pad ? " " + pad : ""}⟧`;
1096
- }
1097
- function matchBrace(message, start) {
1098
- let depth = 0;
1099
- for (let i = start; i < message.length; i++) {
1100
- const two = message.slice(i, i + 2);
1101
- if (two === "{{" || two === "}}") {
1102
- i += 1;
1103
- continue;
1104
- }
1105
- const ch = message[i];
1106
- if (ch === "{") depth += 1;
1107
- else if (ch === "}") {
1108
- depth -= 1;
1109
- if (depth === 0) return i + 1;
1110
- }
1111
- }
1112
- return message.length;
1113
- }
1114
- function pseudoCatalogs(cfg, catalogs, locale = PSEUDO_LOCALE) {
1115
- const source = catalogs[cfg.sourceLocale] ?? {};
1116
- const target = {};
1117
- for (const [key, msg] of Object.entries(source)) target[key] = msg ? pseudoLocalize(msg) : "";
1118
- catalogs[locale] = target;
1119
- return Object.keys(target).filter((key) => target[key]);
1120
- }
1121
- //#endregion
1122
1144
  //#region src/render.ts
1123
1145
  const HREFLANG_OPEN = "<!--verbaly:hreflang-->";
1124
1146
  const HREFLANG_CLOSE = "<!--/verbaly:hreflang-->";
@@ -1389,7 +1411,7 @@ function decodeEntities(text) {
1389
1411
  return text.replace(/&quot;/g, "\"").replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
1390
1412
  }
1391
1413
  //#endregion
1392
- //#region src/cli.ts
1414
+ //#region src/run.ts
1393
1415
  const HELP = `verbaly — i18n compiler
1394
1416
 
1395
1417
  Usage:
@@ -1410,7 +1432,7 @@ Options:
1410
1432
  --locales <csv> extra locales; for translate: target locales to fill
1411
1433
  --prune drop keys no longer referenced (extract)
1412
1434
  --model <id> model override for the claude provider (translate)
1413
- --dry-run list what would happen, write nothing (translate, import)
1435
+ --dry-run list what would happen, write nothing (translate, import, extract)
1414
1436
  --format <f> export format: xliff (default) or csv (export)
1415
1437
  --out <path> export directory (export, default: verbaly-export)
1416
1438
  --missing export only untranslated entries (export)
@@ -1425,8 +1447,9 @@ Options:
1425
1447
  Config file: verbaly.config.{js,mjs,ts,mts,json} at root (flags win).
1426
1448
  The claude provider needs @anthropic-ai/sdk installed and ANTHROPIC_API_KEY set.
1427
1449
  `;
1428
- async function main() {
1450
+ async function runCli(args = process.argv.slice(2)) {
1429
1451
  const { positionals, values } = parseArgs({
1452
+ args,
1430
1453
  allowPositionals: true,
1431
1454
  options: {
1432
1455
  root: { type: "string" },
@@ -1458,6 +1481,7 @@ async function main() {
1458
1481
  process.exitCode = command ? 0 : 1;
1459
1482
  return;
1460
1483
  }
1484
+ if (rejectStrayFlags(command, values)) return;
1461
1485
  if (command === "init") {
1462
1486
  const result = init({
1463
1487
  root: values.root,
@@ -1499,18 +1523,21 @@ async function main() {
1499
1523
  return;
1500
1524
  }
1501
1525
  if (command === "extract") {
1526
+ const dryRun = values["dry-run"];
1502
1527
  const registry = await extractProject(cfg);
1503
1528
  const catalogs = loadCatalogs(cfg);
1504
1529
  if (values.prune) {
1505
1530
  const removed = pruneCatalogs(cfg, catalogs, registry);
1506
- for (const [locale, keys] of Object.entries(removed)) console.log(` ${locale}: -${keys.length} pruned`);
1531
+ for (const [locale, keys] of Object.entries(removed)) console.log(dryRun ? ` ${locale}: would prune ${keys.length} — ${keys.join(", ")}` : ` ${locale}: -${keys.length} pruned`);
1507
1532
  }
1508
1533
  const { added } = syncCatalogs(cfg, catalogs, registry);
1509
- for (const locale of cfg.locales) writeCatalog(cfg, locale, catalogs[locale] ?? {});
1510
- writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));
1534
+ if (!dryRun) {
1535
+ for (const locale of cfg.locales) writeCatalog(cfg, locale, catalogs[locale] ?? {});
1536
+ writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));
1537
+ }
1511
1538
  const total = registry.messages().size;
1512
- console.log(`[verbaly] ${total} messages · locales: ${cfg.locales.join(", ")}`);
1513
- for (const [locale, keys] of Object.entries(added)) console.log(` ${locale}: +${keys.length}`);
1539
+ console.log(`[verbaly] ${total} messages · locales: ${cfg.locales.join(", ")}${dryRun ? " (dry run, nothing written)" : ""}`);
1540
+ for (const [locale, keys] of Object.entries(added)) console.log(` ${locale}: ${dryRun ? `would add ${keys.length}` : `+${keys.length}`}`);
1514
1541
  return;
1515
1542
  }
1516
1543
  if (command === "check") {
@@ -1617,17 +1644,61 @@ async function main() {
1617
1644
  console.error(`[verbaly] unknown command "${command}"\n${HELP}`);
1618
1645
  process.exitCode = 1;
1619
1646
  }
1647
+ const COMMON_FLAGS = /* @__PURE__ */ new Set([
1648
+ "root",
1649
+ "dir",
1650
+ "source",
1651
+ "locales",
1652
+ "help"
1653
+ ]);
1654
+ const COMMAND_FLAGS = {
1655
+ init: [],
1656
+ doctor: [],
1657
+ extract: ["prune", "dry-run"],
1658
+ check: [],
1659
+ translate: ["model", "dry-run"],
1660
+ export: [
1661
+ "format",
1662
+ "out",
1663
+ "missing"
1664
+ ],
1665
+ import: [
1666
+ "locale",
1667
+ "overwrite",
1668
+ "dry-run"
1669
+ ],
1670
+ pseudo: ["locale"],
1671
+ render: [
1672
+ "site",
1673
+ "attribute",
1674
+ "base-url",
1675
+ "sitemap",
1676
+ "clean"
1677
+ ]
1678
+ };
1679
+ function rejectStrayFlags(command, values) {
1680
+ const own = COMMAND_FLAGS[command];
1681
+ if (!own) return false;
1682
+ const allowed = /* @__PURE__ */ new Set([...COMMON_FLAGS, ...own]);
1683
+ const stray = Object.keys(values).filter((k) => values[k] !== void 0 && !allowed.has(k));
1684
+ if (stray.length === 0) return false;
1685
+ for (const flag of stray) console.error(`[verbaly] --${flag} is not a "${command}" flag${flag === "locale" ? " — did you mean --locales?" : ""}`);
1686
+ process.exitCode = 1;
1687
+ return true;
1688
+ }
1620
1689
  async function resolveProvider(cfg, model) {
1621
1690
  const configured = cfg.translate.provider;
1622
1691
  if (typeof configured === "function") return configured;
1623
- const { claudeProvider } = await import("./claude-Bi_Ex2hm.js");
1692
+ const { claudeProvider } = await import("./claude-mpjdqqnY.js");
1624
1693
  return claudeProvider({ model: model ?? cfg.translate.model });
1625
1694
  }
1626
- main().catch((error) => {
1695
+ //#endregion
1696
+ //#region src/cli.ts
1697
+ runCli().catch((error) => {
1627
1698
  console.error("[verbaly]", error instanceof Error ? error.message : error);
1628
1699
  process.exitCode = 1;
1629
1700
  });
1630
1701
  //#endregion
1631
- export {};
1702
+ export { isModuleNotFound as t };
1632
1703
 
1633
1704
  //# sourceMappingURL=cli.js.map