@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,627 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { describe, it, expect, vi } from "vitest";
|
|
3
|
+
import { openInlangProject } from "./openInlangProject.js";
|
|
4
|
+
import { ProjectFilePathNotFoundError, ProjectFileJSONSyntaxError, InvalidConfigError, NoPluginProvidesLoadOrSaveMessagesError, } from "./errors.js";
|
|
5
|
+
import { createNodeishMemoryFs } from "@lix-js/fs";
|
|
6
|
+
// ------------------------------------------------------------------------------------------------
|
|
7
|
+
const getValue = (subscribable) => {
|
|
8
|
+
let value;
|
|
9
|
+
subscribable.subscribe((v) => void (value = v));
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
const config = {
|
|
13
|
+
sourceLanguageTag: "en",
|
|
14
|
+
languageTags: ["en"],
|
|
15
|
+
modules: ["plugin.js", "lintRule.js"],
|
|
16
|
+
settings: {
|
|
17
|
+
"project.messageLintRuleLevels": {
|
|
18
|
+
"messageLintRule.inlang.missingTranslation": "error",
|
|
19
|
+
},
|
|
20
|
+
"plugin.inlang.i18next": {
|
|
21
|
+
pathPattern: "./examples/example01/{languageTag}.json",
|
|
22
|
+
variableReferencePattern: ["{", "}"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const mockPlugin = {
|
|
27
|
+
meta: {
|
|
28
|
+
id: "plugin.inlang.i18next",
|
|
29
|
+
description: { en: "Mock plugin description" },
|
|
30
|
+
displayName: { en: "Mock Plugin" },
|
|
31
|
+
},
|
|
32
|
+
loadMessages: () => exampleMessages,
|
|
33
|
+
saveMessages: () => undefined,
|
|
34
|
+
addCustomApi: () => ({
|
|
35
|
+
"app.inlang.ideExtension": {
|
|
36
|
+
messageReferenceMatcher: (text) => text,
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
// TODO: use `createMessage` utility
|
|
41
|
+
const exampleMessages = [
|
|
42
|
+
{
|
|
43
|
+
id: "a",
|
|
44
|
+
selectors: [],
|
|
45
|
+
variants: [
|
|
46
|
+
{
|
|
47
|
+
languageTag: "en",
|
|
48
|
+
match: {},
|
|
49
|
+
pattern: [
|
|
50
|
+
{
|
|
51
|
+
type: "Text",
|
|
52
|
+
value: "test",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "b",
|
|
60
|
+
selectors: [],
|
|
61
|
+
variants: [
|
|
62
|
+
{
|
|
63
|
+
languageTag: "en",
|
|
64
|
+
match: {},
|
|
65
|
+
pattern: [
|
|
66
|
+
{
|
|
67
|
+
type: "Text",
|
|
68
|
+
value: "test",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
const mockMessageLintRule = {
|
|
76
|
+
meta: {
|
|
77
|
+
id: "messageLintRule.inlang.mock",
|
|
78
|
+
description: { en: "Mock lint rule description" },
|
|
79
|
+
displayName: { en: "Mock Lint Rule" },
|
|
80
|
+
},
|
|
81
|
+
message: () => undefined,
|
|
82
|
+
};
|
|
83
|
+
const _import = async (name) => ({
|
|
84
|
+
default: name === "plugin.js" ? mockPlugin : mockMessageLintRule,
|
|
85
|
+
});
|
|
86
|
+
// ------------------------------------------------------------------------------------------------
|
|
87
|
+
describe("initialization", () => {
|
|
88
|
+
describe("config", () => {
|
|
89
|
+
it("should return an error if config file is not found", async () => {
|
|
90
|
+
const fs = createNodeishMemoryFs();
|
|
91
|
+
const inlang = await openInlangProject({
|
|
92
|
+
projectFilePath: "./test.json",
|
|
93
|
+
nodeishFs: fs,
|
|
94
|
+
_import,
|
|
95
|
+
});
|
|
96
|
+
expect(inlang.errors()[0]).toBeInstanceOf(ProjectFilePathNotFoundError);
|
|
97
|
+
});
|
|
98
|
+
it("should return an error if config file is not a valid JSON", async () => {
|
|
99
|
+
const fs = await createNodeishMemoryFs();
|
|
100
|
+
await fs.writeFile("./project.inlang.json", "invalid json");
|
|
101
|
+
const inlang = await openInlangProject({
|
|
102
|
+
projectFilePath: "./project.inlang.json",
|
|
103
|
+
nodeishFs: fs,
|
|
104
|
+
_import,
|
|
105
|
+
});
|
|
106
|
+
expect(inlang.errors()[0]).toBeInstanceOf(ProjectFileJSONSyntaxError);
|
|
107
|
+
});
|
|
108
|
+
it("should return an error if config file is does not match schema", async () => {
|
|
109
|
+
const fs = await createNodeishMemoryFs();
|
|
110
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify({}));
|
|
111
|
+
const inlang = await openInlangProject({
|
|
112
|
+
projectFilePath: "./project.inlang.json",
|
|
113
|
+
nodeishFs: fs,
|
|
114
|
+
_import,
|
|
115
|
+
});
|
|
116
|
+
expect(inlang.errors()[0]).toBeInstanceOf(InvalidConfigError);
|
|
117
|
+
});
|
|
118
|
+
it("should return the parsed config", async () => {
|
|
119
|
+
const fs = await createNodeishMemoryFs();
|
|
120
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
121
|
+
const inlang = await openInlangProject({
|
|
122
|
+
projectFilePath: "./project.inlang.json",
|
|
123
|
+
nodeishFs: fs,
|
|
124
|
+
_import,
|
|
125
|
+
});
|
|
126
|
+
expect(inlang.config()).toStrictEqual(config);
|
|
127
|
+
});
|
|
128
|
+
it("should not re-write the config to disk when initializing", async () => {
|
|
129
|
+
const fs = await createNodeishMemoryFs();
|
|
130
|
+
const configWithDeifferentFormatting = JSON.stringify(config, undefined, 4);
|
|
131
|
+
await fs.writeFile("./project.inlang.json", configWithDeifferentFormatting);
|
|
132
|
+
const inlang = await openInlangProject({
|
|
133
|
+
projectFilePath: "./project.inlang.json",
|
|
134
|
+
nodeishFs: fs,
|
|
135
|
+
_import,
|
|
136
|
+
});
|
|
137
|
+
const configOnDisk = await fs.readFile("./project.inlang.json", { encoding: "utf-8" });
|
|
138
|
+
expect(configOnDisk).toBe(configWithDeifferentFormatting);
|
|
139
|
+
inlang.setConfig(inlang.config());
|
|
140
|
+
// TODO: how can we await `setConfig` correctly
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
142
|
+
const newConfigOnDisk = await fs.readFile("./project.inlang.json", { encoding: "utf-8" });
|
|
143
|
+
expect(newConfigOnDisk).not.toBe(configWithDeifferentFormatting);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe("modules", () => {
|
|
147
|
+
it("should return an error if no plugin defines readMessages", async () => {
|
|
148
|
+
const $badImport = async () => ({
|
|
149
|
+
default: { ...mockPlugin, loadMessages: undefined },
|
|
150
|
+
});
|
|
151
|
+
const fs = await createNodeishMemoryFs();
|
|
152
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
153
|
+
const inlang = await openInlangProject({
|
|
154
|
+
projectFilePath: "./project.inlang.json",
|
|
155
|
+
nodeishFs: fs,
|
|
156
|
+
_import: $badImport,
|
|
157
|
+
});
|
|
158
|
+
expect(inlang.errors()[0]).toBeInstanceOf(NoPluginProvidesLoadOrSaveMessagesError);
|
|
159
|
+
});
|
|
160
|
+
it("should return an error if no plugin defines writeMessages", async () => {
|
|
161
|
+
const $badImport = async () => ({
|
|
162
|
+
default: { ...mockPlugin, writeMessages: undefined },
|
|
163
|
+
});
|
|
164
|
+
const fs = createNodeishMemoryFs();
|
|
165
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
166
|
+
const inlang = await openInlangProject({
|
|
167
|
+
projectFilePath: "./project.inlang.json",
|
|
168
|
+
nodeishFs: fs,
|
|
169
|
+
_import: $badImport,
|
|
170
|
+
});
|
|
171
|
+
expect(inlang.errors()[0]).toBeInstanceOf(NoPluginProvidesLoadOrSaveMessagesError);
|
|
172
|
+
});
|
|
173
|
+
it("should return an error if an error occurs while resolving a plugin", async () => {
|
|
174
|
+
const $badImport = async () => ({
|
|
175
|
+
default: {},
|
|
176
|
+
});
|
|
177
|
+
const fs = createNodeishMemoryFs();
|
|
178
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
179
|
+
const inlang = await openInlangProject({
|
|
180
|
+
projectFilePath: "./project.inlang.json",
|
|
181
|
+
nodeishFs: fs,
|
|
182
|
+
_import: $badImport,
|
|
183
|
+
});
|
|
184
|
+
expect(inlang.errors()).toHaveLength(1);
|
|
185
|
+
});
|
|
186
|
+
// it.todo("should throw if lintRules contain errors ???")
|
|
187
|
+
// it.todo("should return meta data")
|
|
188
|
+
// it.todo("should return plugins")
|
|
189
|
+
// it.todo("should return lint rules")
|
|
190
|
+
});
|
|
191
|
+
describe("flow", () => {
|
|
192
|
+
it.todo("should not call functions multiple times");
|
|
193
|
+
it.todo("should load modules after config");
|
|
194
|
+
it.todo("should not load messages");
|
|
195
|
+
it.todo("should not call lint");
|
|
196
|
+
});
|
|
197
|
+
describe("instance object", () => {
|
|
198
|
+
it.todo("should contain all fields");
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe("functionality", () => {
|
|
202
|
+
describe("config", () => {
|
|
203
|
+
it("should return the config", async () => {
|
|
204
|
+
const fs = await createNodeishMemoryFs();
|
|
205
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
206
|
+
const inlang = await openInlangProject({
|
|
207
|
+
projectFilePath: "./project.inlang.json",
|
|
208
|
+
nodeishFs: fs,
|
|
209
|
+
_import,
|
|
210
|
+
});
|
|
211
|
+
expect(getValue(inlang.config)).toStrictEqual(config);
|
|
212
|
+
});
|
|
213
|
+
it("should set a new config", async () => {
|
|
214
|
+
const fs = await createNodeishMemoryFs();
|
|
215
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
216
|
+
const inlang = await openInlangProject({
|
|
217
|
+
projectFilePath: "./project.inlang.json",
|
|
218
|
+
nodeishFs: fs,
|
|
219
|
+
_import,
|
|
220
|
+
});
|
|
221
|
+
expect(inlang.config()).toStrictEqual(config);
|
|
222
|
+
inlang.setConfig({ ...config, languageTags: ["en", "de"] });
|
|
223
|
+
expect(getValue(inlang.config)).toStrictEqual({ ...config, languageTags: ["en", "de"] });
|
|
224
|
+
expect(inlang.config().languageTags).toStrictEqual(["en", "de"]);
|
|
225
|
+
inlang.setConfig({ ...config, languageTags: ["en", "de", "fr"] });
|
|
226
|
+
expect(getValue(inlang.config)).toStrictEqual({ ...config, languageTags: ["en", "de", "fr"] });
|
|
227
|
+
expect(inlang.config().languageTags).toStrictEqual(["en", "de", "fr"]);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
describe("setConfig", () => {
|
|
231
|
+
it("should fail if config is not valid", async () => {
|
|
232
|
+
const fs = await createNodeishMemoryFs();
|
|
233
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
234
|
+
const inlang = await openInlangProject({
|
|
235
|
+
projectFilePath: "./project.inlang.json",
|
|
236
|
+
nodeishFs: fs,
|
|
237
|
+
_import,
|
|
238
|
+
});
|
|
239
|
+
const result = inlang.setConfig({});
|
|
240
|
+
expect(result.data).toBeUndefined();
|
|
241
|
+
expect(result.error).toBeInstanceOf(InvalidConfigError);
|
|
242
|
+
});
|
|
243
|
+
it("should write config to disk", async () => {
|
|
244
|
+
const fs = await createNodeishMemoryFs();
|
|
245
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
246
|
+
const inlang = await openInlangProject({
|
|
247
|
+
projectFilePath: "./project.inlang.json",
|
|
248
|
+
nodeishFs: fs,
|
|
249
|
+
_import,
|
|
250
|
+
});
|
|
251
|
+
const before = await fs.readFile("./project.inlang.json", { encoding: "utf-8" });
|
|
252
|
+
expect(before).toBeDefined();
|
|
253
|
+
const result = inlang.setConfig({ ...config, languageTags: [] });
|
|
254
|
+
expect(result.data).toBeUndefined();
|
|
255
|
+
expect(result.error).toBeUndefined();
|
|
256
|
+
// TODO: how to wait for fs.writeFile to finish?
|
|
257
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
258
|
+
const after = await fs.readFile("./project.inlang.json", { encoding: "utf-8" });
|
|
259
|
+
expect(after).toBeDefined();
|
|
260
|
+
expect(after).not.toBe(before);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
describe("installed", () => {
|
|
264
|
+
it("should return the installed items", async () => {
|
|
265
|
+
const fs = createNodeishMemoryFs();
|
|
266
|
+
const config = {
|
|
267
|
+
sourceLanguageTag: "en",
|
|
268
|
+
languageTags: ["en"],
|
|
269
|
+
modules: ["plugin.js", "lintRule.js"],
|
|
270
|
+
settings: {},
|
|
271
|
+
};
|
|
272
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
273
|
+
const inlang = await openInlangProject({
|
|
274
|
+
projectFilePath: "./project.inlang.json",
|
|
275
|
+
nodeishFs: fs,
|
|
276
|
+
_import,
|
|
277
|
+
});
|
|
278
|
+
expect(inlang.installed.plugins()[0]).toStrictEqual({
|
|
279
|
+
meta: mockPlugin.meta,
|
|
280
|
+
module: config.modules[0],
|
|
281
|
+
});
|
|
282
|
+
expect(inlang.installed.messageLintRules()[0]).toEqual({
|
|
283
|
+
meta: mockMessageLintRule.meta,
|
|
284
|
+
module: config.modules[1],
|
|
285
|
+
lintLevel: "warning",
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
it("should apply 'warning' as default lint level to lint rules that have no lint level defined in the config", async () => {
|
|
289
|
+
const fs = createNodeishMemoryFs();
|
|
290
|
+
const config = {
|
|
291
|
+
sourceLanguageTag: "en",
|
|
292
|
+
languageTags: ["en"],
|
|
293
|
+
modules: ["plugin.js", "lintRule.js"],
|
|
294
|
+
settings: {},
|
|
295
|
+
};
|
|
296
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
297
|
+
const inlang = await openInlangProject({
|
|
298
|
+
projectFilePath: "./project.inlang.json",
|
|
299
|
+
nodeishFs: fs,
|
|
300
|
+
_import,
|
|
301
|
+
});
|
|
302
|
+
expect(inlang.installed.messageLintRules()[0]?.lintLevel).toBe("warning");
|
|
303
|
+
});
|
|
304
|
+
// yep, this is a typical "hm, we have a bug here, let's write a test for it" test
|
|
305
|
+
it("should return lint reports if disabled is not set", async () => {
|
|
306
|
+
const _mockLintRule = {
|
|
307
|
+
meta: {
|
|
308
|
+
id: "messageLintRule.namespace.mock",
|
|
309
|
+
description: { en: "Mock lint rule description" },
|
|
310
|
+
displayName: { en: "Mock Lint Rule" },
|
|
311
|
+
},
|
|
312
|
+
message: ({ report }) => {
|
|
313
|
+
report({
|
|
314
|
+
messageId: "some-message-1",
|
|
315
|
+
languageTag: "en",
|
|
316
|
+
body: { en: "lintrule1" },
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
const _mockPlugin = {
|
|
321
|
+
meta: {
|
|
322
|
+
id: "plugin.inlang.i18next",
|
|
323
|
+
description: { en: "Mock plugin description" },
|
|
324
|
+
displayName: { en: "Mock Plugin" },
|
|
325
|
+
},
|
|
326
|
+
loadMessages: () => [{ id: "some-message", selectors: [], variants: [] }],
|
|
327
|
+
saveMessages: () => undefined,
|
|
328
|
+
};
|
|
329
|
+
const fs = await createNodeishMemoryFs();
|
|
330
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify({
|
|
331
|
+
sourceLanguageTag: "en",
|
|
332
|
+
languageTags: ["en"],
|
|
333
|
+
modules: ["plugin.js", "lintRule.js"],
|
|
334
|
+
settings: {},
|
|
335
|
+
}));
|
|
336
|
+
const _import = async (name) => {
|
|
337
|
+
return {
|
|
338
|
+
default: name === "plugin.js" ? _mockPlugin : _mockLintRule,
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
const inlang = await openInlangProject({
|
|
342
|
+
projectFilePath: "./project.inlang.json",
|
|
343
|
+
nodeishFs: fs,
|
|
344
|
+
_import,
|
|
345
|
+
});
|
|
346
|
+
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
347
|
+
expect(inlang.query.messageLintReports.getAll()).toHaveLength(1);
|
|
348
|
+
expect(inlang.query.messageLintReports.getAll()?.[0]?.ruleId).toBe(_mockLintRule.meta.id);
|
|
349
|
+
expect(inlang.installed.messageLintRules()).toHaveLength(1);
|
|
350
|
+
});
|
|
351
|
+
it("should return lint reports for a single message", async () => {
|
|
352
|
+
const _mockLintRule = {
|
|
353
|
+
meta: {
|
|
354
|
+
id: "messageLintRule.namepsace.mock",
|
|
355
|
+
description: { en: "Mock lint rule description" },
|
|
356
|
+
displayName: { en: "Mock Lint Rule" },
|
|
357
|
+
},
|
|
358
|
+
message: ({ report }) => {
|
|
359
|
+
report({
|
|
360
|
+
messageId: "some-message",
|
|
361
|
+
languageTag: "en",
|
|
362
|
+
body: { en: "lintrule1" },
|
|
363
|
+
});
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
const _mockPlugin = {
|
|
367
|
+
meta: {
|
|
368
|
+
id: "plugin.inlang.i18next",
|
|
369
|
+
description: { en: "Mock plugin description" },
|
|
370
|
+
displayName: { en: "Mock Plugin" },
|
|
371
|
+
},
|
|
372
|
+
loadMessages: () => [{ id: "some-message", selectors: [], variants: [] }],
|
|
373
|
+
saveMessages: () => undefined,
|
|
374
|
+
};
|
|
375
|
+
const fs = await createNodeishMemoryFs();
|
|
376
|
+
await fs.writeFile("./inlang.config.json", JSON.stringify({
|
|
377
|
+
sourceLanguageTag: "en",
|
|
378
|
+
languageTags: ["en"],
|
|
379
|
+
modules: ["plugin.js", "lintRule.js"],
|
|
380
|
+
settings: {},
|
|
381
|
+
}));
|
|
382
|
+
const _import = async (name) => {
|
|
383
|
+
return {
|
|
384
|
+
default: name === "plugin.js" ? _mockPlugin : _mockLintRule,
|
|
385
|
+
};
|
|
386
|
+
};
|
|
387
|
+
const inlang = await openInlangProject({
|
|
388
|
+
projectFilePath: "./inlang.config.json",
|
|
389
|
+
nodeishFs: fs,
|
|
390
|
+
_import,
|
|
391
|
+
});
|
|
392
|
+
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
393
|
+
expect(inlang.query.messageLintReports.get({ where: { messageId: "some-message" } })).toHaveLength(1);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
describe("errors", () => {
|
|
397
|
+
it("should return the errors", async () => {
|
|
398
|
+
const fs = await createNodeishMemoryFs();
|
|
399
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
400
|
+
const inlang = await openInlangProject({
|
|
401
|
+
projectFilePath: "./project.inlang.json",
|
|
402
|
+
nodeishFs: fs,
|
|
403
|
+
_import,
|
|
404
|
+
});
|
|
405
|
+
inlang.errors.subscribe((errors) => {
|
|
406
|
+
expect(errors).toStrictEqual([]);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
describe("customApi", () => {
|
|
411
|
+
it("should return the app specific api", async () => {
|
|
412
|
+
const fs = await createNodeishMemoryFs();
|
|
413
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
414
|
+
const inlang = await openInlangProject({
|
|
415
|
+
projectFilePath: "./project.inlang.json",
|
|
416
|
+
nodeishFs: fs,
|
|
417
|
+
_import,
|
|
418
|
+
});
|
|
419
|
+
inlang.customApi.subscribe((api) => {
|
|
420
|
+
expect(api["app.inlang.ideExtension"]).toBeDefined();
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
describe("messages", () => {
|
|
425
|
+
it("should return the messages", async () => {
|
|
426
|
+
const fs = await createNodeishMemoryFs();
|
|
427
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
428
|
+
const inlang = await openInlangProject({
|
|
429
|
+
projectFilePath: "./project.inlang.json",
|
|
430
|
+
nodeishFs: fs,
|
|
431
|
+
_import,
|
|
432
|
+
});
|
|
433
|
+
expect(Object.values(inlang.query.messages.getAll())).toEqual(exampleMessages);
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
describe("query", () => {
|
|
437
|
+
it("updates should trigger the plugin persistence", async () => {
|
|
438
|
+
const fs = await createNodeishMemoryFs();
|
|
439
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify({
|
|
440
|
+
sourceLanguageTag: "en",
|
|
441
|
+
languageTags: ["en", "de"],
|
|
442
|
+
modules: ["plugin.js"],
|
|
443
|
+
settings: {
|
|
444
|
+
"plugin.inlang.json": {
|
|
445
|
+
pathPattern: "./resources/{languageTag}.json",
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
}));
|
|
449
|
+
await fs.mkdir("./resources");
|
|
450
|
+
const mockSaveFn = vi.fn();
|
|
451
|
+
const _mockPlugin = {
|
|
452
|
+
meta: {
|
|
453
|
+
id: "plugin.inlang.json",
|
|
454
|
+
description: { en: "Mock plugin description" },
|
|
455
|
+
displayName: { en: "Mock Plugin" },
|
|
456
|
+
},
|
|
457
|
+
loadMessages: () => exampleMessages,
|
|
458
|
+
saveMessages: mockSaveFn,
|
|
459
|
+
};
|
|
460
|
+
const _import = async () => {
|
|
461
|
+
return {
|
|
462
|
+
default: _mockPlugin,
|
|
463
|
+
};
|
|
464
|
+
};
|
|
465
|
+
const inlang = await openInlangProject({
|
|
466
|
+
projectFilePath: "./project.inlang.json",
|
|
467
|
+
nodeishFs: fs,
|
|
468
|
+
_import,
|
|
469
|
+
});
|
|
470
|
+
await inlang.query.messages.upsert({
|
|
471
|
+
where: { id: "a" },
|
|
472
|
+
data: {
|
|
473
|
+
id: "a",
|
|
474
|
+
selectors: [],
|
|
475
|
+
variants: [
|
|
476
|
+
{
|
|
477
|
+
languageTag: "en",
|
|
478
|
+
match: {},
|
|
479
|
+
pattern: [
|
|
480
|
+
{
|
|
481
|
+
type: "Text",
|
|
482
|
+
value: "a en",
|
|
483
|
+
},
|
|
484
|
+
],
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
languageTag: "de",
|
|
488
|
+
match: {},
|
|
489
|
+
pattern: [
|
|
490
|
+
{
|
|
491
|
+
type: "Text",
|
|
492
|
+
value: "a de",
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
await inlang.query.messages.upsert({
|
|
500
|
+
where: { id: "b" },
|
|
501
|
+
data: {
|
|
502
|
+
id: "b",
|
|
503
|
+
selectors: [],
|
|
504
|
+
variants: [
|
|
505
|
+
{
|
|
506
|
+
languageTag: "en",
|
|
507
|
+
match: {},
|
|
508
|
+
pattern: [
|
|
509
|
+
{
|
|
510
|
+
type: "Text",
|
|
511
|
+
value: "b en",
|
|
512
|
+
},
|
|
513
|
+
],
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
languageTag: "de",
|
|
517
|
+
match: {},
|
|
518
|
+
pattern: [
|
|
519
|
+
{
|
|
520
|
+
type: "Text",
|
|
521
|
+
value: "b de",
|
|
522
|
+
},
|
|
523
|
+
],
|
|
524
|
+
},
|
|
525
|
+
],
|
|
526
|
+
},
|
|
527
|
+
});
|
|
528
|
+
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
529
|
+
expect(mockSaveFn.mock.calls.length).toBe(1);
|
|
530
|
+
expect(mockSaveFn.mock.calls[0][0].settings).toStrictEqual({
|
|
531
|
+
pathPattern: "./resources/{languageTag}.json",
|
|
532
|
+
});
|
|
533
|
+
expect(Object.values(mockSaveFn.mock.calls[0][0].messages)).toStrictEqual([
|
|
534
|
+
{
|
|
535
|
+
id: "a",
|
|
536
|
+
selectors: [],
|
|
537
|
+
variants: [
|
|
538
|
+
{
|
|
539
|
+
languageTag: "en",
|
|
540
|
+
match: {},
|
|
541
|
+
pattern: [
|
|
542
|
+
{
|
|
543
|
+
type: "Text",
|
|
544
|
+
value: "a en",
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
languageTag: "de",
|
|
550
|
+
match: {},
|
|
551
|
+
pattern: [
|
|
552
|
+
{
|
|
553
|
+
type: "Text",
|
|
554
|
+
value: "a de",
|
|
555
|
+
},
|
|
556
|
+
],
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
id: "b",
|
|
562
|
+
selectors: [],
|
|
563
|
+
variants: [
|
|
564
|
+
{
|
|
565
|
+
languageTag: "en",
|
|
566
|
+
match: {},
|
|
567
|
+
pattern: [
|
|
568
|
+
{
|
|
569
|
+
type: "Text",
|
|
570
|
+
value: "b en",
|
|
571
|
+
},
|
|
572
|
+
],
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
languageTag: "de",
|
|
576
|
+
match: {},
|
|
577
|
+
pattern: [
|
|
578
|
+
{
|
|
579
|
+
type: "Text",
|
|
580
|
+
value: "b de",
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
},
|
|
586
|
+
]);
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
describe("lint", () => {
|
|
590
|
+
it.todo("should throw if lint reports are not initialized yet", async () => {
|
|
591
|
+
const fs = await createNodeishMemoryFs();
|
|
592
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
593
|
+
const inlang = await openInlangProject({
|
|
594
|
+
projectFilePath: "./project.inlang.json",
|
|
595
|
+
nodeishFs: fs,
|
|
596
|
+
_import,
|
|
597
|
+
});
|
|
598
|
+
// TODO: test with real lint rules
|
|
599
|
+
try {
|
|
600
|
+
inlang.query.messageLintReports.getAll.subscribe((r) => expect(r).toEqual(undefined));
|
|
601
|
+
throw new Error("Should not reach this");
|
|
602
|
+
}
|
|
603
|
+
catch (e) {
|
|
604
|
+
expect(e.message).toBe("lint not initialized yet");
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
it("should return the message lint reports", async () => {
|
|
608
|
+
const config = {
|
|
609
|
+
sourceLanguageTag: "en",
|
|
610
|
+
languageTags: ["en"],
|
|
611
|
+
modules: ["lintRule.js"],
|
|
612
|
+
settings: {},
|
|
613
|
+
};
|
|
614
|
+
const fs = createNodeishMemoryFs();
|
|
615
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(config));
|
|
616
|
+
const inlang = await openInlangProject({
|
|
617
|
+
projectFilePath: "./project.inlang.json",
|
|
618
|
+
nodeishFs: fs,
|
|
619
|
+
_import: async () => ({
|
|
620
|
+
default: mockMessageLintRule,
|
|
621
|
+
}),
|
|
622
|
+
});
|
|
623
|
+
// TODO: test with real lint rules
|
|
624
|
+
inlang.query.messageLintReports.getAll.subscribe((r) => expect(r).toEqual([]));
|
|
625
|
+
});
|
|
626
|
+
});
|
|
627
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ProjectConfig } from "./versionedInterfaces.js";
|
|
2
|
+
import type { Result } from "@inlang/result";
|
|
3
|
+
export declare class ParseConfigError extends Error {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(message: string, cause?: string);
|
|
6
|
+
}
|
|
7
|
+
export declare const parseConfig: (config: ProjectConfig) => Result<ProjectConfig, ParseConfigError>;
|
|
8
|
+
//# sourceMappingURL=parseConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseConfig.d.ts","sourceRoot":"","sources":["../src/parseConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAG5C,qBAAa,gBAAiB,SAAQ,KAAK;;gBAG9B,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;CAK3C;AAKD,eAAO,MAAM,WAAW,WAAY,aAAa,KAAG,OAAO,aAAa,EAAE,gBAAgB,CAezF,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ProjectConfig } from "./versionedInterfaces.js";
|
|
2
|
+
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
3
|
+
export class ParseConfigError extends Error {
|
|
4
|
+
#id = "ParseConfigException";
|
|
5
|
+
constructor(message, cause) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = this.#id;
|
|
8
|
+
this.cause = cause;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
// @ts-ignore - fix after refactor
|
|
12
|
+
const ConfigCompiler = TypeCompiler.Compile(ProjectConfig);
|
|
13
|
+
export const parseConfig = (config) => {
|
|
14
|
+
if (ConfigCompiler.Check(config)) {
|
|
15
|
+
return {
|
|
16
|
+
data: config,
|
|
17
|
+
error: undefined,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return {
|
|
22
|
+
error: new ParseConfigError("The inlang config is not valid.", [...ConfigCompiler.Errors(config)].toString()),
|
|
23
|
+
data: undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|