@fluenti/cli 0.5.0 → 0.6.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 (118) hide show
  1. package/dist/cli/src/ai-provider.d.ts.map +1 -0
  2. package/dist/{catalog.d.ts → cli/src/catalog.d.ts} +1 -1
  3. package/dist/cli/src/catalog.d.ts.map +1 -0
  4. package/dist/cli/src/check.d.ts.map +1 -0
  5. package/dist/cli/src/cli.d.ts.map +1 -0
  6. package/dist/cli/src/codemod.d.ts +19 -0
  7. package/dist/cli/src/codemod.d.ts.map +1 -0
  8. package/dist/cli/src/compile-cache.d.ts.map +1 -0
  9. package/dist/cli/src/compile-runner.d.ts.map +1 -0
  10. package/dist/cli/src/compile-worker.d.ts.map +1 -0
  11. package/dist/cli/src/compile.d.ts.map +1 -0
  12. package/dist/cli/src/config-loader.d.ts +2 -0
  13. package/dist/cli/src/config-loader.d.ts.map +1 -0
  14. package/dist/{config.d.ts → cli/src/config.d.ts} +1 -1
  15. package/dist/cli/src/config.d.ts.map +1 -0
  16. package/dist/cli/src/doctor.d.ts +19 -0
  17. package/dist/cli/src/doctor.d.ts.map +1 -0
  18. package/dist/{extract-cache.d.ts → cli/src/extract-cache.d.ts} +1 -1
  19. package/dist/cli/src/extract-cache.d.ts.map +1 -0
  20. package/dist/cli/src/extract-runner.d.ts.map +1 -0
  21. package/dist/cli/src/glossary.d.ts.map +1 -0
  22. package/dist/{index.d.ts → cli/src/index.d.ts} +7 -3
  23. package/dist/cli/src/index.d.ts.map +1 -0
  24. package/dist/cli/src/init.d.ts.map +1 -0
  25. package/dist/cli/src/json-format.d.ts.map +1 -0
  26. package/dist/cli/src/lint.d.ts.map +1 -0
  27. package/dist/cli/src/migrate.d.ts.map +1 -0
  28. package/dist/cli/src/parallel-compile.d.ts.map +1 -0
  29. package/dist/cli/src/po-format.d.ts.map +1 -0
  30. package/dist/cli/src/stats-format.d.ts.map +1 -0
  31. package/dist/cli/src/translate-parse.d.ts.map +1 -0
  32. package/dist/cli/src/translate-prompt.d.ts.map +1 -0
  33. package/dist/cli/src/translate.d.ts.map +1 -0
  34. package/dist/{tsx-extractor.d.ts → cli/src/tsx-extractor.d.ts} +1 -1
  35. package/dist/cli/src/tsx-extractor.d.ts.map +1 -0
  36. package/dist/cli/src/validation.d.ts.map +1 -0
  37. package/dist/{vue-extractor.d.ts → cli/src/vue-extractor.d.ts} +1 -1
  38. package/dist/cli/src/vue-extractor.d.ts.map +1 -0
  39. package/dist/cli.cjs +10 -22
  40. package/dist/cli.cjs.map +1 -1
  41. package/dist/cli.js +333 -406
  42. package/dist/cli.js.map +1 -1
  43. package/dist/compile-C3VLvhUf.cjs +8 -0
  44. package/dist/{compile-kXClO6q4.cjs.map → compile-C3VLvhUf.cjs.map} +1 -1
  45. package/dist/{compile-CdA4EZ-p.js → compile-CZVpE5Md.js} +2 -2
  46. package/dist/{compile-CdA4EZ-p.js.map → compile-CZVpE5Md.js.map} +1 -1
  47. package/dist/compile-worker.cjs +1 -1
  48. package/dist/compile-worker.cjs.map +1 -1
  49. package/dist/compile-worker.js +1 -1
  50. package/dist/doctor-BqXXxyST.js +670 -0
  51. package/dist/doctor-BqXXxyST.js.map +1 -0
  52. package/dist/doctor-xp8WS8sr.cjs +24 -0
  53. package/dist/doctor-xp8WS8sr.cjs.map +1 -0
  54. package/dist/index.cjs +1 -1
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.js +64 -64
  57. package/dist/index.js.map +1 -1
  58. package/dist/tsx-extractor-AOjsbOmp.cjs +2 -0
  59. package/dist/{tsx-extractor-B0vFXziu.cjs.map → tsx-extractor-AOjsbOmp.cjs.map} +1 -1
  60. package/dist/tsx-extractor-C-HZNobu.js.map +1 -1
  61. package/dist/vue-extractor.cjs +1 -1
  62. package/dist/vue-extractor.cjs.map +1 -1
  63. package/dist/vue-extractor.js.map +1 -1
  64. package/package.json +2 -2
  65. package/dist/ai-provider.d.ts.map +0 -1
  66. package/dist/catalog.d.ts.map +0 -1
  67. package/dist/check.d.ts.map +0 -1
  68. package/dist/cli.d.ts.map +0 -1
  69. package/dist/compile-cache.d.ts.map +0 -1
  70. package/dist/compile-kXClO6q4.cjs +0 -8
  71. package/dist/compile-runner.d.ts.map +0 -1
  72. package/dist/compile-worker.d.ts.map +0 -1
  73. package/dist/compile.d.ts.map +0 -1
  74. package/dist/config-loader.d.ts +0 -2
  75. package/dist/config-loader.d.ts.map +0 -1
  76. package/dist/config.d.ts.map +0 -1
  77. package/dist/extract-cache-BioSaoFo.cjs +0 -10
  78. package/dist/extract-cache-BioSaoFo.cjs.map +0 -1
  79. package/dist/extract-cache-C-MI1_ll.js +0 -325
  80. package/dist/extract-cache-C-MI1_ll.js.map +0 -1
  81. package/dist/extract-cache.d.ts.map +0 -1
  82. package/dist/extract-runner.d.ts.map +0 -1
  83. package/dist/glossary.d.ts.map +0 -1
  84. package/dist/index.d.ts.map +0 -1
  85. package/dist/init.d.ts.map +0 -1
  86. package/dist/json-format.d.ts.map +0 -1
  87. package/dist/lint.d.ts.map +0 -1
  88. package/dist/migrate.d.ts.map +0 -1
  89. package/dist/parallel-compile.d.ts.map +0 -1
  90. package/dist/po-format.d.ts.map +0 -1
  91. package/dist/stats-format.d.ts.map +0 -1
  92. package/dist/translate-parse.d.ts.map +0 -1
  93. package/dist/translate-prompt.d.ts.map +0 -1
  94. package/dist/translate.d.ts.map +0 -1
  95. package/dist/tsx-extractor-B0vFXziu.cjs +0 -2
  96. package/dist/tsx-extractor.d.ts.map +0 -1
  97. package/dist/validation.d.ts.map +0 -1
  98. package/dist/vue-extractor.d.ts.map +0 -1
  99. /package/dist/{ai-provider.d.ts → cli/src/ai-provider.d.ts} +0 -0
  100. /package/dist/{check.d.ts → cli/src/check.d.ts} +0 -0
  101. /package/dist/{cli.d.ts → cli/src/cli.d.ts} +0 -0
  102. /package/dist/{compile-cache.d.ts → cli/src/compile-cache.d.ts} +0 -0
  103. /package/dist/{compile-runner.d.ts → cli/src/compile-runner.d.ts} +0 -0
  104. /package/dist/{compile-worker.d.ts → cli/src/compile-worker.d.ts} +0 -0
  105. /package/dist/{compile.d.ts → cli/src/compile.d.ts} +0 -0
  106. /package/dist/{extract-runner.d.ts → cli/src/extract-runner.d.ts} +0 -0
  107. /package/dist/{glossary.d.ts → cli/src/glossary.d.ts} +0 -0
  108. /package/dist/{init.d.ts → cli/src/init.d.ts} +0 -0
  109. /package/dist/{json-format.d.ts → cli/src/json-format.d.ts} +0 -0
  110. /package/dist/{lint.d.ts → cli/src/lint.d.ts} +0 -0
  111. /package/dist/{migrate.d.ts → cli/src/migrate.d.ts} +0 -0
  112. /package/dist/{parallel-compile.d.ts → cli/src/parallel-compile.d.ts} +0 -0
  113. /package/dist/{po-format.d.ts → cli/src/po-format.d.ts} +0 -0
  114. /package/dist/{stats-format.d.ts → cli/src/stats-format.d.ts} +0 -0
  115. /package/dist/{translate-parse.d.ts → cli/src/translate-parse.d.ts} +0 -0
  116. /package/dist/{translate-prompt.d.ts → cli/src/translate-prompt.d.ts} +0 -0
  117. /package/dist/{translate.d.ts → cli/src/translate.d.ts} +0 -0
  118. /package/dist/{validation.d.ts → cli/src/validation.d.ts} +0 -0
@@ -1,3 +1,3 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./extract-cache-BioSaoFo.cjs`);const e=require(`./tsx-extractor-B0vFXziu.cjs`);let t=require(`@fluenti/core/transform`),n=require(`@vue/compiler-sfc`);var r=1,i=2,a=7,o=6;function s(e){return e.filter(e=>e.type===i).map(e=>(e.content??``).trim()).join(``)}function c(e,t){let n=e.split(`|`).map(e=>e.trim()),r=[`one`,`other`,`zero`,`few`,`many`],i=[];if(n.length===2)i.push(`one {${n[0]}}`),i.push(`other {${n[1]}}`);else for(let e=0;e<n.length&&e<r.length;e++)i.push(`${r[e]} {${n[e]}}`);return`{${t}, plural, ${i.join(` `)}}`}var l=new Set([`id`,`value`,`context`,`comment`,`options`,`other`,`tag`]);function u(e,t,n){let r=[];for(let[e,n]of Object.entries(t))r.push(`${e} {${n}}`);return r.push(`other {${n}}`),`{${e}, select, ${r.join(` `)}}`}function d(e){let t=e.count??`count`,n=[`zero`,`one`,`two`,`few`,`many`,`other`],r=[],i=e.offset;for(let t of n)if(e[t]!==void 0){let n=t===`zero`?`=0`:t;r.push(`${n} {${e[t]}}`)}return r.length===0?``:`{${t}, plural, ${i?`offset:${i} `:``}${r.join(` `)}}`}function f(e,n,i,h){if(e.type===r){let r=e.props?.find(e=>e.type===a&&m(e)===`t`);if(r){let a=new Set([`plural`]),o=(r.modifiers??[]).map(e=>typeof e==`string`?e:e.content),l=o.includes(`plural`),u=o.filter(e=>!a.has(e)),d=r.arg?.content,f=d?[d,...u].join(`.`):void 0,p=s(e.children??[]);if(l){let e=c(p,r.exp?.content??`count`),a=f??(h??t.createMessageId)(e);i.push({id:a,message:e,origin:{file:n,line:r.loc.start.line,column:r.loc.start.column}})}else if(p){let e=f??(h??t.createMessageId)(p);i.push({id:e,message:p,origin:{file:n,line:r.loc.start.line,column:r.loc.start.column}})}}if(e.tag===`Trans`){let r=e.props?.find(e=>e.type===o&&m(e)===`message`),a=e.props?.find(e=>e.type===o&&m(e)===`id`),s=e.props?.find(e=>e.type===o&&m(e)===`context`),c=e.props?.find(e=>e.type===o&&m(e)===`comment`),l=s?.value?.content,u=c?.value?.content;if(r?.value){let o=r.value.content,s=h??t.createMessageId,c=a?.value?.content??s(o,l);i.push({id:c,message:o,...l===void 0?{}:{context:l},...u===void 0?{}:{comment:u},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}else if(e.children&&e.children.length>0){let r=p(e.children);if(r.message){let o=h??t.createMessageId,s=a?.value?.content??o(r.message,l);i.push({id:s,message:r.message,...l===void 0?{}:{context:l},...u===void 0?{}:{comment:u},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}}if(e.tag===`Plural`){let r={},s,c;for(let t of e.props??[])t.type===o&&t.value&&(r[m(t)]=t.value.content),t.type===a&&m(t)===`bind`&&t.arg?.content===`value`&&t.exp&&(s=t.exp.content),t.type===a&&m(t)===`bind`&&t.arg?.content===`offset`&&t.exp&&(c=t.exp.content);let l=s??r.count??`count`,u=c??r.offset,f=d({...r,count:l,...u===void 0?{}:{offset:u}});if(f){let a=r.id??(h??t.createMessageId)(f);i.push({id:a,message:f,origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}if(e.tag===`Select`){let r,s,c,d,f,p={};for(let t of e.props??[]){if(t.type===o&&t.value){let e=m(t);if(e===`id`){s=t.value.content;continue}if(e===`context`){c=t.value.content;continue}if(e===`comment`){d=t.value.content;continue}if(e===`other`){f=t.value.content;continue}if(l.has(e))continue;p[e]=t.value.content}t.type===a&&m(t)===`bind`&&t.arg?.content===`value`&&t.exp&&(r=t.exp.content)}if(r&&f&&Object.keys(p).length>0){let a=u(r,p,f),o=s??(h??t.createMessageId)(a,c);i.push({id:o,message:a,...c===void 0?{}:{context:c},...d===void 0?{}:{comment:d},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}}if(e.children)for(let t of e.children)f(t,n,i,h)}function p(e){let t=0,n=!1;return{message:e.map(e=>{if(e.type===i)return(e.content??``).trim()?e.content??``:``;if(e.type===r&&e.tag){n=!0;let r=t++;return`<${r}>${p(e.children??[]).message}</${r}>`}return``}).join(``).trim(),hasElements:n}}function m(e){return typeof e.name==`string`?e.name:e.name.content}function h(t,n,r){let i=[],a=/\{\{([\s\S]*?)\}\}/g,o;for(;(o=a.exec(t))!==null;){let a=o[1]?.trim();if(!a)continue;let s=e.t(a,n,r);if(s.length===0)continue;let c=t.slice(0,o.index).split(`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./doctor-xp8WS8sr.cjs`);const e=require(`./tsx-extractor-AOjsbOmp.cjs`);let t=require(`@fluenti/core/transform`),n=require(`@vue/compiler-sfc`);var r=1,i=2,a=7,o=6;function s(e){return e.filter(e=>e.type===i).map(e=>(e.content??``).trim()).join(``)}function c(e,t){let n=e.split(`|`).map(e=>e.trim()),r=[`one`,`other`,`zero`,`few`,`many`],i=[];if(n.length===2)i.push(`one {${n[0]}}`),i.push(`other {${n[1]}}`);else for(let e=0;e<n.length&&e<r.length;e++)i.push(`${r[e]} {${n[e]}}`);return`{${t}, plural, ${i.join(` `)}}`}var l=new Set([`id`,`value`,`context`,`comment`,`options`,`other`,`tag`]);function u(e,t,n){let r=[];for(let[e,n]of Object.entries(t))r.push(`${e} {${n}}`);return r.push(`other {${n}}`),`{${e}, select, ${r.join(` `)}}`}function d(e){let t=e.count??`count`,n=[`zero`,`one`,`two`,`few`,`many`,`other`],r=[],i=e.offset;for(let t of n)if(e[t]!==void 0){let n=t===`zero`?`=0`:t;r.push(`${n} {${e[t]}}`)}return r.length===0?``:`{${t}, plural, ${i?`offset:${i} `:``}${r.join(` `)}}`}function f(e,n,i,h){if(e.type===r){let r=e.props?.find(e=>e.type===a&&m(e)===`t`);if(r){let a=new Set([`plural`]),o=(r.modifiers??[]).map(e=>typeof e==`string`?e:e.content),l=o.includes(`plural`),u=o.filter(e=>!a.has(e)),d=r.arg?.content,f=d?[d,...u].join(`.`):void 0,p=s(e.children??[]);if(l){let e=c(p,r.exp?.content??`count`),a=f??(h??t.createMessageId)(e);i.push({id:a,message:e,origin:{file:n,line:r.loc.start.line,column:r.loc.start.column}})}else if(p){let e=f??(h??t.createMessageId)(p);i.push({id:e,message:p,origin:{file:n,line:r.loc.start.line,column:r.loc.start.column}})}}if(e.tag===`Trans`){let r=e.props?.find(e=>e.type===o&&m(e)===`message`),a=e.props?.find(e=>e.type===o&&m(e)===`id`),s=e.props?.find(e=>e.type===o&&m(e)===`context`),c=e.props?.find(e=>e.type===o&&m(e)===`comment`),l=s?.value?.content,u=c?.value?.content;if(r?.value){let o=r.value.content,s=h??t.createMessageId,c=a?.value?.content??s(o,l);i.push({id:c,message:o,...l===void 0?{}:{context:l},...u===void 0?{}:{comment:u},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}else if(e.children&&e.children.length>0){let r=p(e.children);if(r.message){let o=h??t.createMessageId,s=a?.value?.content??o(r.message,l);i.push({id:s,message:r.message,...l===void 0?{}:{context:l},...u===void 0?{}:{comment:u},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}}if(e.tag===`Plural`){let r={},s,c;for(let t of e.props??[])t.type===o&&t.value&&(r[m(t)]=t.value.content),t.type===a&&m(t)===`bind`&&t.arg?.content===`value`&&t.exp&&(s=t.exp.content),t.type===a&&m(t)===`bind`&&t.arg?.content===`offset`&&t.exp&&(c=t.exp.content);let l=s??r.count??`count`,u=c??r.offset,f=d({...r,count:l,...u===void 0?{}:{offset:u}});if(f){let a=r.id??(h??t.createMessageId)(f);i.push({id:a,message:f,origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}if(e.tag===`Select`){let r,s,c,d,f,p={};for(let t of e.props??[]){if(t.type===o&&t.value){let e=m(t);if(e===`id`){s=t.value.content;continue}if(e===`context`){c=t.value.content;continue}if(e===`comment`){d=t.value.content;continue}if(e===`other`){f=t.value.content;continue}if(l.has(e))continue;p[e]=t.value.content}t.type===a&&m(t)===`bind`&&t.arg?.content===`value`&&t.exp&&(r=t.exp.content)}if(r&&f&&Object.keys(p).length>0){let a=u(r,p,f),o=s??(h??t.createMessageId)(a,c);i.push({id:o,message:a,...c===void 0?{}:{context:c},...d===void 0?{}:{comment:d},origin:{file:n,line:e.loc.start.line,column:e.loc.start.column}})}}}if(e.children)for(let t of e.children)f(t,n,i,h)}function p(e){let t=0,n=!1;return{message:e.map(e=>{if(e.type===i)return(e.content??``).trim()?e.content??``:``;if(e.type===r&&e.tag){n=!0;let r=t++;return`<${r}>${p(e.children??[]).message}</${r}>`}return``}).join(``).trim(),hasElements:n}}function m(e){return typeof e.name==`string`?e.name:e.name.content}function h(t,n,r){let i=[],a=/\{\{([\s\S]*?)\}\}/g,o;for(;(o=a.exec(t))!==null;){let a=o[1]?.trim();if(!a)continue;let s=e.t(a,n,r);if(s.length===0)continue;let c=t.slice(0,o.index).split(`
2
2
  `).length-1;for(let e of s)i.push({...e,origin:{...e.origin,line:e.origin.line+c}})}return i}function g(t,r,i){let a=[],{descriptor:o}=(0,n.parse)(t,{filename:r});if(o.template?.ast&&f(o.template.ast,r,a,i),o.template?.content){let t=e.t(o.template.content,r,i),n=o.template.loc.start.line-1,s=new Set(a.map(e=>e.id));for(let e of t)s.has(e.id)||a.push({...e,origin:{...e.origin,line:e.origin.line+n}});let c=new Set(a.map(e=>e.id)),l=h(o.template.content,r,i);for(let e of l)c.has(e.id)||a.push({...e,origin:{...e.origin,line:e.origin.line+n}})}if(o.scriptSetup?.content){let t=e.t(o.scriptSetup.content,r,i),n=o.scriptSetup.loc.start.line-1;for(let e of t)a.push({...e,origin:{...e.origin,line:e.origin.line+n}})}if(o.script?.content){let t=e.t(o.script.content,r,i),n=o.script.loc.start.line-1;for(let e of t)a.push({...e,origin:{...e.origin,line:e.origin.line+n}})}return a}exports.extractFromVue=g;
3
3
  //# sourceMappingURL=vue-extractor.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"vue-extractor.cjs","names":[],"sources":["../src/vue-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\nimport { parse as parseSFC } from '@vue/compiler-sfc'\nimport { createMessageId } from '@fluenti/core/transform'\nimport { extractFromTsx } from './tsx-extractor'\n\n// Vue template AST node types\nconst ELEMENT_NODE = 1\nconst TEXT_NODE = 2\nconst DIRECTIVE_PROP = 7\nconst ATTRIBUTE_PROP = 6\n\ninterface LocInfo {\n line: number\n column: number\n offset: number\n}\n\ninterface SourceLoc {\n start: LocInfo\n end: LocInfo\n source: string\n}\n\ninterface TemplateNode {\n type: number\n tag?: string\n tagType?: number\n props?: TemplateProp[]\n children?: TemplateNode[]\n content?: string\n loc: SourceLoc\n}\n\ninterface TemplateProp {\n type: number\n name: string | { content: string }\n rawName?: string\n arg?: { content: string; isStatic: boolean }\n exp?: { content: string }\n modifiers?: Array<{ content: string } | string>\n value?: { content: string }\n nameLoc?: SourceLoc\n loc: SourceLoc\n}\n\nfunction getTextContent(children: TemplateNode[]): string {\n return children\n .filter((c) => c.type === TEXT_NODE)\n .map((c) => (c.content ?? '').trim())\n .join('')\n}\n\nfunction buildPluralICUFromPipe(text: string, countVar: string): string {\n const forms = text.split('|').map((s) => s.trim())\n const categories = ['one', 'other', 'zero', 'few', 'many']\n const options: string[] = []\n\n if (forms.length === 2) {\n options.push(`one {${forms[0]}}`)\n options.push(`other {${forms[1]}}`)\n } else {\n for (let i = 0; i < forms.length && i < categories.length; i++) {\n options.push(`${categories[i]} {${forms[i]}}`)\n }\n }\n\n return `{${countVar}, plural, ${options.join(' ')}}`\n}\n\nconst SELECT_RESERVED_PROPS = new Set(['id', 'value', 'context', 'comment', 'options', 'other', 'tag'])\n\nfunction buildSelectICUFromProps(varName: string, cases: Record<string, string>, other: string): string {\n const options: string[] = []\n for (const [key, value] of Object.entries(cases)) {\n options.push(`${key} {${value}}`)\n }\n options.push(`other {${other}}`)\n return `{${varName}, select, ${options.join(' ')}}`\n}\n\nfunction buildPluralICUFromProps(props: Record<string, string>): string {\n const countVar = props['count'] ?? 'count'\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other']\n const options: string[] = []\n const offset = props['offset']\n\n for (const cat of categories) {\n if (props[cat] !== undefined) {\n const key = cat === 'zero' ? '=0' : cat\n options.push(`${key} {${props[cat]}}`)\n }\n }\n\n if (options.length === 0) return ''\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction walkTemplate(\n node: TemplateNode,\n filename: string,\n messages: ExtractedMessage[],\n idGenerator?: (message: string, context?: string) => string,\n): void {\n if (node.type === ELEMENT_NODE) {\n const vtDirective = node.props?.find(\n (p) => p.type === DIRECTIVE_PROP && getPropName(p) === 't',\n )\n\n if (vtDirective) {\n const RESERVED_MODIFIERS = new Set(['plural'])\n const modifiers = (vtDirective.modifiers ?? []).map(\n (m: string | { content: string }) => (typeof m === 'string' ? m : m.content),\n )\n const isPlural = modifiers.includes('plural')\n // Reconstruct dotted ID: v-t:checkout.title → arg=\"checkout\", modifier=\"title\" → \"checkout.title\"\n // Non-reserved modifiers are treated as ID path segments\n const idSegments = modifiers.filter((m: string) => !RESERVED_MODIFIERS.has(m))\n const argContent = vtDirective.arg?.content\n const explicitId = argContent\n ? [argContent, ...idSegments].join('.')\n : undefined\n const textContent = getTextContent(node.children ?? [])\n\n if (isPlural) {\n const countVar = vtDirective.exp?.content ?? 'count'\n const message = buildPluralICUFromPipe(textContent, countVar)\n const id = explicitId ?? (idGenerator ?? createMessageId)(message)\n messages.push({\n id,\n message,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n } else if (textContent) {\n const id = explicitId ?? (idGenerator ?? createMessageId)(textContent)\n messages.push({\n id,\n message: textContent,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Trans') {\n const messageProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'message',\n )\n const idProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'id',\n )\n const contextProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'context',\n )\n const commentProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'comment',\n )\n const context = contextProp?.value?.content\n const comment = commentProp?.value?.content\n\n if (messageProp?.value) {\n // Old API: <Trans message=\"...\" />\n const message = messageProp.value.content\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(message, context)\n messages.push({\n id,\n message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n } else if (node.children && node.children.length > 0) {\n // New API: <Trans>content with <a>rich text</a></Trans>\n const richText = extractRichTextFromTemplateChildren(node.children)\n if (richText.message) {\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(richText.message, context)\n messages.push({\n id,\n message: richText.message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.tag === 'Plural') {\n const propsMap: Record<string, string> = {}\n let valueExpr: string | undefined\n let offsetExpr: string | undefined\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n propsMap[getPropName(prop)] = prop.value.content\n }\n // Handle :value=\"expr\" binding (directive prop)\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n valueExpr = prop.exp.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'offset' && prop.exp) {\n offsetExpr = prop.exp.content\n }\n }\n\n // Use :value binding expression as count variable, fall back to 'count' static prop\n const countVar = valueExpr ?? propsMap['count'] ?? 'count'\n const offset = offsetExpr ?? propsMap['offset']\n const pluralMessage = buildPluralICUFromProps({\n ...propsMap,\n count: countVar,\n ...(offset !== undefined ? { offset } : {}),\n })\n if (pluralMessage) {\n const id = propsMap['id'] ?? (idGenerator ?? createMessageId)(pluralMessage)\n messages.push({\n id,\n message: pluralMessage,\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Select') {\n let varName: string | undefined\n let selectId: string | undefined\n let selectContext: string | undefined\n let selectComment: string | undefined\n let other: string | undefined\n const cases: Record<string, string> = {}\n\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n const name = getPropName(prop)\n if (name === 'id') { selectId = prop.value.content; continue }\n if (name === 'context') { selectContext = prop.value.content; continue }\n if (name === 'comment') { selectComment = prop.value.content; continue }\n if (name === 'other') { other = prop.value.content; continue }\n if (SELECT_RESERVED_PROPS.has(name)) continue\n cases[name] = prop.value.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n varName = prop.exp.content\n }\n }\n\n if (varName && other && Object.keys(cases).length > 0) {\n const message = buildSelectICUFromProps(varName, cases, other)\n const generateId = idGenerator ?? createMessageId\n const id = selectId ?? generateId(message, selectContext)\n messages.push({\n id,\n message,\n ...(selectContext !== undefined ? { context: selectContext } : {}),\n ...(selectComment !== undefined ? { comment: selectComment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.children) {\n for (const child of node.children) {\n walkTemplate(child, filename, messages, idGenerator)\n }\n }\n}\n\nfunction extractRichTextFromTemplateChildren(\n children: TemplateNode[],\n): { message: string; hasElements: boolean } {\n let elementIndex = 0\n let hasElements = false\n\n const parts = children.map((child) => {\n if (child.type === TEXT_NODE) {\n return (child.content ?? '').trim() ? child.content ?? '' : ''\n }\n if (child.type === ELEMENT_NODE && child.tag) {\n hasElements = true\n const idx = elementIndex++\n const innerText = extractRichTextFromTemplateChildren(child.children ?? []).message\n return `<${idx}>${innerText}</${idx}>`\n }\n return ''\n })\n\n return {\n message: parts.join('').trim(),\n hasElements,\n }\n}\n\nfunction getPropName(prop: TemplateProp): string {\n if (typeof prop.name === 'string') return prop.name\n return prop.name.content\n}\n\nfunction extractTemplateInterpolations(\n content: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n const interpolationRegex = /\\{\\{([\\s\\S]*?)\\}\\}/g\n let match: RegExpExecArray | null\n\n while ((match = interpolationRegex.exec(content)) !== null) {\n const expression = match[1]?.trim()\n if (!expression) continue\n\n const extracted = extractFromTsx(expression, filename, idGenerator)\n if (extracted.length === 0) continue\n\n const lineOffset = content.slice(0, match.index).split('\\n').length - 1\n for (const msg of extracted) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n\n/** Extract messages from Vue SFC files */\nexport function extractFromVue(\n code: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n\n const { descriptor } = parseSFC(code, { filename })\n\n if (descriptor.template?.ast) {\n walkTemplate(descriptor.template.ast as unknown as TemplateNode, filename, messages, idGenerator)\n }\n\n // Also extract t() function calls from raw template source\n // (picks up t('source text') in template expressions like {{ t('...') }})\n if (descriptor.template?.content) {\n const templateMessages = extractFromTsx(descriptor.template.content, filename, idGenerator)\n const templateLoc = descriptor.template.loc\n const lineOffset = templateLoc.start.line - 1\n const existingIds = new Set(messages.map((m) => m.id))\n for (const msg of templateMessages) {\n if (!existingIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n // Rebuild the set after template pass to include newly added IDs\n const afterTemplateIds = new Set(messages.map((m) => m.id))\n const interpolationMessages = extractTemplateInterpolations(descriptor.template.content, filename, idGenerator)\n for (const msg of interpolationMessages) {\n if (!afterTemplateIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n }\n\n if (descriptor.scriptSetup?.content) {\n const scriptMessages = extractFromTsx(descriptor.scriptSetup.content, filename, idGenerator)\n const scriptLoc = descriptor.scriptSetup.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n if (descriptor.script?.content) {\n const scriptMessages = extractFromTsx(descriptor.script.content, filename, idGenerator)\n const scriptLoc = descriptor.script.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vue-extractor.cjs","names":[],"sources":["../src/vue-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/compiler'\nimport { parse as parseSFC } from '@vue/compiler-sfc'\nimport { createMessageId } from '@fluenti/core/transform'\nimport { extractFromTsx } from './tsx-extractor'\n\n// Vue template AST node types\nconst ELEMENT_NODE = 1\nconst TEXT_NODE = 2\nconst DIRECTIVE_PROP = 7\nconst ATTRIBUTE_PROP = 6\n\ninterface LocInfo {\n line: number\n column: number\n offset: number\n}\n\ninterface SourceLoc {\n start: LocInfo\n end: LocInfo\n source: string\n}\n\ninterface TemplateNode {\n type: number\n tag?: string\n tagType?: number\n props?: TemplateProp[]\n children?: TemplateNode[]\n content?: string\n loc: SourceLoc\n}\n\ninterface TemplateProp {\n type: number\n name: string | { content: string }\n rawName?: string\n arg?: { content: string; isStatic: boolean }\n exp?: { content: string }\n modifiers?: Array<{ content: string } | string>\n value?: { content: string }\n nameLoc?: SourceLoc\n loc: SourceLoc\n}\n\nfunction getTextContent(children: TemplateNode[]): string {\n return children\n .filter((c) => c.type === TEXT_NODE)\n .map((c) => (c.content ?? '').trim())\n .join('')\n}\n\nfunction buildPluralICUFromPipe(text: string, countVar: string): string {\n const forms = text.split('|').map((s) => s.trim())\n const categories = ['one', 'other', 'zero', 'few', 'many']\n const options: string[] = []\n\n if (forms.length === 2) {\n options.push(`one {${forms[0]}}`)\n options.push(`other {${forms[1]}}`)\n } else {\n for (let i = 0; i < forms.length && i < categories.length; i++) {\n options.push(`${categories[i]} {${forms[i]}}`)\n }\n }\n\n return `{${countVar}, plural, ${options.join(' ')}}`\n}\n\nconst SELECT_RESERVED_PROPS = new Set(['id', 'value', 'context', 'comment', 'options', 'other', 'tag'])\n\nfunction buildSelectICUFromProps(varName: string, cases: Record<string, string>, other: string): string {\n const options: string[] = []\n for (const [key, value] of Object.entries(cases)) {\n options.push(`${key} {${value}}`)\n }\n options.push(`other {${other}}`)\n return `{${varName}, select, ${options.join(' ')}}`\n}\n\nfunction buildPluralICUFromProps(props: Record<string, string>): string {\n const countVar = props['count'] ?? 'count'\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other']\n const options: string[] = []\n const offset = props['offset']\n\n for (const cat of categories) {\n if (props[cat] !== undefined) {\n const key = cat === 'zero' ? '=0' : cat\n options.push(`${key} {${props[cat]}}`)\n }\n }\n\n if (options.length === 0) return ''\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction walkTemplate(\n node: TemplateNode,\n filename: string,\n messages: ExtractedMessage[],\n idGenerator?: (message: string, context?: string) => string,\n): void {\n if (node.type === ELEMENT_NODE) {\n const vtDirective = node.props?.find(\n (p) => p.type === DIRECTIVE_PROP && getPropName(p) === 't',\n )\n\n if (vtDirective) {\n const RESERVED_MODIFIERS = new Set(['plural'])\n const modifiers = (vtDirective.modifiers ?? []).map(\n (m: string | { content: string }) => (typeof m === 'string' ? m : m.content),\n )\n const isPlural = modifiers.includes('plural')\n // Reconstruct dotted ID: v-t:checkout.title → arg=\"checkout\", modifier=\"title\" → \"checkout.title\"\n // Non-reserved modifiers are treated as ID path segments\n const idSegments = modifiers.filter((m: string) => !RESERVED_MODIFIERS.has(m))\n const argContent = vtDirective.arg?.content\n const explicitId = argContent\n ? [argContent, ...idSegments].join('.')\n : undefined\n const textContent = getTextContent(node.children ?? [])\n\n if (isPlural) {\n const countVar = vtDirective.exp?.content ?? 'count'\n const message = buildPluralICUFromPipe(textContent, countVar)\n const id = explicitId ?? (idGenerator ?? createMessageId)(message)\n messages.push({\n id,\n message,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n } else if (textContent) {\n const id = explicitId ?? (idGenerator ?? createMessageId)(textContent)\n messages.push({\n id,\n message: textContent,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Trans') {\n const messageProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'message',\n )\n const idProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'id',\n )\n const contextProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'context',\n )\n const commentProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'comment',\n )\n const context = contextProp?.value?.content\n const comment = commentProp?.value?.content\n\n if (messageProp?.value) {\n // Old API: <Trans message=\"...\" />\n const message = messageProp.value.content\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(message, context)\n messages.push({\n id,\n message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n } else if (node.children && node.children.length > 0) {\n // New API: <Trans>content with <a>rich text</a></Trans>\n const richText = extractRichTextFromTemplateChildren(node.children)\n if (richText.message) {\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(richText.message, context)\n messages.push({\n id,\n message: richText.message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.tag === 'Plural') {\n const propsMap: Record<string, string> = {}\n let valueExpr: string | undefined\n let offsetExpr: string | undefined\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n propsMap[getPropName(prop)] = prop.value.content\n }\n // Handle :value=\"expr\" binding (directive prop)\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n valueExpr = prop.exp.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'offset' && prop.exp) {\n offsetExpr = prop.exp.content\n }\n }\n\n // Use :value binding expression as count variable, fall back to 'count' static prop\n const countVar = valueExpr ?? propsMap['count'] ?? 'count'\n const offset = offsetExpr ?? propsMap['offset']\n const pluralMessage = buildPluralICUFromProps({\n ...propsMap,\n count: countVar,\n ...(offset !== undefined ? { offset } : {}),\n })\n if (pluralMessage) {\n const id = propsMap['id'] ?? (idGenerator ?? createMessageId)(pluralMessage)\n messages.push({\n id,\n message: pluralMessage,\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Select') {\n let varName: string | undefined\n let selectId: string | undefined\n let selectContext: string | undefined\n let selectComment: string | undefined\n let other: string | undefined\n const cases: Record<string, string> = {}\n\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n const name = getPropName(prop)\n if (name === 'id') { selectId = prop.value.content; continue }\n if (name === 'context') { selectContext = prop.value.content; continue }\n if (name === 'comment') { selectComment = prop.value.content; continue }\n if (name === 'other') { other = prop.value.content; continue }\n if (SELECT_RESERVED_PROPS.has(name)) continue\n cases[name] = prop.value.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n varName = prop.exp.content\n }\n }\n\n if (varName && other && Object.keys(cases).length > 0) {\n const message = buildSelectICUFromProps(varName, cases, other)\n const generateId = idGenerator ?? createMessageId\n const id = selectId ?? generateId(message, selectContext)\n messages.push({\n id,\n message,\n ...(selectContext !== undefined ? { context: selectContext } : {}),\n ...(selectComment !== undefined ? { comment: selectComment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.children) {\n for (const child of node.children) {\n walkTemplate(child, filename, messages, idGenerator)\n }\n }\n}\n\nfunction extractRichTextFromTemplateChildren(\n children: TemplateNode[],\n): { message: string; hasElements: boolean } {\n let elementIndex = 0\n let hasElements = false\n\n const parts = children.map((child) => {\n if (child.type === TEXT_NODE) {\n return (child.content ?? '').trim() ? child.content ?? '' : ''\n }\n if (child.type === ELEMENT_NODE && child.tag) {\n hasElements = true\n const idx = elementIndex++\n const innerText = extractRichTextFromTemplateChildren(child.children ?? []).message\n return `<${idx}>${innerText}</${idx}>`\n }\n return ''\n })\n\n return {\n message: parts.join('').trim(),\n hasElements,\n }\n}\n\nfunction getPropName(prop: TemplateProp): string {\n if (typeof prop.name === 'string') return prop.name\n return prop.name.content\n}\n\nfunction extractTemplateInterpolations(\n content: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n const interpolationRegex = /\\{\\{([\\s\\S]*?)\\}\\}/g\n let match: RegExpExecArray | null\n\n while ((match = interpolationRegex.exec(content)) !== null) {\n const expression = match[1]?.trim()\n if (!expression) continue\n\n const extracted = extractFromTsx(expression, filename, idGenerator)\n if (extracted.length === 0) continue\n\n const lineOffset = content.slice(0, match.index).split('\\n').length - 1\n for (const msg of extracted) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n\n/** Extract messages from Vue SFC files */\nexport function extractFromVue(\n code: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n\n const { descriptor } = parseSFC(code, { filename })\n\n if (descriptor.template?.ast) {\n walkTemplate(descriptor.template.ast as unknown as TemplateNode, filename, messages, idGenerator)\n }\n\n // Also extract t() function calls from raw template source\n // (picks up t('source text') in template expressions like {{ t('...') }})\n if (descriptor.template?.content) {\n const templateMessages = extractFromTsx(descriptor.template.content, filename, idGenerator)\n const templateLoc = descriptor.template.loc\n const lineOffset = templateLoc.start.line - 1\n const existingIds = new Set(messages.map((m) => m.id))\n for (const msg of templateMessages) {\n if (!existingIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n // Rebuild the set after template pass to include newly added IDs\n const afterTemplateIds = new Set(messages.map((m) => m.id))\n const interpolationMessages = extractTemplateInterpolations(descriptor.template.content, filename, idGenerator)\n for (const msg of interpolationMessages) {\n if (!afterTemplateIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n }\n\n if (descriptor.scriptSetup?.content) {\n const scriptMessages = extractFromTsx(descriptor.scriptSetup.content, filename, idGenerator)\n const scriptLoc = descriptor.scriptSetup.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n if (descriptor.script?.content) {\n const scriptMessages = extractFromTsx(descriptor.script.content, filename, idGenerator)\n const scriptLoc = descriptor.script.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"vue-extractor.js","names":[],"sources":["../src/vue-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\nimport { parse as parseSFC } from '@vue/compiler-sfc'\nimport { createMessageId } from '@fluenti/core/transform'\nimport { extractFromTsx } from './tsx-extractor'\n\n// Vue template AST node types\nconst ELEMENT_NODE = 1\nconst TEXT_NODE = 2\nconst DIRECTIVE_PROP = 7\nconst ATTRIBUTE_PROP = 6\n\ninterface LocInfo {\n line: number\n column: number\n offset: number\n}\n\ninterface SourceLoc {\n start: LocInfo\n end: LocInfo\n source: string\n}\n\ninterface TemplateNode {\n type: number\n tag?: string\n tagType?: number\n props?: TemplateProp[]\n children?: TemplateNode[]\n content?: string\n loc: SourceLoc\n}\n\ninterface TemplateProp {\n type: number\n name: string | { content: string }\n rawName?: string\n arg?: { content: string; isStatic: boolean }\n exp?: { content: string }\n modifiers?: Array<{ content: string } | string>\n value?: { content: string }\n nameLoc?: SourceLoc\n loc: SourceLoc\n}\n\nfunction getTextContent(children: TemplateNode[]): string {\n return children\n .filter((c) => c.type === TEXT_NODE)\n .map((c) => (c.content ?? '').trim())\n .join('')\n}\n\nfunction buildPluralICUFromPipe(text: string, countVar: string): string {\n const forms = text.split('|').map((s) => s.trim())\n const categories = ['one', 'other', 'zero', 'few', 'many']\n const options: string[] = []\n\n if (forms.length === 2) {\n options.push(`one {${forms[0]}}`)\n options.push(`other {${forms[1]}}`)\n } else {\n for (let i = 0; i < forms.length && i < categories.length; i++) {\n options.push(`${categories[i]} {${forms[i]}}`)\n }\n }\n\n return `{${countVar}, plural, ${options.join(' ')}}`\n}\n\nconst SELECT_RESERVED_PROPS = new Set(['id', 'value', 'context', 'comment', 'options', 'other', 'tag'])\n\nfunction buildSelectICUFromProps(varName: string, cases: Record<string, string>, other: string): string {\n const options: string[] = []\n for (const [key, value] of Object.entries(cases)) {\n options.push(`${key} {${value}}`)\n }\n options.push(`other {${other}}`)\n return `{${varName}, select, ${options.join(' ')}}`\n}\n\nfunction buildPluralICUFromProps(props: Record<string, string>): string {\n const countVar = props['count'] ?? 'count'\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other']\n const options: string[] = []\n const offset = props['offset']\n\n for (const cat of categories) {\n if (props[cat] !== undefined) {\n const key = cat === 'zero' ? '=0' : cat\n options.push(`${key} {${props[cat]}}`)\n }\n }\n\n if (options.length === 0) return ''\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction walkTemplate(\n node: TemplateNode,\n filename: string,\n messages: ExtractedMessage[],\n idGenerator?: (message: string, context?: string) => string,\n): void {\n if (node.type === ELEMENT_NODE) {\n const vtDirective = node.props?.find(\n (p) => p.type === DIRECTIVE_PROP && getPropName(p) === 't',\n )\n\n if (vtDirective) {\n const RESERVED_MODIFIERS = new Set(['plural'])\n const modifiers = (vtDirective.modifiers ?? []).map(\n (m: string | { content: string }) => (typeof m === 'string' ? m : m.content),\n )\n const isPlural = modifiers.includes('plural')\n // Reconstruct dotted ID: v-t:checkout.title → arg=\"checkout\", modifier=\"title\" → \"checkout.title\"\n // Non-reserved modifiers are treated as ID path segments\n const idSegments = modifiers.filter((m: string) => !RESERVED_MODIFIERS.has(m))\n const argContent = vtDirective.arg?.content\n const explicitId = argContent\n ? [argContent, ...idSegments].join('.')\n : undefined\n const textContent = getTextContent(node.children ?? [])\n\n if (isPlural) {\n const countVar = vtDirective.exp?.content ?? 'count'\n const message = buildPluralICUFromPipe(textContent, countVar)\n const id = explicitId ?? (idGenerator ?? createMessageId)(message)\n messages.push({\n id,\n message,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n } else if (textContent) {\n const id = explicitId ?? (idGenerator ?? createMessageId)(textContent)\n messages.push({\n id,\n message: textContent,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Trans') {\n const messageProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'message',\n )\n const idProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'id',\n )\n const contextProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'context',\n )\n const commentProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'comment',\n )\n const context = contextProp?.value?.content\n const comment = commentProp?.value?.content\n\n if (messageProp?.value) {\n // Old API: <Trans message=\"...\" />\n const message = messageProp.value.content\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(message, context)\n messages.push({\n id,\n message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n } else if (node.children && node.children.length > 0) {\n // New API: <Trans>content with <a>rich text</a></Trans>\n const richText = extractRichTextFromTemplateChildren(node.children)\n if (richText.message) {\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(richText.message, context)\n messages.push({\n id,\n message: richText.message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.tag === 'Plural') {\n const propsMap: Record<string, string> = {}\n let valueExpr: string | undefined\n let offsetExpr: string | undefined\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n propsMap[getPropName(prop)] = prop.value.content\n }\n // Handle :value=\"expr\" binding (directive prop)\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n valueExpr = prop.exp.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'offset' && prop.exp) {\n offsetExpr = prop.exp.content\n }\n }\n\n // Use :value binding expression as count variable, fall back to 'count' static prop\n const countVar = valueExpr ?? propsMap['count'] ?? 'count'\n const offset = offsetExpr ?? propsMap['offset']\n const pluralMessage = buildPluralICUFromProps({\n ...propsMap,\n count: countVar,\n ...(offset !== undefined ? { offset } : {}),\n })\n if (pluralMessage) {\n const id = propsMap['id'] ?? (idGenerator ?? createMessageId)(pluralMessage)\n messages.push({\n id,\n message: pluralMessage,\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Select') {\n let varName: string | undefined\n let selectId: string | undefined\n let selectContext: string | undefined\n let selectComment: string | undefined\n let other: string | undefined\n const cases: Record<string, string> = {}\n\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n const name = getPropName(prop)\n if (name === 'id') { selectId = prop.value.content; continue }\n if (name === 'context') { selectContext = prop.value.content; continue }\n if (name === 'comment') { selectComment = prop.value.content; continue }\n if (name === 'other') { other = prop.value.content; continue }\n if (SELECT_RESERVED_PROPS.has(name)) continue\n cases[name] = prop.value.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n varName = prop.exp.content\n }\n }\n\n if (varName && other && Object.keys(cases).length > 0) {\n const message = buildSelectICUFromProps(varName, cases, other)\n const generateId = idGenerator ?? createMessageId\n const id = selectId ?? generateId(message, selectContext)\n messages.push({\n id,\n message,\n ...(selectContext !== undefined ? { context: selectContext } : {}),\n ...(selectComment !== undefined ? { comment: selectComment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.children) {\n for (const child of node.children) {\n walkTemplate(child, filename, messages, idGenerator)\n }\n }\n}\n\nfunction extractRichTextFromTemplateChildren(\n children: TemplateNode[],\n): { message: string; hasElements: boolean } {\n let elementIndex = 0\n let hasElements = false\n\n const parts = children.map((child) => {\n if (child.type === TEXT_NODE) {\n return (child.content ?? '').trim() ? child.content ?? '' : ''\n }\n if (child.type === ELEMENT_NODE && child.tag) {\n hasElements = true\n const idx = elementIndex++\n const innerText = extractRichTextFromTemplateChildren(child.children ?? []).message\n return `<${idx}>${innerText}</${idx}>`\n }\n return ''\n })\n\n return {\n message: parts.join('').trim(),\n hasElements,\n }\n}\n\nfunction getPropName(prop: TemplateProp): string {\n if (typeof prop.name === 'string') return prop.name\n return prop.name.content\n}\n\nfunction extractTemplateInterpolations(\n content: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n const interpolationRegex = /\\{\\{([\\s\\S]*?)\\}\\}/g\n let match: RegExpExecArray | null\n\n while ((match = interpolationRegex.exec(content)) !== null) {\n const expression = match[1]?.trim()\n if (!expression) continue\n\n const extracted = extractFromTsx(expression, filename, idGenerator)\n if (extracted.length === 0) continue\n\n const lineOffset = content.slice(0, match.index).split('\\n').length - 1\n for (const msg of extracted) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n\n/** Extract messages from Vue SFC files */\nexport function extractFromVue(\n code: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n\n const { descriptor } = parseSFC(code, { filename })\n\n if (descriptor.template?.ast) {\n walkTemplate(descriptor.template.ast as unknown as TemplateNode, filename, messages, idGenerator)\n }\n\n // Also extract t() function calls from raw template source\n // (picks up t('source text') in template expressions like {{ t('...') }})\n if (descriptor.template?.content) {\n const templateMessages = extractFromTsx(descriptor.template.content, filename, idGenerator)\n const templateLoc = descriptor.template.loc\n const lineOffset = templateLoc.start.line - 1\n const existingIds = new Set(messages.map((m) => m.id))\n for (const msg of templateMessages) {\n if (!existingIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n // Rebuild the set after template pass to include newly added IDs\n const afterTemplateIds = new Set(messages.map((m) => m.id))\n const interpolationMessages = extractTemplateInterpolations(descriptor.template.content, filename, idGenerator)\n for (const msg of interpolationMessages) {\n if (!afterTemplateIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n }\n\n if (descriptor.scriptSetup?.content) {\n const scriptMessages = extractFromTsx(descriptor.scriptSetup.content, filename, idGenerator)\n const scriptLoc = descriptor.scriptSetup.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n if (descriptor.script?.content) {\n const scriptMessages = extractFromTsx(descriptor.script.content, filename, idGenerator)\n const scriptLoc = descriptor.script.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vue-extractor.js","names":[],"sources":["../src/vue-extractor.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/compiler'\nimport { parse as parseSFC } from '@vue/compiler-sfc'\nimport { createMessageId } from '@fluenti/core/transform'\nimport { extractFromTsx } from './tsx-extractor'\n\n// Vue template AST node types\nconst ELEMENT_NODE = 1\nconst TEXT_NODE = 2\nconst DIRECTIVE_PROP = 7\nconst ATTRIBUTE_PROP = 6\n\ninterface LocInfo {\n line: number\n column: number\n offset: number\n}\n\ninterface SourceLoc {\n start: LocInfo\n end: LocInfo\n source: string\n}\n\ninterface TemplateNode {\n type: number\n tag?: string\n tagType?: number\n props?: TemplateProp[]\n children?: TemplateNode[]\n content?: string\n loc: SourceLoc\n}\n\ninterface TemplateProp {\n type: number\n name: string | { content: string }\n rawName?: string\n arg?: { content: string; isStatic: boolean }\n exp?: { content: string }\n modifiers?: Array<{ content: string } | string>\n value?: { content: string }\n nameLoc?: SourceLoc\n loc: SourceLoc\n}\n\nfunction getTextContent(children: TemplateNode[]): string {\n return children\n .filter((c) => c.type === TEXT_NODE)\n .map((c) => (c.content ?? '').trim())\n .join('')\n}\n\nfunction buildPluralICUFromPipe(text: string, countVar: string): string {\n const forms = text.split('|').map((s) => s.trim())\n const categories = ['one', 'other', 'zero', 'few', 'many']\n const options: string[] = []\n\n if (forms.length === 2) {\n options.push(`one {${forms[0]}}`)\n options.push(`other {${forms[1]}}`)\n } else {\n for (let i = 0; i < forms.length && i < categories.length; i++) {\n options.push(`${categories[i]} {${forms[i]}}`)\n }\n }\n\n return `{${countVar}, plural, ${options.join(' ')}}`\n}\n\nconst SELECT_RESERVED_PROPS = new Set(['id', 'value', 'context', 'comment', 'options', 'other', 'tag'])\n\nfunction buildSelectICUFromProps(varName: string, cases: Record<string, string>, other: string): string {\n const options: string[] = []\n for (const [key, value] of Object.entries(cases)) {\n options.push(`${key} {${value}}`)\n }\n options.push(`other {${other}}`)\n return `{${varName}, select, ${options.join(' ')}}`\n}\n\nfunction buildPluralICUFromProps(props: Record<string, string>): string {\n const countVar = props['count'] ?? 'count'\n const categories = ['zero', 'one', 'two', 'few', 'many', 'other']\n const options: string[] = []\n const offset = props['offset']\n\n for (const cat of categories) {\n if (props[cat] !== undefined) {\n const key = cat === 'zero' ? '=0' : cat\n options.push(`${key} {${props[cat]}}`)\n }\n }\n\n if (options.length === 0) return ''\n const offsetPrefix = offset ? `offset:${offset} ` : ''\n return `{${countVar}, plural, ${offsetPrefix}${options.join(' ')}}`\n}\n\nfunction walkTemplate(\n node: TemplateNode,\n filename: string,\n messages: ExtractedMessage[],\n idGenerator?: (message: string, context?: string) => string,\n): void {\n if (node.type === ELEMENT_NODE) {\n const vtDirective = node.props?.find(\n (p) => p.type === DIRECTIVE_PROP && getPropName(p) === 't',\n )\n\n if (vtDirective) {\n const RESERVED_MODIFIERS = new Set(['plural'])\n const modifiers = (vtDirective.modifiers ?? []).map(\n (m: string | { content: string }) => (typeof m === 'string' ? m : m.content),\n )\n const isPlural = modifiers.includes('plural')\n // Reconstruct dotted ID: v-t:checkout.title → arg=\"checkout\", modifier=\"title\" → \"checkout.title\"\n // Non-reserved modifiers are treated as ID path segments\n const idSegments = modifiers.filter((m: string) => !RESERVED_MODIFIERS.has(m))\n const argContent = vtDirective.arg?.content\n const explicitId = argContent\n ? [argContent, ...idSegments].join('.')\n : undefined\n const textContent = getTextContent(node.children ?? [])\n\n if (isPlural) {\n const countVar = vtDirective.exp?.content ?? 'count'\n const message = buildPluralICUFromPipe(textContent, countVar)\n const id = explicitId ?? (idGenerator ?? createMessageId)(message)\n messages.push({\n id,\n message,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n } else if (textContent) {\n const id = explicitId ?? (idGenerator ?? createMessageId)(textContent)\n messages.push({\n id,\n message: textContent,\n origin: {\n file: filename,\n line: vtDirective.loc.start.line,\n column: vtDirective.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Trans') {\n const messageProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'message',\n )\n const idProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'id',\n )\n const contextProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'context',\n )\n const commentProp = node.props?.find(\n (p) => p.type === ATTRIBUTE_PROP && getPropName(p) === 'comment',\n )\n const context = contextProp?.value?.content\n const comment = commentProp?.value?.content\n\n if (messageProp?.value) {\n // Old API: <Trans message=\"...\" />\n const message = messageProp.value.content\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(message, context)\n messages.push({\n id,\n message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n } else if (node.children && node.children.length > 0) {\n // New API: <Trans>content with <a>rich text</a></Trans>\n const richText = extractRichTextFromTemplateChildren(node.children)\n if (richText.message) {\n const generateId = idGenerator ?? createMessageId\n const id = idProp?.value?.content ?? generateId(richText.message, context)\n messages.push({\n id,\n message: richText.message,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.tag === 'Plural') {\n const propsMap: Record<string, string> = {}\n let valueExpr: string | undefined\n let offsetExpr: string | undefined\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n propsMap[getPropName(prop)] = prop.value.content\n }\n // Handle :value=\"expr\" binding (directive prop)\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n valueExpr = prop.exp.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'offset' && prop.exp) {\n offsetExpr = prop.exp.content\n }\n }\n\n // Use :value binding expression as count variable, fall back to 'count' static prop\n const countVar = valueExpr ?? propsMap['count'] ?? 'count'\n const offset = offsetExpr ?? propsMap['offset']\n const pluralMessage = buildPluralICUFromProps({\n ...propsMap,\n count: countVar,\n ...(offset !== undefined ? { offset } : {}),\n })\n if (pluralMessage) {\n const id = propsMap['id'] ?? (idGenerator ?? createMessageId)(pluralMessage)\n messages.push({\n id,\n message: pluralMessage,\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n\n if (node.tag === 'Select') {\n let varName: string | undefined\n let selectId: string | undefined\n let selectContext: string | undefined\n let selectComment: string | undefined\n let other: string | undefined\n const cases: Record<string, string> = {}\n\n for (const prop of node.props ?? []) {\n if (prop.type === ATTRIBUTE_PROP && prop.value) {\n const name = getPropName(prop)\n if (name === 'id') { selectId = prop.value.content; continue }\n if (name === 'context') { selectContext = prop.value.content; continue }\n if (name === 'comment') { selectComment = prop.value.content; continue }\n if (name === 'other') { other = prop.value.content; continue }\n if (SELECT_RESERVED_PROPS.has(name)) continue\n cases[name] = prop.value.content\n }\n if (prop.type === DIRECTIVE_PROP && getPropName(prop) === 'bind' && prop.arg?.content === 'value' && prop.exp) {\n varName = prop.exp.content\n }\n }\n\n if (varName && other && Object.keys(cases).length > 0) {\n const message = buildSelectICUFromProps(varName, cases, other)\n const generateId = idGenerator ?? createMessageId\n const id = selectId ?? generateId(message, selectContext)\n messages.push({\n id,\n message,\n ...(selectContext !== undefined ? { context: selectContext } : {}),\n ...(selectComment !== undefined ? { comment: selectComment } : {}),\n origin: {\n file: filename,\n line: node.loc.start.line,\n column: node.loc.start.column,\n },\n })\n }\n }\n }\n\n if (node.children) {\n for (const child of node.children) {\n walkTemplate(child, filename, messages, idGenerator)\n }\n }\n}\n\nfunction extractRichTextFromTemplateChildren(\n children: TemplateNode[],\n): { message: string; hasElements: boolean } {\n let elementIndex = 0\n let hasElements = false\n\n const parts = children.map((child) => {\n if (child.type === TEXT_NODE) {\n return (child.content ?? '').trim() ? child.content ?? '' : ''\n }\n if (child.type === ELEMENT_NODE && child.tag) {\n hasElements = true\n const idx = elementIndex++\n const innerText = extractRichTextFromTemplateChildren(child.children ?? []).message\n return `<${idx}>${innerText}</${idx}>`\n }\n return ''\n })\n\n return {\n message: parts.join('').trim(),\n hasElements,\n }\n}\n\nfunction getPropName(prop: TemplateProp): string {\n if (typeof prop.name === 'string') return prop.name\n return prop.name.content\n}\n\nfunction extractTemplateInterpolations(\n content: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n const interpolationRegex = /\\{\\{([\\s\\S]*?)\\}\\}/g\n let match: RegExpExecArray | null\n\n while ((match = interpolationRegex.exec(content)) !== null) {\n const expression = match[1]?.trim()\n if (!expression) continue\n\n const extracted = extractFromTsx(expression, filename, idGenerator)\n if (extracted.length === 0) continue\n\n const lineOffset = content.slice(0, match.index).split('\\n').length - 1\n for (const msg of extracted) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n\n/** Extract messages from Vue SFC files */\nexport function extractFromVue(\n code: string,\n filename: string,\n idGenerator?: (message: string, context?: string) => string,\n): ExtractedMessage[] {\n const messages: ExtractedMessage[] = []\n\n const { descriptor } = parseSFC(code, { filename })\n\n if (descriptor.template?.ast) {\n walkTemplate(descriptor.template.ast as unknown as TemplateNode, filename, messages, idGenerator)\n }\n\n // Also extract t() function calls from raw template source\n // (picks up t('source text') in template expressions like {{ t('...') }})\n if (descriptor.template?.content) {\n const templateMessages = extractFromTsx(descriptor.template.content, filename, idGenerator)\n const templateLoc = descriptor.template.loc\n const lineOffset = templateLoc.start.line - 1\n const existingIds = new Set(messages.map((m) => m.id))\n for (const msg of templateMessages) {\n if (!existingIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n // Rebuild the set after template pass to include newly added IDs\n const afterTemplateIds = new Set(messages.map((m) => m.id))\n const interpolationMessages = extractTemplateInterpolations(descriptor.template.content, filename, idGenerator)\n for (const msg of interpolationMessages) {\n if (!afterTemplateIds.has(msg.id)) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n }\n\n if (descriptor.scriptSetup?.content) {\n const scriptMessages = extractFromTsx(descriptor.scriptSetup.content, filename, idGenerator)\n const scriptLoc = descriptor.scriptSetup.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n if (descriptor.script?.content) {\n const scriptMessages = extractFromTsx(descriptor.script.content, filename, idGenerator)\n const scriptLoc = descriptor.script.loc\n const lineOffset = scriptLoc.start.line - 1\n for (const msg of scriptMessages) {\n messages.push({\n ...msg,\n origin: {\n ...msg.origin,\n line: msg.origin.line + lineOffset,\n },\n })\n }\n }\n\n return messages\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluenti/cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "Fluenti CLI — message extraction from Vue SFC & TSX, PO/JSON catalog compilation",
6
6
  "homepage": "https://fluenti.dev",
@@ -72,7 +72,7 @@
72
72
  "fast-glob": "^3",
73
73
  "gettext-parser": "^9",
74
74
  "jiti": "^2",
75
- "@fluenti/core": "0.5.0"
75
+ "@fluenti/core": "0.6.0"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "@vue/compiler-sfc": "^3.5"
@@ -1 +0,0 @@
1
- {"version":3,"file":"ai-provider.d.ts","sourceRoot":"","sources":["../src/ai-provider.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAiBD,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA0ChF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC5B;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;AAEtD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,oBAAoB,GAC7B;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAiEhD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAE5C,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAA;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oBAAoB;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;CACnC;AAED,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,cAAc,EAAE,CAAA;CAC9B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,OAAO,EAAE,YAAY,GACpB,WAAW,CAoFb;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAiB3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAuBR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAO3D"}
package/dist/cli.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"compile-cache.d.ts","sourceRoot":"","sources":["../src/compile-cache.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAQ;gBAET,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAQlD;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO;IAQ3D;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI;IAOjD;;OAEG;IACH,IAAI,IAAI,IAAI;IAYZ,OAAO,CAAC,IAAI;CAeb"}
@@ -1,8 +0,0 @@
1
- const e=require(`./extract-cache-BioSaoFo.cjs`);let t=require(`@fluenti/core/internal`);var n=e.c({CATALOG_VERSION:()=>1,collectAllIds:()=>y,compileCatalog:()=>g,compileIndex:()=>v,compileTypeDeclaration:()=>S,extractMessageVariables:()=>b}),r=/\{(\w+)\}/g,i=/\{(\w+)\}/;function a(e){return i.test(e)}function o(e){return e.replace(/\\/g,`\\\\`).replace(/'/g,`\\'`).replace(/\n/g,`\\n`).replace(/\r/g,`\\r`)}function s(e,t){return/^\d/.test(t)?`${e}['${t}']`:`${e}.${t}`}function c(e){return e.replace(/\\/g,`\\\\`).replace(/`/g,"\\`").replace(/\$\{/g,"\\${").replace(/\n/g,`\\n`).replace(/\r/g,`\\r`)}function l(e){r.lastIndex=0;let t=[],n=0,i;for(;(i=r.exec(e))!==null;)t.push(c(e.slice(n,i.index))),t.push(`\${${s(`v`,i[1])}}`),n=r.lastIndex;return t.push(c(e.slice(n))),t.join(``)}var u=/\{(\w+),\s*(plural|select|selectordinal)\s*,/;function d(e){return u.test(e)}function f(e,t){if(e.length===0)return`''`;let n=e.map(e=>p(e,t));return n.length===1?n[0]:n.join(` + `)}function p(e,t){switch(e.type){case`text`:return`'${o(e.value)}'`;case`variable`:return e.name===`#`?`String(__c)`:`String(${s(`v`,e.name)} ?? '{${e.name}}')`;case`plural`:return m(e,t);case`select`:return h(e,t);case`function`:return`String(${s(`v`,e.variable)} ?? '')`}}function m(e,t){let n=e.offset??0,r=s(`v`,e.variable),i=n?`(${r} - ${n})`:r,a=[];a.push(`((c) => { const __c = c; `);let c=Object.keys(e.options).filter(e=>e.startsWith(`=`));if(c.length>0)for(let n of c){let r=n.slice(1),i=f(e.options[n],t);a.push(`if (c === ${r}) return ${i}; `)}let l=Object.keys(e.options).filter(e=>!e.startsWith(`=`));if(l.length>1||l.length===1&&l[0]!==`other`){a.push(`const __cat = new Intl.PluralRules('${o(t)}').select(c); `);for(let n of l){if(n===`other`)continue;let r=f(e.options[n],t);a.push(`if (__cat === '${o(n)}') return ${r}; `)}}let u=e.options.other?f(e.options.other,t):`''`;return a.push(`return ${u}; `),a.push(`})(${i})`),a.join(``)}function h(e,t){let n=[];n.push(`((s) => { `);let r=Object.keys(e.options).filter(e=>e!==`other`);for(let i of r){let r=f(e.options[i],t);n.push(`if (s === '${o(i)}') return ${r}; `)}let i=e.options.other?f(e.options.other,t):`''`;return n.push(`return ${i}; `),n.push(`})(String(${s(`v`,e.variable)} ?? ''))`),n.join(``)}function g(e,n,r,i,s){let c=[];c.push(`// @fluenti/compiled v1`),c.push(`// @ts-nocheck`);let u=[],p=0,m=[],h=new Map;for(let g of r){let r=(0,t.hashMessage)(g),v=h.get(r);if(v!==void 0&&v!==g)throw Error(`Hash collision detected: messages "${v}" and "${g}" produce the same hash "${r}"`);h.set(r,g);let y=`_${r}`,b=e[g],x=_(b,g,n,i,s?.skipFuzzy);if(x===void 0)c.push(`export const ${y} = undefined`),m.push(g);else if(d(x)){let e;try{e=(0,t.parse)(x)}catch(e){console.warn(`[fluenti] Skipping malformed ICU translation for "${g}" (${n}): ${e.message}`),c.push(`export const ${y} = undefined`),m.push(g),u.push({id:g,exportName:y});continue}let r=f(e,n);c.push(`export const ${y} = (v) => ${r}`),p++}else if(a(x)){let e=l(x);c.push(`export const ${y} = (v) => \`${e}\``),p++}else c.push(`export const ${y} = '${o(x)}'`),p++;u.push({id:g,exportName:y})}if(u.length===0)return{code:`// @fluenti/compiled v1
2
- // empty catalog
3
- export default {}
4
- `,stats:{compiled:0,missing:[]}};c.push(``),c.push(`export default {`);for(let{id:e,exportName:t}of u)c.push(` '${o(e)}': ${t},`);return c.push(`}`),c.push(``),{code:c.join(`
5
- `),stats:{compiled:p,missing:m}}}function _(e,t,n,r,i){let a=r??n;if(e&&!(i&&e.fuzzy)){if(e.translation!==void 0&&e.translation.length>0)return e.translation;if(n===a)return e.message??t}}function v(e,t){let n=[];n.push(`export const locales = ${JSON.stringify(e)}`),n.push(``),n.push(`export const loaders = {`);for(let t of e)n.push(` '${o(t)}': () => import('./${o(t)}.js'),`);return n.push(`}`),n.push(``),n.join(`
6
- `)}function y(e){let t=new Set;for(let n of Object.values(e))for(let[e,r]of Object.entries(n))r.obsolete||t.add(e);return[...t].sort()}function b(e){let n=(0,t.parse)(e),r=new Map;return x(n,r),[...r.entries()].sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({name:e,type:t}))}function x(e,t){for(let n of e)switch(n.type){case`variable`:n.name!==`#`&&!t.has(n.name)&&t.set(n.name,`string | number`);break;case`plural`:{let e=n;t.set(e.variable,`number`);for(let n of Object.values(e.options))x(n,t);break}case`select`:{let e=n,r=Object.keys(e.options).filter(e=>e!==`other`),i=`other`in e.options,a=r.map(e=>`'${e}'`).join(` | `),o=i?r.length>0?`${a} | string`:`string`:r.length>0?a:`string`;t.set(e.variable,o);for(let n of Object.values(e.options))x(n,t);break}case`function`:t.has(n.variable)||t.set(n.variable,`string | number`);break;case`text`:break}}function S(e,t,n){let r=[];if(r.push(`// Auto-generated by @fluenti/cli — do not edit`),r.push(``),r.push(`export type { LocalizedString } from '@fluenti/core'`),r.push(``),e.length===0)r.push(`export type MessageId = never`);else{r.push(`export type MessageId =`);for(let t of e)r.push(` | '${o(t)}'`)}r.push(``),r.push(`export interface MessageValues {`);for(let i of e){let e=b(t[n]?.[i]?.message??i),a=o(i);if(e.length===0)r.push(` '${a}': Record<string, never>`);else{let t=e.map(e=>`${e.name}: ${e.type}`).join(`; `);r.push(` '${a}': { ${t} }`)}}r.push(`}`),r.push(``);let i=Object.keys(t).map(e=>`'${o(e)}'`).join(` | `);return r.push(`// Auto-wiring: narrows t() and setLocale() to compiled types`),r.push(`declare module '@fluenti/core' {`),r.push(` interface FluentiTypeConfig {`),r.push(` locale: ${i||`string`}`),r.push(` messageIds: MessageId`),r.push(` messageValues: MessageValues`),r.push(` }`),r.push(`}`),r.push(``),r.join(`
7
- `)}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return y}});
8
- //# sourceMappingURL=compile-kXClO6q4.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compile-runner.d.ts","sourceRoot":"","sources":["../src/compile-runner.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuExF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"compile-worker.d.ts","sourceRoot":"","sources":["../src/compile-worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE/C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAA;CACrC;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA4J5C;;;;GAIG;AACH,4EAA4E;AAC5E,eAAO,MAAM,eAAe,IAAI,CAAA;AAEhC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EAAE,EAChB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,cAAc,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CA0EvC;AA8BD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,EAAE,CAU7E;AAID,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,EAAE,CAO1E;AA8CD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,YAAY,EAAE,MAAM,GACnB,MAAM,CAsDR"}
@@ -1,2 +0,0 @@
1
- export { loadConfig, loadConfigSync, DEFAULT_FLUENTI_CONFIG } from '@fluenti/core/config';
2
- //# sourceMappingURL=config-loader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAE7F"}
@@ -1,10 +0,0 @@
1
- var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let l=require(`@fluenti/core/internal`),u=require(`gettext-parser`);u=c(u),require(`@fluenti/core/config`);let d=require(`node:fs`),f=require(`node:path`),p=require(`node:worker_threads`),m=require(`node:os`),h=require(`node:url`);function g(e,t,n){let r=new Set(t.map(e=>e.id)),i=new Set,a={},o=0,s=0,c=0;for(let r of t){let t=e[r.id],c=t?void 0:v(e,r,i),l=`${r.origin.file}:${r.origin.line}`,u=t??c?.entry;if(c&&i.add(c.id),u)a[r.id]={...u,message:r.message??u.message,context:r.context,comment:r.comment,origin:l,obsolete:!1},s++;else if(a[r.id]){let e=a[r.id];a[r.id]={...e,origin:_(e.origin,l)}}else a[r.id]={message:r.message,context:r.context,comment:r.comment,origin:l},o++;if(n?.stripFuzzy){let{fuzzy:e,...t}=a[r.id];a[r.id]=t}}for(let[t,i]of Object.entries(e))if(!r.has(t)){let{fuzzy:e,...r}=i;a[t]=n?.stripFuzzy?{...r,obsolete:!0}:{...i,obsolete:!0},c++}return{catalog:a,result:{added:o,unchanged:s,obsolete:c}}}function _(e,t){if(!e)return t;let n=[...new Set([...Array.isArray(e)?e:[e],t])];return n.length===1?n[0]:n}function v(e,t,n){if(!t.context)return;let r=`${t.origin.file}:${t.origin.line}`;for(let[i,a]of Object.entries(e))if(!n.has(i)&&a.context===void 0&&a.message===t.message&&y(a.origin,r))return{id:i,entry:a}}function y(e,t){return e?(Array.isArray(e)?e:[e]).some(e=>e===t||b(e)===b(t)):!1}function b(e){return e.match(/^(.*):\d+$/)?.[1]??e}function x(e){let t=JSON.parse(e),n={};for(let[e,r]of Object.entries(t))if(typeof r==`object`&&r){let t=r;n[e]={message:typeof t.message==`string`?t.message:void 0,context:typeof t.context==`string`?t.context:void 0,comment:typeof t.comment==`string`?t.comment:void 0,translation:typeof t.translation==`string`?t.translation:void 0,origin:typeof t.origin==`string`||Array.isArray(t.origin)&&t.origin.every(e=>typeof e==`string`)?t.origin:void 0,obsolete:typeof t.obsolete==`boolean`?t.obsolete:void 0,fuzzy:typeof t.fuzzy==`boolean`?t.fuzzy:void 0}}return n}function S(e){let t={};for(let[n,r]of Object.entries(e)){let e={};r.message!==void 0&&(e.message=r.message),r.context!==void 0&&(e.context=r.context),r.comment!==void 0&&(e.comment=r.comment),r.translation!==void 0&&(e.translation=r.translation),r.origin!==void 0&&(e.origin=r.origin),r.obsolete&&(e.obsolete=!0),r.fuzzy&&(e.fuzzy=!0),t[n]=e}return JSON.stringify(t,null,2)+`
2
- `}var C=`fluenti-id:`;function w(e,t,n){for(let[r,i]of Object.entries(e))for(let[e,a]of Object.entries(i)){if(!e)continue;let i=r||a.msgctxt||void 0,o=a.msgstr?.[0]??void 0,s=a.comments?.reference??void 0,c=s?.includes(`
3
- `)?s.split(`
4
- `).map(e=>e.trim()).filter(Boolean):s?.includes(` `)?s.split(/\s+/).filter(Boolean):s,u=Array.isArray(c)&&c.length===1?c[0]:c,d=!n&&(a.comments?.flag?.includes(`fuzzy`)??!1),{comment:f,customId:p,sourceMessage:m}=D(a.comments?.extracted),h=m&&(p!==void 0||(0,l.hashMessage)(m,i)===e)?m:void 0,g=p??(h?e:(0,l.hashMessage)(e,i));t[g]={message:h??e,...i===void 0?{}:{context:i},...f===void 0?{}:{comment:f},...o?{translation:o}:{},...u===void 0?{}:{origin:u},...d?{fuzzy:!0}:{},...n?{obsolete:!0}:{}}}}function T(e){let t=u.po.parse(e),n={};return w(t.translations??{},n,!1),t.obsolete&&w(t.obsolete,n,!0),n}function E(e){let t={"":{"":{msgid:``,msgstr:[`Content-Type: text/plain; charset=UTF-8
5
- `]}}},n={};for(let[r,i]of Object.entries(e)){let e={msgid:i.message!==void 0&&(0,l.hashMessage)(i.message,i.context)===r?i.message??r:r,...i.context===void 0?{}:{msgctxt:i.context},msgstr:[i.translation??``]},a={};i.origin&&!i.obsolete&&(a.reference=Array.isArray(i.origin)?i.origin.join(`
6
- `):i.origin);let o=k(r,i.message??r,i.context,i.comment);if(o&&(a.extracted=o),i.fuzzy&&!i.obsolete&&(a.flag=`fuzzy`),(a.reference||a.extracted||a.flag)&&(e.comments=a),i.obsolete){let t=i.context??``;n[t]??={},n[t][e.msgid]=e}else{let n=i.context??``;t[n]??={},t[n][e.msgid]=e}}let r={headers:{"Content-Type":`text/plain; charset=UTF-8`},translations:t,...Object.keys(n).length>0?{obsolete:n}:{}};return u.po.compile(r).toString()}function D(e){if(!e)return{};let t=e.split(`
7
- `).map(e=>e.trim()).filter(Boolean),n,r,i=[];for(let e of t){if(e.startsWith(C)){n=e.slice(11).trim()||void 0;continue}if(e.startsWith("msg`")&&e.endsWith("`")){r=e.slice(4,-1);continue}if(e.startsWith(`Trans: `)){r=O(e.slice(7));continue}i.push(e)}return{...i.length>0?{comment:i.join(`
8
- `)}:{},...n?{customId:n}:{},...r?{sourceMessage:r}:{}}}function O(e){let t=[],n=0;return e.replace(/<\/?([a-zA-Z][\w-]*)>/g,(e,r)=>{let i=r;if(e.startsWith(`</`)){for(let e=t.length-1;e>=0;e--){let n=t[e];if(n?.tag===i)return t=t.filter((t,n)=>n!==e),`</${n.index}>`}return e}let a=n++;return t.push({tag:i,index:a}),`<${a}>`})}function k(e,t,n,r){let i=[];return r&&i.push(r),e!==(0,l.hashMessage)(t,n)&&(i.push(`${C} ${e}`),i.push(`msg\`${t}\``)),i.length>0?i.join(`
9
- `):void 0}var A=3e4;function j(){return(0,f.resolve)(typeof __dirname<`u`?__dirname:(0,f.dirname)((0,h.fileURLToPath)({}.url)),`compile-worker.js`)}async function M(e,t){if(e.length===0)return[];if(e.length===1){let{compileCatalog:t}=await Promise.resolve().then(()=>require(`./compile-kXClO6q4.cjs`)).then(e=>e.a),n=e[0],{code:r,stats:i}=t(n.catalog,n.locale,n.allIds,n.sourceLocale,n.options);return[{locale:n.locale,code:r,stats:i}]}let n=j();if(!(0,d.existsSync)(n))return N(e);let r=t??Math.min(e.length,(0,m.availableParallelism)()),i=[],a=[...e],o=!1;return new Promise((e,t)=>{let s=0;function c(){if(o)return;let r=a.shift();if(!r){s===0&&e(i);return}s++;let l=new p.Worker(n),u=setTimeout(()=>{o||(o=!0,s--,l.terminate(),t(Error(`Worker timed out after ${A}ms compiling locale "${r.locale}"`)))},A);l.on(`message`,e=>{if(clearTimeout(u),!o){if(e.error){o=!0,s--,l.terminate(),t(Error(`Failed to compile locale "${e.locale}": ${e.error}`));return}i.push({locale:e.locale,code:e.code,stats:e.stats}),s--,l.terminate(),c()}}),l.on(`error`,e=>{clearTimeout(u),o||(o=!0,l.terminate(),t(Error(`Worker error compiling locale "${r.locale}": ${e.message}`)))}),l.on(`exit`,e=>{clearTimeout(u),e!==0&&!o&&(o=!0,t(Error(`Worker exited with code ${e} while compiling locale "${r.locale}"`)))});let d={locale:r.locale,catalog:r.catalog,allIds:r.allIds,sourceLocale:r.sourceLocale,options:r.options};l.postMessage(d)}let l=Math.min(r,a.length);for(let e=0;e<l;e++)c()})}async function N(e){let{compileCatalog:t}=await Promise.resolve().then(()=>require(`./compile-kXClO6q4.cjs`)).then(e=>e.a);return Promise.all(e.map(e=>{let{code:n,stats:r}=t(e.catalog,e.locale,e.allIds,e.sourceLocale,e.options);return{locale:e.locale,code:n,stats:r}}))}var P=`1`,F=class{data;cachePath;dirty=!1;constructor(e,t){this.cachePath=(0,f.resolve)(t?(0,f.resolve)(e,`.cache`,t):(0,f.resolve)(e,`.cache`),`extract-cache.json`),this.data=this.load()}get(e){let t=this.data.entries[e];if(t)try{let n=(0,d.statSync)(e);if(n.mtimeMs===t.mtime&&n.size===t.size)return t.messages}catch{}}set(e,t){try{let n=(0,d.statSync)(e);this.data.entries[e]={mtime:n.mtimeMs,size:n.size,messages:t},this.dirty=!0}catch{}}prune(e){for(let t of Object.keys(this.data.entries))e.has(t)||(delete this.data.entries[t],this.dirty=!0)}save(){if(this.dirty)try{(0,d.mkdirSync)((0,f.dirname)(this.cachePath),{recursive:!0}),(0,d.writeFileSync)(this.cachePath,JSON.stringify(this.data),`utf-8`),this.dirty=!1}catch{}}get size(){return Object.keys(this.data.entries).length}load(){try{if((0,d.existsSync)(this.cachePath)){let e=(0,d.readFileSync)(this.cachePath,`utf-8`),t=JSON.parse(e);if(t.version===P)return t}}catch{}return{version:P,entries:{}}}};Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return F}});
10
- //# sourceMappingURL=extract-cache-BioSaoFo.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extract-cache-BioSaoFo.cjs","names":[],"sources":["../src/catalog.ts","../src/json-format.ts","../src/po-format.ts","../src/parallel-compile.ts","../src/extract-cache.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\n\nexport interface CatalogEntry {\n message?: string | undefined\n context?: string | undefined\n comment?: string | undefined\n translation?: string | undefined\n origin?: string | string[] | undefined\n obsolete?: boolean | undefined\n fuzzy?: boolean | undefined\n}\n\nexport type CatalogData = Record<string, CatalogEntry>\n\nexport interface UpdateResult {\n added: number\n unchanged: number\n obsolete: number\n}\n\nexport interface UpdateCatalogOptions {\n stripFuzzy?: boolean\n}\n\n/** Update catalog with newly extracted messages */\nexport function updateCatalog(\n existing: CatalogData,\n extracted: ExtractedMessage[],\n options?: UpdateCatalogOptions,\n): { catalog: CatalogData; result: UpdateResult } {\n const extractedIds = new Set(extracted.map((m) => m.id))\n const consumedCarryForwardIds = new Set<string>()\n const catalog: CatalogData = {}\n let added = 0\n let unchanged = 0\n let obsolete = 0\n\n for (const msg of extracted) {\n const existingEntry = existing[msg.id]\n const carried = existingEntry\n ? undefined\n : findCarryForwardEntry(existing, msg, consumedCarryForwardIds)\n const origin = `${msg.origin.file}:${msg.origin.line}`\n const baseEntry = existingEntry ?? carried?.entry\n\n if (carried) {\n consumedCarryForwardIds.add(carried.id)\n }\n\n if (baseEntry) {\n catalog[msg.id] = {\n ...baseEntry,\n message: msg.message ?? baseEntry.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n obsolete: false,\n }\n unchanged++\n } else if (catalog[msg.id]) {\n // Same ID already seen in this extraction batch — merge origin\n const existing = catalog[msg.id]!\n catalog[msg.id] = {\n ...existing,\n origin: mergeOrigins(existing.origin, origin),\n }\n } else {\n catalog[msg.id] = {\n message: msg.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n }\n added++\n }\n\n if (options?.stripFuzzy) {\n const { fuzzy: _fuzzy, ...rest } = catalog[msg.id]!\n catalog[msg.id] = rest\n }\n }\n\n for (const [id, entry] of Object.entries(existing)) {\n if (!extractedIds.has(id)) {\n const { fuzzy: _fuzzy, ...rest } = entry\n const obsoleteEntry = options?.stripFuzzy\n ? { ...rest, obsolete: true }\n : { ...entry, obsolete: true }\n catalog[id] = obsoleteEntry\n obsolete++\n }\n }\n\n return { catalog, result: { added, unchanged, obsolete } }\n}\n\nfunction mergeOrigins(\n existing: string | string[] | undefined,\n newOrigin: string,\n): string | string[] {\n if (!existing) return newOrigin\n const existingArray = Array.isArray(existing) ? existing : [existing]\n const merged = [...new Set([...existingArray, newOrigin])]\n return merged.length === 1 ? merged[0]! : merged\n}\n\nfunction findCarryForwardEntry(\n existing: CatalogData,\n extracted: ExtractedMessage,\n consumedCarryForwardIds: Set<string>,\n): { id: string; entry: CatalogEntry } | undefined {\n if (!extracted.context) {\n return undefined\n }\n\n const extractedOrigin = `${extracted.origin.file}:${extracted.origin.line}`\n for (const [id, entry] of Object.entries(existing)) {\n if (consumedCarryForwardIds.has(id)) continue\n if (entry.context !== undefined) continue\n if (entry.message !== extracted.message) continue\n if (!sameOrigin(entry.origin, extractedOrigin)) continue\n return { id, entry }\n }\n\n return undefined\n}\n\nfunction sameOrigin(previous: string | string[] | undefined, next: string): boolean {\n if (!previous) return false\n const origins = Array.isArray(previous) ? previous : [previous]\n return origins.some((o) => o === next || originFile(o) === originFile(next))\n}\n\nfunction originFile(origin: string): string {\n const match = origin.match(/^(.*):\\d+$/)\n return match?.[1] ?? origin\n}\n","import type { CatalogData } from './catalog'\n\n/** Read a JSON catalog file */\nexport function readJsonCatalog(content: string): CatalogData {\n const raw = JSON.parse(content) as Record<string, unknown>\n const catalog: CatalogData = {}\n\n for (const [id, entry] of Object.entries(raw)) {\n if (typeof entry === 'object' && entry !== null) {\n const e = entry as Record<string, unknown>\n catalog[id] = {\n message: typeof e['message'] === 'string' ? e['message'] : undefined,\n context: typeof e['context'] === 'string' ? e['context'] : undefined,\n comment: typeof e['comment'] === 'string' ? e['comment'] : undefined,\n translation: typeof e['translation'] === 'string' ? e['translation'] : undefined,\n origin: typeof e['origin'] === 'string'\n ? e['origin']\n : Array.isArray(e['origin']) && (e['origin'] as unknown[]).every((v) => typeof v === 'string')\n ? (e['origin'] as string[])\n : undefined,\n obsolete: typeof e['obsolete'] === 'boolean' ? e['obsolete'] : undefined,\n fuzzy: typeof e['fuzzy'] === 'boolean' ? e['fuzzy'] : undefined,\n }\n }\n }\n\n return catalog\n}\n\n/** Write a catalog to JSON format */\nexport function writeJsonCatalog(catalog: CatalogData): string {\n const output: Record<string, Record<string, unknown>> = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n const obj: Record<string, unknown> = {}\n if (entry.message !== undefined) obj['message'] = entry.message\n if (entry.context !== undefined) obj['context'] = entry.context\n if (entry.comment !== undefined) obj['comment'] = entry.comment\n if (entry.translation !== undefined) obj['translation'] = entry.translation\n if (entry.origin !== undefined) obj['origin'] = entry.origin\n if (entry.obsolete) obj['obsolete'] = true\n if (entry.fuzzy) obj['fuzzy'] = true\n output[id] = obj\n }\n\n return JSON.stringify(output, null, 2) + '\\n'\n}\n","import type { CatalogData } from './catalog'\nimport { hashMessage } from '@fluenti/core/internal'\nimport * as gettextParser from 'gettext-parser'\n\nconst CUSTOM_ID_MARKER = 'fluenti-id:'\n\ninterface POTranslation {\n msgid: string\n msgctxt?: string\n msgstr: string[]\n comments?: {\n reference?: string\n extracted?: string\n flag?: string\n translator?: string\n previous?: string\n }\n}\n\ninterface POData {\n headers?: Record<string, string>\n translations: Record<string, Record<string, POTranslation>>\n obsolete?: Record<string, Record<string, POTranslation>>\n}\n\ninterface ParsedExtractedComment {\n comment?: string\n customId?: string\n sourceMessage?: string\n}\n\nfunction processPoEntries(\n contextMap: Record<string, Record<string, POTranslation>>,\n catalog: CatalogData,\n isObsolete: boolean,\n): void {\n for (const [contextKey, entries] of Object.entries(contextMap)) {\n for (const [msgid, entry] of Object.entries(entries)) {\n if (!msgid) continue\n\n const context = contextKey || entry.msgctxt || undefined\n const translation = entry.msgstr?.[0] ?? undefined\n const rawReference = entry.comments?.reference ?? undefined\n const origin = rawReference?.includes('\\n')\n ? rawReference.split('\\n').map((r: string) => r.trim()).filter(Boolean)\n : rawReference?.includes(' ')\n ? rawReference.split(/\\s+/).filter(Boolean)\n : rawReference\n const normalizedOrigin = Array.isArray(origin) && origin.length === 1 ? origin[0] : origin\n const isFuzzy = !isObsolete && (entry.comments?.flag?.includes('fuzzy') ?? false)\n const { comment, customId, sourceMessage } = parseExtractedComment(entry.comments?.extracted)\n // When a custom ID is present, the msgid may be the custom key (not source text),\n // so accept sourceMessage directly without requiring a hash match.\n // For hash-ID entries (no customId), verify the hash to prevent double-hashing.\n const resolvedSourceMessage = sourceMessage\n && (customId !== undefined || hashMessage(sourceMessage, context) === msgid)\n ? sourceMessage\n : undefined\n const id = customId\n ?? (resolvedSourceMessage ? msgid : hashMessage(msgid, context))\n\n catalog[id] = {\n message: resolvedSourceMessage ?? msgid,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n ...(translation ? { translation } : {}),\n ...(normalizedOrigin !== undefined ? { origin: normalizedOrigin } : {}),\n ...(isFuzzy ? { fuzzy: true } : {}),\n ...(isObsolete ? { obsolete: true } : {}),\n }\n }\n }\n}\n\n/** Read a PO catalog file */\nexport function readPoCatalog(content: string): CatalogData {\n const po = gettextParser.po.parse(content) as POData\n const catalog: CatalogData = {}\n\n processPoEntries(po.translations ?? {}, catalog, false)\n if (po.obsolete) {\n processPoEntries(po.obsolete, catalog, true)\n }\n\n return catalog\n}\n\n/** Write a catalog to PO format */\nexport function writePoCatalog(catalog: CatalogData): string {\n const translations: POData['translations'] = {\n '': {\n '': {\n msgid: '',\n msgstr: ['Content-Type: text/plain; charset=UTF-8\\n'],\n },\n },\n }\n const obsolete: POData['obsolete'] = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n // Use custom ID as msgid for non-hash entries to prevent collision when two\n // entries share the same source message but have different custom IDs.\n // Hash-ID entries keep source message as msgid (PO-friendly for translators).\n const isHashId = entry.message !== undefined && hashMessage(entry.message, entry.context) === id\n const msgid = isHashId ? (entry.message ?? id) : id\n const poEntry: POTranslation = {\n msgid,\n ...(entry.context !== undefined ? { msgctxt: entry.context } : {}),\n msgstr: [entry.translation ?? ''],\n }\n\n const comments: POTranslation['comments'] = {}\n if (entry.origin && !entry.obsolete) {\n comments.reference = Array.isArray(entry.origin)\n ? entry.origin.join('\\n')\n : entry.origin\n }\n const extractedComment = buildExtractedComment(id, entry.message ?? id, entry.context, entry.comment)\n if (extractedComment) {\n comments.extracted = extractedComment\n }\n if (entry.fuzzy && !entry.obsolete) {\n comments.flag = 'fuzzy'\n }\n if (comments.reference || comments.extracted || comments.flag) {\n poEntry.comments = comments\n }\n\n if (entry.obsolete) {\n const contextKey = entry.context ?? ''\n obsolete[contextKey] ??= {}\n obsolete[contextKey]![poEntry.msgid] = poEntry\n } else {\n const contextKey = entry.context ?? ''\n translations[contextKey] ??= {}\n translations[contextKey]![poEntry.msgid] = poEntry\n }\n }\n\n const poData: POData = {\n headers: {\n 'Content-Type': 'text/plain; charset=UTF-8',\n },\n translations,\n ...(Object.keys(obsolete).length > 0 ? { obsolete } : {}),\n }\n\n const buffer = gettextParser.po.compile(poData as Parameters<typeof gettextParser.po.compile>[0])\n return buffer.toString()\n}\n\nfunction parseExtractedComment(\n extracted: string | undefined,\n): ParsedExtractedComment {\n if (!extracted) {\n return {}\n }\n\n const lines = extracted.split('\\n').map((line) => line.trim()).filter(Boolean)\n let customId: string | undefined\n let sourceMessage: string | undefined\n const commentLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith(CUSTOM_ID_MARKER)) {\n customId = line.slice(CUSTOM_ID_MARKER.length).trim() || undefined\n continue\n }\n if (line.startsWith('msg`') && line.endsWith('`')) {\n sourceMessage = line.slice(4, -1)\n continue\n }\n if (line.startsWith('Trans: ')) {\n sourceMessage = normalizeRichTextComment(line.slice('Trans: '.length))\n continue\n }\n commentLines.push(line)\n }\n\n return {\n ...(commentLines.length > 0 ? { comment: commentLines.join('\\n') } : {}),\n ...(customId ? { customId } : {}),\n ...(sourceMessage ? { sourceMessage } : {}),\n }\n}\n\nfunction normalizeRichTextComment(comment: string): string {\n let stack: Array<{ tag: string; index: number }> = []\n let nextIndex = 0\n\n return comment.replace(/<\\/?([a-zA-Z][\\w-]*)>/g, (match, rawTag: string) => {\n const tag = rawTag\n if (match.startsWith('</')) {\n for (let index = stack.length - 1; index >= 0; index--) {\n const entry = stack[index]\n if (entry?.tag !== tag) continue\n stack = stack.filter((_, i) => i !== index)\n return `</${entry.index}>`\n }\n return match\n }\n\n const index = nextIndex++\n stack.push({ tag, index })\n return `<${index}>`\n })\n}\n\nfunction buildExtractedComment(\n id: string,\n message: string,\n context: string | undefined,\n comment: string | undefined,\n): string | undefined {\n const lines: string[] = []\n\n if (comment) {\n lines.push(comment)\n }\n\n if (id !== hashMessage(message, context)) {\n lines.push(`${CUSTOM_ID_MARKER} ${id}`)\n // Preserve source message so round-trip works when msgid is the custom ID (not source text)\n lines.push(`msg\\`${message}\\``)\n }\n\n return lines.length > 0 ? lines.join('\\n') : undefined\n}\n","import { Worker } from 'node:worker_threads'\nimport { availableParallelism } from 'node:os'\nimport { existsSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { CatalogData } from './catalog'\nimport type { CompileOptions, CompileStats } from './compile'\nimport type { CompileWorkerRequest, CompileWorkerResponse } from './compile-worker'\n\nexport interface ParallelCompileTask {\n locale: string\n catalog: CatalogData\n allIds: string[]\n sourceLocale: string\n options?: CompileOptions\n}\n\nexport interface ParallelCompileResult {\n locale: string\n code: string\n stats: CompileStats\n}\n\n/** Default timeout per worker in milliseconds (30 seconds) */\nconst WORKER_TIMEOUT_MS = 30_000\n\nfunction getWorkerPath(): string {\n const thisDir = typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url))\n return resolve(thisDir, 'compile-worker.js')\n}\n\n/**\n * Compile multiple locales in parallel using worker threads.\n *\n * - Single task → returns result directly (no worker overhead)\n * - Multiple tasks → spawns min(tasks, availableParallelism()) workers\n * - Workers are created per-call and destroyed after completion\n *\n * Falls back to in-process compilation when the compiled worker is unavailable\n * (e.g. when running from TypeScript source in development/tests).\n */\nexport async function parallelCompile(\n tasks: ParallelCompileTask[],\n concurrency?: number,\n): Promise<ParallelCompileResult[]> {\n if (tasks.length === 0) return []\n\n // Single task: compile in-process, no worker overhead\n if (tasks.length === 1) {\n const { compileCatalog } = await import('./compile')\n const task = tasks[0]!\n const { code, stats } = compileCatalog(task.catalog, task.locale, task.allIds, task.sourceLocale, task.options)\n return [{ locale: task.locale, code, stats }]\n }\n\n const workerPath = getWorkerPath()\n\n // If compiled worker doesn't exist (dev/test), fall back to concurrent in-process compilation\n if (!existsSync(workerPath)) {\n return inProcessParallelCompile(tasks)\n }\n\n const maxWorkers = concurrency ?? Math.min(tasks.length, availableParallelism())\n const results: ParallelCompileResult[] = []\n const queue = [...tasks]\n let rejected = false\n\n return new Promise<ParallelCompileResult[]>((resolveAll, rejectAll) => {\n let activeWorkers = 0\n\n function spawnNext(): void {\n if (rejected) return\n const task = queue.shift()\n if (!task) {\n if (activeWorkers === 0) {\n resolveAll(results)\n }\n return\n }\n\n activeWorkers++\n const worker = new Worker(workerPath)\n\n const timer = setTimeout(() => {\n if (!rejected) {\n rejected = true\n activeWorkers--\n worker.terminate()\n rejectAll(new Error(`Worker timed out after ${WORKER_TIMEOUT_MS}ms compiling locale \"${task.locale}\"`))\n }\n }, WORKER_TIMEOUT_MS)\n\n worker.on('message', (response: CompileWorkerResponse) => {\n clearTimeout(timer)\n if (rejected) return\n if (response.error) {\n rejected = true\n activeWorkers--\n worker.terminate()\n rejectAll(new Error(`Failed to compile locale \"${response.locale}\": ${response.error}`))\n return\n }\n results.push({\n locale: response.locale,\n code: response.code,\n stats: response.stats,\n })\n activeWorkers--\n worker.terminate()\n spawnNext()\n })\n\n worker.on('error', (err: Error) => {\n clearTimeout(timer)\n if (!rejected) {\n rejected = true\n worker.terminate()\n rejectAll(new Error(`Worker error compiling locale \"${task.locale}\": ${err.message}`))\n }\n })\n\n worker.on('exit', (code) => {\n clearTimeout(timer)\n if (code !== 0 && !rejected) {\n rejected = true\n rejectAll(new Error(`Worker exited with code ${code} while compiling locale \"${task.locale}\"`))\n }\n })\n\n const request: CompileWorkerRequest = {\n locale: task.locale,\n catalog: task.catalog,\n allIds: task.allIds,\n sourceLocale: task.sourceLocale,\n options: task.options,\n }\n worker.postMessage(request)\n }\n\n // Start initial batch of workers\n const initialBatch = Math.min(maxWorkers, queue.length)\n for (let i = 0; i < initialBatch; i++) {\n spawnNext()\n }\n })\n}\n\n/**\n * In-process fallback for parallel compilation.\n * Uses Promise.all for concurrency when workers are unavailable.\n */\nasync function inProcessParallelCompile(\n tasks: ParallelCompileTask[],\n): Promise<ParallelCompileResult[]> {\n const { compileCatalog } = await import('./compile')\n return Promise.all(\n tasks.map((task) => {\n const { code, stats } = compileCatalog(task.catalog, task.locale, task.allIds, task.sourceLocale, task.options)\n return { locale: task.locale, code, stats }\n }),\n )\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\n\n/** Cache format version — bump when the structure changes */\nconst CACHE_VERSION = '1'\n\ninterface ExtractCacheEntry {\n mtime: number\n size: number\n messages: ExtractedMessage[]\n}\n\ninterface ExtractCacheData {\n version: string\n entries: Record<string, ExtractCacheEntry>\n}\n\n/**\n * File-level extract cache that skips re-extraction for unchanged files.\n *\n * Cache is keyed by file path, with mtime + size as change detection.\n */\nexport class ExtractCache {\n private data: ExtractCacheData\n private cachePath: string\n private dirty = false\n\n constructor(catalogDir: string, projectId?: string) {\n const cacheDir = projectId\n ? resolve(catalogDir, '.cache', projectId)\n : resolve(catalogDir, '.cache')\n this.cachePath = resolve(cacheDir, 'extract-cache.json')\n this.data = this.load()\n }\n\n /**\n * Check if a file has changed since the last extraction.\n * Returns cached messages if unchanged, undefined if re-extraction needed.\n */\n get(filePath: string): ExtractedMessage[] | undefined {\n const entry = this.data.entries[filePath]\n if (!entry) return undefined\n\n try {\n const stat = statSync(filePath)\n if (stat.mtimeMs === entry.mtime && stat.size === entry.size) {\n return entry.messages\n }\n } catch {\n // File no longer exists or can't be stat'd — cache miss\n }\n\n return undefined\n }\n\n /**\n * Update the cache for a file after extraction.\n */\n set(filePath: string, messages: ExtractedMessage[]): void {\n try {\n const stat = statSync(filePath)\n this.data.entries[filePath] = {\n mtime: stat.mtimeMs,\n size: stat.size,\n messages,\n }\n this.dirty = true\n } catch {\n // File doesn't exist — skip caching\n }\n }\n\n /**\n * Remove entries for files that no longer exist in the file list.\n */\n prune(currentFiles: Set<string>): void {\n for (const filePath of Object.keys(this.data.entries)) {\n if (!currentFiles.has(filePath)) {\n delete this.data.entries[filePath]\n this.dirty = true\n }\n }\n }\n\n /**\n * Write the cache to disk if any changes were made.\n */\n save(): void {\n if (!this.dirty) return\n\n try {\n mkdirSync(dirname(this.cachePath), { recursive: true })\n writeFileSync(this.cachePath, JSON.stringify(this.data), 'utf-8')\n this.dirty = false\n } catch {\n // Cache write failure is non-fatal — next run will re-extract\n }\n }\n\n /** Number of cached entries */\n get size(): number {\n return Object.keys(this.data.entries).length\n }\n\n private load(): ExtractCacheData {\n try {\n if (existsSync(this.cachePath)) {\n const raw = readFileSync(this.cachePath, 'utf-8')\n const parsed = JSON.parse(raw) as ExtractCacheData\n if (parsed.version === CACHE_VERSION) {\n return parsed\n }\n }\n } catch {\n // Corrupt or unreadable cache — start fresh\n }\n\n return { version: CACHE_VERSION, entries: {} }\n }\n}\n"],"mappings":"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"}