@fluenti/cli 0.1.2 → 0.2.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.
Files changed (46) hide show
  1. package/dist/catalog.d.ts +6 -2
  2. package/dist/catalog.d.ts.map +1 -1
  3. package/dist/cli.cjs +18 -6
  4. package/dist/cli.cjs.map +1 -1
  5. package/dist/cli.js +434 -282
  6. package/dist/cli.js.map +1 -1
  7. package/dist/compile-runner.d.ts +7 -0
  8. package/dist/compile-runner.d.ts.map +1 -0
  9. package/dist/compile.d.ts +16 -1
  10. package/dist/compile.d.ts.map +1 -1
  11. package/dist/config-loader-CcqRnMzw.js +387 -0
  12. package/dist/config-loader-CcqRnMzw.js.map +1 -0
  13. package/dist/config-loader-DV5Yqrg5.cjs +16 -0
  14. package/dist/config-loader-DV5Yqrg5.cjs.map +1 -0
  15. package/dist/config-loader.d.ts +7 -0
  16. package/dist/config-loader.d.ts.map +1 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +30 -4
  22. package/dist/index.js.map +1 -1
  23. package/dist/init.d.ts +24 -0
  24. package/dist/init.d.ts.map +1 -0
  25. package/dist/json-format.d.ts.map +1 -1
  26. package/dist/migrate.d.ts +36 -0
  27. package/dist/migrate.d.ts.map +1 -1
  28. package/dist/po-format.d.ts.map +1 -1
  29. package/dist/stats-format.d.ts +20 -0
  30. package/dist/stats-format.d.ts.map +1 -0
  31. package/dist/translate.d.ts +4 -0
  32. package/dist/translate.d.ts.map +1 -1
  33. package/dist/tsx-extractor-DNg_iUSd.cjs +2 -0
  34. package/dist/tsx-extractor-DNg_iUSd.cjs.map +1 -0
  35. package/dist/tsx-extractor-DZrY1LMS.js +268 -0
  36. package/dist/tsx-extractor-DZrY1LMS.js.map +1 -0
  37. package/dist/tsx-extractor.d.ts.map +1 -1
  38. package/dist/vue-extractor-DWETY0BN.cjs +3 -0
  39. package/dist/vue-extractor-DWETY0BN.cjs.map +1 -0
  40. package/dist/vue-extractor-iUl6SUkv.js +210 -0
  41. package/dist/vue-extractor-iUl6SUkv.js.map +1 -0
  42. package/package.json +2 -2
  43. package/dist/compile-DK1UYkah.cjs +0 -13
  44. package/dist/compile-DK1UYkah.cjs.map +0 -1
  45. package/dist/compile-DuHUSzlx.js +0 -747
  46. package/dist/compile-DuHUSzlx.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import type { FluentiConfig } from '@fluenti/core'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiConfig>): Partial<FluentiConfig> {\n return config\n}\n"],"mappings":"4IAoBA,SAAgB,EAAa,EAAwD,CACnF,OAAO"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/compile-runner.ts"],"sourcesContent":["import type { FluentiConfig } from '@fluenti/core'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiConfig>): Partial<FluentiConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of config.locales) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n for (const locale of config.locales) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n\n const indexCode = compileIndex(config.locales, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n}\n"],"mappings":"kRAoBA,SAAgB,EAAa,EAAwD,CACnF,OAAO,ECbT,SAAS,EAAY,EAAkB,EAAoC,CACzE,GAAI,EAAA,EAAA,EAAA,YAAY,EAAS,CAAE,MAAO,EAAE,CACpC,IAAM,GAAA,EAAA,EAAA,cAAuB,EAAU,QAAQ,CAC/C,OAAO,IAAW,OAAS,EAAA,EAAgB,EAAQ,CAAG,EAAA,EAAc,EAAQ,CAQ9E,eAAsB,EAAW,EAA4B,CAC3D,IAAM,EAAS,MAAM,EAAA,EAAW,IAAA,GAAW,EAAI,CACzC,EAAM,EAAO,SAAW,OAAS,QAAU,MAE3C,GAAA,EAAA,EAAA,SAAiB,EAAK,EAAO,cAAc,EACjD,EAAA,EAAA,WAAU,EAAQ,CAAE,UAAW,GAAM,CAAC,CAEtC,IAAM,EAA2C,EAAE,CACnD,IAAK,IAAM,KAAU,EAAO,QAE1B,EAAY,GAAU,GAAA,EAAA,EAAA,SADM,EAAK,EAAO,WAAY,GAAG,IAAS,IAAM,CACvB,EAAO,OAAO,CAG/D,IAAM,EAAS,EAAA,EAAc,EAAY,CAEzC,IAAK,IAAM,KAAU,EAAO,QAAS,CACnC,GAAM,CAAE,QAAS,EAAA,EAAe,EAAY,GAAU,EAAQ,EAAQ,EAAO,aAAa,EAC1F,EAAA,EAAA,gBAAA,EAAA,EAAA,SAAsB,EAAQ,GAAG,EAAO,KAAK,CAAE,EAAM,QAAQ,CAG/D,IAAM,EAAY,EAAA,EAAa,EAAO,QAAS,EAAO,cAAc,EACpE,EAAA,EAAA,gBAAA,EAAA,EAAA,SAAsB,EAAQ,WAAW,CAAE,EAAW,QAAQ,CAE9D,IAAM,EAAY,EAAA,EAAuB,EAAQ,EAAa,EAAO,aAAa,EAClF,EAAA,EAAA,gBAAA,EAAA,EAAA,SAAsB,EAAQ,gBAAgB,CAAE,EAAW,QAAQ"}
package/dist/index.d.ts CHANGED
@@ -8,5 +8,7 @@ export { compileCatalog, compileIndex, collectAllIds } from './compile';
8
8
  export type { CompileStats } from './compile';
9
9
  export { hashMessage } from '@fluenti/core';
10
10
  export { defineConfig } from './config';
11
+ export { loadConfig } from './config-loader';
12
+ export { runCompile } from './compile-runner';
11
13
  export type { FluentiConfig } from '@fluenti/core';
12
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA"}
package/dist/index.js CHANGED
@@ -1,10 +1,36 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "./compile-DuHUSzlx.js";
2
- import { hashMessage as u } from "@fluenti/core";
1
+ import { t as e } from "./vue-extractor-iUl6SUkv.js";
2
+ import { t } from "./tsx-extractor-DZrY1LMS.js";
3
+ import { a as n, c as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./config-loader-CcqRnMzw.js";
4
+ import { hashMessage as f } from "@fluenti/core";
5
+ import { existsSync as p, mkdirSync as m, readFileSync as h, writeFileSync as g } from "node:fs";
6
+ import { resolve as _ } from "node:path";
3
7
  //#region src/config.ts
4
- function d(e) {
8
+ function v(e) {
5
9
  return e;
6
10
  }
7
11
  //#endregion
8
- export { c as collectAllIds, i as compileCatalog, o as compileIndex, d as defineConfig, l as extractFromTsx, r as extractFromVue, u as hashMessage, a as readJsonCatalog, n as readPoCatalog, t as updateCatalog, s as writeJsonCatalog, e as writePoCatalog };
12
+ //#region src/compile-runner.ts
13
+ function y(e, t) {
14
+ if (!p(e)) return {};
15
+ let n = h(e, "utf-8");
16
+ return t === "json" ? r(n) : s(n);
17
+ }
18
+ async function b(e) {
19
+ let t = await u(void 0, e), r = t.format === "json" ? ".json" : ".po", a = _(e, t.compileOutDir);
20
+ m(a, { recursive: !0 });
21
+ let s = {};
22
+ for (let n of t.locales) s[n] = y(_(e, t.catalogDir, `${n}${r}`), t.format);
23
+ let l = o(s);
24
+ for (let e of t.locales) {
25
+ let { code: n } = c(s[e], e, l, t.sourceLocale);
26
+ g(_(a, `${e}.js`), n, "utf-8");
27
+ }
28
+ let d = i(t.locales, t.compileOutDir);
29
+ g(_(a, "index.js"), d, "utf-8");
30
+ let f = n(l, s, t.sourceLocale);
31
+ g(_(a, "messages.d.ts"), f, "utf-8");
32
+ }
33
+ //#endregion
34
+ export { o as collectAllIds, c as compileCatalog, i as compileIndex, v as defineConfig, t as extractFromTsx, e as extractFromVue, f as hashMessage, u as loadConfig, r as readJsonCatalog, s as readPoCatalog, b as runCompile, d as updateCatalog, a as writeJsonCatalog, l as writePoCatalog };
9
35
 
10
36
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import type { FluentiConfig } from '@fluenti/core'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiConfig>): Partial<FluentiConfig> {\n return config\n}\n"],"mappings":";;;AAoBA,SAAgB,EAAa,GAAwD;AACnF,QAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/compile-runner.ts"],"sourcesContent":["import type { FluentiConfig } from '@fluenti/core'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiConfig>): Partial<FluentiConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of config.locales) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n for (const locale of config.locales) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n\n const indexCode = compileIndex(config.locales, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n}\n"],"mappings":";;;;;;;AAoBA,SAAgB,EAAa,GAAwD;AACnF,QAAO;;;;ACbT,SAAS,EAAY,GAAkB,GAAoC;AACzE,KAAI,CAAC,EAAW,EAAS,CAAE,QAAO,EAAE;CACpC,IAAM,IAAU,EAAa,GAAU,QAAQ;AAC/C,QAAO,MAAW,SAAS,EAAgB,EAAQ,GAAG,EAAc,EAAQ;;AAQ9E,eAAsB,EAAW,GAA4B;CAC3D,IAAM,IAAS,MAAM,EAAW,KAAA,GAAW,EAAI,EACzC,IAAM,EAAO,WAAW,SAAS,UAAU,OAE3C,IAAS,EAAQ,GAAK,EAAO,cAAc;AACjD,GAAU,GAAQ,EAAE,WAAW,IAAM,CAAC;CAEtC,IAAM,IAA2C,EAAE;AACnD,MAAK,IAAM,KAAU,EAAO,QAE1B,GAAY,KAAU,EADF,EAAQ,GAAK,EAAO,YAAY,GAAG,IAAS,IAAM,EACvB,EAAO,OAAO;CAG/D,IAAM,IAAS,EAAc,EAAY;AAEzC,MAAK,IAAM,KAAU,EAAO,SAAS;EACnC,IAAM,EAAE,YAAS,EAAe,EAAY,IAAU,GAAQ,GAAQ,EAAO,aAAa;AAC1F,IAAc,EAAQ,GAAQ,GAAG,EAAO,KAAK,EAAE,GAAM,QAAQ;;CAG/D,IAAM,IAAY,EAAa,EAAO,SAAS,EAAO,cAAc;AACpE,GAAc,EAAQ,GAAQ,WAAW,EAAE,GAAW,QAAQ;CAE9D,IAAM,IAAY,EAAuB,GAAQ,GAAa,EAAO,aAAa;AAClF,GAAc,EAAQ,GAAQ,gBAAgB,EAAE,GAAW,QAAQ"}
package/dist/init.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ export declare function validateLocale(locale: string): string;
2
+ export interface DetectedFramework {
3
+ name: 'nextjs' | 'nuxt' | 'vue' | 'solid' | 'solidstart' | 'react' | 'unknown';
4
+ pluginPackage: string | null;
5
+ }
6
+ /**
7
+ * Detect the framework from package.json dependencies.
8
+ */
9
+ export declare function detectFramework(deps: Record<string, string>): DetectedFramework;
10
+ /**
11
+ * Generate fluenti.config.ts content.
12
+ */
13
+ export declare function generateFluentiConfig(opts: {
14
+ sourceLocale: string;
15
+ locales: string[];
16
+ format: 'po' | 'json';
17
+ }): string;
18
+ /**
19
+ * Interactive init flow.
20
+ */
21
+ export declare function runInit(options: {
22
+ cwd: string;
23
+ }): Promise<void>;
24
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,CAAA;IAC9E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAeD;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,iBAAiB,CAO/E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,IAAI,GAAG,MAAM,CAAA;CACtB,GAAG,MAAM,CAaT;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4HrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"json-format.d.ts","sourceRoot":"","sources":["../src/json-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAmB5D;AAED,qCAAqC;AACrC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAe7D"}
1
+ {"version":3,"file":"json-format.d.ts","sourceRoot":"","sources":["../src/json-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAwB5D;AAED,qCAAqC;AACrC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAgB7D"}
package/dist/migrate.d.ts CHANGED
@@ -1,9 +1,45 @@
1
1
  import { AIProvider } from './translate';
2
2
  export type SupportedLibrary = 'vue-i18n' | 'nuxt-i18n' | 'react-i18next' | 'next-intl' | 'next-i18next' | 'lingui';
3
+ interface LibraryInfo {
4
+ name: SupportedLibrary;
5
+ framework: string;
6
+ configPatterns: string[];
7
+ localePatterns: string[];
8
+ sourcePatterns: string[];
9
+ migrationGuide: string;
10
+ }
11
+ export declare function resolveLibrary(from: string): SupportedLibrary | undefined;
12
+ export interface DetectedFiles {
13
+ configFiles: Array<{
14
+ path: string;
15
+ content: string;
16
+ }>;
17
+ localeFiles: Array<{
18
+ path: string;
19
+ content: string;
20
+ }>;
21
+ sampleSources: Array<{
22
+ path: string;
23
+ content: string;
24
+ }>;
25
+ packageJson: string | undefined;
26
+ }
27
+ export declare function buildMigratePrompt(library: LibraryInfo, detected: DetectedFiles, migrationGuide: string): string;
28
+ interface MigrateResult {
29
+ config: string | undefined;
30
+ localeFiles: Array<{
31
+ locale: string;
32
+ content: string;
33
+ }>;
34
+ steps: string | undefined;
35
+ installCommands: string | undefined;
36
+ }
37
+ export declare function parseResponse(response: string): MigrateResult;
3
38
  export interface MigrateOptions {
4
39
  from: string;
5
40
  provider: AIProvider;
6
41
  write: boolean;
7
42
  }
8
43
  export declare function runMigrate(options: MigrateOptions): Promise<void>;
44
+ export {};
9
45
  //# sourceMappingURL=migrate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAI7C,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,WAAW,GACX,eAAe,GACf,WAAW,GACX,cAAc,GACd,QAAQ,CAAA;AA6SZ,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGvE"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAI7C,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,WAAW,GACX,eAAe,GACf,WAAW,GACX,cAAc,GACd,QAAQ,CAAA;AAEZ,UAAU,WAAW;IACnB,IAAI,EAAE,gBAAgB,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;CACvB;AAuDD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGzE;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACrD,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACrD,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;CAChC;AAsED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,EACvB,cAAc,EAAE,MAAM,GACrB,MAAM,CA6ER;AA2BD,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAwC7D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"po-format.d.ts","sourceRoot":"","sources":["../src/po-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA8B5C,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAiC1D;AAED,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CA8C3D"}
1
+ {"version":3,"file":"po-format.d.ts","sourceRoot":"","sources":["../src/po-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA8B5C,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAuC1D;AAED,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAgD3D"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Render a Unicode progress bar.
3
+ *
4
+ * @param pct - Percentage (0–100)
5
+ * @param width - Character width of the bar (default 20)
6
+ */
7
+ export declare function formatProgressBar(pct: number, width?: number): string;
8
+ /**
9
+ * Wrap a percentage string in ANSI colour based on value.
10
+ *
11
+ * - ≥90 → green (\x1b[32m)
12
+ * - ≥70 → yellow (\x1b[33m)
13
+ * - <70 → red (\x1b[31m)
14
+ */
15
+ export declare function colorizePercent(pct: number): string;
16
+ /**
17
+ * Format a full stats row for a single locale.
18
+ */
19
+ export declare function formatStatsRow(locale: string, total: number, translated: number): string;
20
+ //# sourceMappingURL=stats-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-format.d.ts","sourceRoot":"","sources":["../src/stats-format.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAIjE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR"}
@@ -1,5 +1,9 @@
1
1
  import { CatalogData } from './catalog';
2
2
  export type AIProvider = 'claude' | 'codex';
3
+ export declare function buildPrompt(sourceLocale: string, targetLocale: string, messages: Record<string, string>): string;
4
+ export declare function extractJSON(text: string): Record<string, string>;
5
+ export declare function getUntranslatedEntries(catalog: CatalogData): Record<string, string>;
6
+ export declare function chunkEntries(entries: Record<string, string>, batchSize: number): Array<Record<string, string>>;
3
7
  export interface TranslateOptions {
4
8
  provider: AIProvider;
5
9
  sourceLocale: string;
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAI5C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAyF3C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC;IACzE,OAAO,EAAE,WAAW,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CAyCD"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAI5C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CAcR;AA2BD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWhE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASnF;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAa/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC;IACzE,OAAO,EAAE,WAAW,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CA0CD"}
@@ -0,0 +1,2 @@
1
+ require(`./config-loader-DV5Yqrg5.cjs`);let e=require(`@fluenti/core/internal`);var t=new Set([`@fluenti/react`,`@fluenti/vue`,`@fluenti/solid`,`@fluenti/next`]);function n(e){let t=e.trim();if(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(t))return t;if(/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(t)&&!t.endsWith(`.`)){let e=t.split(`.`);return e[e.length-1]}let n=t.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\s*\(/);return n?n[1].replace(/\./g,`_`):``}function r(e,t){let r=``,i=0;for(let a=0;a<e.length;a++){if(r+=e[a],a>=t.length)continue;let o=n(t[a]);if(o===``){r+=`{arg${i}}`,i++;continue}r+=`{${o}}`}return r}function i(e,t,n){if(!e.message)return;let r=n.loc?.start.line??1,i=(n.loc?.start.column??0)+1;return{id:e.id,message:e.message,...e.context===void 0?{}:{context:e.context},...e.comment===void 0?{}:{comment:e.comment},origin:{file:t,line:r,column:i}}}function a(t){if(t.message)return{id:t.id??(0,e.createMessageId)(t.message,t.context),message:t.message,...t.context===void 0?{}:{context:t.context},...t.comment===void 0?{}:{comment:t.comment}}}function o(e){if(e.type===`StringLiteral`)return a({message:e.value});if(e.type===`TemplateLiteral`){let t=e;return t.expressions.length===0?a({message:t.quasis.map(e=>e.value.cooked??e.value.raw).join(``)}):void 0}if(e.type!==`ObjectExpression`)return;let t={};for(let n of e.properties){if(n.type!==`ObjectProperty`)continue;let e=n;if(e.computed||!S(e.key))continue;let r=e.key.name;if(![`id`,`message`,`context`,`comment`].includes(r))continue;let i=u(e.value);i!==void 0&&(t[r]=i)}if(t.message)return a(t)}function s(e){let t=[`zero`,`one`,`two`,`few`,`many`,`other`],n=e.value??e.count??`count`,r=[],i=e.offset;for(let n of t){let t=e[n];if(t===void 0)continue;let i=n===`zero`?`=0`:n;r.push(`${i} {${t}}`)}return r.length===0?``:`{${n}, plural, ${i?`offset:${i} `:``}${r.join(` `)}}`}function c(e){let t=0;function n(e){let r=``;for(let i of e){if(i.type===`JSXText`){r+=l(i.value);continue}if(i.type===`JSXElement`){let e=t++,a=n(i.children);if(a===void 0)return;r+=`<${e}>${a}</${e}>`;continue}if(i.type===`JSXFragment`){let e=n(i.children);if(e===void 0)return;r+=e;continue}if(i.type===`JSXExpressionContainer`){let e=i.expression;if(e.type===`StringLiteral`){r+=e.value;continue}if(e.type===`NumericLiteral`){r+=String(e.value);continue}return}}return r}let r=n(e);if(r!==void 0)return r.replace(/\s+/g,` `).trim()||void 0}function l(e){return e.replace(/\s+/g,` `)}function u(e){if(e.type===`StringLiteral`)return e.value;if(e.type===`NumericLiteral`)return String(e.value);if(e.type===`JSXExpressionContainer`)return u(e.expression);if(e.type===`TemplateLiteral`){let t=e;if(t.expressions.length===0)return t.quasis.map(e=>e.value.cooked??e.value.raw).join(``)}}function d(e,t){if(!(e.start==null||e.end==null))return e.type===`JSXExpressionContainer`?d(e.expression,t):t.slice(e.start,e.end).trim()}function f(e,t){for(let n of e.attributes){if(n.type!==`JSXAttribute`)continue;let e=n;if(e.name.type===`JSXIdentifier`&&e.name.name===t)return e}}function p(e,t){let n={};for(let r of[`id`,`value`,`count`,`offset`,`zero`,`one`,`two`,`few`,`many`,`other`]){let i=f(e,r);if(!i?.value)continue;let a=u(i.value);if(a!==void 0){n[r]=a;continue}let o=d(i.value,t);o!==void 0&&(r===`value`||r===`count`||r===`offset`)&&(n[r]=o)}return n}function m(t,n){let i=r(n.quasi.quasis.map(e=>e.value.cooked??e.value.raw),n.quasi.expressions.map(e=>e.start==null||e.end==null?``:t.slice(e.start,e.end)));return{id:(0,e.createMessageId)(i),message:i}}function h(e){let n=new Set,r=Array.isArray(e.body)?e.body:[];for(let e of r)if(_(e)&&t.has(e.source.value))for(let t of e.specifiers)v(t)&&y(t)===`t`&&n.add(t.local.name);return n}function g(t,n){let r=(0,e.parseSourceModule)(t);if(!r)return[];let a=[],l=h(r);return(0,e.walkSourceAst)(r,r=>{if(r.type===`TaggedTemplateExpression`){let e=r;if(S(e.tag)&&(e.tag.name===`t`||l.has(e.tag.name))){let r=i(m(t,e),n,e);r&&a.push(r)}return}if(r.type===`CallExpression`){let e=r;if(S(e.callee)&&(e.callee.name===`t`||l.has(e.callee.name))){if(l.has(e.callee.name)&&e.arguments[0]?.type!==`ObjectExpression`)return;let t=e.arguments[0]?o(e.arguments[0]):void 0,r=t?i(t,n,e):void 0;r&&a.push(r)}return}if(r.type!==`JSXElement`)return;let d=r,h=d.openingElement,g=b(h.name);if(g===`Trans`){let e=f(h,`message`),t=f(h,`id`),r=f(h,`context`),o=f(h,`comment`),s=e?.value?x({id:t?.value?u(t.value):void 0,message:u(e.value),context:r?.value?u(r.value):void 0,comment:o?.value?u(o.value):void 0}):x({id:t?.value?u(t.value):void 0,message:c(d.children),context:r?.value?u(r.value):void 0,comment:o?.value?u(o.value):void 0}),l=s?i(s,n,d):void 0;l&&a.push(l);return}if(g===`Plural`){let r=p(h,t),o=s(r);if(!o)return;let c=i({id:r.id??(0,e.createMessageId)(o),message:o},n,d);c&&a.push(c)}}),a}function _(t){return(0,e.isSourceNode)(t)&&t.type===`ImportDeclaration`}function v(t){return(0,e.isSourceNode)(t)&&t.type===`ImportSpecifier`}function y(e){if(e.imported.type===`Identifier`)return e.imported.name;if(e.imported.type===`StringLiteral`)return e.imported.value}function b(e){if(e.type===`JSXIdentifier`)return String(e.name)}function x(e){let t={};return e.id!==void 0&&(t.id=e.id),e.message!==void 0&&(t.message=e.message),e.context!==void 0&&(t.context=e.context),e.comment!==void 0&&(t.comment=e.comment),a(t)}function S(t){return(0,e.isSourceNode)(t)&&t.type===`Identifier`}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return g}});
2
+ //# sourceMappingURL=tsx-extractor-DNg_iUSd.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsx-extractor-DNg_iUSd.cjs","names":[],"sources":["../src/tsx-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core'\nimport {\n createMessageId,\n isSourceNode,\n parseSourceModule,\n walkSourceAst,\n type SourceNode,\n} from '@fluenti/core/internal'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { raw: string; cooked: string | null }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n quasis: TemplateElementNode[]\n expressions: SourceNode[]\n}\n\ninterface TaggedTemplateExpressionNode extends SourceNode {\n type: 'TaggedTemplateExpression'\n tag: SourceNode\n quasi: TemplateLiteralNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n children: SourceNode[]\n}\n\ninterface JSXFragmentNode extends SourceNode {\n type: 'JSXFragment'\n children: SourceNode[]\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: SourceNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface JSXTextNode extends SourceNode {\n type: 'JSXText'\n value: string\n}\n\ninterface ExtractedDescriptor {\n id: string\n message?: string\n context?: string\n comment?: string\n}\n\nconst DIRECT_T_SOURCES = new Set([\n '@fluenti/react',\n '@fluenti/vue',\n '@fluenti/solid',\n '@fluenti/next',\n])\n\nfunction classifyExpression(expr: string): string {\n const trimmed = expr.trim()\n // Simple identifier: name, count\n if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(trimmed)) {\n return trimmed\n }\n // Dotted path: user.name → name\n if (/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(trimmed) && !trimmed.endsWith('.')) {\n const parts = trimmed.split('.')\n return parts[parts.length - 1]!\n }\n // Function call: fun() → fun, obj.method() → obj_method\n const callMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\\s*\\(/)\n if (callMatch) {\n return callMatch[1]!.replace(/\\./g, '_')\n }\n return ''\n}\n\nfunction buildICUFromTemplate(\n strings: readonly string[],\n expressions: readonly string[],\n): string {\n let result = ''\n let positionalIndex = 0\n\n for (let index = 0; index < strings.length; index++) {\n result += strings[index]!\n if (index >= expressions.length) continue\n\n const name = classifyExpression(expressions[index]!)\n if (name === '') {\n result += `{arg${positionalIndex}}`\n positionalIndex++\n continue\n }\n\n result += `{${name}}`\n }\n\n return result\n}\n\nfunction createExtractedMessage(\n descriptor: ExtractedDescriptor,\n filename: string,\n node: SourceNode,\n): ExtractedMessage | undefined {\n if (!descriptor.message) {\n return undefined\n }\n\n const line = node.loc?.start.line ?? 1\n const column = (node.loc?.start.column ?? 0) + 1\n\n return {\n id: descriptor.id,\n message: descriptor.message,\n ...(descriptor.context !== undefined ? { context: descriptor.context } : {}),\n ...(descriptor.comment !== undefined ? { comment: descriptor.comment } : {}),\n origin: { file: filename, line, column },\n }\n}\n\nfunction descriptorFromStaticParts(parts: {\n id?: string\n message?: string\n context?: string\n comment?: string\n}): ExtractedDescriptor | undefined {\n if (!parts.message) {\n return undefined\n }\n\n return {\n id: parts.id ?? createMessageId(parts.message, parts.context),\n message: parts.message,\n ...(parts.context !== undefined ? { context: parts.context } : {}),\n ...(parts.comment !== undefined ? { comment: parts.comment } : {}),\n }\n}\n\nfunction extractDescriptorFromCallArgument(argument: SourceNode): ExtractedDescriptor | undefined {\n if (argument.type === 'StringLiteral') {\n return descriptorFromStaticParts({ message: (argument as StringLiteralNode).value })\n }\n\n if (argument.type === 'TemplateLiteral') {\n const template = argument as TemplateLiteralNode\n if (template.expressions.length === 0) {\n const message = template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n return descriptorFromStaticParts({ message })\n }\n return undefined\n }\n\n if (argument.type !== 'ObjectExpression') {\n return undefined\n }\n\n const staticParts: { id?: string; message?: string; context?: string; comment?: string } = {}\n for (const property of (argument as ObjectExpressionNode).properties) {\n if (property.type !== 'ObjectProperty') continue\n\n const objectProperty = property as ObjectPropertyNode\n if (objectProperty.computed || !isIdentifier(objectProperty.key)) continue\n\n const key = objectProperty.key.name\n if (!['id', 'message', 'context', 'comment'].includes(key)) continue\n\n const value = readStaticStringValue(objectProperty.value)\n if (value === undefined) continue\n staticParts[key as keyof typeof staticParts] = value\n }\n\n if (!staticParts.message) {\n return undefined\n }\n\n return descriptorFromStaticParts(staticParts)\n}\n\nfunction buildPluralICU(props: Record<string, string>): string {\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n const countVar = props['value'] ?? props['count'] ?? 'count'\n const options: string[] = []\n const offset = props['offset']\n\n for (const category of categories) {\n const value = props[category]\n if (value === undefined) continue\n const key = category === 'zero' ? '=0' : category\n options.push(`${key} {${value}}`)\n }\n\n if (options.length === 0) {\n return ''\n }\n\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction extractRichTextMessage(children: readonly SourceNode[]): string | undefined {\n let nextIndex = 0\n\n function render(nodes: readonly SourceNode[]): string | undefined {\n let message = ''\n\n for (const node of nodes) {\n if (node.type === 'JSXText') {\n message += normalizeJsxText((node as JSXTextNode).value)\n continue\n }\n\n if (node.type === 'JSXElement') {\n const idx = nextIndex++\n const inner = render((node as JSXElementNode).children)\n if (inner === undefined) return undefined\n message += `<${idx}>${inner}</${idx}>`\n continue\n }\n\n if (node.type === 'JSXFragment') {\n const inner = render((node as JSXFragmentNode).children)\n if (inner === undefined) return undefined\n message += inner\n continue\n }\n\n if (node.type === 'JSXExpressionContainer') {\n const expression = (node as JSXExpressionContainerNode).expression\n if (expression.type === 'StringLiteral') {\n message += (expression as StringLiteralNode).value\n continue\n }\n if (expression.type === 'NumericLiteral') {\n message += String((expression as NumericLiteralNode).value)\n continue\n }\n return undefined\n }\n }\n\n return message\n }\n\n const message = render(children)\n if (message === undefined) return undefined\n\n const normalized = message.replace(/\\s+/g, ' ').trim()\n return normalized || undefined\n}\n\nfunction normalizeJsxText(value: string): string {\n return value.replace(/\\s+/g, ' ')\n}\n\nfunction readStaticStringValue(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'NumericLiteral') {\n return String((node as NumericLiteralNode).value)\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readStaticStringValue((node as JSXExpressionContainerNode).expression)\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0) {\n return template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n }\n }\n\n return undefined\n}\n\nfunction readExpressionSource(node: SourceNode, code: string): string | undefined {\n if (node.start == null || node.end == null) {\n return undefined\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readExpressionSource((node as JSXExpressionContainerNode).expression, code)\n }\n\n return code.slice(node.start, node.end).trim()\n}\n\nfunction getJsxAttribute(\n openingElement: JSXOpeningElementNode,\n name: string,\n): JSXAttributeNode | undefined {\n for (const attribute of openingElement.attributes) {\n if (attribute.type !== 'JSXAttribute') continue\n\n const jsxAttribute = attribute as JSXAttributeNode\n if (jsxAttribute.name.type === 'JSXIdentifier' && jsxAttribute.name['name'] === name) {\n return jsxAttribute\n }\n }\n\n return undefined\n}\n\nfunction extractPluralProps(\n openingElement: JSXOpeningElementNode,\n code: string,\n): Record<string, string> {\n const props: Record<string, string> = {}\n const propNames = ['id', 'value', 'count', 'offset', 'zero', 'one', 'two', 'few', 'many', 'other']\n\n for (const name of propNames) {\n const attribute = getJsxAttribute(openingElement, name)\n if (!attribute?.value) continue\n\n const staticValue = readStaticStringValue(attribute.value)\n if (staticValue !== undefined) {\n props[name] = staticValue\n continue\n }\n\n const exprValue = readExpressionSource(attribute.value, code)\n if (exprValue !== undefined && (name === 'value' || name === 'count' || name === 'offset')) {\n props[name] = exprValue\n }\n }\n\n return props\n}\n\nfunction extractTaggedTemplateMessage(\n code: string,\n node: TaggedTemplateExpressionNode,\n): ExtractedDescriptor {\n const strings = node.quasi.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw)\n const expressions = node.quasi.expressions.map((expression) => {\n if (expression.start == null || expression.end == null) {\n return ''\n }\n return code.slice(expression.start, expression.end)\n })\n const message = buildICUFromTemplate(strings, expressions)\n\n return {\n id: createMessageId(message),\n message,\n }\n}\n\nfunction collectDirectImportTBindings(ast: SourceNode): Set<string> {\n const bindings = new Set<string>()\n const body = Array.isArray(ast['body']) ? ast['body'] : []\n\n for (const entry of body) {\n if (!isImportDeclaration(entry)) continue\n if (!DIRECT_T_SOURCES.has(entry.source.value)) continue\n\n for (const specifier of entry.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n if (readImportedName(specifier) !== 't') continue\n bindings.add(specifier.local.name)\n }\n }\n\n return bindings\n}\n\nexport function extractFromTsx(code: string, filename: string): ExtractedMessage[] {\n const ast = parseSourceModule(code)\n if (!ast) {\n return []\n }\n\n const messages: ExtractedMessage[] = []\n const directImportTBindings = collectDirectImportTBindings(ast)\n\n walkSourceAst(ast, (node: SourceNode) => {\n if (node.type === 'TaggedTemplateExpression') {\n const tagged = node as TaggedTemplateExpressionNode\n if (\n isIdentifier(tagged.tag)\n && (tagged.tag.name === 't' || directImportTBindings.has(tagged.tag.name))\n ) {\n const extracted = createExtractedMessage(\n extractTaggedTemplateMessage(code, tagged),\n filename,\n tagged,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type === 'CallExpression') {\n const call = node as CallExpressionNode\n if (isIdentifier(call.callee) && (call.callee.name === 't' || directImportTBindings.has(call.callee.name))) {\n if (directImportTBindings.has(call.callee.name) && call.arguments[0]?.type !== 'ObjectExpression') {\n return\n }\n const descriptor = call.arguments[0] ? extractDescriptorFromCallArgument(call.arguments[0]) : undefined\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, call)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type !== 'JSXElement') {\n return\n }\n\n const element = node as JSXElementNode\n const openingElement = element.openingElement\n const elementName = readJsxElementName(openingElement.name)\n\n if (elementName === 'Trans') {\n const messageAttr = getJsxAttribute(openingElement, 'message')\n const idAttr = getJsxAttribute(openingElement, 'id')\n const contextAttr = getJsxAttribute(openingElement, 'context')\n const commentAttr = getJsxAttribute(openingElement, 'comment')\n\n const descriptor = messageAttr?.value\n ? buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: readStaticStringValue(messageAttr.value),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n })\n : buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: extractRichTextMessage(element.children),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n })\n\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, element)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n return\n }\n\n if (elementName === 'Plural') {\n const props = extractPluralProps(openingElement, code)\n const message = buildPluralICU(props)\n if (!message) {\n return\n }\n\n const extracted = createExtractedMessage(\n {\n id: props['id'] ?? createMessageId(message),\n message,\n },\n filename,\n element,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n })\n\n return messages\n}\n\nfunction isImportDeclaration(node: unknown): node is ImportDeclarationNode {\n return isSourceNode(node) && node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: unknown): node is ImportSpecifierNode {\n return isSourceNode(node) && node.type === 'ImportSpecifier'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n if (specifier.imported.type === 'Identifier') {\n return (specifier.imported as IdentifierNode).name\n }\n if (specifier.imported.type === 'StringLiteral') {\n return (specifier.imported as StringLiteralNode).value\n }\n return undefined\n}\n\nfunction readJsxElementName(node: SourceNode): string | undefined {\n if (node.type === 'JSXIdentifier') {\n return String(node['name'])\n }\n return undefined\n}\n\nfunction buildStaticTransDescriptor(parts: {\n id: string | undefined\n message: string | undefined\n context: string | undefined\n comment: string | undefined\n}): ExtractedDescriptor | undefined {\n const payload: {\n id?: string\n message?: string\n context?: string\n comment?: string\n } = {}\n\n if (parts.id !== undefined) payload.id = parts.id\n if (parts.message !== undefined) payload.message = parts.message\n if (parts.context !== undefined) payload.context = parts.context\n if (parts.comment !== undefined) payload.comment = parts.comment\n\n return descriptorFromStaticParts(payload)\n}\n\nfunction isIdentifier(node: unknown): node is IdentifierNode {\n return isSourceNode(node) && node.type === 'Identifier'\n}\n"],"mappings":"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"}
@@ -0,0 +1,268 @@
1
+ import { createMessageId as e, isSourceNode as t, parseSourceModule as n, walkSourceAst as r } from "@fluenti/core/internal";
2
+ //#region src/tsx-extractor.ts
3
+ var i = new Set([
4
+ "@fluenti/react",
5
+ "@fluenti/vue",
6
+ "@fluenti/solid",
7
+ "@fluenti/next"
8
+ ]);
9
+ function a(e) {
10
+ let t = e.trim();
11
+ if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(t)) return t;
12
+ if (/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(t) && !t.endsWith(".")) {
13
+ let e = t.split(".");
14
+ return e[e.length - 1];
15
+ }
16
+ let n = t.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\s*\(/);
17
+ return n ? n[1].replace(/\./g, "_") : "";
18
+ }
19
+ function o(e, t) {
20
+ let n = "", r = 0;
21
+ for (let i = 0; i < e.length; i++) {
22
+ if (n += e[i], i >= t.length) continue;
23
+ let o = a(t[i]);
24
+ if (o === "") {
25
+ n += `{arg${r}}`, r++;
26
+ continue;
27
+ }
28
+ n += `{${o}}`;
29
+ }
30
+ return n;
31
+ }
32
+ function s(e, t, n) {
33
+ if (!e.message) return;
34
+ let r = n.loc?.start.line ?? 1, i = (n.loc?.start.column ?? 0) + 1;
35
+ return {
36
+ id: e.id,
37
+ message: e.message,
38
+ ...e.context === void 0 ? {} : { context: e.context },
39
+ ...e.comment === void 0 ? {} : { comment: e.comment },
40
+ origin: {
41
+ file: t,
42
+ line: r,
43
+ column: i
44
+ }
45
+ };
46
+ }
47
+ function c(t) {
48
+ if (t.message) return {
49
+ id: t.id ?? e(t.message, t.context),
50
+ message: t.message,
51
+ ...t.context === void 0 ? {} : { context: t.context },
52
+ ...t.comment === void 0 ? {} : { comment: t.comment }
53
+ };
54
+ }
55
+ function l(e) {
56
+ if (e.type === "StringLiteral") return c({ message: e.value });
57
+ if (e.type === "TemplateLiteral") {
58
+ let t = e;
59
+ return t.expressions.length === 0 ? c({ message: t.quasis.map((e) => e.value.cooked ?? e.value.raw).join("") }) : void 0;
60
+ }
61
+ if (e.type !== "ObjectExpression") return;
62
+ let t = {};
63
+ for (let n of e.properties) {
64
+ if (n.type !== "ObjectProperty") continue;
65
+ let e = n;
66
+ if (e.computed || !T(e.key)) continue;
67
+ let r = e.key.name;
68
+ if (![
69
+ "id",
70
+ "message",
71
+ "context",
72
+ "comment"
73
+ ].includes(r)) continue;
74
+ let i = p(e.value);
75
+ i !== void 0 && (t[r] = i);
76
+ }
77
+ if (t.message) return c(t);
78
+ }
79
+ function u(e) {
80
+ let t = [
81
+ "zero",
82
+ "one",
83
+ "two",
84
+ "few",
85
+ "many",
86
+ "other"
87
+ ], n = e.value ?? e.count ?? "count", r = [], i = e.offset;
88
+ for (let n of t) {
89
+ let t = e[n];
90
+ if (t === void 0) continue;
91
+ let i = n === "zero" ? "=0" : n;
92
+ r.push(`${i} {${t}}`);
93
+ }
94
+ return r.length === 0 ? "" : `{${n}, plural, ${i ? `offset:${i} ` : ""}${r.join(" ")}}`;
95
+ }
96
+ function d(e) {
97
+ let t = 0;
98
+ function n(e) {
99
+ let r = "";
100
+ for (let i of e) {
101
+ if (i.type === "JSXText") {
102
+ r += f(i.value);
103
+ continue;
104
+ }
105
+ if (i.type === "JSXElement") {
106
+ let e = t++, a = n(i.children);
107
+ if (a === void 0) return;
108
+ r += `<${e}>${a}</${e}>`;
109
+ continue;
110
+ }
111
+ if (i.type === "JSXFragment") {
112
+ let e = n(i.children);
113
+ if (e === void 0) return;
114
+ r += e;
115
+ continue;
116
+ }
117
+ if (i.type === "JSXExpressionContainer") {
118
+ let e = i.expression;
119
+ if (e.type === "StringLiteral") {
120
+ r += e.value;
121
+ continue;
122
+ }
123
+ if (e.type === "NumericLiteral") {
124
+ r += String(e.value);
125
+ continue;
126
+ }
127
+ return;
128
+ }
129
+ }
130
+ return r;
131
+ }
132
+ let r = n(e);
133
+ if (r !== void 0) return r.replace(/\s+/g, " ").trim() || void 0;
134
+ }
135
+ function f(e) {
136
+ return e.replace(/\s+/g, " ");
137
+ }
138
+ function p(e) {
139
+ if (e.type === "StringLiteral") return e.value;
140
+ if (e.type === "NumericLiteral") return String(e.value);
141
+ if (e.type === "JSXExpressionContainer") return p(e.expression);
142
+ if (e.type === "TemplateLiteral") {
143
+ let t = e;
144
+ if (t.expressions.length === 0) return t.quasis.map((e) => e.value.cooked ?? e.value.raw).join("");
145
+ }
146
+ }
147
+ function m(e, t) {
148
+ if (!(e.start == null || e.end == null)) return e.type === "JSXExpressionContainer" ? m(e.expression, t) : t.slice(e.start, e.end).trim();
149
+ }
150
+ function h(e, t) {
151
+ for (let n of e.attributes) {
152
+ if (n.type !== "JSXAttribute") continue;
153
+ let e = n;
154
+ if (e.name.type === "JSXIdentifier" && e.name.name === t) return e;
155
+ }
156
+ }
157
+ function g(e, t) {
158
+ let n = {};
159
+ for (let r of [
160
+ "id",
161
+ "value",
162
+ "count",
163
+ "offset",
164
+ "zero",
165
+ "one",
166
+ "two",
167
+ "few",
168
+ "many",
169
+ "other"
170
+ ]) {
171
+ let i = h(e, r);
172
+ if (!i?.value) continue;
173
+ let a = p(i.value);
174
+ if (a !== void 0) {
175
+ n[r] = a;
176
+ continue;
177
+ }
178
+ let o = m(i.value, t);
179
+ o !== void 0 && (r === "value" || r === "count" || r === "offset") && (n[r] = o);
180
+ }
181
+ return n;
182
+ }
183
+ function _(t, n) {
184
+ let r = o(n.quasi.quasis.map((e) => e.value.cooked ?? e.value.raw), n.quasi.expressions.map((e) => e.start == null || e.end == null ? "" : t.slice(e.start, e.end)));
185
+ return {
186
+ id: e(r),
187
+ message: r
188
+ };
189
+ }
190
+ function v(e) {
191
+ let t = /* @__PURE__ */ new Set(), n = Array.isArray(e.body) ? e.body : [];
192
+ for (let e of n) if (b(e) && i.has(e.source.value)) for (let n of e.specifiers) x(n) && S(n) === "t" && t.add(n.local.name);
193
+ return t;
194
+ }
195
+ function y(t, i) {
196
+ let a = n(t);
197
+ if (!a) return [];
198
+ let o = [], c = v(a);
199
+ return r(a, (n) => {
200
+ if (n.type === "TaggedTemplateExpression") {
201
+ let e = n;
202
+ if (T(e.tag) && (e.tag.name === "t" || c.has(e.tag.name))) {
203
+ let n = s(_(t, e), i, e);
204
+ n && o.push(n);
205
+ }
206
+ return;
207
+ }
208
+ if (n.type === "CallExpression") {
209
+ let e = n;
210
+ if (T(e.callee) && (e.callee.name === "t" || c.has(e.callee.name))) {
211
+ if (c.has(e.callee.name) && e.arguments[0]?.type !== "ObjectExpression") return;
212
+ let t = e.arguments[0] ? l(e.arguments[0]) : void 0, n = t ? s(t, i, e) : void 0;
213
+ n && o.push(n);
214
+ }
215
+ return;
216
+ }
217
+ if (n.type !== "JSXElement") return;
218
+ let r = n, a = r.openingElement, f = C(a.name);
219
+ if (f === "Trans") {
220
+ let e = h(a, "message"), t = h(a, "id"), n = h(a, "context"), c = h(a, "comment"), l = e?.value ? w({
221
+ id: t?.value ? p(t.value) : void 0,
222
+ message: p(e.value),
223
+ context: n?.value ? p(n.value) : void 0,
224
+ comment: c?.value ? p(c.value) : void 0
225
+ }) : w({
226
+ id: t?.value ? p(t.value) : void 0,
227
+ message: d(r.children),
228
+ context: n?.value ? p(n.value) : void 0,
229
+ comment: c?.value ? p(c.value) : void 0
230
+ }), u = l ? s(l, i, r) : void 0;
231
+ u && o.push(u);
232
+ return;
233
+ }
234
+ if (f === "Plural") {
235
+ let n = g(a, t), c = u(n);
236
+ if (!c) return;
237
+ let l = s({
238
+ id: n.id ?? e(c),
239
+ message: c
240
+ }, i, r);
241
+ l && o.push(l);
242
+ }
243
+ }), o;
244
+ }
245
+ function b(e) {
246
+ return t(e) && e.type === "ImportDeclaration";
247
+ }
248
+ function x(e) {
249
+ return t(e) && e.type === "ImportSpecifier";
250
+ }
251
+ function S(e) {
252
+ if (e.imported.type === "Identifier") return e.imported.name;
253
+ if (e.imported.type === "StringLiteral") return e.imported.value;
254
+ }
255
+ function C(e) {
256
+ if (e.type === "JSXIdentifier") return String(e.name);
257
+ }
258
+ function w(e) {
259
+ let t = {};
260
+ return e.id !== void 0 && (t.id = e.id), e.message !== void 0 && (t.message = e.message), e.context !== void 0 && (t.context = e.context), e.comment !== void 0 && (t.comment = e.comment), c(t);
261
+ }
262
+ function T(e) {
263
+ return t(e) && e.type === "Identifier";
264
+ }
265
+ //#endregion
266
+ export { y as t };
267
+
268
+ //# sourceMappingURL=tsx-extractor-DZrY1LMS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsx-extractor-DZrY1LMS.js","names":[],"sources":["../src/tsx-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core'\nimport {\n createMessageId,\n isSourceNode,\n parseSourceModule,\n walkSourceAst,\n type SourceNode,\n} from '@fluenti/core/internal'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { raw: string; cooked: string | null }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n quasis: TemplateElementNode[]\n expressions: SourceNode[]\n}\n\ninterface TaggedTemplateExpressionNode extends SourceNode {\n type: 'TaggedTemplateExpression'\n tag: SourceNode\n quasi: TemplateLiteralNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n children: SourceNode[]\n}\n\ninterface JSXFragmentNode extends SourceNode {\n type: 'JSXFragment'\n children: SourceNode[]\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: SourceNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface JSXTextNode extends SourceNode {\n type: 'JSXText'\n value: string\n}\n\ninterface ExtractedDescriptor {\n id: string\n message?: string\n context?: string\n comment?: string\n}\n\nconst DIRECT_T_SOURCES = new Set([\n '@fluenti/react',\n '@fluenti/vue',\n '@fluenti/solid',\n '@fluenti/next',\n])\n\nfunction classifyExpression(expr: string): string {\n const trimmed = expr.trim()\n // Simple identifier: name, count\n if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(trimmed)) {\n return trimmed\n }\n // Dotted path: user.name → name\n if (/^[a-zA-Z_$][a-zA-Z0-9_$.]*$/.test(trimmed) && !trimmed.endsWith('.')) {\n const parts = trimmed.split('.')\n return parts[parts.length - 1]!\n }\n // Function call: fun() → fun, obj.method() → obj_method\n const callMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$.]*)\\s*\\(/)\n if (callMatch) {\n return callMatch[1]!.replace(/\\./g, '_')\n }\n return ''\n}\n\nfunction buildICUFromTemplate(\n strings: readonly string[],\n expressions: readonly string[],\n): string {\n let result = ''\n let positionalIndex = 0\n\n for (let index = 0; index < strings.length; index++) {\n result += strings[index]!\n if (index >= expressions.length) continue\n\n const name = classifyExpression(expressions[index]!)\n if (name === '') {\n result += `{arg${positionalIndex}}`\n positionalIndex++\n continue\n }\n\n result += `{${name}}`\n }\n\n return result\n}\n\nfunction createExtractedMessage(\n descriptor: ExtractedDescriptor,\n filename: string,\n node: SourceNode,\n): ExtractedMessage | undefined {\n if (!descriptor.message) {\n return undefined\n }\n\n const line = node.loc?.start.line ?? 1\n const column = (node.loc?.start.column ?? 0) + 1\n\n return {\n id: descriptor.id,\n message: descriptor.message,\n ...(descriptor.context !== undefined ? { context: descriptor.context } : {}),\n ...(descriptor.comment !== undefined ? { comment: descriptor.comment } : {}),\n origin: { file: filename, line, column },\n }\n}\n\nfunction descriptorFromStaticParts(parts: {\n id?: string\n message?: string\n context?: string\n comment?: string\n}): ExtractedDescriptor | undefined {\n if (!parts.message) {\n return undefined\n }\n\n return {\n id: parts.id ?? createMessageId(parts.message, parts.context),\n message: parts.message,\n ...(parts.context !== undefined ? { context: parts.context } : {}),\n ...(parts.comment !== undefined ? { comment: parts.comment } : {}),\n }\n}\n\nfunction extractDescriptorFromCallArgument(argument: SourceNode): ExtractedDescriptor | undefined {\n if (argument.type === 'StringLiteral') {\n return descriptorFromStaticParts({ message: (argument as StringLiteralNode).value })\n }\n\n if (argument.type === 'TemplateLiteral') {\n const template = argument as TemplateLiteralNode\n if (template.expressions.length === 0) {\n const message = template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n return descriptorFromStaticParts({ message })\n }\n return undefined\n }\n\n if (argument.type !== 'ObjectExpression') {\n return undefined\n }\n\n const staticParts: { id?: string; message?: string; context?: string; comment?: string } = {}\n for (const property of (argument as ObjectExpressionNode).properties) {\n if (property.type !== 'ObjectProperty') continue\n\n const objectProperty = property as ObjectPropertyNode\n if (objectProperty.computed || !isIdentifier(objectProperty.key)) continue\n\n const key = objectProperty.key.name\n if (!['id', 'message', 'context', 'comment'].includes(key)) continue\n\n const value = readStaticStringValue(objectProperty.value)\n if (value === undefined) continue\n staticParts[key as keyof typeof staticParts] = value\n }\n\n if (!staticParts.message) {\n return undefined\n }\n\n return descriptorFromStaticParts(staticParts)\n}\n\nfunction buildPluralICU(props: Record<string, string>): string {\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other'] as const\n const countVar = props['value'] ?? props['count'] ?? 'count'\n const options: string[] = []\n const offset = props['offset']\n\n for (const category of categories) {\n const value = props[category]\n if (value === undefined) continue\n const key = category === 'zero' ? '=0' : category\n options.push(`${key} {${value}}`)\n }\n\n if (options.length === 0) {\n return ''\n }\n\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction extractRichTextMessage(children: readonly SourceNode[]): string | undefined {\n let nextIndex = 0\n\n function render(nodes: readonly SourceNode[]): string | undefined {\n let message = ''\n\n for (const node of nodes) {\n if (node.type === 'JSXText') {\n message += normalizeJsxText((node as JSXTextNode).value)\n continue\n }\n\n if (node.type === 'JSXElement') {\n const idx = nextIndex++\n const inner = render((node as JSXElementNode).children)\n if (inner === undefined) return undefined\n message += `<${idx}>${inner}</${idx}>`\n continue\n }\n\n if (node.type === 'JSXFragment') {\n const inner = render((node as JSXFragmentNode).children)\n if (inner === undefined) return undefined\n message += inner\n continue\n }\n\n if (node.type === 'JSXExpressionContainer') {\n const expression = (node as JSXExpressionContainerNode).expression\n if (expression.type === 'StringLiteral') {\n message += (expression as StringLiteralNode).value\n continue\n }\n if (expression.type === 'NumericLiteral') {\n message += String((expression as NumericLiteralNode).value)\n continue\n }\n return undefined\n }\n }\n\n return message\n }\n\n const message = render(children)\n if (message === undefined) return undefined\n\n const normalized = message.replace(/\\s+/g, ' ').trim()\n return normalized || undefined\n}\n\nfunction normalizeJsxText(value: string): string {\n return value.replace(/\\s+/g, ' ')\n}\n\nfunction readStaticStringValue(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'NumericLiteral') {\n return String((node as NumericLiteralNode).value)\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readStaticStringValue((node as JSXExpressionContainerNode).expression)\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0) {\n return template.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join('')\n }\n }\n\n return undefined\n}\n\nfunction readExpressionSource(node: SourceNode, code: string): string | undefined {\n if (node.start == null || node.end == null) {\n return undefined\n }\n\n if (node.type === 'JSXExpressionContainer') {\n return readExpressionSource((node as JSXExpressionContainerNode).expression, code)\n }\n\n return code.slice(node.start, node.end).trim()\n}\n\nfunction getJsxAttribute(\n openingElement: JSXOpeningElementNode,\n name: string,\n): JSXAttributeNode | undefined {\n for (const attribute of openingElement.attributes) {\n if (attribute.type !== 'JSXAttribute') continue\n\n const jsxAttribute = attribute as JSXAttributeNode\n if (jsxAttribute.name.type === 'JSXIdentifier' && jsxAttribute.name['name'] === name) {\n return jsxAttribute\n }\n }\n\n return undefined\n}\n\nfunction extractPluralProps(\n openingElement: JSXOpeningElementNode,\n code: string,\n): Record<string, string> {\n const props: Record<string, string> = {}\n const propNames = ['id', 'value', 'count', 'offset', 'zero', 'one', 'two', 'few', 'many', 'other']\n\n for (const name of propNames) {\n const attribute = getJsxAttribute(openingElement, name)\n if (!attribute?.value) continue\n\n const staticValue = readStaticStringValue(attribute.value)\n if (staticValue !== undefined) {\n props[name] = staticValue\n continue\n }\n\n const exprValue = readExpressionSource(attribute.value, code)\n if (exprValue !== undefined && (name === 'value' || name === 'count' || name === 'offset')) {\n props[name] = exprValue\n }\n }\n\n return props\n}\n\nfunction extractTaggedTemplateMessage(\n code: string,\n node: TaggedTemplateExpressionNode,\n): ExtractedDescriptor {\n const strings = node.quasi.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw)\n const expressions = node.quasi.expressions.map((expression) => {\n if (expression.start == null || expression.end == null) {\n return ''\n }\n return code.slice(expression.start, expression.end)\n })\n const message = buildICUFromTemplate(strings, expressions)\n\n return {\n id: createMessageId(message),\n message,\n }\n}\n\nfunction collectDirectImportTBindings(ast: SourceNode): Set<string> {\n const bindings = new Set<string>()\n const body = Array.isArray(ast['body']) ? ast['body'] : []\n\n for (const entry of body) {\n if (!isImportDeclaration(entry)) continue\n if (!DIRECT_T_SOURCES.has(entry.source.value)) continue\n\n for (const specifier of entry.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n if (readImportedName(specifier) !== 't') continue\n bindings.add(specifier.local.name)\n }\n }\n\n return bindings\n}\n\nexport function extractFromTsx(code: string, filename: string): ExtractedMessage[] {\n const ast = parseSourceModule(code)\n if (!ast) {\n return []\n }\n\n const messages: ExtractedMessage[] = []\n const directImportTBindings = collectDirectImportTBindings(ast)\n\n walkSourceAst(ast, (node: SourceNode) => {\n if (node.type === 'TaggedTemplateExpression') {\n const tagged = node as TaggedTemplateExpressionNode\n if (\n isIdentifier(tagged.tag)\n && (tagged.tag.name === 't' || directImportTBindings.has(tagged.tag.name))\n ) {\n const extracted = createExtractedMessage(\n extractTaggedTemplateMessage(code, tagged),\n filename,\n tagged,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type === 'CallExpression') {\n const call = node as CallExpressionNode\n if (isIdentifier(call.callee) && (call.callee.name === 't' || directImportTBindings.has(call.callee.name))) {\n if (directImportTBindings.has(call.callee.name) && call.arguments[0]?.type !== 'ObjectExpression') {\n return\n }\n const descriptor = call.arguments[0] ? extractDescriptorFromCallArgument(call.arguments[0]) : undefined\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, call)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n }\n return\n }\n\n if (node.type !== 'JSXElement') {\n return\n }\n\n const element = node as JSXElementNode\n const openingElement = element.openingElement\n const elementName = readJsxElementName(openingElement.name)\n\n if (elementName === 'Trans') {\n const messageAttr = getJsxAttribute(openingElement, 'message')\n const idAttr = getJsxAttribute(openingElement, 'id')\n const contextAttr = getJsxAttribute(openingElement, 'context')\n const commentAttr = getJsxAttribute(openingElement, 'comment')\n\n const descriptor = messageAttr?.value\n ? buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: readStaticStringValue(messageAttr.value),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n })\n : buildStaticTransDescriptor({\n id: idAttr?.value ? readStaticStringValue(idAttr.value) : undefined,\n message: extractRichTextMessage(element.children),\n context: contextAttr?.value ? readStaticStringValue(contextAttr.value) : undefined,\n comment: commentAttr?.value ? readStaticStringValue(commentAttr.value) : undefined,\n })\n\n const extracted = descriptor\n ? createExtractedMessage(descriptor, filename, element)\n : undefined\n if (extracted) {\n messages.push(extracted)\n }\n return\n }\n\n if (elementName === 'Plural') {\n const props = extractPluralProps(openingElement, code)\n const message = buildPluralICU(props)\n if (!message) {\n return\n }\n\n const extracted = createExtractedMessage(\n {\n id: props['id'] ?? createMessageId(message),\n message,\n },\n filename,\n element,\n )\n if (extracted) {\n messages.push(extracted)\n }\n }\n })\n\n return messages\n}\n\nfunction isImportDeclaration(node: unknown): node is ImportDeclarationNode {\n return isSourceNode(node) && node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: unknown): node is ImportSpecifierNode {\n return isSourceNode(node) && node.type === 'ImportSpecifier'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n if (specifier.imported.type === 'Identifier') {\n return (specifier.imported as IdentifierNode).name\n }\n if (specifier.imported.type === 'StringLiteral') {\n return (specifier.imported as StringLiteralNode).value\n }\n return undefined\n}\n\nfunction readJsxElementName(node: SourceNode): string | undefined {\n if (node.type === 'JSXIdentifier') {\n return String(node['name'])\n }\n return undefined\n}\n\nfunction buildStaticTransDescriptor(parts: {\n id: string | undefined\n message: string | undefined\n context: string | undefined\n comment: string | undefined\n}): ExtractedDescriptor | undefined {\n const payload: {\n id?: string\n message?: string\n context?: string\n comment?: string\n } = {}\n\n if (parts.id !== undefined) payload.id = parts.id\n if (parts.message !== undefined) payload.message = parts.message\n if (parts.context !== undefined) payload.context = parts.context\n if (parts.comment !== undefined) payload.comment = parts.comment\n\n return descriptorFromStaticParts(payload)\n}\n\nfunction isIdentifier(node: unknown): node is IdentifierNode {\n return isSourceNode(node) && node.type === 'Identifier'\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tsx-extractor.d.ts","sourceRoot":"","sources":["../src/tsx-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AA8arD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA6GjF"}
1
+ {"version":3,"file":"tsx-extractor.d.ts","sourceRoot":"","sources":["../src/tsx-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AA8arD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAwGjF"}