@intlayer/babel 8.1.11 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/babel-plugin-intlayer-extract.cjs +1 -1
- package/dist/cjs/babel-plugin-intlayer-extract.cjs.map +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs +1 -1
- package/dist/cjs/babel-plugin-intlayer-optimize.cjs.map +1 -1
- package/dist/cjs/extractContent/babelProcessor.cjs +2 -0
- package/dist/cjs/extractContent/babelProcessor.cjs.map +1 -0
- package/dist/cjs/extractContent/contentWriter.cjs +2 -0
- package/dist/cjs/extractContent/contentWriter.cjs.map +1 -0
- package/dist/cjs/extractContent/extractContent.cjs +2 -0
- package/dist/cjs/extractContent/extractContent.cjs.map +1 -0
- package/dist/cjs/extractContent/index.cjs +1 -0
- package/dist/cjs/extractContent/processTsxFile.cjs +6 -0
- package/dist/cjs/extractContent/processTsxFile.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/constants.cjs +2 -0
- package/dist/cjs/extractContent/utils/constants.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/detectPackageName.cjs +2 -0
- package/dist/cjs/extractContent/utils/detectPackageName.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs +2 -0
- package/dist/cjs/extractContent/utils/extractDictionaryKey.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/generateKey.cjs +2 -0
- package/dist/cjs/extractContent/utils/generateKey.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/getComponentName.cjs +2 -0
- package/dist/cjs/extractContent/utils/getComponentName.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs +2 -0
- package/dist/cjs/extractContent/utils/getExistingIntlayerInfo.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs +2 -0
- package/dist/cjs/extractContent/utils/getOrGenerateKey.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/index.cjs +1 -0
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs +2 -0
- package/dist/cjs/extractContent/utils/resolveDictionaryKey.cjs.map +1 -0
- package/dist/cjs/extractContent/utils/shouldExtract.cjs +2 -0
- package/dist/cjs/extractContent/utils/shouldExtract.cjs.map +1 -0
- package/dist/cjs/getExtractPluginOptions.cjs +1 -1
- package/dist/cjs/getOptimizePluginOptions.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs +1 -1
- package/dist/esm/babel-plugin-intlayer-extract.mjs.map +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs +1 -1
- package/dist/esm/babel-plugin-intlayer-optimize.mjs.map +1 -1
- package/dist/esm/extractContent/babelProcessor.mjs +2 -0
- package/dist/esm/extractContent/babelProcessor.mjs.map +1 -0
- package/dist/esm/extractContent/contentWriter.mjs +2 -0
- package/dist/esm/extractContent/contentWriter.mjs.map +1 -0
- package/dist/esm/extractContent/extractContent.mjs +2 -0
- package/dist/esm/extractContent/extractContent.mjs.map +1 -0
- package/dist/esm/extractContent/index.mjs +1 -0
- package/dist/esm/extractContent/processTsxFile.mjs +6 -0
- package/dist/esm/extractContent/processTsxFile.mjs.map +1 -0
- package/dist/esm/extractContent/utils/constants.mjs +2 -0
- package/dist/esm/extractContent/utils/constants.mjs.map +1 -0
- package/dist/esm/extractContent/utils/detectPackageName.mjs +2 -0
- package/dist/esm/extractContent/utils/detectPackageName.mjs.map +1 -0
- package/dist/esm/extractContent/utils/extractDictionaryKey.mjs +2 -0
- package/dist/esm/extractContent/utils/extractDictionaryKey.mjs.map +1 -0
- package/dist/esm/extractContent/utils/generateKey.mjs +2 -0
- package/dist/esm/extractContent/utils/generateKey.mjs.map +1 -0
- package/dist/esm/extractContent/utils/getComponentName.mjs +2 -0
- package/dist/esm/extractContent/utils/getComponentName.mjs.map +1 -0
- package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs +2 -0
- package/dist/esm/extractContent/utils/getExistingIntlayerInfo.mjs.map +1 -0
- package/dist/esm/extractContent/utils/getOrGenerateKey.mjs +2 -0
- package/dist/esm/extractContent/utils/getOrGenerateKey.mjs.map +1 -0
- package/dist/esm/extractContent/utils/index.mjs +1 -0
- package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs +2 -0
- package/dist/esm/extractContent/utils/resolveDictionaryKey.mjs.map +1 -0
- package/dist/esm/extractContent/utils/shouldExtract.mjs +2 -0
- package/dist/esm/extractContent/utils/shouldExtract.mjs.map +1 -0
- package/dist/esm/getExtractPluginOptions.mjs +1 -1
- package/dist/esm/getOptimizePluginOptions.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/types/babel-plugin-intlayer-extract.d.ts +28 -58
- package/dist/types/babel-plugin-intlayer-extract.d.ts.map +1 -1
- package/dist/types/babel-plugin-intlayer-optimize.d.ts +2 -2
- package/dist/types/babel-plugin-intlayer-optimize.d.ts.map +1 -1
- package/dist/types/extractContent/babelProcessor.d.ts +41 -0
- package/dist/types/extractContent/babelProcessor.d.ts.map +1 -0
- package/dist/types/extractContent/contentWriter.d.ts +27 -0
- package/dist/types/extractContent/contentWriter.d.ts.map +1 -0
- package/dist/types/extractContent/extractContent.d.ts +52 -0
- package/dist/types/extractContent/extractContent.d.ts.map +1 -0
- package/dist/types/extractContent/index.d.ts +4 -0
- package/dist/types/extractContent/processTsxFile.d.ts +18 -0
- package/dist/types/extractContent/processTsxFile.d.ts.map +1 -0
- package/dist/types/extractContent/utils/constants.d.ts +16 -0
- package/dist/types/extractContent/utils/constants.d.ts.map +1 -0
- package/dist/types/extractContent/utils/detectPackageName.d.ts +8 -0
- package/dist/types/extractContent/utils/detectPackageName.d.ts.map +1 -0
- package/dist/types/extractContent/utils/extractDictionaryKey.d.ts +11 -0
- package/dist/types/extractContent/utils/extractDictionaryKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/generateKey.d.ts +5 -0
- package/dist/types/extractContent/utils/generateKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/getComponentName.d.ts +10 -0
- package/dist/types/extractContent/utils/getComponentName.d.ts.map +1 -0
- package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts +13 -0
- package/dist/types/extractContent/utils/getExistingIntlayerInfo.d.ts.map +1 -0
- package/dist/types/extractContent/utils/getOrGenerateKey.d.ts +8 -0
- package/dist/types/extractContent/utils/getOrGenerateKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/index.d.ts +10 -0
- package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts +12 -0
- package/dist/types/extractContent/utils/resolveDictionaryKey.d.ts.map +1 -0
- package/dist/types/extractContent/utils/shouldExtract.d.ts +14 -0
- package/dist/types/extractContent/utils/shouldExtract.d.ts.map +1 -0
- package/dist/types/getOptimizePluginOptions.d.ts +1 -1
- package/dist/types/index.d.ts +4 -1
- package/package.json +14 -9
- package/dist/cjs/test-babel-error.cjs +0 -7
- package/dist/cjs/test-babel-error.cjs.map +0 -1
- package/dist/cjs/test-merge.cjs +0 -2
- package/dist/cjs/test-merge.cjs.map +0 -1
- package/dist/cjs/test-preserve.cjs +0 -2
- package/dist/cjs/test-preserve.cjs.map +0 -1
- package/dist/esm/test-babel-error.mjs +0 -7
- package/dist/esm/test-babel-error.mjs.map +0 -1
- package/dist/esm/test-merge.mjs +0 -2
- package/dist/esm/test-merge.mjs.map +0 -1
- package/dist/esm/test-preserve.mjs +0 -2
- package/dist/esm/test-preserve.mjs.map +0 -1
- package/dist/types/test-babel-error.d.ts +0 -1
- package/dist/types/test-merge.d.ts +0 -1
- package/dist/types/test-preserve.d.ts +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./constants.cjs`),t=require(`./detectPackageName.cjs`),n=require(`./extractDictionaryKey.cjs`),r=require(`./generateKey.cjs`),i=require(`./getComponentName.cjs`),a=require(`./getExistingIntlayerInfo.cjs`),o=require(`./getOrGenerateKey.cjs`),s=require(`./resolveDictionaryKey.cjs`),c=require(`./shouldExtract.cjs`);exports.ATTRIBUTES_TO_EXTRACT=e.ATTRIBUTES_TO_EXTRACT,exports.detectPackageName=t.detectPackageName,exports.extractDictionaryKey=n.extractDictionaryKey,exports.extractDictionaryKeyFromPath=n.extractDictionaryKeyFromPath,exports.generateKey=r.generateKey,exports.getComponentName=i.getComponentName,exports.getExistingIntlayerInfo=a.getExistingIntlayerInfo,exports.getOrGenerateKey=o.getOrGenerateKey,exports.packageList=e.packageList,exports.resolveDictionaryKey=s.resolveDictionaryKey,exports.shouldExtract=c.shouldExtract;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`../../_virtual/_rolldown/runtime.cjs`);let e=require(`node:path`),t=require(`node:fs`),n=require(`@intlayer/unmerged-dictionaries-entry`);const r=(r,i,a,o,s=new Set)=>{let c=o??(0,n.getUnmergedDictionaries)(a)??{},{fileExtensions:l}=a.content,u=(0,e.dirname)(i),d=l[0],f=d.startsWith(`.`)?d:`.${d}`,p=0;for(;p<100;){let n=p===0?r:`${r}${p}`,i=c[n],a=(0,e.join)(u,`${n}${f}`),o=s.has(n),l=i&&i.length>0,d=(0,t.existsSync)(a);if(!o&&!l&&!d)return n;p++}return r};exports.resolveDictionaryKey=r;
|
|
2
|
+
//# sourceMappingURL=resolveDictionaryKey.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveDictionaryKey.cjs","names":[],"sources":["../../../../src/extractContent/utils/resolveDictionaryKey.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { Dictionary, IntlayerConfig } from '@intlayer/types';\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];\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 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":"sNAUA,MAAa,GACX,EACA,EACA,EACA,EACA,EAAwB,IAAI,MACjB,CACX,IAAM,EACJ,IAAA,EAAA,EAAA,yBAAgD,EAAc,EAAI,EAAE,CAEhE,CAAE,kBAAmB,EAAc,QAEnC,GAAA,EAAA,EAAA,SAAkB,EAAS,CAC3B,EAAiB,EAAe,GAChC,EAAY,EAAe,WAAW,IAAI,CAC5C,EACA,IAAI,IAEJ,EAAQ,EAEZ,KAAO,EAAQ,KAAK,CAClB,IAAM,EAAY,IAAU,EAAI,EAAa,GAAG,IAAa,IACvD,EAAe,EAAM,GACrB,GAAA,EAAA,EAAA,MAAuB,EAAS,GAAG,IAAY,IAAY,CAC3D,EAAY,EAAS,IAAI,EAAU,CACnC,EAAkB,GAAgB,EAAa,OAAS,EACxD,GAAA,EAAA,EAAA,YAAwB,EAAgB,CAE9C,GAAI,CAAC,GAAa,CAAC,GAAmB,CAAC,EACrC,OAAO,EAET,IAGF,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shouldExtract.cjs","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 * - Single words (typically icons or technical terms)\n * - Strings not starting with an uppercase letter (likely technical values)\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 // We usually want to extract full sentences or labels, not single technical words\n if (!trimmed.includes(' ')) return false;\n\n // We assume content to extract starts with an uppercase letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n\n // Ignore dynamic content patterns\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n\n return true;\n};\n"],"mappings":"mEASA,MAAa,EAAiB,GAA0B,CACtD,IAAM,EAAU,EAAK,MAAM,CAa3B,MAFA,EATI,CAAC,GAGD,CAAC,EAAQ,SAAS,IAAI,EAGtB,CAAC,SAAS,KAAK,EAAQ,EAGvB,EAAQ,WAAW,IAAI,EAAI,EAAQ,WAAW,KAAK"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:path`),t=require(`@intlayer/config/client`),n=require(`@intlayer/config/node`),r=require(`node:fs`),i=require(`node:fs/promises`),a=require(`@intlayer/chokidar/build`);const o=(o=process.env.INTLAYER_IS_DEV_COMMAND)=>{let s=(0,n.getConfiguration)(),{baseDir:c}=s.content,l=(0,e.join)(c,s.compiler?.outputDir??`compiler`),u=async e=>{try{if(!(0,r.existsSync)(e))return null;let t=await(0,i.readFile)(e,`utf-8`);if(!t||t.trim()===``)return null;let n=JSON.parse(t);return Array.isArray(n)?n[0]??null:n}catch(t){return(0,r.existsSync)(e)&&(await(0,i.readFile)(e,`utf-8`)).trim()!==``&&console.warn(`[intlayer] Warning: Failed to read existing dictionary at ${e}. It might be corrupt. Translations may be lost. Error:`,t),null}},d=(e,t,n)=>{let r={},i=t?.content,a=Object.keys(e).sort();for(let t of a){let a=e[t],o=i?.[t];o&&o.nodeType===`translation`&&o.translation?r[t]={...o,nodeType:`translation`,translation:{...o.translation,[n]:o.translation[n]??a}}:r[t]={nodeType:`translation`,translation:{[n]:a}}}return r},f=async t=>{let{dictionaryKey:n,content:r,locale:i}=t;try{let t=await u((0,e.join)(l,`${n}.content.json`)),o=d(r,t,i),f={...t,key:n,content:o,filePath:(0,e.join)((0,e.relative)(c,l),`${n}.content.json`)},p=await(0,a.writeContentDeclaration)(f,s,{newDictionariesPath:(0,e.relative)(c,l)});await(0,a.buildDictionary)([{...f,filePath:(0,e.relative)(c,p.path)}],s)}catch(e){if(console.error(`[intlayer] Failed to process extracted content for ${n}:`,e),e instanceof SyntaxError&&e.message.includes(`Unexpected end of JSON input`)){let t=e.message.match(/^(.*\.json):\s*Unexpected end of JSON input/);if(t){let e=t[1];try{let t=require(`fs`).readFileSync(e,`utf-8`);console.error(`[intlayer] Content of the corrupted file (${e}):\n"${t}"`)}catch(t){console.error(`[intlayer] Could not read corrupted file ${e}`,t)}}}}},p=String(o)===`true`,m=s.compiler?.enabled===`build-only`?!p:s.compiler?.enabled??!0,h=(0,t.getAppLogger)(s);return s.compiler?.enabled===`build-only`&&p&&h(`${(0,t.colorize)(`Compiler:`,t.ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`),{enabled:m,defaultLocale:s.internationalization.defaultLocale,prefix:s.compiler?.dictionaryKeyPrefix,saveComponents:s.compiler?.saveComponents,onExtract:f}};exports.getExtractPluginOptions=o;
|
|
2
2
|
//# sourceMappingURL=getExtractPluginOptions.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getOptimizePluginOptions.cjs","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { getComponentTransformPatternSync } from '@intlayer/chokidar/utils';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { Dictionary, IntlayerConfig } from '@intlayer/types';\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) as Record<\n string,\n Dictionary\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 // Build files list from traverse pattern\n const filesListPattern = getComponentTransformPatternSync(config);\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 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
|
|
1
|
+
{"version":3,"file":"getOptimizePluginOptions.cjs","names":[],"sources":["../../src/getOptimizePluginOptions.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { getComponentTransformPatternSync } from '@intlayer/chokidar/utils';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { Dictionary, IntlayerConfig } from '@intlayer/types';\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) as Record<\n string,\n Dictionary\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 // Build files list from traverse pattern\n const filesListPattern = getComponentTransformPatternSync(config);\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 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":"mNA2BA,MAAM,EAAoB,GAAyC,CACjE,GAAI,CAGF,GAAM,CAAE,mBAAoB,QAAQ,+BAA+B,CAC7D,EAAqB,EAAgB,EAAO,CAIlD,OAAO,OAAO,OAAO,EAAmB,MAClC,CAEN,MAAO,EAAE,GASA,EACX,GAC0B,CAC1B,GAAM,CACJ,gBACA,aAAc,EACd,aACE,GAAU,EAAE,CAEV,GAAA,EAAA,EAAA,kBAA0B,EAAc,CACxC,CACJ,UACA,kBACA,0BACA,yBACA,wBACE,EAAO,OACL,CAAE,aAAY,YAAa,EAAO,MAGlC,GAAA,EAAA,EAAA,kCAAoD,EAAO,CAE3D,GAAA,EAAA,EAAA,MAA6B,EAAS,mBAAmB,CACzD,GAAA,EAAA,EAAA,MACJ,EACA,4BACD,CACK,GAAA,EAAA,EAAA,MACJ,EACA,2BACD,CACK,GAAA,EAAA,EAAA,MAAkC,EAAS,yBAAyB,CAEpE,EAAY,CAChB,GAAG,EACH,EACA,EACD,CAGK,EAAe,GAAwB,EAAiB,EAAO,CAE/D,EAGF,EAAE,CAMN,OAJA,EAAa,QAAS,GAAe,CACnC,EAAkB,EAAW,KAAO,EAAW,YAAc,GAC7D,CAEK,CACL,WACA,kBACA,wBACA,0BACA,gCACA,yBACA,+BACA,uBACA,6BACA,uBAAwB,GACxB,aACA,oBACA,YACA,GAAG,EACJ"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./babel-plugin-intlayer-extract.cjs`),
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./extractContent/utils/constants.cjs`),t=require(`./extractContent/utils/detectPackageName.cjs`),n=require(`./babel-plugin-intlayer-extract.cjs`),r=require(`./babel-plugin-intlayer-optimize.cjs`),i=require(`./getExtractPluginOptions.cjs`),a=require(`./getOptimizePluginOptions.cjs`),o=require(`./extractContent/extractContent.cjs`);exports.ATTRIBUTES_TO_EXTRACT=e.ATTRIBUTES_TO_EXTRACT,exports.detectPackageName=t.detectPackageName,exports.extractContent=o.extractContent,exports.getExtractPluginOptions=i.getExtractPluginOptions,exports.getOptimizePluginOptions=a.getOptimizePluginOptions,exports.intlayerExtractBabelPlugin=n.intlayerExtractBabelPlugin,exports.intlayerOptimizeBabelPlugin=r.intlayerOptimizeBabelPlugin,exports.packageList=e.packageList;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{detectPackageName as e}from"./extractContent/utils/detectPackageName.mjs";import{extractDictionaryKeyFromPath as t}from"./extractContent/utils/extractDictionaryKey.mjs";import{processTsxFile as n}from"./extractContent/processTsxFile.mjs";import{dirname as r,extname as i,relative as a}from"node:path";import{parse as o}from"@babel/parser";import{ANSIColors as s,colorize as c,colorizePath as l,getAppLogger as u}from"@intlayer/config/client";import{getConfiguration as d}from"@intlayer/config/node";const f=new Set([`next-intlayer`]),p=p=>({name:`babel-plugin-intlayer-extract`,visitor:{Program:{enter(p,m){let h=m.opts;if(h.enabled===!1)return;let g=m.file.opts.filename;if(!g)return;let _=i(g);if(![`.tsx`,`.jsx`,`.ts`,`.js`].includes(_)||h.filesList&&!h.filesList.includes(g))return;let v=m.file.code??``;if(!v)return;let y=d(),b=u(y),x=h.packageName??e(r(g))??`react-intlayer`,S=t(g,h.prefix??`comp-`),C=h.saveComponents??!1,w=p.node.directives.some(e=>e.value.value===`use client`),T=n(g,S,f.has(x)&&!w?`${x}/server`:x,y,C,{},v);if(!T)return;let{extractedContent:E,modifiedCode:D}=T;if(h.onExtract){let e=h.defaultLocale??y.internationalization.defaultLocale;for(let[t,n]of Object.entries(E))h.onExtract({dictionaryKey:t,filePath:g,content:n,locale:e})}try{let e=o(D,{sourceType:`module`,plugins:[`jsx`,`typescript`]});p.node.body=e.program.body,p.node.directives=e.program.directives,b(`${c(`Compiler:`,s.GREY_DARK)} Extracted content from ${l(a(y.content.baseDir,g))}`,{level:`debug`})}catch(e){console.error(`[intlayer] Failed to parse transformed code for ${g}:`,e)}}}}});export{p as intlayerExtractBabelPlugin};
|
|
2
2
|
//# sourceMappingURL=babel-plugin-intlayer-extract.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":["shouldExtract","defaultShouldExtract"],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { basename, dirname, extname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport _generate from '@babel/generator';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n shouldExtract as defaultShouldExtract,\n detectFormatCommand,\n} from '@intlayer/chokidar/cli';\nimport {\n ANSIColors,\n colorize,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { generateKey } from '@intlayer/core/utils';\n\nconst generate = ((_generate as any).default ?? _generate) as typeof _generate;\n\n// Set this to true to enable debug logs\nconst DEBUG_LOG = false;\n\ntype ExtractedContent = Record<string, string>;\n\n/**\n * Extracted content result from a file transformation\n */\nexport type ExtractResult = {\n /** Dictionary key derived from the file path */\n dictionaryKey: string;\n /** File path that was processed */\n filePath: string;\n /** Extracted content key-value pairs */\n content: ExtractedContent;\n /** Default locale used */\n locale: string;\n};\n\n/**\n * Options for the extraction Babel plugin\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'react-intlayer'\n */\n packageName?: string;\n /**\n * Files list to traverse. If provided, only files in this list will be processed.\n */\n filesList?: string[];\n /**\n * Custom function to determine if a string should be extracted\n */\n shouldExtract?: (text: string) => boolean;\n /**\n * Callback function called when content is extracted from a file.\n * This allows the compiler to capture the extracted content and write it to files.\n * The dictionary will be updated: new keys added, unused keys removed.\n */\n onExtract?: (result: ExtractResult) => void;\n\n /**\n * Whether the extraction compiler is enabled.\n * If false, the plugin will not process the file.\n */\n enabled?: boolean;\n\n /**\n * Prefix for the extracted dictionary keys.\n */\n prefix?: string;\n\n /**\n * Indicates if the components should be saved after being transformed.\n */\n saveComponents?: boolean;\n};\n\ntype State = PluginPass & {\n opts: ExtractPluginOptions;\n /** Extracted content from this file */\n _extractedContent?: ExtractedContent;\n /** Set of existing keys to avoid duplicates */\n _existingKeys?: Set<string>;\n /** The dictionary key for this file */\n _dictionaryKey?: string;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n /** Whether this file has JSX (React component) */\n _hasJSX?: boolean;\n /** Whether we already have useIntlayer imported */\n _hasUseIntlayerImport?: boolean;\n /** The local name for useIntlayer (in case it's aliased) */\n _useIntlayerLocalName?: string;\n /** Whether we already have getIntlayer imported */\n _hasGetIntlayerImport?: boolean;\n /** The local name for getIntlayer (in case it's aliased) */\n _getIntlayerLocalName?: string;\n /** The variable name to use for content (content or _compContent if content is already used) */\n _contentVarName?: string;\n /** Whether the file has 'use client' directive */\n _isClient?: boolean;\n /** Whether there is extracted content at the top level (not in a function) */\n _hasTopLevelContent?: boolean;\n /** Targets to extract and modify */\n _extractionTargets?: {\n path: NodePath<any>;\n key: string;\n isAttribute: boolean;\n }[];\n /** Functions to inject the hook/core logic into */\n _functionsToInject?: Set<NodePath<BabelTypes.Function>>;\n};\nconst extractDictionaryKeyFromPath = (\n filePath: string,\n prefix = 'comp-'\n): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n if (baseName === 'index') baseName = basename(dirname(filePath));\n return `${prefix}${baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()}`;\n};\n\nconst detectPackageName = (dir: string): string => {\n let currentDir = dir;\n while (true) {\n const pkgPath = join(currentDir, 'package.json');\n\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n\n if (\n pkg.dependencies?.['next-intlayer'] ||\n pkg.devDependencies?.['next-intlayer']\n ) {\n return 'next-intlayer';\n }\n\n if (\n pkg.dependencies?.['react-intlayer'] ||\n pkg.devDependencies?.['react-intlayer']\n ) {\n return 'react-intlayer';\n }\n\n if (\n pkg.dependencies?.['preact-intlayer'] ||\n pkg.devDependencies?.['preact-intlayer']\n ) {\n return 'preact-intlayer';\n }\n } catch {}\n }\n const parentDir = dirname(currentDir);\n\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n return 'react-intlayer';\n};\n\nconst unwrapParentheses = (\n node: BabelTypes.Node,\n t: typeof BabelTypes\n): BabelTypes.Node => {\n let current = node;\n\n while (t.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n\n return current;\n};\n\nconst isReactComponent = (\n funcPath: NodePath<BabelTypes.Function>,\n t: typeof BabelTypes\n): boolean => {\n const node = funcPath.node;\n\n if (!t.isBlockStatement(node.body)) {\n const unwrapped = unwrapParentheses(node.body, t);\n return t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped);\n }\n\n let returnsJSX = false;\n\n funcPath.traverse({\n Function(p) {\n p.skip();\n },\n ReturnStatement(p) {\n if (p.node.argument) {\n const unwrapped = unwrapParentheses(p.node.argument, t);\n\n if (t.isJSXElement(unwrapped) || t.isJSXFragment(unwrapped)) {\n returnsJSX = true;\n }\n }\n },\n });\n return returnsJSX;\n};\n\nconst findTargetFunction = (\n startPath: NodePath<any>,\n t: typeof BabelTypes\n): NodePath<BabelTypes.Function> | null => {\n const closestFunc =\n startPath.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n if (!closestFunc) return null;\n\n let currentFunc: NodePath<BabelTypes.Function> | null = closestFunc;\n while (currentFunc) {\n if (isReactComponent(currentFunc, t)) {\n return currentFunc;\n }\n currentFunc =\n currentFunc.getFunctionParent() as NodePath<BabelTypes.Function> | null;\n }\n return closestFunc;\n};\n\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n const config = getConfiguration();\n const appLogger = getAppLogger(config);\n\n return {\n name: 'babel-plugin-intlayer-extract',\n\n pre() {\n this._extractedContent = {};\n this._existingKeys = new Set();\n this._isIncluded = true;\n this._hasJSX = false;\n this._hasUseIntlayerImport = false;\n this._useIntlayerLocalName = 'useIntlayer';\n this._hasGetIntlayerImport = false;\n this._getIntlayerLocalName = 'getIntlayer';\n this._contentVarName = 'content';\n this._isClient = false;\n this._hasTopLevelContent = false;\n this._extractionTargets = [];\n this._functionsToInject = new Set();\n\n const filename = this.file.opts.filename;\n\n if (!this.opts.packageName) {\n const searchDir = filename ? dirname(filename) : process.cwd();\n this.opts.packageName = detectPackageName(searchDir);\n }\n\n // Check if extraction is enabled\n const isEnabled = this.opts.enabled ?? true;\n\n if (!isEnabled) {\n this._isIncluded = false;\n return;\n }\n\n if (this.opts.filesList && filename) {\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n this._isIncluded = this.opts.filesList.some(\n (f) => f.replace(/\\\\/g, '/') === normalizedFilename\n );\n }\n\n if (filename)\n this._dictionaryKey = extractDictionaryKeyFromPath(\n filename,\n this.opts.prefix\n );\n },\n visitor: {\n ImportDeclaration(path, state) {\n if (!state._isIncluded) return;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (importedName === 'useIntlayer') {\n state._hasUseIntlayerImport = true;\n state._useIntlayerLocalName = spec.local.name;\n }\n\n if (importedName === 'getIntlayer') {\n state._hasGetIntlayerImport = true;\n state._getIntlayerLocalName = spec.local.name;\n }\n }\n },\n\n JSXElement(_path, state) {\n if (!state._isIncluded) return;\n state._hasJSX = true;\n },\n\n JSXText(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const rawText = path.node.value;\n\n if (shouldExtract(rawText)) {\n const text = rawText.replace(/\\s+/g, ' ').trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === text\n );\n\n if (!key) {\n key = generateKey(text, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = text;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: false });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n JSXAttribute(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const attrName = path.node.name;\n\n if (!t.isJSXIdentifier(attrName)) return;\n const isKey = attrName.name === 'key';\n\n if (!ATTRIBUTES_TO_EXTRACT.includes(attrName.name) && !isKey) return;\n\n const value = path.node.value;\n let text: string | null = null;\n\n if (t.isStringLiteral(value)) text = value.value;\n else if (\n t.isJSXExpressionContainer(value) &&\n t.isStringLiteral(value.expression)\n )\n text = value.expression.value;\n\n if (text && shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: true });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n StringLiteral(path, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n const shouldExtract = state.opts.shouldExtract ?? defaultShouldExtract;\n const parent = path.parentPath;\n\n if (\n parent.isJSXAttribute() ||\n parent.isImportDeclaration() ||\n parent.isExportDeclaration() ||\n parent.isImportSpecifier()\n )\n return;\n\n if (parent.isObjectProperty() && path.key === 'key') return;\n\n if (parent.isMemberExpression() && path.key === 'property') return;\n\n if (parent.isCallExpression()) {\n const callee = (parent.node as BabelTypes.CallExpression).callee;\n\n if (\n (t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console') ||\n (t.isIdentifier(callee) &&\n (callee.name === state._useIntlayerLocalName ||\n callee.name === state._getIntlayerLocalName ||\n callee.name === 'require')) ||\n callee.type === 'Import'\n )\n return;\n }\n\n const text = path.node.value;\n\n if (shouldExtract(text)) {\n const cleanText = text.trim();\n let key = Object.keys(state._extractedContent!).find(\n (k) => state._extractedContent![k] === cleanText\n );\n\n if (!key) {\n key = generateKey(cleanText, state._existingKeys!);\n state._existingKeys!.add(key);\n state._extractedContent![key] = cleanText;\n }\n\n state._extractionTargets!.push({ path, key, isAttribute: false });\n const func = findTargetFunction(path, t);\n if (func) {\n state._functionsToInject!.add(func);\n } else {\n state._hasTopLevelContent = true;\n }\n }\n },\n\n Program: {\n enter(programPath, state) {\n if (!state._isIncluded) return;\n\n // Check for 'use client' directive\n state._isClient = programPath.node.directives.some(\n (d) => d.value.value === 'use client'\n );\n\n let contentVarUsed = false;\n programPath.traverse({\n VariableDeclarator(varPath) {\n if (\n t.isIdentifier(varPath.node.id) &&\n varPath.node.id.name === 'content'\n )\n contentVarUsed = true;\n },\n });\n state._contentVarName = contentVarUsed ? '_compContent' : 'content';\n },\n\n exit(programPath, state) {\n if (!state._isIncluded || !state._dictionaryKey) return;\n\n const extractionTargets = state._extractionTargets!;\n const functionsToInject = state._functionsToInject!;\n\n if (extractionTargets.length === 0) return;\n\n // Extraction (Modification)\n for (const { path, key, isAttribute } of extractionTargets) {\n let isHook = false;\n let hookDecided = false;\n\n const binding = path.scope.getBinding(state._contentVarName!);\n\n if (\n binding &&\n t.isVariableDeclarator(binding.path.node) &&\n t.isCallExpression(binding.path.node.init) &&\n t.isIdentifier(binding.path.node.init.callee)\n ) {\n if (\n binding.path.node.init.callee.name ===\n state._useIntlayerLocalName\n ) {\n isHook = true;\n hookDecided = true;\n } else if (\n binding.path.node.init.callee.name ===\n state._getIntlayerLocalName\n ) {\n isHook = false;\n hookDecided = true;\n }\n }\n\n if (!hookDecided) {\n const func = findTargetFunction(path, t);\n\n if (func) {\n isHook = isReactComponent(func, t);\n }\n }\n\n if (isAttribute) {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.node.value = t.jsxExpressionContainer(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n } else if (path.isJSXText()) {\n path.replaceWith(\n t.jsxExpressionContainer(\n t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n )\n )\n );\n } else {\n const member = t.optionalMemberExpression(\n t.identifier(state._contentVarName!),\n t.stringLiteral(key),\n true,\n true\n );\n path.replaceWith(\n isHook\n ? t.optionalMemberExpression(\n member,\n t.identifier('value'),\n false,\n true\n )\n : member\n );\n }\n }\n\n // Report\n\n if (state.opts.onExtract && state._dictionaryKey) {\n state.opts.onExtract({\n dictionaryKey: state._dictionaryKey,\n filePath: state.file.opts.filename!,\n content: { ...state._extractedContent! },\n locale: state.opts.defaultLocale!,\n });\n }\n\n // Pass 3: Injection\n let needsUseIntlayer = false;\n let needsGetIntlayer = false;\n\n for (const funcPath of functionsToInject) {\n const type = injectHook(funcPath, state, t);\n\n if (type === 'hook') needsUseIntlayer = true;\n\n if (type === 'core') needsGetIntlayer = true;\n }\n\n if (state._hasTopLevelContent) {\n needsGetIntlayer = true;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const coreName = state._getIntlayerLocalName!;\n\n // Find injection position (after imports)\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n (t.isImportDeclaration(body[pos]) ||\n (t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )))\n )\n pos++;\n\n programPath.node.body.splice(\n pos,\n 0,\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(coreName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n // Pass 4: Imports\n\n if (needsUseIntlayer || needsGetIntlayer) {\n let hookPkg = state.opts.packageName ?? 'react-intlayer';\n const corePkg = 'intlayer';\n\n // Handle next-intlayer server/client split\n\n if (hookPkg === 'next-intlayer' && !state._isClient) {\n hookPkg = `${hookPkg}/server`;\n }\n\n let pos = 0;\n const body = programPath.node.body;\n while (\n pos < body.length &&\n t.isExpressionStatement(body[pos]) &&\n t.isStringLiteral(\n (body[pos] as BabelTypes.ExpressionStatement).expression\n )\n )\n pos++;\n\n if (needsUseIntlayer && !state._hasUseIntlayerImport) {\n body.splice(\n pos++,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('useIntlayer'),\n t.identifier('useIntlayer')\n ),\n ],\n t.stringLiteral(hookPkg)\n )\n );\n }\n\n if (needsGetIntlayer && !state._hasGetIntlayerImport) {\n body.splice(\n pos,\n 0,\n t.importDeclaration(\n [\n t.importSpecifier(\n t.identifier('getIntlayer'),\n t.identifier('getIntlayer')\n ),\n ],\n t.stringLiteral(corePkg)\n )\n );\n }\n }\n\n if (state.opts.saveComponents && state.file.opts.filename) {\n try {\n const transformedCode = generate(programPath.node, {\n retainLines: true,\n }).code;\n\n writeFileSync(state.file.opts.filename, transformedCode, 'utf-8');\n\n const basedir = config.content?.baseDir ?? process.cwd();\n const relativePath = relative(basedir, state.file.opts.filename);\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Saved component: ${colorizePath(relativePath)}`,\n { level: 'info' }\n );\n\n const formatCommand = detectFormatCommand(config);\n\n if (formatCommand) {\n try {\n execSync(\n formatCommand.replace('{{file}}', state.file.opts.filename),\n {\n stdio: 'ignore', // Use 'ignore' to prevent format output from cluttering the extraction process console\n cwd: basedir,\n }\n );\n } catch (error) {\n appLogger(`Extractor formatting error: ${String(error)}`, {\n level: 'error',\n });\n }\n }\n } catch (err: any) {\n appLogger(`Extractor plugin error: ${String(err)}`, {\n level: 'error',\n });\n }\n }\n\n if (DEBUG_LOG) {\n const basedir = config.content?.baseDir ?? process.cwd();\n const relativePath = state.file.opts.filename\n ? relative(basedir, state.file.opts.filename)\n : 'unknown';\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Transformed: ${colorizePath(relativePath)}\\n${generate(programPath.node, { retainLines: false }).code}`,\n { level: 'debug' }\n );\n }\n },\n },\n },\n };\n};\n\nconst injectHook = (\n path: NodePath<BabelTypes.Function>,\n state: State,\n t: typeof BabelTypes\n): 'hook' | 'core' => {\n const node = path.node;\n const contentVarName = state._contentVarName!;\n const dictionaryKey = state._dictionaryKey!;\n const returnsJSX = isReactComponent(path, t);\n\n if (!t.isBlockStatement(node.body)) {\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n\n const hookCall = t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ]);\n\n node.body = t.blockStatement([\n hookCall,\n t.returnStatement(node.body as BabelTypes.Expression),\n ]);\n\n return returnsJSX ? 'hook' : 'core';\n }\n\n const hookName = returnsJSX\n ? state._useIntlayerLocalName!\n : state._getIntlayerLocalName!;\n\n const hasHook = node.body.body.some(\n (s) =>\n t.isVariableDeclaration(s) &&\n s.declarations.some(\n (d) => t.isIdentifier(d.id) && d.id.name === contentVarName\n )\n );\n\n if (!hasHook) {\n node.body.body.unshift(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(contentVarName),\n t.callExpression(t.identifier(hookName), [\n t.stringLiteral(dictionaryKey),\n ])\n ),\n ])\n );\n }\n\n return returnsJSX ? 'hook' : 'core';\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-extract.ts"],"sourcesContent":["import { dirname, extname, relative } from 'node:path';\nimport type { PluginObj, PluginPass } from '@babel/core';\nimport { parse } from '@babel/parser';\nimport type * as BabelTypes from '@babel/types';\nimport {\n ANSIColors,\n colorize,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/client';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { processTsxFile } from './extractContent/processTsxFile';\nimport type { PackageName } from './extractContent/utils/constants';\nimport { detectPackageName } from './extractContent/utils/detectPackageName';\nimport { extractDictionaryKeyFromPath } from './extractContent/utils/extractDictionaryKey';\n\n/** Packages that support a `/server` sub-path for React Server Components. */\nconst SERVER_CAPABLE_PACKAGES: ReadonlySet<string> = new Set(['next-intlayer']);\n\nexport type ExtractResult = {\n dictionaryKey: string;\n filePath: string;\n content: Record<string, string>;\n locale: string;\n};\n\nexport type ExtractPluginOptions = {\n defaultLocale?: string;\n packageName?: string;\n filesList?: string[];\n shouldExtract?: (text: string) => boolean;\n enabled?: boolean;\n prefix?: string;\n saveComponents?: boolean;\n formatCommand?: string;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * Used by `getExtractPluginOptions` to write dictionaries to disk.\n * May be async — the plugin will fire-and-forget (Babel transforms are sync).\n */\n onExtract?: (result: ExtractResult) => void | Promise<void>;\n};\n\ntype State = PluginPass & { opts: ExtractPluginOptions };\n\n/**\n * Babel plugin that extracts translatable content from source files and\n * injects Intlayer hooks (`useIntlayer` / `getIntlayer`) automatically.\n *\n * Designed for use with Babel-based build tools such as Next.js and Webpack.\n *\n * @example babel.config.js\n * ```js\n * const { intlayerExtractBabelPlugin, getExtractPluginOptions } = require('@intlayer/babel');\n * module.exports = {\n * presets: ['next/babel'],\n * plugins: [\n * [intlayerExtractBabelPlugin, getExtractPluginOptions()],\n * ],\n * };\n * ```\n */\nexport const intlayerExtractBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n return {\n name: 'babel-plugin-intlayer-extract',\n\n visitor: {\n Program: {\n enter(programPath, state) {\n const opts = state.opts;\n\n if (opts.enabled === false) return;\n\n const filename = state.file.opts.filename;\n if (!filename) return;\n\n const ext = extname(filename);\n if (!['.tsx', '.jsx', '.ts', '.js'].includes(ext)) return;\n\n if (opts.filesList && !opts.filesList.includes(filename)) return;\n\n // Grab the original source from the Babel file object\n const fileCode: string = (state.file as any).code ?? '';\n if (!fileCode) return;\n\n const configuration = getConfiguration();\n const appLogger = getAppLogger(configuration);\n\n const packageName = (opts.packageName ??\n detectPackageName(dirname(filename)) ??\n 'react-intlayer') as PackageName;\n\n const prefix = opts.prefix ?? 'comp-';\n const componentKey = extractDictionaryKeyFromPath(filename, prefix);\n const saveComponents = opts.saveComponents ?? false;\n\n // For packages that expose a `/server` entry (e.g. next-intlayer),\n // use that sub-path when no \"use client\" directive is present so that\n // React Server Components receive the correct import.\n const hasUseClient = programPath.node.directives.some(\n (d) => d.value.value === 'use client'\n );\n const effectivePackageName =\n SERVER_CAPABLE_PACKAGES.has(packageName) && !hasUseClient\n ? `${packageName}/server`\n : packageName;\n\n const result = processTsxFile(\n filename,\n componentKey,\n effectivePackageName,\n configuration,\n saveComponents,\n {}, // unmergedDictionaries — not needed for Babel plugin use case\n fileCode\n );\n\n if (!result) return;\n\n const { extractedContent, modifiedCode } = result;\n\n // Fire-and-forget: Babel transforms are synchronous, but onExtract may\n // be async (e.g. writing files). We don't await here.\n if (opts.onExtract) {\n const defaultLocale =\n opts.defaultLocale ??\n configuration.internationalization.defaultLocale;\n\n for (const [key, content] of Object.entries(extractedContent)) {\n void opts.onExtract({\n dictionaryKey: key,\n filePath: filename,\n content,\n locale: defaultLocale,\n });\n }\n }\n\n // Replace the Babel AST with the transformed code by re-parsing it.\n // This lets Babel serialise the injected hooks/imports through its\n // own code generator, preserving compatibility with other plugins.\n try {\n const newAst = parse(modifiedCode, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n programPath.node.body = newAst.program.body;\n programPath.node.directives = newAst.program.directives;\n\n appLogger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted content from ${colorizePath(relative(configuration.content.baseDir, filename))}`,\n { level: 'debug' }\n );\n } catch (error) {\n console.error(\n `[intlayer] Failed to parse transformed code for ${filename}:`,\n error\n );\n }\n },\n },\n },\n };\n};\n"],"mappings":"0fAiBA,MAAM,EAA+C,IAAI,IAAI,CAAC,gBAAgB,CAAC,CA6ClE,EAA8B,IAGlC,CACL,KAAM,gCAEN,QAAS,CACP,QAAS,CACP,MAAM,EAAa,EAAO,CACxB,IAAM,EAAO,EAAM,KAEnB,GAAI,EAAK,UAAY,GAAO,OAE5B,IAAM,EAAW,EAAM,KAAK,KAAK,SACjC,GAAI,CAAC,EAAU,OAEf,IAAM,EAAM,EAAQ,EAAS,CAG7B,GAFI,CAAC,CAAC,OAAQ,OAAQ,MAAO,MAAM,CAAC,SAAS,EAAI,EAE7C,EAAK,WAAa,CAAC,EAAK,UAAU,SAAS,EAAS,CAAE,OAG1D,IAAM,EAAoB,EAAM,KAAa,MAAQ,GACrD,GAAI,CAAC,EAAU,OAEf,IAAM,EAAgB,GAAkB,CAClC,EAAY,EAAa,EAAc,CAEvC,EAAe,EAAK,aACxB,EAAkB,EAAQ,EAAS,CAAC,EACpC,iBAGI,EAAe,EAA6B,EADnC,EAAK,QAAU,QACqC,CAC7D,EAAiB,EAAK,gBAAkB,GAKxC,EAAe,EAAY,KAAK,WAAW,KAC9C,GAAM,EAAE,MAAM,QAAU,aAC1B,CAMK,EAAS,EACb,EACA,EANA,EAAwB,IAAI,EAAY,EAAI,CAAC,EACzC,GAAG,EAAY,SACf,EAMJ,EACA,EACA,EAAE,CACF,EACD,CAED,GAAI,CAAC,EAAQ,OAEb,GAAM,CAAE,mBAAkB,gBAAiB,EAI3C,GAAI,EAAK,UAAW,CAClB,IAAM,EACJ,EAAK,eACL,EAAc,qBAAqB,cAErC,IAAK,GAAM,CAAC,EAAK,KAAY,OAAO,QAAQ,EAAiB,CACtD,EAAK,UAAU,CAClB,cAAe,EACf,SAAU,EACV,UACA,OAAQ,EACT,CAAC,CAON,GAAI,CACF,IAAM,EAAS,EAAM,EAAc,CACjC,WAAY,SACZ,QAAS,CAAC,MAAO,aAAa,CAC/B,CAAC,CAEF,EAAY,KAAK,KAAO,EAAO,QAAQ,KACvC,EAAY,KAAK,WAAa,EAAO,QAAQ,WAE7C,EACE,GAAG,EAAS,YAAa,EAAW,UAAU,CAAC,0BAA0B,EAAa,EAAS,EAAc,QAAQ,QAAS,EAAS,CAAC,GACxI,CAAE,MAAO,QAAS,CACnB,OACM,EAAO,CACd,QAAQ,MACN,mDAAmD,EAAS,GAC5D,EACD,GAGN,CACF,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{dirname as e,join as t,relative as n}from"node:path";import{
|
|
1
|
+
import{dirname as e,join as t,relative as n}from"node:path";import{normalizePath as r}from"@intlayer/config/utils";import{getPathHash as i}from"@intlayer/chokidar/utils";const a=[`intlayer`,`@intlayer/core`,`react-intlayer`,`react-intlayer/client`,`react-intlayer/server`,`next-intlayer`,`next-intlayer/client`,`next-intlayer/server`,`svelte-intlayer`,`vue-intlayer`,`angular-intlayer`,`preact-intlayer`,`solid-intlayer`],o=[`useIntlayer`,`getIntlayer`],s=[`react-intlayer`,`react-intlayer/client`,`react-intlayer/server`,`next-intlayer`,`next-intlayer/client`,`next-intlayer/server`,`preact-intlayer`,`vue-intlayer`,`solid-intlayer`,`svelte-intlayer`,`angular-intlayer`],c={getIntlayer:`getDictionary`,useIntlayer:`useDictionary`},l={useIntlayer:`useDictionaryDynamic`},u=(e,t)=>{let n=i(e);return t.identifier(`_${n}`)},d=(i,a,o,s,c,l)=>{let u=t(a,`${c}.json`);l===`fetch`&&(u=t(s,`${c}.mjs`)),l===`dynamic`&&(u=t(o,`${c}.mjs`));let d=n(e(i),u);return d=r(d),!d.startsWith(`./`)&&!d.startsWith(`../`)&&(d=`./${d}`),d},f=e=>{let{types:t}=e;return{name:`babel-plugin-intlayer-transform`,pre(){if(this._newStaticImports=new Map,this._newDynamicImports=new Map,this._callerMap=new Map,this._isIncluded=!0,this._hasValidImport=!1,this._isDictEntry=!1,this._useDynamicHelpers=!1,this.opts.optimize===!1){this._isIncluded=!1;return}let e=this.file.opts.filename;if(this.opts.filesList&&e&&!this.opts.filesList.includes(e)){this._isIncluded=!1;return}},visitor:{Program:{enter(e,n){let r=n.file.opts.filename;n.opts.replaceDictionaryEntry&&r===n.opts.dictionariesEntryPath&&(n._isDictEntry=!0,e.traverse({ImportDeclaration(e){e.remove()},VariableDeclarator(e){t.isObjectExpression(e.node.init)&&(e.node.init.properties=[])}}))},exit(e,n){if(n._isDictEntry||!n._isIncluded)return;let r=!1;if(e.traverse({CallExpression(e){let i=e.node.callee;if(!t.isIdentifier(i)||n._callerMap?.get(i.name)!==`useIntlayer`)return;let a=e.node.arguments[0],o;if(a&&t.isStringLiteral(a)?o=a.value:a&&t.isTemplateLiteral(a)&&a.expressions.length===0&&a.quasis.length===1&&(o=a.quasis[0].value.cooked??a.quasis[0].value.raw),!o)return;let s=n.opts.dictionaryModeMap?.[o];(s===`dynamic`||s===`fetch`)&&(r=!0)}}),e.traverse({ImportDeclaration(e){let i=e.node.source.value;if(a.includes(i)){n._hasValidImport=!0;for(let a of e.node.specifiers){if(!t.isImportSpecifier(a))continue;let e=t.isIdentifier(a.imported)?a.imported.name:a.imported.value;o.includes(e)&&n._callerMap?.set(a.local.name,e);let u=n.opts.importMode,d=(u===`dynamic`||u===`fetch`||r)&&s.includes(i);d&&(n._useDynamicHelpers=!0);let f;f=d?{...c,...l}:c;let p=f[e];p&&(a.imported=t.identifier(p))}}},CallExpression(e){let r=e.node.callee;if(!t.isIdentifier(r))return;let a=n._callerMap?.get(r.name);if(!a)return;n._hasValidImport=!0;let o=e.node.arguments[0],s;if(o&&t.isStringLiteral(o)?s=o.value:o&&t.isTemplateLiteral(o)&&o.expressions.length===0&&o.quasis.length===1&&(s=o.quasis[0].value.cooked??o.quasis[0].value.raw),!s)return;let c=n.opts.importMode,l=a===`useIntlayer`,d=!!n._useDynamicHelpers,f=`static`,p=n.opts.dictionaryModeMap?.[s];l&&d?p?f=p:c===`dynamic`?f=`dynamic`:c===`fetch`&&(f=`fetch`):l&&!d&&(p===`dynamic`||p===`fetch`)&&(f=p);let m;if(f===`fetch`){let r=n._newDynamicImports?.get(s);if(!r){let e=i(s);r=t.identifier(`_${e}_fetch`),n._newDynamicImports?.set(s,r)}m=r,e.node.arguments=[t.identifier(m.name),...e.node.arguments]}else if(f===`dynamic`){let r=n._newDynamicImports?.get(s);if(!r){let e=i(s);r=t.identifier(`_${e}_dyn`),n._newDynamicImports?.set(s,r)}m=r,e.node.arguments=[t.identifier(m.name),...e.node.arguments]}else{let r=n._newStaticImports?.get(s);r||(r=u(s,t),n._newStaticImports?.set(s,r)),m=r,e.node.arguments[0]=t.identifier(m.name)}}}),!n._hasValidImport)return;let f=n.file.opts.filename,p=n.opts.dictionariesDir,m=n.opts.dynamicDictionariesDir,h=n.opts.fetchDictionariesDir,g=[];for(let[e,r]of n._newStaticImports){let n=d(f,p,m,h,e,`static`),i=t.importDeclaration([t.importDefaultSpecifier(t.identifier(r.name))],t.stringLiteral(n));i.attributes=[t.importAttribute(t.identifier(`type`),t.stringLiteral(`json`))],g.push(i)}for(let[e,r]of n._newDynamicImports){let n=d(f,p,m,h,e,r.name.endsWith(`_fetch`)?`fetch`:`dynamic`);g.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(r.name))],t.stringLiteral(n)))}if(!g.length)return;let _=e.get(`body`),v=0;for(let e of _){let n=e.node;if(t.isExpressionStatement(n)&&t.isStringLiteral(n.expression)&&!n.expression.value.startsWith(`import`)&&!n.expression.value.startsWith(`require`))v+=1;else break}e.node.body.splice(v,0,...g)}}}}};export{f as intlayerOptimizeBabelPlugin};
|
|
2
2
|
//# sourceMappingURL=babel-plugin-intlayer-optimize.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-optimize.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { getFileHash } from '@intlayer/chokidar/utils';\nimport { normalizePath } from '@intlayer/config/utils';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'svelte-intlayer',\n 'vue-intlayer',\n 'angular-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n];\n\nconst CALLER_LIST = ['useIntlayer', 'getIntlayer'] as const;\n\n/**\n * Packages that support dynamic import\n */\nconst PACKAGE_LIST_DYNAMIC = [\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'preact-intlayer',\n 'vue-intlayer',\n 'solid-intlayer',\n 'svelte-intlayer',\n 'angular-intlayer',\n] as const;\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n useIntlayer: 'useDictionary',\n} as const;\n\nconst DYNAMIC_IMPORT_FUNCTION = {\n useIntlayer: 'useDictionaryDynamic',\n} as const;\n\n/**\n * Options for the optimization Babel plugin\n */\nexport type OptimizePluginOptions = {\n /**\n * If false, the plugin will not apply any transformation.\n */\n optimize?: boolean;\n /**\n * The path to the dictionaries directory.\n */\n dictionariesDir: string;\n /**\n * The path to the dictionaries entry file.\n */\n dictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries entry file.\n */\n unmergedDictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries directory.\n */\n unmergedDictionariesDir: string;\n /**\n * The path to the dictionaries directory.\n */\n dynamicDictionariesDir: string;\n /**\n * The path to the dynamic dictionaries entry file.\n */\n dynamicDictionariesEntryPath: string;\n /**\n * The path to the fetch dictionaries directory.\n */\n fetchDictionariesDir: string;\n /**\n * The path to the fetch dictionaries entry file.\n */\n fetchDictionariesEntryPath: string;\n /**\n * If true, the plugin will replace the dictionary entry file with `export default {}`.\n */\n replaceDictionaryEntry: boolean;\n /**\n * If true, the plugin will activate the dynamic import of the dictionaries. It will rely on Suspense to load the dictionaries.\n */\n importMode: 'static' | 'dynamic' | 'fetch';\n /**\n * Map of dictionary keys to their specific import mode.\n */\n dictionaryModeMap?: Record<string, 'static' | 'dynamic' | 'fetch'>;\n /**\n * Files list to traverse.\n */\n filesList: string[];\n};\n\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** map key → generated ident (per-file) for static imports */\n _newStaticImports?: Map<string, BabelTypes.Identifier>;\n /** map key → generated ident (per-file) for dynamic imports */\n _newDynamicImports?: Map<string, BabelTypes.Identifier>;\n /** whether the current file imported *any* intlayer package */\n _hasValidImport?: boolean;\n /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */\n _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: boolean;\n /** whether dynamic helpers are active for this file */\n _useDynamicHelpers?: boolean;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n};\n\n/**\n * Replicates the xxHash64 → Base-62 algorithm used by the SWC version\n * and prefixes an underscore so the generated identifiers never collide\n * with user-defined ones.\n */\nconst makeIdent = (\n key: string,\n t: typeof BabelTypes\n): BabelTypes.Identifier => {\n const hash = getFileHash(key);\n return t.identifier(`_${hash}`);\n};\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch'\n): string => {\n let relativePath = join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n relativePath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n relativePath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n let rel = relative(dirname(fromFile), relativePath);\n\n // Fix windows path\n rel = normalizePath(rel);\n\n // Fix relative path\n if (!rel.startsWith('./') && !rel.startsWith('../')) {\n rel = `./${rel}`;\n }\n\n return rel;\n};\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer\n * packages into optimized dictionary access patterns, automatically importing the required\n * dictionary files based on the configured import mode.\n *\n * ## Supported Input Patterns\n *\n * The plugin recognizes these function calls:\n *\n * ```ts\n * // useIntlayer\n * import { useIntlayer } from 'react-intlayer';\n * import { useIntlayer } from 'next-intlayer';\n *\n * // getIntlayer\n * import { getIntlayer } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * ```\n *\n * ## Transformation Modes\n *\n * ### Static Mode (default: `importMode = \"static\"`)\n *\n * Imports JSON dictionaries directly and replaces function calls with dictionary access:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import { useDictionary as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash);\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Dynamic Mode (`importMode = \"dynamic\"`)\n *\n * Uses dynamic dictionary loading with Suspense support:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Live Mode (`importMode = \"live\"`)\n *\n * Uses live-based dictionary loading for remote dictionaries:\n *\n * **Output if `dictionaryModeMap` includes the key with \"live\" value:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_fetch, \"app\");\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * > If `dictionaryModeMap` does not include the key with \"live\" value, the plugin will fallback to the dynamic impor\n *\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n */\nexport const intlayerOptimizeBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-transform',\n\n pre() {\n this._newStaticImports = new Map();\n this._newDynamicImports = new Map();\n this._callerMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = false;\n this._useDynamicHelpers = false;\n\n // If optimize is false, skip processing entirely\n if (this.opts.optimize === false) {\n this._isIncluded = false;\n return;\n }\n\n // If filesList is provided, check if current file is included\n const filename = this.file.opts.filename;\n if (this.opts.filesList && filename) {\n const isIncluded = this.opts.filesList.includes(filename);\n\n if (!isIncluded) {\n // Force _isIncluded to false to skip processing\n this._isIncluded = false;\n return;\n }\n }\n },\n\n visitor: {\n /* If this file *is* the dictionaries entry, short-circuit: export {} */\n Program: {\n enter(programPath, state) {\n // Safe access to filename\n const filename = state.file.opts.filename;\n\n // Check if this is the correct file to transform\n\n if (\n state.opts.replaceDictionaryEntry &&\n filename === state.opts.dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n\n // Traverse the program to surgically remove/edit specific parts\n programPath.traverse({\n // Remove all import statements (cleaning up 'sssss.json')\n ImportDeclaration(path) {\n path.remove();\n },\n\n // Find the variable definition and empty the object\n VariableDeclarator(path) {\n // We look for: const x = { ... }\n\n if (t.isObjectExpression(path.node.init)) {\n // Set the object properties to an empty array: {}\n path.node.init.properties = [];\n }\n },\n });\n\n // (Optional) Stop other plugins from processing this file further if needed\n // programPath.stop();\n }\n },\n\n /**\n * After full traversal, process imports and call expressions, then inject the JSON dictionary imports.\n *\n * We do the transformation in Program.exit (via a manual traverse) rather than using\n * top-level ImportDeclaration/CallExpression visitors. This ensures that if another plugin\n * (like babel-plugin-intlayer-extract) adds new useIntlayer calls in its Program.exit,\n * we will see and transform them here because our Program.exit runs after theirs.\n */\n exit(programPath, state) {\n if (state._isDictEntry) return; // nothing else to do – already replaced\n\n if (!state._isIncluded) return; // early-out if file is not included\n\n // Manual traversal to process imports and call expressions\n // This runs AFTER all other plugins' visitors have completed\n\n // Pre-pass to determine if we should use dynamic helpers\n let fileHasDynamicCall = false;\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (originalImportedName !== 'useIntlayer') return;\n\n const arg = path.node.arguments[0];\n\n let key: string | undefined;\n\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n // If the bundler output is `breadcrumb` instead of 'breadcrumb'\n key = arg.quasis[0].value.cooked ?? arg.quasis[0].value.raw;\n }\n\n if (!key) return;\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n fileHasDynamicCall = true;\n }\n },\n });\n\n programPath.traverse({\n /* Inspect every intlayer import */\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n // Mark that we do import from an intlayer package in this file\n state._hasValidImport = true;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (CALLER_LIST.includes(importedName as any)) {\n state._callerMap?.set(\n spec.local.name,\n importedName as (typeof CALLER_LIST)[number]\n );\n }\n\n const importMode = state.opts.importMode;\n // Determine whether this import should use the dynamic helpers.\n const shouldUseDynamicHelpers =\n (importMode === 'dynamic' ||\n importMode === 'fetch' ||\n fileHasDynamicCall) &&\n PACKAGE_LIST_DYNAMIC.includes(src as any);\n\n // Remember for later (CallExpression) whether we are using the dynamic helpers\n\n if (shouldUseDynamicHelpers) {\n state._useDynamicHelpers = true;\n }\n\n let helperMap: Record<string, string>;\n\n if (shouldUseDynamicHelpers) {\n // Use dynamic helpers for useIntlayer when dynamic mode is enabled\n helperMap = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n } as Record<string, string>;\n } else {\n // Use static helpers by default\n helperMap = STATIC_IMPORT_FUNCTION as Record<string, string>;\n }\n\n const newIdentifier = helperMap[importedName];\n\n // Only rewrite when we actually have a mapping for the imported\n // specifier (ignore unrelated named imports).\n\n if (newIdentifier) {\n // Keep the local alias intact (so calls remain `useIntlayer` /\n // `getIntlayer`), but rewrite the imported identifier so it\n // points to our helper implementation.\n spec.imported = t.identifier(newIdentifier);\n }\n }\n },\n\n /* Replace calls: useIntlayer(\"foo\") → useDictionary(_hash) or useDictionaryDynamic(_hash, \"foo\") */\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (!originalImportedName) return;\n\n // Ensure we ultimately emit helper imports for files that *invoke*\n // the hooks, even if they didn't import them directly (edge cases with\n // re-exports).\n state._hasValidImport = true;\n\n const arg = path.node.arguments[0];\n\n let key: string | undefined;\n\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n // If the bundler output is `breadcrumb` instead of 'breadcrumb'\n key = arg.quasis[0].value.cooked ?? arg.quasis[0].value.raw;\n }\n\n if (!key) return; // must be a static literal\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const useDynamicHelpers = Boolean(state._useDynamicHelpers);\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'\n let perCallMode: 'static' | 'dynamic' | 'fetch' = 'static';\n\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (isUseIntlayer && useDynamicHelpers) {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic') {\n perCallMode = 'dynamic';\n } else if (importMode === 'fetch') {\n perCallMode = 'fetch';\n }\n } else if (isUseIntlayer && !useDynamicHelpers) {\n // If dynamic helpers are NOT active (global mode is static),\n // we STILL might want to force dynamic/live for this specific call\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n perCallMode = dictionaryOverrideMode;\n }\n }\n\n let ident: BabelTypes.Identifier;\n\n if (perCallMode === 'fetch') {\n // Use fetch dictionaries entry (live mode for selected keys)\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n const hash = getFileHash(key);\n dynamicIdent = t.identifier(`_${hash}_fetch`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Helper: first argument is the dictionary entry, second is the key\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else if (perCallMode === 'dynamic') {\n // Use dynamic dictionaries entry\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n // Create a unique identifier for dynamic imports by appending a suffix\n const hash = getFileHash(key);\n dynamicIdent = t.identifier(`_${hash}_dyn`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Dynamic helper: first argument is the dictionary, second is the key.\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else {\n // Use static imports for getIntlayer or useIntlayer when not using dynamic helpers\n let staticIdent = state._newStaticImports?.get(key);\n\n if (!staticIdent) {\n staticIdent = makeIdent(key, t);\n state._newStaticImports?.set(key, staticIdent);\n }\n ident = staticIdent;\n\n // Static helper (useDictionary / getDictionary): replace key with iden\n path.node.arguments[0] = t.identifier(ident.name);\n }\n },\n });\n\n // Early-out if we touched nothing\n\n if (!state._hasValidImport) return;\n\n const file = state.file.opts.filename!;\n const dictionariesDir = state.opts.dictionariesDir;\n const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;\n const fetchDictionariesDir = state.opts.fetchDictionariesDir;\n const imports: BabelTypes.ImportDeclaration[] = [];\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static'\n );\n\n const importDeclarationNode = t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n );\n\n // Add 'type: json' attribute for JSON files\n importDeclarationNode.attributes = [\n t.importAttribute(t.identifier('type'), t.stringLiteral('json')),\n ];\n\n imports.push(importDeclarationNode);\n }\n\n // Generate dynamic/fetch imports (for useIntlayer when using dynamic/live helpers)\n for (const [key, ident] of state._newDynamicImports!) {\n const modeForThisIdent: 'dynamic' | 'fetch' = ident.name.endsWith(\n '_fetch'\n )\n ? 'fetch'\n : 'dynamic';\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n modeForThisIdent\n );\n imports.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n )\n );\n }\n\n if (!imports.length) return;\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n const bodyPaths = programPath.get(\n 'body'\n ) as NodePath<BabelTypes.Statement>[];\n let insertPos = 0;\n for (const stmtPath of bodyPaths) {\n const stmt = stmtPath.node;\n\n if (\n t.isExpressionStatement(stmt) &&\n t.isStringLiteral(stmt.expression) &&\n !stmt.expression.value.startsWith('import') &&\n !stmt.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n programPath.node.body.splice(insertPos, 0, ...imports);\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-optimize.mjs","names":[],"sources":["../../src/babel-plugin-intlayer-optimize.ts"],"sourcesContent":["import { dirname, join, relative } from 'node:path';\nimport type { NodePath, PluginObj, PluginPass } from '@babel/core';\nimport type * as BabelTypes from '@babel/types';\nimport { getPathHash } from '@intlayer/chokidar/utils';\nimport { normalizePath } from '@intlayer/config/utils';\n\nconst PACKAGE_LIST = [\n 'intlayer',\n '@intlayer/core',\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'svelte-intlayer',\n 'vue-intlayer',\n 'angular-intlayer',\n 'preact-intlayer',\n 'solid-intlayer',\n];\n\nconst CALLER_LIST = ['useIntlayer', 'getIntlayer'] as const;\n\n/**\n * Packages that support dynamic import\n */\nconst PACKAGE_LIST_DYNAMIC = [\n 'react-intlayer',\n 'react-intlayer/client',\n 'react-intlayer/server',\n 'next-intlayer',\n 'next-intlayer/client',\n 'next-intlayer/server',\n 'preact-intlayer',\n 'vue-intlayer',\n 'solid-intlayer',\n 'svelte-intlayer',\n 'angular-intlayer',\n] as const;\n\nconst STATIC_IMPORT_FUNCTION = {\n getIntlayer: 'getDictionary',\n useIntlayer: 'useDictionary',\n} as const;\n\nconst DYNAMIC_IMPORT_FUNCTION = {\n useIntlayer: 'useDictionaryDynamic',\n} as const;\n\n/**\n * Options for the optimization Babel plugin\n */\nexport type OptimizePluginOptions = {\n /**\n * If false, the plugin will not apply any transformation.\n */\n optimize?: boolean;\n /**\n * The path to the dictionaries directory.\n */\n dictionariesDir: string;\n /**\n * The path to the dictionaries entry file.\n */\n dictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries entry file.\n */\n unmergedDictionariesEntryPath: string;\n /**\n * The path to the unmerged dictionaries directory.\n */\n unmergedDictionariesDir: string;\n /**\n * The path to the dictionaries directory.\n */\n dynamicDictionariesDir: string;\n /**\n * The path to the dynamic dictionaries entry file.\n */\n dynamicDictionariesEntryPath: string;\n /**\n * The path to the fetch dictionaries directory.\n */\n fetchDictionariesDir: string;\n /**\n * The path to the fetch dictionaries entry file.\n */\n fetchDictionariesEntryPath: string;\n /**\n * If true, the plugin will replace the dictionary entry file with `export default {}`.\n */\n replaceDictionaryEntry: boolean;\n /**\n * If true, the plugin will activate the dynamic import of the dictionaries. It will rely on Suspense to load the dictionaries.\n */\n importMode: 'static' | 'dynamic' | 'fetch' | undefined;\n /**\n * Map of dictionary keys to their specific import mode.\n */\n dictionaryModeMap?: Record<\n string,\n 'static' | 'dynamic' | 'fetch' | undefined\n >;\n /**\n * Files list to traverse.\n */\n filesList: string[];\n};\n\ntype State = PluginPass & {\n opts: OptimizePluginOptions;\n /** map key → generated ident (per-file) for static imports */\n _newStaticImports?: Map<string, BabelTypes.Identifier>;\n /** map key → generated ident (per-file) for dynamic imports */\n _newDynamicImports?: Map<string, BabelTypes.Identifier>;\n /** whether the current file imported *any* intlayer package */\n _hasValidImport?: boolean;\n /** map from local identifier name to the imported intlayer func name ('useIntlayer' | 'getIntlayer') */\n _callerMap?: Map<string, (typeof CALLER_LIST)[number]>;\n /** whether the current file *is* the dictionaries entry file */\n _isDictEntry?: boolean;\n /** whether dynamic helpers are active for this file */\n _useDynamicHelpers?: boolean;\n /** whether the current file is included in the filesList */\n _isIncluded?: boolean;\n};\n\n/**\n * Replicates the xxHash64 → Base-62 algorithm used by the SWC version\n * and prefixes an underscore so the generated identifiers never collide\n * with user-defined ones.\n */\nconst makeIdent = (\n key: string,\n t: typeof BabelTypes\n): BabelTypes.Identifier => {\n const hash = getPathHash(key);\n return t.identifier(`_${hash}`);\n};\n\nconst computeImport = (\n fromFile: string,\n dictionariesDir: string,\n dynamicDictionariesDir: string,\n fetchDictionariesDir: string,\n key: string,\n importMode: 'static' | 'dynamic' | 'fetch'\n): string => {\n let relativePath = join(dictionariesDir, `${key}.json`);\n\n if (importMode === 'fetch') {\n relativePath = join(fetchDictionariesDir, `${key}.mjs`);\n }\n\n if (importMode === 'dynamic') {\n relativePath = join(dynamicDictionariesDir, `${key}.mjs`);\n }\n\n let rel = relative(dirname(fromFile), relativePath);\n\n // Fix windows path\n rel = normalizePath(rel);\n\n // Fix relative path\n if (!rel.startsWith('./') && !rel.startsWith('../')) {\n rel = `./${rel}`;\n }\n\n return rel;\n};\n\n/**\n * Babel plugin that transforms Intlayer function calls and auto-imports dictionaries.\n *\n * This plugin transforms calls to `useIntlayer()` and `getIntlayer()` from various Intlayer\n * packages into optimized dictionary access patterns, automatically importing the required\n * dictionary files based on the configured import mode.\n *\n * ## Supported Input Patterns\n *\n * The plugin recognizes these function calls:\n *\n * ```ts\n * // useIntlayer\n * import { useIntlayer } from 'react-intlayer';\n * import { useIntlayer } from 'next-intlayer';\n *\n * // getIntlayer\n * import { getIntlayer } from 'intlayer';\n *\n * // Usage\n * const content = useIntlayer('app');\n * const content = getIntlayer('app');\n * ```\n *\n * ## Transformation Modes\n *\n * ### Static Mode (default: `importMode = \"static\"`)\n *\n * Imports JSON dictionaries directly and replaces function calls with dictionary access:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import { useDictionary as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash);\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Dynamic Mode (`importMode = \"dynamic\"`)\n *\n * Uses dynamic dictionary loading with Suspense support:\n *\n * **Output:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * ### Live Mode (`importMode = \"live\"`)\n *\n * Uses live-based dictionary loading for remote dictionaries:\n *\n * **Output if `dictionaryModeMap` includes the key with \"live\" value:**\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_fetch from '../../.intlayer/fetch_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_fetch, \"app\");\n * const content2 = getIntlayer(_dicHash);\n * ```\n *\n * > If `dictionaryModeMap` does not include the key with \"live\" value, the plugin will fallback to the dynamic impor\n *\n * ```ts\n * import _dicHash from '../../.intlayer/dictionaries/app.json' with { type: 'json' };\n * import _dicHash_dyn from '../../.intlayer/dynamic_dictionaries/app.mjs';\n * import { useDictionaryDynamic as useIntlayer } from 'react-intlayer';\n * import { getDictionary as getIntlayer } from 'intlayer';\n *\n * const content1 = useIntlayer(_dicHash_dyn, 'app');\n * const content2 = getIntlayer(_dicHash);\n * ```\n */\nexport const intlayerOptimizeBabelPlugin = (babel: {\n types: typeof BabelTypes;\n}): PluginObj<State> => {\n const { types: t } = babel;\n\n return {\n name: 'babel-plugin-intlayer-transform',\n\n pre() {\n this._newStaticImports = new Map();\n this._newDynamicImports = new Map();\n this._callerMap = new Map();\n this._isIncluded = true;\n this._hasValidImport = false;\n this._isDictEntry = false;\n this._useDynamicHelpers = false;\n\n // If optimize is false, skip processing entirely\n if (this.opts.optimize === false) {\n this._isIncluded = false;\n return;\n }\n\n // If filesList is provided, check if current file is included\n const filename = this.file.opts.filename;\n if (this.opts.filesList && filename) {\n const isIncluded = this.opts.filesList.includes(filename);\n\n if (!isIncluded) {\n // Force _isIncluded to false to skip processing\n this._isIncluded = false;\n return;\n }\n }\n },\n\n visitor: {\n /* If this file *is* the dictionaries entry, short-circuit: export {} */\n Program: {\n enter(programPath, state) {\n // Safe access to filename\n const filename = state.file.opts.filename;\n\n // Check if this is the correct file to transform\n\n if (\n state.opts.replaceDictionaryEntry &&\n filename === state.opts.dictionariesEntryPath\n ) {\n state._isDictEntry = true;\n\n // Traverse the program to surgically remove/edit specific parts\n programPath.traverse({\n // Remove all import statements (cleaning up 'sssss.json')\n ImportDeclaration(path) {\n path.remove();\n },\n\n // Find the variable definition and empty the object\n VariableDeclarator(path) {\n // We look for: const x = { ... }\n\n if (t.isObjectExpression(path.node.init)) {\n // Set the object properties to an empty array: {}\n path.node.init.properties = [];\n }\n },\n });\n\n // (Optional) Stop other plugins from processing this file further if needed\n // programPath.stop();\n }\n },\n\n /**\n * After full traversal, process imports and call expressions, then inject the JSON dictionary imports.\n *\n * We do the transformation in Program.exit (via a manual traverse) rather than using\n * top-level ImportDeclaration/CallExpression visitors. This ensures that if another plugin\n * (like babel-plugin-intlayer-extract) adds new useIntlayer calls in its Program.exit,\n * we will see and transform them here because our Program.exit runs after theirs.\n */\n exit(programPath, state) {\n if (state._isDictEntry) return; // nothing else to do – already replaced\n\n if (!state._isIncluded) return; // early-out if file is not included\n\n // Manual traversal to process imports and call expressions\n // This runs AFTER all other plugins' visitors have completed\n\n // Pre-pass to determine if we should use dynamic helpers\n let fileHasDynamicCall = false;\n programPath.traverse({\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (originalImportedName !== 'useIntlayer') return;\n\n const arg = path.node.arguments[0];\n\n let key: string | undefined;\n\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n // If the bundler output is `breadcrumb` instead of 'breadcrumb'\n key = arg.quasis[0].value.cooked ?? arg.quasis[0].value.raw;\n }\n\n if (!key) return;\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n fileHasDynamicCall = true;\n }\n },\n });\n\n programPath.traverse({\n /* Inspect every intlayer import */\n ImportDeclaration(path) {\n const src = path.node.source.value;\n\n if (!PACKAGE_LIST.includes(src)) return;\n\n // Mark that we do import from an intlayer package in this file\n state._hasValidImport = true;\n\n for (const spec of path.node.specifiers) {\n if (!t.isImportSpecifier(spec)) continue;\n\n const importedName = t.isIdentifier(spec.imported)\n ? spec.imported.name\n : (spec.imported as BabelTypes.StringLiteral).value;\n\n if (CALLER_LIST.includes(importedName as any)) {\n state._callerMap?.set(\n spec.local.name,\n importedName as (typeof CALLER_LIST)[number]\n );\n }\n\n const importMode = state.opts.importMode;\n // Determine whether this import should use the dynamic helpers.\n const shouldUseDynamicHelpers =\n (importMode === 'dynamic' ||\n importMode === 'fetch' ||\n fileHasDynamicCall) &&\n PACKAGE_LIST_DYNAMIC.includes(src as any);\n\n // Remember for later (CallExpression) whether we are using the dynamic helpers\n\n if (shouldUseDynamicHelpers) {\n state._useDynamicHelpers = true;\n }\n\n let helperMap: Record<string, string>;\n\n if (shouldUseDynamicHelpers) {\n // Use dynamic helpers for useIntlayer when dynamic mode is enabled\n helperMap = {\n ...STATIC_IMPORT_FUNCTION,\n ...DYNAMIC_IMPORT_FUNCTION,\n } as Record<string, string>;\n } else {\n // Use static helpers by default\n helperMap = STATIC_IMPORT_FUNCTION as Record<string, string>;\n }\n\n const newIdentifier = helperMap[importedName];\n\n // Only rewrite when we actually have a mapping for the imported\n // specifier (ignore unrelated named imports).\n\n if (newIdentifier) {\n // Keep the local alias intact (so calls remain `useIntlayer` /\n // `getIntlayer`), but rewrite the imported identifier so it\n // points to our helper implementation.\n spec.imported = t.identifier(newIdentifier);\n }\n }\n },\n\n /* Replace calls: useIntlayer(\"foo\") → useDictionary(_hash) or useDictionaryDynamic(_hash, \"foo\") */\n CallExpression(path) {\n const callee = path.node.callee;\n\n if (!t.isIdentifier(callee)) return;\n\n const originalImportedName = state._callerMap?.get(callee.name);\n if (!originalImportedName) return;\n\n // Ensure we ultimately emit helper imports for files that *invoke*\n // the hooks, even if they didn't import them directly (edge cases with\n // re-exports).\n state._hasValidImport = true;\n\n const arg = path.node.arguments[0];\n\n let key: string | undefined;\n\n if (arg && t.isStringLiteral(arg)) {\n key = arg.value;\n } else if (\n arg &&\n t.isTemplateLiteral(arg) &&\n arg.expressions.length === 0 &&\n arg.quasis.length === 1\n ) {\n // If the bundler output is `breadcrumb` instead of 'breadcrumb'\n key = arg.quasis[0].value.cooked ?? arg.quasis[0].value.raw;\n }\n\n if (!key) return; // must be a static literal\n const importMode = state.opts.importMode;\n const isUseIntlayer = originalImportedName === 'useIntlayer';\n const useDynamicHelpers = Boolean(state._useDynamicHelpers);\n\n // Decide per-call mode: 'static' | 'dynamic' | 'fetch'\n let perCallMode: 'static' | 'dynamic' | 'fetch' = 'static';\n\n const dictionaryOverrideMode =\n state.opts.dictionaryModeMap?.[key];\n\n if (isUseIntlayer && useDynamicHelpers) {\n if (dictionaryOverrideMode) {\n perCallMode = dictionaryOverrideMode;\n } else if (importMode === 'dynamic') {\n perCallMode = 'dynamic';\n } else if (importMode === 'fetch') {\n perCallMode = 'fetch';\n }\n } else if (isUseIntlayer && !useDynamicHelpers) {\n // If dynamic helpers are NOT active (global mode is static),\n // we STILL might want to force dynamic/live for this specific call\n\n if (\n dictionaryOverrideMode === 'dynamic' ||\n dictionaryOverrideMode === 'fetch'\n ) {\n perCallMode = dictionaryOverrideMode;\n }\n }\n\n let ident: BabelTypes.Identifier;\n\n if (perCallMode === 'fetch') {\n // Use fetch dictionaries entry (live mode for selected keys)\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_fetch`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Helper: first argument is the dictionary entry, second is the key\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else if (perCallMode === 'dynamic') {\n // Use dynamic dictionaries entry\n let dynamicIdent = state._newDynamicImports?.get(key);\n\n if (!dynamicIdent) {\n // Create a unique identifier for dynamic imports by appending a suffix\n const hash = getPathHash(key);\n dynamicIdent = t.identifier(`_${hash}_dyn`);\n state._newDynamicImports?.set(key, dynamicIdent);\n }\n ident = dynamicIdent;\n\n // Dynamic helper: first argument is the dictionary, second is the key.\n path.node.arguments = [\n t.identifier(ident.name),\n ...path.node.arguments,\n ];\n } else {\n // Use static imports for getIntlayer or useIntlayer when not using dynamic helpers\n let staticIdent = state._newStaticImports?.get(key);\n\n if (!staticIdent) {\n staticIdent = makeIdent(key, t);\n state._newStaticImports?.set(key, staticIdent);\n }\n ident = staticIdent;\n\n // Static helper (useDictionary / getDictionary): replace key with iden\n path.node.arguments[0] = t.identifier(ident.name);\n }\n },\n });\n\n // Early-out if we touched nothing\n\n if (!state._hasValidImport) return;\n\n const file = state.file.opts.filename!;\n const dictionariesDir = state.opts.dictionariesDir;\n const dynamicDictionariesDir = state.opts.dynamicDictionariesDir;\n const fetchDictionariesDir = state.opts.fetchDictionariesDir;\n const imports: BabelTypes.ImportDeclaration[] = [];\n\n // Generate static JSON imports (getIntlayer always uses JSON dictionaries)\n for (const [key, ident] of state._newStaticImports!) {\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n 'static'\n );\n\n const importDeclarationNode = t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n );\n\n // Add 'type: json' attribute for JSON files\n importDeclarationNode.attributes = [\n t.importAttribute(t.identifier('type'), t.stringLiteral('json')),\n ];\n\n imports.push(importDeclarationNode);\n }\n\n // Generate dynamic/fetch imports (for useIntlayer when using dynamic/live helpers)\n for (const [key, ident] of state._newDynamicImports!) {\n const modeForThisIdent: 'dynamic' | 'fetch' = ident.name.endsWith(\n '_fetch'\n )\n ? 'fetch'\n : 'dynamic';\n\n const rel = computeImport(\n file,\n dictionariesDir,\n dynamicDictionariesDir,\n fetchDictionariesDir,\n key,\n modeForThisIdent\n );\n imports.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(ident.name))],\n t.stringLiteral(rel)\n )\n );\n }\n\n if (!imports.length) return;\n\n /* Keep \"use client\" / \"use server\" directives at the very top. */\n const bodyPaths = programPath.get(\n 'body'\n ) as NodePath<BabelTypes.Statement>[];\n let insertPos = 0;\n for (const stmtPath of bodyPaths) {\n const stmt = stmtPath.node;\n\n if (\n t.isExpressionStatement(stmt) &&\n t.isStringLiteral(stmt.expression) &&\n !stmt.expression.value.startsWith('import') &&\n !stmt.expression.value.startsWith('require')\n ) {\n insertPos += 1;\n } else {\n break;\n }\n }\n\n programPath.node.body.splice(insertPos, 0, ...imports);\n },\n },\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ATTRIBUTES_TO_EXTRACT as e}from"./utils/constants.mjs";import{getComponentName as t}from"./utils/getComponentName.mjs";import{getExistingIntlayerInfo as n}from"./utils/getExistingIntlayerInfo.mjs";import{getOrGenerateKey as r}from"./utils/getOrGenerateKey.mjs";import{resolveDictionaryKey as i}from"./utils/resolveDictionaryKey.mjs";import{shouldExtract as a}from"./utils/shouldExtract.mjs";import o from"@babel/traverse";import*as s from"@babel/types";const c=typeof o==`function`?o:o.default,l=(e,t,n,i,o,c,l)=>{let u=e.node.children;if(u.length<=1)return!1;let d=[],f=!1,p=!1;for(let e of u)if(s.isJSXText(e)){let t=e.value;t.trim().length>0&&(f=!0),d.push({type:`text`,value:t})}else if(s.isJSXExpressionContainer(e))if(s.isJSXEmptyExpression(e.expression))d.push({type:`text`,value:``});else{let n=e.expression;if(s.isIdentifier(n))d.push({type:`var`,value:n.name,originalExpr:n.name}),p=!0;else if(s.isMemberExpression(n)){let e=t.substring(n.start,n.end),r=s.isIdentifier(n.property)?n.property.name:`var`;d.push({type:`var`,value:r,originalExpr:e}),p=!0}else return!1}else return!1;if(!f)return!1;let m=``;for(let e of d)e.type===`var`?m+=`{{${e.value}}}`:m+=e.value;let h=m.replace(/\s+/g,` `).trim();if(a(h)){let t=i(e),a=r(h,t,n,o),s=d.filter(e=>e.type===`var`).map(e=>`${e.value}: ${e.originalExpr}`),f=Array.from(new Set(s));return p?c.push({path:e,key:a,type:`jsx-insertion`,componentKey:t,childrenToReplace:u,variables:f}):c.push({path:e,key:a,type:`jsx-text-combined`,componentKey:t,childrenToReplace:u}),u.forEach(e=>{l.add(e)}),!0}return!1},u=(o,u,d,f=`default`,p,m,h={})=>{let g={},_=[],v=new Set,y=new Map,b=new Map,x=new Set,S,C=[];c(o,{FunctionDeclaration(e){C.push(e)},ArrowFunctionExpression(e){C.push(e)},FunctionExpression(e){C.push(e)}});for(let e of C){let r=n(e);if(r)y.set(e.node,r.key),x.add(r.key),b.set(e.node,r.hook);else{S||(S=i(f,m,p,h,x),x.add(S)),y.set(e.node,S);let n=t(e),r=n?/^[A-Z]/.test(n):!1;b.set(e.node,r?`useIntlayer`:`getIntlayer`)}}let w=e=>{let t=e;for(;t;){if(y.has(t.node))return y.get(t.node);t=t.parentPath}return S||f};c(o,{JSXElement(e){v.has(e.node)||l(e,u,d,w,g,_,v)},JSXFragment(e){v.has(e.node)||l(e,u,d,w,g,_,v)},JSXText(e){if(v.has(e.node))return;let t=e.node.value;if(a(t)){let n=w(e),i=r(t.replace(/\s+/g,` `).trim(),n,d,g);_.push({path:e,key:i,type:`jsx-text`,componentKey:n})}},JSXAttribute(t){if(v.has(t.node))return;let n=t.node.name.name;if(typeof n!=`string`||!e.includes(n))return;let i=t.node.value;if(s.isStringLiteral(i)&&a(i.value)){let e=w(t),n=r(i.value.trim(),e,d,g);_.push({path:t,key:n,type:`jsx-attribute`,componentKey:e})}},StringLiteral(e){if(v.has(e.node))return;let t=e.node.value;if(!a(t))return;let n=e.parentPath;if(n.isImportDeclaration()||n.isImportSpecifier()||n.isExportDeclaration()||n.isJSXAttribute()||n.isCallExpression()&&s.isMemberExpression(n.node.callee)&&s.isIdentifier(n.node.callee.object)&&n.node.callee.object.name===`console`&&s.isIdentifier(n.node.callee.property)&&n.node.callee.property.name===`log`||n.isObjectProperty()&&n.node.key===e.node||n.isMemberExpression()&&n.node.property===e.node)return;let i=w(e),o=r(t.trim(),i,d,g);_.push({path:e,key:o,type:`string-literal`,componentKey:i})}});let T=new Set;for(let e of C)if(_.some(t=>{let n=t.path;for(;n;){if(n.node===e.node)return!0;n=n.parentPath}return!1})){let t=y.get(e.node),r=!1,i=e.parentPath;for(;i;){let e=C.find(e=>e.node===i?.node);if(e&&y.get(e.node)===t){let t=_.some(t=>{let n=t.path;for(;n;){if(n.node===e.node)return!0;n=n.parentPath}return!1}),i=n(e);if(t||i){r=!0;break}}i=i.parentPath}r||T.add(e)}return{extractedContent:g,replacements:_,componentsNeedingHooks:T,componentKeyMap:y,componentPaths:C,hookMap:b,isSolid:!1}},d=(e,t,n,r,i,a={})=>{let{extractedContent:o,replacements:s}=u(e,t,n,`default`,r,i,a),c={};for(let e of Object.values(o))Object.assign(c,e);return{extractedContent:c,replacements:s}};export{u as extractBabelContentForComponents,d as extractTsContent,l as handleJsxInsertionBabel};
|
|
2
|
+
//# sourceMappingURL=babelProcessor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"babelProcessor.mjs","names":[],"sources":["../../../src/extractContent/babelProcessor.ts"],"sourcesContent":["import _traverse, { type NodePath } from '@babel/traverse';\nimport * as t from '@babel/types';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { resolveDictionaryKey } from '../extractContent/utils';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n getComponentName,\n getExistingIntlayerInfo,\n getOrGenerateKey,\n shouldExtract,\n} from './utils';\n\nexport type BabelReplacement = {\n path: NodePath;\n key: string;\n type:\n | 'jsx-text'\n | 'jsx-attribute'\n | 'string-literal'\n | 'jsx-insertion'\n | 'jsx-text-combined';\n componentKey: string;\n childrenToReplace?: t.Node[];\n variables?: string[];\n};\n\n// CJS/ESM interop: @babel/traverse exports its function as `.default` in CJS bundles\nconst traverse = (\n typeof _traverse === 'function' ? _traverse : (_traverse as any).default\n) as typeof _traverse;\n\n/**\n * Handles JSX insertions (elements with multiple children, including expressions).\n * Replaces complex JSX structures with variable-based translations.\n */\nexport const handleJsxInsertionBabel = (\n path: NodePath<t.JSXElement | t.JSXFragment>,\n fileCode: string,\n existingKeys: Set<string>,\n getComponentKeyForPath: (path: NodePath) => string,\n extractedContent: Record<string, Record<string, string>>,\n replacements: BabelReplacement[],\n handledNodes: Set<t.Node>\n): boolean => {\n const children = path.node.children;\n\n if (children.length <= 1) return false;\n\n const parts: {\n type: 'text' | 'var';\n value: string;\n originalExpr?: string;\n }[] = [];\n let hasSignificantText = false;\n let hasVariables = false;\n\n for (const child of children) {\n if (t.isJSXText(child)) {\n const text = child.value;\n\n if (text.trim().length > 0) hasSignificantText = true;\n\n parts.push({ type: 'text', value: text });\n } else if (t.isJSXExpressionContainer(child)) {\n if (t.isJSXEmptyExpression(child.expression)) {\n parts.push({ type: 'text', value: '' });\n } else {\n const expr = child.expression;\n\n if (t.isIdentifier(expr)) {\n parts.push({\n type: 'var',\n value: expr.name,\n originalExpr: expr.name,\n });\n hasVariables = true;\n } else if (t.isMemberExpression(expr)) {\n const code = fileCode.substring(expr.start!, expr.end!);\n\n const varName = t.isIdentifier(expr.property)\n ? expr.property.name\n : 'var';\n\n parts.push({ type: 'var', value: varName, originalExpr: code });\n\n hasVariables = true;\n } else {\n return false;\n }\n }\n } else {\n return false;\n }\n }\n\n if (!hasSignificantText) return false;\n\n let combinedString = '';\n for (const part of parts) {\n if (part.type === 'var') combinedString += `{{${part.value}}}`;\n else combinedString += part.value;\n }\n\n const cleanString = combinedString.replace(/\\s+/g, ' ').trim();\n\n if (shouldExtract(cleanString)) {\n const componentKey = getComponentKeyForPath(path);\n const key = getOrGenerateKey(\n cleanString,\n componentKey,\n existingKeys,\n extractedContent\n );\n\n const varMap = parts\n .filter((part) => part.type === 'var')\n .map((part) => `${part.value}: ${part.originalExpr}`);\n const uniqueVars = Array.from(new Set(varMap));\n\n if (hasVariables) {\n replacements.push({\n path,\n key,\n type: 'jsx-insertion',\n componentKey,\n childrenToReplace: children,\n variables: uniqueVars,\n });\n } else {\n replacements.push({\n path,\n key,\n type: 'jsx-text-combined',\n componentKey,\n childrenToReplace: children,\n });\n }\n\n children.forEach((child) => {\n handledNodes.add(child);\n });\n return true;\n }\n\n return false;\n};\n\n/**\n * Traverses the AST to identify components and extract content.\n * Returns extraction results and metadata about which components need Intlayer hooks.\n */\nexport const extractBabelContentForComponents = (\n ast: t.File,\n fileCode: string,\n existingKeys: Set<string>,\n defaultKey: string = 'default',\n configuration: IntlayerConfig,\n filePath: string,\n unmergedDictionaries: Record<string, unknown> = {}\n): {\n extractedContent: Record<string, Record<string, string>>;\n replacements: BabelReplacement[];\n componentsNeedingHooks: Set<NodePath>;\n componentKeyMap: Map<t.Node, string>;\n componentPaths: NodePath[];\n hookMap: Map<t.Node, 'useIntlayer' | 'getIntlayer'>;\n isSolid: boolean;\n} => {\n const extractedContent: Record<string, Record<string, string>> = {};\n const replacements: BabelReplacement[] = [];\n const handledNodes = new Set<t.Node>();\n const componentKeyMap = new Map<t.Node, string>();\n const hookMap = new Map<t.Node, 'useIntlayer' | 'getIntlayer'>();\n const usedKeysInFile = new Set<string>();\n let globalFileKey: string | undefined;\n\n const componentPaths: NodePath[] = [];\n\n traverse(ast, {\n FunctionDeclaration(path) {\n componentPaths.push(path);\n },\n ArrowFunctionExpression(path) {\n componentPaths.push(path);\n },\n FunctionExpression(path) {\n componentPaths.push(path);\n },\n });\n\n for (const path of componentPaths) {\n const existingInfo = getExistingIntlayerInfo(path);\n\n if (existingInfo) {\n componentKeyMap.set(path.node, existingInfo.key);\n usedKeysInFile.add(existingInfo.key);\n hookMap.set(path.node, existingInfo.hook);\n } else {\n if (!globalFileKey) {\n globalFileKey = resolveDictionaryKey(\n defaultKey,\n filePath,\n configuration,\n unmergedDictionaries,\n usedKeysInFile\n );\n usedKeysInFile.add(globalFileKey);\n }\n componentKeyMap.set(path.node, globalFileKey);\n\n const compName = getComponentName(path);\n const isComponent = compName ? /^[A-Z]/.test(compName) : false;\n hookMap.set(path.node, isComponent ? 'useIntlayer' : 'getIntlayer');\n }\n }\n\n const getComponentKeyForPath = (path: NodePath): string => {\n let current: NodePath | null = path;\n while (current) {\n if (componentKeyMap.has(current.node)) {\n return componentKeyMap.get(current.node)!;\n }\n current = current.parentPath;\n }\n return globalFileKey || defaultKey;\n };\n\n traverse(ast, {\n JSXElement(path) {\n if (handledNodes.has(path.node)) return;\n\n handleJsxInsertionBabel(\n path,\n fileCode,\n existingKeys,\n getComponentKeyForPath,\n extractedContent,\n replacements,\n handledNodes\n );\n },\n JSXFragment(path) {\n if (handledNodes.has(path.node)) return;\n\n handleJsxInsertionBabel(\n path,\n fileCode,\n existingKeys,\n getComponentKeyForPath,\n extractedContent,\n replacements,\n handledNodes\n );\n },\n JSXText(path) {\n if (handledNodes.has(path.node)) return;\n\n const text = path.node.value;\n\n if (shouldExtract(text)) {\n const componentKey = getComponentKeyForPath(path);\n const key = getOrGenerateKey(\n text.replace(/\\s+/g, ' ').trim(),\n componentKey,\n existingKeys,\n extractedContent\n );\n replacements.push({ path, key, type: 'jsx-text', componentKey });\n }\n },\n JSXAttribute(path) {\n if (handledNodes.has(path.node)) return;\n\n const name = path.node.name.name;\n\n if (\n typeof name !== 'string' ||\n !ATTRIBUTES_TO_EXTRACT.includes(name as any)\n )\n return;\n const value = path.node.value;\n\n if (t.isStringLiteral(value) && shouldExtract(value.value)) {\n const componentKey = getComponentKeyForPath(path);\n const key = getOrGenerateKey(\n value.value.trim(),\n componentKey,\n existingKeys,\n extractedContent\n );\n replacements.push({ path, key, type: 'jsx-attribute', componentKey });\n }\n },\n StringLiteral(path) {\n if (handledNodes.has(path.node)) return;\n\n const text = path.node.value;\n\n if (!shouldExtract(text)) return;\n\n const parent = path.parentPath;\n\n if (\n parent.isImportDeclaration() ||\n parent.isImportSpecifier() ||\n parent.isExportDeclaration()\n )\n return;\n\n if (parent.isJSXAttribute()) return;\n\n if (\n parent.isCallExpression() &&\n t.isMemberExpression(parent.node.callee)\n ) {\n if (\n t.isIdentifier(parent.node.callee.object) &&\n parent.node.callee.object.name === 'console' &&\n t.isIdentifier(parent.node.callee.property) &&\n parent.node.callee.property.name === 'log'\n ) {\n return;\n }\n }\n\n if (parent.isObjectProperty() && parent.node.key === path.node) return;\n\n if (parent.isMemberExpression() && parent.node.property === path.node)\n return;\n\n const componentKey = getComponentKeyForPath(path);\n const key = getOrGenerateKey(\n text.trim(),\n componentKey,\n existingKeys,\n extractedContent\n );\n replacements.push({ path, key, type: 'string-literal', componentKey });\n },\n });\n\n const componentsNeedingHooks = new Set<NodePath>();\n for (const componentPath of componentPaths) {\n const hasReplacements = replacements.some((replacement) => {\n let current: NodePath | null = replacement.path;\n while (current) {\n if (current.node === componentPath.node) return true;\n\n current = current.parentPath;\n }\n return false;\n });\n\n if (hasReplacements) {\n const key = componentKeyMap.get(componentPath.node)!;\n let ancestorProvidesKey = false;\n let currentPath: NodePath | null = componentPath.parentPath;\n while (currentPath) {\n const ancestorPath = componentPaths.find(\n (path) => path.node === currentPath?.node\n );\n\n if (ancestorPath) {\n const ancestorKey = componentKeyMap.get(ancestorPath.node);\n\n if (ancestorKey === key) {\n const ancestorHasReplacements = replacements.some((replacement) => {\n let rPath: NodePath | null = replacement.path;\n while (rPath) {\n if (rPath.node === ancestorPath.node) return true;\n\n rPath = rPath.parentPath;\n }\n return false;\n });\n const existingInfo = getExistingIntlayerInfo(ancestorPath);\n\n if (ancestorHasReplacements || existingInfo) {\n ancestorProvidesKey = true;\n break;\n }\n }\n }\n currentPath = currentPath.parentPath;\n }\n\n if (!ancestorProvidesKey) {\n componentsNeedingHooks.add(componentPath);\n }\n }\n }\n\n return {\n extractedContent,\n replacements,\n componentsNeedingHooks,\n componentKeyMap,\n componentPaths,\n hookMap,\n isSolid: false,\n };\n};\n\n/**\n * High-level function to extract content from TS/JS/JSX/TSX AST.\n */\nexport const extractTsContent = (\n ast: t.File,\n fileCode: string,\n existingKeys: Set<string>,\n configuration: IntlayerConfig,\n filePath: string,\n unmergedDictionaries: Record<string, unknown> = {}\n): {\n extractedContent: Record<string, string>;\n replacements: BabelReplacement[];\n} => {\n const { extractedContent, replacements } = extractBabelContentForComponents(\n ast,\n fileCode,\n existingKeys,\n 'default',\n configuration,\n filePath,\n unmergedDictionaries\n );\n\n const flatContent: Record<string, string> = {};\n for (const group of Object.values(extractedContent)) {\n Object.assign(flatContent, group);\n }\n\n return { extractedContent: flatContent, replacements };\n};\n"],"mappings":"4cA2BA,MAAM,EACJ,OAAO,GAAc,WAAa,EAAa,EAAkB,QAOtD,GACX,EACA,EACA,EACA,EACA,EACA,EACA,IACY,CACZ,IAAM,EAAW,EAAK,KAAK,SAE3B,GAAI,EAAS,QAAU,EAAG,MAAO,GAEjC,IAAM,EAIA,EAAE,CACJ,EAAqB,GACrB,EAAe,GAEnB,IAAK,IAAM,KAAS,EAClB,GAAI,EAAE,UAAU,EAAM,CAAE,CACtB,IAAM,EAAO,EAAM,MAEf,EAAK,MAAM,CAAC,OAAS,IAAG,EAAqB,IAEjD,EAAM,KAAK,CAAE,KAAM,OAAQ,MAAO,EAAM,CAAC,SAChC,EAAE,yBAAyB,EAAM,CAC1C,GAAI,EAAE,qBAAqB,EAAM,WAAW,CAC1C,EAAM,KAAK,CAAE,KAAM,OAAQ,MAAO,GAAI,CAAC,KAClC,CACL,IAAM,EAAO,EAAM,WAEnB,GAAI,EAAE,aAAa,EAAK,CACtB,EAAM,KAAK,CACT,KAAM,MACN,MAAO,EAAK,KACZ,aAAc,EAAK,KACpB,CAAC,CACF,EAAe,WACN,EAAE,mBAAmB,EAAK,CAAE,CACrC,IAAM,EAAO,EAAS,UAAU,EAAK,MAAQ,EAAK,IAAK,CAEjD,EAAU,EAAE,aAAa,EAAK,SAAS,CACzC,EAAK,SAAS,KACd,MAEJ,EAAM,KAAK,CAAE,KAAM,MAAO,MAAO,EAAS,aAAc,EAAM,CAAC,CAE/D,EAAe,QAEf,MAAO,QAIX,MAAO,GAIX,GAAI,CAAC,EAAoB,MAAO,GAEhC,IAAI,EAAiB,GACrB,IAAK,IAAM,KAAQ,EACb,EAAK,OAAS,MAAO,GAAkB,KAAK,EAAK,MAAM,IACtD,GAAkB,EAAK,MAG9B,IAAM,EAAc,EAAe,QAAQ,OAAQ,IAAI,CAAC,MAAM,CAE9D,GAAI,EAAc,EAAY,CAAE,CAC9B,IAAM,EAAe,EAAuB,EAAK,CAC3C,EAAM,EACV,EACA,EACA,EACA,EACD,CAEK,EAAS,EACZ,OAAQ,GAAS,EAAK,OAAS,MAAM,CACrC,IAAK,GAAS,GAAG,EAAK,MAAM,IAAI,EAAK,eAAe,CACjD,EAAa,MAAM,KAAK,IAAI,IAAI,EAAO,CAAC,CAwB9C,OAtBI,EACF,EAAa,KAAK,CAChB,OACA,MACA,KAAM,gBACN,eACA,kBAAmB,EACnB,UAAW,EACZ,CAAC,CAEF,EAAa,KAAK,CAChB,OACA,MACA,KAAM,oBACN,eACA,kBAAmB,EACpB,CAAC,CAGJ,EAAS,QAAS,GAAU,CAC1B,EAAa,IAAI,EAAM,EACvB,CACK,GAGT,MAAO,IAOI,GACX,EACA,EACA,EACA,EAAqB,UACrB,EACA,EACA,EAAgD,EAAE,GAS/C,CACH,IAAM,EAA2D,EAAE,CAC7D,EAAmC,EAAE,CACrC,EAAe,IAAI,IACnB,EAAkB,IAAI,IACtB,EAAU,IAAI,IACd,EAAiB,IAAI,IACvB,EAEE,EAA6B,EAAE,CAErC,EAAS,EAAK,CACZ,oBAAoB,EAAM,CACxB,EAAe,KAAK,EAAK,EAE3B,wBAAwB,EAAM,CAC5B,EAAe,KAAK,EAAK,EAE3B,mBAAmB,EAAM,CACvB,EAAe,KAAK,EAAK,EAE5B,CAAC,CAEF,IAAK,IAAM,KAAQ,EAAgB,CACjC,IAAM,EAAe,EAAwB,EAAK,CAElD,GAAI,EACF,EAAgB,IAAI,EAAK,KAAM,EAAa,IAAI,CAChD,EAAe,IAAI,EAAa,IAAI,CACpC,EAAQ,IAAI,EAAK,KAAM,EAAa,KAAK,KACpC,CACA,IACH,EAAgB,EACd,EACA,EACA,EACA,EACA,EACD,CACD,EAAe,IAAI,EAAc,EAEnC,EAAgB,IAAI,EAAK,KAAM,EAAc,CAE7C,IAAM,EAAW,EAAiB,EAAK,CACjC,EAAc,EAAW,SAAS,KAAK,EAAS,CAAG,GACzD,EAAQ,IAAI,EAAK,KAAM,EAAc,cAAgB,cAAc,EAIvE,IAAM,EAA0B,GAA2B,CACzD,IAAI,EAA2B,EAC/B,KAAO,GAAS,CACd,GAAI,EAAgB,IAAI,EAAQ,KAAK,CACnC,OAAO,EAAgB,IAAI,EAAQ,KAAK,CAE1C,EAAU,EAAQ,WAEpB,OAAO,GAAiB,GAG1B,EAAS,EAAK,CACZ,WAAW,EAAM,CACX,EAAa,IAAI,EAAK,KAAK,EAE/B,EACE,EACA,EACA,EACA,EACA,EACA,EACA,EACD,EAEH,YAAY,EAAM,CACZ,EAAa,IAAI,EAAK,KAAK,EAE/B,EACE,EACA,EACA,EACA,EACA,EACA,EACA,EACD,EAEH,QAAQ,EAAM,CACZ,GAAI,EAAa,IAAI,EAAK,KAAK,CAAE,OAEjC,IAAM,EAAO,EAAK,KAAK,MAEvB,GAAI,EAAc,EAAK,CAAE,CACvB,IAAM,EAAe,EAAuB,EAAK,CAC3C,EAAM,EACV,EAAK,QAAQ,OAAQ,IAAI,CAAC,MAAM,CAChC,EACA,EACA,EACD,CACD,EAAa,KAAK,CAAE,OAAM,MAAK,KAAM,WAAY,eAAc,CAAC,GAGpE,aAAa,EAAM,CACjB,GAAI,EAAa,IAAI,EAAK,KAAK,CAAE,OAEjC,IAAM,EAAO,EAAK,KAAK,KAAK,KAE5B,GACE,OAAO,GAAS,UAChB,CAAC,EAAsB,SAAS,EAAY,CAE5C,OACF,IAAM,EAAQ,EAAK,KAAK,MAExB,GAAI,EAAE,gBAAgB,EAAM,EAAI,EAAc,EAAM,MAAM,CAAE,CAC1D,IAAM,EAAe,EAAuB,EAAK,CAC3C,EAAM,EACV,EAAM,MAAM,MAAM,CAClB,EACA,EACA,EACD,CACD,EAAa,KAAK,CAAE,OAAM,MAAK,KAAM,gBAAiB,eAAc,CAAC,GAGzE,cAAc,EAAM,CAClB,GAAI,EAAa,IAAI,EAAK,KAAK,CAAE,OAEjC,IAAM,EAAO,EAAK,KAAK,MAEvB,GAAI,CAAC,EAAc,EAAK,CAAE,OAE1B,IAAM,EAAS,EAAK,WA2BpB,GAxBE,EAAO,qBAAqB,EAC5B,EAAO,mBAAmB,EAC1B,EAAO,qBAAqB,EAI1B,EAAO,gBAAgB,EAGzB,EAAO,kBAAkB,EACzB,EAAE,mBAAmB,EAAO,KAAK,OAAO,EAGtC,EAAE,aAAa,EAAO,KAAK,OAAO,OAAO,EACzC,EAAO,KAAK,OAAO,OAAO,OAAS,WACnC,EAAE,aAAa,EAAO,KAAK,OAAO,SAAS,EAC3C,EAAO,KAAK,OAAO,SAAS,OAAS,OAMrC,EAAO,kBAAkB,EAAI,EAAO,KAAK,MAAQ,EAAK,MAEtD,EAAO,oBAAoB,EAAI,EAAO,KAAK,WAAa,EAAK,KAC/D,OAEF,IAAM,EAAe,EAAuB,EAAK,CAC3C,EAAM,EACV,EAAK,MAAM,CACX,EACA,EACA,EACD,CACD,EAAa,KAAK,CAAE,OAAM,MAAK,KAAM,iBAAkB,eAAc,CAAC,EAEzE,CAAC,CAEF,IAAM,EAAyB,IAAI,IACnC,IAAK,IAAM,KAAiB,EAW1B,GAVwB,EAAa,KAAM,GAAgB,CACzD,IAAI,EAA2B,EAAY,KAC3C,KAAO,GAAS,CACd,GAAI,EAAQ,OAAS,EAAc,KAAM,MAAO,GAEhD,EAAU,EAAQ,WAEpB,MAAO,IACP,CAEmB,CACnB,IAAM,EAAM,EAAgB,IAAI,EAAc,KAAK,CAC/C,EAAsB,GACtB,EAA+B,EAAc,WACjD,KAAO,GAAa,CAClB,IAAM,EAAe,EAAe,KACjC,GAAS,EAAK,OAAS,GAAa,KACtC,CAED,GAAI,GACkB,EAAgB,IAAI,EAAa,KAAK,GAEtC,EAAK,CACvB,IAAM,EAA0B,EAAa,KAAM,GAAgB,CACjE,IAAI,EAAyB,EAAY,KACzC,KAAO,GAAO,CACZ,GAAI,EAAM,OAAS,EAAa,KAAM,MAAO,GAE7C,EAAQ,EAAM,WAEhB,MAAO,IACP,CACI,EAAe,EAAwB,EAAa,CAE1D,GAAI,GAA2B,EAAc,CAC3C,EAAsB,GACtB,OAIN,EAAc,EAAY,WAGvB,GACH,EAAuB,IAAI,EAAc,CAK/C,MAAO,CACL,mBACA,eACA,yBACA,kBACA,iBACA,UACA,QAAS,GACV,EAMU,GACX,EACA,EACA,EACA,EACA,EACA,EAAgD,EAAE,GAI/C,CACH,GAAM,CAAE,mBAAkB,gBAAiB,EACzC,EACA,EACA,EACA,UACA,EACA,EACA,EACD,CAEK,EAAsC,EAAE,CAC9C,IAAK,IAAM,KAAS,OAAO,OAAO,EAAiB,CACjD,OAAO,OAAO,EAAa,EAAM,CAGnC,MAAO,CAAE,iBAAkB,EAAa,eAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{basename as e,dirname as t,extname as n,join as r,relative as i,resolve as a}from"node:path";import{writeContentDeclaration as o}from"@intlayer/chokidar/cli";import{getUnmergedDictionaries as s}from"@intlayer/unmerged-dictionaries-entry";const c=(o,c,l,u)=>{let{baseDir:d,fileExtensions:f}=l.content,p=(s(l)??{})[c];if(p?.[0]?.filePath)return{contentFilePath:a(d,p[0].filePath),relativeContentFilePath:p[0].filePath};let m=u?a(u):t(o),h=f[0],g=h.startsWith(`.`)?h:`.${h}`,_=e(o,n(o)),v=r(m,`${_.charAt(0).toLowerCase()+_.slice(1)}${g}`);return{contentFilePath:v,relativeContentFilePath:i(d,v)}},l=(e,t,n,r)=>{let{defaultLocale:i}=r.internationalization;if(r?.dictionary?.locale)return{key:t,content:e,locale:i,filePath:n};let a={};for(let[t,n]of Object.entries(e))a[t]={nodeType:`translation`,translation:{[i]:n}};return{key:t,content:a,filePath:n}},u=async(e,n,r,a,s)=>{let{contentFilePath:u,relativeContentFilePath:d}=c(r,n,a,s);return await o(l(e,n,d,a),a,{newDictionariesPath:i(a.content.baseDir,t(u))}),u};export{l as createDictionary,c as resolveContentFilePath,u as writeContentHelper};
|
|
2
|
+
//# sourceMappingURL=contentWriter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentWriter.mjs","names":[],"sources":["../../../src/extractContent/contentWriter.ts"],"sourcesContent":["import { basename, dirname, extname, join, relative, resolve } from 'node:path';\nimport { writeContentDeclaration } from '@intlayer/chokidar/cli';\nimport type {\n Dictionary,\n DictionaryKey,\n IntlayerConfig,\n} from '@intlayer/types';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\n\nexport type TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Resolves the path for the content file associated with a component.\n * Checks for existing dictionaries first.\n */\nexport const resolveContentFilePath = (\n filePath: string,\n componentKey: string,\n configuration: IntlayerConfig,\n outputDir?: string\n): { contentFilePath: string; relativeContentFilePath: string } => {\n const { baseDir, fileExtensions } = configuration.content;\n const unmergedDictionaries = getUnmergedDictionaries(configuration) ?? {};\n const existingDicts = unmergedDictionaries[componentKey] as\n | Dictionary[]\n | undefined;\n\n if (existingDicts?.[0]?.filePath) {\n return {\n contentFilePath: resolve(baseDir, existingDicts[0].filePath),\n relativeContentFilePath: existingDicts[0].filePath,\n };\n }\n\n const dirName = outputDir ? resolve(outputDir) : dirname(filePath);\n const firstExtension = fileExtensions[0];\n const extension = firstExtension.startsWith('.')\n ? firstExtension\n : `.${firstExtension}`;\n const originalFileBase = basename(filePath, extname(filePath));\n const contentBaseName =\n originalFileBase.charAt(0).toLowerCase() + originalFileBase.slice(1);\n const contentFilePath = join(dirName, `${contentBaseName}${extension}`);\n const relativeContentFilePath = relative(baseDir, contentFilePath);\n\n return { contentFilePath, relativeContentFilePath };\n};\n\n/**\n * Creates a dictionary object from extracted content.\n * Handles both single-locale and multi-locale formats based on configuration.\n */\nexport const createDictionary = (\n extractedContent: Record<string, string>,\n componentKey: string,\n relativeContentFilePath: string,\n configuration: IntlayerConfig\n): Dictionary => {\n const { defaultLocale } = configuration.internationalization;\n const isPerLocaleFile = configuration?.dictionary?.locale;\n\n if (isPerLocaleFile) {\n return {\n key: componentKey,\n content: extractedContent,\n locale: defaultLocale,\n filePath: relativeContentFilePath,\n } as Dictionary;\n }\n\n const multilingualContent: Record<string, TranslationNode> = {};\n\n for (const [key, value] of Object.entries(extractedContent)) {\n multilingualContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n\n return {\n key: componentKey as DictionaryKey,\n content: multilingualContent,\n filePath: relativeContentFilePath,\n } as Dictionary;\n};\n\n/**\n * Helper to write extracted content to a dictionary file.\n */\nexport const writeContentHelper = async (\n extractedContent: Record<string, string>,\n componentKey: string,\n filePath: string,\n configuration: IntlayerConfig,\n outputDir?: string\n): Promise<string> => {\n const { contentFilePath, relativeContentFilePath } = resolveContentFilePath(\n filePath,\n componentKey,\n configuration,\n outputDir\n );\n\n const dictionary = createDictionary(\n extractedContent,\n componentKey,\n relativeContentFilePath,\n configuration\n );\n\n const relativeDir = relative(\n configuration.content.baseDir,\n dirname(contentFilePath)\n );\n\n await writeContentDeclaration(dictionary, configuration, {\n newDictionariesPath: relativeDir,\n });\n\n return contentFilePath;\n};\n"],"mappings":"qPAkBA,MAAa,GACX,EACA,EACA,EACA,IACiE,CACjE,GAAM,CAAE,UAAS,kBAAmB,EAAc,QAE5C,GADuB,EAAwB,EAAc,EAAI,EAAE,EAC9B,GAI3C,GAAI,IAAgB,IAAI,SACtB,MAAO,CACL,gBAAiB,EAAQ,EAAS,EAAc,GAAG,SAAS,CAC5D,wBAAyB,EAAc,GAAG,SAC3C,CAGH,IAAM,EAAU,EAAY,EAAQ,EAAU,CAAG,EAAQ,EAAS,CAC5D,EAAiB,EAAe,GAChC,EAAY,EAAe,WAAW,IAAI,CAC5C,EACA,IAAI,IACF,EAAmB,EAAS,EAAU,EAAQ,EAAS,CAAC,CAGxD,EAAkB,EAAK,EAAS,GADpC,EAAiB,OAAO,EAAE,CAAC,aAAa,CAAG,EAAiB,MAAM,EAAE,GACX,IAAY,CAGvE,MAAO,CAAE,kBAAiB,wBAFM,EAAS,EAAS,EAAgB,CAEf,EAOxC,GACX,EACA,EACA,EACA,IACe,CACf,GAAM,CAAE,iBAAkB,EAAc,qBAGxC,GAFwB,GAAe,YAAY,OAGjD,MAAO,CACL,IAAK,EACL,QAAS,EACT,OAAQ,EACR,SAAU,EACX,CAGH,IAAM,EAAuD,EAAE,CAE/D,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAiB,CACzD,EAAoB,GAAO,CACzB,SAAU,cACV,YAAa,EACV,GAAgB,EAClB,CACF,CAGH,MAAO,CACL,IAAK,EACL,QAAS,EACT,SAAU,EACX,EAMU,EAAqB,MAChC,EACA,EACA,EACA,EACA,IACoB,CACpB,GAAM,CAAE,kBAAiB,2BAA4B,EACnD,EACA,EACA,EACA,EACD,CAkBD,OAJA,MAAM,EAZa,EACjB,EACA,EACA,EACA,EACD,CAOyC,EAAe,CACvD,oBANkB,EAClB,EAAc,QAAQ,QACtB,EAAQ,EAAgB,CACzB,CAIA,CAAC,CAEK"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ATTRIBUTES_TO_EXTRACT as e}from"./utils/constants.mjs";import{extractDictionaryKey as t,extractDictionaryKeyFromPath as n}from"./utils/extractDictionaryKey.mjs";import{generateKey as r}from"./utils/generateKey.mjs";import{shouldExtract as i}from"./utils/shouldExtract.mjs";import{extractTsContent as a}from"./babelProcessor.mjs";import{processTsxFile as o}from"./processTsxFile.mjs";import{writeContentHelper as s}from"./contentWriter.mjs";import{basename as c,extname as l,relative as u}from"node:path";import{getConfiguration as d}from"@intlayer/config/node";import{execSync as f}from"node:child_process";import{readFileSync as p}from"node:fs";import{detectFormatCommand as m}from"@intlayer/chokidar/cli";import{getUnmergedDictionaries as h}from"@intlayer/unmerged-dictionaries-entry";import{ANSIColors as g,colorizePath as _,getAppLogger as v}from"@intlayer/config/logger";let y=null,b=null;const x=async(x,S,C)=>{let w=!C?.declarationOnly,T=!C?.codeOnly&&!C?.onExtract,E=C?.configuration??d(C?.configOptions),D=v(E),{baseDir:O}=E.content,k=C?.unmergedDictionaries??h(E),A=C?.code??p(x,`utf-8`),j=t(x,A),M=l(x);c(x,M);let N=u(O,x),P=null,F=null;if(M===`.vue`)try{y??=await import(`@intlayer/vue-compiler`);let t=await y.processVueFile(x,j,S,{generateKey:r,shouldExtract:i,attributesToExtract:e,extractDictionaryKeyFromPath:n,extractTsContent:(e,t,n,r,i)=>a(e,t,n,r,i,k)},w);t&&(P={[j]:t})}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`||e.message?.includes(`Cannot find module`)?Error(`Please install ${_(`@intlayer/vue-compiler`,g.YELLOW)} to process Vue files.`):e}else if(M===`.svelte`)try{b??=await import(`@intlayer/svelte-compiler`);let t=await b.processSvelteFile(x,j,S,{generateKey:r,shouldExtract:i,attributesToExtract:e,extractDictionaryKeyFromPath:n,extractTsContent:(e,t,n,r,i)=>a(e,t,n,r,i,k)},w);t&&(P={[j]:t})}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`||e.message?.includes(`Cannot find module`)?Error(`Please install ${_(`@intlayer/svelte-compiler`,g.YELLOW)} to process Svelte files.`):e}else if([`.tsx`,`.jsx`,`.ts`,`.js`].includes(M))try{let e=o(x,j,S,E,w,k,A);e&&(P=e.extractedContent,F=e.modifiedCode)}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`||e.message?.includes(`Cannot find module`)?Error(`Please install ${_(`@intlayer/babel`,g.YELLOW)} to process TSX/JSX/TS/JS files.`):e}if(!P||Object.keys(P).length===0){D(`No extractable text found in ${_(N)}`);return}if(C?.onExtract)for(let[e,t]of Object.entries(P))await C.onExtract({key:e,content:t,filePath:x});if(T)for(let[e,t]of Object.entries(P)){let n=await s(t,e,x,E,C?.outputDir);D(`Created content file: ${_(u(E.content.baseDir,n))}`)}if(w){let e=m(E);if(e)try{f(e.replace(`{{file}}`,x),{stdio:`inherit`,cwd:O})}catch(e){console.error(e)}D(`Updated component: ${_(u(O,x))}`)}return{transformedCode:F}};export{x as extractContent};
|
|
2
|
+
//# sourceMappingURL=extractContent.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractContent.mjs","names":[],"sources":["../../../src/extractContent/extractContent.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { basename, extname, relative } from 'node:path';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport {\n ANSIColors,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { extractTsContent } from './babelProcessor';\nimport { writeContentHelper } from './contentWriter';\nimport { processTsxFile } from './processTsxFile';\nimport {\n ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n type PackageName,\n shouldExtract,\n} from './utils';\nimport { extractDictionaryKey } from './utils/extractDictionaryKey';\nimport { generateKey } from './utils/generateKey';\n\nexport type ExtractIntlayerOptions = {\n configOptions?: GetConfigurationOptions;\n outputDir?: string;\n /**\n * If true, only transform the source file — skip writing content declarations.\n */\n codeOnly?: boolean;\n /**\n * If true, only write content declarations — skip transforming the source file.\n * When set, `transformedCode` will still be returned (computed but not written to disk).\n */\n declarationOnly?: boolean;\n unmergedDictionaries?: Record<string, unknown>;\n configuration?: IntlayerConfig;\n /**\n * Raw source code to process instead of reading from disk.\n * Useful for Vite/webpack transform hooks where the code may already\n * have been modified by a previous plugin.\n */\n code?: string;\n /**\n * Callback invoked for each extracted dictionary key/content pair.\n * When provided, the caller is responsible for writing content declarations\n * (the built-in `writeContentHelper` is skipped unless `writeContent` is also true).\n * Used by Vite/webpack plugins that manage their own dictionary write pipeline.\n */\n onExtract?: (result: {\n key: string;\n content: Record<string, string>;\n filePath: string;\n }) => void | Promise<void>;\n};\n\n// Module caches for optional compiler packages\nlet vueCompiler: typeof import('@intlayer/vue-compiler') | null = null;\nlet svelteCompiler: typeof import('@intlayer/svelte-compiler') | null = null;\n\n/**\n * Extracts Intlayer content from a single source file and optionally transforms it.\n *\n * - For `.vue` / `.svelte` files the matching optional compiler package is used.\n * - For `.tsx` / `.jsx` / `.ts` / `.js` files the Babel-based `processTsxFile` is used.\n *\n * Returns `{ transformedCode }` so callers (e.g. the Vite plugin) can pass the\n * modified source back to the bundler without writing the file to disk.\n */\nexport const extractContent = async (\n filePath: string,\n packageName: PackageName,\n options?: ExtractIntlayerOptions\n): Promise<{ transformedCode: string | null } | undefined> => {\n const saveComponent = !options?.declarationOnly;\n const writeContent = !options?.codeOnly && !options?.onExtract;\n\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n const { baseDir } = configuration.content;\n\n const unmergedDictionaries =\n options?.unmergedDictionaries ?? getUnmergedDictionaries(configuration);\n\n const fileText = options?.code ?? readFileSync(filePath, 'utf-8');\n const componentKey = extractDictionaryKey(filePath, fileText);\n const ext = extname(filePath);\n const fileBaseName = basename(filePath, ext);\n const relativeFilePath = relative(baseDir, filePath);\n\n let extractedContentMap: Record<string, Record<string, string>> | null = null;\n let transformedCode: string | null = null;\n\n if (ext === '.vue') {\n try {\n vueCompiler ??= await import('@intlayer/vue-compiler');\n\n const res = await vueCompiler.processVueFile(\n filePath,\n componentKey,\n packageName,\n {\n generateKey,\n shouldExtract,\n attributesToExtract: ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n extractTsContent: (\n ast: any,\n code: string,\n keys: Set<string>,\n config: any,\n path: string\n ) =>\n extractTsContent(\n ast,\n code,\n keys,\n config,\n path,\n unmergedDictionaries\n ),\n },\n saveComponent\n );\n\n if (res) {\n extractedContentMap = {\n [componentKey]: res as Record<string, string>,\n };\n }\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/vue-compiler', ANSIColors.YELLOW)} to process Vue files.`\n );\n }\n throw error;\n }\n } else if (ext === '.svelte') {\n try {\n svelteCompiler ??= await import('@intlayer/svelte-compiler');\n\n const res = await svelteCompiler.processSvelteFile(\n filePath,\n componentKey,\n packageName,\n {\n generateKey,\n shouldExtract,\n attributesToExtract: ATTRIBUTES_TO_EXTRACT,\n extractDictionaryKeyFromPath,\n extractTsContent: (\n ast: any,\n code: string,\n keys: Set<string>,\n config: any,\n path: string\n ) =>\n extractTsContent(\n ast,\n code,\n keys,\n config,\n path,\n unmergedDictionaries\n ),\n },\n saveComponent\n );\n\n if (res) {\n extractedContentMap = {\n [componentKey]: res as Record<string, string>,\n };\n }\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/svelte-compiler', ANSIColors.YELLOW)} to process Svelte files.`\n );\n }\n throw error;\n }\n } else if (['.tsx', '.jsx', '.ts', '.js'].includes(ext)) {\n try {\n const result = processTsxFile(\n filePath,\n componentKey,\n packageName,\n configuration,\n saveComponent,\n unmergedDictionaries,\n fileText\n );\n\n if (result) {\n extractedContentMap = result.extractedContent;\n transformedCode = result.modifiedCode;\n }\n } catch (error: any) {\n if (\n error.code === 'ERR_MODULE_NOT_FOUND' ||\n error.message?.includes('Cannot find module')\n ) {\n throw new Error(\n `Please install ${colorizePath('@intlayer/babel', ANSIColors.YELLOW)} to process TSX/JSX/TS/JS files.`\n );\n }\n throw error;\n }\n }\n\n if (!extractedContentMap || Object.keys(extractedContentMap).length === 0) {\n appLogger(`No extractable text found in ${colorizePath(relativeFilePath)}`);\n return undefined;\n }\n\n // Notify caller via callback (e.g. Vite plugin's own dictionary pipeline)\n if (options?.onExtract) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n await options.onExtract({ key, content, filePath });\n }\n }\n\n // Write content declarations using the built-in helper when no custom callback\n if (writeContent) {\n for (const [key, content] of Object.entries(extractedContentMap)) {\n const contentFilePath = await writeContentHelper(\n content,\n key,\n filePath,\n configuration,\n options?.outputDir\n );\n\n const relativeContentFilePath = relative(\n configuration.content.baseDir,\n contentFilePath\n );\n appLogger(\n `Created content file: ${colorizePath(relativeContentFilePath)}`\n );\n }\n }\n\n if (saveComponent) {\n const formatCommand = detectFormatCommand(configuration);\n\n if (formatCommand) {\n try {\n execSync(formatCommand.replace('{{file}}', filePath), {\n stdio: 'inherit',\n cwd: baseDir,\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n appLogger(\n `Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n\n return { transformedCode };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ATTRIBUTES_TO_EXTRACT as e,packageList as t}from"./utils/constants.mjs";import{detectPackageName as n}from"./utils/detectPackageName.mjs";import{extractContent as r}from"./extractContent.mjs";export{e as ATTRIBUTES_TO_EXTRACT,n as detectPackageName,r as extractContent,t as packageList};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{getExistingIntlayerInfo as e}from"./utils/getExistingIntlayerInfo.mjs";import{extractBabelContentForComponents as t}from"./babelProcessor.mjs";import{parse as n}from"@babel/parser";import{execSync as r}from"node:child_process";import{readFileSync as i,writeFileSync as a}from"node:fs";import o from"@babel/traverse";import*as s from"@babel/types";import{detectFormatCommand as c}from"@intlayer/chokidar/cli";const l=typeof o==`function`?o:o.default,u=(o,u,d,f,p=!0,m={},h)=>{let g=h??i(o,`utf-8`),_=n(g,{sourceType:`module`,plugins:[`jsx`,`typescript`]}),v=d===`solid-intlayer`,{extractedContent:y,replacements:b,componentsNeedingHooks:x,componentKeyMap:S,componentPaths:C,hookMap:w}=t(_,g,new Set,u,f,o,m);if(Object.keys(y).length===0)return null;let T=[],E=t=>{let n=t;for(;n;){let t=C.find(e=>e.node===n?.node);if(t){let n=e(t);if(n)return n.hook;if(x.has(t))return w.get(t.node)||`useIntlayer`}n=n.parentPath}return`useIntlayer`};for(let{path:e,key:t,type:n,variables:r,childrenToReplace:i}of b){let a=v?`content().${t}`:`content.${t}`,o=E(e)===`getIntlayer`?``:`.value`;if(n===`jsx-text`&&e.isJSXText())T.push({start:e.node.start,end:e.node.end,replacement:`{${a}}`});else if(n===`jsx-attribute`&&e.isJSXAttribute()){let t=e.node.value;t&&T.push({start:t.start,end:t.end,replacement:`{${a}${o}}`})}else if(n===`string-literal`&&e.isStringLiteral())T.push({start:e.node.start,end:e.node.end,replacement:`${a}${o}`});else if(n===`jsx-text-combined`&&i&&i.length>0){let e=`{${a}}`,t=i[0].start,n=i[i.length-1].end;T.push({start:t,end:n,replacement:e})}else if(n===`jsx-insertion`&&r&&i&&i.length>0){let e=`{${a}({ ${r.map(e=>{let[t,n]=e.split(`:`).map(e=>e.trim());return`${t}: ${n}`}).join(`, `)} })}`,t=i[0].start,n=i[i.length-1].end;T.push({start:t,end:n,replacement:e})}}let D=!1,O=!1;for(let t of x){let n=S.get(t.node),r=e(t);if(r)r.hook===`useIntlayer`&&(D=!0),r.hook===`getIntlayer`&&(O=!0);else{let e=w.get(t.node)||`useIntlayer`;e===`useIntlayer`&&(D=!0),e===`getIntlayer`&&(O=!0);let r=t.get(`body`),i=`\n const content = ${e}('${n}');\n`;if(r.isBlockStatement())T.push({start:r.node.start+1,end:r.node.start+1,replacement:i});else if(r.isExpression()){let t=r.node.start,i=r.node.end,a=-1,o=-1;for(let e=t-1;e>=0;e--){let t=g[e];if(t===`(`){a=e;break}if(t!==` `&&t!==`
|
|
2
|
+
`&&t!==`\r`&&t!==` `)break}if(a!==-1)for(let e=i;e<g.length;e++){let t=g[e];if(t===`)`){o=e;break}if(t!==` `&&t!==`
|
|
3
|
+
`&&t!==`\r`&&t!==` `)break}a!==-1&&o!==-1?(T.push({start:o,end:o+1,replacement:`)
|
|
4
|
+
}`}),T.push({start:a,end:a+1,replacement:`{\n const content = ${e}('${n}');\n return (`})):(T.push({start:i,end:i,replacement:`
|
|
5
|
+
}`}),T.push({start:t,end:t,replacement:`{\n const content = ${e}('${n}');\n return `}))}}}let k=(e,t)=>{let n;if(l(_,{ImportDeclaration(e){e.node.source.value===t&&(n=e,e.stop())}}),!n){let n=`import { ${e} } from '${t}';\n`,r=0;if(_.program.body.length>0)r=_.program.body[0].start;else if(_.program.directives&&_.program.directives.length>0){r=_.program.directives[_.program.directives.length-1].end,g[r]===`;`&&r++,T.push({start:r,end:r,replacement:`\n${n}`});return}(r===0||_.program.body.length>0&&r===_.program.body[0].start)&&T.push({start:r,end:r,replacement:n})}else if(!n.node.specifiers.some(t=>s.isImportSpecifier(t)&&s.isIdentifier(t.imported)&&t.imported.name===e)){let t=g.slice(n.node.start,n.node.end),r=t.lastIndexOf(`}`);if(r!==-1){let i=!t.slice(0,r).trim().endsWith(`,`),a=n.node.start+r,o=i?`, `:` `;T.push({start:a,end:a,replacement:`${o}${e} `})}}};D&&k(`useIntlayer`,d),O&&k(`getIntlayer`,`intlayer`),T.sort((e,t)=>t.start===e.start?t.end-e.end:t.start-e.start);let A=g;for(let e of T)A=A.slice(0,e.start)+e.replacement+A.slice(e.end);if(p){a(o,A);let e=c(f);if(e)try{r(e.replace(`{{file}}`,o),{stdio:`inherit`,cwd:f.content.baseDir})}catch(e){console.error(e)}}return{extractedContent:y,modifiedCode:A}};export{u as processTsxFile};
|
|
6
|
+
//# sourceMappingURL=processTsxFile.mjs.map
|
|
@@ -0,0 +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';\nimport { extractBabelContentForComponents } from './babelProcessor';\nimport { getExistingIntlayerInfo } from './utils';\n\nexport type TextEdit = {\n start: number;\n end: number;\n replacement: string;\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: string,\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 isSolid = packageName === 'solid-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 const getProvidingHookType = (\n path: NodePath\n ): 'useIntlayer' | 'getIntlayer' => {\n let current: NodePath | null = path;\n while (current) {\n const functionPath = componentPaths.find(\n (path) => path.node === current?.node\n );\n\n if (functionPath) {\n const existingInfo = getExistingIntlayerInfo(functionPath);\n\n if (existingInfo) {\n return existingInfo.hook;\n }\n\n if (componentsNeedingHooks.has(functionPath)) {\n return hookMap.get(functionPath.node) || 'useIntlayer';\n }\n }\n current = current.parentPath;\n }\n return 'useIntlayer';\n };\n\n for (const {\n path,\n key,\n type,\n variables,\n childrenToReplace,\n } of replacements) {\n const contentAccessCode = isSolid ? `content().${key}` : `content.${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 textEdits.push({\n start: path.node.start!,\n end: path.node.end!,\n replacement: `${contentAccessCode}${valueSuffix}`,\n });\n } else if (\n type === 'jsx-text-combined' &&\n childrenToReplace &&\n childrenToReplace.length > 0\n ) {\n const accessStr = `{${contentAccessCode}}`;\n const start = childrenToReplace[0].start!;\n const end = childrenToReplace[childrenToReplace.length - 1].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 accessStr = `{${contentAccessCode}({ ${objProps} })}`;\n const start = childrenToReplace[0].start!;\n const end = childrenToReplace[childrenToReplace.length - 1].end!;\n textEdits.push({ start, end, replacement: accessStr });\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 = getExistingIntlayerInfo(componentPath);\n\n if (existingInfo) {\n if (existingInfo.hook === 'useIntlayer') needsUseIntlayer = true;\n\n if (existingInfo.hook === 'getIntlayer') needsGetIntlayer = true;\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 bodyPath = componentPath.get('body') as NodePath;\n const hookStatementStr = `\\n const content = ${hook}('${finalKey}');\\n`;\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 ch = fileCode[i];\n if (ch === '(') {\n parenStart = i;\n break;\n }\n if (ch !== ' ' && ch !== '\\n' && ch !== '\\r' && ch !== '\\t') break;\n }\n\n if (parenStart !== -1) {\n for (let i = end; i < fileCode.length; i++) {\n const ch = fileCode[i];\n if (ch === ')') {\n parenEnd = i;\n break;\n }\n if (ch !== ' ' && ch !== '\\n' && ch !== '\\r' && ch !== '\\t') 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 insertPos = ast.program.body[0].start!;\n } else if (ast.program.directives && ast.program.directives.length > 0) {\n insertPos =\n ast.program.directives[ast.program.directives.length - 1].end!;\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 if (\n insertPos === 0 ||\n (ast.program.body.length > 0 &&\n insertPos === ast.program.body[0].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', packageName);\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.content.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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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=[`title`,`placeholder`,`alt`,`aria-label`,`label`],t=[`next-intlayer`,`react-intlayer`,`vue-intlayer`,`svelte-intlayer`,`preact-intlayer`,`solid-intlayer`,`angular-intlayer`,`express-intlayer`,`hono-intlayer`,`fastify-intlayer`,`adonis-intlayer`];export{e as ATTRIBUTES_TO_EXTRACT,t as packageList};
|
|
2
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +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 */\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 'express-intlayer',\n 'hono-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n] as const;\n\nexport type PackageName = (typeof packageList)[number];\n"],"mappings":"AAKA,MAAa,EAAwB,CACnC,QACA,cACA,MACA,aACA,QACD,CAMY,EAAc,CACzB,gBACA,iBACA,eACA,kBACA,kBACA,iBACA,mBACA,mBACA,gBACA,mBACA,kBACD"}
|