@inlang/paraglide-js 2.26.0 → 2.28.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/README.md +11 -1
- package/dist/bundler-plugins/per-locale-build/index.js +14 -7
- package/dist/bundler-plugins/per-locale-build/index.js.map +1 -1
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +237 -4
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
- package/dist/bundler-plugins/unplugin.d.ts +1 -1
- package/dist/bundler-plugins/unplugin.js +79 -10
- package/dist/bundler-plugins/unplugin.js.map +1 -1
- package/dist/bundler-plugins/unplugin.test.js +334 -1
- package/dist/bundler-plugins/unplugin.test.js.map +1 -1
- package/dist/bundler-plugins/vite.js +2 -1
- package/dist/bundler-plugins/vite.js.map +1 -1
- package/dist/bundler-plugins/vite.test.js +1 -1
- package/dist/bundler-plugins/vite.test.js.map +1 -1
- package/dist/cli/commands/compile/command.js +13 -0
- package/dist/cli/commands/compile/command.js.map +1 -1
- package/dist/cli/commands/compile/command.test.js +87 -3
- package/dist/cli/commands/compile/command.test.js.map +1 -1
- package/dist/cli/commands/init/command.d.ts +5 -0
- package/dist/cli/commands/init/command.js +216 -44
- package/dist/cli/commands/init/command.js.map +1 -1
- package/dist/cli/commands/init/command.test.d.ts +1 -0
- package/dist/cli/commands/init/command.test.js +123 -0
- package/dist/cli/commands/init/command.test.js.map +1 -0
- package/dist/cli/defaults.js +2 -2
- package/dist/cli/defaults.js.map +1 -1
- package/dist/cli/init-options.d.ts +11 -0
- package/dist/cli/init-options.js +2 -0
- package/dist/cli/init-options.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.d.ts +19 -0
- package/dist/cli/steps/add-inlang-check.js +60 -0
- package/dist/cli/steps/add-inlang-check.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
- package/dist/cli/steps/add-inlang-check.test.js +88 -0
- package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
- package/dist/cli/steps/add-message-lint.d.ts +34 -0
- package/dist/cli/steps/add-message-lint.js +105 -0
- package/dist/cli/steps/add-message-lint.js.map +1 -0
- package/dist/cli/steps/add-message-lint.test.d.ts +1 -0
- package/dist/cli/steps/add-message-lint.test.js +74 -0
- package/dist/cli/steps/add-message-lint.test.js.map +1 -0
- package/dist/cli/steps/add-vite-plugin.d.ts +18 -0
- package/dist/cli/steps/add-vite-plugin.js +34 -6
- package/dist/cli/steps/add-vite-plugin.js.map +1 -1
- package/dist/cli/steps/add-vite-plugin.test.js +25 -9
- package/dist/cli/steps/add-vite-plugin.test.js.map +1 -1
- package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
- package/dist/cli/steps/agents-md-suggestion.js +19 -0
- package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
- package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
- package/dist/cli/steps/check-for-uncomitted-changes.d.ts +3 -0
- package/dist/cli/steps/check-for-uncomitted-changes.js +15 -3
- package/dist/cli/steps/check-for-uncomitted-changes.js.map +1 -1
- package/dist/cli/steps/detect-bundler.d.ts +1 -0
- package/dist/cli/steps/detect-bundler.js +7 -1
- package/dist/cli/steps/detect-bundler.js.map +1 -1
- package/dist/cli/steps/initialize-inlang-project.d.ts +4 -3
- package/dist/cli/steps/initialize-inlang-project.js +60 -157
- package/dist/cli/steps/initialize-inlang-project.js.map +1 -1
- package/dist/cli/steps/maybe-add-machine-translation.d.ts +4 -0
- package/dist/cli/steps/maybe-add-machine-translation.js +14 -8
- package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.d.ts +2 -0
- package/dist/cli/steps/maybe-add-sherlock.js +13 -7
- package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.test.d.ts +1 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js +44 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js.map +1 -0
- package/dist/cli/steps/prompt-for-outdir.d.ts +2 -0
- package/dist/cli/steps/prompt-for-outdir.js +4 -0
- package/dist/cli/steps/prompt-for-outdir.js.map +1 -1
- package/dist/cli/steps/update-package-json.js +8 -13
- package/dist/cli/steps/update-package-json.js.map +1 -1
- package/dist/cli/steps/update-ts-config.d.ts +6 -0
- package/dist/cli/steps/update-ts-config.js +27 -4
- package/dist/cli/steps/update-ts-config.js.map +1 -1
- package/dist/cli/utils.d.ts +11 -0
- package/dist/cli/utils.js +21 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/utils.test.d.ts +1 -0
- package/dist/cli/utils.test.js +16 -0
- package/dist/cli/utils.test.js.map +1 -0
- package/dist/compiler/compile-annotation.d.ts +48 -1
- package/dist/compiler/compile-annotation.js +243 -10
- package/dist/compiler/compile-annotation.js.map +1 -1
- package/dist/compiler/compile-bundle.d.ts +7 -2
- package/dist/compiler/compile-bundle.js +97 -3
- package/dist/compiler/compile-bundle.js.map +1 -1
- package/dist/compiler/compile-bundle.test.js +232 -19
- package/dist/compiler/compile-bundle.test.js.map +1 -1
- package/dist/compiler/compile-lifecycle.test.d.ts +1 -0
- package/dist/compiler/compile-lifecycle.test.js +69 -0
- package/dist/compiler/compile-lifecycle.test.js.map +1 -0
- package/dist/compiler/compile-local-variable.d.ts +3 -0
- package/dist/compiler/compile-local-variable.js +5 -2
- package/dist/compiler/compile-local-variable.js.map +1 -1
- package/dist/compiler/compile-local-variable.test.js +55 -15
- package/dist/compiler/compile-local-variable.test.js.map +1 -1
- package/dist/compiler/compile-message.d.ts +29 -1
- package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
- package/dist/compiler/compile-message.exact-number.test.js +786 -0
- package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
- package/dist/compiler/compile-message.js +162 -66
- package/dist/compiler/compile-message.js.map +1 -1
- package/dist/compiler/compile-message.locals.test.d.ts +1 -0
- package/dist/compiler/compile-message.locals.test.js +498 -0
- package/dist/compiler/compile-message.locals.test.js.map +1 -0
- package/dist/compiler/compile-message.test.js +113 -22
- package/dist/compiler/compile-message.test.js.map +1 -1
- package/dist/compiler/compile-pattern.d.ts +5 -0
- package/dist/compiler/compile-pattern.js +6 -18
- package/dist/compiler/compile-pattern.js.map +1 -1
- package/dist/compiler/compile-pattern.test.js +169 -5
- package/dist/compiler/compile-pattern.test.js.map +1 -1
- package/dist/compiler/compile-project.js +5 -1
- package/dist/compiler/compile-project.js.map +1 -1
- package/dist/compiler/compile-project.test.js +1260 -185
- package/dist/compiler/compile-project.test.js.map +1 -1
- package/dist/compiler/compile.js +36 -17
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/compile.test.js +71 -1
- package/dist/compiler/compile.test.js.map +1 -1
- package/dist/compiler/compiler-options.d.ts +41 -0
- package/dist/compiler/compiler-options.js.map +1 -1
- package/dist/compiler/create-readme.d.ts +4 -1
- package/dist/compiler/create-readme.js +33 -125
- package/dist/compiler/create-readme.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
- package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.test.js +4 -4
- package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/index.js +1 -1
- package/dist/compiler/index.js.map +1 -1
- package/dist/compiler/input-alias.d.ts +21 -0
- package/dist/compiler/input-alias.js +42 -0
- package/dist/compiler/input-alias.js.map +1 -0
- package/dist/compiler/input-alias.test.d.ts +1 -0
- package/dist/compiler/input-alias.test.js +58 -0
- package/dist/compiler/input-alias.test.js.map +1 -0
- package/dist/compiler/message-locals.d.ts +46 -0
- package/dist/compiler/message-locals.js +129 -0
- package/dist/compiler/message-locals.js.map +1 -0
- package/dist/compiler/output-structure/locale-modules.js +7 -1
- package/dist/compiler/output-structure/locale-modules.js.map +1 -1
- package/dist/compiler/output-structure/locale-modules.test.js +35 -0
- package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +6 -4
- package/dist/compiler/output-structure/message-modules.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.test.js +35 -0
- package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
- package/dist/compiler/registry.d.ts +12 -0
- package/dist/compiler/registry.js +158 -31
- package/dist/compiler/registry.js.map +1 -1
- package/dist/compiler/registry.test.d.ts +1 -0
- package/dist/compiler/registry.test.js +291 -0
- package/dist/compiler/registry.test.js.map +1 -0
- package/dist/compiler/runtime/create-runtime.d.ts +2 -0
- package/dist/compiler/runtime/create-runtime.js +9 -0
- package/dist/compiler/runtime/create-runtime.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js +8 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js +26 -0
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.js +47 -5
- package/dist/compiler/runtime/extract-locale-from-header.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.test.js +58 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.js.map +1 -1
- package/dist/compiler/runtime/get-locale.js +7 -1
- package/dist/compiler/runtime/get-locale.js.map +1 -1
- package/dist/compiler/runtime/get-locale.test.js +95 -0
- package/dist/compiler/runtime/get-locale.test.js.map +1 -1
- package/dist/compiler/runtime/localize-href.d.ts +8 -0
- package/dist/compiler/runtime/localize-href.js +60 -0
- package/dist/compiler/runtime/localize-href.js.map +1 -1
- package/dist/compiler/runtime/localize-href.test.js +227 -1
- package/dist/compiler/runtime/localize-href.test.js.map +1 -1
- package/dist/compiler/runtime/set-locale.js +24 -6
- package/dist/compiler/runtime/set-locale.js.map +1 -1
- package/dist/compiler/runtime/set-locale.test.js +182 -0
- package/dist/compiler/runtime/set-locale.test.js.map +1 -1
- package/dist/compiler/runtime/type.d.ts +2 -0
- package/dist/compiler/runtime/type.js.map +1 -1
- package/dist/compiler/runtime/type.test.js +34 -0
- package/dist/compiler/runtime/type.test.js.map +1 -1
- package/dist/compiler/runtime/variables.d.ts +2 -0
- package/dist/compiler/runtime/variables.js +7 -0
- package/dist/compiler/runtime/variables.js.map +1 -1
- package/dist/compiler/server/create-server-file.js +24 -0
- package/dist/compiler/server/create-server-file.js.map +1 -1
- package/dist/compiler/server/create-server-file.test.js +8 -2
- package/dist/compiler/server/create-server-file.test.js.map +1 -1
- package/dist/compiler/server/middleware.d.ts +8 -2
- package/dist/compiler/server/middleware.js +204 -11
- package/dist/compiler/server/middleware.js.map +1 -1
- package/dist/compiler/server/middleware.test.js +750 -3
- package/dist/compiler/server/middleware.test.js.map +1 -1
- package/dist/eslint/index.d.ts +4 -0
- package/dist/eslint/index.js +8 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.d.ts +3 -0
- package/dist/eslint/no-dynamic-message-access.js +150 -0
- package/dist/eslint/no-dynamic-message-access.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.test.d.ts +1 -0
- package/dist/eslint/no-dynamic-message-access.test.js +126 -0
- package/dist/eslint/no-dynamic-message-access.test.js.map +1 -0
- package/dist/eslint/oxlint.test.d.ts +1 -0
- package/dist/eslint/oxlint.test.js +64 -0
- package/dist/eslint/oxlint.test.js.map +1 -0
- package/dist/services/config/config-schema.d.ts +2 -0
- package/dist/services/config/config-schema.js +2 -0
- package/dist/services/config/config-schema.js.map +1 -1
- package/dist/services/config/load-paraglide-config.test.js +12 -0
- package/dist/services/config/load-paraglide-config.test.js.map +1 -1
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/env-variables/index.js.map +1 -1
- package/dist/services/file-handling/write-output.bench.js +51 -11
- package/dist/services/file-handling/write-output.bench.js.map +1 -1
- package/dist/services/file-handling/write-output.js +60 -20
- package/dist/services/file-handling/write-output.js.map +1 -1
- package/dist/services/file-handling/write-output.test.js +175 -0
- package/dist/services/file-handling/write-output.test.js.map +1 -1
- package/package.json +15 -5
|
@@ -35,7 +35,7 @@ afterEach(async () => {
|
|
|
35
35
|
async function createProjectFixture(options = {}) {
|
|
36
36
|
const { mkdtemp, mkdir, writeFile } = await import("node:fs/promises");
|
|
37
37
|
const { tmpdir } = await import("node:os");
|
|
38
|
-
const workspace = await mkdtemp(path.join(tmpdir(), "paraglide-plugin-"));
|
|
38
|
+
const workspace = realFs.realpathSync(await mkdtemp(path.join(tmpdir(), "paraglide-plugin-")));
|
|
39
39
|
testDirectories.push(workspace);
|
|
40
40
|
const projectDir = path.join(workspace, "project.inlang");
|
|
41
41
|
await mkdir(projectDir, { recursive: true });
|
|
@@ -67,6 +67,337 @@ function setViteRoot(plugin, root) {
|
|
|
67
67
|
configResolved?.handler?.({ root });
|
|
68
68
|
}
|
|
69
69
|
const mockContext = { addWatchFile: () => { } };
|
|
70
|
+
function configureViteServer(plugin) {
|
|
71
|
+
const ws = {
|
|
72
|
+
send: vi.fn(),
|
|
73
|
+
clients: new Set([{}]),
|
|
74
|
+
on: vi.fn(),
|
|
75
|
+
};
|
|
76
|
+
plugin.configureServer?.({ ws });
|
|
77
|
+
return ws;
|
|
78
|
+
}
|
|
79
|
+
async function connectViteClient(server) {
|
|
80
|
+
const url = new URL(server.resolvedUrls.local[0]);
|
|
81
|
+
url.protocol = "ws:";
|
|
82
|
+
url.searchParams.set("token", server.config.webSocketToken);
|
|
83
|
+
const socket = new WebSocket(url, "vite-hmr");
|
|
84
|
+
const messages = [];
|
|
85
|
+
socket.addEventListener("message", (event) => {
|
|
86
|
+
messages.push(JSON.parse(String(event.data)));
|
|
87
|
+
});
|
|
88
|
+
await vi.waitFor(() => {
|
|
89
|
+
expect(messages).toContainEqual({ type: "connected" });
|
|
90
|
+
});
|
|
91
|
+
// A message sent after connection callbacks provides a transport barrier.
|
|
92
|
+
server.ws.send({ type: "custom", event: "paraglide:test-barrier" });
|
|
93
|
+
await vi.waitFor(() => {
|
|
94
|
+
expect(messages).toContainEqual({
|
|
95
|
+
type: "custom",
|
|
96
|
+
event: "paraglide:test-barrier",
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
return { socket, messages };
|
|
100
|
+
}
|
|
101
|
+
async function startOverlayServer(invalidSettings = false) {
|
|
102
|
+
process.env.NODE_ENV = "development";
|
|
103
|
+
const { createServer } = await import("vite");
|
|
104
|
+
const { paraglideVitePlugin } = await import("./vite.js");
|
|
105
|
+
const fixture = await createProjectFixture();
|
|
106
|
+
const { workspace, projectDir, outdir } = fixture;
|
|
107
|
+
const file = path.join(projectDir, "settings.json");
|
|
108
|
+
const original = await realFs.promises.readFile(file, "utf8");
|
|
109
|
+
if (invalidSettings)
|
|
110
|
+
await realFs.promises.writeFile(file, "{");
|
|
111
|
+
await realFs.promises.writeFile(path.join(workspace, "index.html"), "<html><body>Translation preview</body></html>");
|
|
112
|
+
const server = await createServer({
|
|
113
|
+
root: workspace,
|
|
114
|
+
configFile: false,
|
|
115
|
+
logLevel: "silent",
|
|
116
|
+
plugins: [paraglideVitePlugin({ project: projectDir, outdir })],
|
|
117
|
+
server: { host: "127.0.0.1", port: 0, watch: null },
|
|
118
|
+
optimizeDeps: { noDiscovery: true, include: [] },
|
|
119
|
+
});
|
|
120
|
+
try {
|
|
121
|
+
await server.listen();
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
await server.close();
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
return { ...fixture, server, file, original };
|
|
128
|
+
}
|
|
129
|
+
test.each(["settings", "config"])("vite error overlay reports invalid %s at startup and clears after recovery", async (source) => {
|
|
130
|
+
process.env.NODE_ENV = "development";
|
|
131
|
+
const { projectDir, outdir } = await createProjectFixture();
|
|
132
|
+
const file = path.join(projectDir, source === "settings" ? "settings.json" : "paraglide.config.js");
|
|
133
|
+
const original = await realFs.promises.readFile(file, "utf8");
|
|
134
|
+
await realFs.promises.writeFile(file, source === "settings" ? "{" : "export default { outdir: 42 }");
|
|
135
|
+
const { paraglideVitePlugin } = await import("./vite.js");
|
|
136
|
+
const plugin = paraglideVitePlugin({ project: projectDir, outdir });
|
|
137
|
+
const { send } = configureViteServer(plugin);
|
|
138
|
+
await expect(plugin.buildStart.call(mockContext)).resolves.toBeUndefined();
|
|
139
|
+
expect(send).toHaveBeenCalledWith({
|
|
140
|
+
type: "error",
|
|
141
|
+
err: {
|
|
142
|
+
message: expect.any(String),
|
|
143
|
+
stack: expect.any(String),
|
|
144
|
+
plugin: "unplugin-paraglide-js",
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
expect(send.mock.calls[0][0].err.message.length).toBeGreaterThan(0);
|
|
148
|
+
await realFs.promises.writeFile(file, original);
|
|
149
|
+
await plugin.watchChange.call(mockContext, file);
|
|
150
|
+
expect(send).toHaveBeenLastCalledWith({ type: "full-reload" });
|
|
151
|
+
expect(await realFs.promises.readdir(outdir)).toContain("runtime.js");
|
|
152
|
+
});
|
|
153
|
+
test.each(["settings", "config"])("vite error overlay recovers from invalid %s and preserves the last output until recovery", async (source) => {
|
|
154
|
+
process.env.NODE_ENV = "development";
|
|
155
|
+
const { projectDir, outdir } = await createProjectFixture();
|
|
156
|
+
const { paraglideVitePlugin } = await import("./vite.js");
|
|
157
|
+
const writeFile = vi.spyOn(realFs.promises, "writeFile");
|
|
158
|
+
const plugin = paraglideVitePlugin({ project: projectDir, outdir });
|
|
159
|
+
const { send } = configureViteServer(plugin);
|
|
160
|
+
await plugin.buildStart.call(mockContext);
|
|
161
|
+
expect(send).not.toHaveBeenCalled();
|
|
162
|
+
const runtime = await realFs.promises.readFile(path.join(outdir, "runtime.js"), "utf8");
|
|
163
|
+
const file = path.join(projectDir, source === "settings" ? "settings.json" : "paraglide.config.js");
|
|
164
|
+
const original = await realFs.promises.readFile(file, "utf8");
|
|
165
|
+
await realFs.promises.writeFile(file, source === "settings" ? "{" : "export default { outdir: 42 }");
|
|
166
|
+
await expect(plugin.watchChange.call(mockContext, file)).resolves.toBeUndefined();
|
|
167
|
+
expect(send).toHaveBeenLastCalledWith({
|
|
168
|
+
type: "error",
|
|
169
|
+
err: expect.objectContaining({ message: expect.any(String) }),
|
|
170
|
+
});
|
|
171
|
+
expect(await realFs.promises.readFile(path.join(outdir, "runtime.js"), "utf8")).toBe(runtime);
|
|
172
|
+
await plugin.watchChange.call(mockContext, path.join(outdir, "runtime.js"));
|
|
173
|
+
expect(send).toHaveBeenCalledTimes(1);
|
|
174
|
+
await realFs.promises.writeFile(file, original);
|
|
175
|
+
writeFile.mockClear();
|
|
176
|
+
await plugin.watchChange.call(mockContext, file);
|
|
177
|
+
expect(send).toHaveBeenLastCalledWith({ type: "full-reload" });
|
|
178
|
+
const outputWrites = writeFile.mock.calls.filter(([file]) => String(file).startsWith(outdir));
|
|
179
|
+
if (source === "config") {
|
|
180
|
+
expect(outputWrites).toHaveLength(0);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
expect(outputWrites.length).toBeGreaterThan(0);
|
|
184
|
+
}
|
|
185
|
+
await plugin.watchChange.call(mockContext, file);
|
|
186
|
+
expect(send).toHaveBeenCalledTimes(2);
|
|
187
|
+
});
|
|
188
|
+
test("vite error overlay prevents generated HMR while the config remains invalid", async () => {
|
|
189
|
+
const { server, workspace, projectDir, outdir, file, original } = await startOverlayServer();
|
|
190
|
+
try {
|
|
191
|
+
const main = path.join(workspace, "main.js");
|
|
192
|
+
await realFs.promises.writeFile(main, "import './test-output/runtime.js'; import.meta.hot.accept(); import.meta.hot.accept('./test-output/runtime.js', () => {});");
|
|
193
|
+
await server.transformRequest("/main.js");
|
|
194
|
+
await server.transformRequest("/test-output/runtime.js");
|
|
195
|
+
const client = await connectViteClient(server);
|
|
196
|
+
server.watcher.emit("change", main);
|
|
197
|
+
await vi.waitFor(() => expect(client.messages.some((message) => message.type === "update")).toBe(true));
|
|
198
|
+
await server.transformRequest("/main.js");
|
|
199
|
+
const configFile = path.join(projectDir, "paraglide.config.js");
|
|
200
|
+
const config = await realFs.promises.readFile(configFile, "utf8");
|
|
201
|
+
await realFs.promises.writeFile(configFile, "export default { outdir: 42 }");
|
|
202
|
+
await server.pluginContainer.watchChange(configFile, { event: "update" });
|
|
203
|
+
await vi.waitFor(() => expect(client.messages.some((message) => message.type === "error")).toBe(true));
|
|
204
|
+
const runtimeFile = path.join(outdir, "runtime.js");
|
|
205
|
+
const outputBefore = await realFs.promises.readFile(runtimeFile, "utf8");
|
|
206
|
+
const settings = JSON.parse(original);
|
|
207
|
+
settings.locales.push("fr");
|
|
208
|
+
await realFs.promises.writeFile(file, JSON.stringify(settings));
|
|
209
|
+
await server.pluginContainer.watchChange(file, { event: "update" });
|
|
210
|
+
const outputAfter = await realFs.promises.readFile(runtimeFile, "utf8");
|
|
211
|
+
// The fixture disables file watching; deliver the event a changed output produces.
|
|
212
|
+
if (outputAfter !== outputBefore) {
|
|
213
|
+
server.watcher.emit("change", runtimeFile);
|
|
214
|
+
await vi.waitFor(() => expect(client.messages.filter((message) => message.type === "update")).toHaveLength(2));
|
|
215
|
+
}
|
|
216
|
+
server.ws.send({ type: "custom", event: "paraglide:input-processed" });
|
|
217
|
+
await vi.waitFor(() => expect(client.messages).toContainEqual({
|
|
218
|
+
type: "custom",
|
|
219
|
+
event: "paraglide:input-processed",
|
|
220
|
+
}));
|
|
221
|
+
expect(client.messages
|
|
222
|
+
.filter((message) => ["update", "error", "full-reload"].includes(message.type))
|
|
223
|
+
.at(-1)?.type).toBe("error");
|
|
224
|
+
expect(outputAfter).toBe(outputBefore);
|
|
225
|
+
expect((await fetch(server.resolvedUrls.local[0])).status).toBe(200);
|
|
226
|
+
await realFs.promises.writeFile(configFile, config);
|
|
227
|
+
await server.pluginContainer.watchChange(configFile, { event: "update" });
|
|
228
|
+
await vi.waitFor(() => expect(client.messages).toContainEqual({ type: "full-reload" }));
|
|
229
|
+
expect(await realFs.promises.readFile(runtimeFile, "utf8")).not.toBe(outputBefore);
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
await server.close();
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
test("vite error overlay still reports failures after restarting an inline plugin", async () => {
|
|
236
|
+
const { server, file } = await startOverlayServer();
|
|
237
|
+
try {
|
|
238
|
+
await server.restart();
|
|
239
|
+
const client = await connectViteClient(server);
|
|
240
|
+
await realFs.promises.writeFile(file, "{");
|
|
241
|
+
await server.pluginContainer.watchChange(file, { event: "update" });
|
|
242
|
+
await vi.waitFor(() => expect(client.messages.some((message) => message.type === "error")).toBe(true));
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
await server.close();
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
test("vite error overlay retains errors without buffering them in Vite", async () => {
|
|
249
|
+
process.env.NODE_ENV = "development";
|
|
250
|
+
const { projectDir, outdir } = await createProjectFixture();
|
|
251
|
+
const file = path.join(projectDir, "settings.json");
|
|
252
|
+
const original = await realFs.promises.readFile(file, "utf8");
|
|
253
|
+
await realFs.promises.writeFile(file, "{");
|
|
254
|
+
const { paraglideVitePlugin } = await import("./vite.js");
|
|
255
|
+
const plugin = paraglideVitePlugin({ project: projectDir, outdir });
|
|
256
|
+
const ws = configureViteServer(plugin);
|
|
257
|
+
ws.clients.clear();
|
|
258
|
+
await plugin.buildStart.call(mockContext);
|
|
259
|
+
expect(ws.send).not.toHaveBeenCalled();
|
|
260
|
+
expect(ws.on).toHaveBeenCalledWith("connection", expect.any(Function));
|
|
261
|
+
const onConnection = ws.on.mock.calls[0][1];
|
|
262
|
+
const socket = { send: vi.fn() };
|
|
263
|
+
onConnection(socket);
|
|
264
|
+
expect(JSON.parse(socket.send.mock.calls[0][0])).toMatchObject({
|
|
265
|
+
type: "error",
|
|
266
|
+
err: { message: expect.any(String), plugin: "unplugin-paraglide-js" },
|
|
267
|
+
});
|
|
268
|
+
await realFs.promises.writeFile(file, original);
|
|
269
|
+
await plugin.watchChange.call(mockContext, file);
|
|
270
|
+
expect(ws.send).not.toHaveBeenCalled();
|
|
271
|
+
socket.send.mockClear();
|
|
272
|
+
onConnection(socket);
|
|
273
|
+
expect(socket.send).not.toHaveBeenCalled();
|
|
274
|
+
});
|
|
275
|
+
test("vite error overlay preserves compiler diagnostics and clears after a successful buildStart", async () => {
|
|
276
|
+
process.env.NODE_ENV = "development";
|
|
277
|
+
const actual = await vi.importActual("../compiler/compile.js");
|
|
278
|
+
const error = new SyntaxError("Invalid message pattern in messages/en.json");
|
|
279
|
+
const compile = vi.fn(actual.compile).mockRejectedValueOnce(error);
|
|
280
|
+
vi.doMock("../compiler/compile.js", () => ({ ...actual, compile }));
|
|
281
|
+
try {
|
|
282
|
+
const { projectDir, outdir } = await createProjectFixture();
|
|
283
|
+
const { paraglideVitePlugin } = await import("./vite.js");
|
|
284
|
+
const plugin = paraglideVitePlugin({ project: projectDir, outdir });
|
|
285
|
+
const { send } = configureViteServer(plugin);
|
|
286
|
+
await plugin.buildStart.call(mockContext);
|
|
287
|
+
expect(send).toHaveBeenCalledWith({
|
|
288
|
+
type: "error",
|
|
289
|
+
err: {
|
|
290
|
+
message: error.message,
|
|
291
|
+
stack: error.stack,
|
|
292
|
+
plugin: "unplugin-paraglide-js",
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
await plugin.buildStart.call(mockContext);
|
|
296
|
+
expect(send).toHaveBeenLastCalledWith({ type: "full-reload" });
|
|
297
|
+
await plugin.buildStart.call(mockContext);
|
|
298
|
+
expect(send).toHaveBeenCalledTimes(2);
|
|
299
|
+
}
|
|
300
|
+
finally {
|
|
301
|
+
vi.doUnmock("../compiler/compile.js");
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
test("vite error overlay reports non-Error compiler failures during watchChange", async () => {
|
|
305
|
+
process.env.NODE_ENV = "development";
|
|
306
|
+
const actual = await vi.importActual("../compiler/compile.js");
|
|
307
|
+
const compile = vi.fn(actual.compile);
|
|
308
|
+
vi.doMock("../compiler/compile.js", () => ({ ...actual, compile }));
|
|
309
|
+
try {
|
|
310
|
+
const { projectDir, outdir } = await createProjectFixture();
|
|
311
|
+
const { paraglideVitePlugin } = await import("./vite.js");
|
|
312
|
+
const plugin = paraglideVitePlugin({ project: projectDir, outdir });
|
|
313
|
+
const { send } = configureViteServer(plugin);
|
|
314
|
+
await plugin.buildStart.call(mockContext);
|
|
315
|
+
compile.mockRejectedValueOnce("Invalid translation");
|
|
316
|
+
const file = path.join(projectDir, "settings.json");
|
|
317
|
+
await plugin.watchChange.call(mockContext, file);
|
|
318
|
+
expect(send).toHaveBeenLastCalledWith({
|
|
319
|
+
type: "error",
|
|
320
|
+
err: {
|
|
321
|
+
message: "Invalid translation",
|
|
322
|
+
stack: expect.any(String),
|
|
323
|
+
plugin: "unplugin-paraglide-js",
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
await plugin.watchChange.call(mockContext, file);
|
|
327
|
+
expect(send).toHaveBeenLastCalledWith({ type: "full-reload" });
|
|
328
|
+
}
|
|
329
|
+
finally {
|
|
330
|
+
vi.doUnmock("../compiler/compile.js");
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
test("vite error overlay keeps serving requests while the dev watcher recovers", async () => {
|
|
334
|
+
const { server, file, original } = await startOverlayServer();
|
|
335
|
+
try {
|
|
336
|
+
const send = vi.spyOn(server.ws, "send");
|
|
337
|
+
const client = await connectViteClient(server);
|
|
338
|
+
const url = server.resolvedUrls.local[0];
|
|
339
|
+
await realFs.promises.writeFile(file, "{");
|
|
340
|
+
server.watcher.emit("change", file);
|
|
341
|
+
await vi.waitFor(() => {
|
|
342
|
+
expect(send).toHaveBeenCalledWith({
|
|
343
|
+
type: "error",
|
|
344
|
+
err: expect.objectContaining({ message: expect.any(String) }),
|
|
345
|
+
});
|
|
346
|
+
}, { timeout: 10000 });
|
|
347
|
+
await vi.waitFor(() => expect(client.messages.some((message) => message.type === "error")).toBe(true));
|
|
348
|
+
const response = await fetch(url);
|
|
349
|
+
expect(response.status).toBe(200);
|
|
350
|
+
expect(await response.text()).toContain("Translation preview");
|
|
351
|
+
send.mockClear();
|
|
352
|
+
await realFs.promises.writeFile(file, original);
|
|
353
|
+
server.watcher.emit("change", file);
|
|
354
|
+
await vi.waitFor(() => expect(send).toHaveBeenCalledWith({ type: "full-reload" }), { timeout: 10000 });
|
|
355
|
+
}
|
|
356
|
+
finally {
|
|
357
|
+
await server.close();
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
// Vite 7 and earlier can retain a buffered error after a full reload.
|
|
361
|
+
test("vite error overlay does not replay an error recovered before the first connection", async () => {
|
|
362
|
+
const { server, file, original, outdir } = await startOverlayServer(true);
|
|
363
|
+
try {
|
|
364
|
+
await realFs.promises.writeFile(file, original);
|
|
365
|
+
await server.pluginContainer.watchChange(file, { event: "update" });
|
|
366
|
+
expect(await realFs.promises.readdir(outdir)).toContain("runtime.js");
|
|
367
|
+
const client = await connectViteClient(server);
|
|
368
|
+
expect(client.messages.some((message) => message.type === "error")).toBe(false);
|
|
369
|
+
}
|
|
370
|
+
finally {
|
|
371
|
+
await server.close();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
test("vite error overlay reaches new tabs and reconnecting clients after a startup failure", async () => {
|
|
375
|
+
const { server, file, original } = await startOverlayServer(true);
|
|
376
|
+
try {
|
|
377
|
+
const first = await connectViteClient(server);
|
|
378
|
+
await vi.waitFor(() => {
|
|
379
|
+
expect(first.messages.some((message) => message.type === "error")).toBe(true);
|
|
380
|
+
});
|
|
381
|
+
const second = await connectViteClient(server);
|
|
382
|
+
expect(second.messages.some((message) => message.type === "error")).toBe(true);
|
|
383
|
+
await Promise.all([first, second].map(({ socket }) => new Promise((resolve) => {
|
|
384
|
+
socket.addEventListener("close", () => resolve(), { once: true });
|
|
385
|
+
socket.close();
|
|
386
|
+
})));
|
|
387
|
+
const reconnected = await connectViteClient(server);
|
|
388
|
+
expect(reconnected.messages.some((message) => message.type === "error")).toBe(true);
|
|
389
|
+
await realFs.promises.writeFile(file, original);
|
|
390
|
+
await server.pluginContainer.watchChange(file, { event: "update" });
|
|
391
|
+
await vi.waitFor(() => {
|
|
392
|
+
expect(reconnected.messages).toContainEqual({ type: "full-reload" });
|
|
393
|
+
});
|
|
394
|
+
const recovered = await connectViteClient(server);
|
|
395
|
+
expect(recovered.messages.some((message) => message.type === "error")).toBe(false);
|
|
396
|
+
}
|
|
397
|
+
finally {
|
|
398
|
+
await server.close();
|
|
399
|
+
}
|
|
400
|
+
});
|
|
70
401
|
test("watch mode follows config precedence flips", async () => {
|
|
71
402
|
process.env.NODE_ENV = "development";
|
|
72
403
|
const { writeFile, rm } = await import("node:fs/promises");
|
|
@@ -111,7 +442,9 @@ test("vite plugin throws on compilation errors at build time", async () => {
|
|
|
111
442
|
outdir: path.join(workspace, "out"),
|
|
112
443
|
});
|
|
113
444
|
// In production mode - should throw the error
|
|
445
|
+
const { send } = configureViteServer(plugin);
|
|
114
446
|
await expect(plugin.buildStart?.call(mockContext)).rejects.toThrow();
|
|
447
|
+
expect(send).not.toHaveBeenCalled();
|
|
115
448
|
});
|
|
116
449
|
// Regression test for https://github.com/opral/inlang-paraglide-js/issues/659:
|
|
117
450
|
// the bundler plugins used to wipe `outdir` on every fresh process, racing
|