@intlayer/babel 8.2.2 → 8.2.4
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/extractContent/extractContent.cjs +1 -1
- package/dist/cjs/extractContent/extractContent.cjs.map +1 -1
- package/dist/cjs/getExtractPluginOptions.cjs +1 -1
- package/dist/cjs/getExtractPluginOptions.cjs.map +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/extractContent/extractContent.mjs +1 -1
- package/dist/esm/extractContent/extractContent.mjs.map +1 -1
- package/dist/esm/getExtractPluginOptions.mjs +1 -1
- package/dist/esm/getExtractPluginOptions.mjs.map +1 -1
- package/dist/types/extractContent/extractContent.d.ts.map +1 -1
- package/package.json +11 -11
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);const e=require(`./extractContent/utils/detectPackageName.cjs`),t=require(`./extractContent/utils/extractDictionaryKey.cjs`),n=require(`./extractContent/processTsxFile.cjs`);let r=require(`node:path`),i=require(`@babel/parser`),a=require(`@intlayer/config/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);const e=require(`./extractContent/utils/detectPackageName.cjs`),t=require(`./extractContent/utils/extractDictionaryKey.cjs`),n=require(`./extractContent/processTsxFile.cjs`);let r=require(`node:path`),i=require(`@babel/parser`),a=require(`@intlayer/config/logger`),o=require(`@intlayer/config/node`);const s=new Set([`next-intlayer`]),c=c=>({name:`babel-plugin-intlayer-extract`,visitor:{Program:{enter(c,l){let u=l.opts;if(u.enabled===!1)return;let d=l.file.opts.filename;if(!d)return;let f=(0,r.extname)(d);if(![`.tsx`,`.jsx`,`.ts`,`.js`].includes(f)||u.filesList&&!u.filesList.includes(d))return;let p=l.file.code??``;if(!p)return;let m=(0,o.getConfiguration)(),h=(0,a.getAppLogger)(m),g=u.packageName??e.detectPackageName((0,r.dirname)(d))??`react-intlayer`,_=t.extractDictionaryKeyFromPath(d,u.prefix??`comp-`),v=u.saveComponents??!1,y=c.node.directives.some(e=>e.value.value===`use client`),b=n.processTsxFile(d,_,s.has(g)&&!y?`${g}/server`:g,m,v,{},p);if(!b)return;let{extractedContent:x,modifiedCode:S}=b;if(u.onExtract){let e=u.defaultLocale??m.internationalization.defaultLocale;for(let[t,n]of Object.entries(x))u.onExtract({dictionaryKey:t,filePath:d,content:n,locale:e})}try{let e=(0,i.parse)(S,{sourceType:`module`,plugins:[`jsx`,`typescript`]});c.node.body=e.program.body,c.node.directives=e.program.directives,h(`${(0,a.colorize)(`Compiler:`,a.ANSIColors.GREY_DARK)} Extracted content from ${(0,a.colorizePath)((0,r.relative)(m.content.baseDir,d))}`,{level:`debug`})}catch(e){console.error(`[intlayer] Failed to parse transformed code for ${d}:`,e)}}}}});exports.intlayerExtractBabelPlugin=c;
|
|
2
2
|
//# sourceMappingURL=babel-plugin-intlayer-extract.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["detectPackageName","extractDictionaryKeyFromPath","processTsxFile","ANSIColors"],"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/
|
|
1
|
+
{"version":3,"file":"babel-plugin-intlayer-extract.cjs","names":["detectPackageName","extractDictionaryKeyFromPath","processTsxFile","ANSIColors"],"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/logger';\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":"2ZAiBA,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,GAAA,EAAA,EAAA,SAAc,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,GAAA,EAAA,EAAA,mBAAkC,CAClC,GAAA,EAAA,EAAA,cAAyB,EAAc,CAEvC,EAAe,EAAK,aACxBA,EAAAA,mBAAAA,EAAAA,EAAAA,SAA0B,EAAS,CAAC,EACpC,iBAGI,EAAeC,EAAAA,6BAA6B,EADnC,EAAK,QAAU,QACqC,CAC7D,EAAiB,EAAK,gBAAkB,GAKxC,EAAe,EAAY,KAAK,WAAW,KAC9C,GAAM,EAAE,MAAM,QAAU,aAC1B,CAMK,EAASC,EAAAA,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,GAAA,EAAA,EAAA,OAAe,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,IAAA,EAAA,EAAA,UAAY,YAAaC,EAAAA,WAAW,UAAU,CAAC,2BAAA,EAAA,EAAA,eAAA,EAAA,EAAA,UAAgD,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
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./utils/constants.cjs`),t=require(`./utils/extractDictionaryKey.cjs`),n=require(`./utils/generateKey.cjs`),r=require(`./utils/shouldExtract.cjs`),i=require(`./babelProcessor.cjs`),a=require(`./processTsxFile.cjs`),o=require(`./contentWriter.cjs`);let s=require(`node:path`),c=require(`@intlayer/config/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./utils/constants.cjs`),t=require(`./utils/extractDictionaryKey.cjs`),n=require(`./utils/generateKey.cjs`),r=require(`./utils/shouldExtract.cjs`),i=require(`./babelProcessor.cjs`),a=require(`./processTsxFile.cjs`),o=require(`./contentWriter.cjs`);let s=require(`node:path`),c=require(`@intlayer/config/logger`),l=require(`@intlayer/config/node`),u=require(`node:child_process`),d=require(`node:fs`),f=require(`@intlayer/chokidar/cli`),p=require(`@intlayer/unmerged-dictionaries-entry`),m=null,h=null;const g=async(g,_,v)=>{let y=!v?.declarationOnly,b=!v?.codeOnly&&!v?.onExtract,x=v?.configuration??(0,l.getConfiguration)(v?.configOptions),S=(0,c.getAppLogger)(x),{baseDir:C}=x.content,w=v?.unmergedDictionaries??(0,p.getUnmergedDictionaries)(x),T=v?.code??(0,d.readFileSync)(g,`utf-8`),E=t.extractDictionaryKey(g,T),D=(0,s.extname)(g),O=(0,s.relative)(C,g),k=null,A=null;if(D===`.vue`)try{m??=await import(`@intlayer/vue-compiler`);let a=await m.processVueFile(g,E,_,{generateKey:n.generateKey,shouldExtract:r.shouldExtract,attributesToExtract:e.ATTRIBUTES_TO_EXTRACT,extractDictionaryKeyFromPath:t.extractDictionaryKeyFromPath,extractTsContent:(e,t,n,r,a)=>i.extractTsContent(e,t,n,r,a,w)},y);a&&(k={[E]:a})}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`||e.message?.includes(`Cannot find module`)?Error(`Please install ${(0,c.colorizePath)(`@intlayer/vue-compiler`,c.ANSIColors.YELLOW)} to process Vue files.`):e}else if(D===`.svelte`)try{h??=await import(`@intlayer/svelte-compiler`);let a=await h.processSvelteFile(g,E,_,{generateKey:n.generateKey,shouldExtract:r.shouldExtract,attributesToExtract:e.ATTRIBUTES_TO_EXTRACT,extractDictionaryKeyFromPath:t.extractDictionaryKeyFromPath,extractTsContent:(e,t,n,r,a)=>i.extractTsContent(e,t,n,r,a,w)},y);a&&(k={[E]:a})}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`||e.message?.includes(`Cannot find module`)?Error(`Please install ${(0,c.colorizePath)(`@intlayer/svelte-compiler`,c.ANSIColors.YELLOW)} to process Svelte files.`):e}else if([`.tsx`,`.jsx`,`.ts`,`.js`].includes(D))try{let e=a.processTsxFile(g,E,_,x,y,w,T);e&&(k=e.extractedContent,A=e.modifiedCode)}catch(e){throw e.code===`ERR_MODULE_NOT_FOUND`||e.message?.includes(`Cannot find module`)?Error(`Please install ${(0,c.colorizePath)(`@intlayer/babel`,c.ANSIColors.YELLOW)} to process TSX/JSX/TS/JS files.`):e}if(!k||Object.keys(k).length===0){S(`${(0,c.colorize)(`Compiler:`,c.ANSIColors.GREY_DARK)} No extractable text found in ${(0,c.colorizePath)(O)}`,{isVerbose:!0});return}if(v?.onExtract)for(let[e,t]of Object.entries(k))await v.onExtract({key:e,content:t,filePath:g});if(b)for(let[e,t]of Object.entries(k)){let n=await o.writeContentHelper(t,e,g,x,v?.outputDir),r=(0,s.relative)(x.content.baseDir,n);S(`${(0,c.colorize)(`Compiler:`,c.ANSIColors.GREY_DARK)} Created content file: ${(0,c.colorizePath)(r)}`)}if(y){let e=(0,f.detectFormatCommand)(x);if(e)try{(0,u.execSync)(e.replace(`{{file}}`,g),{stdio:`inherit`,cwd:C})}catch(e){console.error(e)}S(`${(0,c.colorize)(`Compiler:`,c.ANSIColors.GREY_DARK)} Updated component: ${(0,c.colorizePath)((0,s.relative)(C,g))}`)}return{transformedCode:A}};exports.extractContent=g;
|
|
2
2
|
//# sourceMappingURL=extractContent.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractContent.cjs","names":["extractDictionaryKey","ATTRIBUTES_TO_EXTRACT","extractTsContent","ANSIColors","processTsxFile","writeContentHelper"],"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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"}
|
|
1
|
+
{"version":3,"file":"extractContent.cjs","names":["extractDictionaryKey","ATTRIBUTES_TO_EXTRACT","extractTsContent","ANSIColors","processTsxFile","writeContentHelper"],"sources":["../../../src/extractContent/extractContent.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { extname, relative } from 'node:path';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport {\n ANSIColors,\n colorize,\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 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(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relativeFilePath)}`,\n {\n isVerbose: true,\n }\n );\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 `${colorize('Compiler:', ANSIColors.GREY_DARK)} 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 `${colorize('Compiler:', ANSIColors.GREY_DARK)} Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n\n return { transformedCode };\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:path`),t=require(`@intlayer/config/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./_virtual/_rolldown/runtime.cjs`);let e=require(`node:path`),t=require(`@intlayer/config/logger`),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":"getExtractPluginOptions.cjs","names":["ANSIColors"],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/
|
|
1
|
+
{"version":3,"file":"getExtractPluginOptions.cjs","names":["ANSIColors"],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Dictionary } from '@intlayer/types';\nimport type {\n ExtractPluginOptions,\n ExtractResult,\n} from './babel-plugin-intlayer-extract';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n isDev = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n const config = getConfiguration();\n const { baseDir } = config.content;\n\n const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler');\n\n /**\n * Read existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryPath: string\n ): Promise<Dictionary | null> => {\n try {\n if (!existsSync(dictionaryPath)) {\n return null;\n }\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (!content || content.trim() === '') {\n return null;\n }\n\n const parsed = JSON.parse(content);\n\n if (Array.isArray(parsed)) {\n return (parsed[0] ?? null) as Dictionary | null;\n }\n\n return parsed as Dictionary;\n } catch (error) {\n if (existsSync(dictionaryPath)) {\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (content.trim() !== '') {\n console.warn(\n `[intlayer] Warning: Failed to read existing dictionary at ${dictionaryPath}. It might be corrupt. Translations may be lost. Error:`,\n error\n );\n }\n }\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary, preserving translations.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n const sortedKeys = Object.keys(extractedContent).sort();\n\n for (const key of sortedKeys) {\n const value = extractedContent[key];\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n // Key exists in both - preserve existing translations AND existing metadata\n mergedContent[key] = {\n ...existingEntry,\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: existingEntry.translation[defaultLocale] ?? value,\n },\n };\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n }\n\n return mergedContent;\n };\n\n const handleExtractedContent = async (result: ExtractResult) => {\n const { dictionaryKey, content, locale } = result;\n\n try {\n const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`);\n\n // Read existing dictionary to preserve translations\n const existingDictionary = await readExistingDictionary(dictionaryPath);\n\n // Merge extracted content with existing translations\n const mergedContent = mergeWithExistingDictionary(\n content,\n existingDictionary,\n locale\n );\n\n const dictionary: Dictionary = {\n ...existingDictionary,\n key: dictionaryKey,\n content: mergedContent,\n filePath: join(\n relative(baseDir, compilerDir),\n `${dictionaryKey}.content.json`\n ),\n };\n\n const writeResult = await writeContentDeclaration(dictionary, config, {\n newDictionariesPath: relative(baseDir, compilerDir),\n });\n\n // Build the dictionary immediately\n const dictionaryToBuild: Dictionary = {\n ...dictionary,\n filePath: relative(baseDir, writeResult.path),\n };\n\n await buildDictionary([dictionaryToBuild], config);\n } catch (error: any) {\n console.error(\n `[intlayer] Failed to process extracted content for ${dictionaryKey}:`,\n error\n );\n if (\n error instanceof SyntaxError &&\n error.message.includes('Unexpected end of JSON input')\n ) {\n const match = error.message.match(\n /^(.*\\.json):\\s*Unexpected end of JSON input/\n );\n if (match) {\n const filePath = match[1];\n try {\n const fs = require('fs');\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n console.error(\n `[intlayer] Content of the corrupted file (${filePath}):\\n\"${fileContent}\"`\n );\n } catch (e) {\n console.error(\n `[intlayer] Could not read corrupted file ${filePath}`,\n e\n );\n }\n }\n }\n }\n };\n\n const isDevBoolean = String(isDev) === 'true';\n const isEnabled =\n config.compiler?.enabled === 'build-only'\n ? !isDevBoolean\n : (config.compiler?.enabled ?? true);\n\n const logger = getAppLogger(config);\n\n if (config.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n return {\n enabled: isEnabled,\n defaultLocale: config.internationalization.defaultLocale,\n prefix: config.compiler?.dictionaryKeyPrefix,\n saveComponents: config.compiler?.saveComponents,\n // filesList can be passed if needed, but usually handled by include/exclude in build tool\n onExtract: handleExtractedContent,\n };\n};\n"],"mappings":"2SAiCA,MAAa,GACX,EAAQ,QAAQ,IAAI,0BACK,CACzB,IAAM,GAAA,EAAA,EAAA,mBAA2B,CAC3B,CAAE,WAAY,EAAO,QAErB,GAAA,EAAA,EAAA,MAAmB,EAAS,EAAO,UAAU,WAAa,WAAW,CAKrE,EAAyB,KAC7B,IAC+B,CAC/B,GAAI,CACF,GAAI,EAAA,EAAA,EAAA,YAAY,EAAe,CAC7B,OAAO,KAET,IAAM,EAAU,MAAA,EAAA,EAAA,UAAe,EAAgB,QAAQ,CAEvD,GAAI,CAAC,GAAW,EAAQ,MAAM,GAAK,GACjC,OAAO,KAGT,IAAM,EAAS,KAAK,MAAM,EAAQ,CAMlC,OAJI,MAAM,QAAQ,EAAO,CACf,EAAO,IAAM,KAGhB,QACA,EAAO,CAWd,OAVA,EAAA,EAAA,YAAe,EAAe,GACZ,MAAA,EAAA,EAAA,UAAe,EAAgB,QAAQ,EAE3C,MAAM,GAAK,IACrB,QAAQ,KACN,6DAA6D,EAAe,yDAC5E,EACD,CAGE,OAUL,GACJ,EACA,EACA,IACyB,CACzB,IAAM,EAAsC,EAAE,CACxC,EAAkB,GAAoB,QAItC,EAAa,OAAO,KAAK,EAAiB,CAAC,MAAM,CAEvD,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAiB,GACzB,EAAgB,IAAkB,GAGtC,GACA,EAAc,WAAa,eAC3B,EAAc,YAGd,EAAc,GAAO,CACnB,GAAG,EACH,SAAU,cACV,YAAa,CACX,GAAG,EAAc,aAChB,GAAgB,EAAc,YAAY,IAAkB,EAC9D,CACF,CAGD,EAAc,GAAO,CACnB,SAAU,cACV,YAAa,EACV,GAAgB,EAClB,CACF,CAIL,OAAO,GAGH,EAAyB,KAAO,IAA0B,CAC9D,GAAM,CAAE,gBAAe,UAAS,UAAW,EAE3C,GAAI,CAIF,IAAM,EAAqB,MAAM,GAAA,EAAA,EAAA,MAHL,EAAa,GAAG,EAAc,eAAe,CAGF,CAGjE,EAAgB,EACpB,EACA,EACA,EACD,CAEK,EAAyB,CAC7B,GAAG,EACH,IAAK,EACL,QAAS,EACT,UAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UACW,EAAS,EAAY,CAC9B,GAAG,EAAc,eAClB,CACF,CAEK,EAAc,MAAA,EAAA,EAAA,yBAA8B,EAAY,EAAQ,CACpE,qBAAA,EAAA,EAAA,UAA8B,EAAS,EAAY,CACpD,CAAC,CAQF,MAAA,EAAA,EAAA,iBAAsB,CALgB,CACpC,GAAG,EACH,UAAA,EAAA,EAAA,UAAmB,EAAS,EAAY,KAAK,CAC9C,CAEwC,CAAE,EAAO,OAC3C,EAAY,CAKnB,GAJA,QAAQ,MACN,sDAAsD,EAAc,GACpE,EACD,CAEC,aAAiB,aACjB,EAAM,QAAQ,SAAS,+BAA+B,CACtD,CACA,IAAM,EAAQ,EAAM,QAAQ,MAC1B,8CACD,CACD,GAAI,EAAO,CACT,IAAM,EAAW,EAAM,GACvB,GAAI,CAEF,IAAM,EADK,QAAQ,KAAK,CACD,aAAa,EAAU,QAAQ,CACtD,QAAQ,MACN,6CAA6C,EAAS,OAAO,EAAY,GAC1E,OACM,EAAG,CACV,QAAQ,MACN,4CAA4C,IAC5C,EACD,MAOL,EAAe,OAAO,EAAM,GAAK,OACjC,EACJ,EAAO,UAAU,UAAY,aACzB,CAAC,EACA,EAAO,UAAU,SAAW,GAE7B,GAAA,EAAA,EAAA,cAAsB,EAAO,CAQnC,OANI,EAAO,UAAU,UAAY,cAAgB,GAC/C,EACE,IAAA,EAAA,EAAA,UAAY,YAAaA,EAAAA,WAAW,UAAU,CAAC,wIAChD,CAGI,CACL,QAAS,EACT,cAAe,EAAO,qBAAqB,cAC3C,OAAQ,EAAO,UAAU,oBACzB,eAAgB,EAAO,UAAU,eAEjC,UAAW,EACZ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
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/
|
|
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/logger";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":[],"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/
|
|
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/logger';\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{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{
|
|
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{extname as c,relative as l}from"node:path";import{ANSIColors as u,colorize as d,colorizePath as f,getAppLogger as p}from"@intlayer/config/logger";import{getConfiguration as m}from"@intlayer/config/node";import{execSync as h}from"node:child_process";import{readFileSync as g}from"node:fs";import{detectFormatCommand as _}from"@intlayer/chokidar/cli";import{getUnmergedDictionaries as v}from"@intlayer/unmerged-dictionaries-entry";let y=null,b=null;const x=async(x,S,C)=>{let w=!C?.declarationOnly,T=!C?.codeOnly&&!C?.onExtract,E=C?.configuration??m(C?.configOptions),D=p(E),{baseDir:O}=E.content,k=C?.unmergedDictionaries??v(E),A=C?.code??g(x,`utf-8`),j=t(x,A),M=c(x),N=l(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 ${f(`@intlayer/vue-compiler`,u.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 ${f(`@intlayer/svelte-compiler`,u.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 ${f(`@intlayer/babel`,u.YELLOW)} to process TSX/JSX/TS/JS files.`):e}if(!P||Object.keys(P).length===0){D(`${d(`Compiler:`,u.GREY_DARK)} No extractable text found in ${f(N)}`,{isVerbose:!0});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),r=l(E.content.baseDir,n);D(`${d(`Compiler:`,u.GREY_DARK)} Created content file: ${f(r)}`)}if(w){let e=_(E);if(e)try{h(e.replace(`{{file}}`,x),{stdio:`inherit`,cwd:O})}catch(e){console.error(e)}D(`${d(`Compiler:`,u.GREY_DARK)} Updated component: ${f(l(O,x))}`)}return{transformedCode:F}};export{x as extractContent};
|
|
2
2
|
//# sourceMappingURL=extractContent.mjs.map
|
|
@@ -1 +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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"}
|
|
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 { extname, relative } from 'node:path';\nimport { detectFormatCommand } from '@intlayer/chokidar/cli';\nimport {\n ANSIColors,\n colorize,\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 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(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} No extractable text found in ${colorizePath(relativeFilePath)}`,\n {\n isVerbose: true,\n }\n );\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 `${colorize('Compiler:', ANSIColors.GREY_DARK)} 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 `${colorize('Compiler:', ANSIColors.GREY_DARK)} Updated component: ${colorizePath(relative(baseDir, filePath))}`\n );\n }\n\n return { transformedCode };\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{__require as e}from"./_virtual/_rolldown/runtime.mjs";import{join as t,relative as n}from"node:path";import{ANSIColors as r,colorize as i,getAppLogger as a}from"@intlayer/config/
|
|
1
|
+
import{__require as e}from"./_virtual/_rolldown/runtime.mjs";import{join as t,relative as n}from"node:path";import{ANSIColors as r,colorize as i,getAppLogger as a}from"@intlayer/config/logger";import{getConfiguration as o}from"@intlayer/config/node";import{existsSync as s}from"node:fs";import{readFile as c}from"node:fs/promises";import{buildDictionary as l,writeContentDeclaration as u}from"@intlayer/chokidar/build";const d=(d=process.env.INTLAYER_IS_DEV_COMMAND)=>{let f=o(),{baseDir:p}=f.content,m=t(p,f.compiler?.outputDir??`compiler`),h=async e=>{try{if(!s(e))return null;let t=await c(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 s(e)&&(await c(e,`utf-8`)).trim()!==``&&console.warn(`[intlayer] Warning: Failed to read existing dictionary at ${e}. It might be corrupt. Translations may be lost. Error:`,t),null}},g=(e,t,n)=>{let r={},i=t?.content,a=Object.keys(e).sort();for(let t of a){let a=e[t],o=i?.[t];o&&o.nodeType===`translation`&&o.translation?r[t]={...o,nodeType:`translation`,translation:{...o.translation,[n]:o.translation[n]??a}}:r[t]={nodeType:`translation`,translation:{[n]:a}}}return r},_=async r=>{let{dictionaryKey:i,content:a,locale:o}=r;try{let e=await h(t(m,`${i}.content.json`)),r=g(a,e,o),s={...e,key:i,content:r,filePath:t(n(p,m),`${i}.content.json`)},c=await u(s,f,{newDictionariesPath:n(p,m)});await l([{...s,filePath:n(p,c.path)}],f)}catch(t){if(console.error(`[intlayer] Failed to process extracted content for ${i}:`,t),t instanceof SyntaxError&&t.message.includes(`Unexpected end of JSON input`)){let n=t.message.match(/^(.*\.json):\s*Unexpected end of JSON input/);if(n){let t=n[1];try{let n=e(`fs`).readFileSync(t,`utf-8`);console.error(`[intlayer] Content of the corrupted file (${t}):\n"${n}"`)}catch(e){console.error(`[intlayer] Could not read corrupted file ${t}`,e)}}}}},v=String(d)===`true`,y=f.compiler?.enabled===`build-only`?!v:f.compiler?.enabled??!0,b=a(f);return f.compiler?.enabled===`build-only`&&v&&b(`${i(`Compiler:`,r.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`),{enabled:y,defaultLocale:f.internationalization.defaultLocale,prefix:f.compiler?.dictionaryKeyPrefix,saveComponents:f.compiler?.saveComponents,onExtract:_}};export{d as getExtractPluginOptions};
|
|
2
2
|
//# sourceMappingURL=getExtractPluginOptions.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getExtractPluginOptions.mjs","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/
|
|
1
|
+
{"version":3,"file":"getExtractPluginOptions.mjs","names":[],"sources":["../../src/getExtractPluginOptions.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport {\n buildDictionary,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { Dictionary } from '@intlayer/types';\nimport type {\n ExtractPluginOptions,\n ExtractResult,\n} from './babel-plugin-intlayer-extract';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Get the options for the Intlayer Babel extraction plugin\n * This function loads the Intlayer configuration and sets up the onExtract callback\n * to write dictionaries to the filesystem.\n */\nexport const getExtractPluginOptions = (\n isDev = process.env.INTLAYER_IS_DEV_COMMAND\n): ExtractPluginOptions => {\n const config = getConfiguration();\n const { baseDir } = config.content;\n\n const compilerDir = join(baseDir, config.compiler?.outputDir ?? 'compiler');\n\n /**\n * Read existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryPath: string\n ): Promise<Dictionary | null> => {\n try {\n if (!existsSync(dictionaryPath)) {\n return null;\n }\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (!content || content.trim() === '') {\n return null;\n }\n\n const parsed = JSON.parse(content);\n\n if (Array.isArray(parsed)) {\n return (parsed[0] ?? null) as Dictionary | null;\n }\n\n return parsed as Dictionary;\n } catch (error) {\n if (existsSync(dictionaryPath)) {\n const content = await readFile(dictionaryPath, 'utf-8');\n\n if (content.trim() !== '') {\n console.warn(\n `[intlayer] Warning: Failed to read existing dictionary at ${dictionaryPath}. It might be corrupt. Translations may be lost. Error:`,\n error\n );\n }\n }\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary, preserving translations.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n const sortedKeys = Object.keys(extractedContent).sort();\n\n for (const key of sortedKeys) {\n const value = extractedContent[key];\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n // Key exists in both - preserve existing translations AND existing metadata\n mergedContent[key] = {\n ...existingEntry,\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: existingEntry.translation[defaultLocale] ?? value,\n },\n };\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n }\n }\n\n return mergedContent;\n };\n\n const handleExtractedContent = async (result: ExtractResult) => {\n const { dictionaryKey, content, locale } = result;\n\n try {\n const dictionaryPath = join(compilerDir, `${dictionaryKey}.content.json`);\n\n // Read existing dictionary to preserve translations\n const existingDictionary = await readExistingDictionary(dictionaryPath);\n\n // Merge extracted content with existing translations\n const mergedContent = mergeWithExistingDictionary(\n content,\n existingDictionary,\n locale\n );\n\n const dictionary: Dictionary = {\n ...existingDictionary,\n key: dictionaryKey,\n content: mergedContent,\n filePath: join(\n relative(baseDir, compilerDir),\n `${dictionaryKey}.content.json`\n ),\n };\n\n const writeResult = await writeContentDeclaration(dictionary, config, {\n newDictionariesPath: relative(baseDir, compilerDir),\n });\n\n // Build the dictionary immediately\n const dictionaryToBuild: Dictionary = {\n ...dictionary,\n filePath: relative(baseDir, writeResult.path),\n };\n\n await buildDictionary([dictionaryToBuild], config);\n } catch (error: any) {\n console.error(\n `[intlayer] Failed to process extracted content for ${dictionaryKey}:`,\n error\n );\n if (\n error instanceof SyntaxError &&\n error.message.includes('Unexpected end of JSON input')\n ) {\n const match = error.message.match(\n /^(.*\\.json):\\s*Unexpected end of JSON input/\n );\n if (match) {\n const filePath = match[1];\n try {\n const fs = require('fs');\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n console.error(\n `[intlayer] Content of the corrupted file (${filePath}):\\n\"${fileContent}\"`\n );\n } catch (e) {\n console.error(\n `[intlayer] Could not read corrupted file ${filePath}`,\n e\n );\n }\n }\n }\n }\n };\n\n const isDevBoolean = String(isDev) === 'true';\n const isEnabled =\n config.compiler?.enabled === 'build-only'\n ? !isDevBoolean\n : (config.compiler?.enabled ?? true);\n\n const logger = getAppLogger(config);\n\n if (config.compiler?.enabled === 'build-only' && isDevBoolean) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} i18n function is not inserted in the code in dev mode to optimize build time. (to test i18n in dev mode set compiler.enabled to true)`\n );\n }\n\n return {\n enabled: isEnabled,\n defaultLocale: config.internationalization.defaultLocale,\n prefix: config.compiler?.dictionaryKeyPrefix,\n saveComponents: config.compiler?.saveComponents,\n // filesList can be passed if needed, but usually handled by include/exclude in build tool\n onExtract: handleExtractedContent,\n };\n};\n"],"mappings":"maAiCA,MAAa,GACX,EAAQ,QAAQ,IAAI,0BACK,CACzB,IAAM,EAAS,GAAkB,CAC3B,CAAE,WAAY,EAAO,QAErB,EAAc,EAAK,EAAS,EAAO,UAAU,WAAa,WAAW,CAKrE,EAAyB,KAC7B,IAC+B,CAC/B,GAAI,CACF,GAAI,CAAC,EAAW,EAAe,CAC7B,OAAO,KAET,IAAM,EAAU,MAAM,EAAS,EAAgB,QAAQ,CAEvD,GAAI,CAAC,GAAW,EAAQ,MAAM,GAAK,GACjC,OAAO,KAGT,IAAM,EAAS,KAAK,MAAM,EAAQ,CAMlC,OAJI,MAAM,QAAQ,EAAO,CACf,EAAO,IAAM,KAGhB,QACA,EAAO,CAWd,OAVI,EAAW,EAAe,GACZ,MAAM,EAAS,EAAgB,QAAQ,EAE3C,MAAM,GAAK,IACrB,QAAQ,KACN,6DAA6D,EAAe,yDAC5E,EACD,CAGE,OAUL,GACJ,EACA,EACA,IACyB,CACzB,IAAM,EAAsC,EAAE,CACxC,EAAkB,GAAoB,QAItC,EAAa,OAAO,KAAK,EAAiB,CAAC,MAAM,CAEvD,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAiB,GACzB,EAAgB,IAAkB,GAGtC,GACA,EAAc,WAAa,eAC3B,EAAc,YAGd,EAAc,GAAO,CACnB,GAAG,EACH,SAAU,cACV,YAAa,CACX,GAAG,EAAc,aAChB,GAAgB,EAAc,YAAY,IAAkB,EAC9D,CACF,CAGD,EAAc,GAAO,CACnB,SAAU,cACV,YAAa,EACV,GAAgB,EAClB,CACF,CAIL,OAAO,GAGH,EAAyB,KAAO,IAA0B,CAC9D,GAAM,CAAE,gBAAe,UAAS,UAAW,EAE3C,GAAI,CAIF,IAAM,EAAqB,MAAM,EAHV,EAAK,EAAa,GAAG,EAAc,eAAe,CAGF,CAGjE,EAAgB,EACpB,EACA,EACA,EACD,CAEK,EAAyB,CAC7B,GAAG,EACH,IAAK,EACL,QAAS,EACT,SAAU,EACR,EAAS,EAAS,EAAY,CAC9B,GAAG,EAAc,eAClB,CACF,CAEK,EAAc,MAAM,EAAwB,EAAY,EAAQ,CACpE,oBAAqB,EAAS,EAAS,EAAY,CACpD,CAAC,CAQF,MAAM,EAAgB,CALgB,CACpC,GAAG,EACH,SAAU,EAAS,EAAS,EAAY,KAAK,CAC9C,CAEwC,CAAE,EAAO,OAC3C,EAAY,CAKnB,GAJA,QAAQ,MACN,sDAAsD,EAAc,GACpE,EACD,CAEC,aAAiB,aACjB,EAAM,QAAQ,SAAS,+BAA+B,CACtD,CACA,IAAM,EAAQ,EAAM,QAAQ,MAC1B,8CACD,CACD,GAAI,EAAO,CACT,IAAM,EAAW,EAAM,GACvB,GAAI,CAEF,IAAM,EAAA,EADa,KAAK,CACD,aAAa,EAAU,QAAQ,CACtD,QAAQ,MACN,6CAA6C,EAAS,OAAO,EAAY,GAC1E,OACM,EAAG,CACV,QAAQ,MACN,4CAA4C,IAC5C,EACD,MAOL,EAAe,OAAO,EAAM,GAAK,OACjC,EACJ,EAAO,UAAU,UAAY,aACzB,CAAC,EACA,EAAO,UAAU,SAAW,GAE7B,EAAS,EAAa,EAAO,CAQnC,OANI,EAAO,UAAU,UAAY,cAAgB,GAC/C,EACE,GAAG,EAAS,YAAa,EAAW,UAAU,CAAC,wIAChD,CAGI,CACL,QAAS,EACT,cAAe,EAAO,qBAAqB,cAC3C,OAAQ,EAAO,UAAU,oBACzB,eAAgB,EAAO,UAAU,eAEjC,UAAW,EACZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractContent.d.ts","names":[],"sources":["../../../src/extractContent/extractContent.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"extractContent.d.ts","names":[],"sources":["../../../src/extractContent/extractContent.ts"],"mappings":";;;;;KA4BY,sBAAA;EACV,aAAA,GAAgB,uBAAA;EAChB,SAAA;EAFU;;;EAMV,QAAA;EAMuB;;;;EADvB,eAAA;EACA,oBAAA,GAAuB,MAAA;EACvB,aAAA,GAAgB,cAAA;EAZA;;;;;EAkBhB,IAAA;EANA;;;;;;EAaA,SAAA,IAAa,MAAA;IACX,GAAA;IACA,OAAA,EAAS,MAAA;IACT,QAAA;EAAA,aACW,OAAA;AAAA;AAgBf;;;;;;;;;AAAA,cAAa,cAAA,GACX,QAAA,UACA,WAAA,EAAa,WAAA,EACb,OAAA,GAAU,sBAAA,KACT,OAAA;EAAU,eAAA;AAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/babel",
|
|
3
|
-
"version": "8.2.
|
|
3
|
+
"version": "8.2.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A Babel plugin for Intlayer that transforms declaration files and provides internationalization features during the build process according to the Intlayer configuration.",
|
|
6
6
|
"keywords": [
|
|
@@ -81,10 +81,10 @@
|
|
|
81
81
|
"@babel/plugin-syntax-jsx": "7.28.6",
|
|
82
82
|
"@babel/traverse": "7.29.0",
|
|
83
83
|
"@babel/types": "7.29.0",
|
|
84
|
-
"@intlayer/chokidar": "8.2.
|
|
85
|
-
"@intlayer/config": "8.2.
|
|
86
|
-
"@intlayer/core": "8.2.
|
|
87
|
-
"@intlayer/types": "8.2.
|
|
84
|
+
"@intlayer/chokidar": "8.2.3",
|
|
85
|
+
"@intlayer/config": "8.2.3",
|
|
86
|
+
"@intlayer/core": "8.2.3",
|
|
87
|
+
"@intlayer/types": "8.2.3",
|
|
88
88
|
"@types/babel__core": "7.20.5",
|
|
89
89
|
"@types/babel__generator": "7.27.0",
|
|
90
90
|
"@types/babel__traverse": "7.28.0",
|
|
@@ -92,21 +92,21 @@
|
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@babel/plugin-syntax-jsx": "^7.28.6",
|
|
95
|
-
"@intlayer/dictionaries-entry": "8.2.
|
|
96
|
-
"@intlayer/unmerged-dictionaries-entry": "8.2.
|
|
97
|
-
"@types/node": "25.3.
|
|
95
|
+
"@intlayer/dictionaries-entry": "8.2.3",
|
|
96
|
+
"@intlayer/unmerged-dictionaries-entry": "8.2.3",
|
|
97
|
+
"@types/node": "25.3.5",
|
|
98
98
|
"@utils/ts-config": "1.0.4",
|
|
99
99
|
"@utils/ts-config-types": "1.0.4",
|
|
100
100
|
"@utils/tsdown-config": "1.0.4",
|
|
101
101
|
"@vitejs/plugin-react": "5.1.4",
|
|
102
102
|
"rimraf": "6.1.3",
|
|
103
|
-
"tsdown": "0.
|
|
103
|
+
"tsdown": "0.21.0",
|
|
104
104
|
"typescript": "5.9.3",
|
|
105
105
|
"vitest": "4.0.18"
|
|
106
106
|
},
|
|
107
107
|
"peerDependencies": {
|
|
108
|
-
"@intlayer/svelte-compiler": "8.2.
|
|
109
|
-
"@intlayer/vue-compiler": "8.2.
|
|
108
|
+
"@intlayer/svelte-compiler": "8.2.3",
|
|
109
|
+
"@intlayer/vue-compiler": "8.2.3"
|
|
110
110
|
},
|
|
111
111
|
"peerDependenciesMeta": {
|
|
112
112
|
"@intlayer/svelte-compiler": {
|