@intlayer/svelte-compiler 7.3.2-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,204 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ let node_path = require("node:path");
3
+
4
+ //#region src/svelte-intlayer-extract.ts
5
+ /**
6
+ * Attributes that should be extracted for localization
7
+ */
8
+ const ATTRIBUTES_TO_EXTRACT = [
9
+ "title",
10
+ "placeholder",
11
+ "alt",
12
+ "aria-label",
13
+ "label"
14
+ ];
15
+ /**
16
+ * Default function to determine if a string should be extracted
17
+ */
18
+ const defaultShouldExtract = (text) => {
19
+ const trimmed = text.trim();
20
+ if (!trimmed) return false;
21
+ if (!trimmed.includes(" ")) return false;
22
+ if (!/^[A-Z]/.test(trimmed)) return false;
23
+ if (trimmed.startsWith("{") || trimmed.startsWith("v-")) return false;
24
+ return true;
25
+ };
26
+ /**
27
+ * Generate a unique key from text
28
+ */
29
+ const generateKey = (text, existingKeys) => {
30
+ let key = text.replace(/\s+/g, " ").replace(/_+/g, " ").replace(/-+/g, " ").replace(/[^a-zA-Z0-9 ]/g, "").trim().split(" ").filter(Boolean).slice(0, 5).map((word, index) => index === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
31
+ if (!key) key = "content";
32
+ if (existingKeys.has(key)) {
33
+ let i = 1;
34
+ while (existingKeys.has(`${key}${i}`)) i++;
35
+ key = `${key}${i}`;
36
+ }
37
+ return key;
38
+ };
39
+ /**
40
+ * Extract dictionary key from file path
41
+ */
42
+ const extractDictionaryKeyFromPath = (filePath) => {
43
+ let baseName = (0, node_path.basename)(filePath, (0, node_path.extname)(filePath));
44
+ if (baseName === "index") baseName = (0, node_path.basename)((0, node_path.dirname)(filePath));
45
+ return `comp-${baseName.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase()}`;
46
+ };
47
+ /**
48
+ * Check if a file should be processed based on filesList
49
+ */
50
+ const shouldProcessFile = (filename, filesList) => {
51
+ if (!filename) return false;
52
+ if (!filesList || filesList.length === 0) return true;
53
+ const normalizedFilename = filename.replace(/\\/g, "/");
54
+ return filesList.some((f) => {
55
+ return f.replace(/\\/g, "/") === normalizedFilename;
56
+ });
57
+ };
58
+ /**
59
+ * Svelte extraction plugin that extracts content and transforms Svelte components to use useIntlayer.
60
+ *
61
+ * This plugin:
62
+ * 1. Scans Svelte files for extractable text (template text, attributes)
63
+ * 2. Auto-injects useIntlayer import and store binding
64
+ * 3. Reports extracted content via onExtract callback (for the compiler to write dictionaries)
65
+ * 4. Replaces extractable strings with content references using Svelte's reactive `$` prefix
66
+ *
67
+ * ## Input
68
+ * ```svelte
69
+ * <h1>Hello World</h1>
70
+ * <p>Welcome to our app</p>
71
+ * ```
72
+ *
73
+ * ## Output
74
+ * ```svelte
75
+ * <script>
76
+ * import { useIntlayer } from 'svelte-intlayer';
77
+ * const content = useIntlayer('hello-world');
78
+ * <\/script>
79
+ * <h1>{$content.helloWorld}</h1>
80
+ * <p>{$content.welcomeToOurApp}</p>
81
+ * ```
82
+ *
83
+ * Note: Svelte uses reactive stores with `$` prefix for automatic subscription.
84
+ * The `useIntlayer` composable returns a Svelte store that can be accessed reactively.
85
+ */
86
+ const intlayerSvelteExtract = async (code, filename, options = {}) => {
87
+ const { defaultLocale = "en", packageName = "svelte-intlayer", filesList, shouldExtract = defaultShouldExtract, onExtract } = options;
88
+ if (!shouldProcessFile(filename, filesList)) return null;
89
+ if (!filename.endsWith(".svelte")) return null;
90
+ let MagicString;
91
+ try {
92
+ MagicString = (await import("magic-string")).default;
93
+ } catch {
94
+ console.warn("Svelte extraction: magic-string not found. Install it to enable Svelte content extraction.");
95
+ return null;
96
+ }
97
+ const magic = new MagicString(code);
98
+ const extractedContent = {};
99
+ const existingKeys = /* @__PURE__ */ new Set();
100
+ const dictionaryKey = extractDictionaryKeyFromPath(filename);
101
+ const replacements = [];
102
+ const scriptBlockRegex = /<script[^>]*>[\s\S]*?<\/script>/gi;
103
+ const styleBlockRegex = /<style[^>]*>[\s\S]*?<\/style>/gi;
104
+ const skipRanges = [];
105
+ const scriptMatches = code.matchAll(scriptBlockRegex);
106
+ for (const match of scriptMatches) if (match.index !== void 0) skipRanges.push({
107
+ start: match.index,
108
+ end: match.index + match[0].length
109
+ });
110
+ const styleMatches = code.matchAll(styleBlockRegex);
111
+ for (const match of styleMatches) if (match.index !== void 0) skipRanges.push({
112
+ start: match.index,
113
+ end: match.index + match[0].length
114
+ });
115
+ skipRanges.sort((a, b) => a.start - b.start);
116
+ const isInSkipRange = (pos) => {
117
+ return skipRanges.some((range) => pos >= range.start && pos < range.end);
118
+ };
119
+ const textMatches = code.matchAll(/>([^<]+)</g);
120
+ for (const match of textMatches) {
121
+ if (match.index === void 0) continue;
122
+ const textStart = match.index + 1;
123
+ const text = match[1];
124
+ const textEnd = textStart + text.length;
125
+ if (isInSkipRange(textStart)) continue;
126
+ if (shouldExtract(text)) {
127
+ const key = generateKey(text, existingKeys);
128
+ existingKeys.add(key);
129
+ const normalizedValue = text.replace(/\s+/g, " ").trim();
130
+ replacements.push({
131
+ start: textStart,
132
+ end: textEnd,
133
+ replacement: `{$content.${key}}`,
134
+ key,
135
+ value: normalizedValue
136
+ });
137
+ }
138
+ }
139
+ for (const attrName of ATTRIBUTES_TO_EXTRACT) {
140
+ const attrRegex = new RegExp(`(${attrName})=["']([^"']+)["']`, "gi");
141
+ const attrMatches = code.matchAll(attrRegex);
142
+ for (const match of attrMatches) {
143
+ if (match.index === void 0) continue;
144
+ const attrStart = match.index;
145
+ const attrEnd = attrStart + match[0].length;
146
+ const text = match[2];
147
+ if (isInSkipRange(attrStart)) continue;
148
+ if (shouldExtract(text)) {
149
+ const key = generateKey(text, existingKeys);
150
+ existingKeys.add(key);
151
+ replacements.push({
152
+ start: attrStart,
153
+ end: attrEnd,
154
+ replacement: `${attrName}={$content.${key}.value}`,
155
+ key,
156
+ value: text.trim()
157
+ });
158
+ }
159
+ }
160
+ }
161
+ replacements.sort((a, b) => b.start - a.start);
162
+ for (const { start, end, replacement, key, value } of replacements) {
163
+ magic.overwrite(start, end, replacement);
164
+ extractedContent[key] = value;
165
+ }
166
+ if (Object.keys(extractedContent).length === 0) return null;
167
+ const scriptMatch = /<script[^>]*>([\s\S]*?)<\/script>/.exec(code);
168
+ const scriptContent = scriptMatch ? scriptMatch[1] : "";
169
+ const hasUseIntlayerImport = /import\s*{[^}]*useIntlayer[^}]*}\s*from\s*['"][^'"]+['"]/.test(scriptContent) || /import\s+useIntlayer\s+from\s*['"][^'"]+['"]/.test(scriptContent);
170
+ const hasContentDeclaration = /const\s+content\s*=\s*useIntlayer\s*\(/.test(scriptContent);
171
+ if (hasUseIntlayerImport && hasContentDeclaration) return null;
172
+ const importStmt = hasUseIntlayerImport ? "" : `import { useIntlayer } from '${packageName}';`;
173
+ const contentDecl = hasContentDeclaration ? "" : `const content = useIntlayer('${dictionaryKey}');`;
174
+ const injectionParts = [importStmt, contentDecl].filter(Boolean);
175
+ if (injectionParts.length === 0) return null;
176
+ const injection = `\n ${injectionParts.join("\n ")}\n`;
177
+ if (scriptMatch) {
178
+ const scriptContentStart = scriptMatch.index + scriptMatch[0].indexOf(">") + 1;
179
+ magic.appendLeft(scriptContentStart, injection);
180
+ } else magic.prepend(`<script>\n ${importStmt}\n ${contentDecl}\n<\/script>\n\n`);
181
+ if (onExtract) onExtract({
182
+ dictionaryKey,
183
+ filePath: filename,
184
+ content: { ...extractedContent },
185
+ locale: defaultLocale
186
+ });
187
+ return {
188
+ code: magic.toString(),
189
+ map: magic.generateMap({
190
+ source: filename,
191
+ includeContent: true
192
+ }),
193
+ extracted: true
194
+ };
195
+ };
196
+
197
+ //#endregion
198
+ exports.ATTRIBUTES_TO_EXTRACT = ATTRIBUTES_TO_EXTRACT;
199
+ exports.defaultShouldExtract = defaultShouldExtract;
200
+ exports.extractDictionaryKeyFromPath = extractDictionaryKeyFromPath;
201
+ exports.generateKey = generateKey;
202
+ exports.intlayerSvelteExtract = intlayerSvelteExtract;
203
+ exports.shouldProcessFile = shouldProcessFile;
204
+ //# sourceMappingURL=svelte-intlayer-extract.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svelte-intlayer-extract.cjs","names":["MagicString: new (code: string) => MagicStringType","extractedContent: ExtractedContent","replacements: Replacement[]","skipRanges: Array<{ start: number; end: number }>"],"sources":["../../src/svelte-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 'svelte-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/* ────────────────────────────────────────── MagicString type ────────────── */\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 * Svelte extraction plugin that extracts content and transforms Svelte components to use useIntlayer.\n *\n * This plugin:\n * 1. Scans Svelte files for extractable text (template text, attributes)\n * 2. Auto-injects useIntlayer import and store binding\n * 3. Reports extracted content via onExtract callback (for the compiler to write dictionaries)\n * 4. Replaces extractable strings with content references using Svelte's reactive `$` prefix\n *\n * ## Input\n * ```svelte\n * <h1>Hello World</h1>\n * <p>Welcome to our app</p>\n * ```\n *\n * ## Output\n * ```svelte\n * <script>\n * import { useIntlayer } from 'svelte-intlayer';\n * const content = useIntlayer('hello-world');\n * </script>\n * <h1>{$content.helloWorld}</h1>\n * <p>{$content.welcomeToOurApp}</p>\n * ```\n *\n * Note: Svelte uses reactive stores with `$` prefix for automatic subscription.\n * The `useIntlayer` composable returns a Svelte store that can be accessed reactively.\n */\nexport const intlayerSvelteExtract = 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 = 'svelte-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-Svelte files\n if (!filename.endsWith('.svelte')) {\n return null;\n }\n\n // Dynamic import for MagicString\n let MagicString: new (code: string) => MagicStringType;\n\n try {\n const magicStringModule = await import('magic-string');\n MagicString = magicStringModule.default;\n } catch {\n console.warn(\n 'Svelte extraction: magic-string not found. Install it to enable Svelte content extraction.'\n );\n return null;\n }\n\n const magic = new MagicString(code);\n const extractedContent: ExtractedContent = {};\n const existingKeys = new Set<string>();\n const dictionaryKey = extractDictionaryKeyFromPath(filename);\n\n // Collect all replacements first, then apply them in reverse order\n // This prevents MagicString \"chunk already edited\" errors\n type Replacement = {\n start: number;\n end: number;\n replacement: string;\n key: string;\n value: string;\n };\n const replacements: Replacement[] = [];\n\n // Extract template content (everything outside <script> and <style> tags)\n // This regex-based approach works with both TypeScript and JavaScript files\n const scriptBlockRegex = /<script[^>]*>[\\s\\S]*?<\\/script>/gi;\n const styleBlockRegex = /<style[^>]*>[\\s\\S]*?<\\/style>/gi;\n\n // Get ranges of script and style blocks to skip\n const skipRanges: Array<{ start: number; end: number }> = [];\n\n // Find all script blocks\n const scriptMatches = code.matchAll(scriptBlockRegex);\n for (const match of scriptMatches) {\n if (match.index !== undefined) {\n skipRanges.push({\n start: match.index,\n end: match.index + match[0].length,\n });\n }\n }\n\n // Find all style blocks\n const styleMatches = code.matchAll(styleBlockRegex);\n for (const match of styleMatches) {\n if (match.index !== undefined) {\n skipRanges.push({\n start: match.index,\n end: match.index + match[0].length,\n });\n }\n }\n\n // Sort ranges by start position\n skipRanges.sort((a, b) => a.start - b.start);\n\n // Function to check if a position is within a skip range\n const isInSkipRange = (pos: number): boolean => {\n return skipRanges.some((range) => pos >= range.start && pos < range.end);\n };\n\n // Extract text content between HTML tags (but not inside script/style)\n // Match text that's between > and < (tag content)\n const textContentRegex = />([^<]+)</g;\n const textMatches = code.matchAll(textContentRegex);\n for (const match of textMatches) {\n if (match.index === undefined) continue;\n\n const textStart = match.index + 1; // Skip the >\n const text = match[1];\n const textEnd = textStart + text.length;\n\n // Skip if inside script or style block\n if (isInSkipRange(textStart)) {\n continue;\n }\n\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n const normalizedValue = text.replace(/\\s+/g, ' ').trim();\n // Collect replacement instead of applying immediately\n replacements.push({\n start: textStart,\n end: textEnd,\n replacement: `{$content.${key}}`,\n key,\n value: normalizedValue,\n });\n }\n }\n\n // Extract localizable attributes (title, placeholder, alt, aria-label, label)\n for (const attrName of ATTRIBUTES_TO_EXTRACT) {\n // Match attribute=\"value\" or attribute='value'\n const attrRegex = new RegExp(`(${attrName})=[\"']([^\"']+)[\"']`, 'gi');\n const attrMatches = code.matchAll(attrRegex);\n for (const match of attrMatches) {\n if (match.index === undefined) continue;\n\n const attrStart = match.index;\n const attrEnd = attrStart + match[0].length;\n const text = match[2];\n\n // Skip if inside script or style block\n if (isInSkipRange(attrStart)) {\n continue;\n }\n\n if (shouldExtract(text)) {\n const key = generateKey(text, existingKeys);\n existingKeys.add(key);\n // Collect replacement instead of applying immediately\n replacements.push({\n start: attrStart,\n end: attrEnd,\n replacement: `${attrName}={$content.${key}.value}`,\n key,\n value: text.trim(),\n });\n }\n }\n }\n\n // Sort replacements by start position in REVERSE order (end to start)\n // This ensures earlier edits don't affect the positions of later edits\n replacements.sort((a, b) => b.start - a.start);\n\n // Apply all replacements and collect extracted content\n for (const { start, end, replacement, key, value } of replacements) {\n magic.overwrite(start, end, replacement);\n extractedContent[key] = value;\n }\n\n // If nothing was extracted, return null\n if (Object.keys(extractedContent).length === 0) {\n return null;\n }\n\n // Find existing script tag\n const scriptRegex = /<script[^>]*>([\\s\\S]*?)<\\/script>/;\n const scriptMatch = scriptRegex.exec(code);\n const scriptContent = scriptMatch ? scriptMatch[1] : '';\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 (scriptMatch) {\n // Insert at the beginning of script content\n const scriptContentStart =\n scriptMatch.index + scriptMatch[0].indexOf('>') + 1;\n magic.appendLeft(scriptContentStart, injection);\n } else {\n // No script block, create one\n magic.prepend(`<script>\\n ${importStmt}\\n ${contentDecl}\\n</script>\\n\\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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"}
@@ -0,0 +1,240 @@
1
+ import { createRequire } from "node:module";
2
+ import { join, relative } from "node:path";
3
+ import { intlayerOptimizeBabelPlugin } from "@intlayer/babel";
4
+ import { prepareIntlayer, watch } from "@intlayer/chokidar";
5
+ import { getAppLogger, getConfiguration } from "@intlayer/config";
6
+ import fg from "fast-glob";
7
+
8
+ //#region src/SvelteIntlayerCompiler.ts
9
+ /**
10
+ * Create a SvelteIntlayerCompiler - A Vite-compatible compiler plugin for Svelte with Intlayer
11
+ *
12
+ * Handles Svelte components with special handling for:
13
+ * - Script blocks in .svelte files
14
+ * - TypeScript in Svelte files
15
+ * - Svelte-specific transformations
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * // vite.config.ts
20
+ * import { defineConfig } from 'vite';
21
+ * import { svelte } from '@sveltejs/vite-plugin-svelte';
22
+ * import { svelteIntlayerCompiler } from '@intlayer/svelte-compiler';
23
+ *
24
+ * export default defineConfig({
25
+ * plugins: [svelte(), svelteIntlayerCompiler()],
26
+ * });
27
+ * ```
28
+ */
29
+ const createSvelteIntlayerCompiler = (options) => {
30
+ const pluginName = "svelte-intlayer-compiler";
31
+ let config;
32
+ let logger;
33
+ let projectRoot = "";
34
+ let mode = "dev";
35
+ let hmrVersion = -1;
36
+ const lastSourceTriggeredWrite = 0;
37
+ let filesList = [];
38
+ let babel = null;
39
+ let liveSyncKeys = [];
40
+ const configOptions = options?.configOptions;
41
+ const customCompilerConfig = options?.compilerConfig;
42
+ /**
43
+ * Build the list of files to transform based on configuration patterns
44
+ * Includes Svelte-specific patterns
45
+ */
46
+ const buildFilesList = async () => {
47
+ const { traversePattern } = config.build;
48
+ const { baseDir, mainDir } = config.content;
49
+ const transformPattern = customCompilerConfig?.transformPattern ?? traversePattern;
50
+ const excludePattern = customCompilerConfig?.excludePattern ?? ["**/node_modules/**"];
51
+ const patterns = Array.isArray(transformPattern) ? transformPattern : [transformPattern];
52
+ const sveltePatterns = patterns.map((p) => {
53
+ if (p.includes(".svelte") || p.includes("{")) return p;
54
+ return p.replace(/\{([^}]+)\}/, (_, exts) => `{${exts},svelte}`);
55
+ });
56
+ const excludePatterns = Array.isArray(excludePattern) ? excludePattern : [excludePattern];
57
+ const filesListPattern = fg.sync([...new Set([...patterns, ...sveltePatterns])], {
58
+ cwd: baseDir,
59
+ ignore: excludePatterns
60
+ }).map((file) => join(baseDir, file));
61
+ const dictionariesEntryPath = join(mainDir, "dictionaries.mjs");
62
+ const unmergedDictionariesEntryPath = join(mainDir, "unmerged_dictionaries.mjs");
63
+ filesList = [
64
+ ...filesListPattern,
65
+ dictionariesEntryPath,
66
+ unmergedDictionariesEntryPath
67
+ ];
68
+ };
69
+ /**
70
+ * Load dictionary keys that have live sync enabled
71
+ */
72
+ const loadLiveSyncKeys = async () => {
73
+ try {
74
+ const { getDictionaries } = await import("@intlayer/dictionaries-entry");
75
+ const dictionaries = getDictionaries();
76
+ liveSyncKeys = Object.values(dictionaries).filter((dictionary) => dictionary.live).map((dictionary) => dictionary.key);
77
+ } catch {
78
+ liveSyncKeys = [];
79
+ }
80
+ };
81
+ /**
82
+ * Initialize the compiler with the given mode
83
+ */
84
+ const init = async (compilerMode) => {
85
+ mode = compilerMode;
86
+ config = getConfiguration(configOptions);
87
+ logger = getAppLogger(config);
88
+ try {
89
+ babel = createRequire(import.meta.url)("@babel/core");
90
+ } catch {
91
+ logger("Failed to load @babel/core. Transformation will be disabled.", { level: "warn" });
92
+ }
93
+ await buildFilesList();
94
+ await loadLiveSyncKeys();
95
+ };
96
+ /**
97
+ * Vite hook: configResolved
98
+ */
99
+ const configResolved = async (viteConfig) => {
100
+ const compilerMode = viteConfig.env?.DEV ? "dev" : "build";
101
+ projectRoot = viteConfig.root;
102
+ await init(compilerMode);
103
+ };
104
+ /**
105
+ * Prepare intlayer dictionaries and types
106
+ */
107
+ const buildStart = async () => {
108
+ const isBuild = mode === "build";
109
+ await prepareIntlayer(config, {
110
+ clean: isBuild,
111
+ cacheTimeoutMs: isBuild ? 1e3 * 30 : 1e3 * 60 * 60
112
+ });
113
+ };
114
+ /**
115
+ * Configure the dev server with file watching
116
+ */
117
+ const configureServer = async () => {
118
+ if (config.content.watch) watch({ configuration: config });
119
+ };
120
+ /**
121
+ * Handle HMR for content changes
122
+ */
123
+ const handleHotUpdate = async (ctx) => {
124
+ const { file, server } = ctx;
125
+ if (!config.content.watchedFilesPatternWithPath.some((pattern) => {
126
+ return new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*")).test(file);
127
+ })) {
128
+ const dictionariesDir = config.content.dictionariesDir;
129
+ if (file.startsWith(dictionariesDir)) return [];
130
+ hmrVersion++;
131
+ return;
132
+ }
133
+ if (!(performance.now() - lastSourceTriggeredWrite < 1e3)) {
134
+ server.ws.send({ type: "full-reload" });
135
+ return [];
136
+ }
137
+ };
138
+ /**
139
+ * Transform handler with Svelte-specific handling
140
+ */
141
+ const transformHandler = async (code, id, _options) => {
142
+ if (!babel) return null;
143
+ const { optimize, importMode } = config.build;
144
+ if (!optimize && mode !== "build") return null;
145
+ const { dictionariesDir, dynamicDictionariesDir, unmergedDictionariesDir, fetchDictionariesDir, mainDir } = config.content;
146
+ /**
147
+ * Handle Svelte compiled modules
148
+ * Svelte plugin transforms .svelte files into JS
149
+ * We need to transform the resulting JS code
150
+ */
151
+ const filename = id.split("?", 1)[0];
152
+ const isSvelteFile = filename.endsWith(".svelte");
153
+ if (!filesList.includes(filename)) {
154
+ if (!isSvelteFile) return null;
155
+ if (!filesList.some((f) => f === filename || f.startsWith(filename))) return null;
156
+ }
157
+ const dictionariesEntryPath = join(mainDir, "dictionaries.mjs");
158
+ const unmergedDictionariesEntryPath = join(mainDir, "unmerged_dictionaries.mjs");
159
+ const dynamicDictionariesEntryPath = join(mainDir, "dynamic_dictionaries.mjs");
160
+ try {
161
+ const result = babel.transformSync(code, {
162
+ filename,
163
+ plugins: [[intlayerOptimizeBabelPlugin, {
164
+ dictionariesDir,
165
+ dictionariesEntryPath,
166
+ unmergedDictionariesEntryPath,
167
+ unmergedDictionariesDir,
168
+ dynamicDictionariesDir,
169
+ dynamicDictionariesEntryPath,
170
+ fetchDictionariesDir,
171
+ importMode,
172
+ filesList,
173
+ replaceDictionaryEntry: true,
174
+ liveSyncKeys
175
+ }]],
176
+ parserOpts: {
177
+ sourceType: "module",
178
+ allowImportExportEverywhere: true,
179
+ plugins: [
180
+ "typescript",
181
+ "jsx",
182
+ "decorators-legacy",
183
+ "classProperties",
184
+ "objectRestSpread",
185
+ "asyncGenerators",
186
+ "functionBind",
187
+ "exportDefaultFrom",
188
+ "exportNamespaceFrom",
189
+ "dynamicImport",
190
+ "nullishCoalescingOperator",
191
+ "optionalChaining"
192
+ ]
193
+ }
194
+ });
195
+ if (result?.code) return {
196
+ code: result.code,
197
+ map: result.map
198
+ };
199
+ } catch (error) {
200
+ logger(`Failed to transform Svelte file ${relative(projectRoot, filename)}: ${error}`, { level: "error" });
201
+ }
202
+ return null;
203
+ };
204
+ /**
205
+ * Apply hook for determining when plugin should be active
206
+ */
207
+ const apply = (_config, env) => {
208
+ const { optimize } = config?.build ?? {};
209
+ const isEnabled = customCompilerConfig?.enabled ?? true;
210
+ const isBuild = env.command === "build";
211
+ return isEnabled && (isBuild ? optimize ?? true : optimize ?? false);
212
+ };
213
+ return {
214
+ name: pluginName,
215
+ enforce: "post",
216
+ configResolved,
217
+ buildStart,
218
+ configureServer,
219
+ handleHotUpdate,
220
+ transform: {
221
+ order: "post",
222
+ handler: transformHandler
223
+ },
224
+ apply: (_viteConfig, env) => {
225
+ if (!config) config = getConfiguration(configOptions);
226
+ return apply(_viteConfig, env);
227
+ }
228
+ };
229
+ };
230
+ /**
231
+ * Factory function for creating a Vite plugin
232
+ */
233
+ const svelteIntlayerCompiler = (options) => {
234
+ return createSvelteIntlayerCompiler(options);
235
+ };
236
+ const SvelteIntlayerCompiler = createSvelteIntlayerCompiler;
237
+
238
+ //#endregion
239
+ export { SvelteIntlayerCompiler, createSvelteIntlayerCompiler, svelteIntlayerCompiler };
240
+ //# sourceMappingURL=SvelteIntlayerCompiler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SvelteIntlayerCompiler.mjs","names":["config: IntlayerConfig","logger: ReturnType<typeof getAppLogger>","mode: CompilerMode","filesList: string[]","babel: typeof import('@babel/core') | null","liveSyncKeys: string[]","compilerMode: CompilerMode"],"sources":["../../src/SvelteIntlayerCompiler.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 Svelte compiler\n */\nexport type SvelteIntlayerCompilerOptions = {\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 SvelteIntlayerVitePlugin = {\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 SvelteIntlayerCompiler - A Vite-compatible compiler plugin for Svelte with Intlayer\n *\n * Handles Svelte components with special handling for:\n * - Script blocks in .svelte files\n * - TypeScript in Svelte files\n * - Svelte-specific transformations\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import { svelte } from '@sveltejs/vite-plugin-svelte';\n * import { svelteIntlayerCompiler } from '@intlayer/svelte-compiler';\n *\n * export default defineConfig({\n * plugins: [svelte(), svelteIntlayerCompiler()],\n * });\n * ```\n */\nexport const createSvelteIntlayerCompiler = (\n options?: SvelteIntlayerCompilerOptions\n): SvelteIntlayerVitePlugin => {\n const pluginName = 'svelte-intlayer-compiler';\n\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\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 Svelte-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 Svelte file patterns\n const patterns = Array.isArray(transformPattern)\n ? transformPattern\n : [transformPattern];\n const sveltePatterns = patterns.map((p) => {\n // Ensure Svelte files are included\n if (p.includes('.svelte') || p.includes('{')) {\n return p;\n }\n // Add .svelte extension to patterns\n return p.replace(/\\{([^}]+)\\}/, (_, exts) => `{${exts},svelte}`);\n });\n\n const excludePatterns = Array.isArray(excludePattern)\n ? excludePattern\n : [excludePattern];\n\n const filesListPattern = fg\n .sync([...new Set([...patterns, ...sveltePatterns])], {\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 Svelte-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 Svelte compiled modules\n * Svelte plugin transforms .svelte files into JS\n * We need to transform the resulting JS code\n */\n const filename = id.split('?', 1)[0];\n\n // Check if this file should be transformed\n const isSvelteFile = filename.endsWith('.svelte');\n\n if (!filesList.includes(filename)) {\n // Also check if it's a compiled Svelte file\n if (!isSvelteFile) {\n return null;\n }\n // Check if the base svelte file is in our list\n if (!filesList.some((f) => f === filename || f.startsWith(filename))) {\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 Svelte 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: pluginName,\n enforce: 'post', // Run after Svelte plugin\n configResolved,\n buildStart,\n configureServer,\n handleHotUpdate,\n transform: {\n order: 'post', // Run after Svelte 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 svelteIntlayerCompiler = (\n options?: SvelteIntlayerCompilerOptions\n): SvelteIntlayerVitePlugin => {\n return createSvelteIntlayerCompiler(options);\n};\n\n// Legacy export for backwards compatibility\nexport const SvelteIntlayerCompiler = createSvelteIntlayerCompiler;\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { SvelteIntlayerCompiler, createSvelteIntlayerCompiler, svelteIntlayerCompiler } from "./SvelteIntlayerCompiler.mjs";
2
+ import { ATTRIBUTES_TO_EXTRACT, defaultShouldExtract, extractDictionaryKeyFromPath, generateKey, intlayerSvelteExtract, shouldProcessFile } from "./svelte-intlayer-extract.mjs";
3
+
4
+ export { ATTRIBUTES_TO_EXTRACT, SvelteIntlayerCompiler, createSvelteIntlayerCompiler, defaultShouldExtract, extractDictionaryKeyFromPath, generateKey, intlayerSvelteExtract, shouldProcessFile, svelteIntlayerCompiler };