@fluenti/vite-plugin 0.4.0-rc.1 → 0.4.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-runner.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +152 -143
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/dev-runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-runner.d.ts","sourceRoot":"","sources":["../src/dev-runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev-runner.d.ts","sourceRoot":"","sources":["../src/dev-runner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;IAC9B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,sEAAsE;IACtE,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAChE,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5C;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyEhF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,EACzB,KAAK,SAAM,GACV,MAAM,IAAI,CAiCZ"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vite`),t=require(`@fluenti/core/internal`),n=require(`node:module`),r=require(`node:path`),i=require(
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vite`),t=require(`@fluenti/core/internal`),n=require(`node:module`),r=require(`node:path`),i=require(`node:fs`),a=require(`@fluenti/core/transform`),o=require(`@fluenti/core`);var s=`dev`;function c(e){s=e===`build`?`build`:`dev`}function l(e){if(typeof e==`object`&&e&&`environment`in e){let t=e.environment;if(typeof t==`object`&&t)return t}}function u(e){return e?.mode===`build`||s===`build`||process.env.NODE_ENV===`production`}async function d(e){try{let{DEFAULT_FLUENTI_CONFIG:t,loadConfigSync:a}=(0,n.createRequire)((0,r.join)(e.cwd,`package.json`))(`@fluenti/core/config`),o;try{o=a(void 0,e.cwd)}catch{o=t}(0,i.mkdirSync)((0,r.resolve)(e.cwd,o.compileOutDir),{recursive:!0}),(0,i.mkdirSync)((0,r.resolve)(e.cwd,o.catalogDir),{recursive:!0})}catch{}if(!(e.onBeforeCompile&&await e.onBeforeCompile()===!1)){if(e.compileOnly)try{let{runCompile:t}=(0,n.createRequire)((0,r.join)(e.cwd,`package.json`))(`@fluenti/cli`);await t(e.cwd),console.log(`[fluenti] Compiling... done`),e.onAfterCompile&&await e.onAfterCompile(),e.onSuccess?.();return}catch(t){let n=t instanceof Error?t:Error(String(t));if(e.throwOnError)throw n;console.warn(`[fluenti] Compile failed:`,n.message),e.onError?.(n);return}try{let{runExtract:t,runCompile:i}=(0,n.createRequire)((0,r.join)(e.cwd,`package.json`))(`@fluenti/cli`);await t(e.cwd),await i(e.cwd,{parallel:e.parallelCompile}),console.log(`[fluenti] Extracting and compiling... done`),e.onAfterCompile&&await e.onAfterCompile(),e.onSuccess?.();return}catch(t){let n=t instanceof Error?t:Error(String(t));if(n.message.includes(`Cannot find module`)){let t=`[fluenti] @fluenti/cli is required for auto-compile.
|
|
2
2
|
Install it as a devDependency:
|
|
3
3
|
pnpm add -D @fluenti/cli
|
|
4
|
-
See: https://fluenti.dev/start/introduction/`;if(e.throwOnError)throw Error(t);console.warn(t),e.onError?.(Error(t));return}if(e.throwOnError)throw n;console.warn(`[fluenti] Extract/compile failed:`,n.message),e.onError?.(n)}}}function f(e,t=300){let n=null,r=!1,i=!1;async function a(){r=!0;try{await d(e)}finally{r=!1,i&&(i=!1,o())}}function o(){n!==null&&clearTimeout(n),n=setTimeout(()=>{n=null,r?i=!0:a()},t)}return o}function p(e,t){return h(e,`dynamic`,t)}function m(e,t){return h(e,`static`,t)}function h(e,n,r){let a=r?.hashFn??t.hashMessage,o=(0,i.parseSourceModule)(e);if(!o||o.type!==`Program`)return{code:e,needsCatalogImport:!1,usedHashes:new Set};let s=g(o),c=[],l=new Set;if((0,i.walkSourceAst)(o,t=>{let r=v(e,t,s,n,l,a);if(r){c.push(r);return}x(t,l,a)}),c.length===0)return{code:e,needsCatalogImport:!1,usedHashes:l};let u=e;for(let e=c.length-1;e>=0;e--){let{start:t,end:n,replacement:r}=c[e];u=u.slice(0,t)+r+u.slice(n)}return{code:u,needsCatalogImport:!0,usedHashes:l}}function g(e){let t=new Set,n=new Set,r=new Set,a=new Set;for(let t of e.body)if(N(t))for(let e of t.specifiers){if(!P(e))continue;let t=H(e);t&&(t===`useI18n`&&n.add(e.local.name),t===`getI18n`&&r.add(e.local.name),t===`unref`&&a.add(e.local.name))}return(0,i.walkSourceAst)(e,e=>{if(!te(e)||!e.init||!ne(e.id))return;if(L(e.init)&&z(e.init.callee)&&n.has(e.init.callee.name)){_(e.id,t);return}let i=e.init.type===`AwaitExpression`?e.init.argument:null;i&&L(i)&&z(i.callee)&&r.has(i.callee.name)&&_(e.id,t)}),{tracked:t,unref:a}}function _(e,t){for(let n of e.properties)!I(n)||n.computed||!z(n.key)||n.key.name!==`t`||z(n.value)&&t.add(n.value.name)}function v(e,t,n,r,i,a){if(!L(t)||t.start==null||t.end==null)return;let o=y(e,t,n,a);if(!o)return;let{catalogId:s}=o;i.add(s);let c=a(s),l=r===`dynamic`?`__catalog[${JSON.stringify(s)}]`:`_${c}`,u=o.valuesSource?`${l}(${o.valuesSource})`:l;return{start:t.start,end:t.end,replacement:u}}function y(e,t,n,r){if(t.arguments.length===0)return;let i=t.callee,a=z(i)&&(n.tracked.has(i.name)||i.name===`$t`),o=R(i)&&!i.computed&&z(i.property)&&(i.property.name===`$t`||i.property.name===`t`&&z(i.object)&&(i.object.name===`_ctx`||i.object.name===`$setup`)),s=L(i)&&z(i.callee)&&n.unref.has(i.callee.name)&&i.arguments.length===1&&z(i.arguments[0])&&n.tracked.has(i.arguments[0].name);if(!a&&!o&&!s)return;let c=b(t.arguments[0],r);if(!c)return;let l=t.arguments[1]&&t.arguments[1].start!=null&&t.arguments[1].end!=null?e.slice(t.arguments[1].start,t.arguments[1].end):void 0;return l===void 0?{catalogId:c}:{catalogId:c,valuesSource:l}}function b(e,t){let n=j(e);if(n!==void 0)return t(n);if(!F(e))return;let r,i,a;for(let t of e.properties){if(!I(t)||t.computed)continue;let e=M(t.key);if(!e)continue;let n=j(t.value);n!==void 0&&(e===`id`&&(r=n),e===`message`&&(i=n),e===`context`&&(a=n))}if(r)return r;if(i)return t(i,a)}function x(e,t,n){if(!B(e))return;let r=A(e.openingElement.name);if(r){if(r===`Trans`){let r=E(e.openingElement,`__id`)??E(e.openingElement,`id`);if(r){t.add(r);return}let i=E(e.openingElement,`__message`),a=E(e.openingElement,`context`);i&&t.add(n(i,a));return}if(r===`Plural`){let r=S(e.openingElement,n);r&&t.add(r);return}if(r===`Select`){let r=C(e.openingElement,n);r&&t.add(r)}}}function S(e,t){let n=E(e,`id`);if(n)return n;let r=E(e,`context`),i=D(e,`offset`),a=[E(e,`zero`)===void 0?void 0:`=0 {${E(e,`zero`)}}`,E(e,`one`)===void 0?void 0:`one {${E(e,`one`)}}`,E(e,`two`)===void 0?void 0:`two {${E(e,`two`)}}`,E(e,`few`)===void 0?void 0:`few {${E(e,`few`)}}`,E(e,`many`)===void 0?void 0:`many {${E(e,`many`)}}`,E(e,`other`)===void 0?void 0:`other {${E(e,`other`)}}`].filter(Boolean);if(a.length!==0)return t(`{count, plural,${typeof i==`number`?` offset:${i}`:``} ${a.join(` `)}}`,r)}function C(e,t){let n=E(e,`id`);if(n)return n;let r=E(e,`context`),i=w(e);if(!(!i||i.other===void 0))return t(`{value, select, ${[...Object.keys(i).filter(e=>e!==`other`).sort(),`other`].map(e=>`${e} {${i[e]}}`).join(` `)}}`,r)}function w(e){let t=ee(e,`options`);if(t){let n=E(e,`other`);return{...t,...n===void 0?{}:{other:n}}}let n={};for(let t of e.attributes){if(!V(t))continue;let e=t.name.name;if([`value`,`id`,`context`,`comment`,`options`].includes(e))continue;let r=k(t);r!==void 0&&(n[e]=r)}return Object.keys(n).length>0?n:void 0}function T(e){if(!F(e))return;let t={};for(let n of e.properties){if(!I(n)||n.computed)return;let e=M(n.key),r=j(n.value);if(!e||r===void 0)return;t[e]=r}return t}function ee(e,t){let n=O(e,t);if(n?.value&&n.value.type===`JSXExpressionContainer`)return T(n.value.expression)}function E(e,t){return k(O(e,t))}function D(e,t){let n=O(e,t);if(!n?.value||n.value.type!==`JSXExpressionContainer`)return;let r=n.value.expression;return r.type===`NumericLiteral`?r.value:void 0}function O(e,t){return e.attributes.find(e=>V(e)&&e.name.name===t)}function k(e){if(e?.value){if(e.value.type===`StringLiteral`)return e.value.value;if(e.value.type===`JSXExpressionContainer`)return j(e.value.expression)}}function A(e){return e.type===`JSXIdentifier`?e.name:void 0}function j(e){if(e.type===`StringLiteral`)return e.value;if(e.type===`TemplateLiteral`){let t=e;if(t.expressions.length===0&&t.quasis.length===1)return t.quasis[0].value.cooked??t.quasis[0].value.raw}}function M(e){if(z(e))return e.name;if(e.type===`StringLiteral`)return e.value}function N(e){return e.type===`ImportDeclaration`}function P(e){return e.type===`ImportSpecifier`}function te(e){return e.type===`VariableDeclarator`}function ne(e){return e.type===`ObjectPattern`}function F(e){return e.type===`ObjectExpression`}function I(e){return e.type===`ObjectProperty`}function L(e){return e.type===`CallExpression`}function R(e){return e.type===`MemberExpression`}function z(e){return e?.type===`Identifier`}function B(e){return e.type===`JSXElement`}function V(e){return e.type===`JSXAttribute`}function H(e){let t=e.imported;if(t.type===`Identifier`)return t.name;if(t.type===`StringLiteral`)return t.value}function U(e,n,r,i){if(n===`dynamic`)return`import { __catalog } from 'virtual:fluenti/runtime';\n${e}`;let a=i??t.hashMessage;return`import { ${[...r].map(e=>`_${a(e)}`).join(`, `)} } from 'virtual:fluenti/messages';\n${e}`}function W(e){return JSON.stringify(e)}function G(e){if(e.includes("`")||e.includes(`$`))throw Error(`[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(e)}`)}var K=`virtual:fluenti/runtime`,q=`virtual:fluenti/messages`,J=`\0virtual:fluenti/runtime`,Y=`\0virtual:fluenti/messages`;function X(e){if(e===K)return J;if(e===q)return Y}function Z(e,t){if(e===J)return re(t);if(e===Y)return ie(t)}function re(e){let{locales:t,runtimeGenerator:n,catalogDir:r}=e;G(r);for(let e of t)(0,o.validateLocale)(e,`vite-plugin`);if(!n)throw Error(`[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).`);return n.generateRuntime(ae(e))}function ie(e){let{rootDir:t,catalogDir:n,catalogExtension:i,defaultBuildLocale:s,sourceLocale:c}=e,l=s||c;(0,o.validateLocale)(l,`vite-plugin`),G(n);let u=(0,r.resolve)((0,r.resolve)(t,n),l+i);return(0,a.existsSync)(u)||console.warn(`[fluenti] Compiled catalog for locale "${l}" not found at ${u}. Run "fluenti compile" first.`),`export * from ${W(u)}\n`}function ae(e){let{rootDir:t,catalogDir:n,catalogExtension:r,locales:i,sourceLocale:a,defaultBuildLocale:o}=e;return{rootDir:t,catalogDir:n,catalogExtension:r,locales:i,sourceLocale:a,defaultBuildLocale:o}}var Q=(0,n.createRequire)(typeof __filename<`u`?__filename:{}.url),oe=`virtual:fluenti/messages/`,se=`\0virtual:fluenti/messages/`;function $(e,t){if(typeof e==`object`){let{DEFAULT_FLUENTI_CONFIG:t}=Q(`@fluenti/core/config`);return{...t,...e}}let{loadConfigSync:n}=Q(`@fluenti/core/config`);return n(typeof e==`string`?e:void 0,t)}function ce(n,r,a){let o,s=process.cwd();function h(e){let t=e??s;return o||=$(n.config,t),o}let g=n.framework;function _(e){let n=h(e),r=n.compileOutDir.replace(/^\.\//,``),i=n.catalogExtension??`.js`,a=n.splitting??!1;a&&a!==`dynamic`&&a!==`static`&&console.warn(`[fluenti] Invalid splitting value "${a}". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`);let o=a===`static`?`static`:a?`dynamic`:!1,s=n.sourceLocale;return{config:n,catalogDir:r,catalogExtension:i,splitting:o,sourceLocale:s,localeCodes:(0,t.resolveLocaleCodes)(n.locales),defaultBuildLocale:n.defaultBuildLocale??s}}let v={name:`fluenti:virtual`,configResolved(e){s=e.root,o=$(n.config,s),c(e.command)},resolveId(e){if(e.startsWith(oe))return`\0`+e;let{splitting:t}=_();if(t){let t=X(e);if(t)return t}},load(e){let{catalogDir:t,catalogExtension:n,splitting:r,localeCodes:i,sourceLocale:o,defaultBuildLocale:c}=_();if(e.startsWith(se)){let r=e.slice(26);return i.includes(r)?`export { default } from '${`${t}/${r}${n}`}'`:void 0}if(r){let r=Z(e,{rootDir:s,catalogDir:t,catalogExtension:n,locales:i,sourceLocale:o,defaultBuildLocale:c,framework:g,runtimeGenerator:a});if(r)return r}}},y=(0,i.createTransformPipeline)({framework:g}),b={name:`fluenti:script-transform`,enforce:`pre`,transform(e,t){if(t.includes(`node_modules`)||!t.match(/\.(vue|tsx|jsx|ts|js)(\?|$)/)||t.includes(`.vue`)&&!t.includes(`type=script`))return;let n=g===`vue`&&t.includes(`.vue`),r=e,a=!1;if(t.match(/\.[jt]sx(\?|$)/)&&/<Trans[\s>]/.test(r)){let e=y.transformTrans(r);e.transformed&&(r=e.code,a=!0)}if((0,i.hasScopeTransformCandidate)(r)){let e=y.transformScope(r,n?{allowTopLevelImportedT:!0}:void 0);if(e.transformed)return{code:e.code,map:null}}return a?{code:r,map:null}:void 0}},x={name:`fluenti:build-split`,transform(e,t){let{splitting:n,config:r}=_();if(!n||!u(l(this))||t.includes(`node_modules`)||!t.match(/\.(vue|tsx|jsx|ts|js)(\?|$)/))return;let i=n===`static`?`static`:`dynamic`,a=r.idGenerator?{hashFn:r.idGenerator}:void 0,o=i===`static`?m(e,a):p(e,a);if(o.needsCatalogImport)return{code:U(o.code,i,o.usedHashes,r.idGenerator),map:null}}},S={name:`fluenti:build-compile`,async buildStart(){let{config:e}=_();u(l(this))&&(e.buildAutoCompile??!0)&&(e.onBeforeCompile&&await e.onBeforeCompile()===!1||(await d({cwd:s,throwOnError:!0,compileOnly:!0}),e.onAfterCompile&&await e.onAfterCompile()))}},C={name:`fluenti:dev`,configureServer(t){let{config:n,catalogDir:r}=_(t.config.root);if(!(n.devAutoCompile??!0))return;let i=(0,e.createFilter)(n.include??[`src/**/*.{vue,tsx,jsx,ts,js}`],[...n.exclude??[],`**/node_modules/**`,`**/${r}/**`]),a={cwd:t.config.root,onSuccess:()=>{}};n.parallelCompile&&(a.parallelCompile=!0),n.onBeforeCompile&&(a.onBeforeCompile=n.onBeforeCompile),n.onAfterCompile&&(a.onAfterCompile=n.onAfterCompile);let o=f(a,n.devAutoCompileDelay??500);o(),t.watcher.on(`change`,e=>{i(e)&&o()})},hotUpdate({file:e}){let{catalogDir:t}=_();if(e.includes(t)){let e=[...this.environment.moduleGraph.urlToModuleMap.entries()].filter(([e])=>e.includes(`virtual:fluenti`)).map(([,e])=>e);if(e.length>0)return e}}};return[v,...r,b,S,x,C]}exports.createFluentiPlugins=ce,Object.defineProperty(exports,`createRuntimeGenerator`,{enumerable:!0,get:function(){return i.createRuntimeGenerator}}),exports.getPluginEnvironment=l,exports.isBuildMode=u,exports.loadVirtualSplitModule=Z,exports.resolveVirtualSplitId=X,exports.setResolvedMode=c;
|
|
4
|
+
See: https://fluenti.dev/start/introduction/`;if(e.throwOnError)throw Error(t);console.warn(t),e.onError?.(Error(t));return}if(e.throwOnError)throw n;console.warn(`[fluenti] Extract/compile failed:`,n.message),e.onError?.(n)}}}function f(e,t=300){let n=null,r=!1,i=!1;async function a(){r=!0;try{await d(e)}finally{r=!1,i&&(i=!1,o())}}function o(){n!==null&&clearTimeout(n),n=setTimeout(()=>{n=null,r?i=!0:a()},t)}return o}function p(e,t){return h(e,`dynamic`,t)}function m(e,t){return h(e,`static`,t)}function h(e,n,r){let i=r?.hashFn??t.hashMessage,o=(0,a.parseSourceModule)(e);if(!o||o.type!==`Program`)return{code:e,needsCatalogImport:!1,usedHashes:new Set};let s=g(o),c=[],l=new Set;if((0,a.walkSourceAst)(o,t=>{let r=v(e,t,s,n,l,i);if(r){c.push(r);return}x(t,l,i)}),c.length===0)return{code:e,needsCatalogImport:!1,usedHashes:l};let u=e;for(let e=c.length-1;e>=0;e--){let{start:t,end:n,replacement:r}=c[e];u=u.slice(0,t)+r+u.slice(n)}return{code:u,needsCatalogImport:!0,usedHashes:l}}function g(e){let t=new Set,n=new Set,r=new Set,i=new Set;for(let t of e.body)if(N(t))for(let e of t.specifiers){if(!P(e))continue;let t=H(e);t&&(t===`useI18n`&&n.add(e.local.name),t===`getI18n`&&r.add(e.local.name),t===`unref`&&i.add(e.local.name))}return(0,a.walkSourceAst)(e,e=>{if(!te(e)||!e.init||!ne(e.id))return;if(L(e.init)&&z(e.init.callee)&&n.has(e.init.callee.name)){_(e.id,t);return}let i=e.init.type===`AwaitExpression`?e.init.argument:null;i&&L(i)&&z(i.callee)&&r.has(i.callee.name)&&_(e.id,t)}),{tracked:t,unref:i}}function _(e,t){for(let n of e.properties)!I(n)||n.computed||!z(n.key)||n.key.name!==`t`||z(n.value)&&t.add(n.value.name)}function v(e,t,n,r,i,a){if(!L(t)||t.start==null||t.end==null)return;let o=y(e,t,n,a);if(!o)return;let{catalogId:s}=o;i.add(s);let c=a(s),l=r===`dynamic`?`__catalog[${JSON.stringify(s)}]`:`_${c}`,u=o.valuesSource?`${l}(${o.valuesSource})`:l;return{start:t.start,end:t.end,replacement:u}}function y(e,t,n,r){if(t.arguments.length===0)return;let i=t.callee,a=z(i)&&(n.tracked.has(i.name)||i.name===`$t`),o=R(i)&&!i.computed&&z(i.property)&&(i.property.name===`$t`||i.property.name===`t`&&z(i.object)&&(i.object.name===`_ctx`||i.object.name===`$setup`)),s=L(i)&&z(i.callee)&&n.unref.has(i.callee.name)&&i.arguments.length===1&&z(i.arguments[0])&&n.tracked.has(i.arguments[0].name);if(!a&&!o&&!s)return;let c=b(t.arguments[0],r);if(!c)return;let l=t.arguments[1]&&t.arguments[1].start!=null&&t.arguments[1].end!=null?e.slice(t.arguments[1].start,t.arguments[1].end):void 0;return l===void 0?{catalogId:c}:{catalogId:c,valuesSource:l}}function b(e,t){let n=j(e);if(n!==void 0)return t(n);if(!F(e))return;let r,i,a;for(let t of e.properties){if(!I(t)||t.computed)continue;let e=M(t.key);if(!e)continue;let n=j(t.value);n!==void 0&&(e===`id`&&(r=n),e===`message`&&(i=n),e===`context`&&(a=n))}if(r)return r;if(i)return t(i,a)}function x(e,t,n){if(!B(e))return;let r=A(e.openingElement.name);if(r){if(r===`Trans`){let r=E(e.openingElement,`__id`)??E(e.openingElement,`id`);if(r){t.add(r);return}let i=E(e.openingElement,`__message`),a=E(e.openingElement,`context`);i&&t.add(n(i,a));return}if(r===`Plural`){let r=S(e.openingElement,n);r&&t.add(r);return}if(r===`Select`){let r=C(e.openingElement,n);r&&t.add(r)}}}function S(e,t){let n=E(e,`id`);if(n)return n;let r=E(e,`context`),i=D(e,`offset`),a=[E(e,`zero`)===void 0?void 0:`=0 {${E(e,`zero`)}}`,E(e,`one`)===void 0?void 0:`one {${E(e,`one`)}}`,E(e,`two`)===void 0?void 0:`two {${E(e,`two`)}}`,E(e,`few`)===void 0?void 0:`few {${E(e,`few`)}}`,E(e,`many`)===void 0?void 0:`many {${E(e,`many`)}}`,E(e,`other`)===void 0?void 0:`other {${E(e,`other`)}}`].filter(Boolean);if(a.length!==0)return t(`{count, plural,${typeof i==`number`?` offset:${i}`:``} ${a.join(` `)}}`,r)}function C(e,t){let n=E(e,`id`);if(n)return n;let r=E(e,`context`),i=w(e);if(!(!i||i.other===void 0))return t(`{value, select, ${[...Object.keys(i).filter(e=>e!==`other`).sort(),`other`].map(e=>`${e} {${i[e]}}`).join(` `)}}`,r)}function w(e){let t=ee(e,`options`);if(t){let n=E(e,`other`);return{...t,...n===void 0?{}:{other:n}}}let n={};for(let t of e.attributes){if(!V(t))continue;let e=t.name.name;if([`value`,`id`,`context`,`comment`,`options`].includes(e))continue;let r=k(t);r!==void 0&&(n[e]=r)}return Object.keys(n).length>0?n:void 0}function T(e){if(!F(e))return;let t={};for(let n of e.properties){if(!I(n)||n.computed)return;let e=M(n.key),r=j(n.value);if(!e||r===void 0)return;t[e]=r}return t}function ee(e,t){let n=O(e,t);if(n?.value&&n.value.type===`JSXExpressionContainer`)return T(n.value.expression)}function E(e,t){return k(O(e,t))}function D(e,t){let n=O(e,t);if(!n?.value||n.value.type!==`JSXExpressionContainer`)return;let r=n.value.expression;return r.type===`NumericLiteral`?r.value:void 0}function O(e,t){return e.attributes.find(e=>V(e)&&e.name.name===t)}function k(e){if(e?.value){if(e.value.type===`StringLiteral`)return e.value.value;if(e.value.type===`JSXExpressionContainer`)return j(e.value.expression)}}function A(e){return e.type===`JSXIdentifier`?e.name:void 0}function j(e){if(e.type===`StringLiteral`)return e.value;if(e.type===`TemplateLiteral`){let t=e;if(t.expressions.length===0&&t.quasis.length===1)return t.quasis[0].value.cooked??t.quasis[0].value.raw}}function M(e){if(z(e))return e.name;if(e.type===`StringLiteral`)return e.value}function N(e){return e.type===`ImportDeclaration`}function P(e){return e.type===`ImportSpecifier`}function te(e){return e.type===`VariableDeclarator`}function ne(e){return e.type===`ObjectPattern`}function F(e){return e.type===`ObjectExpression`}function I(e){return e.type===`ObjectProperty`}function L(e){return e.type===`CallExpression`}function R(e){return e.type===`MemberExpression`}function z(e){return e?.type===`Identifier`}function B(e){return e.type===`JSXElement`}function V(e){return e.type===`JSXAttribute`}function H(e){let t=e.imported;if(t.type===`Identifier`)return t.name;if(t.type===`StringLiteral`)return t.value}function U(e,n,r,i){if(n===`dynamic`)return`import { __catalog } from 'virtual:fluenti/runtime';\n${e}`;let a=i??t.hashMessage;return`import { ${[...r].map(e=>`_${a(e)}`).join(`, `)} } from 'virtual:fluenti/messages';\n${e}`}function W(e){return JSON.stringify(e)}function G(e){if(e.includes("`")||e.includes(`$`))throw Error(`[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(e)}`)}var K=`virtual:fluenti/runtime`,q=`virtual:fluenti/messages`,J=`\0virtual:fluenti/runtime`,Y=`\0virtual:fluenti/messages`;function X(e){if(e===K)return J;if(e===q)return Y}function Z(e,t){if(e===J)return re(t);if(e===Y)return ie(t)}function re(e){let{locales:t,runtimeGenerator:n,catalogDir:r}=e;G(r);for(let e of t)(0,o.validateLocale)(e,`vite-plugin`);if(!n)throw Error(`[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).`);return n.generateRuntime(ae(e))}function ie(e){let{rootDir:t,catalogDir:n,catalogExtension:a,defaultBuildLocale:s,sourceLocale:c}=e,l=s||c;(0,o.validateLocale)(l,`vite-plugin`),G(n);let u=(0,r.resolve)((0,r.resolve)(t,n),l+a);return(0,i.existsSync)(u)||console.warn(`[fluenti] Compiled catalog for locale "${l}" not found at ${u}. Run "fluenti compile" first.`),`export * from ${W(u)}\n`}function ae(e){let{rootDir:t,catalogDir:n,catalogExtension:r,locales:i,sourceLocale:a,defaultBuildLocale:o}=e;return{rootDir:t,catalogDir:n,catalogExtension:r,locales:i,sourceLocale:a,defaultBuildLocale:o}}var Q=(0,n.createRequire)(typeof __filename<`u`?__filename:{}.url),oe=`virtual:fluenti/messages/`,se=`\0virtual:fluenti/messages/`;function $(e,t){if(typeof e==`object`){let{DEFAULT_FLUENTI_CONFIG:t}=Q(`@fluenti/core/config`);return{...t,...e}}let{loadConfigSync:n}=Q(`@fluenti/core/config`);return n(typeof e==`string`?e:void 0,t)}function ce(n,r,i){let o,s=process.cwd();function h(e){let t=e??s;return o||=$(n.config,t),o}let g=n.framework;function _(e){let n=h(e),r=n.compileOutDir.replace(/^\.\//,``),i=n.catalogExtension??`.js`,a=n.splitting??!1;a&&a!==`dynamic`&&a!==`static`&&console.warn(`[fluenti] Invalid splitting value "${a}". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`);let o=a===`static`?`static`:a?`dynamic`:!1,s=n.sourceLocale;return{config:n,catalogDir:r,catalogExtension:i,splitting:o,sourceLocale:s,localeCodes:(0,t.resolveLocaleCodes)(n.locales),defaultBuildLocale:n.defaultBuildLocale??s}}let v={name:`fluenti:virtual`,configResolved(e){s=e.root,o=$(n.config,s),c(e.command)},resolveId(e){if(e.startsWith(oe))return`\0`+e;let{splitting:t}=_();if(t){let t=X(e);if(t)return t}},load(e){let{catalogDir:t,catalogExtension:n,splitting:r,localeCodes:a,sourceLocale:o,defaultBuildLocale:c}=_();if(e.startsWith(se)){let r=e.slice(26);return a.includes(r)?`export { default } from '${`${t}/${r}${n}`}'`:void 0}if(r){let r=Z(e,{rootDir:s,catalogDir:t,catalogExtension:n,locales:a,sourceLocale:o,defaultBuildLocale:c,framework:g,runtimeGenerator:i});if(r)return r}}},y=(0,a.createTransformPipeline)({framework:g}),b={name:`fluenti:script-transform`,enforce:`pre`,transform(e,t){if(t.includes(`node_modules`)||!t.match(/\.(vue|tsx|jsx|ts|js)(\?|$)/)||t.includes(`.vue`)&&!t.includes(`type=script`))return;let n=g===`vue`&&t.includes(`.vue`),r=e,i=!1;if(t.match(/\.[jt]sx(\?|$)/)&&/<Trans[\s>]/.test(r)){let e=y.transformTrans(r);e.transformed&&(r=e.code,i=!0)}if((0,a.hasScopeTransformCandidate)(r)){let e=y.transformScope(r,n?{allowTopLevelImportedT:!0}:void 0);if(e.transformed)return{code:e.code,map:null}}return i?{code:r,map:null}:void 0}},x={name:`fluenti:build-split`,transform(e,t){let{splitting:n,config:r}=_();if(!n||!u(l(this))||t.includes(`node_modules`)||!t.match(/\.(vue|tsx|jsx|ts|js)(\?|$)/))return;let i=n===`static`?`static`:`dynamic`,a=r.idGenerator?{hashFn:r.idGenerator}:void 0,o=i===`static`?m(e,a):p(e,a);if(o.needsCatalogImport)return{code:U(o.code,i,o.usedHashes,r.idGenerator),map:null}}},S={name:`fluenti:build-compile`,async buildStart(){let{config:e}=_();u(l(this))&&(e.buildAutoCompile??!0)&&(e.onBeforeCompile&&await e.onBeforeCompile()===!1||(await d({cwd:s,throwOnError:!0,compileOnly:!0}),e.onAfterCompile&&await e.onAfterCompile()))}},C={name:`fluenti:dev`,configureServer(t){let{config:n,catalogDir:r}=_(t.config.root);if(!(n.devAutoCompile??!0))return;let i=(0,e.createFilter)(n.include??[`src/**/*.{vue,tsx,jsx,ts,js}`],[...n.exclude??[],`**/node_modules/**`,`**/${r}/**`]),a={cwd:t.config.root,onSuccess:()=>{}};n.parallelCompile&&(a.parallelCompile=!0),n.onBeforeCompile&&(a.onBeforeCompile=n.onBeforeCompile),n.onAfterCompile&&(a.onAfterCompile=n.onAfterCompile);let o=f(a,n.devAutoCompileDelay??500);o(),t.watcher.on(`change`,e=>{i(e)&&o()})},hotUpdate({file:e}){let{catalogDir:t}=_();if(e.includes(t)){let e=[...this.environment.moduleGraph.urlToModuleMap.entries()].filter(([e])=>e.includes(`virtual:fluenti`)).map(([,e])=>e);if(e.length>0)return e}}};return[v,...r,b,S,x,C]}exports.createFluentiPlugins=ce,Object.defineProperty(exports,`createRuntimeGenerator`,{enumerable:!0,get:function(){return a.createRuntimeGenerator}}),exports.getPluginEnvironment=l,exports.isBuildMode=u,exports.loadVirtualSplitModule=Z,exports.resolveVirtualSplitId=X,exports.setResolvedMode=c;
|
|
5
5
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/mode-detect.ts","../src/dev-runner.ts","../src/build-transform.ts","../src/virtual-modules.ts","../src/index.ts"],"sourcesContent":["/**\n * Detect whether Vite is running in build or dev mode.\n * Supports Vite 7 (configResolved) and Vite 8+ (environment API).\n */\n\nlet resolvedMode: 'build' | 'dev' = 'dev'\n\n/** Called from configResolved hook to capture the mode early */\nexport function setResolvedMode(command: string): void {\n resolvedMode = command === 'build' ? 'build' : 'dev'\n}\n\n/** Get the current resolved mode */\nexport function getResolvedMode(): 'build' | 'dev' {\n return resolvedMode\n}\n\n/**\n * Safely extract the environment object from a Vite plugin context.\n * Handles Vite 8+ environment API without direct `(this as any)` casts at call sites.\n */\nexport function getPluginEnvironment(pluginContext: unknown): { mode?: string } | undefined {\n if (\n typeof pluginContext === 'object' &&\n pluginContext !== null &&\n 'environment' in pluginContext\n ) {\n const env = (pluginContext as Record<string, unknown>)['environment']\n if (typeof env === 'object' && env !== null) {\n return env as { mode?: string }\n }\n }\n return undefined\n}\n\n/**\n * Check if we're in build mode.\n * Tries environment API (Vite 8+), then falls back to configResolved capture,\n * then falls back to NODE_ENV.\n */\nexport function isBuildMode(environment?: { mode?: string }): boolean {\n // Vite 8+: environment.mode === 'build'\n if (environment?.mode === 'build') return true\n\n // Vite 7: captured from configResolved\n if (resolvedMode === 'build') return true\n\n // Last resort: NODE_ENV\n if (process.env['NODE_ENV'] === 'production') return true\n\n return false\n}\n","import { join } from 'node:path'\nimport { createRequire } from 'node:module'\n\nexport interface DevRunnerOptions {\n cwd: string\n onSuccess?: () => void\n onError?: (err: Error) => void\n /** If true, reject the promise on failure instead of swallowing the error */\n throwOnError?: boolean\n /** Run only compile (skip extract). Useful for production builds where source is unchanged. */\n compileOnly?: boolean\n /** Enable parallel compilation across locales using worker threads */\n parallelCompile?: boolean\n /** Called before compile runs. Return false to skip compilation. */\n onBeforeCompile?: () => boolean | void | Promise<boolean | void>\n /** Called after compile completes successfully */\n onAfterCompile?: () => void | Promise<void>\n}\n\n/**\n * Run compile in-process via `@fluenti/cli`.\n *\n * In `compileOnly` mode, only compilation is performed (extract is skipped).\n * In dev mode, both extract and compile run in sequence.\n *\n * If `@fluenti/cli` is not installed, shows an install guide instead of\n * falling back to shell-out — keeping the process boundary clean.\n */\nexport async function runExtractCompile(options: DevRunnerOptions): Promise<void> {\n if (options.onBeforeCompile) {\n const result = await options.onBeforeCompile()\n if (result === false) return\n }\n\n if (options.compileOnly) {\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runCompile } = projectRequire('@fluenti/cli')\n await runCompile(options.cwd)\n console.log('[fluenti] Compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n if (options.throwOnError) throw error\n console.warn('[fluenti] Compile failed:', error.message)\n options.onError?.(error)\n return\n }\n }\n\n // Dev mode: in-process extract + compile\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runExtract, runCompile } = projectRequire('@fluenti/cli')\n await runExtract(options.cwd)\n await runCompile(options.cwd, { parallel: options.parallelCompile })\n console.log('[fluenti] Extracting and compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n const isNotInstalled = error.message.includes('Cannot find module')\n\n if (isNotInstalled) {\n const msg =\n '[fluenti] @fluenti/cli is required for auto-compile.\\n' +\n ' Install it as a devDependency:\\n' +\n ' pnpm add -D @fluenti/cli\\n' +\n ' See: https://fluenti.dev/start/introduction/'\n if (options.throwOnError) throw new Error(msg)\n console.warn(msg)\n options.onError?.(new Error(msg))\n return\n }\n\n if (options.throwOnError) throw error\n console.warn('[fluenti] Extract/compile failed:', error.message)\n options.onError?.(error)\n }\n}\n\n/**\n * Create a debounced runner that collapses rapid calls.\n *\n * - If called while idle, schedules a run after `delay` ms.\n * - If called while a run is in progress, marks a pending rerun.\n * - Never runs concurrently.\n */\nexport function createDebouncedRunner(\n options: DevRunnerOptions,\n delay = 300,\n): () => void {\n let timer: ReturnType<typeof setTimeout> | null = null\n let running = false\n let pendingRerun = false\n\n async function execute(): Promise<void> {\n running = true\n try {\n await runExtractCompile(options)\n } finally {\n running = false\n if (pendingRerun) {\n pendingRerun = false\n schedule()\n }\n }\n }\n\n function schedule(): void {\n if (timer !== null) {\n clearTimeout(timer)\n }\n timer = setTimeout(() => {\n timer = null\n if (running) {\n pendingRerun = true\n } else {\n execute()\n }\n }, delay)\n }\n\n return schedule\n}\n","/**\n * Build-mode transform for code-splitting.\n *\n * Strategy 'dynamic': rewrites supported translation calls to __catalog._<hash> references.\n * Strategy 'static': rewrites to direct named imports from compiled locale modules.\n */\n\nimport { hashMessage as defaultHashMessage } from '@fluenti/core/internal'\nimport { parseSourceModule, walkSourceAst, type SourceNode } from '@fluenti/core/transform'\n\nexport type HashFunction = (message: string, context?: string) => string\n\nexport interface BuildTransformResult {\n code: string\n needsCatalogImport: boolean\n usedHashes: Set<string>\n}\n\nexport interface BuildTransformOptions {\n /** Custom hash function for message IDs (defaults to @fluenti/core hashMessage) */\n hashFn?: HashFunction\n}\n\ntype SplitStrategy = 'dynamic' | 'static'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { cooked: string | null; raw: string }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n expressions: SourceNode[]\n quasis: TemplateElementNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface AwaitExpressionNode extends SourceNode {\n type: 'AwaitExpression'\n argument: SourceNode\n}\n\ninterface VariableDeclaratorNode extends SourceNode {\n type: 'VariableDeclarator'\n id: SourceNode\n init?: SourceNode | null\n}\n\ninterface ProgramNode extends SourceNode {\n type: 'Program'\n body: SourceNode[]\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface ObjectPatternNode extends SourceNode {\n type: 'ObjectPattern'\n properties: SourceNode[]\n}\n\ninterface MemberExpressionNode extends SourceNode {\n type: 'MemberExpression'\n object: SourceNode\n property: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXIdentifierNode extends SourceNode {\n type: 'JSXIdentifier'\n name: string\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: JSXIdentifierNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface SplitReplacement {\n start: number\n end: number\n replacement: string\n}\n\ninterface SplitTarget {\n catalogId: string\n valuesSource?: string\n}\n\ninterface RuntimeBindings {\n tracked: Set<string>\n unref: Set<string>\n}\n\nexport function transformForDynamicSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'dynamic', options)\n}\n\nexport function transformForStaticSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'static', options)\n}\n\nfunction transformForSplitStrategy(\n code: string,\n strategy: SplitStrategy,\n options?: BuildTransformOptions,\n): BuildTransformResult {\n const hashFn = options?.hashFn ?? defaultHashMessage\n const ast = parseSourceModule(code)\n if (!ast || ast.type !== 'Program') {\n return { code, needsCatalogImport: false, usedHashes: new Set() }\n }\n\n const bindings = collectTrackedRuntimeBindings(ast as ProgramNode)\n const replacements: SplitReplacement[] = []\n const usedHashes = new Set<string>()\n\n walkSourceAst(ast, (node) => {\n const replacement = extractCallReplacement(code, node, bindings, strategy, usedHashes, hashFn)\n if (replacement) {\n replacements.push(replacement)\n return\n }\n\n collectComponentUsage(node, usedHashes, hashFn)\n })\n\n if (replacements.length === 0) {\n return { code, needsCatalogImport: false, usedHashes }\n }\n\n let result = code\n for (let i = replacements.length - 1; i >= 0; i--) {\n const { start, end, replacement } = replacements[i]!\n result = result.slice(0, start) + replacement + result.slice(end)\n }\n\n return { code: result, needsCatalogImport: true, usedHashes }\n}\n\nfunction collectTrackedRuntimeBindings(program: ProgramNode): RuntimeBindings {\n const tracked = new Set<string>()\n const useI18nBindings = new Set<string>()\n const getI18nBindings = new Set<string>()\n const unrefBindings = new Set<string>()\n\n for (const statement of program.body) {\n if (!isImportDeclaration(statement)) continue\n for (const specifier of statement.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n const importedName = readImportedName(specifier)\n if (!importedName) continue\n if (importedName === 'useI18n') {\n useI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'getI18n') {\n getI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'unref') {\n unrefBindings.add(specifier.local.name)\n }\n }\n }\n\n walkSourceAst(program, (node) => {\n if (!isVariableDeclarator(node) || !node.init || !isObjectPattern(node.id)) return\n\n if (isCallExpression(node.init) && isIdentifier(node.init.callee) && useI18nBindings.has(node.init.callee.name)) {\n addTrackedObjectPatternBindings(node.id, tracked)\n return\n }\n\n const awaitedCall = node.init.type === 'AwaitExpression'\n ? (node.init as AwaitExpressionNode).argument\n : null\n\n if (\n awaitedCall\n && isCallExpression(awaitedCall)\n && isIdentifier(awaitedCall.callee)\n && getI18nBindings.has(awaitedCall.callee.name)\n ) {\n addTrackedObjectPatternBindings(node.id, tracked)\n }\n })\n\n return { tracked, unref: unrefBindings }\n}\n\nfunction addTrackedObjectPatternBindings(pattern: ObjectPatternNode, tracked: Set<string>): void {\n for (const property of pattern.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n if (!isIdentifier(property.key) || property.key.name !== 't') continue\n if (isIdentifier(property.value)) {\n tracked.add(property.value.name)\n }\n }\n}\n\nfunction extractCallReplacement(\n code: string,\n node: SourceNode,\n bindings: RuntimeBindings,\n strategy: SplitStrategy,\n usedHashes: Set<string>,\n hashFn: HashFunction,\n): SplitReplacement | undefined {\n if (!isCallExpression(node) || node.start == null || node.end == null) {\n return undefined\n }\n\n const splitTarget = resolveSplitTarget(code, node, bindings, hashFn)\n if (!splitTarget) {\n return undefined\n }\n\n const { catalogId } = splitTarget\n usedHashes.add(catalogId)\n const exportHash = hashFn(catalogId)\n const replacementTarget = strategy === 'dynamic'\n ? `__catalog[${JSON.stringify(catalogId)}]`\n : `_${exportHash}`\n const replacement = splitTarget.valuesSource\n ? `${replacementTarget}(${splitTarget.valuesSource})`\n : replacementTarget\n\n return {\n start: node.start,\n end: node.end,\n replacement,\n }\n}\n\nfunction resolveSplitTarget(\n code: string,\n call: CallExpressionNode,\n bindings: RuntimeBindings,\n hashFn: HashFunction,\n): SplitTarget | undefined {\n if (call.arguments.length === 0) return undefined\n\n const callee = call.callee\n const isTrackedIdentifierCall = isIdentifier(callee) && (bindings.tracked.has(callee.name) || callee.name === '$t')\n const isTemplateMemberCall = isMemberExpression(callee)\n && !callee.computed\n && isIdentifier(callee.property)\n && (\n callee.property.name === '$t'\n || (\n callee.property.name === 't'\n && isIdentifier(callee.object)\n && (callee.object.name === '_ctx' || callee.object.name === '$setup')\n )\n )\n const isVueUnrefCall = isCallExpression(callee)\n && isIdentifier(callee.callee)\n && bindings.unref.has(callee.callee.name)\n && callee.arguments.length === 1\n && isIdentifier(callee.arguments[0])\n && bindings.tracked.has(callee.arguments[0].name)\n\n if (!isTrackedIdentifierCall && !isTemplateMemberCall && !isVueUnrefCall) {\n return undefined\n }\n\n const catalogId = extractCatalogId(call.arguments[0]!, hashFn)\n if (!catalogId) return undefined\n\n const valuesSource = call.arguments[1] && call.arguments[1]!.start != null && call.arguments[1]!.end != null\n ? code.slice(call.arguments[1]!.start, call.arguments[1]!.end)\n : undefined\n\n return valuesSource === undefined\n ? { catalogId }\n : { catalogId, valuesSource }\n}\n\nfunction extractCatalogId(argument: SourceNode, hashFn: HashFunction): string | undefined {\n const staticString = readStaticString(argument)\n if (staticString !== undefined) {\n return hashFn(staticString)\n }\n\n if (!isObjectExpression(argument)) {\n return undefined\n }\n\n let id: string | undefined\n let message: string | undefined\n let context: string | undefined\n\n for (const property of argument.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n const key = readPropertyKey(property.key)\n if (!key) continue\n\n const value = readStaticString(property.value)\n if (value === undefined) continue\n\n if (key === 'id') id = value\n if (key === 'message') message = value\n if (key === 'context') context = value\n }\n\n if (id) return id\n if (message) return hashFn(message, context)\n return undefined\n}\n\nfunction collectComponentUsage(node: SourceNode, usedHashes: Set<string>, hashFn: HashFunction): void {\n if (!isJsxElement(node)) return\n\n const componentName = readJsxName(node.openingElement.name)\n if (!componentName) return\n\n if (componentName === 'Trans') {\n const id = readJsxStaticAttribute(node.openingElement, '__id') ?? readJsxStaticAttribute(node.openingElement, 'id')\n if (id) {\n usedHashes.add(id)\n return\n }\n\n const message = readJsxStaticAttribute(node.openingElement, '__message')\n const context = readJsxStaticAttribute(node.openingElement, 'context')\n if (message) {\n usedHashes.add(hashFn(message, context))\n }\n return\n }\n\n if (componentName === 'Plural') {\n const messageId = buildPluralMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n return\n }\n\n if (componentName === 'Select') {\n const messageId = buildSelectMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n }\n}\n\nfunction buildPluralMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const offsetRaw = readJsxStaticNumber(openingElement, 'offset')\n const forms = [\n readJsxStaticAttribute(openingElement, 'zero') === undefined ? undefined : `=0 {${readJsxStaticAttribute(openingElement, 'zero')}}`,\n readJsxStaticAttribute(openingElement, 'one') === undefined ? undefined : `one {${readJsxStaticAttribute(openingElement, 'one')}}`,\n readJsxStaticAttribute(openingElement, 'two') === undefined ? undefined : `two {${readJsxStaticAttribute(openingElement, 'two')}}`,\n readJsxStaticAttribute(openingElement, 'few') === undefined ? undefined : `few {${readJsxStaticAttribute(openingElement, 'few')}}`,\n readJsxStaticAttribute(openingElement, 'many') === undefined ? undefined : `many {${readJsxStaticAttribute(openingElement, 'many')}}`,\n readJsxStaticAttribute(openingElement, 'other') === undefined ? undefined : `other {${readJsxStaticAttribute(openingElement, 'other')}}`,\n ].filter(Boolean)\n\n if (forms.length === 0) return undefined\n\n const offsetPart = typeof offsetRaw === 'number' ? ` offset:${offsetRaw}` : ''\n const icuMessage = `{count, plural,${offsetPart} ${forms.join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction buildSelectMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const forms = readStaticSelectForms(openingElement)\n if (!forms || forms['other'] === undefined) return undefined\n\n const orderedKeys = [...Object.keys(forms).filter((key) => key !== 'other').sort(), 'other']\n const icuMessage = `{value, select, ${orderedKeys.map((key) => `${key} {${forms[key]!}}`).join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction readStaticSelectForms(openingElement: JSXOpeningElementNode): Record<string, string> | undefined {\n const optionForms = readJsxStaticObject(openingElement, 'options')\n if (optionForms) {\n const other = readJsxStaticAttribute(openingElement, 'other')\n return {\n ...optionForms,\n ...(other !== undefined ? { other } : {}),\n }\n }\n\n const forms: Record<string, string> = {}\n for (const attribute of openingElement.attributes) {\n if (!isJsxAttribute(attribute)) continue\n const name = attribute.name.name\n if (['value', 'id', 'context', 'comment', 'options'].includes(name)) continue\n const value = readJsxAttributeValue(attribute)\n if (value !== undefined) {\n forms[name] = value\n }\n }\n\n return Object.keys(forms).length > 0 ? forms : undefined\n}\n\nfunction readStaticSelectObjectValue(node: SourceNode): Record<string, string> | undefined {\n if (!isObjectExpression(node)) return undefined\n const values: Record<string, string> = {}\n\n for (const property of node.properties) {\n if (!isObjectProperty(property) || property.computed) return undefined\n const key = readPropertyKey(property.key)\n const value = readStaticString(property.value)\n if (!key || value === undefined) return undefined\n values[key] = value\n }\n\n return values\n}\n\nfunction readJsxStaticObject(openingElement: JSXOpeningElementNode, name: string): Record<string, string> | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value) return undefined\n if (attribute.value.type !== 'JSXExpressionContainer') return undefined\n return readStaticSelectObjectValue((attribute.value as JSXExpressionContainerNode).expression)\n}\n\nfunction readJsxStaticAttribute(openingElement: JSXOpeningElementNode, name: string): string | undefined {\n return readJsxAttributeValue(findJsxAttribute(openingElement, name))\n}\n\nfunction readJsxStaticNumber(openingElement: JSXOpeningElementNode, name: string): number | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value || attribute.value.type !== 'JSXExpressionContainer') return undefined\n const expression = (attribute.value as JSXExpressionContainerNode).expression\n return expression.type === 'NumericLiteral' ? (expression as NumericLiteralNode).value : undefined\n}\n\nfunction findJsxAttribute(openingElement: JSXOpeningElementNode, name: string): JSXAttributeNode | undefined {\n return openingElement.attributes.find((attribute) => {\n return isJsxAttribute(attribute) && attribute.name.name === name\n }) as JSXAttributeNode | undefined\n}\n\nfunction readJsxAttributeValue(attribute: JSXAttributeNode | undefined): string | undefined {\n if (!attribute?.value) return undefined\n\n if (attribute.value.type === 'StringLiteral') {\n return (attribute.value as StringLiteralNode).value\n }\n\n if (attribute.value.type === 'JSXExpressionContainer') {\n return readStaticString((attribute.value as JSXExpressionContainerNode).expression)\n }\n\n return undefined\n}\n\nfunction readJsxName(node: SourceNode): string | undefined {\n return node.type === 'JSXIdentifier' ? (node as JSXIdentifierNode).name : undefined\n}\n\nfunction readStaticString(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0 && template.quasis.length === 1) {\n return template.quasis[0]!.value.cooked ?? template.quasis[0]!.value.raw\n }\n }\n\n return undefined\n}\n\nfunction readPropertyKey(node: SourceNode): string | undefined {\n if (isIdentifier(node)) return node.name\n if (node.type === 'StringLiteral') return (node as StringLiteralNode).value\n return undefined\n}\n\nfunction isImportDeclaration(node: SourceNode): node is ImportDeclarationNode {\n return node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: SourceNode): node is ImportSpecifierNode {\n return node.type === 'ImportSpecifier'\n}\n\nfunction isVariableDeclarator(node: SourceNode): node is VariableDeclaratorNode {\n return node.type === 'VariableDeclarator'\n}\n\nfunction isObjectPattern(node: SourceNode): node is ObjectPatternNode {\n return node.type === 'ObjectPattern'\n}\n\nfunction isObjectExpression(node: SourceNode): node is ObjectExpressionNode {\n return node.type === 'ObjectExpression'\n}\n\nfunction isObjectProperty(node: SourceNode): node is ObjectPropertyNode {\n return node.type === 'ObjectProperty'\n}\n\nfunction isCallExpression(node: SourceNode): node is CallExpressionNode {\n return node.type === 'CallExpression'\n}\n\nfunction isMemberExpression(node: SourceNode): node is MemberExpressionNode {\n return node.type === 'MemberExpression'\n}\n\nfunction isIdentifier(node: SourceNode | undefined | null): node is IdentifierNode {\n return node?.type === 'Identifier'\n}\n\nfunction isJsxElement(node: SourceNode): node is JSXElementNode {\n return node.type === 'JSXElement'\n}\n\nfunction isJsxAttribute(node: SourceNode): node is JSXAttributeNode {\n return node.type === 'JSXAttribute'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n const imported = specifier.imported\n if (imported.type === 'Identifier') return imported.name\n if (imported.type === 'StringLiteral') return imported.value\n return undefined\n}\n\n/**\n * Inject the catalog import statement at the top of the module.\n */\nexport function injectCatalogImport(code: string, strategy: 'dynamic' | 'static', hashes: Set<string>, hashFn?: HashFunction): string {\n if (strategy === 'dynamic') {\n return `import { __catalog } from 'virtual:fluenti/runtime';\\n${code}`\n }\n\n // Static: import named exports directly\n const hash = hashFn ?? defaultHashMessage\n const imports = [...hashes].map((id) => `_${hash(id)}`).join(', ')\n return `import { ${imports} } from 'virtual:fluenti/messages';\\n${code}`\n}\n","/**\n * Virtual module resolution for code-splitting mode.\n *\n * Provides:\n * - virtual:fluenti/runtime → reactive catalog + switchLocale + preloadLocale\n * - virtual:fluenti/messages → re-export from static locale (for static strategy)\n */\n\nimport { resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { validateLocale } from '@fluenti/core'\nimport type { RuntimeGenerator, RuntimeGeneratorOptions } from './types'\n\n/**\n * Escapes a string value for safe embedding in generated JavaScript code.\n * Returns a JSON-encoded string (with double quotes), preventing injection\n * of quotes, backticks, template interpolation, and other special characters.\n */\nfunction safeStringLiteral(value: string): string {\n return JSON.stringify(value)\n}\n\n/**\n * Validates that a catalog directory path does not contain characters\n * that could enable code injection in generated template literals.\n */\nfunction validateCatalogDir(catalogDir: string): void {\n if (catalogDir.includes('`') || catalogDir.includes('$')) {\n throw new Error(\n `[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(catalogDir)}`,\n )\n }\n}\n\nconst VIRTUAL_RUNTIME = 'virtual:fluenti/runtime'\nconst VIRTUAL_MESSAGES = 'virtual:fluenti/messages'\nconst RESOLVED_RUNTIME = '\\0virtual:fluenti/runtime'\nconst RESOLVED_MESSAGES = '\\0virtual:fluenti/messages'\n\nexport interface VirtualModuleOptions {\n rootDir: string\n catalogDir: string\n catalogExtension: string\n locales: string[]\n sourceLocale: string\n defaultBuildLocale: string\n framework: string\n runtimeGenerator?: RuntimeGenerator | undefined\n}\n\nexport function resolveVirtualSplitId(id: string): string | undefined {\n if (id === VIRTUAL_RUNTIME) return RESOLVED_RUNTIME\n if (id === VIRTUAL_MESSAGES) return RESOLVED_MESSAGES\n return undefined\n}\n\nexport function loadVirtualSplitModule(\n id: string,\n options: VirtualModuleOptions,\n): string | undefined {\n if (id === RESOLVED_RUNTIME) {\n return generateRuntimeModule(options)\n }\n if (id === RESOLVED_MESSAGES) {\n return generateStaticMessagesModule(options)\n }\n return undefined\n}\n\nfunction generateRuntimeModule(options: VirtualModuleOptions): string {\n const { locales, runtimeGenerator, catalogDir } = options\n validateCatalogDir(catalogDir)\n for (const locale of locales) {\n validateLocale(locale, 'vite-plugin')\n }\n\n if (!runtimeGenerator) {\n throw new Error('[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).')\n }\n\n return runtimeGenerator.generateRuntime(toRuntimeGeneratorOptions(options))\n}\n\nfunction generateStaticMessagesModule(options: VirtualModuleOptions): string {\n const { rootDir, catalogDir, catalogExtension, defaultBuildLocale, sourceLocale } = options\n const defaultLocale = defaultBuildLocale || sourceLocale\n validateLocale(defaultLocale, 'vite-plugin')\n validateCatalogDir(catalogDir)\n const absoluteCatalogDir = resolve(rootDir, catalogDir)\n const catalogFile = resolve(absoluteCatalogDir, defaultLocale + catalogExtension)\n\n if (!existsSync(catalogFile)) {\n console.warn(\n `[fluenti] Compiled catalog for locale \"${defaultLocale}\" not found at ${catalogFile}. Run \"fluenti compile\" first.`,\n )\n }\n\n return `export * from ${safeStringLiteral(catalogFile)}\\n`\n}\n\nfunction toRuntimeGeneratorOptions(options: VirtualModuleOptions): RuntimeGeneratorOptions {\n const { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale } = options\n return { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale }\n}\n","import type { Plugin } from 'vite'\nimport { createFilter } from 'vite'\nimport type { FluentiCoreOptions, RuntimeGenerator } from './types'\nimport type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\nimport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\nimport { createRequire } from 'node:module'\n\nconst _require = createRequire(\n typeof __filename !== 'undefined' ? __filename : import.meta.url,\n)\nimport { createDebouncedRunner, runExtractCompile } from './dev-runner'\nimport { transformForDynamicSplit, transformForStaticSplit, injectCatalogImport } from './build-transform'\nimport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nimport { createTransformPipeline, hasScopeTransformCandidate } from '@fluenti/core/transform'\nexport type { FluentiPluginOptions, FluentiCoreOptions, RuntimeGenerator, RuntimeGeneratorOptions, IdGenerator } from './types'\nexport { createRuntimeGenerator } from './runtime-template'\nexport type { RuntimePrimitives } from './runtime-template'\nexport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nexport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\n\nconst VIRTUAL_PREFIX = 'virtual:fluenti/messages/'\nconst RESOLVED_PREFIX = '\\0virtual:fluenti/messages/'\n\n/**\n * Resolve a config option (string path, inline object, or undefined) into a full FluentiBuildConfig.\n */\nfunction resolvePluginConfig(configOption?: string | FluentiBuildConfig, cwd?: string): FluentiBuildConfig {\n if (typeof configOption === 'object') {\n // Inline config — merge with defaults\n const { DEFAULT_FLUENTI_CONFIG } = _require('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: FluentiBuildConfig\n }\n return { ...DEFAULT_FLUENTI_CONFIG, ...configOption }\n }\n // string → specified path; undefined → auto-discover\n const { loadConfigSync: loadSync } = _require('@fluenti/core/config') as {\n loadConfigSync: (configPath?: string, cwd?: string) => FluentiBuildConfig\n }\n return loadSync(\n typeof configOption === 'string' ? configOption : undefined,\n cwd,\n )\n}\n\n// ─── Public factory for framework packages ─────────────────────────────────\n\n/**\n * Create the Fluenti plugin pipeline.\n * Framework packages call this with their framework-specific plugins and runtime generator.\n */\nexport function createFluentiPlugins(\n options: FluentiCoreOptions,\n frameworkPlugins: Plugin[],\n runtimeGenerator?: RuntimeGenerator,\n): Plugin[] {\n let fluentiConfig: FluentiBuildConfig | undefined\n let rootDir = process.cwd()\n\n function getConfig(cwd?: string): FluentiBuildConfig {\n const effectiveCwd = cwd ?? rootDir\n if (!fluentiConfig) {\n fluentiConfig = resolvePluginConfig(options.config, effectiveCwd)\n }\n return fluentiConfig\n }\n\n const framework = options.framework\n\n function getResolvedSettings(cwd?: string) {\n const config = getConfig(cwd)\n const catalogDir = config.compileOutDir.replace(/^\\.\\//, '')\n const catalogExtension = config.catalogExtension ?? '.js'\n const rawSplitting = config.splitting ?? false\n if (rawSplitting && rawSplitting !== 'dynamic' && rawSplitting !== 'static') {\n console.warn(`[fluenti] Invalid splitting value \"${rawSplitting}\". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`)\n }\n const splitting = rawSplitting === 'static' ? 'static' as const : rawSplitting ? 'dynamic' as const : false as const\n const sourceLocale = config.sourceLocale\n const localeCodes = resolveLocaleCodes(config.locales)\n const defaultBuildLocale = config.defaultBuildLocale ?? sourceLocale\n return {\n config,\n catalogDir,\n catalogExtension,\n splitting,\n sourceLocale,\n localeCodes,\n defaultBuildLocale,\n }\n }\n\n const virtualPlugin: Plugin = {\n name: 'fluenti:virtual',\n configResolved(config) {\n rootDir = config.root\n fluentiConfig = resolvePluginConfig(options.config, rootDir)\n setResolvedMode(config.command)\n },\n resolveId(id) {\n if (id.startsWith(VIRTUAL_PREFIX)) {\n return '\\0' + id\n }\n const { splitting } = getResolvedSettings()\n if (splitting) {\n const resolved = resolveVirtualSplitId(id)\n if (resolved) return resolved\n }\n return undefined\n },\n load(id) {\n const {\n catalogDir,\n catalogExtension,\n splitting,\n localeCodes,\n sourceLocale,\n defaultBuildLocale,\n } = getResolvedSettings()\n if (id.startsWith(RESOLVED_PREFIX)) {\n const locale = id.slice(RESOLVED_PREFIX.length)\n if (!localeCodes.includes(locale)) {\n return undefined\n }\n const catalogPath = `${catalogDir}/${locale}${catalogExtension}`\n return `export { default } from '${catalogPath}'`\n }\n if (splitting) {\n const result = loadVirtualSplitModule(id, {\n rootDir,\n catalogDir,\n catalogExtension,\n locales: localeCodes,\n sourceLocale,\n defaultBuildLocale,\n framework,\n runtimeGenerator,\n })\n if (result) return result\n }\n return undefined\n },\n }\n\n const pipeline = createTransformPipeline({ framework })\n\n const scriptTransformPlugin: Plugin = {\n name: 'fluenti:script-transform',\n enforce: 'pre',\n transform(code, id) {\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n if (id.includes('.vue') && !id.includes('type=script')) return undefined\n\n // Vue .vue files need allowTopLevelImportedT for top-level `import { t }`\n const isVueSfc = framework === 'vue' && id.includes('.vue')\n\n let result = code\n let changed = false\n\n // ── <Trans> compile-time optimization (JSX/TSX only) ──────────────\n if (id.match(/\\.[jt]sx(\\?|$)/) && /<Trans[\\s>]/.test(result)) {\n const transResult = pipeline.transformTrans(result)\n if (transResult.transformed) {\n result = transResult.code\n changed = true\n }\n }\n\n // ── t`` / t() scope-aware transform ────────────────────────────────\n if (hasScopeTransformCandidate(result)) {\n const scoped = pipeline.transformScope(result,\n isVueSfc ? { allowTopLevelImportedT: true } : undefined,\n )\n if (scoped.transformed) {\n return { code: scoped.code, map: null }\n }\n }\n\n return changed ? { code: result, map: null } : undefined\n },\n }\n\n const buildSplitPlugin: Plugin = {\n name: 'fluenti:build-split',\n transform(code, id) {\n const { splitting, config } = getResolvedSettings()\n if (!splitting) return undefined\n if (!isBuildMode(getPluginEnvironment(this))) return undefined\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n\n const strategy = splitting === 'static' ? 'static' : 'dynamic'\n const transformOptions = config.idGenerator ? { hashFn: config.idGenerator } : undefined\n const transformed = strategy === 'static'\n ? transformForStaticSplit(code, transformOptions)\n : transformForDynamicSplit(code, transformOptions)\n\n if (!transformed.needsCatalogImport) return undefined\n\n const finalCode = injectCatalogImport(\n transformed.code,\n strategy,\n transformed.usedHashes,\n config.idGenerator,\n )\n return { code: finalCode, map: null }\n },\n }\n\n const buildCompilePlugin: Plugin = {\n name: 'fluenti:build-compile',\n async buildStart() {\n const { config } = getResolvedSettings()\n if (!isBuildMode(getPluginEnvironment(this))) return\n const buildAutoCompile = config.buildAutoCompile ?? true\n if (!buildAutoCompile) return\n if (config.onBeforeCompile) {\n const result = await config.onBeforeCompile()\n if (result === false) return\n }\n await runExtractCompile({ cwd: rootDir, throwOnError: true, compileOnly: true })\n if (config.onAfterCompile) {\n await config.onAfterCompile()\n }\n },\n }\n\n const devPlugin: Plugin = {\n name: 'fluenti:dev',\n configureServer(server) {\n const { config, catalogDir } = getResolvedSettings(server.config.root)\n const devAutoCompile = config.devAutoCompile ?? true\n if (!devAutoCompile) return\n\n const includePatterns = config.include ?? ['src/**/*.{vue,tsx,jsx,ts,js}']\n const excludePatterns = config.exclude ?? []\n\n const filter = createFilter(includePatterns, [\n ...excludePatterns,\n '**/node_modules/**',\n `**/${catalogDir}/**`,\n ])\n\n const runnerOptions: Parameters<typeof createDebouncedRunner>[0] = {\n cwd: server.config.root,\n onSuccess: () => {\n // Existing hotUpdate will pick up catalog changes\n },\n }\n if (config.parallelCompile) runnerOptions.parallelCompile = true\n if (config.onBeforeCompile) runnerOptions.onBeforeCompile = config.onBeforeCompile\n if (config.onAfterCompile) runnerOptions.onAfterCompile = config.onAfterCompile\n const debouncedRun = createDebouncedRunner(runnerOptions, config.devAutoCompileDelay ?? 500)\n\n debouncedRun()\n\n server.watcher.on('change', (file) => {\n if (filter(file)) {\n debouncedRun()\n }\n })\n },\n hotUpdate({ file }) {\n const { catalogDir } = getResolvedSettings()\n if (file.includes(catalogDir)) {\n const modules = [...this.environment.moduleGraph.urlToModuleMap.entries()]\n .filter(([url]) => url.includes('virtual:fluenti'))\n .map(([, mod]) => mod)\n\n if (modules.length > 0) {\n return modules\n }\n }\n return undefined\n },\n }\n\n // Plugin order matters:\n // 1. virtualPlugin — resolves virtual:fluenti/* module IDs (must be first)\n // 2. frameworkPlugins — framework-specific template transforms (e.g., Vue v-t directive)\n // must run after virtual resolution but before script transforms\n // 3. scriptTransformPlugin — t()/t`` scope transforms + <Trans> optimization (enforce: 'pre')\n // 4. buildCompilePlugin — triggers extract+compile before the build starts\n // 5. buildSplitPlugin — rewrites t() calls to catalog refs (dynamic/static)\n // 6. devPlugin — file watcher + HMR for dev mode (must be last)\n return [virtualPlugin, ...frameworkPlugins, scriptTransformPlugin, buildCompilePlugin, buildSplitPlugin, devPlugin]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/mode-detect.ts","../src/dev-runner.ts","../src/build-transform.ts","../src/virtual-modules.ts","../src/index.ts"],"sourcesContent":["/**\n * Detect whether Vite is running in build or dev mode.\n * Supports Vite 7 (configResolved) and Vite 8+ (environment API).\n */\n\nlet resolvedMode: 'build' | 'dev' = 'dev'\n\n/** Called from configResolved hook to capture the mode early */\nexport function setResolvedMode(command: string): void {\n resolvedMode = command === 'build' ? 'build' : 'dev'\n}\n\n/** Get the current resolved mode */\nexport function getResolvedMode(): 'build' | 'dev' {\n return resolvedMode\n}\n\n/**\n * Safely extract the environment object from a Vite plugin context.\n * Handles Vite 8+ environment API without direct `(this as any)` casts at call sites.\n */\nexport function getPluginEnvironment(pluginContext: unknown): { mode?: string } | undefined {\n if (\n typeof pluginContext === 'object' &&\n pluginContext !== null &&\n 'environment' in pluginContext\n ) {\n const env = (pluginContext as Record<string, unknown>)['environment']\n if (typeof env === 'object' && env !== null) {\n return env as { mode?: string }\n }\n }\n return undefined\n}\n\n/**\n * Check if we're in build mode.\n * Tries environment API (Vite 8+), then falls back to configResolved capture,\n * then falls back to NODE_ENV.\n */\nexport function isBuildMode(environment?: { mode?: string }): boolean {\n // Vite 8+: environment.mode === 'build'\n if (environment?.mode === 'build') return true\n\n // Vite 7: captured from configResolved\n if (resolvedMode === 'build') return true\n\n // Last resort: NODE_ENV\n if (process.env['NODE_ENV'] === 'production') return true\n\n return false\n}\n","import { join, resolve } from 'node:path'\nimport { createRequire } from 'node:module'\nimport { mkdirSync } from 'node:fs'\n\nexport interface DevRunnerOptions {\n cwd: string\n onSuccess?: () => void\n onError?: (err: Error) => void\n /** If true, reject the promise on failure instead of swallowing the error */\n throwOnError?: boolean\n /** Run only compile (skip extract). Useful for production builds where source is unchanged. */\n compileOnly?: boolean\n /** Enable parallel compilation across locales using worker threads */\n parallelCompile?: boolean\n /** Called before compile runs. Return false to skip compilation. */\n onBeforeCompile?: () => boolean | void | Promise<boolean | void>\n /** Called after compile completes successfully */\n onAfterCompile?: () => void | Promise<void>\n}\n\n/**\n * Run compile in-process via `@fluenti/cli`.\n *\n * In `compileOnly` mode, only compilation is performed (extract is skipped).\n * In dev mode, both extract and compile run in sequence.\n *\n * If `@fluenti/cli` is not installed, shows an install guide instead of\n * falling back to shell-out — keeping the process boundary clean.\n */\nexport async function runExtractCompile(options: DevRunnerOptions): Promise<void> {\n // Ensure compileOutDir exists on first run (auto-init for zero-config DX)\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { DEFAULT_FLUENTI_CONFIG, loadConfigSync } = projectRequire('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: { compileOutDir: string; catalogDir: string }\n loadConfigSync: (path?: string, cwd?: string) => { compileOutDir: string; catalogDir: string }\n }\n let config: { compileOutDir: string; catalogDir: string }\n try {\n config = loadConfigSync(undefined, options.cwd)\n } catch {\n config = DEFAULT_FLUENTI_CONFIG\n }\n mkdirSync(resolve(options.cwd, config.compileOutDir), { recursive: true })\n mkdirSync(resolve(options.cwd, config.catalogDir), { recursive: true })\n } catch {\n // Non-critical — directories may already exist or config may not be available\n }\n\n if (options.onBeforeCompile) {\n const result = await options.onBeforeCompile()\n if (result === false) return\n }\n\n if (options.compileOnly) {\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runCompile } = projectRequire('@fluenti/cli')\n await runCompile(options.cwd)\n console.log('[fluenti] Compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n if (options.throwOnError) throw error\n console.warn('[fluenti] Compile failed:', error.message)\n options.onError?.(error)\n return\n }\n }\n\n // Dev mode: in-process extract + compile\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runExtract, runCompile } = projectRequire('@fluenti/cli')\n await runExtract(options.cwd)\n await runCompile(options.cwd, { parallel: options.parallelCompile })\n console.log('[fluenti] Extracting and compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n const isNotInstalled = error.message.includes('Cannot find module')\n\n if (isNotInstalled) {\n const msg =\n '[fluenti] @fluenti/cli is required for auto-compile.\\n' +\n ' Install it as a devDependency:\\n' +\n ' pnpm add -D @fluenti/cli\\n' +\n ' See: https://fluenti.dev/start/introduction/'\n if (options.throwOnError) throw new Error(msg)\n console.warn(msg)\n options.onError?.(new Error(msg))\n return\n }\n\n if (options.throwOnError) throw error\n console.warn('[fluenti] Extract/compile failed:', error.message)\n options.onError?.(error)\n }\n}\n\n/**\n * Create a debounced runner that collapses rapid calls.\n *\n * - If called while idle, schedules a run after `delay` ms.\n * - If called while a run is in progress, marks a pending rerun.\n * - Never runs concurrently.\n */\nexport function createDebouncedRunner(\n options: DevRunnerOptions,\n delay = 300,\n): () => void {\n let timer: ReturnType<typeof setTimeout> | null = null\n let running = false\n let pendingRerun = false\n\n async function execute(): Promise<void> {\n running = true\n try {\n await runExtractCompile(options)\n } finally {\n running = false\n if (pendingRerun) {\n pendingRerun = false\n schedule()\n }\n }\n }\n\n function schedule(): void {\n if (timer !== null) {\n clearTimeout(timer)\n }\n timer = setTimeout(() => {\n timer = null\n if (running) {\n pendingRerun = true\n } else {\n execute()\n }\n }, delay)\n }\n\n return schedule\n}\n","/**\n * Build-mode transform for code-splitting.\n *\n * Strategy 'dynamic': rewrites supported translation calls to __catalog._<hash> references.\n * Strategy 'static': rewrites to direct named imports from compiled locale modules.\n */\n\nimport { hashMessage as defaultHashMessage } from '@fluenti/core/internal'\nimport { parseSourceModule, walkSourceAst, type SourceNode } from '@fluenti/core/transform'\n\nexport type HashFunction = (message: string, context?: string) => string\n\nexport interface BuildTransformResult {\n code: string\n needsCatalogImport: boolean\n usedHashes: Set<string>\n}\n\nexport interface BuildTransformOptions {\n /** Custom hash function for message IDs (defaults to @fluenti/core hashMessage) */\n hashFn?: HashFunction\n}\n\ntype SplitStrategy = 'dynamic' | 'static'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { cooked: string | null; raw: string }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n expressions: SourceNode[]\n quasis: TemplateElementNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface AwaitExpressionNode extends SourceNode {\n type: 'AwaitExpression'\n argument: SourceNode\n}\n\ninterface VariableDeclaratorNode extends SourceNode {\n type: 'VariableDeclarator'\n id: SourceNode\n init?: SourceNode | null\n}\n\ninterface ProgramNode extends SourceNode {\n type: 'Program'\n body: SourceNode[]\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface ObjectPatternNode extends SourceNode {\n type: 'ObjectPattern'\n properties: SourceNode[]\n}\n\ninterface MemberExpressionNode extends SourceNode {\n type: 'MemberExpression'\n object: SourceNode\n property: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXIdentifierNode extends SourceNode {\n type: 'JSXIdentifier'\n name: string\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: JSXIdentifierNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface SplitReplacement {\n start: number\n end: number\n replacement: string\n}\n\ninterface SplitTarget {\n catalogId: string\n valuesSource?: string\n}\n\ninterface RuntimeBindings {\n tracked: Set<string>\n unref: Set<string>\n}\n\nexport function transformForDynamicSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'dynamic', options)\n}\n\nexport function transformForStaticSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'static', options)\n}\n\nfunction transformForSplitStrategy(\n code: string,\n strategy: SplitStrategy,\n options?: BuildTransformOptions,\n): BuildTransformResult {\n const hashFn = options?.hashFn ?? defaultHashMessage\n const ast = parseSourceModule(code)\n if (!ast || ast.type !== 'Program') {\n return { code, needsCatalogImport: false, usedHashes: new Set() }\n }\n\n const bindings = collectTrackedRuntimeBindings(ast as ProgramNode)\n const replacements: SplitReplacement[] = []\n const usedHashes = new Set<string>()\n\n walkSourceAst(ast, (node) => {\n const replacement = extractCallReplacement(code, node, bindings, strategy, usedHashes, hashFn)\n if (replacement) {\n replacements.push(replacement)\n return\n }\n\n collectComponentUsage(node, usedHashes, hashFn)\n })\n\n if (replacements.length === 0) {\n return { code, needsCatalogImport: false, usedHashes }\n }\n\n let result = code\n for (let i = replacements.length - 1; i >= 0; i--) {\n const { start, end, replacement } = replacements[i]!\n result = result.slice(0, start) + replacement + result.slice(end)\n }\n\n return { code: result, needsCatalogImport: true, usedHashes }\n}\n\nfunction collectTrackedRuntimeBindings(program: ProgramNode): RuntimeBindings {\n const tracked = new Set<string>()\n const useI18nBindings = new Set<string>()\n const getI18nBindings = new Set<string>()\n const unrefBindings = new Set<string>()\n\n for (const statement of program.body) {\n if (!isImportDeclaration(statement)) continue\n for (const specifier of statement.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n const importedName = readImportedName(specifier)\n if (!importedName) continue\n if (importedName === 'useI18n') {\n useI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'getI18n') {\n getI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'unref') {\n unrefBindings.add(specifier.local.name)\n }\n }\n }\n\n walkSourceAst(program, (node) => {\n if (!isVariableDeclarator(node) || !node.init || !isObjectPattern(node.id)) return\n\n if (isCallExpression(node.init) && isIdentifier(node.init.callee) && useI18nBindings.has(node.init.callee.name)) {\n addTrackedObjectPatternBindings(node.id, tracked)\n return\n }\n\n const awaitedCall = node.init.type === 'AwaitExpression'\n ? (node.init as AwaitExpressionNode).argument\n : null\n\n if (\n awaitedCall\n && isCallExpression(awaitedCall)\n && isIdentifier(awaitedCall.callee)\n && getI18nBindings.has(awaitedCall.callee.name)\n ) {\n addTrackedObjectPatternBindings(node.id, tracked)\n }\n })\n\n return { tracked, unref: unrefBindings }\n}\n\nfunction addTrackedObjectPatternBindings(pattern: ObjectPatternNode, tracked: Set<string>): void {\n for (const property of pattern.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n if (!isIdentifier(property.key) || property.key.name !== 't') continue\n if (isIdentifier(property.value)) {\n tracked.add(property.value.name)\n }\n }\n}\n\nfunction extractCallReplacement(\n code: string,\n node: SourceNode,\n bindings: RuntimeBindings,\n strategy: SplitStrategy,\n usedHashes: Set<string>,\n hashFn: HashFunction,\n): SplitReplacement | undefined {\n if (!isCallExpression(node) || node.start == null || node.end == null) {\n return undefined\n }\n\n const splitTarget = resolveSplitTarget(code, node, bindings, hashFn)\n if (!splitTarget) {\n return undefined\n }\n\n const { catalogId } = splitTarget\n usedHashes.add(catalogId)\n const exportHash = hashFn(catalogId)\n const replacementTarget = strategy === 'dynamic'\n ? `__catalog[${JSON.stringify(catalogId)}]`\n : `_${exportHash}`\n const replacement = splitTarget.valuesSource\n ? `${replacementTarget}(${splitTarget.valuesSource})`\n : replacementTarget\n\n return {\n start: node.start,\n end: node.end,\n replacement,\n }\n}\n\nfunction resolveSplitTarget(\n code: string,\n call: CallExpressionNode,\n bindings: RuntimeBindings,\n hashFn: HashFunction,\n): SplitTarget | undefined {\n if (call.arguments.length === 0) return undefined\n\n const callee = call.callee\n const isTrackedIdentifierCall = isIdentifier(callee) && (bindings.tracked.has(callee.name) || callee.name === '$t')\n const isTemplateMemberCall = isMemberExpression(callee)\n && !callee.computed\n && isIdentifier(callee.property)\n && (\n callee.property.name === '$t'\n || (\n callee.property.name === 't'\n && isIdentifier(callee.object)\n && (callee.object.name === '_ctx' || callee.object.name === '$setup')\n )\n )\n const isVueUnrefCall = isCallExpression(callee)\n && isIdentifier(callee.callee)\n && bindings.unref.has(callee.callee.name)\n && callee.arguments.length === 1\n && isIdentifier(callee.arguments[0])\n && bindings.tracked.has(callee.arguments[0].name)\n\n if (!isTrackedIdentifierCall && !isTemplateMemberCall && !isVueUnrefCall) {\n return undefined\n }\n\n const catalogId = extractCatalogId(call.arguments[0]!, hashFn)\n if (!catalogId) return undefined\n\n const valuesSource = call.arguments[1] && call.arguments[1]!.start != null && call.arguments[1]!.end != null\n ? code.slice(call.arguments[1]!.start, call.arguments[1]!.end)\n : undefined\n\n return valuesSource === undefined\n ? { catalogId }\n : { catalogId, valuesSource }\n}\n\nfunction extractCatalogId(argument: SourceNode, hashFn: HashFunction): string | undefined {\n const staticString = readStaticString(argument)\n if (staticString !== undefined) {\n return hashFn(staticString)\n }\n\n if (!isObjectExpression(argument)) {\n return undefined\n }\n\n let id: string | undefined\n let message: string | undefined\n let context: string | undefined\n\n for (const property of argument.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n const key = readPropertyKey(property.key)\n if (!key) continue\n\n const value = readStaticString(property.value)\n if (value === undefined) continue\n\n if (key === 'id') id = value\n if (key === 'message') message = value\n if (key === 'context') context = value\n }\n\n if (id) return id\n if (message) return hashFn(message, context)\n return undefined\n}\n\nfunction collectComponentUsage(node: SourceNode, usedHashes: Set<string>, hashFn: HashFunction): void {\n if (!isJsxElement(node)) return\n\n const componentName = readJsxName(node.openingElement.name)\n if (!componentName) return\n\n if (componentName === 'Trans') {\n const id = readJsxStaticAttribute(node.openingElement, '__id') ?? readJsxStaticAttribute(node.openingElement, 'id')\n if (id) {\n usedHashes.add(id)\n return\n }\n\n const message = readJsxStaticAttribute(node.openingElement, '__message')\n const context = readJsxStaticAttribute(node.openingElement, 'context')\n if (message) {\n usedHashes.add(hashFn(message, context))\n }\n return\n }\n\n if (componentName === 'Plural') {\n const messageId = buildPluralMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n return\n }\n\n if (componentName === 'Select') {\n const messageId = buildSelectMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n }\n}\n\nfunction buildPluralMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const offsetRaw = readJsxStaticNumber(openingElement, 'offset')\n const forms = [\n readJsxStaticAttribute(openingElement, 'zero') === undefined ? undefined : `=0 {${readJsxStaticAttribute(openingElement, 'zero')}}`,\n readJsxStaticAttribute(openingElement, 'one') === undefined ? undefined : `one {${readJsxStaticAttribute(openingElement, 'one')}}`,\n readJsxStaticAttribute(openingElement, 'two') === undefined ? undefined : `two {${readJsxStaticAttribute(openingElement, 'two')}}`,\n readJsxStaticAttribute(openingElement, 'few') === undefined ? undefined : `few {${readJsxStaticAttribute(openingElement, 'few')}}`,\n readJsxStaticAttribute(openingElement, 'many') === undefined ? undefined : `many {${readJsxStaticAttribute(openingElement, 'many')}}`,\n readJsxStaticAttribute(openingElement, 'other') === undefined ? undefined : `other {${readJsxStaticAttribute(openingElement, 'other')}}`,\n ].filter(Boolean)\n\n if (forms.length === 0) return undefined\n\n const offsetPart = typeof offsetRaw === 'number' ? ` offset:${offsetRaw}` : ''\n const icuMessage = `{count, plural,${offsetPart} ${forms.join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction buildSelectMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const forms = readStaticSelectForms(openingElement)\n if (!forms || forms['other'] === undefined) return undefined\n\n const orderedKeys = [...Object.keys(forms).filter((key) => key !== 'other').sort(), 'other']\n const icuMessage = `{value, select, ${orderedKeys.map((key) => `${key} {${forms[key]!}}`).join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction readStaticSelectForms(openingElement: JSXOpeningElementNode): Record<string, string> | undefined {\n const optionForms = readJsxStaticObject(openingElement, 'options')\n if (optionForms) {\n const other = readJsxStaticAttribute(openingElement, 'other')\n return {\n ...optionForms,\n ...(other !== undefined ? { other } : {}),\n }\n }\n\n const forms: Record<string, string> = {}\n for (const attribute of openingElement.attributes) {\n if (!isJsxAttribute(attribute)) continue\n const name = attribute.name.name\n if (['value', 'id', 'context', 'comment', 'options'].includes(name)) continue\n const value = readJsxAttributeValue(attribute)\n if (value !== undefined) {\n forms[name] = value\n }\n }\n\n return Object.keys(forms).length > 0 ? forms : undefined\n}\n\nfunction readStaticSelectObjectValue(node: SourceNode): Record<string, string> | undefined {\n if (!isObjectExpression(node)) return undefined\n const values: Record<string, string> = {}\n\n for (const property of node.properties) {\n if (!isObjectProperty(property) || property.computed) return undefined\n const key = readPropertyKey(property.key)\n const value = readStaticString(property.value)\n if (!key || value === undefined) return undefined\n values[key] = value\n }\n\n return values\n}\n\nfunction readJsxStaticObject(openingElement: JSXOpeningElementNode, name: string): Record<string, string> | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value) return undefined\n if (attribute.value.type !== 'JSXExpressionContainer') return undefined\n return readStaticSelectObjectValue((attribute.value as JSXExpressionContainerNode).expression)\n}\n\nfunction readJsxStaticAttribute(openingElement: JSXOpeningElementNode, name: string): string | undefined {\n return readJsxAttributeValue(findJsxAttribute(openingElement, name))\n}\n\nfunction readJsxStaticNumber(openingElement: JSXOpeningElementNode, name: string): number | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value || attribute.value.type !== 'JSXExpressionContainer') return undefined\n const expression = (attribute.value as JSXExpressionContainerNode).expression\n return expression.type === 'NumericLiteral' ? (expression as NumericLiteralNode).value : undefined\n}\n\nfunction findJsxAttribute(openingElement: JSXOpeningElementNode, name: string): JSXAttributeNode | undefined {\n return openingElement.attributes.find((attribute) => {\n return isJsxAttribute(attribute) && attribute.name.name === name\n }) as JSXAttributeNode | undefined\n}\n\nfunction readJsxAttributeValue(attribute: JSXAttributeNode | undefined): string | undefined {\n if (!attribute?.value) return undefined\n\n if (attribute.value.type === 'StringLiteral') {\n return (attribute.value as StringLiteralNode).value\n }\n\n if (attribute.value.type === 'JSXExpressionContainer') {\n return readStaticString((attribute.value as JSXExpressionContainerNode).expression)\n }\n\n return undefined\n}\n\nfunction readJsxName(node: SourceNode): string | undefined {\n return node.type === 'JSXIdentifier' ? (node as JSXIdentifierNode).name : undefined\n}\n\nfunction readStaticString(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0 && template.quasis.length === 1) {\n return template.quasis[0]!.value.cooked ?? template.quasis[0]!.value.raw\n }\n }\n\n return undefined\n}\n\nfunction readPropertyKey(node: SourceNode): string | undefined {\n if (isIdentifier(node)) return node.name\n if (node.type === 'StringLiteral') return (node as StringLiteralNode).value\n return undefined\n}\n\nfunction isImportDeclaration(node: SourceNode): node is ImportDeclarationNode {\n return node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: SourceNode): node is ImportSpecifierNode {\n return node.type === 'ImportSpecifier'\n}\n\nfunction isVariableDeclarator(node: SourceNode): node is VariableDeclaratorNode {\n return node.type === 'VariableDeclarator'\n}\n\nfunction isObjectPattern(node: SourceNode): node is ObjectPatternNode {\n return node.type === 'ObjectPattern'\n}\n\nfunction isObjectExpression(node: SourceNode): node is ObjectExpressionNode {\n return node.type === 'ObjectExpression'\n}\n\nfunction isObjectProperty(node: SourceNode): node is ObjectPropertyNode {\n return node.type === 'ObjectProperty'\n}\n\nfunction isCallExpression(node: SourceNode): node is CallExpressionNode {\n return node.type === 'CallExpression'\n}\n\nfunction isMemberExpression(node: SourceNode): node is MemberExpressionNode {\n return node.type === 'MemberExpression'\n}\n\nfunction isIdentifier(node: SourceNode | undefined | null): node is IdentifierNode {\n return node?.type === 'Identifier'\n}\n\nfunction isJsxElement(node: SourceNode): node is JSXElementNode {\n return node.type === 'JSXElement'\n}\n\nfunction isJsxAttribute(node: SourceNode): node is JSXAttributeNode {\n return node.type === 'JSXAttribute'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n const imported = specifier.imported\n if (imported.type === 'Identifier') return imported.name\n if (imported.type === 'StringLiteral') return imported.value\n return undefined\n}\n\n/**\n * Inject the catalog import statement at the top of the module.\n */\nexport function injectCatalogImport(code: string, strategy: 'dynamic' | 'static', hashes: Set<string>, hashFn?: HashFunction): string {\n if (strategy === 'dynamic') {\n return `import { __catalog } from 'virtual:fluenti/runtime';\\n${code}`\n }\n\n // Static: import named exports directly\n const hash = hashFn ?? defaultHashMessage\n const imports = [...hashes].map((id) => `_${hash(id)}`).join(', ')\n return `import { ${imports} } from 'virtual:fluenti/messages';\\n${code}`\n}\n","/**\n * Virtual module resolution for code-splitting mode.\n *\n * Provides:\n * - virtual:fluenti/runtime → reactive catalog + switchLocale + preloadLocale\n * - virtual:fluenti/messages → re-export from static locale (for static strategy)\n */\n\nimport { resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { validateLocale } from '@fluenti/core'\nimport type { RuntimeGenerator, RuntimeGeneratorOptions } from './types'\n\n/**\n * Escapes a string value for safe embedding in generated JavaScript code.\n * Returns a JSON-encoded string (with double quotes), preventing injection\n * of quotes, backticks, template interpolation, and other special characters.\n */\nfunction safeStringLiteral(value: string): string {\n return JSON.stringify(value)\n}\n\n/**\n * Validates that a catalog directory path does not contain characters\n * that could enable code injection in generated template literals.\n */\nfunction validateCatalogDir(catalogDir: string): void {\n if (catalogDir.includes('`') || catalogDir.includes('$')) {\n throw new Error(\n `[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(catalogDir)}`,\n )\n }\n}\n\nconst VIRTUAL_RUNTIME = 'virtual:fluenti/runtime'\nconst VIRTUAL_MESSAGES = 'virtual:fluenti/messages'\nconst RESOLVED_RUNTIME = '\\0virtual:fluenti/runtime'\nconst RESOLVED_MESSAGES = '\\0virtual:fluenti/messages'\n\nexport interface VirtualModuleOptions {\n rootDir: string\n catalogDir: string\n catalogExtension: string\n locales: string[]\n sourceLocale: string\n defaultBuildLocale: string\n framework: string\n runtimeGenerator?: RuntimeGenerator | undefined\n}\n\nexport function resolveVirtualSplitId(id: string): string | undefined {\n if (id === VIRTUAL_RUNTIME) return RESOLVED_RUNTIME\n if (id === VIRTUAL_MESSAGES) return RESOLVED_MESSAGES\n return undefined\n}\n\nexport function loadVirtualSplitModule(\n id: string,\n options: VirtualModuleOptions,\n): string | undefined {\n if (id === RESOLVED_RUNTIME) {\n return generateRuntimeModule(options)\n }\n if (id === RESOLVED_MESSAGES) {\n return generateStaticMessagesModule(options)\n }\n return undefined\n}\n\nfunction generateRuntimeModule(options: VirtualModuleOptions): string {\n const { locales, runtimeGenerator, catalogDir } = options\n validateCatalogDir(catalogDir)\n for (const locale of locales) {\n validateLocale(locale, 'vite-plugin')\n }\n\n if (!runtimeGenerator) {\n throw new Error('[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).')\n }\n\n return runtimeGenerator.generateRuntime(toRuntimeGeneratorOptions(options))\n}\n\nfunction generateStaticMessagesModule(options: VirtualModuleOptions): string {\n const { rootDir, catalogDir, catalogExtension, defaultBuildLocale, sourceLocale } = options\n const defaultLocale = defaultBuildLocale || sourceLocale\n validateLocale(defaultLocale, 'vite-plugin')\n validateCatalogDir(catalogDir)\n const absoluteCatalogDir = resolve(rootDir, catalogDir)\n const catalogFile = resolve(absoluteCatalogDir, defaultLocale + catalogExtension)\n\n if (!existsSync(catalogFile)) {\n console.warn(\n `[fluenti] Compiled catalog for locale \"${defaultLocale}\" not found at ${catalogFile}. Run \"fluenti compile\" first.`,\n )\n }\n\n return `export * from ${safeStringLiteral(catalogFile)}\\n`\n}\n\nfunction toRuntimeGeneratorOptions(options: VirtualModuleOptions): RuntimeGeneratorOptions {\n const { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale } = options\n return { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale }\n}\n","import type { Plugin } from 'vite'\nimport { createFilter } from 'vite'\nimport type { FluentiCoreOptions, RuntimeGenerator } from './types'\nimport type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\nimport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\nimport { createRequire } from 'node:module'\n\nconst _require = createRequire(\n typeof __filename !== 'undefined' ? __filename : import.meta.url,\n)\nimport { createDebouncedRunner, runExtractCompile } from './dev-runner'\nimport { transformForDynamicSplit, transformForStaticSplit, injectCatalogImport } from './build-transform'\nimport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nimport { createTransformPipeline, hasScopeTransformCandidate } from '@fluenti/core/transform'\nexport type { FluentiPluginOptions, FluentiCoreOptions, RuntimeGenerator, RuntimeGeneratorOptions, IdGenerator } from './types'\nexport { createRuntimeGenerator } from './runtime-template'\nexport type { RuntimePrimitives } from './runtime-template'\nexport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nexport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\n\nconst VIRTUAL_PREFIX = 'virtual:fluenti/messages/'\nconst RESOLVED_PREFIX = '\\0virtual:fluenti/messages/'\n\n/**\n * Resolve a config option (string path, inline object, or undefined) into a full FluentiBuildConfig.\n */\nfunction resolvePluginConfig(configOption?: string | FluentiBuildConfig, cwd?: string): FluentiBuildConfig {\n if (typeof configOption === 'object') {\n // Inline config — merge with defaults\n const { DEFAULT_FLUENTI_CONFIG } = _require('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: FluentiBuildConfig\n }\n return { ...DEFAULT_FLUENTI_CONFIG, ...configOption }\n }\n // string → specified path; undefined → auto-discover\n const { loadConfigSync: loadSync } = _require('@fluenti/core/config') as {\n loadConfigSync: (configPath?: string, cwd?: string) => FluentiBuildConfig\n }\n return loadSync(\n typeof configOption === 'string' ? configOption : undefined,\n cwd,\n )\n}\n\n// ─── Public factory for framework packages ─────────────────────────────────\n\n/**\n * Create the Fluenti plugin pipeline.\n * Framework packages call this with their framework-specific plugins and runtime generator.\n */\nexport function createFluentiPlugins(\n options: FluentiCoreOptions,\n frameworkPlugins: Plugin[],\n runtimeGenerator?: RuntimeGenerator,\n): Plugin[] {\n let fluentiConfig: FluentiBuildConfig | undefined\n let rootDir = process.cwd()\n\n function getConfig(cwd?: string): FluentiBuildConfig {\n const effectiveCwd = cwd ?? rootDir\n if (!fluentiConfig) {\n fluentiConfig = resolvePluginConfig(options.config, effectiveCwd)\n }\n return fluentiConfig\n }\n\n const framework = options.framework\n\n function getResolvedSettings(cwd?: string) {\n const config = getConfig(cwd)\n const catalogDir = config.compileOutDir.replace(/^\\.\\//, '')\n const catalogExtension = config.catalogExtension ?? '.js'\n const rawSplitting = config.splitting ?? false\n if (rawSplitting && rawSplitting !== 'dynamic' && rawSplitting !== 'static') {\n console.warn(`[fluenti] Invalid splitting value \"${rawSplitting}\". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`)\n }\n const splitting = rawSplitting === 'static' ? 'static' as const : rawSplitting ? 'dynamic' as const : false as const\n const sourceLocale = config.sourceLocale\n const localeCodes = resolveLocaleCodes(config.locales)\n const defaultBuildLocale = config.defaultBuildLocale ?? sourceLocale\n return {\n config,\n catalogDir,\n catalogExtension,\n splitting,\n sourceLocale,\n localeCodes,\n defaultBuildLocale,\n }\n }\n\n const virtualPlugin: Plugin = {\n name: 'fluenti:virtual',\n configResolved(config) {\n rootDir = config.root\n fluentiConfig = resolvePluginConfig(options.config, rootDir)\n setResolvedMode(config.command)\n },\n resolveId(id) {\n if (id.startsWith(VIRTUAL_PREFIX)) {\n return '\\0' + id\n }\n const { splitting } = getResolvedSettings()\n if (splitting) {\n const resolved = resolveVirtualSplitId(id)\n if (resolved) return resolved\n }\n return undefined\n },\n load(id) {\n const {\n catalogDir,\n catalogExtension,\n splitting,\n localeCodes,\n sourceLocale,\n defaultBuildLocale,\n } = getResolvedSettings()\n if (id.startsWith(RESOLVED_PREFIX)) {\n const locale = id.slice(RESOLVED_PREFIX.length)\n if (!localeCodes.includes(locale)) {\n return undefined\n }\n const catalogPath = `${catalogDir}/${locale}${catalogExtension}`\n return `export { default } from '${catalogPath}'`\n }\n if (splitting) {\n const result = loadVirtualSplitModule(id, {\n rootDir,\n catalogDir,\n catalogExtension,\n locales: localeCodes,\n sourceLocale,\n defaultBuildLocale,\n framework,\n runtimeGenerator,\n })\n if (result) return result\n }\n return undefined\n },\n }\n\n const pipeline = createTransformPipeline({ framework })\n\n const scriptTransformPlugin: Plugin = {\n name: 'fluenti:script-transform',\n enforce: 'pre',\n transform(code, id) {\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n if (id.includes('.vue') && !id.includes('type=script')) return undefined\n\n // Vue .vue files need allowTopLevelImportedT for top-level `import { t }`\n const isVueSfc = framework === 'vue' && id.includes('.vue')\n\n let result = code\n let changed = false\n\n // ── <Trans> compile-time optimization (JSX/TSX only) ──────────────\n if (id.match(/\\.[jt]sx(\\?|$)/) && /<Trans[\\s>]/.test(result)) {\n const transResult = pipeline.transformTrans(result)\n if (transResult.transformed) {\n result = transResult.code\n changed = true\n }\n }\n\n // ── t`` / t() scope-aware transform ────────────────────────────────\n if (hasScopeTransformCandidate(result)) {\n const scoped = pipeline.transformScope(result,\n isVueSfc ? { allowTopLevelImportedT: true } : undefined,\n )\n if (scoped.transformed) {\n return { code: scoped.code, map: null }\n }\n }\n\n return changed ? { code: result, map: null } : undefined\n },\n }\n\n const buildSplitPlugin: Plugin = {\n name: 'fluenti:build-split',\n transform(code, id) {\n const { splitting, config } = getResolvedSettings()\n if (!splitting) return undefined\n if (!isBuildMode(getPluginEnvironment(this))) return undefined\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n\n const strategy = splitting === 'static' ? 'static' : 'dynamic'\n const transformOptions = config.idGenerator ? { hashFn: config.idGenerator } : undefined\n const transformed = strategy === 'static'\n ? transformForStaticSplit(code, transformOptions)\n : transformForDynamicSplit(code, transformOptions)\n\n if (!transformed.needsCatalogImport) return undefined\n\n const finalCode = injectCatalogImport(\n transformed.code,\n strategy,\n transformed.usedHashes,\n config.idGenerator,\n )\n return { code: finalCode, map: null }\n },\n }\n\n const buildCompilePlugin: Plugin = {\n name: 'fluenti:build-compile',\n async buildStart() {\n const { config } = getResolvedSettings()\n if (!isBuildMode(getPluginEnvironment(this))) return\n const buildAutoCompile = config.buildAutoCompile ?? true\n if (!buildAutoCompile) return\n if (config.onBeforeCompile) {\n const result = await config.onBeforeCompile()\n if (result === false) return\n }\n await runExtractCompile({ cwd: rootDir, throwOnError: true, compileOnly: true })\n if (config.onAfterCompile) {\n await config.onAfterCompile()\n }\n },\n }\n\n const devPlugin: Plugin = {\n name: 'fluenti:dev',\n configureServer(server) {\n const { config, catalogDir } = getResolvedSettings(server.config.root)\n const devAutoCompile = config.devAutoCompile ?? true\n if (!devAutoCompile) return\n\n const includePatterns = config.include ?? ['src/**/*.{vue,tsx,jsx,ts,js}']\n const excludePatterns = config.exclude ?? []\n\n const filter = createFilter(includePatterns, [\n ...excludePatterns,\n '**/node_modules/**',\n `**/${catalogDir}/**`,\n ])\n\n const runnerOptions: Parameters<typeof createDebouncedRunner>[0] = {\n cwd: server.config.root,\n onSuccess: () => {\n // Existing hotUpdate will pick up catalog changes\n },\n }\n if (config.parallelCompile) runnerOptions.parallelCompile = true\n if (config.onBeforeCompile) runnerOptions.onBeforeCompile = config.onBeforeCompile\n if (config.onAfterCompile) runnerOptions.onAfterCompile = config.onAfterCompile\n const debouncedRun = createDebouncedRunner(runnerOptions, config.devAutoCompileDelay ?? 500)\n\n debouncedRun()\n\n server.watcher.on('change', (file) => {\n if (filter(file)) {\n debouncedRun()\n }\n })\n },\n hotUpdate({ file }) {\n const { catalogDir } = getResolvedSettings()\n if (file.includes(catalogDir)) {\n const modules = [...this.environment.moduleGraph.urlToModuleMap.entries()]\n .filter(([url]) => url.includes('virtual:fluenti'))\n .map(([, mod]) => mod)\n\n if (modules.length > 0) {\n return modules\n }\n }\n return undefined\n },\n }\n\n // Plugin order matters:\n // 1. virtualPlugin — resolves virtual:fluenti/* module IDs (must be first)\n // 2. frameworkPlugins — framework-specific template transforms (e.g., Vue v-t directive)\n // must run after virtual resolution but before script transforms\n // 3. scriptTransformPlugin — t()/t`` scope transforms + <Trans> optimization (enforce: 'pre')\n // 4. buildCompilePlugin — triggers extract+compile before the build starts\n // 5. buildSplitPlugin — rewrites t() calls to catalog refs (dynamic/static)\n // 6. devPlugin — file watcher + HMR for dev mode (must be last)\n return [virtualPlugin, ...frameworkPlugins, scriptTransformPlugin, buildCompilePlugin, buildSplitPlugin, devPlugin]\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,26 +2,35 @@ import { createFilter as e } from "vite";
|
|
|
2
2
|
import { hashMessage as t, resolveLocaleCodes as n } from "@fluenti/core/internal";
|
|
3
3
|
import { createRequire as r } from "node:module";
|
|
4
4
|
import { join as i, resolve as a } from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { validateLocale as
|
|
5
|
+
import { existsSync as o, mkdirSync as s } from "node:fs";
|
|
6
|
+
import { createRuntimeGenerator as c, createTransformPipeline as l, hasScopeTransformCandidate as u, parseSourceModule as d, walkSourceAst as f } from "@fluenti/core/transform";
|
|
7
|
+
import { validateLocale as p } from "@fluenti/core";
|
|
8
8
|
//#region src/mode-detect.ts
|
|
9
|
-
var
|
|
10
|
-
function m(e) {
|
|
11
|
-
p = e === "build" ? "build" : "dev";
|
|
12
|
-
}
|
|
9
|
+
var m = "dev";
|
|
13
10
|
function h(e) {
|
|
11
|
+
m = e === "build" ? "build" : "dev";
|
|
12
|
+
}
|
|
13
|
+
function g(e) {
|
|
14
14
|
if (typeof e == "object" && e && "environment" in e) {
|
|
15
15
|
let t = e.environment;
|
|
16
16
|
if (typeof t == "object" && t) return t;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
function
|
|
20
|
-
return e?.mode === "build" ||
|
|
19
|
+
function _(e) {
|
|
20
|
+
return e?.mode === "build" || m === "build" || process.env.NODE_ENV === "production";
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/dev-runner.ts
|
|
24
|
-
async function
|
|
24
|
+
async function v(e) {
|
|
25
|
+
try {
|
|
26
|
+
let { DEFAULT_FLUENTI_CONFIG: t, loadConfigSync: n } = r(i(e.cwd, "package.json"))("@fluenti/core/config"), o;
|
|
27
|
+
try {
|
|
28
|
+
o = n(void 0, e.cwd);
|
|
29
|
+
} catch {
|
|
30
|
+
o = t;
|
|
31
|
+
}
|
|
32
|
+
s(a(e.cwd, o.compileOutDir), { recursive: !0 }), s(a(e.cwd, o.catalogDir), { recursive: !0 });
|
|
33
|
+
} catch {}
|
|
25
34
|
if (!(e.onBeforeCompile && await e.onBeforeCompile() === !1)) {
|
|
26
35
|
if (e.compileOnly) try {
|
|
27
36
|
let { runCompile: t } = r(i(e.cwd, "package.json"))("@fluenti/cli");
|
|
@@ -55,7 +64,7 @@ function ee(e, t = 300) {
|
|
|
55
64
|
async function a() {
|
|
56
65
|
r = !0;
|
|
57
66
|
try {
|
|
58
|
-
await
|
|
67
|
+
await v(e);
|
|
59
68
|
} finally {
|
|
60
69
|
r = !1, i && (i = !1, o());
|
|
61
70
|
}
|
|
@@ -69,69 +78,69 @@ function ee(e, t = 300) {
|
|
|
69
78
|
}
|
|
70
79
|
//#endregion
|
|
71
80
|
//#region src/build-transform.ts
|
|
72
|
-
function
|
|
73
|
-
return
|
|
81
|
+
function y(e, t) {
|
|
82
|
+
return b(e, "dynamic", t);
|
|
74
83
|
}
|
|
75
|
-
function
|
|
76
|
-
return
|
|
84
|
+
function te(e, t) {
|
|
85
|
+
return b(e, "static", t);
|
|
77
86
|
}
|
|
78
|
-
function
|
|
79
|
-
let i = r?.hashFn ?? t, a =
|
|
87
|
+
function b(e, n, r) {
|
|
88
|
+
let i = r?.hashFn ?? t, a = d(e);
|
|
80
89
|
if (!a || a.type !== "Program") return {
|
|
81
90
|
code: e,
|
|
82
91
|
needsCatalogImport: !1,
|
|
83
92
|
usedHashes: /* @__PURE__ */ new Set()
|
|
84
93
|
};
|
|
85
|
-
let o =
|
|
86
|
-
if (
|
|
87
|
-
let r =
|
|
94
|
+
let o = x(a), s = [], c = /* @__PURE__ */ new Set();
|
|
95
|
+
if (f(a, (t) => {
|
|
96
|
+
let r = ne(e, t, o, n, c, i);
|
|
88
97
|
if (r) {
|
|
89
98
|
s.push(r);
|
|
90
99
|
return;
|
|
91
100
|
}
|
|
92
|
-
|
|
101
|
+
ie(t, c, i);
|
|
93
102
|
}), s.length === 0) return {
|
|
94
103
|
code: e,
|
|
95
104
|
needsCatalogImport: !1,
|
|
96
105
|
usedHashes: c
|
|
97
106
|
};
|
|
98
|
-
let
|
|
107
|
+
let l = e;
|
|
99
108
|
for (let e = s.length - 1; e >= 0; e--) {
|
|
100
109
|
let { start: t, end: n, replacement: r } = s[e];
|
|
101
|
-
|
|
110
|
+
l = l.slice(0, t) + r + l.slice(n);
|
|
102
111
|
}
|
|
103
112
|
return {
|
|
104
|
-
code:
|
|
113
|
+
code: l,
|
|
105
114
|
needsCatalogImport: !0,
|
|
106
115
|
usedHashes: c
|
|
107
116
|
};
|
|
108
117
|
}
|
|
109
|
-
function
|
|
118
|
+
function x(e) {
|
|
110
119
|
let t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set();
|
|
111
|
-
for (let t of e.body) if (
|
|
112
|
-
if (!
|
|
113
|
-
let t =
|
|
120
|
+
for (let t of e.body) if (P(t)) for (let e of t.specifiers) {
|
|
121
|
+
if (!F(e)) continue;
|
|
122
|
+
let t = G(e);
|
|
114
123
|
t && (t === "useI18n" && n.add(e.local.name), t === "getI18n" && r.add(e.local.name), t === "unref" && i.add(e.local.name));
|
|
115
124
|
}
|
|
116
|
-
return
|
|
117
|
-
if (!
|
|
118
|
-
if (
|
|
119
|
-
|
|
125
|
+
return f(e, (e) => {
|
|
126
|
+
if (!I(e) || !e.init || !L(e.id)) return;
|
|
127
|
+
if (B(e.init) && H(e.init.callee) && n.has(e.init.callee.name)) {
|
|
128
|
+
S(e.id, t);
|
|
120
129
|
return;
|
|
121
130
|
}
|
|
122
131
|
let i = e.init.type === "AwaitExpression" ? e.init.argument : null;
|
|
123
|
-
i &&
|
|
132
|
+
i && B(i) && H(i.callee) && r.has(i.callee.name) && S(e.id, t);
|
|
124
133
|
}), {
|
|
125
134
|
tracked: t,
|
|
126
135
|
unref: i
|
|
127
136
|
};
|
|
128
137
|
}
|
|
129
|
-
function
|
|
130
|
-
for (let n of e.properties) !
|
|
138
|
+
function S(e, t) {
|
|
139
|
+
for (let n of e.properties) !z(n) || n.computed || !H(n.key) || n.key.name !== "t" || H(n.value) && t.add(n.value.name);
|
|
131
140
|
}
|
|
132
|
-
function
|
|
133
|
-
if (!
|
|
134
|
-
let o =
|
|
141
|
+
function ne(e, t, n, r, i, a) {
|
|
142
|
+
if (!B(t) || t.start == null || t.end == null) return;
|
|
143
|
+
let o = C(e, t, n, a);
|
|
135
144
|
if (!o) return;
|
|
136
145
|
let { catalogId: s } = o;
|
|
137
146
|
i.add(s);
|
|
@@ -142,11 +151,11 @@ function x(e, t, n, r, i, a) {
|
|
|
142
151
|
replacement: u
|
|
143
152
|
};
|
|
144
153
|
}
|
|
145
|
-
function
|
|
154
|
+
function C(e, t, n, r) {
|
|
146
155
|
if (t.arguments.length === 0) return;
|
|
147
|
-
let i = t.callee, a =
|
|
156
|
+
let i = t.callee, a = H(i) && (n.tracked.has(i.name) || i.name === "$t"), o = V(i) && !i.computed && H(i.property) && (i.property.name === "$t" || i.property.name === "t" && H(i.object) && (i.object.name === "_ctx" || i.object.name === "$setup")), s = B(i) && H(i.callee) && n.unref.has(i.callee.name) && i.arguments.length === 1 && H(i.arguments[0]) && n.tracked.has(i.arguments[0].name);
|
|
148
157
|
if (!a && !o && !s) return;
|
|
149
|
-
let c =
|
|
158
|
+
let c = re(t.arguments[0], r);
|
|
150
159
|
if (!c) return;
|
|
151
160
|
let l = t.arguments[1] && t.arguments[1].start != null && t.arguments[1].end != null ? e.slice(t.arguments[1].start, t.arguments[1].end) : void 0;
|
|
152
161
|
return l === void 0 ? { catalogId: c } : {
|
|
@@ -154,69 +163,69 @@ function S(e, t, n, r) {
|
|
|
154
163
|
valuesSource: l
|
|
155
164
|
};
|
|
156
165
|
}
|
|
157
|
-
function
|
|
158
|
-
let n =
|
|
166
|
+
function re(e, t) {
|
|
167
|
+
let n = M(e);
|
|
159
168
|
if (n !== void 0) return t(n);
|
|
160
|
-
if (!
|
|
169
|
+
if (!R(e)) return;
|
|
161
170
|
let r, i, a;
|
|
162
171
|
for (let t of e.properties) {
|
|
163
|
-
if (!
|
|
164
|
-
let e =
|
|
172
|
+
if (!z(t) || t.computed) continue;
|
|
173
|
+
let e = N(t.key);
|
|
165
174
|
if (!e) continue;
|
|
166
|
-
let n =
|
|
175
|
+
let n = M(t.value);
|
|
167
176
|
n !== void 0 && (e === "id" && (r = n), e === "message" && (i = n), e === "context" && (a = n));
|
|
168
177
|
}
|
|
169
178
|
if (r) return r;
|
|
170
179
|
if (i) return t(i, a);
|
|
171
180
|
}
|
|
172
|
-
function
|
|
173
|
-
if (!
|
|
181
|
+
function ie(e, t, n) {
|
|
182
|
+
if (!U(e)) return;
|
|
174
183
|
let r = oe(e.openingElement.name);
|
|
175
184
|
if (r) {
|
|
176
185
|
if (r === "Trans") {
|
|
177
|
-
let r =
|
|
186
|
+
let r = k(e.openingElement, "__id") ?? k(e.openingElement, "id");
|
|
178
187
|
if (r) {
|
|
179
188
|
t.add(r);
|
|
180
189
|
return;
|
|
181
190
|
}
|
|
182
|
-
let i =
|
|
191
|
+
let i = k(e.openingElement, "__message"), a = k(e.openingElement, "context");
|
|
183
192
|
i && t.add(n(i, a));
|
|
184
193
|
return;
|
|
185
194
|
}
|
|
186
195
|
if (r === "Plural") {
|
|
187
|
-
let r =
|
|
196
|
+
let r = w(e.openingElement, n);
|
|
188
197
|
r && t.add(r);
|
|
189
198
|
return;
|
|
190
199
|
}
|
|
191
200
|
if (r === "Select") {
|
|
192
|
-
let r =
|
|
201
|
+
let r = T(e.openingElement, n);
|
|
193
202
|
r && t.add(r);
|
|
194
203
|
}
|
|
195
204
|
}
|
|
196
205
|
}
|
|
197
|
-
function
|
|
198
|
-
let n =
|
|
206
|
+
function w(e, t) {
|
|
207
|
+
let n = k(e, "id");
|
|
199
208
|
if (n) return n;
|
|
200
|
-
let r =
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
let r = k(e, "context"), i = ae(e, "offset"), a = [
|
|
210
|
+
k(e, "zero") === void 0 ? void 0 : `=0 {${k(e, "zero")}}`,
|
|
211
|
+
k(e, "one") === void 0 ? void 0 : `one {${k(e, "one")}}`,
|
|
212
|
+
k(e, "two") === void 0 ? void 0 : `two {${k(e, "two")}}`,
|
|
213
|
+
k(e, "few") === void 0 ? void 0 : `few {${k(e, "few")}}`,
|
|
214
|
+
k(e, "many") === void 0 ? void 0 : `many {${k(e, "many")}}`,
|
|
215
|
+
k(e, "other") === void 0 ? void 0 : `other {${k(e, "other")}}`
|
|
207
216
|
].filter(Boolean);
|
|
208
217
|
if (a.length !== 0) return t(`{count, plural,${typeof i == "number" ? ` offset:${i}` : ""} ${a.join(" ")}}`, r);
|
|
209
218
|
}
|
|
210
|
-
function
|
|
211
|
-
let n =
|
|
219
|
+
function T(e, t) {
|
|
220
|
+
let n = k(e, "id");
|
|
212
221
|
if (n) return n;
|
|
213
|
-
let r =
|
|
222
|
+
let r = k(e, "context"), i = E(e);
|
|
214
223
|
if (!(!i || i.other === void 0)) return t(`{value, select, ${[...Object.keys(i).filter((e) => e !== "other").sort(), "other"].map((e) => `${e} {${i[e]}}`).join(" ")}}`, r);
|
|
215
224
|
}
|
|
216
|
-
function
|
|
217
|
-
let t =
|
|
225
|
+
function E(e) {
|
|
226
|
+
let t = O(e, "options");
|
|
218
227
|
if (t) {
|
|
219
|
-
let n =
|
|
228
|
+
let n = k(e, "other");
|
|
220
229
|
return {
|
|
221
230
|
...t,
|
|
222
231
|
...n === void 0 ? {} : { other: n }
|
|
@@ -224,7 +233,7 @@ function T(e) {
|
|
|
224
233
|
}
|
|
225
234
|
let n = {};
|
|
226
235
|
for (let t of e.attributes) {
|
|
227
|
-
if (!
|
|
236
|
+
if (!W(t)) continue;
|
|
228
237
|
let e = t.name.name;
|
|
229
238
|
if ([
|
|
230
239
|
"value",
|
|
@@ -233,132 +242,132 @@ function T(e) {
|
|
|
233
242
|
"comment",
|
|
234
243
|
"options"
|
|
235
244
|
].includes(e)) continue;
|
|
236
|
-
let r =
|
|
245
|
+
let r = j(t);
|
|
237
246
|
r !== void 0 && (n[e] = r);
|
|
238
247
|
}
|
|
239
248
|
return Object.keys(n).length > 0 ? n : void 0;
|
|
240
249
|
}
|
|
241
|
-
function
|
|
242
|
-
if (!
|
|
250
|
+
function D(e) {
|
|
251
|
+
if (!R(e)) return;
|
|
243
252
|
let t = {};
|
|
244
253
|
for (let n of e.properties) {
|
|
245
|
-
if (!
|
|
246
|
-
let e =
|
|
254
|
+
if (!z(n) || n.computed) return;
|
|
255
|
+
let e = N(n.key), r = M(n.value);
|
|
247
256
|
if (!e || r === void 0) return;
|
|
248
257
|
t[e] = r;
|
|
249
258
|
}
|
|
250
259
|
return t;
|
|
251
260
|
}
|
|
252
|
-
function D(e, t) {
|
|
253
|
-
let n = k(e, t);
|
|
254
|
-
if (n?.value && n.value.type === "JSXExpressionContainer") return E(n.value.expression);
|
|
255
|
-
}
|
|
256
261
|
function O(e, t) {
|
|
257
|
-
|
|
262
|
+
let n = A(e, t);
|
|
263
|
+
if (n?.value && n.value.type === "JSXExpressionContainer") return D(n.value.expression);
|
|
264
|
+
}
|
|
265
|
+
function k(e, t) {
|
|
266
|
+
return j(A(e, t));
|
|
258
267
|
}
|
|
259
268
|
function ae(e, t) {
|
|
260
|
-
let n =
|
|
269
|
+
let n = A(e, t);
|
|
261
270
|
if (!n?.value || n.value.type !== "JSXExpressionContainer") return;
|
|
262
271
|
let r = n.value.expression;
|
|
263
272
|
return r.type === "NumericLiteral" ? r.value : void 0;
|
|
264
273
|
}
|
|
265
|
-
function
|
|
266
|
-
return e.attributes.find((e) =>
|
|
274
|
+
function A(e, t) {
|
|
275
|
+
return e.attributes.find((e) => W(e) && e.name.name === t);
|
|
267
276
|
}
|
|
268
|
-
function
|
|
277
|
+
function j(e) {
|
|
269
278
|
if (e?.value) {
|
|
270
279
|
if (e.value.type === "StringLiteral") return e.value.value;
|
|
271
|
-
if (e.value.type === "JSXExpressionContainer") return
|
|
280
|
+
if (e.value.type === "JSXExpressionContainer") return M(e.value.expression);
|
|
272
281
|
}
|
|
273
282
|
}
|
|
274
283
|
function oe(e) {
|
|
275
284
|
return e.type === "JSXIdentifier" ? e.name : void 0;
|
|
276
285
|
}
|
|
277
|
-
function
|
|
286
|
+
function M(e) {
|
|
278
287
|
if (e.type === "StringLiteral") return e.value;
|
|
279
288
|
if (e.type === "TemplateLiteral") {
|
|
280
289
|
let t = e;
|
|
281
290
|
if (t.expressions.length === 0 && t.quasis.length === 1) return t.quasis[0].value.cooked ?? t.quasis[0].value.raw;
|
|
282
291
|
}
|
|
283
292
|
}
|
|
284
|
-
function
|
|
285
|
-
if (
|
|
293
|
+
function N(e) {
|
|
294
|
+
if (H(e)) return e.name;
|
|
286
295
|
if (e.type === "StringLiteral") return e.value;
|
|
287
296
|
}
|
|
288
|
-
function
|
|
297
|
+
function P(e) {
|
|
289
298
|
return e.type === "ImportDeclaration";
|
|
290
299
|
}
|
|
291
|
-
function
|
|
300
|
+
function F(e) {
|
|
292
301
|
return e.type === "ImportSpecifier";
|
|
293
302
|
}
|
|
294
|
-
function
|
|
303
|
+
function I(e) {
|
|
295
304
|
return e.type === "VariableDeclarator";
|
|
296
305
|
}
|
|
297
|
-
function
|
|
306
|
+
function L(e) {
|
|
298
307
|
return e.type === "ObjectPattern";
|
|
299
308
|
}
|
|
300
|
-
function
|
|
309
|
+
function R(e) {
|
|
301
310
|
return e.type === "ObjectExpression";
|
|
302
311
|
}
|
|
303
|
-
function
|
|
312
|
+
function z(e) {
|
|
304
313
|
return e.type === "ObjectProperty";
|
|
305
314
|
}
|
|
306
|
-
function
|
|
315
|
+
function B(e) {
|
|
307
316
|
return e.type === "CallExpression";
|
|
308
317
|
}
|
|
309
|
-
function
|
|
318
|
+
function V(e) {
|
|
310
319
|
return e.type === "MemberExpression";
|
|
311
320
|
}
|
|
312
|
-
function
|
|
321
|
+
function H(e) {
|
|
313
322
|
return e?.type === "Identifier";
|
|
314
323
|
}
|
|
315
|
-
function
|
|
324
|
+
function U(e) {
|
|
316
325
|
return e.type === "JSXElement";
|
|
317
326
|
}
|
|
318
|
-
function
|
|
327
|
+
function W(e) {
|
|
319
328
|
return e.type === "JSXAttribute";
|
|
320
329
|
}
|
|
321
|
-
function
|
|
330
|
+
function G(e) {
|
|
322
331
|
let t = e.imported;
|
|
323
332
|
if (t.type === "Identifier") return t.name;
|
|
324
333
|
if (t.type === "StringLiteral") return t.value;
|
|
325
334
|
}
|
|
326
|
-
function
|
|
335
|
+
function K(e, n, r, i) {
|
|
327
336
|
if (n === "dynamic") return `import { __catalog } from 'virtual:fluenti/runtime';\n${e}`;
|
|
328
337
|
let a = i ?? t;
|
|
329
338
|
return `import { ${[...r].map((e) => `_${a(e)}`).join(", ")} } from 'virtual:fluenti/messages';\n${e}`;
|
|
330
339
|
}
|
|
331
340
|
//#endregion
|
|
332
341
|
//#region src/virtual-modules.ts
|
|
333
|
-
function
|
|
342
|
+
function se(e) {
|
|
334
343
|
return JSON.stringify(e);
|
|
335
344
|
}
|
|
336
345
|
function q(e) {
|
|
337
346
|
if (e.includes("`") || e.includes("$")) throw Error(`[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(e)}`);
|
|
338
347
|
}
|
|
339
|
-
var
|
|
348
|
+
var ce = "virtual:fluenti/runtime", le = "virtual:fluenti/messages", J = "\0virtual:fluenti/runtime", Y = "\0virtual:fluenti/messages";
|
|
340
349
|
function X(e) {
|
|
341
|
-
if (e ===
|
|
342
|
-
if (e ===
|
|
350
|
+
if (e === ce) return J;
|
|
351
|
+
if (e === le) return Y;
|
|
343
352
|
}
|
|
344
353
|
function Z(e, t) {
|
|
345
|
-
if (e === J) return
|
|
346
|
-
if (e === Y) return
|
|
354
|
+
if (e === J) return ue(t);
|
|
355
|
+
if (e === Y) return de(t);
|
|
347
356
|
}
|
|
348
|
-
function
|
|
357
|
+
function ue(e) {
|
|
349
358
|
let { locales: t, runtimeGenerator: n, catalogDir: r } = e;
|
|
350
359
|
q(r);
|
|
351
|
-
for (let e of t)
|
|
360
|
+
for (let e of t) p(e, "vite-plugin");
|
|
352
361
|
if (!n) throw Error("[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).");
|
|
353
|
-
return n.generateRuntime(
|
|
354
|
-
}
|
|
355
|
-
function ue(e) {
|
|
356
|
-
let { rootDir: t, catalogDir: n, catalogExtension: r, defaultBuildLocale: i, sourceLocale: o } = e, s = i || o;
|
|
357
|
-
f(s, "vite-plugin"), q(n);
|
|
358
|
-
let c = a(a(t, n), s + r);
|
|
359
|
-
return d(c) || console.warn(`[fluenti] Compiled catalog for locale "${s}" not found at ${c}. Run "fluenti compile" first.`), `export * from ${K(c)}\n`;
|
|
362
|
+
return n.generateRuntime(fe(e));
|
|
360
363
|
}
|
|
361
364
|
function de(e) {
|
|
365
|
+
let { rootDir: t, catalogDir: n, catalogExtension: r, defaultBuildLocale: i, sourceLocale: s } = e, c = i || s;
|
|
366
|
+
p(c, "vite-plugin"), q(n);
|
|
367
|
+
let l = a(a(t, n), c + r);
|
|
368
|
+
return o(l) || console.warn(`[fluenti] Compiled catalog for locale "${c}" not found at ${l}. Run "fluenti compile" first.`), `export * from ${se(l)}\n`;
|
|
369
|
+
}
|
|
370
|
+
function fe(e) {
|
|
362
371
|
let { rootDir: t, catalogDir: n, catalogExtension: r, locales: i, sourceLocale: a, defaultBuildLocale: o } = e;
|
|
363
372
|
return {
|
|
364
373
|
rootDir: t,
|
|
@@ -371,7 +380,7 @@ function de(e) {
|
|
|
371
380
|
}
|
|
372
381
|
//#endregion
|
|
373
382
|
//#region src/index.ts
|
|
374
|
-
var Q = r(typeof __filename < "u" ? __filename : import.meta.url),
|
|
383
|
+
var Q = r(typeof __filename < "u" ? __filename : import.meta.url), pe = "virtual:fluenti/messages/", me = "\0virtual:fluenti/messages/";
|
|
375
384
|
function $(e, t) {
|
|
376
385
|
if (typeof e == "object") {
|
|
377
386
|
let { DEFAULT_FLUENTI_CONFIG: t } = Q("@fluenti/core/config");
|
|
@@ -383,34 +392,34 @@ function $(e, t) {
|
|
|
383
392
|
let { loadConfigSync: n } = Q("@fluenti/core/config");
|
|
384
393
|
return n(typeof e == "string" ? e : void 0, t);
|
|
385
394
|
}
|
|
386
|
-
function
|
|
395
|
+
function he(t, r, i) {
|
|
387
396
|
let a, o = process.cwd();
|
|
388
|
-
function
|
|
397
|
+
function s(e) {
|
|
389
398
|
let n = e ?? o;
|
|
390
399
|
return a ||= $(t.config, n), a;
|
|
391
400
|
}
|
|
392
|
-
let
|
|
401
|
+
let c = t.framework;
|
|
393
402
|
function d(e) {
|
|
394
|
-
let t =
|
|
403
|
+
let t = s(e), r = t.compileOutDir.replace(/^\.\//, ""), i = t.catalogExtension ?? ".js", a = t.splitting ?? !1;
|
|
395
404
|
a && a !== "dynamic" && a !== "static" && console.warn(`[fluenti] Invalid splitting value "${a}". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`);
|
|
396
|
-
let o = a === "static" ? "static" : a ? "dynamic" : !1,
|
|
405
|
+
let o = a === "static" ? "static" : a ? "dynamic" : !1, c = t.sourceLocale;
|
|
397
406
|
return {
|
|
398
407
|
config: t,
|
|
399
408
|
catalogDir: r,
|
|
400
409
|
catalogExtension: i,
|
|
401
410
|
splitting: o,
|
|
402
|
-
sourceLocale:
|
|
411
|
+
sourceLocale: c,
|
|
403
412
|
localeCodes: n(t.locales),
|
|
404
|
-
defaultBuildLocale: t.defaultBuildLocale ??
|
|
413
|
+
defaultBuildLocale: t.defaultBuildLocale ?? c
|
|
405
414
|
};
|
|
406
415
|
}
|
|
407
416
|
let f = {
|
|
408
417
|
name: "fluenti:virtual",
|
|
409
418
|
configResolved(e) {
|
|
410
|
-
o = e.root, a = $(t.config, o),
|
|
419
|
+
o = e.root, a = $(t.config, o), h(e.command);
|
|
411
420
|
},
|
|
412
421
|
resolveId(e) {
|
|
413
|
-
if (e.startsWith(
|
|
422
|
+
if (e.startsWith(pe)) return "\0" + e;
|
|
414
423
|
let { splitting: t } = d();
|
|
415
424
|
if (t) {
|
|
416
425
|
let t = X(e);
|
|
@@ -418,8 +427,8 @@ function me(t, r, i) {
|
|
|
418
427
|
}
|
|
419
428
|
},
|
|
420
429
|
load(e) {
|
|
421
|
-
let { catalogDir: t, catalogExtension: n, splitting: r, localeCodes: a, sourceLocale: s, defaultBuildLocale:
|
|
422
|
-
if (e.startsWith(
|
|
430
|
+
let { catalogDir: t, catalogExtension: n, splitting: r, localeCodes: a, sourceLocale: s, defaultBuildLocale: l } = d();
|
|
431
|
+
if (e.startsWith(me)) {
|
|
423
432
|
let r = e.slice(26);
|
|
424
433
|
return a.includes(r) ? `export { default } from '${`${t}/${r}${n}`}'` : void 0;
|
|
425
434
|
}
|
|
@@ -430,24 +439,24 @@ function me(t, r, i) {
|
|
|
430
439
|
catalogExtension: n,
|
|
431
440
|
locales: a,
|
|
432
441
|
sourceLocale: s,
|
|
433
|
-
defaultBuildLocale:
|
|
434
|
-
framework:
|
|
442
|
+
defaultBuildLocale: l,
|
|
443
|
+
framework: c,
|
|
435
444
|
runtimeGenerator: i
|
|
436
445
|
});
|
|
437
446
|
if (r) return r;
|
|
438
447
|
}
|
|
439
448
|
}
|
|
440
|
-
}, p =
|
|
449
|
+
}, p = l({ framework: c }), m = {
|
|
441
450
|
name: "fluenti:script-transform",
|
|
442
451
|
enforce: "pre",
|
|
443
452
|
transform(e, t) {
|
|
444
453
|
if (t.includes("node_modules") || !t.match(/\.(vue|tsx|jsx|ts|js)(\?|$)/) || t.includes(".vue") && !t.includes("type=script")) return;
|
|
445
|
-
let n =
|
|
454
|
+
let n = c === "vue" && t.includes(".vue"), r = e, i = !1;
|
|
446
455
|
if (t.match(/\.[jt]sx(\?|$)/) && /<Trans[\s>]/.test(r)) {
|
|
447
456
|
let e = p.transformTrans(r);
|
|
448
457
|
e.transformed && (r = e.code, i = !0);
|
|
449
458
|
}
|
|
450
|
-
if (
|
|
459
|
+
if (u(r)) {
|
|
451
460
|
let e = p.transformScope(r, n ? { allowTopLevelImportedT: !0 } : void 0);
|
|
452
461
|
if (e.transformed) return {
|
|
453
462
|
code: e.code,
|
|
@@ -459,28 +468,28 @@ function me(t, r, i) {
|
|
|
459
468
|
map: null
|
|
460
469
|
} : void 0;
|
|
461
470
|
}
|
|
462
|
-
},
|
|
471
|
+
}, b = {
|
|
463
472
|
name: "fluenti:build-split",
|
|
464
473
|
transform(e, t) {
|
|
465
474
|
let { splitting: n, config: r } = d();
|
|
466
|
-
if (!n || !g(
|
|
467
|
-
let i = n === "static" ? "static" : "dynamic", a = r.idGenerator ? { hashFn: r.idGenerator } : void 0, o = i === "static" ?
|
|
475
|
+
if (!n || !_(g(this)) || t.includes("node_modules") || !t.match(/\.(vue|tsx|jsx|ts|js)(\?|$)/)) return;
|
|
476
|
+
let i = n === "static" ? "static" : "dynamic", a = r.idGenerator ? { hashFn: r.idGenerator } : void 0, o = i === "static" ? te(e, a) : y(e, a);
|
|
468
477
|
if (o.needsCatalogImport) return {
|
|
469
|
-
code:
|
|
478
|
+
code: K(o.code, i, o.usedHashes, r.idGenerator),
|
|
470
479
|
map: null
|
|
471
480
|
};
|
|
472
481
|
}
|
|
473
|
-
},
|
|
482
|
+
}, x = {
|
|
474
483
|
name: "fluenti:build-compile",
|
|
475
484
|
async buildStart() {
|
|
476
485
|
let { config: e } = d();
|
|
477
|
-
g(
|
|
486
|
+
_(g(this)) && (e.buildAutoCompile ?? !0) && (e.onBeforeCompile && await e.onBeforeCompile() === !1 || (await v({
|
|
478
487
|
cwd: o,
|
|
479
488
|
throwOnError: !0,
|
|
480
489
|
compileOnly: !0
|
|
481
490
|
}), e.onAfterCompile && await e.onAfterCompile()));
|
|
482
491
|
}
|
|
483
|
-
},
|
|
492
|
+
}, S = {
|
|
484
493
|
name: "fluenti:dev",
|
|
485
494
|
configureServer(t) {
|
|
486
495
|
let { config: n, catalogDir: r } = d(t.config.root);
|
|
@@ -510,13 +519,13 @@ function me(t, r, i) {
|
|
|
510
519
|
return [
|
|
511
520
|
f,
|
|
512
521
|
...r,
|
|
513
|
-
|
|
522
|
+
m,
|
|
523
|
+
x,
|
|
514
524
|
b,
|
|
515
|
-
|
|
516
|
-
x
|
|
525
|
+
S
|
|
517
526
|
];
|
|
518
527
|
}
|
|
519
528
|
//#endregion
|
|
520
|
-
export {
|
|
529
|
+
export { he as createFluentiPlugins, c as createRuntimeGenerator, g as getPluginEnvironment, _ as isBuildMode, Z as loadVirtualSplitModule, X as resolveVirtualSplitId, h as setResolvedMode };
|
|
521
530
|
|
|
522
531
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/mode-detect.ts","../src/dev-runner.ts","../src/build-transform.ts","../src/virtual-modules.ts","../src/index.ts"],"sourcesContent":["/**\n * Detect whether Vite is running in build or dev mode.\n * Supports Vite 7 (configResolved) and Vite 8+ (environment API).\n */\n\nlet resolvedMode: 'build' | 'dev' = 'dev'\n\n/** Called from configResolved hook to capture the mode early */\nexport function setResolvedMode(command: string): void {\n resolvedMode = command === 'build' ? 'build' : 'dev'\n}\n\n/** Get the current resolved mode */\nexport function getResolvedMode(): 'build' | 'dev' {\n return resolvedMode\n}\n\n/**\n * Safely extract the environment object from a Vite plugin context.\n * Handles Vite 8+ environment API without direct `(this as any)` casts at call sites.\n */\nexport function getPluginEnvironment(pluginContext: unknown): { mode?: string } | undefined {\n if (\n typeof pluginContext === 'object' &&\n pluginContext !== null &&\n 'environment' in pluginContext\n ) {\n const env = (pluginContext as Record<string, unknown>)['environment']\n if (typeof env === 'object' && env !== null) {\n return env as { mode?: string }\n }\n }\n return undefined\n}\n\n/**\n * Check if we're in build mode.\n * Tries environment API (Vite 8+), then falls back to configResolved capture,\n * then falls back to NODE_ENV.\n */\nexport function isBuildMode(environment?: { mode?: string }): boolean {\n // Vite 8+: environment.mode === 'build'\n if (environment?.mode === 'build') return true\n\n // Vite 7: captured from configResolved\n if (resolvedMode === 'build') return true\n\n // Last resort: NODE_ENV\n if (process.env['NODE_ENV'] === 'production') return true\n\n return false\n}\n","import { join } from 'node:path'\nimport { createRequire } from 'node:module'\n\nexport interface DevRunnerOptions {\n cwd: string\n onSuccess?: () => void\n onError?: (err: Error) => void\n /** If true, reject the promise on failure instead of swallowing the error */\n throwOnError?: boolean\n /** Run only compile (skip extract). Useful for production builds where source is unchanged. */\n compileOnly?: boolean\n /** Enable parallel compilation across locales using worker threads */\n parallelCompile?: boolean\n /** Called before compile runs. Return false to skip compilation. */\n onBeforeCompile?: () => boolean | void | Promise<boolean | void>\n /** Called after compile completes successfully */\n onAfterCompile?: () => void | Promise<void>\n}\n\n/**\n * Run compile in-process via `@fluenti/cli`.\n *\n * In `compileOnly` mode, only compilation is performed (extract is skipped).\n * In dev mode, both extract and compile run in sequence.\n *\n * If `@fluenti/cli` is not installed, shows an install guide instead of\n * falling back to shell-out — keeping the process boundary clean.\n */\nexport async function runExtractCompile(options: DevRunnerOptions): Promise<void> {\n if (options.onBeforeCompile) {\n const result = await options.onBeforeCompile()\n if (result === false) return\n }\n\n if (options.compileOnly) {\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runCompile } = projectRequire('@fluenti/cli')\n await runCompile(options.cwd)\n console.log('[fluenti] Compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n if (options.throwOnError) throw error\n console.warn('[fluenti] Compile failed:', error.message)\n options.onError?.(error)\n return\n }\n }\n\n // Dev mode: in-process extract + compile\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runExtract, runCompile } = projectRequire('@fluenti/cli')\n await runExtract(options.cwd)\n await runCompile(options.cwd, { parallel: options.parallelCompile })\n console.log('[fluenti] Extracting and compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n const isNotInstalled = error.message.includes('Cannot find module')\n\n if (isNotInstalled) {\n const msg =\n '[fluenti] @fluenti/cli is required for auto-compile.\\n' +\n ' Install it as a devDependency:\\n' +\n ' pnpm add -D @fluenti/cli\\n' +\n ' See: https://fluenti.dev/start/introduction/'\n if (options.throwOnError) throw new Error(msg)\n console.warn(msg)\n options.onError?.(new Error(msg))\n return\n }\n\n if (options.throwOnError) throw error\n console.warn('[fluenti] Extract/compile failed:', error.message)\n options.onError?.(error)\n }\n}\n\n/**\n * Create a debounced runner that collapses rapid calls.\n *\n * - If called while idle, schedules a run after `delay` ms.\n * - If called while a run is in progress, marks a pending rerun.\n * - Never runs concurrently.\n */\nexport function createDebouncedRunner(\n options: DevRunnerOptions,\n delay = 300,\n): () => void {\n let timer: ReturnType<typeof setTimeout> | null = null\n let running = false\n let pendingRerun = false\n\n async function execute(): Promise<void> {\n running = true\n try {\n await runExtractCompile(options)\n } finally {\n running = false\n if (pendingRerun) {\n pendingRerun = false\n schedule()\n }\n }\n }\n\n function schedule(): void {\n if (timer !== null) {\n clearTimeout(timer)\n }\n timer = setTimeout(() => {\n timer = null\n if (running) {\n pendingRerun = true\n } else {\n execute()\n }\n }, delay)\n }\n\n return schedule\n}\n","/**\n * Build-mode transform for code-splitting.\n *\n * Strategy 'dynamic': rewrites supported translation calls to __catalog._<hash> references.\n * Strategy 'static': rewrites to direct named imports from compiled locale modules.\n */\n\nimport { hashMessage as defaultHashMessage } from '@fluenti/core/internal'\nimport { parseSourceModule, walkSourceAst, type SourceNode } from '@fluenti/core/transform'\n\nexport type HashFunction = (message: string, context?: string) => string\n\nexport interface BuildTransformResult {\n code: string\n needsCatalogImport: boolean\n usedHashes: Set<string>\n}\n\nexport interface BuildTransformOptions {\n /** Custom hash function for message IDs (defaults to @fluenti/core hashMessage) */\n hashFn?: HashFunction\n}\n\ntype SplitStrategy = 'dynamic' | 'static'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { cooked: string | null; raw: string }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n expressions: SourceNode[]\n quasis: TemplateElementNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface AwaitExpressionNode extends SourceNode {\n type: 'AwaitExpression'\n argument: SourceNode\n}\n\ninterface VariableDeclaratorNode extends SourceNode {\n type: 'VariableDeclarator'\n id: SourceNode\n init?: SourceNode | null\n}\n\ninterface ProgramNode extends SourceNode {\n type: 'Program'\n body: SourceNode[]\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface ObjectPatternNode extends SourceNode {\n type: 'ObjectPattern'\n properties: SourceNode[]\n}\n\ninterface MemberExpressionNode extends SourceNode {\n type: 'MemberExpression'\n object: SourceNode\n property: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXIdentifierNode extends SourceNode {\n type: 'JSXIdentifier'\n name: string\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: JSXIdentifierNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface SplitReplacement {\n start: number\n end: number\n replacement: string\n}\n\ninterface SplitTarget {\n catalogId: string\n valuesSource?: string\n}\n\ninterface RuntimeBindings {\n tracked: Set<string>\n unref: Set<string>\n}\n\nexport function transformForDynamicSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'dynamic', options)\n}\n\nexport function transformForStaticSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'static', options)\n}\n\nfunction transformForSplitStrategy(\n code: string,\n strategy: SplitStrategy,\n options?: BuildTransformOptions,\n): BuildTransformResult {\n const hashFn = options?.hashFn ?? defaultHashMessage\n const ast = parseSourceModule(code)\n if (!ast || ast.type !== 'Program') {\n return { code, needsCatalogImport: false, usedHashes: new Set() }\n }\n\n const bindings = collectTrackedRuntimeBindings(ast as ProgramNode)\n const replacements: SplitReplacement[] = []\n const usedHashes = new Set<string>()\n\n walkSourceAst(ast, (node) => {\n const replacement = extractCallReplacement(code, node, bindings, strategy, usedHashes, hashFn)\n if (replacement) {\n replacements.push(replacement)\n return\n }\n\n collectComponentUsage(node, usedHashes, hashFn)\n })\n\n if (replacements.length === 0) {\n return { code, needsCatalogImport: false, usedHashes }\n }\n\n let result = code\n for (let i = replacements.length - 1; i >= 0; i--) {\n const { start, end, replacement } = replacements[i]!\n result = result.slice(0, start) + replacement + result.slice(end)\n }\n\n return { code: result, needsCatalogImport: true, usedHashes }\n}\n\nfunction collectTrackedRuntimeBindings(program: ProgramNode): RuntimeBindings {\n const tracked = new Set<string>()\n const useI18nBindings = new Set<string>()\n const getI18nBindings = new Set<string>()\n const unrefBindings = new Set<string>()\n\n for (const statement of program.body) {\n if (!isImportDeclaration(statement)) continue\n for (const specifier of statement.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n const importedName = readImportedName(specifier)\n if (!importedName) continue\n if (importedName === 'useI18n') {\n useI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'getI18n') {\n getI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'unref') {\n unrefBindings.add(specifier.local.name)\n }\n }\n }\n\n walkSourceAst(program, (node) => {\n if (!isVariableDeclarator(node) || !node.init || !isObjectPattern(node.id)) return\n\n if (isCallExpression(node.init) && isIdentifier(node.init.callee) && useI18nBindings.has(node.init.callee.name)) {\n addTrackedObjectPatternBindings(node.id, tracked)\n return\n }\n\n const awaitedCall = node.init.type === 'AwaitExpression'\n ? (node.init as AwaitExpressionNode).argument\n : null\n\n if (\n awaitedCall\n && isCallExpression(awaitedCall)\n && isIdentifier(awaitedCall.callee)\n && getI18nBindings.has(awaitedCall.callee.name)\n ) {\n addTrackedObjectPatternBindings(node.id, tracked)\n }\n })\n\n return { tracked, unref: unrefBindings }\n}\n\nfunction addTrackedObjectPatternBindings(pattern: ObjectPatternNode, tracked: Set<string>): void {\n for (const property of pattern.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n if (!isIdentifier(property.key) || property.key.name !== 't') continue\n if (isIdentifier(property.value)) {\n tracked.add(property.value.name)\n }\n }\n}\n\nfunction extractCallReplacement(\n code: string,\n node: SourceNode,\n bindings: RuntimeBindings,\n strategy: SplitStrategy,\n usedHashes: Set<string>,\n hashFn: HashFunction,\n): SplitReplacement | undefined {\n if (!isCallExpression(node) || node.start == null || node.end == null) {\n return undefined\n }\n\n const splitTarget = resolveSplitTarget(code, node, bindings, hashFn)\n if (!splitTarget) {\n return undefined\n }\n\n const { catalogId } = splitTarget\n usedHashes.add(catalogId)\n const exportHash = hashFn(catalogId)\n const replacementTarget = strategy === 'dynamic'\n ? `__catalog[${JSON.stringify(catalogId)}]`\n : `_${exportHash}`\n const replacement = splitTarget.valuesSource\n ? `${replacementTarget}(${splitTarget.valuesSource})`\n : replacementTarget\n\n return {\n start: node.start,\n end: node.end,\n replacement,\n }\n}\n\nfunction resolveSplitTarget(\n code: string,\n call: CallExpressionNode,\n bindings: RuntimeBindings,\n hashFn: HashFunction,\n): SplitTarget | undefined {\n if (call.arguments.length === 0) return undefined\n\n const callee = call.callee\n const isTrackedIdentifierCall = isIdentifier(callee) && (bindings.tracked.has(callee.name) || callee.name === '$t')\n const isTemplateMemberCall = isMemberExpression(callee)\n && !callee.computed\n && isIdentifier(callee.property)\n && (\n callee.property.name === '$t'\n || (\n callee.property.name === 't'\n && isIdentifier(callee.object)\n && (callee.object.name === '_ctx' || callee.object.name === '$setup')\n )\n )\n const isVueUnrefCall = isCallExpression(callee)\n && isIdentifier(callee.callee)\n && bindings.unref.has(callee.callee.name)\n && callee.arguments.length === 1\n && isIdentifier(callee.arguments[0])\n && bindings.tracked.has(callee.arguments[0].name)\n\n if (!isTrackedIdentifierCall && !isTemplateMemberCall && !isVueUnrefCall) {\n return undefined\n }\n\n const catalogId = extractCatalogId(call.arguments[0]!, hashFn)\n if (!catalogId) return undefined\n\n const valuesSource = call.arguments[1] && call.arguments[1]!.start != null && call.arguments[1]!.end != null\n ? code.slice(call.arguments[1]!.start, call.arguments[1]!.end)\n : undefined\n\n return valuesSource === undefined\n ? { catalogId }\n : { catalogId, valuesSource }\n}\n\nfunction extractCatalogId(argument: SourceNode, hashFn: HashFunction): string | undefined {\n const staticString = readStaticString(argument)\n if (staticString !== undefined) {\n return hashFn(staticString)\n }\n\n if (!isObjectExpression(argument)) {\n return undefined\n }\n\n let id: string | undefined\n let message: string | undefined\n let context: string | undefined\n\n for (const property of argument.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n const key = readPropertyKey(property.key)\n if (!key) continue\n\n const value = readStaticString(property.value)\n if (value === undefined) continue\n\n if (key === 'id') id = value\n if (key === 'message') message = value\n if (key === 'context') context = value\n }\n\n if (id) return id\n if (message) return hashFn(message, context)\n return undefined\n}\n\nfunction collectComponentUsage(node: SourceNode, usedHashes: Set<string>, hashFn: HashFunction): void {\n if (!isJsxElement(node)) return\n\n const componentName = readJsxName(node.openingElement.name)\n if (!componentName) return\n\n if (componentName === 'Trans') {\n const id = readJsxStaticAttribute(node.openingElement, '__id') ?? readJsxStaticAttribute(node.openingElement, 'id')\n if (id) {\n usedHashes.add(id)\n return\n }\n\n const message = readJsxStaticAttribute(node.openingElement, '__message')\n const context = readJsxStaticAttribute(node.openingElement, 'context')\n if (message) {\n usedHashes.add(hashFn(message, context))\n }\n return\n }\n\n if (componentName === 'Plural') {\n const messageId = buildPluralMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n return\n }\n\n if (componentName === 'Select') {\n const messageId = buildSelectMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n }\n}\n\nfunction buildPluralMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const offsetRaw = readJsxStaticNumber(openingElement, 'offset')\n const forms = [\n readJsxStaticAttribute(openingElement, 'zero') === undefined ? undefined : `=0 {${readJsxStaticAttribute(openingElement, 'zero')}}`,\n readJsxStaticAttribute(openingElement, 'one') === undefined ? undefined : `one {${readJsxStaticAttribute(openingElement, 'one')}}`,\n readJsxStaticAttribute(openingElement, 'two') === undefined ? undefined : `two {${readJsxStaticAttribute(openingElement, 'two')}}`,\n readJsxStaticAttribute(openingElement, 'few') === undefined ? undefined : `few {${readJsxStaticAttribute(openingElement, 'few')}}`,\n readJsxStaticAttribute(openingElement, 'many') === undefined ? undefined : `many {${readJsxStaticAttribute(openingElement, 'many')}}`,\n readJsxStaticAttribute(openingElement, 'other') === undefined ? undefined : `other {${readJsxStaticAttribute(openingElement, 'other')}}`,\n ].filter(Boolean)\n\n if (forms.length === 0) return undefined\n\n const offsetPart = typeof offsetRaw === 'number' ? ` offset:${offsetRaw}` : ''\n const icuMessage = `{count, plural,${offsetPart} ${forms.join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction buildSelectMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const forms = readStaticSelectForms(openingElement)\n if (!forms || forms['other'] === undefined) return undefined\n\n const orderedKeys = [...Object.keys(forms).filter((key) => key !== 'other').sort(), 'other']\n const icuMessage = `{value, select, ${orderedKeys.map((key) => `${key} {${forms[key]!}}`).join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction readStaticSelectForms(openingElement: JSXOpeningElementNode): Record<string, string> | undefined {\n const optionForms = readJsxStaticObject(openingElement, 'options')\n if (optionForms) {\n const other = readJsxStaticAttribute(openingElement, 'other')\n return {\n ...optionForms,\n ...(other !== undefined ? { other } : {}),\n }\n }\n\n const forms: Record<string, string> = {}\n for (const attribute of openingElement.attributes) {\n if (!isJsxAttribute(attribute)) continue\n const name = attribute.name.name\n if (['value', 'id', 'context', 'comment', 'options'].includes(name)) continue\n const value = readJsxAttributeValue(attribute)\n if (value !== undefined) {\n forms[name] = value\n }\n }\n\n return Object.keys(forms).length > 0 ? forms : undefined\n}\n\nfunction readStaticSelectObjectValue(node: SourceNode): Record<string, string> | undefined {\n if (!isObjectExpression(node)) return undefined\n const values: Record<string, string> = {}\n\n for (const property of node.properties) {\n if (!isObjectProperty(property) || property.computed) return undefined\n const key = readPropertyKey(property.key)\n const value = readStaticString(property.value)\n if (!key || value === undefined) return undefined\n values[key] = value\n }\n\n return values\n}\n\nfunction readJsxStaticObject(openingElement: JSXOpeningElementNode, name: string): Record<string, string> | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value) return undefined\n if (attribute.value.type !== 'JSXExpressionContainer') return undefined\n return readStaticSelectObjectValue((attribute.value as JSXExpressionContainerNode).expression)\n}\n\nfunction readJsxStaticAttribute(openingElement: JSXOpeningElementNode, name: string): string | undefined {\n return readJsxAttributeValue(findJsxAttribute(openingElement, name))\n}\n\nfunction readJsxStaticNumber(openingElement: JSXOpeningElementNode, name: string): number | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value || attribute.value.type !== 'JSXExpressionContainer') return undefined\n const expression = (attribute.value as JSXExpressionContainerNode).expression\n return expression.type === 'NumericLiteral' ? (expression as NumericLiteralNode).value : undefined\n}\n\nfunction findJsxAttribute(openingElement: JSXOpeningElementNode, name: string): JSXAttributeNode | undefined {\n return openingElement.attributes.find((attribute) => {\n return isJsxAttribute(attribute) && attribute.name.name === name\n }) as JSXAttributeNode | undefined\n}\n\nfunction readJsxAttributeValue(attribute: JSXAttributeNode | undefined): string | undefined {\n if (!attribute?.value) return undefined\n\n if (attribute.value.type === 'StringLiteral') {\n return (attribute.value as StringLiteralNode).value\n }\n\n if (attribute.value.type === 'JSXExpressionContainer') {\n return readStaticString((attribute.value as JSXExpressionContainerNode).expression)\n }\n\n return undefined\n}\n\nfunction readJsxName(node: SourceNode): string | undefined {\n return node.type === 'JSXIdentifier' ? (node as JSXIdentifierNode).name : undefined\n}\n\nfunction readStaticString(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0 && template.quasis.length === 1) {\n return template.quasis[0]!.value.cooked ?? template.quasis[0]!.value.raw\n }\n }\n\n return undefined\n}\n\nfunction readPropertyKey(node: SourceNode): string | undefined {\n if (isIdentifier(node)) return node.name\n if (node.type === 'StringLiteral') return (node as StringLiteralNode).value\n return undefined\n}\n\nfunction isImportDeclaration(node: SourceNode): node is ImportDeclarationNode {\n return node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: SourceNode): node is ImportSpecifierNode {\n return node.type === 'ImportSpecifier'\n}\n\nfunction isVariableDeclarator(node: SourceNode): node is VariableDeclaratorNode {\n return node.type === 'VariableDeclarator'\n}\n\nfunction isObjectPattern(node: SourceNode): node is ObjectPatternNode {\n return node.type === 'ObjectPattern'\n}\n\nfunction isObjectExpression(node: SourceNode): node is ObjectExpressionNode {\n return node.type === 'ObjectExpression'\n}\n\nfunction isObjectProperty(node: SourceNode): node is ObjectPropertyNode {\n return node.type === 'ObjectProperty'\n}\n\nfunction isCallExpression(node: SourceNode): node is CallExpressionNode {\n return node.type === 'CallExpression'\n}\n\nfunction isMemberExpression(node: SourceNode): node is MemberExpressionNode {\n return node.type === 'MemberExpression'\n}\n\nfunction isIdentifier(node: SourceNode | undefined | null): node is IdentifierNode {\n return node?.type === 'Identifier'\n}\n\nfunction isJsxElement(node: SourceNode): node is JSXElementNode {\n return node.type === 'JSXElement'\n}\n\nfunction isJsxAttribute(node: SourceNode): node is JSXAttributeNode {\n return node.type === 'JSXAttribute'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n const imported = specifier.imported\n if (imported.type === 'Identifier') return imported.name\n if (imported.type === 'StringLiteral') return imported.value\n return undefined\n}\n\n/**\n * Inject the catalog import statement at the top of the module.\n */\nexport function injectCatalogImport(code: string, strategy: 'dynamic' | 'static', hashes: Set<string>, hashFn?: HashFunction): string {\n if (strategy === 'dynamic') {\n return `import { __catalog } from 'virtual:fluenti/runtime';\\n${code}`\n }\n\n // Static: import named exports directly\n const hash = hashFn ?? defaultHashMessage\n const imports = [...hashes].map((id) => `_${hash(id)}`).join(', ')\n return `import { ${imports} } from 'virtual:fluenti/messages';\\n${code}`\n}\n","/**\n * Virtual module resolution for code-splitting mode.\n *\n * Provides:\n * - virtual:fluenti/runtime → reactive catalog + switchLocale + preloadLocale\n * - virtual:fluenti/messages → re-export from static locale (for static strategy)\n */\n\nimport { resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { validateLocale } from '@fluenti/core'\nimport type { RuntimeGenerator, RuntimeGeneratorOptions } from './types'\n\n/**\n * Escapes a string value for safe embedding in generated JavaScript code.\n * Returns a JSON-encoded string (with double quotes), preventing injection\n * of quotes, backticks, template interpolation, and other special characters.\n */\nfunction safeStringLiteral(value: string): string {\n return JSON.stringify(value)\n}\n\n/**\n * Validates that a catalog directory path does not contain characters\n * that could enable code injection in generated template literals.\n */\nfunction validateCatalogDir(catalogDir: string): void {\n if (catalogDir.includes('`') || catalogDir.includes('$')) {\n throw new Error(\n `[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(catalogDir)}`,\n )\n }\n}\n\nconst VIRTUAL_RUNTIME = 'virtual:fluenti/runtime'\nconst VIRTUAL_MESSAGES = 'virtual:fluenti/messages'\nconst RESOLVED_RUNTIME = '\\0virtual:fluenti/runtime'\nconst RESOLVED_MESSAGES = '\\0virtual:fluenti/messages'\n\nexport interface VirtualModuleOptions {\n rootDir: string\n catalogDir: string\n catalogExtension: string\n locales: string[]\n sourceLocale: string\n defaultBuildLocale: string\n framework: string\n runtimeGenerator?: RuntimeGenerator | undefined\n}\n\nexport function resolveVirtualSplitId(id: string): string | undefined {\n if (id === VIRTUAL_RUNTIME) return RESOLVED_RUNTIME\n if (id === VIRTUAL_MESSAGES) return RESOLVED_MESSAGES\n return undefined\n}\n\nexport function loadVirtualSplitModule(\n id: string,\n options: VirtualModuleOptions,\n): string | undefined {\n if (id === RESOLVED_RUNTIME) {\n return generateRuntimeModule(options)\n }\n if (id === RESOLVED_MESSAGES) {\n return generateStaticMessagesModule(options)\n }\n return undefined\n}\n\nfunction generateRuntimeModule(options: VirtualModuleOptions): string {\n const { locales, runtimeGenerator, catalogDir } = options\n validateCatalogDir(catalogDir)\n for (const locale of locales) {\n validateLocale(locale, 'vite-plugin')\n }\n\n if (!runtimeGenerator) {\n throw new Error('[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).')\n }\n\n return runtimeGenerator.generateRuntime(toRuntimeGeneratorOptions(options))\n}\n\nfunction generateStaticMessagesModule(options: VirtualModuleOptions): string {\n const { rootDir, catalogDir, catalogExtension, defaultBuildLocale, sourceLocale } = options\n const defaultLocale = defaultBuildLocale || sourceLocale\n validateLocale(defaultLocale, 'vite-plugin')\n validateCatalogDir(catalogDir)\n const absoluteCatalogDir = resolve(rootDir, catalogDir)\n const catalogFile = resolve(absoluteCatalogDir, defaultLocale + catalogExtension)\n\n if (!existsSync(catalogFile)) {\n console.warn(\n `[fluenti] Compiled catalog for locale \"${defaultLocale}\" not found at ${catalogFile}. Run \"fluenti compile\" first.`,\n )\n }\n\n return `export * from ${safeStringLiteral(catalogFile)}\\n`\n}\n\nfunction toRuntimeGeneratorOptions(options: VirtualModuleOptions): RuntimeGeneratorOptions {\n const { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale } = options\n return { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale }\n}\n","import type { Plugin } from 'vite'\nimport { createFilter } from 'vite'\nimport type { FluentiCoreOptions, RuntimeGenerator } from './types'\nimport type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\nimport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\nimport { createRequire } from 'node:module'\n\nconst _require = createRequire(\n typeof __filename !== 'undefined' ? __filename : import.meta.url,\n)\nimport { createDebouncedRunner, runExtractCompile } from './dev-runner'\nimport { transformForDynamicSplit, transformForStaticSplit, injectCatalogImport } from './build-transform'\nimport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nimport { createTransformPipeline, hasScopeTransformCandidate } from '@fluenti/core/transform'\nexport type { FluentiPluginOptions, FluentiCoreOptions, RuntimeGenerator, RuntimeGeneratorOptions, IdGenerator } from './types'\nexport { createRuntimeGenerator } from './runtime-template'\nexport type { RuntimePrimitives } from './runtime-template'\nexport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nexport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\n\nconst VIRTUAL_PREFIX = 'virtual:fluenti/messages/'\nconst RESOLVED_PREFIX = '\\0virtual:fluenti/messages/'\n\n/**\n * Resolve a config option (string path, inline object, or undefined) into a full FluentiBuildConfig.\n */\nfunction resolvePluginConfig(configOption?: string | FluentiBuildConfig, cwd?: string): FluentiBuildConfig {\n if (typeof configOption === 'object') {\n // Inline config — merge with defaults\n const { DEFAULT_FLUENTI_CONFIG } = _require('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: FluentiBuildConfig\n }\n return { ...DEFAULT_FLUENTI_CONFIG, ...configOption }\n }\n // string → specified path; undefined → auto-discover\n const { loadConfigSync: loadSync } = _require('@fluenti/core/config') as {\n loadConfigSync: (configPath?: string, cwd?: string) => FluentiBuildConfig\n }\n return loadSync(\n typeof configOption === 'string' ? configOption : undefined,\n cwd,\n )\n}\n\n// ─── Public factory for framework packages ─────────────────────────────────\n\n/**\n * Create the Fluenti plugin pipeline.\n * Framework packages call this with their framework-specific plugins and runtime generator.\n */\nexport function createFluentiPlugins(\n options: FluentiCoreOptions,\n frameworkPlugins: Plugin[],\n runtimeGenerator?: RuntimeGenerator,\n): Plugin[] {\n let fluentiConfig: FluentiBuildConfig | undefined\n let rootDir = process.cwd()\n\n function getConfig(cwd?: string): FluentiBuildConfig {\n const effectiveCwd = cwd ?? rootDir\n if (!fluentiConfig) {\n fluentiConfig = resolvePluginConfig(options.config, effectiveCwd)\n }\n return fluentiConfig\n }\n\n const framework = options.framework\n\n function getResolvedSettings(cwd?: string) {\n const config = getConfig(cwd)\n const catalogDir = config.compileOutDir.replace(/^\\.\\//, '')\n const catalogExtension = config.catalogExtension ?? '.js'\n const rawSplitting = config.splitting ?? false\n if (rawSplitting && rawSplitting !== 'dynamic' && rawSplitting !== 'static') {\n console.warn(`[fluenti] Invalid splitting value \"${rawSplitting}\". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`)\n }\n const splitting = rawSplitting === 'static' ? 'static' as const : rawSplitting ? 'dynamic' as const : false as const\n const sourceLocale = config.sourceLocale\n const localeCodes = resolveLocaleCodes(config.locales)\n const defaultBuildLocale = config.defaultBuildLocale ?? sourceLocale\n return {\n config,\n catalogDir,\n catalogExtension,\n splitting,\n sourceLocale,\n localeCodes,\n defaultBuildLocale,\n }\n }\n\n const virtualPlugin: Plugin = {\n name: 'fluenti:virtual',\n configResolved(config) {\n rootDir = config.root\n fluentiConfig = resolvePluginConfig(options.config, rootDir)\n setResolvedMode(config.command)\n },\n resolveId(id) {\n if (id.startsWith(VIRTUAL_PREFIX)) {\n return '\\0' + id\n }\n const { splitting } = getResolvedSettings()\n if (splitting) {\n const resolved = resolveVirtualSplitId(id)\n if (resolved) return resolved\n }\n return undefined\n },\n load(id) {\n const {\n catalogDir,\n catalogExtension,\n splitting,\n localeCodes,\n sourceLocale,\n defaultBuildLocale,\n } = getResolvedSettings()\n if (id.startsWith(RESOLVED_PREFIX)) {\n const locale = id.slice(RESOLVED_PREFIX.length)\n if (!localeCodes.includes(locale)) {\n return undefined\n }\n const catalogPath = `${catalogDir}/${locale}${catalogExtension}`\n return `export { default } from '${catalogPath}'`\n }\n if (splitting) {\n const result = loadVirtualSplitModule(id, {\n rootDir,\n catalogDir,\n catalogExtension,\n locales: localeCodes,\n sourceLocale,\n defaultBuildLocale,\n framework,\n runtimeGenerator,\n })\n if (result) return result\n }\n return undefined\n },\n }\n\n const pipeline = createTransformPipeline({ framework })\n\n const scriptTransformPlugin: Plugin = {\n name: 'fluenti:script-transform',\n enforce: 'pre',\n transform(code, id) {\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n if (id.includes('.vue') && !id.includes('type=script')) return undefined\n\n // Vue .vue files need allowTopLevelImportedT for top-level `import { t }`\n const isVueSfc = framework === 'vue' && id.includes('.vue')\n\n let result = code\n let changed = false\n\n // ── <Trans> compile-time optimization (JSX/TSX only) ──────────────\n if (id.match(/\\.[jt]sx(\\?|$)/) && /<Trans[\\s>]/.test(result)) {\n const transResult = pipeline.transformTrans(result)\n if (transResult.transformed) {\n result = transResult.code\n changed = true\n }\n }\n\n // ── t`` / t() scope-aware transform ────────────────────────────────\n if (hasScopeTransformCandidate(result)) {\n const scoped = pipeline.transformScope(result,\n isVueSfc ? { allowTopLevelImportedT: true } : undefined,\n )\n if (scoped.transformed) {\n return { code: scoped.code, map: null }\n }\n }\n\n return changed ? { code: result, map: null } : undefined\n },\n }\n\n const buildSplitPlugin: Plugin = {\n name: 'fluenti:build-split',\n transform(code, id) {\n const { splitting, config } = getResolvedSettings()\n if (!splitting) return undefined\n if (!isBuildMode(getPluginEnvironment(this))) return undefined\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n\n const strategy = splitting === 'static' ? 'static' : 'dynamic'\n const transformOptions = config.idGenerator ? { hashFn: config.idGenerator } : undefined\n const transformed = strategy === 'static'\n ? transformForStaticSplit(code, transformOptions)\n : transformForDynamicSplit(code, transformOptions)\n\n if (!transformed.needsCatalogImport) return undefined\n\n const finalCode = injectCatalogImport(\n transformed.code,\n strategy,\n transformed.usedHashes,\n config.idGenerator,\n )\n return { code: finalCode, map: null }\n },\n }\n\n const buildCompilePlugin: Plugin = {\n name: 'fluenti:build-compile',\n async buildStart() {\n const { config } = getResolvedSettings()\n if (!isBuildMode(getPluginEnvironment(this))) return\n const buildAutoCompile = config.buildAutoCompile ?? true\n if (!buildAutoCompile) return\n if (config.onBeforeCompile) {\n const result = await config.onBeforeCompile()\n if (result === false) return\n }\n await runExtractCompile({ cwd: rootDir, throwOnError: true, compileOnly: true })\n if (config.onAfterCompile) {\n await config.onAfterCompile()\n }\n },\n }\n\n const devPlugin: Plugin = {\n name: 'fluenti:dev',\n configureServer(server) {\n const { config, catalogDir } = getResolvedSettings(server.config.root)\n const devAutoCompile = config.devAutoCompile ?? true\n if (!devAutoCompile) return\n\n const includePatterns = config.include ?? ['src/**/*.{vue,tsx,jsx,ts,js}']\n const excludePatterns = config.exclude ?? []\n\n const filter = createFilter(includePatterns, [\n ...excludePatterns,\n '**/node_modules/**',\n `**/${catalogDir}/**`,\n ])\n\n const runnerOptions: Parameters<typeof createDebouncedRunner>[0] = {\n cwd: server.config.root,\n onSuccess: () => {\n // Existing hotUpdate will pick up catalog changes\n },\n }\n if (config.parallelCompile) runnerOptions.parallelCompile = true\n if (config.onBeforeCompile) runnerOptions.onBeforeCompile = config.onBeforeCompile\n if (config.onAfterCompile) runnerOptions.onAfterCompile = config.onAfterCompile\n const debouncedRun = createDebouncedRunner(runnerOptions, config.devAutoCompileDelay ?? 500)\n\n debouncedRun()\n\n server.watcher.on('change', (file) => {\n if (filter(file)) {\n debouncedRun()\n }\n })\n },\n hotUpdate({ file }) {\n const { catalogDir } = getResolvedSettings()\n if (file.includes(catalogDir)) {\n const modules = [...this.environment.moduleGraph.urlToModuleMap.entries()]\n .filter(([url]) => url.includes('virtual:fluenti'))\n .map(([, mod]) => mod)\n\n if (modules.length > 0) {\n return modules\n }\n }\n return undefined\n },\n }\n\n // Plugin order matters:\n // 1. virtualPlugin — resolves virtual:fluenti/* module IDs (must be first)\n // 2. frameworkPlugins — framework-specific template transforms (e.g., Vue v-t directive)\n // must run after virtual resolution but before script transforms\n // 3. scriptTransformPlugin — t()/t`` scope transforms + <Trans> optimization (enforce: 'pre')\n // 4. buildCompilePlugin — triggers extract+compile before the build starts\n // 5. buildSplitPlugin — rewrites t() calls to catalog refs (dynamic/static)\n // 6. devPlugin — file watcher + HMR for dev mode (must be last)\n return [virtualPlugin, ...frameworkPlugins, scriptTransformPlugin, buildCompilePlugin, buildSplitPlugin, devPlugin]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/mode-detect.ts","../src/dev-runner.ts","../src/build-transform.ts","../src/virtual-modules.ts","../src/index.ts"],"sourcesContent":["/**\n * Detect whether Vite is running in build or dev mode.\n * Supports Vite 7 (configResolved) and Vite 8+ (environment API).\n */\n\nlet resolvedMode: 'build' | 'dev' = 'dev'\n\n/** Called from configResolved hook to capture the mode early */\nexport function setResolvedMode(command: string): void {\n resolvedMode = command === 'build' ? 'build' : 'dev'\n}\n\n/** Get the current resolved mode */\nexport function getResolvedMode(): 'build' | 'dev' {\n return resolvedMode\n}\n\n/**\n * Safely extract the environment object from a Vite plugin context.\n * Handles Vite 8+ environment API without direct `(this as any)` casts at call sites.\n */\nexport function getPluginEnvironment(pluginContext: unknown): { mode?: string } | undefined {\n if (\n typeof pluginContext === 'object' &&\n pluginContext !== null &&\n 'environment' in pluginContext\n ) {\n const env = (pluginContext as Record<string, unknown>)['environment']\n if (typeof env === 'object' && env !== null) {\n return env as { mode?: string }\n }\n }\n return undefined\n}\n\n/**\n * Check if we're in build mode.\n * Tries environment API (Vite 8+), then falls back to configResolved capture,\n * then falls back to NODE_ENV.\n */\nexport function isBuildMode(environment?: { mode?: string }): boolean {\n // Vite 8+: environment.mode === 'build'\n if (environment?.mode === 'build') return true\n\n // Vite 7: captured from configResolved\n if (resolvedMode === 'build') return true\n\n // Last resort: NODE_ENV\n if (process.env['NODE_ENV'] === 'production') return true\n\n return false\n}\n","import { join, resolve } from 'node:path'\nimport { createRequire } from 'node:module'\nimport { mkdirSync } from 'node:fs'\n\nexport interface DevRunnerOptions {\n cwd: string\n onSuccess?: () => void\n onError?: (err: Error) => void\n /** If true, reject the promise on failure instead of swallowing the error */\n throwOnError?: boolean\n /** Run only compile (skip extract). Useful for production builds where source is unchanged. */\n compileOnly?: boolean\n /** Enable parallel compilation across locales using worker threads */\n parallelCompile?: boolean\n /** Called before compile runs. Return false to skip compilation. */\n onBeforeCompile?: () => boolean | void | Promise<boolean | void>\n /** Called after compile completes successfully */\n onAfterCompile?: () => void | Promise<void>\n}\n\n/**\n * Run compile in-process via `@fluenti/cli`.\n *\n * In `compileOnly` mode, only compilation is performed (extract is skipped).\n * In dev mode, both extract and compile run in sequence.\n *\n * If `@fluenti/cli` is not installed, shows an install guide instead of\n * falling back to shell-out — keeping the process boundary clean.\n */\nexport async function runExtractCompile(options: DevRunnerOptions): Promise<void> {\n // Ensure compileOutDir exists on first run (auto-init for zero-config DX)\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { DEFAULT_FLUENTI_CONFIG, loadConfigSync } = projectRequire('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: { compileOutDir: string; catalogDir: string }\n loadConfigSync: (path?: string, cwd?: string) => { compileOutDir: string; catalogDir: string }\n }\n let config: { compileOutDir: string; catalogDir: string }\n try {\n config = loadConfigSync(undefined, options.cwd)\n } catch {\n config = DEFAULT_FLUENTI_CONFIG\n }\n mkdirSync(resolve(options.cwd, config.compileOutDir), { recursive: true })\n mkdirSync(resolve(options.cwd, config.catalogDir), { recursive: true })\n } catch {\n // Non-critical — directories may already exist or config may not be available\n }\n\n if (options.onBeforeCompile) {\n const result = await options.onBeforeCompile()\n if (result === false) return\n }\n\n if (options.compileOnly) {\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runCompile } = projectRequire('@fluenti/cli')\n await runCompile(options.cwd)\n console.log('[fluenti] Compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n if (options.throwOnError) throw error\n console.warn('[fluenti] Compile failed:', error.message)\n options.onError?.(error)\n return\n }\n }\n\n // Dev mode: in-process extract + compile\n try {\n const projectRequire = createRequire(join(options.cwd, 'package.json'))\n const { runExtract, runCompile } = projectRequire('@fluenti/cli')\n await runExtract(options.cwd)\n await runCompile(options.cwd, { parallel: options.parallelCompile })\n console.log('[fluenti] Extracting and compiling... done')\n if (options.onAfterCompile) await options.onAfterCompile()\n options.onSuccess?.()\n return\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e))\n const isNotInstalled = error.message.includes('Cannot find module')\n\n if (isNotInstalled) {\n const msg =\n '[fluenti] @fluenti/cli is required for auto-compile.\\n' +\n ' Install it as a devDependency:\\n' +\n ' pnpm add -D @fluenti/cli\\n' +\n ' See: https://fluenti.dev/start/introduction/'\n if (options.throwOnError) throw new Error(msg)\n console.warn(msg)\n options.onError?.(new Error(msg))\n return\n }\n\n if (options.throwOnError) throw error\n console.warn('[fluenti] Extract/compile failed:', error.message)\n options.onError?.(error)\n }\n}\n\n/**\n * Create a debounced runner that collapses rapid calls.\n *\n * - If called while idle, schedules a run after `delay` ms.\n * - If called while a run is in progress, marks a pending rerun.\n * - Never runs concurrently.\n */\nexport function createDebouncedRunner(\n options: DevRunnerOptions,\n delay = 300,\n): () => void {\n let timer: ReturnType<typeof setTimeout> | null = null\n let running = false\n let pendingRerun = false\n\n async function execute(): Promise<void> {\n running = true\n try {\n await runExtractCompile(options)\n } finally {\n running = false\n if (pendingRerun) {\n pendingRerun = false\n schedule()\n }\n }\n }\n\n function schedule(): void {\n if (timer !== null) {\n clearTimeout(timer)\n }\n timer = setTimeout(() => {\n timer = null\n if (running) {\n pendingRerun = true\n } else {\n execute()\n }\n }, delay)\n }\n\n return schedule\n}\n","/**\n * Build-mode transform for code-splitting.\n *\n * Strategy 'dynamic': rewrites supported translation calls to __catalog._<hash> references.\n * Strategy 'static': rewrites to direct named imports from compiled locale modules.\n */\n\nimport { hashMessage as defaultHashMessage } from '@fluenti/core/internal'\nimport { parseSourceModule, walkSourceAst, type SourceNode } from '@fluenti/core/transform'\n\nexport type HashFunction = (message: string, context?: string) => string\n\nexport interface BuildTransformResult {\n code: string\n needsCatalogImport: boolean\n usedHashes: Set<string>\n}\n\nexport interface BuildTransformOptions {\n /** Custom hash function for message IDs (defaults to @fluenti/core hashMessage) */\n hashFn?: HashFunction\n}\n\ntype SplitStrategy = 'dynamic' | 'static'\n\ninterface IdentifierNode extends SourceNode {\n type: 'Identifier'\n name: string\n}\n\ninterface StringLiteralNode extends SourceNode {\n type: 'StringLiteral'\n value: string\n}\n\ninterface NumericLiteralNode extends SourceNode {\n type: 'NumericLiteral'\n value: number\n}\n\ninterface TemplateElementNode extends SourceNode {\n type: 'TemplateElement'\n value: { cooked: string | null; raw: string }\n}\n\ninterface TemplateLiteralNode extends SourceNode {\n type: 'TemplateLiteral'\n expressions: SourceNode[]\n quasis: TemplateElementNode[]\n}\n\ninterface ImportDeclarationNode extends SourceNode {\n type: 'ImportDeclaration'\n source: StringLiteralNode\n specifiers: SourceNode[]\n}\n\ninterface ImportSpecifierNode extends SourceNode {\n type: 'ImportSpecifier'\n imported: IdentifierNode | StringLiteralNode\n local: IdentifierNode\n}\n\ninterface CallExpressionNode extends SourceNode {\n type: 'CallExpression'\n callee: SourceNode\n arguments: SourceNode[]\n}\n\ninterface AwaitExpressionNode extends SourceNode {\n type: 'AwaitExpression'\n argument: SourceNode\n}\n\ninterface VariableDeclaratorNode extends SourceNode {\n type: 'VariableDeclarator'\n id: SourceNode\n init?: SourceNode | null\n}\n\ninterface ProgramNode extends SourceNode {\n type: 'Program'\n body: SourceNode[]\n}\n\ninterface ObjectExpressionNode extends SourceNode {\n type: 'ObjectExpression'\n properties: SourceNode[]\n}\n\ninterface ObjectPropertyNode extends SourceNode {\n type: 'ObjectProperty'\n key: SourceNode\n value: SourceNode\n computed?: boolean\n}\n\ninterface ObjectPatternNode extends SourceNode {\n type: 'ObjectPattern'\n properties: SourceNode[]\n}\n\ninterface MemberExpressionNode extends SourceNode {\n type: 'MemberExpression'\n object: SourceNode\n property: SourceNode\n computed?: boolean\n}\n\ninterface JSXElementNode extends SourceNode {\n type: 'JSXElement'\n openingElement: JSXOpeningElementNode\n}\n\ninterface JSXOpeningElementNode extends SourceNode {\n type: 'JSXOpeningElement'\n name: SourceNode\n attributes: SourceNode[]\n}\n\ninterface JSXIdentifierNode extends SourceNode {\n type: 'JSXIdentifier'\n name: string\n}\n\ninterface JSXAttributeNode extends SourceNode {\n type: 'JSXAttribute'\n name: JSXIdentifierNode\n value?: SourceNode | null\n}\n\ninterface JSXExpressionContainerNode extends SourceNode {\n type: 'JSXExpressionContainer'\n expression: SourceNode\n}\n\ninterface SplitReplacement {\n start: number\n end: number\n replacement: string\n}\n\ninterface SplitTarget {\n catalogId: string\n valuesSource?: string\n}\n\ninterface RuntimeBindings {\n tracked: Set<string>\n unref: Set<string>\n}\n\nexport function transformForDynamicSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'dynamic', options)\n}\n\nexport function transformForStaticSplit(code: string, options?: BuildTransformOptions): BuildTransformResult {\n return transformForSplitStrategy(code, 'static', options)\n}\n\nfunction transformForSplitStrategy(\n code: string,\n strategy: SplitStrategy,\n options?: BuildTransformOptions,\n): BuildTransformResult {\n const hashFn = options?.hashFn ?? defaultHashMessage\n const ast = parseSourceModule(code)\n if (!ast || ast.type !== 'Program') {\n return { code, needsCatalogImport: false, usedHashes: new Set() }\n }\n\n const bindings = collectTrackedRuntimeBindings(ast as ProgramNode)\n const replacements: SplitReplacement[] = []\n const usedHashes = new Set<string>()\n\n walkSourceAst(ast, (node) => {\n const replacement = extractCallReplacement(code, node, bindings, strategy, usedHashes, hashFn)\n if (replacement) {\n replacements.push(replacement)\n return\n }\n\n collectComponentUsage(node, usedHashes, hashFn)\n })\n\n if (replacements.length === 0) {\n return { code, needsCatalogImport: false, usedHashes }\n }\n\n let result = code\n for (let i = replacements.length - 1; i >= 0; i--) {\n const { start, end, replacement } = replacements[i]!\n result = result.slice(0, start) + replacement + result.slice(end)\n }\n\n return { code: result, needsCatalogImport: true, usedHashes }\n}\n\nfunction collectTrackedRuntimeBindings(program: ProgramNode): RuntimeBindings {\n const tracked = new Set<string>()\n const useI18nBindings = new Set<string>()\n const getI18nBindings = new Set<string>()\n const unrefBindings = new Set<string>()\n\n for (const statement of program.body) {\n if (!isImportDeclaration(statement)) continue\n for (const specifier of statement.specifiers) {\n if (!isImportSpecifier(specifier)) continue\n const importedName = readImportedName(specifier)\n if (!importedName) continue\n if (importedName === 'useI18n') {\n useI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'getI18n') {\n getI18nBindings.add(specifier.local.name)\n }\n if (importedName === 'unref') {\n unrefBindings.add(specifier.local.name)\n }\n }\n }\n\n walkSourceAst(program, (node) => {\n if (!isVariableDeclarator(node) || !node.init || !isObjectPattern(node.id)) return\n\n if (isCallExpression(node.init) && isIdentifier(node.init.callee) && useI18nBindings.has(node.init.callee.name)) {\n addTrackedObjectPatternBindings(node.id, tracked)\n return\n }\n\n const awaitedCall = node.init.type === 'AwaitExpression'\n ? (node.init as AwaitExpressionNode).argument\n : null\n\n if (\n awaitedCall\n && isCallExpression(awaitedCall)\n && isIdentifier(awaitedCall.callee)\n && getI18nBindings.has(awaitedCall.callee.name)\n ) {\n addTrackedObjectPatternBindings(node.id, tracked)\n }\n })\n\n return { tracked, unref: unrefBindings }\n}\n\nfunction addTrackedObjectPatternBindings(pattern: ObjectPatternNode, tracked: Set<string>): void {\n for (const property of pattern.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n if (!isIdentifier(property.key) || property.key.name !== 't') continue\n if (isIdentifier(property.value)) {\n tracked.add(property.value.name)\n }\n }\n}\n\nfunction extractCallReplacement(\n code: string,\n node: SourceNode,\n bindings: RuntimeBindings,\n strategy: SplitStrategy,\n usedHashes: Set<string>,\n hashFn: HashFunction,\n): SplitReplacement | undefined {\n if (!isCallExpression(node) || node.start == null || node.end == null) {\n return undefined\n }\n\n const splitTarget = resolveSplitTarget(code, node, bindings, hashFn)\n if (!splitTarget) {\n return undefined\n }\n\n const { catalogId } = splitTarget\n usedHashes.add(catalogId)\n const exportHash = hashFn(catalogId)\n const replacementTarget = strategy === 'dynamic'\n ? `__catalog[${JSON.stringify(catalogId)}]`\n : `_${exportHash}`\n const replacement = splitTarget.valuesSource\n ? `${replacementTarget}(${splitTarget.valuesSource})`\n : replacementTarget\n\n return {\n start: node.start,\n end: node.end,\n replacement,\n }\n}\n\nfunction resolveSplitTarget(\n code: string,\n call: CallExpressionNode,\n bindings: RuntimeBindings,\n hashFn: HashFunction,\n): SplitTarget | undefined {\n if (call.arguments.length === 0) return undefined\n\n const callee = call.callee\n const isTrackedIdentifierCall = isIdentifier(callee) && (bindings.tracked.has(callee.name) || callee.name === '$t')\n const isTemplateMemberCall = isMemberExpression(callee)\n && !callee.computed\n && isIdentifier(callee.property)\n && (\n callee.property.name === '$t'\n || (\n callee.property.name === 't'\n && isIdentifier(callee.object)\n && (callee.object.name === '_ctx' || callee.object.name === '$setup')\n )\n )\n const isVueUnrefCall = isCallExpression(callee)\n && isIdentifier(callee.callee)\n && bindings.unref.has(callee.callee.name)\n && callee.arguments.length === 1\n && isIdentifier(callee.arguments[0])\n && bindings.tracked.has(callee.arguments[0].name)\n\n if (!isTrackedIdentifierCall && !isTemplateMemberCall && !isVueUnrefCall) {\n return undefined\n }\n\n const catalogId = extractCatalogId(call.arguments[0]!, hashFn)\n if (!catalogId) return undefined\n\n const valuesSource = call.arguments[1] && call.arguments[1]!.start != null && call.arguments[1]!.end != null\n ? code.slice(call.arguments[1]!.start, call.arguments[1]!.end)\n : undefined\n\n return valuesSource === undefined\n ? { catalogId }\n : { catalogId, valuesSource }\n}\n\nfunction extractCatalogId(argument: SourceNode, hashFn: HashFunction): string | undefined {\n const staticString = readStaticString(argument)\n if (staticString !== undefined) {\n return hashFn(staticString)\n }\n\n if (!isObjectExpression(argument)) {\n return undefined\n }\n\n let id: string | undefined\n let message: string | undefined\n let context: string | undefined\n\n for (const property of argument.properties) {\n if (!isObjectProperty(property) || property.computed) continue\n const key = readPropertyKey(property.key)\n if (!key) continue\n\n const value = readStaticString(property.value)\n if (value === undefined) continue\n\n if (key === 'id') id = value\n if (key === 'message') message = value\n if (key === 'context') context = value\n }\n\n if (id) return id\n if (message) return hashFn(message, context)\n return undefined\n}\n\nfunction collectComponentUsage(node: SourceNode, usedHashes: Set<string>, hashFn: HashFunction): void {\n if (!isJsxElement(node)) return\n\n const componentName = readJsxName(node.openingElement.name)\n if (!componentName) return\n\n if (componentName === 'Trans') {\n const id = readJsxStaticAttribute(node.openingElement, '__id') ?? readJsxStaticAttribute(node.openingElement, 'id')\n if (id) {\n usedHashes.add(id)\n return\n }\n\n const message = readJsxStaticAttribute(node.openingElement, '__message')\n const context = readJsxStaticAttribute(node.openingElement, 'context')\n if (message) {\n usedHashes.add(hashFn(message, context))\n }\n return\n }\n\n if (componentName === 'Plural') {\n const messageId = buildPluralMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n return\n }\n\n if (componentName === 'Select') {\n const messageId = buildSelectMessageId(node.openingElement, hashFn)\n if (messageId) {\n usedHashes.add(messageId)\n }\n }\n}\n\nfunction buildPluralMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const offsetRaw = readJsxStaticNumber(openingElement, 'offset')\n const forms = [\n readJsxStaticAttribute(openingElement, 'zero') === undefined ? undefined : `=0 {${readJsxStaticAttribute(openingElement, 'zero')}}`,\n readJsxStaticAttribute(openingElement, 'one') === undefined ? undefined : `one {${readJsxStaticAttribute(openingElement, 'one')}}`,\n readJsxStaticAttribute(openingElement, 'two') === undefined ? undefined : `two {${readJsxStaticAttribute(openingElement, 'two')}}`,\n readJsxStaticAttribute(openingElement, 'few') === undefined ? undefined : `few {${readJsxStaticAttribute(openingElement, 'few')}}`,\n readJsxStaticAttribute(openingElement, 'many') === undefined ? undefined : `many {${readJsxStaticAttribute(openingElement, 'many')}}`,\n readJsxStaticAttribute(openingElement, 'other') === undefined ? undefined : `other {${readJsxStaticAttribute(openingElement, 'other')}}`,\n ].filter(Boolean)\n\n if (forms.length === 0) return undefined\n\n const offsetPart = typeof offsetRaw === 'number' ? ` offset:${offsetRaw}` : ''\n const icuMessage = `{count, plural,${offsetPart} ${forms.join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction buildSelectMessageId(openingElement: JSXOpeningElementNode, hashFn: HashFunction): string | undefined {\n const id = readJsxStaticAttribute(openingElement, 'id')\n if (id) return id\n\n const context = readJsxStaticAttribute(openingElement, 'context')\n const forms = readStaticSelectForms(openingElement)\n if (!forms || forms['other'] === undefined) return undefined\n\n const orderedKeys = [...Object.keys(forms).filter((key) => key !== 'other').sort(), 'other']\n const icuMessage = `{value, select, ${orderedKeys.map((key) => `${key} {${forms[key]!}}`).join(' ')}}`\n return hashFn(icuMessage, context)\n}\n\nfunction readStaticSelectForms(openingElement: JSXOpeningElementNode): Record<string, string> | undefined {\n const optionForms = readJsxStaticObject(openingElement, 'options')\n if (optionForms) {\n const other = readJsxStaticAttribute(openingElement, 'other')\n return {\n ...optionForms,\n ...(other !== undefined ? { other } : {}),\n }\n }\n\n const forms: Record<string, string> = {}\n for (const attribute of openingElement.attributes) {\n if (!isJsxAttribute(attribute)) continue\n const name = attribute.name.name\n if (['value', 'id', 'context', 'comment', 'options'].includes(name)) continue\n const value = readJsxAttributeValue(attribute)\n if (value !== undefined) {\n forms[name] = value\n }\n }\n\n return Object.keys(forms).length > 0 ? forms : undefined\n}\n\nfunction readStaticSelectObjectValue(node: SourceNode): Record<string, string> | undefined {\n if (!isObjectExpression(node)) return undefined\n const values: Record<string, string> = {}\n\n for (const property of node.properties) {\n if (!isObjectProperty(property) || property.computed) return undefined\n const key = readPropertyKey(property.key)\n const value = readStaticString(property.value)\n if (!key || value === undefined) return undefined\n values[key] = value\n }\n\n return values\n}\n\nfunction readJsxStaticObject(openingElement: JSXOpeningElementNode, name: string): Record<string, string> | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value) return undefined\n if (attribute.value.type !== 'JSXExpressionContainer') return undefined\n return readStaticSelectObjectValue((attribute.value as JSXExpressionContainerNode).expression)\n}\n\nfunction readJsxStaticAttribute(openingElement: JSXOpeningElementNode, name: string): string | undefined {\n return readJsxAttributeValue(findJsxAttribute(openingElement, name))\n}\n\nfunction readJsxStaticNumber(openingElement: JSXOpeningElementNode, name: string): number | undefined {\n const attribute = findJsxAttribute(openingElement, name)\n if (!attribute?.value || attribute.value.type !== 'JSXExpressionContainer') return undefined\n const expression = (attribute.value as JSXExpressionContainerNode).expression\n return expression.type === 'NumericLiteral' ? (expression as NumericLiteralNode).value : undefined\n}\n\nfunction findJsxAttribute(openingElement: JSXOpeningElementNode, name: string): JSXAttributeNode | undefined {\n return openingElement.attributes.find((attribute) => {\n return isJsxAttribute(attribute) && attribute.name.name === name\n }) as JSXAttributeNode | undefined\n}\n\nfunction readJsxAttributeValue(attribute: JSXAttributeNode | undefined): string | undefined {\n if (!attribute?.value) return undefined\n\n if (attribute.value.type === 'StringLiteral') {\n return (attribute.value as StringLiteralNode).value\n }\n\n if (attribute.value.type === 'JSXExpressionContainer') {\n return readStaticString((attribute.value as JSXExpressionContainerNode).expression)\n }\n\n return undefined\n}\n\nfunction readJsxName(node: SourceNode): string | undefined {\n return node.type === 'JSXIdentifier' ? (node as JSXIdentifierNode).name : undefined\n}\n\nfunction readStaticString(node: SourceNode): string | undefined {\n if (node.type === 'StringLiteral') {\n return (node as StringLiteralNode).value\n }\n\n if (node.type === 'TemplateLiteral') {\n const template = node as TemplateLiteralNode\n if (template.expressions.length === 0 && template.quasis.length === 1) {\n return template.quasis[0]!.value.cooked ?? template.quasis[0]!.value.raw\n }\n }\n\n return undefined\n}\n\nfunction readPropertyKey(node: SourceNode): string | undefined {\n if (isIdentifier(node)) return node.name\n if (node.type === 'StringLiteral') return (node as StringLiteralNode).value\n return undefined\n}\n\nfunction isImportDeclaration(node: SourceNode): node is ImportDeclarationNode {\n return node.type === 'ImportDeclaration'\n}\n\nfunction isImportSpecifier(node: SourceNode): node is ImportSpecifierNode {\n return node.type === 'ImportSpecifier'\n}\n\nfunction isVariableDeclarator(node: SourceNode): node is VariableDeclaratorNode {\n return node.type === 'VariableDeclarator'\n}\n\nfunction isObjectPattern(node: SourceNode): node is ObjectPatternNode {\n return node.type === 'ObjectPattern'\n}\n\nfunction isObjectExpression(node: SourceNode): node is ObjectExpressionNode {\n return node.type === 'ObjectExpression'\n}\n\nfunction isObjectProperty(node: SourceNode): node is ObjectPropertyNode {\n return node.type === 'ObjectProperty'\n}\n\nfunction isCallExpression(node: SourceNode): node is CallExpressionNode {\n return node.type === 'CallExpression'\n}\n\nfunction isMemberExpression(node: SourceNode): node is MemberExpressionNode {\n return node.type === 'MemberExpression'\n}\n\nfunction isIdentifier(node: SourceNode | undefined | null): node is IdentifierNode {\n return node?.type === 'Identifier'\n}\n\nfunction isJsxElement(node: SourceNode): node is JSXElementNode {\n return node.type === 'JSXElement'\n}\n\nfunction isJsxAttribute(node: SourceNode): node is JSXAttributeNode {\n return node.type === 'JSXAttribute'\n}\n\nfunction readImportedName(specifier: ImportSpecifierNode): string | undefined {\n const imported = specifier.imported\n if (imported.type === 'Identifier') return imported.name\n if (imported.type === 'StringLiteral') return imported.value\n return undefined\n}\n\n/**\n * Inject the catalog import statement at the top of the module.\n */\nexport function injectCatalogImport(code: string, strategy: 'dynamic' | 'static', hashes: Set<string>, hashFn?: HashFunction): string {\n if (strategy === 'dynamic') {\n return `import { __catalog } from 'virtual:fluenti/runtime';\\n${code}`\n }\n\n // Static: import named exports directly\n const hash = hashFn ?? defaultHashMessage\n const imports = [...hashes].map((id) => `_${hash(id)}`).join(', ')\n return `import { ${imports} } from 'virtual:fluenti/messages';\\n${code}`\n}\n","/**\n * Virtual module resolution for code-splitting mode.\n *\n * Provides:\n * - virtual:fluenti/runtime → reactive catalog + switchLocale + preloadLocale\n * - virtual:fluenti/messages → re-export from static locale (for static strategy)\n */\n\nimport { resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { validateLocale } from '@fluenti/core'\nimport type { RuntimeGenerator, RuntimeGeneratorOptions } from './types'\n\n/**\n * Escapes a string value for safe embedding in generated JavaScript code.\n * Returns a JSON-encoded string (with double quotes), preventing injection\n * of quotes, backticks, template interpolation, and other special characters.\n */\nfunction safeStringLiteral(value: string): string {\n return JSON.stringify(value)\n}\n\n/**\n * Validates that a catalog directory path does not contain characters\n * that could enable code injection in generated template literals.\n */\nfunction validateCatalogDir(catalogDir: string): void {\n if (catalogDir.includes('`') || catalogDir.includes('$')) {\n throw new Error(\n `[fluenti] vite-plugin: catalogDir must not contain backticks or $ characters, got ${JSON.stringify(catalogDir)}`,\n )\n }\n}\n\nconst VIRTUAL_RUNTIME = 'virtual:fluenti/runtime'\nconst VIRTUAL_MESSAGES = 'virtual:fluenti/messages'\nconst RESOLVED_RUNTIME = '\\0virtual:fluenti/runtime'\nconst RESOLVED_MESSAGES = '\\0virtual:fluenti/messages'\n\nexport interface VirtualModuleOptions {\n rootDir: string\n catalogDir: string\n catalogExtension: string\n locales: string[]\n sourceLocale: string\n defaultBuildLocale: string\n framework: string\n runtimeGenerator?: RuntimeGenerator | undefined\n}\n\nexport function resolveVirtualSplitId(id: string): string | undefined {\n if (id === VIRTUAL_RUNTIME) return RESOLVED_RUNTIME\n if (id === VIRTUAL_MESSAGES) return RESOLVED_MESSAGES\n return undefined\n}\n\nexport function loadVirtualSplitModule(\n id: string,\n options: VirtualModuleOptions,\n): string | undefined {\n if (id === RESOLVED_RUNTIME) {\n return generateRuntimeModule(options)\n }\n if (id === RESOLVED_MESSAGES) {\n return generateStaticMessagesModule(options)\n }\n return undefined\n}\n\nfunction generateRuntimeModule(options: VirtualModuleOptions): string {\n const { locales, runtimeGenerator, catalogDir } = options\n validateCatalogDir(catalogDir)\n for (const locale of locales) {\n validateLocale(locale, 'vite-plugin')\n }\n\n if (!runtimeGenerator) {\n throw new Error('[fluenti] vite-plugin: runtimeGenerator is required. Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).')\n }\n\n return runtimeGenerator.generateRuntime(toRuntimeGeneratorOptions(options))\n}\n\nfunction generateStaticMessagesModule(options: VirtualModuleOptions): string {\n const { rootDir, catalogDir, catalogExtension, defaultBuildLocale, sourceLocale } = options\n const defaultLocale = defaultBuildLocale || sourceLocale\n validateLocale(defaultLocale, 'vite-plugin')\n validateCatalogDir(catalogDir)\n const absoluteCatalogDir = resolve(rootDir, catalogDir)\n const catalogFile = resolve(absoluteCatalogDir, defaultLocale + catalogExtension)\n\n if (!existsSync(catalogFile)) {\n console.warn(\n `[fluenti] Compiled catalog for locale \"${defaultLocale}\" not found at ${catalogFile}. Run \"fluenti compile\" first.`,\n )\n }\n\n return `export * from ${safeStringLiteral(catalogFile)}\\n`\n}\n\nfunction toRuntimeGeneratorOptions(options: VirtualModuleOptions): RuntimeGeneratorOptions {\n const { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale } = options\n return { rootDir, catalogDir, catalogExtension, locales, sourceLocale, defaultBuildLocale }\n}\n","import type { Plugin } from 'vite'\nimport { createFilter } from 'vite'\nimport type { FluentiCoreOptions, RuntimeGenerator } from './types'\nimport type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\nimport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\nimport { createRequire } from 'node:module'\n\nconst _require = createRequire(\n typeof __filename !== 'undefined' ? __filename : import.meta.url,\n)\nimport { createDebouncedRunner, runExtractCompile } from './dev-runner'\nimport { transformForDynamicSplit, transformForStaticSplit, injectCatalogImport } from './build-transform'\nimport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nimport { createTransformPipeline, hasScopeTransformCandidate } from '@fluenti/core/transform'\nexport type { FluentiPluginOptions, FluentiCoreOptions, RuntimeGenerator, RuntimeGeneratorOptions, IdGenerator } from './types'\nexport { createRuntimeGenerator } from './runtime-template'\nexport type { RuntimePrimitives } from './runtime-template'\nexport { resolveVirtualSplitId, loadVirtualSplitModule } from './virtual-modules'\nexport { setResolvedMode, isBuildMode, getPluginEnvironment } from './mode-detect'\n\nconst VIRTUAL_PREFIX = 'virtual:fluenti/messages/'\nconst RESOLVED_PREFIX = '\\0virtual:fluenti/messages/'\n\n/**\n * Resolve a config option (string path, inline object, or undefined) into a full FluentiBuildConfig.\n */\nfunction resolvePluginConfig(configOption?: string | FluentiBuildConfig, cwd?: string): FluentiBuildConfig {\n if (typeof configOption === 'object') {\n // Inline config — merge with defaults\n const { DEFAULT_FLUENTI_CONFIG } = _require('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: FluentiBuildConfig\n }\n return { ...DEFAULT_FLUENTI_CONFIG, ...configOption }\n }\n // string → specified path; undefined → auto-discover\n const { loadConfigSync: loadSync } = _require('@fluenti/core/config') as {\n loadConfigSync: (configPath?: string, cwd?: string) => FluentiBuildConfig\n }\n return loadSync(\n typeof configOption === 'string' ? configOption : undefined,\n cwd,\n )\n}\n\n// ─── Public factory for framework packages ─────────────────────────────────\n\n/**\n * Create the Fluenti plugin pipeline.\n * Framework packages call this with their framework-specific plugins and runtime generator.\n */\nexport function createFluentiPlugins(\n options: FluentiCoreOptions,\n frameworkPlugins: Plugin[],\n runtimeGenerator?: RuntimeGenerator,\n): Plugin[] {\n let fluentiConfig: FluentiBuildConfig | undefined\n let rootDir = process.cwd()\n\n function getConfig(cwd?: string): FluentiBuildConfig {\n const effectiveCwd = cwd ?? rootDir\n if (!fluentiConfig) {\n fluentiConfig = resolvePluginConfig(options.config, effectiveCwd)\n }\n return fluentiConfig\n }\n\n const framework = options.framework\n\n function getResolvedSettings(cwd?: string) {\n const config = getConfig(cwd)\n const catalogDir = config.compileOutDir.replace(/^\\.\\//, '')\n const catalogExtension = config.catalogExtension ?? '.js'\n const rawSplitting = config.splitting ?? false\n if (rawSplitting && rawSplitting !== 'dynamic' && rawSplitting !== 'static') {\n console.warn(`[fluenti] Invalid splitting value \"${rawSplitting}\". Expected 'dynamic', 'static', or false. Falling back to 'dynamic'.`)\n }\n const splitting = rawSplitting === 'static' ? 'static' as const : rawSplitting ? 'dynamic' as const : false as const\n const sourceLocale = config.sourceLocale\n const localeCodes = resolveLocaleCodes(config.locales)\n const defaultBuildLocale = config.defaultBuildLocale ?? sourceLocale\n return {\n config,\n catalogDir,\n catalogExtension,\n splitting,\n sourceLocale,\n localeCodes,\n defaultBuildLocale,\n }\n }\n\n const virtualPlugin: Plugin = {\n name: 'fluenti:virtual',\n configResolved(config) {\n rootDir = config.root\n fluentiConfig = resolvePluginConfig(options.config, rootDir)\n setResolvedMode(config.command)\n },\n resolveId(id) {\n if (id.startsWith(VIRTUAL_PREFIX)) {\n return '\\0' + id\n }\n const { splitting } = getResolvedSettings()\n if (splitting) {\n const resolved = resolveVirtualSplitId(id)\n if (resolved) return resolved\n }\n return undefined\n },\n load(id) {\n const {\n catalogDir,\n catalogExtension,\n splitting,\n localeCodes,\n sourceLocale,\n defaultBuildLocale,\n } = getResolvedSettings()\n if (id.startsWith(RESOLVED_PREFIX)) {\n const locale = id.slice(RESOLVED_PREFIX.length)\n if (!localeCodes.includes(locale)) {\n return undefined\n }\n const catalogPath = `${catalogDir}/${locale}${catalogExtension}`\n return `export { default } from '${catalogPath}'`\n }\n if (splitting) {\n const result = loadVirtualSplitModule(id, {\n rootDir,\n catalogDir,\n catalogExtension,\n locales: localeCodes,\n sourceLocale,\n defaultBuildLocale,\n framework,\n runtimeGenerator,\n })\n if (result) return result\n }\n return undefined\n },\n }\n\n const pipeline = createTransformPipeline({ framework })\n\n const scriptTransformPlugin: Plugin = {\n name: 'fluenti:script-transform',\n enforce: 'pre',\n transform(code, id) {\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n if (id.includes('.vue') && !id.includes('type=script')) return undefined\n\n // Vue .vue files need allowTopLevelImportedT for top-level `import { t }`\n const isVueSfc = framework === 'vue' && id.includes('.vue')\n\n let result = code\n let changed = false\n\n // ── <Trans> compile-time optimization (JSX/TSX only) ──────────────\n if (id.match(/\\.[jt]sx(\\?|$)/) && /<Trans[\\s>]/.test(result)) {\n const transResult = pipeline.transformTrans(result)\n if (transResult.transformed) {\n result = transResult.code\n changed = true\n }\n }\n\n // ── t`` / t() scope-aware transform ────────────────────────────────\n if (hasScopeTransformCandidate(result)) {\n const scoped = pipeline.transformScope(result,\n isVueSfc ? { allowTopLevelImportedT: true } : undefined,\n )\n if (scoped.transformed) {\n return { code: scoped.code, map: null }\n }\n }\n\n return changed ? { code: result, map: null } : undefined\n },\n }\n\n const buildSplitPlugin: Plugin = {\n name: 'fluenti:build-split',\n transform(code, id) {\n const { splitting, config } = getResolvedSettings()\n if (!splitting) return undefined\n if (!isBuildMode(getPluginEnvironment(this))) return undefined\n if (id.includes('node_modules')) return undefined\n if (!id.match(/\\.(vue|tsx|jsx|ts|js)(\\?|$)/)) return undefined\n\n const strategy = splitting === 'static' ? 'static' : 'dynamic'\n const transformOptions = config.idGenerator ? { hashFn: config.idGenerator } : undefined\n const transformed = strategy === 'static'\n ? transformForStaticSplit(code, transformOptions)\n : transformForDynamicSplit(code, transformOptions)\n\n if (!transformed.needsCatalogImport) return undefined\n\n const finalCode = injectCatalogImport(\n transformed.code,\n strategy,\n transformed.usedHashes,\n config.idGenerator,\n )\n return { code: finalCode, map: null }\n },\n }\n\n const buildCompilePlugin: Plugin = {\n name: 'fluenti:build-compile',\n async buildStart() {\n const { config } = getResolvedSettings()\n if (!isBuildMode(getPluginEnvironment(this))) return\n const buildAutoCompile = config.buildAutoCompile ?? true\n if (!buildAutoCompile) return\n if (config.onBeforeCompile) {\n const result = await config.onBeforeCompile()\n if (result === false) return\n }\n await runExtractCompile({ cwd: rootDir, throwOnError: true, compileOnly: true })\n if (config.onAfterCompile) {\n await config.onAfterCompile()\n }\n },\n }\n\n const devPlugin: Plugin = {\n name: 'fluenti:dev',\n configureServer(server) {\n const { config, catalogDir } = getResolvedSettings(server.config.root)\n const devAutoCompile = config.devAutoCompile ?? true\n if (!devAutoCompile) return\n\n const includePatterns = config.include ?? ['src/**/*.{vue,tsx,jsx,ts,js}']\n const excludePatterns = config.exclude ?? []\n\n const filter = createFilter(includePatterns, [\n ...excludePatterns,\n '**/node_modules/**',\n `**/${catalogDir}/**`,\n ])\n\n const runnerOptions: Parameters<typeof createDebouncedRunner>[0] = {\n cwd: server.config.root,\n onSuccess: () => {\n // Existing hotUpdate will pick up catalog changes\n },\n }\n if (config.parallelCompile) runnerOptions.parallelCompile = true\n if (config.onBeforeCompile) runnerOptions.onBeforeCompile = config.onBeforeCompile\n if (config.onAfterCompile) runnerOptions.onAfterCompile = config.onAfterCompile\n const debouncedRun = createDebouncedRunner(runnerOptions, config.devAutoCompileDelay ?? 500)\n\n debouncedRun()\n\n server.watcher.on('change', (file) => {\n if (filter(file)) {\n debouncedRun()\n }\n })\n },\n hotUpdate({ file }) {\n const { catalogDir } = getResolvedSettings()\n if (file.includes(catalogDir)) {\n const modules = [...this.environment.moduleGraph.urlToModuleMap.entries()]\n .filter(([url]) => url.includes('virtual:fluenti'))\n .map(([, mod]) => mod)\n\n if (modules.length > 0) {\n return modules\n }\n }\n return undefined\n },\n }\n\n // Plugin order matters:\n // 1. virtualPlugin — resolves virtual:fluenti/* module IDs (must be first)\n // 2. frameworkPlugins — framework-specific template transforms (e.g., Vue v-t directive)\n // must run after virtual resolution but before script transforms\n // 3. scriptTransformPlugin — t()/t`` scope transforms + <Trans> optimization (enforce: 'pre')\n // 4. buildCompilePlugin — triggers extract+compile before the build starts\n // 5. buildSplitPlugin — rewrites t() calls to catalog refs (dynamic/static)\n // 6. devPlugin — file watcher + HMR for dev mode (must be last)\n return [virtualPlugin, ...frameworkPlugins, scriptTransformPlugin, buildCompilePlugin, buildSplitPlugin, devPlugin]\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluenti/vite-plugin",
|
|
3
|
-
"version": "0.4.0-rc.
|
|
3
|
+
"version": "0.4.0-rc.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vite plugin for Fluenti — build-time transforms, virtual modules, code splitting",
|
|
6
6
|
"homepage": "https://fluenti.dev",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"llms*.txt"
|
|
62
62
|
],
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@fluenti/core": "0.4.0-rc.
|
|
64
|
+
"@fluenti/core": "0.4.0-rc.2"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"vite": "^5 || ^6 || ^8"
|