@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,44 @@
|
|
|
1
|
+
class PluginError extends Error {
|
|
2
|
+
plugin;
|
|
3
|
+
constructor(message, options) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "PluginError";
|
|
6
|
+
this.plugin = options.plugin;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class PluginHasInvalidIdError extends PluginError {
|
|
10
|
+
constructor(message, options) {
|
|
11
|
+
super(message, options);
|
|
12
|
+
this.name = "PluginHasInvalidIdError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class PluginUsesReservedNamespaceError extends PluginError {
|
|
16
|
+
constructor(message, options) {
|
|
17
|
+
super(message, options);
|
|
18
|
+
this.name = "PluginUsesReservedNamespaceError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class PluginHasInvalidSchemaError extends PluginError {
|
|
22
|
+
constructor(message, options) {
|
|
23
|
+
super(message, options);
|
|
24
|
+
this.name = "PluginHasInvalidSchemaError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class PluginLoadMessagesFunctionAlreadyDefinedError extends PluginError {
|
|
28
|
+
constructor(message, options) {
|
|
29
|
+
super(message, options);
|
|
30
|
+
this.name = "PluginLoadMessagesFunctionAlreadyDefinedError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class PluginSaveMessagesFunctionAlreadyDefinedError extends PluginError {
|
|
34
|
+
constructor(message, options) {
|
|
35
|
+
super(message, options);
|
|
36
|
+
this.name = "PluginSaveMessagesFunctionAlreadyDefinedError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class PluginReturnedInvalidCustomApiError extends PluginError {
|
|
40
|
+
constructor(message, options) {
|
|
41
|
+
super(message, options);
|
|
42
|
+
this.name = "PluginReturnedInvalidCustomApiError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePlugins.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/resolvePlugins.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAsBxD,eAAO,MAAM,cAAc,EAAE,sBAkJ5B,CAAA"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Plugin } from "@inlang/plugin";
|
|
2
|
+
import { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, PluginUsesReservedNamespaceError, } from "./errors.js";
|
|
3
|
+
import { deepmerge } from "deepmerge-ts";
|
|
4
|
+
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
5
|
+
import { tryCatch } from "@inlang/result";
|
|
6
|
+
const whitelistedPlugins = [
|
|
7
|
+
"plugin.inlang.json",
|
|
8
|
+
"plugin.inlang.i18next",
|
|
9
|
+
"plugin.inlang.paraglideJs",
|
|
10
|
+
];
|
|
11
|
+
// @ts-ignore - type mismatch error
|
|
12
|
+
const PluginCompiler = TypeCompiler.Compile(Plugin);
|
|
13
|
+
export const resolvePlugins = async (args) => {
|
|
14
|
+
const result = {
|
|
15
|
+
data: {
|
|
16
|
+
loadMessages: undefined,
|
|
17
|
+
saveMessages: undefined,
|
|
18
|
+
detectedLanguageTags: [],
|
|
19
|
+
customApi: {},
|
|
20
|
+
},
|
|
21
|
+
errors: [],
|
|
22
|
+
};
|
|
23
|
+
for (const plugin of args.plugins) {
|
|
24
|
+
const errors = [...PluginCompiler.Errors(plugin)];
|
|
25
|
+
/**
|
|
26
|
+
* -------------- RESOLVE PLUGIN --------------
|
|
27
|
+
*/
|
|
28
|
+
// -- INVALID ID in META --
|
|
29
|
+
const hasInvalidId = errors.some((error) => error.path === "/meta/id");
|
|
30
|
+
if (hasInvalidId) {
|
|
31
|
+
result.errors.push(new PluginHasInvalidIdError(`Plugin ${plugin.meta.id} has an invalid id "${plugin.meta.id}". It must be kebap-case and contain a namespace like project.my-plugin.`, { plugin: plugin.meta.id }));
|
|
32
|
+
}
|
|
33
|
+
// -- USES RESERVED NAMESPACE --
|
|
34
|
+
if (plugin.meta.id.includes("inlang") && !whitelistedPlugins.includes(plugin.meta.id)) {
|
|
35
|
+
result.errors.push(new PluginUsesReservedNamespaceError(`Plugin ${plugin.meta.id} uses reserved namespace 'inlang'.`, {
|
|
36
|
+
plugin: plugin.meta.id,
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
// -- USES INVALID SCHEMA --
|
|
40
|
+
if (errors.length > 0) {
|
|
41
|
+
result.errors.push(new PluginHasInvalidSchemaError(`Plugin ${plugin.meta.id} uses an invalid schema. Please check the documentation for the correct Plugin type.`, {
|
|
42
|
+
plugin: plugin.meta.id,
|
|
43
|
+
cause: errors,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
// -- ALREADY DEFINED LOADMESSAGES / SAVEMESSAGES / DETECTEDLANGUAGETAGS --
|
|
47
|
+
if (typeof plugin.loadMessages === "function" && result.data.loadMessages !== undefined) {
|
|
48
|
+
result.errors.push(new PluginLoadMessagesFunctionAlreadyDefinedError(`Plugin ${plugin.meta.id} defines the loadMessages function, but it was already defined by another plugin.`, { plugin: plugin.meta.id }));
|
|
49
|
+
}
|
|
50
|
+
if (typeof plugin.saveMessages === "function" && result.data.saveMessages !== undefined) {
|
|
51
|
+
result.errors.push(new PluginSaveMessagesFunctionAlreadyDefinedError(`Plugin ${plugin.meta.id} defines the saveMessages function, but it was already defined by another plugin.`, { plugin: plugin.meta.id }));
|
|
52
|
+
}
|
|
53
|
+
// --- ADD APP SPECIFIC API ---
|
|
54
|
+
if (typeof plugin.addCustomApi === "function") {
|
|
55
|
+
// TODO: why do we call this function 2 times (here for validation and later for retrieving the actual value)?
|
|
56
|
+
const { data: customApi, error } = tryCatch(() => plugin.addCustomApi({
|
|
57
|
+
settings: args.settings?.[plugin.meta.id] ?? {},
|
|
58
|
+
}));
|
|
59
|
+
if (error) {
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
delete error.stack;
|
|
62
|
+
result.errors.push(error); // TODO: add correct error type
|
|
63
|
+
}
|
|
64
|
+
if (typeof customApi !== "object") {
|
|
65
|
+
result.errors.push(new PluginReturnedInvalidCustomApiError(`Plugin ${plugin.meta.id} defines the addCustomApi function, but it does not return an object.`, { plugin: plugin.meta.id, cause: error }));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// -- CONTINUE IF ERRORS --
|
|
69
|
+
if (result.errors.length > 0) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* -------------- BEGIN ADDING TO RESULT --------------
|
|
74
|
+
*/
|
|
75
|
+
if (typeof plugin.loadMessages === "function") {
|
|
76
|
+
result.data.loadMessages = (_args) => plugin.loadMessages({
|
|
77
|
+
..._args,
|
|
78
|
+
settings: args.settings?.[plugin.meta.id] ?? {},
|
|
79
|
+
nodeishFs: args.nodeishFs,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (typeof plugin.saveMessages === "function") {
|
|
83
|
+
result.data.saveMessages = (_args) => plugin.saveMessages({
|
|
84
|
+
..._args,
|
|
85
|
+
settings: args.settings?.[plugin.meta.id] ?? {},
|
|
86
|
+
nodeishFs: args.nodeishFs,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (typeof plugin.detectedLanguageTags === "function") {
|
|
90
|
+
const detectedLangugeTags = await plugin.detectedLanguageTags({
|
|
91
|
+
settings: args.settings?.[plugin.meta.id] ?? {},
|
|
92
|
+
nodeishFs: args.nodeishFs,
|
|
93
|
+
});
|
|
94
|
+
result.data.detectedLanguageTags = [
|
|
95
|
+
...new Set([...result.data.detectedLanguageTags, ...detectedLangugeTags]),
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
if (typeof plugin.addCustomApi === "function") {
|
|
99
|
+
const { data: customApi } = tryCatch(() => plugin.addCustomApi({
|
|
100
|
+
settings: args.settings?.[plugin.meta.id] ?? {},
|
|
101
|
+
}));
|
|
102
|
+
if (customApi) {
|
|
103
|
+
result.data.customApi = deepmerge(result.data.customApi, customApi);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePlugins.test.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/resolvePlugins.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { resolvePlugins } from "./resolvePlugins.js";
|
|
4
|
+
import { PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginUsesReservedNamespaceError, PluginReturnedInvalidCustomApiError, PluginHasInvalidSchemaError, } from "./errors.js";
|
|
5
|
+
describe("generally", () => {
|
|
6
|
+
it("should return an error if a plugin uses an invalid id", async () => {
|
|
7
|
+
const mockPlugin = {
|
|
8
|
+
meta: {
|
|
9
|
+
// @ts-expect-error - invalid id
|
|
10
|
+
id: "no-namespace",
|
|
11
|
+
description: { en: "My plugin description" },
|
|
12
|
+
displayName: { en: "My plugin" },
|
|
13
|
+
},
|
|
14
|
+
loadMessages: () => undefined,
|
|
15
|
+
saveMessages: () => undefined,
|
|
16
|
+
addCustomApi() {
|
|
17
|
+
return {};
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
const resolved = await resolvePlugins({
|
|
21
|
+
plugins: [mockPlugin],
|
|
22
|
+
settings: {},
|
|
23
|
+
nodeishFs: {},
|
|
24
|
+
});
|
|
25
|
+
expect(resolved.errors[0]).toBeInstanceOf(PluginHasInvalidIdError);
|
|
26
|
+
});
|
|
27
|
+
it("should return an error if a plugin uses APIs that are not available", async () => {
|
|
28
|
+
const mockPlugin = {
|
|
29
|
+
meta: {
|
|
30
|
+
id: "plugin.namespace.undefinedApi",
|
|
31
|
+
description: { en: "My plugin description" },
|
|
32
|
+
displayName: { en: "My plugin" },
|
|
33
|
+
},
|
|
34
|
+
// @ts-expect-error the key is not available in type
|
|
35
|
+
nonExistentKey: {
|
|
36
|
+
nonexistentOptions: "value",
|
|
37
|
+
},
|
|
38
|
+
loadMessages: () => undefined,
|
|
39
|
+
saveMessages: () => undefined,
|
|
40
|
+
};
|
|
41
|
+
const resolved = await resolvePlugins({
|
|
42
|
+
plugins: [mockPlugin],
|
|
43
|
+
settings: {},
|
|
44
|
+
nodeishFs: {},
|
|
45
|
+
});
|
|
46
|
+
expect(resolved.errors.length).toBe(1);
|
|
47
|
+
expect(resolved.errors[0]).toBeInstanceOf(PluginHasInvalidSchemaError);
|
|
48
|
+
});
|
|
49
|
+
it("should not initialize a plugin that uses the 'inlang' namespace except for inlang whitelisted plugins", async () => {
|
|
50
|
+
const mockPlugin = {
|
|
51
|
+
meta: {
|
|
52
|
+
id: "plugin.inlang.notWhitelisted",
|
|
53
|
+
description: { en: "My plugin description" },
|
|
54
|
+
displayName: { en: "My plugin" },
|
|
55
|
+
},
|
|
56
|
+
loadMessages: () => undefined,
|
|
57
|
+
};
|
|
58
|
+
const resolved = await resolvePlugins({
|
|
59
|
+
plugins: [mockPlugin],
|
|
60
|
+
settings: {},
|
|
61
|
+
nodeishFs: {},
|
|
62
|
+
});
|
|
63
|
+
expect(resolved.errors.length).toBe(1);
|
|
64
|
+
expect(resolved.errors[0]).toBeInstanceOf(PluginUsesReservedNamespaceError);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe("loadMessages", () => {
|
|
68
|
+
it("should load messages from a local source", async () => {
|
|
69
|
+
const mockPlugin = {
|
|
70
|
+
meta: {
|
|
71
|
+
id: "plugin.namespace.placeholder",
|
|
72
|
+
description: { en: "My plugin description" },
|
|
73
|
+
displayName: { en: "My plugin" },
|
|
74
|
+
},
|
|
75
|
+
loadMessages: async () => [{ id: "test", expressions: [], selectors: [], variants: [] }],
|
|
76
|
+
};
|
|
77
|
+
const resolved = await resolvePlugins({
|
|
78
|
+
plugins: [mockPlugin],
|
|
79
|
+
settings: {},
|
|
80
|
+
nodeishFs: {},
|
|
81
|
+
});
|
|
82
|
+
expect(await resolved.data.loadMessages({
|
|
83
|
+
languageTags: ["en"],
|
|
84
|
+
sourceLanguageTag: "en",
|
|
85
|
+
})).toEqual([{ id: "test", expressions: [], selectors: [], variants: [] }]);
|
|
86
|
+
});
|
|
87
|
+
it("should collect an error if function is defined twice in multiple plugins", async () => {
|
|
88
|
+
const mockPlugin = {
|
|
89
|
+
meta: {
|
|
90
|
+
id: "plugin.namepsace.loadMessagesFirst",
|
|
91
|
+
description: { en: "My plugin description" },
|
|
92
|
+
displayName: { en: "My plugin" },
|
|
93
|
+
},
|
|
94
|
+
loadMessages: async () => undefined,
|
|
95
|
+
};
|
|
96
|
+
const mockPlugin2 = {
|
|
97
|
+
meta: {
|
|
98
|
+
id: "plugin.namepsace.loadMessagesSecond",
|
|
99
|
+
description: { en: "My plugin description" },
|
|
100
|
+
displayName: { en: "My plugin" },
|
|
101
|
+
},
|
|
102
|
+
loadMessages: async () => undefined,
|
|
103
|
+
};
|
|
104
|
+
const resolved = await resolvePlugins({
|
|
105
|
+
plugins: [mockPlugin, mockPlugin2],
|
|
106
|
+
nodeishFs: {},
|
|
107
|
+
settings: {},
|
|
108
|
+
});
|
|
109
|
+
expect(resolved.errors).toHaveLength(1);
|
|
110
|
+
expect(resolved.errors[0]).toBeInstanceOf(PluginLoadMessagesFunctionAlreadyDefinedError);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe("saveMessages", () => {
|
|
114
|
+
it("should save messages to a local source", async () => {
|
|
115
|
+
const mockPlugin = {
|
|
116
|
+
meta: {
|
|
117
|
+
id: "plugin.namespace.placeholder",
|
|
118
|
+
description: { en: "My plugin description" },
|
|
119
|
+
displayName: { en: "My plugin" },
|
|
120
|
+
},
|
|
121
|
+
saveMessages: async () => undefined,
|
|
122
|
+
};
|
|
123
|
+
const resolved = await resolvePlugins({
|
|
124
|
+
plugins: [mockPlugin],
|
|
125
|
+
nodeishFs: {},
|
|
126
|
+
settings: {},
|
|
127
|
+
});
|
|
128
|
+
expect(resolved.errors).toHaveLength(0);
|
|
129
|
+
});
|
|
130
|
+
it("should collect an error if function is defined twice in multiple plugins", async () => {
|
|
131
|
+
const mockPlugin = {
|
|
132
|
+
meta: {
|
|
133
|
+
id: "plugin.namepsace.saveMessages",
|
|
134
|
+
description: { en: "My plugin description" },
|
|
135
|
+
displayName: { en: "My plugin" },
|
|
136
|
+
},
|
|
137
|
+
saveMessages: async () => undefined,
|
|
138
|
+
};
|
|
139
|
+
const mockPlugin2 = {
|
|
140
|
+
meta: {
|
|
141
|
+
id: "plugin.namepsace.saveMessages2",
|
|
142
|
+
description: { en: "My plugin description" },
|
|
143
|
+
displayName: { en: "My plugin" },
|
|
144
|
+
},
|
|
145
|
+
saveMessages: async () => undefined,
|
|
146
|
+
};
|
|
147
|
+
const resolved = await resolvePlugins({
|
|
148
|
+
plugins: [mockPlugin, mockPlugin2],
|
|
149
|
+
settings: {},
|
|
150
|
+
nodeishFs: {},
|
|
151
|
+
});
|
|
152
|
+
expect(resolved.errors).toHaveLength(1);
|
|
153
|
+
expect(resolved.errors[0]).toBeInstanceOf(PluginSaveMessagesFunctionAlreadyDefinedError);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
describe("detectedLanguageTags", () => {
|
|
157
|
+
it("should merge language tags from plugins", async () => {
|
|
158
|
+
const mockPlugin = {
|
|
159
|
+
meta: {
|
|
160
|
+
id: "plugin.namepsace.detectedLanguageTags",
|
|
161
|
+
description: { en: "My plugin description" },
|
|
162
|
+
displayName: { en: "My plugin" },
|
|
163
|
+
},
|
|
164
|
+
detectedLanguageTags: async () => ["de", "en"],
|
|
165
|
+
addCustomApi: () => {
|
|
166
|
+
return {};
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const mockPlugin2 = {
|
|
170
|
+
meta: {
|
|
171
|
+
id: "plugin.namepsace.detectedLanguageTags2",
|
|
172
|
+
description: { en: "My plugin description" },
|
|
173
|
+
displayName: { en: "My plugin" },
|
|
174
|
+
},
|
|
175
|
+
addCustomApi: () => {
|
|
176
|
+
return {};
|
|
177
|
+
},
|
|
178
|
+
detectedLanguageTags: async () => ["de", "fr"],
|
|
179
|
+
};
|
|
180
|
+
const resolved = await resolvePlugins({
|
|
181
|
+
plugins: [mockPlugin, mockPlugin2],
|
|
182
|
+
settings: {},
|
|
183
|
+
nodeishFs: {},
|
|
184
|
+
});
|
|
185
|
+
expect(resolved.data.detectedLanguageTags).toEqual(["de", "en", "fr"]);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe("addCustomApi", () => {
|
|
189
|
+
it("it should resolve app specific api", async () => {
|
|
190
|
+
const mockPlugin = {
|
|
191
|
+
meta: {
|
|
192
|
+
id: "plugin.namespace.placeholder",
|
|
193
|
+
description: { en: "My plugin description" },
|
|
194
|
+
displayName: { en: "My plugin" },
|
|
195
|
+
},
|
|
196
|
+
addCustomApi: () => ({
|
|
197
|
+
"my-app": {
|
|
198
|
+
messageReferenceMatcher: () => undefined,
|
|
199
|
+
},
|
|
200
|
+
}),
|
|
201
|
+
};
|
|
202
|
+
const resolved = await resolvePlugins({
|
|
203
|
+
plugins: [mockPlugin],
|
|
204
|
+
settings: {},
|
|
205
|
+
nodeishFs: {},
|
|
206
|
+
});
|
|
207
|
+
expect(resolved.data.customApi).toHaveProperty("my-app");
|
|
208
|
+
});
|
|
209
|
+
it("it should resolve multiple app specific apis", async () => {
|
|
210
|
+
const mockPlugin = {
|
|
211
|
+
meta: {
|
|
212
|
+
id: "plugin.namespace.placeholder",
|
|
213
|
+
description: { en: "My plugin description" },
|
|
214
|
+
displayName: { en: "My plugin" },
|
|
215
|
+
},
|
|
216
|
+
addCustomApi: () => ({
|
|
217
|
+
"my-app-1": {
|
|
218
|
+
functionOfMyApp1: () => undefined,
|
|
219
|
+
},
|
|
220
|
+
"my-app-2": {
|
|
221
|
+
functionOfMyApp2: () => undefined,
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
224
|
+
};
|
|
225
|
+
const mockPlugin2 = {
|
|
226
|
+
meta: {
|
|
227
|
+
id: "plugin.namespace.placeholder2",
|
|
228
|
+
description: { en: "My plugin description" },
|
|
229
|
+
displayName: { en: "My plugin" },
|
|
230
|
+
},
|
|
231
|
+
addCustomApi: () => ({
|
|
232
|
+
"my-app-3": {
|
|
233
|
+
functionOfMyApp3: () => undefined,
|
|
234
|
+
},
|
|
235
|
+
}),
|
|
236
|
+
};
|
|
237
|
+
const resolved = await resolvePlugins({
|
|
238
|
+
plugins: [mockPlugin, mockPlugin2],
|
|
239
|
+
settings: {},
|
|
240
|
+
nodeishFs: {},
|
|
241
|
+
});
|
|
242
|
+
expect(resolved.data.customApi).toHaveProperty("my-app-1");
|
|
243
|
+
expect(resolved.data.customApi).toHaveProperty("my-app-2");
|
|
244
|
+
expect(resolved.data.customApi).toHaveProperty("my-app-3");
|
|
245
|
+
});
|
|
246
|
+
it("it should throw an error if return value is not an object", async () => {
|
|
247
|
+
const mockPlugin = {
|
|
248
|
+
meta: {
|
|
249
|
+
id: "plugin.namespace.placeholder",
|
|
250
|
+
description: { en: "My plugin description" },
|
|
251
|
+
displayName: { en: "My plugin" },
|
|
252
|
+
},
|
|
253
|
+
// @ts-expect-error - invalid return type
|
|
254
|
+
addCustomApi: () => undefined,
|
|
255
|
+
};
|
|
256
|
+
const resolved = await resolvePlugins({
|
|
257
|
+
plugins: [mockPlugin],
|
|
258
|
+
settings: {},
|
|
259
|
+
nodeishFs: {},
|
|
260
|
+
});
|
|
261
|
+
expect(resolved.errors).toHaveLength(1);
|
|
262
|
+
expect(resolved.errors[0]).toBeInstanceOf(PluginReturnedInvalidCustomApiError);
|
|
263
|
+
});
|
|
264
|
+
it("it should throw an error if the passed options are not defined inside customApi", async () => {
|
|
265
|
+
const mockPlugin = {
|
|
266
|
+
meta: {
|
|
267
|
+
id: "plugin.namepsace.placeholder",
|
|
268
|
+
description: { en: "My plugin description" },
|
|
269
|
+
displayName: { en: "My plugin" },
|
|
270
|
+
},
|
|
271
|
+
addCustomApi: () => ({
|
|
272
|
+
"app.inlang.placeholder": {
|
|
273
|
+
messageReferenceMatcher: () => {
|
|
274
|
+
return { hello: "world" };
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
}),
|
|
278
|
+
};
|
|
279
|
+
const resolved = await resolvePlugins({
|
|
280
|
+
plugins: [mockPlugin],
|
|
281
|
+
settings: {},
|
|
282
|
+
nodeishFs: {},
|
|
283
|
+
});
|
|
284
|
+
expect(resolved.data.customApi).toHaveProperty("app.inlang.placeholder");
|
|
285
|
+
expect((resolved.data.customApi?.["app.inlang.placeholder"]).messageReferenceMatcher()).toEqual({
|
|
286
|
+
hello: "world",
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { LanguageTag } from "@inlang/language-tag";
|
|
2
|
+
import type { NodeishFilesystem as LisaNodeishFilesystem } from "@lix-js/fs";
|
|
3
|
+
import type { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, PluginUsesReservedNamespaceError } from "./errors.js";
|
|
4
|
+
import type { Message } from "@inlang/message";
|
|
5
|
+
import type { JSONObject } from "@inlang/json-types";
|
|
6
|
+
import type { CustomApiInlangIdeExtension, Plugin } from "@inlang/plugin";
|
|
7
|
+
/**
|
|
8
|
+
* The filesystem is a subset of project lisa's nodeish filesystem.
|
|
9
|
+
*
|
|
10
|
+
* - only uses minimally required functions to decrease the API footprint on the ecosystem.
|
|
11
|
+
*/
|
|
12
|
+
export type NodeishFilesystemSubset = Pick<LisaNodeishFilesystem, "readFile" | "readdir" | "mkdir" | "writeFile">;
|
|
13
|
+
/**
|
|
14
|
+
* Function that resolves (imports and initializes) the plugins.
|
|
15
|
+
*/
|
|
16
|
+
export type ResolvePluginsFunction = (args: {
|
|
17
|
+
plugins: Array<Plugin>;
|
|
18
|
+
settings: Record<Plugin["meta"]["id"], JSONObject>;
|
|
19
|
+
nodeishFs: NodeishFilesystemSubset;
|
|
20
|
+
}) => Promise<{
|
|
21
|
+
data: ResolvedPluginApi;
|
|
22
|
+
errors: Array<PluginReturnedInvalidCustomApiError | PluginLoadMessagesFunctionAlreadyDefinedError | PluginSaveMessagesFunctionAlreadyDefinedError | PluginHasInvalidIdError | PluginHasInvalidSchemaError | PluginUsesReservedNamespaceError>;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* The API after resolving the plugins.
|
|
26
|
+
*/
|
|
27
|
+
export type ResolvedPluginApi = {
|
|
28
|
+
loadMessages: (args: {
|
|
29
|
+
languageTags: LanguageTag[];
|
|
30
|
+
sourceLanguageTag: LanguageTag;
|
|
31
|
+
}) => Promise<Message[]> | Message[];
|
|
32
|
+
saveMessages: (args: {
|
|
33
|
+
messages: Message[];
|
|
34
|
+
}) => Promise<void> | void;
|
|
35
|
+
/**
|
|
36
|
+
* Detect language tags in the project provided plugins.
|
|
37
|
+
*/
|
|
38
|
+
detectedLanguageTags: LanguageTag[];
|
|
39
|
+
/**
|
|
40
|
+
* App specific APIs.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // define
|
|
44
|
+
* customApi: ({ settings }) => ({
|
|
45
|
+
* "app.inlang.ide-extension": {
|
|
46
|
+
* messageReferenceMatcher: () => {
|
|
47
|
+
* // use settings
|
|
48
|
+
* settings.pathPattern
|
|
49
|
+
* return
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* })
|
|
53
|
+
* // use
|
|
54
|
+
* customApi['app.inlang.ide-extension'].messageReferenceMatcher()
|
|
55
|
+
*/
|
|
56
|
+
customApi: Record<`app.${string}.${string}` | `library.${string}.${string}`, unknown> & {
|
|
57
|
+
"app.inlang.ideExtension"?: CustomApiInlangIdeExtension;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,iBAAiB,IAAI,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,KAAK,EACX,mCAAmC,EACnC,6CAA6C,EAC7C,6CAA6C,EAC7C,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEzE;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACzC,qBAAqB,EACrB,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAC9C,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE;IAC3C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAA;IAClD,SAAS,EAAE,uBAAuB,CAAA;CAClC,KAAK,OAAO,CAAC;IACb,IAAI,EAAE,iBAAiB,CAAA;IACvB,MAAM,EAAE,KAAK,CACV,mCAAmC,GACnC,6CAA6C,GAC7C,6CAA6C,GAC7C,uBAAuB,GACvB,2BAA2B,GAC3B,gCAAgC,CAClC,CAAA;CACD,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,YAAY,EAAE,CAAC,IAAI,EAAE;QACpB,YAAY,EAAE,WAAW,EAAE,CAAA;QAC3B,iBAAiB,EAAE,WAAW,CAAA;KAC9B,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAA;IACpC,YAAY,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrE;;OAEG;IACH,oBAAoB,EAAE,WAAW,EAAE,CAAA;IACnC;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,EAAE,MAAM,CAAC,OAAO,MAAM,IAAI,MAAM,EAAE,GAAG,WAAW,MAAM,IAAI,MAAM,EAAE,EAAE,OAAO,CAAC,GAAG;QACvF,yBAAyB,CAAC,EAAE,2BAA2B,CAAA;KACvD,CAAA;CACD,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/types.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ProjectConfig } from "@inlang/project-config";
|
|
2
|
+
import { Value } from "@sinclair/typebox/value";
|
|
3
|
+
import { describe, test, expect } from "vitest";
|
|
4
|
+
import { expectType } from "tsd";
|
|
5
|
+
import { Plugin } from "@inlang/plugin";
|
|
6
|
+
describe("Plugin", () => {
|
|
7
|
+
test("meta.id should enforce plugin.namespace.* patterns", () => {
|
|
8
|
+
expectType("");
|
|
9
|
+
const mockPlugin = {
|
|
10
|
+
meta: {
|
|
11
|
+
id: "plugin.namespace.placeholder",
|
|
12
|
+
displayName: { en: "" },
|
|
13
|
+
description: { en: "" },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const passCases = ["plugin.namespace.helloWorld", "plugin.namespace.i18n"];
|
|
17
|
+
const failCases = [
|
|
18
|
+
"namespace.hello_World",
|
|
19
|
+
"plugin.namespace-HelloWorld",
|
|
20
|
+
"lintRule.namespace.coolPlugin",
|
|
21
|
+
];
|
|
22
|
+
for (const pass of passCases) {
|
|
23
|
+
mockPlugin.meta.id = pass;
|
|
24
|
+
// @ts-ignore - type mismatch error. fix after refactor
|
|
25
|
+
expect(Value.Check(Plugin, mockPlugin)).toBe(true);
|
|
26
|
+
}
|
|
27
|
+
for (const fail of failCases) {
|
|
28
|
+
mockPlugin.meta.id = fail;
|
|
29
|
+
// @ts-ignore - type mismatch error. fix after refactor
|
|
30
|
+
expect(Value.Check(Plugin, mockPlugin)).toBe(false);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
test("meta.id should be a valid inlang.config.setting key", () => {
|
|
34
|
+
const mockConfig = {
|
|
35
|
+
sourceLanguageTag: "en",
|
|
36
|
+
languageTags: ["en", "de"],
|
|
37
|
+
modules: [],
|
|
38
|
+
settings: {},
|
|
39
|
+
};
|
|
40
|
+
const cases = ["plugin.namespace.helloWorld", "plugin.namespace.i18n"];
|
|
41
|
+
for (const _case of cases) {
|
|
42
|
+
const config = { ...mockConfig, settings: { [_case]: {} } };
|
|
43
|
+
// @ts-ignore - type mismatch error. fix after refactor
|
|
44
|
+
expect(Value.Check(ProjectConfig, config)).toBe(true);
|
|
45
|
+
// @ts-ignore - type mismatch error. fix after refactor
|
|
46
|
+
expect(Value.Check(Plugin["properties"]["meta"]["properties"]["id"], _case)).toBe(true);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveModules.d.ts","sourceRoot":"","sources":["../../src/resolve-modules/resolveModules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAkBvD,eAAO,MAAM,cAAc,EAAE,qBA8E5B,CAAA"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { InlangModule } from "@inlang/module";
|
|
2
|
+
import { ModuleError, ModuleImportError, ModuleHasNoExportsError, ModuleExportIsInvalidError, } from "./errors.js";
|
|
3
|
+
import { tryCatch } from "@inlang/result";
|
|
4
|
+
import { resolveMessageLintRules } from "./message-lint-rules/resolveMessageLintRules.js";
|
|
5
|
+
import { createImport } from "./import.js";
|
|
6
|
+
import { resolvePlugins } from "./plugins/resolvePlugins.js";
|
|
7
|
+
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
8
|
+
const ModuleCompiler = TypeCompiler.Compile(InlangModule);
|
|
9
|
+
export const resolveModules = async (args) => {
|
|
10
|
+
const _import = args._import ?? createImport({ readFile: args.nodeishFs.readFile, fetch });
|
|
11
|
+
const moduleErrors = [];
|
|
12
|
+
const allPlugins = [];
|
|
13
|
+
const allMessageLintRules = [];
|
|
14
|
+
const meta = [];
|
|
15
|
+
for (const module of args.config.modules) {
|
|
16
|
+
/**
|
|
17
|
+
* -------------- BEGIN SETUP --------------
|
|
18
|
+
*/
|
|
19
|
+
const importedModule = await tryCatch(() => _import(module));
|
|
20
|
+
// -- IMPORT MODULE --
|
|
21
|
+
if (importedModule.error) {
|
|
22
|
+
moduleErrors.push(new ModuleImportError(`Couldn't import the plugin "${module}"`, {
|
|
23
|
+
module: module,
|
|
24
|
+
cause: importedModule.error,
|
|
25
|
+
}));
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// -- MODULE DOES NOT EXPORT PLUGINS OR LINT RULES --
|
|
29
|
+
if (importedModule.data?.default?.meta?.id === undefined) {
|
|
30
|
+
moduleErrors.push(new ModuleHasNoExportsError(`Module "${module}" has no exports.`, {
|
|
31
|
+
module: module,
|
|
32
|
+
}));
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const isValidModule = ModuleCompiler.Check(importedModule.data);
|
|
36
|
+
if (isValidModule === false) {
|
|
37
|
+
const errors = [...ModuleCompiler.Errors(importedModule.data)];
|
|
38
|
+
moduleErrors.push(new ModuleExportIsInvalidError(`Module "${module}" is invalid: ` + errors, {
|
|
39
|
+
module: module,
|
|
40
|
+
}));
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
meta.push({
|
|
44
|
+
module: module,
|
|
45
|
+
id: importedModule.data.default.meta.id,
|
|
46
|
+
});
|
|
47
|
+
if (importedModule.data.default.meta.id.startsWith("plugin.")) {
|
|
48
|
+
allPlugins.push(importedModule.data.default);
|
|
49
|
+
}
|
|
50
|
+
else if (importedModule.data.default.meta.id.startsWith("messageLintRule.")) {
|
|
51
|
+
allMessageLintRules.push(importedModule.data.default);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
throw new Error(`Unimplemented module type. Must start with "plugin." or "messageLintRule.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const resolvedPlugins = await resolvePlugins({
|
|
58
|
+
plugins: allPlugins,
|
|
59
|
+
settings: args.config.settings,
|
|
60
|
+
nodeishFs: args.nodeishFs,
|
|
61
|
+
});
|
|
62
|
+
const resolvedLintRules = resolveMessageLintRules({ messageLintRules: allMessageLintRules });
|
|
63
|
+
return {
|
|
64
|
+
meta,
|
|
65
|
+
messageLintRules: allMessageLintRules,
|
|
66
|
+
plugins: allPlugins,
|
|
67
|
+
resolvedPluginApi: resolvedPlugins.data,
|
|
68
|
+
errors: [...moduleErrors, ...resolvedLintRules.errors, ...resolvedPlugins.errors],
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveModules.test.d.ts","sourceRoot":"","sources":["../../src/resolve-modules/resolveModules.test.ts"],"names":[],"mappings":""}
|