vite-intlayer 7.3.11 → 7.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -15
- package/dist/cjs/IntlayerCompilerPlugin.cjs +0 -520
- package/dist/cjs/IntlayerCompilerPlugin.cjs.map +0 -1
- package/dist/cjs/_virtual/rolldown_runtime.cjs +0 -29
- package/dist/cjs/index.cjs +0 -13
- package/dist/cjs/intlayerPlugin.cjs +0 -92
- package/dist/cjs/intlayerPlugin.cjs.map +0 -1
- package/dist/cjs/intlayerProxyPlugin.cjs +0 -238
- package/dist/cjs/intlayerProxyPlugin.cjs.map +0 -1
- package/dist/cjs/intlayerPrunePlugin.cjs +0 -116
- package/dist/cjs/intlayerPrunePlugin.cjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-intlayer",
|
|
3
|
-
"version": "7.3.
|
|
3
|
+
"version": "7.3.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A Vite plugin for seamless internationalization (i18n), providing locale detection, redirection, and environment-based configuration",
|
|
6
6
|
"keywords": [
|
|
@@ -35,17 +35,18 @@
|
|
|
35
35
|
}
|
|
36
36
|
],
|
|
37
37
|
"sideEffects": false,
|
|
38
|
+
"type": "module",
|
|
38
39
|
"exports": {
|
|
39
40
|
".": {
|
|
40
41
|
"types": "./dist/types/index.d.ts",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
42
|
+
"import": "./dist/esm/index.mjs",
|
|
43
|
+
"default": "./dist/esm/index.mjs"
|
|
43
44
|
},
|
|
44
45
|
"./package.json": "./package.json"
|
|
45
46
|
},
|
|
46
|
-
"main": "dist/
|
|
47
|
-
"module": "dist/esm/index.mjs",
|
|
48
|
-
"types": "dist/types/index.d.ts",
|
|
47
|
+
"main": "./dist/esm/index.mjs",
|
|
48
|
+
"module": "./dist/esm/index.mjs",
|
|
49
|
+
"types": "./dist/types/index.d.ts",
|
|
49
50
|
"typesVersions": {
|
|
50
51
|
"*": {
|
|
51
52
|
"package.json": [
|
|
@@ -77,14 +78,14 @@
|
|
|
77
78
|
},
|
|
78
79
|
"dependencies": {
|
|
79
80
|
"@babel/core": "7.28.4",
|
|
80
|
-
"@intlayer/babel": "7.3.
|
|
81
|
-
"@intlayer/chokidar": "7.3.
|
|
82
|
-
"@intlayer/config": "7.3.
|
|
83
|
-
"@intlayer/core": "7.3.
|
|
84
|
-
"@intlayer/dictionaries-entry": "7.3.
|
|
85
|
-
"@intlayer/types": "7.3.
|
|
81
|
+
"@intlayer/babel": "7.3.12",
|
|
82
|
+
"@intlayer/chokidar": "7.3.12",
|
|
83
|
+
"@intlayer/config": "7.3.12",
|
|
84
|
+
"@intlayer/core": "7.3.12",
|
|
85
|
+
"@intlayer/dictionaries-entry": "7.3.12",
|
|
86
|
+
"@intlayer/types": "7.3.12",
|
|
86
87
|
"fast-glob": "3.3.3",
|
|
87
|
-
"intlayer": "7.3.
|
|
88
|
+
"intlayer": "7.3.12"
|
|
88
89
|
},
|
|
89
90
|
"devDependencies": {
|
|
90
91
|
"@types/node": "24.10.1",
|
|
@@ -98,8 +99,8 @@
|
|
|
98
99
|
},
|
|
99
100
|
"peerDependencies": {
|
|
100
101
|
"@babel/core": ">=6.0.0",
|
|
101
|
-
"@intlayer/svelte-compiler": "7.3.
|
|
102
|
-
"@intlayer/vue-compiler": "7.3.
|
|
102
|
+
"@intlayer/svelte-compiler": "7.3.12",
|
|
103
|
+
"@intlayer/vue-compiler": "7.3.12",
|
|
103
104
|
"vite": ">=4.0.0"
|
|
104
105
|
},
|
|
105
106
|
"peerDependenciesMeta": {
|
|
@@ -1,520 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
-
let node_fs = require("node:fs");
|
|
3
|
-
let node_fs_promises = require("node:fs/promises");
|
|
4
|
-
let node_module = require("node:module");
|
|
5
|
-
let node_path = require("node:path");
|
|
6
|
-
let __intlayer_babel = require("@intlayer/babel");
|
|
7
|
-
let __intlayer_chokidar = require("@intlayer/chokidar");
|
|
8
|
-
let __intlayer_config = require("@intlayer/config");
|
|
9
|
-
|
|
10
|
-
//#region src/IntlayerCompilerPlugin.ts
|
|
11
|
-
/**
|
|
12
|
-
* Create an IntlayerCompiler - A Vite-compatible compiler plugin for Intlayer
|
|
13
|
-
*
|
|
14
|
-
* This autonomous compiler handles:
|
|
15
|
-
* - Configuration loading and management
|
|
16
|
-
* - Hot Module Replacement (HMR) for content changes
|
|
17
|
-
* - File transformation with content extraction
|
|
18
|
-
* - Dictionary persistence and building
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* // vite.config.ts
|
|
23
|
-
* import { defineConfig } from 'vite';
|
|
24
|
-
* import { intlayerCompiler } from 'vite-intlayer';
|
|
25
|
-
*
|
|
26
|
-
* export default defineConfig({
|
|
27
|
-
* plugins: [intlayerCompiler()],
|
|
28
|
-
* });
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
const intlayerCompiler = (options) => {
|
|
32
|
-
let config;
|
|
33
|
-
let logger;
|
|
34
|
-
let projectRoot = "";
|
|
35
|
-
let filesList = [];
|
|
36
|
-
let babel = null;
|
|
37
|
-
let pendingDictionaryWrite = null;
|
|
38
|
-
const recentlyProcessedFiles = /* @__PURE__ */ new Map();
|
|
39
|
-
const recentDictionaryContent = /* @__PURE__ */ new Map();
|
|
40
|
-
const DEBOUNCE_MS = 500;
|
|
41
|
-
const configOptions = options?.configOptions;
|
|
42
|
-
const customCompilerConfig = options?.compilerConfig;
|
|
43
|
-
/**
|
|
44
|
-
* Check if a file was recently processed (within debounce window)
|
|
45
|
-
* and should be skipped to prevent infinite loops
|
|
46
|
-
*/
|
|
47
|
-
const wasRecentlyProcessed = (filePath) => {
|
|
48
|
-
const lastProcessed = recentlyProcessedFiles.get(filePath);
|
|
49
|
-
if (!lastProcessed) return false;
|
|
50
|
-
return Date.now() - lastProcessed < DEBOUNCE_MS;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Mark a file as recently processed
|
|
54
|
-
*/
|
|
55
|
-
const markAsProcessed = (filePath) => {
|
|
56
|
-
recentlyProcessedFiles.set(filePath, Date.now());
|
|
57
|
-
const now = Date.now();
|
|
58
|
-
for (const [path, timestamp] of recentlyProcessedFiles.entries()) if (now - timestamp > DEBOUNCE_MS * 2) recentlyProcessedFiles.delete(path);
|
|
59
|
-
};
|
|
60
|
-
/**
|
|
61
|
-
* Create a simple hash of content for comparison
|
|
62
|
-
* Used to detect if dictionary content has actually changed
|
|
63
|
-
*/
|
|
64
|
-
const hashContent = (content) => {
|
|
65
|
-
return JSON.stringify(Object.keys(content).sort().map((k) => [k, content[k]]));
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Check if dictionary content has changed since last write
|
|
69
|
-
*/
|
|
70
|
-
const hasDictionaryContentChanged = (dictionaryKey, content) => {
|
|
71
|
-
const newHash = hashContent(content);
|
|
72
|
-
if (recentDictionaryContent.get(dictionaryKey) === newHash) return false;
|
|
73
|
-
recentDictionaryContent.set(dictionaryKey, newHash);
|
|
74
|
-
return true;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Get compiler config from intlayer config or custom options
|
|
78
|
-
*/
|
|
79
|
-
const getCompilerConfig = () => {
|
|
80
|
-
const rawConfig = config;
|
|
81
|
-
return {
|
|
82
|
-
enabled: customCompilerConfig?.enabled ?? rawConfig.compiler?.enabled ?? true,
|
|
83
|
-
transformPattern: customCompilerConfig?.transformPattern ?? rawConfig.compiler?.transformPattern ?? config.build.traversePattern,
|
|
84
|
-
excludePattern: [
|
|
85
|
-
...customCompilerConfig?.excludePattern ?? [],
|
|
86
|
-
"**/node_modules/**",
|
|
87
|
-
...config.content.fileExtensions.map((pattern) => `*${pattern}`)
|
|
88
|
-
],
|
|
89
|
-
outputDir: customCompilerConfig?.outputDir ?? rawConfig.compiler?.outputDir ?? "compiler"
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* Get the output directory path for compiler dictionaries
|
|
94
|
-
*/
|
|
95
|
-
const getOutputDir = () => {
|
|
96
|
-
const { baseDir } = config.content;
|
|
97
|
-
return (0, node_path.join)(baseDir, getCompilerConfig().outputDir);
|
|
98
|
-
};
|
|
99
|
-
/**
|
|
100
|
-
* Get the file path for a dictionary
|
|
101
|
-
*/
|
|
102
|
-
const getDictionaryFilePath = (dictionaryKey) => {
|
|
103
|
-
return (0, node_path.join)(getOutputDir(), `${dictionaryKey}.content.json`);
|
|
104
|
-
};
|
|
105
|
-
/**
|
|
106
|
-
* Read an existing dictionary file if it exists
|
|
107
|
-
*/
|
|
108
|
-
const readExistingDictionary = async (dictionaryKey) => {
|
|
109
|
-
const filePath = getDictionaryFilePath(dictionaryKey);
|
|
110
|
-
if (!(0, node_fs.existsSync)(filePath)) return null;
|
|
111
|
-
try {
|
|
112
|
-
const content = await (0, node_fs_promises.readFile)(filePath, "utf-8");
|
|
113
|
-
return JSON.parse(content);
|
|
114
|
-
} catch {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* Merge extracted content with existing dictionary for multilingual format.
|
|
120
|
-
* - Keys in extracted but not in existing: added with default locale only
|
|
121
|
-
* - Keys in both: preserve existing translations, update default locale value
|
|
122
|
-
* - Keys in existing but not in extracted: removed (no longer in source)
|
|
123
|
-
*/
|
|
124
|
-
const mergeWithExistingMultilingualDictionary = (extractedContent, existingDictionary, defaultLocale) => {
|
|
125
|
-
const mergedContent = {};
|
|
126
|
-
const existingContent = existingDictionary?.content;
|
|
127
|
-
for (const [key, value] of Object.entries(extractedContent)) {
|
|
128
|
-
const existingEntry = existingContent?.[key];
|
|
129
|
-
if (existingEntry && existingEntry.nodeType === "translation" && existingEntry.translation) {
|
|
130
|
-
const oldValue = existingEntry.translation[defaultLocale];
|
|
131
|
-
const isUpdated = oldValue !== value;
|
|
132
|
-
mergedContent[key] = {
|
|
133
|
-
nodeType: "translation",
|
|
134
|
-
translation: {
|
|
135
|
-
...existingEntry.translation,
|
|
136
|
-
[defaultLocale]: value
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
if (isUpdated) logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Updated "${key}" [${defaultLocale}]: "${oldValue?.slice(0, 30)}..." → "${value.slice(0, 30)}..."`, {
|
|
140
|
-
level: "info",
|
|
141
|
-
isVerbose: true
|
|
142
|
-
});
|
|
143
|
-
} else {
|
|
144
|
-
mergedContent[key] = {
|
|
145
|
-
nodeType: "translation",
|
|
146
|
-
translation: { [defaultLocale]: value }
|
|
147
|
-
};
|
|
148
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Added new key "${key}"`, {
|
|
149
|
-
level: "info",
|
|
150
|
-
isVerbose: true
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (existingContent) {
|
|
155
|
-
const removedKeys = Object.keys(existingContent).filter((key) => !(key in extractedContent));
|
|
156
|
-
for (const key of removedKeys) logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Removed key "${key}" (no longer in source)`, {
|
|
157
|
-
level: "info",
|
|
158
|
-
isVerbose: true
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
return mergedContent;
|
|
162
|
-
};
|
|
163
|
-
/**
|
|
164
|
-
* Merge extracted content with existing dictionary for per-locale format.
|
|
165
|
-
* - Keys in extracted but not in existing: added
|
|
166
|
-
* - Keys in both: update value
|
|
167
|
-
* - Keys in existing but not in extracted: removed (no longer in source)
|
|
168
|
-
*/
|
|
169
|
-
const mergeWithExistingPerLocaleDictionary = (extractedContent, existingDictionary, defaultLocale) => {
|
|
170
|
-
const mergedContent = {};
|
|
171
|
-
const existingContent = existingDictionary?.content;
|
|
172
|
-
for (const [key, value] of Object.entries(extractedContent)) {
|
|
173
|
-
const existingValue = existingContent?.[key];
|
|
174
|
-
if (existingValue && typeof existingValue === "string") {
|
|
175
|
-
const isUpdated = existingValue !== value;
|
|
176
|
-
mergedContent[key] = value;
|
|
177
|
-
if (isUpdated) logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Updated "${key}" [${defaultLocale}]: "${existingValue?.slice(0, 30)}..." → "${value.slice(0, 30)}..."`, {
|
|
178
|
-
level: "info",
|
|
179
|
-
isVerbose: true
|
|
180
|
-
});
|
|
181
|
-
} else {
|
|
182
|
-
mergedContent[key] = value;
|
|
183
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Added new key "${key}"`, {
|
|
184
|
-
level: "info",
|
|
185
|
-
isVerbose: true
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (existingContent) {
|
|
190
|
-
const removedKeys = Object.keys(existingContent).filter((key) => !(key in extractedContent));
|
|
191
|
-
for (const key of removedKeys) logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Removed key "${key}" (no longer in source)`, {
|
|
192
|
-
level: "info",
|
|
193
|
-
isVerbose: true
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
return mergedContent;
|
|
197
|
-
};
|
|
198
|
-
/**
|
|
199
|
-
* Build the list of files to transform based on configuration patterns
|
|
200
|
-
*/
|
|
201
|
-
const buildFilesListFn = async () => {
|
|
202
|
-
const { baseDir, fileExtensions } = config.content;
|
|
203
|
-
const compilerConfig = getCompilerConfig();
|
|
204
|
-
const excludePatterns = Array.isArray(compilerConfig.excludePattern) ? compilerConfig.excludePattern : [compilerConfig.excludePattern];
|
|
205
|
-
filesList = (0, __intlayer_chokidar.buildFilesList)({
|
|
206
|
-
transformPattern: compilerConfig.transformPattern,
|
|
207
|
-
excludePattern: [
|
|
208
|
-
...excludePatterns,
|
|
209
|
-
"**/node_modules/**",
|
|
210
|
-
...fileExtensions.map((pattern) => `**/*${pattern}`)
|
|
211
|
-
],
|
|
212
|
-
baseDir
|
|
213
|
-
});
|
|
214
|
-
};
|
|
215
|
-
/**
|
|
216
|
-
* Initialize the compiler with the given mode
|
|
217
|
-
*/
|
|
218
|
-
const init = async (_compilerMode) => {
|
|
219
|
-
config = (0, __intlayer_config.getConfiguration)(configOptions);
|
|
220
|
-
logger = (0, __intlayer_config.getAppLogger)(config);
|
|
221
|
-
try {
|
|
222
|
-
babel = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("@babel/core");
|
|
223
|
-
} catch {
|
|
224
|
-
logger("Failed to load @babel/core. Transformation will be disabled.", { level: "warn" });
|
|
225
|
-
}
|
|
226
|
-
await buildFilesListFn();
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* Vite hook: config
|
|
230
|
-
* Called before Vite config is resolved - perfect time to prepare dictionaries
|
|
231
|
-
*/
|
|
232
|
-
const configHook = async (_config, env) => {
|
|
233
|
-
config = (0, __intlayer_config.getConfiguration)(configOptions);
|
|
234
|
-
logger = (0, __intlayer_config.getAppLogger)(config);
|
|
235
|
-
const isDevCommand = env.command === "serve" && env.mode === "development";
|
|
236
|
-
const isBuildCommand = env.command === "build";
|
|
237
|
-
if (isDevCommand || isBuildCommand) await (0, __intlayer_chokidar.prepareIntlayer)(config, {
|
|
238
|
-
clean: isBuildCommand,
|
|
239
|
-
cacheTimeoutMs: isBuildCommand ? 1e3 * 30 : 1e3 * 60 * 60
|
|
240
|
-
});
|
|
241
|
-
};
|
|
242
|
-
/**
|
|
243
|
-
* Vite hook: configResolved
|
|
244
|
-
* Called when Vite config is resolved
|
|
245
|
-
*/
|
|
246
|
-
const configResolved = async (viteConfig) => {
|
|
247
|
-
const compilerMode = viteConfig.env?.DEV ? "dev" : "build";
|
|
248
|
-
projectRoot = viteConfig.root;
|
|
249
|
-
await init(compilerMode);
|
|
250
|
-
};
|
|
251
|
-
/**
|
|
252
|
-
* Build start hook - no longer needs to prepare dictionaries
|
|
253
|
-
* The compiler is now autonomous and extracts content inline
|
|
254
|
-
*/
|
|
255
|
-
const buildStart = async () => {
|
|
256
|
-
logger("Intlayer compiler initialized", { level: "info" });
|
|
257
|
-
};
|
|
258
|
-
/**
|
|
259
|
-
* Build end hook - wait for any pending dictionary writes
|
|
260
|
-
*/
|
|
261
|
-
const buildEnd = async () => {
|
|
262
|
-
if (pendingDictionaryWrite) await pendingDictionaryWrite;
|
|
263
|
-
};
|
|
264
|
-
/**
|
|
265
|
-
* Configure the dev server
|
|
266
|
-
*/
|
|
267
|
-
const configureServer = async () => {};
|
|
268
|
-
/**
|
|
269
|
-
* Vite hook: handleHotUpdate
|
|
270
|
-
* Handles HMR for content files - invalidates cache and triggers re-transform
|
|
271
|
-
*/
|
|
272
|
-
const handleHotUpdate = async (ctx) => {
|
|
273
|
-
const { file, server, modules } = ctx;
|
|
274
|
-
if (filesList.some((f) => f === file)) {
|
|
275
|
-
if (wasRecentlyProcessed(file)) {
|
|
276
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Skipping re-transform of ${(0, __intlayer_config.colorizePath)((0, node_path.relative)(projectRoot, file))} (recently processed)`, {
|
|
277
|
-
level: "info",
|
|
278
|
-
isVerbose: true
|
|
279
|
-
});
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
markAsProcessed(file);
|
|
283
|
-
for (const mod of modules) server.moduleGraph.invalidateModule(mod);
|
|
284
|
-
try {
|
|
285
|
-
await transformHandler(await (0, node_fs_promises.readFile)(file, "utf-8"), file);
|
|
286
|
-
} catch (error) {
|
|
287
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Failed to re-transform ${file}: ${error}`, { level: "error" });
|
|
288
|
-
}
|
|
289
|
-
server.ws.send({ type: "full-reload" });
|
|
290
|
-
return [];
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
/**
|
|
294
|
-
* Write and build a single dictionary immediately
|
|
295
|
-
* This is called during transform to ensure dictionaries are always up-to-date.
|
|
296
|
-
*
|
|
297
|
-
* The merge strategy:
|
|
298
|
-
* - New keys are added with the default locale only
|
|
299
|
-
* - Existing keys preserve their translations, with default locale updated
|
|
300
|
-
* - Keys no longer in source are removed
|
|
301
|
-
*
|
|
302
|
-
* Dictionary format:
|
|
303
|
-
* - Per-locale: When config.dictionary.locale is set, content is simple strings with locale property
|
|
304
|
-
* - Multilingual: When not set, content is wrapped in translation nodes without locale property
|
|
305
|
-
*/
|
|
306
|
-
const writeAndBuildDictionary = async (result) => {
|
|
307
|
-
const { dictionaryKey, content } = result;
|
|
308
|
-
if (!hasDictionaryContentChanged(dictionaryKey, content)) {
|
|
309
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Skipping dictionary ${(0, __intlayer_config.colorizeKey)(dictionaryKey)} (content unchanged)`, {
|
|
310
|
-
level: "info",
|
|
311
|
-
isVerbose: true
|
|
312
|
-
});
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
const outputDir = getOutputDir();
|
|
316
|
-
const { defaultLocale } = config.internationalization;
|
|
317
|
-
const isPerLocaleFile = Boolean(config?.dictionary?.locale);
|
|
318
|
-
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
319
|
-
const existingDictionary = await readExistingDictionary(dictionaryKey);
|
|
320
|
-
const relativeFilePath = (0, node_path.join)((0, node_path.relative)(config.content.baseDir, outputDir), `${dictionaryKey}.content.json`);
|
|
321
|
-
let mergedDictionary;
|
|
322
|
-
if (isPerLocaleFile) {
|
|
323
|
-
const mergedContent = mergeWithExistingPerLocaleDictionary(content, existingDictionary, defaultLocale);
|
|
324
|
-
mergedDictionary = {
|
|
325
|
-
...existingDictionary && {
|
|
326
|
-
$schema: existingDictionary.$schema,
|
|
327
|
-
id: existingDictionary.id,
|
|
328
|
-
title: existingDictionary.title,
|
|
329
|
-
description: existingDictionary.description,
|
|
330
|
-
tags: existingDictionary.tags,
|
|
331
|
-
fill: existingDictionary.fill,
|
|
332
|
-
filled: existingDictionary.filled,
|
|
333
|
-
priority: existingDictionary.priority,
|
|
334
|
-
version: existingDictionary.version
|
|
335
|
-
},
|
|
336
|
-
key: dictionaryKey,
|
|
337
|
-
content: mergedContent,
|
|
338
|
-
locale: defaultLocale,
|
|
339
|
-
filePath: relativeFilePath
|
|
340
|
-
};
|
|
341
|
-
} else {
|
|
342
|
-
const mergedContent = mergeWithExistingMultilingualDictionary(content, existingDictionary, defaultLocale);
|
|
343
|
-
mergedDictionary = {
|
|
344
|
-
...existingDictionary && {
|
|
345
|
-
$schema: existingDictionary.$schema,
|
|
346
|
-
id: existingDictionary.id,
|
|
347
|
-
title: existingDictionary.title,
|
|
348
|
-
description: existingDictionary.description,
|
|
349
|
-
tags: existingDictionary.tags,
|
|
350
|
-
fill: existingDictionary.fill,
|
|
351
|
-
filled: existingDictionary.filled,
|
|
352
|
-
priority: existingDictionary.priority,
|
|
353
|
-
version: existingDictionary.version
|
|
354
|
-
},
|
|
355
|
-
key: dictionaryKey,
|
|
356
|
-
content: mergedContent,
|
|
357
|
-
filePath: relativeFilePath
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
try {
|
|
361
|
-
const writeResult = await (0, __intlayer_chokidar.writeContentDeclaration)(mergedDictionary, config, { newDictionariesPath: (0, node_path.relative)(config.content.baseDir, outputDir) });
|
|
362
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} ${writeResult.status === "created" ? "Created" : writeResult.status === "updated" ? "Updated" : "Processed"} content declaration: ${(0, __intlayer_config.colorizePath)((0, node_path.relative)(projectRoot, writeResult.path))}`, { level: "info" });
|
|
363
|
-
const dictionaryToBuild = {
|
|
364
|
-
...mergedDictionary,
|
|
365
|
-
filePath: (0, node_path.relative)(config.content.baseDir, writeResult.path)
|
|
366
|
-
};
|
|
367
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Building dictionary ${(0, __intlayer_config.colorizeKey)(dictionaryKey)}`, { level: "info" });
|
|
368
|
-
await (0, __intlayer_chokidar.buildDictionary)([dictionaryToBuild], config);
|
|
369
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Dictionary ${(0, __intlayer_config.colorizeKey)(dictionaryKey)} built successfully`, { level: "info" });
|
|
370
|
-
} catch (error) {
|
|
371
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Failed to write/build dictionary for ${(0, __intlayer_config.colorizeKey)(dictionaryKey)}: ${error}`, { level: "error" });
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
/**
|
|
375
|
-
* Callback for when content is extracted from a file
|
|
376
|
-
* Immediately writes and builds the dictionary
|
|
377
|
-
*/
|
|
378
|
-
const handleExtractedContent = (result) => {
|
|
379
|
-
const contentKeys = Object.keys(result.content);
|
|
380
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Extracted ${contentKeys.length} content keys from ${(0, __intlayer_config.colorizePath)((0, node_path.relative)(projectRoot, result.filePath))}`, { level: "info" });
|
|
381
|
-
pendingDictionaryWrite = (pendingDictionaryWrite ?? Promise.resolve()).then(() => writeAndBuildDictionary(result)).catch((error) => {
|
|
382
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Error in dictionary write chain: ${error}`, { level: "error" });
|
|
383
|
-
});
|
|
384
|
-
};
|
|
385
|
-
/**
|
|
386
|
-
* Detect the package name to import useIntlayer from based on file extension
|
|
387
|
-
*/
|
|
388
|
-
const detectPackageName = (filename) => {
|
|
389
|
-
if (filename.endsWith(".vue")) return "vue-intlayer";
|
|
390
|
-
if (filename.endsWith(".svelte")) return "svelte-intlayer";
|
|
391
|
-
if (filename.endsWith(".tsx") || filename.endsWith(".jsx")) return "react-intlayer";
|
|
392
|
-
return "intlayer";
|
|
393
|
-
};
|
|
394
|
-
/**
|
|
395
|
-
* Transform a Vue file using the Vue extraction plugin
|
|
396
|
-
*/
|
|
397
|
-
const transformVue = async (code, filename, defaultLocale) => {
|
|
398
|
-
const { intlayerVueExtract } = await import("@intlayer/vue-compiler");
|
|
399
|
-
return intlayerVueExtract(code, filename, {
|
|
400
|
-
defaultLocale,
|
|
401
|
-
filesList,
|
|
402
|
-
packageName: "vue-intlayer",
|
|
403
|
-
onExtract: handleExtractedContent
|
|
404
|
-
});
|
|
405
|
-
};
|
|
406
|
-
/**
|
|
407
|
-
* Transform a Svelte file using the Svelte extraction plugin
|
|
408
|
-
*/
|
|
409
|
-
const transformSvelte = async (code, filename, defaultLocale) => {
|
|
410
|
-
const { intlayerSvelteExtract } = await import("@intlayer/svelte-compiler");
|
|
411
|
-
return await intlayerSvelteExtract(code, filename, {
|
|
412
|
-
defaultLocale,
|
|
413
|
-
filesList,
|
|
414
|
-
packageName: "svelte-intlayer",
|
|
415
|
-
onExtract: handleExtractedContent
|
|
416
|
-
});
|
|
417
|
-
};
|
|
418
|
-
/**
|
|
419
|
-
* Transform a JSX/TSX file using the Babel extraction plugin
|
|
420
|
-
*/
|
|
421
|
-
const transformJsx = (code, filename, defaultLocale) => {
|
|
422
|
-
if (!babel) return;
|
|
423
|
-
const packageName = detectPackageName(filename);
|
|
424
|
-
const result = babel.transformSync(code, {
|
|
425
|
-
filename,
|
|
426
|
-
plugins: [[__intlayer_babel.intlayerExtractBabelPlugin, {
|
|
427
|
-
defaultLocale,
|
|
428
|
-
filesList,
|
|
429
|
-
packageName,
|
|
430
|
-
onExtract: handleExtractedContent
|
|
431
|
-
}]],
|
|
432
|
-
parserOpts: {
|
|
433
|
-
sourceType: "module",
|
|
434
|
-
allowImportExportEverywhere: true,
|
|
435
|
-
plugins: [
|
|
436
|
-
"typescript",
|
|
437
|
-
"jsx",
|
|
438
|
-
"decorators-legacy",
|
|
439
|
-
"classProperties",
|
|
440
|
-
"objectRestSpread",
|
|
441
|
-
"asyncGenerators",
|
|
442
|
-
"functionBind",
|
|
443
|
-
"exportDefaultFrom",
|
|
444
|
-
"exportNamespaceFrom",
|
|
445
|
-
"dynamicImport",
|
|
446
|
-
"nullishCoalescingOperator",
|
|
447
|
-
"optionalChaining"
|
|
448
|
-
]
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
if (result?.code) return {
|
|
452
|
-
code: result.code,
|
|
453
|
-
map: result.map,
|
|
454
|
-
extracted: true
|
|
455
|
-
};
|
|
456
|
-
};
|
|
457
|
-
/**
|
|
458
|
-
* Transform a file using the appropriate extraction plugin based on file type
|
|
459
|
-
*/
|
|
460
|
-
const transformHandler = async (code, id, _options) => {
|
|
461
|
-
if (!getCompilerConfig().enabled) return;
|
|
462
|
-
if (id.includes("?")) return;
|
|
463
|
-
const { defaultLocale } = config.internationalization;
|
|
464
|
-
const filename = id;
|
|
465
|
-
if (!filesList.includes(filename)) return;
|
|
466
|
-
const isVue = filename.endsWith(".vue");
|
|
467
|
-
const isSvelte = filename.endsWith(".svelte");
|
|
468
|
-
if (!isVue && !isSvelte) {
|
|
469
|
-
try {
|
|
470
|
-
const result = transformJsx(code, filename, defaultLocale);
|
|
471
|
-
if (pendingDictionaryWrite) await pendingDictionaryWrite;
|
|
472
|
-
if (result?.code) return {
|
|
473
|
-
code: result.code,
|
|
474
|
-
map: result.map
|
|
475
|
-
};
|
|
476
|
-
} catch (error) {
|
|
477
|
-
logger(`Failed to transform ${(0, __intlayer_config.colorizePath)((0, node_path.relative)(projectRoot, filename))}: ${error}`, { level: "error" });
|
|
478
|
-
}
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
logger(`${(0, __intlayer_config.colorize)("Compiler:", __intlayer_config.ANSIColors.GREY_DARK)} Transforming ${(0, __intlayer_config.colorizePath)((0, node_path.relative)(projectRoot, filename))}`, { level: "info" });
|
|
482
|
-
try {
|
|
483
|
-
let result;
|
|
484
|
-
if (isVue) result = await transformVue(code, filename, defaultLocale);
|
|
485
|
-
else if (isSvelte) result = await transformSvelte(code, filename, defaultLocale);
|
|
486
|
-
if (pendingDictionaryWrite) await pendingDictionaryWrite;
|
|
487
|
-
if (result?.code) return {
|
|
488
|
-
code: result.code,
|
|
489
|
-
map: result.map
|
|
490
|
-
};
|
|
491
|
-
} catch (error) {
|
|
492
|
-
logger(`Failed to transform ${(0, node_path.relative)(projectRoot, filename)}: ${error}`, { level: "error" });
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
/**
|
|
496
|
-
* Apply hook for determining when plugin should be active
|
|
497
|
-
*/
|
|
498
|
-
const apply = (_config, _env) => {
|
|
499
|
-
return getCompilerConfig().enabled;
|
|
500
|
-
};
|
|
501
|
-
return {
|
|
502
|
-
name: "vite-intlayer-compiler",
|
|
503
|
-
enforce: "pre",
|
|
504
|
-
config: configHook,
|
|
505
|
-
configResolved,
|
|
506
|
-
buildStart,
|
|
507
|
-
buildEnd,
|
|
508
|
-
configureServer,
|
|
509
|
-
handleHotUpdate,
|
|
510
|
-
transform: transformHandler,
|
|
511
|
-
apply: (_viteConfig, env) => {
|
|
512
|
-
if (!config) config = (0, __intlayer_config.getConfiguration)(configOptions);
|
|
513
|
-
return apply(_viteConfig, env);
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
//#endregion
|
|
519
|
-
exports.intlayerCompiler = intlayerCompiler;
|
|
520
|
-
//# sourceMappingURL=IntlayerCompilerPlugin.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"IntlayerCompilerPlugin.cjs","names":["config: IntlayerConfig","logger: ReturnType<typeof getAppLogger>","filesList: string[]","babel: any","pendingDictionaryWrite: Promise<void> | null","mergedContent: DictionaryContentMap","ANSIColors","mergedContent: Record<string, string>","compilerMode: CompilerMode","mergedDictionary: Dictionary","dictionaryToBuild: Dictionary","intlayerExtractBabelPlugin","result:\n | { code: string; map?: unknown; extracted?: boolean }\n | null\n | undefined"],"sources":["../../src/IntlayerCompilerPlugin.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { join, relative } from 'node:path';\nimport {\n type ExtractResult,\n intlayerExtractBabelPlugin,\n} from '@intlayer/babel';\nimport {\n buildDictionary,\n buildFilesList,\n prepareIntlayer,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n ANSIColors,\n colorize,\n colorizeKey,\n colorizePath,\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n} from '@intlayer/config';\nimport type {\n CompilerConfig,\n Dictionary,\n IntlayerConfig,\n} from '@intlayer/types';\n\n/**\n * Translation node structure used in dictionaries\n */\ntype TranslationNode = {\n nodeType: 'translation';\n translation: Record<string, string>;\n};\n\n/**\n * Dictionary content structure - map of keys to translation nodes\n */\ntype DictionaryContentMap = Record<string, TranslationNode>;\n\n/**\n * Mode of the compiler\n * - 'dev': Development mode with HMR support\n * - 'build': Production build mode\n */\nexport type CompilerMode = 'dev' | 'build';\n\n/**\n * Options for initializing the compiler\n */\nexport type IntlayerCompilerOptions = {\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 * Create an IntlayerCompiler - A Vite-compatible compiler plugin for Intlayer\n *\n * This autonomous compiler handles:\n * - Configuration loading and management\n * - Hot Module Replacement (HMR) for content changes\n * - File transformation with content extraction\n * - Dictionary persistence and building\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import { intlayerCompiler } from 'vite-intlayer';\n *\n * export default defineConfig({\n * plugins: [intlayerCompiler()],\n * });\n * ```\n */\nexport const intlayerCompiler = (options?: IntlayerCompilerOptions): any => {\n // Private state\n let config: IntlayerConfig;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let filesList: string[] = [];\n let babel: any = null;\n\n // Promise to track dictionary writing (for synchronization)\n let pendingDictionaryWrite: Promise<void> | null = null;\n\n // Track recently processed files to prevent infinite loops\n // Key: file path, Value: timestamp of last processing\n const recentlyProcessedFiles = new Map<string, number>();\n // Track recently written dictionaries to prevent duplicate writes\n // Key: dictionary key, Value: hash of content that was written\n const recentDictionaryContent = new Map<string, string>();\n // Debounce window in milliseconds - skip re-processing files within this window\n const DEBOUNCE_MS = 500;\n\n const configOptions = options?.configOptions;\n const customCompilerConfig = options?.compilerConfig;\n\n /**\n * Check if a file was recently processed (within debounce window)\n * and should be skipped to prevent infinite loops\n */\n const wasRecentlyProcessed = (filePath: string): boolean => {\n const lastProcessed = recentlyProcessedFiles.get(filePath);\n if (!lastProcessed) return false;\n\n const now = Date.now();\n return now - lastProcessed < DEBOUNCE_MS;\n };\n\n /**\n * Mark a file as recently processed\n */\n const markAsProcessed = (filePath: string): void => {\n recentlyProcessedFiles.set(filePath, Date.now());\n\n // Clean up old entries to prevent memory leaks\n const now = Date.now();\n for (const [path, timestamp] of recentlyProcessedFiles.entries()) {\n if (now - timestamp > DEBOUNCE_MS * 2) {\n recentlyProcessedFiles.delete(path);\n }\n }\n };\n\n /**\n * Create a simple hash of content for comparison\n * Used to detect if dictionary content has actually changed\n */\n const hashContent = (content: Record<string, string>): string => {\n return JSON.stringify(\n Object.keys(content)\n .sort()\n .map((k) => [k, content[k]])\n );\n };\n\n /**\n * Check if dictionary content has changed since last write\n */\n const hasDictionaryContentChanged = (\n dictionaryKey: string,\n content: Record<string, string>\n ): boolean => {\n const newHash = hashContent(content);\n const previousHash = recentDictionaryContent.get(dictionaryKey);\n\n if (previousHash === newHash) {\n return false;\n }\n\n // Update the stored hash\n recentDictionaryContent.set(dictionaryKey, newHash);\n return true;\n };\n\n /**\n * Get compiler config from intlayer config or custom options\n */\n const getCompilerConfig = () => {\n // Access compiler config from the raw config (may not be in the type)\n const rawConfig = config as IntlayerConfig & {\n compiler?: Partial<CompilerConfig>;\n };\n\n return {\n enabled:\n customCompilerConfig?.enabled ?? rawConfig.compiler?.enabled ?? true,\n transformPattern:\n customCompilerConfig?.transformPattern ??\n rawConfig.compiler?.transformPattern ??\n config.build.traversePattern,\n excludePattern: [\n ...(customCompilerConfig?.excludePattern ?? []),\n '**/node_modules/**',\n ...config.content.fileExtensions.map((pattern) => `*${pattern}`),\n ],\n outputDir:\n customCompilerConfig?.outputDir ??\n rawConfig.compiler?.outputDir ??\n 'compiler',\n };\n };\n\n /**\n * Get the output directory path for compiler dictionaries\n */\n const getOutputDir = (): string => {\n const { baseDir } = config.content;\n const compilerConfig = getCompilerConfig();\n return join(baseDir, compilerConfig.outputDir);\n };\n\n /**\n * Get the file path for a dictionary\n */\n const getDictionaryFilePath = (dictionaryKey: string): string => {\n const outputDir = getOutputDir();\n return join(outputDir, `${dictionaryKey}.content.json`);\n };\n\n /**\n * Read an existing dictionary file if it exists\n */\n const readExistingDictionary = async (\n dictionaryKey: string\n ): Promise<Dictionary | null> => {\n const filePath = getDictionaryFilePath(dictionaryKey);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as Dictionary;\n } catch {\n return null;\n }\n };\n\n /**\n * Merge extracted content with existing dictionary for multilingual format.\n * - Keys in extracted but not in existing: added with default locale only\n * - Keys in both: preserve existing translations, update default locale value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingMultilingualDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): DictionaryContentMap => {\n const mergedContent: DictionaryContentMap = {};\n const existingContent = existingDictionary?.content as\n | DictionaryContentMap\n | undefined;\n\n for (const [key, value] of Object.entries(extractedContent)) {\n const existingEntry = existingContent?.[key];\n\n if (\n existingEntry &&\n existingEntry.nodeType === 'translation' &&\n existingEntry.translation\n ) {\n const oldValue = existingEntry.translation[defaultLocale];\n const isUpdated = oldValue !== value;\n\n // Key exists in both - preserve existing translations, update default locale\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n ...existingEntry.translation,\n [defaultLocale]: value,\n },\n };\n\n if (isUpdated) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Updated \"${key}\" [${defaultLocale}]: \"${oldValue?.slice(0, 30)}...\" → \"${value.slice(0, 30)}...\"`,\n { level: 'info', isVerbose: true }\n );\n }\n } else {\n // New key - add with default locale only\n mergedContent[key] = {\n nodeType: 'translation',\n translation: {\n [defaultLocale]: value,\n },\n };\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Added new key \"${key}\"`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n }\n }\n\n // Log removed keys\n if (existingContent) {\n const removedKeys = Object.keys(existingContent).filter(\n (key) => !(key in extractedContent)\n );\n for (const key of removedKeys) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Removed key \"${key}\" (no longer in source)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n }\n }\n\n return mergedContent;\n };\n\n /**\n * Merge extracted content with existing dictionary for per-locale format.\n * - Keys in extracted but not in existing: added\n * - Keys in both: update value\n * - Keys in existing but not in extracted: removed (no longer in source)\n */\n const mergeWithExistingPerLocaleDictionary = (\n extractedContent: Record<string, string>,\n existingDictionary: Dictionary | null,\n defaultLocale: string\n ): Record<string, string> => {\n const mergedContent: Record<string, string> = {};\n const existingContent = existingDictionary?.content as\n | Record<string, string>\n | undefined;\n\n for (const [key, value] of Object.entries(extractedContent)) {\n const existingValue = existingContent?.[key];\n\n if (existingValue && typeof existingValue === 'string') {\n const isUpdated = existingValue !== value;\n\n mergedContent[key] = value;\n\n if (isUpdated) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Updated \"${key}\" [${defaultLocale}]: \"${existingValue?.slice(0, 30)}...\" → \"${value.slice(0, 30)}...\"`,\n { level: 'info', isVerbose: true }\n );\n }\n } else {\n // New key\n mergedContent[key] = value;\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Added new key \"${key}\"`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n }\n }\n\n // Log removed keys\n if (existingContent) {\n const removedKeys = Object.keys(existingContent).filter(\n (key) => !(key in extractedContent)\n );\n for (const key of removedKeys) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Removed key \"${key}\" (no longer in source)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n }\n }\n\n return mergedContent;\n };\n\n /**\n * Build the list of files to transform based on configuration patterns\n */\n const buildFilesListFn = async (): Promise<void> => {\n const { baseDir, fileExtensions } = config.content;\n const compilerConfig = getCompilerConfig();\n\n const excludePatterns = Array.isArray(compilerConfig.excludePattern)\n ? compilerConfig.excludePattern\n : [compilerConfig.excludePattern];\n\n filesList = buildFilesList({\n transformPattern: compilerConfig.transformPattern,\n excludePattern: [\n ...excludePatterns,\n '**/node_modules/**',\n ...fileExtensions.map((pattern) => `**/*${pattern}`),\n ],\n baseDir,\n });\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (_compilerMode: CompilerMode): Promise<void> => {\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\n /**\n * Vite hook: config\n * Called before Vite config is resolved - perfect time to prepare dictionaries\n */\n const configHook = async (\n _config: unknown,\n env: { command: string; mode: string }\n ): Promise<void> => {\n // Initialize config early\n config = getConfiguration(configOptions);\n logger = getAppLogger(config);\n\n const isDevCommand = env.command === 'serve' && env.mode === 'development';\n const isBuildCommand = env.command === 'build';\n\n // Prepare all existing dictionaries (builds them to .intlayer/dictionary/)\n // This ensures built dictionaries exist before the prune plugin runs\n if (isDevCommand || isBuildCommand) {\n await prepareIntlayer(config, {\n clean: isBuildCommand,\n cacheTimeoutMs: isBuildCommand\n ? 1000 * 30 // 30 seconds for build\n : 1000 * 60 * 60, // 1 hour for dev\n });\n }\n };\n\n /**\n * Vite hook: configResolved\n * Called when Vite config is resolved\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 * Build start hook - no longer needs to prepare dictionaries\n * The compiler is now autonomous and extracts content inline\n */\n const buildStart = async (): Promise<void> => {\n // Autonomous compiler - no need to prepare dictionaries\n // Content is extracted inline during transformation\n logger('Intlayer compiler initialized', {\n level: 'info',\n });\n };\n\n /**\n * Build end hook - wait for any pending dictionary writes\n */\n const buildEnd = async (): Promise<void> => {\n // Wait for any pending dictionary writes to complete\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\n }\n };\n\n /**\n * Configure the dev server\n */\n const configureServer = async (): Promise<void> => {\n // In autonomous mode, we don't need file watching for dictionaries\n // Content is extracted inline during transformation\n };\n\n /**\n * Vite hook: handleHotUpdate\n * Handles HMR for content files - invalidates cache and triggers re-transform\n */\n const handleHotUpdate = async (ctx: any): Promise<unknown[] | undefined> => {\n const { file, server, modules } = ctx;\n\n // Check if this is a file we should transform\n const isTransformableFile = filesList.some((f) => f === file);\n\n if (isTransformableFile) {\n // Check if this file was recently processed to prevent infinite loops\n // When a component is transformed, it writes a dictionary, which triggers HMR,\n // which would re-transform the component - this debounce prevents that loop\n if (wasRecentlyProcessed(file)) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Skipping re-transform of ${colorizePath(relative(projectRoot, file))} (recently processed)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n return undefined;\n }\n\n // Mark file as being processed before transformation\n markAsProcessed(file);\n\n // Invalidate all affected modules to ensure re-transform\n for (const mod of modules) {\n server.moduleGraph.invalidateModule(mod);\n }\n\n // Force re-transform by reading and processing the file\n // This ensures content extraction happens on every file change\n try {\n const code = await readFile(file, 'utf-8');\n\n // Trigger the transform manually to extract content\n await transformHandler(code, file);\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to re-transform ${file}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n // Trigger full reload for content changes\n server.ws.send({ type: 'full-reload' });\n return [];\n }\n\n return undefined;\n };\n\n /**\n * Write and build a single dictionary immediately\n * This is called during transform to ensure dictionaries are always up-to-date.\n *\n * The merge strategy:\n * - New keys are added with the default locale only\n * - Existing keys preserve their translations, with default locale updated\n * - Keys no longer in source are removed\n *\n * Dictionary format:\n * - Per-locale: When config.dictionary.locale is set, content is simple strings with locale property\n * - Multilingual: When not set, content is wrapped in translation nodes without locale property\n */\n const writeAndBuildDictionary = async (\n result: ExtractResult\n ): Promise<void> => {\n const { dictionaryKey, content } = result;\n\n // Skip if content hasn't changed - prevents infinite loops during HMR\n if (!hasDictionaryContentChanged(dictionaryKey, content)) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Skipping dictionary ${colorizeKey(dictionaryKey)} (content unchanged)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n return;\n }\n\n const outputDir = getOutputDir();\n const { defaultLocale } = config.internationalization;\n\n // Check if per-locale format is configured\n // When config.dictionary.locale is set, use per-locale format (simple strings with locale property)\n // Otherwise, use multilingual format (content wrapped in TranslationNode objects)\n const isPerLocaleFile = Boolean(config?.dictionary?.locale);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n // Read existing dictionary to preserve translations and metadata\n const existingDictionary = await readExistingDictionary(dictionaryKey);\n\n const relativeFilePath = join(\n relative(config.content.baseDir, outputDir),\n `${dictionaryKey}.content.json`\n );\n\n // Build dictionary based on format - matching transformFiles.ts behavior\n let mergedDictionary: Dictionary;\n\n if (isPerLocaleFile) {\n // Per-locale format: simple string content with locale property\n const mergedContent = mergeWithExistingPerLocaleDictionary(\n content,\n existingDictionary,\n defaultLocale\n );\n\n mergedDictionary = {\n // Preserve existing metadata (title, description, tags, etc.)\n ...(existingDictionary && {\n $schema: existingDictionary.$schema,\n id: existingDictionary.id,\n title: existingDictionary.title,\n description: existingDictionary.description,\n tags: existingDictionary.tags,\n fill: existingDictionary.fill,\n filled: existingDictionary.filled,\n priority: existingDictionary.priority,\n version: existingDictionary.version,\n }),\n // Required fields\n key: dictionaryKey,\n content: mergedContent,\n locale: defaultLocale,\n filePath: relativeFilePath,\n };\n } else {\n // Multilingual format: content wrapped in translation nodes, no locale property\n const mergedContent = mergeWithExistingMultilingualDictionary(\n content,\n existingDictionary,\n defaultLocale\n );\n\n mergedDictionary = {\n // Preserve existing metadata (title, description, tags, etc.)\n ...(existingDictionary && {\n $schema: existingDictionary.$schema,\n id: existingDictionary.id,\n title: existingDictionary.title,\n description: existingDictionary.description,\n tags: existingDictionary.tags,\n fill: existingDictionary.fill,\n filled: existingDictionary.filled,\n priority: existingDictionary.priority,\n version: existingDictionary.version,\n }),\n // Required fields\n key: dictionaryKey,\n content: mergedContent,\n filePath: relativeFilePath,\n };\n }\n\n try {\n const writeResult = await writeContentDeclaration(\n mergedDictionary,\n config,\n {\n newDictionariesPath: relative(config.content.baseDir, outputDir),\n }\n );\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} ${writeResult.status === 'created' ? 'Created' : writeResult.status === 'updated' ? 'Updated' : 'Processed'} content declaration: ${colorizePath(relative(projectRoot, writeResult.path))}`,\n {\n level: 'info',\n }\n );\n\n // Build the dictionary immediately so it's available for the prune plugin\n const dictionaryToBuild: Dictionary = {\n ...mergedDictionary,\n filePath: relative(config.content.baseDir, writeResult.path),\n };\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Building dictionary ${colorizeKey(dictionaryKey)}`,\n {\n level: 'info',\n }\n );\n\n await buildDictionary([dictionaryToBuild], config);\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Dictionary ${colorizeKey(dictionaryKey)} built successfully`,\n {\n level: 'info',\n }\n );\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to write/build dictionary for ${colorizeKey(dictionaryKey)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n };\n\n /**\n * Callback for when content is extracted from a file\n * Immediately writes and builds the dictionary\n */\n const handleExtractedContent = (result: ExtractResult): void => {\n const contentKeys = Object.keys(result.content);\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted ${contentKeys.length} content keys from ${colorizePath(relative(projectRoot, result.filePath))}`,\n {\n level: 'info',\n }\n );\n\n // Chain the write operation to ensure sequential writes\n pendingDictionaryWrite = (pendingDictionaryWrite ?? Promise.resolve())\n .then(() => writeAndBuildDictionary(result))\n .catch((error) => {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Error in dictionary write chain: ${error}`,\n {\n level: 'error',\n }\n );\n });\n };\n\n /**\n * Detect the package name to import useIntlayer from based on file extension\n */\n const detectPackageName = (filename: string): string => {\n if (filename.endsWith('.vue')) {\n return 'vue-intlayer';\n }\n if (filename.endsWith('.svelte')) {\n return 'svelte-intlayer';\n }\n if (filename.endsWith('.tsx') || filename.endsWith('.jsx')) {\n return 'react-intlayer';\n }\n // Default to react-intlayer for JSX/TSX files\n return 'intlayer';\n };\n\n /**\n * Transform a Vue file using the Vue extraction plugin\n */\n const transformVue = async (\n code: string,\n filename: string,\n defaultLocale: string\n ) => {\n const { intlayerVueExtract } = await import('@intlayer/vue-compiler');\n return intlayerVueExtract(code, filename, {\n defaultLocale,\n filesList,\n packageName: 'vue-intlayer',\n onExtract: handleExtractedContent,\n });\n };\n\n /**\n * Transform a Svelte file using the Svelte extraction plugin\n */\n const transformSvelte = async (\n code: string,\n filename: string,\n defaultLocale: string\n ) => {\n const { intlayerSvelteExtract } = await import('@intlayer/svelte-compiler');\n const result = await intlayerSvelteExtract(code, filename, {\n defaultLocale,\n filesList,\n packageName: 'svelte-intlayer',\n onExtract: handleExtractedContent,\n });\n\n return result;\n };\n\n /**\n * Transform a JSX/TSX file using the Babel extraction plugin\n */\n const transformJsx = (\n code: string,\n filename: string,\n defaultLocale: string\n ) => {\n if (!babel) {\n return undefined;\n }\n\n const packageName = detectPackageName(filename);\n\n const result = babel.transformSync(code, {\n filename,\n plugins: [\n [\n intlayerExtractBabelPlugin,\n {\n defaultLocale,\n filesList,\n packageName,\n onExtract: handleExtractedContent,\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 extracted: true,\n };\n }\n\n return undefined;\n };\n\n /**\n * Transform a file using the appropriate extraction plugin based on file type\n */\n const transformHandler = async (\n code: string,\n id: string,\n _options?: { ssr?: boolean }\n ) => {\n const compilerConfig = getCompilerConfig();\n\n // Only transform if compiler is enabled\n if (!compilerConfig.enabled) {\n return undefined;\n }\n\n // Skip virtual modules (query strings indicate compiled/virtual modules)\n // e.g., App.svelte?svelte&type=style, Component.vue?vue&type=script\n if (id.includes('?')) {\n return undefined;\n }\n\n const { defaultLocale } = config.internationalization;\n\n const filename = id;\n\n if (!filesList.includes(filename)) {\n return undefined;\n }\n\n // Only process Vue and Svelte source files with extraction\n // JSX/TSX files are handled by Babel which has its own detection\n const isVue = filename.endsWith('.vue');\n const isSvelte = filename.endsWith('.svelte');\n\n if (!isVue && !isSvelte) {\n // For non-Vue/Svelte files, use JSX transformation via Babel\n try {\n const result = transformJsx(code, filename, defaultLocale);\n\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\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 ${colorizePath(relative(projectRoot, filename))}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n return undefined;\n }\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Transforming ${colorizePath(relative(projectRoot, filename))}`,\n {\n level: 'info',\n }\n );\n\n try {\n let result:\n | { code: string; map?: unknown; extracted?: boolean }\n | null\n | undefined;\n\n // Route to appropriate transformer based on file extension\n if (isVue) {\n result = await transformVue(code, filename, defaultLocale);\n } else if (isSvelte) {\n result = await transformSvelte(code, filename, defaultLocale);\n }\n\n // Wait for the dictionary to be written before returning\n // This ensures the dictionary exists before the prune plugin runs\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\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 ${relative(projectRoot, filename)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n return undefined;\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 compilerConfig = getCompilerConfig();\n // Apply if compiler is enabled\n return compilerConfig.enabled;\n };\n\n return {\n name: 'vite-intlayer-compiler',\n enforce: 'pre',\n config: configHook,\n configResolved,\n buildStart,\n buildEnd,\n configureServer,\n handleHotUpdate,\n transform: transformHandler,\n apply: (_viteConfig: unknown, env: { command: string }) => {\n // Initialize config if not already done\n if (!config) {\n config = getConfiguration(configOptions);\n }\n return apply(_viteConfig, env);\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -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;
|
package/dist/cjs/index.cjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const require_IntlayerCompilerPlugin = require('./IntlayerCompilerPlugin.cjs');
|
|
2
|
-
const require_intlayerPrunePlugin = require('./intlayerPrunePlugin.cjs');
|
|
3
|
-
const require_intlayerPlugin = require('./intlayerPlugin.cjs');
|
|
4
|
-
const require_intlayerProxyPlugin = require('./intlayerProxyPlugin.cjs');
|
|
5
|
-
|
|
6
|
-
exports.intLayerMiddlewarePlugin = require_intlayerProxyPlugin.intLayerMiddlewarePlugin;
|
|
7
|
-
exports.intLayerPlugin = require_intlayerPlugin.intLayerPlugin;
|
|
8
|
-
exports.intlayer = require_intlayerPlugin.intlayer;
|
|
9
|
-
exports.intlayerCompiler = require_IntlayerCompilerPlugin.intlayerCompiler;
|
|
10
|
-
exports.intlayerMiddleware = require_intlayerProxyPlugin.intlayerMiddleware;
|
|
11
|
-
exports.intlayerPlugin = require_intlayerPlugin.intlayerPlugin;
|
|
12
|
-
exports.intlayerProxy = require_intlayerProxyPlugin.intlayerProxy;
|
|
13
|
-
exports.intlayerPrune = require_intlayerPrunePlugin.intlayerPrune;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
-
const require_intlayerPrunePlugin = require('./intlayerPrunePlugin.cjs');
|
|
3
|
-
let node_path = require("node:path");
|
|
4
|
-
let __intlayer_chokidar = require("@intlayer/chokidar");
|
|
5
|
-
let __intlayer_config = require("@intlayer/config");
|
|
6
|
-
|
|
7
|
-
//#region src/intlayerPlugin.ts
|
|
8
|
-
/**
|
|
9
|
-
* @deprecated Rename to intlayer instead
|
|
10
|
-
*
|
|
11
|
-
* A Vite plugin that integrates Intlayer configuration into the build process
|
|
12
|
-
*
|
|
13
|
-
* ```ts
|
|
14
|
-
* // Example usage of the plugin in a Vite configuration
|
|
15
|
-
* export default defineConfig({
|
|
16
|
-
* plugins: [ intlayer() ],
|
|
17
|
-
* });
|
|
18
|
-
* ```
|
|
19
|
-
* */
|
|
20
|
-
const intlayerPlugin = (configOptions) => {
|
|
21
|
-
const intlayerConfig = (0, __intlayer_config.getConfiguration)(configOptions);
|
|
22
|
-
const alias = (0, __intlayer_config.getAlias)({
|
|
23
|
-
configuration: intlayerConfig,
|
|
24
|
-
formatter: (value) => (0, node_path.resolve)(value)
|
|
25
|
-
});
|
|
26
|
-
const aliasPackages = Object.keys(alias);
|
|
27
|
-
const plugins = [{
|
|
28
|
-
name: "vite-intlayer-plugin",
|
|
29
|
-
config: async (config, env) => {
|
|
30
|
-
const isDevCommand = env.command === "serve" && env.mode === "development";
|
|
31
|
-
const isBuildCommand = env.command === "build";
|
|
32
|
-
if (isDevCommand || isBuildCommand) await (0, __intlayer_chokidar.prepareIntlayer)(intlayerConfig, {
|
|
33
|
-
clean: isBuildCommand,
|
|
34
|
-
cacheTimeoutMs: isBuildCommand ? 1e3 * 30 : 1e3 * 60 * 60
|
|
35
|
-
});
|
|
36
|
-
config.resolve = {
|
|
37
|
-
...config.resolve,
|
|
38
|
-
alias: {
|
|
39
|
-
...config.resolve?.alias,
|
|
40
|
-
...alias
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
config.optimizeDeps = {
|
|
44
|
-
...config.optimizeDeps,
|
|
45
|
-
exclude: [...config.optimizeDeps?.exclude ?? [], ...aliasPackages]
|
|
46
|
-
};
|
|
47
|
-
if (config.ssr?.noExternal !== true) {
|
|
48
|
-
const currentNoExternal = Array.isArray(config.ssr?.noExternal) ? config.ssr.noExternal : config.ssr?.noExternal ? [config.ssr.noExternal] : [];
|
|
49
|
-
config.ssr = {
|
|
50
|
-
...config.ssr,
|
|
51
|
-
noExternal: [...currentNoExternal, /(^@intlayer\/|intlayer$)/]
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return config;
|
|
55
|
-
},
|
|
56
|
-
configureServer: async (_server) => {
|
|
57
|
-
if (intlayerConfig.content.watch) (0, __intlayer_chokidar.watch)({ configuration: intlayerConfig });
|
|
58
|
-
}
|
|
59
|
-
}];
|
|
60
|
-
plugins.push(require_intlayerPrunePlugin.intlayerPrune(intlayerConfig));
|
|
61
|
-
return plugins;
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* A Vite plugin that integrates Intlayer configuration into the build process
|
|
65
|
-
*
|
|
66
|
-
* ```ts
|
|
67
|
-
* // Example usage of the plugin in a Vite configuration
|
|
68
|
-
* export default defineConfig({
|
|
69
|
-
* plugins: [ intlayer() ],
|
|
70
|
-
* });
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
const intlayer = intlayerPlugin;
|
|
74
|
-
/**
|
|
75
|
-
* @deprecated Rename to intlayer instead
|
|
76
|
-
*
|
|
77
|
-
* A Vite plugin that integrates Intlayer configuration into the build process
|
|
78
|
-
*
|
|
79
|
-
* ```ts
|
|
80
|
-
* // Example usage of the plugin in a Vite configuration
|
|
81
|
-
* export default defineConfig({
|
|
82
|
-
* plugins: [ intlayer() ],
|
|
83
|
-
* });
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
const intLayerPlugin = intlayerPlugin;
|
|
87
|
-
|
|
88
|
-
//#endregion
|
|
89
|
-
exports.intLayerPlugin = intLayerPlugin;
|
|
90
|
-
exports.intlayer = intlayer;
|
|
91
|
-
exports.intlayerPlugin = intlayerPlugin;
|
|
92
|
-
//# sourceMappingURL=intlayerPlugin.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerPlugin.cjs","names":["plugins: PluginOption[]","intlayerPrune"],"sources":["../../src/intlayerPlugin.ts"],"sourcesContent":["import { resolve } from 'node:path';\nimport { prepareIntlayer, watch } from '@intlayer/chokidar';\nimport {\n type GetConfigurationOptions,\n getAlias,\n getConfiguration,\n} from '@intlayer/config';\n// @ts-ignore - Fix error Module '\"vite\"' has no exported member\nimport type { PluginOption } from 'vite';\nimport { intlayerPrune } from './intlayerPrunePlugin';\n\n/**\n * @deprecated Rename to intlayer instead\n *\n * A Vite plugin that integrates Intlayer configuration into the build process\n *\n * ```ts\n * // Example usage of the plugin in a Vite configuration\n * export default defineConfig({\n * plugins: [ intlayer() ],\n * });\n * ```\n * */\nexport const intlayerPlugin = (\n configOptions?: GetConfigurationOptions\n): PluginOption => {\n const intlayerConfig = getConfiguration(configOptions);\n\n const alias = getAlias({\n configuration: intlayerConfig,\n formatter: (value: string) => resolve(value),\n });\n\n const aliasPackages = Object.keys(alias);\n\n const plugins: PluginOption[] = [\n {\n name: 'vite-intlayer-plugin',\n\n config: async (config, env) => {\n const isDevCommand =\n env.command === 'serve' && env.mode === 'development';\n const isBuildCommand = env.command === 'build';\n\n // Only call prepareIntlayer during `dev` or `build` (not during `start`)\n // If prod: clean and rebuild once\n // If dev: rebuild only once if it's more than 1 hour since last rebuild\n if (isDevCommand || isBuildCommand) {\n // prepareIntlayer use runOnce to ensure to run only once because will run twice on client and server side otherwise\n await prepareIntlayer(intlayerConfig, {\n clean: isBuildCommand,\n cacheTimeoutMs: isBuildCommand\n ? 1000 * 30 // 30 seconds for build (to ensure to rebuild all dictionaries)\n : 1000 * 60 * 60, // 1 hour for dev (default cache timeout)\n });\n }\n\n // Update Vite's resolve alias\n config.resolve = {\n ...config.resolve,\n alias: {\n ...config.resolve?.alias,\n ...alias,\n },\n };\n\n config.optimizeDeps = {\n ...config.optimizeDeps,\n exclude: [...(config.optimizeDeps?.exclude ?? []), ...aliasPackages],\n };\n\n // Update Vite's SSR Externalization\n // We must ensure that intlayer packages are processed by Vite (bundled)\n // so that the aliases defined above are actually applied\n if (config.ssr?.noExternal !== true) {\n const currentNoExternal = Array.isArray(config.ssr?.noExternal)\n ? config.ssr.noExternal\n : config.ssr?.noExternal\n ? [config.ssr.noExternal]\n : [];\n\n config.ssr = {\n ...config.ssr,\n noExternal: [\n ...(currentNoExternal as (string | RegExp)[]),\n // Regex to bundle all intlayer related packages\n /(^@intlayer\\/|intlayer$)/,\n ],\n };\n }\n\n return config;\n },\n\n configureServer: async (_server) => {\n if (intlayerConfig.content.watch) {\n // Start watching (assuming watch is also async)\n watch({ configuration: intlayerConfig });\n }\n },\n },\n ];\n\n // Add Babel transform plugin if enabled\n plugins.push(intlayerPrune(intlayerConfig));\n\n return plugins;\n};\n\n/**\n * A Vite plugin that integrates Intlayer configuration into the build process\n *\n * ```ts\n * // Example usage of the plugin in a Vite configuration\n * export default defineConfig({\n * plugins: [ intlayer() ],\n * });\n * ```\n */\nexport const intlayer = intlayerPlugin;\n/**\n * @deprecated Rename to intlayer instead\n *\n * A Vite plugin that integrates Intlayer configuration into the build process\n *\n * ```ts\n * // Example usage of the plugin in a Vite configuration\n * export default defineConfig({\n * plugins: [ intlayer() ],\n * });\n * ```\n */\nexport const intLayerPlugin = intlayerPlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuBA,MAAa,kBACX,kBACiB;CACjB,MAAM,yDAAkC,cAAc;CAEtD,MAAM,wCAAiB;EACrB,eAAe;EACf,YAAY,iCAA0B,MAAM;EAC7C,CAAC;CAEF,MAAM,gBAAgB,OAAO,KAAK,MAAM;CAExC,MAAMA,UAA0B,CAC9B;EACE,MAAM;EAEN,QAAQ,OAAO,QAAQ,QAAQ;GAC7B,MAAM,eACJ,IAAI,YAAY,WAAW,IAAI,SAAS;GAC1C,MAAM,iBAAiB,IAAI,YAAY;AAKvC,OAAI,gBAAgB,eAElB,gDAAsB,gBAAgB;IACpC,OAAO;IACP,gBAAgB,iBACZ,MAAO,KACP,MAAO,KAAK;IACjB,CAAC;AAIJ,UAAO,UAAU;IACf,GAAG,OAAO;IACV,OAAO;KACL,GAAG,OAAO,SAAS;KACnB,GAAG;KACJ;IACF;AAED,UAAO,eAAe;IACpB,GAAG,OAAO;IACV,SAAS,CAAC,GAAI,OAAO,cAAc,WAAW,EAAE,EAAG,GAAG,cAAc;IACrE;AAKD,OAAI,OAAO,KAAK,eAAe,MAAM;IACnC,MAAM,oBAAoB,MAAM,QAAQ,OAAO,KAAK,WAAW,GAC3D,OAAO,IAAI,aACX,OAAO,KAAK,aACV,CAAC,OAAO,IAAI,WAAW,GACvB,EAAE;AAER,WAAO,MAAM;KACX,GAAG,OAAO;KACV,YAAY,CACV,GAAI,mBAEJ,2BACD;KACF;;AAGH,UAAO;;EAGT,iBAAiB,OAAO,YAAY;AAClC,OAAI,eAAe,QAAQ,MAEzB,gCAAM,EAAE,eAAe,gBAAgB,CAAC;;EAG7C,CACF;AAGD,SAAQ,KAAKC,0CAAc,eAAe,CAAC;AAE3C,QAAO;;;;;;;;;;;;AAaT,MAAa,WAAW;;;;;;;;;;;;;AAaxB,MAAa,iBAAiB"}
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
-
let __intlayer_config = require("@intlayer/config");
|
|
3
|
-
let node_url = require("node:url");
|
|
4
|
-
let __intlayer_config_client = require("@intlayer/config/client");
|
|
5
|
-
let __intlayer_core = require("@intlayer/core");
|
|
6
|
-
|
|
7
|
-
//#region src/intlayerProxyPlugin.ts
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
* A Vite plugin that integrates a logic similar to the Next.js intlayer middleware.
|
|
11
|
-
*
|
|
12
|
-
* // Example usage of the plugin in a Vite configuration
|
|
13
|
-
* export default defineConfig({
|
|
14
|
-
* plugins: [ intlayerProxyPlugin() ],
|
|
15
|
-
* });
|
|
16
|
-
*
|
|
17
|
-
*/
|
|
18
|
-
const intlayerProxy = (configOptions, options) => {
|
|
19
|
-
const { internationalization, routing } = (0, __intlayer_config.getConfiguration)(configOptions);
|
|
20
|
-
const { locales: supportedLocales, defaultLocale } = internationalization;
|
|
21
|
-
const { basePath = "", mode = __intlayer_config_client.DefaultValues.Routing.ROUTING_MODE } = routing;
|
|
22
|
-
const noPrefix = mode === "no-prefix" || mode === "search-params";
|
|
23
|
-
const prefixDefault = mode === "prefix-all";
|
|
24
|
-
/**
|
|
25
|
-
* Retrieves the locale from storage (cookies, localStorage, sessionStorage).
|
|
26
|
-
*/
|
|
27
|
-
const getStorageLocale = (req) => {
|
|
28
|
-
return (0, __intlayer_core.getLocaleFromStorage)({ getCookie: (name) => {
|
|
29
|
-
return (req.headers.cookie ?? "").split(";").reduce((acc, cookie) => {
|
|
30
|
-
const [key, val] = cookie.trim().split("=");
|
|
31
|
-
acc[key] = val;
|
|
32
|
-
return acc;
|
|
33
|
-
}, {})[name] ?? null;
|
|
34
|
-
} });
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Appends locale to search params when routing mode is 'search-params'.
|
|
38
|
-
*/
|
|
39
|
-
const appendLocaleSearchIfNeeded = (search, locale) => {
|
|
40
|
-
if (mode !== "search-params") return search;
|
|
41
|
-
const params = new URLSearchParams(search ?? "");
|
|
42
|
-
params.set("locale", locale);
|
|
43
|
-
return `?${params.toString()}`;
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Extracts the locale from the URL pathname if present as the first segment.
|
|
47
|
-
*/
|
|
48
|
-
const getPathLocale = (pathname) => {
|
|
49
|
-
const firstSegment = pathname.split("/").filter(Boolean)[0];
|
|
50
|
-
if (firstSegment && supportedLocales.includes(firstSegment)) return firstSegment;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Writes a 301 redirect response with the given new URL.
|
|
54
|
-
*/
|
|
55
|
-
const redirectUrl = (res, newUrl) => {
|
|
56
|
-
res.writeHead(301, { Location: newUrl });
|
|
57
|
-
return res.end();
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* "Rewrite" the request internally by adjusting req.url;
|
|
61
|
-
* we also set the locale in the response header if needed.
|
|
62
|
-
*/
|
|
63
|
-
const rewriteUrl = (req, res, newUrl, locale) => {
|
|
64
|
-
req.url = newUrl;
|
|
65
|
-
if (locale) (0, __intlayer_core.setLocaleInStorage)(locale, { setHeader: (name, value) => res.setHeader(name, value) });
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Constructs a new path string, optionally including a locale prefix, basePath, and search parameters.
|
|
69
|
-
* - basePath: (e.g., '/myapp')
|
|
70
|
-
* - locale: (e.g., 'en')
|
|
71
|
-
* - currentPath:(e.g., '/products/shoes')
|
|
72
|
-
* - search: (e.g., '?foo=bar')
|
|
73
|
-
*/
|
|
74
|
-
const constructPath = (locale, currentPath, search) => {
|
|
75
|
-
const pathWithoutPrefix = currentPath.startsWith(`/${locale}`) ? currentPath.slice(`/${locale}`.length) ?? "/" : currentPath;
|
|
76
|
-
const cleanBasePath = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
77
|
-
const normalizedBasePath = cleanBasePath === "/" ? "" : cleanBasePath;
|
|
78
|
-
if (mode === "no-prefix") return search ? `${pathWithoutPrefix}${search}` : pathWithoutPrefix;
|
|
79
|
-
if (mode === "search-params") return search ? `${pathWithoutPrefix}${search}` : pathWithoutPrefix;
|
|
80
|
-
const pathWithLocalePrefix = currentPath.startsWith(`/${locale}`) ? currentPath : `/${locale}${currentPath}`;
|
|
81
|
-
let newPath = `${normalizedBasePath}${basePath.endsWith("/") ? "" : ""}${pathWithLocalePrefix}`;
|
|
82
|
-
if (!prefixDefault && locale === defaultLocale) newPath = `${normalizedBasePath}${pathWithoutPrefix}`;
|
|
83
|
-
if (search) newPath += search;
|
|
84
|
-
return newPath;
|
|
85
|
-
};
|
|
86
|
-
/**
|
|
87
|
-
* If `noPrefix` is true, we never prefix the locale in the URL.
|
|
88
|
-
* We simply rewrite the request to the same path, but with the best-chosen locale
|
|
89
|
-
* in a header or search params if desired.
|
|
90
|
-
*/
|
|
91
|
-
const handleNoPrefix = ({ req, res, next, originalPath, searchParams, storageLocale }) => {
|
|
92
|
-
let locale = storageLocale ?? defaultLocale;
|
|
93
|
-
if (!storageLocale) locale = (0, __intlayer_core.localeDetector)(req.headers, supportedLocales, defaultLocale);
|
|
94
|
-
if (mode === "search-params") {
|
|
95
|
-
if (new URLSearchParams(searchParams ?? "").get("locale") === locale) {
|
|
96
|
-
rewriteUrl(req, res, `${`/${locale}${originalPath}`}${searchParams ?? ""}`, locale);
|
|
97
|
-
return next();
|
|
98
|
-
}
|
|
99
|
-
const search$1 = appendLocaleSearchIfNeeded(searchParams, locale);
|
|
100
|
-
return redirectUrl(res, search$1 ? `${originalPath}${search$1}` : `${originalPath}${searchParams ?? ""}`);
|
|
101
|
-
}
|
|
102
|
-
const internalPath = `/${locale}${originalPath}`;
|
|
103
|
-
const search = appendLocaleSearchIfNeeded(searchParams, locale);
|
|
104
|
-
rewriteUrl(req, res, search ? `${internalPath}${search}` : `${internalPath}${searchParams ?? ""}`, locale);
|
|
105
|
-
return next();
|
|
106
|
-
};
|
|
107
|
-
/**
|
|
108
|
-
* The main prefix logic:
|
|
109
|
-
* - If there's no pathLocale in the URL, we might want to detect & redirect or rewrite
|
|
110
|
-
* - If there is a pathLocale, handle storage mismatch or default locale special cases
|
|
111
|
-
*/
|
|
112
|
-
const handlePrefix = ({ req, res, next, originalPath, searchParams, pathLocale, storageLocale }) => {
|
|
113
|
-
if (!pathLocale) {
|
|
114
|
-
handleMissingPathLocale({
|
|
115
|
-
req,
|
|
116
|
-
res,
|
|
117
|
-
next,
|
|
118
|
-
originalPath,
|
|
119
|
-
searchParams,
|
|
120
|
-
storageLocale
|
|
121
|
-
});
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
handleExistingPathLocale({
|
|
125
|
-
req,
|
|
126
|
-
res,
|
|
127
|
-
next,
|
|
128
|
-
originalPath,
|
|
129
|
-
searchParams,
|
|
130
|
-
pathLocale
|
|
131
|
-
});
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* Handles requests where the locale is missing from the URL pathname.
|
|
135
|
-
* We detect a locale from storage / headers / default, then either redirect or rewrite.
|
|
136
|
-
*/
|
|
137
|
-
const handleMissingPathLocale = ({ req, res, next, originalPath, searchParams, storageLocale }) => {
|
|
138
|
-
let locale = storageLocale ?? (0, __intlayer_core.localeDetector)(req.headers, supportedLocales, defaultLocale);
|
|
139
|
-
if (!supportedLocales.includes(locale)) locale = defaultLocale;
|
|
140
|
-
const search = appendLocaleSearchIfNeeded(searchParams, locale);
|
|
141
|
-
const newPath = constructPath(locale, originalPath, search);
|
|
142
|
-
if (prefixDefault || locale !== defaultLocale) return redirectUrl(res, newPath);
|
|
143
|
-
rewriteUrl(req, res, newPath, locale);
|
|
144
|
-
return next();
|
|
145
|
-
};
|
|
146
|
-
/**
|
|
147
|
-
* Handles requests where the locale prefix is present in the pathname.
|
|
148
|
-
*/
|
|
149
|
-
const handleExistingPathLocale = ({ req, res, next, originalPath, searchParams, pathLocale }) => {
|
|
150
|
-
handleDefaultLocaleRedirect({
|
|
151
|
-
req,
|
|
152
|
-
res,
|
|
153
|
-
next,
|
|
154
|
-
originalPath,
|
|
155
|
-
searchParams,
|
|
156
|
-
pathLocale
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
/**
|
|
160
|
-
* If the path locale is the default locale but we don't want to prefix the default, remove it.
|
|
161
|
-
*/
|
|
162
|
-
const handleDefaultLocaleRedirect = ({ req, res, next, originalPath, searchParams, pathLocale }) => {
|
|
163
|
-
if (!prefixDefault && pathLocale === defaultLocale) {
|
|
164
|
-
let newPath = originalPath.replace(`/${defaultLocale}`, "") || "/";
|
|
165
|
-
if (searchParams) newPath += searchParams;
|
|
166
|
-
rewriteUrl(req, res, newPath, pathLocale);
|
|
167
|
-
return next();
|
|
168
|
-
}
|
|
169
|
-
rewriteUrl(req, res, searchParams ? `${originalPath}${searchParams}` : originalPath, pathLocale);
|
|
170
|
-
return next();
|
|
171
|
-
};
|
|
172
|
-
return {
|
|
173
|
-
name: "vite-intlayer-middleware-plugin",
|
|
174
|
-
configureServer: (server) => {
|
|
175
|
-
server.middlewares.use((req, res, next) => {
|
|
176
|
-
if ((options?.ignore?.(req) ?? false) || req.url?.startsWith("/node_modules") || req.url?.startsWith("/@") || req.url?.startsWith("/_") || req.url?.split("?")[0].match(/\.[a-z]+$/i)) return next();
|
|
177
|
-
const parsedUrl = (0, node_url.parse)(req.url ?? "/", true);
|
|
178
|
-
const originalPath = parsedUrl.pathname ?? "/";
|
|
179
|
-
const searchParams = parsedUrl.search ?? "";
|
|
180
|
-
const pathLocale = getPathLocale(originalPath);
|
|
181
|
-
const storageLocale = getStorageLocale(req);
|
|
182
|
-
const effectiveStorageLocale = pathLocale && supportedLocales.includes(pathLocale) ? pathLocale : storageLocale;
|
|
183
|
-
if (noPrefix) {
|
|
184
|
-
handleNoPrefix({
|
|
185
|
-
req,
|
|
186
|
-
res,
|
|
187
|
-
next,
|
|
188
|
-
originalPath,
|
|
189
|
-
searchParams,
|
|
190
|
-
storageLocale: effectiveStorageLocale
|
|
191
|
-
});
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
handlePrefix({
|
|
195
|
-
req,
|
|
196
|
-
res,
|
|
197
|
-
next,
|
|
198
|
-
originalPath,
|
|
199
|
-
searchParams,
|
|
200
|
-
pathLocale,
|
|
201
|
-
storageLocale: effectiveStorageLocale
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
};
|
|
207
|
-
/**
|
|
208
|
-
* @deprecated Rename to intlayerProxy instead
|
|
209
|
-
*
|
|
210
|
-
* A Vite plugin that integrates a logic similar to the Next.js intlayer middleware.
|
|
211
|
-
*
|
|
212
|
-
* ```ts
|
|
213
|
-
* // Example usage of the plugin in a Vite configuration
|
|
214
|
-
* export default defineConfig({
|
|
215
|
-
* plugins: [ intlayerMiddleware() ],
|
|
216
|
-
* });
|
|
217
|
-
* ```
|
|
218
|
-
*/
|
|
219
|
-
const intlayerMiddleware = intlayerProxy;
|
|
220
|
-
/**
|
|
221
|
-
* @deprecated Rename to intlayerProxy instead
|
|
222
|
-
*
|
|
223
|
-
* A Vite plugin that integrates a logic similar to the Next.js intlayer middleware.
|
|
224
|
-
|
|
225
|
-
* ```ts
|
|
226
|
-
* // Example usage of the plugin in a Vite configuration
|
|
227
|
-
* export default defineConfig({
|
|
228
|
-
* plugins: [ intlayerMiddleware() ],
|
|
229
|
-
* });
|
|
230
|
-
* ```
|
|
231
|
-
*/
|
|
232
|
-
const intLayerMiddlewarePlugin = intlayerProxy;
|
|
233
|
-
|
|
234
|
-
//#endregion
|
|
235
|
-
exports.intLayerMiddlewarePlugin = intLayerMiddlewarePlugin;
|
|
236
|
-
exports.intlayerMiddleware = intlayerMiddleware;
|
|
237
|
-
exports.intlayerProxy = intlayerProxy;
|
|
238
|
-
//# sourceMappingURL=intlayerProxyPlugin.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerProxyPlugin.cjs","names":["DefaultValues","search"],"sources":["../../src/intlayerProxyPlugin.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { parse } from 'node:url';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config';\nimport { DefaultValues } from '@intlayer/config/client';\nimport {\n getLocaleFromStorage,\n localeDetector,\n setLocaleInStorage,\n} from '@intlayer/core';\nimport type { Locale } from '@intlayer/types';\n/* @ts-ignore - Vite types error */\nimport type { Connect, Plugin } from 'vite';\n\ntype IntlayerProxyPluginOptions = {\n /**\n * A function that allows you to ignore specific requests from the intlayer proxy.\n *\n * @example\n * ```ts\n * export default defineConfig({\n * plugins: [ intlayerProxyPlugin({ ignore: (req) => req.url?.startsWith('/api') }) ],\n * });\n * ```\n *\n * @param req - The incoming request.\n * @returns A boolean value indicating whether to ignore the request.\n */\n ignore?: (req: IncomingMessage) => boolean;\n};\n\n/**\n *\n * A Vite plugin that integrates a logic similar to the Next.js intlayer middleware.\n *\n * // Example usage of the plugin in a Vite configuration\n * export default defineConfig({\n * plugins: [ intlayerProxyPlugin() ],\n * });\n *\n */\nexport const intlayerProxy = (\n configOptions?: GetConfigurationOptions,\n options?: IntlayerProxyPluginOptions\n): Plugin => {\n const intlayerConfig = getConfiguration(configOptions);\n\n const { internationalization, routing } = intlayerConfig;\n const { locales: supportedLocales, defaultLocale } = internationalization;\n\n const { basePath = '', mode = DefaultValues.Routing.ROUTING_MODE } = routing;\n\n // Derived flags from routing.mode\n const noPrefix = mode === 'no-prefix' || mode === 'search-params';\n const prefixDefault = mode === 'prefix-all';\n\n /* --------------------------------------------------------------------\n * Helper & Utility Functions\n * --------------------------------------------------------------------\n */\n\n /**\n * Retrieves the locale from storage (cookies, localStorage, sessionStorage).\n */\n const getStorageLocale = (req: IncomingMessage): Locale | undefined => {\n const locale = getLocaleFromStorage({\n getCookie: (name: string) => {\n const cookieHeader = req.headers.cookie ?? '';\n const cookies = cookieHeader.split(';').reduce(\n (acc, cookie) => {\n const [key, val] = cookie.trim().split('=');\n acc[key] = val;\n return acc;\n },\n {} as Record<string, string>\n );\n return cookies[name] ?? null;\n },\n });\n return locale;\n };\n\n /**\n * Appends locale to search params when routing mode is 'search-params'.\n */\n const appendLocaleSearchIfNeeded = (\n search: string | undefined,\n locale: Locale\n ): string | undefined => {\n if (mode !== 'search-params') return search;\n\n const params = new URLSearchParams(search ?? '');\n params.set('locale', locale);\n return `?${params.toString()}`;\n };\n\n /**\n * Extracts the locale from the URL pathname if present as the first segment.\n */\n const getPathLocale = (pathname: string): Locale | undefined => {\n // e.g. if pathname is /en/some/page or /en\n // we check if \"en\" is in your supportedLocales\n const segments = pathname.split('/').filter(Boolean);\n const firstSegment = segments[0];\n if (firstSegment && supportedLocales.includes(firstSegment as Locale)) {\n return firstSegment as Locale;\n }\n return undefined;\n };\n\n /**\n * Writes a 301 redirect response with the given new URL.\n */\n const redirectUrl = (\n res: ServerResponse<IncomingMessage>,\n newUrl: string\n ) => {\n res.writeHead(301, { Location: newUrl });\n return res.end();\n };\n\n /**\n * \"Rewrite\" the request internally by adjusting req.url;\n * we also set the locale in the response header if needed.\n */\n const rewriteUrl = (\n req: Connect.IncomingMessage,\n res: ServerResponse<IncomingMessage>,\n newUrl: string,\n locale?: Locale\n ) => {\n req.url = newUrl;\n // If you want to mimic Next.js's behavior of setting a header for the locale:\n if (locale) {\n setLocaleInStorage(locale, {\n setHeader: (name: string, value: string) => res.setHeader(name, value),\n });\n }\n };\n\n /**\n * Constructs a new path string, optionally including a locale prefix, basePath, and search parameters.\n * - basePath: (e.g., '/myapp')\n * - locale: (e.g., 'en')\n * - currentPath:(e.g., '/products/shoes')\n * - search: (e.g., '?foo=bar')\n */\n const constructPath = (\n locale: Locale,\n currentPath: string,\n search?: string\n ) => {\n // Strip any incoming locale prefix if present\n const pathWithoutPrefix = currentPath.startsWith(`/${locale}`)\n ? (currentPath.slice(`/${locale}`.length) ?? '/')\n : currentPath;\n\n // Ensure basePath always starts with '/', and remove trailing slash if needed\n const cleanBasePath = basePath.startsWith('/') ? basePath : `/${basePath}`;\n // If basePath is '/', no trailing slash is needed\n const normalizedBasePath = cleanBasePath === '/' ? '' : cleanBasePath;\n\n // In 'search-params' and 'no-prefix' modes, do not prefix the path with the locale\n if (mode === 'no-prefix') {\n const newPath = search\n ? `${pathWithoutPrefix}${search}`\n : pathWithoutPrefix;\n return newPath;\n }\n\n if (mode === 'search-params') {\n const newPath = search\n ? `${pathWithoutPrefix}${search}`\n : pathWithoutPrefix;\n return newPath;\n }\n\n // Check if path already starts with locale to avoid double-prefixing\n const pathWithLocalePrefix = currentPath.startsWith(`/${locale}`)\n ? currentPath\n : `/${locale}${currentPath}`;\n\n const basePathTrailingSlash = basePath.endsWith('/');\n\n let newPath = `${normalizedBasePath}${basePathTrailingSlash ? '' : ''}${pathWithLocalePrefix}`;\n\n // Special case: if prefixDefault is false and locale is defaultLocale, remove the locale prefix\n if (!prefixDefault && locale === defaultLocale) {\n newPath = `${normalizedBasePath}${pathWithoutPrefix}`;\n }\n\n // Append search parameters if provided\n if (search) {\n newPath += search;\n }\n\n return newPath;\n };\n\n /* --------------------------------------------------------------------\n * Handlers that mirror Next.js style logic\n * --------------------------------------------------------------------\n */\n\n /**\n * If `noPrefix` is true, we never prefix the locale in the URL.\n * We simply rewrite the request to the same path, but with the best-chosen locale\n * in a header or search params if desired.\n */\n const handleNoPrefix = ({\n req,\n res,\n next,\n originalPath,\n searchParams,\n storageLocale,\n }: {\n req: Connect.IncomingMessage;\n res: ServerResponse<IncomingMessage>;\n next: Connect.NextFunction;\n originalPath: string;\n searchParams: string;\n storageLocale?: Locale;\n }) => {\n // Determine the best locale\n let locale = storageLocale ?? defaultLocale;\n\n // Use fallback to localeDetector if no storage locale\n if (!storageLocale) {\n const detectedLocale = localeDetector(\n req.headers as Record<string, string>,\n supportedLocales,\n defaultLocale\n );\n locale = detectedLocale as Locale;\n }\n\n // In search-params mode, we need to redirect to add the locale search param\n if (mode === 'search-params') {\n // Check if locale search param already exists and matches the detected locale\n const existingSearchParams = new URLSearchParams(searchParams ?? '');\n const existingLocale = existingSearchParams.get('locale');\n\n // If the existing locale matches the detected locale, no redirect needed\n if (existingLocale === locale) {\n // For internal routing, we need to add the locale prefix so the framework can match [locale] param\n const internalPath = `/${locale}${originalPath}`;\n const rewritePath = `${internalPath}${searchParams ?? ''}`;\n\n // Rewrite internally (URL stays the same in browser, but internally routes to /[locale]/path)\n rewriteUrl(req, res, rewritePath, locale);\n return next();\n }\n\n // Locale param missing or doesn't match - redirect to add/update it\n const search = appendLocaleSearchIfNeeded(searchParams, locale);\n const redirectPath = search\n ? `${originalPath}${search}`\n : `${originalPath}${searchParams ?? ''}`;\n\n // Redirect to add/update the locale search param (URL changes in browser)\n return redirectUrl(res, redirectPath);\n }\n\n // For no-prefix mode (not search-params), add locale prefix internally for routing\n const internalPath = `/${locale}${originalPath}`;\n\n // Add search params if needed\n const search = appendLocaleSearchIfNeeded(searchParams, locale);\n const rewritePath = search\n ? `${internalPath}${search}`\n : `${internalPath}${searchParams ?? ''}`;\n\n // Rewrite internally (URL stays the same in browser, but internally routes to /[locale]/path)\n rewriteUrl(req, res, rewritePath, locale);\n\n return next();\n };\n\n /**\n * The main prefix logic:\n * - If there's no pathLocale in the URL, we might want to detect & redirect or rewrite\n * - If there is a pathLocale, handle storage mismatch or default locale special cases\n */\n const handlePrefix = ({\n req,\n res,\n next,\n originalPath,\n searchParams,\n pathLocale,\n storageLocale,\n }: {\n req: Connect.IncomingMessage;\n res: ServerResponse<IncomingMessage>;\n next: Connect.NextFunction;\n originalPath: string;\n searchParams: string;\n pathLocale?: Locale;\n storageLocale?: Locale;\n }) => {\n // 1. If pathLocale is missing, handle\n if (!pathLocale) {\n handleMissingPathLocale({\n req,\n res,\n next,\n originalPath,\n searchParams,\n storageLocale,\n });\n return;\n }\n\n // 2. If pathLocale exists, handle it\n handleExistingPathLocale({\n req,\n res,\n next,\n originalPath,\n searchParams,\n pathLocale,\n });\n };\n\n /**\n * Handles requests where the locale is missing from the URL pathname.\n * We detect a locale from storage / headers / default, then either redirect or rewrite.\n */\n const handleMissingPathLocale = ({\n req,\n res,\n next,\n originalPath,\n searchParams,\n storageLocale,\n }: {\n req: Connect.IncomingMessage;\n res: ServerResponse<IncomingMessage>;\n next: Connect.NextFunction;\n originalPath: string;\n searchParams: string;\n storageLocale?: Locale;\n }) => {\n // 1. Choose the best locale\n let locale = (storageLocale ??\n localeDetector(\n req.headers as Record<string, string>,\n supportedLocales,\n defaultLocale\n )) as Locale;\n\n // 2. If still invalid, fallback\n if (!supportedLocales.includes(locale)) {\n locale = defaultLocale;\n }\n\n // 3. Construct new path - preserving original search params\n const search = appendLocaleSearchIfNeeded(searchParams, locale);\n const newPath = constructPath(locale, originalPath, search);\n\n // If we always prefix default or if this is not the default locale, do a 301 redirect\n // so that the user sees the locale in the URL.\n if (prefixDefault || locale !== defaultLocale) {\n return redirectUrl(res, newPath);\n }\n\n // If we do NOT prefix the default locale, just rewrite in place\n rewriteUrl(req, res, newPath, locale);\n return next();\n };\n\n /**\n * Handles requests where the locale prefix is present in the pathname.\n */\n const handleExistingPathLocale = ({\n req,\n res,\n next,\n originalPath,\n searchParams,\n pathLocale,\n }: {\n req: Connect.IncomingMessage;\n res: ServerResponse<IncomingMessage>;\n next: Connect.NextFunction;\n originalPath: string;\n searchParams: string;\n pathLocale: Locale;\n }) => {\n // In prefix modes, respect the URL path locale\n // The path locale takes precedence, and we'll update storage to match\n handleDefaultLocaleRedirect({\n req,\n res,\n next,\n originalPath,\n searchParams,\n pathLocale,\n });\n };\n\n /**\n * If the path locale is the default locale but we don't want to prefix the default, remove it.\n */\n const handleDefaultLocaleRedirect = ({\n req,\n res,\n next,\n originalPath,\n searchParams,\n pathLocale,\n }: {\n req: Connect.IncomingMessage;\n res: ServerResponse<IncomingMessage>;\n next: Connect.NextFunction;\n originalPath: string;\n searchParams: string;\n pathLocale: Locale;\n }) => {\n // If we don't prefix default AND the path locale is the default locale -> remove it\n if (!prefixDefault && pathLocale === defaultLocale) {\n // Remove the default locale part from the path\n let newPath = originalPath.replace(`/${defaultLocale}`, '') || '/';\n // In prefix modes, don't add locale to search params\n // Just preserve the original search params if they exist\n if (searchParams) {\n newPath += searchParams;\n }\n rewriteUrl(req, res, newPath, pathLocale);\n return next();\n }\n\n // If we do prefix default or pathLocale != default, keep as is, but rewrite headers\n // Preserve original search params without adding locale\n const newPath = searchParams\n ? `${originalPath}${searchParams}`\n : originalPath;\n rewriteUrl(req, res, newPath, pathLocale);\n return next();\n };\n\n return {\n name: 'vite-intlayer-middleware-plugin',\n configureServer: (server) => {\n server.middlewares.use((req, res, next) => {\n // Bypass assets and special Vite endpoints\n if (\n // Custom ignore function\n (options?.ignore?.(req) ?? false) ||\n req.url?.startsWith('/node_modules') ||\n /**\n * /^@vite/ # HMR client and helpers\n * /^@fs/ # file-system import serving\n * /^@id/ # virtual module ids\n * /^@tanstack/start-router-manifest # Tanstack Start Router manifest\n */\n req.url?.startsWith('/@') ||\n /**\n * /^__vite_ping$ # health ping\n * /^__open-in-editor$\n * /^__manifest$ # Remix/RR7 lazyRouteDiscovery\n */\n req.url?.startsWith('/_') ||\n /**\n * ./myFile.js\n */\n req.url\n ?.split('?')[0]\n .match(/\\.[a-z]+$/i) // checks for file extensions\n ) {\n return next();\n }\n\n // Parse original URL for path and query\n const parsedUrl = parse(req.url ?? '/', true);\n const originalPath = parsedUrl.pathname ?? '/';\n const searchParams = parsedUrl.search ?? '';\n\n // Check if there's a locale prefix in the path FIRST\n const pathLocale = getPathLocale(originalPath);\n\n // Attempt to read the locale from storage (cookies, localStorage, etc.)\n const storageLocale = getStorageLocale(req);\n\n // CRITICAL FIX: If there's a valid pathLocale, it takes precedence over storage\n // This prevents race conditions when cookies are stale during locale switches\n const effectiveStorageLocale =\n pathLocale && supportedLocales.includes(pathLocale)\n ? pathLocale\n : storageLocale;\n\n // If noPrefix is true, we skip prefix logic altogether\n if (noPrefix) {\n handleNoPrefix({\n req,\n res,\n next,\n originalPath,\n searchParams,\n storageLocale: effectiveStorageLocale,\n });\n return;\n }\n\n // Otherwise, handle prefix logic\n handlePrefix({\n req,\n res,\n next,\n originalPath,\n searchParams,\n pathLocale,\n storageLocale: effectiveStorageLocale,\n });\n });\n },\n };\n};\n\n/**\n * @deprecated Rename to intlayerProxy instead\n *\n * A Vite plugin that integrates a logic similar to the Next.js intlayer middleware.\n *\n * ```ts\n * // Example usage of the plugin in a Vite configuration\n * export default defineConfig({\n * plugins: [ intlayerMiddleware() ],\n * });\n * ```\n */\nexport const intlayerMiddleware = intlayerProxy;\n\n/**\n * @deprecated Rename to intlayerProxy instead\n * \n * A Vite plugin that integrates a logic similar to the Next.js intlayer middleware.\n\n * ```ts\n * // Example usage of the plugin in a Vite configuration\n * export default defineConfig({\n * plugins: [ intlayerMiddleware() ],\n * });\n * ```\n */\nexport const intLayerMiddlewarePlugin = intlayerProxy;\n"],"mappings":"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"}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
-
let node_module = require("node:module");
|
|
3
|
-
let node_path = require("node:path");
|
|
4
|
-
let __intlayer_babel = require("@intlayer/babel");
|
|
5
|
-
let __intlayer_chokidar = require("@intlayer/chokidar");
|
|
6
|
-
let __intlayer_config = require("@intlayer/config");
|
|
7
|
-
let __intlayer_dictionaries_entry = require("@intlayer/dictionaries-entry");
|
|
8
|
-
let fast_glob = require("fast-glob");
|
|
9
|
-
fast_glob = require_rolldown_runtime.__toESM(fast_glob);
|
|
10
|
-
|
|
11
|
-
//#region src/intlayerPrunePlugin.ts
|
|
12
|
-
const intlayerPrune = (intlayerConfig) => {
|
|
13
|
-
try {
|
|
14
|
-
const babel = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("@babel/core");
|
|
15
|
-
const logger = (0, __intlayer_config.getAppLogger)(intlayerConfig);
|
|
16
|
-
const { importMode, traversePattern, optimize } = intlayerConfig.build;
|
|
17
|
-
const { dictionariesDir, dynamicDictionariesDir, unmergedDictionariesDir, fetchDictionariesDir, mainDir, baseDir } = intlayerConfig.content;
|
|
18
|
-
const filesListPattern = fast_glob.default.sync(traversePattern, { cwd: baseDir }).map((file) => {
|
|
19
|
-
if ((0, node_path.isAbsolute)(file)) return file;
|
|
20
|
-
return (0, node_path.join)(baseDir, file);
|
|
21
|
-
});
|
|
22
|
-
const dictionariesEntryPath = (0, node_path.join)(mainDir, "dictionaries.mjs");
|
|
23
|
-
const unmergedDictionariesEntryPath = (0, node_path.join)(mainDir, "unmerged_dictionaries.mjs");
|
|
24
|
-
const dynamicDictionariesEntryPath = (0, node_path.join)(mainDir, "dynamic_dictionaries.mjs");
|
|
25
|
-
const filesList = [
|
|
26
|
-
...filesListPattern,
|
|
27
|
-
dictionariesEntryPath,
|
|
28
|
-
unmergedDictionariesEntryPath
|
|
29
|
-
];
|
|
30
|
-
const dictionaries = (0, __intlayer_dictionaries_entry.getDictionaries)(intlayerConfig);
|
|
31
|
-
const liveSyncKeys = Object.values(dictionaries).filter((dictionary) => dictionary.live).map((dictionary) => dictionary.key);
|
|
32
|
-
return [{
|
|
33
|
-
name: "vite-intlayer-simple-transform",
|
|
34
|
-
enforce: "pre",
|
|
35
|
-
apply: (_config, env) => {
|
|
36
|
-
const isBuild = env.command === "build";
|
|
37
|
-
return (optimize === void 0 && isBuild || optimize === true) && (importMode === "dynamic" || importMode === "live");
|
|
38
|
-
},
|
|
39
|
-
transform(code, id) {
|
|
40
|
-
if (!id.endsWith(".vue")) return null;
|
|
41
|
-
if (!code.includes("useIntlayer")) return null;
|
|
42
|
-
return {
|
|
43
|
-
code: code.replace(/(\s+|=\s*)useIntlayer\s*\(/g, "$1await useIntlayer("),
|
|
44
|
-
map: null
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
}, {
|
|
48
|
-
name: "vite-intlayer-babel-transform",
|
|
49
|
-
enforce: "post",
|
|
50
|
-
apply: (_config, env) => {
|
|
51
|
-
const isBuild = env.command === "build";
|
|
52
|
-
const isEnabled = optimize === void 0 && isBuild || optimize === true;
|
|
53
|
-
if (isEnabled) (0, __intlayer_chokidar.runOnce)((0, node_path.join)(baseDir, ".intlayer", "cache", "intlayer-prune-plugin-enabled.lock"), () => logger("Build optimization enabled"), { cacheTimeoutMs: 1e3 * 10 });
|
|
54
|
-
return isEnabled;
|
|
55
|
-
},
|
|
56
|
-
transform(code, id) {
|
|
57
|
-
/**
|
|
58
|
-
* Transform file as
|
|
59
|
-
* .../HelloWorld.vue?vue&type=script&setup=true&lang.ts
|
|
60
|
-
* Into
|
|
61
|
-
* .../HelloWorld.vue
|
|
62
|
-
*
|
|
63
|
-
* Prevention for virtual file
|
|
64
|
-
*/
|
|
65
|
-
const filename = id.split("?", 1)[0];
|
|
66
|
-
if (!filesList.includes(filename)) return null;
|
|
67
|
-
const result = babel.transformSync(code, {
|
|
68
|
-
filename,
|
|
69
|
-
plugins: [[__intlayer_babel.intlayerOptimizeBabelPlugin, {
|
|
70
|
-
optimize,
|
|
71
|
-
dictionariesDir,
|
|
72
|
-
dictionariesEntryPath,
|
|
73
|
-
unmergedDictionariesEntryPath,
|
|
74
|
-
unmergedDictionariesDir,
|
|
75
|
-
dynamicDictionariesDir,
|
|
76
|
-
dynamicDictionariesEntryPath,
|
|
77
|
-
fetchDictionariesDir,
|
|
78
|
-
importMode,
|
|
79
|
-
filesList,
|
|
80
|
-
replaceDictionaryEntry: true,
|
|
81
|
-
liveSyncKeys
|
|
82
|
-
}]],
|
|
83
|
-
parserOpts: {
|
|
84
|
-
sourceType: "module",
|
|
85
|
-
allowImportExportEverywhere: true,
|
|
86
|
-
plugins: [
|
|
87
|
-
"typescript",
|
|
88
|
-
"jsx",
|
|
89
|
-
"decorators-legacy",
|
|
90
|
-
"classProperties",
|
|
91
|
-
"objectRestSpread",
|
|
92
|
-
"asyncGenerators",
|
|
93
|
-
"functionBind",
|
|
94
|
-
"exportDefaultFrom",
|
|
95
|
-
"exportNamespaceFrom",
|
|
96
|
-
"dynamicImport",
|
|
97
|
-
"nullishCoalescingOperator",
|
|
98
|
-
"optionalChaining"
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
if (result?.code) return {
|
|
103
|
-
code: result.code,
|
|
104
|
-
map: result.map
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}];
|
|
108
|
-
} catch (error) {
|
|
109
|
-
console.warn("Failed to transform with Babel plugin:", error);
|
|
110
|
-
return [];
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
//#endregion
|
|
115
|
-
exports.intlayerPrune = intlayerPrune;
|
|
116
|
-
//# sourceMappingURL=intlayerPrunePlugin.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerPrunePlugin.cjs","names":["fg","intlayerOptimizeBabelPlugin"],"sources":["../../src/intlayerPrunePlugin.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { isAbsolute, join } from 'node:path';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport { runOnce } from '@intlayer/chokidar';\nimport { getAppLogger } from '@intlayer/config';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport fg from 'fast-glob';\nimport type { PluginOption } from 'vite';\n\nexport const intlayerPrune = (\n intlayerConfig: IntlayerConfig\n): PluginOption[] => {\n try {\n const localeRequire = createRequire(import.meta.url);\n const babel = localeRequire('@babel/core');\n const logger = getAppLogger(intlayerConfig);\n\n const { importMode, traversePattern, optimize } = intlayerConfig.build;\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n baseDir,\n } = intlayerConfig.content;\n\n const filesListPattern = fg\n .sync(traversePattern, {\n cwd: baseDir,\n })\n .map((file) => {\n if (isAbsolute(file)) {\n return file;\n }\n return join(baseDir, file);\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 const filesList = [\n ...filesListPattern,\n dictionariesEntryPath, // should add dictionariesEntryPath to replace it by a empty object if import made dynamic\n unmergedDictionariesEntryPath, // should add dictionariesEntryPath to replace it by a empty object if import made dynamic\n ];\n\n const dictionaries = getDictionaries(intlayerConfig);\n const liveSyncKeys = Object.values(dictionaries)\n .filter((dictionary) => dictionary.live)\n .map((dictionary) => dictionary.key);\n\n return [\n {\n /**\n * On vue, we pre-insert the 'await' to the useIntlayer call\n * It will trigger the transformation of the async call by the vue compiler\n *\n * Then the second plugin will make the second transformation to replace the useIntlayer call by the useDictionaryDynamic call\n */\n name: 'vite-intlayer-simple-transform',\n enforce: 'pre', // Run before Vue so Vue sees the 'await'\n apply: (_config, env) => {\n // Only apply babel plugin if optimize is enabled\n\n const isBuild = env.command === 'build';\n const isEnabled =\n (optimize === undefined && isBuild) || optimize === true;\n const isAsync = importMode === 'dynamic' || importMode === 'live';\n\n return isEnabled && isAsync;\n },\n\n transform(code, id) {\n // 1. Only process .vue files\n // The await injection is only needed for Vue to trigger async component compilation\n if (!id.endsWith('.vue')) return null;\n\n // 2. Check if the file actually uses the composable to avoid unnecessary work\n if (!code.includes('useIntlayer')) return null;\n\n // B. Add 'await' to the function call\n // Matches: useIntlayer(args) -> await useIntlayer(args)\n // Note: Since we aliased the import above, 'useIntlayer' now refers to 'useDictionaryAsync'\n const transformedCode = code.replace(\n /(\\s+|=\\s*)useIntlayer\\s*\\(/g,\n '$1await useIntlayer('\n );\n\n return {\n code: transformedCode,\n map: null, // Simple string replace doesn't strictly need a sourcemap for this case\n };\n },\n },\n {\n name: 'vite-intlayer-babel-transform',\n enforce: 'post', // Run after other transformations as vue\n apply: (_config, env) => {\n // Only apply babel plugin if optimize is enabled\n\n const isBuild = env.command === 'build';\n const isEnabled =\n (optimize === undefined && isBuild) || optimize === true;\n\n if (isEnabled) {\n runOnce(\n join(\n baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-prune-plugin-enabled.lock'\n ),\n () => logger('Build optimization enabled'),\n {\n cacheTimeoutMs: 1000 * 10, // 10 seconds\n }\n );\n }\n\n return isEnabled;\n },\n transform(code, id) {\n /**\n * Transform file as\n * .../HelloWorld.vue?vue&type=script&setup=true&lang.ts\n * Into\n * .../HelloWorld.vue\n *\n * Prevention for virtual file\n */\n const filename = id.split('?', 1)[0];\n\n if (!filesList.includes(filename)) return null;\n\n const result = babel.transformSync(code, {\n filename,\n plugins: [\n [\n intlayerOptimizeBabelPlugin,\n {\n optimize,\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 },\n },\n ];\n } catch (error) {\n console.warn('Failed to transform with Babel plugin:', error);\n\n return [];\n }\n};\n"],"mappings":";;;;;;;;;;;AAUA,MAAa,iBACX,mBACmB;AACnB,KAAI;EAEF,MAAM,qFAD8C,CACxB,cAAc;EAC1C,MAAM,6CAAsB,eAAe;EAE3C,MAAM,EAAE,YAAY,iBAAiB,aAAa,eAAe;EAEjE,MAAM,EACJ,iBACA,wBACA,yBACA,sBACA,SACA,YACE,eAAe;EAEnB,MAAM,mBAAmBA,kBACtB,KAAK,iBAAiB,EACrB,KAAK,SACN,CAAC,CACD,KAAK,SAAS;AACb,iCAAe,KAAK,CAClB,QAAO;AAET,8BAAY,SAAS,KAAK;IAC1B;EAEJ,MAAM,4CAA6B,SAAS,mBAAmB;EAC/D,MAAM,oDACJ,SACA,4BACD;EACD,MAAM,mDACJ,SACA,2BACD;EAED,MAAM,YAAY;GAChB,GAAG;GACH;GACA;GACD;EAED,MAAM,kEAA+B,eAAe;EACpD,MAAM,eAAe,OAAO,OAAO,aAAa,CAC7C,QAAQ,eAAe,WAAW,KAAK,CACvC,KAAK,eAAe,WAAW,IAAI;AAEtC,SAAO,CACL;GAOE,MAAM;GACN,SAAS;GACT,QAAQ,SAAS,QAAQ;IAGvB,MAAM,UAAU,IAAI,YAAY;AAKhC,YAHG,aAAa,UAAa,WAAY,aAAa,UACtC,eAAe,aAAa,eAAe;;GAK7D,UAAU,MAAM,IAAI;AAGlB,QAAI,CAAC,GAAG,SAAS,OAAO,CAAE,QAAO;AAGjC,QAAI,CAAC,KAAK,SAAS,cAAc,CAAE,QAAO;AAU1C,WAAO;KACL,MANsB,KAAK,QAC3B,+BACA,uBACD;KAIC,KAAK;KACN;;GAEJ,EACD;GACE,MAAM;GACN,SAAS;GACT,QAAQ,SAAS,QAAQ;IAGvB,MAAM,UAAU,IAAI,YAAY;IAChC,MAAM,YACH,aAAa,UAAa,WAAY,aAAa;AAEtD,QAAI,UACF,sDAEI,SACA,aACA,SACA,qCACD,QACK,OAAO,6BAA6B,EAC1C,EACE,gBAAgB,MAAO,IACxB,CACF;AAGH,WAAO;;GAET,UAAU,MAAM,IAAI;;;;;;;;;IASlB,MAAM,WAAW,GAAG,MAAM,KAAK,EAAE,CAAC;AAElC,QAAI,CAAC,UAAU,SAAS,SAAS,CAAE,QAAO;IAE1C,MAAM,SAAS,MAAM,cAAc,MAAM;KACvC;KACA,SAAS,CACP,CACEC,8CACA;MACE;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,wBAAwB;MACxB;MACD,CACF,CACF;KACD,YAAY;MACV,YAAY;MACZ,6BAA6B;MAC7B,SAAS;OACP;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACD;MACF;KACF,CAAC;AAEF,QAAI,QAAQ,KACV,QAAO;KACL,MAAM,OAAO;KACb,KAAK,OAAO;KACb;;GAGN,CACF;UACM,OAAO;AACd,UAAQ,KAAK,0CAA0C,MAAM;AAE7D,SAAO,EAAE"}
|