@intlayer/babel 8.0.0-canary.1 → 8.0.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/babel-plugin-intlayer-extract.cjs +2 -2
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/esm/_virtual/rolldown_runtime.mjs +1 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs +7 -7
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/types/babel-plugin-intlayer-extract.d.ts +13 -27
- package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts +6 -13
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/dist/types/getExtractPluginOptions.d.ts +0 -1
- package/dist/types/getExtractPluginOptions.d.ts.map +1 -1
- package/dist/types/getOptimizePluginOptions.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -167,8 +167,8 @@ const injectHook = (path, state, t) => {
|
|
|
167
167
|
if (!t.isBlockStatement(node.body)) {
|
|
168
168
|
const unwrapped = unwrapParentheses(node.body, t);
|
|
169
169
|
const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);
|
|
170
|
-
const hookName
|
|
171
|
-
const hookCall = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(contentVarName), t.callExpression(t.identifier(hookName
|
|
170
|
+
const hookName = isJSX ? state._useIntlayerLocalName : state._getIntlayerLocalName;
|
|
171
|
+
const hookCall = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(contentVarName), t.callExpression(t.identifier(hookName), [t.stringLiteral(dictionaryKey)]))]);
|
|
172
172
|
node.body = t.blockStatement([hookCall, t.returnStatement(node.body)]);
|
|
173
173
|
return isJSX ? "hook" : "core";
|
|
174
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["defaultShouldExtract","ATTRIBUTES_TO_EXTRACT","hookName"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n generateKey,\n} from '@intlayer/chokidar';\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\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};\nconst extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `comp-${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\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\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\n const filename = this.file.opts.filename;\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 if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(filename);\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\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 if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\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 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._hasJSX) 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 // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text\n .replace(/\\s+/g, ' ')\n .trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\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 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 key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: true });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n if (parent.isObjectProperty() && path.key === 'key') return;\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\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 if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\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 if (isAttribute) {\n const member = t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n );\n path.node.value = t.jsxExpressionContainer(\n t.memberExpression(member, t.identifier('value'))\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n )\n );\n } else {\n path.replaceWith(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n );\n }\n }\n\n // Report\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 if (type === 'hook') needsUseIntlayer = true;\n if (type === 'core') needsGetIntlayer = true;\n }\n\n // Pass 4: Imports\n if (needsUseIntlayer || needsGetIntlayer) {\n const pkg = state.opts.packageName!;\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(pkg)\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(pkg)\n )\n );\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\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n const hookName = isJSX\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 isJSX ? 'hook' : 'core';\n }\n\n let returnsJSX = false;\n path.traverse({\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped))\n returnsJSX = true;\n }\n },\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":["defaultShouldExtract","ATTRIBUTES_TO_EXTRACT"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n generateKey,\n} from '@intlayer/chokidar';\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\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};\nconst extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `comp-${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\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\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\n const filename = this.file.opts.filename;\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 if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(filename);\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\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 if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\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 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._hasJSX) 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 // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text\n .replace(/\\s+/g, ' ')\n .trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\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 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 key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: true });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n if (parent.isObjectProperty() && path.key === 'key') return;\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\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 if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\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 if (isAttribute) {\n const member = t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n );\n path.node.value = t.jsxExpressionContainer(\n t.memberExpression(member, t.identifier('value'))\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n )\n );\n } else {\n path.replaceWith(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n );\n }\n }\n\n // Report\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 if (type === 'hook') needsUseIntlayer = true;\n if (type === 'core') needsGetIntlayer = true;\n }\n\n // Pass 4: Imports\n if (needsUseIntlayer || needsGetIntlayer) {\n const pkg = state.opts.packageName!;\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(pkg)\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(pkg)\n )\n );\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\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n const hookName = isJSX\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 isJSX ? 'hook' : 'core';\n }\n\n let returnsJSX = false;\n path.traverse({\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped))\n returnsJSX = true;\n }\n },\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,7 +1,7 @@
|
|
|
1
1
|
//#region rolldown:runtime
|
|
2
2
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
|
|
3
3
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
4
|
-
throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function.");
|
|
4
|
+
throw Error("Calling `require` for \"" + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
|
|
5
5
|
});
|
|
6
6
|
|
|
7
7
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, dirname, extname } from "node:path";
|
|
2
|
-
import { ATTRIBUTES_TO_EXTRACT, generateKey, shouldExtract } from "@intlayer/chokidar";
|
|
2
|
+
import { ATTRIBUTES_TO_EXTRACT, generateKey, shouldExtract as shouldExtract$1 } from "@intlayer/chokidar";
|
|
3
3
|
|
|
4
4
|
//#region src/babel-plugin-intlayer-extract.ts
|
|
5
5
|
const extractDictionaryKeyFromPath = (filePath) => {
|
|
@@ -66,11 +66,11 @@ const intlayerExtractBabelPlugin = (babel) => {
|
|
|
66
66
|
if (!state._isIncluded || !state._hasJSX) return;
|
|
67
67
|
const extractionTargets = [];
|
|
68
68
|
const functionsToInject = /* @__PURE__ */ new Set();
|
|
69
|
-
const shouldExtract
|
|
69
|
+
const shouldExtract = state.opts.shouldExtract ?? shouldExtract$1;
|
|
70
70
|
programPath.traverse({
|
|
71
71
|
JSXText(path) {
|
|
72
72
|
const text = path.node.value;
|
|
73
|
-
if (shouldExtract
|
|
73
|
+
if (shouldExtract(text)) {
|
|
74
74
|
const key = generateKey(text, state._existingKeys);
|
|
75
75
|
state._existingKeys.add(key);
|
|
76
76
|
state._extractedContent[key] = text.replace(/\s+/g, " ").trim();
|
|
@@ -92,7 +92,7 @@ const intlayerExtractBabelPlugin = (babel) => {
|
|
|
92
92
|
let text = null;
|
|
93
93
|
if (t.isStringLiteral(value)) text = value.value;
|
|
94
94
|
else if (t.isJSXExpressionContainer(value) && t.isStringLiteral(value.expression)) text = value.expression.value;
|
|
95
|
-
if (text && shouldExtract
|
|
95
|
+
if (text && shouldExtract(text)) {
|
|
96
96
|
const key = generateKey(text, state._existingKeys);
|
|
97
97
|
state._existingKeys.add(key);
|
|
98
98
|
state._extractedContent[key] = text.trim();
|
|
@@ -114,7 +114,7 @@ const intlayerExtractBabelPlugin = (babel) => {
|
|
|
114
114
|
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object) && callee.object.name === "console" || t.isIdentifier(callee) && (callee.name === state._useIntlayerLocalName || callee.name === state._getIntlayerLocalName || callee.name === "require") || callee.type === "Import") return;
|
|
115
115
|
}
|
|
116
116
|
const text = path.node.value;
|
|
117
|
-
if (shouldExtract
|
|
117
|
+
if (shouldExtract(text)) {
|
|
118
118
|
const key = generateKey(text, state._existingKeys);
|
|
119
119
|
state._existingKeys.add(key);
|
|
120
120
|
state._extractedContent[key] = text.trim();
|
|
@@ -167,8 +167,8 @@ const injectHook = (path, state, t) => {
|
|
|
167
167
|
if (!t.isBlockStatement(node.body)) {
|
|
168
168
|
const unwrapped = unwrapParentheses(node.body, t);
|
|
169
169
|
const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);
|
|
170
|
-
const hookName
|
|
171
|
-
const hookCall = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(contentVarName), t.callExpression(t.identifier(hookName
|
|
170
|
+
const hookName = isJSX ? state._useIntlayerLocalName : state._getIntlayerLocalName;
|
|
171
|
+
const hookCall = t.variableDeclaration("const", [t.variableDeclarator(t.identifier(contentVarName), t.callExpression(t.identifier(hookName), [t.stringLiteral(dictionaryKey)]))]);
|
|
172
172
|
node.body = t.blockStatement([hookCall, t.returnStatement(node.body)]);
|
|
173
173
|
return isJSX ? "hook" : "core";
|
|
174
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":["shouldExtract","defaultShouldExtract","hookName"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n generateKey,\n} from '@intlayer/chokidar';\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\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};\nconst extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `comp-${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\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\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\n const filename = this.file.opts.filename;\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 if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(filename);\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\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 if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\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 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._hasJSX) 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 // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text\n .replace(/\\s+/g, ' ')\n .trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\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 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 key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: true });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n if (parent.isObjectProperty() && path.key === 'key') return;\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\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 if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\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 if (isAttribute) {\n const member = t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n );\n path.node.value = t.jsxExpressionContainer(\n t.memberExpression(member, t.identifier('value'))\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n )\n );\n } else {\n path.replaceWith(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n );\n }\n }\n\n // Report\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 if (type === 'hook') needsUseIntlayer = true;\n if (type === 'core') needsGetIntlayer = true;\n }\n\n // Pass 4: Imports\n if (needsUseIntlayer || needsGetIntlayer) {\n const pkg = state.opts.packageName!;\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(pkg)\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(pkg)\n )\n );\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\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n const hookName = isJSX\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 isJSX ? 'hook' : 'core';\n }\n\n let returnsJSX = false;\n path.traverse({\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped))\n returnsJSX = true;\n }\n },\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":["defaultShouldExtract"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n generateKey,\n} from '@intlayer/chokidar';\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\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};\nconst extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `comp-${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\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\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\n const filename = this.file.opts.filename;\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 if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(filename);\n },\n\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\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 if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\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 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._hasJSX) 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 // Pass 1: Identification (Read only)\n programPath.traverse({\n JSXText(path) {\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text\n .replace(/\\s+/g, ' ')\n .trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n JSXAttribute(path) {\n const attrName = path.node.name;\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\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 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 key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: true });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\n }\n },\n StringLiteral(path) {\n const parent = path.parentPath;\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n if (parent.isObjectProperty() && path.key === 'key') return;\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression)\n .callee;\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 if (shouldExtract(text)) {\n const key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text.trim();\n extractionTargets.push({ path, key, isAttribute: false });\n const func = path.getFunctionParent();\n if (func)\n functionsToInject.add(func as NodePath<BabelTypes.Function>);\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 if (isAttribute) {\n const member = t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n );\n path.node.value = t.jsxExpressionContainer(\n t.memberExpression(member, t.identifier('value'))\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n )\n );\n } else {\n path.replaceWith(\n t.memberExpression(\n t.identifier(state._contentVarName!),\n t.identifier(key)\n )\n );\n }\n }\n\n // Report\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 if (type === 'hook') needsUseIntlayer = true;\n if (type === 'core') needsGetIntlayer = true;\n }\n\n // Pass 4: Imports\n if (needsUseIntlayer || needsGetIntlayer) {\n const pkg = state.opts.packageName!;\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(pkg)\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(pkg)\n )\n );\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\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n const isJSX = t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n const hookName = isJSX\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 isJSX ? 'hook' : 'core';\n }\n\n let returnsJSX = false;\n path.traverse({\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped))\n returnsJSX = true;\n }\n },\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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"}
|
|
@@ -7,13 +7,9 @@ type ExtractedContent = Record<string, string>;
|
|
|
7
7
|
* Extracted content result from a file transformation
|
|
8
8
|
*/
|
|
9
9
|
type ExtractResult = {
|
|
10
|
-
/** Dictionary key derived from the file path */
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
filePath: string;
|
|
14
|
-
/** Extracted content key-value pairs */
|
|
15
|
-
content: ExtractedContent;
|
|
16
|
-
/** Default locale used */
|
|
10
|
+
/** Dictionary key derived from the file path */dictionaryKey: string; /** File path that was processed */
|
|
11
|
+
filePath: string; /** Extracted content key-value pairs */
|
|
12
|
+
content: ExtractedContent; /** Default locale used */
|
|
17
13
|
locale: string;
|
|
18
14
|
};
|
|
19
15
|
/**
|
|
@@ -45,26 +41,16 @@ type ExtractPluginOptions = {
|
|
|
45
41
|
onExtract?: (result: ExtractResult) => void;
|
|
46
42
|
};
|
|
47
43
|
type State = PluginPass & {
|
|
48
|
-
opts: ExtractPluginOptions;
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
_hasJSX?: boolean;
|
|
59
|
-
/** Whether we already have useIntlayer imported */
|
|
60
|
-
_hasUseIntlayerImport?: boolean;
|
|
61
|
-
/** The local name for useIntlayer (in case it's aliased) */
|
|
62
|
-
_useIntlayerLocalName?: string;
|
|
63
|
-
/** Whether we already have getIntlayer imported */
|
|
64
|
-
_hasGetIntlayerImport?: boolean;
|
|
65
|
-
/** The local name for getIntlayer (in case it's aliased) */
|
|
66
|
-
_getIntlayerLocalName?: string;
|
|
67
|
-
/** The variable name to use for content (content or _compContent if content is already used) */
|
|
44
|
+
opts: ExtractPluginOptions; /** Extracted content from this file */
|
|
45
|
+
_extractedContent?: ExtractedContent; /** Set of existing keys to avoid duplicates */
|
|
46
|
+
_existingKeys?: Set<string>; /** The dictionary key for this file */
|
|
47
|
+
_dictionaryKey?: string; /** whether the current file is included in the filesList */
|
|
48
|
+
_isIncluded?: boolean; /** Whether this file has JSX (React component) */
|
|
49
|
+
_hasJSX?: boolean; /** Whether we already have useIntlayer imported */
|
|
50
|
+
_hasUseIntlayerImport?: boolean; /** The local name for useIntlayer (in case it's aliased) */
|
|
51
|
+
_useIntlayerLocalName?: string; /** Whether we already have getIntlayer imported */
|
|
52
|
+
_hasGetIntlayerImport?: boolean; /** The local name for getIntlayer (in case it's aliased) */
|
|
53
|
+
_getIntlayerLocalName?: string; /** The variable name to use for content (content or _compContent if content is already used) */
|
|
68
54
|
_contentVarName?: string;
|
|
69
55
|
};
|
|
70
56
|
declare const intlayerExtractBabelPlugin: (babel: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"mappings":";;;;KASK,gBAAA,GAAmB,MAAA;;AAPwB;;KAYpC,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;EAUkC;AAClC;;EAPA,aAAA,IAAiB,IAAA;EASN;;;;;EAHX,SAAA,IAAa,MAAA,EAAQ,aAAA;AAAA;AAAA,KAGlB,KAAA,GAAQ,UAAA;EACX,IAAA,EAAM,oBAAA,EAEN;EAAA,iBAAA,GAAoB,gBAAA,EAEpB;EAAA,aAAA,GAAgB,GAAA,UAEhB;EAAA,cAAA,WAIA;EAFA,WAAA,YAMA;EAJA,OAAA,YAQA;EANA,qBAAA,YAQe;EANf,qBAAA,WA6BW;EA3BX,qBAAA;EAEA,qBAAA,WA2BY;EAzBZ,eAAA;AAAA;AAAA,cAuBW,0BAAA,GAA8B,KAAA;EACzC,KAAA,SAAc,UAAA;AAAA,MACZ,SAAA,CAAU,KAAA"}
|
|
@@ -2,7 +2,6 @@ import { PluginObj, PluginPass } from "@babel/core";
|
|
|
2
2
|
import * as BabelTypes from "@babel/types";
|
|
3
3
|
|
|
4
4
|
//#region src/babel-plugin-intlayer-optimize.d.ts
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* Options for the optimization Babel plugin
|
|
8
7
|
*/
|
|
@@ -61,18 +60,12 @@ type OptimizePluginOptions = {
|
|
|
61
60
|
filesList: string[];
|
|
62
61
|
};
|
|
63
62
|
type State = PluginPass & {
|
|
64
|
-
opts: OptimizePluginOptions;
|
|
65
|
-
/** map key → generated ident (per-file) for
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/** whether the current file
|
|
70
|
-
_hasValidImport?: boolean;
|
|
71
|
-
/** whether the current file *is* the dictionaries entry file */
|
|
72
|
-
_isDictEntry?: boolean;
|
|
73
|
-
/** whether dynamic helpers are active for this file */
|
|
74
|
-
_useDynamicHelpers?: boolean;
|
|
75
|
-
/** whether the current file is included in the filesList */
|
|
63
|
+
opts: OptimizePluginOptions; /** map key → generated ident (per-file) for static imports */
|
|
64
|
+
_newStaticImports?: Map<string, BabelTypes.Identifier>; /** map key → generated ident (per-file) for dynamic imports */
|
|
65
|
+
_newDynamicImports?: Map<string, BabelTypes.Identifier>; /** whether the current file imported *any* intlayer package */
|
|
66
|
+
_hasValidImport?: boolean; /** whether the current file *is* the dictionaries entry file */
|
|
67
|
+
_isDictEntry?: boolean; /** whether dynamic helpers are active for this file */
|
|
68
|
+
_useDynamicHelpers?: boolean; /** whether the current file is included in the filesList */
|
|
76
69
|
_isIncluded?: boolean;
|
|
77
70
|
};
|
|
78
71
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-optimize.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-optimize.d.ts","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"mappings":";;;;;;AAqDA;KAAY,qBAAA;;;;EAIV,QAAA;EAQA;;;EAJA,eAAA;EAoBA;;;EAhBA,qBAAA;EAgCA;;;EA5BA,6BAAA;EAoCS;;AACT;EAjCA,uBAAA;;;;EAIA,sBAAA;EAkCoB;;;EA9BpB,4BAAA;EAgCwB;;;EA5BxB,oBAAA;EA0BA;;;EAtBA,0BAAA;EAwBA;;;EApBA,sBAAA;EAsBA;;;EAlBA,UAAA;EAwBW;;AAiIb;EArJE,iBAAA,GAAoB,MAAA;;;;EAIpB,SAAA;AAAA;AAAA,KAGG,KAAA,GAAQ,UAAA;EACX,IAAA,EAAM,qBAAA,EA8IQ;EA5Id,iBAAA,GAAoB,GAAA,SAAY,UAAA,CAAW,UAAA,GA6IzC;EA3IF,kBAAA,GAAqB,GAAA,SAAY,UAAA,CAAW,UAAA,GA2I3B;EAzIjB,eAAA;EAEA,YAAA;EAEA,kBAAA;EAEA,WAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiIW,2BAAA,GAA+B,KAAA;EAC1C,KAAA,SAAc,UAAA;AAAA,MACZ,SAAA,CAAU,KAAA"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ExtractPluginOptions } from "./babel-plugin-intlayer-extract.js";
|
|
2
2
|
|
|
3
3
|
//#region src/getExtractPluginOptions.d.ts
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* Get the options for the Intlayer Babel extraction plugin
|
|
7
6
|
* This function loads the Intlayer configuration and sets up the onExtract callback
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getExtractPluginOptions.d.ts","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"
|
|
1
|
+
{"version":3,"file":"getExtractPluginOptions.d.ts","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"mappings":";;;;;AA6BA;;;cAAa,uBAAA,QAA8B,oBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getOptimizePluginOptions.d.ts","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"
|
|
1
|
+
{"version":3,"file":"getOptimizePluginOptions.d.ts","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"mappings":";;;;;KASK,8BAAA;;AAFyE;;EAM5E,aAAA,GAAgB,uBAAA;EAAA;;;EAIhB,YAAA,GAAe,UAAA;EAII;;;EAAnB,SAAA,GAAY,OAAA,CAAQ,qBAAA;AAAA;;;;;;cA2BT,wBAAA,GACX,MAAA,GAAS,8BAAA,KACR,qBAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/babel",
|
|
3
|
-
"version": "8.0.0-canary.
|
|
3
|
+
"version": "8.0.0-canary.2",
|
|
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": [
|
|
@@ -81,28 +81,28 @@
|
|
|
81
81
|
"@babel/parser": "7.1.5",
|
|
82
82
|
"@babel/traverse": "7.28.0",
|
|
83
83
|
"@babel/types": "7.28.4",
|
|
84
|
-
"@intlayer/chokidar": "8.0.0-canary.
|
|
85
|
-
"@intlayer/config": "8.0.0-canary.
|
|
86
|
-
"@intlayer/types": "8.0.0-canary.
|
|
84
|
+
"@intlayer/chokidar": "8.0.0-canary.2",
|
|
85
|
+
"@intlayer/config": "8.0.0-canary.2",
|
|
86
|
+
"@intlayer/types": "8.0.0-canary.2",
|
|
87
87
|
"@types/babel__core": "7.20.5",
|
|
88
88
|
"@types/babel__generator": "7.27.0",
|
|
89
89
|
"@types/babel__traverse": "7.28.0",
|
|
90
90
|
"fast-glob": "3.3.3"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
-
"@intlayer/dictionaries-entry": "8.0.0-canary.
|
|
93
|
+
"@intlayer/dictionaries-entry": "8.0.0-canary.2",
|
|
94
94
|
"@types/crypto-js": "4.2.2",
|
|
95
95
|
"@types/node": "25.0.9",
|
|
96
96
|
"@utils/ts-config": "1.0.4",
|
|
97
97
|
"@utils/ts-config-types": "1.0.4",
|
|
98
98
|
"@utils/tsdown-config": "1.0.4",
|
|
99
99
|
"rimraf": "6.1.2",
|
|
100
|
-
"tsdown": "0.
|
|
100
|
+
"tsdown": "0.20.0",
|
|
101
101
|
"typescript": "5.9.3",
|
|
102
|
-
"vitest": "4.0.
|
|
102
|
+
"vitest": "4.0.18"
|
|
103
103
|
},
|
|
104
104
|
"peerDependencies": {
|
|
105
|
-
"@intlayer/dictionaries-entry": "8.0.0-canary.
|
|
105
|
+
"@intlayer/dictionaries-entry": "8.0.0-canary.2"
|
|
106
106
|
},
|
|
107
107
|
"peerDependenciesMeta": {
|
|
108
108
|
"@intlayer/dictionaries-entry": {
|