@inlang/sdk 0.1.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 (170) hide show
  1. package/README.md +25 -0
  2. package/dist/adapter/solidAdapter.d.ts +32 -0
  3. package/dist/adapter/solidAdapter.d.ts.map +1 -0
  4. package/dist/adapter/solidAdapter.js +39 -0
  5. package/dist/adapter/solidAdapter.test.d.ts +2 -0
  6. package/dist/adapter/solidAdapter.test.d.ts.map +1 -0
  7. package/dist/adapter/solidAdapter.test.js +284 -0
  8. package/dist/api.d.ts +88 -0
  9. package/dist/api.d.ts.map +1 -0
  10. package/dist/api.js +1 -0
  11. package/dist/createMessageLintReportsQuery.d.ts +9 -0
  12. package/dist/createMessageLintReportsQuery.d.ts.map +1 -0
  13. package/dist/createMessageLintReportsQuery.js +48 -0
  14. package/dist/createMessagesQuery.d.ts +7 -0
  15. package/dist/createMessagesQuery.d.ts.map +1 -0
  16. package/dist/createMessagesQuery.js +57 -0
  17. package/dist/createMessagesQuery.test.d.ts +2 -0
  18. package/dist/createMessagesQuery.test.d.ts.map +1 -0
  19. package/dist/createMessagesQuery.test.js +304 -0
  20. package/dist/errors.d.ts +22 -0
  21. package/dist/errors.d.ts.map +1 -0
  22. package/dist/errors.js +39 -0
  23. package/dist/index.d.ts +15 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +13 -0
  26. package/dist/lint/index.d.ts +3 -0
  27. package/dist/lint/index.d.ts.map +1 -0
  28. package/dist/lint/index.js +2 -0
  29. package/dist/lint/message/errors.d.ts +7 -0
  30. package/dist/lint/message/errors.d.ts.map +1 -0
  31. package/dist/lint/message/errors.js +9 -0
  32. package/dist/lint/message/lintMessages.d.ts +17 -0
  33. package/dist/lint/message/lintMessages.d.ts.map +1 -0
  34. package/dist/lint/message/lintMessages.js +12 -0
  35. package/dist/lint/message/lintMessages.test.d.ts +2 -0
  36. package/dist/lint/message/lintMessages.test.d.ts.map +1 -0
  37. package/dist/lint/message/lintMessages.test.js +105 -0
  38. package/dist/lint/message/lintSingleMessage.d.ts +23 -0
  39. package/dist/lint/message/lintSingleMessage.d.ts.map +1 -0
  40. package/dist/lint/message/lintSingleMessage.js +36 -0
  41. package/dist/lint/message/lintSingleMessage.test.d.ts +2 -0
  42. package/dist/lint/message/lintSingleMessage.test.d.ts.map +1 -0
  43. package/dist/lint/message/lintSingleMessage.test.js +155 -0
  44. package/dist/messages/errors.d.ts +13 -0
  45. package/dist/messages/errors.d.ts.map +1 -0
  46. package/dist/messages/errors.js +18 -0
  47. package/dist/messages/index.d.ts +3 -0
  48. package/dist/messages/index.d.ts.map +1 -0
  49. package/dist/messages/index.js +2 -0
  50. package/dist/messages/variant.d.ts +46 -0
  51. package/dist/messages/variant.d.ts.map +1 -0
  52. package/dist/messages/variant.js +177 -0
  53. package/dist/messages/variant.test.d.ts +2 -0
  54. package/dist/messages/variant.test.d.ts.map +1 -0
  55. package/dist/messages/variant.test.js +379 -0
  56. package/dist/openInlangProject.d.ts +18 -0
  57. package/dist/openInlangProject.d.ts.map +1 -0
  58. package/dist/openInlangProject.js +226 -0
  59. package/dist/openInlangProject.test.d.ts +2 -0
  60. package/dist/openInlangProject.test.d.ts.map +1 -0
  61. package/dist/openInlangProject.test.js +627 -0
  62. package/dist/parseConfig.d.ts +8 -0
  63. package/dist/parseConfig.d.ts.map +1 -0
  64. package/dist/parseConfig.js +26 -0
  65. package/dist/reactivity/map.d.ts +66 -0
  66. package/dist/reactivity/map.d.ts.map +1 -0
  67. package/dist/reactivity/map.js +143 -0
  68. package/dist/reactivity/solid.d.ts +12 -0
  69. package/dist/reactivity/solid.d.ts.map +1 -0
  70. package/dist/reactivity/solid.js +13 -0
  71. package/dist/reactivity/trigger.d.ts +11 -0
  72. package/dist/reactivity/trigger.d.ts.map +1 -0
  73. package/dist/reactivity/trigger.js +46 -0
  74. package/dist/resolve-modules/errors.d.ts +34 -0
  75. package/dist/resolve-modules/errors.d.ts.map +1 -0
  76. package/dist/resolve-modules/errors.js +35 -0
  77. package/dist/resolve-modules/import.d.ts +35 -0
  78. package/dist/resolve-modules/import.d.ts.map +1 -0
  79. package/dist/resolve-modules/import.js +40 -0
  80. package/dist/resolve-modules/import.test.d.ts +2 -0
  81. package/dist/resolve-modules/import.test.d.ts.map +1 -0
  82. package/dist/resolve-modules/import.test.js +45 -0
  83. package/dist/resolve-modules/index.d.ts +3 -0
  84. package/dist/resolve-modules/index.d.ts.map +1 -0
  85. package/dist/resolve-modules/index.js +2 -0
  86. package/dist/resolve-modules/message-lint-rules/errors.d.ts +8 -0
  87. package/dist/resolve-modules/message-lint-rules/errors.d.ts.map +1 -0
  88. package/dist/resolve-modules/message-lint-rules/errors.js +8 -0
  89. package/dist/resolve-modules/message-lint-rules/resolveMessageLintRules.d.ts +9 -0
  90. package/dist/resolve-modules/message-lint-rules/resolveMessageLintRules.d.ts.map +1 -0
  91. package/dist/resolve-modules/message-lint-rules/resolveMessageLintRules.js +21 -0
  92. package/dist/resolve-modules/plugins/errors.d.ts +28 -0
  93. package/dist/resolve-modules/plugins/errors.d.ts.map +1 -0
  94. package/dist/resolve-modules/plugins/errors.js +44 -0
  95. package/dist/resolve-modules/plugins/resolvePlugins.d.ts +3 -0
  96. package/dist/resolve-modules/plugins/resolvePlugins.d.ts.map +1 -0
  97. package/dist/resolve-modules/plugins/resolvePlugins.js +108 -0
  98. package/dist/resolve-modules/plugins/resolvePlugins.test.d.ts +2 -0
  99. package/dist/resolve-modules/plugins/resolvePlugins.test.d.ts.map +1 -0
  100. package/dist/resolve-modules/plugins/resolvePlugins.test.js +289 -0
  101. package/dist/resolve-modules/plugins/types.d.ts +60 -0
  102. package/dist/resolve-modules/plugins/types.d.ts.map +1 -0
  103. package/dist/resolve-modules/plugins/types.js +1 -0
  104. package/dist/resolve-modules/plugins/types.test.d.ts +2 -0
  105. package/dist/resolve-modules/plugins/types.test.d.ts.map +1 -0
  106. package/dist/resolve-modules/plugins/types.test.js +49 -0
  107. package/dist/resolve-modules/resolveModules.d.ts +3 -0
  108. package/dist/resolve-modules/resolveModules.d.ts.map +1 -0
  109. package/dist/resolve-modules/resolveModules.js +70 -0
  110. package/dist/resolve-modules/resolveModules.test.d.ts +2 -0
  111. package/dist/resolve-modules/resolveModules.test.d.ts.map +1 -0
  112. package/dist/resolve-modules/resolveModules.test.js +143 -0
  113. package/dist/resolve-modules/types.d.ts +62 -0
  114. package/dist/resolve-modules/types.d.ts.map +1 -0
  115. package/dist/resolve-modules/types.js +1 -0
  116. package/dist/test-utilities/createMessage.d.ts +17 -0
  117. package/dist/test-utilities/createMessage.d.ts.map +1 -0
  118. package/dist/test-utilities/createMessage.js +16 -0
  119. package/dist/test-utilities/createMessage.test.d.ts +2 -0
  120. package/dist/test-utilities/createMessage.test.d.ts.map +1 -0
  121. package/dist/test-utilities/createMessage.test.js +91 -0
  122. package/dist/test-utilities/index.d.ts +2 -0
  123. package/dist/test-utilities/index.d.ts.map +1 -0
  124. package/dist/test-utilities/index.js +1 -0
  125. package/dist/versionedInterfaces.d.ts +8 -0
  126. package/dist/versionedInterfaces.d.ts.map +1 -0
  127. package/dist/versionedInterfaces.js +8 -0
  128. package/package.json +58 -0
  129. package/src/adapter/solidAdapter.test.ts +363 -0
  130. package/src/adapter/solidAdapter.ts +77 -0
  131. package/src/api.ts +86 -0
  132. package/src/createMessageLintReportsQuery.ts +77 -0
  133. package/src/createMessagesQuery.test.ts +435 -0
  134. package/src/createMessagesQuery.ts +64 -0
  135. package/src/errors.ts +46 -0
  136. package/src/index.ts +29 -0
  137. package/src/lint/index.ts +2 -0
  138. package/src/lint/message/errors.ts +9 -0
  139. package/src/lint/message/lintMessages.test.ts +122 -0
  140. package/src/lint/message/lintMessages.ts +33 -0
  141. package/src/lint/message/lintSingleMessage.test.ts +183 -0
  142. package/src/lint/message/lintSingleMessage.ts +62 -0
  143. package/src/messages/errors.ts +25 -0
  144. package/src/messages/index.ts +2 -0
  145. package/src/messages/variant.test.ts +444 -0
  146. package/src/messages/variant.ts +242 -0
  147. package/src/openInlangProject.test.ts +734 -0
  148. package/src/openInlangProject.ts +337 -0
  149. package/src/parseConfig.ts +33 -0
  150. package/src/reactivity/map.ts +135 -0
  151. package/src/reactivity/solid.ts +36 -0
  152. package/src/reactivity/trigger.ts +46 -0
  153. package/src/resolve-modules/errors.ts +39 -0
  154. package/src/resolve-modules/import.test.ts +58 -0
  155. package/src/resolve-modules/import.ts +69 -0
  156. package/src/resolve-modules/index.ts +2 -0
  157. package/src/resolve-modules/message-lint-rules/errors.ts +9 -0
  158. package/src/resolve-modules/message-lint-rules/resolveMessageLintRules.ts +24 -0
  159. package/src/resolve-modules/plugins/errors.ts +57 -0
  160. package/src/resolve-modules/plugins/resolvePlugins.test.ts +340 -0
  161. package/src/resolve-modules/plugins/resolvePlugins.ts +170 -0
  162. package/src/resolve-modules/plugins/types.test.ts +57 -0
  163. package/src/resolve-modules/plugins/types.ts +77 -0
  164. package/src/resolve-modules/resolveModules.test.ts +176 -0
  165. package/src/resolve-modules/resolveModules.ts +97 -0
  166. package/src/resolve-modules/types.ts +71 -0
  167. package/src/test-utilities/createMessage.test.ts +100 -0
  168. package/src/test-utilities/createMessage.ts +20 -0
  169. package/src/test-utilities/index.ts +1 -0
  170. package/src/versionedInterfaces.ts +9 -0
@@ -0,0 +1,363 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+ import { describe, it, expect } from "vitest"
3
+ import type { ImportFunction } from "../resolve-modules/index.js"
4
+ import { createEffect, from, createRoot } from "../reactivity/solid.js"
5
+ import { solidAdapter } from "./solidAdapter.js"
6
+ import { openInlangProject } from "../openInlangProject.js"
7
+ import { createNodeishMemoryFs } from "@lix-js/fs"
8
+ import type {
9
+ Message,
10
+ ProjectConfig,
11
+ Plugin,
12
+ MessageLintRule,
13
+ Text,
14
+ } from "../versionedInterfaces.js"
15
+
16
+ // ------------------------------------------------------------------------------------------------
17
+
18
+ const config: ProjectConfig = {
19
+ sourceLanguageTag: "en",
20
+ languageTags: ["en"],
21
+ modules: ["plugin.js", "plugin2.js"],
22
+ settings: {
23
+ "project.messageLintRuleLevels": {
24
+ "messageLintRule.inlang.missingTranslation": "error",
25
+ },
26
+ "plugin.inlang.i18next": {
27
+ pathPattern: "./examples/example01/{languageTag}.json",
28
+ variableReferencePattern: ["{", "}"],
29
+ },
30
+ },
31
+ }
32
+
33
+ const mockPlugin: Plugin = {
34
+ meta: {
35
+ id: "plugin.inlang.i18next",
36
+ description: { en: "Mock plugin description" },
37
+ displayName: { en: "Mock Plugin" },
38
+ },
39
+ loadMessages: () => exampleMessages,
40
+ saveMessages: () => undefined,
41
+ }
42
+
43
+ // TODO: use `createMessage` utility
44
+ const exampleMessages: Message[] = [
45
+ {
46
+ id: "a",
47
+ selectors: [],
48
+ variants: [
49
+ {
50
+ languageTag: "en",
51
+ match: {},
52
+ pattern: [
53
+ {
54
+ type: "Text",
55
+ value: "test",
56
+ },
57
+ ],
58
+ },
59
+ ],
60
+ },
61
+ {
62
+ id: "b",
63
+ selectors: [],
64
+ variants: [
65
+ {
66
+ languageTag: "en",
67
+ match: {},
68
+ pattern: [
69
+ {
70
+ type: "Text",
71
+ value: "test",
72
+ },
73
+ ],
74
+ },
75
+ ],
76
+ },
77
+ ]
78
+
79
+ const mockLintRule: MessageLintRule = {
80
+ meta: {
81
+ id: "messageLintRule.namespace.mock",
82
+ description: { en: "Mock lint rule description" },
83
+ displayName: { en: "Mock Lint Rule" },
84
+ },
85
+ message: () => undefined,
86
+ }
87
+
88
+ const $import: ImportFunction = async (name) => ({
89
+ default: name === "plugin.js" ? mockPlugin : mockLintRule,
90
+ })
91
+
92
+ // ------------------------------------------------------------------------------------------------
93
+
94
+ describe("config", () => {
95
+ it("should react to changes in config", async () => {
96
+ const fs = createNodeishMemoryFs()
97
+ await fs.writeFile("./project.inlang.json", JSON.stringify(config))
98
+ const inlang = solidAdapter(
99
+ await openInlangProject({
100
+ projectFilePath: "./project.inlang.json",
101
+ nodeishFs: fs,
102
+ _import: $import,
103
+ }),
104
+ { from },
105
+ )
106
+
107
+ let counter = 0
108
+ createEffect(() => {
109
+ inlang.config()
110
+ counter += 1
111
+ })
112
+
113
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
114
+ const newConfig = { ...inlang.config()!, languageTags: ["en", "de"] }
115
+
116
+ inlang.setConfig(newConfig)
117
+ // TODO: how can we await `setConfig` correctly
118
+ await new Promise((resolve) => setTimeout(resolve, 0))
119
+ expect(counter).toBe(2) // 2 times because effect creation + set
120
+ expect(inlang.config()).toStrictEqual(newConfig)
121
+ })
122
+ })
123
+
124
+ describe("installed", () => {
125
+ it("react to changes that are unrelated to installed items", async () => {
126
+ const fs = createNodeishMemoryFs()
127
+ await fs.writeFile("./project.inlang.json", JSON.stringify(config))
128
+ const inlang = solidAdapter(
129
+ await openInlangProject({
130
+ projectFilePath: "./project.inlang.json",
131
+ nodeishFs: fs,
132
+ _import: $import,
133
+ }),
134
+ { from },
135
+ )
136
+ let counterPlugins = 0
137
+ let counterLint = 0
138
+
139
+ createEffect(() => {
140
+ inlang.installed.plugins()
141
+ counterPlugins += 1
142
+ })
143
+
144
+ createEffect(() => {
145
+ inlang.installed.messageLintRules()
146
+ counterLint += 1
147
+ })
148
+
149
+ inlang.setConfig({ ...inlang.config()!, languageTags: ["en", "fr"] })
150
+
151
+ // TODO: how can we await `setConfig` correctly
152
+ await new Promise((resolve) => setTimeout(resolve, 0))
153
+
154
+ expect(counterPlugins).toBe(2) // 2 times because effect creation + set
155
+ expect(counterLint).toBe(2) // 2 times because effect creation + set
156
+ })
157
+ })
158
+
159
+ describe("messages", () => {
160
+ it("should react to changes in config", async () => {
161
+ const fs = createNodeishMemoryFs()
162
+ const mockConfig: ProjectConfig = {
163
+ sourceLanguageTag: "en",
164
+ languageTags: ["en", "de"],
165
+ modules: ["./plugin-a.js"],
166
+ settings: {
167
+ "library.inlang.paraglideJsSveltekit": {
168
+ languageNegotiation: {
169
+ strategies: [
170
+ {
171
+ type: "localStorage",
172
+ } as any,
173
+ ],
174
+ },
175
+ },
176
+ },
177
+ }
178
+ const mockPlugin: Plugin = {
179
+ meta: {
180
+ id: "plugin.mock.id",
181
+ displayName: {
182
+ en: "hello",
183
+ },
184
+ description: {
185
+ en: "wo",
186
+ },
187
+ },
188
+ loadMessages: ({ languageTags }) => (languageTags.length ? exampleMessages : []),
189
+ saveMessages: () => undefined,
190
+ }
191
+
192
+ const mockImport: ImportFunction = async () => ({ default: mockPlugin })
193
+
194
+ await fs.writeFile("./project.inlang.json", JSON.stringify(mockConfig))
195
+ const inlang = solidAdapter(
196
+ await openInlangProject({
197
+ projectFilePath: "./project.inlang.json",
198
+ nodeishFs: fs,
199
+ _import: mockImport,
200
+ }),
201
+ { from },
202
+ )
203
+
204
+ let counter = 0
205
+ createEffect(() => {
206
+ inlang.query.messages.getAll()
207
+ counter += 1
208
+ })
209
+
210
+ expect(Object.values(inlang.query.messages.getAll()).length).toBe(2)
211
+
212
+ inlang.setConfig({ ...inlang.config()!, languageTags: [] })
213
+
214
+ // TODO: how can we await `setConfig` correctly
215
+ await new Promise((resolve) => setTimeout(resolve, 0))
216
+
217
+ expect(counter).toBe(2) // 2 times because effect creation + set
218
+ expect(Object.values(inlang.query.messages.getAll()).length).toBe(0)
219
+ })
220
+
221
+ it("should react to changes in messages", async () => {
222
+ const fs = createNodeishMemoryFs()
223
+ await fs.writeFile("./project.inlang.json", JSON.stringify(config))
224
+ const inlang = solidAdapter(
225
+ await openInlangProject({
226
+ projectFilePath: "./project.inlang.json",
227
+ nodeishFs: fs,
228
+ _import: $import,
229
+ }),
230
+ { from },
231
+ )
232
+
233
+ let counter = 0
234
+ createEffect(() => {
235
+ inlang.query.messages.getAll()
236
+ counter += 1
237
+ })
238
+
239
+ const messagesBefore = inlang.query.messages.getAll
240
+ expect(Object.values(messagesBefore()).length).toBe(2)
241
+ expect(
242
+ (
243
+ Object.values(messagesBefore())[0]?.variants.find((variant) => variant.languageTag === "en")
244
+ ?.pattern[0] as Text
245
+ ).value,
246
+ ).toBe("test")
247
+
248
+ inlang.query.messages.update({
249
+ where: { id: "a" },
250
+ // TODO: use `createMessage` utility
251
+ data: {
252
+ ...exampleMessages[0],
253
+ variants: [
254
+ {
255
+ languageTag: "en",
256
+ match: {},
257
+ pattern: [
258
+ {
259
+ type: "Text",
260
+ value: "test2",
261
+ },
262
+ ],
263
+ },
264
+ ],
265
+ },
266
+ })
267
+
268
+ expect(counter).toBe(2) // 2 times because effect creation + set
269
+ const messagesAfter = inlang.query.messages.getAll
270
+ expect(Object.values(messagesAfter()).length).toBe(2)
271
+ expect(
272
+ (
273
+ Object.values(messagesAfter())[0]?.variants.find((variant) => variant.languageTag === "en")
274
+ ?.pattern[0] as Text
275
+ ).value,
276
+ ).toBe("test2")
277
+ })
278
+ })
279
+
280
+ describe("lint", () => {
281
+ it.todo("should react to changes in config", async () => {
282
+ await createRoot(async () => {
283
+ const fs = createNodeishMemoryFs()
284
+ await fs.writeFile("./inlang.config.json", JSON.stringify(config))
285
+ const inlang = solidAdapter(
286
+ await openInlangProject({
287
+ projectFilePath: "./inlang.config.json",
288
+ nodeishFs: fs,
289
+ _import: $import,
290
+ }),
291
+ { from },
292
+ )
293
+
294
+ let counter = 0
295
+ createEffect(() => {
296
+ inlang.query.messageLintReports.getAll()
297
+ counter += 1
298
+ })
299
+
300
+ const newConfig = { ...inlang.config()!, languageTags: ["en", "de"] }
301
+ inlang.setConfig(newConfig)
302
+
303
+ expect(counter).toBe(1)
304
+ expect(inlang.query.messageLintReports.getAll()).toEqual([])
305
+
306
+ await new Promise((resolve) => setTimeout(resolve, 510))
307
+
308
+ const newConfig2 = { ...inlang.config()!, languageTags: ["en", "de", "fr"] }
309
+ inlang.setConfig(newConfig2)
310
+
311
+ expect(counter).toBe(9)
312
+ expect(inlang.query.messageLintReports.getAll()).toEqual([])
313
+ })
314
+ })
315
+
316
+ it.todo("should react to changes to packages")
317
+ it.todo("should react to changes to modules")
318
+
319
+ it.todo("should react to changes to messages", async () => {
320
+ await createRoot(async () => {
321
+ const fs = createNodeishMemoryFs()
322
+ await fs.writeFile("./inlang.config.json", JSON.stringify(config))
323
+ const inlang = solidAdapter(
324
+ await openInlangProject({
325
+ projectFilePath: "./inlang.config.json",
326
+ nodeishFs: fs,
327
+ _import: $import,
328
+ }),
329
+ { from },
330
+ )
331
+
332
+ let counter = 0
333
+ createEffect(() => {
334
+ inlang.query.messageLintReports.getAll()
335
+ counter += 1
336
+ })
337
+
338
+ inlang.query.messages.update({
339
+ where: { id: "a" },
340
+ data: {
341
+ ...exampleMessages[0],
342
+ variants: [{ languageTag: "en", match: {}, pattern: [{ type: "Text", value: "new" }] }],
343
+ },
344
+ })
345
+
346
+ expect(counter).toBe(1)
347
+ expect(inlang.query.messageLintReports.getAll()).toEqual([])
348
+
349
+ await new Promise((resolve) => setTimeout(resolve, 510))
350
+
351
+ inlang.query.messages.update({
352
+ where: { id: "a" },
353
+ data: {
354
+ ...exampleMessages[0],
355
+ variants: [{ languageTag: "en", match: {}, pattern: [{ type: "Text", value: "new" }] }],
356
+ },
357
+ })
358
+
359
+ expect(counter).toBe(6)
360
+ expect(inlang.query.messageLintReports.getAll()).toEqual([])
361
+ })
362
+ })
363
+ })
@@ -0,0 +1,77 @@
1
+ import type { InlangProject, MessageLintReportsQueryApi } from "../api.js"
2
+ import { observable, type from as solidFrom } from "../reactivity/solid.js"
3
+ import type { MessageQueryApi } from "@inlang/sdk"
4
+
5
+ export const solidAdapter = (
6
+ project: InlangProject,
7
+ arg: {
8
+ from: typeof solidFrom
9
+ },
10
+ ): InlangProjectWithSolidAdapter => {
11
+ const convert = <T>(signal: () => T): (() => T) => {
12
+ return arg.from(observable(signal)) as () => T
13
+ }
14
+
15
+ return {
16
+ customApi: convert(project.customApi),
17
+ config: convert(project.config),
18
+ errors: convert(project.errors),
19
+ installed: {
20
+ messageLintRules: convert(project.installed.messageLintRules),
21
+ plugins: convert(project.installed.plugins),
22
+ },
23
+ setConfig: project.setConfig,
24
+ query: {
25
+ messages: {
26
+ create: project.query.messages.create,
27
+ update: project.query.messages.update,
28
+ delete: project.query.messages.delete,
29
+ upsert: project.query.messages.upsert,
30
+ get: project.query.messages.get,
31
+ // get: (args) => {
32
+ // const [message, setMessage] = createSignal<Message | undefined>()
33
+ // project.query.messages.get.subscribe(args, setMessage)
34
+ // return message()
35
+ // },
36
+ getAll: convert(project.query.messages.getAll),
37
+ includedMessageIds: convert(project.query.messages.includedMessageIds),
38
+ },
39
+ messageLintReports: {
40
+ get: project.query.messageLintReports.get,
41
+ getAll: convert(project.query.messageLintReports.getAll),
42
+ },
43
+ },
44
+ } satisfies InlangProjectWithSolidAdapter
45
+ }
46
+
47
+ export type InlangProjectWithSolidAdapter = {
48
+ customApi: () => ReturnType<InlangProject["customApi"]>
49
+ installed: {
50
+ plugins: () => ReturnType<InlangProject["installed"]["plugins"]>
51
+ messageLintRules: () => ReturnType<InlangProject["installed"]["messageLintRules"]>
52
+ }
53
+ errors: () => ReturnType<InlangProject["errors"]>
54
+ config: () => ReturnType<InlangProject["config"]>
55
+ setConfig: InlangProject["setConfig"]
56
+ query: {
57
+ messages: {
58
+ create: MessageQueryApi["create"]
59
+ update: MessageQueryApi["update"]
60
+ delete: MessageQueryApi["delete"]
61
+ upsert: MessageQueryApi["upsert"]
62
+ get: MessageQueryApi["get"]
63
+ //get: (args: Parameters<MessageQueryApi["get"]>[0]) => ReturnType<MessageQueryApi["get"]>
64
+ getAll: () => ReturnType<MessageQueryApi["getAll"]>
65
+ includedMessageIds: () => ReturnType<MessageQueryApi["includedMessageIds"]>
66
+ }
67
+ messageLintReports: {
68
+ get: MessageLintReportsQueryApi["get"]
69
+ getAll: () => ReturnType<MessageLintReportsQueryApi["getAll"]>
70
+ }
71
+ }
72
+ }
73
+
74
+ // const x = {} as InlangProjectWithSolidAdapter
75
+ // x.query.lintReports.getAll()
76
+
77
+ // console.log(await x.lint())
package/src/api.ts ADDED
@@ -0,0 +1,86 @@
1
+ import type { Result } from "@inlang/result"
2
+ import type * as RuntimeError from "./errors.js"
3
+ import type * as ModuleResolutionError from "./resolve-modules/errors.js"
4
+ import type {
5
+ MessageLintLevel,
6
+ MessageLintRule,
7
+ Message,
8
+ Plugin,
9
+ ProjectConfig,
10
+ MessageLintReport,
11
+ } from "./versionedInterfaces.js"
12
+ import type { ResolvedPluginApi } from "./resolve-modules/plugins/types.js"
13
+
14
+ export type InstalledPlugin = {
15
+ meta: Plugin["meta"]
16
+ /**
17
+ * The module which the plugin is installed from.
18
+ */
19
+ module: string
20
+ // disabled: boolean
21
+ }
22
+
23
+ export type InstalledMessageLintRule = {
24
+ meta: MessageLintRule["meta"]
25
+ /**
26
+ * The module which the lint rule is installed from.
27
+ */
28
+ module: string
29
+ lintLevel: MessageLintLevel
30
+ }
31
+
32
+ export type InlangProject = {
33
+ installed: {
34
+ plugins: Subscribable<InstalledPlugin[]>
35
+ messageLintRules: Subscribable<InstalledMessageLintRule[]>
36
+ }
37
+ errors: Subscribable<
38
+ ((typeof ModuleResolutionError)[keyof typeof ModuleResolutionError] | Error)[]
39
+ >
40
+ customApi: Subscribable<ResolvedPluginApi["customApi"]>
41
+ config: Subscribable<ProjectConfig | undefined>
42
+ setConfig: (config: ProjectConfig) => Result<void, RuntimeError.InvalidConfigError>
43
+ query: {
44
+ messages: MessageQueryApi
45
+ messageLintReports: MessageLintReportsQueryApi
46
+ }
47
+ }
48
+
49
+ // const x = {} as InlangProject
50
+ // const l = await x.lint()
51
+ // x.lint.subscribe((m) => console.log(m))
52
+
53
+ export type Subscribable<Value> = {
54
+ (): Value
55
+ subscribe: (callback: (value: Value) => void) => void
56
+ }
57
+
58
+ export type MessageQueryApi = {
59
+ create: (args: { data: Message }) => boolean
60
+ get: ((args: { where: { id: Message["id"] } }) => Readonly<Message>) & {
61
+ subscribe: (
62
+ args: { where: { id: Message["id"] } },
63
+ callback: (message: Message) => void,
64
+ ) => void
65
+ }
66
+ includedMessageIds: Subscribable<Message["id"][]>
67
+ /*
68
+ * getAll is depricated do not use it
69
+ */
70
+ getAll: Subscribable<Readonly<Message[]>>
71
+ update: (args: { where: { id: Message["id"] }; data: Partial<Message> }) => boolean
72
+ upsert: (args: { where: { id: Message["id"] }; data: Message }) => void
73
+ delete: (args: { where: { id: Message["id"] } }) => boolean
74
+ }
75
+
76
+ export type MessageLintReportsQueryApi = {
77
+ getAll: Subscribable<MessageLintReport[]>
78
+ get: ((args: {
79
+ where: { messageId: MessageLintReport["messageId"] }
80
+ }) => Readonly<MessageLintReport[]>) & {
81
+ subscribe: (
82
+ args: { where: { messageId: MessageLintReport["messageId"] } },
83
+ callback: (MessageLintRules: Readonly<MessageLintReport[]>) => void,
84
+ ) => void
85
+ }
86
+ }
@@ -0,0 +1,77 @@
1
+ import { createEffect } from "./reactivity/solid.js"
2
+ import { createSubscribable } from "./openInlangProject.js"
3
+ import type { InlangProject, InstalledMessageLintRule, MessageLintReportsQueryApi } from "./api.js"
4
+ import type { ProjectConfig } from "@inlang/project-config"
5
+ import type { resolveModules } from "./resolve-modules/index.js"
6
+ import type {
7
+ JSONObject,
8
+ MessageLintReport,
9
+ MessageLintRule,
10
+ Message,
11
+ } from "./versionedInterfaces.js"
12
+ import { lintSingleMessage } from "./lint/index.js"
13
+ import { ReactiveMap } from "./reactivity/map.js"
14
+
15
+ /**
16
+ * Creates a reactive query API for messages.
17
+ */
18
+ export function createMessageLintReportsQuery(
19
+ messages: () => Array<Message> | undefined,
20
+ config: () => ProjectConfig | undefined,
21
+ installedMessageLintRules: () => Array<InstalledMessageLintRule>,
22
+ resolvedModules: () => Awaited<ReturnType<typeof resolveModules>> | undefined,
23
+ ): InlangProject["query"]["messageLintReports"] {
24
+ // @ts-expect-error
25
+ const index = new ReactiveMap<MessageLintReport["messageId"], MessageLintReport[]>()
26
+
27
+ createEffect(() => {
28
+ const msgs = messages()
29
+ const conf = config()
30
+ const modules = resolvedModules()
31
+
32
+ if (msgs && conf && modules) {
33
+ // console.log("new calculation")
34
+ // index.clear()
35
+ for (const message of msgs) {
36
+ // TODO: only lint changed messages and update arrays selectively
37
+
38
+ lintSingleMessage({
39
+ rules: modules.messageLintRules,
40
+ ruleSettings: conf.settings as Record<MessageLintRule["meta"]["id"], JSONObject>,
41
+ ruleLevels: Object.fromEntries(
42
+ installedMessageLintRules().map((rule) => [rule.meta.id, rule.lintLevel]),
43
+ ),
44
+ sourceLanguageTag: conf.sourceLanguageTag,
45
+ languageTags: conf.languageTags,
46
+ messages: msgs,
47
+ message: message,
48
+ }).then((report) => {
49
+ if (
50
+ report.errors.length === 0 &&
51
+ JSON.stringify(index.get(message.id)) !== JSON.stringify(report.data)
52
+ ) {
53
+ index.set(message.id, report.data || [])
54
+ }
55
+ })
56
+ }
57
+ }
58
+ })
59
+
60
+ const get = (args: Parameters<MessageLintReportsQueryApi["get"]>[0]) => {
61
+ return structuredClone(index.get(args.where.messageId))
62
+ }
63
+
64
+ return {
65
+ getAll: createSubscribable(() => {
66
+ return structuredClone(
67
+ [...index.values()].flat().length === 0 ? [] : [...index.values()].flat(),
68
+ )
69
+ }),
70
+ get: Object.assign(get, {
71
+ subscribe: (
72
+ args: Parameters<MessageLintReportsQueryApi["get"]["subscribe"]>[0],
73
+ callback: Parameters<MessageLintReportsQueryApi["get"]["subscribe"]>[1],
74
+ ) => createSubscribable(() => get(args)).subscribe(callback),
75
+ }) as any,
76
+ }
77
+ }