@intlayer/babel 8.12.2 → 8.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
  2. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs +14 -9
  3. package/dist/cjs/babel-plugin-intlayer-field-rename.cjs.map +1 -1
  4. package/dist/cjs/babel-plugin-intlayer-minify.cjs +83 -0
  5. package/dist/cjs/babel-plugin-intlayer-minify.cjs.map +1 -0
  6. package/dist/cjs/babel-plugin-intlayer-optimize.cjs +1 -0
  7. package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
  8. package/dist/cjs/babel-plugin-intlayer-purge.cjs +403 -0
  9. package/dist/cjs/babel-plugin-intlayer-purge.cjs.map +1 -0
  10. package/dist/cjs/babel-plugin-intlayer-usage-analyzer.cjs.map +1 -1
  11. package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -1
  12. package/dist/cjs/extractContent/contentWriter.cjs.map +1 -1
  13. package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
  14. package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -1
  15. package/dist/cjs/extractContent/utils/constants.cjs.map +1 -1
  16. package/dist/cjs/extractContent/utils/detectPackageName.cjs +1 -0
  17. package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -1
  18. package/dist/cjs/extractContent/utils/extractDictionaryInfo.cjs.map +1 -1
  19. package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs +1 -0
  20. package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -1
  21. package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -1
  22. package/dist/cjs/extractContent/utils/getComponentName.cjs.map +1 -1
  23. package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -1
  24. package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs.map +1 -1
  25. package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs +1 -0
  26. package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -1
  27. package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +1 -1
  28. package/dist/cjs/extractScriptBlocks.cjs +1 -0
  29. package/dist/cjs/extractScriptBlocks.cjs.map +1 -1
  30. package/dist/cjs/getExtractPluginOptions.cjs.map +1 -1
  31. package/dist/cjs/getOptimizePluginOptions.cjs +1 -0
  32. package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
  33. package/dist/cjs/getPurgePluginOptions.cjs +108 -0
  34. package/dist/cjs/getPurgePluginOptions.cjs.map +1 -0
  35. package/dist/cjs/index.cjs +9 -1
  36. package/dist/cjs/transformers.cjs +1 -0
  37. package/dist/cjs/transformers.cjs.map +1 -1
  38. package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
  39. package/dist/esm/babel-plugin-intlayer-field-rename.mjs +14 -9
  40. package/dist/esm/babel-plugin-intlayer-field-rename.mjs.map +1 -1
  41. package/dist/esm/babel-plugin-intlayer-minify.mjs +82 -0
  42. package/dist/esm/babel-plugin-intlayer-minify.mjs.map +1 -0
  43. package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
  44. package/dist/esm/babel-plugin-intlayer-purge.mjs +400 -0
  45. package/dist/esm/babel-plugin-intlayer-purge.mjs.map +1 -0
  46. package/dist/esm/babel-plugin-intlayer-usage-analyzer.mjs.map +1 -1
  47. package/dist/esm/extractContent/babelProcessor.mjs.map +1 -1
  48. package/dist/esm/extractContent/contentWriter.mjs.map +1 -1
  49. package/dist/esm/extractContent/extractContent.mjs.map +1 -1
  50. package/dist/esm/extractContent/processTsxFile.mjs.map +1 -1
  51. package/dist/esm/extractContent/utils/constants.mjs.map +1 -1
  52. package/dist/esm/extractContent/utils/detectPackageName.mjs.map +1 -1
  53. package/dist/esm/extractContent/utils/extractDictionaryInfo.mjs.map +1 -1
  54. package/dist/esm/extractContent/utils/extractDictionaryKey.mjs.map +1 -1
  55. package/dist/esm/extractContent/utils/generateKey.mjs.map +1 -1
  56. package/dist/esm/extractContent/utils/getComponentName.mjs.map +1 -1
  57. package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -1
  58. package/dist/esm/extractContent/utils/getOrGenerateKey.mjs.map +1 -1
  59. package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs.map +1 -1
  60. package/dist/esm/extractContent/utils/shouldExtract.mjs.map +1 -1
  61. package/dist/esm/extractScriptBlocks.mjs.map +1 -1
  62. package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
  63. package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
  64. package/dist/esm/getPurgePluginOptions.mjs +106 -0
  65. package/dist/esm/getPurgePluginOptions.mjs.map +1 -0
  66. package/dist/esm/index.mjs +5 -2
  67. package/dist/esm/transformers.mjs.map +1 -1
  68. package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
  69. package/dist/types/babel-plugin-intlayer-field-rename.d.ts.map +1 -1
  70. package/dist/types/babel-plugin-intlayer-minify.d.ts +84 -0
  71. package/dist/types/babel-plugin-intlayer-minify.d.ts.map +1 -0
  72. package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
  73. package/dist/types/babel-plugin-intlayer-purge.d.ts +127 -0
  74. package/dist/types/babel-plugin-intlayer-purge.d.ts.map +1 -0
  75. package/dist/types/babel-plugin-intlayer-usage-analyzer.d.ts.map +1 -1
  76. package/dist/types/extractContent/babelProcessor.d.ts.map +1 -1
  77. package/dist/types/extractContent/contentWriter.d.ts.map +1 -1
  78. package/dist/types/extractContent/extractContent.d.ts.map +1 -1
  79. package/dist/types/extractContent/utils/constants.d.ts.map +1 -1
  80. package/dist/types/extractContent/utils/detectPackageName.d.ts.map +1 -1
  81. package/dist/types/extractContent/utils/extractDictionaryInfo.d.ts.map +1 -1
  82. package/dist/types/extractContent/utils/extractDictionaryKey.d.ts.map +1 -1
  83. package/dist/types/extractContent/utils/generateKey.d.ts.map +1 -1
  84. package/dist/types/extractContent/utils/getComponentName.d.ts.map +1 -1
  85. package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts.map +1 -1
  86. package/dist/types/extractContent/utils/shouldExtract.d.ts.map +1 -1
  87. package/dist/types/extractScriptBlocks.d.ts.map +1 -1
  88. package/dist/types/getExtractPluginOptions.d.ts.map +1 -1
  89. package/dist/types/getOptimizePluginOptions.d.ts.map +1 -1
  90. package/dist/types/getPurgePluginOptions.d.ts +83 -0
  91. package/dist/types/getPurgePluginOptions.d.ts.map +1 -0
  92. package/dist/types/index.d.ts +4 -1
  93. package/dist/types/transformers.d.ts.map +1 -1
  94. package/package.json +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"processTsxFile.mjs","names":[],"sources":["../../../src/extractContent/processTsxFile.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport { parse } from '@babel/parser';\nimport _traverse, { type NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { extractBabelContentForComponents } from './babelProcessor';\nimport {\n type ExistingIntlayerInfo,\n getExistingIntlayerInfo,\n type PackageName,\n SERVER_CAPABLE_PACKAGES,\n} from './utils';\n\nexport type TextEdit = {\n start: number;\n end: number;\n replacement: string;\n};\n\n/**\n * Returns true when a string literal sits inside a JSX child expression\n * container (i.e. a React node slot), meaning content.key renders as an\n * IntlayerNode and should NOT receive a .value suffix.\n * Returns false for attribute-value containers and non-JSX contexts.\n */\nconst isInJsxNodeContext = (path: NodePath): boolean => {\n let current: NodePath | null = path.parentPath;\n while (current) {\n if (current.isJSXExpressionContainer()) {\n return !current.parentPath?.isJSXAttribute();\n }\n if (current.isFunction() || current.isProgram()) return false;\n current = current.parentPath;\n }\n return false;\n};\n\nconst traverse = (\n typeof _traverse === 'function' ? _traverse : (_traverse as any).default\n) as typeof _traverse;\n\n/**\n * Processes a TSX/JSX/TS/JS file to extract content and inject Intlayer hooks/calls.\n */\nexport const processTsxFile = (\n filePath: string,\n componentKey: string,\n packageName: PackageName,\n configuration: IntlayerConfig,\n save: boolean = true,\n unmergedDictionaries: Record<string, unknown> = {},\n providedFileCode?: string\n): {\n extractedContent: Record<string, Record<string, string>>;\n modifiedCode: string;\n} | null => {\n const fileCode = providedFileCode ?? readFileSync(filePath, 'utf-8');\n\n const ast = parse(fileCode, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n const hasUseClient = ast.program.directives.some(\n (directive) => directive.value.value === 'use client'\n );\n\n const effectivePackageName =\n SERVER_CAPABLE_PACKAGES.has(packageName) && !hasUseClient\n ? `${packageName}/server`\n : packageName;\n\n // Angular exposes content via a reactive signal — access is `content().key`.\n // solid-intlayer now returns a Proxy that supports direct `content.key` access.\n const usesSignalAccessor = packageName === 'angular-intlayer';\n const existingKeys = new Set<string>();\n\n const {\n extractedContent,\n replacements,\n componentsNeedingHooks,\n componentKeyMap,\n componentPaths,\n hookMap,\n } = extractBabelContentForComponents(\n ast,\n fileCode,\n existingKeys,\n componentKey,\n configuration,\n filePath,\n unmergedDictionaries\n );\n\n if (Object.keys(extractedContent).length === 0) return null;\n\n const textEdits: TextEdit[] = [];\n\n // Build a lookup map: component AST node → NodePath (O(1) access)\n const componentNodeToPath = new Map<t.Node, NodePath>();\n for (const componentPath of componentPaths) {\n componentNodeToPath.set(componentPath.node, componentPath);\n }\n\n // Cache getExistingIntlayerInfo results for all component paths (avoids repeated traversals)\n const existingInfoCache = new Map<t.Node, ExistingIntlayerInfo | undefined>();\n for (const componentPath of componentPaths) {\n existingInfoCache.set(\n componentPath.node,\n getExistingIntlayerInfo(componentPath)\n );\n }\n\n /**\n * Walks up the ancestor chain to find the nearest enclosing component's\n * existing Intlayer info (if any).\n */\n const getExistingInfoForPath = (\n path: NodePath\n ): ExistingIntlayerInfo | undefined => {\n let current: NodePath | null = path;\n while (current) {\n if (componentNodeToPath.has(current.node)) {\n const componentPath = componentNodeToPath.get(current.node)!;\n\n const existingInfo = existingInfoCache.get(current.node);\n if (existingInfo) {\n return existingInfo;\n }\n\n if (componentsNeedingHooks.has(componentPath)) {\n return undefined;\n }\n }\n current = current.parentPath;\n }\n return undefined;\n };\n\n const getProvidingHookType = (\n path: NodePath\n ): 'useIntlayer' | 'getIntlayer' => {\n let current: NodePath | null = path;\n while (current) {\n const componentPath = componentNodeToPath.get(current.node);\n\n if (componentPath) {\n const existingInfo = existingInfoCache.get(componentPath.node);\n\n if (existingInfo) {\n return existingInfo.hook;\n }\n\n if (componentsNeedingHooks.has(componentPath)) {\n return hookMap.get(componentPath.node) || 'useIntlayer';\n }\n }\n current = current.parentPath;\n }\n return 'useIntlayer';\n };\n\n const generatedVarNames = new Map<NodePath, string>();\n for (const componentPath of componentsNeedingHooks) {\n let varName = 'content';\n let counter = 1;\n while (componentPath.scope.hasBinding(varName)) {\n varName = `content${counter}`;\n counter++;\n }\n generatedVarNames.set(componentPath, varName);\n }\n\n const getProvidingVarName = (path: NodePath): string => {\n let current: NodePath | null = path;\n while (current) {\n const componentPath = componentNodeToPath.get(current.node);\n\n if (componentPath) {\n const existingInfo = existingInfoCache.get(componentPath.node);\n if (existingInfo) {\n return existingInfo.variableName ?? 'content';\n }\n if (componentsNeedingHooks.has(componentPath)) {\n return generatedVarNames.get(componentPath) || 'content';\n }\n }\n current = current.parentPath;\n }\n return 'content';\n };\n\n for (const {\n path,\n key,\n type,\n variables,\n childrenToReplace,\n } of replacements) {\n const existingInfo = getExistingInfoForPath(path);\n // When the existing call is destructured (e.g. `const { a } = getIntlayer(...)`),\n // new keys are added directly to that destructuring, so access them by name alone.\n const varName = existingInfo?.variableName ?? getProvidingVarName(path);\n const contentAccessCode = existingInfo?.isDestructured\n ? key\n : usesSignalAccessor\n ? `${varName}().${key}`\n : `${varName}.${key}`;\n const hookType = getProvidingHookType(path);\n const valueSuffix = hookType === 'getIntlayer' ? '' : '.value';\n\n if (type === 'jsx-text' && path.isJSXText()) {\n textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement: `{${contentAccessCode}}`,\n });\n } else if (type === 'jsx-attribute' && path.isJSXAttribute()) {\n const valNode = path.node.value;\n\n if (valNode) {\n textEdits.push({\n start: valNode.start!,\n end: valNode.end!,\n replacement: `{${contentAccessCode}${valueSuffix}}`,\n });\n }\n } else if (type === 'string-literal' && path.isStringLiteral()) {\n const suffix = isInJsxNodeContext(path) ? '' : valueSuffix;\n textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement: `${contentAccessCode}${suffix}`,\n });\n } else if (\n type === 'jsx-text-combined' &&\n childrenToReplace &&\n childrenToReplace.length > 0\n ) {\n const accessStr = `{${contentAccessCode}}`;\n const firstChild = childrenToReplace[0];\n const lastChild = childrenToReplace[childrenToReplace.length - 1];\n if (\n !firstChild ||\n !lastChild ||\n firstChild.start == null ||\n lastChild.end == null\n )\n continue;\n const start = firstChild.start;\n const end = lastChild.end;\n textEdits.push({ start, end, replacement: accessStr });\n } else if (\n type === 'jsx-insertion' &&\n variables &&\n childrenToReplace &&\n childrenToReplace.length > 0\n ) {\n const objProps = variables\n .map((variableString) => {\n const [key, variableValue] = variableString\n .split(':')\n .map((part) => part.trim());\n return `${key}: ${variableValue}`;\n })\n .join(', ');\n\n const firstChild = childrenToReplace[0];\n const lastChild = childrenToReplace[childrenToReplace.length - 1];\n if (\n !firstChild ||\n !lastChild ||\n firstChild.start == null ||\n lastChild.end == null\n )\n continue;\n const accessStr = `{${contentAccessCode}({ ${objProps} })}`;\n const start = firstChild.start;\n const end = lastChild.end;\n textEdits.push({ start, end, replacement: accessStr });\n } else if (type === 'template-literal' && path.isTemplateLiteral()) {\n let replacement = `${contentAccessCode}`;\n\n if (variables && variables.length > 0) {\n const objProps = variables\n .map((variableString) => {\n const [key, variableValue] = variableString\n .split(':')\n .map((part) => part.trim());\n return `${key}: ${variableValue}`;\n })\n .join(', ');\n replacement += `({ ${objProps} })`;\n } else {\n replacement += valueSuffix;\n }\n\n textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement,\n });\n }\n }\n\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const componentPath of componentsNeedingHooks) {\n const finalKey = componentKeyMap.get(componentPath.node)!;\n const existingInfo = existingInfoCache.get(componentPath.node);\n\n if (existingInfo) {\n if (existingInfo.hook === 'useIntlayer') needsUseIntlayer = true;\n\n if (existingInfo.hook === 'getIntlayer') needsGetIntlayer = true;\n\n // When the existing call is destructured, inject any missing keys into\n // the destructuring pattern so they can be accessed by name directly.\n if (existingInfo.isDestructured && existingInfo.objectPatternNode) {\n const neededKeys = new Set<string>();\n\n for (const { path: rPath, key: rKey } of replacements) {\n let current: NodePath | null = rPath;\n\n while (current) {\n if (current.node === componentPath.node) {\n neededKeys.add(rKey);\n break;\n }\n current = current.parentPath;\n }\n }\n\n const missingKeys = [...neededKeys].filter(\n (key) => !existingInfo.existingDestructuredKeys.includes(key)\n );\n\n if (missingKeys.length > 0) {\n const { objectPatternNode } = existingInfo;\n // Insert right after the last property so the space/newline before\n // `}` is naturally preserved: `{ a }` → `{ a, b }`.\n const lastProp =\n objectPatternNode.properties[\n objectPatternNode.properties.length - 1\n ];\n if (lastProp?.end != null) {\n textEdits.push({\n start: lastProp.end,\n end: lastProp.end,\n replacement: `, ${missingKeys.join(', ')}`,\n });\n }\n }\n }\n } else {\n const hook = hookMap.get(componentPath.node) || 'useIntlayer';\n\n if (hook === 'useIntlayer') needsUseIntlayer = true;\n\n if (hook === 'getIntlayer') needsGetIntlayer = true;\n\n const hookVarName = generatedVarNames.get(componentPath) || 'content';\n const hookStatementStr = `\\n const ${hookVarName} = ${hook}('${finalKey}');\\n`;\n\n if (componentPath.isProgram()) {\n // Find the last import or directive to inject the getIntlayer call\n let insertPos = 0;\n if (componentPath.node.directives.length > 0) {\n const lastDirective =\n componentPath.node.directives[\n componentPath.node.directives.length - 1\n ];\n if (lastDirective?.end != null) {\n insertPos = lastDirective.end;\n }\n }\n for (const stmt of componentPath.node.body) {\n if (t.isImportDeclaration(stmt)) {\n insertPos = Math.max(insertPos, stmt.end!);\n }\n }\n\n if (insertPos === 0 && componentPath.node.body.length > 0) {\n const firstBodyStmt = componentPath.node.body[0];\n if (firstBodyStmt?.start != null) {\n insertPos = firstBodyStmt.start;\n }\n }\n\n textEdits.push({\n start: insertPos,\n end: insertPos,\n replacement: `\\n${hookStatementStr}`,\n });\n continue;\n }\n\n const bodyPath = componentPath.get('body') as NodePath;\n\n if (bodyPath.isBlockStatement()) {\n textEdits.push({\n start: bodyPath.node.start! + 1,\n end: bodyPath.node.start! + 1,\n replacement: hookStatementStr,\n });\n } else if (bodyPath.isExpression()) {\n const start = bodyPath.node.start!;\n const end = bodyPath.node.end!;\n\n // Detect wrapping parentheses: `() => (expr)` — scan backward from\n // the expression start and forward from its end for matching `(` / `)`.\n let parenStart = -1;\n let parenEnd = -1;\n\n for (let i = start - 1; i >= 0; i--) {\n const char = fileCode[i];\n if (char === '(') {\n parenStart = i;\n break;\n }\n if (char !== ' ' && char !== '\\n' && char !== '\\r' && char !== '\\t')\n break;\n }\n\n if (parenStart !== -1) {\n for (let i = end; i < fileCode.length; i++) {\n const char = fileCode[i];\n if (char === ')') {\n parenEnd = i;\n break;\n }\n if (char !== ' ' && char !== '\\n' && char !== '\\r' && char !== '\\t')\n break;\n }\n }\n\n if (parenStart !== -1 && parenEnd !== -1) {\n // Replace the surrounding `(` … `)` with a block statement. We keep\n // the parentheses as `return (…)` to prevent automatic semicolon\n // insertion when the returned expression starts on a new line.\n textEdits.push({\n start: parenEnd,\n end: parenEnd + 1,\n replacement: `)\\n}`,\n });\n textEdits.push({\n start: parenStart,\n end: parenStart + 1,\n replacement: `{\\n const content = ${hook}('${finalKey}');\\n return (`,\n });\n } else {\n textEdits.push({\n start: end,\n end: end,\n replacement: `\\n}`,\n });\n textEdits.push({\n start: start,\n end: start,\n replacement: `{\\n const content = ${hook}('${finalKey}');\\n return `,\n });\n }\n }\n }\n }\n\n const injectImport = (hookName: string, targetPackage: string) => {\n let existingImportPath: NodePath<t.ImportDeclaration> | undefined;\n\n traverse(ast, {\n ImportDeclaration(path) {\n if (path.node.source.value === targetPackage) {\n existingImportPath = path;\n path.stop();\n }\n },\n });\n\n if (!existingImportPath) {\n const newImportStr = `import { ${hookName} } from '${targetPackage}';\\n`;\n let insertPos = 0;\n\n if (ast.program.body.length > 0) {\n const firstBodyStmt = ast.program.body[0];\n if (firstBodyStmt?.start != null) {\n insertPos = firstBodyStmt.start;\n }\n } else if (ast.program.directives && ast.program.directives.length > 0) {\n const lastDirective =\n ast.program.directives[ast.program.directives.length - 1];\n if (lastDirective?.end != null) {\n insertPos = lastDirective.end;\n }\n\n if (fileCode[insertPos] === ';') insertPos++;\n\n textEdits.push({\n start: insertPos,\n end: insertPos,\n replacement: `\\n${newImportStr}`,\n });\n return;\n }\n\n const firstBodyStmt = ast.program.body[0];\n if (\n insertPos === 0 ||\n (ast.program.body.length > 0 &&\n firstBodyStmt?.start != null &&\n insertPos === firstBodyStmt.start)\n ) {\n textEdits.push({\n start: insertPos,\n end: insertPos,\n replacement: newImportStr,\n });\n }\n } else {\n const existingSpecifiers = existingImportPath.node.specifiers;\n const missingImport = !existingSpecifiers.some(\n (specifier) =>\n t.isImportSpecifier(specifier) &&\n t.isIdentifier(specifier.imported) &&\n specifier.imported.name === hookName\n );\n\n if (missingImport) {\n const importCode = fileCode.slice(\n existingImportPath.node.start!,\n existingImportPath.node.end!\n );\n const closingBraceIndex = importCode.lastIndexOf('}');\n\n if (closingBraceIndex !== -1) {\n const isCommaNeeded = !importCode\n .slice(0, closingBraceIndex)\n .trim()\n .endsWith(',');\n const absolutePos =\n existingImportPath.node.start! + closingBraceIndex;\n const prefix = isCommaNeeded ? ', ' : ' ';\n textEdits.push({\n start: absolutePos,\n end: absolutePos,\n replacement: `${prefix}${hookName} `,\n });\n }\n }\n }\n };\n\n if (needsUseIntlayer) injectImport('useIntlayer', effectivePackageName);\n\n if (needsGetIntlayer) injectImport('getIntlayer', 'intlayer');\n\n textEdits.sort((editA, editB) => {\n if (editB.start !== editA.start) return editB.start - editA.start;\n\n return editB.end - editA.end;\n });\n\n let formattedCode = fileCode;\n\n for (const edit of textEdits) {\n formattedCode =\n formattedCode.slice(0, edit.start) +\n edit.replacement +\n formattedCode.slice(edit.end);\n }\n\n if (save) {\n writeFileSync(filePath, formattedCode);\n\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'inherit',\n cwd: configuration.system.baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n }\n\n return { extractedContent, modifiedCode: formattedCode };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"processTsxFile.mjs","names":[],"sources":["../../../src/extractContent/processTsxFile.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync, writeFileSync } from 'node:fs';\nimport { parse } from '@babel/parser';\nimport _traverse, { type NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { extractBabelContentForComponents } from './babelProcessor';\nimport {\n type ExistingIntlayerInfo,\n getExistingIntlayerInfo,\n type PackageName,\n SERVER_CAPABLE_PACKAGES,\n} from './utils';\n\nexport type TextEdit = {\n start: number;\n end: number;\n replacement: string;\n};\n\n/**\n * Returns true when a string literal sits inside a JSX child expression\n * container (i.e. a React node slot), meaning content.key renders as an\n * IntlayerNode and should NOT receive a .value suffix.\n * Returns false for attribute-value containers and non-JSX contexts.\n */\nconst isInJsxNodeContext = (path: NodePath): boolean => {\n let current: NodePath | null = path.parentPath;\n while (current) {\n if (current.isJSXExpressionContainer()) {\n return !current.parentPath?.isJSXAttribute();\n }\n if (current.isFunction() || current.isProgram()) return false;\n current = current.parentPath;\n }\n return false;\n};\n\nconst traverse = (\n typeof _traverse === 'function' ? _traverse : (_traverse as any).default\n) as typeof _traverse;\n\n/**\n * Processes a TSX/JSX/TS/JS file to extract content and inject Intlayer hooks/calls.\n */\nexport const processTsxFile = (\n filePath: string,\n componentKey: string,\n packageName: PackageName,\n configuration: IntlayerConfig,\n save: boolean = true,\n unmergedDictionaries: Record<string, unknown> = {},\n providedFileCode?: string\n): {\n extractedContent: Record<string, Record<string, string>>;\n modifiedCode: string;\n} | null => {\n const fileCode = providedFileCode ?? readFileSync(filePath, 'utf-8');\n\n const ast = parse(fileCode, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n const hasUseClient = ast.program.directives.some(\n (directive) => directive.value.value === 'use client'\n );\n\n const effectivePackageName =\n SERVER_CAPABLE_PACKAGES.has(packageName) && !hasUseClient\n ? `${packageName}/server`\n : packageName;\n\n // Angular exposes content via a reactive signal — access is `content().key`.\n // solid-intlayer now returns a Proxy that supports direct `content.key` access.\n const usesSignalAccessor = packageName === 'angular-intlayer';\n const existingKeys = new Set<string>();\n\n const {\n extractedContent,\n replacements,\n componentsNeedingHooks,\n componentKeyMap,\n componentPaths,\n hookMap,\n } = extractBabelContentForComponents(\n ast,\n fileCode,\n existingKeys,\n componentKey,\n configuration,\n filePath,\n unmergedDictionaries\n );\n\n if (Object.keys(extractedContent).length === 0) return null;\n\n const textEdits: TextEdit[] = [];\n\n // Build a lookup map: component AST node → NodePath (O(1) access)\n const componentNodeToPath = new Map<t.Node, NodePath>();\n for (const componentPath of componentPaths) {\n componentNodeToPath.set(componentPath.node, componentPath);\n }\n\n // Cache getExistingIntlayerInfo results for all component paths (avoids repeated traversals)\n const existingInfoCache = new Map<t.Node, ExistingIntlayerInfo | undefined>();\n for (const componentPath of componentPaths) {\n existingInfoCache.set(\n componentPath.node,\n getExistingIntlayerInfo(componentPath)\n );\n }\n\n /**\n * Walks up the ancestor chain to find the nearest enclosing component's\n * existing Intlayer info (if any).\n */\n const getExistingInfoForPath = (\n path: NodePath\n ): ExistingIntlayerInfo | undefined => {\n let current: NodePath | null = path;\n while (current) {\n if (componentNodeToPath.has(current.node)) {\n const componentPath = componentNodeToPath.get(current.node)!;\n\n const existingInfo = existingInfoCache.get(current.node);\n if (existingInfo) {\n return existingInfo;\n }\n\n if (componentsNeedingHooks.has(componentPath)) {\n return undefined;\n }\n }\n current = current.parentPath;\n }\n return undefined;\n };\n\n const getProvidingHookType = (\n path: NodePath\n ): 'useIntlayer' | 'getIntlayer' => {\n let current: NodePath | null = path;\n while (current) {\n const componentPath = componentNodeToPath.get(current.node);\n\n if (componentPath) {\n const existingInfo = existingInfoCache.get(componentPath.node);\n\n if (existingInfo) {\n return existingInfo.hook;\n }\n\n if (componentsNeedingHooks.has(componentPath)) {\n return hookMap.get(componentPath.node) || 'useIntlayer';\n }\n }\n current = current.parentPath;\n }\n return 'useIntlayer';\n };\n\n const generatedVarNames = new Map<NodePath, string>();\n for (const componentPath of componentsNeedingHooks) {\n let varName = 'content';\n let counter = 1;\n while (componentPath.scope.hasBinding(varName)) {\n varName = `content${counter}`;\n counter++;\n }\n generatedVarNames.set(componentPath, varName);\n }\n\n const getProvidingVarName = (path: NodePath): string => {\n let current: NodePath | null = path;\n while (current) {\n const componentPath = componentNodeToPath.get(current.node);\n\n if (componentPath) {\n const existingInfo = existingInfoCache.get(componentPath.node);\n if (existingInfo) {\n return existingInfo.variableName ?? 'content';\n }\n if (componentsNeedingHooks.has(componentPath)) {\n return generatedVarNames.get(componentPath) || 'content';\n }\n }\n current = current.parentPath;\n }\n return 'content';\n };\n\n for (const {\n path,\n key,\n type,\n variables,\n childrenToReplace,\n } of replacements) {\n const existingInfo = getExistingInfoForPath(path);\n // When the existing call is destructured (e.g. `const { a } = getIntlayer(...)`),\n // new keys are added directly to that destructuring, so access them by name alone.\n const varName = existingInfo?.variableName ?? getProvidingVarName(path);\n const contentAccessCode = existingInfo?.isDestructured\n ? key\n : usesSignalAccessor\n ? `${varName}().${key}`\n : `${varName}.${key}`;\n const hookType = getProvidingHookType(path);\n const valueSuffix = hookType === 'getIntlayer' ? '' : '.value';\n\n if (type === 'jsx-text' && path.isJSXText()) {\n textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement: `{${contentAccessCode}}`,\n });\n } else if (type === 'jsx-attribute' && path.isJSXAttribute()) {\n const valNode = path.node.value;\n\n if (valNode) {\n textEdits.push({\n start: valNode.start!,\n end: valNode.end!,\n replacement: `{${contentAccessCode}${valueSuffix}}`,\n });\n }\n } else if (type === 'string-literal' && path.isStringLiteral()) {\n const suffix = isInJsxNodeContext(path) ? '' : valueSuffix;\n textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement: `${contentAccessCode}${suffix}`,\n });\n } else if (\n type === 'jsx-text-combined' &&\n childrenToReplace &&\n childrenToReplace.length > 0\n ) {\n const accessStr = `{${contentAccessCode}}`;\n const firstChild = childrenToReplace[0];\n const lastChild = childrenToReplace[childrenToReplace.length - 1];\n if (\n !firstChild ||\n !lastChild ||\n firstChild.start == null ||\n lastChild.end == null\n )\n continue;\n const start = firstChild.start;\n const end = lastChild.end;\n textEdits.push({ start, end, replacement: accessStr });\n } else if (\n type === 'jsx-insertion' &&\n variables &&\n childrenToReplace &&\n childrenToReplace.length > 0\n ) {\n const objProps = variables\n .map((variableString) => {\n const [key, variableValue] = variableString\n .split(':')\n .map((part) => part.trim());\n return `${key}: ${variableValue}`;\n })\n .join(', ');\n\n const firstChild = childrenToReplace[0];\n const lastChild = childrenToReplace[childrenToReplace.length - 1];\n if (\n !firstChild ||\n !lastChild ||\n firstChild.start == null ||\n lastChild.end == null\n )\n continue;\n const accessStr = `{${contentAccessCode}({ ${objProps} })}`;\n const start = firstChild.start;\n const end = lastChild.end;\n textEdits.push({ start, end, replacement: accessStr });\n } else if (type === 'template-literal' && path.isTemplateLiteral()) {\n let replacement = `${contentAccessCode}`;\n\n if (variables && variables.length > 0) {\n const objProps = variables\n .map((variableString) => {\n const [key, variableValue] = variableString\n .split(':')\n .map((part) => part.trim());\n return `${key}: ${variableValue}`;\n })\n .join(', ');\n replacement += `({ ${objProps} })`;\n } else {\n replacement += valueSuffix;\n }\n\n textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement,\n });\n }\n }\n\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const componentPath of componentsNeedingHooks) {\n const finalKey = componentKeyMap.get(componentPath.node)!;\n const existingInfo = existingInfoCache.get(componentPath.node);\n\n if (existingInfo) {\n if (existingInfo.hook === 'useIntlayer') needsUseIntlayer = true;\n\n if (existingInfo.hook === 'getIntlayer') needsGetIntlayer = true;\n\n // When the existing call is destructured, inject any missing keys into\n // the destructuring pattern so they can be accessed by name directly.\n if (existingInfo.isDestructured && existingInfo.objectPatternNode) {\n const neededKeys = new Set<string>();\n\n for (const { path: rPath, key: rKey } of replacements) {\n let current: NodePath | null = rPath;\n\n while (current) {\n if (current.node === componentPath.node) {\n neededKeys.add(rKey);\n break;\n }\n current = current.parentPath;\n }\n }\n\n const missingKeys = [...neededKeys].filter(\n (key) => !existingInfo.existingDestructuredKeys.includes(key)\n );\n\n if (missingKeys.length > 0) {\n const { objectPatternNode } = existingInfo;\n // Insert right after the last property so the space/newline before\n // `}` is naturally preserved: `{ a }` → `{ a, b }`.\n const lastProp =\n objectPatternNode.properties[\n objectPatternNode.properties.length - 1\n ];\n if (lastProp?.end != null) {\n textEdits.push({\n start: lastProp.end,\n end: lastProp.end,\n replacement: `, ${missingKeys.join(', ')}`,\n });\n }\n }\n }\n } else {\n const hook = hookMap.get(componentPath.node) || 'useIntlayer';\n\n if (hook === 'useIntlayer') needsUseIntlayer = true;\n\n if (hook === 'getIntlayer') needsGetIntlayer = true;\n\n const hookVarName = generatedVarNames.get(componentPath) || 'content';\n const hookStatementStr = `\\n const ${hookVarName} = ${hook}('${finalKey}');\\n`;\n\n if (componentPath.isProgram()) {\n // Find the last import or directive to inject the getIntlayer call\n let insertPos = 0;\n if (componentPath.node.directives.length > 0) {\n const lastDirective =\n componentPath.node.directives[\n componentPath.node.directives.length - 1\n ];\n if (lastDirective?.end != null) {\n insertPos = lastDirective.end;\n }\n }\n for (const stmt of componentPath.node.body) {\n if (t.isImportDeclaration(stmt)) {\n insertPos = Math.max(insertPos, stmt.end!);\n }\n }\n\n if (insertPos === 0 && componentPath.node.body.length > 0) {\n const firstBodyStmt = componentPath.node.body[0];\n if (firstBodyStmt?.start != null) {\n insertPos = firstBodyStmt.start;\n }\n }\n\n textEdits.push({\n start: insertPos,\n end: insertPos,\n replacement: `\\n${hookStatementStr}`,\n });\n continue;\n }\n\n const bodyPath = componentPath.get('body') as NodePath;\n\n if (bodyPath.isBlockStatement()) {\n textEdits.push({\n start: bodyPath.node.start! + 1,\n end: bodyPath.node.start! + 1,\n replacement: hookStatementStr,\n });\n } else if (bodyPath.isExpression()) {\n const start = bodyPath.node.start!;\n const end = bodyPath.node.end!;\n\n // Detect wrapping parentheses: `() => (expr)` — scan backward from\n // the expression start and forward from its end for matching `(` / `)`.\n let parenStart = -1;\n let parenEnd = -1;\n\n for (let i = start - 1; i >= 0; i--) {\n const char = fileCode[i];\n if (char === '(') {\n parenStart = i;\n break;\n }\n if (char !== ' ' && char !== '\\n' && char !== '\\r' && char !== '\\t')\n break;\n }\n\n if (parenStart !== -1) {\n for (let i = end; i < fileCode.length; i++) {\n const char = fileCode[i];\n if (char === ')') {\n parenEnd = i;\n break;\n }\n if (char !== ' ' && char !== '\\n' && char !== '\\r' && char !== '\\t')\n break;\n }\n }\n\n if (parenStart !== -1 && parenEnd !== -1) {\n // Replace the surrounding `(` … `)` with a block statement. We keep\n // the parentheses as `return (…)` to prevent automatic semicolon\n // insertion when the returned expression starts on a new line.\n textEdits.push({\n start: parenEnd,\n end: parenEnd + 1,\n replacement: `)\\n}`,\n });\n textEdits.push({\n start: parenStart,\n end: parenStart + 1,\n replacement: `{\\n const content = ${hook}('${finalKey}');\\n return (`,\n });\n } else {\n textEdits.push({\n start: end,\n end: end,\n replacement: `\\n}`,\n });\n textEdits.push({\n start: start,\n end: start,\n replacement: `{\\n const content = ${hook}('${finalKey}');\\n return `,\n });\n }\n }\n }\n }\n\n const injectImport = (hookName: string, targetPackage: string) => {\n let existingImportPath: NodePath<t.ImportDeclaration> | undefined;\n\n traverse(ast, {\n ImportDeclaration(path) {\n if (path.node.source.value === targetPackage) {\n existingImportPath = path;\n path.stop();\n }\n },\n });\n\n if (!existingImportPath) {\n const newImportStr = `import { ${hookName} } from '${targetPackage}';\\n`;\n let insertPos = 0;\n\n if (ast.program.body.length > 0) {\n const firstBodyStmt = ast.program.body[0];\n if (firstBodyStmt?.start != null) {\n insertPos = firstBodyStmt.start;\n }\n } else if (ast.program.directives && ast.program.directives.length > 0) {\n const lastDirective =\n ast.program.directives[ast.program.directives.length - 1];\n if (lastDirective?.end != null) {\n insertPos = lastDirective.end;\n }\n\n if (fileCode[insertPos] === ';') insertPos++;\n\n textEdits.push({\n start: insertPos,\n end: insertPos,\n replacement: `\\n${newImportStr}`,\n });\n return;\n }\n\n const firstBodyStmt = ast.program.body[0];\n if (\n insertPos === 0 ||\n (ast.program.body.length > 0 &&\n firstBodyStmt?.start != null &&\n insertPos === firstBodyStmt.start)\n ) {\n textEdits.push({\n start: insertPos,\n end: insertPos,\n replacement: newImportStr,\n });\n }\n } else {\n const existingSpecifiers = existingImportPath.node.specifiers;\n const missingImport = !existingSpecifiers.some(\n (specifier) =>\n t.isImportSpecifier(specifier) &&\n t.isIdentifier(specifier.imported) &&\n specifier.imported.name === hookName\n );\n\n if (missingImport) {\n const importCode = fileCode.slice(\n existingImportPath.node.start!,\n existingImportPath.node.end!\n );\n const closingBraceIndex = importCode.lastIndexOf('}');\n\n if (closingBraceIndex !== -1) {\n const isCommaNeeded = !importCode\n .slice(0, closingBraceIndex)\n .trim()\n .endsWith(',');\n const absolutePos =\n existingImportPath.node.start! + closingBraceIndex;\n const prefix = isCommaNeeded ? ', ' : ' ';\n textEdits.push({\n start: absolutePos,\n end: absolutePos,\n replacement: `${prefix}${hookName} `,\n });\n }\n }\n }\n };\n\n if (needsUseIntlayer) injectImport('useIntlayer', effectivePackageName);\n\n if (needsGetIntlayer) injectImport('getIntlayer', 'intlayer');\n\n textEdits.sort((editA, editB) => {\n if (editB.start !== editA.start) return editB.start - editA.start;\n\n return editB.end - editA.end;\n });\n\n let formattedCode = fileCode;\n\n for (const edit of textEdits) {\n formattedCode =\n formattedCode.slice(0, edit.start) +\n edit.replacement +\n formattedCode.slice(edit.end);\n }\n\n if (save) {\n writeFileSync(filePath, formattedCode);\n\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'inherit',\n cwd: configuration.system.baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n }\n\n return { extractedContent, modifiedCode: formattedCode };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","names":[],"sources":["../../../../src/extractContent/utils/constants.ts"],"sourcesContent":["/**\n * Attributes that should be extracted as translatable strings from JSX/HTML elements.\n * This is the single source of truth shared across all Intlayer compiler packages\n * (@intlayer/babel, @intlayer/vue-compiler, @intlayer/svelte-compiler, @intlayer/chokidar).\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n] as const;\n\n/**\n * The list of supported Intlayer integration packages.\n * This is the single source of truth for package name validation.\n *\n * Order matter for resolution\n */\nexport const packageList = [\n 'next-intlayer',\n 'react-intlayer',\n 'vue-intlayer',\n 'svelte-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'express-intlayer',\n 'hono-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n 'intlayer',\n] as const;\n\n/** Packages that support a `/server` sub-path for React Server Components. */\nexport const SERVER_CAPABLE_PACKAGES: ReadonlySet<string> = new Set([\n 'next-intlayer',\n]);\n\nexport type PackageName = (typeof packageList)[number];\n"],"mappings":";;;;;;AAKA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;AACF;;;;;;;AAQA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,0BAA+C,IAAI,IAAI,CAClE,eACF,CAAC"}
1
+ {"version":3,"file":"constants.mjs","names":[],"sources":["../../../../src/extractContent/utils/constants.ts"],"sourcesContent":["/**\n * Attributes that should be extracted as translatable strings from JSX/HTML elements.\n * This is the single source of truth shared across all Intlayer compiler packages\n * (@intlayer/babel, @intlayer/vue-compiler, @intlayer/svelte-compiler, @intlayer/chokidar).\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n] as const;\n\n/**\n * The list of supported Intlayer integration packages.\n * This is the single source of truth for package name validation.\n *\n * Order matter for resolution\n */\nexport const packageList = [\n 'next-intlayer',\n 'react-intlayer',\n 'vue-intlayer',\n 'svelte-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n 'angular-intlayer',\n 'lit-intlayer',\n 'express-intlayer',\n 'hono-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n 'intlayer',\n] as const;\n\n/** Packages that support a `/server` sub-path for React Server Components. */\nexport const SERVER_CAPABLE_PACKAGES: ReadonlySet<string> = new Set([\n 'next-intlayer',\n]);\n\nexport type PackageName = (typeof packageList)[number];\n"],"mappings":";;;;;;AAKA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACD;;;;;;;AAQD,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;AAGD,MAAa,0BAA+C,IAAI,IAAI,CAClE,gBACD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"detectPackageName.mjs","names":[],"sources":["../../../../src/extractContent/utils/detectPackageName.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { getPackageJsonPath } from '@intlayer/config/utils';\nimport { type PackageName, packageList } from './constants';\n\n/**\n * Detects which intlayer package is used in the project by reading package.json.\n */\nexport const detectPackageName = (searchDir: string): PackageName => {\n const { packageJsonPath } = getPackageJsonPath(searchDir);\n\n if (existsSync(packageJsonPath)) {\n try {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n\n for (const pkgName of packageList) {\n if (allDeps[pkgName]) return pkgName;\n }\n } catch {\n // Ignore JSON errors\n }\n }\n\n return packageList[packageList.length - 1] ?? 'intlayer';\n};\n"],"mappings":";;;;;;;;AAOA,MAAa,qBAAqB,cAAmC;CACnE,MAAM,EAAE,oBAAoB,mBAAmB,SAAS;CAExD,IAAI,WAAW,eAAe,GAC5B,IAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;EAC7D,MAAM,UAAU;GACd,GAAG,IAAI;GACP,GAAG,IAAI;GACP,GAAG,IAAI;EACT;EAEA,KAAK,MAAM,WAAW,aACpB,IAAI,QAAQ,UAAU,OAAO;CAEjC,QAAQ,CAER;CAGF,OAAO,YAAY,YAAY,SAAS,MAAM;AAChD"}
1
+ {"version":3,"file":"detectPackageName.mjs","names":[],"sources":["../../../../src/extractContent/utils/detectPackageName.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { getPackageJsonPath } from '@intlayer/config/utils';\nimport { type PackageName, packageList } from './constants';\n\n/**\n * Detects which intlayer package is used in the project by reading package.json.\n */\nexport const detectPackageName = (searchDir: string): PackageName => {\n const { packageJsonPath } = getPackageJsonPath(searchDir);\n\n if (existsSync(packageJsonPath)) {\n try {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n const allDeps = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n\n for (const pkgName of packageList) {\n if (allDeps[pkgName]) return pkgName;\n }\n } catch {\n // Ignore JSON errors\n }\n }\n\n return packageList[packageList.length - 1] ?? 'intlayer';\n};\n"],"mappings":";;;;;;;;AAOA,MAAa,qBAAqB,cAAmC;CACnE,MAAM,EAAE,oBAAoB,mBAAmB,UAAU;AAEzD,KAAI,WAAW,gBAAgB,CAC7B,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,iBAAiB,QAAQ,CAAC;EAC9D,MAAM,UAAU;GACd,GAAG,IAAI;GACP,GAAG,IAAI;GACP,GAAG,IAAI;GACR;AAED,OAAK,MAAM,WAAW,YACpB,KAAI,QAAQ,SAAU,QAAO;SAEzB;AAKV,QAAO,YAAY,YAAY,SAAS,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"extractDictionaryInfo.mjs","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"sourcesContent":["import { basename, dirname, extname, relative, resolve } from 'node:path';\nimport {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { assertPathWithin, parseStringPattern } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Fill } from '@intlayer/types/dictionary';\nimport type {\n FilePathPattern,\n FilePathPatternContext,\n FilePathPatternFunction,\n} from '@intlayer/types/filePathPattern';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { extractDictionaryKey } from './extractDictionaryKey';\n\nexport const getOutput = (\n configuration: IntlayerConfig,\n locale?: Locale\n): FilePathPatternFunction | false => {\n const output = configuration.compiler?.output as Fill | undefined;\n\n if (output === undefined || output === null) {\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n }\n\n if (output === false) return false;\n\n // Object per-locale record: look up the entry for the given locale\n if (typeof output === 'object' && typeof output !== 'function') {\n const entry = locale\n ? (output as Record<string, boolean | FilePathPattern>)[locale]\n : undefined;\n if (entry === false) return false;\n if (entry === undefined || entry === true) {\n throw new Error(\n `No output pattern configured for locale \"${locale}\" in compiler.output.`\n );\n }\n return typeof entry === 'string'\n ? (context: FilePathPatternContext) =>\n parseStringPattern(entry as string, context)\n : (entry as FilePathPatternFunction);\n }\n\n if (typeof output === 'string') {\n return (context: FilePathPatternContext) =>\n parseStringPattern(output, context);\n }\n\n if (typeof output === 'function') {\n return output as FilePathPatternFunction;\n }\n\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n};\n\nexport type ResolveContentFilePaths = {\n absolutePath: string;\n relativePath: string;\n isPerLocale: boolean;\n};\n\n/**\n * Resolves the paths for the content files associated with a component.\n * Checks for existing dictionaries first.\n */\nexport const resolveContentFilePaths = async (\n filePath: string,\n componentKey: string,\n configuration: IntlayerConfig,\n locale?: Locale\n): Promise<ResolveContentFilePaths> => {\n const { baseDir } = configuration.system;\n const { defaultLocale } = configuration.internationalization;\n\n const unmergedDictionaries = getUnmergedDictionaries(configuration) ?? {};\n const existingDicts = unmergedDictionaries[componentKey]\n ?.filter(\n (dictionary) =>\n // Remove remote dictionaries (Fix: Check for !== instead of ===)\n dictionary.location !== 'remote'\n )\n .filter(\n (dictionary) =>\n // Check for first locale dictionary sorted by priority that include the targeted locale\n dictionary.locale === undefined ||\n dictionary.locale === (locale ?? defaultLocale)\n );\n\n if (existingDicts?.[0]?.filePath) {\n const existingPath = existingDicts[0].filePath;\n const resolvedAbsolutePath = resolve(baseDir, existingPath);\n\n assertPathWithin(resolvedAbsolutePath, baseDir);\n\n return {\n absolutePath: resolvedAbsolutePath,\n relativePath: relative(baseDir, resolvedAbsolutePath),\n isPerLocale: false,\n };\n }\n\n const output = configuration.compiler?.output as Fill | undefined;\n const isObjectOutput =\n typeof output === 'object' &&\n output !== null &&\n typeof output !== 'function';\n\n // Build shared context (used for both object and scalar output paths)\n const extension = extname(\n filePath\n ) as FilePathPatternContext['componentExtension'];\n const componentName = basename(filePath, extension);\n const uncapitalizedName =\n componentName.charAt(0).toLowerCase() + componentName.slice(1);\n const componentFormat = getFormatFromExtension(\n extension!\n ) as FilePathPatternContext['componentFormat'];\n\n const targetLocale = (locale ?? defaultLocale) as Locale;\n\n const context: FilePathPatternContext = {\n key: componentKey,\n componentDirPath: relative(baseDir, dirname(filePath)),\n componentFileName: componentName,\n fileName: uncapitalizedName,\n componentFormat,\n componentExtension: extension,\n format: componentFormat!,\n locale: targetLocale,\n extension: configuration.content.fileExtensions[0] ?? '.ts',\n };\n\n // Object output: each locale has its own pattern → always per-locale\n if (isObjectOutput) {\n const pattern = getOutput(configuration, targetLocale);\n if (pattern === false) {\n throw new Error(\n `compiler.output is disabled for locale \"${targetLocale}\".`\n );\n }\n const rawAbsolutePath = await pattern(context);\n const absolutePath = resolveRelativePath(\n rawAbsolutePath,\n filePath,\n baseDir\n );\n return {\n absolutePath,\n relativePath: relative(baseDir, absolutePath),\n isPerLocale: true,\n };\n }\n\n // Scalar string/function output: detect per-locale via dummy locale probe\n const pattern = getOutput(configuration);\n if (pattern === false) {\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n }\n\n const rawAbsolutePath = await pattern({ ...context, locale: defaultLocale });\n\n // Apply the resolution rules\n const absolutePath = resolveRelativePath(rawAbsolutePath, filePath, baseDir);\n\n const localeIdentifier = '###########locale###########' as Locale;\n\n const rawPerLocalePath = await pattern({\n ...context,\n locale: localeIdentifier,\n });\n const isPerLocale = rawPerLocalePath.includes(localeIdentifier);\n\n return {\n absolutePath,\n relativePath: relative(baseDir, absolutePath),\n isPerLocale,\n };\n};\n\nexport type ExtractDictionaryInfoOptions = {\n configuration?: IntlayerConfig;\n};\n\n/**\n * Extracts the dictionary key and dictionary file path for a given component file.\n */\nexport const extractDictionaryInfo = async (\n filePath: string,\n fileText: string,\n configuration: IntlayerConfig\n): Promise<\n {\n dictionaryKey: string;\n } & ResolveContentFilePaths\n> => {\n const dictionaryKey = extractDictionaryKey(filePath, fileText);\n\n const resolvedPaths = await resolveContentFilePaths(\n filePath,\n dictionaryKey,\n configuration\n );\n\n return {\n dictionaryKey,\n ...resolvedPaths,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"extractDictionaryInfo.mjs","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryInfo.ts"],"sourcesContent":["import { basename, dirname, extname, relative, resolve } from 'node:path';\nimport {\n getFormatFromExtension,\n resolveRelativePath,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize } from '@intlayer/config/logger';\nimport { assertPathWithin, parseStringPattern } from '@intlayer/config/utils';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Fill } from '@intlayer/types/dictionary';\nimport type {\n FilePathPattern,\n FilePathPatternContext,\n FilePathPatternFunction,\n} from '@intlayer/types/filePathPattern';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { extractDictionaryKey } from './extractDictionaryKey';\n\nexport const getOutput = (\n configuration: IntlayerConfig,\n locale?: Locale\n): FilePathPatternFunction | false => {\n const output = configuration.compiler?.output as Fill | undefined;\n\n if (output === undefined || output === null) {\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n }\n\n if (output === false) return false;\n\n // Object per-locale record: look up the entry for the given locale\n if (typeof output === 'object' && typeof output !== 'function') {\n const entry = locale\n ? (output as Record<string, boolean | FilePathPattern>)[locale]\n : undefined;\n if (entry === false) return false;\n if (entry === undefined || entry === true) {\n throw new Error(\n `No output pattern configured for locale \"${locale}\" in compiler.output.`\n );\n }\n return typeof entry === 'string'\n ? (context: FilePathPatternContext) =>\n parseStringPattern(entry as string, context)\n : (entry as FilePathPatternFunction);\n }\n\n if (typeof output === 'string') {\n return (context: FilePathPatternContext) =>\n parseStringPattern(output, context);\n }\n\n if (typeof output === 'function') {\n return output as FilePathPatternFunction;\n }\n\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n};\n\nexport type ResolveContentFilePaths = {\n absolutePath: string;\n relativePath: string;\n isPerLocale: boolean;\n};\n\n/**\n * Resolves the paths for the content files associated with a component.\n * Checks for existing dictionaries first.\n */\nexport const resolveContentFilePaths = async (\n filePath: string,\n componentKey: string,\n configuration: IntlayerConfig,\n locale?: Locale\n): Promise<ResolveContentFilePaths> => {\n const { baseDir } = configuration.system;\n const { defaultLocale } = configuration.internationalization;\n\n const unmergedDictionaries = getUnmergedDictionaries(configuration) ?? {};\n const existingDicts = unmergedDictionaries[componentKey]\n ?.filter(\n (dictionary) =>\n // Remove remote dictionaries (Fix: Check for !== instead of ===)\n dictionary.location !== 'remote'\n )\n .filter(\n (dictionary) =>\n // Check for first locale dictionary sorted by priority that include the targeted locale\n dictionary.locale === undefined ||\n dictionary.locale === (locale ?? defaultLocale)\n );\n\n if (existingDicts?.[0]?.filePath) {\n const existingPath = existingDicts[0].filePath;\n const resolvedAbsolutePath = resolve(baseDir, existingPath);\n\n assertPathWithin(resolvedAbsolutePath, baseDir);\n\n return {\n absolutePath: resolvedAbsolutePath,\n relativePath: relative(baseDir, resolvedAbsolutePath),\n isPerLocale: false,\n };\n }\n\n const output = configuration.compiler?.output as Fill | undefined;\n const isObjectOutput =\n typeof output === 'object' &&\n output !== null &&\n typeof output !== 'function';\n\n // Build shared context (used for both object and scalar output paths)\n const extension = extname(\n filePath\n ) as FilePathPatternContext['componentExtension'];\n const componentName = basename(filePath, extension);\n const uncapitalizedName =\n componentName.charAt(0).toLowerCase() + componentName.slice(1);\n const componentFormat = getFormatFromExtension(\n extension!\n ) as FilePathPatternContext['componentFormat'];\n\n const targetLocale = (locale ?? defaultLocale) as Locale;\n\n const context: FilePathPatternContext = {\n key: componentKey,\n componentDirPath: relative(baseDir, dirname(filePath)),\n componentFileName: componentName,\n fileName: uncapitalizedName,\n componentFormat,\n componentExtension: extension,\n format: componentFormat!,\n locale: targetLocale,\n extension: configuration.content.fileExtensions[0] ?? '.ts',\n };\n\n // Object output: each locale has its own pattern → always per-locale\n if (isObjectOutput) {\n const pattern = getOutput(configuration, targetLocale);\n if (pattern === false) {\n throw new Error(\n `compiler.output is disabled for locale \"${targetLocale}\".`\n );\n }\n const rawAbsolutePath = await pattern(context);\n const absolutePath = resolveRelativePath(\n rawAbsolutePath,\n filePath,\n baseDir\n );\n return {\n absolutePath,\n relativePath: relative(baseDir, absolutePath),\n isPerLocale: true,\n };\n }\n\n // Scalar string/function output: detect per-locale via dummy locale probe\n const pattern = getOutput(configuration);\n if (pattern === false) {\n throw new Error(\n `No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`\n );\n }\n\n const rawAbsolutePath = await pattern({ ...context, locale: defaultLocale });\n\n // Apply the resolution rules\n const absolutePath = resolveRelativePath(rawAbsolutePath, filePath, baseDir);\n\n const localeIdentifier = '###########locale###########' as Locale;\n\n const rawPerLocalePath = await pattern({\n ...context,\n locale: localeIdentifier,\n });\n const isPerLocale = rawPerLocalePath.includes(localeIdentifier);\n\n return {\n absolutePath,\n relativePath: relative(baseDir, absolutePath),\n isPerLocale,\n };\n};\n\nexport type ExtractDictionaryInfoOptions = {\n configuration?: IntlayerConfig;\n};\n\n/**\n * Extracts the dictionary key and dictionary file path for a given component file.\n */\nexport const extractDictionaryInfo = async (\n filePath: string,\n fileText: string,\n configuration: IntlayerConfig\n): Promise<\n {\n dictionaryKey: string;\n } & ResolveContentFilePaths\n> => {\n const dictionaryKey = extractDictionaryKey(filePath, fileText);\n\n const resolvedPaths = await resolveContentFilePaths(\n filePath,\n dictionaryKey,\n configuration\n );\n\n return {\n dictionaryKey,\n ...resolvedPaths,\n };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"extractDictionaryKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryKey.ts"],"sourcesContent":["import { detectExportedComponentName } from '@intlayer/chokidar/cli';\nimport { COMPILER_DICTIONARY_KEY_PREFIX } from '@intlayer/config/defaultValues';\nimport { camelCaseToKebabCase } from '@intlayer/config/utils';\n\n/**\n * Extracts a dictionary key from a file path.\n *\n * Example: \"src/components/MyComponent/index.tsx\" -> \"comp-my-component\"\n */\nexport const extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = COMPILER_DICTIONARY_KEY_PREFIX\n): string => {\n const pathParts = filePath.split(/[\\\\/]/);\n const fileNameWithExt = pathParts.pop() || '';\n const lastDotIndex = fileNameWithExt.lastIndexOf('.');\n let baseName =\n lastDotIndex !== -1\n ? fileNameWithExt.slice(0, lastDotIndex)\n : fileNameWithExt;\n\n if (baseName.toLowerCase() === 'index') {\n baseName = pathParts.pop() || baseName;\n }\n\n return `${prefix}${camelCaseToKebabCase(baseName)}`;\n};\n\nexport const extractDictionaryKey = (\n filePath: string,\n fileText: string,\n prefix = COMPILER_DICTIONARY_KEY_PREFIX\n): string => {\n const componentName = detectExportedComponentName(fileText);\n\n if (componentName) {\n return `${prefix}${camelCaseToKebabCase(componentName)}`;\n }\n\n return extractDictionaryKeyFromPath(filePath, prefix);\n};\n"],"mappings":";;;;;;;;;;AASA,MAAa,gCACX,UACA,SAAS,mCACE;CACX,MAAM,YAAY,SAAS,MAAM,OAAO;CACxC,MAAM,kBAAkB,UAAU,IAAI,KAAK;CAC3C,MAAM,eAAe,gBAAgB,YAAY,GAAG;CACpD,IAAI,WACF,iBAAiB,KACb,gBAAgB,MAAM,GAAG,YAAY,IACrC;CAEN,IAAI,SAAS,YAAY,MAAM,SAC7B,WAAW,UAAU,IAAI,KAAK;CAGhC,OAAO,GAAG,SAAS,qBAAqB,QAAQ;AAClD;AAEA,MAAa,wBACX,UACA,UACA,SAAS,mCACE;CACX,MAAM,gBAAgB,4BAA4B,QAAQ;CAE1D,IAAI,eACF,OAAO,GAAG,SAAS,qBAAqB,aAAa;CAGvD,OAAO,6BAA6B,UAAU,MAAM;AACtD"}
1
+ {"version":3,"file":"extractDictionaryKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/extractDictionaryKey.ts"],"sourcesContent":["import { detectExportedComponentName } from '@intlayer/chokidar/cli';\nimport { COMPILER_DICTIONARY_KEY_PREFIX } from '@intlayer/config/defaultValues';\nimport { camelCaseToKebabCase } from '@intlayer/config/utils';\n\n/**\n * Extracts a dictionary key from a file path.\n *\n * Example: \"src/components/MyComponent/index.tsx\" -> \"comp-my-component\"\n */\nexport const extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = COMPILER_DICTIONARY_KEY_PREFIX\n): string => {\n const pathParts = filePath.split(/[\\\\/]/);\n const fileNameWithExt = pathParts.pop() || '';\n const lastDotIndex = fileNameWithExt.lastIndexOf('.');\n let baseName =\n lastDotIndex !== -1\n ? fileNameWithExt.slice(0, lastDotIndex)\n : fileNameWithExt;\n\n if (baseName.toLowerCase() === 'index') {\n baseName = pathParts.pop() || baseName;\n }\n\n return `${prefix}${camelCaseToKebabCase(baseName)}`;\n};\n\nexport const extractDictionaryKey = (\n filePath: string,\n fileText: string,\n prefix = COMPILER_DICTIONARY_KEY_PREFIX\n): string => {\n const componentName = detectExportedComponentName(fileText);\n\n if (componentName) {\n return `${prefix}${camelCaseToKebabCase(componentName)}`;\n }\n\n return extractDictionaryKeyFromPath(filePath, prefix);\n};\n"],"mappings":";;;;;;;;;;AASA,MAAa,gCACX,UACA,SAAS,mCACE;CACX,MAAM,YAAY,SAAS,MAAM,QAAQ;CACzC,MAAM,kBAAkB,UAAU,KAAK,IAAI;CAC3C,MAAM,eAAe,gBAAgB,YAAY,IAAI;CACrD,IAAI,WACF,iBAAiB,KACb,gBAAgB,MAAM,GAAG,aAAa,GACtC;AAEN,KAAI,SAAS,aAAa,KAAK,QAC7B,YAAW,UAAU,KAAK,IAAI;AAGhC,QAAO,GAAG,SAAS,qBAAqB,SAAS;;AAGnD,MAAa,wBACX,UACA,UACA,SAAS,mCACE;CACX,MAAM,gBAAgB,4BAA4B,SAAS;AAE3D,KAAI,cACF,QAAO,GAAG,SAAS,qBAAqB,cAAc;AAGxD,QAAO,6BAA6B,UAAU,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"generateKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/generateKey.ts"],"sourcesContent":["export const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n const maxWordLength = 20;\n const maxKeyLength = 40;\n\n let key = text\n .normalize('NFD') // Normalize to decomposes combined characters (e.g., é -> e + ´)\n .replace(/[\\u0300-\\u036f]/g, '') // Remove the accent characters\n .replace(/[\\s_-]+/g, ' ')\n .replace(/[^\\p{L}\\p{N} ]/gu, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word) =>\n word.length > maxWordLength ? word.substring(0, maxWordLength) : word\n )\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (key.length > maxKeyLength) {\n key = key.substring(0, maxKeyLength);\n }\n\n if (!key) key = 'content';\n\n // If the key starts with a number, prepend 'x' to make it a valid JS identifier\n if (/^[0-9]/.test(key)) {\n key = `x${key}`;\n }\n\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n"],"mappings":";AAAA,MAAa,eACX,MACA,iBACW;CACX,MAAM,WAAW;CACjB,MAAM,gBAAgB;CACtB,MAAM,eAAe;CAErB,IAAI,MAAM,KACP,UAAU,KAAK,EACf,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,YAAY,GAAG,EACvB,QAAQ,oBAAoB,EAAE,EAC9B,KAAK,EACL,MAAM,GAAG,EACT,OAAO,OAAO,EACd,MAAM,GAAG,QAAQ,EACjB,KAAK,SACJ,KAAK,SAAS,gBAAgB,KAAK,UAAU,GAAG,aAAa,IAAI,IACnE,EACC,KAAK,MAAM,UACV,UAAU,IACN,KAAK,YAAY,IACjB,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY,CAC/D,EACC,KAAK,EAAE;CAEV,IAAI,IAAI,SAAS,cACf,MAAM,IAAI,UAAU,GAAG,YAAY;CAGrC,IAAI,CAAC,KAAK,MAAM;CAGhB,IAAI,SAAS,KAAK,GAAG,GACnB,MAAM,IAAI;CAGZ,IAAI,aAAa,IAAI,GAAG,GAAG;EACzB,IAAI,IAAI;EACR,OAAO,aAAa,IAAI,GAAG,MAAM,GAAG,GAAG;EACvC,MAAM,GAAG,MAAM;CACjB;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"generateKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/generateKey.ts"],"sourcesContent":["export const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n const maxWordLength = 20;\n const maxKeyLength = 40;\n\n let key = text\n .normalize('NFD') // Normalize to decomposes combined characters (e.g., é -> e + ´)\n .replace(/[\\u0300-\\u036f]/g, '') // Remove the accent characters\n .replace(/[\\s_-]+/g, ' ')\n .replace(/[^\\p{L}\\p{N} ]/gu, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word) =>\n word.length > maxWordLength ? word.substring(0, maxWordLength) : word\n )\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (key.length > maxKeyLength) {\n key = key.substring(0, maxKeyLength);\n }\n\n if (!key) key = 'content';\n\n // If the key starts with a number, prepend 'x' to make it a valid JS identifier\n if (/^[0-9]/.test(key)) {\n key = `x${key}`;\n }\n\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n"],"mappings":";AAAA,MAAa,eACX,MACA,iBACW;CACX,MAAM,WAAW;CACjB,MAAM,gBAAgB;CACtB,MAAM,eAAe;CAErB,IAAI,MAAM,KACP,UAAU,MAAM,CAChB,QAAQ,oBAAoB,GAAG,CAC/B,QAAQ,YAAY,IAAI,CACxB,QAAQ,oBAAoB,GAAG,CAC/B,MAAM,CACN,MAAM,IAAI,CACV,OAAO,QAAQ,CACf,MAAM,GAAG,SAAS,CAClB,KAAK,SACJ,KAAK,SAAS,gBAAgB,KAAK,UAAU,GAAG,cAAc,GAAG,KAClE,CACA,KAAK,MAAM,UACV,UAAU,IACN,KAAK,aAAa,GAClB,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,aAAa,CAC/D,CACA,KAAK,GAAG;AAEX,KAAI,IAAI,SAAS,aACf,OAAM,IAAI,UAAU,GAAG,aAAa;AAGtC,KAAI,CAAC,IAAK,OAAM;AAGhB,KAAI,SAAS,KAAK,IAAI,CACpB,OAAM,IAAI;AAGZ,KAAI,aAAa,IAAI,IAAI,EAAE;EACzB,IAAI,IAAI;AACR,SAAO,aAAa,IAAI,GAAG,MAAM,IAAI,CAAE;AACvC,QAAM,GAAG,MAAM;;AAEjB,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"getComponentName.mjs","names":[],"sources":["../../../../src/extractContent/utils/getComponentName.ts"],"sourcesContent":["import type { NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\n\n/**\n * Resolves the name of the component from various function declaration types.\n */\nexport const getComponentName = (path: NodePath): string | undefined => {\n if (path.isFunctionDeclaration()) {\n return path.node.id?.name;\n }\n\n if (path.isArrowFunctionExpression() || path.isFunctionExpression()) {\n if (\n path.parentPath.isVariableDeclarator() &&\n t.isIdentifier(path.parentPath.node.id)\n ) {\n return path.parentPath.node.id.name;\n }\n }\n\n return undefined;\n};\n"],"mappings":";;;;;;AAMA,MAAa,oBAAoB,SAAuC;CACtE,IAAI,KAAK,sBAAsB,GAC7B,OAAO,KAAK,KAAK,IAAI;CAGvB,IAAI,KAAK,0BAA0B,KAAK,KAAK,qBAAqB,GAChE;MACE,KAAK,WAAW,qBAAqB,KACrC,EAAE,aAAa,KAAK,WAAW,KAAK,EAAE,GAEtC,OAAO,KAAK,WAAW,KAAK,GAAG;CACjC;AAIJ"}
1
+ {"version":3,"file":"getComponentName.mjs","names":[],"sources":["../../../../src/extractContent/utils/getComponentName.ts"],"sourcesContent":["import type { NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\n\n/**\n * Resolves the name of the component from various function declaration types.\n */\nexport const getComponentName = (path: NodePath): string | undefined => {\n if (path.isFunctionDeclaration()) {\n return path.node.id?.name;\n }\n\n if (path.isArrowFunctionExpression() || path.isFunctionExpression()) {\n if (\n path.parentPath.isVariableDeclarator() &&\n t.isIdentifier(path.parentPath.node.id)\n ) {\n return path.parentPath.node.id.name;\n }\n }\n\n return undefined;\n};\n"],"mappings":";;;;;;AAMA,MAAa,oBAAoB,SAAuC;AACtE,KAAI,KAAK,uBAAuB,CAC9B,QAAO,KAAK,KAAK,IAAI;AAGvB,KAAI,KAAK,2BAA2B,IAAI,KAAK,sBAAsB,EACjE;MACE,KAAK,WAAW,sBAAsB,IACtC,EAAE,aAAa,KAAK,WAAW,KAAK,GAAG,CAEvC,QAAO,KAAK,WAAW,KAAK,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"getExistingIntlayerInfo.mjs","names":[],"sources":["../../../../src/extractContent/utils/getExistingIntlayerInfo.ts"],"sourcesContent":["import type { NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\n\nexport type ExistingIntlayerInfo = {\n key: string;\n hook: 'useIntlayer' | 'getIntlayer';\n /** The variable name used to store the call result (e.g. `t` in `const t = useIntlayer(...)`) */\n variableName: string;\n /** True when the call result is destructured: `const { a, b } = getIntlayer(...)` */\n isDestructured: boolean;\n /** Keys already present in the destructuring pattern (empty when not destructured) */\n existingDestructuredKeys: string[];\n /** The ObjectPattern AST node, present only when `isDestructured` is true */\n objectPatternNode?: t.ObjectPattern;\n};\n\n/**\n * Searches for an existing useIntlayer or getIntlayer call in the function body.\n */\nexport const getExistingIntlayerInfo = (\n path: NodePath\n): ExistingIntlayerInfo | undefined => {\n let result: ExistingIntlayerInfo | undefined;\n\n // We only check the direct body of the function, not nested functions\n path.traverse({\n CallExpression(childPath) {\n const callee = childPath.node.callee;\n\n if (\n t.isIdentifier(callee) &&\n (callee.name === 'useIntlayer' || callee.name === 'getIntlayer')\n ) {\n const arg = childPath.node.arguments[0];\n\n if (t.isStringLiteral(arg)) {\n const parentNode = childPath.parent;\n let isDestructured = false;\n let existingDestructuredKeys: string[] = [];\n let objectPatternNode: t.ObjectPattern | undefined;\n let variableName = 'content';\n\n if (t.isVariableDeclarator(parentNode)) {\n if (t.isObjectPattern(parentNode.id)) {\n isDestructured = true;\n objectPatternNode = parentNode.id;\n existingDestructuredKeys = parentNode.id.properties\n .filter(\n (p): p is t.ObjectProperty =>\n t.isObjectProperty(p) && t.isIdentifier(p.key)\n )\n .map((p) => (p.key as t.Identifier).name);\n } else if (t.isIdentifier(parentNode.id)) {\n variableName = parentNode.id.name;\n }\n }\n\n result = {\n key: arg.value,\n hook: callee.name as 'useIntlayer' | 'getIntlayer',\n variableName,\n isDestructured,\n existingDestructuredKeys,\n objectPatternNode,\n };\n childPath.stop();\n }\n }\n },\n Function(childPath) {\n childPath.skip(); // Don't look inside nested functions\n },\n });\n\n return result;\n};\n"],"mappings":";;;;;;AAmBA,MAAa,2BACX,SACqC;CACrC,IAAI;CAGJ,KAAK,SAAS;EACZ,eAAe,WAAW;GACxB,MAAM,SAAS,UAAU,KAAK;GAE9B,IACE,EAAE,aAAa,MAAM,MACpB,OAAO,SAAS,iBAAiB,OAAO,SAAS,gBAClD;IACA,MAAM,MAAM,UAAU,KAAK,UAAU;IAErC,IAAI,EAAE,gBAAgB,GAAG,GAAG;KAC1B,MAAM,aAAa,UAAU;KAC7B,IAAI,iBAAiB;KACrB,IAAI,2BAAqC,CAAC;KAC1C,IAAI;KACJ,IAAI,eAAe;KAEnB,IAAI,EAAE,qBAAqB,UAAU,GACnC;UAAI,EAAE,gBAAgB,WAAW,EAAE,GAAG;OACpC,iBAAiB;OACjB,oBAAoB,WAAW;OAC/B,2BAA2B,WAAW,GAAG,WACtC,QACE,MACC,EAAE,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,CACjD,EACC,KAAK,MAAO,EAAE,IAAqB,IAAI;MAC5C,OAAO,IAAI,EAAE,aAAa,WAAW,EAAE,GACrC,eAAe,WAAW,GAAG;KAC/B;KAGF,SAAS;MACP,KAAK,IAAI;MACT,MAAM,OAAO;MACb;MACA;MACA;MACA;KACF;KACA,UAAU,KAAK;IACjB;GACF;EACF;EACA,SAAS,WAAW;GAClB,UAAU,KAAK;EACjB;CACF,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"getExistingIntlayerInfo.mjs","names":[],"sources":["../../../../src/extractContent/utils/getExistingIntlayerInfo.ts"],"sourcesContent":["import type { NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\n\nexport type ExistingIntlayerInfo = {\n key: string;\n hook: 'useIntlayer' | 'getIntlayer';\n /** The variable name used to store the call result (e.g. `t` in `const t = useIntlayer(...)`) */\n variableName: string;\n /** True when the call result is destructured: `const { a, b } = getIntlayer(...)` */\n isDestructured: boolean;\n /** Keys already present in the destructuring pattern (empty when not destructured) */\n existingDestructuredKeys: string[];\n /** The ObjectPattern AST node, present only when `isDestructured` is true */\n objectPatternNode?: t.ObjectPattern;\n};\n\n/**\n * Searches for an existing useIntlayer or getIntlayer call in the function body.\n */\nexport const getExistingIntlayerInfo = (\n path: NodePath\n): ExistingIntlayerInfo | undefined => {\n let result: ExistingIntlayerInfo | undefined;\n\n // We only check the direct body of the function, not nested functions\n path.traverse({\n CallExpression(childPath) {\n const callee = childPath.node.callee;\n\n if (\n t.isIdentifier(callee) &&\n (callee.name === 'useIntlayer' || callee.name === 'getIntlayer')\n ) {\n const arg = childPath.node.arguments[0];\n\n if (t.isStringLiteral(arg)) {\n const parentNode = childPath.parent;\n let isDestructured = false;\n let existingDestructuredKeys: string[] = [];\n let objectPatternNode: t.ObjectPattern | undefined;\n let variableName = 'content';\n\n if (t.isVariableDeclarator(parentNode)) {\n if (t.isObjectPattern(parentNode.id)) {\n isDestructured = true;\n objectPatternNode = parentNode.id;\n existingDestructuredKeys = parentNode.id.properties\n .filter(\n (p): p is t.ObjectProperty =>\n t.isObjectProperty(p) && t.isIdentifier(p.key)\n )\n .map((p) => (p.key as t.Identifier).name);\n } else if (t.isIdentifier(parentNode.id)) {\n variableName = parentNode.id.name;\n }\n }\n\n result = {\n key: arg.value,\n hook: callee.name as 'useIntlayer' | 'getIntlayer',\n variableName,\n isDestructured,\n existingDestructuredKeys,\n objectPatternNode,\n };\n childPath.stop();\n }\n }\n },\n Function(childPath) {\n childPath.skip(); // Don't look inside nested functions\n },\n });\n\n return result;\n};\n"],"mappings":";;;;;;AAmBA,MAAa,2BACX,SACqC;CACrC,IAAI;AAGJ,MAAK,SAAS;EACZ,eAAe,WAAW;GACxB,MAAM,SAAS,UAAU,KAAK;AAE9B,OACE,EAAE,aAAa,OAAO,KACrB,OAAO,SAAS,iBAAiB,OAAO,SAAS,gBAClD;IACA,MAAM,MAAM,UAAU,KAAK,UAAU;AAErC,QAAI,EAAE,gBAAgB,IAAI,EAAE;KAC1B,MAAM,aAAa,UAAU;KAC7B,IAAI,iBAAiB;KACrB,IAAI,2BAAqC,EAAE;KAC3C,IAAI;KACJ,IAAI,eAAe;AAEnB,SAAI,EAAE,qBAAqB,WAAW,EACpC;UAAI,EAAE,gBAAgB,WAAW,GAAG,EAAE;AACpC,wBAAiB;AACjB,2BAAoB,WAAW;AAC/B,kCAA2B,WAAW,GAAG,WACtC,QACE,MACC,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,CACjD,CACA,KAAK,MAAO,EAAE,IAAqB,KAAK;iBAClC,EAAE,aAAa,WAAW,GAAG,CACtC,gBAAe,WAAW,GAAG;;AAIjC,cAAS;MACP,KAAK,IAAI;MACT,MAAM,OAAO;MACb;MACA;MACA;MACA;MACD;AACD,eAAU,MAAM;;;;EAItB,SAAS,WAAW;AAClB,aAAU,MAAM;;EAEnB,CAAC;AAEF,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"getOrGenerateKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/getOrGenerateKey.ts"],"sourcesContent":["import { generateKey } from './generateKey';\n\n/**\n * Gets an existing key for a given text or generates a new one.\n */\nexport const getOrGenerateKey = (\n text: string,\n componentKey: string,\n existingKeys: Set<string>,\n extractedContent: Record<string, Record<string, string>>\n): string => {\n if (!extractedContent[componentKey]) {\n extractedContent[componentKey] = {};\n }\n const existingEntry = Object.entries(extractedContent[componentKey]).find(\n ([_, value]) => value === text\n );\n\n if (existingEntry) {\n return existingEntry[0];\n }\n const key = generateKey(text, existingKeys);\n\n existingKeys.add(key);\n extractedContent[componentKey][key] = text;\n return key;\n};\n"],"mappings":";;;;;;AAKA,MAAa,oBACX,MACA,cACA,cACA,qBACW;CACX,IAAI,CAAC,iBAAiB,eACpB,iBAAiB,gBAAgB,CAAC;CAEpC,MAAM,gBAAgB,OAAO,QAAQ,iBAAiB,aAAa,EAAE,MAClE,CAAC,GAAG,WAAW,UAAU,IAC5B;CAEA,IAAI,eACF,OAAO,cAAc;CAEvB,MAAM,MAAM,YAAY,MAAM,YAAY;CAE1C,aAAa,IAAI,GAAG;CACpB,iBAAiB,cAAc,OAAO;CACtC,OAAO;AACT"}
1
+ {"version":3,"file":"getOrGenerateKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/getOrGenerateKey.ts"],"sourcesContent":["import { generateKey } from './generateKey';\n\n/**\n * Gets an existing key for a given text or generates a new one.\n */\nexport const getOrGenerateKey = (\n text: string,\n componentKey: string,\n existingKeys: Set<string>,\n extractedContent: Record<string, Record<string, string>>\n): string => {\n if (!extractedContent[componentKey]) {\n extractedContent[componentKey] = {};\n }\n const existingEntry = Object.entries(extractedContent[componentKey]).find(\n ([_, value]) => value === text\n );\n\n if (existingEntry) {\n return existingEntry[0];\n }\n const key = generateKey(text, existingKeys);\n\n existingKeys.add(key);\n extractedContent[componentKey][key] = text;\n return key;\n};\n"],"mappings":";;;;;;AAKA,MAAa,oBACX,MACA,cACA,cACA,qBACW;AACX,KAAI,CAAC,iBAAiB,cACpB,kBAAiB,gBAAgB,EAAE;CAErC,MAAM,gBAAgB,OAAO,QAAQ,iBAAiB,cAAc,CAAC,MAClE,CAAC,GAAG,WAAW,UAAU,KAC3B;AAED,KAAI,cACF,QAAO,cAAc;CAEvB,MAAM,MAAM,YAAY,MAAM,aAAa;AAE3C,cAAa,IAAI,IAAI;AACrB,kBAAiB,cAAc,OAAO;AACtC,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveDictionaryKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { assertPathWithin } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\n/**\n * Resolves a unique dictionary key, checking for existing dictionaries and files.\n * Note: this chokidar-specific variant fetches unmergedDictionaries internally\n * from the configuration (unlike the `@intlayer/babel` version which takes it as a parameter).\n */\nexport const resolveDictionaryKey = (\n initialKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n unmergedDictionaries?: Record<string, unknown>,\n usedKeys: Set<string> = new Set()\n): string => {\n const dicts =\n unmergedDictionaries ?? getUnmergedDictionaries(configuration) ?? {};\n\n const { fileExtensions } = configuration.content;\n\n const dirName = dirname(filePath);\n const firstExtension = fileExtensions[0] ?? '.ts';\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n\n let index = 0;\n\n while (index < 100) {\n const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;\n const dictionaries = dicts[keyToTest] as Dictionary[] | undefined;\n const contentFilePath = join(dirName, `${keyToTest}${extension}`);\n\n assertPathWithin(resolve(contentFilePath), dirName);\n\n const isKeyUsed = usedKeys.has(keyToTest);\n const hasDictionaries = dictionaries && dictionaries.length > 0;\n const fileExists = existsSync(contentFilePath);\n\n if (!isKeyUsed && !hasDictionaries && !fileExists) {\n return keyToTest;\n }\n index++;\n }\n\n return initialKey;\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,wBACX,YACA,UACA,eACA,sBACA,2BAAwB,IAAI,IAAI,MACrB;CACX,MAAM,QACJ,wBAAwB,wBAAwB,aAAa,KAAK,CAAC;CAErE,MAAM,EAAE,mBAAmB,cAAc;CAEzC,MAAM,UAAU,QAAQ,QAAQ;CAChC,MAAM,iBAAiB,eAAe,MAAM;CAC5C,MAAM,YAAY,eAAe,WAAW,GAAG,IAC3C,iBACA,IAAI;CAER,IAAI,QAAQ;CAEZ,OAAO,QAAQ,KAAK;EAClB,MAAM,YAAY,UAAU,IAAI,aAAa,GAAG,aAAa;EAC7D,MAAM,eAAe,MAAM;EAC3B,MAAM,kBAAkB,KAAK,SAAS,GAAG,YAAY,WAAW;EAEhE,iBAAiB,QAAQ,eAAe,GAAG,OAAO;EAElD,MAAM,YAAY,SAAS,IAAI,SAAS;EACxC,MAAM,kBAAkB,gBAAgB,aAAa,SAAS;EAC9D,MAAM,aAAa,WAAW,eAAe;EAE7C,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,YACrC,OAAO;EAET;CACF;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"resolveDictionaryKey.mjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { assertPathWithin } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\n/**\n * Resolves a unique dictionary key, checking for existing dictionaries and files.\n * Note: this chokidar-specific variant fetches unmergedDictionaries internally\n * from the configuration (unlike the `@intlayer/babel` version which takes it as a parameter).\n */\nexport const resolveDictionaryKey = (\n initialKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n unmergedDictionaries?: Record<string, unknown>,\n usedKeys: Set<string> = new Set()\n): string => {\n const dicts =\n unmergedDictionaries ?? getUnmergedDictionaries(configuration) ?? {};\n\n const { fileExtensions } = configuration.content;\n\n const dirName = dirname(filePath);\n const firstExtension = fileExtensions[0] ?? '.ts';\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n\n let index = 0;\n\n while (index < 100) {\n const keyToTest = index === 0 ? initialKey : `${initialKey}${index}`;\n const dictionaries = dicts[keyToTest] as Dictionary[] | undefined;\n const contentFilePath = join(dirName, `${keyToTest}${extension}`);\n\n assertPathWithin(resolve(contentFilePath), dirName);\n\n const isKeyUsed = usedKeys.has(keyToTest);\n const hasDictionaries = dictionaries && dictionaries.length > 0;\n const fileExists = existsSync(contentFilePath);\n\n if (!isKeyUsed && !hasDictionaries && !fileExists) {\n return keyToTest;\n }\n index++;\n }\n\n return initialKey;\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,wBACX,YACA,UACA,eACA,sBACA,2BAAwB,IAAI,KAAK,KACtB;CACX,MAAM,QACJ,wBAAwB,wBAAwB,cAAc,IAAI,EAAE;CAEtE,MAAM,EAAE,mBAAmB,cAAc;CAEzC,MAAM,UAAU,QAAQ,SAAS;CACjC,MAAM,iBAAiB,eAAe,MAAM;CAC5C,MAAM,YAAY,eAAe,WAAW,IAAI,GAC5C,iBACA,IAAI;CAER,IAAI,QAAQ;AAEZ,QAAO,QAAQ,KAAK;EAClB,MAAM,YAAY,UAAU,IAAI,aAAa,GAAG,aAAa;EAC7D,MAAM,eAAe,MAAM;EAC3B,MAAM,kBAAkB,KAAK,SAAS,GAAG,YAAY,YAAY;AAEjE,mBAAiB,QAAQ,gBAAgB,EAAE,QAAQ;EAEnD,MAAM,YAAY,SAAS,IAAI,UAAU;EACzC,MAAM,kBAAkB,gBAAgB,aAAa,SAAS;EAC9D,MAAM,aAAa,WAAW,gBAAgB;AAE9C,MAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,WACrC,QAAO;AAET;;AAGF,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"shouldExtract.mjs","names":[],"sources":["../../../../src/extractContent/utils/shouldExtract.ts"],"sourcesContent":["/**\n * Checks whether the given text should be extracted as a translatable string.\n *\n * Filters out:\n * - Empty strings\n * - Emails\n * - Uncapitalized strings of 2 words or fewer (likely technical terms)\n * - Dynamic content patterns like Vue bindings (`v-`) or object patterns (`{`)\n */\nexport const shouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n\n if (!trimmed) return false;\n\n // Ignore emails\n if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) return false;\n\n // Ignore dynamic content patterns, but allow {{placeholder}} which is intlayer's insertion format\n if (\n (trimmed.startsWith('{') && !trimmed.startsWith('{{')) ||\n trimmed.startsWith('v-')\n )\n return false;\n\n // Ignore explicit code patterns (markers)\n if (\n trimmed.includes('=>') ||\n trimmed.includes(');') ||\n trimmed.includes('(){') ||\n trimmed.includes('==') ||\n trimmed.includes('window.') ||\n trimmed.startsWith('(function') ||\n trimmed.startsWith('function(')\n ) {\n return false;\n }\n\n // Heuristic: check for characters that are common in code but rare in natural text.\n // Whitelist: letters, numbers, spaces, and frequent text symbols (including punctuation, braces, and technical symbols)\n const nonTextualRegex =\n /[^\\p{L}\\p{N}\\s.,!?;:'\"()[\\]{}–—/«»„“\\p{Sc}%&*+#@^_+=<>/~]/gu;\n const nonTextualMatches = trimmed.match(nonTextualRegex) || [];\n\n // If a string contains a high density of truly exceptional symbols (like |, \\, etc.),\n // it is highly likely to be code or complex technical data.\n if (nonTextualMatches.length > 5) return false;\n\n const wordCount = trimmed.split(/\\s+/).length;\n\n // Ignore CSS/Tailwind utility class strings. A string whose tokens all look\n // like CSS utility classes (lowercase, optional responsive/state prefix like\n // \"sm:\" or \"hover:\", optional hyphenated suffix like \"-4\" or \"-full\") and\n // where at least one token contains a hyphen is almost certainly a className\n // value, not translatable text.\n const cssClassTokenRegex =\n /^!?([a-z][a-z0-9-]*:)*[a-z][a-z0-9]*(-[a-z0-9[\\].,%#/]+)*(\\/[a-z0-9]+)?$/;\n if (wordCount > 1) {\n const tokens = trimmed.split(/\\s+/);\n if (\n tokens.every((token) => cssClassTokenRegex.test(token)) &&\n tokens.some((token) => token.includes('-'))\n ) {\n return false;\n }\n }\n\n // Check if starts with a capital letter (including after an opening parenthesis/quote)\n const isCapitalized = /^['\"([]*\\p{Lu}/u.test(trimmed);\n\n // Ignore technical identifiers (one word strings with camelCase, kebab-case, snake_case etc.)\n if (wordCount === 1) {\n // CamelCase or internal capitals (like camelCaseProperty or CamelCaseProperty)\n if (/[a-z]\\p{Lu}/u.test(trimmed)) return false;\n // kebab-case or snake_case\n if (trimmed.includes('-') || trimmed.includes('_')) return false;\n }\n\n // We usually want to extract full sentences or labels, not single/short technical words.\n // Extract if capitalized, or if it contains more than 2 words.\n if (!isCapitalized && wordCount <= 2) return false;\n\n return true;\n};\n"],"mappings":";;;;;;;;;;AASA,MAAa,iBAAiB,SAA0B;CACtD,MAAM,UAAU,KAAK,KAAK;CAE1B,IAAI,CAAC,SAAS,OAAO;CAGrB,IAAI,6BAA6B,KAAK,OAAO,GAAG,OAAO;CAGvD,IACG,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,WAAW,IAAI,KACpD,QAAQ,WAAW,IAAI,GAEvB,OAAO;CAGT,IACE,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,KAAK,KACtB,QAAQ,SAAS,IAAI,KACrB,QAAQ,SAAS,SAAS,KAC1B,QAAQ,WAAW,WAAW,KAC9B,QAAQ,WAAW,WAAW,GAE9B,OAAO;CAWT,KAJ0B,QAAQ,MAAM,6DAAe,KAAK,CAAC,GAIvC,SAAS,GAAG,OAAO;CAEzC,MAAM,YAAY,QAAQ,MAAM,KAAK,EAAE;CAOvC,MAAM,qBACJ;CACF,IAAI,YAAY,GAAG;EACjB,MAAM,SAAS,QAAQ,MAAM,KAAK;EAClC,IACE,OAAO,OAAO,UAAU,mBAAmB,KAAK,KAAK,CAAC,KACtD,OAAO,MAAM,UAAU,MAAM,SAAS,GAAG,CAAC,GAE1C,OAAO;CAEX;CAGA,MAAM,gBAAgB,kBAAkB,KAAK,OAAO;CAGpD,IAAI,cAAc,GAAG;EAEnB,IAAI,eAAe,KAAK,OAAO,GAAG,OAAO;EAEzC,IAAI,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAG,OAAO;CAC7D;CAIA,IAAI,CAAC,iBAAiB,aAAa,GAAG,OAAO;CAE7C,OAAO;AACT"}
1
+ {"version":3,"file":"shouldExtract.mjs","names":[],"sources":["../../../../src/extractContent/utils/shouldExtract.ts"],"sourcesContent":["/**\n * Checks whether the given text should be extracted as a translatable string.\n *\n * Filters out:\n * - Empty strings\n * - Emails\n * - Uncapitalized strings of 2 words or fewer (likely technical terms)\n * - Dynamic content patterns like Vue bindings (`v-`) or object patterns (`{`)\n */\nexport const shouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n\n if (!trimmed) return false;\n\n // Ignore emails\n if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) return false;\n\n // Ignore dynamic content patterns, but allow {{placeholder}} which is intlayer's insertion format\n if (\n (trimmed.startsWith('{') && !trimmed.startsWith('{{')) ||\n trimmed.startsWith('v-')\n )\n return false;\n\n // Ignore explicit code patterns (markers)\n if (\n trimmed.includes('=>') ||\n trimmed.includes(');') ||\n trimmed.includes('(){') ||\n trimmed.includes('==') ||\n trimmed.includes('window.') ||\n trimmed.startsWith('(function') ||\n trimmed.startsWith('function(')\n ) {\n return false;\n }\n\n // Heuristic: check for characters that are common in code but rare in natural text.\n // Whitelist: letters, numbers, spaces, and frequent text symbols (including punctuation, braces, and technical symbols)\n const nonTextualRegex =\n /[^\\p{L}\\p{N}\\s.,!?;:'\"()[\\]{}–—/«»„“\\p{Sc}%&*+#@^_+=<>/~]/gu;\n const nonTextualMatches = trimmed.match(nonTextualRegex) || [];\n\n // If a string contains a high density of truly exceptional symbols (like |, \\, etc.),\n // it is highly likely to be code or complex technical data.\n if (nonTextualMatches.length > 5) return false;\n\n const wordCount = trimmed.split(/\\s+/).length;\n\n // Ignore CSS/Tailwind utility class strings. A string whose tokens all look\n // like CSS utility classes (lowercase, optional responsive/state prefix like\n // \"sm:\" or \"hover:\", optional hyphenated suffix like \"-4\" or \"-full\") and\n // where at least one token contains a hyphen is almost certainly a className\n // value, not translatable text.\n const cssClassTokenRegex =\n /^!?([a-z][a-z0-9-]*:)*[a-z][a-z0-9]*(-[a-z0-9[\\].,%#/]+)*(\\/[a-z0-9]+)?$/;\n if (wordCount > 1) {\n const tokens = trimmed.split(/\\s+/);\n if (\n tokens.every((token) => cssClassTokenRegex.test(token)) &&\n tokens.some((token) => token.includes('-'))\n ) {\n return false;\n }\n }\n\n // Check if starts with a capital letter (including after an opening parenthesis/quote)\n const isCapitalized = /^['\"([]*\\p{Lu}/u.test(trimmed);\n\n // Ignore technical identifiers (one word strings with camelCase, kebab-case, snake_case etc.)\n if (wordCount === 1) {\n // CamelCase or internal capitals (like camelCaseProperty or CamelCaseProperty)\n if (/[a-z]\\p{Lu}/u.test(trimmed)) return false;\n // kebab-case or snake_case\n if (trimmed.includes('-') || trimmed.includes('_')) return false;\n }\n\n // We usually want to extract full sentences or labels, not single/short technical words.\n // Extract if capitalized, or if it contains more than 2 words.\n if (!isCapitalized && wordCount <= 2) return false;\n\n return true;\n};\n"],"mappings":";;;;;;;;;;AASA,MAAa,iBAAiB,SAA0B;CACtD,MAAM,UAAU,KAAK,MAAM;AAE3B,KAAI,CAAC,QAAS,QAAO;AAGrB,KAAI,6BAA6B,KAAK,QAAQ,CAAE,QAAO;AAGvD,KACG,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,WAAW,KAAK,IACrD,QAAQ,WAAW,KAAK,CAExB,QAAO;AAGT,KACE,QAAQ,SAAS,KAAK,IACtB,QAAQ,SAAS,KAAK,IACtB,QAAQ,SAAS,MAAM,IACvB,QAAQ,SAAS,KAAK,IACtB,QAAQ,SAAS,UAAU,IAC3B,QAAQ,WAAW,YAAY,IAC/B,QAAQ,WAAW,YAAY,CAE/B,QAAO;AAWT,MAJ0B,QAAQ,MAAM,8DAAgB,IAAI,EAAE,EAIxC,SAAS,EAAG,QAAO;CAEzC,MAAM,YAAY,QAAQ,MAAM,MAAM,CAAC;CAOvC,MAAM,qBACJ;AACF,KAAI,YAAY,GAAG;EACjB,MAAM,SAAS,QAAQ,MAAM,MAAM;AACnC,MACE,OAAO,OAAO,UAAU,mBAAmB,KAAK,MAAM,CAAC,IACvD,OAAO,MAAM,UAAU,MAAM,SAAS,IAAI,CAAC,CAE3C,QAAO;;CAKX,MAAM,gBAAgB,kBAAkB,KAAK,QAAQ;AAGrD,KAAI,cAAc,GAAG;AAEnB,MAAI,eAAe,KAAK,QAAQ,CAAE,QAAO;AAEzC,MAAI,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,IAAI,CAAE,QAAO;;AAK7D,KAAI,CAAC,iBAAiB,aAAa,EAAG,QAAO;AAE7C,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"extractScriptBlocks.mjs","names":[],"sources":["../../src/extractScriptBlocks.ts"],"sourcesContent":["import { extname } from 'node:path';\n\n/**\n * A script block extracted from an SFC (Vue or Svelte) source file.\n *\n * `content` – The raw JS/TS text between the opening and closing\n * `<script>` tags (does NOT include the tags).\n * `contentStartOffset` – Byte offset of `content[0]` in the full source string.\n * `contentEndOffset` – Byte offset one past the last byte of `content` in the\n * full source string (i.e. `source.slice(start, end) === content`).\n */\nexport type ScriptBlock = {\n content: string;\n contentStartOffset: number;\n contentEndOffset: number;\n};\n\n// ── SFC script extraction ─────────────────────────────────────────────────────\n\n/**\n * Regex that matches every `<script …>…</script>` block in an SFC (Vue or\n * Svelte). Works for both instance scripts and module/setup scripts.\n *\n * Limitations (shared with `@intlayer/svelte-compiler`'s own approach):\n * - A literal `</script>` inside a string or comment inside the script block\n * would prematurely close the match. This is an accepted trade-off for the\n * vast majority of real-world files.\n */\nconst SFC_SCRIPT_RE = /<script([^>]*)>([\\s\\S]*?)<\\/script>/g;\n\n/**\n * Matches an Astro frontmatter block: the JS/TS code between the opening `---`\n * and closing `---` at the top of an `.astro` file.\n *\n * Group 1 captures the raw script content (without the fence markers).\n */\nconst ASTRO_FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n\n/**\n * Extracts the frontmatter script block from a raw `.astro` source file.\n * Returns an empty array when no frontmatter fence is present (static pages).\n */\nconst extractAstroFrontmatter = (code: string): ScriptBlock[] => {\n const match = ASTRO_FRONTMATTER_RE.exec(code);\n if (!match) return [];\n\n const openingFence = match[0].slice(0, match[0].indexOf('\\n') + 1); // \"---\\n\" or \"---\\r\\n\"\n const contentStartOffset = openingFence.length;\n const content = match[1] ?? '';\n\n return [\n {\n content,\n contentStartOffset,\n contentEndOffset: contentStartOffset + content.length,\n },\n ];\n};\n\n/**\n * Extracts all `<script>` blocks from a Vue SFC or Svelte source string,\n * returning each block's text content together with its start/end byte offsets\n * in the original source.\n *\n * Uses the same regex strategy as `@intlayer/svelte-compiler` internally.\n */\nconst extractSFCScriptBlocks = (code: string): ScriptBlock[] => {\n const blocks: ScriptBlock[] = [];\n SFC_SCRIPT_RE.lastIndex = 0;\n\n for (\n let match = SFC_SCRIPT_RE.exec(code);\n match !== null;\n match = SFC_SCRIPT_RE.exec(code)\n ) {\n // match[0]: full `<script ATTRS>CONTENT</script>`\n // match[1]: the attribute string (may be empty)\n // match[2]: the script content\n const attrs = match[1] ?? '';\n const openingTagLength = '<script'.length + attrs.length + '>'.length;\n const contentStart = match.index + openingTagLength;\n const content = match[2] ?? '';\n blocks.push({\n content,\n contentStartOffset: contentStart,\n contentEndOffset: contentStart + content.length,\n });\n }\n\n return blocks;\n};\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Extracts the script block(s) from a source file, dispatching by extension:\n *\n * - `.vue` / `.svelte` → searches for `<script>` blocks using a regex.\n * Returns an **empty array** when no `<script>` tag is found, which\n * happens both for template-only SFCs and for already-compiled JS that\n * Vite passes to `enforce:'post'` transform hooks.\n * - `.astro` → extracts the frontmatter block between the opening and closing\n * `---` fences. Returns an empty array when called on already-compiled JS\n * (no fences present), which is the case inside the `enforce:'post'`\n * transform hook where Astro has already compiled the file.\n * - everything else → treats the whole file as a single script block and\n * returns it wrapped in a single-element array.\n */\nexport const extractScriptBlocks = (\n filePath: string,\n code: string\n): ScriptBlock[] => {\n const ext = extname(filePath);\n\n if (ext === '.vue' || ext === '.svelte') {\n return extractSFCScriptBlocks(code);\n }\n\n if (ext === '.astro') {\n return extractAstroFrontmatter(code);\n }\n\n // Plain JS / TS / JSX / TSX / MJS / CJS – the whole file is the script.\n return [\n {\n content: code,\n contentStartOffset: 0,\n contentEndOffset: code.length,\n },\n ];\n};\n\n/**\n * Applies modified script block content back into the original source string.\n *\n * Each entry in `modifications` pairs an original `ScriptBlock` (as returned\n * by `extractScriptBlocks`) with the replacement text for its content.\n * Replacements are applied in reverse offset order so that earlier offsets\n * remain valid while later replacements are being processed.\n *\n * Returns `originalCode` unchanged when `modifications` is empty.\n */\nexport const injectScriptBlocks = (\n originalCode: string,\n modifications: ReadonlyArray<{\n block: ScriptBlock;\n modifiedContent: string;\n }>\n): string => {\n if (modifications.length === 0) return originalCode;\n\n const sorted = [...modifications].sort(\n (a, b) => b.block.contentStartOffset - a.block.contentStartOffset\n );\n\n let result = originalCode;\n for (const { block, modifiedContent } of sorted) {\n result =\n result.slice(0, block.contentStartOffset) +\n modifiedContent +\n result.slice(block.contentEndOffset);\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;;AA4BA,MAAM,gBAAgB;;;;;;;AAQtB,MAAM,uBAAuB;;;;;AAM7B,MAAM,2BAA2B,SAAgC;CAC/D,MAAM,QAAQ,qBAAqB,KAAK,IAAI;CAC5C,IAAI,CAAC,OAAO,OAAO,CAAC;CAGpB,MAAM,qBADe,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,IAAI,IAAI,CAC1B,EAAE;CACxC,MAAM,UAAU,MAAM,MAAM;CAE5B,OAAO,CACL;EACE;EACA;EACA,kBAAkB,qBAAqB,QAAQ;CACjD,CACF;AACF;;;;;;;;AASA,MAAM,0BAA0B,SAAgC;CAC9D,MAAM,SAAwB,CAAC;CAC/B,cAAc,YAAY;CAE1B,KACE,IAAI,QAAQ,cAAc,KAAK,IAAI,GACnC,UAAU,MACV,QAAQ,cAAc,KAAK,IAAI,GAC/B;EAKA,MAAM,mBAAmB,KADX,MAAM,MAAM,IACwB,SAAS;EAC3D,MAAM,eAAe,MAAM,QAAQ;EACnC,MAAM,UAAU,MAAM,MAAM;EAC5B,OAAO,KAAK;GACV;GACA,oBAAoB;GACpB,kBAAkB,eAAe,QAAQ;EAC3C,CAAC;CACH;CAEA,OAAO;AACT;;;;;;;;;;;;;;;AAkBA,MAAa,uBACX,UACA,SACkB;CAClB,MAAM,MAAM,QAAQ,QAAQ;CAE5B,IAAI,QAAQ,UAAU,QAAQ,WAC5B,OAAO,uBAAuB,IAAI;CAGpC,IAAI,QAAQ,UACV,OAAO,wBAAwB,IAAI;CAIrC,OAAO,CACL;EACE,SAAS;EACT,oBAAoB;EACpB,kBAAkB,KAAK;CACzB,CACF;AACF;;;;;;;;;;;AAYA,MAAa,sBACX,cACA,kBAIW;CACX,IAAI,cAAc,WAAW,GAAG,OAAO;CAEvC,MAAM,SAAS,CAAC,GAAG,aAAa,EAAE,MAC/B,GAAG,MAAM,EAAE,MAAM,qBAAqB,EAAE,MAAM,kBACjD;CAEA,IAAI,SAAS;CACb,KAAK,MAAM,EAAE,OAAO,qBAAqB,QACvC,SACE,OAAO,MAAM,GAAG,MAAM,kBAAkB,IACxC,kBACA,OAAO,MAAM,MAAM,gBAAgB;CAGvC,OAAO;AACT"}
1
+ {"version":3,"file":"extractScriptBlocks.mjs","names":[],"sources":["../../src/extractScriptBlocks.ts"],"sourcesContent":["import { extname } from 'node:path';\n\n/**\n * A script block extracted from an SFC (Vue or Svelte) source file.\n *\n * `content` – The raw JS/TS text between the opening and closing\n * `<script>` tags (does NOT include the tags).\n * `contentStartOffset` – Byte offset of `content[0]` in the full source string.\n * `contentEndOffset` – Byte offset one past the last byte of `content` in the\n * full source string (i.e. `source.slice(start, end) === content`).\n */\nexport type ScriptBlock = {\n content: string;\n contentStartOffset: number;\n contentEndOffset: number;\n};\n\n// ── SFC script extraction ─────────────────────────────────────────────────────\n\n/**\n * Regex that matches every `<script …>…</script>` block in an SFC (Vue or\n * Svelte). Works for both instance scripts and module/setup scripts.\n *\n * Limitations (shared with `@intlayer/svelte-compiler`'s own approach):\n * - A literal `</script>` inside a string or comment inside the script block\n * would prematurely close the match. This is an accepted trade-off for the\n * vast majority of real-world files.\n */\nconst SFC_SCRIPT_RE = /<script([^>]*)>([\\s\\S]*?)<\\/script>/g;\n\n/**\n * Matches an Astro frontmatter block: the JS/TS code between the opening `---`\n * and closing `---` at the top of an `.astro` file.\n *\n * Group 1 captures the raw script content (without the fence markers).\n */\nconst ASTRO_FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n\n/**\n * Extracts the frontmatter script block from a raw `.astro` source file.\n * Returns an empty array when no frontmatter fence is present (static pages).\n */\nconst extractAstroFrontmatter = (code: string): ScriptBlock[] => {\n const match = ASTRO_FRONTMATTER_RE.exec(code);\n if (!match) return [];\n\n const openingFence = match[0].slice(0, match[0].indexOf('\\n') + 1); // \"---\\n\" or \"---\\r\\n\"\n const contentStartOffset = openingFence.length;\n const content = match[1] ?? '';\n\n return [\n {\n content,\n contentStartOffset,\n contentEndOffset: contentStartOffset + content.length,\n },\n ];\n};\n\n/**\n * Extracts all `<script>` blocks from a Vue SFC or Svelte source string,\n * returning each block's text content together with its start/end byte offsets\n * in the original source.\n *\n * Uses the same regex strategy as `@intlayer/svelte-compiler` internally.\n */\nconst extractSFCScriptBlocks = (code: string): ScriptBlock[] => {\n const blocks: ScriptBlock[] = [];\n SFC_SCRIPT_RE.lastIndex = 0;\n\n for (\n let match = SFC_SCRIPT_RE.exec(code);\n match !== null;\n match = SFC_SCRIPT_RE.exec(code)\n ) {\n // match[0]: full `<script ATTRS>CONTENT</script>`\n // match[1]: the attribute string (may be empty)\n // match[2]: the script content\n const attrs = match[1] ?? '';\n const openingTagLength = '<script'.length + attrs.length + '>'.length;\n const contentStart = match.index + openingTagLength;\n const content = match[2] ?? '';\n blocks.push({\n content,\n contentStartOffset: contentStart,\n contentEndOffset: contentStart + content.length,\n });\n }\n\n return blocks;\n};\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Extracts the script block(s) from a source file, dispatching by extension:\n *\n * - `.vue` / `.svelte` → searches for `<script>` blocks using a regex.\n * Returns an **empty array** when no `<script>` tag is found, which\n * happens both for template-only SFCs and for already-compiled JS that\n * Vite passes to `enforce:'post'` transform hooks.\n * - `.astro` → extracts the frontmatter block between the opening and closing\n * `---` fences. Returns an empty array when called on already-compiled JS\n * (no fences present), which is the case inside the `enforce:'post'`\n * transform hook where Astro has already compiled the file.\n * - everything else → treats the whole file as a single script block and\n * returns it wrapped in a single-element array.\n */\nexport const extractScriptBlocks = (\n filePath: string,\n code: string\n): ScriptBlock[] => {\n const ext = extname(filePath);\n\n if (ext === '.vue' || ext === '.svelte') {\n return extractSFCScriptBlocks(code);\n }\n\n if (ext === '.astro') {\n return extractAstroFrontmatter(code);\n }\n\n // Plain JS / TS / JSX / TSX / MJS / CJS – the whole file is the script.\n return [\n {\n content: code,\n contentStartOffset: 0,\n contentEndOffset: code.length,\n },\n ];\n};\n\n/**\n * Applies modified script block content back into the original source string.\n *\n * Each entry in `modifications` pairs an original `ScriptBlock` (as returned\n * by `extractScriptBlocks`) with the replacement text for its content.\n * Replacements are applied in reverse offset order so that earlier offsets\n * remain valid while later replacements are being processed.\n *\n * Returns `originalCode` unchanged when `modifications` is empty.\n */\nexport const injectScriptBlocks = (\n originalCode: string,\n modifications: ReadonlyArray<{\n block: ScriptBlock;\n modifiedContent: string;\n }>\n): string => {\n if (modifications.length === 0) return originalCode;\n\n const sorted = [...modifications].sort(\n (a, b) => b.block.contentStartOffset - a.block.contentStartOffset\n );\n\n let result = originalCode;\n for (const { block, modifiedContent } of sorted) {\n result =\n result.slice(0, block.contentStartOffset) +\n modifiedContent +\n result.slice(block.contentEndOffset);\n }\n\n return result;\n};\n"],"mappings":";;;;;;;;;;;;AA4BA,MAAM,gBAAgB;;;;;;;AAQtB,MAAM,uBAAuB;;;;;AAM7B,MAAM,2BAA2B,SAAgC;CAC/D,MAAM,QAAQ,qBAAqB,KAAK,KAAK;AAC7C,KAAI,CAAC,MAAO,QAAO,EAAE;CAGrB,MAAM,qBADe,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,KAAK,GAAG,EACzB,CAAC;CACxC,MAAM,UAAU,MAAM,MAAM;AAE5B,QAAO,CACL;EACE;EACA;EACA,kBAAkB,qBAAqB,QAAQ;EAChD,CACF;;;;;;;;;AAUH,MAAM,0BAA0B,SAAgC;CAC9D,MAAM,SAAwB,EAAE;AAChC,eAAc,YAAY;AAE1B,MACE,IAAI,QAAQ,cAAc,KAAK,KAAK,EACpC,UAAU,MACV,QAAQ,cAAc,KAAK,KAAK,EAChC;EAKA,MAAM,mBAAmB,KADX,MAAM,MAAM,IACwB,SAAS;EAC3D,MAAM,eAAe,MAAM,QAAQ;EACnC,MAAM,UAAU,MAAM,MAAM;AAC5B,SAAO,KAAK;GACV;GACA,oBAAoB;GACpB,kBAAkB,eAAe,QAAQ;GAC1C,CAAC;;AAGJ,QAAO;;;;;;;;;;;;;;;;AAmBT,MAAa,uBACX,UACA,SACkB;CAClB,MAAM,MAAM,QAAQ,SAAS;AAE7B,KAAI,QAAQ,UAAU,QAAQ,UAC5B,QAAO,uBAAuB,KAAK;AAGrC,KAAI,QAAQ,SACV,QAAO,wBAAwB,KAAK;AAItC,QAAO,CACL;EACE,SAAS;EACT,oBAAoB;EACpB,kBAAkB,KAAK;EACxB,CACF;;;;;;;;;;;;AAaH,MAAa,sBACX,cACA,kBAIW;AACX,KAAI,cAAc,WAAW,EAAG,QAAO;CAEvC,MAAM,SAAS,CAAC,GAAG,cAAc,CAAC,MAC/B,GAAG,MAAM,EAAE,MAAM,qBAAqB,EAAE,MAAM,mBAChD;CAED,IAAI,SAAS;AACb,MAAK,MAAM,EAAE,OAAO,qBAAqB,OACvC,UACE,OAAO,MAAM,GAAG,MAAM,mBAAmB,GACzC,kBACA,OAAO,MAAM,MAAM,iBAAiB;AAGxC,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"getExtractPluginOptions.mjs","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { buildComponentFilesList } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { COMPILER_ENABLED } from '@intlayer/config/defaultValues';\nimport { colorize, colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { ExtractPluginOptions } from './babel-plugin-intlayer-extract';\nimport { writeContentHelper } from './extractContent/contentWriter';\n\n/**\n * Mode of the compiler\n * - 'dev': Development mode with HMR support\n * - 'build': Production build mode\n */\nexport type CompilerMode = 'dev' | 'build';\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 configuration: IntlayerConfig = getConfiguration(),\n isDev: CompilerMode | string | undefined = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n // Accept 'dev'/'serve' (Vite), boolean true, or the string 'true' (env var)\n const isDevBoolean = isDev === 'dev' || isDev === 'serve' || isDev === 'true';\n\n const compilerMode: CompilerMode = isDevBoolean ? 'dev' : 'build';\n\n const logger = getAppLogger(configuration);\n\n if (configuration.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 let enabled = configuration.compiler?.enabled ?? COMPILER_ENABLED;\n\n if (enabled === 'build-only') {\n if (compilerMode) {\n enabled = compilerMode === 'build';\n } else {\n // Fallback if mode isn't explicitly provided (e.g. pure babel plugin context)\n enabled = process.env.NODE_ENV === 'production';\n }\n }\n\n const filesList = buildComponentFilesList(configuration);\n\n return {\n enabled,\n configuration,\n filesList,\n onExtract: async ({ dictionaryKey, content, filePath }) => {\n try {\n await writeContentHelper(\n content,\n dictionaryKey,\n filePath,\n configuration\n );\n } catch (error) {\n logger(\n [\n `Failed to process extracted content for ${colorizeKey(dictionaryKey)}:`,\n error,\n ],\n { level: 'error' }\n );\n }\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;AAqBA,MAAa,2BACX,gBAAgC,iBAAiB,GACjD,QAA2C,QAAQ,IAAI,4BAC9B;CAEzB,MAAM,eAAe,UAAU,SAAS,UAAU,WAAW,UAAU;CAEvE,MAAM,eAA6B,eAAe,QAAQ;CAE1D,MAAM,SAAS,aAAa,aAAa;CAEzC,IAAI,cAAc,UAAU,YAAY,gBAAgB,cACtD,OACE,GAAG,SAAS,aAAa,WAAW,SAAS,EAAE,uIACjD;CAGF,IAAI,UAAU,cAAc,UAAU,WAAW;CAEjD,IAAI,YAAY,cACd,IAAI,cACF,UAAU,iBAAiB;MAG3B,UAAU;CAId,MAAM,YAAY,wBAAwB,aAAa;CAEvD,OAAO;EACL;EACA;EACA;EACA,WAAW,OAAO,EAAE,eAAe,SAAS,eAAe;GACzD,IAAI;IACF,MAAM,mBACJ,SACA,eACA,UACA,aACF;GACF,SAAS,OAAO;IACd,OACE,CACE,2CAA2C,YAAY,aAAa,EAAE,IACtE,KACF,GACA,EAAE,OAAO,QAAQ,CACnB;GACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"getExtractPluginOptions.mjs","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { buildComponentFilesList } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { COMPILER_ENABLED } from '@intlayer/config/defaultValues';\nimport { colorize, colorizeKey, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { ExtractPluginOptions } from './babel-plugin-intlayer-extract';\nimport { writeContentHelper } from './extractContent/contentWriter';\n\n/**\n * Mode of the compiler\n * - 'dev': Development mode with HMR support\n * - 'build': Production build mode\n */\nexport type CompilerMode = 'dev' | 'build';\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 configuration: IntlayerConfig = getConfiguration(),\n isDev: CompilerMode | string | undefined = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n // Accept 'dev'/'serve' (Vite), boolean true, or the string 'true' (env var)\n const isDevBoolean = isDev === 'dev' || isDev === 'serve' || isDev === 'true';\n\n const compilerMode: CompilerMode = isDevBoolean ? 'dev' : 'build';\n\n const logger = getAppLogger(configuration);\n\n if (configuration.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 let enabled = configuration.compiler?.enabled ?? COMPILER_ENABLED;\n\n if (enabled === 'build-only') {\n if (compilerMode) {\n enabled = compilerMode === 'build';\n } else {\n // Fallback if mode isn't explicitly provided (e.g. pure babel plugin context)\n enabled = process.env.NODE_ENV === 'production';\n }\n }\n\n const filesList = buildComponentFilesList(configuration);\n\n return {\n enabled,\n configuration,\n filesList,\n onExtract: async ({ dictionaryKey, content, filePath }) => {\n try {\n await writeContentHelper(\n content,\n dictionaryKey,\n filePath,\n configuration\n );\n } catch (error) {\n logger(\n [\n `Failed to process extracted content for ${colorizeKey(dictionaryKey)}:`,\n error,\n ],\n { level: 'error' }\n );\n }\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;AAqBA,MAAa,2BACX,gBAAgC,kBAAkB,EAClD,QAA2C,QAAQ,IAAI,4BAC9B;CAEzB,MAAM,eAAe,UAAU,SAAS,UAAU,WAAW,UAAU;CAEvE,MAAM,eAA6B,eAAe,QAAQ;CAE1D,MAAM,SAAS,aAAa,cAAc;AAE1C,KAAI,cAAc,UAAU,YAAY,gBAAgB,aACtD,QACE,GAAG,SAAS,aAAa,WAAW,UAAU,CAAC,wIAChD;CAGH,IAAI,UAAU,cAAc,UAAU,WAAW;AAEjD,KAAI,YAAY,aACd,KAAI,aACF,WAAU,iBAAiB;KAG3B,WAAU;CAId,MAAM,YAAY,wBAAwB,cAAc;AAExD,QAAO;EACL;EACA;EACA;EACA,WAAW,OAAO,EAAE,eAAe,SAAS,eAAe;AACzD,OAAI;AACF,UAAM,mBACJ,SACA,eACA,UACA,cACD;YACM,OAAO;AACd,WACE,CACE,2CAA2C,YAAY,cAAc,CAAC,IACtE,MACD,EACD,EAAE,OAAO,SAAS,CACnB;;;EAGN"}
@@ -1 +1 @@
1
- {"version":3,"file":"getOptimizePluginOptions.mjs","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { buildComponentFilesList } from '@intlayer/chokidar/utils';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { OptimizePluginOptions } from './babel-plugin-intlayer-optimize';\n\ntype GetOptimizePluginOptionsParams = {\n /**\n * Configuration options for loading intlayer config\n */\n configOptions?: GetConfigurationOptions;\n /**\n * Pre-loaded dictionaries (optional - will be loaded if not provided)\n */\n dictionaries?: Dictionary[];\n /**\n * Override specific options\n */\n overrides?: Partial<OptimizePluginOptions>;\n};\n\n/**\n * Load dictionaries from the dictionaries-entry package\n */\nconst loadDictionaries = (config: IntlayerConfig): Dictionary[] => {\n try {\n // Dynamic require to avoid build-time dependency issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getDictionaries } = require('@intlayer/dictionaries-entry');\n const dictionariesRecord = getDictionaries(config);\n\n return Object.values(dictionariesRecord);\n } catch {\n // If dictionaries-entry is not available, return empty array\n return [];\n }\n};\n\n/**\n * Get the options for the Intlayer Babel optimization plugin\n * This function loads the Intlayer configuration and returns the paths\n * needed for dictionary optimization and import rewriting.\n */\nexport const getOptimizePluginOptions = (\n params?: GetOptimizePluginOptionsParams\n): OptimizePluginOptions => {\n const {\n configOptions,\n dictionaries: providedDictionaries,\n overrides,\n } = params ?? {};\n\n const config = getConfiguration(configOptions);\n const {\n mainDir,\n dictionariesDir,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n } = config.system;\n const { importMode, optimize } = config.build;\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n const dynamicDictionariesEntryPath = join(\n mainDir,\n 'dynamic_dictionaries.mjs'\n );\n const fetchDictionariesEntryPath = join(mainDir, 'fetch_dictionaries.mjs');\n\n const filesListPattern = buildComponentFilesList(config);\n\n const filesList = [\n ...filesListPattern,\n dictionariesEntryPath, // should add dictionariesEntryPath to replace it by an empty object if import made dynamic\n unmergedDictionariesEntryPath, // should add dictionariesEntryPath to replace it by an empty object if import made dynamic\n ];\n\n // Load dictionaries if not provided\n const dictionaries = providedDictionaries ?? loadDictionaries(config);\n\n const dictionaryModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n > = {};\n\n dictionaries.forEach((dictionary) => {\n dictionaryModeMap[dictionary.key] = dictionary.importMode ?? importMode;\n });\n\n return {\n optimize,\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesDir,\n unmergedDictionariesEntryPath,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n fetchDictionariesEntryPath,\n replaceDictionaryEntry: true,\n importMode,\n dictionaryModeMap,\n filesList,\n ...overrides,\n };\n};\n"],"mappings":";;;;;;;;;AA4BA,MAAM,oBAAoB,WAAyC;CACjE,IAAI;EAGF,MAAM,EAAE,8BAA4B,8BAA8B;EAClE,MAAM,qBAAqB,gBAAgB,MAAM;EAEjD,OAAO,OAAO,OAAO,kBAAkB;CACzC,QAAQ;EAEN,OAAO,CAAC;CACV;AACF;;;;;;AAOA,MAAa,4BACX,WAC0B;CAC1B,MAAM,EACJ,eACA,cAAc,sBACd,cACE,UAAU,CAAC;CAEf,MAAM,SAAS,iBAAiB,aAAa;CAC7C,MAAM,EACJ,SACA,iBACA,yBACA,wBACA,yBACE,OAAO;CACX,MAAM,EAAE,YAAY,aAAa,OAAO;CAExC,MAAM,wBAAwB,KAAK,SAAS,kBAAkB;CAC9D,MAAM,gCAAgC,KACpC,SACA,2BACF;CACA,MAAM,+BAA+B,KACnC,SACA,0BACF;CACA,MAAM,6BAA6B,KAAK,SAAS,wBAAwB;CAIzE,MAAM,YAAY;EAChB,GAHuB,wBAAwB,MAG7B;EAClB;EACA;CACF;CAGA,MAAM,eAAe,wBAAwB,iBAAiB,MAAM;CAEpE,MAAM,oBAGF,CAAC;CAEL,aAAa,SAAS,eAAe;EACnC,kBAAkB,WAAW,OAAO,WAAW,cAAc;CAC/D,CAAC;CAED,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,wBAAwB;EACxB;EACA;EACA;EACA,GAAG;CACL;AACF"}
1
+ {"version":3,"file":"getOptimizePluginOptions.mjs","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { buildComponentFilesList } from '@intlayer/chokidar/utils';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { OptimizePluginOptions } from './babel-plugin-intlayer-optimize';\n\ntype GetOptimizePluginOptionsParams = {\n /**\n * Configuration options for loading intlayer config\n */\n configOptions?: GetConfigurationOptions;\n /**\n * Pre-loaded dictionaries (optional - will be loaded if not provided)\n */\n dictionaries?: Dictionary[];\n /**\n * Override specific options\n */\n overrides?: Partial<OptimizePluginOptions>;\n};\n\n/**\n * Load dictionaries from the dictionaries-entry package\n */\nconst loadDictionaries = (config: IntlayerConfig): Dictionary[] => {\n try {\n // Dynamic require to avoid build-time dependency issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getDictionaries } = require('@intlayer/dictionaries-entry');\n const dictionariesRecord = getDictionaries(config);\n\n return Object.values(dictionariesRecord);\n } catch {\n // If dictionaries-entry is not available, return empty array\n return [];\n }\n};\n\n/**\n * Get the options for the Intlayer Babel optimization plugin\n * This function loads the Intlayer configuration and returns the paths\n * needed for dictionary optimization and import rewriting.\n */\nexport const getOptimizePluginOptions = (\n params?: GetOptimizePluginOptionsParams\n): OptimizePluginOptions => {\n const {\n configOptions,\n dictionaries: providedDictionaries,\n overrides,\n } = params ?? {};\n\n const config = getConfiguration(configOptions);\n const {\n mainDir,\n dictionariesDir,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n } = config.system;\n const { importMode, optimize } = config.build;\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n const dynamicDictionariesEntryPath = join(\n mainDir,\n 'dynamic_dictionaries.mjs'\n );\n const fetchDictionariesEntryPath = join(mainDir, 'fetch_dictionaries.mjs');\n\n const filesListPattern = buildComponentFilesList(config);\n\n const filesList = [\n ...filesListPattern,\n dictionariesEntryPath, // should add dictionariesEntryPath to replace it by an empty object if import made dynamic\n unmergedDictionariesEntryPath, // should add dictionariesEntryPath to replace it by an empty object if import made dynamic\n ];\n\n // Load dictionaries if not provided\n const dictionaries = providedDictionaries ?? loadDictionaries(config);\n\n const dictionaryModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n > = {};\n\n dictionaries.forEach((dictionary) => {\n dictionaryModeMap[dictionary.key] = dictionary.importMode ?? importMode;\n });\n\n return {\n optimize,\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesDir,\n unmergedDictionariesEntryPath,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n fetchDictionariesEntryPath,\n replaceDictionaryEntry: true,\n importMode,\n dictionaryModeMap,\n filesList,\n ...overrides,\n };\n};\n"],"mappings":";;;;;;;;;AA4BA,MAAM,oBAAoB,WAAyC;AACjE,KAAI;EAGF,MAAM,EAAE,8BAA4B,+BAA+B;EACnE,MAAM,qBAAqB,gBAAgB,OAAO;AAElD,SAAO,OAAO,OAAO,mBAAmB;SAClC;AAEN,SAAO,EAAE;;;;;;;;AASb,MAAa,4BACX,WAC0B;CAC1B,MAAM,EACJ,eACA,cAAc,sBACd,cACE,UAAU,EAAE;CAEhB,MAAM,SAAS,iBAAiB,cAAc;CAC9C,MAAM,EACJ,SACA,iBACA,yBACA,wBACA,yBACE,OAAO;CACX,MAAM,EAAE,YAAY,aAAa,OAAO;CAExC,MAAM,wBAAwB,KAAK,SAAS,mBAAmB;CAC/D,MAAM,gCAAgC,KACpC,SACA,4BACD;CACD,MAAM,+BAA+B,KACnC,SACA,2BACD;CACD,MAAM,6BAA6B,KAAK,SAAS,yBAAyB;CAI1E,MAAM,YAAY;EAChB,GAHuB,wBAAwB,OAG5B;EACnB;EACA;EACD;CAGD,MAAM,eAAe,wBAAwB,iBAAiB,OAAO;CAErE,MAAM,oBAGF,EAAE;AAEN,cAAa,SAAS,eAAe;AACnC,oBAAkB,WAAW,OAAO,WAAW,cAAc;GAC7D;AAEF,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,wBAAwB;EACxB;EACA;EACA;EACA,GAAG;EACJ"}
@@ -0,0 +1,106 @@
1
+ import { __require } from "./_virtual/_rolldown/runtime.mjs";
2
+ import { buildComponentFilesList } from "@intlayer/chokidar/utils";
3
+ import { IMPORT_MODE } from "@intlayer/config/defaultValues";
4
+ import { getConfiguration } from "@intlayer/config/node";
5
+
6
+ //#region src/getPurgePluginOptions.ts
7
+ /**
8
+ * Attempts to load compiled dictionaries from `@intlayer/dictionaries-entry`.
9
+ * Returns an empty array if the entry point is not available (e.g. dictionaries
10
+ * have not been built yet).
11
+ */
12
+ const loadDictionaries = (config) => {
13
+ try {
14
+ const { getDictionaries } = __require("@intlayer/dictionaries-entry");
15
+ const dictionariesRecord = getDictionaries(config);
16
+ return Object.values(dictionariesRecord);
17
+ } catch {
18
+ return [];
19
+ }
20
+ };
21
+ /**
22
+ * Returns fully-resolved options for {@link intlayerPurgeBabelPlugin}.
23
+ *
24
+ * Loads the intlayer configuration once at babel.config.js evaluation time so
25
+ * the plugin itself does not need to re-read the config on every file
26
+ * transform.
27
+ *
28
+ * @example
29
+ * ```js
30
+ * // babel.config.js
31
+ * const {
32
+ * intlayerPurgeBabelPlugin,
33
+ * getPurgePluginOptions,
34
+ * } = require("@intlayer/babel");
35
+ *
36
+ * module.exports = {
37
+ * presets: ["next/babel"],
38
+ * plugins: [
39
+ * [intlayerPurgeBabelPlugin, getPurgePluginOptions()],
40
+ * ],
41
+ * };
42
+ * ```
43
+ */
44
+ const getPurgePluginOptions = (params) => {
45
+ const { configOptions, dictionaries: providedDictionaries, overrides } = params ?? {};
46
+ const config = getConfiguration(configOptions);
47
+ const { baseDir, dictionariesDir, dynamicDictionariesDir } = config.system;
48
+ const { purge, minify, optimize } = config.build;
49
+ const editorEnabled = config.editor.enabled;
50
+ const importMode = config.build.importMode ?? config.dictionary?.importMode;
51
+ const componentFilesList = buildComponentFilesList(config);
52
+ const dictionaries = providedDictionaries ?? loadDictionaries(config);
53
+ const dictionaryKeyToImportModeMap = {};
54
+ for (const dictionary of dictionaries) dictionaryKeyToImportModeMap[dictionary.key] = dictionary.importMode ?? importMode ?? IMPORT_MODE;
55
+ return {
56
+ baseDir,
57
+ purge: Boolean(purge),
58
+ minify: Boolean(minify),
59
+ optimize,
60
+ editorEnabled,
61
+ dictionariesDir,
62
+ dynamicDictionariesDir,
63
+ componentFilesList,
64
+ dictionaryKeyToImportModeMap,
65
+ ...overrides
66
+ };
67
+ };
68
+ /**
69
+ * Returns fully-resolved options for {@link intlayerMinifyBabelPlugin}.
70
+ *
71
+ * Loads the intlayer configuration once at babel.config.js evaluation time.
72
+ *
73
+ * @example
74
+ * ```js
75
+ * // babel.config.js
76
+ * const {
77
+ * intlayerMinifyBabelPlugin,
78
+ * getMinifyPluginOptions,
79
+ * } = require("@intlayer/babel");
80
+ *
81
+ * module.exports = {
82
+ * presets: ["next/babel"],
83
+ * plugins: [
84
+ * [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],
85
+ * ],
86
+ * };
87
+ * ```
88
+ */
89
+ const getMinifyPluginOptions = (params) => {
90
+ const { configOptions, overrides } = params ?? {};
91
+ const config = getConfiguration(configOptions);
92
+ const { baseDir } = config.system;
93
+ const { minify, optimize } = config.build;
94
+ const editorEnabled = config.editor.enabled;
95
+ return {
96
+ baseDir,
97
+ minify: Boolean(minify),
98
+ optimize,
99
+ editorEnabled,
100
+ ...overrides
101
+ };
102
+ };
103
+
104
+ //#endregion
105
+ export { getMinifyPluginOptions, getPurgePluginOptions };
106
+ //# sourceMappingURL=getPurgePluginOptions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getPurgePluginOptions.mjs","names":[],"sources":["../../src/getPurgePluginOptions.ts"],"sourcesContent":["import { buildComponentFilesList } from '@intlayer/chokidar/utils';\nimport { IMPORT_MODE } from '@intlayer/config/defaultValues';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { MinifyPluginOptions } from './babel-plugin-intlayer-minify';\nimport type { PurgePluginOptions } from './babel-plugin-intlayer-purge';\n\n// ── Shared config helpers ─────────────────────────────────────────────────────\n\n/**\n * Attempts to load compiled dictionaries from `@intlayer/dictionaries-entry`.\n * Returns an empty array if the entry point is not available (e.g. dictionaries\n * have not been built yet).\n */\nconst loadDictionaries = (config: IntlayerConfig): Dictionary[] => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getDictionaries } = require('@intlayer/dictionaries-entry');\n const dictionariesRecord = getDictionaries(config) as Record<\n string,\n Dictionary\n >;\n return Object.values(dictionariesRecord);\n } catch {\n return [];\n }\n};\n\n// ── getPurgePluginOptions ─────────────────────────────────────────────────────\n\ntype GetPurgePluginOptionsParams = {\n /**\n * Options forwarded to the intlayer configuration loader.\n * Pass this when `intlayer.config.ts` lives outside the default search path\n * (e.g. in a monorepo workspace root).\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Pre-loaded dictionaries (optional – loaded automatically when omitted).\n * Providing them avoids a second `getDictionaries` call when you already\n * have them at hand.\n */\n dictionaries?: Dictionary[];\n\n /**\n * Override specific resolved option values after the defaults are computed.\n */\n overrides?: Partial<PurgePluginOptions>;\n};\n\n/**\n * Returns fully-resolved options for {@link intlayerPurgeBabelPlugin}.\n *\n * Loads the intlayer configuration once at babel.config.js evaluation time so\n * the plugin itself does not need to re-read the config on every file\n * transform.\n *\n * @example\n * ```js\n * // babel.config.js\n * const {\n * intlayerPurgeBabelPlugin,\n * getPurgePluginOptions,\n * } = require(\"@intlayer/babel\");\n *\n * module.exports = {\n * presets: [\"next/babel\"],\n * plugins: [\n * [intlayerPurgeBabelPlugin, getPurgePluginOptions()],\n * ],\n * };\n * ```\n */\nexport const getPurgePluginOptions = (\n params?: GetPurgePluginOptionsParams\n): PurgePluginOptions => {\n const {\n configOptions,\n dictionaries: providedDictionaries,\n overrides,\n } = params ?? {};\n\n const config = getConfiguration(configOptions);\n\n const { baseDir, dictionariesDir, dynamicDictionariesDir } = config.system;\n const { purge, minify, optimize } = config.build;\n const editorEnabled = config.editor.enabled;\n\n const importMode = config.build.importMode ?? config.dictionary?.importMode;\n\n const componentFilesList = buildComponentFilesList(config);\n\n const dictionaries = providedDictionaries ?? loadDictionaries(config);\n\n const dictionaryKeyToImportModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n > = {};\n for (const dictionary of dictionaries) {\n dictionaryKeyToImportModeMap[dictionary.key] =\n dictionary.importMode ?? importMode ?? IMPORT_MODE;\n }\n\n return {\n baseDir,\n purge: Boolean(purge),\n minify: Boolean(minify),\n optimize,\n editorEnabled,\n dictionariesDir,\n dynamicDictionariesDir,\n componentFilesList,\n dictionaryKeyToImportModeMap,\n ...overrides,\n };\n};\n\n// ── getMinifyPluginOptions ────────────────────────────────────────────────────\n\ntype GetMinifyPluginOptionsParams = {\n /**\n * Options forwarded to the intlayer configuration loader.\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Override specific resolved option values after the defaults are computed.\n */\n overrides?: Partial<MinifyPluginOptions>;\n};\n\n/**\n * Returns fully-resolved options for {@link intlayerMinifyBabelPlugin}.\n *\n * Loads the intlayer configuration once at babel.config.js evaluation time.\n *\n * @example\n * ```js\n * // babel.config.js\n * const {\n * intlayerMinifyBabelPlugin,\n * getMinifyPluginOptions,\n * } = require(\"@intlayer/babel\");\n *\n * module.exports = {\n * presets: [\"next/babel\"],\n * plugins: [\n * [intlayerMinifyBabelPlugin, getMinifyPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const getMinifyPluginOptions = (\n params?: GetMinifyPluginOptionsParams\n): MinifyPluginOptions => {\n const { configOptions, overrides } = params ?? {};\n\n const config = getConfiguration(configOptions);\n\n const { baseDir } = config.system;\n const { minify, optimize } = config.build;\n const editorEnabled = config.editor.enabled;\n\n return {\n baseDir,\n minify: Boolean(minify),\n optimize,\n editorEnabled,\n ...overrides,\n };\n};\n"],"mappings":";;;;;;;;;;;AAkBA,MAAM,oBAAoB,WAAyC;AACjE,KAAI;EAEF,MAAM,EAAE,8BAA4B,+BAA+B;EACnE,MAAM,qBAAqB,gBAAgB,OAAO;AAIlD,SAAO,OAAO,OAAO,mBAAmB;SAClC;AACN,SAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDb,MAAa,yBACX,WACuB;CACvB,MAAM,EACJ,eACA,cAAc,sBACd,cACE,UAAU,EAAE;CAEhB,MAAM,SAAS,iBAAiB,cAAc;CAE9C,MAAM,EAAE,SAAS,iBAAiB,2BAA2B,OAAO;CACpE,MAAM,EAAE,OAAO,QAAQ,aAAa,OAAO;CAC3C,MAAM,gBAAgB,OAAO,OAAO;CAEpC,MAAM,aAAa,OAAO,MAAM,cAAc,OAAO,YAAY;CAEjE,MAAM,qBAAqB,wBAAwB,OAAO;CAE1D,MAAM,eAAe,wBAAwB,iBAAiB,OAAO;CAErE,MAAM,+BAGF,EAAE;AACN,MAAK,MAAM,cAAc,aACvB,8BAA6B,WAAW,OACtC,WAAW,cAAc,cAAc;AAG3C,QAAO;EACL;EACA,OAAO,QAAQ,MAAM;EACrB,QAAQ,QAAQ,OAAO;EACvB;EACA;EACA;EACA;EACA;EACA;EACA,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;AAsCH,MAAa,0BACX,WACwB;CACxB,MAAM,EAAE,eAAe,cAAc,UAAU,EAAE;CAEjD,MAAM,SAAS,iBAAiB,cAAc;CAE9C,MAAM,EAAE,YAAY,OAAO;CAC3B,MAAM,EAAE,QAAQ,aAAa,OAAO;CACpC,MAAM,gBAAgB,OAAO,OAAO;AAEpC,QAAO;EACL;EACA,QAAQ,QAAQ,OAAO;EACvB;EACA;EACA,GAAG;EACJ"}
@@ -11,8 +11,11 @@ import { getComponentName } from "./extractContent/utils/getComponentName.mjs";
11
11
  import { extractContent, extractContentSync } from "./extractContent/extractContent.mjs";
12
12
  import { intlayerExtractBabelPlugin } from "./babel-plugin-intlayer-extract.mjs";
13
13
  import { buildNestedRenameMapFromContent, generateShortFieldName, makeFieldRenameBabelPlugin } from "./babel-plugin-intlayer-field-rename.mjs";
14
- import { getOptimizePluginOptions } from "./getOptimizePluginOptions.mjs";
15
14
  import { intlayerOptimizeBabelPlugin } from "./babel-plugin-intlayer-optimize.mjs";
16
15
  import { BABEL_PARSER_OPTIONS, COMPAT_USAGE_REGEX, INTLAYER_OR_COMPAT_USAGE_REGEX, INTLAYER_USAGE_REGEX, SOURCE_FILE_REGEX, analyzeFieldUsageInFile, optimizeSourceFile, renameFieldsInCode, renameFieldsInSourceFile } from "./transformers.mjs";
16
+ import { getSharedPruneContext, intlayerPurgeBabelPlugin } from "./babel-plugin-intlayer-purge.mjs";
17
+ import { intlayerMinifyBabelPlugin } from "./babel-plugin-intlayer-minify.mjs";
18
+ import { getOptimizePluginOptions } from "./getOptimizePluginOptions.mjs";
19
+ import { getMinifyPluginOptions, getPurgePluginOptions } from "./getPurgePluginOptions.mjs";
17
20
 
18
- export { ATTRIBUTES_TO_EXTRACT, BABEL_PARSER_OPTIONS, COMPAT_USAGE_REGEX, DEFAULT_COMPAT_CALLERS, INTLAYER_CALLER_NAMES, INTLAYER_OR_COMPAT_USAGE_REGEX, INTLAYER_USAGE_REGEX, SERVER_CAPABLE_PACKAGES, SOURCE_FILE_REGEX, analyzeFieldUsageInFile, buildNestedRenameMapFromContent, createPruneContext, detectPackageName, extractContent, extractContentSync, extractDictionaryInfo, extractDictionaryKey, extractDictionaryKeyFromPath, extractScriptBlocks, generateKey, generateShortFieldName, getComponentName, getExtractPluginOptions, getOptimizePluginOptions, getOutput, injectScriptBlocks, intlayerExtractBabelPlugin, intlayerOptimizeBabelPlugin, makeFieldRenameBabelPlugin, makeUsageAnalyzerBabelPlugin, mergeWithExistingMultilingualDictionary, mergeWithExistingPerLocaleDictionary, optimizeSourceFile, packageList, renameFieldsInCode, renameFieldsInSourceFile, resolveContentFilePaths, writeContentHelper };
21
+ export { ATTRIBUTES_TO_EXTRACT, BABEL_PARSER_OPTIONS, COMPAT_USAGE_REGEX, DEFAULT_COMPAT_CALLERS, INTLAYER_CALLER_NAMES, INTLAYER_OR_COMPAT_USAGE_REGEX, INTLAYER_USAGE_REGEX, SERVER_CAPABLE_PACKAGES, SOURCE_FILE_REGEX, analyzeFieldUsageInFile, buildNestedRenameMapFromContent, createPruneContext, detectPackageName, extractContent, extractContentSync, extractDictionaryInfo, extractDictionaryKey, extractDictionaryKeyFromPath, extractScriptBlocks, generateKey, generateShortFieldName, getComponentName, getExtractPluginOptions, getMinifyPluginOptions, getOptimizePluginOptions, getOutput, getPurgePluginOptions, getSharedPruneContext, injectScriptBlocks, intlayerExtractBabelPlugin, intlayerMinifyBabelPlugin, intlayerOptimizeBabelPlugin, intlayerPurgeBabelPlugin, makeFieldRenameBabelPlugin, makeUsageAnalyzerBabelPlugin, mergeWithExistingMultilingualDictionary, mergeWithExistingPerLocaleDictionary, optimizeSourceFile, packageList, renameFieldsInCode, renameFieldsInSourceFile, resolveContentFilePaths, writeContentHelper };