@intlayer/babel 8.1.7 → 8.1.8

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.
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:fs`),t=require(`node:path`);require(`@babel/generator`);let n=require(`@intlayer/chokidar/cli`),r=require(`@intlayer/core/utils`);const i=(e,n=`comp-`)=>{let r=(0,t.basename)(e,(0,t.extname)(e));return r===`index`&&(r=(0,t.basename)((0,t.dirname)(e))),`${n}${r.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}`},a=n=>{let r=n;for(;;){let n=(0,t.join)(r,`package.json`);if((0,e.existsSync)(n))try{let t=JSON.parse((0,e.readFileSync)(n,`utf-8`));if(t.dependencies?.[`next-intlayer`]||t.devDependencies?.[`next-intlayer`])return`next-intlayer`;if(t.dependencies?.[`react-intlayer`]||t.devDependencies?.[`react-intlayer`])return`react-intlayer`;if(t.dependencies?.[`preact-intlayer`]||t.devDependencies?.[`preact-intlayer`])return`preact-intlayer`}catch{}let i=(0,t.dirname)(r);if(i===r)break;r=i}return`react-intlayer`},o=(e,t)=>{let n=e;for(;t.isParenthesizedExpression(n);)n=n.expression;return n},s=(e,t)=>{let n=e.node;if(!t.isBlockStatement(n.body)){let e=o(n.body,t);return t.isJSXElement(e)||t.isJSXFragment(e)}let r=!1;return e.traverse({Function(e){e.skip()},ReturnStatement(e){if(e.node.argument){let n=o(e.node.argument,t);(t.isJSXElement(n)||t.isJSXFragment(n))&&(r=!0)}}}),r},c=(e,t)=>{let n=e.getFunctionParent();if(!n)return null;let r=n;for(;r;){if(s(r,t))return r;r=r.getFunctionParent()}return n},l=e=>{let{types:o}=e;return{name:`babel-plugin-intlayer-extract`,pre(){this._extractedContent={},this._existingKeys=new Set,this._isIncluded=!0,this._hasJSX=!1,this._hasUseIntlayerImport=!1,this._useIntlayerLocalName=`useIntlayer`,this._hasGetIntlayerImport=!1,this._getIntlayerLocalName=`getIntlayer`,this._contentVarName=`content`,this._isClient=!1,this._hasTopLevelContent=!1;let e=this.file.opts.filename;if(!this.opts.packageName){let n=e?(0,t.dirname)(e):process.cwd();this.opts.packageName=a(n)}if(!(this.opts.enabled??!0)){this._isIncluded=!1;return}if(this.opts.filesList&&e){let t=e.replace(/\\/g,`/`);this._isIncluded=this.opts.filesList.some(e=>e.replace(/\\/g,`/`)===t)}e&&(this._dictionaryKey=i(e,this.opts.prefix))},visitor:{ImportDeclaration(e,t){if(t._isIncluded)for(let n of e.node.specifiers){if(!o.isImportSpecifier(n))continue;let e=o.isIdentifier(n.imported)?n.imported.name:n.imported.value;e===`useIntlayer`&&(t._hasUseIntlayerImport=!0,t._useIntlayerLocalName=n.local.name),e===`getIntlayer`&&(t._hasGetIntlayerImport=!0,t._getIntlayerLocalName=n.local.name)}},JSXElement(e,t){t._isIncluded&&(t._hasJSX=!0)},Program:{enter(e,t){if(!t._isIncluded)return;t._isClient=e.node.directives.some(e=>e.value.value===`use client`);let n=!1;e.traverse({VariableDeclarator(e){o.isIdentifier(e.node.id)&&e.node.id.name===`content`&&(n=!0)}}),t._contentVarName=n?`_compContent`:`content`},exit(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let i=[],a=new Set,l=t.opts.shouldExtract??n.shouldExtract,d=e=>{let n=c(e,o);n?a.add(n):t._hasTopLevelContent=!0};if(e.traverse({JSXText(e){let n=e.node.value;if(l(n)){let a=n.replace(/\s+/g,` `).trim(),o=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===a);o||(o=(0,r.generateKey)(a,t._existingKeys),t._existingKeys.add(o),t._extractedContent[o]=a),i.push({path:e,key:o,isAttribute:!1}),d(e)}},JSXAttribute(e){let a=e.node.name;if(!o.isJSXIdentifier(a))return;let s=a.name===`key`;if(!n.ATTRIBUTES_TO_EXTRACT.includes(a.name)&&!s)return;let c=e.node.value,u=null;if(o.isStringLiteral(c)?u=c.value:o.isJSXExpressionContainer(c)&&o.isStringLiteral(c.expression)&&(u=c.expression.value),u&&l(u)){let n=u.trim(),a=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===n);a||(a=(0,r.generateKey)(n,t._existingKeys),t._existingKeys.add(a),t._extractedContent[a]=n),i.push({path:e,key:a,isAttribute:!0}),d(e)}},StringLiteral(e){let n=e.parentPath;if(n.isJSXAttribute()||n.isImportDeclaration()||n.isExportDeclaration()||n.isImportSpecifier()||n.isObjectProperty()&&e.key===`key`||n.isMemberExpression()&&e.key===`property`)return;if(n.isCallExpression()){let e=n.node.callee;if(o.isMemberExpression(e)&&o.isIdentifier(e.object)&&e.object.name===`console`||o.isIdentifier(e)&&(e.name===t._useIntlayerLocalName||e.name===t._getIntlayerLocalName||e.name===`require`)||e.type===`Import`)return}let a=e.node.value;if(l(a)){let n=a.trim(),o=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===n);o||(o=(0,r.generateKey)(n,t._existingKeys),t._existingKeys.add(o),t._extractedContent[o]=n),i.push({path:e,key:o,isAttribute:!1}),d(e)}}}),i.length===0)return;for(let{path:e,key:n,isAttribute:r}of i){let i=!1,a=!1,l=e.scope.getBinding(t._contentVarName);if(l&&o.isVariableDeclarator(l.path.node)&&o.isCallExpression(l.path.node.init)&&o.isIdentifier(l.path.node.init.callee)&&(l.path.node.init.callee.name===t._useIntlayerLocalName?(i=!0,a=!0):l.path.node.init.callee.name===t._getIntlayerLocalName&&(i=!1,a=!0)),!a){let t=c(e,o);t&&(i=s(t,o))}if(r){let r=o.optionalMemberExpression(o.identifier(t._contentVarName),o.stringLiteral(n),!0,!0);e.node.value=o.jsxExpressionContainer(i?o.optionalMemberExpression(r,o.identifier(`value`),!1,!0):r)}else if(e.isJSXText())e.replaceWith(o.jsxExpressionContainer(o.optionalMemberExpression(o.identifier(t._contentVarName),o.stringLiteral(n),!0,!0)));else{let r=o.optionalMemberExpression(o.identifier(t._contentVarName),o.stringLiteral(n),!0,!0);e.replaceWith(i?o.optionalMemberExpression(r,o.identifier(`value`),!1,!0):r)}}t.opts.onExtract&&t._dictionaryKey&&t.opts.onExtract({dictionaryKey:t._dictionaryKey,filePath:t.file.opts.filename,content:{...t._extractedContent},locale:t.opts.defaultLocale});let f=!1,p=!1;for(let e of a){let n=u(e,t,o);n===`hook`&&(f=!0),n===`core`&&(p=!0)}if(t._hasTopLevelContent){p=!0;let n=t._contentVarName,r=t._dictionaryKey,i=t._getIntlayerLocalName,a=0,s=e.node.body;for(;a<s.length&&(o.isImportDeclaration(s[a])||o.isExpressionStatement(s[a])&&o.isStringLiteral(s[a].expression));)a++;e.node.body.splice(a,0,o.variableDeclaration(`const`,[o.variableDeclarator(o.identifier(n),o.callExpression(o.identifier(i),[o.stringLiteral(r)]))]))}if(f||p){let n=t.opts.packageName??`react-intlayer`;n===`next-intlayer`&&!t._isClient&&(n=`${n}/server`);let r=0,i=e.node.body;for(;r<i.length&&o.isExpressionStatement(i[r])&&o.isStringLiteral(i[r].expression);)r++;f&&!t._hasUseIntlayerImport&&i.splice(r++,0,o.importDeclaration([o.importSpecifier(o.identifier(`useIntlayer`),o.identifier(`useIntlayer`))],o.stringLiteral(n))),p&&!t._hasGetIntlayerImport&&i.splice(r,0,o.importDeclaration([o.importSpecifier(o.identifier(`getIntlayer`),o.identifier(`getIntlayer`))],o.stringLiteral(`intlayer`)))}}}}}},u=(e,t,n)=>{let r=e.node,i=t._contentVarName,a=t._dictionaryKey,o=s(e,n);if(!n.isBlockStatement(r.body)){let e=o?t._useIntlayerLocalName:t._getIntlayerLocalName,s=n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(e),[n.stringLiteral(a)]))]);return r.body=n.blockStatement([s,n.returnStatement(r.body)]),o?`hook`:`core`}let c=o?t._useIntlayerLocalName:t._getIntlayerLocalName;return r.body.body.some(e=>n.isVariableDeclaration(e)&&e.declarations.some(e=>n.isIdentifier(e.id)&&e.id.name===i))||r.body.body.unshift(n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(c),[n.stringLiteral(a)]))])),o?`hook`:`core`};exports.intlayerExtractBabelPlugin=l;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./_virtual/_rolldown/runtime.cjs`);let t=require(`node:child_process`),n=require(`node:fs`),r=require(`node:path`),i=require(`@babel/generator`);i=e.__toESM(i);let a=require(`@intlayer/chokidar/cli`),o=require(`@intlayer/config/client`),s=require(`@intlayer/config/node`),c=require(`@intlayer/core/utils`);const l=i.default.default??i.default,u=(e,t=`comp-`)=>{let n=(0,r.basename)(e,(0,r.extname)(e));return n===`index`&&(n=(0,r.basename)((0,r.dirname)(e))),`${t}${n.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}`},d=e=>{let t=e;for(;;){let e=(0,r.join)(t,`package.json`);if((0,n.existsSync)(e))try{let t=JSON.parse((0,n.readFileSync)(e,`utf-8`));if(t.dependencies?.[`next-intlayer`]||t.devDependencies?.[`next-intlayer`])return`next-intlayer`;if(t.dependencies?.[`react-intlayer`]||t.devDependencies?.[`react-intlayer`])return`react-intlayer`;if(t.dependencies?.[`preact-intlayer`]||t.devDependencies?.[`preact-intlayer`])return`preact-intlayer`}catch{}let i=(0,r.dirname)(t);if(i===t)break;t=i}return`react-intlayer`},f=(e,t)=>{let n=e;for(;t.isParenthesizedExpression(n);)n=n.expression;return n},p=(e,t)=>{let n=e.node;if(!t.isBlockStatement(n.body)){let e=f(n.body,t);return t.isJSXElement(e)||t.isJSXFragment(e)}let r=!1;return e.traverse({Function(e){e.skip()},ReturnStatement(e){if(e.node.argument){let n=f(e.node.argument,t);(t.isJSXElement(n)||t.isJSXFragment(n))&&(r=!0)}}}),r},m=(e,t)=>{let n=e.getFunctionParent();if(!n)return null;let r=n;for(;r;){if(p(r,t))return r;r=r.getFunctionParent()}return n},h=e=>{let{types:i}=e,f=(0,s.getConfiguration)(),h=(0,o.getAppLogger)(f);return{name:`babel-plugin-intlayer-extract`,pre(){this._extractedContent={},this._existingKeys=new Set,this._isIncluded=!0,this._hasJSX=!1,this._hasUseIntlayerImport=!1,this._useIntlayerLocalName=`useIntlayer`,this._hasGetIntlayerImport=!1,this._getIntlayerLocalName=`getIntlayer`,this._contentVarName=`content`,this._isClient=!1,this._hasTopLevelContent=!1,this._extractionTargets=[],this._functionsToInject=new Set;let e=this.file.opts.filename;if(!this.opts.packageName){let t=e?(0,r.dirname)(e):process.cwd();this.opts.packageName=d(t)}if(!(this.opts.enabled??!0)){this._isIncluded=!1;return}if(this.opts.filesList&&e){let t=e.replace(/\\/g,`/`);this._isIncluded=this.opts.filesList.some(e=>e.replace(/\\/g,`/`)===t)}e&&(this._dictionaryKey=u(e,this.opts.prefix))},visitor:{ImportDeclaration(e,t){if(t._isIncluded)for(let n of e.node.specifiers){if(!i.isImportSpecifier(n))continue;let e=i.isIdentifier(n.imported)?n.imported.name:n.imported.value;e===`useIntlayer`&&(t._hasUseIntlayerImport=!0,t._useIntlayerLocalName=n.local.name),e===`getIntlayer`&&(t._hasGetIntlayerImport=!0,t._getIntlayerLocalName=n.local.name)}},JSXElement(e,t){t._isIncluded&&(t._hasJSX=!0)},JSXText(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let n=t.opts.shouldExtract??a.shouldExtract,r=e.node.value;if(n(r)){let n=r.replace(/\s+/g,` `).trim(),a=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===n);a||(a=(0,c.generateKey)(n,t._existingKeys),t._existingKeys.add(a),t._extractedContent[a]=n),t._extractionTargets.push({path:e,key:a,isAttribute:!1});let o=m(e,i);o?t._functionsToInject.add(o):t._hasTopLevelContent=!0}},JSXAttribute(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let n=t.opts.shouldExtract??a.shouldExtract,r=e.node.name;if(!i.isJSXIdentifier(r))return;let o=r.name===`key`;if(!a.ATTRIBUTES_TO_EXTRACT.includes(r.name)&&!o)return;let s=e.node.value,l=null;if(i.isStringLiteral(s)?l=s.value:i.isJSXExpressionContainer(s)&&i.isStringLiteral(s.expression)&&(l=s.expression.value),l&&n(l)){let n=l.trim(),r=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===n);r||(r=(0,c.generateKey)(n,t._existingKeys),t._existingKeys.add(r),t._extractedContent[r]=n),t._extractionTargets.push({path:e,key:r,isAttribute:!0});let a=m(e,i);a?t._functionsToInject.add(a):t._hasTopLevelContent=!0}},StringLiteral(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let n=t.opts.shouldExtract??a.shouldExtract,r=e.parentPath;if(r.isJSXAttribute()||r.isImportDeclaration()||r.isExportDeclaration()||r.isImportSpecifier()||r.isObjectProperty()&&e.key===`key`||r.isMemberExpression()&&e.key===`property`)return;if(r.isCallExpression()){let e=r.node.callee;if(i.isMemberExpression(e)&&i.isIdentifier(e.object)&&e.object.name===`console`||i.isIdentifier(e)&&(e.name===t._useIntlayerLocalName||e.name===t._getIntlayerLocalName||e.name===`require`)||e.type===`Import`)return}let o=e.node.value;if(n(o)){let n=o.trim(),r=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===n);r||(r=(0,c.generateKey)(n,t._existingKeys),t._existingKeys.add(r),t._extractedContent[r]=n),t._extractionTargets.push({path:e,key:r,isAttribute:!1});let a=m(e,i);a?t._functionsToInject.add(a):t._hasTopLevelContent=!0}},Program:{enter(e,t){if(!t._isIncluded)return;t._isClient=e.node.directives.some(e=>e.value.value===`use client`);let n=!1;e.traverse({VariableDeclarator(e){i.isIdentifier(e.node.id)&&e.node.id.name===`content`&&(n=!0)}}),t._contentVarName=n?`_compContent`:`content`},exit(e,s){if(!s._isIncluded||!s._dictionaryKey)return;let c=s._extractionTargets,u=s._functionsToInject;if(c.length===0)return;for(let{path:e,key:t,isAttribute:n}of c){let r=!1,a=!1,o=e.scope.getBinding(s._contentVarName);if(o&&i.isVariableDeclarator(o.path.node)&&i.isCallExpression(o.path.node.init)&&i.isIdentifier(o.path.node.init.callee)&&(o.path.node.init.callee.name===s._useIntlayerLocalName?(r=!0,a=!0):o.path.node.init.callee.name===s._getIntlayerLocalName&&(r=!1,a=!0)),!a){let t=m(e,i);t&&(r=p(t,i))}if(n){let n=i.optionalMemberExpression(i.identifier(s._contentVarName),i.stringLiteral(t),!0,!0);e.node.value=i.jsxExpressionContainer(r?i.optionalMemberExpression(n,i.identifier(`value`),!1,!0):n)}else if(e.isJSXText())e.replaceWith(i.jsxExpressionContainer(i.optionalMemberExpression(i.identifier(s._contentVarName),i.stringLiteral(t),!0,!0)));else{let n=i.optionalMemberExpression(i.identifier(s._contentVarName),i.stringLiteral(t),!0,!0);e.replaceWith(r?i.optionalMemberExpression(n,i.identifier(`value`),!1,!0):n)}}s.opts.onExtract&&s._dictionaryKey&&s.opts.onExtract({dictionaryKey:s._dictionaryKey,filePath:s.file.opts.filename,content:{...s._extractedContent},locale:s.opts.defaultLocale});let d=!1,_=!1;for(let e of u){let t=g(e,s,i);t===`hook`&&(d=!0),t===`core`&&(_=!0)}if(s._hasTopLevelContent){_=!0;let t=s._contentVarName,n=s._dictionaryKey,r=s._getIntlayerLocalName,a=0,o=e.node.body;for(;a<o.length&&(i.isImportDeclaration(o[a])||i.isExpressionStatement(o[a])&&i.isStringLiteral(o[a].expression));)a++;e.node.body.splice(a,0,i.variableDeclaration(`const`,[i.variableDeclarator(i.identifier(t),i.callExpression(i.identifier(r),[i.stringLiteral(n)]))]))}if(d||_){let t=s.opts.packageName??`react-intlayer`;t===`next-intlayer`&&!s._isClient&&(t=`${t}/server`);let n=0,r=e.node.body;for(;n<r.length&&i.isExpressionStatement(r[n])&&i.isStringLiteral(r[n].expression);)n++;d&&!s._hasUseIntlayerImport&&r.splice(n++,0,i.importDeclaration([i.importSpecifier(i.identifier(`useIntlayer`),i.identifier(`useIntlayer`))],i.stringLiteral(t))),_&&!s._hasGetIntlayerImport&&r.splice(n,0,i.importDeclaration([i.importSpecifier(i.identifier(`getIntlayer`),i.identifier(`getIntlayer`))],i.stringLiteral(`intlayer`)))}if(s.opts.saveComponents&&s.file.opts.filename)try{let i=l(e.node,{retainLines:!0}).code;(0,n.writeFileSync)(s.file.opts.filename,i,`utf-8`);let c=f.content?.baseDir??process.cwd(),u=(0,r.relative)(c,s.file.opts.filename);h(`${(0,o.colorize)(`Compiler:`,o.ANSIColors.GREY_DARK)} Saved component: ${(0,o.colorizePath)(u)}`,{level:`info`});let d=(0,a.detectFormatCommand)(f);if(d)try{(0,t.execSync)(d.replace(`{{file}}`,s.file.opts.filename),{stdio:`ignore`,cwd:c})}catch(e){h(`Extractor formatting error: ${String(e)}`,{level:`error`})}}catch(e){h(`Extractor plugin error: ${String(e)}`,{level:`error`})}}}}}},g=(e,t,n)=>{let r=e.node,i=t._contentVarName,a=t._dictionaryKey,o=p(e,n);if(!n.isBlockStatement(r.body)){let e=o?t._useIntlayerLocalName:t._getIntlayerLocalName,s=n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(e),[n.stringLiteral(a)]))]);return r.body=n.blockStatement([s,n.returnStatement(r.body)]),o?`hook`:`core`}let s=o?t._useIntlayerLocalName:t._getIntlayerLocalName;return r.body.body.some(e=>n.isVariableDeclaration(e)&&e.declarations.some(e=>n.isIdentifier(e.id)&&e.id.name===i))||r.body.body.unshift(n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(s),[n.stringLiteral(a)]))])),o?`hook`:`core`};exports.intlayerExtractBabelPlugin=h;
2
2
  //# sourceMappingURL=babel-plugin-intlayer-extract.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["defaultShouldExtract","ATTRIBUTES_TO_EXTRACT"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { basename, dirname, extname, join } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport generator from '@babel/generator';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n} from '@intlayer/chokidar/cli';\nimport { generateKey } from '@intlayer/core/utils';\n\n// Set this to true to enable debug logs\nconst DEBUG_LOG = false;\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n\n /**\n * Whether the extraction compiler is enabled.\n * If false, the plugin will not process the file.\n */\n enabled?: boolean;\n\n /**\n * Prefix for the extracted dictionary keys.\n */\n prefix?: string;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n /** Whether the file has 'use client' directive */\n _isClient?: boolean;\n /** Whether there is extracted content at the top level (not in a function) */\n _hasTopLevelContent?: boolean;\n};\nconst extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = 'comp-'\n): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `${prefix}${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst detectPackageName = (dir: string): string => {\n let currentDir = dir;\n while (true) {\n const pkgPath = join(currentDir, 'package.json');\n\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n if (\n pkg.dependencies?.['next-intlayer'] ||\n pkg.devDependencies?.['next-intlayer']\n ) {\n return 'next-intlayer';\n }\n\n if (\n pkg.dependencies?.['react-intlayer'] ||\n pkg.devDependencies?.['react-intlayer']\n ) {\n return 'react-intlayer';\n }\n\n if (\n pkg.dependencies?.['preact-intlayer'] ||\n pkg.devDependencies?.['preact-intlayer']\n ) {\n return 'preact-intlayer';\n }\n } catch {}\n }\n const parentDir = dirname(currentDir);\n\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n return 'react-intlayer';\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n};\n\nconst isReactComponent = (\n funcPath: NodePath<BabelTypes.Function>,\n t: typeof BabelTypes\n): boolean => {\n const node = funcPath.node;\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n return t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n }\n let returnsJSX = false;\n funcPath.traverse({\n Function(p) {\n p.skip();\n },\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped)) {\n returnsJSX = true;\n }\n }\n },\n });\n return returnsJSX;\n};\n\nconst findTargetFunction = (\n startPath: NodePath<any>,\n t: typeof BabelTypes\n): NodePath<BabelTypes.Function> | null => {\n const closestFunc =\n startPath.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n if (!closestFunc) return null;\n\n let currentFunc: NodePath<BabelTypes.Function> | null = closestFunc;\n while (currentFunc) {\n if (isReactComponent(currentFunc, t)) {\n return currentFunc;\n }\n currentFunc =\n currentFunc.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n }\n return closestFunc;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n this._isClient = false;\n this._hasTopLevelContent = false;\n\n const filename = this.file.opts.filename;\n\n if (!this.opts.packageName) {\n const searchDir = filename ? dirname(filename) : process.cwd();\n this.opts.packageName = detectPackageName(searchDir);\n }\n\n // Check if extraction is enabled\n const isEnabled = this.opts.enabled ?? true;\n\n if (!isEnabled) {\n this._isIncluded = false;\n return;\n }\n\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(\n filename,\n this.opts.prefix\n );\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n\n // Check for 'use client' directive\n state._isClient = programPath.node.directives.some(\n (d) => d.value.value === 'use client'\n );\n\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n\n const extractionTargets: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[] = [];\n const functionsToInject = new Set<NodePath<BabelTypes.Function>>();\n const shouldExtract =\n state.opts.shouldExtract ?? defaultShouldExtract;\n\n const addTarget = (path: NodePath<any>) => {\n const func = findTargetFunction(path, t);\n\n if (func) {\n functionsToInject.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n };\n\n // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const rawText = path.node.value;\n\n if (shouldExtract(rawText)) {\n const text = rawText.replace(/\\s+/g, ' ').trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === text\n );\n\n if (!key) {\n key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text;\n }\n\n extractionTargets.push({ path, key, isAttribute: false });\n addTarget(path);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey)\n return;\n\n const value = path.node.value;\n let text: string | null = null;\n\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n extractionTargets.push({ path, key, isAttribute: true });\n addTarget(path);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n\n if (parent.isObjectProperty() && path.key === 'key') return;\n\n if (parent.isMemberExpression() && path.key === 'property')\n return;\n\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\n\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n\n if (shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n extractionTargets.push({ path, key, isAttribute: false });\n addTarget(path);\n }\n },\n });\n\n if (extractionTargets.length === 0) return;\n\n // Pass 2: Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n let isHook = false;\n let hookDecided = false;\n\n const binding = path.scope.getBinding(state._contentVarName!);\n\n if (\n binding &&\n t.isVariableDeclarator(binding.path.node) &&\n t.isCallExpression(binding.path.node.init) &&\n t.isIdentifier(binding.path.node.init.callee)\n ) {\n if (\n binding.path.node.init.callee.name ===\n state._useIntlayerLocalName\n ) {\n isHook = true;\n hookDecided = true;\n } else if (\n binding.path.node.init.callee.name ===\n state._getIntlayerLocalName\n ) {\n isHook = false;\n hookDecided = true;\n }\n }\n\n if (!hookDecided) {\n const func = findTargetFunction(path, t);\n\n if (func) {\n isHook = isReactComponent(func, t);\n }\n }\n\n if (isAttribute) {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.node.value = t.jsxExpressionContainer(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n )\n )\n );\n } else {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.replaceWith(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n }\n }\n\n // Report\n\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n\n if (type === 'hook') needsUseIntlayer = true;\n\n if (type === 'core') needsGetIntlayer = true;\n }\n\n if (state._hasTopLevelContent) {\n needsGetIntlayer = true;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const coreName = state._getIntlayerLocalName!;\n\n // Find injection position (after imports)\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n (t.isImportDeclaration(body[pos]) ||\n (t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )))\n )\n pos++;\n\n programPath.node.body.splice(\n pos,\n 0,\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(coreName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n // Pass 4: Imports\n\n if (needsUseIntlayer || needsGetIntlayer) {\n let hookPkg = state.opts.packageName ?? 'react-intlayer';\n const corePkg = 'intlayer';\n\n // Handle next-intlayer server/client split\n\n if (hookPkg === 'next-intlayer' && !state._isClient) {\n hookPkg = `${hookPkg}/server`;\n }\n\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(hookPkg)\n )\n );\n }\n\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(corePkg)\n )\n );\n }\n }\n\n if (DEBUG_LOG) {\n console.log(\n '[babel-plugin-intlayer-extract] Transformed:',\n state.file.opts.filename\n );\n\n console.log(\n generator(programPath.node, { retainLines: true }).code\n );\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const returnsJSX = isReactComponent(path, t);\n\n if (!t.isBlockStatement(node.body)) {\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n return returnsJSX ? 'hook' : 'core';\n }\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["_generate","defaultShouldExtract","ATTRIBUTES_TO_EXTRACT","ANSIColors"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { basename, dirname, extname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport _generate from '@babel/generator';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n detectFormatCommand,\n} from '@intlayer/chokidar/cli';\nimport {\n ANSIColors,\n colorize,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { generateKey } from '@intlayer/core/utils';\n\nconst generate = ((_generate as any).default ?? _generate) as typeof _generate;\n\n// Set this to true to enable debug logs\nconst DEBUG_LOG = false;\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n\n /**\n * Whether the extraction compiler is enabled.\n * If false, the plugin will not process the file.\n */\n enabled?: boolean;\n\n /**\n * Prefix for the extracted dictionary keys.\n */\n prefix?: string;\n\n /**\n * Indicates if the components should be saved after being transformed.\n */\n saveComponents?: boolean;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n /** Whether the file has 'use client' directive */\n _isClient?: boolean;\n /** Whether there is extracted content at the top level (not in a function) */\n _hasTopLevelContent?: boolean;\n /** Targets to extract and modify */\n _extractionTargets?: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[];\n /** Functions to inject the hook/core logic into */\n _functionsToInject?: Set<NodePath<BabelTypes.Function>>;\n};\nconst extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = 'comp-'\n): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `${prefix}${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst detectPackageName = (dir: string): string => {\n let currentDir = dir;\n while (true) {\n const pkgPath = join(currentDir, 'package.json');\n\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n if (\n pkg.dependencies?.['next-intlayer'] ||\n pkg.devDependencies?.['next-intlayer']\n ) {\n return 'next-intlayer';\n }\n\n if (\n pkg.dependencies?.['react-intlayer'] ||\n pkg.devDependencies?.['react-intlayer']\n ) {\n return 'react-intlayer';\n }\n\n if (\n pkg.dependencies?.['preact-intlayer'] ||\n pkg.devDependencies?.['preact-intlayer']\n ) {\n return 'preact-intlayer';\n }\n } catch {}\n }\n const parentDir = dirname(currentDir);\n\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n return 'react-intlayer';\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n\n return current;\n};\n\nconst isReactComponent = (\n funcPath: NodePath<BabelTypes.Function>,\n t: typeof BabelTypes\n): boolean => {\n const node = funcPath.node;\n\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n return t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n }\n\n let returnsJSX = false;\n\n funcPath.traverse({\n Function(p) {\n p.skip();\n },\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped)) {\n returnsJSX = true;\n }\n }\n },\n });\n return returnsJSX;\n};\n\nconst findTargetFunction = (\n startPath: NodePath<any>,\n t: typeof BabelTypes\n): NodePath<BabelTypes.Function> | null => {\n const closestFunc =\n startPath.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n if (!closestFunc) return null;\n\n let currentFunc: NodePath<BabelTypes.Function> | null = closestFunc;\n while (currentFunc) {\n if (isReactComponent(currentFunc, t)) {\n return currentFunc;\n }\n currentFunc =\n currentFunc.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n }\n return closestFunc;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n const config = getConfiguration();\n const appLogger = getAppLogger(config);\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n this._isClient = false;\n this._hasTopLevelContent = false;\n this._extractionTargets = [];\n this._functionsToInject = new Set();\n\n const filename = this.file.opts.filename;\n\n if (!this.opts.packageName) {\n const searchDir = filename ? dirname(filename) : process.cwd();\n this.opts.packageName = detectPackageName(searchDir);\n }\n\n // Check if extraction is enabled\n const isEnabled = this.opts.enabled ?? true;\n\n if (!isEnabled) {\n this._isIncluded = false;\n return;\n }\n\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(\n filename,\n this.opts.prefix\n );\n },\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n JSXText(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const rawText = path.node.value;\n\n if (shouldExtract(rawText)) {\n const text = rawText.replace(/\\s+/g, ' ').trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === text\n );\n\n if (!key) {\n key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: false });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n JSXAttribute(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const attrName = path.node.name;\n\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey) return;\n\n const value = path.node.value;\n let text: string | null = null;\n\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: true });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n StringLiteral(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const parent = path.parentPath;\n\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n\n if (parent.isObjectProperty() && path.key === 'key') return;\n\n if (parent.isMemberExpression() && path.key === 'property') return;\n\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression).callee;\n\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n\n if (shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: false });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n\n // Check for 'use client' directive\n state._isClient = programPath.node.directives.some(\n (d) => d.value.value === 'use client'\n );\n\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n\n const extractionTargets = state._extractionTargets!;\n const functionsToInject = state._functionsToInject!;\n\n if (extractionTargets.length === 0) return;\n\n // Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n let isHook = false;\n let hookDecided = false;\n\n const binding = path.scope.getBinding(state._contentVarName!);\n\n if (\n binding &&\n t.isVariableDeclarator(binding.path.node) &&\n t.isCallExpression(binding.path.node.init) &&\n t.isIdentifier(binding.path.node.init.callee)\n ) {\n if (\n binding.path.node.init.callee.name ===\n state._useIntlayerLocalName\n ) {\n isHook = true;\n hookDecided = true;\n } else if (\n binding.path.node.init.callee.name ===\n state._getIntlayerLocalName\n ) {\n isHook = false;\n hookDecided = true;\n }\n }\n\n if (!hookDecided) {\n const func = findTargetFunction(path, t);\n\n if (func) {\n isHook = isReactComponent(func, t);\n }\n }\n\n if (isAttribute) {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.node.value = t.jsxExpressionContainer(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n )\n )\n );\n } else {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.replaceWith(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n }\n }\n\n // Report\n\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n\n if (type === 'hook') needsUseIntlayer = true;\n\n if (type === 'core') needsGetIntlayer = true;\n }\n\n if (state._hasTopLevelContent) {\n needsGetIntlayer = true;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const coreName = state._getIntlayerLocalName!;\n\n // Find injection position (after imports)\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n (t.isImportDeclaration(body[pos]) ||\n (t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )))\n )\n pos++;\n\n programPath.node.body.splice(\n pos,\n 0,\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(coreName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n // Pass 4: Imports\n\n if (needsUseIntlayer || needsGetIntlayer) {\n let hookPkg = state.opts.packageName ?? 'react-intlayer';\n const corePkg = 'intlayer';\n\n // Handle next-intlayer server/client split\n\n if (hookPkg === 'next-intlayer' && !state._isClient) {\n hookPkg = `${hookPkg}/server`;\n }\n\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(hookPkg)\n )\n );\n }\n\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(corePkg)\n )\n );\n }\n }\n\n if (state.opts.saveComponents && state.file.opts.filename) {\n try {\n const transformedCode = generate(programPath.node, {\n retainLines: true,\n }).code;\n\n writeFileSync(state.file.opts.filename, transformedCode, 'utf-8');\n\n const basedir = config.content?.baseDir ?? process.cwd();\n const relativePath = relative(basedir, state.file.opts.filename);\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Saved component: ${colorizePath(relativePath)}`,\n { level: 'info' }\n );\n\n const formatCommand = detectFormatCommand(config);\n\n if (formatCommand) {\n try {\n execSync(\n formatCommand.replace('{{file}}', state.file.opts.filename),\n {\n stdio: 'ignore', // Use 'ignore' to prevent format output from cluttering the extraction process console\n cwd: basedir,\n }\n );\n } catch (error) {\n appLogger(`Extractor formatting error: ${String(error)}`, {\n level: 'error',\n });\n }\n }\n } catch (err: any) {\n appLogger(`Extractor plugin error: ${String(err)}`, {\n level: 'error',\n });\n }\n }\n\n if (DEBUG_LOG) {\n const basedir = config.content?.baseDir ?? process.cwd();\n const relativePath = state.file.opts.filename\n ? relative(basedir, state.file.opts.filename)\n : 'unknown';\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Transformed: ${colorizePath(relativePath)}\\n${generate(programPath.node, { retainLines: false }).code}`,\n { level: 'debug' }\n );\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const returnsJSX = isReactComponent(path, t);\n\n if (!t.isBlockStatement(node.body)) {\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n\n return returnsJSX ? 'hook' : 'core';\n }\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:fs`),t=require(`node:path`),n=require(`node:fs/promises`),r=require(`@intlayer/chokidar/build`),i=require(`@intlayer/config/client`),a=require(`@intlayer/config/node`);const o=(o=process.env.INTLAYER_IS_DEV_COMMAND)=>{let s=(0,a.getConfiguration)(),{baseDir:c}=s.content,l=(0,t.join)(c,s.compiler?.outputDir??`compiler`),u=async t=>{try{if(!(0,e.existsSync)(t))return null;let r=await(0,n.readFile)(t,`utf-8`);if(!r||r.trim()===``)return null;let i=JSON.parse(r);return Array.isArray(i)?i[0]??null:i}catch(r){return(0,e.existsSync)(t)&&(await(0,n.readFile)(t,`utf-8`)).trim()!==``&&console.warn(`[intlayer] Warning: Failed to read existing dictionary at ${t}. It might be corrupt. Translations may be lost. Error:`,r),null}},d=(e,t,n)=>{let r={},i=t?.content,a=Object.keys(e).sort();for(let t of a){let a=e[t],o=i?.[t];o&&o.nodeType===`translation`&&o.translation?r[t]={...o,nodeType:`translation`,translation:{...o.translation,[n]:o.translation[n]??a}}:r[t]={nodeType:`translation`,translation:{[n]:a}}}return r},f=async e=>{let{dictionaryKey:n,content:i,locale:a}=e;try{let e=await u((0,t.join)(l,`${n}.content.json`)),o=d(i,e,a),f={...e,key:n,content:o,filePath:(0,t.join)((0,t.relative)(c,l),`${n}.content.json`)},p=await(0,r.writeContentDeclaration)(f,s,{newDictionariesPath:(0,t.relative)(c,l)});await(0,r.buildDictionary)([{...f,filePath:(0,t.relative)(c,p.path)}],s)}catch(e){if(console.error(`[intlayer] Failed to process extracted content for ${n}:`,e),e instanceof SyntaxError&&e.message.includes(`Unexpected end of JSON input`)){let t=e.message.match(/^(.*\.json):\s*Unexpected end of JSON input/);if(t){let e=t[1];try{let t=require(`fs`).readFileSync(e,`utf-8`);console.error(`[intlayer] Content of the corrupted file (${e}):\n"${t}"`)}catch(t){console.error(`[intlayer] Could not read corrupted file ${e}`,t)}}}}},p=String(o)===`true`,m=s.compiler?.enabled===`build-only`?!p:s.compiler?.enabled??!0,h=(0,i.getAppLogger)(s);return s.compiler?.enabled===`build-only`&&p&&h(`${(0,i.colorize)(`Compiler:`,i.ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`),{enabled:m,defaultLocale:s.internationalization.defaultLocale,prefix:s.compiler?.dictionaryKeyPrefix,onExtract:f}};exports.getExtractPluginOptions=o;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:fs`),t=require(`node:path`),n=require(`@intlayer/config/client`),r=require(`@intlayer/config/node`),i=require(`node:fs/promises`),a=require(`@intlayer/chokidar/build`);const o=(o=process.env.INTLAYER_IS_DEV_COMMAND)=>{let s=(0,r.getConfiguration)(),{baseDir:c}=s.content,l=(0,t.join)(c,s.compiler?.outputDir??`compiler`),u=async t=>{try{if(!(0,e.existsSync)(t))return null;let n=await(0,i.readFile)(t,`utf-8`);if(!n||n.trim()===``)return null;let r=JSON.parse(n);return Array.isArray(r)?r[0]??null:r}catch(n){return(0,e.existsSync)(t)&&(await(0,i.readFile)(t,`utf-8`)).trim()!==``&&console.warn(`[intlayer] Warning: Failed to read existing dictionary at ${t}. It might be corrupt. Translations may be lost. Error:`,n),null}},d=(e,t,n)=>{let r={},i=t?.content,a=Object.keys(e).sort();for(let t of a){let a=e[t],o=i?.[t];o&&o.nodeType===`translation`&&o.translation?r[t]={...o,nodeType:`translation`,translation:{...o.translation,[n]:o.translation[n]??a}}:r[t]={nodeType:`translation`,translation:{[n]:a}}}return r},f=async e=>{let{dictionaryKey:n,content:r,locale:i}=e;try{let e=await u((0,t.join)(l,`${n}.content.json`)),o=d(r,e,i),f={...e,key:n,content:o,filePath:(0,t.join)((0,t.relative)(c,l),`${n}.content.json`)},p=await(0,a.writeContentDeclaration)(f,s,{newDictionariesPath:(0,t.relative)(c,l)});await(0,a.buildDictionary)([{...f,filePath:(0,t.relative)(c,p.path)}],s)}catch(e){if(console.error(`[intlayer] Failed to process extracted content for ${n}:`,e),e instanceof SyntaxError&&e.message.includes(`Unexpected end of JSON input`)){let t=e.message.match(/^(.*\.json):\s*Unexpected end of JSON input/);if(t){let e=t[1];try{let t=require(`fs`).readFileSync(e,`utf-8`);console.error(`[intlayer] Content of the corrupted file (${e}):\n"${t}"`)}catch(t){console.error(`[intlayer] Could not read corrupted file ${e}`,t)}}}}},p=String(o)===`true`,m=s.compiler?.enabled===`build-only`?!p:s.compiler?.enabled??!0,h=(0,n.getAppLogger)(s);return s.compiler?.enabled===`build-only`&&p&&h(`${(0,n.colorize)(`Compiler:`,n.ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`),{enabled:m,defaultLocale:s.internationalization.defaultLocale,prefix:s.compiler?.dictionaryKeyPrefix,saveComponents:s.compiler?.saveComponents,onExtract:f}};exports.getExtractPluginOptions=o;
2
2
  //# sourceMappingURL=getExtractPluginOptions.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"getExtractPluginOptions.cjs","names":["ANSIColors"],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Dictionary } from '@intlayer/types';\nimport type {\n ExtractPluginOptions,\n ExtractResult,\n} from './babel-plugin-intlayer-extract';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n isDev = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n const config = getConfiguration();\n const { baseDir } = config.content;\n\n const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler');\n\n /**\n * Read existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryPath: string\n ): Promise<Dictionary | null> => {\n try {\n if (!existsSync(dictionaryPath)) {\n return null;\n }\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (!content || content.trim() === '') {\n return null;\n }\n\n const parsed = JSON.parse(content);\n\n if (Array.isArray(parsed)) {\n return (parsed[0] ?? null) as Dictionary | null;\n }\n\n return parsed as Dictionary;\n } catch (error) {\n if (existsSync(dictionaryPath)) {\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (content.trim() !== '') {\n console.warn(\n `[intlayer] Warning: Failed to read existing dictionary at ${dictionaryPath}. It might be corrupt. Translations may be lost. Error:`,\n error\n );\n }\n }\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary, preserving translations.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n const sortedKeys = Object.keys(extractedContent).sort();\n\n for (const key of sortedKeys) {\n const value = extractedContent[key];\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n // Key exists in both - preserve existing translations AND existing metadata\n mergedContent[key] = {\n ...existingEntry,\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: existingEntry.translation[defaultLocale] ?? value,\n },\n };\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n }\n\n return mergedContent;\n };\n\n const handleExtractedContent = async (result: ExtractResult) => {\n const { dictionaryKey, content, locale } = result;\n\n try {\n const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`);\n\n // Read existing dictionary to preserve translations\n const existingDictionary = await readExistingDictionary(dictionaryPath);\n\n // Merge extracted content with existing translations\n const mergedContent = mergeWithExistingDictionary(\n content,\n existingDictionary,\n locale\n );\n\n const dictionary: Dictionary = {\n ...existingDictionary,\n key: dictionaryKey,\n content: mergedContent,\n filePath: join(\n relative(baseDir, compilerDir),\n `${dictionaryKey}.content.json`\n ),\n };\n\n const writeResult = await writeContentDeclaration(dictionary, config, {\n newDictionariesPath: relative(baseDir, compilerDir),\n });\n\n // Build the dictionary immediately\n const dictionaryToBuild: Dictionary = {\n ...dictionary,\n filePath: relative(baseDir, writeResult.path),\n };\n\n await buildDictionary([dictionaryToBuild], config);\n } catch (error: any) {\n console.error(\n `[intlayer] Failed to process extracted content for ${dictionaryKey}:`,\n error\n );\n if (\n error instanceof SyntaxError &&\n error.message.includes('Unexpected end of JSON input')\n ) {\n const match = error.message.match(\n /^(.*\\.json):\\s*Unexpected end of JSON input/\n );\n if (match) {\n const filePath = match[1];\n try {\n const fs = require('fs');\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n console.error(\n `[intlayer] Content of the corrupted file (${filePath}):\\n\"${fileContent}\"`\n );\n } catch (e) {\n console.error(\n `[intlayer] Could not read corrupted file ${filePath}`,\n e\n );\n }\n }\n }\n }\n };\n\n const isDevBoolean = String(isDev) === 'true';\n const isEnabled =\n config.compiler?.enabled === 'build-only'\n ? !isDevBoolean\n : (config.compiler?.enabled ?? true);\n\n const logger = getAppLogger(config);\n\n if (config.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n return {\n enabled: isEnabled,\n defaultLocale: config.internationalization.defaultLocale,\n prefix: config.compiler?.dictionaryKeyPrefix,\n // filesList can be passed if needed, but usually handled by include/exclude in build tool\n onExtract: handleExtractedContent,\n };\n};\n"],"mappings":"2SAiCA,MAAa,GACX,EAAQ,QAAQ,IAAI,0BACK,CACzB,IAAM,GAAA,EAAA,EAAA,mBAA2B,CAC3B,CAAE,WAAY,EAAO,QAErB,GAAA,EAAA,EAAA,MAAmB,EAAS,EAAO,UAAU,WAAa,WAAW,CAKrE,EAAyB,KAC7B,IAC+B,CAC/B,GAAI,CACF,GAAI,EAAA,EAAA,EAAA,YAAY,EAAe,CAC7B,OAAO,KAET,IAAM,EAAU,MAAA,EAAA,EAAA,UAAe,EAAgB,QAAQ,CAEvD,GAAI,CAAC,GAAW,EAAQ,MAAM,GAAK,GACjC,OAAO,KAGT,IAAM,EAAS,KAAK,MAAM,EAAQ,CAMlC,OAJI,MAAM,QAAQ,EAAO,CACf,EAAO,IAAM,KAGhB,QACA,EAAO,CAWd,OAVA,EAAA,EAAA,YAAe,EAAe,GACZ,MAAA,EAAA,EAAA,UAAe,EAAgB,QAAQ,EAE3C,MAAM,GAAK,IACrB,QAAQ,KACN,6DAA6D,EAAe,yDAC5E,EACD,CAGE,OAUL,GACJ,EACA,EACA,IACyB,CACzB,IAAM,EAAsC,EAAE,CACxC,EAAkB,GAAoB,QAItC,EAAa,OAAO,KAAK,EAAiB,CAAC,MAAM,CAEvD,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAiB,GACzB,EAAgB,IAAkB,GAGtC,GACA,EAAc,WAAa,eAC3B,EAAc,YAGd,EAAc,GAAO,CACnB,GAAG,EACH,SAAU,cACV,YAAa,CACX,GAAG,EAAc,aAChB,GAAgB,EAAc,YAAY,IAAkB,EAC9D,CACF,CAGD,EAAc,GAAO,CACnB,SAAU,cACV,YAAa,EACV,GAAgB,EAClB,CACF,CAIL,OAAO,GAGH,EAAyB,KAAO,IAA0B,CAC9D,GAAM,CAAE,gBAAe,UAAS,UAAW,EAE3C,GAAI,CAIF,IAAM,EAAqB,MAAM,GAAA,EAAA,EAAA,MAHL,EAAa,GAAG,EAAc,eAAe,CAGF,CAGjE,EAAgB,EACpB,EACA,EACA,EACD,CAEK,EAAyB,CAC7B,GAAG,EACH,IAAK,EACL,QAAS,EACT,UAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UACW,EAAS,EAAY,CAC9B,GAAG,EAAc,eAClB,CACF,CAEK,EAAc,MAAA,EAAA,EAAA,yBAA8B,EAAY,EAAQ,CACpE,qBAAA,EAAA,EAAA,UAA8B,EAAS,EAAY,CACpD,CAAC,CAQF,MAAA,EAAA,EAAA,iBAAsB,CALgB,CACpC,GAAG,EACH,UAAA,EAAA,EAAA,UAAmB,EAAS,EAAY,KAAK,CAC9C,CAEwC,CAAE,EAAO,OAC3C,EAAY,CAKnB,GAJA,QAAQ,MACN,sDAAsD,EAAc,GACpE,EACD,CAEC,aAAiB,aACjB,EAAM,QAAQ,SAAS,+BAA+B,CACtD,CACA,IAAM,EAAQ,EAAM,QAAQ,MAC1B,8CACD,CACD,GAAI,EAAO,CACT,IAAM,EAAW,EAAM,GACvB,GAAI,CAEF,IAAM,EADK,QAAQ,KAAK,CACD,aAAa,EAAU,QAAQ,CACtD,QAAQ,MACN,6CAA6C,EAAS,OAAO,EAAY,GAC1E,OACM,EAAG,CACV,QAAQ,MACN,4CAA4C,IAC5C,EACD,MAOL,EAAe,OAAO,EAAM,GAAK,OACjC,EACJ,EAAO,UAAU,UAAY,aACzB,CAAC,EACA,EAAO,UAAU,SAAW,GAE7B,GAAA,EAAA,EAAA,cAAsB,EAAO,CAQnC,OANI,EAAO,UAAU,UAAY,cAAgB,GAC/C,EACE,IAAA,EAAA,EAAA,UAAY,YAAaA,EAAAA,WAAW,UAAU,CAAC,wIAChD,CAGI,CACL,QAAS,EACT,cAAe,EAAO,qBAAqB,cAC3C,OAAQ,EAAO,UAAU,oBAEzB,UAAW,EACZ"}
1
+ {"version":3,"file":"getExtractPluginOptions.cjs","names":["ANSIColors"],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Dictionary } from '@intlayer/types';\nimport type {\n ExtractPluginOptions,\n ExtractResult,\n} from './babel-plugin-intlayer-extract';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n isDev = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n const config = getConfiguration();\n const { baseDir } = config.content;\n\n const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler');\n\n /**\n * Read existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryPath: string\n ): Promise<Dictionary | null> => {\n try {\n if (!existsSync(dictionaryPath)) {\n return null;\n }\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (!content || content.trim() === '') {\n return null;\n }\n\n const parsed = JSON.parse(content);\n\n if (Array.isArray(parsed)) {\n return (parsed[0] ?? null) as Dictionary | null;\n }\n\n return parsed as Dictionary;\n } catch (error) {\n if (existsSync(dictionaryPath)) {\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (content.trim() !== '') {\n console.warn(\n `[intlayer] Warning: Failed to read existing dictionary at ${dictionaryPath}. It might be corrupt. Translations may be lost. Error:`,\n error\n );\n }\n }\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary, preserving translations.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n const sortedKeys = Object.keys(extractedContent).sort();\n\n for (const key of sortedKeys) {\n const value = extractedContent[key];\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n // Key exists in both - preserve existing translations AND existing metadata\n mergedContent[key] = {\n ...existingEntry,\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: existingEntry.translation[defaultLocale] ?? value,\n },\n };\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n }\n\n return mergedContent;\n };\n\n const handleExtractedContent = async (result: ExtractResult) => {\n const { dictionaryKey, content, locale } = result;\n\n try {\n const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`);\n\n // Read existing dictionary to preserve translations\n const existingDictionary = await readExistingDictionary(dictionaryPath);\n\n // Merge extracted content with existing translations\n const mergedContent = mergeWithExistingDictionary(\n content,\n existingDictionary,\n locale\n );\n\n const dictionary: Dictionary = {\n ...existingDictionary,\n key: dictionaryKey,\n content: mergedContent,\n filePath: join(\n relative(baseDir, compilerDir),\n `${dictionaryKey}.content.json`\n ),\n };\n\n const writeResult = await writeContentDeclaration(dictionary, config, {\n newDictionariesPath: relative(baseDir, compilerDir),\n });\n\n // Build the dictionary immediately\n const dictionaryToBuild: Dictionary = {\n ...dictionary,\n filePath: relative(baseDir, writeResult.path),\n };\n\n await buildDictionary([dictionaryToBuild], config);\n } catch (error: any) {\n console.error(\n `[intlayer] Failed to process extracted content for ${dictionaryKey}:`,\n error\n );\n if (\n error instanceof SyntaxError &&\n error.message.includes('Unexpected end of JSON input')\n ) {\n const match = error.message.match(\n /^(.*\\.json):\\s*Unexpected end of JSON input/\n );\n if (match) {\n const filePath = match[1];\n try {\n const fs = require('fs');\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n console.error(\n `[intlayer] Content of the corrupted file (${filePath}):\\n\"${fileContent}\"`\n );\n } catch (e) {\n console.error(\n `[intlayer] Could not read corrupted file ${filePath}`,\n e\n );\n }\n }\n }\n }\n };\n\n const isDevBoolean = String(isDev) === 'true';\n const isEnabled =\n config.compiler?.enabled === 'build-only'\n ? !isDevBoolean\n : (config.compiler?.enabled ?? true);\n\n const logger = getAppLogger(config);\n\n if (config.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n return {\n enabled: isEnabled,\n defaultLocale: config.internationalization.defaultLocale,\n prefix: config.compiler?.dictionaryKeyPrefix,\n saveComponents: config.compiler?.saveComponents,\n // filesList can be passed if needed, but usually handled by include/exclude in build tool\n onExtract: handleExtractedContent,\n };\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:path`),t=require(`@intlayer/chokidar/utils`),n=require(`@intlayer/config/node`);const r=e=>{try{let{getDictionaries:t}=require(`@intlayer/dictionaries-entry`),n=t(e);return Object.values(n)}catch{return[]}},i=i=>{let{configOptions:a,dictionaries:o,overrides:s}=i??{},c=(0,n.getConfiguration)(a),{mainDir:l,dictionariesDir:u,unmergedDictionariesDir:d,dynamicDictionariesDir:f,fetchDictionariesDir:p}=c.system,{importMode:m,optimize:h}=c.build,g=(0,t.getComponentTransformPatternSync)(c),_=(0,e.join)(l,`dictionaries.mjs`),v=(0,e.join)(l,`unmerged_dictionaries.mjs`),y=(0,e.join)(l,`dynamic_dictionaries.mjs`),b=(0,e.join)(l,`fetch_dictionaries.mjs`),x=[...g,_,v],S=o??r(c),C={};return S.forEach(e=>{C[e.key]=e.importMode??m}),{optimize:h,dictionariesDir:u,dictionariesEntryPath:_,unmergedDictionariesDir:d,unmergedDictionariesEntryPath:v,dynamicDictionariesDir:f,dynamicDictionariesEntryPath:y,fetchDictionariesDir:p,fetchDictionariesEntryPath:b,replaceDictionaryEntry:!0,importMode:m,dictionaryModeMap:C,filesList:x,...s}};exports.getOptimizePluginOptions=i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:path`),t=require(`@intlayer/config/node`),n=require(`@intlayer/chokidar/utils`);const r=e=>{try{let{getDictionaries:t}=require(`@intlayer/dictionaries-entry`),n=t(e);return Object.values(n)}catch{return[]}},i=i=>{let{configOptions:a,dictionaries:o,overrides:s}=i??{},c=(0,t.getConfiguration)(a),{mainDir:l,dictionariesDir:u,unmergedDictionariesDir:d,dynamicDictionariesDir:f,fetchDictionariesDir:p}=c.system,{importMode:m,optimize:h}=c.build,g=(0,n.getComponentTransformPatternSync)(c),_=(0,e.join)(l,`dictionaries.mjs`),v=(0,e.join)(l,`unmerged_dictionaries.mjs`),y=(0,e.join)(l,`dynamic_dictionaries.mjs`),b=(0,e.join)(l,`fetch_dictionaries.mjs`),x=[...g,_,v],S=o??r(c),C={};return S.forEach(e=>{C[e.key]=e.importMode??m}),{optimize:h,dictionariesDir:u,dictionariesEntryPath:_,unmergedDictionariesDir:d,unmergedDictionariesEntryPath:v,dynamicDictionariesDir:f,dynamicDictionariesEntryPath:y,fetchDictionariesDir:p,fetchDictionariesEntryPath:b,replaceDictionaryEntry:!0,importMode:m,dictionaryModeMap:C,filesList:x,...s}};exports.getOptimizePluginOptions=i;
2
2
  //# sourceMappingURL=getOptimizePluginOptions.cjs.map
@@ -1,2 +1,2 @@
1
- import{existsSync as e,readFileSync as t}from"node:fs";import{basename as n,dirname as r,extname as i,join as a}from"node:path";import"@babel/generator";import{ATTRIBUTES_TO_EXTRACT as o,shouldExtract as s}from"@intlayer/chokidar/cli";import{generateKey as c}from"@intlayer/core/utils";const l=(e,t=`comp-`)=>{let a=n(e,i(e));return a===`index`&&(a=n(r(e))),`${t}${a.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}`},u=n=>{let i=n;for(;;){let n=a(i,`package.json`);if(e(n))try{let e=JSON.parse(t(n,`utf-8`));if(e.dependencies?.[`next-intlayer`]||e.devDependencies?.[`next-intlayer`])return`next-intlayer`;if(e.dependencies?.[`react-intlayer`]||e.devDependencies?.[`react-intlayer`])return`react-intlayer`;if(e.dependencies?.[`preact-intlayer`]||e.devDependencies?.[`preact-intlayer`])return`preact-intlayer`}catch{}let o=r(i);if(o===i)break;i=o}return`react-intlayer`},d=(e,t)=>{let n=e;for(;t.isParenthesizedExpression(n);)n=n.expression;return n},f=(e,t)=>{let n=e.node;if(!t.isBlockStatement(n.body)){let e=d(n.body,t);return t.isJSXElement(e)||t.isJSXFragment(e)}let r=!1;return e.traverse({Function(e){e.skip()},ReturnStatement(e){if(e.node.argument){let n=d(e.node.argument,t);(t.isJSXElement(n)||t.isJSXFragment(n))&&(r=!0)}}}),r},p=(e,t)=>{let n=e.getFunctionParent();if(!n)return null;let r=n;for(;r;){if(f(r,t))return r;r=r.getFunctionParent()}return n},m=e=>{let{types:t}=e;return{name:`babel-plugin-intlayer-extract`,pre(){this._extractedContent={},this._existingKeys=new Set,this._isIncluded=!0,this._hasJSX=!1,this._hasUseIntlayerImport=!1,this._useIntlayerLocalName=`useIntlayer`,this._hasGetIntlayerImport=!1,this._getIntlayerLocalName=`getIntlayer`,this._contentVarName=`content`,this._isClient=!1,this._hasTopLevelContent=!1;let e=this.file.opts.filename;if(!this.opts.packageName){let t=e?r(e):process.cwd();this.opts.packageName=u(t)}if(!(this.opts.enabled??!0)){this._isIncluded=!1;return}if(this.opts.filesList&&e){let t=e.replace(/\\/g,`/`);this._isIncluded=this.opts.filesList.some(e=>e.replace(/\\/g,`/`)===t)}e&&(this._dictionaryKey=l(e,this.opts.prefix))},visitor:{ImportDeclaration(e,n){if(n._isIncluded)for(let r of e.node.specifiers){if(!t.isImportSpecifier(r))continue;let e=t.isIdentifier(r.imported)?r.imported.name:r.imported.value;e===`useIntlayer`&&(n._hasUseIntlayerImport=!0,n._useIntlayerLocalName=r.local.name),e===`getIntlayer`&&(n._hasGetIntlayerImport=!0,n._getIntlayerLocalName=r.local.name)}},JSXElement(e,t){t._isIncluded&&(t._hasJSX=!0)},Program:{enter(e,n){if(!n._isIncluded)return;n._isClient=e.node.directives.some(e=>e.value.value===`use client`);let r=!1;e.traverse({VariableDeclarator(e){t.isIdentifier(e.node.id)&&e.node.id.name===`content`&&(r=!0)}}),n._contentVarName=r?`_compContent`:`content`},exit(e,n){if(!n._isIncluded||!n._dictionaryKey)return;let r=[],i=new Set,a=n.opts.shouldExtract??s,l=e=>{let r=p(e,t);r?i.add(r):n._hasTopLevelContent=!0};if(e.traverse({JSXText(e){let t=e.node.value;if(a(t)){let i=t.replace(/\s+/g,` `).trim(),a=Object.keys(n._extractedContent).find(e=>n._extractedContent[e]===i);a||(a=c(i,n._existingKeys),n._existingKeys.add(a),n._extractedContent[a]=i),r.push({path:e,key:a,isAttribute:!1}),l(e)}},JSXAttribute(e){let i=e.node.name;if(!t.isJSXIdentifier(i))return;let s=i.name===`key`;if(!o.includes(i.name)&&!s)return;let u=e.node.value,d=null;if(t.isStringLiteral(u)?d=u.value:t.isJSXExpressionContainer(u)&&t.isStringLiteral(u.expression)&&(d=u.expression.value),d&&a(d)){let t=d.trim(),i=Object.keys(n._extractedContent).find(e=>n._extractedContent[e]===t);i||(i=c(t,n._existingKeys),n._existingKeys.add(i),n._extractedContent[i]=t),r.push({path:e,key:i,isAttribute:!0}),l(e)}},StringLiteral(e){let i=e.parentPath;if(i.isJSXAttribute()||i.isImportDeclaration()||i.isExportDeclaration()||i.isImportSpecifier()||i.isObjectProperty()&&e.key===`key`||i.isMemberExpression()&&e.key===`property`)return;if(i.isCallExpression()){let e=i.node.callee;if(t.isMemberExpression(e)&&t.isIdentifier(e.object)&&e.object.name===`console`||t.isIdentifier(e)&&(e.name===n._useIntlayerLocalName||e.name===n._getIntlayerLocalName||e.name===`require`)||e.type===`Import`)return}let o=e.node.value;if(a(o)){let t=o.trim(),i=Object.keys(n._extractedContent).find(e=>n._extractedContent[e]===t);i||(i=c(t,n._existingKeys),n._existingKeys.add(i),n._extractedContent[i]=t),r.push({path:e,key:i,isAttribute:!1}),l(e)}}}),r.length===0)return;for(let{path:e,key:i,isAttribute:a}of r){let r=!1,o=!1,s=e.scope.getBinding(n._contentVarName);if(s&&t.isVariableDeclarator(s.path.node)&&t.isCallExpression(s.path.node.init)&&t.isIdentifier(s.path.node.init.callee)&&(s.path.node.init.callee.name===n._useIntlayerLocalName?(r=!0,o=!0):s.path.node.init.callee.name===n._getIntlayerLocalName&&(r=!1,o=!0)),!o){let n=p(e,t);n&&(r=f(n,t))}if(a){let a=t.optionalMemberExpression(t.identifier(n._contentVarName),t.stringLiteral(i),!0,!0);e.node.value=t.jsxExpressionContainer(r?t.optionalMemberExpression(a,t.identifier(`value`),!1,!0):a)}else if(e.isJSXText())e.replaceWith(t.jsxExpressionContainer(t.optionalMemberExpression(t.identifier(n._contentVarName),t.stringLiteral(i),!0,!0)));else{let a=t.optionalMemberExpression(t.identifier(n._contentVarName),t.stringLiteral(i),!0,!0);e.replaceWith(r?t.optionalMemberExpression(a,t.identifier(`value`),!1,!0):a)}}n.opts.onExtract&&n._dictionaryKey&&n.opts.onExtract({dictionaryKey:n._dictionaryKey,filePath:n.file.opts.filename,content:{...n._extractedContent},locale:n.opts.defaultLocale});let u=!1,d=!1;for(let e of i){let r=h(e,n,t);r===`hook`&&(u=!0),r===`core`&&(d=!0)}if(n._hasTopLevelContent){d=!0;let r=n._contentVarName,i=n._dictionaryKey,a=n._getIntlayerLocalName,o=0,s=e.node.body;for(;o<s.length&&(t.isImportDeclaration(s[o])||t.isExpressionStatement(s[o])&&t.isStringLiteral(s[o].expression));)o++;e.node.body.splice(o,0,t.variableDeclaration(`const`,[t.variableDeclarator(t.identifier(r),t.callExpression(t.identifier(a),[t.stringLiteral(i)]))]))}if(u||d){let r=n.opts.packageName??`react-intlayer`;r===`next-intlayer`&&!n._isClient&&(r=`${r}/server`);let i=0,a=e.node.body;for(;i<a.length&&t.isExpressionStatement(a[i])&&t.isStringLiteral(a[i].expression);)i++;u&&!n._hasUseIntlayerImport&&a.splice(i++,0,t.importDeclaration([t.importSpecifier(t.identifier(`useIntlayer`),t.identifier(`useIntlayer`))],t.stringLiteral(r))),d&&!n._hasGetIntlayerImport&&a.splice(i,0,t.importDeclaration([t.importSpecifier(t.identifier(`getIntlayer`),t.identifier(`getIntlayer`))],t.stringLiteral(`intlayer`)))}}}}}},h=(e,t,n)=>{let r=e.node,i=t._contentVarName,a=t._dictionaryKey,o=f(e,n);if(!n.isBlockStatement(r.body)){let e=o?t._useIntlayerLocalName:t._getIntlayerLocalName,s=n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(e),[n.stringLiteral(a)]))]);return r.body=n.blockStatement([s,n.returnStatement(r.body)]),o?`hook`:`core`}let s=o?t._useIntlayerLocalName:t._getIntlayerLocalName;return r.body.body.some(e=>n.isVariableDeclaration(e)&&e.declarations.some(e=>n.isIdentifier(e.id)&&e.id.name===i))||r.body.body.unshift(n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(s),[n.stringLiteral(a)]))])),o?`hook`:`core`};export{m as intlayerExtractBabelPlugin};
1
+ import{execSync as e}from"node:child_process";import{existsSync as t,readFileSync as n,writeFileSync as r}from"node:fs";import{basename as i,dirname as a,extname as o,join as s,relative as c}from"node:path";import l from"@babel/generator";import{ATTRIBUTES_TO_EXTRACT as u,detectFormatCommand as d,shouldExtract as f}from"@intlayer/chokidar/cli";import{ANSIColors as p,colorize as m,colorizePath as h,getAppLogger as g}from"@intlayer/config/client";import{getConfiguration as _}from"@intlayer/config/node";import{generateKey as v}from"@intlayer/core/utils";const y=l.default??l,b=(e,t=`comp-`)=>{let n=i(e,o(e));return n===`index`&&(n=i(a(e))),`${t}${n.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}`},x=e=>{let r=e;for(;;){let e=s(r,`package.json`);if(t(e))try{let t=JSON.parse(n(e,`utf-8`));if(t.dependencies?.[`next-intlayer`]||t.devDependencies?.[`next-intlayer`])return`next-intlayer`;if(t.dependencies?.[`react-intlayer`]||t.devDependencies?.[`react-intlayer`])return`react-intlayer`;if(t.dependencies?.[`preact-intlayer`]||t.devDependencies?.[`preact-intlayer`])return`preact-intlayer`}catch{}let i=a(r);if(i===r)break;r=i}return`react-intlayer`},S=(e,t)=>{let n=e;for(;t.isParenthesizedExpression(n);)n=n.expression;return n},C=(e,t)=>{let n=e.node;if(!t.isBlockStatement(n.body)){let e=S(n.body,t);return t.isJSXElement(e)||t.isJSXFragment(e)}let r=!1;return e.traverse({Function(e){e.skip()},ReturnStatement(e){if(e.node.argument){let n=S(e.node.argument,t);(t.isJSXElement(n)||t.isJSXFragment(n))&&(r=!0)}}}),r},w=(e,t)=>{let n=e.getFunctionParent();if(!n)return null;let r=n;for(;r;){if(C(r,t))return r;r=r.getFunctionParent()}return n},T=t=>{let{types:n}=t,i=_(),o=g(i);return{name:`babel-plugin-intlayer-extract`,pre(){this._extractedContent={},this._existingKeys=new Set,this._isIncluded=!0,this._hasJSX=!1,this._hasUseIntlayerImport=!1,this._useIntlayerLocalName=`useIntlayer`,this._hasGetIntlayerImport=!1,this._getIntlayerLocalName=`getIntlayer`,this._contentVarName=`content`,this._isClient=!1,this._hasTopLevelContent=!1,this._extractionTargets=[],this._functionsToInject=new Set;let e=this.file.opts.filename;if(!this.opts.packageName){let t=e?a(e):process.cwd();this.opts.packageName=x(t)}if(!(this.opts.enabled??!0)){this._isIncluded=!1;return}if(this.opts.filesList&&e){let t=e.replace(/\\/g,`/`);this._isIncluded=this.opts.filesList.some(e=>e.replace(/\\/g,`/`)===t)}e&&(this._dictionaryKey=b(e,this.opts.prefix))},visitor:{ImportDeclaration(e,t){if(t._isIncluded)for(let r of e.node.specifiers){if(!n.isImportSpecifier(r))continue;let e=n.isIdentifier(r.imported)?r.imported.name:r.imported.value;e===`useIntlayer`&&(t._hasUseIntlayerImport=!0,t._useIntlayerLocalName=r.local.name),e===`getIntlayer`&&(t._hasGetIntlayerImport=!0,t._getIntlayerLocalName=r.local.name)}},JSXElement(e,t){t._isIncluded&&(t._hasJSX=!0)},JSXText(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let r=t.opts.shouldExtract??f,i=e.node.value;if(r(i)){let r=i.replace(/\s+/g,` `).trim(),a=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===r);a||(a=v(r,t._existingKeys),t._existingKeys.add(a),t._extractedContent[a]=r),t._extractionTargets.push({path:e,key:a,isAttribute:!1});let o=w(e,n);o?t._functionsToInject.add(o):t._hasTopLevelContent=!0}},JSXAttribute(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let r=t.opts.shouldExtract??f,i=e.node.name;if(!n.isJSXIdentifier(i))return;let a=i.name===`key`;if(!u.includes(i.name)&&!a)return;let o=e.node.value,s=null;if(n.isStringLiteral(o)?s=o.value:n.isJSXExpressionContainer(o)&&n.isStringLiteral(o.expression)&&(s=o.expression.value),s&&r(s)){let r=s.trim(),i=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===r);i||(i=v(r,t._existingKeys),t._existingKeys.add(i),t._extractedContent[i]=r),t._extractionTargets.push({path:e,key:i,isAttribute:!0});let a=w(e,n);a?t._functionsToInject.add(a):t._hasTopLevelContent=!0}},StringLiteral(e,t){if(!t._isIncluded||!t._dictionaryKey)return;let r=t.opts.shouldExtract??f,i=e.parentPath;if(i.isJSXAttribute()||i.isImportDeclaration()||i.isExportDeclaration()||i.isImportSpecifier()||i.isObjectProperty()&&e.key===`key`||i.isMemberExpression()&&e.key===`property`)return;if(i.isCallExpression()){let e=i.node.callee;if(n.isMemberExpression(e)&&n.isIdentifier(e.object)&&e.object.name===`console`||n.isIdentifier(e)&&(e.name===t._useIntlayerLocalName||e.name===t._getIntlayerLocalName||e.name===`require`)||e.type===`Import`)return}let a=e.node.value;if(r(a)){let r=a.trim(),i=Object.keys(t._extractedContent).find(e=>t._extractedContent[e]===r);i||(i=v(r,t._existingKeys),t._existingKeys.add(i),t._extractedContent[i]=r),t._extractionTargets.push({path:e,key:i,isAttribute:!1});let o=w(e,n);o?t._functionsToInject.add(o):t._hasTopLevelContent=!0}},Program:{enter(e,t){if(!t._isIncluded)return;t._isClient=e.node.directives.some(e=>e.value.value===`use client`);let r=!1;e.traverse({VariableDeclarator(e){n.isIdentifier(e.node.id)&&e.node.id.name===`content`&&(r=!0)}}),t._contentVarName=r?`_compContent`:`content`},exit(t,a){if(!a._isIncluded||!a._dictionaryKey)return;let s=a._extractionTargets,l=a._functionsToInject;if(s.length===0)return;for(let{path:e,key:t,isAttribute:r}of s){let i=!1,o=!1,s=e.scope.getBinding(a._contentVarName);if(s&&n.isVariableDeclarator(s.path.node)&&n.isCallExpression(s.path.node.init)&&n.isIdentifier(s.path.node.init.callee)&&(s.path.node.init.callee.name===a._useIntlayerLocalName?(i=!0,o=!0):s.path.node.init.callee.name===a._getIntlayerLocalName&&(i=!1,o=!0)),!o){let t=w(e,n);t&&(i=C(t,n))}if(r){let r=n.optionalMemberExpression(n.identifier(a._contentVarName),n.stringLiteral(t),!0,!0);e.node.value=n.jsxExpressionContainer(i?n.optionalMemberExpression(r,n.identifier(`value`),!1,!0):r)}else if(e.isJSXText())e.replaceWith(n.jsxExpressionContainer(n.optionalMemberExpression(n.identifier(a._contentVarName),n.stringLiteral(t),!0,!0)));else{let r=n.optionalMemberExpression(n.identifier(a._contentVarName),n.stringLiteral(t),!0,!0);e.replaceWith(i?n.optionalMemberExpression(r,n.identifier(`value`),!1,!0):r)}}a.opts.onExtract&&a._dictionaryKey&&a.opts.onExtract({dictionaryKey:a._dictionaryKey,filePath:a.file.opts.filename,content:{...a._extractedContent},locale:a.opts.defaultLocale});let u=!1,f=!1;for(let e of l){let t=E(e,a,n);t===`hook`&&(u=!0),t===`core`&&(f=!0)}if(a._hasTopLevelContent){f=!0;let e=a._contentVarName,r=a._dictionaryKey,i=a._getIntlayerLocalName,o=0,s=t.node.body;for(;o<s.length&&(n.isImportDeclaration(s[o])||n.isExpressionStatement(s[o])&&n.isStringLiteral(s[o].expression));)o++;t.node.body.splice(o,0,n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(e),n.callExpression(n.identifier(i),[n.stringLiteral(r)]))]))}if(u||f){let e=a.opts.packageName??`react-intlayer`;e===`next-intlayer`&&!a._isClient&&(e=`${e}/server`);let r=0,i=t.node.body;for(;r<i.length&&n.isExpressionStatement(i[r])&&n.isStringLiteral(i[r].expression);)r++;u&&!a._hasUseIntlayerImport&&i.splice(r++,0,n.importDeclaration([n.importSpecifier(n.identifier(`useIntlayer`),n.identifier(`useIntlayer`))],n.stringLiteral(e))),f&&!a._hasGetIntlayerImport&&i.splice(r,0,n.importDeclaration([n.importSpecifier(n.identifier(`getIntlayer`),n.identifier(`getIntlayer`))],n.stringLiteral(`intlayer`)))}if(a.opts.saveComponents&&a.file.opts.filename)try{let n=y(t.node,{retainLines:!0}).code;r(a.file.opts.filename,n,`utf-8`);let s=i.content?.baseDir??process.cwd(),l=c(s,a.file.opts.filename);o(`${m(`Compiler:`,p.GREY_DARK)} Saved component: ${h(l)}`,{level:`info`});let u=d(i);if(u)try{e(u.replace(`{{file}}`,a.file.opts.filename),{stdio:`ignore`,cwd:s})}catch(e){o(`Extractor formatting error: ${String(e)}`,{level:`error`})}}catch(e){o(`Extractor plugin error: ${String(e)}`,{level:`error`})}}}}}},E=(e,t,n)=>{let r=e.node,i=t._contentVarName,a=t._dictionaryKey,o=C(e,n);if(!n.isBlockStatement(r.body)){let e=o?t._useIntlayerLocalName:t._getIntlayerLocalName,s=n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(e),[n.stringLiteral(a)]))]);return r.body=n.blockStatement([s,n.returnStatement(r.body)]),o?`hook`:`core`}let s=o?t._useIntlayerLocalName:t._getIntlayerLocalName;return r.body.body.some(e=>n.isVariableDeclaration(e)&&e.declarations.some(e=>n.isIdentifier(e.id)&&e.id.name===i))||r.body.body.unshift(n.variableDeclaration(`const`,[n.variableDeclarator(n.identifier(i),n.callExpression(n.identifier(s),[n.stringLiteral(a)]))])),o?`hook`:`core`};export{T as intlayerExtractBabelPlugin};
2
2
  //# sourceMappingURL=babel-plugin-intlayer-extract.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":["shouldExtract","defaultShouldExtract"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { basename, dirname, extname, join } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport generator from '@babel/generator';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n} from '@intlayer/chokidar/cli';\nimport { generateKey } from '@intlayer/core/utils';\n\n// Set this to true to enable debug logs\nconst DEBUG_LOG = false;\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n\n /**\n * Whether the extraction compiler is enabled.\n * If false, the plugin will not process the file.\n */\n enabled?: boolean;\n\n /**\n * Prefix for the extracted dictionary keys.\n */\n prefix?: string;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n /** Whether the file has 'use client' directive */\n _isClient?: boolean;\n /** Whether there is extracted content at the top level (not in a function) */\n _hasTopLevelContent?: boolean;\n};\nconst extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = 'comp-'\n): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `${prefix}${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst detectPackageName = (dir: string): string => {\n let currentDir = dir;\n while (true) {\n const pkgPath = join(currentDir, 'package.json');\n\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n if (\n pkg.dependencies?.['next-intlayer'] ||\n pkg.devDependencies?.['next-intlayer']\n ) {\n return 'next-intlayer';\n }\n\n if (\n pkg.dependencies?.['react-intlayer'] ||\n pkg.devDependencies?.['react-intlayer']\n ) {\n return 'react-intlayer';\n }\n\n if (\n pkg.dependencies?.['preact-intlayer'] ||\n pkg.devDependencies?.['preact-intlayer']\n ) {\n return 'preact-intlayer';\n }\n } catch {}\n }\n const parentDir = dirname(currentDir);\n\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n return 'react-intlayer';\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n};\n\nconst isReactComponent = (\n funcPath: NodePath<BabelTypes.Function>,\n t: typeof BabelTypes\n): boolean => {\n const node = funcPath.node;\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n return t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n }\n let returnsJSX = false;\n funcPath.traverse({\n Function(p) {\n p.skip();\n },\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped)) {\n returnsJSX = true;\n }\n }\n },\n });\n return returnsJSX;\n};\n\nconst findTargetFunction = (\n startPath: NodePath<any>,\n t: typeof BabelTypes\n): NodePath<BabelTypes.Function> | null => {\n const closestFunc =\n startPath.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n if (!closestFunc) return null;\n\n let currentFunc: NodePath<BabelTypes.Function> | null = closestFunc;\n while (currentFunc) {\n if (isReactComponent(currentFunc, t)) {\n return currentFunc;\n }\n currentFunc =\n currentFunc.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n }\n return closestFunc;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n this._isClient = false;\n this._hasTopLevelContent = false;\n\n const filename = this.file.opts.filename;\n\n if (!this.opts.packageName) {\n const searchDir = filename ? dirname(filename) : process.cwd();\n this.opts.packageName = detectPackageName(searchDir);\n }\n\n // Check if extraction is enabled\n const isEnabled = this.opts.enabled ?? true;\n\n if (!isEnabled) {\n this._isIncluded = false;\n return;\n }\n\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(\n filename,\n this.opts.prefix\n );\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n\n // Check for 'use client' directive\n state._isClient = programPath.node.directives.some(\n (d) => d.value.value === 'use client'\n );\n\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n\n const extractionTargets: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[] = [];\n const functionsToInject = new Set<NodePath<BabelTypes.Function>>();\n const shouldExtract =\n state.opts.shouldExtract ?? defaultShouldExtract;\n\n const addTarget = (path: NodePath<any>) => {\n const func = findTargetFunction(path, t);\n\n if (func) {\n functionsToInject.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n };\n\n // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const rawText = path.node.value;\n\n if (shouldExtract(rawText)) {\n const text = rawText.replace(/\\s+/g, ' ').trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === text\n );\n\n if (!key) {\n key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text;\n }\n\n extractionTargets.push({ path, key, isAttribute: false });\n addTarget(path);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey)\n return;\n\n const value = path.node.value;\n let text: string | null = null;\n\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n extractionTargets.push({ path, key, isAttribute: true });\n addTarget(path);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n\n if (parent.isObjectProperty() && path.key === 'key') return;\n\n if (parent.isMemberExpression() && path.key === 'property')\n return;\n\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\n\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n\n if (shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n extractionTargets.push({ path, key, isAttribute: false });\n addTarget(path);\n }\n },\n });\n\n if (extractionTargets.length === 0) return;\n\n // Pass 2: Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n let isHook = false;\n let hookDecided = false;\n\n const binding = path.scope.getBinding(state._contentVarName!);\n\n if (\n binding &&\n t.isVariableDeclarator(binding.path.node) &&\n t.isCallExpression(binding.path.node.init) &&\n t.isIdentifier(binding.path.node.init.callee)\n ) {\n if (\n binding.path.node.init.callee.name ===\n state._useIntlayerLocalName\n ) {\n isHook = true;\n hookDecided = true;\n } else if (\n binding.path.node.init.callee.name ===\n state._getIntlayerLocalName\n ) {\n isHook = false;\n hookDecided = true;\n }\n }\n\n if (!hookDecided) {\n const func = findTargetFunction(path, t);\n\n if (func) {\n isHook = isReactComponent(func, t);\n }\n }\n\n if (isAttribute) {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.node.value = t.jsxExpressionContainer(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n )\n )\n );\n } else {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.replaceWith(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n }\n }\n\n // Report\n\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n\n if (type === 'hook') needsUseIntlayer = true;\n\n if (type === 'core') needsGetIntlayer = true;\n }\n\n if (state._hasTopLevelContent) {\n needsGetIntlayer = true;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const coreName = state._getIntlayerLocalName!;\n\n // Find injection position (after imports)\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n (t.isImportDeclaration(body[pos]) ||\n (t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )))\n )\n pos++;\n\n programPath.node.body.splice(\n pos,\n 0,\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(coreName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n // Pass 4: Imports\n\n if (needsUseIntlayer || needsGetIntlayer) {\n let hookPkg = state.opts.packageName ?? 'react-intlayer';\n const corePkg = 'intlayer';\n\n // Handle next-intlayer server/client split\n\n if (hookPkg === 'next-intlayer' && !state._isClient) {\n hookPkg = `${hookPkg}/server`;\n }\n\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(hookPkg)\n )\n );\n }\n\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(corePkg)\n )\n );\n }\n }\n\n if (DEBUG_LOG) {\n console.log(\n '[babel-plugin-intlayer-extract] Transformed:',\n state.file.opts.filename\n );\n\n console.log(\n generator(programPath.node, { retainLines: true }).code\n );\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const returnsJSX = isReactComponent(path, t);\n\n if (!t.isBlockStatement(node.body)) {\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n return returnsJSX ? 'hook' : 'core';\n }\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":["shouldExtract","defaultShouldExtract"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { basename, dirname, extname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport _generate from '@babel/generator';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n detectFormatCommand,\n} from '@intlayer/chokidar/cli';\nimport {\n ANSIColors,\n colorize,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { generateKey } from '@intlayer/core/utils';\n\nconst generate = ((_generate as any).default ?? _generate) as typeof _generate;\n\n// Set this to true to enable debug logs\nconst DEBUG_LOG = false;\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n\n /**\n * Whether the extraction compiler is enabled.\n * If false, the plugin will not process the file.\n */\n enabled?: boolean;\n\n /**\n * Prefix for the extracted dictionary keys.\n */\n prefix?: string;\n\n /**\n * Indicates if the components should be saved after being transformed.\n */\n saveComponents?: boolean;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n /** Whether the file has 'use client' directive */\n _isClient?: boolean;\n /** Whether there is extracted content at the top level (not in a function) */\n _hasTopLevelContent?: boolean;\n /** Targets to extract and modify */\n _extractionTargets?: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[];\n /** Functions to inject the hook/core logic into */\n _functionsToInject?: Set<NodePath<BabelTypes.Function>>;\n};\nconst extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = 'comp-'\n): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `${prefix}${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst detectPackageName = (dir: string): string => {\n let currentDir = dir;\n while (true) {\n const pkgPath = join(currentDir, 'package.json');\n\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n if (\n pkg.dependencies?.['next-intlayer'] ||\n pkg.devDependencies?.['next-intlayer']\n ) {\n return 'next-intlayer';\n }\n\n if (\n pkg.dependencies?.['react-intlayer'] ||\n pkg.devDependencies?.['react-intlayer']\n ) {\n return 'react-intlayer';\n }\n\n if (\n pkg.dependencies?.['preact-intlayer'] ||\n pkg.devDependencies?.['preact-intlayer']\n ) {\n return 'preact-intlayer';\n }\n } catch {}\n }\n const parentDir = dirname(currentDir);\n\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n return 'react-intlayer';\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n\n return current;\n};\n\nconst isReactComponent = (\n funcPath: NodePath<BabelTypes.Function>,\n t: typeof BabelTypes\n): boolean => {\n const node = funcPath.node;\n\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n return t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n }\n\n let returnsJSX = false;\n\n funcPath.traverse({\n Function(p) {\n p.skip();\n },\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped)) {\n returnsJSX = true;\n }\n }\n },\n });\n return returnsJSX;\n};\n\nconst findTargetFunction = (\n startPath: NodePath<any>,\n t: typeof BabelTypes\n): NodePath<BabelTypes.Function> | null => {\n const closestFunc =\n startPath.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n if (!closestFunc) return null;\n\n let currentFunc: NodePath<BabelTypes.Function> | null = closestFunc;\n while (currentFunc) {\n if (isReactComponent(currentFunc, t)) {\n return currentFunc;\n }\n currentFunc =\n currentFunc.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n }\n return closestFunc;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n const config = getConfiguration();\n const appLogger = getAppLogger(config);\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n this._isClient = false;\n this._hasTopLevelContent = false;\n this._extractionTargets = [];\n this._functionsToInject = new Set();\n\n const filename = this.file.opts.filename;\n\n if (!this.opts.packageName) {\n const searchDir = filename ? dirname(filename) : process.cwd();\n this.opts.packageName = detectPackageName(searchDir);\n }\n\n // Check if extraction is enabled\n const isEnabled = this.opts.enabled ?? true;\n\n if (!isEnabled) {\n this._isIncluded = false;\n return;\n }\n\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(\n filename,\n this.opts.prefix\n );\n },\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n JSXText(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const rawText = path.node.value;\n\n if (shouldExtract(rawText)) {\n const text = rawText.replace(/\\s+/g, ' ').trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === text\n );\n\n if (!key) {\n key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: false });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n JSXAttribute(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const attrName = path.node.name;\n\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey) return;\n\n const value = path.node.value;\n let text: string | null = null;\n\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: true });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n StringLiteral(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const parent = path.parentPath;\n\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n\n if (parent.isObjectProperty() && path.key === 'key') return;\n\n if (parent.isMemberExpression() && path.key === 'property') return;\n\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression).callee;\n\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n\n if (shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: false });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n\n // Check for 'use client' directive\n state._isClient = programPath.node.directives.some(\n (d) => d.value.value === 'use client'\n );\n\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n\n const extractionTargets = state._extractionTargets!;\n const functionsToInject = state._functionsToInject!;\n\n if (extractionTargets.length === 0) return;\n\n // Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n let isHook = false;\n let hookDecided = false;\n\n const binding = path.scope.getBinding(state._contentVarName!);\n\n if (\n binding &&\n t.isVariableDeclarator(binding.path.node) &&\n t.isCallExpression(binding.path.node.init) &&\n t.isIdentifier(binding.path.node.init.callee)\n ) {\n if (\n binding.path.node.init.callee.name ===\n state._useIntlayerLocalName\n ) {\n isHook = true;\n hookDecided = true;\n } else if (\n binding.path.node.init.callee.name ===\n state._getIntlayerLocalName\n ) {\n isHook = false;\n hookDecided = true;\n }\n }\n\n if (!hookDecided) {\n const func = findTargetFunction(path, t);\n\n if (func) {\n isHook = isReactComponent(func, t);\n }\n }\n\n if (isAttribute) {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.node.value = t.jsxExpressionContainer(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n )\n )\n );\n } else {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.replaceWith(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n }\n }\n\n // Report\n\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n\n if (type === 'hook') needsUseIntlayer = true;\n\n if (type === 'core') needsGetIntlayer = true;\n }\n\n if (state._hasTopLevelContent) {\n needsGetIntlayer = true;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const coreName = state._getIntlayerLocalName!;\n\n // Find injection position (after imports)\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n (t.isImportDeclaration(body[pos]) ||\n (t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )))\n )\n pos++;\n\n programPath.node.body.splice(\n pos,\n 0,\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(coreName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n // Pass 4: Imports\n\n if (needsUseIntlayer || needsGetIntlayer) {\n let hookPkg = state.opts.packageName ?? 'react-intlayer';\n const corePkg = 'intlayer';\n\n // Handle next-intlayer server/client split\n\n if (hookPkg === 'next-intlayer' && !state._isClient) {\n hookPkg = `${hookPkg}/server`;\n }\n\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(hookPkg)\n )\n );\n }\n\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(corePkg)\n )\n );\n }\n }\n\n if (state.opts.saveComponents && state.file.opts.filename) {\n try {\n const transformedCode = generate(programPath.node, {\n retainLines: true,\n }).code;\n\n writeFileSync(state.file.opts.filename, transformedCode, 'utf-8');\n\n const basedir = config.content?.baseDir ?? process.cwd();\n const relativePath = relative(basedir, state.file.opts.filename);\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Saved component: ${colorizePath(relativePath)}`,\n { level: 'info' }\n );\n\n const formatCommand = detectFormatCommand(config);\n\n if (formatCommand) {\n try {\n execSync(\n formatCommand.replace('{{file}}', state.file.opts.filename),\n {\n stdio: 'ignore', // Use 'ignore' to prevent format output from cluttering the extraction process console\n cwd: basedir,\n }\n );\n } catch (error) {\n appLogger(`Extractor formatting error: ${String(error)}`, {\n level: 'error',\n });\n }\n }\n } catch (err: any) {\n appLogger(`Extractor plugin error: ${String(err)}`, {\n level: 'error',\n });\n }\n }\n\n if (DEBUG_LOG) {\n const basedir = config.content?.baseDir ?? process.cwd();\n const relativePath = state.file.opts.filename\n ? relative(basedir, state.file.opts.filename)\n : 'unknown';\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Transformed: ${colorizePath(relativePath)}\\n${generate(programPath.node, { retainLines: false }).code}`,\n { level: 'debug' }\n );\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const returnsJSX = isReactComponent(path, t);\n\n if (!t.isBlockStatement(node.body)) {\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n\n return returnsJSX ? 'hook' : 'core';\n }\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{__require as e}from"./_virtual/_rolldown/runtime.mjs";import{existsSync as t}from"node:fs";import{join as n,relative as r}from"node:path";import{readFile as i}from"node:fs/promises";import{buildDictionary as a,writeContentDeclaration as o}from"@intlayer/chokidar/build";import{ANSIColors as s,colorize as c,getAppLogger as l}from"@intlayer/config/client";import{getConfiguration as u}from"@intlayer/config/node";const d=(d=process.env.INTLAYER_IS_DEV_COMMAND)=>{let f=u(),{baseDir:p}=f.content,m=n(p,f.compiler?.outputDir??`compiler`),h=async e=>{try{if(!t(e))return null;let n=await i(e,`utf-8`);if(!n||n.trim()===``)return null;let r=JSON.parse(n);return Array.isArray(r)?r[0]??null:r}catch(n){return t(e)&&(await i(e,`utf-8`)).trim()!==``&&console.warn(`[intlayer] Warning: Failed to read existing dictionary at ${e}. It might be corrupt. Translations may be lost. Error:`,n),null}},g=(e,t,n)=>{let r={},i=t?.content,a=Object.keys(e).sort();for(let t of a){let a=e[t],o=i?.[t];o&&o.nodeType===`translation`&&o.translation?r[t]={...o,nodeType:`translation`,translation:{...o.translation,[n]:o.translation[n]??a}}:r[t]={nodeType:`translation`,translation:{[n]:a}}}return r},_=async t=>{let{dictionaryKey:i,content:s,locale:c}=t;try{let e=await h(n(m,`${i}.content.json`)),t=g(s,e,c),l={...e,key:i,content:t,filePath:n(r(p,m),`${i}.content.json`)},u=await o(l,f,{newDictionariesPath:r(p,m)});await a([{...l,filePath:r(p,u.path)}],f)}catch(t){if(console.error(`[intlayer] Failed to process extracted content for ${i}:`,t),t instanceof SyntaxError&&t.message.includes(`Unexpected end of JSON input`)){let n=t.message.match(/^(.*\.json):\s*Unexpected end of JSON input/);if(n){let t=n[1];try{let n=e(`fs`).readFileSync(t,`utf-8`);console.error(`[intlayer] Content of the corrupted file (${t}):\n"${n}"`)}catch(e){console.error(`[intlayer] Could not read corrupted file ${t}`,e)}}}}},v=String(d)===`true`,y=f.compiler?.enabled===`build-only`?!v:f.compiler?.enabled??!0,b=l(f);return f.compiler?.enabled===`build-only`&&v&&b(`${c(`Compiler:`,s.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`),{enabled:y,defaultLocale:f.internationalization.defaultLocale,prefix:f.compiler?.dictionaryKeyPrefix,onExtract:_}};export{d as getExtractPluginOptions};
1
+ import{__require as e}from"./_virtual/_rolldown/runtime.mjs";import{existsSync as t}from"node:fs";import{join as n,relative as r}from"node:path";import{ANSIColors as i,colorize as a,getAppLogger as o}from"@intlayer/config/client";import{getConfiguration as s}from"@intlayer/config/node";import{readFile as c}from"node:fs/promises";import{buildDictionary as l,writeContentDeclaration as u}from"@intlayer/chokidar/build";const d=(d=process.env.INTLAYER_IS_DEV_COMMAND)=>{let f=s(),{baseDir:p}=f.content,m=n(p,f.compiler?.outputDir??`compiler`),h=async e=>{try{if(!t(e))return null;let n=await c(e,`utf-8`);if(!n||n.trim()===``)return null;let r=JSON.parse(n);return Array.isArray(r)?r[0]??null:r}catch(n){return t(e)&&(await c(e,`utf-8`)).trim()!==``&&console.warn(`[intlayer] Warning: Failed to read existing dictionary at ${e}. It might be corrupt. Translations may be lost. Error:`,n),null}},g=(e,t,n)=>{let r={},i=t?.content,a=Object.keys(e).sort();for(let t of a){let a=e[t],o=i?.[t];o&&o.nodeType===`translation`&&o.translation?r[t]={...o,nodeType:`translation`,translation:{...o.translation,[n]:o.translation[n]??a}}:r[t]={nodeType:`translation`,translation:{[n]:a}}}return r},_=async t=>{let{dictionaryKey:i,content:a,locale:o}=t;try{let e=await h(n(m,`${i}.content.json`)),t=g(a,e,o),s={...e,key:i,content:t,filePath:n(r(p,m),`${i}.content.json`)},c=await u(s,f,{newDictionariesPath:r(p,m)});await l([{...s,filePath:r(p,c.path)}],f)}catch(t){if(console.error(`[intlayer] Failed to process extracted content for ${i}:`,t),t instanceof SyntaxError&&t.message.includes(`Unexpected end of JSON input`)){let n=t.message.match(/^(.*\.json):\s*Unexpected end of JSON input/);if(n){let t=n[1];try{let n=e(`fs`).readFileSync(t,`utf-8`);console.error(`[intlayer] Content of the corrupted file (${t}):\n"${n}"`)}catch(e){console.error(`[intlayer] Could not read corrupted file ${t}`,e)}}}}},v=String(d)===`true`,y=f.compiler?.enabled===`build-only`?!v:f.compiler?.enabled??!0,b=o(f);return f.compiler?.enabled===`build-only`&&v&&b(`${a(`Compiler:`,i.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`),{enabled:y,defaultLocale:f.internationalization.defaultLocale,prefix:f.compiler?.dictionaryKeyPrefix,saveComponents:f.compiler?.saveComponents,onExtract:_}};export{d as getExtractPluginOptions};
2
2
  //# sourceMappingURL=getExtractPluginOptions.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"getExtractPluginOptions.mjs","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Dictionary } from '@intlayer/types';\nimport type {\n ExtractPluginOptions,\n ExtractResult,\n} from './babel-plugin-intlayer-extract';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n isDev = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n const config = getConfiguration();\n const { baseDir } = config.content;\n\n const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler');\n\n /**\n * Read existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryPath: string\n ): Promise<Dictionary | null> => {\n try {\n if (!existsSync(dictionaryPath)) {\n return null;\n }\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (!content || content.trim() === '') {\n return null;\n }\n\n const parsed = JSON.parse(content);\n\n if (Array.isArray(parsed)) {\n return (parsed[0] ?? null) as Dictionary | null;\n }\n\n return parsed as Dictionary;\n } catch (error) {\n if (existsSync(dictionaryPath)) {\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (content.trim() !== '') {\n console.warn(\n `[intlayer] Warning: Failed to read existing dictionary at ${dictionaryPath}. It might be corrupt. Translations may be lost. Error:`,\n error\n );\n }\n }\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary, preserving translations.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n const sortedKeys = Object.keys(extractedContent).sort();\n\n for (const key of sortedKeys) {\n const value = extractedContent[key];\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n // Key exists in both - preserve existing translations AND existing metadata\n mergedContent[key] = {\n ...existingEntry,\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: existingEntry.translation[defaultLocale] ?? value,\n },\n };\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n }\n\n return mergedContent;\n };\n\n const handleExtractedContent = async (result: ExtractResult) => {\n const { dictionaryKey, content, locale } = result;\n\n try {\n const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`);\n\n // Read existing dictionary to preserve translations\n const existingDictionary = await readExistingDictionary(dictionaryPath);\n\n // Merge extracted content with existing translations\n const mergedContent = mergeWithExistingDictionary(\n content,\n existingDictionary,\n locale\n );\n\n const dictionary: Dictionary = {\n ...existingDictionary,\n key: dictionaryKey,\n content: mergedContent,\n filePath: join(\n relative(baseDir, compilerDir),\n `${dictionaryKey}.content.json`\n ),\n };\n\n const writeResult = await writeContentDeclaration(dictionary, config, {\n newDictionariesPath: relative(baseDir, compilerDir),\n });\n\n // Build the dictionary immediately\n const dictionaryToBuild: Dictionary = {\n ...dictionary,\n filePath: relative(baseDir, writeResult.path),\n };\n\n await buildDictionary([dictionaryToBuild], config);\n } catch (error: any) {\n console.error(\n `[intlayer] Failed to process extracted content for ${dictionaryKey}:`,\n error\n );\n if (\n error instanceof SyntaxError &&\n error.message.includes('Unexpected end of JSON input')\n ) {\n const match = error.message.match(\n /^(.*\\.json):\\s*Unexpected end of JSON input/\n );\n if (match) {\n const filePath = match[1];\n try {\n const fs = require('fs');\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n console.error(\n `[intlayer] Content of the corrupted file (${filePath}):\\n\"${fileContent}\"`\n );\n } catch (e) {\n console.error(\n `[intlayer] Could not read corrupted file ${filePath}`,\n e\n );\n }\n }\n }\n }\n };\n\n const isDevBoolean = String(isDev) === 'true';\n const isEnabled =\n config.compiler?.enabled === 'build-only'\n ? !isDevBoolean\n : (config.compiler?.enabled ?? true);\n\n const logger = getAppLogger(config);\n\n if (config.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n return {\n enabled: isEnabled,\n defaultLocale: config.internationalization.defaultLocale,\n prefix: config.compiler?.dictionaryKeyPrefix,\n // filesList can be passed if needed, but usually handled by include/exclude in build tool\n onExtract: handleExtractedContent,\n };\n};\n"],"mappings":"maAiCA,MAAa,GACX,EAAQ,QAAQ,IAAI,0BACK,CACzB,IAAM,EAAS,GAAkB,CAC3B,CAAE,WAAY,EAAO,QAErB,EAAc,EAAK,EAAS,EAAO,UAAU,WAAa,WAAW,CAKrE,EAAyB,KAC7B,IAC+B,CAC/B,GAAI,CACF,GAAI,CAAC,EAAW,EAAe,CAC7B,OAAO,KAET,IAAM,EAAU,MAAM,EAAS,EAAgB,QAAQ,CAEvD,GAAI,CAAC,GAAW,EAAQ,MAAM,GAAK,GACjC,OAAO,KAGT,IAAM,EAAS,KAAK,MAAM,EAAQ,CAMlC,OAJI,MAAM,QAAQ,EAAO,CACf,EAAO,IAAM,KAGhB,QACA,EAAO,CAWd,OAVI,EAAW,EAAe,GACZ,MAAM,EAAS,EAAgB,QAAQ,EAE3C,MAAM,GAAK,IACrB,QAAQ,KACN,6DAA6D,EAAe,yDAC5E,EACD,CAGE,OAUL,GACJ,EACA,EACA,IACyB,CACzB,IAAM,EAAsC,EAAE,CACxC,EAAkB,GAAoB,QAItC,EAAa,OAAO,KAAK,EAAiB,CAAC,MAAM,CAEvD,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAiB,GACzB,EAAgB,IAAkB,GAGtC,GACA,EAAc,WAAa,eAC3B,EAAc,YAGd,EAAc,GAAO,CACnB,GAAG,EACH,SAAU,cACV,YAAa,CACX,GAAG,EAAc,aAChB,GAAgB,EAAc,YAAY,IAAkB,EAC9D,CACF,CAGD,EAAc,GAAO,CACnB,SAAU,cACV,YAAa,EACV,GAAgB,EAClB,CACF,CAIL,OAAO,GAGH,EAAyB,KAAO,IAA0B,CAC9D,GAAM,CAAE,gBAAe,UAAS,UAAW,EAE3C,GAAI,CAIF,IAAM,EAAqB,MAAM,EAHV,EAAK,EAAa,GAAG,EAAc,eAAe,CAGF,CAGjE,EAAgB,EACpB,EACA,EACA,EACD,CAEK,EAAyB,CAC7B,GAAG,EACH,IAAK,EACL,QAAS,EACT,SAAU,EACR,EAAS,EAAS,EAAY,CAC9B,GAAG,EAAc,eAClB,CACF,CAEK,EAAc,MAAM,EAAwB,EAAY,EAAQ,CACpE,oBAAqB,EAAS,EAAS,EAAY,CACpD,CAAC,CAQF,MAAM,EAAgB,CALgB,CACpC,GAAG,EACH,SAAU,EAAS,EAAS,EAAY,KAAK,CAC9C,CAEwC,CAAE,EAAO,OAC3C,EAAY,CAKnB,GAJA,QAAQ,MACN,sDAAsD,EAAc,GACpE,EACD,CAEC,aAAiB,aACjB,EAAM,QAAQ,SAAS,+BAA+B,CACtD,CACA,IAAM,EAAQ,EAAM,QAAQ,MAC1B,8CACD,CACD,GAAI,EAAO,CACT,IAAM,EAAW,EAAM,GACvB,GAAI,CAEF,IAAM,EAAA,EADa,KAAK,CACD,aAAa,EAAU,QAAQ,CACtD,QAAQ,MACN,6CAA6C,EAAS,OAAO,EAAY,GAC1E,OACM,EAAG,CACV,QAAQ,MACN,4CAA4C,IAC5C,EACD,MAOL,EAAe,OAAO,EAAM,GAAK,OACjC,EACJ,EAAO,UAAU,UAAY,aACzB,CAAC,EACA,EAAO,UAAU,SAAW,GAE7B,EAAS,EAAa,EAAO,CAQnC,OANI,EAAO,UAAU,UAAY,cAAgB,GAC/C,EACE,GAAG,EAAS,YAAa,EAAW,UAAU,CAAC,wIAChD,CAGI,CACL,QAAS,EACT,cAAe,EAAO,qBAAqB,cAC3C,OAAQ,EAAO,UAAU,oBAEzB,UAAW,EACZ"}
1
+ {"version":3,"file":"getExtractPluginOptions.mjs","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Dictionary } from '@intlayer/types';\nimport type {\n ExtractPluginOptions,\n ExtractResult,\n} from './babel-plugin-intlayer-extract';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n isDev = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n const config = getConfiguration();\n const { baseDir } = config.content;\n\n const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler');\n\n /**\n * Read existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryPath: string\n ): Promise<Dictionary | null> => {\n try {\n if (!existsSync(dictionaryPath)) {\n return null;\n }\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (!content || content.trim() === '') {\n return null;\n }\n\n const parsed = JSON.parse(content);\n\n if (Array.isArray(parsed)) {\n return (parsed[0] ?? null) as Dictionary | null;\n }\n\n return parsed as Dictionary;\n } catch (error) {\n if (existsSync(dictionaryPath)) {\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (content.trim() !== '') {\n console.warn(\n `[intlayer] Warning: Failed to read existing dictionary at ${dictionaryPath}. It might be corrupt. Translations may be lost. Error:`,\n error\n );\n }\n }\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary, preserving translations.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n const sortedKeys = Object.keys(extractedContent).sort();\n\n for (const key of sortedKeys) {\n const value = extractedContent[key];\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n // Key exists in both - preserve existing translations AND existing metadata\n mergedContent[key] = {\n ...existingEntry,\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: existingEntry.translation[defaultLocale] ?? value,\n },\n };\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n }\n\n return mergedContent;\n };\n\n const handleExtractedContent = async (result: ExtractResult) => {\n const { dictionaryKey, content, locale } = result;\n\n try {\n const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`);\n\n // Read existing dictionary to preserve translations\n const existingDictionary = await readExistingDictionary(dictionaryPath);\n\n // Merge extracted content with existing translations\n const mergedContent = mergeWithExistingDictionary(\n content,\n existingDictionary,\n locale\n );\n\n const dictionary: Dictionary = {\n ...existingDictionary,\n key: dictionaryKey,\n content: mergedContent,\n filePath: join(\n relative(baseDir, compilerDir),\n `${dictionaryKey}.content.json`\n ),\n };\n\n const writeResult = await writeContentDeclaration(dictionary, config, {\n newDictionariesPath: relative(baseDir, compilerDir),\n });\n\n // Build the dictionary immediately\n const dictionaryToBuild: Dictionary = {\n ...dictionary,\n filePath: relative(baseDir, writeResult.path),\n };\n\n await buildDictionary([dictionaryToBuild], config);\n } catch (error: any) {\n console.error(\n `[intlayer] Failed to process extracted content for ${dictionaryKey}:`,\n error\n );\n if (\n error instanceof SyntaxError &&\n error.message.includes('Unexpected end of JSON input')\n ) {\n const match = error.message.match(\n /^(.*\\.json):\\s*Unexpected end of JSON input/\n );\n if (match) {\n const filePath = match[1];\n try {\n const fs = require('fs');\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n console.error(\n `[intlayer] Content of the corrupted file (${filePath}):\\n\"${fileContent}\"`\n );\n } catch (e) {\n console.error(\n `[intlayer] Could not read corrupted file ${filePath}`,\n e\n );\n }\n }\n }\n }\n };\n\n const isDevBoolean = String(isDev) === 'true';\n const isEnabled =\n config.compiler?.enabled === 'build-only'\n ? !isDevBoolean\n : (config.compiler?.enabled ?? true);\n\n const logger = getAppLogger(config);\n\n if (config.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n return {\n enabled: isEnabled,\n defaultLocale: config.internationalization.defaultLocale,\n prefix: config.compiler?.dictionaryKeyPrefix,\n saveComponents: config.compiler?.saveComponents,\n // filesList can be passed if needed, but usually handled by include/exclude in build tool\n onExtract: handleExtractedContent,\n };\n};\n"],"mappings":"maAiCA,MAAa,GACX,EAAQ,QAAQ,IAAI,0BACK,CACzB,IAAM,EAAS,GAAkB,CAC3B,CAAE,WAAY,EAAO,QAErB,EAAc,EAAK,EAAS,EAAO,UAAU,WAAa,WAAW,CAKrE,EAAyB,KAC7B,IAC+B,CAC/B,GAAI,CACF,GAAI,CAAC,EAAW,EAAe,CAC7B,OAAO,KAET,IAAM,EAAU,MAAM,EAAS,EAAgB,QAAQ,CAEvD,GAAI,CAAC,GAAW,EAAQ,MAAM,GAAK,GACjC,OAAO,KAGT,IAAM,EAAS,KAAK,MAAM,EAAQ,CAMlC,OAJI,MAAM,QAAQ,EAAO,CACf,EAAO,IAAM,KAGhB,QACA,EAAO,CAWd,OAVI,EAAW,EAAe,GACZ,MAAM,EAAS,EAAgB,QAAQ,EAE3C,MAAM,GAAK,IACrB,QAAQ,KACN,6DAA6D,EAAe,yDAC5E,EACD,CAGE,OAUL,GACJ,EACA,EACA,IACyB,CACzB,IAAM,EAAsC,EAAE,CACxC,EAAkB,GAAoB,QAItC,EAAa,OAAO,KAAK,EAAiB,CAAC,MAAM,CAEvD,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAiB,GACzB,EAAgB,IAAkB,GAGtC,GACA,EAAc,WAAa,eAC3B,EAAc,YAGd,EAAc,GAAO,CACnB,GAAG,EACH,SAAU,cACV,YAAa,CACX,GAAG,EAAc,aAChB,GAAgB,EAAc,YAAY,IAAkB,EAC9D,CACF,CAGD,EAAc,GAAO,CACnB,SAAU,cACV,YAAa,EACV,GAAgB,EAClB,CACF,CAIL,OAAO,GAGH,EAAyB,KAAO,IAA0B,CAC9D,GAAM,CAAE,gBAAe,UAAS,UAAW,EAE3C,GAAI,CAIF,IAAM,EAAqB,MAAM,EAHV,EAAK,EAAa,GAAG,EAAc,eAAe,CAGF,CAGjE,EAAgB,EACpB,EACA,EACA,EACD,CAEK,EAAyB,CAC7B,GAAG,EACH,IAAK,EACL,QAAS,EACT,SAAU,EACR,EAAS,EAAS,EAAY,CAC9B,GAAG,EAAc,eAClB,CACF,CAEK,EAAc,MAAM,EAAwB,EAAY,EAAQ,CACpE,oBAAqB,EAAS,EAAS,EAAY,CACpD,CAAC,CAQF,MAAM,EAAgB,CALgB,CACpC,GAAG,EACH,SAAU,EAAS,EAAS,EAAY,KAAK,CAC9C,CAEwC,CAAE,EAAO,OAC3C,EAAY,CAKnB,GAJA,QAAQ,MACN,sDAAsD,EAAc,GACpE,EACD,CAEC,aAAiB,aACjB,EAAM,QAAQ,SAAS,+BAA+B,CACtD,CACA,IAAM,EAAQ,EAAM,QAAQ,MAC1B,8CACD,CACD,GAAI,EAAO,CACT,IAAM,EAAW,EAAM,GACvB,GAAI,CAEF,IAAM,EAAA,EADa,KAAK,CACD,aAAa,EAAU,QAAQ,CACtD,QAAQ,MACN,6CAA6C,EAAS,OAAO,EAAY,GAC1E,OACM,EAAG,CACV,QAAQ,MACN,4CAA4C,IAC5C,EACD,MAOL,EAAe,OAAO,EAAM,GAAK,OACjC,EACJ,EAAO,UAAU,UAAY,aACzB,CAAC,EACA,EAAO,UAAU,SAAW,GAE7B,EAAS,EAAa,EAAO,CAQnC,OANI,EAAO,UAAU,UAAY,cAAgB,GAC/C,EACE,GAAG,EAAS,YAAa,EAAW,UAAU,CAAC,wIAChD,CAGI,CACL,QAAS,EACT,cAAe,EAAO,qBAAqB,cAC3C,OAAQ,EAAO,UAAU,oBACzB,eAAgB,EAAO,UAAU,eAEjC,UAAW,EACZ"}
@@ -1,2 +1,2 @@
1
- import{__require as e}from"./_virtual/_rolldown/runtime.mjs";import{join as t}from"node:path";import{getComponentTransformPatternSync as n}from"@intlayer/chokidar/utils";import{getConfiguration as r}from"@intlayer/config/node";const i=t=>{try{let{getDictionaries:n}=e(`@intlayer/dictionaries-entry`),r=n(t);return Object.values(r)}catch{return[]}},a=e=>{let{configOptions:a,dictionaries:o,overrides:s}=e??{},c=r(a),{mainDir:l,dictionariesDir:u,unmergedDictionariesDir:d,dynamicDictionariesDir:f,fetchDictionariesDir:p}=c.system,{importMode:m,optimize:h}=c.build,g=n(c),_=t(l,`dictionaries.mjs`),v=t(l,`unmerged_dictionaries.mjs`),y=t(l,`dynamic_dictionaries.mjs`),b=t(l,`fetch_dictionaries.mjs`),x=[...g,_,v],S=o??i(c),C={};return S.forEach(e=>{C[e.key]=e.importMode??m}),{optimize:h,dictionariesDir:u,dictionariesEntryPath:_,unmergedDictionariesDir:d,unmergedDictionariesEntryPath:v,dynamicDictionariesDir:f,dynamicDictionariesEntryPath:y,fetchDictionariesDir:p,fetchDictionariesEntryPath:b,replaceDictionaryEntry:!0,importMode:m,dictionaryModeMap:C,filesList:x,...s}};export{a as getOptimizePluginOptions};
1
+ import{__require as e}from"./_virtual/_rolldown/runtime.mjs";import{join as t}from"node:path";import{getConfiguration as n}from"@intlayer/config/node";import{getComponentTransformPatternSync as r}from"@intlayer/chokidar/utils";const i=t=>{try{let{getDictionaries:n}=e(`@intlayer/dictionaries-entry`),r=n(t);return Object.values(r)}catch{return[]}},a=e=>{let{configOptions:a,dictionaries:o,overrides:s}=e??{},c=n(a),{mainDir:l,dictionariesDir:u,unmergedDictionariesDir:d,dynamicDictionariesDir:f,fetchDictionariesDir:p}=c.system,{importMode:m,optimize:h}=c.build,g=r(c),_=t(l,`dictionaries.mjs`),v=t(l,`unmerged_dictionaries.mjs`),y=t(l,`dynamic_dictionaries.mjs`),b=t(l,`fetch_dictionaries.mjs`),x=[...g,_,v],S=o??i(c),C={};return S.forEach(e=>{C[e.key]=e.importMode??m}),{optimize:h,dictionariesDir:u,dictionariesEntryPath:_,unmergedDictionariesDir:d,unmergedDictionariesEntryPath:v,dynamicDictionariesDir:f,dynamicDictionariesEntryPath:y,fetchDictionariesDir:p,fetchDictionariesEntryPath:b,replaceDictionaryEntry:!0,importMode:m,dictionaryModeMap:C,filesList:x,...s}};export{a as getOptimizePluginOptions};
2
2
  //# sourceMappingURL=getOptimizePluginOptions.mjs.map
@@ -1,4 +1,4 @@
1
- import { PluginObj, PluginPass } from "@babel/core";
1
+ import { NodePath, PluginObj, PluginPass } from "@babel/core";
2
2
  import * as BabelTypes from "@babel/types";
3
3
 
4
4
  //#region src/babel-plugin-intlayer-extract.d.ts
@@ -48,6 +48,10 @@ type ExtractPluginOptions = {
48
48
  * Prefix for the extracted dictionary keys.
49
49
  */
50
50
  prefix?: string;
51
+ /**
52
+ * Indicates if the components should be saved after being transformed.
53
+ */
54
+ saveComponents?: boolean;
51
55
  };
52
56
  type State = PluginPass & {
53
57
  opts: ExtractPluginOptions; /** Extracted content from this file */
@@ -62,7 +66,13 @@ type State = PluginPass & {
62
66
  _getIntlayerLocalName?: string; /** The variable name to use for content (content or _compContent if content is already used) */
63
67
  _contentVarName?: string; /** Whether the file has 'use client' directive */
64
68
  _isClient?: boolean; /** Whether there is extracted content at the top level (not in a function) */
65
- _hasTopLevelContent?: boolean;
69
+ _hasTopLevelContent?: boolean; /** Targets to extract and modify */
70
+ _extractionTargets?: {
71
+ path: NodePath<any>;
72
+ key: string;
73
+ isAttribute: boolean;
74
+ }[]; /** Functions to inject the hook/core logic into */
75
+ _functionsToInject?: Set<NodePath<BabelTypes.Function>>;
66
76
  };
67
77
  declare const intlayerExtractBabelPlugin: (babel: {
68
78
  types: typeof BabelTypes;
@@ -1 +1 @@
1
- {"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;KAcK,gBAAA,GAAmB,MAAA;;AAVwB;;KAepC,aAAA;EALY,gDAOtB,aAAA,UAFU;EAIV,QAAA;EAEA,OAAA,EAAS,gBAAA,EAJT;EAMA,MAAA;AAAA;;;;KAMU,oBAAA;EAAA;;;EAIV,aAAA;EAAA;;;;EAKA,WAAA;EAcA;;;EAVA,SAAA;EAqBA;;;EAjBA,aAAA,IAAiB,IAAA;EAoBT;;;;;EAdR,SAAA,IAAa,MAAA,EAAQ,aAAA;EAmBF;;;;EAbnB,OAAA;EAWA;;;EANA,MAAA;AAAA;AAAA,KAGG,KAAA,GAAQ,UAAA;EACX,IAAA,EAAM,oBAAA,EAYN;EAVA,iBAAA,GAAoB,gBAAA,EAcpB;EAZA,aAAA,GAAgB,GAAA,UAgBhB;EAdA,cAAA,WAkBA;EAhBA,WAAA,YAgBmB;EAdnB,OAAA,YAujBD;EArjBC,qBAAA,YA4Hc;EA1Hd,qBAAA,WA2HE;EAzHF,qBAAA,YAyHW;EAvHX,qBAAA,WAsHc;EApHd,eAAA,WAqHE;EAnHF,SAAA,YAmHiB;EAjHjB,mBAAA;AAAA;AAAA,cA+GW,0BAAA,GAA8B,KAAA;EACzC,KAAA,SAAc,UAAA;AAAA,MACZ,SAAA,CAAU,KAAA"}
1
+ {"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;KAyBK,gBAAA,GAAmB,MAAA;;AApBwB;;KAyBpC,aAAA;EALY,gDAOtB,aAAA,UAFU;EAIV,QAAA;EAEA,OAAA,EAAS,gBAAA,EAJT;EAMA,MAAA;AAAA;;;;KAMU,oBAAA;EAAA;;;EAIV,aAAA;EAAA;;;;EAKA,WAAA;EAcA;;;EAVA,SAAA;EAqBA;;;EAjBA,aAAA,IAAiB,IAAA;EAyBd;;;;;EAnBH,SAAA,IAAa,MAAA,EAAQ,aAAA;EAwBL;;;;EAlBhB,OAAA;EA8CwB;;;EAzCxB,MAAA;EASM;;;EAJN,cAAA;AAAA;AAAA,KAGG,KAAA,GAAQ,UAAA;EACX,IAAA,EAAM,oBAAA,EAUN;EARA,iBAAA,GAAoB,gBAAA,EAYpB;EAVA,aAAA,GAAgB,GAAA,UAchB;EAZA,cAAA,WAgBA;EAdA,WAAA,YAkBA;EAhBA,OAAA,YAiBQ;EAfR,qBAAA,YAiBE;EAfF,qBAAA,WAkBqB;EAhBrB,qBAAA,YAgBkC;EAdlC,qBAAA,WAcqD;EAZrD,eAAA,WAgIW;EA9HX,SAAA;EAEA,mBAAA,YA8HY;EA5HZ,kBAAA;IACE,IAAA,EAAM,QAAA;IACN,GAAA;IACA,WAAA;EAAA,KAuHuC;EApHzC,kBAAA,GAAqB,GAAA,CAAI,QAAA,CAAS,UAAA,CAAW,QAAA;AAAA;AAAA,cAoHlC,0BAAA,GAA8B,KAAA;EACzC,KAAA,SAAc,UAAA;AAAA,MACZ,SAAA,CAAU,KAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/babel",
3
- "version": "8.1.7",
3
+ "version": "8.1.8",
4
4
  "private": false,
5
5
  "description": "A Babel plugin for Intlayer that transforms declaration files and provides internationalization features during the build process according to the Intlayer configuration.",
6
6
  "keywords": [
@@ -80,10 +80,10 @@
80
80
  "@babel/parser": "7.1.5",
81
81
  "@babel/traverse": "7.28.0",
82
82
  "@babel/types": "7.28.4",
83
- "@intlayer/chokidar": "8.1.7",
84
- "@intlayer/config": "8.1.7",
85
- "@intlayer/core": "8.1.7",
86
- "@intlayer/types": "8.1.7",
83
+ "@intlayer/chokidar": "8.1.8",
84
+ "@intlayer/config": "8.1.8",
85
+ "@intlayer/core": "8.1.8",
86
+ "@intlayer/types": "8.1.8",
87
87
  "@types/babel__core": "7.20.5",
88
88
  "@types/babel__generator": "7.27.0",
89
89
  "@types/babel__traverse": "7.28.0",
@@ -91,7 +91,7 @@
91
91
  },
92
92
  "devDependencies": {
93
93
  "@babel/plugin-syntax-jsx": "^7.28.6",
94
- "@intlayer/dictionaries-entry": "8.1.7",
94
+ "@intlayer/dictionaries-entry": "8.1.8",
95
95
  "@types/crypto-js": "4.2.2",
96
96
  "@types/node": "25.3.0",
97
97
  "@utils/ts-config": "1.0.4",
@@ -104,7 +104,7 @@
104
104
  "vitest": "4.0.18"
105
105
  },
106
106
  "peerDependencies": {
107
- "@intlayer/dictionaries-entry": "8.1.7"
107
+ "@intlayer/dictionaries-entry": "8.1.8"
108
108
  },
109
109
  "peerDependenciesMeta": {
110
110
  "@intlayer/dictionaries-entry": {