@inlang/sdk 0.32.0 → 0.34.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.
Files changed (50) hide show
  1. package/dist/createNewProject.d.ts +17 -0
  2. package/dist/createNewProject.d.ts.map +1 -0
  3. package/dist/createNewProject.js +22 -0
  4. package/dist/createNewProject.test.d.ts +2 -0
  5. package/dist/createNewProject.test.d.ts.map +1 -0
  6. package/dist/createNewProject.test.js +93 -0
  7. package/dist/createNodeishFsWithAbsolutePaths.js +1 -1
  8. package/dist/defaultProjectSettings.d.ts +14 -0
  9. package/dist/defaultProjectSettings.d.ts.map +1 -0
  10. package/dist/defaultProjectSettings.js +23 -0
  11. package/dist/index.d.ts +3 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -0
  14. package/dist/loadProject.d.ts.map +1 -1
  15. package/dist/loadProject.js +19 -23
  16. package/dist/loadProject.test.js +4 -4
  17. package/dist/migrations/maybeCreateFirstProjectId.test.js +3 -6
  18. package/dist/storage/helper.d.ts +24 -0
  19. package/dist/storage/helper.d.ts.map +1 -1
  20. package/dist/storage/helper.js +35 -7
  21. package/dist/storage/helpers.test.d.ts +2 -0
  22. package/dist/storage/helpers.test.d.ts.map +1 -0
  23. package/dist/storage/helpers.test.js +84 -0
  24. package/dist/validateProjectPath.d.ts +23 -0
  25. package/dist/validateProjectPath.d.ts.map +1 -0
  26. package/dist/validateProjectPath.js +52 -0
  27. package/dist/validateProjectPath.test.d.ts +2 -0
  28. package/dist/validateProjectPath.test.d.ts.map +1 -0
  29. package/dist/validateProjectPath.test.js +56 -0
  30. package/package.json +7 -7
  31. package/src/createNewProject.test.ts +108 -0
  32. package/src/createNewProject.ts +31 -0
  33. package/src/createNodeishFsWithAbsolutePaths.ts +1 -1
  34. package/src/defaultProjectSettings.ts +27 -0
  35. package/src/index.ts +3 -0
  36. package/src/loadProject.test.ts +5 -4
  37. package/src/loadProject.ts +22 -28
  38. package/src/migrations/maybeCreateFirstProjectId.test.ts +3 -6
  39. package/src/storage/helper.ts +36 -10
  40. package/src/storage/helpers.test.ts +95 -0
  41. package/src/validateProjectPath.test.ts +68 -0
  42. package/src/validateProjectPath.ts +58 -0
  43. package/dist/isAbsolutePath.d.ts +0 -2
  44. package/dist/isAbsolutePath.d.ts.map +0 -1
  45. package/dist/isAbsolutePath.js +0 -4
  46. package/dist/isAbsolutePath.test.d.ts +0 -2
  47. package/dist/isAbsolutePath.test.d.ts.map +0 -1
  48. package/dist/isAbsolutePath.test.js +0 -20
  49. package/src/isAbsolutePath.test.ts +0 -23
  50. package/src/isAbsolutePath.ts +0 -5
@@ -0,0 +1,95 @@
1
+ import { describe, it, expect } from "vitest"
2
+ // import { parseLixUri, parseOrigin } from "./helpers.js"
3
+ import { normalizeMessage, stringifyMessage } from "./helper.js"
4
+ import type { Message } from "@inlang/message"
5
+
6
+ const unsortedMessageRaw: Message = {
7
+ alias: {},
8
+ selectors: [],
9
+ id: "footer_categories_apps",
10
+ variants: [
11
+ { languageTag: "a", match: ["*", "1"], pattern: [{ type: "Text", value: "2" }] },
12
+ { languageTag: "a", match: ["*", "*"], pattern: [{ type: "Text", value: "1" }] },
13
+ {
14
+ languageTag: "a",
15
+ match: ["1", "*"],
16
+ pattern: [
17
+ { type: "Text", value: "2" },
18
+ { type: "Text", value: "2" },
19
+ ],
20
+ },
21
+ { languageTag: "b", match: [], pattern: [{ type: "Text", value: "4" }] },
22
+ { languageTag: "a", match: ["1", "1"], pattern: [{ type: "Text", value: "2" }] },
23
+ { languageTag: "c", match: [], pattern: [{ value: "5", type: "Text" }] },
24
+ { match: [], languageTag: "d", pattern: [{ type: "Text", value: "6" }] },
25
+ { languageTag: "e", match: [], pattern: [{ type: "Text", value: "7" }] },
26
+ { languageTag: "f", match: [], pattern: [{ type: "Text", value: "8" }] },
27
+ { languageTag: "g", match: [], pattern: [{ type: "Text", value: "9" }] },
28
+ ],
29
+ }
30
+
31
+ const sortedMessageRaw: Message = {
32
+ alias: {},
33
+ id: "footer_categories_apps",
34
+ selectors: [],
35
+ variants: [
36
+ { languageTag: "a", match: ["*", "*"], pattern: [{ type: "Text", value: "1" }] },
37
+ { languageTag: "a", match: ["*", "1"], pattern: [{ type: "Text", value: "2" }] },
38
+ {
39
+ languageTag: "a",
40
+ match: ["1", "*"],
41
+ pattern: [
42
+ { type: "Text", value: "2" },
43
+ { type: "Text", value: "2" },
44
+ ],
45
+ },
46
+ { languageTag: "a", match: ["1", "1"], pattern: [{ type: "Text", value: "2" }] },
47
+ { languageTag: "b", match: [], pattern: [{ type: "Text", value: "4" }] },
48
+ { languageTag: "c", match: [], pattern: [{ type: "Text", value: "5" }] },
49
+ { languageTag: "d", match: [], pattern: [{ type: "Text", value: "6" }] },
50
+ { languageTag: "e", match: [], pattern: [{ type: "Text", value: "7" }] },
51
+ { languageTag: "f", match: [], pattern: [{ type: "Text", value: "8" }] },
52
+ { languageTag: "g", match: [], pattern: [{ type: "Text", value: "9" }] },
53
+ ],
54
+ }
55
+
56
+ // stringify with no indentation
57
+ function str(obj: any) {
58
+ return JSON.stringify(obj)
59
+ }
60
+
61
+ // stringify with 2 space indentation
62
+ function str2(obj: any) {
63
+ return JSON.stringify(obj, undefined, 2)
64
+ }
65
+
66
+ // stringify with 4 space indentation
67
+ function str4(obj: any) {
68
+ return JSON.stringify(obj, undefined, 4)
69
+ }
70
+
71
+ describe("normalizeMessage", () => {
72
+ it("should return the message with sorted keys and variants", () => {
73
+ // test cases are not the same (deep equal) before normalization
74
+ // array order of variants is different
75
+ expect(unsortedMessageRaw).not.toEqual(sortedMessageRaw)
76
+
77
+ // test cases are the same after normalization
78
+ expect(normalizeMessage(unsortedMessageRaw)).toEqual(sortedMessageRaw)
79
+
80
+ // stringify results are not the same before normalization
81
+ expect(str(unsortedMessageRaw)).not.toBe(str(sortedMessageRaw))
82
+
83
+ // stringify results are the same after normalization
84
+ expect(str(normalizeMessage(unsortedMessageRaw))).toBe(str(sortedMessageRaw))
85
+ expect(str2(normalizeMessage(unsortedMessageRaw))).toBe(str2(sortedMessageRaw))
86
+ expect(str4(normalizeMessage(unsortedMessageRaw))).toBe(str4(sortedMessageRaw))
87
+ })
88
+ })
89
+
90
+ describe("stringifyMessage", () => {
91
+ it("should normalize and JSON stringify a message with 4 space indentation", () => {
92
+ expect(stringifyMessage(unsortedMessageRaw)).toBe(str4(sortedMessageRaw))
93
+ expect(stringifyMessage(sortedMessageRaw)).toBe(str4(sortedMessageRaw))
94
+ })
95
+ })
@@ -0,0 +1,68 @@
1
+ import { assert, describe, expect, it } from "vitest"
2
+ import {
3
+ assertValidProjectPath,
4
+ isAbsolutePath,
5
+ isInlangProjectPath,
6
+ pathExists,
7
+ } from "./validateProjectPath.js"
8
+ import { mockRepo } from "@lix-js/client"
9
+
10
+ describe("isAbsolutePath", () => {
11
+ it("should correctly identify Unix absolute paths", () => {
12
+ assert.isTrue(isAbsolutePath("/home/user/documents/file.txt"))
13
+ assert.isTrue(isAbsolutePath("/usr/local/bin/script.sh"))
14
+ assert.isFalse(isAbsolutePath("relative/path/to/file.txt"))
15
+ })
16
+
17
+ it("should correctly identify Windows absolute paths", () => {
18
+ assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt"))
19
+ assert.isTrue(isAbsolutePath("C:/Users/user/project.inlang/settings.json"))
20
+ assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt"))
21
+ })
22
+
23
+ it("should handle edge cases", () => {
24
+ assert.isFalse(isAbsolutePath("")) // Empty path should return false
25
+ assert.isFalse(isAbsolutePath("relative/path/../file.txt")) // Relative path with ".." should return false
26
+ assert.isFalse(isAbsolutePath("../relative/path/to/file.txt"))
27
+ assert.isFalse(isAbsolutePath("./relative/path/to/file.txt"))
28
+ })
29
+ })
30
+
31
+ describe("isInlangProjectPath", () => {
32
+ it("should correctly identify valid inlang project paths", () => {
33
+ assert.isTrue(isInlangProjectPath("/path/to/orange-mouse.inlang"))
34
+ assert.isFalse(isInlangProjectPath("relative/path/to/file.txt"))
35
+ assert.isFalse(isInlangProjectPath("/path/to/.inlang"))
36
+ assert.isFalse(isInlangProjectPath("/path/to/white-elephant.inlang/"))
37
+ assert.isFalse(isInlangProjectPath("/path/to/blue-elephant.inlang/settings.json"))
38
+ })
39
+ })
40
+
41
+ describe("assertValidProjectPath", () => {
42
+ it("should not throw for valid project paths", () => {
43
+ assert.doesNotThrow(() => assertValidProjectPath("/path/to/brown-mouse.inlang"))
44
+ assert.doesNotThrow(() => assertValidProjectPath("/path/to/green-elephant.inlang"))
45
+ })
46
+
47
+ it("should throw for invalid project paths", () => {
48
+ assert.throws(() => assertValidProjectPath("relative/path/to/flying-lizard.inlang"))
49
+ assert.throws(() => assertValidProjectPath("/path/to/loud-mouse.inlang/"))
50
+ assert.throws(() => assertValidProjectPath("/path/to/green-elephant.inlang/settings.json"))
51
+ })
52
+ })
53
+
54
+ // moar tests in paraglide-js/src/services/file-handling/exists.test.ts
55
+ describe("pathExists", () => {
56
+ it("should work for files", async () => {
57
+ const repo = await mockRepo()
58
+ await repo.nodeishFs.writeFile("/test.txt", "hello")
59
+ expect(await pathExists("/test.txt", repo.nodeishFs)).toBe(true)
60
+ expect(await pathExists("/does-not-exist.txt", repo.nodeishFs)).toBe(false)
61
+ })
62
+ it("should work for directories", async () => {
63
+ const repo = await mockRepo()
64
+ await repo.nodeishFs.mkdir("/test/project.inlang", { recursive: true })
65
+ expect(await pathExists("/test/project.inlang", repo.nodeishFs)).toBe(true)
66
+ expect(await pathExists("/test/white-gorilla.inlang", repo.nodeishFs)).toBe(false)
67
+ })
68
+ })
@@ -0,0 +1,58 @@
1
+ import type { NodeishFilesystem } from "@lix-js/fs"
2
+
3
+ /**
4
+ * validate that a project path is absolute and ends with {name}.inlang.
5
+ *
6
+ * @throws if the path is not valid.
7
+ */
8
+ export function assertValidProjectPath(projectPath: string) {
9
+ if (!isAbsolutePath(projectPath)) {
10
+ throw new Error(`Expected an absolute path but received "${projectPath}".`)
11
+ }
12
+ if (!isInlangProjectPath(projectPath)) {
13
+ throw new Error(
14
+ `Expected a path ending in "{name}.inlang" but received "${projectPath}".\n\nValid examples: \n- "/path/to/micky-mouse.inlang"\n- "/path/to/green-elephant.inlang\n`
15
+ )
16
+ }
17
+ }
18
+
19
+ /**
20
+ * tests whether a path ends with {name}.inlang
21
+ * (does not remove trailing slash)
22
+ */
23
+ export function isInlangProjectPath(path: string) {
24
+ return /[^\\/]+\.inlang$/.test(path)
25
+ }
26
+
27
+ /**
28
+ * tests whether a path starts with a forward slash (/) or a windows-style
29
+ * drive letter (C: or D:, etc.) followed by a slash
30
+ */
31
+ export function isAbsolutePath(path: string) {
32
+ return /^\/|^[A-Za-z]:[\\/]/.test(path)
33
+
34
+ // OG from sdk/src/isAbsolutePath.ts - TODO: find out where this regex came from
35
+ // const matchPosixAndWindowsAbsolutePaths =
36
+ // /^(?:[A-Za-z]:\\(?:[^\\]+\\)*[^\\]+|[A-Za-z]:\/(?:[^/]+\/)*[^/]+|\/(?:[^/]+\/)*[^/]+)$/
37
+ // return matchPosixAndWindowsAbsolutePaths.test(path)
38
+ }
39
+
40
+ /**
41
+ * Returns true if the path exists (file or directory), false otherwise.
42
+ *
43
+ */
44
+ export async function pathExists(filePath: string, nodeishFs: NodeishFilesystem) {
45
+ // from paraglide-js/src/services/file-handling/exists.ts
46
+ // TODO: add fs.exists to @lix-js/fs
47
+ try {
48
+ await nodeishFs.stat(filePath)
49
+ return true
50
+ } catch (error) {
51
+ //@ts-ignore
52
+ if (error.code === "ENOENT") {
53
+ return false
54
+ } else {
55
+ throw new Error(`Failed to check if path exists: ${error}`, { cause: error })
56
+ }
57
+ }
58
+ }
@@ -1,2 +0,0 @@
1
- export declare const isAbsolutePath: (path: string) => boolean;
2
- //# sourceMappingURL=isAbsolutePath.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isAbsolutePath.d.ts","sourceRoot":"","sources":["../src/isAbsolutePath.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,SAAU,MAAM,YAI1C,CAAA"}
@@ -1,4 +0,0 @@
1
- export const isAbsolutePath = (path) => {
2
- const matchPosixAndWindowsAbsolutePaths = /^(?:[A-Za-z]:\\(?:[^\\]+\\)*[^\\]+|[A-Za-z]:\/(?:[^/]+\/)*[^/]+|\/(?:[^/]+\/)*[^/]+)$/;
3
- return matchPosixAndWindowsAbsolutePaths.test(path);
4
- };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=isAbsolutePath.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isAbsolutePath.test.d.ts","sourceRoot":"","sources":["../src/isAbsolutePath.test.ts"],"names":[],"mappings":""}
@@ -1,20 +0,0 @@
1
- import { assert, describe, it } from "vitest";
2
- import { isAbsolutePath } from "./isAbsolutePath.js";
3
- describe("isAbsolutePath", () => {
4
- it("should correctly identify Unix absolute paths", () => {
5
- assert.isTrue(isAbsolutePath("/home/user/documents/file.txt"));
6
- assert.isTrue(isAbsolutePath("/usr/local/bin/script.sh"));
7
- assert.isFalse(isAbsolutePath("relative/path/to/file.txt"));
8
- });
9
- it("should correctly identify Windows absolute paths", () => {
10
- assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt"));
11
- assert.isTrue(isAbsolutePath("C:/Users/user/project.inlang/settings.json"));
12
- assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt"));
13
- });
14
- it("should handle edge cases", () => {
15
- assert.isFalse(isAbsolutePath("")); // Empty path should return false
16
- assert.isFalse(isAbsolutePath("relative/path/../file.txt")); // Relative path with ".." should return false
17
- assert.isFalse(isAbsolutePath("../relative/path/to/file.txt"));
18
- assert.isFalse(isAbsolutePath("./relative/path/to/file.txt"));
19
- });
20
- });
@@ -1,23 +0,0 @@
1
- import { assert, describe, it } from "vitest"
2
- import { isAbsolutePath } from "./isAbsolutePath.js"
3
-
4
- describe("isAbsolutePath", () => {
5
- it("should correctly identify Unix absolute paths", () => {
6
- assert.isTrue(isAbsolutePath("/home/user/documents/file.txt"))
7
- assert.isTrue(isAbsolutePath("/usr/local/bin/script.sh"))
8
- assert.isFalse(isAbsolutePath("relative/path/to/file.txt"))
9
- })
10
-
11
- it("should correctly identify Windows absolute paths", () => {
12
- assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt"))
13
- assert.isTrue(isAbsolutePath("C:/Users/user/project.inlang/settings.json"))
14
- assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt"))
15
- })
16
-
17
- it("should handle edge cases", () => {
18
- assert.isFalse(isAbsolutePath("")) // Empty path should return false
19
- assert.isFalse(isAbsolutePath("relative/path/../file.txt")) // Relative path with ".." should return false
20
- assert.isFalse(isAbsolutePath("../relative/path/to/file.txt"))
21
- assert.isFalse(isAbsolutePath("./relative/path/to/file.txt"))
22
- })
23
- })
@@ -1,5 +0,0 @@
1
- export const isAbsolutePath = (path: string) => {
2
- const matchPosixAndWindowsAbsolutePaths =
3
- /^(?:[A-Za-z]:\\(?:[^\\]+\\)*[^\\]+|[A-Za-z]:\/(?:[^/]+\/)*[^/]+|\/(?:[^/]+\/)*[^/]+)$/
4
- return matchPosixAndWindowsAbsolutePaths.test(path)
5
- }