@inlang/sdk 0.26.5 → 0.27.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 (60) hide show
  1. package/dist/adapter/solidAdapter.test.js +52 -4
  2. package/dist/api.d.ts +3 -0
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/createMessageLintReportsQuery.d.ts +1 -1
  5. package/dist/createMessageLintReportsQuery.d.ts.map +1 -1
  6. package/dist/createMessageLintReportsQuery.js +30 -22
  7. package/dist/createMessagesQuery.d.ts.map +1 -1
  8. package/dist/createMessagesQuery.js +24 -1
  9. package/dist/createMessagesQuery.test.js +46 -2
  10. package/dist/createNodeishFsWithAbsolutePaths.d.ts +3 -3
  11. package/dist/createNodeishFsWithAbsolutePaths.d.ts.map +1 -1
  12. package/dist/createNodeishFsWithAbsolutePaths.js +9 -1
  13. package/dist/createNodeishFsWithAbsolutePaths.test.js +7 -1
  14. package/dist/createNodeishFsWithWatcher.d.ts +3 -3
  15. package/dist/createNodeishFsWithWatcher.d.ts.map +1 -1
  16. package/dist/createNodeishFsWithWatcher.js +3 -0
  17. package/dist/errors.d.ts +14 -0
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js +12 -0
  20. package/dist/loadProject.d.ts.map +1 -1
  21. package/dist/loadProject.js +472 -39
  22. package/dist/loadProject.test.js +91 -14
  23. package/dist/messages/variant.test.js +3 -0
  24. package/dist/resolve-modules/plugins/resolvePlugins.test.js +4 -2
  25. package/dist/storage/helper.d.ts +5 -0
  26. package/dist/storage/helper.d.ts.map +1 -0
  27. package/dist/storage/helper.js +35 -0
  28. package/dist/storage/human-id/human-readable-id.d.ts +3 -0
  29. package/dist/storage/human-id/human-readable-id.d.ts.map +1 -0
  30. package/dist/storage/human-id/human-readable-id.js +20 -0
  31. package/dist/storage/human-id/words.d.ts +5 -0
  32. package/dist/storage/human-id/words.d.ts.map +1 -0
  33. package/dist/storage/human-id/words.js +1032 -0
  34. package/dist/storage/human-id/words.test.d.ts +2 -0
  35. package/dist/storage/human-id/words.test.d.ts.map +1 -0
  36. package/dist/storage/human-id/words.test.js +25 -0
  37. package/dist/test-utilities/createMessage.d.ts +1 -0
  38. package/dist/test-utilities/createMessage.d.ts.map +1 -1
  39. package/dist/test-utilities/createMessage.js +1 -0
  40. package/dist/test-utilities/createMessage.test.js +70 -55
  41. package/package.json +12 -8
  42. package/src/adapter/solidAdapter.test.ts +76 -4
  43. package/src/api.ts +4 -0
  44. package/src/createMessageLintReportsQuery.ts +46 -34
  45. package/src/createMessagesQuery.test.ts +54 -2
  46. package/src/createMessagesQuery.ts +30 -1
  47. package/src/createNodeishFsWithAbsolutePaths.test.ts +10 -3
  48. package/src/createNodeishFsWithAbsolutePaths.ts +14 -5
  49. package/src/createNodeishFsWithWatcher.ts +6 -3
  50. package/src/errors.ts +20 -0
  51. package/src/loadProject.test.ts +106 -14
  52. package/src/loadProject.ts +655 -60
  53. package/src/messages/variant.test.ts +3 -0
  54. package/src/resolve-modules/plugins/resolvePlugins.test.ts +4 -2
  55. package/src/storage/helper.ts +48 -0
  56. package/src/storage/human-id/human-readable-id.ts +27 -0
  57. package/src/storage/human-id/words.test.ts +27 -0
  58. package/src/storage/human-id/words.ts +1035 -0
  59. package/src/test-utilities/createMessage.test.ts +72 -54
  60. package/src/test-utilities/createMessage.ts +1 -0
@@ -1,5 +1,4 @@
1
- import type { NodeishFilesystemSubset } from "@inlang/plugin"
2
- import { normalizePath } from "@lix-js/fs"
1
+ import { normalizePath, type NodeishFilesystem } from "@lix-js/fs"
3
2
  import { isAbsolutePath } from "./isAbsolutePath.js"
4
3
 
5
4
  /**
@@ -10,8 +9,8 @@ import { isAbsolutePath } from "./isAbsolutePath.js"
10
9
  */
11
10
  export const createNodeishFsWithAbsolutePaths = (args: {
12
11
  projectPath: string
13
- nodeishFs: NodeishFilesystemSubset
14
- }): NodeishFilesystemSubset => {
12
+ nodeishFs: NodeishFilesystem
13
+ }): NodeishFilesystem => {
15
14
  if (!isAbsolutePath(args.projectPath)) {
16
15
  throw new Error(`Expected an absolute path but received "${args.projectPath}".`)
17
16
  }
@@ -33,11 +32,21 @@ export const createNodeishFsWithAbsolutePaths = (args: {
33
32
  readFile: (path: string, options: { encoding: "utf-8" | "binary" }) =>
34
33
  args.nodeishFs.readFile(makeAbsolute(path), options),
35
34
  readdir: (path: string) => args.nodeishFs.readdir(makeAbsolute(path)),
36
- mkdir: (path: string) => args.nodeishFs.mkdir(makeAbsolute(path)),
35
+ mkdir: (path: string, options: { recursive: boolean }) =>
36
+ args.nodeishFs.mkdir(makeAbsolute(path), options),
37
37
  writeFile: (path: string, data: string) => args.nodeishFs.writeFile(makeAbsolute(path), data),
38
+ stat: (path: string) => args.nodeishFs.stat(makeAbsolute(path)),
39
+ rm: (path: string) => args.nodeishFs.rm(makeAbsolute(path)),
40
+ rmdir: (path: string) => (args.nodeishFs as any).rmdir(makeAbsolute(path)),
38
41
  watch: (
39
42
  path: string,
40
43
  options: { signal: AbortSignal | undefined; recursive: boolean | undefined }
41
44
  ) => args.nodeishFs.watch(makeAbsolute(path), options),
45
+ // This might be surprising when symlinks were intended to be relative
46
+ symlink: (target: string, path: string) =>
47
+ args.nodeishFs.symlink(makeAbsolute(target), makeAbsolute(path)),
48
+ unlink: (path: string) => args.nodeishFs.unlink(makeAbsolute(path)),
49
+ readlink: (path: string) => args.nodeishFs.readlink(makeAbsolute(path)),
50
+ lstat: (path: string) => args.nodeishFs.lstat(makeAbsolute(path)),
42
51
  }
43
52
  }
@@ -1,4 +1,4 @@
1
- import type { NodeishFilesystemSubset } from "@inlang/plugin"
1
+ import type { NodeishFilesystem } from "@lix-js/fs"
2
2
 
3
3
  /**
4
4
  * Wraps the nodeish filesystem subset with a function that intercepts paths
@@ -7,9 +7,9 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin"
7
7
  * The paths are resolved from the `projectPath` argument.
8
8
  */
9
9
  export const createNodeishFsWithWatcher = (args: {
10
- nodeishFs: NodeishFilesystemSubset
10
+ nodeishFs: NodeishFilesystem
11
11
  updateMessages: () => void
12
- }): NodeishFilesystemSubset => {
12
+ }): NodeishFilesystem => {
13
13
  const pathList: string[] = []
14
14
 
15
15
  const makeWatcher = (path: string) => {
@@ -50,9 +50,12 @@ export const createNodeishFsWithWatcher = (args: {
50
50
  // @ts-expect-error
51
51
  readFile: (path: string, options: { encoding: "utf-8" | "binary" }) =>
52
52
  readFileAndExtractPath(path, options),
53
+ rm: args.nodeishFs.rm,
53
54
  readdir: args.nodeishFs.readdir,
54
55
  mkdir: args.nodeishFs.mkdir,
56
+ rmdir: (args.nodeishFs as any).rmdir,
55
57
  writeFile: args.nodeishFs.writeFile,
56
58
  watch: args.nodeishFs.watch,
59
+ stat: args.nodeishFs.stat,
57
60
  }
58
61
  }
package/src/errors.ts CHANGED
@@ -50,3 +50,23 @@ export class PluginLoadMessagesError extends Error {
50
50
  this.name = "PluginLoadMessagesError"
51
51
  }
52
52
  }
53
+
54
+ export class LoadMessageError extends Error {
55
+ constructor(options: { path: string; messageId: string; cause: ErrorOptions["cause"] }) {
56
+ super(
57
+ `An error occured when loading message ${options.messageId} from path ${options.path} caused by ${options.cause}.`,
58
+ options
59
+ )
60
+ this.name = "LoadMessageError"
61
+ }
62
+ }
63
+
64
+ export class SaveMessageError extends Error {
65
+ constructor(options: { path: string; messageId: string; cause: ErrorOptions["cause"] }) {
66
+ super(
67
+ `An error occured when loading message ${options.messageId} from path ${options.path} caused by ${options.cause}.`,
68
+ options
69
+ )
70
+ this.name = "SaveMessageError"
71
+ }
72
+ }
@@ -65,6 +65,7 @@ const mockPlugin: Plugin = {
65
65
  const exampleMessages: Message[] = [
66
66
  {
67
67
  id: "a",
68
+ alias: {},
68
69
  selectors: [],
69
70
  variants: [
70
71
  {
@@ -81,6 +82,48 @@ const exampleMessages: Message[] = [
81
82
  },
82
83
  {
83
84
  id: "b",
85
+ alias: {},
86
+ selectors: [],
87
+ variants: [
88
+ {
89
+ languageTag: "en",
90
+ match: [],
91
+ pattern: [
92
+ {
93
+ type: "Text",
94
+ value: "test",
95
+ },
96
+ ],
97
+ },
98
+ ],
99
+ },
100
+ ]
101
+
102
+ const exampleAliasedMessages: Message[] = [
103
+ {
104
+ id: "raw_tapir_pause_grateful",
105
+ alias: {
106
+ default: "a",
107
+ },
108
+ selectors: [],
109
+ variants: [
110
+ {
111
+ languageTag: "en",
112
+ match: [],
113
+ pattern: [
114
+ {
115
+ type: "Text",
116
+ value: "test",
117
+ },
118
+ ],
119
+ },
120
+ ],
121
+ },
122
+ {
123
+ id: "dizzy_halibut_dial_vaguely",
124
+ alias: {
125
+ default: "b",
126
+ },
84
127
  selectors: [],
85
128
  variants: [
86
129
  {
@@ -561,7 +604,7 @@ describe("functionality", () => {
561
604
  description: { en: "Mock plugin description" },
562
605
  displayName: { en: "Mock Plugin" },
563
606
 
564
- loadMessages: () => [{ id: "some-message", selectors: [], variants: [] }],
607
+ loadMessages: () => [{ id: "some-message", alias: {}, selectors: [], variants: [] }],
565
608
  saveMessages: () => undefined,
566
609
  }
567
610
  const repo = await mockRepo()
@@ -613,7 +656,7 @@ describe("functionality", () => {
613
656
  description: { en: "Mock plugin description" },
614
657
  displayName: { en: "Mock Plugin" },
615
658
 
616
- loadMessages: () => [{ id: "some-message", selectors: [], variants: [] }],
659
+ loadMessages: () => [{ id: "some-message", alias: {}, selectors: [], variants: [] }],
617
660
  saveMessages: () => undefined,
618
661
  }
619
662
  const repo = await mockRepo()
@@ -698,6 +741,25 @@ describe("functionality", () => {
698
741
  })
699
742
  })
700
743
 
744
+ describe("messages with aliases", () => {
745
+ it("should return the messages", async () => {
746
+ const repo = await mockRepo()
747
+ const fs = repo.nodeishFs
748
+ await fs.mkdir("/user/project.inlang", { recursive: true })
749
+ await fs.writeFile(
750
+ "/user/project.inlang/settings.json",
751
+ JSON.stringify({ ...settings, experimental: { aliases: true } })
752
+ )
753
+ const project = await loadProject({
754
+ projectPath: "/user/project.inlang",
755
+ repo,
756
+ _import,
757
+ })
758
+
759
+ expect(Object.values(project.query.messages.getAll())).toEqual(exampleAliasedMessages)
760
+ })
761
+ })
762
+
701
763
  describe("query", () => {
702
764
  it("should call saveMessages() on updates", async () => {
703
765
  const repo = await mockRepo()
@@ -744,6 +806,7 @@ describe("functionality", () => {
744
806
  where: { id: "a" },
745
807
  data: {
746
808
  id: "a",
809
+ alias: {},
747
810
  selectors: [],
748
811
  variants: [
749
812
  {
@@ -774,6 +837,7 @@ describe("functionality", () => {
774
837
  where: { id: "b" },
775
838
  data: {
776
839
  id: "b",
840
+ alias: {},
777
841
  selectors: [],
778
842
  variants: [
779
843
  {
@@ -800,7 +864,8 @@ describe("functionality", () => {
800
864
  },
801
865
  })
802
866
 
803
- await new Promise((resolve) => setTimeout(resolve, 510))
867
+ // lets wait for the next tick
868
+ await new Promise((resolve) => setTimeout(resolve, 100))
804
869
 
805
870
  expect(mockSaveFn.mock.calls.length).toBe(1)
806
871
 
@@ -809,25 +874,26 @@ describe("functionality", () => {
809
874
  expect(Object.values(mockSaveFn.mock.calls[0][0].messages)).toStrictEqual([
810
875
  {
811
876
  id: "a",
877
+ alias: {},
812
878
  selectors: [],
813
879
  variants: [
814
880
  {
815
- languageTag: "en",
881
+ languageTag: "de",
816
882
  match: [],
817
883
  pattern: [
818
884
  {
819
885
  type: "Text",
820
- value: "a en",
886
+ value: "a de",
821
887
  },
822
888
  ],
823
889
  },
824
890
  {
825
- languageTag: "de",
891
+ languageTag: "en",
826
892
  match: [],
827
893
  pattern: [
828
894
  {
829
895
  type: "Text",
830
- value: "a de",
896
+ value: "a en",
831
897
  },
832
898
  ],
833
899
  },
@@ -835,25 +901,26 @@ describe("functionality", () => {
835
901
  },
836
902
  {
837
903
  id: "b",
904
+ alias: {},
838
905
  selectors: [],
839
906
  variants: [
840
907
  {
841
- languageTag: "en",
908
+ languageTag: "de",
842
909
  match: [],
843
910
  pattern: [
844
911
  {
845
912
  type: "Text",
846
- value: "b en",
913
+ value: "b de",
847
914
  },
848
915
  ],
849
916
  },
850
917
  {
851
- languageTag: "de",
918
+ languageTag: "en",
852
919
  match: [],
853
920
  pattern: [
854
921
  {
855
922
  type: "Text",
856
- value: "b de",
923
+ value: "b en",
857
924
  },
858
925
  ],
859
926
  },
@@ -926,6 +993,20 @@ describe("functionality", () => {
926
993
 
927
994
  expect(mockSaveFn.mock.calls.length).toBe(1)
928
995
  expect(mockSaveFn.mock.calls[0][0].messages).toHaveLength(4)
996
+
997
+ project.query.messages.create({ data: createMessage("fifth", { en: "fifth message" }) })
998
+
999
+ await new Promise((resolve) => setTimeout(resolve, 510))
1000
+
1001
+ expect(mockSaveFn.mock.calls.length).toBe(2)
1002
+ expect(mockSaveFn.mock.calls[1][0].messages).toHaveLength(5)
1003
+
1004
+ project.query.messages.delete({ where: { id: "fourth" } })
1005
+
1006
+ await new Promise((resolve) => setTimeout(resolve, 510))
1007
+
1008
+ expect(mockSaveFn.mock.calls.length).toBe(3)
1009
+ expect(mockSaveFn.mock.calls[2][0].messages).toHaveLength(4)
929
1010
  })
930
1011
  })
931
1012
 
@@ -1040,17 +1121,28 @@ describe("functionality", () => {
1040
1121
  counter = counter + 1
1041
1122
  })
1042
1123
 
1124
+ // subscribe fires once
1043
1125
  expect(counter).toBe(1)
1044
1126
 
1045
- // change file
1127
+ // saving the file without changing should not trigger a message query
1046
1128
  await fs.writeFile("./messages.json", JSON.stringify(messages))
1047
- await new Promise((resolve) => setTimeout(resolve, 0))
1129
+ await new Promise((resolve) => setTimeout(resolve, 200)) // file event will lock a file and be handled sequentially - give it time to pickup the change
1130
+
1131
+ // we didn't change the message we write into message.json - shouldn't change the messages
1132
+ expect(counter).toBe(1)
1133
+
1134
+ // saving the file without changing should trigger a change
1135
+ messages.data[0]!.variants[0]!.pattern[0]!.value = "changed"
1136
+ await fs.writeFile("./messages.json", JSON.stringify(messages))
1137
+ await new Promise((resolve) => setTimeout(resolve, 200)) // file event will lock a file and be handled sequentially - give it time to pickup the change
1048
1138
 
1049
1139
  expect(counter).toBe(2)
1050
1140
 
1141
+ messages.data[0]!.variants[0]!.pattern[0]!.value = "changed3"
1142
+
1051
1143
  // change file
1052
1144
  await fs.writeFile("./messages.json", JSON.stringify(messages))
1053
- await new Promise((resolve) => setTimeout(resolve, 0))
1145
+ await new Promise((resolve) => setTimeout(resolve, 200)) // file event will lock a file and be handled sequentially - give it time to pickup the change
1054
1146
 
1055
1147
  expect(counter).toBe(3)
1056
1148
  })