@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,122 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from "vitest"
|
|
2
|
+
import { lintMessages } from "./lintMessages.js"
|
|
3
|
+
import type { MessageLintReport, MessageLintRule } from "@inlang/message-lint-rule"
|
|
4
|
+
import type { Message } from "@inlang/message"
|
|
5
|
+
|
|
6
|
+
const lintRule1 = {
|
|
7
|
+
meta: {
|
|
8
|
+
id: "messageLintRule.x.1",
|
|
9
|
+
displayName: { en: "" },
|
|
10
|
+
description: { en: "" },
|
|
11
|
+
},
|
|
12
|
+
message: vi.fn(),
|
|
13
|
+
} satisfies MessageLintRule
|
|
14
|
+
|
|
15
|
+
const lintRule2 = {
|
|
16
|
+
meta: {
|
|
17
|
+
id: "messageLintRule.x.2",
|
|
18
|
+
displayName: { en: "" },
|
|
19
|
+
description: { en: "" },
|
|
20
|
+
},
|
|
21
|
+
message: vi.fn(),
|
|
22
|
+
} satisfies MessageLintRule
|
|
23
|
+
|
|
24
|
+
const message1 = { id: "m1" } as Message
|
|
25
|
+
const message2 = { id: "m2" } as Message
|
|
26
|
+
const message3 = { id: "m3" } as Message
|
|
27
|
+
|
|
28
|
+
const messages = [message1, message2, message3]
|
|
29
|
+
|
|
30
|
+
describe("lintMessages", async () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
vi.resetAllMocks()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test("it should await all messages", async () => {
|
|
36
|
+
let called = 0
|
|
37
|
+
lintRule2.message.mockImplementation(async () => {
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
39
|
+
called++
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
await lintMessages({
|
|
43
|
+
ruleLevels: {
|
|
44
|
+
[lintRule1.meta.id]: "warning",
|
|
45
|
+
[lintRule2.meta.id]: "warning",
|
|
46
|
+
},
|
|
47
|
+
ruleSettings: {},
|
|
48
|
+
sourceLanguageTag: "en",
|
|
49
|
+
languageTags: [],
|
|
50
|
+
messages,
|
|
51
|
+
rules: [lintRule1, lintRule2],
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
expect(lintRule1.message).toHaveBeenCalledTimes(3)
|
|
55
|
+
expect(called).toBe(3)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test("it should process all messages and rules in parallel", async () => {
|
|
59
|
+
const fn = vi.fn()
|
|
60
|
+
|
|
61
|
+
lintRule1.message.mockImplementation(async ({ message }) => {
|
|
62
|
+
fn("r1", "before", message.id)
|
|
63
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
64
|
+
fn("r1", "after", message.id)
|
|
65
|
+
})
|
|
66
|
+
lintRule2.message.mockImplementation(async ({ message }) => {
|
|
67
|
+
fn("r2", "before", message.id)
|
|
68
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
69
|
+
fn("r2", "after", message.id)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
await lintMessages({
|
|
73
|
+
ruleLevels: {
|
|
74
|
+
[lintRule1.meta.id]: "warning",
|
|
75
|
+
[lintRule2.meta.id]: "warning",
|
|
76
|
+
},
|
|
77
|
+
ruleSettings: {},
|
|
78
|
+
rules: [lintRule1, lintRule2],
|
|
79
|
+
sourceLanguageTag: "en",
|
|
80
|
+
languageTags: [],
|
|
81
|
+
messages,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
expect(fn).toHaveBeenCalledTimes(12)
|
|
85
|
+
expect(fn).toHaveBeenNthCalledWith(1, "r1", "before", "m1")
|
|
86
|
+
expect(fn).toHaveBeenNthCalledWith(2, "r2", "before", "m1")
|
|
87
|
+
expect(fn).toHaveBeenNthCalledWith(3, "r1", "before", "m2")
|
|
88
|
+
expect(fn).toHaveBeenNthCalledWith(4, "r2", "before", "m2")
|
|
89
|
+
expect(fn).toHaveBeenNthCalledWith(5, "r1", "before", "m3")
|
|
90
|
+
expect(fn).toHaveBeenNthCalledWith(6, "r2", "before", "m3")
|
|
91
|
+
expect(fn).toHaveBeenNthCalledWith(7, "r1", "after", "m1")
|
|
92
|
+
expect(fn).toHaveBeenNthCalledWith(8, "r2", "after", "m1")
|
|
93
|
+
expect(fn).toHaveBeenNthCalledWith(9, "r1", "after", "m2")
|
|
94
|
+
expect(fn).toHaveBeenNthCalledWith(10, "r2", "after", "m2")
|
|
95
|
+
expect(fn).toHaveBeenNthCalledWith(11, "r1", "after", "m3")
|
|
96
|
+
expect(fn).toHaveBeenNthCalledWith(12, "r2", "after", "m3")
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test("it should not abort the linting process when errors occur", async () => {
|
|
100
|
+
lintRule1.message.mockImplementation(({ report }) => {
|
|
101
|
+
report({} as MessageLintReport)
|
|
102
|
+
})
|
|
103
|
+
lintRule2.message.mockImplementation(() => {
|
|
104
|
+
throw new Error("error")
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const { data, errors } = await lintMessages({
|
|
108
|
+
ruleLevels: {
|
|
109
|
+
[lintRule1.meta.id]: "warning",
|
|
110
|
+
[lintRule2.meta.id]: "warning",
|
|
111
|
+
},
|
|
112
|
+
ruleSettings: {},
|
|
113
|
+
sourceLanguageTag: "en",
|
|
114
|
+
languageTags: [],
|
|
115
|
+
messages,
|
|
116
|
+
rules: [lintRule1, lintRule2],
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
expect(data).toHaveLength(3)
|
|
120
|
+
expect(errors).toHaveLength(3)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Message } from "@inlang/message"
|
|
2
|
+
import { lintSingleMessage } from "./lintSingleMessage.js"
|
|
3
|
+
import type { MessagedLintRuleThrowedError } from "./errors.js"
|
|
4
|
+
import type { LanguageTag } from "@inlang/language-tag"
|
|
5
|
+
import type { JSONObject } from "@inlang/json-types"
|
|
6
|
+
import type {
|
|
7
|
+
MessageLintLevel,
|
|
8
|
+
MessageLintReport,
|
|
9
|
+
MessageLintRule,
|
|
10
|
+
} from "@inlang/message-lint-rule"
|
|
11
|
+
|
|
12
|
+
export const lintMessages = async (args: {
|
|
13
|
+
sourceLanguageTag: LanguageTag
|
|
14
|
+
languageTags: LanguageTag[]
|
|
15
|
+
ruleSettings: Record<MessageLintRule["meta"]["id"], JSONObject>
|
|
16
|
+
ruleLevels: Record<MessageLintRule["meta"]["id"], MessageLintLevel>
|
|
17
|
+
rules: MessageLintRule[]
|
|
18
|
+
messages: Message[]
|
|
19
|
+
}): Promise<{ data: MessageLintReport[]; errors: MessagedLintRuleThrowedError[] }> => {
|
|
20
|
+
const promises = args.messages.map((message) =>
|
|
21
|
+
lintSingleMessage({
|
|
22
|
+
...args,
|
|
23
|
+
message,
|
|
24
|
+
}),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const results = await Promise.all(promises)
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
data: results.flatMap((result) => result.data).filter(Boolean),
|
|
31
|
+
errors: results.flatMap((result) => result.errors).filter(Boolean),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from "vitest"
|
|
2
|
+
import { lintSingleMessage } from "./lintSingleMessage.js"
|
|
3
|
+
import type { MessageLintReport, MessageLintRule } from "@inlang/message-lint-rule"
|
|
4
|
+
import type { Message } from "@inlang/message"
|
|
5
|
+
import { tryCatch } from "@inlang/result"
|
|
6
|
+
|
|
7
|
+
const lintRule1 = {
|
|
8
|
+
meta: {
|
|
9
|
+
id: "messageLintRule.r.1",
|
|
10
|
+
displayName: { en: "" },
|
|
11
|
+
description: { en: "" },
|
|
12
|
+
},
|
|
13
|
+
message: vi.fn(),
|
|
14
|
+
} satisfies MessageLintRule
|
|
15
|
+
|
|
16
|
+
const lintRule2 = {
|
|
17
|
+
meta: {
|
|
18
|
+
id: "messageLintRule.r.2",
|
|
19
|
+
displayName: { en: "" },
|
|
20
|
+
description: { en: "" },
|
|
21
|
+
},
|
|
22
|
+
message: vi.fn(),
|
|
23
|
+
} satisfies MessageLintRule
|
|
24
|
+
|
|
25
|
+
const message1 = {} as Message
|
|
26
|
+
|
|
27
|
+
const messages = [message1]
|
|
28
|
+
|
|
29
|
+
describe("lintSingleMessage", async () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
vi.resetAllMocks()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
describe("resolve rules and settings", async () => {
|
|
35
|
+
// the lint function is un-opinionated and does not set a default level.
|
|
36
|
+
// opinionated users like the inlang instance can very well set a default level (separation of concerns)
|
|
37
|
+
test("it should throw if a lint level is not provided for a given lint rule", async () => {
|
|
38
|
+
lintRule1.message.mockImplementation(({ report }) => report({} as MessageLintReport))
|
|
39
|
+
|
|
40
|
+
const result = await tryCatch(() =>
|
|
41
|
+
lintSingleMessage({
|
|
42
|
+
ruleLevels: {},
|
|
43
|
+
ruleSettings: {},
|
|
44
|
+
sourceLanguageTag: "en",
|
|
45
|
+
languageTags: ["en"],
|
|
46
|
+
messages,
|
|
47
|
+
message: message1,
|
|
48
|
+
rules: [lintRule1],
|
|
49
|
+
}),
|
|
50
|
+
)
|
|
51
|
+
expect(result.error).toBeDefined()
|
|
52
|
+
expect(result.data).toBeUndefined()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test("it should override the default lint level", async () => {
|
|
56
|
+
lintRule1.message.mockImplementation(({ report }) => report({} as MessageLintReport))
|
|
57
|
+
|
|
58
|
+
const reports = await lintSingleMessage({
|
|
59
|
+
ruleLevels: {
|
|
60
|
+
[lintRule1.meta.id]: "error",
|
|
61
|
+
},
|
|
62
|
+
ruleSettings: {},
|
|
63
|
+
sourceLanguageTag: "en",
|
|
64
|
+
languageTags: ["en"],
|
|
65
|
+
messages,
|
|
66
|
+
message: message1,
|
|
67
|
+
rules: [lintRule1],
|
|
68
|
+
})
|
|
69
|
+
expect(reports.data[0]?.level).toBe("error")
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test("it should pass the correct settings", async () => {
|
|
73
|
+
const settings = {}
|
|
74
|
+
|
|
75
|
+
const fn = vi.fn()
|
|
76
|
+
lintRule1.message.mockImplementation(({ settings }) => fn(settings))
|
|
77
|
+
|
|
78
|
+
await lintSingleMessage({
|
|
79
|
+
ruleLevels: {
|
|
80
|
+
[lintRule1.meta.id]: "warning",
|
|
81
|
+
},
|
|
82
|
+
ruleSettings: {
|
|
83
|
+
[lintRule1.meta.id]: settings,
|
|
84
|
+
},
|
|
85
|
+
sourceLanguageTag: "en",
|
|
86
|
+
languageTags: ["en"],
|
|
87
|
+
messages,
|
|
88
|
+
message: message1,
|
|
89
|
+
rules: [lintRule1],
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
expect(fn).toHaveBeenCalledWith(settings)
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test("it should await all rules", async () => {
|
|
97
|
+
let m1Called = false
|
|
98
|
+
let m2Called = false
|
|
99
|
+
lintRule1.message.mockImplementation(() => {
|
|
100
|
+
m1Called = true
|
|
101
|
+
})
|
|
102
|
+
lintRule2.message.mockImplementation(async () => {
|
|
103
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
104
|
+
m2Called = true
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
await lintSingleMessage({
|
|
108
|
+
ruleLevels: {
|
|
109
|
+
[lintRule1.meta.id]: "warning",
|
|
110
|
+
[lintRule2.meta.id]: "warning",
|
|
111
|
+
},
|
|
112
|
+
ruleSettings: {},
|
|
113
|
+
sourceLanguageTag: "en",
|
|
114
|
+
languageTags: ["en"],
|
|
115
|
+
messages,
|
|
116
|
+
message: message1,
|
|
117
|
+
rules: [lintRule1, lintRule2],
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(m1Called).toBe(true)
|
|
121
|
+
expect(m2Called).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test("it should process all rules in parallel", async () => {
|
|
125
|
+
const fn = vi.fn()
|
|
126
|
+
|
|
127
|
+
lintRule1.message.mockImplementation(async () => {
|
|
128
|
+
fn(lintRule1.meta.id, "before")
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
130
|
+
fn(lintRule1.meta.id, "after")
|
|
131
|
+
})
|
|
132
|
+
lintRule2.message.mockImplementation(async () => {
|
|
133
|
+
fn(lintRule2.meta.id, "before")
|
|
134
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
135
|
+
fn(lintRule2.meta.id, "after")
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
await lintSingleMessage({
|
|
139
|
+
ruleLevels: {
|
|
140
|
+
[lintRule1.meta.id]: "warning",
|
|
141
|
+
[lintRule2.meta.id]: "warning",
|
|
142
|
+
},
|
|
143
|
+
ruleSettings: {},
|
|
144
|
+
sourceLanguageTag: "en",
|
|
145
|
+
languageTags: ["en"],
|
|
146
|
+
messages,
|
|
147
|
+
message: message1,
|
|
148
|
+
rules: [lintRule1, lintRule2],
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
expect(fn).toHaveBeenCalledTimes(4)
|
|
152
|
+
expect(fn).toHaveBeenNthCalledWith(1, lintRule1.meta.id, "before")
|
|
153
|
+
expect(fn).toHaveBeenNthCalledWith(2, lintRule2.meta.id, "before")
|
|
154
|
+
expect(fn).toHaveBeenNthCalledWith(3, lintRule1.meta.id, "after")
|
|
155
|
+
expect(fn).toHaveBeenNthCalledWith(4, lintRule2.meta.id, "after")
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test("it should not abort the linting process when errors occur", async () => {
|
|
159
|
+
lintRule1.message.mockImplementation(() => {
|
|
160
|
+
throw new Error("error")
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
lintRule2.message.mockImplementation(({ report }) => {
|
|
164
|
+
report({} as MessageLintReport)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const result = await lintSingleMessage({
|
|
168
|
+
ruleLevels: {
|
|
169
|
+
[lintRule1.meta.id]: "warning",
|
|
170
|
+
[lintRule2.meta.id]: "warning",
|
|
171
|
+
},
|
|
172
|
+
ruleSettings: {},
|
|
173
|
+
sourceLanguageTag: "en",
|
|
174
|
+
languageTags: ["en"],
|
|
175
|
+
messages,
|
|
176
|
+
message: message1,
|
|
177
|
+
rules: [lintRule1, lintRule2],
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
expect(result.data).length(1)
|
|
181
|
+
expect(result.errors).length(1)
|
|
182
|
+
})
|
|
183
|
+
})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MessageLintLevel,
|
|
3
|
+
MessageLintRule,
|
|
4
|
+
MessageLintReport,
|
|
5
|
+
} from "@inlang/message-lint-rule"
|
|
6
|
+
import type { Message } from "@inlang/message"
|
|
7
|
+
import { MessagedLintRuleThrowedError } from "./errors.js"
|
|
8
|
+
import type { LanguageTag } from "@inlang/language-tag"
|
|
9
|
+
import type { JSONObject } from "@inlang/json-types"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Lint a single message.
|
|
13
|
+
*
|
|
14
|
+
* - the lint rule levels defaults to `warning`.
|
|
15
|
+
*/
|
|
16
|
+
export const lintSingleMessage = async (args: {
|
|
17
|
+
sourceLanguageTag: LanguageTag
|
|
18
|
+
languageTags: LanguageTag[]
|
|
19
|
+
ruleSettings: Record<MessageLintRule["meta"]["id"], JSONObject>
|
|
20
|
+
ruleLevels: Record<MessageLintRule["meta"]["id"], MessageLintLevel>
|
|
21
|
+
rules: MessageLintRule[]
|
|
22
|
+
messages: Message[]
|
|
23
|
+
message: Message
|
|
24
|
+
}): Promise<{ data: MessageLintReport[]; errors: MessagedLintRuleThrowedError[] }> => {
|
|
25
|
+
const reports: MessageLintReport[] = []
|
|
26
|
+
const errors: MessagedLintRuleThrowedError[] = []
|
|
27
|
+
|
|
28
|
+
const promises = args.rules.map(async (rule) => {
|
|
29
|
+
const ruleId = rule.meta.id
|
|
30
|
+
const settings = args.ruleSettings?.[ruleId] ?? {}
|
|
31
|
+
const level = args.ruleLevels?.[ruleId]
|
|
32
|
+
|
|
33
|
+
if (level === undefined) {
|
|
34
|
+
throw Error("No lint level provided for lint rule: " + ruleId)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await rule.message({
|
|
39
|
+
...args,
|
|
40
|
+
settings,
|
|
41
|
+
report: (reportArgs) => {
|
|
42
|
+
reports.push({
|
|
43
|
+
ruleId,
|
|
44
|
+
level,
|
|
45
|
+
...reportArgs,
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
} catch (error) {
|
|
50
|
+
errors.push(
|
|
51
|
+
new MessagedLintRuleThrowedError(
|
|
52
|
+
`Lint rule '${ruleId}' throwed while linting message "${args.message.id}".`,
|
|
53
|
+
{ cause: error },
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
await Promise.all(promises)
|
|
60
|
+
|
|
61
|
+
return { data: reports, errors }
|
|
62
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class MessageVariantDoesNotExistError extends Error {
|
|
2
|
+
readonly #id = "MessageVariantDoesNotExistError"
|
|
3
|
+
|
|
4
|
+
constructor(messageId: string, languageTag: string) {
|
|
5
|
+
super(
|
|
6
|
+
`For message '${messageId}' and '${languageTag}', there doesn't exist a variant for this specific matchers.`,
|
|
7
|
+
)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class MessageVariantAlreadyExistsError extends Error {
|
|
11
|
+
readonly #id = "MessageVariantAlreadyExistsError"
|
|
12
|
+
|
|
13
|
+
constructor(messageId: string, languageTag: string) {
|
|
14
|
+
super(
|
|
15
|
+
`For message '${messageId}' and '${languageTag}', there already exists a variant for this specific matchers.`,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class MessagePatternsForLanguageTagDoNotExistError extends Error {
|
|
20
|
+
readonly #id = "MessagePatternsForLanguageTagDoNotExistError"
|
|
21
|
+
|
|
22
|
+
constructor(messageId: string, languageTag: string) {
|
|
23
|
+
super(`For message '${messageId}' there are no patterns with the languageTag '${languageTag}'.`)
|
|
24
|
+
}
|
|
25
|
+
}
|