@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.
- package/README.md +25 -0
- package/dist/adapter/solidAdapter.d.ts +32 -0
- package/dist/adapter/solidAdapter.d.ts.map +1 -0
- package/dist/adapter/solidAdapter.js +39 -0
- package/dist/adapter/solidAdapter.test.d.ts +2 -0
- package/dist/adapter/solidAdapter.test.d.ts.map +1 -0
- package/dist/adapter/solidAdapter.test.js +284 -0
- package/dist/api.d.ts +88 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +1 -0
- package/dist/createMessageLintReportsQuery.d.ts +9 -0
- package/dist/createMessageLintReportsQuery.d.ts.map +1 -0
- package/dist/createMessageLintReportsQuery.js +48 -0
- package/dist/createMessagesQuery.d.ts +7 -0
- package/dist/createMessagesQuery.d.ts.map +1 -0
- package/dist/createMessagesQuery.js +57 -0
- package/dist/createMessagesQuery.test.d.ts +2 -0
- package/dist/createMessagesQuery.test.d.ts.map +1 -0
- package/dist/createMessagesQuery.test.js +304 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/lint/index.d.ts +3 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +2 -0
- package/dist/lint/message/errors.d.ts +7 -0
- package/dist/lint/message/errors.d.ts.map +1 -0
- package/dist/lint/message/errors.js +9 -0
- package/dist/lint/message/lintMessages.d.ts +17 -0
- package/dist/lint/message/lintMessages.d.ts.map +1 -0
- package/dist/lint/message/lintMessages.js +12 -0
- package/dist/lint/message/lintMessages.test.d.ts +2 -0
- package/dist/lint/message/lintMessages.test.d.ts.map +1 -0
- package/dist/lint/message/lintMessages.test.js +105 -0
- package/dist/lint/message/lintSingleMessage.d.ts +23 -0
- package/dist/lint/message/lintSingleMessage.d.ts.map +1 -0
- package/dist/lint/message/lintSingleMessage.js +36 -0
- package/dist/lint/message/lintSingleMessage.test.d.ts +2 -0
- package/dist/lint/message/lintSingleMessage.test.d.ts.map +1 -0
- package/dist/lint/message/lintSingleMessage.test.js +155 -0
- package/dist/messages/errors.d.ts +13 -0
- package/dist/messages/errors.d.ts.map +1 -0
- package/dist/messages/errors.js +18 -0
- package/dist/messages/index.d.ts +3 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +2 -0
- package/dist/messages/variant.d.ts +46 -0
- package/dist/messages/variant.d.ts.map +1 -0
- package/dist/messages/variant.js +177 -0
- package/dist/messages/variant.test.d.ts +2 -0
- package/dist/messages/variant.test.d.ts.map +1 -0
- package/dist/messages/variant.test.js +379 -0
- package/dist/openInlangProject.d.ts +18 -0
- package/dist/openInlangProject.d.ts.map +1 -0
- package/dist/openInlangProject.js +226 -0
- package/dist/openInlangProject.test.d.ts +2 -0
- package/dist/openInlangProject.test.d.ts.map +1 -0
- package/dist/openInlangProject.test.js +627 -0
- package/dist/parseConfig.d.ts +8 -0
- package/dist/parseConfig.d.ts.map +1 -0
- package/dist/parseConfig.js +26 -0
- package/dist/reactivity/map.d.ts +66 -0
- package/dist/reactivity/map.d.ts.map +1 -0
- package/dist/reactivity/map.js +143 -0
- package/dist/reactivity/solid.d.ts +12 -0
- package/dist/reactivity/solid.d.ts.map +1 -0
- package/dist/reactivity/solid.js +13 -0
- package/dist/reactivity/trigger.d.ts +11 -0
- package/dist/reactivity/trigger.d.ts.map +1 -0
- package/dist/reactivity/trigger.js +46 -0
- package/dist/resolve-modules/errors.d.ts +34 -0
- package/dist/resolve-modules/errors.d.ts.map +1 -0
- package/dist/resolve-modules/errors.js +35 -0
- package/dist/resolve-modules/import.d.ts +35 -0
- package/dist/resolve-modules/import.d.ts.map +1 -0
- package/dist/resolve-modules/import.js +40 -0
- package/dist/resolve-modules/import.test.d.ts +2 -0
- package/dist/resolve-modules/import.test.d.ts.map +1 -0
- package/dist/resolve-modules/import.test.js +45 -0
- package/dist/resolve-modules/index.d.ts +3 -0
- package/dist/resolve-modules/index.d.ts.map +1 -0
- package/dist/resolve-modules/index.js +2 -0
- package/dist/resolve-modules/message-lint-rules/errors.d.ts +8 -0
- package/dist/resolve-modules/message-lint-rules/errors.d.ts.map +1 -0
- package/dist/resolve-modules/message-lint-rules/errors.js +8 -0
- package/dist/resolve-modules/message-lint-rules/resolveMessageLintRules.d.ts +9 -0
- package/dist/resolve-modules/message-lint-rules/resolveMessageLintRules.d.ts.map +1 -0
- package/dist/resolve-modules/message-lint-rules/resolveMessageLintRules.js +21 -0
- package/dist/resolve-modules/plugins/errors.d.ts +28 -0
- package/dist/resolve-modules/plugins/errors.d.ts.map +1 -0
- package/dist/resolve-modules/plugins/errors.js +44 -0
- package/dist/resolve-modules/plugins/resolvePlugins.d.ts +3 -0
- package/dist/resolve-modules/plugins/resolvePlugins.d.ts.map +1 -0
- package/dist/resolve-modules/plugins/resolvePlugins.js +108 -0
- package/dist/resolve-modules/plugins/resolvePlugins.test.d.ts +2 -0
- package/dist/resolve-modules/plugins/resolvePlugins.test.d.ts.map +1 -0
- package/dist/resolve-modules/plugins/resolvePlugins.test.js +289 -0
- package/dist/resolve-modules/plugins/types.d.ts +60 -0
- package/dist/resolve-modules/plugins/types.d.ts.map +1 -0
- package/dist/resolve-modules/plugins/types.js +1 -0
- package/dist/resolve-modules/plugins/types.test.d.ts +2 -0
- package/dist/resolve-modules/plugins/types.test.d.ts.map +1 -0
- package/dist/resolve-modules/plugins/types.test.js +49 -0
- package/dist/resolve-modules/resolveModules.d.ts +3 -0
- package/dist/resolve-modules/resolveModules.d.ts.map +1 -0
- package/dist/resolve-modules/resolveModules.js +70 -0
- package/dist/resolve-modules/resolveModules.test.d.ts +2 -0
- package/dist/resolve-modules/resolveModules.test.d.ts.map +1 -0
- package/dist/resolve-modules/resolveModules.test.js +143 -0
- package/dist/resolve-modules/types.d.ts +62 -0
- package/dist/resolve-modules/types.d.ts.map +1 -0
- package/dist/resolve-modules/types.js +1 -0
- package/dist/test-utilities/createMessage.d.ts +17 -0
- package/dist/test-utilities/createMessage.d.ts.map +1 -0
- package/dist/test-utilities/createMessage.js +16 -0
- package/dist/test-utilities/createMessage.test.d.ts +2 -0
- package/dist/test-utilities/createMessage.test.d.ts.map +1 -0
- package/dist/test-utilities/createMessage.test.js +91 -0
- package/dist/test-utilities/index.d.ts +2 -0
- package/dist/test-utilities/index.d.ts.map +1 -0
- package/dist/test-utilities/index.js +1 -0
- package/dist/versionedInterfaces.d.ts +8 -0
- package/dist/versionedInterfaces.d.ts.map +1 -0
- package/dist/versionedInterfaces.js +8 -0
- package/package.json +58 -0
- package/src/adapter/solidAdapter.test.ts +363 -0
- package/src/adapter/solidAdapter.ts +77 -0
- package/src/api.ts +86 -0
- package/src/createMessageLintReportsQuery.ts +77 -0
- package/src/createMessagesQuery.test.ts +435 -0
- package/src/createMessagesQuery.ts +64 -0
- package/src/errors.ts +46 -0
- package/src/index.ts +29 -0
- package/src/lint/index.ts +2 -0
- package/src/lint/message/errors.ts +9 -0
- package/src/lint/message/lintMessages.test.ts +122 -0
- package/src/lint/message/lintMessages.ts +33 -0
- package/src/lint/message/lintSingleMessage.test.ts +183 -0
- package/src/lint/message/lintSingleMessage.ts +62 -0
- package/src/messages/errors.ts +25 -0
- package/src/messages/index.ts +2 -0
- package/src/messages/variant.test.ts +444 -0
- package/src/messages/variant.ts +242 -0
- package/src/openInlangProject.test.ts +734 -0
- package/src/openInlangProject.ts +337 -0
- package/src/parseConfig.ts +33 -0
- package/src/reactivity/map.ts +135 -0
- package/src/reactivity/solid.ts +36 -0
- package/src/reactivity/trigger.ts +46 -0
- package/src/resolve-modules/errors.ts +39 -0
- package/src/resolve-modules/import.test.ts +58 -0
- package/src/resolve-modules/import.ts +69 -0
- package/src/resolve-modules/index.ts +2 -0
- package/src/resolve-modules/message-lint-rules/errors.ts +9 -0
- package/src/resolve-modules/message-lint-rules/resolveMessageLintRules.ts +24 -0
- package/src/resolve-modules/plugins/errors.ts +57 -0
- package/src/resolve-modules/plugins/resolvePlugins.test.ts +340 -0
- package/src/resolve-modules/plugins/resolvePlugins.ts +170 -0
- package/src/resolve-modules/plugins/types.test.ts +57 -0
- package/src/resolve-modules/plugins/types.ts +77 -0
- package/src/resolve-modules/resolveModules.test.ts +176 -0
- package/src/resolve-modules/resolveModules.ts +97 -0
- package/src/resolve-modules/types.ts +71 -0
- package/src/test-utilities/createMessage.test.ts +100 -0
- package/src/test-utilities/createMessage.ts +20 -0
- package/src/test-utilities/index.ts +1 -0
- package/src/versionedInterfaces.ts +9 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { describe, it, expect } from "vitest"
|
|
3
|
+
import { createMessagesQuery } from "./createMessagesQuery.js"
|
|
4
|
+
import { createEffect, createRoot, createSignal } from "./reactivity/solid.js"
|
|
5
|
+
import type { Message, Text } from "@inlang/message"
|
|
6
|
+
import { createMessage } from "./test-utilities/createMessage.js"
|
|
7
|
+
|
|
8
|
+
const createChangeListener = async (cb: () => void) => createEffect(cb)
|
|
9
|
+
|
|
10
|
+
describe("create", () => {
|
|
11
|
+
it("should create a message", () => {
|
|
12
|
+
const query = createMessagesQuery(() => [])
|
|
13
|
+
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
14
|
+
|
|
15
|
+
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
16
|
+
const created = query.create({ data: mockMessage })
|
|
17
|
+
|
|
18
|
+
expect(query.get({ where: { id: "first-message" } })).toEqual(mockMessage)
|
|
19
|
+
expect(created).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it("should return false if message with id already exists", () => {
|
|
23
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
24
|
+
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
25
|
+
|
|
26
|
+
const mockMessage = createMessage("first-message", { en: "Some Text" })
|
|
27
|
+
query.create({ data: mockMessage })
|
|
28
|
+
|
|
29
|
+
const created = query.create({ data: mockMessage })
|
|
30
|
+
expect(created).toBe(false)
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
describe("get", () => {
|
|
35
|
+
it("should return undefined if a message does not exist", () => {
|
|
36
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
37
|
+
const message = query.get({ where: { id: "none-existent-message" } })
|
|
38
|
+
expect(message).toBeUndefined()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it("should return an object, not an array", () => {
|
|
42
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
43
|
+
const message = query.get({ where: { id: "first-message" } })
|
|
44
|
+
expect(message).toBeDefined()
|
|
45
|
+
expect(Array.isArray(message)).toBe(false)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// todo: improve the readonly type
|
|
49
|
+
it.skip("mutating the returned value should not affect subsequent return values", () => {
|
|
50
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
51
|
+
const message1 = query.get({ where: { id: "first-message" } })!
|
|
52
|
+
;(message1.variants.find((v) => v.languageTag === "en")!.pattern![0]! as Text).value =
|
|
53
|
+
"Hello World 2"
|
|
54
|
+
const message2 = query.get({ where: { id: "first-message" } })!
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
(message1.variants.find((v) => v.languageTag === "en")!.pattern![0]! as Text).value,
|
|
58
|
+
).toBe("Hello World 2")
|
|
59
|
+
expect(
|
|
60
|
+
(message2.variants.find((v) => v.languageTag === "en")!.pattern![0]! as Text).value,
|
|
61
|
+
).toBe("Hello World")
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe("getAll", () => {
|
|
66
|
+
it("should return an empty array if no messages exist", () => {
|
|
67
|
+
const query = createMessagesQuery(() => [])
|
|
68
|
+
const messages = query.getAll()
|
|
69
|
+
|
|
70
|
+
expect(Object.values(messages!)).toEqual([])
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("should return all message objects", () => {
|
|
74
|
+
const query = createMessagesQuery(() => [])
|
|
75
|
+
const mockMessage1 = createMessage("first-message", { en: "Hello World" })
|
|
76
|
+
const mockMessage2 = createMessage("second-message", { en: "Hello World 2" })
|
|
77
|
+
query.create({ data: mockMessage1 })
|
|
78
|
+
query.create({ data: mockMessage2 })
|
|
79
|
+
|
|
80
|
+
const messages = query.getAll()
|
|
81
|
+
expect(Object.values(messages!)).toEqual([mockMessage1, mockMessage2])
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// todo: improve the readonly type
|
|
85
|
+
it.skip("mutating the returned value should not affect subsequent return values", () => {
|
|
86
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
87
|
+
const messages1 = query.getAll()
|
|
88
|
+
;(
|
|
89
|
+
Object.values(messages1!)[0]!.variants.find((v) => v.languageTag === "en")!
|
|
90
|
+
.pattern![0]! as Text
|
|
91
|
+
).value = "Hello World 2"
|
|
92
|
+
|
|
93
|
+
expect(
|
|
94
|
+
(
|
|
95
|
+
Object.values(query.getAll()!)[0]!.variants.find((v) => v.languageTag === "en")!
|
|
96
|
+
.pattern![0]! as Text
|
|
97
|
+
).value,
|
|
98
|
+
).toBe("Hello World")
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe("update", () => {
|
|
103
|
+
it("should update a message", () => {
|
|
104
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
105
|
+
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
106
|
+
|
|
107
|
+
const mockMessage = createMessage("first-message", { en: "Hello World 2" })
|
|
108
|
+
const updated = query.update({ where: { id: "first-message" }, data: mockMessage })
|
|
109
|
+
|
|
110
|
+
expect(query.get({ where: { id: "first-message" } })).toEqual(mockMessage)
|
|
111
|
+
expect(updated).toBe(true)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it("should return false if message with id does not exist exists", () => {
|
|
115
|
+
const query = createMessagesQuery(() => [])
|
|
116
|
+
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
117
|
+
|
|
118
|
+
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
119
|
+
const updated = query.update({ where: { id: "first-message" }, data: mockMessage })
|
|
120
|
+
expect(updated).toBe(false)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe("upsert", () => {
|
|
125
|
+
it("should create a message if not present yet", () => {
|
|
126
|
+
const query = createMessagesQuery(() => [])
|
|
127
|
+
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
128
|
+
|
|
129
|
+
const mockMessage = createMessage("first-message", { en: "Hello World" })
|
|
130
|
+
const upserted = query.upsert({ where: { id: "first-message" }, data: mockMessage })
|
|
131
|
+
|
|
132
|
+
expect(query.get({ where: { id: "first-message" } })).toEqual(mockMessage)
|
|
133
|
+
expect(upserted).toBe(true)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it("should update message if id already exists", () => {
|
|
137
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
138
|
+
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
139
|
+
|
|
140
|
+
const mockMessage = createMessage("first-message", { en: "Hello World 2" })
|
|
141
|
+
const upserted = query.upsert({ where: { id: "first-message" }, data: mockMessage })
|
|
142
|
+
|
|
143
|
+
expect(query.get({ where: { id: "first-message" } })).toEqual(mockMessage)
|
|
144
|
+
expect(upserted).toBe(true)
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
describe("delete", () => {
|
|
149
|
+
it("should delete a message", () => {
|
|
150
|
+
const query = createMessagesQuery(() => [createMessage("first-message", { en: "Hello World" })])
|
|
151
|
+
expect(query.get({ where: { id: "first-message" } })).toBeDefined()
|
|
152
|
+
|
|
153
|
+
const deleted = query.delete({ where: { id: "first-message" } })
|
|
154
|
+
|
|
155
|
+
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
156
|
+
expect(deleted).toBe(true)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it("should return false if message with id does not exist", () => {
|
|
160
|
+
const query = createMessagesQuery(() => [])
|
|
161
|
+
expect(query.get({ where: { id: "first-message" } })).toBeUndefined()
|
|
162
|
+
|
|
163
|
+
const deleted = query.delete({ where: { id: "first-message" } })
|
|
164
|
+
expect(deleted).toBe(false)
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
describe("reactivity", () => {
|
|
169
|
+
describe("get", () => {
|
|
170
|
+
it("should react to `create`", async () => {
|
|
171
|
+
await createRoot(async () => {
|
|
172
|
+
const query = createMessagesQuery(() => [])
|
|
173
|
+
|
|
174
|
+
// eslint-disable-next-line unicorn/no-null
|
|
175
|
+
let message: Message | undefined | null = null
|
|
176
|
+
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
177
|
+
expect(message).toBeUndefined()
|
|
178
|
+
|
|
179
|
+
query.create({ data: createMessage("1", { en: "before" }) })
|
|
180
|
+
expect(message).toBeDefined()
|
|
181
|
+
|
|
182
|
+
const anotherMessage = query.get({ where: { id: "1" } })
|
|
183
|
+
expect(anotherMessage).toBeDefined()
|
|
184
|
+
expect(message).toStrictEqual(anotherMessage)
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it("should react to `update`", async () => {
|
|
189
|
+
await createRoot(async () => {
|
|
190
|
+
const query = createMessagesQuery(() => [createMessage("1", { en: "before" })])
|
|
191
|
+
|
|
192
|
+
let message: Message | undefined
|
|
193
|
+
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
194
|
+
expect(message).toBeDefined()
|
|
195
|
+
expect(
|
|
196
|
+
(message?.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
197
|
+
.value,
|
|
198
|
+
).toBe("before")
|
|
199
|
+
|
|
200
|
+
query.update({ where: { id: "1" }, data: createMessage("1", { en: "after" }) })
|
|
201
|
+
expect(
|
|
202
|
+
(message?.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
203
|
+
.value,
|
|
204
|
+
).toBe("after")
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it("should react to `upsert`", async () => {
|
|
209
|
+
await createRoot(async () => {
|
|
210
|
+
const query = createMessagesQuery(() => [])
|
|
211
|
+
|
|
212
|
+
let message: Message | undefined
|
|
213
|
+
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
214
|
+
expect(message).toBeUndefined()
|
|
215
|
+
|
|
216
|
+
query.upsert({ where: { id: "1" }, data: createMessage("1", { en: "before" }) })
|
|
217
|
+
expect(message).toBeDefined()
|
|
218
|
+
expect(
|
|
219
|
+
(message?.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
220
|
+
.value,
|
|
221
|
+
).toBe("before")
|
|
222
|
+
|
|
223
|
+
query.upsert({ where: { id: "1" }, data: createMessage("1", { en: "after" }) })
|
|
224
|
+
expect(
|
|
225
|
+
(message?.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
226
|
+
.value,
|
|
227
|
+
).toBe("after")
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it("should react to `delete`", async () => {
|
|
232
|
+
await createRoot(async () => {
|
|
233
|
+
const query = createMessagesQuery(() => [createMessage("1", { en: "" })])
|
|
234
|
+
|
|
235
|
+
let message: Message | undefined
|
|
236
|
+
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
237
|
+
expect(message).toBeDefined()
|
|
238
|
+
|
|
239
|
+
query.delete({ where: { id: "1" } })
|
|
240
|
+
expect(message).toBeUndefined()
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it("should react to changes to the input `messages`", async () => {
|
|
245
|
+
const [messages, setMessages] = createSignal<Message[]>([])
|
|
246
|
+
const query = createMessagesQuery(messages)
|
|
247
|
+
|
|
248
|
+
// eslint-disable-next-line unicorn/no-null
|
|
249
|
+
let message: Message | undefined | null = null
|
|
250
|
+
await createChangeListener(() => (message = query.get({ where: { id: "1" } })))
|
|
251
|
+
expect(message).toBeUndefined()
|
|
252
|
+
|
|
253
|
+
query.create({ data: createMessage("1", { en: "before" }) })
|
|
254
|
+
expect(message).toBeDefined()
|
|
255
|
+
expect(
|
|
256
|
+
(message!.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
257
|
+
.value,
|
|
258
|
+
).toBe("before")
|
|
259
|
+
|
|
260
|
+
setMessages([createMessage("1", { en: "after" })])
|
|
261
|
+
expect(message).toBeDefined()
|
|
262
|
+
expect(
|
|
263
|
+
(message!.variants.find((variant) => variant.languageTag === "en")?.pattern[0] as Text)
|
|
264
|
+
.value,
|
|
265
|
+
).toBe("after")
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
describe.todo("subscribe", () => {
|
|
270
|
+
// TODO: add tests for `subscribe`
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
describe("getAll", () => {
|
|
274
|
+
it("should react to `create`", async () => {
|
|
275
|
+
await createRoot(async () => {
|
|
276
|
+
const query = createMessagesQuery(() => [])
|
|
277
|
+
|
|
278
|
+
let messages: Readonly<Message[]> | undefined = undefined
|
|
279
|
+
await createChangeListener(() => (messages = query.getAll()))
|
|
280
|
+
expect(Object.values(messages!)).toHaveLength(0)
|
|
281
|
+
|
|
282
|
+
query.create({ data: createMessage("1", { en: "before" }) })
|
|
283
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
284
|
+
|
|
285
|
+
query.create({ data: createMessage("2", { en: "before" }) })
|
|
286
|
+
expect(Object.values(messages!)).toHaveLength(2)
|
|
287
|
+
|
|
288
|
+
query.create({ data: createMessage("3", { en: "before" }) })
|
|
289
|
+
expect(Object.values(messages!)).toHaveLength(3)
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it("should react to `update`", async () => {
|
|
294
|
+
await createRoot(async () => {
|
|
295
|
+
const query = createMessagesQuery(() => [createMessage("1", { en: "before" })])
|
|
296
|
+
|
|
297
|
+
let messages: Readonly<Message[]> | undefined = undefined
|
|
298
|
+
await createChangeListener(() => (messages = query.getAll()))
|
|
299
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
300
|
+
expect(
|
|
301
|
+
(
|
|
302
|
+
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
303
|
+
.pattern[0]! as Text
|
|
304
|
+
).value,
|
|
305
|
+
).toBe("before")
|
|
306
|
+
|
|
307
|
+
query.update({ where: { id: "1" }, data: createMessage("1", { en: "after" }) })
|
|
308
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
309
|
+
expect(
|
|
310
|
+
(
|
|
311
|
+
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
312
|
+
.pattern[0]! as Text
|
|
313
|
+
).value,
|
|
314
|
+
).toBe("after")
|
|
315
|
+
})
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it("should react to `upsert`", async () => {
|
|
319
|
+
await createRoot(async () => {
|
|
320
|
+
const query = createMessagesQuery(() => [])
|
|
321
|
+
|
|
322
|
+
let messages: Readonly<Message[]> | undefined = undefined
|
|
323
|
+
await createChangeListener(() => (messages = query.getAll()))
|
|
324
|
+
expect(Object.values(messages!)).toHaveLength(0)
|
|
325
|
+
|
|
326
|
+
query.upsert({ where: { id: "1" }, data: createMessage("1", { en: "before" }) })
|
|
327
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
328
|
+
expect(
|
|
329
|
+
(
|
|
330
|
+
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
331
|
+
.pattern[0]! as Text
|
|
332
|
+
).value,
|
|
333
|
+
).toBe("before")
|
|
334
|
+
|
|
335
|
+
query.upsert({ where: { id: "1" }, data: createMessage("1", { en: "after" }) })
|
|
336
|
+
expect(
|
|
337
|
+
(
|
|
338
|
+
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
339
|
+
.pattern[0]! as Text
|
|
340
|
+
).value,
|
|
341
|
+
).toBe("after")
|
|
342
|
+
})
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
it("should react to `delete`", async () => {
|
|
346
|
+
await createRoot(async () => {
|
|
347
|
+
const query = createMessagesQuery(() => [
|
|
348
|
+
createMessage("1", { en: "" }),
|
|
349
|
+
createMessage("2", { en: "" }),
|
|
350
|
+
createMessage("3", { en: "" }),
|
|
351
|
+
])
|
|
352
|
+
|
|
353
|
+
let messages: Readonly<Message[]> | undefined = undefined
|
|
354
|
+
await createChangeListener(() => (messages = query.getAll()))
|
|
355
|
+
expect(Object.values(messages!)).toHaveLength(3)
|
|
356
|
+
|
|
357
|
+
query.delete({ where: { id: "1" } })
|
|
358
|
+
expect(Object.values(messages!)).toHaveLength(2)
|
|
359
|
+
|
|
360
|
+
// deleting the same id again should not have an effect
|
|
361
|
+
query.delete({ where: { id: "1" } })
|
|
362
|
+
expect(Object.values(messages!)).toHaveLength(2)
|
|
363
|
+
|
|
364
|
+
query.delete({ where: { id: "2" } })
|
|
365
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
366
|
+
|
|
367
|
+
query.delete({ where: { id: "3" } })
|
|
368
|
+
expect(Object.values(messages!)).toHaveLength(0)
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
it("should react to changes to the input `messages`", async () => {
|
|
373
|
+
const [inputMessages, setMessages] = createSignal<Message[]>([
|
|
374
|
+
createMessage("1", { en: "before" }),
|
|
375
|
+
])
|
|
376
|
+
const query = createMessagesQuery(inputMessages)
|
|
377
|
+
|
|
378
|
+
let messages: Readonly<Message[]> | undefined = undefined
|
|
379
|
+
await createChangeListener(() => (messages = query.getAll()))
|
|
380
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
381
|
+
|
|
382
|
+
query.create({ data: createMessage("2", { en: "" }) })
|
|
383
|
+
expect(Object.values(messages!)).toHaveLength(2)
|
|
384
|
+
expect(
|
|
385
|
+
(
|
|
386
|
+
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
387
|
+
.pattern[0]! as Text
|
|
388
|
+
).value,
|
|
389
|
+
).toBe("before")
|
|
390
|
+
|
|
391
|
+
setMessages([createMessage("1", { en: "after" })])
|
|
392
|
+
expect(Object.values(messages!)).toHaveLength(1)
|
|
393
|
+
expect(
|
|
394
|
+
(
|
|
395
|
+
Object.values(messages!)![0]!.variants.find((variant) => variant.languageTag === "en")!
|
|
396
|
+
.pattern[0]! as Text
|
|
397
|
+
).value,
|
|
398
|
+
).toBe("after")
|
|
399
|
+
})
|
|
400
|
+
})
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
it("instances should not share state", async () => {
|
|
404
|
+
await createRoot(async () => {
|
|
405
|
+
const query1 = createMessagesQuery(() => [createMessage("1", { en: "before" })])
|
|
406
|
+
const query2 = createMessagesQuery(() => [])
|
|
407
|
+
|
|
408
|
+
// eslint-disable-next-line unicorn/no-null
|
|
409
|
+
let message1: Message | undefined | null = null
|
|
410
|
+
await createChangeListener(() => (message1 = query1.get({ where: { id: "1" } })))
|
|
411
|
+
// eslint-disable-next-line unicorn/no-null
|
|
412
|
+
let message2: Message | undefined | null = null
|
|
413
|
+
await createChangeListener(() => (message2 = query2.get({ where: { id: "1" } })))
|
|
414
|
+
|
|
415
|
+
expect(message1).toBeDefined()
|
|
416
|
+
expect(message2).toBeUndefined()
|
|
417
|
+
|
|
418
|
+
query2.create({ data: createMessage("1", { en: "before" }) })
|
|
419
|
+
expect(message2).toBeDefined()
|
|
420
|
+
|
|
421
|
+
query1.update({ where: { id: "1" }, data: createMessage("1", { en: "after" }) })
|
|
422
|
+
expect(
|
|
423
|
+
(message1!.variants.find((variant) => variant.languageTag === "en")!.pattern[0]! as Text)
|
|
424
|
+
.value,
|
|
425
|
+
).toBe("after")
|
|
426
|
+
expect(
|
|
427
|
+
(message2!.variants.find((variant) => variant.languageTag === "en")!.pattern[0]! as Text)
|
|
428
|
+
.value,
|
|
429
|
+
).toBe("before")
|
|
430
|
+
|
|
431
|
+
query1.delete({ where: { id: "1" } })
|
|
432
|
+
expect(message1).toBeUndefined()
|
|
433
|
+
expect(message2).toBeDefined()
|
|
434
|
+
})
|
|
435
|
+
})
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Message } from "@inlang/message"
|
|
2
|
+
import { ReactiveMap } from "./reactivity/map.js"
|
|
3
|
+
import { createEffect } from "./reactivity/solid.js"
|
|
4
|
+
import { createSubscribable } from "./openInlangProject.js"
|
|
5
|
+
import type { InlangProject, MessageQueryApi } from "./api.js"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a reactive query API for messages.
|
|
9
|
+
*/
|
|
10
|
+
export function createMessagesQuery(
|
|
11
|
+
messages: () => Array<Message>,
|
|
12
|
+
): InlangProject["query"]["messages"] {
|
|
13
|
+
// @ts-expect-error
|
|
14
|
+
const index = new ReactiveMap<string, Message>()
|
|
15
|
+
|
|
16
|
+
createEffect(() => {
|
|
17
|
+
index.clear()
|
|
18
|
+
for (const message of messages()) {
|
|
19
|
+
index.set(message.id, message)
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const get = (args: Parameters<MessageQueryApi["get"]>[0]) => index.get(args.where.id)
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
create: ({ data }): boolean => {
|
|
27
|
+
if (index.has(data.id)) return false
|
|
28
|
+
index.set(data.id, data)
|
|
29
|
+
return true
|
|
30
|
+
},
|
|
31
|
+
get: Object.assign(get, {
|
|
32
|
+
subscribe: (
|
|
33
|
+
args: Parameters<MessageQueryApi["get"]["subscribe"]>[0],
|
|
34
|
+
callback: Parameters<MessageQueryApi["get"]["subscribe"]>[1],
|
|
35
|
+
) => createSubscribable(() => get(args)).subscribe(callback),
|
|
36
|
+
}) as any,
|
|
37
|
+
includedMessageIds: createSubscribable(() => {
|
|
38
|
+
return [...index.keys()]
|
|
39
|
+
}),
|
|
40
|
+
getAll: createSubscribable(() => {
|
|
41
|
+
return [...index.values()]
|
|
42
|
+
}),
|
|
43
|
+
update: ({ where, data }): boolean => {
|
|
44
|
+
const message = index.get(where.id)
|
|
45
|
+
if (message === undefined) return false
|
|
46
|
+
index.set(where.id, { ...message, ...data })
|
|
47
|
+
return true
|
|
48
|
+
},
|
|
49
|
+
upsert: ({ where, data }) => {
|
|
50
|
+
const message = index.get(where.id)
|
|
51
|
+
if (message === undefined) {
|
|
52
|
+
index.set(where.id, data)
|
|
53
|
+
} else {
|
|
54
|
+
index.set(where.id, { ...message, ...data })
|
|
55
|
+
}
|
|
56
|
+
return true
|
|
57
|
+
},
|
|
58
|
+
delete: ({ where }): boolean => {
|
|
59
|
+
if (!index.has(where.id)) return false
|
|
60
|
+
index.delete(where.id)
|
|
61
|
+
return true
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export class InvalidConfigError extends Error {
|
|
2
|
+
constructor(message: string, options: ErrorOptions) {
|
|
3
|
+
super(message, options)
|
|
4
|
+
this.name = "InvalidConfigError"
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class ProjectFileJSONSyntaxError extends Error {
|
|
9
|
+
constructor(message: string, options: ErrorOptions) {
|
|
10
|
+
super(message, options)
|
|
11
|
+
this.name = "ProjectFileJSONSyntaxError"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class ProjectFilePathNotFoundError extends Error {
|
|
16
|
+
constructor(message: string, options: ErrorOptions) {
|
|
17
|
+
super(message, options)
|
|
18
|
+
this.name = "ProjectFilePathNotFoundError"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class PluginSaveMessagesError extends Error {
|
|
23
|
+
constructor(message: string, options: ErrorOptions) {
|
|
24
|
+
super(message, options)
|
|
25
|
+
this.name = "PluginSaveMessagesError"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class PluginLoadMessagesError extends Error {
|
|
30
|
+
constructor(message: string, options: ErrorOptions) {
|
|
31
|
+
super(message, options)
|
|
32
|
+
this.name = "PluginLoadMessagesError"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Error when no package provides the API to handle messages.
|
|
38
|
+
*/
|
|
39
|
+
export class NoPluginProvidesLoadOrSaveMessagesError extends Error {
|
|
40
|
+
constructor() {
|
|
41
|
+
super(
|
|
42
|
+
"It seems you did not install any plugin that handles messages. Please add one to make inlang work. See https://inlang.com/documentation/plugins/registry.",
|
|
43
|
+
) // TODO: check if link is correct
|
|
44
|
+
this.name = "NoPluginProvidesLoadOrSaveMessagesError"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*! PUBLIC API FOR THE INLANG SDK.
|
|
3
|
+
*!
|
|
4
|
+
*! EXPORT AS LITTLE AS POSSIBLE TO MINIMIZE THE CHANCE OF BREAKING CHANGES.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
InlangProject,
|
|
9
|
+
InstalledMessageLintRule,
|
|
10
|
+
InstalledPlugin,
|
|
11
|
+
MessageQueryApi,
|
|
12
|
+
Subscribable,
|
|
13
|
+
} from "./api.js"
|
|
14
|
+
export { type ImportFunction, createImport } from "./resolve-modules/index.js"
|
|
15
|
+
export { openInlangProject } from "./openInlangProject.js"
|
|
16
|
+
export { solidAdapter, type InlangProjectWithSolidAdapter } from "./adapter/solidAdapter.js"
|
|
17
|
+
export { createMessagesQuery } from "./createMessagesQuery.js"
|
|
18
|
+
export {
|
|
19
|
+
ProjectFilePathNotFoundError,
|
|
20
|
+
ProjectFileJSONSyntaxError,
|
|
21
|
+
InvalidConfigError,
|
|
22
|
+
NoPluginProvidesLoadOrSaveMessagesError,
|
|
23
|
+
PluginLoadMessagesError,
|
|
24
|
+
PluginSaveMessagesError,
|
|
25
|
+
} from "./errors.js"
|
|
26
|
+
|
|
27
|
+
export * from "./messages/variant.js"
|
|
28
|
+
export * from "./versionedInterfaces.js"
|
|
29
|
+
export { InlangModule } from "@inlang/module"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error when a lint rule throws during the linting process.
|
|
3
|
+
*/
|
|
4
|
+
export class MessagedLintRuleThrowedError extends Error {
|
|
5
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
6
|
+
super(message, options)
|
|
7
|
+
this.name = "MessagedLintRuleThrowedError"
|
|
8
|
+
}
|
|
9
|
+
}
|