@fluenti/cli 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/cli.cjs CHANGED
@@ -6,9 +6,10 @@ const e=require(`./extract-cache-BioSaoFo.cjs`),t=require(`./tsx-extractor-B0vFX
6
6
  `)}`}function L(e){let{sourceLocale:t,targetLocale:n,messages:r,glossary:i,context:a}=e,o=JSON.stringify(r,null,2),s=[`You are a professional translator. Translate the following messages from "${t}" to "${n}".`,``,`Rules:`,`1. Output ONLY a valid JSON object with the same keys and translated values.`,`2. Keep ICU MessageFormat placeholders unchanged: {name}, {count, plural, ...}, {val, number}, etc.`,`3. Keep HTML tags unchanged: <b>, <a href="...">, </span>, <br/>, etc.`,`4. Keep numbered rich-text tags unchanged: <0>, </0>, <1/>, etc.`,`5. Do not add any explanation, markdown formatting, or code fences — output raw JSON only.`];if(i&&Object.keys(i).length>0){let e=I(i);e&&s.push(``,e)}return a&&s.push(``,`=== PROJECT CONTEXT ===`,a),s.push(``,`Input (JSON):`,o),s.join(`
7
7
  `)}function R(e){let t=e.indexOf(`{`);if(t===-1)throw Error(`No JSON object found in AI response`);let n=0,r=!1,i=!1;for(let a=t;a<e.length;a++){let o=e[a];if(i){i=!1;continue}if(o===`\\`&&r){i=!0;continue}if(o===`"`&&!i){r=!r;continue}if(!r&&(o===`{`&&n++,o===`}`&&(n--,n===0)))return e.slice(t,a+1)}throw Error(`Unterminated JSON object in AI response`)}function z(e){let t=e.match(/```(?:json)?\s*\n?([\s\S]*?)```/);return t?t[1]:e}function B(e,t){let n=[],r=R(z(e)),i;try{i=JSON.parse(r)}catch{throw Error(`Failed to parse JSON from AI response: ${r.slice(0,200)}`)}if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`AI response is not a valid JSON object`);let a=i,o={},s=new Set(Object.keys(t));for(let[e,r]of Object.entries(a)){if(!s.has(e)){n.push(`Extra key in AI response (ignored): "${e}"`);continue}if(typeof r!=`string`){n.push(`Non-string value for key "${e}" (ignored)`);continue}o[e]=r;let i=t[e],a=ee(i,r);if(!a.valid){let t=[];a.missingPlaceholders.length>0&&t.push(`missing placeholders: ${a.missingPlaceholders.join(`, `)}`),a.extraPlaceholders.length>0&&t.push(`extra placeholders: ${a.extraPlaceholders.join(`, `)}`),a.missingHtmlTags.length>0&&t.push(`missing HTML tags: ${a.missingHtmlTags.join(`, `)}`),a.extraHtmlTags.length>0&&t.push(`extra HTML tags: ${a.extraHtmlTags.join(`, `)}`),a.syntaxErrors.length>0&&t.push(`ICU syntax errors: ${a.syntaxErrors.join(`; `)}`),n.push(`QA issue for "${e}": ${t.join(`; `)}`)}}for(let e of s)e in o||n.push(`Missing translation for key: "${e}"`);return{translations:o,warnings:n}}function V(e){let t={};for(let[n,r]of Object.entries(e))r.obsolete||(!r.translation||r.translation.length===0)&&(t[n]=r.message??n);return t}function H(e,t){let n=Object.keys(e),r=[];for(let i=0;i<n.length;i+=t){let a={};for(let r of n.slice(i,i+t))a[r]=e[r];r.push(a)}return r}async function U(e){let{provider:t,sourceLocale:n,targetLocale:r,catalog:i,batchSize:a,context:o,glossary:s,timeoutMs:c}=e,l=V(i),d=Object.keys(l).length;if(d===0)return{catalog:{...i},translated:0,warnings:[]};u.default.info(` ${d} untranslated messages, translating with ${t}...`);let f={...i},p=H(l,a),m=0,h=[];for(let e=0;e<p.length;e++){let i=p[e],a=Object.keys(i);p.length>1&&u.default.info(` Batch ${e+1}/${p.length} (${a.length} messages)`);try{let{stdout:e}=await se({provider:t,prompt:L({sourceLocale:n,targetLocale:r,messages:i,glossary:s,context:o}),timeoutMs:c}),{translations:l,warnings:d}=B(e,i);for(let e of d)h.push(`[${r}] ${e}`),u.default.warn(` ${e}`);for(let e of a)e in l&&(f[e]={...f[e],translation:l[e]},m++)}catch(t){let n=t instanceof Error?t.message:String(t);h.push(`[${r}] Batch ${e+1} failed: ${n}`),u.default.error(` Batch ${e+1} failed: ${n}`)}}return{catalog:f,translated:m,warnings:h}}var W=(0,f.promisify)(d.execFile),G={"vue-i18n":{name:`vue-i18n`,framework:`Vue`,configPatterns:[`i18n.ts`,`i18n.js`,`i18n/index.ts`,`i18n/index.js`,`src/i18n.ts`,`src/i18n.js`,`src/i18n/index.ts`,`src/plugins/i18n.ts`],localePatterns:[`locales/*.json`,`src/locales/*.json`,`i18n/*.json`,`src/i18n/*.json`,`lang/*.json`,`src/lang/*.json`,`locales/*.yaml`,`locales/*.yml`],sourcePatterns:[`src/**/*.vue`],migrationGuide:`vue/llms-migration.txt`},"nuxt-i18n":{name:`nuxt-i18n`,framework:`Nuxt`,configPatterns:[`nuxt.config.ts`,`nuxt.config.js`,`i18n.config.ts`,`i18n.config.js`],localePatterns:[`locales/*.json`,`lang/*.json`,`i18n/*.json`,`locales/*.yaml`,`locales/*.yml`],sourcePatterns:[`pages/**/*.vue`,`components/**/*.vue`,`layouts/**/*.vue`],migrationGuide:`nuxt/llms-migration.txt`},"react-i18next":{name:`react-i18next`,framework:`React`,configPatterns:[`i18n.ts`,`i18n.js`,`src/i18n.ts`,`src/i18n.js`,`src/i18n/index.ts`,`src/i18n/config.ts`],localePatterns:[`locales/*.json`,`src/locales/*.json`,`public/locales/**/*.json`,`translations/*.json`,`src/translations/*.json`],sourcePatterns:[`src/**/*.tsx`,`src/**/*.jsx`,`src/**/*.ts`],migrationGuide:`react/llms-migration.txt`},"next-intl":{name:`next-intl`,framework:`Next.js`,configPatterns:[`next.config.ts`,`next.config.js`,`next.config.mjs`,`i18n.ts`,`src/i18n.ts`,`i18n/request.ts`,`src/i18n/request.ts`],localePatterns:[`messages/*.json`,`locales/*.json`,`src/messages/*.json`,`src/locales/*.json`],sourcePatterns:[`app/**/*.tsx`,`src/app/**/*.tsx`,`pages/**/*.tsx`,`components/**/*.tsx`],migrationGuide:`next-plugin/llms-migration.txt`},"next-i18next":{name:`next-i18next`,framework:`Next.js`,configPatterns:[`next-i18next.config.js`,`next-i18next.config.mjs`,`next.config.ts`,`next.config.js`],localePatterns:[`public/locales/**/*.json`],sourcePatterns:[`pages/**/*.tsx`,`src/pages/**/*.tsx`,`components/**/*.tsx`,`src/components/**/*.tsx`],migrationGuide:`next-plugin/llms-migration.txt`},lingui:{name:`lingui`,framework:`React`,configPatterns:[`lingui.config.ts`,`lingui.config.js`,`.linguirc`],localePatterns:[`locales/*.po`,`src/locales/*.po`,`locales/*/messages.po`,`src/locales/*/messages.po`],sourcePatterns:[`src/**/*.tsx`,`src/**/*.jsx`,`src/**/*.ts`],migrationGuide:`react/llms-migration.txt`}},K=Object.keys(G);function ce(e){let t=e.toLowerCase().replace(/^@nuxtjs\//,`nuxt-`).replace(/^@/,``);return K.find(e=>e===t)}async function le(e){let t={configFiles:[],localeFiles:[],sampleSources:[],packageJson:void 0},n=(0,a.resolve)(`package.json`);(0,i.existsSync)(n)&&(t.packageJson=(0,i.readFileSync)(n,`utf-8`));for(let n of e.configPatterns){let e=(0,a.resolve)(n);(0,i.existsSync)(e)&&t.configFiles.push({path:n,content:(0,i.readFileSync)(e,`utf-8`)})}let r=await(0,s.default)(e.localePatterns,{absolute:!1});for(let e of r.slice(0,10)){let n=(0,i.readFileSync)((0,a.resolve)(e),`utf-8`);t.localeFiles.push({path:e,content:n.length>5e3?n.slice(0,5e3)+`
8
8
  ... (truncated)`:n})}let o=await(0,s.default)(e.sourcePatterns,{absolute:!1});for(let e of o.slice(0,5)){let n=(0,i.readFileSync)((0,a.resolve)(e),`utf-8`);t.sampleSources.push({path:e,content:n.length>3e3?n.slice(0,3e3)+`
9
- ... (truncated)`:n})}return t}function ue(e){let t=typeof __dirname<`u`?__dirname:(0,a.dirname)((0,o.fileURLToPath)({}.url)),n=[(0,a.resolve)(`node_modules`,`@fluenti`,`cli`,`..`,`..`,e),(0,a.join)(t,`..`,`..`,`..`,e),(0,a.join)(t,`..`,`..`,e)];for(let e of n)if((0,i.existsSync)(e))return(0,i.readFileSync)(e,`utf-8`);return``}function q(e,t,n){let r=[];if(r.push(`You are a migration assistant helping convert a ${e.framework} project from "${e.name}" to Fluenti (@fluenti).`,``,`Your task:`,"1. Generate a `fluenti.config.ts` file based on the existing i18n configuration",`2. Convert each locale/translation file to Fluenti PO format`,`3. List the code changes needed (file by file) to migrate source code from the old API to Fluenti API`,``),n&&r.push(`=== MIGRATION GUIDE ===`,n,``),t.packageJson&&r.push(`=== package.json ===`,t.packageJson,``),t.configFiles.length>0){r.push(`=== EXISTING CONFIG FILES ===`);for(let e of t.configFiles)r.push(`--- ${e.path} ---`,e.content,``)}if(t.localeFiles.length>0){r.push(`=== EXISTING LOCALE FILES ===`);for(let e of t.localeFiles)r.push(`--- ${e.path} ---`,e.content,``)}if(t.sampleSources.length>0){r.push(`=== SAMPLE SOURCE FILES ===`);for(let e of t.sampleSources)r.push(`--- ${e.path} ---`,e.content,``)}return r.push(``,`=== OUTPUT FORMAT ===`,`Respond with the following sections, each starting with the exact header shown:`,``,`### FLUENTI_CONFIG`,"```ts",`// The fluenti.config.ts content`,"```",``,`### LOCALE_FILES`,`For each locale file, output:`,`#### LOCALE: {locale_code}`,"```po",`// The PO file content`,"```",``,`### MIGRATION_STEPS`,`A numbered checklist of specific code changes needed, with before/after examples.`,``,`### INSTALL_COMMANDS`,"```bash",`// The install and uninstall commands`,"```"),r.join(`
10
- `)}async function de(e,t){let n=10*1024*1024;try{if(e===`claude`){let{stdout:e}=await W(`claude`,[`-p`,t],{maxBuffer:n});return e}else{let{stdout:e}=await W(`codex`,[`-p`,t,`--full-auto`],{maxBuffer:n});return e}}catch(t){let n=t;throw n.code===`ENOENT`||n.code===`EPERM`||n.code===`EACCES`?Error(`"${e}" CLI not found or not executable. Please install it first:\n`+(e===`claude`?` npm install -g @anthropic-ai/claude-code`:` npm install -g @openai/codex`)):t}}function fe(e){let t=5e5,n=e.length>t?e.slice(0,t):e,r={config:void 0,localeFiles:[],steps:void 0,installCommands:void 0},i=n.match(/### FLUENTI_CONFIG[\s\S]*?```(?:ts|typescript)?\n([\s\S]*?)```/);i&&(r.config=i[1].trim());let a=n.match(/### LOCALE_FILES([\s\S]*?)(?=### MIGRATION_STEPS|### INSTALL_COMMANDS|$)/);if(a){let e=/#### LOCALE:\s*(\S+)\s*\n```(?:po)?\n([\s\S]*?)```/g,t;for(;(t=e.exec(a[1]))!==null;)r.localeFiles.push({locale:t[1],content:t[2].trim()})}let o=n.match(/### MIGRATION_STEPS\s*\n([\s\S]*?)(?=### INSTALL_COMMANDS|$)/);o&&(r.steps=o[1].trim());let s=n.match(/### INSTALL_COMMANDS[\s\S]*?```(?:bash|sh)?\n([\s\S]*?)```/);return s&&(r.installCommands=s[1].trim()),r}async function pe(e){let{from:t,provider:n,write:r}=e,i=ce(t);if(!i){u.default.error(`Unsupported library "${t}". Supported libraries:`);for(let e of K)u.default.log(` - ${e}`);return}let o=G[i];u.default.info(`Migrating from ${o.name} (${o.framework}) to Fluenti`),u.default.info(`Scanning project for existing i18n files...`);let s=await le(o);if(s.configFiles.length===0&&s.localeFiles.length===0){u.default.warn(`No ${o.name} configuration or locale files found.`),u.default.info(`Make sure you are running this command from the project root directory.`);return}u.default.info(`Found: ${s.configFiles.length} config file(s), ${s.localeFiles.length} locale file(s), ${s.sampleSources.length} source file(s)`);let c=ue(o.migrationGuide);u.default.info(`Generating migration plan with ${n}...`);let l=fe(await de(n,q(o,s,c)));if(l.installCommands&&(u.default.log(``),u.default.box({title:`Install Commands`,message:l.installCommands})),l.config)if(r){let{writeFileSync:e}=await import(`node:fs`),t=(0,a.resolve)(`fluenti.config.ts`);e(t,l.config,`utf-8`),u.default.success(`Written: ${t}`)}else u.default.log(``),u.default.box({title:`fluenti.config.ts`,message:l.config});if(l.localeFiles.length>0)if(r){let{writeFileSync:e,mkdirSync:t}=await import(`node:fs`),n=`./locales`;t((0,a.resolve)(n),{recursive:!0});for(let t of l.localeFiles){let r=(0,a.resolve)(n,`${t.locale}.po`);e(r,t.content,`utf-8`),u.default.success(`Written: ${r}`)}}else for(let e of l.localeFiles)u.default.log(``),u.default.box({title:`locales/${e.locale}.po`,message:e.content.length>500?e.content.slice(0,500)+`
11
- ... (use --write to save full file)`:e.content});l.steps&&(u.default.log(``),u.default.box({title:`Migration Steps`,message:l.steps})),!r&&(l.config||l.localeFiles.length>0)&&(u.default.log(``),u.default.info(`Run with --write to save generated files to disk:`),u.default.log(` fluenti migrate --from ${t} --write`))}var me=/^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{1,8})*$/;function J(e){if(!me.test(e))throw Error(`Invalid locale format: "${e}"`);return e}var he=[{dep:`next`,name:`nextjs`,pluginPackage:`@fluenti/next`},{dep:`nuxt`,name:`nuxt`,pluginPackage:`@fluenti/vue`},{dep:`@solidjs/start`,name:`solidstart`,pluginPackage:`@fluenti/solid`},{dep:`vue`,name:`vue`,pluginPackage:`@fluenti/vue`},{dep:`solid-js`,name:`solid`,pluginPackage:`@fluenti/solid`},{dep:`react`,name:`react`,pluginPackage:`@fluenti/react`}];function ge(e){for(let t of he)if(t.dep in e)return{name:t.name,pluginPackage:t.pluginPackage};return{name:`unknown`,pluginPackage:null}}function _e(e){let t=e.locales.map(e=>JSON.stringify(e)).join(`, `);return`import { defineConfig } from '@fluenti/cli'
9
+ ... (truncated)`:n})}return t}function ue(e){let t=typeof __dirname<`u`?__dirname:(0,a.dirname)((0,o.fileURLToPath)({}.url)),n=[(0,a.resolve)(`node_modules`,`@fluenti`,`cli`,`..`,`..`,e),(0,a.join)(t,`..`,`..`,`..`,e),(0,a.join)(t,`..`,`..`,e)];for(let e of n)if((0,i.existsSync)(e))return(0,i.readFileSync)(e,`utf-8`);return``}function q(e,t,n){let r=[];if(r.push(`You are a migration tool converting a ${e.framework} project from "${e.name}" to Fluenti (@fluenti).`,``,`Tasks:`,"1. Generate a `fluenti.config.ts` based on the existing i18n configuration",`2. Convert each locale/translation file to standard gettext PO format`,`3. Generate unified diff patches for every source file that needs changes`,`4. Generate install/uninstall commands`,``,`=== TRANSLATION API RULES ===`,"Fluenti provides a compile-time `t` tagged template that does NOT require useI18n():",``,` import { t } from '@fluenti/react' // or @fluenti/vue, @fluenti/solid`,` const name = "World"`," t`Hello, ${name}!`",``,"Use `import { t }` for ALL translation calls. Only use `useI18n()` when you need:","- `d()` / `n()` for date/number formatting","- `setLocale()` for locale switching","- `locale` for reading the current locale reactively",``,`=== SOURCE CODE REWRITING RULES ===`,`Imports:`,`- ${e.name}: remove all imports from "${e.name}" (and related packages)`,`- Add: import { t } from '@fluenti/${e.framework===`Vue`?`vue`:e.framework===`Next.js`?`react`:e.framework.toLowerCase()}'`,`- Only add useI18n import if d()/n()/setLocale is needed in that file`,``,`Translation calls:`,"- t('key') t`Source text` (tagged template with the actual source text, not the key)","- t('key', { name }) → t`Hello, ${name}` (interpolate directly in template)","- $t('key') → t`Source text` (Vue template)",`- Remove useI18n()/useTranslation()/useTranslations() destructuring if only t was used`,``,`Components:`,`- <i18n-t keypath="key"> → <Trans>Source text</Trans>`,`- <Trans i18nKey="key"> → <Trans>Source text</Trans>`,``,`ICU syntax conversion:`,`- {{variable}} (double braces) → {variable} (single braces)`,`- _one/_other suffixes → ICU {count, plural, one {...} other {...}}`,`- @:key references → inline the referenced text directly`,`- Pipe-separated plurals → ICU plural`,``,`=== PO FORMAT RULES ===`,`Each PO file must have a standard header:`,` msgid ""`,` msgstr ""`,` "Content-Type: text/plain; charset=UTF-8\\n"`,` "Content-Transfer-Encoding: 8bit\\n"`,` "Language: {locale}\\n"`,``,`Message entries: msgid is the source text (English), msgstr is the translation.`,`Flatten nested JSON keys: "home.title" → use the actual source text as msgid.`,``),n&&r.push(`=== MIGRATION GUIDE ===`,n,``),t.packageJson&&r.push(`=== package.json ===`,t.packageJson,``),t.configFiles.length>0){r.push(`=== EXISTING CONFIG FILES ===`);for(let e of t.configFiles)r.push(`--- ${e.path} ---`,e.content,``)}if(t.localeFiles.length>0){r.push(`=== EXISTING LOCALE FILES ===`);for(let e of t.localeFiles)r.push(`--- ${e.path} ---`,e.content,``)}if(t.sampleSources.length>0){r.push(`=== SAMPLE SOURCE FILES ===`);for(let e of t.sampleSources)r.push(`--- ${e.path} ---`,e.content,``)}return r.push(``,`=== OUTPUT FORMAT ===`,`Output ONLY the following sections. No explanations, no commentary.`,``,`### FLUENTI_CONFIG`,"```ts",`// Complete fluenti.config.ts`,"```",``,`### LOCALE_FILES`,`#### LOCALE: {locale_code}`,"```po",`// Complete PO file with standard header`,"```",`(repeat for each locale)`,``,`### SOURCE_PATCHES`,`#### FILE: {relative_file_path}`,"```diff",`--- a/{file_path}`,`+++ b/{file_path}`,`@@ ... @@`,` context line`,`-removed line`,`+added line`,"```",`(repeat for each file that needs changes)`,``,`### INSTALL_COMMANDS`,"```bash",`// install + uninstall commands`,"```"),r.join(`
10
+ `)}async function de(e,t){let n=10*1024*1024;try{if(e===`claude`){let{stdout:e}=await W(`claude`,[`-p`,t],{maxBuffer:n});return e}else{let{stdout:e}=await W(`codex`,[`-p`,t,`--full-auto`],{maxBuffer:n});return e}}catch(t){let n=t;throw n.code===`ENOENT`||n.code===`EPERM`||n.code===`EACCES`?Error(`"${e}" CLI not found or not executable. Please install it first:\n`+(e===`claude`?` npm install -g @anthropic-ai/claude-code`:` npm install -g @openai/codex`)):t}}function fe(e){let t=5e5,n=e.length>t?e.slice(0,t):e,r={config:void 0,localeFiles:[],sourcePatches:[],steps:void 0,installCommands:void 0},i=n.match(/### FLUENTI_CONFIG[\s\S]*?```(?:ts|typescript)?\n([\s\S]*?)```/);i&&(r.config=i[1].trim());let a=n.match(/### LOCALE_FILES([\s\S]*?)(?=### SOURCE_PATCHES|### MIGRATION_STEPS|### INSTALL_COMMANDS|$)/);if(a){let e=/#### LOCALE:\s*(\S+)\s*\n```(?:po)?\n([\s\S]*?)```/g,t;for(;(t=e.exec(a[1]))!==null;)r.localeFiles.push({locale:t[1],content:t[2].trim()})}let o=n.match(/### SOURCE_PATCHES([\s\S]*?)(?=### INSTALL_COMMANDS|$)/);if(o){let e=/#### FILE:\s*(\S+)\s*\n```(?:diff)?\n([\s\S]*?)```/g,t;for(;(t=e.exec(o[1]))!==null;)r.sourcePatches.push({file:t[1],patch:t[2].trim()})}let s=n.match(/### MIGRATION_STEPS\s*\n([\s\S]*?)(?=### INSTALL_COMMANDS|$)/);s&&(r.steps=s[1].trim());let c=n.match(/### INSTALL_COMMANDS[\s\S]*?```(?:bash|sh)?\n([\s\S]*?)```/);return c&&(r.installCommands=c[1].trim()),r}async function pe(e){let{from:t,provider:n,write:r}=e,i=ce(t);if(!i){u.default.error(`Unsupported library "${t}". Supported libraries:`);for(let e of K)u.default.log(` - ${e}`);return}let o=G[i];u.default.info(`Migrating from ${o.name} (${o.framework}) to Fluenti`),u.default.info(`Scanning project for existing i18n files...`);let s=await le(o);if(s.configFiles.length===0&&s.localeFiles.length===0){u.default.warn(`No ${o.name} configuration or locale files found.`),u.default.info(`Make sure you are running this command from the project root directory.`);return}u.default.info(`Found: ${s.configFiles.length} config file(s), ${s.localeFiles.length} locale file(s), ${s.sampleSources.length} source file(s)`);let c=ue(o.migrationGuide);u.default.info(`Generating migration plan with ${n}...`);let l=fe(await de(n,q(o,s,c)));if(l.installCommands&&(u.default.log(``),u.default.box({title:`Install Commands`,message:l.installCommands})),l.config)if(r){let{writeFileSync:e}=await import(`node:fs`),t=(0,a.resolve)(`fluenti.config.ts`);e(t,l.config,`utf-8`),u.default.success(`Written: ${t}`)}else u.default.log(``),u.default.box({title:`fluenti.config.ts`,message:l.config});if(l.localeFiles.length>0)if(r){let{writeFileSync:e,mkdirSync:t}=await import(`node:fs`),n=`./locales`;t((0,a.resolve)(n),{recursive:!0});for(let t of l.localeFiles){let r=(0,a.resolve)(n,`${t.locale}.po`);e(r,t.content,`utf-8`),u.default.success(`Written: ${r}`)}}else for(let e of l.localeFiles)u.default.log(``),u.default.box({title:`locales/${e.locale}.po`,message:e.content.length>500?e.content.slice(0,500)+`
11
+ ... (use --write to save full file)`:e.content});if(l.sourcePatches.length>0)if(r){u.default.log(``),u.default.info(`Generated ${l.sourcePatches.length} source patch(es). Apply with:`);for(let e of l.sourcePatches){let t=(0,a.resolve)(`.fluenti-migrate-${e.file.replace(/[/\\]/g,`-`)}.patch`),{writeFileSync:n}=await import(`node:fs`);n(t,e.patch,`utf-8`),u.default.success(`Patch written: ${t}`),u.default.log(` patch -p1 < ${t}`)}}else for(let e of l.sourcePatches)u.default.log(``),u.default.box({title:`Patch: ${e.file}`,message:e.patch.length>800?e.patch.slice(0,800)+`
12
+ ... (use --write to save full patch)`:e.patch});l.steps&&l.sourcePatches.length===0&&(u.default.log(``),u.default.box({title:`Migration Steps`,message:l.steps})),!r&&(l.config||l.localeFiles.length>0||l.sourcePatches.length>0)&&(u.default.log(``),u.default.info(`Run with --write to save generated files and patches to disk:`),u.default.log(` fluenti migrate --from ${t} --write`))}var me=/^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{1,8})*$/;function J(e){if(!me.test(e))throw Error(`Invalid locale format: "${e}"`);return e}var he=[{dep:`next`,name:`nextjs`,pluginPackage:`@fluenti/next`},{dep:`nuxt`,name:`nuxt`,pluginPackage:`@fluenti/vue`},{dep:`@solidjs/start`,name:`solidstart`,pluginPackage:`@fluenti/solid`},{dep:`vue`,name:`vue`,pluginPackage:`@fluenti/vue`},{dep:`solid-js`,name:`solid`,pluginPackage:`@fluenti/solid`},{dep:`react`,name:`react`,pluginPackage:`@fluenti/react`}];function ge(e){for(let t of he)if(t.dep in e)return{name:t.name,pluginPackage:t.pluginPackage};return{name:`unknown`,pluginPackage:null}}function _e(e){let t=e.locales.map(e=>JSON.stringify(e)).join(`, `);return`import { defineConfig } from '@fluenti/cli'
12
13
 
13
14
  export default defineConfig({
14
15
  sourceLocale: ${JSON.stringify(e.sourceLocale)},