@inlang/paraglide-js 1.0.0-prerelease.2 → 1.0.0-prerelease.4

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.
Files changed (42) hide show
  1. package/README.md +10 -2
  2. package/dist/cli/commands/compile.d.ts.map +1 -1
  3. package/dist/cli/commands/compile.js +16 -19
  4. package/dist/cli/commands/compile.test.d.ts +2 -0
  5. package/dist/cli/commands/compile.test.d.ts.map +1 -0
  6. package/dist/cli/commands/compile.test.js +77 -0
  7. package/dist/cli/commands/init.d.ts +26 -0
  8. package/dist/cli/commands/init.d.ts.map +1 -0
  9. package/dist/cli/commands/init.js +277 -0
  10. package/dist/cli/commands/init.test.d.ts +2 -0
  11. package/dist/cli/commands/init.test.d.ts.map +1 -0
  12. package/dist/cli/commands/init.test.js +472 -0
  13. package/dist/cli/main.d.ts +0 -8
  14. package/dist/cli/main.d.ts.map +1 -1
  15. package/dist/cli/main.js +12 -21
  16. package/dist/cli/main.test.d.ts +2 -0
  17. package/dist/cli/main.test.d.ts.map +1 -0
  18. package/dist/cli/main.test.js +37 -0
  19. package/dist/cli/state.d.ts +14 -0
  20. package/dist/cli/state.d.ts.map +1 -0
  21. package/dist/cli/state.js +28 -0
  22. package/dist/compiled-output/website/messages.d.ts +73 -0
  23. package/dist/compiled-output/website/messages.js +1543 -0
  24. package/dist/compiled-output/{sveltekit-example → website}/runtime.d.ts +1 -1
  25. package/dist/compiled-output/{react-example → website}/runtime.js +1 -1
  26. package/package.json +4 -1
  27. package/dist/compiled-output/example-javascript/messages.d.ts +0 -7
  28. package/dist/compiled-output/example-javascript/messages.js +0 -42
  29. package/dist/compiled-output/example-javascript/runtime.d.ts +0 -38
  30. package/dist/compiled-output/example-javascript/runtime.js +0 -112
  31. package/dist/compiled-output/react-example/messages.d.ts +0 -7
  32. package/dist/compiled-output/react-example/messages.js +0 -42
  33. package/dist/compiled-output/react-example/runtime.d.ts +0 -38
  34. package/dist/compiled-output/sveltekit-example/messages.d.ts +0 -7
  35. package/dist/compiled-output/sveltekit-example/messages.js +0 -42
  36. package/dist/compiled-output/sveltekit-example/runtime.js +0 -112
  37. package/dist/compiler/jsdocFromParams.d.ts +0 -12
  38. package/dist/compiler/jsdocFromParams.d.ts.map +0 -1
  39. package/dist/compiler/jsdocFromParams.js +0 -17
  40. package/dist/compiler/jsdocFromParams.test.d.ts +0 -2
  41. package/dist/compiler/jsdocFromParams.test.d.ts.map +0 -1
  42. package/dist/compiler/jsdocFromParams.test.js +0 -6
@@ -0,0 +1,472 @@
1
+ import { test, expect, vi, beforeAll, beforeEach } from "vitest";
2
+ import { addCompileStepToPackageJSON, addParaglideJsToDependencies, adjustTsConfigIfNecessary, checkIfPackageJsonExists, checkIfUncommittedChanges, createNewProjectFlow, existingProjectFlow, findExistingInlangProjectPath, initializeInlangProject, newProjectTemplate, promptForNamespace, } from "./init.js";
3
+ import consola from "consola";
4
+ import { describe } from "node:test";
5
+ import fsSync from "node:fs";
6
+ import fs from "node:fs/promises";
7
+ import childProcess from "node:child_process";
8
+ import memfs from "memfs";
9
+ import { version } from "../state.js";
10
+ beforeAll(() => {
11
+ // spy on commonly used functions to prevent console output
12
+ // and allow expecations
13
+ vi.spyOn(consola, "log").mockImplementation(() => undefined);
14
+ vi.spyOn(consola, "info").mockImplementation(() => undefined);
15
+ vi.spyOn(consola, "success").mockImplementation(() => undefined);
16
+ vi.spyOn(consola, "error").mockImplementation(() => undefined);
17
+ vi.spyOn(consola, "warn").mockImplementation(() => undefined);
18
+ });
19
+ beforeEach(() => {
20
+ vi.resetAllMocks();
21
+ // Re-mock consola before each test call to remove calls from before
22
+ consola.mockTypes(() => vi.fn());
23
+ // set the current working directory to some mock value to prevent
24
+ // the tests from failing when running in a different environment
25
+ process.cwd = () => "/";
26
+ });
27
+ describe("end to end tests", () => {
28
+ test("it should exit if the user presses CTRL+C", async () => {
29
+ mockFiles({});
30
+ mockUserInput([
31
+ // the first user input is CTRL+C
32
+ () => process.emit("SIGINT", "SIGINT"),
33
+ ]);
34
+ // simulating a throw to exit the command early without
35
+ // killing the process the test runs in
36
+ vi.spyOn(process, "exit").mockImplementation(() => {
37
+ throw "process.exit";
38
+ });
39
+ try {
40
+ await checkIfPackageJsonExists();
41
+ }
42
+ catch (e) {
43
+ expect(e).toBe("process.exit");
44
+ }
45
+ expect(process.exit).toHaveBeenCalledOnce();
46
+ });
47
+ });
48
+ describe("initializeInlangProject()", () => {
49
+ test("it should execute existingProjectFlow() if a project has been found", async () => {
50
+ mockFiles({
51
+ "/folder/project.inlang.json": JSON.stringify(newProjectTemplate),
52
+ "/folder/subfolder": {},
53
+ });
54
+ process.cwd = () => "/folder/subfolder";
55
+ mockUserInput(["useExistingProject"]);
56
+ const path = await initializeInlangProject();
57
+ expect(path).toBe("../project.inlang.json");
58
+ }, {
59
+ // i am on a plane with bad internet
60
+ timeout: 20000,
61
+ });
62
+ test("it should execute newProjectFlow() if not project has been found", async () => {
63
+ const { existsSync } = mockFiles({});
64
+ mockUserInput(["newProject"]);
65
+ const path = await initializeInlangProject();
66
+ expect(path).toBe("./project.inlang.json");
67
+ expect(existsSync("./project.inlang.json")).toBe(true);
68
+ });
69
+ });
70
+ describe("addParaglideJsToDependencies()", () => {
71
+ test("it should add paraglide-js to the dependencies with the latest version", async () => {
72
+ mockFiles({
73
+ "/package.json": "{}",
74
+ });
75
+ await addParaglideJsToDependencies();
76
+ expect(fs.writeFile).toHaveBeenCalledOnce();
77
+ expect(consola.success).toHaveBeenCalledOnce();
78
+ const packageJson = JSON.parse((await fs.readFile("/package.json", { encoding: "utf-8" })));
79
+ expect(packageJson.dependencies["@inlang/paraglide-js"]).toBe(version);
80
+ });
81
+ });
82
+ describe("addCompileStepToPackageJSON()", () => {
83
+ test("if no scripts exist, it should add scripts.build", async () => {
84
+ mockFiles({
85
+ "/package.json": "{}",
86
+ });
87
+ await addCompileStepToPackageJSON({
88
+ projectPath: "./project.inlang.json",
89
+ namespace: "frontend",
90
+ });
91
+ expect(fs.writeFile).toHaveBeenCalledOnce();
92
+ expect(consola.success).toHaveBeenCalledOnce();
93
+ const packageJson = JSON.parse((await fs.readFile("/package.json", { encoding: "utf-8" })));
94
+ expect(packageJson.scripts.build).toBe(`paraglide-js compile --project ./project.inlang.json --namespace frontend`);
95
+ });
96
+ test("if an existing build step exists, it should be preceeded by the paraglide-js compile command", async () => {
97
+ mockFiles({
98
+ "/package.json": JSON.stringify({
99
+ scripts: {
100
+ build: "some build step",
101
+ },
102
+ }),
103
+ });
104
+ await addCompileStepToPackageJSON({
105
+ projectPath: "./project.inlang.json",
106
+ namespace: "frontend",
107
+ });
108
+ expect(fs.writeFile).toHaveBeenCalledOnce();
109
+ expect(consola.success).toHaveBeenCalledOnce();
110
+ const packageJson = JSON.parse((await fs.readFile("/package.json", { encoding: "utf-8" })));
111
+ expect(packageJson.scripts.build).toBe(`paraglide-js compile --project ./project.inlang.json --namespace frontend && some build step`);
112
+ });
113
+ test("if a paraglide-js compile step already exists, the user should be prompted to update it manually and exit if the user rejects", async () => {
114
+ mockFiles({
115
+ "/package.json": JSON.stringify({
116
+ scripts: {
117
+ build: "paraglide-js compile --project ./project.inlang.json",
118
+ },
119
+ }),
120
+ });
121
+ mockUserInput([
122
+ // user does not want to update the build step
123
+ false,
124
+ ]);
125
+ await addCompileStepToPackageJSON({
126
+ projectPath: "./project.inlang.json",
127
+ namespace: "frontend",
128
+ });
129
+ expect(fs.writeFile).not.toHaveBeenCalled();
130
+ expect(consola.success).not.toHaveBeenCalled();
131
+ expect(consola.warn).toHaveBeenCalledOnce();
132
+ expect(process.exit).toHaveBeenCalled();
133
+ });
134
+ test("if a paraglide-js compile step already exists, the user should be prompted to update it manually and return if they did so", async () => {
135
+ mockFiles({
136
+ "/package.json": JSON.stringify({
137
+ scripts: {
138
+ build: "paraglide-js compile --project ./project.inlang.json",
139
+ },
140
+ }),
141
+ });
142
+ mockUserInput([
143
+ // user does not want to update the build step
144
+ true,
145
+ ]);
146
+ await addCompileStepToPackageJSON({
147
+ projectPath: "./project.inlang.json",
148
+ namespace: "frontend",
149
+ });
150
+ expect(fs.writeFile).not.toHaveBeenCalled();
151
+ expect(consola.success).not.toHaveBeenCalled();
152
+ expect(consola.warn).toHaveBeenCalledOnce();
153
+ expect(process.exit).not.toHaveBeenCalled();
154
+ });
155
+ });
156
+ describe("promptForNamespace()", async () => {
157
+ test("it should trim the input from whitespace", async () => {
158
+ mockUserInput([" frontend "]);
159
+ const namespace = await promptForNamespace();
160
+ expect(namespace).toBe("frontend");
161
+ });
162
+ });
163
+ describe("existingProjectFlow()", () => {
164
+ test("if the user selects to proceed with the existing project and the project has no errors, the function should return", async () => {
165
+ mockFiles({
166
+ "/project.inlang.json": JSON.stringify(newProjectTemplate),
167
+ });
168
+ mockUserInput(["useExistingProject"]);
169
+ expect(existingProjectFlow({ existingProjectPath: "/project.inlang.json" })).resolves.toBeUndefined();
170
+ });
171
+ test("if the user selects new project, the newProjectFlow() should be executed", async () => {
172
+ const { existsSync } = mockFiles({
173
+ "/folder/project.inlang.json": JSON.stringify(newProjectTemplate),
174
+ });
175
+ mockUserInput(["newProject"]);
176
+ await existingProjectFlow({ existingProjectPath: "/folder/project.inlang.json" });
177
+ // info that a new project is created
178
+ expect(consola.info).toHaveBeenCalledOnce();
179
+ // the newly created project file should exist
180
+ expect(existsSync("/project.inlang.json")).toBe(true);
181
+ });
182
+ test("it should exit if the existing project contains errors", async () => {
183
+ mockFiles({
184
+ "/project.inlang.json": `BROKEN PROJECT FILE`,
185
+ });
186
+ mockUserInput(["useExistingProject"]);
187
+ await existingProjectFlow({ existingProjectPath: "/project.inlang.json" });
188
+ expect(consola.error).toHaveBeenCalled();
189
+ expect(process.exit).toHaveBeenCalled();
190
+ });
191
+ });
192
+ describe("createNewProjectFlow()", async () => {
193
+ test("it should succeed in creating a new project", async () => {
194
+ const { existsSync } = mockFiles({});
195
+ await createNewProjectFlow();
196
+ // user is informed that a new project is created
197
+ expect(consola.info).toHaveBeenCalledOnce();
198
+ // the project shouldn't have errors
199
+ expect(consola.error).not.toHaveBeenCalled();
200
+ // user is informed that the project has successfully been created
201
+ expect(consola.success).toHaveBeenCalledOnce();
202
+ // the project file should exist
203
+ expect(existsSync("/project.inlang.json")).toBe(true);
204
+ }, {
205
+ // i am testing this while i am on an airplane with slow internet
206
+ timeout: 20000,
207
+ });
208
+ test("it should exit if the project has errors", async () => {
209
+ mockFiles({});
210
+ // invalid project settings file
211
+ vi.spyOn(JSON, "stringify").mockReturnValue(`{}`);
212
+ await createNewProjectFlow();
213
+ // user is informed that a new project is created
214
+ expect(consola.info).toHaveBeenCalledOnce();
215
+ // the project has errors
216
+ expect(consola.error).toHaveBeenCalled();
217
+ // the commands exits
218
+ expect(process.exit).toHaveBeenCalled();
219
+ });
220
+ });
221
+ describe("checkIfUncommittedChanges()", () => {
222
+ test("it should not fail if the git cli is not installed", async () => {
223
+ vi.spyOn(childProcess, "execSync").mockImplementation(() => {
224
+ throw Error("Command failed: git status");
225
+ });
226
+ expect(checkIfUncommittedChanges()).resolves.toBeUndefined();
227
+ });
228
+ test("it should continue if no uncomitted changes exist", async () => {
229
+ vi.spyOn(childProcess, "execSync").mockImplementation(() => {
230
+ return Buffer.from("");
231
+ });
232
+ expect(checkIfUncommittedChanges()).resolves.toBeUndefined();
233
+ });
234
+ test("it should prompt the user if there are uncommitted changes and exit if the user doesn't want to continue", async () => {
235
+ vi.spyOn(childProcess, "execSync").mockImplementation(() => {
236
+ return Buffer.from("M package.json");
237
+ });
238
+ const processExit = vi.spyOn(process, "exit").mockImplementation(() => undefined);
239
+ mockUserInput([
240
+ // user does not want to continue
241
+ false,
242
+ ]);
243
+ await checkIfUncommittedChanges();
244
+ expect(consola.info).toHaveBeenCalledOnce();
245
+ expect(consola.prompt).toHaveBeenCalledOnce();
246
+ expect(processExit).toHaveBeenCalledOnce();
247
+ });
248
+ test("it should prompt the user if there are uncommitted changes and return if the user wants to continue", async () => {
249
+ vi.spyOn(childProcess, "execSync").mockImplementation(() => {
250
+ return Buffer.from("M package.json");
251
+ });
252
+ const processExit = vi.spyOn(process, "exit").mockImplementation(() => undefined);
253
+ mockUserInput([
254
+ // user does want to continue
255
+ true,
256
+ ]);
257
+ await checkIfUncommittedChanges();
258
+ expect(consola.info).toHaveBeenCalledOnce();
259
+ expect(consola.prompt).toHaveBeenCalledOnce();
260
+ expect(processExit).not.toHaveBeenCalledOnce();
261
+ });
262
+ test("it should not prompt the user if no uncommitted changes exist", async () => {
263
+ await checkIfUncommittedChanges();
264
+ expect(consola.prompt).not.toHaveBeenCalled();
265
+ });
266
+ });
267
+ describe("checkIfPackageJsonExists()", () => {
268
+ test("it should exit if no package.json has been found", async () => {
269
+ mockFiles({});
270
+ await checkIfPackageJsonExists();
271
+ expect(consola.warn).toHaveBeenCalledOnce();
272
+ expect(process.exit).toHaveBeenCalledOnce();
273
+ });
274
+ test("it should not exit if a package.json exists in the current working directory", async () => {
275
+ mockFiles({ "package.json": "" });
276
+ await checkIfPackageJsonExists();
277
+ expect(consola.warn).not.toHaveBeenCalled();
278
+ expect(process.exit).not.toHaveBeenCalled();
279
+ });
280
+ });
281
+ describe("findExistingInlangProjectPath()", () => {
282
+ test("it should return undefined if no project.inlang.json has been found", async () => {
283
+ mockFiles({});
284
+ const path = await findExistingInlangProjectPath();
285
+ expect(path).toBeUndefined();
286
+ });
287
+ test("it find a project in the current working directory", async () => {
288
+ process.cwd = () => "/";
289
+ mockFiles({ "project.inlang.json": "{}" });
290
+ const path = await findExistingInlangProjectPath();
291
+ expect(path).toBe("./project.inlang.json");
292
+ });
293
+ test("it should find a project in a parent directory", async () => {
294
+ process.cwd = () => "/nested/";
295
+ mockFiles({
296
+ "/project.inlang.json": "{}",
297
+ "/nested/": {},
298
+ });
299
+ const path = await findExistingInlangProjectPath();
300
+ expect(path).toBe("../project.inlang.json");
301
+ });
302
+ test("it should find a project in a parent parent directory", async () => {
303
+ process.cwd = () => "/nested/nested/";
304
+ mockFiles({
305
+ "/project.inlang.json": "{}",
306
+ "/nested/nested/": {},
307
+ });
308
+ const path = await findExistingInlangProjectPath();
309
+ expect(path).toBe("../../project.inlang.json");
310
+ });
311
+ });
312
+ describe("adjustTsConfigIfNecessary()", () => {
313
+ test("it should return if no tsconfig.json exists", async () => {
314
+ mockFiles({});
315
+ const result = await adjustTsConfigIfNecessary();
316
+ // no tsconfig exists, immediately return
317
+ expect(result).toBeUndefined();
318
+ // the tsconfig should not have been read
319
+ expect(fs.readFile).not.toHaveBeenCalled();
320
+ // no info that the moduleResolution needs to be adapted should be logged
321
+ expect(consola.info).not.toHaveBeenCalled();
322
+ });
323
+ test("it should warn if the extended from tsconfig can't be read", async () => {
324
+ mockFiles({
325
+ "/tsconfig.json": `{
326
+ "extends": "./non-existend.json",
327
+ "compilerOptions": {
328
+ "moduleResolution": "Bundler"
329
+ }
330
+ }`,
331
+ });
332
+ await adjustTsConfigIfNecessary();
333
+ // no info that the moduleResolution needs to be adapted should be logged
334
+ expect(consola.warn).toHaveBeenCalledOnce();
335
+ });
336
+ test("it should detect if the extended from tsconfig already set the moduleResolution to bundler", async () => {
337
+ mockFiles({
338
+ "/tsconfig.base.json": `{
339
+ "compilerOptions": {
340
+ "moduleResolution": "Bundler"
341
+ }
342
+ }`,
343
+ "/tsconfig.json": `{
344
+ "extends": "tsconfig.base.json",
345
+ }`,
346
+ });
347
+ await adjustTsConfigIfNecessary();
348
+ // no info that the moduleResolution needs to be adapted should be logged
349
+ expect(consola.info).not.toHaveBeenCalled();
350
+ });
351
+ test("it should prompt the user to set the moduleResolution to bundler", async () => {
352
+ mockFiles({
353
+ "/tsconfig.json": `{}`,
354
+ });
355
+ const userAdjustsTsConfigSpy = vi.fn();
356
+ mockUserInput([
357
+ // user confirms that the moduleResolution has been set to bundler
358
+ () => {
359
+ userAdjustsTsConfigSpy();
360
+ fs.writeFile("/tsconfig.json", `{
361
+ "compilerOptions": {
362
+ "moduleResolution": "Bundler"
363
+ }
364
+ }`);
365
+ return true;
366
+ },
367
+ ]);
368
+ await adjustTsConfigIfNecessary();
369
+ // info that the moduleResolution needs to be adapted
370
+ expect(consola.info).toHaveBeenCalledOnce();
371
+ // prompt the user to set the moduleResolution to bundler
372
+ expect(consola.prompt).toHaveBeenCalledOnce();
373
+ // user has set the moduleResolution to bundler
374
+ expect(userAdjustsTsConfigSpy).toHaveBeenCalledOnce();
375
+ });
376
+ test("it should keep prompting the user to set the moduleResolution to bundler if the moduleResolution has not been set", async () => {
377
+ mockFiles({
378
+ "/tsconfig.json": `{}`,
379
+ });
380
+ mockUserInput([
381
+ // user confirms that the moduleResolution has been set to bundler
382
+ // while the moduleResolution is still not set
383
+ // -> should prompt again
384
+ true,
385
+ // user wants to exit
386
+ // -> should warn that type errors might occur and continue with init
387
+ false,
388
+ ]);
389
+ await adjustTsConfigIfNecessary();
390
+ // info that the moduleResolution needs to be adapted
391
+ expect(consola.warn).toHaveBeenCalledOnce();
392
+ // 1. prompt the user to set the moduleResolution to bundler
393
+ // 2. prompt again because the moduleResolution is still not set
394
+ expect(consola.prompt).toHaveBeenCalledTimes(2);
395
+ // the user has not set the moduleResolution to bundler
396
+ // after the first prompt eventhough the user said it did
397
+ expect(consola.error).toHaveBeenCalledOnce();
398
+ // the user exists without setting the moduleResolution to bundler
399
+ // warn about type errors
400
+ expect(consola.warn).toHaveBeenCalledOnce();
401
+ });
402
+ });
403
+ // test("the paraglide plugin for vscode should be installed", () => {
404
+ // throw new Error("Not implemented")
405
+ // })
406
+ // test("it sets the tsconfig compiler option 'moduleResolution' to 'bundler'", () => {
407
+ // throw new Error("Not implemented")
408
+ // })
409
+ // test("it should create a project if it doesn't exist", () => {
410
+ // test("the inlang message format should be the default selection", () => {
411
+ // throw new Error("Not implemented")
412
+ // })
413
+ // })
414
+ // test("the vscode extension should be added to the workspace recommendations", () => {
415
+ // test("automatically if the .vscode folder exists", () => {
416
+ // throw new Error("Not implemented")
417
+ // })
418
+ // test("else, the user should be prompted if the vscode extension should be added", () => {
419
+ // throw new Error("Not implemented")
420
+ // })
421
+ // })
422
+ // describe("it should prompt the user if the cli should be added for linting and machine translations", () => {
423
+ // test("the cli should be added to the devDependencies", () => {
424
+ // throw new Error("Not implemented")
425
+ // })
426
+ // test("if a lint script exists, inlang lint should be added to the lint script", () => {
427
+ // throw new Error("Not implemented")
428
+ // })
429
+ // test("if no lint script exists, the lint script should be created in the package.json", () => {
430
+ // throw new Error("Not implemented")
431
+ // })
432
+ // })
433
+ // test("the user should be prompted for the framework and forwarded to the corresponding guide", () => {
434
+ // throw new Error("Not implemented")
435
+ // })
436
+ /**
437
+ * Mock user input.
438
+ *
439
+ * @example
440
+ * mockUserInput([
441
+ * "some input",
442
+ * () => {
443
+ * fs.writeFileSync("some-file", "some content")
444
+ * return true
445
+ * }
446
+ * ]),
447
+ */
448
+ const mockUserInput = (testUserInput) => {
449
+ vi.spyOn(consola, "prompt").mockImplementation(() => {
450
+ const value = testUserInput.shift();
451
+ if (value === undefined) {
452
+ throw new Error("End of test input");
453
+ }
454
+ else if (typeof value === "function") {
455
+ return value();
456
+ }
457
+ return value;
458
+ });
459
+ };
460
+ const mockFiles = (files) => {
461
+ const _memfs = memfs.createFsFromVolume(memfs.Volume.fromNestedJSON(files));
462
+ vi.spyOn(fsSync, "existsSync").mockImplementation(_memfs.existsSync);
463
+ for (const prop in fs) {
464
+ // @ts-ignore - memfs has the same interface as node:fs/promises
465
+ if (typeof fs[prop] !== "function")
466
+ continue;
467
+ // @ts-ignore - memfs has the same interface as node:fs/promises
468
+ vi.spyOn(fs, prop).mockImplementation(_memfs.promises[prop]);
469
+ }
470
+ return { existsSync: _memfs.existsSync };
471
+ };
472
+ test("a tsconfig with comments should be loaded correctly", () => { });
@@ -1,11 +1,3 @@
1
1
  import { Command } from "commander";
2
- /**
3
- * The absolute path to the paraglide directory.
4
- *
5
- * slices a path
6
- * from '/Users/samuel/example/repository/node_modules/paraglide-js/dist/cli/main.js'
7
- * to '/Users/samuel/example/repository/node_modules/paraglide-js'
8
- */
9
- export declare const paraglideDirectory: string;
10
2
  export declare const cli: Command;
11
3
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAUnC;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAA4D,CAAA;AAE7F,eAAO,MAAM,GAAG,SAqBb,CAAA"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,eAAO,MAAM,GAAG,SA0Bb,CAAA"}
package/dist/cli/main.js CHANGED
@@ -1,40 +1,31 @@
1
1
  import consola from "consola";
2
2
  import dedent from "dedent";
3
- import { fileURLToPath } from "node:url";
4
3
  import { Command } from "commander";
5
4
  import { compileCommand } from "./commands/compile.js";
6
- /**
7
- * The path this file is executed from.
8
- *
9
- * Usually something like '/Users/samuel/example/repository/node_modules/paraglide-js/dist/cli/main.js'
10
- */
11
- const metaUrlPath = fileURLToPath(import.meta.url);
12
- /**
13
- * The absolute path to the paraglide directory.
14
- *
15
- * slices a path
16
- * from '/Users/samuel/example/repository/node_modules/paraglide-js/dist/cli/main.js'
17
- * to '/Users/samuel/example/repository/node_modules/paraglide-js'
18
- */
19
- export const paraglideDirectory = metaUrlPath.slice(0, metaUrlPath.indexOf("/dist/"));
5
+ import { paraglideDirectory, version } from "./state.js";
6
+ import { initCommand } from "./commands/init.js";
20
7
  export const cli = new Command()
21
8
  .name("paraglide-js")
22
9
  .addCommand(compileCommand)
23
- .hook("preAction", () => {
10
+ .addCommand(initCommand)
11
+ .showHelpAfterError()
12
+ .version(version)
13
+ .action(() => {
24
14
  // ------------------- VALIDATE IF RUNNING FROM CORRECT FOLDER -------------------
25
15
  // the CLI expects to be running from the dist folder of the specific paraglide package
26
16
  // to compile the output in the correct directory
27
- if (metaUrlPath.includes(`paraglide-js/dist/`) === false) {
17
+ if (paraglideDirectory.endsWith(`paraglide-js`) === false) {
28
18
  consola.error(dedent `
29
- The CLI is not running from the dist folder.
19
+ The CLI is not running from a paraglide-js directory.
30
20
 
31
21
  This is likely an internal bug. Please file an issue at https://github.com/inlang/monorepo/issues.
32
22
 
33
23
  Debug information:
34
24
 
35
- - metaUrlPath: ${metaUrlPath}
25
+ - paraglideDirectory: ${paraglideDirectory}
36
26
  `);
37
- process.exit(1);
27
+ return process.exit(1);
38
28
  }
29
+ // show the help because no command is specified
30
+ return cli.help();
39
31
  });
40
- cli.showHelpAfterError(true);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.test.d.ts","sourceRoot":"","sources":["../../src/cli/main.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { describe, test, expect, vi } from "vitest";
2
+ import { _setStateForTest } from "./state.js";
3
+ import { cli } from "./main.js";
4
+ import consola from "consola";
5
+ // surpress output for clean test output
6
+ cli.configureOutput({ writeErr: () => { }, writeOut: () => { } });
7
+ describe("it should exit if the CLI is not running from the dist folder", () => {
8
+ const shouldSucceed = [
9
+ "/Users/example/repository/node_modules/paraglide-js",
10
+ "/node_modules/paraglide-js",
11
+ // windows... https://github.com/inlang/monorepo/issues/1478
12
+ "C:\\Users\\Projects\\svelte-one\\node_modules\\@inlang\\paraglide-js",
13
+ ];
14
+ const shouldFail = ["/Users/samuel/example/repository"];
15
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined);
16
+ // remove error message to have clean test output
17
+ vi.spyOn(consola, "error").mockImplementation(() => undefined);
18
+ for (const path of shouldSucceed) {
19
+ test("suceed with " + path, async () => {
20
+ // surpress output to have clean test output
21
+ _setStateForTest({
22
+ paraglideDirectory: path,
23
+ });
24
+ await cli.parseAsync([]);
25
+ expect(exitSpy).toHaveBeenLastCalledWith(0);
26
+ });
27
+ }
28
+ for (const path of shouldFail) {
29
+ test("fail with " + path, async () => {
30
+ _setStateForTest({
31
+ paraglideDirectory: path,
32
+ });
33
+ await cli.parseAsync([]);
34
+ expect(exitSpy).toHaveBeenLastCalledWith(1);
35
+ });
36
+ }
37
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The absolute path to the paraglide directory.
3
+ *
4
+ * slices a path
5
+ * from '/Users/samuel/example/repository/node_modules/paraglide-js/dist/cli/main.js'
6
+ * to '/Users/samuel/example/repository/node_modules/paraglide-js'
7
+ */
8
+ export declare let paraglideDirectory: string;
9
+ export declare const _setStateForTest: (values: Record<"paraglideDirectory", any>) => void;
10
+ /**
11
+ * The version of the paraglide-js package.
12
+ */
13
+ export declare const version: any;
14
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/cli/state.ts"],"names":[],"mappings":"AAaA;;;;;;GAMG;AACH,eAAO,IAAI,kBAAkB,EAAE,MAG9B,CAAA;AAID,eAAO,MAAM,gBAAgB,WAAY,OAAO,oBAAoB,EAAE,GAAG,CAAC,SAEzE,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,KAEX,CAAA"}
@@ -0,0 +1,28 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ /**
5
+ * The posix path this file is executed from.
6
+ *
7
+ * Usually something like '/Users/samuel/example/repository/node_modules/paraglide-js/dist/cli/main.js'
8
+ */
9
+ const currentFilePath = fileURLToPath(import.meta.url)
10
+ .split(path.sep)
11
+ .join(path.posix.sep);
12
+ /**
13
+ * The absolute path to the paraglide directory.
14
+ *
15
+ * slices a path
16
+ * from '/Users/samuel/example/repository/node_modules/paraglide-js/dist/cli/main.js'
17
+ * to '/Users/samuel/example/repository/node_modules/paraglide-js'
18
+ */
19
+ export let paraglideDirectory = currentFilePath.slice(0, currentFilePath.indexOf("/paraglide-js/") + "/paraglide-js".length);
20
+ // this is only used for testing
21
+ // use cmd + f to find all usages
22
+ export const _setStateForTest = (values) => {
23
+ paraglideDirectory = values.paraglideDirectory;
24
+ };
25
+ /**
26
+ * The version of the paraglide-js package.
27
+ */
28
+ export const version = JSON.parse(fs.readFileSync(`${paraglideDirectory}/package.json`, "utf-8")).version;