@intlayer/vue-compiler 7.3.8 → 7.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,8 @@
1
- const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
1
  let node_module = require("node:module");
3
2
  let node_path = require("node:path");
4
3
  let __intlayer_babel = require("@intlayer/babel");
5
4
  let __intlayer_chokidar = require("@intlayer/chokidar");
6
5
  let __intlayer_config = require("@intlayer/config");
7
- let fast_glob = require("fast-glob");
8
- fast_glob = require_rolldown_runtime.__toESM(fast_glob);
9
6
 
10
7
  //#region src/VueIntlayerCompiler.ts
11
8
  /**
@@ -44,21 +41,18 @@ const createVueIntlayerCompiler = (options) => {
44
41
  * Build the list of files to transform based on configuration patterns
45
42
  * Includes Vue-specific patterns
46
43
  */
47
- const buildFilesList = async () => {
44
+ const buildFilesListFn = async () => {
48
45
  const { traversePattern } = config.build;
49
- const { baseDir, mainDir } = config.content;
50
- const transformPattern = customCompilerConfig?.transformPattern ?? traversePattern;
51
- const excludePattern = customCompilerConfig?.excludePattern ?? ["**/node_modules/**"];
52
- const patterns = Array.isArray(transformPattern) ? transformPattern : [transformPattern];
53
- const vuePatterns = patterns.map((p) => {
54
- if (p.includes(".vue") || p.includes("{")) return p;
55
- return p.replace(/\{([^}]+)\}/, (_, exts) => `{${exts},vue}`);
46
+ const { baseDir, mainDir, fileExtensions } = config.content;
47
+ const filesListPattern = (0, __intlayer_chokidar.buildFilesList)({
48
+ transformPattern: customCompilerConfig?.transformPattern ?? traversePattern,
49
+ excludePattern: [
50
+ ...customCompilerConfig?.excludePattern ?? [],
51
+ "**/node_modules/**",
52
+ ...fileExtensions.map((pattern) => `**/*${pattern}`)
53
+ ],
54
+ baseDir
56
55
  });
57
- const excludePatterns = Array.isArray(excludePattern) ? excludePattern : [excludePattern];
58
- const filesListPattern = fast_glob.default.sync([...new Set([...patterns, ...vuePatterns])], {
59
- cwd: baseDir,
60
- ignore: excludePatterns
61
- }).map((file) => (0, node_path.join)(baseDir, file));
62
56
  const dictionariesEntryPath = (0, node_path.join)(mainDir, "dictionaries.mjs");
63
57
  const unmergedDictionariesEntryPath = (0, node_path.join)(mainDir, "unmerged_dictionaries.mjs");
64
58
  filesList = [
@@ -91,7 +85,7 @@ const createVueIntlayerCompiler = (options) => {
91
85
  } catch {
92
86
  logger("Failed to load @babel/core. Transformation will be disabled.", { level: "warn" });
93
87
  }
94
- await buildFilesList();
88
+ await buildFilesListFn();
95
89
  await loadLiveSyncKeys();
96
90
  };
97
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"VueIntlayerCompiler.cjs","names":["config: IntlayerConfig","logger: ReturnType<typeof getAppLogger>","mode: CompilerMode","filesList: string[]","babel: typeof import('@babel/core') | null","liveSyncKeys: string[]","fg","compilerMode: CompilerMode","intlayerOptimizeBabelPlugin"],"sources":["../../src/VueIntlayerCompiler.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { join, relative } from 'node:path';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport { watch as chokidarWatch, prepareIntlayer } from '@intlayer/chokidar';\nimport {\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type { CompilerConfig, IntlayerConfig } from '@intlayer/types';\nimport fg from 'fast-glob';\n\n/**\n * Mode of the compiler\n */\nexport type CompilerMode = 'dev' | 'build';\n\n/**\n * Context for hot update handling\n */\nexport type HotUpdateContext = {\n file: string;\n server: {\n ws: { send: (message: { type: string }) => void };\n moduleGraph: {\n getModulesByFile: (file: string) => Set<unknown> | null | undefined;\n invalidateModule: (\n module: unknown,\n seen: Set<unknown>,\n timestamp: number,\n isHmr: boolean\n ) => void;\n };\n };\n timestamp: number;\n};\n\n/**\n * Transform result from the compiler\n */\nexport type TransformResult = {\n code?: string;\n map?: unknown;\n} | null;\n\n/**\n * Options for initializing the Vue compiler\n */\nexport type VueIntlayerCompilerOptions = {\n /**\n * Configuration options for getting the intlayer configuration\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Custom compiler configuration to override defaults\n */\n compilerConfig?: Partial<CompilerConfig>;\n};\n\n/**\n * Vite plugin object returned by the compiler\n */\nexport type VueIntlayerVitePlugin = {\n name: string;\n enforce: 'pre' | 'post';\n configResolved: (config: {\n env?: { DEV?: boolean };\n root: string;\n }) => Promise<void>;\n buildStart: () => Promise<void>;\n configureServer: () => Promise<void>;\n handleHotUpdate: (ctx: HotUpdateContext) => Promise<unknown[] | undefined>;\n transform: {\n order: 'pre' | 'post';\n handler: (\n code: string,\n id: string,\n options?: { ssr?: boolean }\n ) => Promise<TransformResult>;\n };\n apply: (config: unknown, env: { command: string }) => boolean;\n};\n\n/**\n * Create a VueIntlayerCompiler - A Vite-compatible compiler plugin for Vue with Intlayer\n *\n * Handles Vue Single File Components (SFC) with special handling for:\n * - Script blocks in .vue files\n * - TypeScript in Vue files\n * - Vue-specific transformations\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import vue from '@vitejs/plugin-vue';\n * import { vueIntlayerCompiler } from '@intlayer/vue-compiler';\n *\n * export default defineConfig({\n * plugins: [vue(), vueIntlayerCompiler()],\n * });\n * ```\n */\nexport const createVueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n // Private state\n let config: IntlayerConfig;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let mode: CompilerMode = 'dev';\n let hmrVersion = -1;\n const lastSourceTriggeredWrite = 0;\n let filesList: string[] = [];\n // @ts-expect-error - @babel/core is a peer dependency\n let babel: typeof import('@babel/core') | null = null;\n let liveSyncKeys: string[] = [];\n\n const configOptions = options?.configOptions;\n const customCompilerConfig = options?.compilerConfig;\n\n /**\n * Build the list of files to transform based on configuration patterns\n * Includes Vue-specific patterns\n */\n const buildFilesList = async (): Promise<void> => {\n const { traversePattern } = config.build;\n const { baseDir, mainDir } = config.content;\n\n const transformPattern =\n customCompilerConfig?.transformPattern ?? traversePattern;\n const excludePattern = customCompilerConfig?.excludePattern ?? [\n '**/node_modules/**',\n ];\n\n // Add Vue file patterns\n const patterns = Array.isArray(transformPattern)\n ? transformPattern\n : [transformPattern];\n const vuePatterns = patterns.map((p) => {\n // Ensure Vue files are included\n if (p.includes('.vue') || p.includes('{')) {\n return p;\n }\n // Add .vue extension to patterns\n return p.replace(/\\{([^}]+)\\}/, (_, exts) => `{${exts},vue}`);\n });\n\n const excludePatterns = Array.isArray(excludePattern)\n ? excludePattern\n : [excludePattern];\n\n const filesListPattern = fg\n .sync([...new Set([...patterns, ...vuePatterns])], {\n cwd: baseDir,\n ignore: excludePatterns,\n })\n .map((file) => join(baseDir, file));\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n\n filesList = [\n ...filesListPattern,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ];\n };\n\n /**\n * Load dictionary keys that have live sync enabled\n */\n const loadLiveSyncKeys = async (): Promise<void> => {\n try {\n const { getDictionaries } = await import('@intlayer/dictionaries-entry');\n const dictionaries = getDictionaries() as Record<\n string,\n { live?: boolean; key: string }\n >;\n liveSyncKeys = Object.values(dictionaries)\n .filter((dictionary) => dictionary.live)\n .map((dictionary) => dictionary.key);\n } catch {\n liveSyncKeys = [];\n }\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (compilerMode: CompilerMode): Promise<void> => {\n mode = compilerMode;\n config = getConfiguration(configOptions);\n logger = getAppLogger(config);\n\n // Load Babel dynamically\n try {\n const localRequire = createRequire(import.meta.url);\n babel = localRequire('@babel/core');\n } catch {\n logger('Failed to load @babel/core. Transformation will be disabled.', {\n level: 'warn',\n });\n }\n\n // Build files list for transformation\n await buildFilesList();\n\n // Load live sync keys\n await loadLiveSyncKeys();\n };\n\n /**\n * Vite hook: configResolved\n */\n const configResolved = async (viteConfig: {\n env?: { DEV?: boolean };\n root: string;\n }): Promise<void> => {\n const compilerMode: CompilerMode = viteConfig.env?.DEV ? 'dev' : 'build';\n projectRoot = viteConfig.root;\n await init(compilerMode);\n };\n\n /**\n * Prepare intlayer dictionaries and types\n */\n const buildStart = async (): Promise<void> => {\n const isBuild = mode === 'build';\n\n await prepareIntlayer(config, {\n clean: isBuild,\n cacheTimeoutMs: isBuild ? 1000 * 30 : 1000 * 60 * 60,\n });\n };\n\n /**\n * Configure the dev server with file watching\n */\n const configureServer = async (): Promise<void> => {\n if (config.content.watch) {\n chokidarWatch({ configuration: config });\n }\n };\n\n /**\n * Handle HMR for content changes\n */\n const handleHotUpdate = async (\n ctx: HotUpdateContext\n ): Promise<unknown[] | undefined> => {\n const { file, server } = ctx;\n\n // Check if this is a content declaration file\n const isContentFile = config.content.watchedFilesPatternWithPath.some(\n (pattern: string) => {\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/]*')\n );\n return regex.test(file);\n }\n );\n\n if (!isContentFile) {\n const dictionariesDir = config.content.dictionariesDir;\n if (file.startsWith(dictionariesDir)) {\n return [];\n }\n hmrVersion++;\n return undefined;\n }\n\n const sourceTriggered = performance.now() - lastSourceTriggeredWrite < 1000;\n\n if (!sourceTriggered) {\n server.ws.send({ type: 'full-reload' });\n return [];\n }\n\n return undefined;\n };\n\n /**\n * Transform handler with Vue-specific handling\n */\n const transformHandler = async (\n code: string,\n id: string,\n _options?: { ssr?: boolean }\n ): Promise<TransformResult> => {\n if (!babel) {\n return null;\n }\n\n const { optimize, importMode } = config.build;\n\n if (!optimize && mode !== 'build') {\n return null;\n }\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n } = config.content;\n\n /**\n * Handle Vue SFC virtual modules\n * Transform paths like:\n * - .../Component.vue?vue&type=script&setup=true&lang.ts\n * Into:\n * - .../Component.vue\n */\n const filename = id.split('?', 1)[0];\n\n // Check if this file should be transformed\n // For Vue files, also check the base .vue file\n const isVueVirtualModule = id.includes('?vue&type=script');\n const checkFilename = isVueVirtualModule ? filename : filename;\n\n if (!filesList.includes(checkFilename)) {\n // Also check without the virtual module query\n const baseVueFile = filename.endsWith('.vue') ? filename : null;\n if (\n !baseVueFile ||\n !filesList.some((f) => f === baseVueFile || f.startsWith(baseVueFile))\n ) {\n return null;\n }\n }\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\n try {\n const result = babel.transformSync(code, {\n filename,\n plugins: [\n [\n intlayerOptimizeBabelPlugin,\n {\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n importMode,\n filesList,\n replaceDictionaryEntry: true,\n liveSyncKeys,\n },\n ],\n ],\n parserOpts: {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n },\n });\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n } catch (error) {\n logger(\n `Failed to transform Vue file ${relative(projectRoot, filename)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n return null;\n };\n\n /**\n * Apply hook for determining when plugin should be active\n */\n const apply = (_config: unknown, env: { command: string }): boolean => {\n const { optimize } = config?.build ?? {};\n const isEnabled = customCompilerConfig?.enabled ?? true;\n const isBuild = env.command === 'build';\n\n return isEnabled && (isBuild ? (optimize ?? true) : (optimize ?? false));\n };\n\n return {\n name: 'vue-intlayer-compiler',\n enforce: 'post', // Run after Vue plugin\n configResolved,\n buildStart,\n configureServer,\n handleHotUpdate,\n transform: {\n order: 'post', // Run after Vue plugin transformation\n handler: transformHandler,\n },\n apply: (_viteConfig: unknown, env: { command: string }) => {\n if (!config) {\n config = getConfiguration(configOptions);\n }\n return apply(_viteConfig, env);\n },\n };\n};\n\n/**\n * Factory function for creating a Vite plugin\n */\nexport const vueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n return createVueIntlayerCompiler(options);\n};\n\n// Legacy export for backwards compatibility\nexport const VueIntlayerCompiler = createVueIntlayerCompiler;\n"],"mappings":"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"}
1
+ {"version":3,"file":"VueIntlayerCompiler.cjs","names":["config: IntlayerConfig","logger: ReturnType<typeof getAppLogger>","mode: CompilerMode","filesList: string[]","babel: typeof import('@babel/core') | null","liveSyncKeys: string[]","compilerMode: CompilerMode","intlayerOptimizeBabelPlugin"],"sources":["../../src/VueIntlayerCompiler.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { join, relative } from 'node:path';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport {\n buildFilesList,\n watch as chokidarWatch,\n prepareIntlayer,\n} from '@intlayer/chokidar';\nimport {\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type { CompilerConfig, IntlayerConfig } from '@intlayer/types';\n\n/**\n * Mode of the compiler\n */\nexport type CompilerMode = 'dev' | 'build';\n\n/**\n * Context for hot update handling\n */\nexport type HotUpdateContext = {\n file: string;\n server: {\n ws: { send: (message: { type: string }) => void };\n moduleGraph: {\n getModulesByFile: (file: string) => Set<unknown> | null | undefined;\n invalidateModule: (\n module: unknown,\n seen: Set<unknown>,\n timestamp: number,\n isHmr: boolean\n ) => void;\n };\n };\n timestamp: number;\n};\n\n/**\n * Transform result from the compiler\n */\nexport type TransformResult = {\n code?: string;\n map?: unknown;\n} | null;\n\n/**\n * Options for initializing the Vue compiler\n */\nexport type VueIntlayerCompilerOptions = {\n /**\n * Configuration options for getting the intlayer configuration\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Custom compiler configuration to override defaults\n */\n compilerConfig?: Partial<CompilerConfig>;\n};\n\n/**\n * Vite plugin object returned by the compiler\n */\nexport type VueIntlayerVitePlugin = {\n name: string;\n enforce: 'pre' | 'post';\n configResolved: (config: {\n env?: { DEV?: boolean };\n root: string;\n }) => Promise<void>;\n buildStart: () => Promise<void>;\n configureServer: () => Promise<void>;\n handleHotUpdate: (ctx: HotUpdateContext) => Promise<unknown[] | undefined>;\n transform: {\n order: 'pre' | 'post';\n handler: (\n code: string,\n id: string,\n options?: { ssr?: boolean }\n ) => Promise<TransformResult>;\n };\n apply: (config: unknown, env: { command: string }) => boolean;\n};\n\n/**\n * Create a VueIntlayerCompiler - A Vite-compatible compiler plugin for Vue with Intlayer\n *\n * Handles Vue Single File Components (SFC) with special handling for:\n * - Script blocks in .vue files\n * - TypeScript in Vue files\n * - Vue-specific transformations\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import vue from '@vitejs/plugin-vue';\n * import { vueIntlayerCompiler } from '@intlayer/vue-compiler';\n *\n * export default defineConfig({\n * plugins: [vue(), vueIntlayerCompiler()],\n * });\n * ```\n */\nexport const createVueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n // Private state\n let config: IntlayerConfig;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let mode: CompilerMode = 'dev';\n let hmrVersion = -1;\n const lastSourceTriggeredWrite = 0;\n let filesList: string[] = [];\n // @ts-expect-error - @babel/core is a peer dependency\n let babel: typeof import('@babel/core') | null = null;\n let liveSyncKeys: string[] = [];\n\n const configOptions = options?.configOptions;\n const customCompilerConfig = options?.compilerConfig;\n\n /**\n * Build the list of files to transform based on configuration patterns\n * Includes Vue-specific patterns\n */\n const buildFilesListFn = async (): Promise<void> => {\n const { traversePattern } = config.build;\n const { baseDir, mainDir, fileExtensions } = config.content;\n\n const filesListPattern = buildFilesList({\n transformPattern:\n customCompilerConfig?.transformPattern ?? traversePattern,\n excludePattern: [\n ...(customCompilerConfig?.excludePattern ?? []),\n '**/node_modules/**',\n ...fileExtensions.map((pattern) => `**/*${pattern}`),\n ],\n baseDir,\n });\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n\n filesList = [\n ...filesListPattern,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ];\n };\n\n /**\n * Load dictionary keys that have live sync enabled\n */\n const loadLiveSyncKeys = async (): Promise<void> => {\n try {\n const { getDictionaries } = await import('@intlayer/dictionaries-entry');\n const dictionaries = getDictionaries() as Record<\n string,\n { live?: boolean; key: string }\n >;\n liveSyncKeys = Object.values(dictionaries)\n .filter((dictionary) => dictionary.live)\n .map((dictionary) => dictionary.key);\n } catch {\n liveSyncKeys = [];\n }\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (compilerMode: CompilerMode): Promise<void> => {\n mode = compilerMode;\n config = getConfiguration(configOptions);\n logger = getAppLogger(config);\n\n // Load Babel dynamically\n try {\n const localRequire = createRequire(import.meta.url);\n babel = localRequire('@babel/core');\n } catch {\n logger('Failed to load @babel/core. Transformation will be disabled.', {\n level: 'warn',\n });\n }\n\n // Build files list for transformation\n await buildFilesListFn();\n\n // Load live sync keys\n await loadLiveSyncKeys();\n };\n\n /**\n * Vite hook: configResolved\n */\n const configResolved = async (viteConfig: {\n env?: { DEV?: boolean };\n root: string;\n }): Promise<void> => {\n const compilerMode: CompilerMode = viteConfig.env?.DEV ? 'dev' : 'build';\n projectRoot = viteConfig.root;\n await init(compilerMode);\n };\n\n /**\n * Prepare intlayer dictionaries and types\n */\n const buildStart = async (): Promise<void> => {\n const isBuild = mode === 'build';\n\n await prepareIntlayer(config, {\n clean: isBuild,\n cacheTimeoutMs: isBuild ? 1000 * 30 : 1000 * 60 * 60,\n });\n };\n\n /**\n * Configure the dev server with file watching\n */\n const configureServer = async (): Promise<void> => {\n if (config.content.watch) {\n chokidarWatch({ configuration: config });\n }\n };\n\n /**\n * Handle HMR for content changes\n */\n const handleHotUpdate = async (\n ctx: HotUpdateContext\n ): Promise<unknown[] | undefined> => {\n const { file, server } = ctx;\n\n // Check if this is a content declaration file\n const isContentFile = config.content.watchedFilesPatternWithPath.some(\n (pattern: string) => {\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/]*')\n );\n return regex.test(file);\n }\n );\n\n if (!isContentFile) {\n const dictionariesDir = config.content.dictionariesDir;\n if (file.startsWith(dictionariesDir)) {\n return [];\n }\n hmrVersion++;\n return undefined;\n }\n\n const sourceTriggered = performance.now() - lastSourceTriggeredWrite < 1000;\n\n if (!sourceTriggered) {\n server.ws.send({ type: 'full-reload' });\n return [];\n }\n\n return undefined;\n };\n\n /**\n * Transform handler with Vue-specific handling\n */\n const transformHandler = async (\n code: string,\n id: string,\n _options?: { ssr?: boolean }\n ): Promise<TransformResult> => {\n if (!babel) {\n return null;\n }\n\n const { optimize, importMode } = config.build;\n\n if (!optimize && mode !== 'build') {\n return null;\n }\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n } = config.content;\n\n /**\n * Handle Vue SFC virtual modules\n * Transform paths like:\n * - .../Component.vue?vue&type=script&setup=true&lang.ts\n * Into:\n * - .../Component.vue\n */\n const filename = id.split('?', 1)[0];\n\n // Check if this file should be transformed\n // For Vue files, also check the base .vue file\n const isVueVirtualModule = id.includes('?vue&type=script');\n const checkFilename = isVueVirtualModule ? filename : filename;\n\n if (!filesList.includes(checkFilename)) {\n // Also check without the virtual module query\n const baseVueFile = filename.endsWith('.vue') ? filename : null;\n if (\n !baseVueFile ||\n !filesList.some((f) => f === baseVueFile || f.startsWith(baseVueFile))\n ) {\n return null;\n }\n }\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\n try {\n const result = babel.transformSync(code, {\n filename,\n plugins: [\n [\n intlayerOptimizeBabelPlugin,\n {\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n importMode,\n filesList,\n replaceDictionaryEntry: true,\n liveSyncKeys,\n },\n ],\n ],\n parserOpts: {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n },\n });\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n } catch (error) {\n logger(\n `Failed to transform Vue file ${relative(projectRoot, filename)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n return null;\n };\n\n /**\n * Apply hook for determining when plugin should be active\n */\n const apply = (_config: unknown, env: { command: string }): boolean => {\n const { optimize } = config?.build ?? {};\n const isEnabled = customCompilerConfig?.enabled ?? true;\n const isBuild = env.command === 'build';\n\n return isEnabled && (isBuild ? (optimize ?? true) : (optimize ?? false));\n };\n\n return {\n name: 'vue-intlayer-compiler',\n enforce: 'post', // Run after Vue plugin\n configResolved,\n buildStart,\n configureServer,\n handleHotUpdate,\n transform: {\n order: 'post', // Run after Vue plugin transformation\n handler: transformHandler,\n },\n apply: (_viteConfig: unknown, env: { command: string }) => {\n if (!config) {\n config = getConfiguration(configOptions);\n }\n return apply(_viteConfig, env);\n },\n };\n};\n\n/**\n * Factory function for creating a Vite plugin\n */\nexport const vueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n return createVueIntlayerCompiler(options);\n};\n\n// Legacy export for backwards compatibility\nexport const VueIntlayerCompiler = createVueIntlayerCompiler;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
1
  let node_path = require("node:path");
2
+ let __babel_core = require("@babel/core");
3
3
 
4
4
  //#region src/vue-intlayer-extract.ts
5
5
  /**
@@ -135,6 +135,38 @@ const intlayerVueExtract = async (code, filename, options = {}) => {
135
135
  };
136
136
  walkVueAst(sfc.descriptor.template.ast);
137
137
  }
138
+ const scriptBlock = sfc.descriptor.scriptSetup ?? sfc.descriptor.script;
139
+ if (scriptBlock) {
140
+ const scriptContent$1 = scriptBlock.content;
141
+ const offset = scriptBlock.loc.start.offset;
142
+ try {
143
+ (0, __babel_core.traverse)((0, __babel_core.parse)(scriptContent$1, { parserOpts: {
144
+ sourceType: "module",
145
+ plugins: ["typescript", "jsx"]
146
+ } }), { StringLiteral(path) {
147
+ if (path.parentPath.isImportDeclaration()) return;
148
+ if (path.parentPath.isExportDeclaration()) return;
149
+ if (path.parentPath.isImportSpecifier()) return;
150
+ if (path.parentPath.isObjectProperty() && path.key === "key") return;
151
+ if (path.parentPath.isCallExpression()) {
152
+ const callee = path.parentPath.node.callee;
153
+ if (__babel_core.types.isMemberExpression(callee) && __babel_core.types.isIdentifier(callee.object) && callee.object.name === "console") return;
154
+ if (__babel_core.types.isIdentifier(callee) && (callee.name === "useIntlayer" || callee.name === "t")) return;
155
+ if (callee.type === "Import") return;
156
+ if (__babel_core.types.isIdentifier(callee) && callee.name === "require") return;
157
+ }
158
+ const text = path.node.value;
159
+ if (shouldExtract(text)) {
160
+ const key = generateKey(text, existingKeys);
161
+ existingKeys.add(key);
162
+ extractedContent[key] = text.trim();
163
+ if (path.node.start != null && path.node.end != null) magic.overwrite(offset + path.node.start, offset + path.node.end, `content.${key}`);
164
+ }
165
+ } });
166
+ } catch (e) {
167
+ console.warn(`Vue extraction: Failed to parse script content for ${filename}`, e);
168
+ }
169
+ }
138
170
  if (Object.keys(extractedContent).length === 0) return null;
139
171
  const scriptContent = sfc.descriptor.scriptSetup?.content ?? sfc.descriptor.script?.content ?? "";
140
172
  const hasUseIntlayerImport = /import\s*{[^}]*useIntlayer[^}]*}\s*from\s*['"][^'"]+['"]/.test(scriptContent) || /import\s+useIntlayer\s+from\s*['"][^'"]+['"]/.test(scriptContent);
@@ -1 +1 @@
1
- {"version":3,"file":"vue-intlayer-extract.cjs","names":["parseVue: (code: string) => VueParseResult","MagicString: new (code: string) => MagicStringType","extractedContent: ExtractedContent"],"sources":["../../src/vue-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\n\n/* ────────────────────────────────────────── constants ───────────────────── */\n\n/**\n * Attributes that should be extracted for localization\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n];\n\n/* ────────────────────────────────────────── types ───────────────────────── */\n\nexport type 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 extraction plugins\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n * @default 'en'\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'vue-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/* ────────────────────────────────────────── helpers ─────────────────────── */\n\n/**\n * Default function to determine if a string should be extracted\n */\nexport const defaultShouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed) return false;\n // Must contain at least one space (likely a sentence/phrase)\n if (!trimmed.includes(' ')) return false;\n // Must start with a capital letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n // Filter out template logic identifiers\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n return true;\n};\n\n/**\n * Generate a unique key from text\n */\nexport const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n let key = text\n .replace(/\\s+/g, ' ')\n .replace(/_+/g, ' ')\n .replace(/-+/g, ' ')\n .replace(/[^a-zA-Z0-9 ]/g, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (!key) key = 'content';\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n\n/**\n * Extract dictionary key from file path\n */\nexport const extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n\n if (baseName === 'index') {\n baseName = basename(dirname(filePath));\n }\n\n // Convert to kebab-case\n const key = baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n\n return `comp-${key}`;\n};\n\n/**\n * Check if a file should be processed based on filesList\n */\nexport const shouldProcessFile = (\n filename: string | undefined,\n filesList?: string[]\n): boolean => {\n if (!filename) return false;\n if (!filesList || filesList.length === 0) return true;\n\n // Normalize paths for comparison (handle potential path separator issues)\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n return filesList.some((f) => {\n const normalizedF = f.replace(/\\\\/g, '/');\n return normalizedF === normalizedFilename;\n });\n};\n\n/* ────────────────────────────────────────── Vue types ───────────────────── */\n\ntype VueParseResult = {\n descriptor: {\n template?: {\n ast: VueAstNode;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n script?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n scriptSetup?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n };\n};\n\ntype VueAstNode = {\n type: number;\n content?: string;\n children?: VueAstNode[];\n props?: VueAstProp[];\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\ntype VueAstProp = {\n type: number;\n name: string;\n value?: { content: string };\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\n// Vue AST NodeTypes\nconst NODE_TYPES = {\n TEXT: 2,\n ELEMENT: 1,\n ATTRIBUTE: 6,\n};\n\n// MagicString type for dynamic import\ntype MagicStringType = {\n overwrite: (start: number, end: number, content: string) => void;\n appendLeft: (index: number, content: string) => void;\n prepend: (content: string) => void;\n toString: () => string;\n generateMap: (options: {\n source: string;\n includeContent: boolean;\n }) => unknown;\n};\n\n/* ────────────────────────────────────────── plugin ──────────────────────── */\n\n/**\n * Vue extraction plugin that extracts content and transforms Vue SFC to use useIntlayer.\n *\n * This plugin:\n * 1. Scans Vue SFC files for extractable text (template text, attributes)\n * 2. Auto-injects useIntlayer import and composable call\n * 3. Reports extracted content via onExtract callback (for the compiler to write dictionaries)\n * 4. Replaces extractable strings with content references\n *\n * ## Input\n * ```vue\n * <template>\n * <div>Hello World</div>\n * </template>\n * ```\n *\n * ## Output\n * ```vue\n * <script setup>\n * import { useIntlayer } from 'vue-intlayer';\n * const content = useIntlayer('hello-world');\n * </script>\n * <template>\n * <div>{{ content.helloWorld }}</div>\n * </template>\n * ```\n */\nexport const intlayerVueExtract = async (\n code: string,\n filename: string,\n options: ExtractPluginOptions = {}\n): Promise<{ code: string; map?: unknown; extracted: boolean } | null> => {\n const {\n defaultLocale = 'en',\n packageName = 'vue-intlayer',\n filesList,\n shouldExtract = defaultShouldExtract,\n onExtract,\n } = options;\n\n // Check if file should be processed\n if (!shouldProcessFile(filename, filesList)) {\n return null;\n }\n\n // Skip non-Vue files\n if (!filename.endsWith('.vue')) {\n return null;\n }\n\n // Dynamic imports for dependencies (peer dependencies)\n let parseVue: (code: string) => VueParseResult;\n let MagicString: new (code: string) => MagicStringType;\n\n try {\n const vueSfc = await import('@vue/compiler-sfc');\n // Type assertion needed because Vue's SFCParseResult uses `null` for optional properties\n // while our VueParseResult uses `undefined` (optional). This is safe since we check\n // for truthy values before accessing template/script properties.\n parseVue = vueSfc.parse as unknown as (code: string) => VueParseResult;\n } catch {\n console.warn(\n 'Vue extraction: @vue/compiler-sfc not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n try {\n const magicStringModule = await import('magic-string');\n MagicString = magicStringModule.default;\n } catch {\n console.warn(\n 'Vue extraction: magic-string not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n const sfc = parseVue(code);\n const magic = new MagicString(code);\n\n const extractedContent: ExtractedContent = {};\n const existingKeys = new Set<string>();\n const dictionaryKey = extractDictionaryKeyFromPath(filename);\n\n // Walk the template AST\n if (sfc.descriptor.template) {\n const walkVueAst = (node: VueAstNode) => {\n if (node.type === NODE_TYPES.TEXT) {\n // Text node\n const text = node.content ?? '';\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.replace(/\\s+/g, ' ').trim();\n magic.overwrite(\n node.loc.start.offset,\n node.loc.end.offset,\n `{{ content.${key} }}`\n );\n }\n } else if (node.type === NODE_TYPES.ELEMENT) {\n // Element node - check attributes\n node.props?.forEach((prop) => {\n if (\n prop.type === NODE_TYPES.ATTRIBUTE &&\n ATTRIBUTES_TO_EXTRACT.includes(prop.name) &&\n prop.value\n ) {\n const text = prop.value.content;\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n magic.overwrite(\n prop.loc.start.offset,\n prop.loc.end.offset,\n `:${prop.name}=\"content.${key}.value\"`\n );\n }\n }\n });\n }\n\n // Recurse into children\n if (node.children) {\n node.children.forEach(walkVueAst);\n }\n };\n\n walkVueAst(sfc.descriptor.template.ast);\n }\n\n // If nothing was extracted, return null\n if (Object.keys(extractedContent).length === 0) {\n return null;\n }\n\n // Get script content for checking existing imports/declarations\n const scriptContent =\n sfc.descriptor.scriptSetup?.content ?? sfc.descriptor.script?.content ?? '';\n\n // Check if useIntlayer is already imported\n const hasUseIntlayerImport =\n /import\\s*{[^}]*useIntlayer[^}]*}\\s*from\\s*['\"][^'\"]+['\"]/.test(\n scriptContent\n ) || /import\\s+useIntlayer\\s+from\\s*['\"][^'\"]+['\"]/.test(scriptContent);\n\n // Check if content variable is already declared with useIntlayer\n const hasContentDeclaration = /const\\s+content\\s*=\\s*useIntlayer\\s*\\(/.test(\n scriptContent\n );\n\n // Skip injection if already using useIntlayer\n if (hasUseIntlayerImport && hasContentDeclaration) {\n return null;\n }\n\n // Prepare injection statements (only what's missing)\n const importStmt = hasUseIntlayerImport\n ? ''\n : `import { useIntlayer } from '${packageName}';`;\n const contentDecl = hasContentDeclaration\n ? ''\n : `const content = useIntlayer('${dictionaryKey}');`;\n\n // Build injection string\n const injectionParts = [importStmt, contentDecl].filter(Boolean);\n if (injectionParts.length === 0) {\n return null;\n }\n const injection = `\\n${injectionParts.join('\\n')}\\n`;\n\n if (sfc.descriptor.scriptSetup) {\n // Insert at the beginning of script setup content\n magic.appendLeft(sfc.descriptor.scriptSetup.loc.start.offset, injection);\n } else if (sfc.descriptor.script) {\n // Insert at the beginning of script content\n magic.appendLeft(sfc.descriptor.script.loc.start.offset, injection);\n } else {\n // No script block, create one\n magic.prepend(`<script setup>\\n${importStmt}\\n${contentDecl}\\n</script>\\n`);\n }\n\n // Call the onExtract callback with extracted content\n if (onExtract) {\n const result: ExtractResult = {\n dictionaryKey,\n filePath: filename,\n content: { ...extractedContent },\n locale: defaultLocale,\n };\n onExtract(result);\n }\n\n return {\n code: magic.toString(),\n map: magic.generateMap({ source: filename, includeContent: true }),\n extracted: true,\n };\n};\n"],"mappings":";;;;;;;AAOA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACD;;;;AAuDD,MAAa,wBAAwB,SAA0B;CAC7D,MAAM,UAAU,KAAK,MAAM;AAC3B,KAAI,CAAC,QAAS,QAAO;AAErB,KAAI,CAAC,QAAQ,SAAS,IAAI,CAAE,QAAO;AAEnC,KAAI,CAAC,SAAS,KAAK,QAAQ,CAAE,QAAO;AAEpC,KAAI,QAAQ,WAAW,IAAI,IAAI,QAAQ,WAAW,KAAK,CAAE,QAAO;AAChE,QAAO;;;;;AAMT,MAAa,eACX,MACA,iBACW;CAEX,IAAI,MAAM,KACP,QAAQ,QAAQ,IAAI,CACpB,QAAQ,OAAO,IAAI,CACnB,QAAQ,OAAO,IAAI,CACnB,QAAQ,kBAAkB,GAAG,CAC7B,MAAM,CACN,MAAM,IAAI,CACV,OAAO,QAAQ,CACf,MAAM,GATQ,EASI,CAClB,KAAK,MAAM,UACV,UAAU,IACN,KAAK,aAAa,GAClB,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,aAAa,CAC/D,CACA,KAAK,GAAG;AAEX,KAAI,CAAC,IAAK,OAAM;AAChB,KAAI,aAAa,IAAI,IAAI,EAAE;EACzB,IAAI,IAAI;AACR,SAAO,aAAa,IAAI,GAAG,MAAM,IAAI,CAAE;AACvC,QAAM,GAAG,MAAM;;AAEjB,QAAO;;;;;AAMT,MAAa,gCAAgC,aAA6B;CAExE,IAAI,mCAAoB,iCADJ,SAAS,CACS;AAEtC,KAAI,aAAa,QACf,2DAA4B,SAAS,CAAC;AASxC,QAAO,QALK,SACT,QAAQ,mBAAmB,QAAQ,CACnC,QAAQ,WAAW,IAAI,CACvB,aAAa;;;;;AAQlB,MAAa,qBACX,UACA,cACY;AACZ,KAAI,CAAC,SAAU,QAAO;AACtB,KAAI,CAAC,aAAa,UAAU,WAAW,EAAG,QAAO;CAGjD,MAAM,qBAAqB,SAAS,QAAQ,OAAO,IAAI;AACvD,QAAO,UAAU,MAAM,MAAM;AAE3B,SADoB,EAAE,QAAQ,OAAO,IAAI,KAClB;GACvB;;AAsCJ,MAAM,aAAa;CACjB,MAAM;CACN,SAAS;CACT,WAAW;CACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CD,MAAa,qBAAqB,OAChC,MACA,UACA,UAAgC,EAAE,KACsC;CACxE,MAAM,EACJ,gBAAgB,MAChB,cAAc,gBACd,WACA,gBAAgB,sBAChB,cACE;AAGJ,KAAI,CAAC,kBAAkB,UAAU,UAAU,CACzC,QAAO;AAIT,KAAI,CAAC,SAAS,SAAS,OAAO,CAC5B,QAAO;CAIT,IAAIA;CACJ,IAAIC;AAEJ,KAAI;AAKF,cAJe,MAAM,OAAO,sBAIV;SACZ;AACN,UAAQ,KACN,4FACD;AACD,SAAO;;AAGT,KAAI;AAEF,iBAD0B,MAAM,OAAO,iBACP;SAC1B;AACN,UAAQ,KACN,uFACD;AACD,SAAO;;CAGT,MAAM,MAAM,SAAS,KAAK;CAC1B,MAAM,QAAQ,IAAI,YAAY,KAAK;CAEnC,MAAMC,mBAAqC,EAAE;CAC7C,MAAM,+BAAe,IAAI,KAAa;CACtC,MAAM,gBAAgB,6BAA6B,SAAS;AAG5D,KAAI,IAAI,WAAW,UAAU;EAC3B,MAAM,cAAc,SAAqB;AACvC,OAAI,KAAK,SAAS,WAAW,MAAM;IAEjC,MAAM,OAAO,KAAK,WAAW;AAC7B,QAAI,cAAc,KAAK,EAAE;KACvB,MAAM,MAAM,YAAY,MAAM,aAAa;AAC3C,kBAAa,IAAI,IAAI;AACrB,sBAAiB,OAAO,KAAK,QAAQ,QAAQ,IAAI,CAAC,MAAM;AACxD,WAAM,UACJ,KAAK,IAAI,MAAM,QACf,KAAK,IAAI,IAAI,QACb,cAAc,IAAI,KACnB;;cAEM,KAAK,SAAS,WAAW,QAElC,MAAK,OAAO,SAAS,SAAS;AAC5B,QACE,KAAK,SAAS,WAAW,aACzB,sBAAsB,SAAS,KAAK,KAAK,IACzC,KAAK,OACL;KACA,MAAM,OAAO,KAAK,MAAM;AACxB,SAAI,cAAc,KAAK,EAAE;MACvB,MAAM,MAAM,YAAY,MAAM,aAAa;AAC3C,mBAAa,IAAI,IAAI;AACrB,uBAAiB,OAAO,KAAK,MAAM;AACnC,YAAM,UACJ,KAAK,IAAI,MAAM,QACf,KAAK,IAAI,IAAI,QACb,IAAI,KAAK,KAAK,YAAY,IAAI,SAC/B;;;KAGL;AAIJ,OAAI,KAAK,SACP,MAAK,SAAS,QAAQ,WAAW;;AAIrC,aAAW,IAAI,WAAW,SAAS,IAAI;;AAIzC,KAAI,OAAO,KAAK,iBAAiB,CAAC,WAAW,EAC3C,QAAO;CAIT,MAAM,gBACJ,IAAI,WAAW,aAAa,WAAW,IAAI,WAAW,QAAQ,WAAW;CAG3E,MAAM,uBACJ,2DAA2D,KACzD,cACD,IAAI,+CAA+C,KAAK,cAAc;CAGzE,MAAM,wBAAwB,yCAAyC,KACrE,cACD;AAGD,KAAI,wBAAwB,sBAC1B,QAAO;CAIT,MAAM,aAAa,uBACf,KACA,gCAAgC,YAAY;CAChD,MAAM,cAAc,wBAChB,KACA,gCAAgC,cAAc;CAGlD,MAAM,iBAAiB,CAAC,YAAY,YAAY,CAAC,OAAO,QAAQ;AAChE,KAAI,eAAe,WAAW,EAC5B,QAAO;CAET,MAAM,YAAY,KAAK,eAAe,KAAK,KAAK,CAAC;AAEjD,KAAI,IAAI,WAAW,YAEjB,OAAM,WAAW,IAAI,WAAW,YAAY,IAAI,MAAM,QAAQ,UAAU;UAC/D,IAAI,WAAW,OAExB,OAAM,WAAW,IAAI,WAAW,OAAO,IAAI,MAAM,QAAQ,UAAU;KAGnE,OAAM,QAAQ,mBAAmB,WAAW,IAAI,YAAY,gBAAe;AAI7E,KAAI,UAOF,WAN8B;EAC5B;EACA,UAAU;EACV,SAAS,EAAE,GAAG,kBAAkB;EAChC,QAAQ;EACT,CACgB;AAGnB,QAAO;EACL,MAAM,MAAM,UAAU;EACtB,KAAK,MAAM,YAAY;GAAE,QAAQ;GAAU,gBAAgB;GAAM,CAAC;EAClE,WAAW;EACZ"}
1
+ {"version":3,"file":"vue-intlayer-extract.cjs","names":["parseVue: (code: string) => VueParseResult","MagicString: new (code: string) => MagicStringType","extractedContent: ExtractedContent","scriptContent","t"],"sources":["../../src/vue-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport { parse, types as t, traverse } from '@babel/core';\n\n/* ────────────────────────────────────────── constants ───────────────────── */\n\n/**\n * Attributes that should be extracted for localization\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n];\n\n/* ────────────────────────────────────────── types ───────────────────────── */\n\nexport type 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 extraction plugins\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n * @default 'en'\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'vue-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/* ────────────────────────────────────────── helpers ─────────────────────── */\n\n/**\n * Default function to determine if a string should be extracted\n */\nexport const defaultShouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed) return false;\n // Must contain at least one space (likely a sentence/phrase)\n if (!trimmed.includes(' ')) return false;\n // Must start with a capital letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n // Filter out template logic identifiers\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n return true;\n};\n\n/**\n * Generate a unique key from text\n */\nexport const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n let key = text\n .replace(/\\s+/g, ' ')\n .replace(/_+/g, ' ')\n .replace(/-+/g, ' ')\n .replace(/[^a-zA-Z0-9 ]/g, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (!key) key = 'content';\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n\n/**\n * Extract dictionary key from file path\n */\nexport const extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n\n if (baseName === 'index') {\n baseName = basename(dirname(filePath));\n }\n\n // Convert to kebab-case\n const key = baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n\n return `comp-${key}`;\n};\n\n/**\n * Check if a file should be processed based on filesList\n */\nexport const shouldProcessFile = (\n filename: string | undefined,\n filesList?: string[]\n): boolean => {\n if (!filename) return false;\n if (!filesList || filesList.length === 0) return true;\n\n // Normalize paths for comparison (handle potential path separator issues)\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n return filesList.some((f) => {\n const normalizedF = f.replace(/\\\\/g, '/');\n return normalizedF === normalizedFilename;\n });\n};\n\n/* ────────────────────────────────────────── Vue types ───────────────────── */\n\ntype VueParseResult = {\n descriptor: {\n template?: {\n ast: VueAstNode;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n script?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n scriptSetup?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n };\n};\n\ntype VueAstNode = {\n type: number;\n content?: string;\n children?: VueAstNode[];\n props?: VueAstProp[];\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\ntype VueAstProp = {\n type: number;\n name: string;\n value?: { content: string };\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\n// Vue AST NodeTypes\nconst NODE_TYPES = {\n TEXT: 2,\n ELEMENT: 1,\n ATTRIBUTE: 6,\n};\n\n// MagicString type for dynamic import\ntype MagicStringType = {\n overwrite: (start: number, end: number, content: string) => void;\n appendLeft: (index: number, content: string) => void;\n prepend: (content: string) => void;\n toString: () => string;\n generateMap: (options: {\n source: string;\n includeContent: boolean;\n }) => unknown;\n};\n\n/* ────────────────────────────────────────── plugin ──────────────────────── */\n\n/**\n * Vue extraction plugin that extracts content and transforms Vue SFC to use useIntlayer.\n *\n * This plugin:\n * 1. Scans Vue SFC files for extractable text (template text, attributes)\n * 2. Auto-injects useIntlayer import and composable call\n * 3. Reports extracted content via onExtract callback (for the compiler to write dictionaries)\n * 4. Replaces extractable strings with content references\n *\n * ## Input\n * ```vue\n * <template>\n * <div>Hello World</div>\n * </template>\n * ```\n *\n * ## Output\n * ```vue\n * <script setup>\n * import { useIntlayer } from 'vue-intlayer';\n * const content = useIntlayer('hello-world');\n * </script>\n * <template>\n * <div>{{ content.helloWorld }}</div>\n * </template>\n * ```\n */\nexport const intlayerVueExtract = async (\n code: string,\n filename: string,\n options: ExtractPluginOptions = {}\n): Promise<{ code: string; map?: unknown; extracted: boolean } | null> => {\n const {\n defaultLocale = 'en',\n packageName = 'vue-intlayer',\n filesList,\n shouldExtract = defaultShouldExtract,\n onExtract,\n } = options;\n\n // Check if file should be processed\n if (!shouldProcessFile(filename, filesList)) {\n return null;\n }\n\n // Skip non-Vue files\n if (!filename.endsWith('.vue')) {\n return null;\n }\n\n // Dynamic imports for dependencies (peer dependencies)\n let parseVue: (code: string) => VueParseResult;\n let MagicString: new (code: string) => MagicStringType;\n\n try {\n const vueSfc = await import('@vue/compiler-sfc');\n // Type assertion needed because Vue's SFCParseResult uses `null` for optional properties\n // while our VueParseResult uses `undefined` (optional). This is safe since we check\n // for truthy values before accessing template/script properties.\n parseVue = vueSfc.parse as unknown as (code: string) => VueParseResult;\n } catch {\n console.warn(\n 'Vue extraction: @vue/compiler-sfc not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n try {\n const magicStringModule = await import('magic-string');\n MagicString = magicStringModule.default;\n } catch {\n console.warn(\n 'Vue extraction: magic-string not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n const sfc = parseVue(code);\n const magic = new MagicString(code);\n\n const extractedContent: ExtractedContent = {};\n const existingKeys = new Set<string>();\n const dictionaryKey = extractDictionaryKeyFromPath(filename);\n\n // Walk the template AST\n if (sfc.descriptor.template) {\n const walkVueAst = (node: VueAstNode) => {\n if (node.type === NODE_TYPES.TEXT) {\n // Text node\n const text = node.content ?? '';\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.replace(/\\s+/g, ' ').trim();\n magic.overwrite(\n node.loc.start.offset,\n node.loc.end.offset,\n `{{ content.${key} }}`\n );\n }\n } else if (node.type === NODE_TYPES.ELEMENT) {\n // Element node - check attributes\n node.props?.forEach((prop) => {\n if (\n prop.type === NODE_TYPES.ATTRIBUTE &&\n ATTRIBUTES_TO_EXTRACT.includes(prop.name) &&\n prop.value\n ) {\n const text = prop.value.content;\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n magic.overwrite(\n prop.loc.start.offset,\n prop.loc.end.offset,\n `:${prop.name}=\"content.${key}.value\"`\n );\n }\n }\n });\n }\n\n // Recurse into children\n if (node.children) {\n node.children.forEach(walkVueAst);\n }\n };\n\n walkVueAst(sfc.descriptor.template.ast);\n }\n\n // Extract script content\n const scriptBlock = sfc.descriptor.scriptSetup ?? sfc.descriptor.script;\n\n if (scriptBlock) {\n const scriptContent = scriptBlock.content;\n const offset = scriptBlock.loc.start.offset;\n\n try {\n const ast = parse(scriptContent, {\n parserOpts: {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n },\n });\n\n traverse(ast, {\n StringLiteral(path) {\n if (path.parentPath.isImportDeclaration()) return;\n if (path.parentPath.isExportDeclaration()) return;\n if (path.parentPath.isImportSpecifier()) return;\n if (path.parentPath.isObjectProperty() && path.key === 'key') return;\n\n if (path.parentPath.isCallExpression()) {\n const callee = path.parentPath.node.callee;\n if (\n t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console'\n ) {\n return;\n }\n if (\n t.isIdentifier(callee) &&\n (callee.name === 'useIntlayer' || callee.name === 't')\n ) {\n return;\n }\n\n // Check for dynamic import import()\n if (callee.type === 'Import') return;\n\n // Check for require()\n if (t.isIdentifier(callee) && callee.name === 'require') return;\n }\n\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n\n if (path.node.start != null && path.node.end != null) {\n magic.overwrite(\n offset + path.node.start,\n offset + path.node.end,\n `content.${key}`\n );\n }\n }\n },\n });\n } catch (e) {\n console.warn(\n `Vue extraction: Failed to parse script content for ${filename}`,\n e\n );\n }\n }\n\n // If nothing was extracted, return null\n if (Object.keys(extractedContent).length === 0) {\n return null;\n }\n\n // Get script content for checking existing imports/declarations\n const scriptContent =\n sfc.descriptor.scriptSetup?.content ?? sfc.descriptor.script?.content ?? '';\n\n // Check if useIntlayer is already imported\n const hasUseIntlayerImport =\n /import\\s*{[^}]*useIntlayer[^}]*}\\s*from\\s*['\"][^'\"]+['\"]/.test(\n scriptContent\n ) || /import\\s+useIntlayer\\s+from\\s*['\"][^'\"]+['\"]/.test(scriptContent);\n\n // Check if content variable is already declared with useIntlayer\n const hasContentDeclaration = /const\\s+content\\s*=\\s*useIntlayer\\s*\\(/.test(\n scriptContent\n );\n\n // Skip injection if already using useIntlayer\n if (hasUseIntlayerImport && hasContentDeclaration) {\n return null;\n }\n\n // Prepare injection statements (only what's missing)\n const importStmt = hasUseIntlayerImport\n ? ''\n : `import { useIntlayer } from '${packageName}';`;\n const contentDecl = hasContentDeclaration\n ? ''\n : `const content = useIntlayer('${dictionaryKey}');`;\n\n // Build injection string\n const injectionParts = [importStmt, contentDecl].filter(Boolean);\n if (injectionParts.length === 0) {\n return null;\n }\n const injection = `\\n${injectionParts.join('\\n')}\\n`;\n\n if (sfc.descriptor.scriptSetup) {\n // Insert at the beginning of script setup content\n magic.appendLeft(sfc.descriptor.scriptSetup.loc.start.offset, injection);\n } else if (sfc.descriptor.script) {\n // Insert at the beginning of script content\n magic.appendLeft(sfc.descriptor.script.loc.start.offset, injection);\n } else {\n // No script block, create one\n magic.prepend(`<script setup>\\n${importStmt}\\n${contentDecl}\\n</script>\\n`);\n }\n\n // Call the onExtract callback with extracted content\n if (onExtract) {\n const result: ExtractResult = {\n dictionaryKey,\n filePath: filename,\n content: { ...extractedContent },\n locale: defaultLocale,\n };\n onExtract(result);\n }\n\n return {\n code: magic.toString(),\n map: magic.generateMap({ source: filename, includeContent: true }),\n extracted: true,\n };\n};\n"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { join, relative } from "node:path";
3
3
  import { intlayerOptimizeBabelPlugin } from "@intlayer/babel";
4
- import { prepareIntlayer, watch } from "@intlayer/chokidar";
4
+ import { buildFilesList, prepareIntlayer, watch } from "@intlayer/chokidar";
5
5
  import { getAppLogger, getConfiguration } from "@intlayer/config";
6
- import fg from "fast-glob";
7
6
 
8
7
  //#region src/VueIntlayerCompiler.ts
9
8
  /**
@@ -42,21 +41,18 @@ const createVueIntlayerCompiler = (options) => {
42
41
  * Build the list of files to transform based on configuration patterns
43
42
  * Includes Vue-specific patterns
44
43
  */
45
- const buildFilesList = async () => {
44
+ const buildFilesListFn = async () => {
46
45
  const { traversePattern } = config.build;
47
- const { baseDir, mainDir } = config.content;
48
- const transformPattern = customCompilerConfig?.transformPattern ?? traversePattern;
49
- const excludePattern = customCompilerConfig?.excludePattern ?? ["**/node_modules/**"];
50
- const patterns = Array.isArray(transformPattern) ? transformPattern : [transformPattern];
51
- const vuePatterns = patterns.map((p) => {
52
- if (p.includes(".vue") || p.includes("{")) return p;
53
- return p.replace(/\{([^}]+)\}/, (_, exts) => `{${exts},vue}`);
46
+ const { baseDir, mainDir, fileExtensions } = config.content;
47
+ const filesListPattern = buildFilesList({
48
+ transformPattern: customCompilerConfig?.transformPattern ?? traversePattern,
49
+ excludePattern: [
50
+ ...customCompilerConfig?.excludePattern ?? [],
51
+ "**/node_modules/**",
52
+ ...fileExtensions.map((pattern) => `**/*${pattern}`)
53
+ ],
54
+ baseDir
54
55
  });
55
- const excludePatterns = Array.isArray(excludePattern) ? excludePattern : [excludePattern];
56
- const filesListPattern = fg.sync([...new Set([...patterns, ...vuePatterns])], {
57
- cwd: baseDir,
58
- ignore: excludePatterns
59
- }).map((file) => join(baseDir, file));
60
56
  const dictionariesEntryPath = join(mainDir, "dictionaries.mjs");
61
57
  const unmergedDictionariesEntryPath = join(mainDir, "unmerged_dictionaries.mjs");
62
58
  filesList = [
@@ -89,7 +85,7 @@ const createVueIntlayerCompiler = (options) => {
89
85
  } catch {
90
86
  logger("Failed to load @babel/core. Transformation will be disabled.", { level: "warn" });
91
87
  }
92
- await buildFilesList();
88
+ await buildFilesListFn();
93
89
  await loadLiveSyncKeys();
94
90
  };
95
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"VueIntlayerCompiler.mjs","names":["config: IntlayerConfig","logger: ReturnType<typeof getAppLogger>","mode: CompilerMode","filesList: string[]","babel: typeof import('@babel/core') | null","liveSyncKeys: string[]","compilerMode: CompilerMode"],"sources":["../../src/VueIntlayerCompiler.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { join, relative } from 'node:path';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport { watch as chokidarWatch, prepareIntlayer } from '@intlayer/chokidar';\nimport {\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type { CompilerConfig, IntlayerConfig } from '@intlayer/types';\nimport fg from 'fast-glob';\n\n/**\n * Mode of the compiler\n */\nexport type CompilerMode = 'dev' | 'build';\n\n/**\n * Context for hot update handling\n */\nexport type HotUpdateContext = {\n file: string;\n server: {\n ws: { send: (message: { type: string }) => void };\n moduleGraph: {\n getModulesByFile: (file: string) => Set<unknown> | null | undefined;\n invalidateModule: (\n module: unknown,\n seen: Set<unknown>,\n timestamp: number,\n isHmr: boolean\n ) => void;\n };\n };\n timestamp: number;\n};\n\n/**\n * Transform result from the compiler\n */\nexport type TransformResult = {\n code?: string;\n map?: unknown;\n} | null;\n\n/**\n * Options for initializing the Vue compiler\n */\nexport type VueIntlayerCompilerOptions = {\n /**\n * Configuration options for getting the intlayer configuration\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Custom compiler configuration to override defaults\n */\n compilerConfig?: Partial<CompilerConfig>;\n};\n\n/**\n * Vite plugin object returned by the compiler\n */\nexport type VueIntlayerVitePlugin = {\n name: string;\n enforce: 'pre' | 'post';\n configResolved: (config: {\n env?: { DEV?: boolean };\n root: string;\n }) => Promise<void>;\n buildStart: () => Promise<void>;\n configureServer: () => Promise<void>;\n handleHotUpdate: (ctx: HotUpdateContext) => Promise<unknown[] | undefined>;\n transform: {\n order: 'pre' | 'post';\n handler: (\n code: string,\n id: string,\n options?: { ssr?: boolean }\n ) => Promise<TransformResult>;\n };\n apply: (config: unknown, env: { command: string }) => boolean;\n};\n\n/**\n * Create a VueIntlayerCompiler - A Vite-compatible compiler plugin for Vue with Intlayer\n *\n * Handles Vue Single File Components (SFC) with special handling for:\n * - Script blocks in .vue files\n * - TypeScript in Vue files\n * - Vue-specific transformations\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import vue from '@vitejs/plugin-vue';\n * import { vueIntlayerCompiler } from '@intlayer/vue-compiler';\n *\n * export default defineConfig({\n * plugins: [vue(), vueIntlayerCompiler()],\n * });\n * ```\n */\nexport const createVueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n // Private state\n let config: IntlayerConfig;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let mode: CompilerMode = 'dev';\n let hmrVersion = -1;\n const lastSourceTriggeredWrite = 0;\n let filesList: string[] = [];\n // @ts-expect-error - @babel/core is a peer dependency\n let babel: typeof import('@babel/core') | null = null;\n let liveSyncKeys: string[] = [];\n\n const configOptions = options?.configOptions;\n const customCompilerConfig = options?.compilerConfig;\n\n /**\n * Build the list of files to transform based on configuration patterns\n * Includes Vue-specific patterns\n */\n const buildFilesList = async (): Promise<void> => {\n const { traversePattern } = config.build;\n const { baseDir, mainDir } = config.content;\n\n const transformPattern =\n customCompilerConfig?.transformPattern ?? traversePattern;\n const excludePattern = customCompilerConfig?.excludePattern ?? [\n '**/node_modules/**',\n ];\n\n // Add Vue file patterns\n const patterns = Array.isArray(transformPattern)\n ? transformPattern\n : [transformPattern];\n const vuePatterns = patterns.map((p) => {\n // Ensure Vue files are included\n if (p.includes('.vue') || p.includes('{')) {\n return p;\n }\n // Add .vue extension to patterns\n return p.replace(/\\{([^}]+)\\}/, (_, exts) => `{${exts},vue}`);\n });\n\n const excludePatterns = Array.isArray(excludePattern)\n ? excludePattern\n : [excludePattern];\n\n const filesListPattern = fg\n .sync([...new Set([...patterns, ...vuePatterns])], {\n cwd: baseDir,\n ignore: excludePatterns,\n })\n .map((file) => join(baseDir, file));\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n\n filesList = [\n ...filesListPattern,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ];\n };\n\n /**\n * Load dictionary keys that have live sync enabled\n */\n const loadLiveSyncKeys = async (): Promise<void> => {\n try {\n const { getDictionaries } = await import('@intlayer/dictionaries-entry');\n const dictionaries = getDictionaries() as Record<\n string,\n { live?: boolean; key: string }\n >;\n liveSyncKeys = Object.values(dictionaries)\n .filter((dictionary) => dictionary.live)\n .map((dictionary) => dictionary.key);\n } catch {\n liveSyncKeys = [];\n }\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (compilerMode: CompilerMode): Promise<void> => {\n mode = compilerMode;\n config = getConfiguration(configOptions);\n logger = getAppLogger(config);\n\n // Load Babel dynamically\n try {\n const localRequire = createRequire(import.meta.url);\n babel = localRequire('@babel/core');\n } catch {\n logger('Failed to load @babel/core. Transformation will be disabled.', {\n level: 'warn',\n });\n }\n\n // Build files list for transformation\n await buildFilesList();\n\n // Load live sync keys\n await loadLiveSyncKeys();\n };\n\n /**\n * Vite hook: configResolved\n */\n const configResolved = async (viteConfig: {\n env?: { DEV?: boolean };\n root: string;\n }): Promise<void> => {\n const compilerMode: CompilerMode = viteConfig.env?.DEV ? 'dev' : 'build';\n projectRoot = viteConfig.root;\n await init(compilerMode);\n };\n\n /**\n * Prepare intlayer dictionaries and types\n */\n const buildStart = async (): Promise<void> => {\n const isBuild = mode === 'build';\n\n await prepareIntlayer(config, {\n clean: isBuild,\n cacheTimeoutMs: isBuild ? 1000 * 30 : 1000 * 60 * 60,\n });\n };\n\n /**\n * Configure the dev server with file watching\n */\n const configureServer = async (): Promise<void> => {\n if (config.content.watch) {\n chokidarWatch({ configuration: config });\n }\n };\n\n /**\n * Handle HMR for content changes\n */\n const handleHotUpdate = async (\n ctx: HotUpdateContext\n ): Promise<unknown[] | undefined> => {\n const { file, server } = ctx;\n\n // Check if this is a content declaration file\n const isContentFile = config.content.watchedFilesPatternWithPath.some(\n (pattern: string) => {\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/]*')\n );\n return regex.test(file);\n }\n );\n\n if (!isContentFile) {\n const dictionariesDir = config.content.dictionariesDir;\n if (file.startsWith(dictionariesDir)) {\n return [];\n }\n hmrVersion++;\n return undefined;\n }\n\n const sourceTriggered = performance.now() - lastSourceTriggeredWrite < 1000;\n\n if (!sourceTriggered) {\n server.ws.send({ type: 'full-reload' });\n return [];\n }\n\n return undefined;\n };\n\n /**\n * Transform handler with Vue-specific handling\n */\n const transformHandler = async (\n code: string,\n id: string,\n _options?: { ssr?: boolean }\n ): Promise<TransformResult> => {\n if (!babel) {\n return null;\n }\n\n const { optimize, importMode } = config.build;\n\n if (!optimize && mode !== 'build') {\n return null;\n }\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n } = config.content;\n\n /**\n * Handle Vue SFC virtual modules\n * Transform paths like:\n * - .../Component.vue?vue&type=script&setup=true&lang.ts\n * Into:\n * - .../Component.vue\n */\n const filename = id.split('?', 1)[0];\n\n // Check if this file should be transformed\n // For Vue files, also check the base .vue file\n const isVueVirtualModule = id.includes('?vue&type=script');\n const checkFilename = isVueVirtualModule ? filename : filename;\n\n if (!filesList.includes(checkFilename)) {\n // Also check without the virtual module query\n const baseVueFile = filename.endsWith('.vue') ? filename : null;\n if (\n !baseVueFile ||\n !filesList.some((f) => f === baseVueFile || f.startsWith(baseVueFile))\n ) {\n return null;\n }\n }\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\n try {\n const result = babel.transformSync(code, {\n filename,\n plugins: [\n [\n intlayerOptimizeBabelPlugin,\n {\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n importMode,\n filesList,\n replaceDictionaryEntry: true,\n liveSyncKeys,\n },\n ],\n ],\n parserOpts: {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n },\n });\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n } catch (error) {\n logger(\n `Failed to transform Vue file ${relative(projectRoot, filename)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n return null;\n };\n\n /**\n * Apply hook for determining when plugin should be active\n */\n const apply = (_config: unknown, env: { command: string }): boolean => {\n const { optimize } = config?.build ?? {};\n const isEnabled = customCompilerConfig?.enabled ?? true;\n const isBuild = env.command === 'build';\n\n return isEnabled && (isBuild ? (optimize ?? true) : (optimize ?? false));\n };\n\n return {\n name: 'vue-intlayer-compiler',\n enforce: 'post', // Run after Vue plugin\n configResolved,\n buildStart,\n configureServer,\n handleHotUpdate,\n transform: {\n order: 'post', // Run after Vue plugin transformation\n handler: transformHandler,\n },\n apply: (_viteConfig: unknown, env: { command: string }) => {\n if (!config) {\n config = getConfiguration(configOptions);\n }\n return apply(_viteConfig, env);\n },\n };\n};\n\n/**\n * Factory function for creating a Vite plugin\n */\nexport const vueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n return createVueIntlayerCompiler(options);\n};\n\n// Legacy export for backwards compatibility\nexport const VueIntlayerCompiler = createVueIntlayerCompiler;\n"],"mappings":"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"}
1
+ {"version":3,"file":"VueIntlayerCompiler.mjs","names":["config: IntlayerConfig","logger: ReturnType<typeof getAppLogger>","mode: CompilerMode","filesList: string[]","babel: typeof import('@babel/core') | null","liveSyncKeys: string[]","compilerMode: CompilerMode"],"sources":["../../src/VueIntlayerCompiler.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { join, relative } from 'node:path';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport {\n buildFilesList,\n watch as chokidarWatch,\n prepareIntlayer,\n} from '@intlayer/chokidar';\nimport {\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type { CompilerConfig, IntlayerConfig } from '@intlayer/types';\n\n/**\n * Mode of the compiler\n */\nexport type CompilerMode = 'dev' | 'build';\n\n/**\n * Context for hot update handling\n */\nexport type HotUpdateContext = {\n file: string;\n server: {\n ws: { send: (message: { type: string }) => void };\n moduleGraph: {\n getModulesByFile: (file: string) => Set<unknown> | null | undefined;\n invalidateModule: (\n module: unknown,\n seen: Set<unknown>,\n timestamp: number,\n isHmr: boolean\n ) => void;\n };\n };\n timestamp: number;\n};\n\n/**\n * Transform result from the compiler\n */\nexport type TransformResult = {\n code?: string;\n map?: unknown;\n} | null;\n\n/**\n * Options for initializing the Vue compiler\n */\nexport type VueIntlayerCompilerOptions = {\n /**\n * Configuration options for getting the intlayer configuration\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Custom compiler configuration to override defaults\n */\n compilerConfig?: Partial<CompilerConfig>;\n};\n\n/**\n * Vite plugin object returned by the compiler\n */\nexport type VueIntlayerVitePlugin = {\n name: string;\n enforce: 'pre' | 'post';\n configResolved: (config: {\n env?: { DEV?: boolean };\n root: string;\n }) => Promise<void>;\n buildStart: () => Promise<void>;\n configureServer: () => Promise<void>;\n handleHotUpdate: (ctx: HotUpdateContext) => Promise<unknown[] | undefined>;\n transform: {\n order: 'pre' | 'post';\n handler: (\n code: string,\n id: string,\n options?: { ssr?: boolean }\n ) => Promise<TransformResult>;\n };\n apply: (config: unknown, env: { command: string }) => boolean;\n};\n\n/**\n * Create a VueIntlayerCompiler - A Vite-compatible compiler plugin for Vue with Intlayer\n *\n * Handles Vue Single File Components (SFC) with special handling for:\n * - Script blocks in .vue files\n * - TypeScript in Vue files\n * - Vue-specific transformations\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import vue from '@vitejs/plugin-vue';\n * import { vueIntlayerCompiler } from '@intlayer/vue-compiler';\n *\n * export default defineConfig({\n * plugins: [vue(), vueIntlayerCompiler()],\n * });\n * ```\n */\nexport const createVueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n // Private state\n let config: IntlayerConfig;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let mode: CompilerMode = 'dev';\n let hmrVersion = -1;\n const lastSourceTriggeredWrite = 0;\n let filesList: string[] = [];\n // @ts-expect-error - @babel/core is a peer dependency\n let babel: typeof import('@babel/core') | null = null;\n let liveSyncKeys: string[] = [];\n\n const configOptions = options?.configOptions;\n const customCompilerConfig = options?.compilerConfig;\n\n /**\n * Build the list of files to transform based on configuration patterns\n * Includes Vue-specific patterns\n */\n const buildFilesListFn = async (): Promise<void> => {\n const { traversePattern } = config.build;\n const { baseDir, mainDir, fileExtensions } = config.content;\n\n const filesListPattern = buildFilesList({\n transformPattern:\n customCompilerConfig?.transformPattern ?? traversePattern,\n excludePattern: [\n ...(customCompilerConfig?.excludePattern ?? []),\n '**/node_modules/**',\n ...fileExtensions.map((pattern) => `**/*${pattern}`),\n ],\n baseDir,\n });\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n\n filesList = [\n ...filesListPattern,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ];\n };\n\n /**\n * Load dictionary keys that have live sync enabled\n */\n const loadLiveSyncKeys = async (): Promise<void> => {\n try {\n const { getDictionaries } = await import('@intlayer/dictionaries-entry');\n const dictionaries = getDictionaries() as Record<\n string,\n { live?: boolean; key: string }\n >;\n liveSyncKeys = Object.values(dictionaries)\n .filter((dictionary) => dictionary.live)\n .map((dictionary) => dictionary.key);\n } catch {\n liveSyncKeys = [];\n }\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (compilerMode: CompilerMode): Promise<void> => {\n mode = compilerMode;\n config = getConfiguration(configOptions);\n logger = getAppLogger(config);\n\n // Load Babel dynamically\n try {\n const localRequire = createRequire(import.meta.url);\n babel = localRequire('@babel/core');\n } catch {\n logger('Failed to load @babel/core. Transformation will be disabled.', {\n level: 'warn',\n });\n }\n\n // Build files list for transformation\n await buildFilesListFn();\n\n // Load live sync keys\n await loadLiveSyncKeys();\n };\n\n /**\n * Vite hook: configResolved\n */\n const configResolved = async (viteConfig: {\n env?: { DEV?: boolean };\n root: string;\n }): Promise<void> => {\n const compilerMode: CompilerMode = viteConfig.env?.DEV ? 'dev' : 'build';\n projectRoot = viteConfig.root;\n await init(compilerMode);\n };\n\n /**\n * Prepare intlayer dictionaries and types\n */\n const buildStart = async (): Promise<void> => {\n const isBuild = mode === 'build';\n\n await prepareIntlayer(config, {\n clean: isBuild,\n cacheTimeoutMs: isBuild ? 1000 * 30 : 1000 * 60 * 60,\n });\n };\n\n /**\n * Configure the dev server with file watching\n */\n const configureServer = async (): Promise<void> => {\n if (config.content.watch) {\n chokidarWatch({ configuration: config });\n }\n };\n\n /**\n * Handle HMR for content changes\n */\n const handleHotUpdate = async (\n ctx: HotUpdateContext\n ): Promise<unknown[] | undefined> => {\n const { file, server } = ctx;\n\n // Check if this is a content declaration file\n const isContentFile = config.content.watchedFilesPatternWithPath.some(\n (pattern: string) => {\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/]*')\n );\n return regex.test(file);\n }\n );\n\n if (!isContentFile) {\n const dictionariesDir = config.content.dictionariesDir;\n if (file.startsWith(dictionariesDir)) {\n return [];\n }\n hmrVersion++;\n return undefined;\n }\n\n const sourceTriggered = performance.now() - lastSourceTriggeredWrite < 1000;\n\n if (!sourceTriggered) {\n server.ws.send({ type: 'full-reload' });\n return [];\n }\n\n return undefined;\n };\n\n /**\n * Transform handler with Vue-specific handling\n */\n const transformHandler = async (\n code: string,\n id: string,\n _options?: { ssr?: boolean }\n ): Promise<TransformResult> => {\n if (!babel) {\n return null;\n }\n\n const { optimize, importMode } = config.build;\n\n if (!optimize && mode !== 'build') {\n return null;\n }\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n } = config.content;\n\n /**\n * Handle Vue SFC virtual modules\n * Transform paths like:\n * - .../Component.vue?vue&type=script&setup=true&lang.ts\n * Into:\n * - .../Component.vue\n */\n const filename = id.split('?', 1)[0];\n\n // Check if this file should be transformed\n // For Vue files, also check the base .vue file\n const isVueVirtualModule = id.includes('?vue&type=script');\n const checkFilename = isVueVirtualModule ? filename : filename;\n\n if (!filesList.includes(checkFilename)) {\n // Also check without the virtual module query\n const baseVueFile = filename.endsWith('.vue') ? filename : null;\n if (\n !baseVueFile ||\n !filesList.some((f) => f === baseVueFile || f.startsWith(baseVueFile))\n ) {\n return null;\n }\n }\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\n try {\n const result = babel.transformSync(code, {\n filename,\n plugins: [\n [\n intlayerOptimizeBabelPlugin,\n {\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n importMode,\n filesList,\n replaceDictionaryEntry: true,\n liveSyncKeys,\n },\n ],\n ],\n parserOpts: {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n },\n });\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n } catch (error) {\n logger(\n `Failed to transform Vue file ${relative(projectRoot, filename)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n return null;\n };\n\n /**\n * Apply hook for determining when plugin should be active\n */\n const apply = (_config: unknown, env: { command: string }): boolean => {\n const { optimize } = config?.build ?? {};\n const isEnabled = customCompilerConfig?.enabled ?? true;\n const isBuild = env.command === 'build';\n\n return isEnabled && (isBuild ? (optimize ?? true) : (optimize ?? false));\n };\n\n return {\n name: 'vue-intlayer-compiler',\n enforce: 'post', // Run after Vue plugin\n configResolved,\n buildStart,\n configureServer,\n handleHotUpdate,\n transform: {\n order: 'post', // Run after Vue plugin transformation\n handler: transformHandler,\n },\n apply: (_viteConfig: unknown, env: { command: string }) => {\n if (!config) {\n config = getConfiguration(configOptions);\n }\n return apply(_viteConfig, env);\n },\n };\n};\n\n/**\n * Factory function for creating a Vite plugin\n */\nexport const vueIntlayerCompiler = (\n options?: VueIntlayerCompilerOptions\n): VueIntlayerVitePlugin => {\n return createVueIntlayerCompiler(options);\n};\n\n// Legacy export for backwards compatibility\nexport const VueIntlayerCompiler = createVueIntlayerCompiler;\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { basename, dirname, extname } from "node:path";
2
+ import { parse, traverse, types } from "@babel/core";
2
3
 
3
4
  //#region src/vue-intlayer-extract.ts
4
5
  /**
@@ -134,6 +135,38 @@ const intlayerVueExtract = async (code, filename, options = {}) => {
134
135
  };
135
136
  walkVueAst(sfc.descriptor.template.ast);
136
137
  }
138
+ const scriptBlock = sfc.descriptor.scriptSetup ?? sfc.descriptor.script;
139
+ if (scriptBlock) {
140
+ const scriptContent$1 = scriptBlock.content;
141
+ const offset = scriptBlock.loc.start.offset;
142
+ try {
143
+ traverse(parse(scriptContent$1, { parserOpts: {
144
+ sourceType: "module",
145
+ plugins: ["typescript", "jsx"]
146
+ } }), { StringLiteral(path) {
147
+ if (path.parentPath.isImportDeclaration()) return;
148
+ if (path.parentPath.isExportDeclaration()) return;
149
+ if (path.parentPath.isImportSpecifier()) return;
150
+ if (path.parentPath.isObjectProperty() && path.key === "key") return;
151
+ if (path.parentPath.isCallExpression()) {
152
+ const callee = path.parentPath.node.callee;
153
+ if (types.isMemberExpression(callee) && types.isIdentifier(callee.object) && callee.object.name === "console") return;
154
+ if (types.isIdentifier(callee) && (callee.name === "useIntlayer" || callee.name === "t")) return;
155
+ if (callee.type === "Import") return;
156
+ if (types.isIdentifier(callee) && callee.name === "require") return;
157
+ }
158
+ const text = path.node.value;
159
+ if (shouldExtract(text)) {
160
+ const key = generateKey(text, existingKeys);
161
+ existingKeys.add(key);
162
+ extractedContent[key] = text.trim();
163
+ if (path.node.start != null && path.node.end != null) magic.overwrite(offset + path.node.start, offset + path.node.end, `content.${key}`);
164
+ }
165
+ } });
166
+ } catch (e) {
167
+ console.warn(`Vue extraction: Failed to parse script content for ${filename}`, e);
168
+ }
169
+ }
137
170
  if (Object.keys(extractedContent).length === 0) return null;
138
171
  const scriptContent = sfc.descriptor.scriptSetup?.content ?? sfc.descriptor.script?.content ?? "";
139
172
  const hasUseIntlayerImport = /import\s*{[^}]*useIntlayer[^}]*}\s*from\s*['"][^'"]+['"]/.test(scriptContent) || /import\s+useIntlayer\s+from\s*['"][^'"]+['"]/.test(scriptContent);
@@ -1 +1 @@
1
- {"version":3,"file":"vue-intlayer-extract.mjs","names":["parseVue: (code: string) => VueParseResult","MagicString: new (code: string) => MagicStringType","extractedContent: ExtractedContent"],"sources":["../../src/vue-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\n\n/* ────────────────────────────────────────── constants ───────────────────── */\n\n/**\n * Attributes that should be extracted for localization\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n];\n\n/* ────────────────────────────────────────── types ───────────────────────── */\n\nexport type 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 extraction plugins\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n * @default 'en'\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'vue-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/* ────────────────────────────────────────── helpers ─────────────────────── */\n\n/**\n * Default function to determine if a string should be extracted\n */\nexport const defaultShouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed) return false;\n // Must contain at least one space (likely a sentence/phrase)\n if (!trimmed.includes(' ')) return false;\n // Must start with a capital letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n // Filter out template logic identifiers\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n return true;\n};\n\n/**\n * Generate a unique key from text\n */\nexport const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n let key = text\n .replace(/\\s+/g, ' ')\n .replace(/_+/g, ' ')\n .replace(/-+/g, ' ')\n .replace(/[^a-zA-Z0-9 ]/g, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (!key) key = 'content';\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n\n/**\n * Extract dictionary key from file path\n */\nexport const extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n\n if (baseName === 'index') {\n baseName = basename(dirname(filePath));\n }\n\n // Convert to kebab-case\n const key = baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n\n return `comp-${key}`;\n};\n\n/**\n * Check if a file should be processed based on filesList\n */\nexport const shouldProcessFile = (\n filename: string | undefined,\n filesList?: string[]\n): boolean => {\n if (!filename) return false;\n if (!filesList || filesList.length === 0) return true;\n\n // Normalize paths for comparison (handle potential path separator issues)\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n return filesList.some((f) => {\n const normalizedF = f.replace(/\\\\/g, '/');\n return normalizedF === normalizedFilename;\n });\n};\n\n/* ────────────────────────────────────────── Vue types ───────────────────── */\n\ntype VueParseResult = {\n descriptor: {\n template?: {\n ast: VueAstNode;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n script?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n scriptSetup?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n };\n};\n\ntype VueAstNode = {\n type: number;\n content?: string;\n children?: VueAstNode[];\n props?: VueAstProp[];\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\ntype VueAstProp = {\n type: number;\n name: string;\n value?: { content: string };\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\n// Vue AST NodeTypes\nconst NODE_TYPES = {\n TEXT: 2,\n ELEMENT: 1,\n ATTRIBUTE: 6,\n};\n\n// MagicString type for dynamic import\ntype MagicStringType = {\n overwrite: (start: number, end: number, content: string) => void;\n appendLeft: (index: number, content: string) => void;\n prepend: (content: string) => void;\n toString: () => string;\n generateMap: (options: {\n source: string;\n includeContent: boolean;\n }) => unknown;\n};\n\n/* ────────────────────────────────────────── plugin ──────────────────────── */\n\n/**\n * Vue extraction plugin that extracts content and transforms Vue SFC to use useIntlayer.\n *\n * This plugin:\n * 1. Scans Vue SFC files for extractable text (template text, attributes)\n * 2. Auto-injects useIntlayer import and composable call\n * 3. Reports extracted content via onExtract callback (for the compiler to write dictionaries)\n * 4. Replaces extractable strings with content references\n *\n * ## Input\n * ```vue\n * <template>\n * <div>Hello World</div>\n * </template>\n * ```\n *\n * ## Output\n * ```vue\n * <script setup>\n * import { useIntlayer } from 'vue-intlayer';\n * const content = useIntlayer('hello-world');\n * </script>\n * <template>\n * <div>{{ content.helloWorld }}</div>\n * </template>\n * ```\n */\nexport const intlayerVueExtract = async (\n code: string,\n filename: string,\n options: ExtractPluginOptions = {}\n): Promise<{ code: string; map?: unknown; extracted: boolean } | null> => {\n const {\n defaultLocale = 'en',\n packageName = 'vue-intlayer',\n filesList,\n shouldExtract = defaultShouldExtract,\n onExtract,\n } = options;\n\n // Check if file should be processed\n if (!shouldProcessFile(filename, filesList)) {\n return null;\n }\n\n // Skip non-Vue files\n if (!filename.endsWith('.vue')) {\n return null;\n }\n\n // Dynamic imports for dependencies (peer dependencies)\n let parseVue: (code: string) => VueParseResult;\n let MagicString: new (code: string) => MagicStringType;\n\n try {\n const vueSfc = await import('@vue/compiler-sfc');\n // Type assertion needed because Vue's SFCParseResult uses `null` for optional properties\n // while our VueParseResult uses `undefined` (optional). This is safe since we check\n // for truthy values before accessing template/script properties.\n parseVue = vueSfc.parse as unknown as (code: string) => VueParseResult;\n } catch {\n console.warn(\n 'Vue extraction: @vue/compiler-sfc not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n try {\n const magicStringModule = await import('magic-string');\n MagicString = magicStringModule.default;\n } catch {\n console.warn(\n 'Vue extraction: magic-string not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n const sfc = parseVue(code);\n const magic = new MagicString(code);\n\n const extractedContent: ExtractedContent = {};\n const existingKeys = new Set<string>();\n const dictionaryKey = extractDictionaryKeyFromPath(filename);\n\n // Walk the template AST\n if (sfc.descriptor.template) {\n const walkVueAst = (node: VueAstNode) => {\n if (node.type === NODE_TYPES.TEXT) {\n // Text node\n const text = node.content ?? '';\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.replace(/\\s+/g, ' ').trim();\n magic.overwrite(\n node.loc.start.offset,\n node.loc.end.offset,\n `{{ content.${key} }}`\n );\n }\n } else if (node.type === NODE_TYPES.ELEMENT) {\n // Element node - check attributes\n node.props?.forEach((prop) => {\n if (\n prop.type === NODE_TYPES.ATTRIBUTE &&\n ATTRIBUTES_TO_EXTRACT.includes(prop.name) &&\n prop.value\n ) {\n const text = prop.value.content;\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n magic.overwrite(\n prop.loc.start.offset,\n prop.loc.end.offset,\n `:${prop.name}=\"content.${key}.value\"`\n );\n }\n }\n });\n }\n\n // Recurse into children\n if (node.children) {\n node.children.forEach(walkVueAst);\n }\n };\n\n walkVueAst(sfc.descriptor.template.ast);\n }\n\n // If nothing was extracted, return null\n if (Object.keys(extractedContent).length === 0) {\n return null;\n }\n\n // Get script content for checking existing imports/declarations\n const scriptContent =\n sfc.descriptor.scriptSetup?.content ?? sfc.descriptor.script?.content ?? '';\n\n // Check if useIntlayer is already imported\n const hasUseIntlayerImport =\n /import\\s*{[^}]*useIntlayer[^}]*}\\s*from\\s*['\"][^'\"]+['\"]/.test(\n scriptContent\n ) || /import\\s+useIntlayer\\s+from\\s*['\"][^'\"]+['\"]/.test(scriptContent);\n\n // Check if content variable is already declared with useIntlayer\n const hasContentDeclaration = /const\\s+content\\s*=\\s*useIntlayer\\s*\\(/.test(\n scriptContent\n );\n\n // Skip injection if already using useIntlayer\n if (hasUseIntlayerImport && hasContentDeclaration) {\n return null;\n }\n\n // Prepare injection statements (only what's missing)\n const importStmt = hasUseIntlayerImport\n ? ''\n : `import { useIntlayer } from '${packageName}';`;\n const contentDecl = hasContentDeclaration\n ? ''\n : `const content = useIntlayer('${dictionaryKey}');`;\n\n // Build injection string\n const injectionParts = [importStmt, contentDecl].filter(Boolean);\n if (injectionParts.length === 0) {\n return null;\n }\n const injection = `\\n${injectionParts.join('\\n')}\\n`;\n\n if (sfc.descriptor.scriptSetup) {\n // Insert at the beginning of script setup content\n magic.appendLeft(sfc.descriptor.scriptSetup.loc.start.offset, injection);\n } else if (sfc.descriptor.script) {\n // Insert at the beginning of script content\n magic.appendLeft(sfc.descriptor.script.loc.start.offset, injection);\n } else {\n // No script block, create one\n magic.prepend(`<script setup>\\n${importStmt}\\n${contentDecl}\\n</script>\\n`);\n }\n\n // Call the onExtract callback with extracted content\n if (onExtract) {\n const result: ExtractResult = {\n dictionaryKey,\n filePath: filename,\n content: { ...extractedContent },\n locale: defaultLocale,\n };\n onExtract(result);\n }\n\n return {\n code: magic.toString(),\n map: magic.generateMap({ source: filename, includeContent: true }),\n extracted: true,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"vue-intlayer-extract.mjs","names":["parseVue: (code: string) => VueParseResult","MagicString: new (code: string) => MagicStringType","extractedContent: ExtractedContent","scriptContent","t"],"sources":["../../src/vue-intlayer-extract.ts"],"sourcesContent":["import { basename, dirname, extname } from 'node:path';\nimport { parse, types as t, traverse } from '@babel/core';\n\n/* ────────────────────────────────────────── constants ───────────────────── */\n\n/**\n * Attributes that should be extracted for localization\n */\nexport const ATTRIBUTES_TO_EXTRACT = [\n 'title',\n 'placeholder',\n 'alt',\n 'aria-label',\n 'label',\n];\n\n/* ────────────────────────────────────────── types ───────────────────────── */\n\nexport type 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 extraction plugins\n */\nexport type ExtractPluginOptions = {\n /**\n * The default locale for the extracted content\n * @default 'en'\n */\n defaultLocale?: string;\n /**\n * The package to import useIntlayer from\n * @default 'vue-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/* ────────────────────────────────────────── helpers ─────────────────────── */\n\n/**\n * Default function to determine if a string should be extracted\n */\nexport const defaultShouldExtract = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed) return false;\n // Must contain at least one space (likely a sentence/phrase)\n if (!trimmed.includes(' ')) return false;\n // Must start with a capital letter\n if (!/^[A-Z]/.test(trimmed)) return false;\n // Filter out template logic identifiers\n if (trimmed.startsWith('{') || trimmed.startsWith('v-')) return false;\n return true;\n};\n\n/**\n * Generate a unique key from text\n */\nexport const generateKey = (\n text: string,\n existingKeys: Set<string>\n): string => {\n const maxWords = 5;\n let key = text\n .replace(/\\s+/g, ' ')\n .replace(/_+/g, ' ')\n .replace(/-+/g, ' ')\n .replace(/[^a-zA-Z0-9 ]/g, '')\n .trim()\n .split(' ')\n .filter(Boolean)\n .slice(0, maxWords)\n .map((word, index) =>\n index === 0\n ? word.toLowerCase()\n : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n )\n .join('');\n\n if (!key) key = 'content';\n if (existingKeys.has(key)) {\n let i = 1;\n while (existingKeys.has(`${key}${i}`)) i++;\n key = `${key}${i}`;\n }\n return key;\n};\n\n/**\n * Extract dictionary key from file path\n */\nexport const extractDictionaryKeyFromPath = (filePath: string): string => {\n const ext = extname(filePath);\n let baseName = basename(filePath, ext);\n\n if (baseName === 'index') {\n baseName = basename(dirname(filePath));\n }\n\n // Convert to kebab-case\n const key = baseName\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n\n return `comp-${key}`;\n};\n\n/**\n * Check if a file should be processed based on filesList\n */\nexport const shouldProcessFile = (\n filename: string | undefined,\n filesList?: string[]\n): boolean => {\n if (!filename) return false;\n if (!filesList || filesList.length === 0) return true;\n\n // Normalize paths for comparison (handle potential path separator issues)\n const normalizedFilename = filename.replace(/\\\\/g, '/');\n return filesList.some((f) => {\n const normalizedF = f.replace(/\\\\/g, '/');\n return normalizedF === normalizedFilename;\n });\n};\n\n/* ────────────────────────────────────────── Vue types ───────────────────── */\n\ntype VueParseResult = {\n descriptor: {\n template?: {\n ast: VueAstNode;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n script?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n scriptSetup?: {\n content: string;\n loc: { start: { offset: number }; end: { offset: number } };\n };\n };\n};\n\ntype VueAstNode = {\n type: number;\n content?: string;\n children?: VueAstNode[];\n props?: VueAstProp[];\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\ntype VueAstProp = {\n type: number;\n name: string;\n value?: { content: string };\n loc: { start: { offset: number }; end: { offset: number } };\n};\n\n// Vue AST NodeTypes\nconst NODE_TYPES = {\n TEXT: 2,\n ELEMENT: 1,\n ATTRIBUTE: 6,\n};\n\n// MagicString type for dynamic import\ntype MagicStringType = {\n overwrite: (start: number, end: number, content: string) => void;\n appendLeft: (index: number, content: string) => void;\n prepend: (content: string) => void;\n toString: () => string;\n generateMap: (options: {\n source: string;\n includeContent: boolean;\n }) => unknown;\n};\n\n/* ────────────────────────────────────────── plugin ──────────────────────── */\n\n/**\n * Vue extraction plugin that extracts content and transforms Vue SFC to use useIntlayer.\n *\n * This plugin:\n * 1. Scans Vue SFC files for extractable text (template text, attributes)\n * 2. Auto-injects useIntlayer import and composable call\n * 3. Reports extracted content via onExtract callback (for the compiler to write dictionaries)\n * 4. Replaces extractable strings with content references\n *\n * ## Input\n * ```vue\n * <template>\n * <div>Hello World</div>\n * </template>\n * ```\n *\n * ## Output\n * ```vue\n * <script setup>\n * import { useIntlayer } from 'vue-intlayer';\n * const content = useIntlayer('hello-world');\n * </script>\n * <template>\n * <div>{{ content.helloWorld }}</div>\n * </template>\n * ```\n */\nexport const intlayerVueExtract = async (\n code: string,\n filename: string,\n options: ExtractPluginOptions = {}\n): Promise<{ code: string; map?: unknown; extracted: boolean } | null> => {\n const {\n defaultLocale = 'en',\n packageName = 'vue-intlayer',\n filesList,\n shouldExtract = defaultShouldExtract,\n onExtract,\n } = options;\n\n // Check if file should be processed\n if (!shouldProcessFile(filename, filesList)) {\n return null;\n }\n\n // Skip non-Vue files\n if (!filename.endsWith('.vue')) {\n return null;\n }\n\n // Dynamic imports for dependencies (peer dependencies)\n let parseVue: (code: string) => VueParseResult;\n let MagicString: new (code: string) => MagicStringType;\n\n try {\n const vueSfc = await import('@vue/compiler-sfc');\n // Type assertion needed because Vue's SFCParseResult uses `null` for optional properties\n // while our VueParseResult uses `undefined` (optional). This is safe since we check\n // for truthy values before accessing template/script properties.\n parseVue = vueSfc.parse as unknown as (code: string) => VueParseResult;\n } catch {\n console.warn(\n 'Vue extraction: @vue/compiler-sfc not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n try {\n const magicStringModule = await import('magic-string');\n MagicString = magicStringModule.default;\n } catch {\n console.warn(\n 'Vue extraction: magic-string not found. Install it to enable Vue content extraction.'\n );\n return null;\n }\n\n const sfc = parseVue(code);\n const magic = new MagicString(code);\n\n const extractedContent: ExtractedContent = {};\n const existingKeys = new Set<string>();\n const dictionaryKey = extractDictionaryKeyFromPath(filename);\n\n // Walk the template AST\n if (sfc.descriptor.template) {\n const walkVueAst = (node: VueAstNode) => {\n if (node.type === NODE_TYPES.TEXT) {\n // Text node\n const text = node.content ?? '';\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.replace(/\\s+/g, ' ').trim();\n magic.overwrite(\n node.loc.start.offset,\n node.loc.end.offset,\n `{{ content.${key} }}`\n );\n }\n } else if (node.type === NODE_TYPES.ELEMENT) {\n // Element node - check attributes\n node.props?.forEach((prop) => {\n if (\n prop.type === NODE_TYPES.ATTRIBUTE &&\n ATTRIBUTES_TO_EXTRACT.includes(prop.name) &&\n prop.value\n ) {\n const text = prop.value.content;\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n magic.overwrite(\n prop.loc.start.offset,\n prop.loc.end.offset,\n `:${prop.name}=\"content.${key}.value\"`\n );\n }\n }\n });\n }\n\n // Recurse into children\n if (node.children) {\n node.children.forEach(walkVueAst);\n }\n };\n\n walkVueAst(sfc.descriptor.template.ast);\n }\n\n // Extract script content\n const scriptBlock = sfc.descriptor.scriptSetup ?? sfc.descriptor.script;\n\n if (scriptBlock) {\n const scriptContent = scriptBlock.content;\n const offset = scriptBlock.loc.start.offset;\n\n try {\n const ast = parse(scriptContent, {\n parserOpts: {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n },\n });\n\n traverse(ast, {\n StringLiteral(path) {\n if (path.parentPath.isImportDeclaration()) return;\n if (path.parentPath.isExportDeclaration()) return;\n if (path.parentPath.isImportSpecifier()) return;\n if (path.parentPath.isObjectProperty() && path.key === 'key') return;\n\n if (path.parentPath.isCallExpression()) {\n const callee = path.parentPath.node.callee;\n if (\n t.isMemberExpression(callee) &&\n t.isIdentifier(callee.object) &&\n callee.object.name === 'console'\n ) {\n return;\n }\n if (\n t.isIdentifier(callee) &&\n (callee.name === 'useIntlayer' || callee.name === 't')\n ) {\n return;\n }\n\n // Check for dynamic import import()\n if (callee.type === 'Import') return;\n\n // Check for require()\n if (t.isIdentifier(callee) && callee.name === 'require') return;\n }\n\n const text = path.node.value;\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n extractedContent[key] = text.trim();\n\n if (path.node.start != null && path.node.end != null) {\n magic.overwrite(\n offset + path.node.start,\n offset + path.node.end,\n `content.${key}`\n );\n }\n }\n },\n });\n } catch (e) {\n console.warn(\n `Vue extraction: Failed to parse script content for ${filename}`,\n e\n );\n }\n }\n\n // If nothing was extracted, return null\n if (Object.keys(extractedContent).length === 0) {\n return null;\n }\n\n // Get script content for checking existing imports/declarations\n const scriptContent =\n sfc.descriptor.scriptSetup?.content ?? sfc.descriptor.script?.content ?? '';\n\n // Check if useIntlayer is already imported\n const hasUseIntlayerImport =\n /import\\s*{[^}]*useIntlayer[^}]*}\\s*from\\s*['\"][^'\"]+['\"]/.test(\n scriptContent\n ) || /import\\s+useIntlayer\\s+from\\s*['\"][^'\"]+['\"]/.test(scriptContent);\n\n // Check if content variable is already declared with useIntlayer\n const hasContentDeclaration = /const\\s+content\\s*=\\s*useIntlayer\\s*\\(/.test(\n scriptContent\n );\n\n // Skip injection if already using useIntlayer\n if (hasUseIntlayerImport && hasContentDeclaration) {\n return null;\n }\n\n // Prepare injection statements (only what's missing)\n const importStmt = hasUseIntlayerImport\n ? ''\n : `import { useIntlayer } from '${packageName}';`;\n const contentDecl = hasContentDeclaration\n ? ''\n : `const content = useIntlayer('${dictionaryKey}');`;\n\n // Build injection string\n const injectionParts = [importStmt, contentDecl].filter(Boolean);\n if (injectionParts.length === 0) {\n return null;\n }\n const injection = `\\n${injectionParts.join('\\n')}\\n`;\n\n if (sfc.descriptor.scriptSetup) {\n // Insert at the beginning of script setup content\n magic.appendLeft(sfc.descriptor.scriptSetup.loc.start.offset, injection);\n } else if (sfc.descriptor.script) {\n // Insert at the beginning of script content\n magic.appendLeft(sfc.descriptor.script.loc.start.offset, injection);\n } else {\n // No script block, create one\n magic.prepend(`<script setup>\\n${importStmt}\\n${contentDecl}\\n</script>\\n`);\n }\n\n // Call the onExtract callback with extracted content\n if (onExtract) {\n const result: ExtractResult = {\n dictionaryKey,\n filePath: filename,\n content: { ...extractedContent },\n locale: defaultLocale,\n };\n onExtract(result);\n }\n\n return {\n code: magic.toString(),\n map: magic.generateMap({ source: filename, includeContent: true }),\n extracted: true,\n };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"VueIntlayerCompiler.d.ts","names":[],"sources":["../../src/VueIntlayerCompiler.ts"],"sourcesContent":[],"mappings":";;;;;;;AAeA;AAKY,KALA,YAAA,GAKgB,KAAA,GAKc,OAG5B;AAYd;AAQA;;AAS2B,KArCf,gBAAA,GAqCe;EAAR,IAAA,EAAA,MAAA;EAAO,MAAA,EAAA;IAMd,EAAA,EAAA;MAMJ,IAAA,EAAA,CAAA,OAAA,EAAA;QACY,IAAA,EAAA,MAAA;MACK,CAAA,EAAA,GAAA,IAAA;IACA,CAAA;IAAqB,WAAA,EAAA;MAO7B,gBAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAtDyB,GAsDzB,CAAA,OAAA,CAAA,GAAA,IAAA,GAAA,SAAA;MAAR,gBAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,IAAA,EAnDK,GAmDL,CAAA,OAAA,CAAA,EAAA,SAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;IAAO,CAAA;EAyBH,CAAA;EAgVA,SAAA,EAAA,MAAA;AAOb,CAAA;;;;KAvZY,eAAA;;;;;;;KAQA,0BAAA;;;;kBAIM;;;;mBAKC,QAAQ;;;;;KAMf,qBAAA;;;;;;;;QAMJ;oBACY;yBACK;yBACA,qBAAqB;;;;;UAOrC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;cAyBJ,sCACD,+BACT;;;;cA8UU,gCACD,+BACT;cAKU,gCAtVD,+BACT"}
1
+ {"version":3,"file":"VueIntlayerCompiler.d.ts","names":[],"sources":["../../src/VueIntlayerCompiler.ts"],"sourcesContent":[],"mappings":";;;;;;;AAkBA;AAKY,KALA,YAAA,GAKgB,KAAA,GAKc,OAG5B;AAYd;AAQA;;AAS2B,KArCf,gBAAA,GAqCe;EAAR,IAAA,EAAA,MAAA;EAAO,MAAA,EAAA;IAMd,EAAA,EAAA;MAMJ,IAAA,EAAA,CAAA,OAAA,EAAA;QACY,IAAA,EAAA,MAAA;MACK,CAAA,EAAA,GAAA,IAAA;IACA,CAAA;IAAqB,WAAA,EAAA;MAO7B,gBAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAtDyB,GAsDzB,CAAA,OAAA,CAAA,GAAA,IAAA,GAAA,SAAA;MAAR,gBAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,IAAA,EAnDK,GAmDL,CAAA,OAAA,CAAA,EAAA,SAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA;IAAO,CAAA;EAyBH,CAAA;EA6TA,SAAA,EAAA,MAAA;AAOb,CAAA;;;;KApYY,eAAA;;;;;;;KAQA,0BAAA;;;;kBAIM;;;;mBAKC,QAAQ;;;;;KAMf,qBAAA;;;;;;;;QAMJ;oBACY;yBACK;yBACA,qBAAqB;;;;;UAOrC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;cAyBJ,sCACD,+BACT;;;;cA2TU,gCACD,+BACT;cAKU,gCAnUD,+BACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"vue-intlayer-extract.d.ts","names":[],"sources":["../../src/vue-intlayer-extract.ts"],"sourcesContent":[],"mappings":";;AAOA;AAUA;AAKY,cAfC,qBAqBF,EAAA,MAAgB,EAAA;AAQf,KAnBA,gBAAA,GAAmB,MAmBC,CAwBT,MAAA,EAAA,MAAa,CAAA;AAQpC;AAeA;AAiCA;AAoBa,KAlHD,aAAA,GA+HX;EAoFY;;;;;WA7MF;;;;;;;KAQC,oBAAA;;;;;;;;;;;;;;;;;;;;;;;;uBAwBW;;;;;cAQV;;;;cAeA,0CAEG;;;;cA+BH;;;;cAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiGA,+DAGF,yBACR"}
1
+ {"version":3,"file":"vue-intlayer-extract.d.ts","names":[],"sources":["../../src/vue-intlayer-extract.ts"],"sourcesContent":[],"mappings":";;AAQA;AAUA;AAKY,cAfC,qBAqBF,EAAA,MAAgB,EAAA;AAQf,KAnBA,gBAAA,GAAmB,MAmBC,CAAA,MAwBT,EAAA,MAAA,CAAa;AAQpC;AAeA;AAiCA;AAoBa,KAlHD,aAAA,GA+HX;EAoFY;;;;;WA7MF;;;;;;;KAQC,oBAAA;;;;;;;;;;;;;;;;;;;;;;;;uBAwBW;;;;;cAQV;;;;cAeA,0CAEG;;;;cA+BH;;;;cAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiGA,+DAGF,yBACR"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/vue-compiler",
3
- "version": "7.3.8",
3
+ "version": "7.3.9",
4
4
  "private": false,
5
5
  "description": "Vite-compatible compiler plugin for Vue with Intlayer, providing HMR support, file transformation, and optimized dictionary loading for Vue applications.",
6
6
  "keywords": [
@@ -82,12 +82,12 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@babel/core": "7.28.4",
85
- "@intlayer/babel": "7.3.8",
86
- "@intlayer/chokidar": "7.3.8",
87
- "@intlayer/cli": "7.3.8",
88
- "@intlayer/config": "7.3.8",
89
- "@intlayer/dictionaries-entry": "7.3.8",
90
- "@intlayer/types": "7.3.8",
85
+ "@intlayer/babel": "7.3.9",
86
+ "@intlayer/chokidar": "7.3.9",
87
+ "@intlayer/cli": "7.3.9",
88
+ "@intlayer/config": "7.3.9",
89
+ "@intlayer/dictionaries-entry": "7.3.9",
90
+ "@intlayer/types": "7.3.9",
91
91
  "fast-glob": "3.3.3",
92
92
  "magic-string": "^0.30.17"
93
93
  },
@@ -1,29 +0,0 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") {
10
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) {
13
- __defProp(to, key, {
14
- get: ((k) => from[k]).bind(null, key),
15
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
- });
17
- }
18
- }
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
- value: mod,
24
- enumerable: true
25
- }) : target, mod));
26
-
27
- //#endregion
28
-
29
- exports.__toESM = __toESM;