@mariokreitz/langsync 0.1.0 → 0.1.1

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,21 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import { logger } from '@langsync/shared/logger';
4
- import chalk3 from 'chalk';
3
+ import chalk from 'chalk';
5
4
  import ora from 'ora';
6
5
  import { relative, join, resolve, dirname } from 'path';
7
6
  import { readFile, mkdir, writeFile, access } from 'fs/promises';
8
- import '@langsync/shared/types';
9
7
  import prompts from 'prompts';
10
- import { loadConfig } from '@langsync/shared/config';
11
- import { loadLocaleFiles, writeJson } from '@langsync/shared/fs';
12
- import { syncTrees, validateLocales } from '@langsync/core';
13
- import { exportToExcel, importFromExcel } from '@langsync/excel-engine';
8
+ import { cosmiconfig } from 'cosmiconfig';
9
+ import { TypeScriptLoader } from 'cosmiconfig-typescript-loader';
10
+ import { z } from 'zod';
11
+ import ExcelJS from 'exceljs';
14
12
 
13
+ var PREFIX = chalk.bold.cyan("langsync");
14
+ var logger = {
15
+ info: (message) => console.log(`${PREFIX} ${chalk.blue("\u2139")} ${message}`),
16
+ success: (message) => console.log(`${PREFIX} ${chalk.green("\u2714")} ${message}`),
17
+ warn: (message) => console.warn(`${PREFIX} ${chalk.yellow("\u26A0")} ${message}`),
18
+ error: (message) => console.error(`${PREFIX} ${chalk.red("\u2716")} ${message}`),
19
+ debug: (message) => {
20
+ if (process.env.LANGSYNC_DEBUG) {
21
+ console.log(`${PREFIX} ${chalk.gray("\u2022")} ${chalk.gray(message)}`);
22
+ }
23
+ }
24
+ };
15
25
  function printBanner(version) {
16
- const title = chalk3.bold.cyan("LangSync");
17
- const tagline = chalk3.gray("Modern localization workflow tooling.");
18
- const ver = chalk3.dim(`v${version}`);
26
+ const title = chalk.bold.cyan("LangSync");
27
+ const tagline = chalk.gray("Modern localization workflow tooling.");
28
+ const ver = chalk.dim(`v${version}`);
19
29
  console.log(`
20
30
  ${title} ${ver}
21
31
  ${tagline}
@@ -26,7 +36,7 @@ function assertNodeVersion(minMajor) {
26
36
  const major = Number.parseInt(current.split(".")[0] ?? "0", 10);
27
37
  if (major < minMajor) {
28
38
  console.error(
29
- chalk3.red(
39
+ chalk.red(
30
40
  `langsync requires Node.js >= ${String(minMajor)}. You are running ${current}. Please upgrade.`
31
41
  )
32
42
  );
@@ -206,7 +216,7 @@ function registerInitCommand(program) {
206
216
  const detectSpinner = ora("Detecting i18n framework\u2026").start();
207
217
  const detectedFramework = await detectFramework(cwd);
208
218
  detectSpinner.succeed(
209
- detectedFramework ? `Detected ${chalk3.cyan(detectedFramework)}` : "No known framework detected"
219
+ detectedFramework ? `Detected ${chalk.cyan(detectedFramework)}` : "No known framework detected"
210
220
  );
211
221
  const answers = await runInitPrompts({
212
222
  detectedFramework,
@@ -221,12 +231,12 @@ function registerInitCommand(program) {
221
231
  });
222
232
  writeSpinner.succeed("Files written");
223
233
  console.log();
224
- logger.success(`Created ${chalk3.bold(relative(cwd, result.configPath))}`);
234
+ logger.success(`Created ${chalk.bold(relative(cwd, result.configPath))}`);
225
235
  for (const localeFile of result.createdLocaleFiles) {
226
- logger.success(`Created ${chalk3.bold(relative(cwd, localeFile))}`);
236
+ logger.success(`Created ${chalk.bold(relative(cwd, localeFile))}`);
227
237
  }
228
238
  console.log();
229
- logger.info(`Next: run ${chalk3.bold("langsync validate")} to check your locales.`);
239
+ logger.info(`Next: run ${chalk.bold("langsync validate")} to check your locales.`);
230
240
  } catch (error) {
231
241
  const message = error instanceof Error ? error.message : String(error);
232
242
  logger.error(message);
@@ -234,6 +244,131 @@ function registerInitCommand(program) {
234
244
  }
235
245
  });
236
246
  }
247
+ var LangSyncConfigSchema = z.object({
248
+ input: z.string().describe("Path to the source i18n directory."),
249
+ output: z.string().describe("Path to the output/translations directory."),
250
+ locales: z.array(z.string()).min(1).describe("List of supported locales."),
251
+ defaultLocale: z.string().optional(),
252
+ framework: z.enum(["i18next", "ngx-translate", "react-intl"]).optional().describe("i18n framework integration."),
253
+ excel: z.object({
254
+ file: z.string().default("translations.xlsx"),
255
+ sheetName: z.string().default("Translations")
256
+ }).optional()
257
+ });
258
+ async function loadConfig(cwd = process.cwd()) {
259
+ const explorer = cosmiconfig("langsync", {
260
+ searchPlaces: [
261
+ "langsync.config.ts",
262
+ "langsync.config.js",
263
+ "langsync.config.mjs",
264
+ "langsync.config.json",
265
+ ".langsyncrc",
266
+ ".langsyncrc.json",
267
+ "package.json"
268
+ ],
269
+ loaders: {
270
+ ".ts": TypeScriptLoader()
271
+ }
272
+ });
273
+ const result = await explorer.search(cwd);
274
+ if (!result) return null;
275
+ const parsed = LangSyncConfigSchema.parse(result.config);
276
+ return { config: parsed, filepath: result.filepath };
277
+ }
278
+ async function writeJson(filePath, data, { indent = 2 } = {}) {
279
+ const absolute = resolve(filePath);
280
+ await mkdir(dirname(absolute), { recursive: true });
281
+ await writeFile(absolute, JSON.stringify(data, null, indent) + "\n", "utf-8");
282
+ }
283
+ async function loadLocaleFiles(options) {
284
+ const inputAbs = resolve(options.cwd, options.inputDir);
285
+ const out = [];
286
+ for (const locale of options.locales) {
287
+ const path = join(inputAbs, `${locale}.json`);
288
+ let translations = {};
289
+ try {
290
+ const content = await readFile(path, "utf-8");
291
+ try {
292
+ translations = JSON.parse(content);
293
+ } catch (error) {
294
+ const message = error instanceof Error ? error.message : String(error);
295
+ throw new Error(`Failed to parse ${locale}.json: ${message}`, { cause: error });
296
+ }
297
+ } catch (error) {
298
+ const errno = error.code;
299
+ if (errno !== "ENOENT") throw error;
300
+ }
301
+ out.push({ locale, path, translations });
302
+ }
303
+ return out;
304
+ }
305
+
306
+ // ../core/dist/index.js
307
+ function flatten(tree, prefix = "") {
308
+ const out = {};
309
+ for (const [key, value] of Object.entries(tree)) {
310
+ const fullKey = prefix ? `${prefix}.${key}` : key;
311
+ if (typeof value === "string") {
312
+ out[fullKey] = value;
313
+ } else {
314
+ Object.assign(out, flatten(value, fullKey));
315
+ }
316
+ }
317
+ return out;
318
+ }
319
+ function unflatten(flat) {
320
+ const result = {};
321
+ for (const [key, value] of Object.entries(flat)) {
322
+ const parts = key.split(".");
323
+ let cursor = result;
324
+ for (let i = 0; i < parts.length - 1; i++) {
325
+ const part = parts[i];
326
+ const next = cursor[part];
327
+ if (typeof next !== "object" || next === null) {
328
+ const fresh = {};
329
+ cursor[part] = fresh;
330
+ cursor = fresh;
331
+ } else {
332
+ cursor = next;
333
+ }
334
+ }
335
+ cursor[parts[parts.length - 1]] = value;
336
+ }
337
+ return result;
338
+ }
339
+ function validateLocales(files, referenceLocale) {
340
+ const issues = [];
341
+ const reference = files.find((f) => f.locale === referenceLocale);
342
+ if (!reference) return issues;
343
+ const referenceKeys = new Set(Object.keys(flatten(reference.translations)));
344
+ for (const file of files) {
345
+ const flat = flatten(file.translations);
346
+ const fileKeys = new Set(Object.keys(flat));
347
+ if (file.locale !== referenceLocale) {
348
+ for (const key of referenceKeys) {
349
+ if (!fileKeys.has(key)) issues.push({ type: "missing", locale: file.locale, key });
350
+ }
351
+ for (const key of fileKeys) {
352
+ if (!referenceKeys.has(key)) issues.push({ type: "extra", locale: file.locale, key });
353
+ }
354
+ }
355
+ for (const [key, value] of Object.entries(flat)) {
356
+ if (!value || value.trim() === "") issues.push({ type: "empty", locale: file.locale, key });
357
+ }
358
+ }
359
+ return issues;
360
+ }
361
+ function syncTrees(source, target) {
362
+ const sourceFlat = flatten(source);
363
+ const targetFlat = flatten(target);
364
+ const merged = {};
365
+ for (const key of Object.keys(sourceFlat)) {
366
+ merged[key] = targetFlat[key] ?? "";
367
+ }
368
+ return unflatten(merged);
369
+ }
370
+
371
+ // src/commands/sync/run.ts
237
372
  async function runSync(options) {
238
373
  const loaded = await loadConfig(options.cwd);
239
374
  if (!loaded) {
@@ -275,11 +410,11 @@ function registerSyncCommand(program) {
275
410
  });
276
411
  const targets = flags.dryRun ? planned : written;
277
412
  if (targets.length === 0) {
278
- logger.info(`Nothing to sync against ${chalk3.cyan(referenceLocale)}.`);
413
+ logger.info(`Nothing to sync against ${chalk.cyan(referenceLocale)}.`);
279
414
  } else {
280
415
  const verb = flags.dryRun ? "Would update" : "Updated";
281
416
  for (const path of targets) {
282
- logger.success(`${verb} ${chalk3.bold(relative(cwd, path))}`);
417
+ logger.success(`${verb} ${chalk.bold(relative(cwd, path))}`);
283
418
  }
284
419
  }
285
420
  } catch (error) {
@@ -289,6 +424,8 @@ function registerSyncCommand(program) {
289
424
  }
290
425
  });
291
426
  }
427
+
428
+ // src/commands/validate/run.ts
292
429
  async function runValidate(options) {
293
430
  const loaded = await loadConfig(options.cwd);
294
431
  if (!loaded) {
@@ -319,13 +456,13 @@ function registerValidateCommand(program) {
319
456
  console.log(JSON.stringify({ referenceLocale, issues }, null, 2));
320
457
  } else {
321
458
  if (issues.length === 0) {
322
- logger.success(`All locales are consistent with ${chalk3.cyan(referenceLocale)}.`);
459
+ logger.success(`All locales are consistent with ${chalk.cyan(referenceLocale)}.`);
323
460
  } else {
324
461
  const byType = { missing: 0, extra: 0, empty: 0 };
325
462
  for (const issue of issues) {
326
463
  byType[issue.type]++;
327
- const colored = issue.type === "empty" ? chalk3.yellow(issue.type) : chalk3.red(issue.type);
328
- logger.info(`${colored} ${chalk3.cyan(issue.locale)} ${issue.key}`);
464
+ const colored = issue.type === "empty" ? chalk.yellow(issue.type) : chalk.red(issue.type);
465
+ logger.info(`${colored} ${chalk.cyan(issue.locale)} ${issue.key}`);
329
466
  }
330
467
  console.log();
331
468
  logger.info(
@@ -367,10 +504,10 @@ function registerFindMissingCommand(program) {
367
504
  if (flags.reporter === "json") {
368
505
  console.log(JSON.stringify({ referenceLocale, missingByLocale }, null, 2));
369
506
  } else if (Object.keys(missingByLocale).length === 0) {
370
- logger.success(`No missing keys relative to ${chalk3.cyan(referenceLocale)}.`);
507
+ logger.success(`No missing keys relative to ${chalk.cyan(referenceLocale)}.`);
371
508
  } else {
372
509
  for (const [locale, keys] of Object.entries(missingByLocale)) {
373
- logger.warn(`${chalk3.cyan(locale)} is missing ${keys.length} key(s):`);
510
+ logger.warn(`${chalk.cyan(locale)} is missing ${keys.length} key(s):`);
374
511
  for (const key of keys) console.log(` - ${key}`);
375
512
  }
376
513
  }
@@ -382,6 +519,51 @@ function registerFindMissingCommand(program) {
382
519
  }
383
520
  });
384
521
  }
522
+ async function exportToExcel(options) {
523
+ const workbook = new ExcelJS.Workbook();
524
+ const sheet = workbook.addWorksheet(options.sheetName ?? "Translations");
525
+ const localeKeys = options.locales.map((l) => l.locale);
526
+ sheet.addRow(["key", ...localeKeys]);
527
+ const allKeys = /* @__PURE__ */ new Set();
528
+ const flatPerLocale = options.locales.map((l) => flatten(l.translations));
529
+ for (const flat of flatPerLocale) {
530
+ for (const k of Object.keys(flat)) allKeys.add(k);
531
+ }
532
+ for (const key of [...allKeys].sort()) {
533
+ sheet.addRow([key, ...flatPerLocale.map((flat) => flat[key] ?? "")]);
534
+ }
535
+ sheet.getRow(1).font = { bold: true };
536
+ await workbook.xlsx.writeFile(options.file);
537
+ }
538
+ async function importFromExcel(file, sheetName) {
539
+ const workbook = new ExcelJS.Workbook();
540
+ await workbook.xlsx.readFile(file);
541
+ const sheet = sheetName ? workbook.getWorksheet(sheetName) : workbook.worksheets[0];
542
+ if (!sheet) throw new Error(`Worksheet not found: ${sheetName ?? "<first>"}`);
543
+ const header = sheet.getRow(1).values;
544
+ const locales = header.slice(2).filter((v) => typeof v === "string");
545
+ const flatPerLocale = Object.fromEntries(
546
+ locales.map((l) => [l, {}])
547
+ );
548
+ sheet.eachRow({ includeEmpty: false }, (row, rowNumber) => {
549
+ if (rowNumber === 1) return;
550
+ const values = row.values;
551
+ const key = values[1];
552
+ if (!key) return;
553
+ locales.forEach((locale, idx) => {
554
+ const value = values[idx + 2];
555
+ flatPerLocale[locale][key] = typeof value === "string" ? value : "";
556
+ });
557
+ });
558
+ return {
559
+ locales: locales.map((locale) => ({
560
+ locale,
561
+ translations: unflatten(flatPerLocale[locale])
562
+ }))
563
+ };
564
+ }
565
+
566
+ // src/commands/export/run.ts
385
567
  var DEFAULT_FILE = "translations.xlsx";
386
568
  var DEFAULT_SHEET = "Translations";
387
569
  async function runExportExcel(options) {
@@ -417,7 +599,7 @@ function registerExportCommand(program) {
417
599
  sheetName: flags.sheet
418
600
  });
419
601
  logger.success(
420
- `Exported ${chalk3.cyan(String(locales.length))} locale(s) to ${chalk3.bold(
602
+ `Exported ${chalk.cyan(String(locales.length))} locale(s) to ${chalk.bold(
421
603
  relative(cwd, file)
422
604
  )}`
423
605
  );
@@ -474,10 +656,10 @@ function registerImportCommand(program) {
474
656
  const targets = flags.dryRun ? planned : written;
475
657
  const verb = flags.dryRun ? "Would write" : "Wrote";
476
658
  for (const path of targets) {
477
- logger.success(`${verb} ${chalk3.bold(relative(cwd, path))}`);
659
+ logger.success(`${verb} ${chalk.bold(relative(cwd, path))}`);
478
660
  }
479
661
  for (const locale of skipped) {
480
- logger.warn(`Skipped ${chalk3.cyan(locale)} (not in configured locales).`);
662
+ logger.warn(`Skipped ${chalk.cyan(locale)} (not in configured locales).`);
481
663
  }
482
664
  } catch (error) {
483
665
  const message = error instanceof Error ? error.message : String(error);
@@ -508,5 +690,3 @@ main().catch((error) => {
508
690
  logger.error(message);
509
691
  process.exit(1);
510
692
  });
511
- //# sourceMappingURL=cli.js.map
512
- //# sourceMappingURL=cli.js.map
package/dist/index.js CHANGED
@@ -1,4 +1,21 @@
1
1
  #!/usr/bin/env node
2
- export { defineConfig } from '@langsync/shared/config';
3
- //# sourceMappingURL=index.js.map
4
- //# sourceMappingURL=index.js.map
2
+ import 'cosmiconfig';
3
+ import 'cosmiconfig-typescript-loader';
4
+ import { z } from 'zod';
5
+
6
+ z.object({
7
+ input: z.string().describe("Path to the source i18n directory."),
8
+ output: z.string().describe("Path to the output/translations directory."),
9
+ locales: z.array(z.string()).min(1).describe("List of supported locales."),
10
+ defaultLocale: z.string().optional(),
11
+ framework: z.enum(["i18next", "ngx-translate", "react-intl"]).optional().describe("i18n framework integration."),
12
+ excel: z.object({
13
+ file: z.string().default("translations.xlsx"),
14
+ sheetName: z.string().default("Translations")
15
+ }).optional()
16
+ });
17
+ function defineConfig(config) {
18
+ return config;
19
+ }
20
+
21
+ export { defineConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mariokreitz/langsync",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Modern localization workflow tooling for TypeScript applications.",
5
5
  "keywords": [
6
6
  "i18n",
@@ -50,16 +50,20 @@
50
50
  "dependencies": {
51
51
  "chalk": "^5.3.0",
52
52
  "commander": "^12.1.0",
53
+ "cosmiconfig": "^9.0.0",
54
+ "cosmiconfig-typescript-loader": "^6.1.0",
55
+ "exceljs": "^4.4.0",
53
56
  "listr2": "^8.2.5",
54
57
  "ora": "^8.1.1",
55
58
  "prompts": "^2.4.2",
56
- "@langsync/shared": "0.1.0",
57
- "@langsync/excel-engine": "0.1.0",
58
- "@langsync/core": "0.1.0"
59
+ "zod": "^3.24.1"
59
60
  },
60
61
  "devDependencies": {
61
62
  "@types/prompts": "^2.4.9",
62
- "memfs": "^4.15.1"
63
+ "memfs": "^4.15.1",
64
+ "@langsync/core": "0.1.0",
65
+ "@langsync/excel-engine": "0.1.0",
66
+ "@langsync/shared": "0.1.0"
63
67
  },
64
68
  "scripts": {
65
69
  "build": "tsup",
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ui/banner.ts","../src/ui/node-version.ts","../src/commands/init/detect-framework.ts","../src/commands/init/prompt.ts","../src/commands/init/write-config.ts","../src/commands/init.ts","../src/commands/sync/run.ts","../src/commands/sync.ts","../src/commands/validate/run.ts","../src/commands/validate.ts","../src/commands/find-missing/run.ts","../src/commands/find-missing.ts","../src/commands/export/run.ts","../src/commands/export.ts","../src/commands/import/run.ts","../src/commands/import.ts","../src/cli.ts"],"names":["chalk","join","logger","relative","loadConfig","loadLocaleFiles","resolve","DEFAULT_FILE","DEFAULT_SHEET","writeJson"],"mappings":";;;;;;;;;;;;;;AAEO,SAAS,YAAY,OAAA,EAAuB;AACjD,EAAA,MAAM,KAAA,GAAQA,MAAA,CAAM,IAAA,CAAK,IAAA,CAAK,UAAU,CAAA;AACxC,EAAA,MAAM,OAAA,GAAUA,MAAA,CAAM,IAAA,CAAK,uCAAuC,CAAA;AAClE,EAAA,MAAM,GAAA,GAAMA,MAAA,CAAM,GAAA,CAAI,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAA;AACnC,EAAA,OAAA,CAAQ,GAAA,CAAI;AAAA,EAAA,EAAO,KAAK,KAAK,GAAG;AAAA,EAAA,EAAO,OAAO;AAAA,CAAI,CAAA;AACpD;ACLO,SAAS,kBAAkB,QAAA,EAAwB;AACxD,EAAA,MAAM,OAAA,GAAU,QAAQ,QAAA,CAAS,IAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,GAAA,EAAK,EAAE,CAAA;AAC9D,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,OAAA,CAAQ,KAAA;AAAA,MACNA,MAAAA,CAAM,GAAA;AAAA,QACJ,CAAA,6BAAA,EAAgC,MAAA,CAAO,QAAQ,CAAC,qBAC3B,OAAO,CAAA,iBAAA;AAAA;AAC9B,KACF;AACA,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF;ACJA,IAAM,oBAAA,GAGA;AAAA,EACJ,EAAE,WAAW,SAAA,EAAW,QAAA,EAAU,CAAC,SAAA,EAAW,eAAA,EAAiB,aAAa,CAAA,EAAE;AAAA,EAC9E,EAAE,SAAA,EAAW,eAAA,EAAiB,UAAU,CAAC,qBAAA,EAAuB,4BAA4B,CAAA,EAAE;AAAA,EAC9F,EAAE,SAAA,EAAW,YAAA,EAAc,UAAU,CAAC,YAAA,EAAc,gBAAgB,CAAA;AACtE,CAAA;AAMA,eAAsB,gBAAgB,GAAA,EAA4C;AAChF,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAK,cAAc,CAAA;AACxC,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,KAAK,KAAA,CAAM,MAAM,QAAA,CAAS,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,EACnD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,GAAG,GAAA,CAAI,YAAA;AAAA,IACP,GAAG,GAAA,CAAI,eAAA;AAAA,IACP,GAAG,GAAA,CAAI;AAAA,GACT;AAEA,EAAA,KAAA,MAAW,EAAE,SAAA,EAAW,QAAA,EAAS,IAAK,oBAAA,EAAsB;AAC1D,IAAA,IAAI,SAAS,IAAA,CAAK,CAAC,MAAM,CAAA,IAAK,OAAO,GAAG,OAAO,SAAA;AAAA,EACjD;AACA,EAAA,OAAO,IAAA;AACT;ACzBA,IAAM,iBAAA,GAAoB;AAAA,EACxB,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,SAAA,EAAmB;AAAA,EAC9C,EAAE,KAAA,EAAO,yBAAA,EAA2B,KAAA,EAAO,eAAA,EAAyB;AAAA,EACpE,EAAE,KAAA,EAAO,YAAA,EAAc,KAAA,EAAO,YAAA,EAAsB;AAAA,EACpD,EAAE,KAAA,EAAO,eAAA,EAAiB,KAAA,EAAO,MAAA;AACnC,CAAA;AAEA,IAAM,QAAA,GAAW;AAAA,EACf,KAAA,EAAO,YAAA;AAAA,EACP,MAAA,EAAQ,gBAAA;AAAA,EACR,OAAA,EAAS,OAAA;AAAA,EACT,aAAA,EAAe;AACjB,CAAA;AAEA,eAAsB,eAAe,OAAA,EAAkD;AACrF,EAAA,MAAM,SAAA,GAAsC,QAAQ,iBAAA,IAAqB,MAAA;AAEzE,EAAA,IAAI,QAAQ,GAAA,EAAK;AACf,IAAA,OAAO;AAAA,MACL,OAAO,QAAA,CAAS,KAAA;AAAA,MAChB,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AAAA,MACxD,eAAe,QAAA,CAAS,aAAA;AAAA,MACxB;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,MAAM,OAAA;AAAA,IACrB;AAAA,MACE;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,IAAA,EAAM,OAAA;AAAA,QACN,OAAA,EAAS,mCAAA;AAAA,QACT,SAAS,QAAA,CAAS;AAAA,OACpB;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,IAAA,EAAM,QAAA;AAAA,QACN,OAAA,EAAS,qCAAA;AAAA,QACT,SAAS,QAAA,CAAS;AAAA,OACpB;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,IAAA,EAAM,SAAA;AAAA,QACN,OAAA,EAAS,kCAAA;AAAA,QACT,SAAS,QAAA,CAAS,OAAA;AAAA,QAClB,MAAA,EAAQ,CAAC,KAAA,KACP,KAAA,CACG,MAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CACnB,OAAO,OAAO,CAAA;AAAA,QACnB,QAAA,EAAU,CAAC,KAAA,KAAkB;AAC3B,UAAA,MAAM,IAAA,GAAO,KAAA,CACV,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CACnB,OAAO,OAAO,CAAA;AACjB,UAAA,OAAO,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,IAAA,GAAO,qCAAA;AAAA,QAClC;AAAA,OACF;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,IAAA,EAAM,eAAA;AAAA,QACN,OAAA,EAAS,6BAAA;AAAA,QACT,SAAS,QAAA,CAAS;AAAA,OACpB;AAAA,MACA;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,EAAS,kCAAA;AAAA,QACT,OAAA,EAAS,iBAAA;AAAA,QACT,SAAS,iBAAA,CAAkB,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,SAAS;AAAA;AACnE,KACF;AAAA,IACA;AAAA,MACE,UAAU,MAAM;AACd,QAAA,MAAM,IAAI,MAAM,kBAAkB,CAAA;AAAA,MACpC;AAAA;AACF,GACF;AAIA,EAAA,OAAO,QAAA;AACT;AClFA,IAAM,sBAAA,GAAyB;AAAA,EAC7B,oBAAA;AAAA,EACA,oBAAA;AAAA,EACA,qBAAA;AAAA,EACA;AACF,CAAA;AAEA,eAAe,WAAW,CAAA,EAA6B;AACrD,EAAA,IAAI;AACF,IAAA,MAAM,OAAO,CAAC,CAAA;AACd,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,eAAe,mBAAmB,GAAA,EAAqC;AACrE,EAAA,KAAA,MAAW,QAAQ,sBAAA,EAAwB;AACzC,IAAA,MAAM,IAAA,GAAOC,IAAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAC3B,IAAA,IAAI,MAAM,UAAA,CAAW,IAAI,CAAA,EAAG,OAAO,IAAA;AAAA,EACrC;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,eAAe,OAAA,EAA8B;AACpD,EAAA,MAAM,gBACJ,OAAA,CAAQ,SAAA,KAAc,SAAS,EAAA,GAAK,CAAA,cAAA,EAAiB,QAAQ,SAAS,CAAA;AAAA,CAAA;AACxE,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AACjE,EAAA,OAAO,CAAA;;AAAA;AAAA,UAAA,EAGG,QAAQ,KAAK,CAAA;AAAA,WAAA,EACZ,QAAQ,MAAM,CAAA;AAAA,YAAA,EACb,UAAU,CAAA;AAAA,kBAAA,EACJ,QAAQ,aAAa,CAAA;AAAA,EACvC,aAAa,CAAA;AAAA,CAAA;AAEf;AAEA,SAAS,iBAAiB,OAAA,EAA8B;AACtD,EAAA,MAAM,GAAA,GAA+B;AAAA,IACnC,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,QAAQ,OAAA,CAAQ,MAAA;AAAA,IAChB,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,eAAe,OAAA,CAAQ;AAAA,GACzB;AACA,EAAA,IAAI,OAAA,CAAQ,SAAA,KAAc,MAAA,EAAQ,GAAA,CAAI,YAAY,OAAA,CAAQ,SAAA;AAC1D,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA;AACxC;AAMA,eAAsB,YAAY,OAAA,EAAyD;AACzF,EAAA,MAAM,EAAE,GAAA,EAAK,OAAA,EAAS,MAAA,EAAQ,OAAM,GAAI,OAAA;AAExC,EAAA,MAAM,QAAA,GAAW,MAAM,kBAAA,CAAmB,GAAG,CAAA;AAC7C,EAAA,IAAI,QAAA,IAAY,CAAC,KAAA,EAAO;AACtB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,uCAAuC,QAAQ,CAAA,mCAAA;AAAA,KACjD;AAAA,EACF;AAEA,EAAA,MAAM,cAAA,GAAiB,MAAA,KAAW,IAAA,GAAO,oBAAA,GAAuB,sBAAA;AAChE,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,GAAA,EAAK,cAAc,CAAA;AAC9C,EAAA,MAAM,UAAU,MAAA,KAAW,IAAA,GAAO,eAAe,OAAO,CAAA,GAAI,iBAAiB,OAAO,CAAA;AAEpF,EAAA,MAAM,MAAM,OAAA,CAAQ,UAAU,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AACpD,EAAA,MAAM,SAAA,CAAU,UAAA,EAAY,OAAA,EAAS,OAAO,CAAA;AAG5C,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,EAAK,OAAA,CAAQ,KAAK,CAAA;AAC3C,EAAA,MAAM,KAAA,CAAM,QAAA,EAAU,EAAE,SAAA,EAAW,MAAM,CAAA;AACzC,EAAA,MAAM,qBAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,MAAA,IAAU,QAAQ,OAAA,EAAS;AACpC,IAAA,MAAM,UAAA,GAAaA,IAAAA,CAAK,QAAA,EAAU,CAAA,EAAG,MAAM,CAAA,KAAA,CAAO,CAAA;AAClD,IAAA,IAAI,CAAE,MAAM,UAAA,CAAW,UAAU,CAAA,EAAI;AACnC,MAAA,MAAM,SAAA,CAAU,UAAA,EAAY,MAAA,EAAQ,OAAO,CAAA;AAC3C,MAAA,kBAAA,CAAmB,KAAK,UAAU,CAAA;AAAA,IACpC;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,YAAY,kBAAA,EAAmB;AAC1C;;;ACvFO,SAAS,oBAAoB,OAAA,EAAwB;AAC1D,EAAA,OAAA,CACG,OAAA,CAAQ,MAAM,CAAA,CACd,WAAA,CAAY,iEAAiE,CAAA,CAC7E,MAAA,CAAO,SAAA,EAAW,mDAAA,EAAqD,KAAK,CAAA,CAC5E,OAAO,QAAA,EAAU,0DAAA,EAA4D,KAAK,CAAA,CAClF,MAAA,CAAO,WAAA,EAAa,sCAAsC,KAAK,CAAA,CAC/D,MAAA,CAAO,OAAO,KAAA,KAAqB;AAClC,IAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,IAAA,MAAM,MAAA,GAAuB,KAAA,CAAM,IAAA,GAAO,MAAA,GAAS,IAAA;AAEnD,IAAA,IAAI;AACF,MAAA,MAAM,aAAA,GAAgB,GAAA,CAAI,gCAA2B,CAAA,CAAE,KAAA,EAAM;AAC7D,MAAA,MAAM,iBAAA,GAAoB,MAAM,eAAA,CAAgB,GAAG,CAAA;AACnD,MAAA,aAAA,CAAc,OAAA;AAAA,QACZ,oBACI,CAAA,SAAA,EAAYD,MAAAA,CAAM,IAAA,CAAK,iBAAiB,CAAC,CAAA,CAAA,GACzC;AAAA,OACN;AAGA,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,CAAe;AAAA,QACnC,iBAAA;AAAA,QACA,KAAK,KAAA,CAAM;AAAA,OACZ,CAAA;AAED,MAAA,MAAM,YAAA,GAAe,GAAA,CAAI,mDAA8C,CAAA,CAAE,KAAA,EAAM;AAC/E,MAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY;AAAA,QAC/B,GAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,OAAO,KAAA,CAAM;AAAA,OACd,CAAA;AACD,MAAA,YAAA,CAAa,QAAQ,eAAe,CAAA;AAEpC,MAAA,OAAA,CAAQ,GAAA,EAAI;AACZ,MAAA,MAAA,CAAO,OAAA,CAAQ,CAAA,QAAA,EAAWA,MAAAA,CAAM,IAAA,CAAK,QAAA,CAAS,KAAK,MAAA,CAAO,UAAU,CAAC,CAAC,CAAA,CAAE,CAAA;AACxE,MAAA,KAAA,MAAW,UAAA,IAAc,OAAO,kBAAA,EAAoB;AAClD,QAAA,MAAA,CAAO,OAAA,CAAQ,WAAWA,MAAAA,CAAM,IAAA,CAAK,SAAS,GAAA,EAAK,UAAU,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,MACnE;AACA,MAAA,OAAA,CAAQ,GAAA,EAAI;AACZ,MAAA,MAAA,CAAO,KAAK,CAAA,UAAA,EAAaA,MAAAA,CAAM,IAAA,CAAK,mBAAmB,CAAC,CAAA,uBAAA,CAAyB,CAAA;AAAA,IACnF,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,MAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,IACrB;AAAA,EACF,CAAC,CAAA;AACL;AC5CA,eAAsB,QAAQ,OAAA,EAAiD;AAC7E,EAAA,MAAM,MAAA,GAAS,MAAM,UAAA,CAAW,OAAA,CAAQ,GAAG,CAAA;AAC3C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,EACxE;AACA,EAAA,MAAM,EAAE,QAAO,GAAI,MAAA;AACnB,EAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,aAAA,IAAiB,MAAA,CAAO,QAAQ,CAAC,CAAA;AAEhE,EAAA,MAAM,KAAA,GAAQ,MAAM,eAAA,CAAgB;AAAA,IAClC,KAAK,OAAA,CAAQ,GAAA;AAAA,IACb,UAAU,MAAA,CAAO,KAAA;AAAA,IACjB,SAAS,MAAA,CAAO;AAAA,GACjB,CAAA;AAED,EAAA,MAAM,YAAY,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,eAAe,CAAA;AAChE,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0CAAA,EAA6C,eAAe,CAAA,EAAA,CAAI,CAAA;AAAA,EAClF;AAEA,EAAA,MAAM,UAAU,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,eAAe,CAAA;AAChE,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,UAAoB,EAAC;AAE3B,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,MAAM,MAAA,GAAS,SAAA,CAAU,SAAA,CAAU,YAAA,EAAc,OAAO,YAAY,CAAA;AACpE,IAAA,OAAA,CAAQ,IAAA,CAAK,OAAO,IAAI,CAAA;AACxB,IAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,MAAA,MAAM,SAAA,CAAU,MAAA,CAAO,IAAA,EAAM,MAAM,CAAA;AACnC,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,eAAA,EAAiB,OAAA,EAAS,OAAA,EAAQ;AAC7C;;;AC1CO,SAAS,oBAAoB,OAAA,EAAwB;AAC1D,EAAA,OAAA,CACG,OAAA,CAAQ,MAAM,CAAA,CACd,WAAA,CAAY,6DAA6D,CAAA,CACzE,MAAA,CAAO,WAAA,EAAa,+CAAA,EAAiD,KAAK,CAAA,CAC1E,MAAA,CAAO,OAAO,KAAA,KAAqB;AAClC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,MAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAS,eAAA,EAAgB,GAAI,MAAM,OAAA,CAAQ;AAAA,QAC1D,GAAA;AAAA,QACA,QAAQ,KAAA,CAAM;AAAA,OACf,CAAA;AAED,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,MAAA,GAAS,OAAA,GAAU,OAAA;AACzC,MAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,QAAAE,OAAO,IAAA,CAAK,CAAA,wBAAA,EAA2BF,OAAM,IAAA,CAAK,eAAe,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,MACvE,CAAA,MAAO;AACL,QAAA,MAAM,IAAA,GAAO,KAAA,CAAM,MAAA,GAAS,cAAA,GAAiB,SAAA;AAC7C,QAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,UAAAE,MAAAA,CAAO,OAAA,CAAQ,CAAA,EAAG,IAAI,CAAA,CAAA,EAAIF,MAAAA,CAAM,IAAA,CAAKG,QAAAA,CAAS,GAAA,EAAK,IAAI,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,QAC7D;AAAA,MACF;AAAA,IACF,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,MAAAD,MAAAA,CAAO,MAAM,OAAO,CAAA;AACpB,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,IACrB;AAAA,EACF,CAAC,CAAA;AACL;AClBA,eAAsB,YAAY,OAAA,EAAyD;AACzF,EAAA,MAAM,MAAA,GAAS,MAAME,UAAAA,CAAW,OAAA,CAAQ,GAAG,CAAA;AAC3C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,EACxE;AAEA,EAAA,MAAM,EAAE,QAAO,GAAI,MAAA;AACnB,EAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,aAAA,IAAiB,MAAA,CAAO,QAAQ,CAAC,CAAA;AAEhE,EAAA,MAAM,KAAA,GAAQ,MAAMC,eAAAA,CAAgB;AAAA,IAClC,KAAK,OAAA,CAAQ,GAAA;AAAA,IACb,UAAU,MAAA,CAAO,KAAA;AAAA,IACjB,SAAS,MAAA,CAAO;AAAA,GACjB,CAAA;AAED,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,KAAA,EAAO,eAAe,CAAA;AACrD,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,SAAA,IAAa,CAAA,CAAE,IAAA,KAAS,OAAO,CAAA;AAE/E,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA,EAAU,YAAY,CAAA,GAAI;AAAA,GAC5B;AACF;;;AClCO,SAAS,wBAAwB,OAAA,EAAwB;AAC9D,EAAA,OAAA,CACG,OAAA,CAAQ,UAAU,CAAA,CAClB,WAAA,CAAY,0DAA0D,CAAA,CACtE,MAAA,CAAO,mBAAA,EAAqB,+BAAA,EAAiC,QAAQ,CAAA,CACrE,MAAA,CAAO,OAAO,KAAA,KAAyB;AACtC,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,eAAA,EAAgB,GAAI,MAAM,WAAA,CAAY,EAAE,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAI,EAAG,CAAA;AAEtF,MAAA,IAAI,KAAA,CAAM,aAAa,MAAA,EAAQ;AAC7B,QAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,SAAA,CAAU,EAAE,iBAAiB,MAAA,EAAO,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,MAClE,CAAA,MAAO;AACL,QAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,UAAAH,OAAO,OAAA,CAAQ,CAAA,gCAAA,EAAmCF,OAAM,IAAA,CAAK,eAAe,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,QAClF,CAAA,MAAO;AACL,UAAA,MAAM,SAAS,EAAE,OAAA,EAAS,GAAG,KAAA,EAAO,CAAA,EAAG,OAAO,CAAA,EAAE;AAChD,UAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,YAAA,MAAA,CAAO,MAAM,IAAI,CAAA,EAAA;AACjB,YAAA,MAAM,OAAA,GACJ,KAAA,CAAM,IAAA,KAAS,OAAA,GAAUA,MAAAA,CAAM,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,GAAIA,MAAAA,CAAM,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA;AAC1E,YAAAE,MAAAA,CAAO,IAAA,CAAK,CAAA,EAAG,OAAO,CAAA,EAAA,EAAKF,MAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,GAAG,CAAA,CAAE,CAAA;AAAA,UACrE;AACA,UAAA,OAAA,CAAQ,GAAA,EAAI;AACZ,UAAAE,MAAAA,CAAO,IAAA;AAAA,YACL,CAAA,SAAA,EAAY,OAAO,OAAO,CAAA,UAAA,EAAa,OAAO,KAAK,CAAA,QAAA,EAAW,OAAO,KAAK,CAAA,MAAA;AAAA,WAC5E;AAAA,QACF;AAAA,MACF;AAEA,MAAA,OAAA,CAAQ,QAAA,GAAW,QAAA;AAAA,IACrB,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,MAAAA,MAAAA,CAAO,MAAM,OAAO,CAAA;AACpB,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,IACrB;AAAA,EACF,CAAC,CAAA;AACL;;;AC9BA,eAAsB,eACpB,OAAA,EAC+B;AAC/B,EAAA,MAAM,EAAE,MAAA,EAAQ,eAAA,EAAgB,GAAI,MAAM,YAAY,EAAE,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,CAAA;AAE1E,EAAA,MAAM,kBAA4C,EAAC;AACnD,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAI,KAAA,CAAM,SAAS,SAAA,EAAW;AAC9B,IAAA,CAAC,eAAA,CAAgB,MAAM,MAAM,CAAA,KAAM,EAAC,EAAG,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvD;AACA,EAAA,KAAA,MAAW,MAAA,IAAU,MAAA,CAAO,IAAA,CAAK,eAAe,CAAA,EAAG;AACjD,IAAA,eAAA,CAAgB,MAAM,EAAG,IAAA,EAAK;AAAA,EAChC;AAEA,EAAA,MAAM,WAAkB,MAAA,CAAO,IAAA,CAAK,eAAe,CAAA,CAAE,MAAA,KAAW,IAAI,CAAA,GAAI,CAAA;AACxE,EAAA,OAAO,EAAE,eAAA,EAAiB,eAAA,EAAiB,QAAA,EAAS;AACtD;;;ACtBO,SAAS,2BAA2B,OAAA,EAAwB;AACjE,EAAA,OAAA,CACG,OAAA,CAAQ,cAAc,CAAA,CACtB,WAAA,CAAY,+CAA+C,CAAA,CAC3D,MAAA,CAAO,mBAAA,EAAqB,+BAAA,EAAiC,QAAQ,CAAA,CACrE,MAAA,CAAO,OAAO,KAAA,KAA4B;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,eAAA,EAAiB,eAAA,EAAiB,QAAA,EAAS,GAAI,MAAM,cAAA,CAAe;AAAA,QAC1E,GAAA,EAAK,QAAQ,GAAA;AAAI,OAClB,CAAA;AAED,MAAA,IAAI,KAAA,CAAM,aAAa,MAAA,EAAQ;AAC7B,QAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,SAAA,CAAU,EAAE,iBAAiB,eAAA,EAAgB,EAAG,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,MAC3E,WAAW,MAAA,CAAO,IAAA,CAAK,eAAe,CAAA,CAAE,WAAW,CAAA,EAAG;AACpD,QAAAA,OAAO,OAAA,CAAQ,CAAA,4BAAA,EAA+BF,OAAM,IAAA,CAAK,eAAe,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,MAC9E,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,EAAG;AAC5D,UAAAE,MAAAA,CAAO,IAAA,CAAK,CAAA,EAAGF,MAAAA,CAAM,IAAA,CAAK,MAAM,CAAC,CAAA,YAAA,EAAe,IAAA,CAAK,MAAM,CAAA,QAAA,CAAU,CAAA;AACrE,UAAA,KAAA,MAAW,OAAO,IAAA,EAAM,OAAA,CAAQ,GAAA,CAAI,CAAA,IAAA,EAAO,GAAG,CAAA,CAAE,CAAA;AAAA,QAClD;AAAA,MACF;AAEA,MAAA,OAAA,CAAQ,QAAA,GAAW,QAAA;AAAA,IACrB,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,MAAAE,MAAAA,CAAO,MAAM,OAAO,CAAA;AACpB,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,IACrB;AAAA,EACF,CAAC,CAAA;AACL;ACnBA,IAAM,YAAA,GAAe,mBAAA;AACrB,IAAM,aAAA,GAAgB,cAAA;AAKtB,eAAsB,eACpB,OAAA,EAC+B;AAC/B,EAAA,MAAM,MAAA,GAAS,MAAME,UAAAA,CAAW,OAAA,CAAQ,GAAG,CAAA;AAC3C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,EACxE;AACA,EAAA,MAAM,EAAE,QAAO,GAAI,MAAA;AAEnB,EAAA,MAAM,IAAA,GAAOE,QAAQ,OAAA,CAAQ,GAAA,EAAK,QAAQ,IAAA,IAAQ,MAAA,CAAO,KAAA,EAAO,IAAA,IAAQ,YAAY,CAAA;AACpF,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA,IAAa,MAAA,CAAO,OAAO,SAAA,IAAa,aAAA;AAElE,EAAA,MAAM,KAAA,GAAQ,MAAMD,eAAAA,CAAgB;AAAA,IAClC,KAAK,OAAA,CAAQ,GAAA;AAAA,IACb,UAAU,MAAA,CAAO,KAAA;AAAA,IACjB,SAAS,MAAA,CAAO;AAAA,GACjB,CAAA;AAED,EAAA,MAAM,aAAA,CAAc;AAAA,IAClB,IAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAA,EAAS,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,YAAA,EAAc,CAAA,CAAE,YAAA,EAAa,CAAE;AAAA,GAC/E,CAAA;AAED,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,CAAA,EAAE;AAChE;;;ACvCO,SAAS,sBAAsB,OAAA,EAAwB;AAC5D,EAAA,MAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA,CAAE,YAAY,0CAA0C,CAAA;AAE5F,EAAA,GAAA,CACG,QAAQ,OAAO,CAAA,CACf,WAAA,CAAY,2CAA2C,EACvD,MAAA,CAAO,eAAA,EAAiB,uCAAuC,CAAA,CAC/D,OAAO,gBAAA,EAAkB,oCAAoC,CAAA,CAC7D,MAAA,CAAO,OAAO,KAAA,KAA4B;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,MAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAI,MAAM,cAAA,CAAe;AAAA,QAC7C,GAAA;AAAA,QACA,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,WAAW,KAAA,CAAM;AAAA,OAClB,CAAA;AACD,MAAAH,MAAAA,CAAO,OAAA;AAAA,QACL,CAAA,SAAA,EAAYF,OAAM,IAAA,CAAK,MAAA,CAAO,QAAQ,MAAM,CAAC,CAAC,CAAA,cAAA,EAAiBA,MAAAA,CAAM,IAAA;AAAA,UACnEG,QAAAA,CAAS,KAAK,IAAI;AAAA,SACnB,CAAA;AAAA,OACH;AAAA,IACF,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,MAAAD,MAAAA,CAAO,MAAM,OAAO,CAAA;AACpB,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,IACrB;AAAA,EACF,CAAC,CAAA;AACL;AClBA,IAAMK,aAAAA,GAAe,mBAAA;AACrB,IAAMC,cAAAA,GAAgB,cAAA;AAMtB,eAAsB,eACpB,OAAA,EAC+B;AAC/B,EAAA,MAAM,MAAA,GAAS,MAAMJ,UAAAA,CAAW,OAAA,CAAQ,GAAG,CAAA;AAC3C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,EACxE;AACA,EAAA,MAAM,EAAE,QAAO,GAAI,MAAA;AAEnB,EAAA,MAAM,IAAA,GAAOE,QAAQ,OAAA,CAAQ,GAAA,EAAK,QAAQ,IAAA,IAAQ,MAAA,CAAO,KAAA,EAAO,IAAA,IAAQC,aAAY,CAAA;AACpF,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA,IAAa,MAAA,CAAO,OAAO,SAAA,IAAaC,cAAAA;AAClE,EAAA,MAAM,QAAA,GAAWF,OAAAA,CAAQ,OAAA,CAAQ,GAAA,EAAK,OAAO,KAAK,CAAA;AAClD,EAAA,MAAM,iBAAA,GAAoB,IAAI,GAAA,CAAI,MAAA,CAAO,OAAO,CAAA;AAEhD,EAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB,IAAA,EAAM,SAAS,CAAA;AAEpD,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,UAAoB,EAAC;AAE3B,EAAA,KAAA,MAAW,KAAA,IAAS,OAAO,OAAA,EAAS;AAClC,IAAA,IAAI,CAAC,iBAAA,CAAkB,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,EAAG;AACxC,MAAA,OAAA,CAAQ,IAAA,CAAK,MAAM,MAAM,CAAA;AACzB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAOL,IAAAA,CAAK,QAAA,EAAU,CAAA,EAAG,KAAA,CAAM,MAAM,CAAA,KAAA,CAAO,CAAA;AAClD,IAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AACjB,IAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,MAAA,MAAMQ,SAAAA,CAAU,IAAA,EAAM,KAAA,CAAM,YAAY,CAAA;AACxC,MAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,IACnB;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,SAAS,OAAA,EAAQ;AACtD;;;ACjDO,SAAS,sBAAsB,OAAA,EAAwB;AAC5D,EAAA,MAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA,CAAE,YAAY,4CAA4C,CAAA;AAE9F,EAAA,GAAA,CACG,OAAA,CAAQ,OAAO,CAAA,CACf,WAAA,CAAY,6CAA6C,CAAA,CACzD,MAAA,CAAO,iBAAiB,sCAAsC,CAAA,CAC9D,OAAO,gBAAA,EAAkB,oCAAoC,EAC7D,MAAA,CAAO,WAAA,EAAa,gDAAgD,KAAK,CAAA,CACzE,MAAA,CAAO,OAAO,KAAA,KAA4B;AACzC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,MAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAS,OAAA,EAAQ,GAAI,MAAM,cAAA,CAAe;AAAA,QACzD,GAAA;AAAA,QACA,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,WAAW,KAAA,CAAM,KAAA;AAAA,QACjB,QAAQ,KAAA,CAAM;AAAA,OACf,CAAA;AAED,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,MAAA,GAAS,OAAA,GAAU,OAAA;AACzC,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,MAAA,GAAS,aAAA,GAAgB,OAAA;AAC5C,MAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,QAAAP,MAAAA,CAAO,OAAA,CAAQ,CAAA,EAAG,IAAI,CAAA,CAAA,EAAIF,MAAAA,CAAM,IAAA,CAAKG,QAAAA,CAAS,GAAA,EAAK,IAAI,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,MAC7D;AACA,MAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,QAAAD,OAAO,IAAA,CAAK,CAAA,QAAA,EAAWF,OAAM,IAAA,CAAK,MAAM,CAAC,CAAA,6BAAA,CAA+B,CAAA;AAAA,MAC1E;AAAA,IACF,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,MAAAE,MAAAA,CAAO,MAAM,OAAO,CAAA;AACpB,MAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AAAA,IACrB;AAAA,EACF,CAAC,CAAA;AACL;;;AClCA,IAAM,OAAA,GAAU,OAAA;AAEhB,eAAe,IAAA,GAAsB;AACnC,EAAA,iBAAA,CAAkB,EAAE,CAAA;AAEpB,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAE5B,EAAA,OAAA,CACG,IAAA,CAAK,UAAU,CAAA,CACf,WAAA,CAAY,mEAAmE,CAAA,CAC/E,OAAA,CAAQ,OAAA,EAAS,eAAA,EAAiB,6BAA6B,CAAA,CAC/D,IAAA,CAAK,aAAa,MAAM;AACvB,IAAA,WAAA,CAAY,OAAO,CAAA;AAAA,EACrB,CAAC,CAAA;AAEH,EAAA,mBAAA,CAAoB,OAAO,CAAA;AAC3B,EAAA,mBAAA,CAAoB,OAAO,CAAA;AAC3B,EAAA,uBAAA,CAAwB,OAAO,CAAA;AAC/B,EAAA,0BAAA,CAA2B,OAAO,CAAA;AAClC,EAAA,qBAAA,CAAsB,OAAO,CAAA;AAC7B,EAAA,qBAAA,CAAsB,OAAO,CAAA;AAE7B,EAAA,MAAM,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ,IAAI,CAAA;AACvC;AAEA,IAAA,EAAK,CAAE,KAAA,CAAM,CAAC,KAAA,KAAmB;AAC/B,EAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,EAAAA,MAAAA,CAAO,MAAM,OAAO,CAAA;AACpB,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAChB,CAAC,CAAA","file":"cli.js","sourcesContent":["import chalk from 'chalk';\n\nexport function printBanner(version: string): void {\n const title = chalk.bold.cyan('LangSync');\n const tagline = chalk.gray('Modern localization workflow tooling.');\n const ver = chalk.dim(`v${version}`);\n console.log(`\\n ${title} ${ver}\\n ${tagline}\\n`);\n}\n","import chalk from 'chalk';\n\nexport function assertNodeVersion(minMajor: number): void {\n const current = process.versions.node;\n const major = Number.parseInt(current.split('.')[0] ?? '0', 10);\n if (major < minMajor) {\n console.error(\n chalk.red(\n `langsync requires Node.js >= ${String(minMajor)}. ` +\n `You are running ${current}. Please upgrade.`,\n ),\n );\n process.exit(1);\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { type I18nFramework } from '@langsync/shared/types';\n\ninterface PackageJsonLike {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nconst FRAMEWORK_SIGNATURES: readonly {\n framework: I18nFramework;\n packages: readonly string[];\n}[] = [\n { framework: 'i18next', packages: ['i18next', 'react-i18next', 'vue-i18next'] },\n { framework: 'ngx-translate', packages: ['@ngx-translate/core', '@ngx-translate/http-loader'] },\n { framework: 'react-intl', packages: ['react-intl', '@formatjs/intl'] },\n];\n\n/**\n * Detect the i18n framework used by the project at `cwd` by inspecting its `package.json`.\n * Returns `null` when no known framework dependency is present.\n */\nexport async function detectFramework(cwd: string): Promise<I18nFramework | null> {\n const pkgPath = join(cwd, 'package.json');\n let pkg: PackageJsonLike;\n try {\n pkg = JSON.parse(await readFile(pkgPath, 'utf-8')) as PackageJsonLike;\n } catch {\n return null;\n }\n\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n\n for (const { framework, packages } of FRAMEWORK_SIGNATURES) {\n if (packages.some((p) => p in allDeps)) return framework;\n }\n return null;\n}\n","import prompts from 'prompts';\nimport { type I18nFramework } from '@langsync/shared/types';\n\nexport interface InitAnswers {\n input: string;\n output: string;\n locales: string[];\n defaultLocale: string;\n framework: I18nFramework | 'none';\n}\n\nexport interface InitPromptOptions {\n detectedFramework: I18nFramework | null;\n /** When true, skip prompts and use defaults (with detected framework). */\n yes?: boolean;\n}\n\nconst FRAMEWORK_CHOICES = [\n { title: 'i18next', value: 'i18next' as const },\n { title: 'ngx-translate (Angular)', value: 'ngx-translate' as const },\n { title: 'react-intl', value: 'react-intl' as const },\n { title: 'None / Custom', value: 'none' as const },\n];\n\nconst DEFAULTS = {\n input: './src/i18n',\n output: './translations',\n locales: 'en,de',\n defaultLocale: 'en',\n};\n\nexport async function runInitPrompts(options: InitPromptOptions): Promise<InitAnswers> {\n const framework: InitAnswers['framework'] = options.detectedFramework ?? 'none';\n\n if (options.yes) {\n return {\n input: DEFAULTS.input,\n output: DEFAULTS.output,\n locales: DEFAULTS.locales.split(',').map((l) => l.trim()),\n defaultLocale: DEFAULTS.defaultLocale,\n framework,\n };\n }\n\n const response = await prompts(\n [\n {\n type: 'text',\n name: 'input',\n message: 'Where are your source i18n files?',\n initial: DEFAULTS.input,\n },\n {\n type: 'text',\n name: 'output',\n message: 'Where should translation output go?',\n initial: DEFAULTS.output,\n },\n {\n type: 'text',\n name: 'locales',\n message: 'Which locales? (comma-separated)',\n initial: DEFAULTS.locales,\n format: (value: string) =>\n value\n .split(',')\n .map((l) => l.trim())\n .filter(Boolean),\n validate: (value: string) => {\n const list = value\n .split(',')\n .map((l) => l.trim())\n .filter(Boolean);\n return list.length > 0 ? true : 'Please provide at least one locale.';\n },\n },\n {\n type: 'text',\n name: 'defaultLocale',\n message: 'Default (reference) locale?',\n initial: DEFAULTS.defaultLocale,\n },\n {\n type: 'select',\n name: 'framework',\n message: 'Which i18n framework do you use?',\n choices: FRAMEWORK_CHOICES,\n initial: FRAMEWORK_CHOICES.findIndex((c) => c.value === framework),\n },\n ],\n {\n onCancel: () => {\n throw new Error('Aborted by user.');\n },\n },\n );\n\n // prompts() returns a typed-erased Answers record; trust our shape.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n return response as InitAnswers;\n}\n","import { mkdir, writeFile, access } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { type InitAnswers } from './prompt.js';\n\nexport type ConfigFormat = 'ts' | 'json';\n\nexport interface WriteConfigOptions {\n cwd: string;\n answers: InitAnswers;\n format: ConfigFormat;\n force: boolean;\n}\n\nexport interface WriteConfigResult {\n configPath: string;\n createdLocaleFiles: string[];\n}\n\nconst CANDIDATE_CONFIG_FILES = [\n 'langsync.config.ts',\n 'langsync.config.js',\n 'langsync.config.mjs',\n 'langsync.config.json',\n];\n\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function findExistingConfig(cwd: string): Promise<string | null> {\n for (const file of CANDIDATE_CONFIG_FILES) {\n const full = join(cwd, file);\n if (await pathExists(full)) return full;\n }\n return null;\n}\n\nfunction renderTsConfig(answers: InitAnswers): string {\n const frameworkLine =\n answers.framework === 'none' ? '' : ` framework: '${answers.framework}',\\n`;\n const localesArr = answers.locales.map((l) => `'${l}'`).join(', ');\n return `import { defineConfig } from '@mariokreitz/langsync';\n\nexport default defineConfig({\n input: '${answers.input}',\n output: '${answers.output}',\n locales: [${localesArr}],\n defaultLocale: '${answers.defaultLocale}',\n${frameworkLine}});\n`;\n}\n\nfunction renderJsonConfig(answers: InitAnswers): string {\n const obj: Record<string, unknown> = {\n input: answers.input,\n output: answers.output,\n locales: answers.locales,\n defaultLocale: answers.defaultLocale,\n };\n if (answers.framework !== 'none') obj.framework = answers.framework;\n return JSON.stringify(obj, null, 2) + '\\n';\n}\n\n/**\n * Write the LangSync config file and scaffold empty locale JSON stubs.\n * Refuses to overwrite an existing config unless `force` is set.\n */\nexport async function writeConfig(options: WriteConfigOptions): Promise<WriteConfigResult> {\n const { cwd, answers, format, force } = options;\n\n const existing = await findExistingConfig(cwd);\n if (existing && !force) {\n throw new Error(\n `A LangSync config already exists at ${existing}. Re-run with --force to overwrite.`,\n );\n }\n\n const configFilename = format === 'ts' ? 'langsync.config.ts' : 'langsync.config.json';\n const configPath = resolve(cwd, configFilename);\n const content = format === 'ts' ? renderTsConfig(answers) : renderJsonConfig(answers);\n\n await mkdir(dirname(configPath), { recursive: true });\n await writeFile(configPath, content, 'utf-8');\n\n // Scaffold empty locale stubs in the input directory.\n const inputDir = resolve(cwd, answers.input);\n await mkdir(inputDir, { recursive: true });\n const createdLocaleFiles: string[] = [];\n for (const locale of answers.locales) {\n const localePath = join(inputDir, `${locale}.json`);\n if (!(await pathExists(localePath))) {\n await writeFile(localePath, '{}\\n', 'utf-8');\n createdLocaleFiles.push(localePath);\n }\n }\n\n return { configPath, createdLocaleFiles };\n}\n","import { type Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { relative } from 'node:path';\nimport { logger } from '@langsync/shared/logger';\nimport { detectFramework } from './init/detect-framework.js';\nimport { runInitPrompts } from './init/prompt.js';\nimport { writeConfig, type ConfigFormat } from './init/write-config.js';\n\ninterface InitFlags {\n force: boolean;\n json: boolean;\n yes: boolean;\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('init')\n .description('Initialize a new LangSync configuration in the current project.')\n .option('--force', 'Overwrite an existing config file without asking.', false)\n .option('--json', 'Emit langsync.config.json instead of langsync.config.ts.', false)\n .option('-y, --yes', 'Accept all defaults; skip prompts.', false)\n .action(async (flags: InitFlags) => {\n const cwd = process.cwd();\n const format: ConfigFormat = flags.json ? 'json' : 'ts';\n\n try {\n const detectSpinner = ora('Detecting i18n framework…').start();\n const detectedFramework = await detectFramework(cwd);\n detectSpinner.succeed(\n detectedFramework\n ? `Detected ${chalk.cyan(detectedFramework)}`\n : 'No known framework detected',\n );\n\n // prompts owns stdio — must NOT be wrapped in a spinner.\n const answers = await runInitPrompts({\n detectedFramework,\n yes: flags.yes,\n });\n\n const writeSpinner = ora('Writing config and scaffolding locale files…').start();\n const result = await writeConfig({\n cwd,\n answers,\n format,\n force: flags.force,\n });\n writeSpinner.succeed('Files written');\n\n console.log();\n logger.success(`Created ${chalk.bold(relative(cwd, result.configPath))}`);\n for (const localeFile of result.createdLocaleFiles) {\n logger.success(`Created ${chalk.bold(relative(cwd, localeFile))}`);\n }\n console.log();\n logger.info(`Next: run ${chalk.bold('langsync validate')} to check your locales.`);\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exitCode = 1;\n }\n });\n}\n","import { loadConfig } from '@langsync/shared/config';\nimport { loadLocaleFiles, writeJson } from '@langsync/shared/fs';\nimport { syncTrees } from '@langsync/core';\n\nexport interface RunSyncOptions {\n cwd: string;\n dryRun?: boolean;\n}\n\nexport interface RunSyncResult {\n referenceLocale: string;\n written: string[];\n planned: string[];\n}\n\n/**\n * Synchronize keys from the reference locale into every other locale,\n * preserving existing translations and adding empty placeholders for new keys.\n */\nexport async function runSync(options: RunSyncOptions): Promise<RunSyncResult> {\n const loaded = await loadConfig(options.cwd);\n if (!loaded) {\n throw new Error('No LangSync config found. Run `langsync init` first.');\n }\n const { config } = loaded;\n const referenceLocale = config.defaultLocale ?? config.locales[0]!;\n\n const files = await loadLocaleFiles({\n cwd: options.cwd,\n inputDir: config.input,\n locales: config.locales,\n });\n\n const reference = files.find((f) => f.locale === referenceLocale);\n if (!reference) {\n throw new Error(`Could not find reference locale file for \"${referenceLocale}\".`);\n }\n\n const targets = files.filter((f) => f.locale !== referenceLocale);\n const planned: string[] = [];\n const written: string[] = [];\n\n for (const target of targets) {\n const merged = syncTrees(reference.translations, target.translations);\n planned.push(target.path);\n if (!options.dryRun) {\n await writeJson(target.path, merged);\n written.push(target.path);\n }\n }\n\n return { referenceLocale, written, planned };\n}\n","import { type Command } from 'commander';\nimport chalk from 'chalk';\nimport { relative } from 'node:path';\nimport { logger } from '@langsync/shared/logger';\nimport { runSync } from './sync/run.js';\n\ninterface SyncFlags {\n dryRun: boolean;\n}\n\nexport function registerSyncCommand(program: Command): void {\n program\n .command('sync')\n .description('Synchronize translation keys across all configured locales.')\n .option('--dry-run', 'Report planned changes without writing files.', false)\n .action(async (flags: SyncFlags) => {\n try {\n const cwd = process.cwd();\n const { written, planned, referenceLocale } = await runSync({\n cwd,\n dryRun: flags.dryRun,\n });\n\n const targets = flags.dryRun ? planned : written;\n if (targets.length === 0) {\n logger.info(`Nothing to sync against ${chalk.cyan(referenceLocale)}.`);\n } else {\n const verb = flags.dryRun ? 'Would update' : 'Updated';\n for (const path of targets) {\n logger.success(`${verb} ${chalk.bold(relative(cwd, path))}`);\n }\n }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exitCode = 1;\n }\n });\n}\n","import { loadConfig } from '@langsync/shared/config';\nimport { loadLocaleFiles } from '@langsync/shared/fs';\nimport { validateLocales, type ValidationIssue } from '@langsync/core';\n\nexport interface RunValidateOptions {\n cwd: string;\n}\n\nexport interface RunValidateResult {\n referenceLocale: string;\n issues: ValidationIssue[];\n exitCode: 0 | 1;\n}\n\n/**\n * Validate the locale files configured in the LangSync config at `cwd`.\n *\n * - `missing` and `extra` issues are treated as errors (exit code 1).\n * - `empty` issues are treated as warnings only (exit code 0).\n */\nexport async function runValidate(options: RunValidateOptions): Promise<RunValidateResult> {\n const loaded = await loadConfig(options.cwd);\n if (!loaded) {\n throw new Error('No LangSync config found. Run `langsync init` first.');\n }\n\n const { config } = loaded;\n const referenceLocale = config.defaultLocale ?? config.locales[0]!;\n\n const files = await loadLocaleFiles({\n cwd: options.cwd,\n inputDir: config.input,\n locales: config.locales,\n });\n\n const issues = validateLocales(files, referenceLocale);\n const hasErrors = issues.some((i) => i.type === 'missing' || i.type === 'extra');\n\n return {\n referenceLocale,\n issues,\n exitCode: hasErrors ? 1 : 0,\n };\n}\n","import { type Command } from 'commander';\nimport chalk from 'chalk';\nimport { logger } from '@langsync/shared/logger';\nimport { runValidate } from './validate/run.js';\n\ninterface ValidateFlags {\n reporter: 'pretty' | 'json';\n}\n\nexport function registerValidateCommand(program: Command): void {\n program\n .command('validate')\n .description('Validate locale consistency, structure and missing keys.')\n .option('--reporter <kind>', 'Output format: pretty | json.', 'pretty')\n .action(async (flags: ValidateFlags) => {\n try {\n const { issues, exitCode, referenceLocale } = await runValidate({ cwd: process.cwd() });\n\n if (flags.reporter === 'json') {\n console.log(JSON.stringify({ referenceLocale, issues }, null, 2));\n } else {\n if (issues.length === 0) {\n logger.success(`All locales are consistent with ${chalk.cyan(referenceLocale)}.`);\n } else {\n const byType = { missing: 0, extra: 0, empty: 0 };\n for (const issue of issues) {\n byType[issue.type]++;\n const colored =\n issue.type === 'empty' ? chalk.yellow(issue.type) : chalk.red(issue.type);\n logger.info(`${colored} ${chalk.cyan(issue.locale)} ${issue.key}`);\n }\n console.log();\n logger.info(\n `Summary: ${byType.missing} missing, ${byType.extra} extra, ${byType.empty} empty`,\n );\n }\n }\n\n process.exitCode = exitCode;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exitCode = 1;\n }\n });\n}\n","import { runValidate } from '../validate/run.js';\n\nexport interface RunFindMissingOptions {\n cwd: string;\n}\n\nexport interface RunFindMissingResult {\n referenceLocale: string;\n missingByLocale: Record<string, string[]>;\n exitCode: 0 | 1;\n}\n\n/**\n * Report missing translation keys per locale, relative to the reference locale.\n */\nexport async function runFindMissing(\n options: RunFindMissingOptions,\n): Promise<RunFindMissingResult> {\n const { issues, referenceLocale } = await runValidate({ cwd: options.cwd });\n\n const missingByLocale: Record<string, string[]> = {};\n for (const issue of issues) {\n if (issue.type !== 'missing') continue;\n (missingByLocale[issue.locale] ??= []).push(issue.key);\n }\n for (const locale of Object.keys(missingByLocale)) {\n missingByLocale[locale]!.sort();\n }\n\n const exitCode: 0 | 1 = Object.keys(missingByLocale).length === 0 ? 0 : 1;\n return { referenceLocale, missingByLocale, exitCode };\n}\n","import { type Command } from 'commander';\nimport chalk from 'chalk';\nimport { logger } from '@langsync/shared/logger';\nimport { runFindMissing } from './find-missing/run.js';\n\ninterface FindMissingFlags {\n reporter: 'pretty' | 'json';\n}\n\nexport function registerFindMissingCommand(program: Command): void {\n program\n .command('find-missing')\n .description('Find missing translation keys across locales.')\n .option('--reporter <kind>', 'Output format: pretty | json.', 'pretty')\n .action(async (flags: FindMissingFlags) => {\n try {\n const { referenceLocale, missingByLocale, exitCode } = await runFindMissing({\n cwd: process.cwd(),\n });\n\n if (flags.reporter === 'json') {\n console.log(JSON.stringify({ referenceLocale, missingByLocale }, null, 2));\n } else if (Object.keys(missingByLocale).length === 0) {\n logger.success(`No missing keys relative to ${chalk.cyan(referenceLocale)}.`);\n } else {\n for (const [locale, keys] of Object.entries(missingByLocale)) {\n logger.warn(`${chalk.cyan(locale)} is missing ${keys.length} key(s):`);\n for (const key of keys) console.log(` - ${key}`);\n }\n }\n\n process.exitCode = exitCode;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exitCode = 1;\n }\n });\n}\n","import { resolve } from 'node:path';\nimport { loadConfig } from '@langsync/shared/config';\nimport { loadLocaleFiles } from '@langsync/shared/fs';\nimport { exportToExcel } from '@langsync/excel-engine';\n\nexport interface RunExportExcelOptions {\n cwd: string;\n /** Override the excel file path (relative to cwd). */\n file?: string;\n /** Override the worksheet name. */\n sheetName?: string;\n}\n\nexport interface RunExportExcelResult {\n file: string;\n sheetName: string;\n locales: string[];\n}\n\nconst DEFAULT_FILE = 'translations.xlsx';\nconst DEFAULT_SHEET = 'Translations';\n\n/**\n * Export all configured locales into a single Excel workbook.\n */\nexport async function runExportExcel(\n options: RunExportExcelOptions,\n): Promise<RunExportExcelResult> {\n const loaded = await loadConfig(options.cwd);\n if (!loaded) {\n throw new Error('No LangSync config found. Run `langsync init` first.');\n }\n const { config } = loaded;\n\n const file = resolve(options.cwd, options.file ?? config.excel?.file ?? DEFAULT_FILE);\n const sheetName = options.sheetName ?? config.excel?.sheetName ?? DEFAULT_SHEET;\n\n const files = await loadLocaleFiles({\n cwd: options.cwd,\n inputDir: config.input,\n locales: config.locales,\n });\n\n await exportToExcel({\n file,\n sheetName,\n locales: files.map((f) => ({ locale: f.locale, translations: f.translations })),\n });\n\n return { file, sheetName, locales: files.map((f) => f.locale) };\n}\n","import { type Command } from 'commander';\nimport chalk from 'chalk';\nimport { relative } from 'node:path';\nimport { logger } from '@langsync/shared/logger';\nimport { runExportExcel } from './export/run.js';\n\ninterface ExportExcelFlags {\n file?: string;\n sheet?: string;\n}\n\nexport function registerExportCommand(program: Command): void {\n const cmd = program.command('export').description('Export translations to external formats.');\n\n cmd\n .command('excel')\n .description('Export translations to an Excel workbook.')\n .option('--file <path>', 'Output Excel file (overrides config).')\n .option('--sheet <name>', 'Worksheet name (overrides config).')\n .action(async (flags: ExportExcelFlags) => {\n try {\n const cwd = process.cwd();\n const { file, locales } = await runExportExcel({\n cwd,\n file: flags.file,\n sheetName: flags.sheet,\n });\n logger.success(\n `Exported ${chalk.cyan(String(locales.length))} locale(s) to ${chalk.bold(\n relative(cwd, file),\n )}`,\n );\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exitCode = 1;\n }\n });\n}\n","import { join, resolve } from 'node:path';\nimport { loadConfig } from '@langsync/shared/config';\nimport { writeJson } from '@langsync/shared/fs';\nimport { importFromExcel } from '@langsync/excel-engine';\n\nexport interface RunImportExcelOptions {\n cwd: string;\n file?: string;\n sheetName?: string;\n dryRun?: boolean;\n}\n\nexport interface RunImportExcelResult {\n file: string;\n sheetName: string;\n written: string[];\n planned: string[];\n skipped: string[];\n}\n\nconst DEFAULT_FILE = 'translations.xlsx';\nconst DEFAULT_SHEET = 'Translations';\n\n/**\n * Import locales from an Excel workbook and write them back to the configured\n * input directory as JSON files. Locales not listed in the config are skipped.\n */\nexport async function runImportExcel(\n options: RunImportExcelOptions,\n): Promise<RunImportExcelResult> {\n const loaded = await loadConfig(options.cwd);\n if (!loaded) {\n throw new Error('No LangSync config found. Run `langsync init` first.');\n }\n const { config } = loaded;\n\n const file = resolve(options.cwd, options.file ?? config.excel?.file ?? DEFAULT_FILE);\n const sheetName = options.sheetName ?? config.excel?.sheetName ?? DEFAULT_SHEET;\n const inputAbs = resolve(options.cwd, config.input);\n const configuredLocales = new Set(config.locales);\n\n const result = await importFromExcel(file, sheetName);\n\n const planned: string[] = [];\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const entry of result.locales) {\n if (!configuredLocales.has(entry.locale)) {\n skipped.push(entry.locale);\n continue;\n }\n const path = join(inputAbs, `${entry.locale}.json`);\n planned.push(path);\n if (!options.dryRun) {\n await writeJson(path, entry.translations);\n written.push(path);\n }\n }\n\n return { file, sheetName, written, planned, skipped };\n}\n","import { type Command } from 'commander';\nimport chalk from 'chalk';\nimport { relative } from 'node:path';\nimport { logger } from '@langsync/shared/logger';\nimport { runImportExcel } from './import/run.js';\n\ninterface ImportExcelFlags {\n file?: string;\n sheet?: string;\n dryRun: boolean;\n}\n\nexport function registerImportCommand(program: Command): void {\n const cmd = program.command('import').description('Import translations from external formats.');\n\n cmd\n .command('excel')\n .description('Import translations from an Excel workbook.')\n .option('--file <path>', 'Input Excel file (overrides config).')\n .option('--sheet <name>', 'Worksheet name (overrides config).')\n .option('--dry-run', 'Report planned writes without touching disk.', false)\n .action(async (flags: ImportExcelFlags) => {\n try {\n const cwd = process.cwd();\n const { written, planned, skipped } = await runImportExcel({\n cwd,\n file: flags.file,\n sheetName: flags.sheet,\n dryRun: flags.dryRun,\n });\n\n const targets = flags.dryRun ? planned : written;\n const verb = flags.dryRun ? 'Would write' : 'Wrote';\n for (const path of targets) {\n logger.success(`${verb} ${chalk.bold(relative(cwd, path))}`);\n }\n for (const locale of skipped) {\n logger.warn(`Skipped ${chalk.cyan(locale)} (not in configured locales).`);\n }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exitCode = 1;\n }\n });\n}\n","import { Command } from 'commander';\nimport { logger } from '@langsync/shared/logger';\nimport { printBanner } from './ui/banner.js';\nimport { assertNodeVersion } from './ui/node-version.js';\nimport { registerInitCommand } from './commands/init.js';\nimport { registerSyncCommand } from './commands/sync.js';\nimport { registerValidateCommand } from './commands/validate.js';\nimport { registerFindMissingCommand } from './commands/find-missing.js';\nimport { registerExportCommand } from './commands/export.js';\nimport { registerImportCommand } from './commands/import.js';\n\nconst VERSION = '0.0.0';\n\nasync function main(): Promise<void> {\n assertNodeVersion(22);\n\n const program = new Command();\n\n program\n .name('langsync')\n .description('Modern localization workflow tooling for TypeScript applications.')\n .version(VERSION, '-v, --version', 'Output the current version.')\n .hook('preAction', () => {\n printBanner(VERSION);\n });\n\n registerInitCommand(program);\n registerSyncCommand(program);\n registerValidateCommand(program);\n registerFindMissingCommand(program);\n registerExportCommand(program);\n registerImportCommand(program);\n\n await program.parseAsync(process.argv);\n}\n\nmain().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(message);\n process.exit(1);\n});\n"]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}