@intlayer/chokidar 8.11.2 → 8.12.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli.cjs +2 -0
- package/dist/cjs/init/index.cjs +28 -0
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/installLSP.cjs +58 -0
- package/dist/cjs/installLSP.cjs.map +1 -0
- package/dist/cjs/utils/buildComponentFilesList.cjs +42 -17
- package/dist/cjs/utils/buildComponentFilesList.cjs.map +1 -1
- package/dist/cjs/watcher.cjs +142 -111
- package/dist/cjs/watcher.cjs.map +1 -1
- package/dist/esm/cli.mjs +2 -1
- package/dist/esm/init/index.mjs +28 -0
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/installLSP.mjs +55 -0
- package/dist/esm/installLSP.mjs.map +1 -0
- package/dist/esm/utils/buildComponentFilesList.mjs +43 -18
- package/dist/esm/utils/buildComponentFilesList.mjs.map +1 -1
- package/dist/esm/watcher.mjs +144 -113
- package/dist/esm/watcher.mjs.map +1 -1
- package/dist/types/cli.d.ts +2 -1
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/installLSP.d.ts +12 -0
- package/dist/types/installLSP.d.ts.map +1 -0
- package/dist/types/utils/buildComponentFilesList.d.ts +10 -8
- package/dist/types/utils/buildComponentFilesList.d.ts.map +1 -1
- package/dist/types/watcher.d.ts +5 -3
- package/dist/types/watcher.d.ts.map +1 -1
- package/package.json +12 -12
package/dist/cjs/watcher.cjs
CHANGED
|
@@ -38,14 +38,25 @@ const processEvent = (task) => {
|
|
|
38
38
|
taskQueue.push(task);
|
|
39
39
|
processQueue();
|
|
40
40
|
};
|
|
41
|
+
const STABILITY_THRESHOLD = 1e3;
|
|
42
|
+
const createStabilityDebounce = () => {
|
|
43
|
+
const pending = /* @__PURE__ */ new Map();
|
|
44
|
+
return (path, handler) => {
|
|
45
|
+
const existing = pending.get(path);
|
|
46
|
+
if (existing) clearTimeout(existing);
|
|
47
|
+
pending.set(path, setTimeout(() => {
|
|
48
|
+
pending.delete(path);
|
|
49
|
+
handler();
|
|
50
|
+
}, STABILITY_THRESHOLD));
|
|
51
|
+
};
|
|
52
|
+
};
|
|
41
53
|
const watch = async (options) => {
|
|
42
|
-
const {
|
|
54
|
+
const { subscribe } = await import("@parcel/watcher");
|
|
43
55
|
const configResult = (0, _intlayer_config_node.getConfigurationAndFilePath)(options?.configOptions);
|
|
44
56
|
const configurationFilePath = configResult.configurationFilePath;
|
|
45
57
|
let configuration = options?.configuration ?? configResult.configuration;
|
|
46
58
|
const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
|
|
47
59
|
const { watch: isWatchMode, fileExtensions, contentDir, excludedPath } = configuration.content;
|
|
48
|
-
const pathsToWatch = [...contentDir.map((dir) => (0, _intlayer_config_utils.normalizePath)(dir)).filter(node_fs.existsSync), ...configurationFilePath ? [configurationFilePath] : []];
|
|
49
60
|
if (!configuration.content.watch) return;
|
|
50
61
|
appLogger("Watching Intlayer content declarations");
|
|
51
62
|
if (configuration.build.optimize === true) appLogger([
|
|
@@ -60,50 +71,51 @@ const watch = async (options) => {
|
|
|
60
71
|
const excludedSegments = excludedPath.map((segment) => segment.replace(/^\*\*\//, "").replace(/\/\*\*$/, ""));
|
|
61
72
|
const normalizedConfigPath = configurationFilePath ? (0, _intlayer_config_utils.normalizePath)(configurationFilePath) : null;
|
|
62
73
|
const { mainDir, baseDir } = configuration.system;
|
|
74
|
+
const normalizedMainDir = (0, _intlayer_config_utils.normalizePath)(mainDir);
|
|
63
75
|
const normalizedIntlayerDir = (0, _intlayer_config_utils.normalizePath)((0, node_path.dirname)(mainDir));
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
const subscriptions = [];
|
|
77
|
+
const fsWatchers = [];
|
|
78
|
+
const scheduleStable = createStabilityDebounce();
|
|
79
|
+
if ((0, node_fs.existsSync)(mainDir)) {
|
|
80
|
+
const mainDirSub = await subscribe(normalizedMainDir, (err, events) => {
|
|
81
|
+
if (err || isProcessing) return;
|
|
82
|
+
for (const event of events) {
|
|
83
|
+
const rel = (0, _intlayer_config_utils.normalizePath)(event.path).slice(normalizedMainDir.length + 1);
|
|
84
|
+
if (!rel || rel.includes("/")) continue;
|
|
85
|
+
if (rel.endsWith(".tmp")) continue;
|
|
86
|
+
if (event.type === "update") processEvent(async () => {
|
|
87
|
+
(0, _intlayer_config_utils.clearModuleCache)(event.path);
|
|
88
|
+
try {
|
|
89
|
+
await import(`${(0, node_url.pathToFileURL)(event.path).href}?update=${Date.now()}`);
|
|
90
|
+
} catch {
|
|
91
|
+
appLogger(`Entry point ${(0, node_path.basename)(event.path)} failed to load, running clean rebuild...`, { level: "warn" });
|
|
92
|
+
await require_prepareIntlayer.prepareIntlayer(configuration, {
|
|
93
|
+
clean: true,
|
|
94
|
+
forceRun: true
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
else if (event.type === "delete") processEvent(async () => {
|
|
99
|
+
appLogger([
|
|
100
|
+
"Entry point",
|
|
101
|
+
require_utils_formatter.formatPath((0, node_path.basename)(event.path)),
|
|
102
|
+
"was removed, running clean rebuild..."
|
|
103
|
+
], { level: "warn" });
|
|
104
|
+
await require_prepareIntlayer.prepareIntlayer(configuration, {
|
|
105
|
+
clean: true,
|
|
106
|
+
forceRun: true
|
|
107
|
+
});
|
|
79
108
|
});
|
|
80
109
|
}
|
|
81
110
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
await require_prepareIntlayer.prepareIntlayer(configuration, {
|
|
91
|
-
clean: true,
|
|
92
|
-
forceRun: true
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
chokidarWatch(baseDir, {
|
|
97
|
-
persistent: isWatchMode,
|
|
98
|
-
ignoreInitial: true,
|
|
99
|
-
depth: 0,
|
|
100
|
-
ignored: (filePath) => {
|
|
101
|
-
const path = (0, _intlayer_config_utils.normalizePath)(filePath);
|
|
102
|
-
return path !== (0, _intlayer_config_utils.normalizePath)(baseDir) && path !== normalizedIntlayerDir;
|
|
103
|
-
}
|
|
104
|
-
}).on("unlinkDir", async (dirPath) => {
|
|
105
|
-
if (isProcessing) return;
|
|
106
|
-
if ((0, _intlayer_config_utils.normalizePath)(dirPath) === normalizedIntlayerDir) {
|
|
111
|
+
subscriptions.push(mainDirSub);
|
|
112
|
+
}
|
|
113
|
+
const intlayerDirName = (0, node_path.basename)(normalizedIntlayerDir);
|
|
114
|
+
const fsDirWatcher = (0, node_fs.watch)(baseDir, { persistent: isWatchMode }, (eventType, filename) => {
|
|
115
|
+
if (isProcessing || !filename) return;
|
|
116
|
+
if (filename !== intlayerDirName) return;
|
|
117
|
+
if ((0, _intlayer_config_utils.normalizePath)((0, node_path.resolve)(baseDir, filename)) !== normalizedIntlayerDir) return;
|
|
118
|
+
if (eventType === "rename" && !(0, node_fs.existsSync)(normalizedIntlayerDir)) {
|
|
107
119
|
appLogger([require_utils_formatter.formatPath(".intlayer"), "directory removed, running clean rebuild..."]);
|
|
108
120
|
processEvent(() => require_prepareIntlayer.prepareIntlayer(configuration, {
|
|
109
121
|
clean: true,
|
|
@@ -111,81 +123,100 @@ const watch = async (options) => {
|
|
|
111
123
|
}));
|
|
112
124
|
}
|
|
113
125
|
});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (stats?.isFile()) return !fileExtensions.some((extension) => path.endsWith(extension));
|
|
126
|
-
return false;
|
|
127
|
-
},
|
|
128
|
-
...options
|
|
129
|
-
}).on("add", async (filePath) => {
|
|
130
|
-
const fileName = (0, node_path.basename)(filePath);
|
|
131
|
-
let isMove = false;
|
|
132
|
-
let matchedOldPath;
|
|
133
|
-
for (const [oldPath] of pendingUnlinks) if ((0, node_path.basename)(oldPath) === fileName) {
|
|
134
|
-
matchedOldPath = oldPath;
|
|
135
|
-
break;
|
|
126
|
+
fsWatchers.push(fsDirWatcher);
|
|
127
|
+
const ignorePatterns = excludedSegments.map((s) => `**/${s}/**`);
|
|
128
|
+
const contentDirs = contentDir.map((dir) => (0, _intlayer_config_utils.normalizePath)(dir)).filter(node_fs.existsSync);
|
|
129
|
+
const dirsToWatch = new Set(contentDirs);
|
|
130
|
+
if (normalizedConfigPath) dirsToWatch.add((0, _intlayer_config_utils.normalizePath)((0, node_path.dirname)(normalizedConfigPath)));
|
|
131
|
+
const contentHandler = (err, events) => {
|
|
132
|
+
if (err) {
|
|
133
|
+
appLogger(`Watcher error: ${err}`, { level: "error" });
|
|
134
|
+
appLogger("Restarting watcher");
|
|
135
|
+
require_prepareIntlayer.prepareIntlayer(configuration);
|
|
136
|
+
return;
|
|
136
137
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
for (const event of events) {
|
|
139
|
+
const filePath = event.path;
|
|
140
|
+
const path = (0, _intlayer_config_utils.normalizePath)(filePath);
|
|
141
|
+
const isConfigFile = normalizedConfigPath && path === normalizedConfigPath;
|
|
142
|
+
if (!isConfigFile) {
|
|
143
|
+
if (!contentDirs.some((d) => path.startsWith(`${d}/`) || path === d)) continue;
|
|
144
|
+
if (excludedSegments.some((segment) => path.includes(`/${segment}`))) continue;
|
|
145
|
+
if (!fileExtensions.some((extension) => path.endsWith(extension))) continue;
|
|
143
146
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
147
|
+
if (event.type === "create") {
|
|
148
|
+
const fileName = (0, node_path.basename)(filePath);
|
|
149
|
+
let isMove = false;
|
|
150
|
+
let matchedOldPath;
|
|
151
|
+
for (const [oldPath] of pendingUnlinks) if ((0, node_path.basename)(oldPath) === fileName) {
|
|
152
|
+
matchedOldPath = oldPath;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
if (!matchedOldPath && pendingUnlinks.size === 1) matchedOldPath = pendingUnlinks.keys().next().value;
|
|
156
|
+
if (matchedOldPath) {
|
|
157
|
+
const pending = pendingUnlinks.get(matchedOldPath);
|
|
158
|
+
if (pending) {
|
|
159
|
+
clearTimeout(pending.timer);
|
|
160
|
+
pendingUnlinks.delete(matchedOldPath);
|
|
161
|
+
}
|
|
162
|
+
isMove = true;
|
|
163
|
+
appLogger(`File moved from ${matchedOldPath} to ${filePath}`);
|
|
157
164
|
}
|
|
158
|
-
|
|
165
|
+
if (isMove && matchedOldPath) processEvent(async () => {
|
|
166
|
+
await require_handleContentDeclarationFileMoved.handleContentDeclarationFileMoved(matchedOldPath, filePath, configuration);
|
|
167
|
+
});
|
|
168
|
+
else scheduleStable(path, () => {
|
|
169
|
+
processEvent(async () => {
|
|
170
|
+
if (await (0, node_fs_promises.readFile)(filePath, "utf-8") === "") {
|
|
171
|
+
const extensionPattern = fileExtensions.map((ext) => ext.replace(/\./g, "\\.")).join("|");
|
|
172
|
+
await require_writeContentDeclaration_writeContentDeclaration.writeContentDeclaration({
|
|
173
|
+
key: fileName.replace(new RegExp(`(${extensionPattern})$`), ""),
|
|
174
|
+
content: {},
|
|
175
|
+
filePath
|
|
176
|
+
}, configuration);
|
|
177
|
+
}
|
|
178
|
+
await require_handleAdditionalContentDeclarationFile.handleAdditionalContentDeclarationFile(filePath, configuration);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
} else if (event.type === "update") scheduleStable(path, () => {
|
|
182
|
+
processEvent(async () => {
|
|
183
|
+
if (isConfigFile) {
|
|
184
|
+
appLogger("Configuration file changed, repreparing Intlayer");
|
|
185
|
+
(0, _intlayer_config_utils.clearModuleCache)(filePath);
|
|
186
|
+
(0, _intlayer_config_utils.clearAllCache)();
|
|
187
|
+
const { configuration: newConfiguration } = (0, _intlayer_config_node.getConfigurationAndFilePath)(options?.configOptions);
|
|
188
|
+
configuration = options?.configuration ?? newConfiguration;
|
|
189
|
+
await require_prepareIntlayer.prepareIntlayer(configuration, { clean: false });
|
|
190
|
+
} else {
|
|
191
|
+
(0, _intlayer_config_utils.clearModuleCache)(filePath);
|
|
192
|
+
(0, _intlayer_config_utils.clearAllCache)();
|
|
193
|
+
(0, _intlayer_config_utils.clearDiskCacheMemory)();
|
|
194
|
+
await require_handleContentDeclarationFileChange.handleContentDeclarationFileChange(filePath, configuration);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
else if (event.type === "delete") {
|
|
199
|
+
const timer = setTimeout(async () => {
|
|
200
|
+
pendingUnlinks.delete(filePath);
|
|
201
|
+
processEvent(async () => require_handleUnlinkedContentDeclarationFile.handleUnlinkedContentDeclarationFile(filePath, configuration));
|
|
202
|
+
}, 200);
|
|
203
|
+
pendingUnlinks.set(filePath, {
|
|
204
|
+
timer,
|
|
205
|
+
oldPath: filePath
|
|
206
|
+
});
|
|
159
207
|
}
|
|
160
|
-
});
|
|
161
|
-
}).on("change", async (filePath) => processEvent(async () => {
|
|
162
|
-
if (configurationFilePath && filePath === configurationFilePath) {
|
|
163
|
-
appLogger("Configuration file changed, repreparing Intlayer");
|
|
164
|
-
(0, _intlayer_config_utils.clearModuleCache)(configurationFilePath);
|
|
165
|
-
(0, _intlayer_config_utils.clearAllCache)();
|
|
166
|
-
const { configuration: newConfiguration } = (0, _intlayer_config_node.getConfigurationAndFilePath)(options?.configOptions);
|
|
167
|
-
configuration = options?.configuration ?? newConfiguration;
|
|
168
|
-
await require_prepareIntlayer.prepareIntlayer(configuration, { clean: false });
|
|
169
|
-
} else {
|
|
170
|
-
(0, _intlayer_config_utils.clearModuleCache)(filePath);
|
|
171
|
-
(0, _intlayer_config_utils.clearAllCache)();
|
|
172
|
-
(0, _intlayer_config_utils.clearDiskCacheMemory)();
|
|
173
|
-
await require_handleContentDeclarationFileChange.handleContentDeclarationFileChange(filePath, configuration);
|
|
174
208
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
209
|
+
};
|
|
210
|
+
for (const dir of dirsToWatch) {
|
|
211
|
+
const sub = await subscribe(dir, contentHandler, { ignore: ignorePatterns });
|
|
212
|
+
subscriptions.push(sub);
|
|
213
|
+
}
|
|
214
|
+
return { unsubscribe: async () => {
|
|
215
|
+
await Promise.all(subscriptions.map((subscription) => subscription.unsubscribe()));
|
|
216
|
+
fsWatchers.forEach((watcher) => {
|
|
217
|
+
watcher.close();
|
|
183
218
|
});
|
|
184
|
-
}
|
|
185
|
-
appLogger(`Watcher error: ${error}`, { level: "error" });
|
|
186
|
-
appLogger("Restarting watcher");
|
|
187
|
-
await require_prepareIntlayer.prepareIntlayer(configuration);
|
|
188
|
-
});
|
|
219
|
+
} };
|
|
189
220
|
};
|
|
190
221
|
const buildAndWatchIntlayer = async (options) => {
|
|
191
222
|
const { skipPrepare, ...rest } = options ?? {};
|
package/dist/cjs/watcher.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.cjs","names":["existsSync","ANSIColor","prepareIntlayer","formatPath","handleContentDeclarationFileMoved","writeContentDeclaration","handleAdditionalContentDeclarationFile","handleContentDeclarationFileChange","handleUnlinkedContentDeclarationFile"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { basename, dirname } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport * as ANSIColor from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearDiskCacheMemory,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { ChokidarOptions } from 'chokidar';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { formatPath } from './utils';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Array-based sequential task queue — no Promise chain accumulation, no race conditions\nconst taskQueue: (() => Promise<void>)[] = [];\nlet isProcessing = false;\n\nconst processQueue = async () => {\n if (isProcessing) return;\n isProcessing = true;\n while (taskQueue.length > 0) {\n const task = taskQueue.shift()!;\n try {\n await task();\n } catch (error) {\n console.error(error);\n }\n }\n isProcessing = false;\n};\n\nconst processEvent = (task: () => Promise<void>) => {\n taskQueue.push(task);\n processQueue();\n};\n\ntype WatchOptions = ChokidarOptions & {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n};\n\n// Initialize chokidar watcher (non-persistent)\nexport const watch = async (options?: WatchOptions) => {\n const { watch: chokidarWatch } = await import('chokidar');\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n excludedPath,\n } = configuration.content;\n\n // chokidar v5 dropped glob support — use fs to resolve dirs, filter extensions via ignored\n const pathsToWatch = [\n ...contentDir.map((dir) => normalizePath(dir)).filter(existsSync),\n ...(configurationFilePath ? [configurationFilePath] : []),\n ];\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n if (configuration.build.optimize === true) {\n appLogger(\n [\n `Build optimization is forced to ${colorize('true', ANSIColor.GREY)}, but watching is enabled too.`,\n 'It may lead to dev mode performance degradation as well as import errors.',\n 'Its recommended to keep the',\n colorize('`build.optimized`', ANSIColor.BLUE),\n 'option',\n colorize('undefined', ANSIColor.GREY),\n 'to get the best dev mode experience',\n ],\n {\n level: 'warn',\n }\n );\n }\n\n // Strip glob markers from excludedPath entries to get plain segments (e.g. 'node_modules')\n const excludedSegments = excludedPath.map((segment) =>\n segment.replace(/^\\*\\*\\//, '').replace(/\\/\\*\\*$/, '')\n );\n\n const normalizedConfigPath = configurationFilePath\n ? normalizePath(configurationFilePath)\n : null;\n\n const { mainDir, baseDir } = configuration.system;\n const normalizedIntlayerDir = normalizePath(dirname(mainDir));\n\n // Watch mainDir to detect broken or missing entry point files\n if (existsSync(mainDir)) {\n chokidarWatch(mainDir, {\n persistent: isWatchMode,\n ignoreInitial: true,\n depth: 0,\n })\n .on('change', async (filePath) => {\n if (isProcessing) return;\n\n processEvent(async () => {\n clearModuleCache(filePath);\n try {\n // Convert absolute path to a valid file:// URL\n const fileUrl = pathToFileURL(filePath).href;\n\n // Append a timestamp to bypass the ESM cache\n await import(`${fileUrl}?update=${Date.now()}`);\n } catch {\n appLogger(\n `Entry point ${basename(filePath)} failed to load, running clean rebuild...`,\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n }\n });\n })\n .on('unlink', async (filePath) => {\n if (isProcessing) return;\n\n processEvent(async () => {\n appLogger(\n [\n 'Entry point',\n formatPath(basename(filePath)),\n 'was removed, running clean rebuild...',\n ],\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, { clean: true, forceRun: true });\n });\n });\n }\n\n // Watch baseDir at depth 0 to detect the entire .intlayer folder being removed\n chokidarWatch(baseDir, {\n persistent: isWatchMode,\n ignoreInitial: true,\n depth: 0,\n ignored: (filePath: string) => {\n const path = normalizePath(filePath);\n return path !== normalizePath(baseDir) && path !== normalizedIntlayerDir;\n },\n }).on('unlinkDir', async (dirPath) => {\n if (isProcessing) return;\n\n if (normalizePath(dirPath) === normalizedIntlayerDir) {\n appLogger([\n formatPath('.intlayer'),\n 'directory removed, running clean rebuild...',\n ]);\n\n processEvent(() =>\n prepareIntlayer(configuration, { clean: true, forceRun: true })\n );\n }\n });\n\n return chokidarWatch(pathsToWatch, {\n persistent: isWatchMode, // Make the watcher persistent\n ignoreInitial: true, // Process existing files\n awaitWriteFinish: {\n stabilityThreshold: 1000,\n pollInterval: 100,\n },\n ignored: (filePath: string, stats?: import('node:fs').Stats) => {\n const path = normalizePath(filePath);\n\n if (normalizedConfigPath && path === normalizedConfigPath) return false;\n\n if (excludedSegments.some((segment) => path.includes(`/${segment}`)))\n return true;\n\n if (stats?.isFile()) {\n return !fileExtensions.some((extension) => path.endsWith(extension));\n }\n\n return false;\n },\n ...options,\n })\n .on('add', async (filePath) => {\n const fileName = basename(filePath);\n let isMove = false;\n\n // Check if this Add corresponds to a pending Unlink (Move/Rename detection)\n // Heuristic:\n // - Priority A: Exact basename match (Moved to different folder)\n // - Priority B: Single entry in pendingUnlinks (Renamed file)\n let matchedOldPath: string | undefined;\n\n // Search for basename match\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n // If no basename match, but exactly one file was recently unlinked, assume it's a rename\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n // It is a move! Cancel the unlink handler\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n processEvent(async () => {\n if (isMove && matchedOldPath) {\n await handleContentDeclarationFileMoved(\n matchedOldPath,\n filePath,\n configuration\n );\n } else {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n // Fill template content declaration file if it is empty\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n {\n key: name,\n content: {},\n filePath,\n },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(filePath, configuration);\n }\n });\n })\n .on('change', async (filePath) =>\n processEvent(async () => {\n if (configurationFilePath && filePath === configurationFilePath) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(configurationFilePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n // Evict in-memory caches so loadContentDeclaration picks up fresh content\n clearAllCache();\n clearDiskCacheMemory();\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n })\n )\n .on('unlink', async (filePath) => {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'add' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n })\n .on('error', async (error) => {\n appLogger(`Watcher error: ${error}`, {\n level: 'error',\n });\n\n appLogger('Restarting watcher');\n\n await prepareIntlayer(configuration);\n });\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n // Only enter watch mode when the caller explicitly opts in via `persistent`.\n // `configuration.content.watch` is the dev-mode signal consumed by bundler\n // plugins (e.g. vite-intlayer's `configureServer`); it must not coerce\n // `intlayer build` (which passes `persistent: false`) into a persistent\n // watcher, since that prevents the build command from ever exiting.\n if (options?.persistent) {\n await watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"watcher.cjs","names":["ANSIColor","prepareIntlayer","formatPath","existsSync","handleContentDeclarationFileMoved","writeContentDeclaration","handleAdditionalContentDeclarationFile","handleContentDeclarationFileChange","handleUnlinkedContentDeclarationFile"],"sources":["../../src/watcher.ts"],"sourcesContent":["import { existsSync, watch as fsWatch } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { basename, dirname, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport * as ANSIColor from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n getConfigurationAndFilePath,\n} from '@intlayer/config/node';\nimport {\n clearAllCache,\n clearDiskCacheMemory,\n clearModuleCache,\n normalizePath,\n} from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { handleAdditionalContentDeclarationFile } from './handleAdditionalContentDeclarationFile';\nimport { handleContentDeclarationFileChange } from './handleContentDeclarationFileChange';\nimport { handleContentDeclarationFileMoved } from './handleContentDeclarationFileMoved';\nimport { handleUnlinkedContentDeclarationFile } from './handleUnlinkedContentDeclarationFile';\nimport { prepareIntlayer } from './prepareIntlayer';\nimport { formatPath } from './utils';\nimport { writeContentDeclaration } from './writeContentDeclaration';\n\n// Map to track files that were recently unlinked: oldPath -> { timer, timestamp }\nconst pendingUnlinks = new Map<\n string,\n { timer: NodeJS.Timeout; oldPath: string }\n>();\n\n// Array-based sequential task queue — no Promise chain accumulation, no race conditions\nconst taskQueue: (() => Promise<void>)[] = [];\nlet isProcessing = false;\n\nconst processQueue = async () => {\n if (isProcessing) return;\n isProcessing = true;\n while (taskQueue.length > 0) {\n const task = taskQueue.shift()!;\n try {\n await task();\n } catch (error) {\n console.error(error);\n }\n }\n isProcessing = false;\n};\n\nconst processEvent = (task: () => Promise<void>) => {\n taskQueue.push(task);\n processQueue();\n};\n\ntype WatchOptions = {\n configuration?: IntlayerConfig;\n configOptions?: GetConfigurationOptions;\n skipPrepare?: boolean;\n persistent?: boolean;\n};\n\n// awaitWriteFinish equivalent: debounce per path until the file is stable\nconst STABILITY_THRESHOLD = 1000;\n\nconst createStabilityDebounce = () => {\n const pending = new Map<string, NodeJS.Timeout>();\n return (path: string, handler: () => void) => {\n const existing = pending.get(path);\n if (existing) clearTimeout(existing);\n pending.set(\n path,\n setTimeout(() => {\n pending.delete(path);\n handler();\n }, STABILITY_THRESHOLD)\n );\n };\n};\n\n// Initialize @parcel/watcher (non-persistent until subscribed)\nexport const watch = async (options?: WatchOptions) => {\n const { subscribe } = await import('@parcel/watcher');\n\n const configResult = getConfigurationAndFilePath(options?.configOptions);\n const configurationFilePath = configResult.configurationFilePath;\n let configuration: IntlayerConfig =\n options?.configuration ?? configResult.configuration;\n const appLogger = getAppLogger(configuration);\n\n const {\n watch: isWatchMode,\n fileExtensions,\n contentDir,\n excludedPath,\n } = configuration.content;\n\n if (!configuration.content.watch) return;\n\n appLogger('Watching Intlayer content declarations');\n\n if (configuration.build.optimize === true) {\n appLogger(\n [\n `Build optimization is forced to ${colorize('true', ANSIColor.GREY)}, but watching is enabled too.`,\n 'It may lead to dev mode performance degradation as well as import errors.',\n 'Its recommended to keep the',\n colorize('`build.optimized`', ANSIColor.BLUE),\n 'option',\n colorize('undefined', ANSIColor.GREY),\n 'to get the best dev mode experience',\n ],\n {\n level: 'warn',\n }\n );\n }\n\n // Strip glob markers from excludedPath entries to get plain segments (e.g. 'node_modules')\n const excludedSegments = excludedPath.map((segment) =>\n segment.replace(/^\\*\\*\\//, '').replace(/\\/\\*\\*$/, '')\n );\n\n const normalizedConfigPath = configurationFilePath\n ? normalizePath(configurationFilePath)\n : null;\n\n const { mainDir, baseDir } = configuration.system;\n const normalizedMainDir = normalizePath(mainDir);\n const normalizedIntlayerDir = normalizePath(dirname(mainDir));\n\n const subscriptions: { unsubscribe: () => Promise<void> }[] = [];\n const fsWatchers: import('node:fs').FSWatcher[] = [];\n\n const scheduleStable = createStabilityDebounce();\n\n // ── mainDir watcher (depth 0) ──────────────────────────────────────────────\n // Detects broken or missing entry-point files inside .intlayer/main\n if (existsSync(mainDir)) {\n const mainDirSub = await subscribe(normalizedMainDir, (err, events) => {\n if (err || isProcessing) return;\n\n for (const event of events) {\n const eventPath = normalizePath(event.path);\n // depth-0 filter: only files directly inside mainDir\n const rel = eventPath.slice(normalizedMainDir.length + 1);\n if (!rel || rel.includes('/')) continue;\n // Temp files written by the bundler (write-then-rename) are build-internal;\n // their deletion must not trigger a clean rebuild.\n if (rel.endsWith('.tmp')) continue;\n\n if (event.type === 'update') {\n processEvent(async () => {\n clearModuleCache(event.path);\n try {\n const fileUrl = pathToFileURL(event.path).href;\n await import(`${fileUrl}?update=${Date.now()}`);\n } catch {\n appLogger(\n `Entry point ${basename(event.path)} failed to load, running clean rebuild...`,\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n }\n });\n } else if (event.type === 'delete') {\n processEvent(async () => {\n appLogger(\n [\n 'Entry point',\n formatPath(basename(event.path)),\n 'was removed, running clean rebuild...',\n ],\n { level: 'warn' }\n );\n await prepareIntlayer(configuration, {\n clean: true,\n forceRun: true,\n });\n });\n }\n }\n });\n subscriptions.push(mainDirSub);\n }\n\n // ── baseDir watcher (depth 0) — detect .intlayer directory removal ─────────\n // Native fs.watch is non-recursive and ideal for single-directory depth-0 detection.\n const intlayerDirName = basename(normalizedIntlayerDir);\n const fsDirWatcher = fsWatch(\n baseDir,\n { persistent: isWatchMode },\n (eventType, filename) => {\n if (isProcessing || !filename) return;\n if (filename !== intlayerDirName) return;\n\n const fullPath = normalizePath(resolve(baseDir, filename));\n if (fullPath !== normalizedIntlayerDir) return;\n\n if (eventType === 'rename' && !existsSync(normalizedIntlayerDir)) {\n appLogger([\n formatPath('.intlayer'),\n 'directory removed, running clean rebuild...',\n ]);\n processEvent(() =>\n prepareIntlayer(configuration, { clean: true, forceRun: true })\n );\n }\n }\n );\n fsWatchers.push(fsDirWatcher);\n\n // ── main content watcher ───────────────────────────────────────────────────\n // Ignore patterns for @parcel/watcher (micromatch globs)\n const ignorePatterns = excludedSegments.map((s) => `**/${s}/**`);\n\n const contentDirs = contentDir\n .map((dir) => normalizePath(dir))\n .filter(existsSync);\n\n // Collect unique directories to subscribe to (dirs only, not file paths)\n const dirsToWatch = new Set<string>(contentDirs);\n if (normalizedConfigPath) {\n dirsToWatch.add(normalizePath(dirname(normalizedConfigPath)));\n }\n\n const contentHandler = (\n err: Error | null,\n events: Array<{ type: string; path: string }>\n ) => {\n if (err) {\n appLogger(`Watcher error: ${err}`, { level: 'error' });\n appLogger('Restarting watcher');\n prepareIntlayer(configuration);\n return;\n }\n\n for (const event of events) {\n const filePath = event.path;\n const path = normalizePath(filePath);\n\n const isConfigFile =\n normalizedConfigPath && path === normalizedConfigPath;\n\n if (!isConfigFile) {\n // Must originate from a watched content directory\n const isInContentDir = contentDirs.some(\n (d) => path.startsWith(`${d}/`) || path === d\n );\n if (!isInContentDir) continue;\n\n if (excludedSegments.some((segment) => path.includes(`/${segment}`)))\n continue;\n\n if (!fileExtensions.some((extension) => path.endsWith(extension)))\n continue;\n }\n\n if (event.type === 'create') {\n const fileName = basename(filePath);\n\n // Move detection must happen synchronously before any debounce\n let isMove = false;\n let matchedOldPath: string | undefined;\n\n for (const [oldPath] of pendingUnlinks) {\n if (basename(oldPath) === fileName) {\n matchedOldPath = oldPath;\n break;\n }\n }\n\n if (!matchedOldPath && pendingUnlinks.size === 1) {\n matchedOldPath = pendingUnlinks.keys().next().value;\n }\n\n if (matchedOldPath) {\n const pending = pendingUnlinks.get(matchedOldPath);\n if (pending) {\n clearTimeout(pending.timer);\n pendingUnlinks.delete(matchedOldPath);\n }\n isMove = true;\n appLogger(`File moved from ${matchedOldPath} to ${filePath}`);\n }\n\n if (isMove && matchedOldPath) {\n processEvent(async () => {\n await handleContentDeclarationFileMoved(\n matchedOldPath!,\n filePath,\n configuration\n );\n });\n } else {\n // Debounce: wait for write to finish before reading the file\n scheduleStable(path, () => {\n processEvent(async () => {\n const fileContent = await readFile(filePath, 'utf-8');\n const isEmpty = fileContent === '';\n\n if (isEmpty) {\n const extensionPattern = fileExtensions\n .map((ext) => ext.replace(/\\./g, '\\\\.'))\n .join('|');\n const name = fileName.replace(\n new RegExp(`(${extensionPattern})$`),\n ''\n );\n\n await writeContentDeclaration(\n { key: name, content: {}, filePath },\n configuration\n );\n }\n\n await handleAdditionalContentDeclarationFile(\n filePath,\n configuration\n );\n });\n });\n }\n } else if (event.type === 'update') {\n scheduleStable(path, () => {\n processEvent(async () => {\n if (isConfigFile) {\n appLogger('Configuration file changed, repreparing Intlayer');\n\n clearModuleCache(filePath);\n clearAllCache();\n\n const { configuration: newConfiguration } =\n getConfigurationAndFilePath(options?.configOptions);\n\n configuration = options?.configuration ?? newConfiguration;\n\n await prepareIntlayer(configuration, { clean: false });\n } else {\n // Clear module cache for the changed file to avoid stale require() results\n clearModuleCache(filePath);\n // Evict in-memory caches so loadContentDeclaration picks up fresh content\n clearAllCache();\n clearDiskCacheMemory();\n await handleContentDeclarationFileChange(filePath, configuration);\n }\n });\n });\n } else if (event.type === 'delete') {\n // Delay unlink processing to see if an 'add' event occurs (indicating a move)\n const timer = setTimeout(async () => {\n // If timer fires, the file was genuinely removed\n pendingUnlinks.delete(filePath);\n processEvent(async () =>\n handleUnlinkedContentDeclarationFile(filePath, configuration)\n );\n }, 200); // 200ms window to catch the 'create' event\n\n pendingUnlinks.set(filePath, { timer, oldPath: filePath });\n }\n }\n };\n\n for (const dir of dirsToWatch) {\n const sub = await subscribe(dir, contentHandler, {\n ignore: ignorePatterns,\n });\n\n subscriptions.push(sub);\n }\n\n return {\n unsubscribe: async () => {\n await Promise.all(\n subscriptions.map((subscription) => subscription.unsubscribe())\n );\n\n fsWatchers.forEach((watcher) => {\n watcher.close();\n });\n },\n };\n};\n\nexport const buildAndWatchIntlayer = async (options?: WatchOptions) => {\n const { skipPrepare, ...rest } = options ?? {};\n const configuration =\n options?.configuration ?? getConfiguration(options?.configOptions);\n\n if (!skipPrepare) {\n await prepareIntlayer(configuration, { forceRun: true });\n }\n\n // Only enter watch mode when the caller explicitly opts in via `persistent`.\n // `configuration.content.watch` is the dev-mode signal consumed by bundler\n // plugins (e.g. vite-intlayer's `configureServer`); it must not coerce\n // `intlayer build` (which passes `persistent: false`) into a persistent\n // watcher, since that prevents the build command from ever exiting.\n if (options?.persistent) {\n await watch({ ...rest, configuration });\n }\n};\n"],"mappings":"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"}
|
package/dist/esm/cli.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { listProjects } from "./listProjects.mjs";
|
|
2
|
+
import { installLSP } from "./installLSP.mjs";
|
|
2
3
|
import { listDictionaries, listDictionariesWithStats } from "./listDictionariesPath.mjs";
|
|
3
4
|
import { prepareIntlayer } from "./prepareIntlayer.mjs";
|
|
4
5
|
import { detectExportedComponentName } from "./writeContentDeclaration/detectExportedComponentName.mjs";
|
|
@@ -13,4 +14,4 @@ import { installMCP } from "./installMCP/installMCP.mjs";
|
|
|
13
14
|
import { listGitFiles, listGitLines } from "./listGitFiles.mjs";
|
|
14
15
|
import { logConfigDetails } from "./logConfigDetails.mjs";
|
|
15
16
|
|
|
16
|
-
export { PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, detectExportedComponentName, detectFormatCommand, getContentDeclarationFileTemplate, getInitialSkills, initIntlayer, installMCP, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, prepareIntlayer, transformJSFile, writeContentDeclaration, writeJSFile };
|
|
17
|
+
export { PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, detectExportedComponentName, detectFormatCommand, getContentDeclarationFileTemplate, getInitialSkills, initIntlayer, installLSP, installMCP, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, prepareIntlayer, transformJSFile, writeContentDeclaration, writeJSFile };
|
package/dist/esm/init/index.mjs
CHANGED
|
@@ -36,6 +36,7 @@ const DocumentationRouter = {
|
|
|
36
36
|
NestJS: "https://intlayer.org/doc/environment/nestjs.md",
|
|
37
37
|
Fastify: "https://intlayer.org/doc/environment/fastify.md",
|
|
38
38
|
Default: "https://intlayer.org/doc/get-started",
|
|
39
|
+
LSP: "https://intlayer.org/doc/lsp.md",
|
|
39
40
|
NextIntl: "https://intlayer.org/blog/intlayer-with-next-intl.md",
|
|
40
41
|
ReactI18Next: "https://intlayer.org/blog/intlayer-with-react-i18next.md",
|
|
41
42
|
ReactIntl: "https://intlayer.org/blog/intlayer-with-react-intl.md",
|
|
@@ -137,6 +138,27 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
137
138
|
} catch {
|
|
138
139
|
logger(`${x} Could not update ${colorizePath(extensionsJsonPath)}. You may need to add ${colorize(extensionId, ANSIColors.MAGENTA)} manually.`, { level: "warn" });
|
|
139
140
|
}
|
|
141
|
+
const settingsJsonPath = join(vscodeDir, "settings.json");
|
|
142
|
+
try {
|
|
143
|
+
let settingsConfig = {};
|
|
144
|
+
if (await exists(rootDir, settingsJsonPath)) settingsConfig = parseJSONWithComments(await readFileFromRoot(rootDir, settingsJsonPath));
|
|
145
|
+
else await ensureDirectory(rootDir, vscodeDir);
|
|
146
|
+
let settingsUpdated = false;
|
|
147
|
+
if (!settingsConfig["intlayer.languageServer.command"]) {
|
|
148
|
+
settingsConfig["intlayer.languageServer.command"] = "npx";
|
|
149
|
+
settingsUpdated = true;
|
|
150
|
+
}
|
|
151
|
+
if (!settingsConfig["intlayer.languageServer.args"]) {
|
|
152
|
+
settingsConfig["intlayer.languageServer.args"] = ["@intlayer/lsp"];
|
|
153
|
+
settingsUpdated = true;
|
|
154
|
+
}
|
|
155
|
+
if (settingsUpdated) {
|
|
156
|
+
await writeFileToRoot(rootDir, settingsJsonPath, JSON.stringify(settingsConfig, null, 2));
|
|
157
|
+
logger(`${v} Updated ${colorizePath(settingsJsonPath)} with LSP configuration`);
|
|
158
|
+
} else logger(`${v} ${colorizePath(settingsJsonPath)} already includes LSP configuration`);
|
|
159
|
+
} catch {
|
|
160
|
+
logger(`${x} Could not update ${colorizePath(settingsJsonPath)}. You may need to add the LSP settings manually.`, { level: "warn" });
|
|
161
|
+
}
|
|
140
162
|
const tsConfigFiles = await findTsConfigFiles(rootDir);
|
|
141
163
|
let hasTsConfig = false;
|
|
142
164
|
for (const fileName of tsConfigFiles) if (await exists(rootDir, fileName)) {
|
|
@@ -313,6 +335,12 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
313
335
|
colorize(`Follow the instructions in the documentation to complete the setup:`, ANSIColors.GREY_LIGHT),
|
|
314
336
|
colorizePath(guideUrl)
|
|
315
337
|
]);
|
|
338
|
+
logger([
|
|
339
|
+
colorize("Intlayer LSP →", ANSIColors.MAGENTA),
|
|
340
|
+
colorize("The Intlayer Language Server is available via the `@intlayer/lsp` package. It lets IDEs and AI agents jump from `useIntlayer`/`getIntlayer` keys to their `.content` files.", ANSIColors.GREY_LIGHT),
|
|
341
|
+
colorize("Ask the user which platform/editor they want to enable it on (VS Code, Cursor, Windsurf, Zed, Neovim, Claude Code, …), then follow the matching setup instructions:", ANSIColors.GREY_LIGHT),
|
|
342
|
+
colorizePath(DocumentationRouter.LSP)
|
|
343
|
+
]);
|
|
316
344
|
};
|
|
317
345
|
|
|
318
346
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/init/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\n\nimport { getAlias } from '@intlayer/config/utils';\nimport { initConfig } from '../initConfig';\nimport {\n ensureDirectory,\n exists,\n findTsConfigFiles,\n parseJSONWithComments,\n readFileFromRoot,\n updateAstroConfig,\n updateNextConfig,\n updateNuxtConfig,\n updateViteConfig,\n writeFileToRoot,\n} from './utils';\n\n/**\n * Documentation URL Constants\n */\nconst DocumentationRouter = {\n NextJS: 'https://intlayer.org/doc/environment/nextjs.md',\n NextJS_15: 'https://intlayer.org/doc/environment/nextjs/15.md',\n NextJS_14: 'https://intlayer.org/doc/environment/nextjs/14.md',\n CRA: 'https://intlayer.org/doc/environment/create-react-app.md',\n Astro: 'https://intlayer.org/doc/environment/astro.md',\n ViteAndReact: 'https://intlayer.org/doc/environment/vite-and-react.md',\n ViteAndReact_ReactRouterV7:\n 'https://intlayer.org/doc/environment/vite-and-react/react-router-v7.md',\n ViteAndReact_ReactRouterV7_FSRoutes:\n 'https://intlayer.org/doc/environment/vite-and-react/react-router-v7-fs-routes.md',\n ViteAndVue: 'https://intlayer.org/doc/environment/vite-and-vue.md',\n ViteAndSolid: 'https://intlayer.org/doc/environment/vite-and-solid.md',\n ViteAndSvelte: 'https://intlayer.org/doc/environment/vite-and-svelte.md',\n ViteAndPreact: 'https://intlayer.org/doc/environment/vite-and-preact.md',\n TanStackRouter: 'https://intlayer.org/doc/environment/tanstack.md',\n NuxtAndVue: 'https://intlayer.org/doc/environment/nuxt-and-vue.md',\n Angular: 'https://intlayer.org/doc/environment/angular.md',\n SvelteKit: 'https://intlayer.org/doc/environment/sveltekit.md',\n ReactNativeAndExpo:\n 'https://intlayer.org/doc/environment/react-native-and-expo.md',\n Lynx: 'https://intlayer.org/doc/environment/lynx-and-react.md',\n Express: 'https://intlayer.org/doc/environment/express.md',\n NestJS: 'https://intlayer.org/doc/environment/nestjs.md',\n Fastify: 'https://intlayer.org/doc/environment/fastify.md',\n Default: 'https://intlayer.org/doc/get-started',\n\n // Check for competitors libs\n NextIntl: 'https://intlayer.org/blog/intlayer-with-next-intl.md',\n ReactI18Next: 'https://intlayer.org/blog/intlayer-with-react-i18next.md',\n ReactIntl: 'https://intlayer.org/blog/intlayer-with-react-intl.md',\n NextI18Next: 'https://intlayer.org/blog/intlayer-with-next-i18next.md',\n VueI18n: 'https://intlayer.org/blog/intlayer-with-vue-i18n.md',\n};\n\n/**\n * Helper: Detects the environment and returns the doc URL\n */\nconst getDocumentationUrl = (packageJson: any): string => {\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n /**\n * Helper to check if a version string matches a specific major version\n * Matches: \"15\", \"^15.0.0\", \"~15.2\", \"15.0.0-beta\"\n */\n const isVersion = (versionString: string, major: number): boolean => {\n if (!versionString || typeof versionString !== 'string') return false;\n const regex = new RegExp(`^[\\\\^~]?${major}(?:\\\\.|$)`);\n return regex.test(versionString);\n };\n\n // Mobile / Cross-platform\n if (deps['@lynx-js/react'] || deps['@lynx-js/core']) {\n return DocumentationRouter.Lynx;\n }\n if (deps['react-native'] || deps.expo) {\n return DocumentationRouter.ReactNativeAndExpo;\n }\n\n // Meta-frameworks (Next, Nuxt, Astro, SvelteKit)\n if (deps.next) {\n const version = deps.next;\n\n if (isVersion(version, 14)) {\n return DocumentationRouter.NextJS_14;\n }\n\n if (isVersion(version, 15)) {\n return DocumentationRouter.NextJS_15;\n }\n\n return DocumentationRouter.NextJS;\n }\n\n if (deps.nuxt) return DocumentationRouter.NuxtAndVue;\n if (deps.astro) return DocumentationRouter.Astro;\n if (deps['@sveltejs/kit']) return DocumentationRouter.SvelteKit;\n\n // Routers (TanStack & React Router v7)\n if (deps['@tanstack/react-router']) {\n return DocumentationRouter.TanStackRouter;\n }\n\n // Check for React Router v7\n const reactRouterVersion = deps['react-router'];\n if (reactRouterVersion && typeof reactRouterVersion === 'string') {\n // Distinguish between standard v7 and v7 with FS routes\n if (deps['@react-router/fs-routes']) {\n return DocumentationRouter.ViteAndReact_ReactRouterV7_FSRoutes;\n }\n\n // Use Regex to ensure it is v7\n if (isVersion(reactRouterVersion, 7)) {\n return DocumentationRouter.ViteAndReact_ReactRouterV7;\n }\n }\n\n // Vite Ecosystem (General)\n if (deps.vite) {\n if (deps.vue) return DocumentationRouter.ViteAndVue;\n if (deps['solid-js']) return DocumentationRouter.ViteAndSolid;\n if (deps.svelte) return DocumentationRouter.ViteAndSvelte;\n if (deps.preact) return DocumentationRouter.ViteAndPreact;\n\n // Default to React if Vite is present but specific other frameworks aren't found\n return DocumentationRouter.ViteAndReact;\n }\n\n // Other Web Frameworks\n if (deps['react-scripts']) return DocumentationRouter.CRA;\n if (deps['@angular/core']) return DocumentationRouter.Angular;\n\n // Backend\n if (deps['@nestjs/core']) return DocumentationRouter.NestJS;\n if (deps.express) return DocumentationRouter.Express;\n if (deps.fastify) return DocumentationRouter.Fastify;\n\n // Competitor Libs (Migration Guides)\n // We check these last as specific environment setup is usually higher priority,\n // but if no specific framework logic matched (or as a fallback), we guide to migration.\n if (deps['next-intl']) return DocumentationRouter.NextIntl;\n if (deps['react-i18next'] || deps.i18next)\n return DocumentationRouter.ReactI18Next;\n if (deps['react-intl']) return DocumentationRouter.ReactIntl;\n if (deps['next-i18next']) return DocumentationRouter.NextI18Next;\n if (deps['vue-i18n']) return DocumentationRouter.VueI18n;\n\n return DocumentationRouter.Default;\n};\n\n/**\n * OPTIONS\n */\nexport type InitOptions = {\n noGitignore?: boolean;\n};\n\n/**\n * MAIN LOGIC\n */\nexport const initIntlayer = async (rootDir: string, options?: InitOptions) => {\n logger(colorize('Checking Intlayer configuration...', ANSIColors.CYAN));\n\n // READ PACKAGE.JSON\n const packageJsonPath = 'package.json';\n if (!(await exists(rootDir, packageJsonPath))) {\n logger(\n `${x} No ${colorizePath('package.json')} found. Please run this script from the project root.`,\n { level: 'error' }\n );\n process.exit(1);\n }\n\n const packageJsonContent = await readFileFromRoot(rootDir, packageJsonPath);\n let packageJson: Record<string, any>;\n try {\n packageJson = JSON.parse(packageJsonContent);\n } catch {\n logger(`${x} Could not parse ${colorizePath('package.json')}.`, {\n level: 'error',\n });\n process.exit(1);\n }\n\n // Determine the correct documentation URL based on dependencies\n const guideUrl = getDocumentationUrl(packageJson);\n\n // CHECK .GITIGNORE\n const gitignorePath = '.gitignore';\n if (!options?.noGitignore && (await exists(rootDir, gitignorePath))) {\n const gitignoreContent = await readFileFromRoot(rootDir, gitignorePath);\n\n if (!gitignoreContent.includes('intlayer')) {\n const newContent = `${gitignoreContent}\\n# Intlayer\\n.intlayer\\n`;\n await writeFileToRoot(rootDir, gitignorePath, newContent);\n logger(\n `${v} Added ${colorizePath('.intlayer')} to ${colorizePath(gitignorePath)}`\n );\n } else {\n logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);\n }\n }\n\n // CHECK VS CODE EXTENSION RECOMMENDATIONS\n const vscodeDir = '.vscode';\n const extensionsJsonPath = join(vscodeDir, 'extensions.json');\n const extensionId = 'intlayer.intlayer-vs-code-extension';\n\n try {\n let extensionsConfig: { recommendations: string[] } = {\n recommendations: [],\n };\n\n if (await exists(rootDir, extensionsJsonPath)) {\n const content = await readFileFromRoot(rootDir, extensionsJsonPath);\n extensionsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n if (!extensionsConfig.recommendations) {\n extensionsConfig.recommendations = [];\n }\n\n if (!extensionsConfig.recommendations.includes(extensionId)) {\n extensionsConfig.recommendations.push(extensionId);\n await writeFileToRoot(\n rootDir,\n extensionsJsonPath,\n JSON.stringify(extensionsConfig, null, 2)\n );\n logger(\n `${v} Added ${colorize(extensionId, ANSIColors.MAGENTA)} to ${colorizePath(extensionsJsonPath)}`\n );\n } else {\n logger(\n `${v} ${colorizePath(extensionsJsonPath)} already includes ${colorize(extensionId, ANSIColors.MAGENTA)}`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(extensionsJsonPath)}. You may need to add ${colorize(extensionId, ANSIColors.MAGENTA)} manually.`,\n { level: 'warn' }\n );\n }\n\n // CHECK TSCONFIGS\n const tsConfigFiles = await findTsConfigFiles(rootDir);\n let hasTsConfig = false;\n\n for (const fileName of tsConfigFiles) {\n if (await exists(rootDir, fileName)) {\n hasTsConfig = true;\n try {\n const fileContent = await readFileFromRoot(rootDir, fileName);\n const config = parseJSONWithComments(fileContent);\n const typeDefinition = '.intlayer/**/*.ts';\n\n let updated = false;\n\n if (!config.include) {\n // Skip if no include array (solution-style)\n } else if (\n Array.isArray(config.include) &&\n !(config.include as string[]).some((pattern: string) =>\n pattern.includes('.intlayer')\n )\n ) {\n config.include.push(typeDefinition);\n updated = true;\n } else if (config.include.includes(typeDefinition)) {\n logger(\n `${v} ${colorizePath(fileName)} already includes intlayer types`\n );\n }\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n fileName,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(fileName)} to include intlayer types`\n );\n }\n } catch {\n logger(\n `${x} Could not parse or update ${colorizePath(fileName)}. You may need to add ${colorizePath('.intlayer/types/**/*.ts')} manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // INITIALIZE CONFIG FILE\n const format = hasTsConfig ? 'intlayer.config.ts' : 'intlayer.config.mjs';\n await initConfig(format, rootDir);\n\n let hasAliasConfiguration = false;\n\n // CHECK VITE CONFIG\n const viteConfigs = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n\n for (const file of viteConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('vite-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateViteConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(`${v} Updated ${colorizePath(file)} to include Intlayer plugin`);\n }\n break;\n }\n }\n\n // CHECK NEXT CONFIG\n const nextConfigs = ['next.config.js', 'next.config.mjs', 'next.config.ts'];\n let isNextJsProject = false;\n\n for (const file of nextConfigs) {\n if (await exists(rootDir, file)) {\n isNextJsProject = true;\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('next-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateNextConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(`${v} Updated ${colorizePath(file)} to include Intlayer plugin`);\n }\n break;\n }\n }\n\n // CHECK OTHER FRAMEWORKS CONFIG\n const astroConfigs = [\n 'astro.config.mjs',\n 'astro.config.js',\n 'astro.config.ts',\n 'astro.config.cjs',\n ];\n\n for (const file of astroConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n if (file.startsWith('astro.config.')) {\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('astro-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateAstroConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer integration`\n );\n }\n }\n break;\n }\n }\n\n const nuxtConfigs = ['nuxt.config.js', 'nuxt.config.ts'];\n for (const file of nuxtConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('nuxt-intlayer')) {\n const updatedContent = updateNuxtConfig(content);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(`${v} Updated ${colorizePath(file)} to include Intlayer module`);\n }\n break;\n }\n }\n\n // UPDATE PACKAGE.JSON DEV SCRIPT\n // Next.js >= 16 uses a bun-specific wrapper; backend frameworks wrap whatever\n // the existing dev script is. Both use `intlayer watch --with`.\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const isVersionGreaterOrEqual = (\n versionString: string,\n major: number\n ): boolean => {\n if (!versionString || typeof versionString !== 'string') return false;\n const match = versionString.match(/^[^\\d]*(\\d+)/);\n if (!match) return false;\n return parseInt(match[1], 10) >= major;\n };\n\n const backendIntlayerPackages = [\n 'express-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n 'hono-intlayer',\n ];\n\n const devScript = packageJson.scripts?.dev;\n\n let newDevScript: string | undefined;\n\n if (\n ((isNextJsProject && isVersionGreaterOrEqual(allDeps.next, 16)) ||\n backendIntlayerPackages.some((pkg) => allDeps[pkg])) &&\n !devScript.includes('intlayer watch')\n ) {\n newDevScript = `intlayer watch --with '${devScript}'`;\n }\n\n if (newDevScript) {\n packageJson.scripts.dev = newDevScript;\n\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n JSON.stringify(packageJson, null, 2)\n );\n\n logger(\n `${v} Updated ${colorizePath('package.json')} dev script to run intlayer watch`\n );\n }\n\n // CHECK WEBPACK CONFIG\n const webpackConfigs = [\n 'webpack.config.js',\n 'webpack.config.ts',\n 'webpack.config.mjs',\n 'webpack.config.cjs',\n ];\n\n for (const file of webpackConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n logger(\n `${v} Found ${colorizePath(\n file\n )}. Make sure to configure aliases manually or use the Intlayer Webpack plugin.`\n );\n break;\n }\n }\n\n const backendConfigPackages = [\n 'express',\n 'fastify',\n '@adonisjs/core',\n 'hono',\n ...backendIntlayerPackages,\n ];\n\n if (backendConfigPackages.some((pkg) => allDeps[pkg])) {\n hasAliasConfiguration = true;\n }\n\n if (!hasAliasConfiguration) {\n const configuration = getConfiguration({ baseDir: rootDir });\n const aliases = getAlias({ configuration });\n\n if (hasTsConfig && tsConfigFiles.length > 0) {\n const tsConfigPath =\n tsConfigFiles.find((file) => file === 'tsconfig.json') ||\n tsConfigFiles[0];\n const tsConfigContent = await readFileFromRoot(rootDir, tsConfigPath);\n const config = parseJSONWithComments(tsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n tsConfigPath,\n JSON.stringify(config, null, 2)\n );\n\n logger(\n `${v} Updated ${colorizePath(\n tsConfigPath\n )} to include Intlayer aliases`\n );\n }\n } else {\n const jsConfigPath = 'jsconfig.json';\n\n if (await exists(rootDir, jsConfigPath)) {\n const jsConfigContent = await readFileFromRoot(rootDir, jsConfigPath);\n const config = parseJSONWithComments(jsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n jsConfigPath,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n jsConfigPath\n )} to include Intlayer aliases`\n );\n }\n } else {\n packageJson.imports ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n const importAlias = alias.replace('@', '#');\n const importPath = path.startsWith('.') ? path : `./${path}`;\n\n if (!packageJson.imports[importAlias]) {\n packageJson.imports[importAlias] = importPath;\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n JSON.stringify(packageJson, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n packageJsonPath\n )} to include Intlayer imports`\n );\n }\n }\n }\n }\n\n // FINAL SUCCESS MESSAGE\n logger(`${v} ${colorize('Intlayer init setup complete.', ANSIColors.GREEN)}`);\n logger([\n colorize('Next →', ANSIColors.MAGENTA),\n colorize(\n `Follow the instructions in the documentation to complete the setup:`,\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(guideUrl),\n ]);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/init/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\n\nimport { getAlias } from '@intlayer/config/utils';\nimport { initConfig } from '../initConfig';\nimport {\n ensureDirectory,\n exists,\n findTsConfigFiles,\n parseJSONWithComments,\n readFileFromRoot,\n updateAstroConfig,\n updateNextConfig,\n updateNuxtConfig,\n updateViteConfig,\n writeFileToRoot,\n} from './utils';\n\n/**\n * Documentation URL Constants\n */\nconst DocumentationRouter = {\n NextJS: 'https://intlayer.org/doc/environment/nextjs.md',\n NextJS_15: 'https://intlayer.org/doc/environment/nextjs/15.md',\n NextJS_14: 'https://intlayer.org/doc/environment/nextjs/14.md',\n CRA: 'https://intlayer.org/doc/environment/create-react-app.md',\n Astro: 'https://intlayer.org/doc/environment/astro.md',\n ViteAndReact: 'https://intlayer.org/doc/environment/vite-and-react.md',\n ViteAndReact_ReactRouterV7:\n 'https://intlayer.org/doc/environment/vite-and-react/react-router-v7.md',\n ViteAndReact_ReactRouterV7_FSRoutes:\n 'https://intlayer.org/doc/environment/vite-and-react/react-router-v7-fs-routes.md',\n ViteAndVue: 'https://intlayer.org/doc/environment/vite-and-vue.md',\n ViteAndSolid: 'https://intlayer.org/doc/environment/vite-and-solid.md',\n ViteAndSvelte: 'https://intlayer.org/doc/environment/vite-and-svelte.md',\n ViteAndPreact: 'https://intlayer.org/doc/environment/vite-and-preact.md',\n TanStackRouter: 'https://intlayer.org/doc/environment/tanstack.md',\n NuxtAndVue: 'https://intlayer.org/doc/environment/nuxt-and-vue.md',\n Angular: 'https://intlayer.org/doc/environment/angular.md',\n SvelteKit: 'https://intlayer.org/doc/environment/sveltekit.md',\n ReactNativeAndExpo:\n 'https://intlayer.org/doc/environment/react-native-and-expo.md',\n Lynx: 'https://intlayer.org/doc/environment/lynx-and-react.md',\n Express: 'https://intlayer.org/doc/environment/express.md',\n NestJS: 'https://intlayer.org/doc/environment/nestjs.md',\n Fastify: 'https://intlayer.org/doc/environment/fastify.md',\n Default: 'https://intlayer.org/doc/get-started',\n\n // Intlayer Language Server (Go-to-Definition from getter keys to .content files)\n LSP: 'https://intlayer.org/doc/lsp.md',\n\n // Check for competitors libs\n NextIntl: 'https://intlayer.org/blog/intlayer-with-next-intl.md',\n ReactI18Next: 'https://intlayer.org/blog/intlayer-with-react-i18next.md',\n ReactIntl: 'https://intlayer.org/blog/intlayer-with-react-intl.md',\n NextI18Next: 'https://intlayer.org/blog/intlayer-with-next-i18next.md',\n VueI18n: 'https://intlayer.org/blog/intlayer-with-vue-i18n.md',\n};\n\n/**\n * Helper: Detects the environment and returns the doc URL\n */\nconst getDocumentationUrl = (packageJson: any): string => {\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n /**\n * Helper to check if a version string matches a specific major version\n * Matches: \"15\", \"^15.0.0\", \"~15.2\", \"15.0.0-beta\"\n */\n const isVersion = (versionString: string, major: number): boolean => {\n if (!versionString || typeof versionString !== 'string') return false;\n const regex = new RegExp(`^[\\\\^~]?${major}(?:\\\\.|$)`);\n return regex.test(versionString);\n };\n\n // Mobile / Cross-platform\n if (deps['@lynx-js/react'] || deps['@lynx-js/core']) {\n return DocumentationRouter.Lynx;\n }\n if (deps['react-native'] || deps.expo) {\n return DocumentationRouter.ReactNativeAndExpo;\n }\n\n // Meta-frameworks (Next, Nuxt, Astro, SvelteKit)\n if (deps.next) {\n const version = deps.next;\n\n if (isVersion(version, 14)) {\n return DocumentationRouter.NextJS_14;\n }\n\n if (isVersion(version, 15)) {\n return DocumentationRouter.NextJS_15;\n }\n\n return DocumentationRouter.NextJS;\n }\n\n if (deps.nuxt) return DocumentationRouter.NuxtAndVue;\n if (deps.astro) return DocumentationRouter.Astro;\n if (deps['@sveltejs/kit']) return DocumentationRouter.SvelteKit;\n\n // Routers (TanStack & React Router v7)\n if (deps['@tanstack/react-router']) {\n return DocumentationRouter.TanStackRouter;\n }\n\n // Check for React Router v7\n const reactRouterVersion = deps['react-router'];\n if (reactRouterVersion && typeof reactRouterVersion === 'string') {\n // Distinguish between standard v7 and v7 with FS routes\n if (deps['@react-router/fs-routes']) {\n return DocumentationRouter.ViteAndReact_ReactRouterV7_FSRoutes;\n }\n\n // Use Regex to ensure it is v7\n if (isVersion(reactRouterVersion, 7)) {\n return DocumentationRouter.ViteAndReact_ReactRouterV7;\n }\n }\n\n // Vite Ecosystem (General)\n if (deps.vite) {\n if (deps.vue) return DocumentationRouter.ViteAndVue;\n if (deps['solid-js']) return DocumentationRouter.ViteAndSolid;\n if (deps.svelte) return DocumentationRouter.ViteAndSvelte;\n if (deps.preact) return DocumentationRouter.ViteAndPreact;\n\n // Default to React if Vite is present but specific other frameworks aren't found\n return DocumentationRouter.ViteAndReact;\n }\n\n // Other Web Frameworks\n if (deps['react-scripts']) return DocumentationRouter.CRA;\n if (deps['@angular/core']) return DocumentationRouter.Angular;\n\n // Backend\n if (deps['@nestjs/core']) return DocumentationRouter.NestJS;\n if (deps.express) return DocumentationRouter.Express;\n if (deps.fastify) return DocumentationRouter.Fastify;\n\n // Competitor Libs (Migration Guides)\n // We check these last as specific environment setup is usually higher priority,\n // but if no specific framework logic matched (or as a fallback), we guide to migration.\n if (deps['next-intl']) return DocumentationRouter.NextIntl;\n if (deps['react-i18next'] || deps.i18next)\n return DocumentationRouter.ReactI18Next;\n if (deps['react-intl']) return DocumentationRouter.ReactIntl;\n if (deps['next-i18next']) return DocumentationRouter.NextI18Next;\n if (deps['vue-i18n']) return DocumentationRouter.VueI18n;\n\n return DocumentationRouter.Default;\n};\n\n/**\n * OPTIONS\n */\nexport type InitOptions = {\n noGitignore?: boolean;\n};\n\n/**\n * MAIN LOGIC\n */\nexport const initIntlayer = async (rootDir: string, options?: InitOptions) => {\n logger(colorize('Checking Intlayer configuration...', ANSIColors.CYAN));\n\n // READ PACKAGE.JSON\n const packageJsonPath = 'package.json';\n if (!(await exists(rootDir, packageJsonPath))) {\n logger(\n `${x} No ${colorizePath('package.json')} found. Please run this script from the project root.`,\n { level: 'error' }\n );\n process.exit(1);\n }\n\n const packageJsonContent = await readFileFromRoot(rootDir, packageJsonPath);\n let packageJson: Record<string, any>;\n try {\n packageJson = JSON.parse(packageJsonContent);\n } catch {\n logger(`${x} Could not parse ${colorizePath('package.json')}.`, {\n level: 'error',\n });\n process.exit(1);\n }\n\n // Determine the correct documentation URL based on dependencies\n const guideUrl = getDocumentationUrl(packageJson);\n\n // CHECK .GITIGNORE\n const gitignorePath = '.gitignore';\n if (!options?.noGitignore && (await exists(rootDir, gitignorePath))) {\n const gitignoreContent = await readFileFromRoot(rootDir, gitignorePath);\n\n if (!gitignoreContent.includes('intlayer')) {\n const newContent = `${gitignoreContent}\\n# Intlayer\\n.intlayer\\n`;\n await writeFileToRoot(rootDir, gitignorePath, newContent);\n logger(\n `${v} Added ${colorizePath('.intlayer')} to ${colorizePath(gitignorePath)}`\n );\n } else {\n logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);\n }\n }\n\n // CHECK VS CODE EXTENSION RECOMMENDATIONS\n const vscodeDir = '.vscode';\n const extensionsJsonPath = join(vscodeDir, 'extensions.json');\n const extensionId = 'intlayer.intlayer-vs-code-extension';\n\n try {\n let extensionsConfig: { recommendations: string[] } = {\n recommendations: [],\n };\n\n if (await exists(rootDir, extensionsJsonPath)) {\n const content = await readFileFromRoot(rootDir, extensionsJsonPath);\n extensionsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n if (!extensionsConfig.recommendations) {\n extensionsConfig.recommendations = [];\n }\n\n if (!extensionsConfig.recommendations.includes(extensionId)) {\n extensionsConfig.recommendations.push(extensionId);\n await writeFileToRoot(\n rootDir,\n extensionsJsonPath,\n JSON.stringify(extensionsConfig, null, 2)\n );\n logger(\n `${v} Added ${colorize(extensionId, ANSIColors.MAGENTA)} to ${colorizePath(extensionsJsonPath)}`\n );\n } else {\n logger(\n `${v} ${colorizePath(extensionsJsonPath)} already includes ${colorize(extensionId, ANSIColors.MAGENTA)}`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(extensionsJsonPath)}. You may need to add ${colorize(extensionId, ANSIColors.MAGENTA)} manually.`,\n { level: 'warn' }\n );\n }\n\n // CHECK VS CODE LSP SETTINGS\n const settingsJsonPath = join(vscodeDir, 'settings.json');\n\n try {\n let settingsConfig: Record<string, unknown> = {};\n\n if (await exists(rootDir, settingsJsonPath)) {\n const content = await readFileFromRoot(rootDir, settingsJsonPath);\n settingsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n let settingsUpdated = false;\n\n if (!settingsConfig['intlayer.languageServer.command']) {\n settingsConfig['intlayer.languageServer.command'] = 'npx';\n settingsUpdated = true;\n }\n\n if (!settingsConfig['intlayer.languageServer.args']) {\n settingsConfig['intlayer.languageServer.args'] = ['@intlayer/lsp'];\n settingsUpdated = true;\n }\n\n if (settingsUpdated) {\n await writeFileToRoot(\n rootDir,\n settingsJsonPath,\n JSON.stringify(settingsConfig, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(settingsJsonPath)} with LSP configuration`\n );\n } else {\n logger(\n `${v} ${colorizePath(settingsJsonPath)} already includes LSP configuration`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(settingsJsonPath)}. You may need to add the LSP settings manually.`,\n { level: 'warn' }\n );\n }\n\n // CHECK TSCONFIGS\n const tsConfigFiles = await findTsConfigFiles(rootDir);\n let hasTsConfig = false;\n\n for (const fileName of tsConfigFiles) {\n if (await exists(rootDir, fileName)) {\n hasTsConfig = true;\n try {\n const fileContent = await readFileFromRoot(rootDir, fileName);\n const config = parseJSONWithComments(fileContent);\n const typeDefinition = '.intlayer/**/*.ts';\n\n let updated = false;\n\n if (!config.include) {\n // Skip if no include array (solution-style)\n } else if (\n Array.isArray(config.include) &&\n !(config.include as string[]).some((pattern: string) =>\n pattern.includes('.intlayer')\n )\n ) {\n config.include.push(typeDefinition);\n updated = true;\n } else if (config.include.includes(typeDefinition)) {\n logger(\n `${v} ${colorizePath(fileName)} already includes intlayer types`\n );\n }\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n fileName,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(fileName)} to include intlayer types`\n );\n }\n } catch {\n logger(\n `${x} Could not parse or update ${colorizePath(fileName)}. You may need to add ${colorizePath('.intlayer/types/**/*.ts')} manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // INITIALIZE CONFIG FILE\n const format = hasTsConfig ? 'intlayer.config.ts' : 'intlayer.config.mjs';\n await initConfig(format, rootDir);\n\n let hasAliasConfiguration = false;\n\n // CHECK VITE CONFIG\n const viteConfigs = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n\n for (const file of viteConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('vite-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateViteConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(`${v} Updated ${colorizePath(file)} to include Intlayer plugin`);\n }\n break;\n }\n }\n\n // CHECK NEXT CONFIG\n const nextConfigs = ['next.config.js', 'next.config.mjs', 'next.config.ts'];\n let isNextJsProject = false;\n\n for (const file of nextConfigs) {\n if (await exists(rootDir, file)) {\n isNextJsProject = true;\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('next-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateNextConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(`${v} Updated ${colorizePath(file)} to include Intlayer plugin`);\n }\n break;\n }\n }\n\n // CHECK OTHER FRAMEWORKS CONFIG\n const astroConfigs = [\n 'astro.config.mjs',\n 'astro.config.js',\n 'astro.config.ts',\n 'astro.config.cjs',\n ];\n\n for (const file of astroConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n if (file.startsWith('astro.config.')) {\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('astro-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateAstroConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer integration`\n );\n }\n }\n break;\n }\n }\n\n const nuxtConfigs = ['nuxt.config.js', 'nuxt.config.ts'];\n for (const file of nuxtConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('nuxt-intlayer')) {\n const updatedContent = updateNuxtConfig(content);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(`${v} Updated ${colorizePath(file)} to include Intlayer module`);\n }\n break;\n }\n }\n\n // UPDATE PACKAGE.JSON DEV SCRIPT\n // Next.js >= 16 uses a bun-specific wrapper; backend frameworks wrap whatever\n // the existing dev script is. Both use `intlayer watch --with`.\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const isVersionGreaterOrEqual = (\n versionString: string,\n major: number\n ): boolean => {\n if (!versionString || typeof versionString !== 'string') return false;\n const match = versionString.match(/^[^\\d]*(\\d+)/);\n if (!match) return false;\n return parseInt(match[1], 10) >= major;\n };\n\n const backendIntlayerPackages = [\n 'express-intlayer',\n 'fastify-intlayer',\n 'adonis-intlayer',\n 'hono-intlayer',\n ];\n\n const devScript = packageJson.scripts?.dev;\n\n let newDevScript: string | undefined;\n\n if (\n ((isNextJsProject && isVersionGreaterOrEqual(allDeps.next, 16)) ||\n backendIntlayerPackages.some((pkg) => allDeps[pkg])) &&\n !devScript.includes('intlayer watch')\n ) {\n newDevScript = `intlayer watch --with '${devScript}'`;\n }\n\n if (newDevScript) {\n packageJson.scripts.dev = newDevScript;\n\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n JSON.stringify(packageJson, null, 2)\n );\n\n logger(\n `${v} Updated ${colorizePath('package.json')} dev script to run intlayer watch`\n );\n }\n\n // CHECK WEBPACK CONFIG\n const webpackConfigs = [\n 'webpack.config.js',\n 'webpack.config.ts',\n 'webpack.config.mjs',\n 'webpack.config.cjs',\n ];\n\n for (const file of webpackConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n logger(\n `${v} Found ${colorizePath(\n file\n )}. Make sure to configure aliases manually or use the Intlayer Webpack plugin.`\n );\n break;\n }\n }\n\n const backendConfigPackages = [\n 'express',\n 'fastify',\n '@adonisjs/core',\n 'hono',\n ...backendIntlayerPackages,\n ];\n\n if (backendConfigPackages.some((pkg) => allDeps[pkg])) {\n hasAliasConfiguration = true;\n }\n\n if (!hasAliasConfiguration) {\n const configuration = getConfiguration({ baseDir: rootDir });\n const aliases = getAlias({ configuration });\n\n if (hasTsConfig && tsConfigFiles.length > 0) {\n const tsConfigPath =\n tsConfigFiles.find((file) => file === 'tsconfig.json') ||\n tsConfigFiles[0];\n const tsConfigContent = await readFileFromRoot(rootDir, tsConfigPath);\n const config = parseJSONWithComments(tsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n tsConfigPath,\n JSON.stringify(config, null, 2)\n );\n\n logger(\n `${v} Updated ${colorizePath(\n tsConfigPath\n )} to include Intlayer aliases`\n );\n }\n } else {\n const jsConfigPath = 'jsconfig.json';\n\n if (await exists(rootDir, jsConfigPath)) {\n const jsConfigContent = await readFileFromRoot(rootDir, jsConfigPath);\n const config = parseJSONWithComments(jsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n jsConfigPath,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n jsConfigPath\n )} to include Intlayer aliases`\n );\n }\n } else {\n packageJson.imports ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n const importAlias = alias.replace('@', '#');\n const importPath = path.startsWith('.') ? path : `./${path}`;\n\n if (!packageJson.imports[importAlias]) {\n packageJson.imports[importAlias] = importPath;\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n JSON.stringify(packageJson, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n packageJsonPath\n )} to include Intlayer imports`\n );\n }\n }\n }\n }\n\n // FINAL SUCCESS MESSAGE\n logger(`${v} ${colorize('Intlayer init setup complete.', ANSIColors.GREEN)}`);\n logger([\n colorize('Next →', ANSIColors.MAGENTA),\n colorize(\n `Follow the instructions in the documentation to complete the setup:`,\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(guideUrl),\n ]);\n\n // INTLAYER LSP — instruction for the AI agent running `intlayer init`.\n // The Intlayer Language Server (`@intlayer/lsp`) provides Go-to-Definition\n // from `useIntlayer` / `getIntlayer` keys to their `.content` files, for both\n // IDEs and AI agents. Setup is editor-specific (VS Code, Cursor, Windsurf,\n // Zed, Neovim, Claude Code, …), so we don't scaffold anything here — instead\n // we point to the doc and ask the agent to confirm the target platform.\n logger([\n colorize('Intlayer LSP →', ANSIColors.MAGENTA),\n colorize(\n 'The Intlayer Language Server is available via the `@intlayer/lsp` package. It lets IDEs and AI agents jump from `useIntlayer`/`getIntlayer` keys to their `.content` files.',\n ANSIColors.GREY_LIGHT\n ),\n colorize(\n 'Ask the user which platform/editor they want to enable it on (VS Code, Cursor, Windsurf, Zed, Neovim, Claude Code, …), then follow the matching setup instructions:',\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(DocumentationRouter.LSP),\n ]);\n};\n"],"mappings":"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"}
|