@inlang/sdk 0.10.0 → 0.12.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/dist/adapter/solidAdapter.test.js +12 -8
- package/dist/createNodeishFsWithAbsolutePaths.d.ts +13 -0
- package/dist/createNodeishFsWithAbsolutePaths.d.ts.map +1 -0
- package/dist/createNodeishFsWithAbsolutePaths.js +29 -0
- package/dist/createNodeishFsWithAbsolutePaths.test.d.ts +2 -0
- package/dist/createNodeishFsWithAbsolutePaths.test.d.ts.map +1 -0
- package/dist/createNodeishFsWithAbsolutePaths.test.js +37 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -0
- package/dist/loadProject.d.ts +4 -1
- package/dist/loadProject.d.ts.map +1 -1
- package/dist/loadProject.js +18 -5
- package/dist/loadProject.test.js +134 -44
- package/dist/resolve-modules/import.d.ts.map +1 -1
- package/dist/resolve-modules/import.js +3 -2
- package/dist/resolve-modules/plugins/types.d.ts +2 -2
- package/dist/resolve-modules/plugins/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapter/solidAdapter.test.ts +12 -8
- package/src/createNodeishFsWithAbsolutePaths.test.ts +47 -0
- package/src/createNodeishFsWithAbsolutePaths.ts +40 -0
- package/src/errors.ts +7 -0
- package/src/loadProject.test.ts +148 -43
- package/src/loadProject.ts +25 -4
- package/src/resolve-modules/import.ts +3 -2
- package/src/resolve-modules/plugins/types.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/resolve-modules/import.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/resolve-modules/import.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAG7D;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;AAE1D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAClC,6CAA6C;IAC7C,QAAQ,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAA;CAC7C,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC,OAAO,OAAO,CAAC,CAG9C;AAED,iBAAe,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IACR;;OAEG;IACH,QAAQ,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAA;CAC7C,GACC,OAAO,CAAC,GAAG,CAAC,CAyBd"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import dedent from "dedent";
|
|
2
|
-
import { normalizePath } from "@lix-js/fs";
|
|
3
2
|
import { ModuleImportError } from "./errors.js";
|
|
4
3
|
/**
|
|
5
4
|
* Creates the import function.
|
|
@@ -20,7 +19,9 @@ async function $import(uri, options) {
|
|
|
20
19
|
moduleAsText = await (await fetch(uri)).text();
|
|
21
20
|
}
|
|
22
21
|
else {
|
|
23
|
-
moduleAsText = await options.readFile(
|
|
22
|
+
moduleAsText = await options.readFile(uri, {
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
});
|
|
24
25
|
}
|
|
25
26
|
const moduleWithMimeType = "data:application/javascript," + encodeURIComponent(moduleAsText);
|
|
26
27
|
try {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NodeishFilesystem
|
|
1
|
+
import type { NodeishFilesystem } from "@lix-js/fs";
|
|
2
2
|
import type { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, PluginUsesReservedNamespaceError, PluginsDoNotProvideLoadOrSaveMessagesError } from "./errors.js";
|
|
3
3
|
import type { Message } from "@inlang/message";
|
|
4
4
|
import type { CustomApiInlangIdeExtension, Plugin } from "@inlang/plugin";
|
|
@@ -8,7 +8,7 @@ import type { ProjectSettings } from "@inlang/project-settings";
|
|
|
8
8
|
*
|
|
9
9
|
* - only uses minimally required functions to decrease the API footprint on the ecosystem.
|
|
10
10
|
*/
|
|
11
|
-
export type NodeishFilesystemSubset = Pick<
|
|
11
|
+
export type NodeishFilesystemSubset = Pick<NodeishFilesystem, "readFile" | "readdir" | "mkdir" | "writeFile">;
|
|
12
12
|
/**
|
|
13
13
|
* Function that resolves (imports and initializes) the plugins.
|
|
14
14
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EACX,mCAAmC,EACnC,6CAA6C,EAC7C,6CAA6C,EAC7C,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,0CAA0C,EAC1C,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAE/D;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACzC,iBAAiB,EACjB,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,eAAe,CAAA;IACzB,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,GAChC,0CAA0C,CAC5C,CAAA;CACD,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,YAAY,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAA;IACrF,YAAY,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAC;QAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChG;;;;;;;;;;;;;;;;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"}
|
package/package.json
CHANGED
|
@@ -88,10 +88,11 @@ const $import: ImportFunction = async (name) => ({
|
|
|
88
88
|
describe("config", () => {
|
|
89
89
|
it("should react to changes in config", async () => {
|
|
90
90
|
const fs = createNodeishMemoryFs()
|
|
91
|
-
await fs.
|
|
91
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
92
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config))
|
|
92
93
|
const project = solidAdapter(
|
|
93
94
|
await loadProject({
|
|
94
|
-
settingsFilePath: "
|
|
95
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
95
96
|
nodeishFs: fs,
|
|
96
97
|
_import: $import,
|
|
97
98
|
}),
|
|
@@ -118,10 +119,11 @@ describe("config", () => {
|
|
|
118
119
|
describe("installed", () => {
|
|
119
120
|
it("react to changes that are unrelated to installed items", async () => {
|
|
120
121
|
const fs = createNodeishMemoryFs()
|
|
121
|
-
await fs.
|
|
122
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
123
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config))
|
|
122
124
|
const project = solidAdapter(
|
|
123
125
|
await loadProject({
|
|
124
|
-
settingsFilePath: "
|
|
126
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
125
127
|
nodeishFs: fs,
|
|
126
128
|
_import: $import,
|
|
127
129
|
}),
|
|
@@ -181,10 +183,11 @@ describe("messages", () => {
|
|
|
181
183
|
|
|
182
184
|
const mockImport: ImportFunction = async () => ({ default: mockPlugin })
|
|
183
185
|
|
|
184
|
-
await fs.
|
|
186
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
187
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(mockConfig))
|
|
185
188
|
const project = solidAdapter(
|
|
186
189
|
await loadProject({
|
|
187
|
-
settingsFilePath: "
|
|
190
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
188
191
|
nodeishFs: fs,
|
|
189
192
|
_import: mockImport,
|
|
190
193
|
}),
|
|
@@ -210,10 +213,11 @@ describe("messages", () => {
|
|
|
210
213
|
|
|
211
214
|
it("should react to changes in messages", async () => {
|
|
212
215
|
const fs = createNodeishMemoryFs()
|
|
213
|
-
await fs.
|
|
216
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
217
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config))
|
|
214
218
|
const project = solidAdapter(
|
|
215
219
|
await loadProject({
|
|
216
|
-
settingsFilePath: "
|
|
220
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
217
221
|
nodeishFs: fs,
|
|
218
222
|
_import: $import,
|
|
219
223
|
}),
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { it, expect, vi } from "vitest"
|
|
2
|
+
import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js"
|
|
3
|
+
import type { NodeishFilesystemSubset } from "./versionedInterfaces.js"
|
|
4
|
+
|
|
5
|
+
it("throws an error if settingsFilePath is not an absolute path", () => {
|
|
6
|
+
const relativePath = "relative/path"
|
|
7
|
+
|
|
8
|
+
expect(() =>
|
|
9
|
+
createNodeishFsWithAbsolutePaths({ settingsFilePath: relativePath, nodeishFs: {} as any })
|
|
10
|
+
).toThrow()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it("intercepts paths correctly for readFile", async () => {
|
|
14
|
+
const settingsFilePath = `/Users/samuel/Documents/paraglide/example/project.inlang.json`
|
|
15
|
+
|
|
16
|
+
const filePaths = [
|
|
17
|
+
["file.txt", `/Users/samuel/Documents/paraglide/example/file.txt`],
|
|
18
|
+
["./file.txt", `/Users/samuel/Documents/paraglide/example/file.txt`],
|
|
19
|
+
["./folder/file.txt", `/Users/samuel/Documents/paraglide/example/folder/file.txt`],
|
|
20
|
+
["../file.txt", `/Users/samuel/Documents/paraglide/file.txt`],
|
|
21
|
+
["../folder/file.txt", `/Users/samuel/Documents/paraglide/folder/file.txt`],
|
|
22
|
+
["../../file.txt", `/Users/samuel/Documents/file.txt`],
|
|
23
|
+
["../../../file.txt", `/Users/samuel/file.txt`],
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
const mockNodeishFs = {
|
|
27
|
+
readFile: vi.fn(),
|
|
28
|
+
readdir: vi.fn(),
|
|
29
|
+
mkdir: vi.fn(),
|
|
30
|
+
writeFile: vi.fn(),
|
|
31
|
+
} satisfies Record<keyof NodeishFilesystemSubset, any>
|
|
32
|
+
|
|
33
|
+
const interceptedFs = createNodeishFsWithAbsolutePaths({
|
|
34
|
+
settingsFilePath,
|
|
35
|
+
nodeishFs: mockNodeishFs,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
for (const [path, expectedPath] of filePaths) {
|
|
39
|
+
for (const fn of Object.keys(mockNodeishFs)) {
|
|
40
|
+
// @ts-expect-error
|
|
41
|
+
await interceptedFs[fn](path)
|
|
42
|
+
// @ts-expect-error
|
|
43
|
+
// expect the first argument to be the expectedPath
|
|
44
|
+
expect(mockNodeishFs[fn].mock.lastCall[0]).toBe(expectedPath)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { NodeishFilesystemSubset } from "@inlang/plugin"
|
|
2
|
+
import { normalizePath } from "@lix-js/fs"
|
|
3
|
+
|
|
4
|
+
export const isAbsolutePath = (path: string) => /^[/\\]/.test(path)
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Wraps the nodeish filesystem subset with a function that intercepts paths
|
|
8
|
+
* and prepends the base path.
|
|
9
|
+
*
|
|
10
|
+
* The paths are resolved from the `settingsFilePath` argument.
|
|
11
|
+
*/
|
|
12
|
+
export const createNodeishFsWithAbsolutePaths = (args: {
|
|
13
|
+
settingsFilePath: string
|
|
14
|
+
nodeishFs: NodeishFilesystemSubset
|
|
15
|
+
}): NodeishFilesystemSubset => {
|
|
16
|
+
if (!isAbsolutePath(args.settingsFilePath)) {
|
|
17
|
+
throw new Error("The argument `settingsFilePath` must be an absolute path.")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// get the base path of the settings file by
|
|
21
|
+
// removing the file name from the path
|
|
22
|
+
const bathPath = args.settingsFilePath.split("/").slice(0, -1).join("/")
|
|
23
|
+
|
|
24
|
+
const makeAbsolute = (path: string) => {
|
|
25
|
+
if (isAbsolutePath(path)) {
|
|
26
|
+
return path
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return normalizePath(bathPath + "/" + path)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
// @ts-expect-error
|
|
34
|
+
readFile: (path: string, options: { encoding: "utf-8" | "binary" }) =>
|
|
35
|
+
args.nodeishFs.readFile(makeAbsolute(path), options),
|
|
36
|
+
readdir: (path: string) => args.nodeishFs.readdir(makeAbsolute(path)),
|
|
37
|
+
mkdir: (path: string) => args.nodeishFs.mkdir(makeAbsolute(path)),
|
|
38
|
+
writeFile: (path: string, data: string) => args.nodeishFs.writeFile(makeAbsolute(path), data),
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { ValueError } from "@sinclair/typebox/errors"
|
|
2
2
|
|
|
3
|
+
export class LoadProjectInvalidArgument extends Error {
|
|
4
|
+
constructor(message: string, options: { argument: string }) {
|
|
5
|
+
super(`The argument "${options.argument}" of loadProject() is invalid: ${message}`)
|
|
6
|
+
this.name = "LoadProjectInvalidArgument"
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
export class ProjectSettingsInvalidError extends Error {
|
|
4
11
|
constructor(options: { errors: ValueError[] }) {
|
|
5
12
|
super(
|
package/src/loadProject.test.ts
CHANGED
|
@@ -5,11 +5,14 @@ import type { ProjectSettings, Plugin, MessageLintRule, Message } from "./versio
|
|
|
5
5
|
import type { ImportFunction } from "./resolve-modules/index.js"
|
|
6
6
|
import type { InlangModule } from "@inlang/module"
|
|
7
7
|
import {
|
|
8
|
+
LoadProjectInvalidArgument,
|
|
8
9
|
ProjectSettingsFileJSONSyntaxError,
|
|
9
10
|
ProjectSettingsFileNotFoundError,
|
|
10
11
|
ProjectSettingsInvalidError,
|
|
11
12
|
} from "./errors.js"
|
|
12
13
|
import { createNodeishMemoryFs } from "@lix-js/fs"
|
|
14
|
+
import { createMessage } from "./test-utilities/createMessage.js"
|
|
15
|
+
import { tryCatch } from "@inlang/result"
|
|
13
16
|
|
|
14
17
|
// ------------------------------------------------------------------------------------------------
|
|
15
18
|
|
|
@@ -96,12 +99,27 @@ const _import: ImportFunction = async (name) =>
|
|
|
96
99
|
// ------------------------------------------------------------------------------------------------
|
|
97
100
|
|
|
98
101
|
describe("initialization", () => {
|
|
102
|
+
it("should throw if settingsFilePath is not an absolute path", async () => {
|
|
103
|
+
const fs = createNodeishMemoryFs()
|
|
104
|
+
|
|
105
|
+
const result = await tryCatch(() =>
|
|
106
|
+
loadProject({
|
|
107
|
+
settingsFilePath: "relative/path",
|
|
108
|
+
nodeishFs: fs,
|
|
109
|
+
_import,
|
|
110
|
+
})
|
|
111
|
+
)
|
|
112
|
+
expect(result.error).toBeInstanceOf(LoadProjectInvalidArgument)
|
|
113
|
+
expect(result.data).toBeUndefined()
|
|
114
|
+
})
|
|
115
|
+
|
|
99
116
|
describe("settings", () => {
|
|
100
117
|
it("should return an error if settings file is not found", async () => {
|
|
101
118
|
const fs = createNodeishMemoryFs()
|
|
119
|
+
fs.mkdir("/user/project", { recursive: true })
|
|
102
120
|
|
|
103
121
|
const project = await loadProject({
|
|
104
|
-
settingsFilePath: "
|
|
122
|
+
settingsFilePath: "/user/project/test.json",
|
|
105
123
|
nodeishFs: fs,
|
|
106
124
|
_import,
|
|
107
125
|
})
|
|
@@ -111,10 +129,11 @@ describe("initialization", () => {
|
|
|
111
129
|
|
|
112
130
|
it("should return an error if settings file is not a valid JSON", async () => {
|
|
113
131
|
const fs = await createNodeishMemoryFs()
|
|
114
|
-
await fs.
|
|
132
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
133
|
+
await fs.writeFile("/user/project/project.inlang.json", "invalid json")
|
|
115
134
|
|
|
116
135
|
const project = await loadProject({
|
|
117
|
-
settingsFilePath: "
|
|
136
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
118
137
|
nodeishFs: fs,
|
|
119
138
|
_import,
|
|
120
139
|
})
|
|
@@ -124,10 +143,11 @@ describe("initialization", () => {
|
|
|
124
143
|
|
|
125
144
|
it("should return an error if settings file is does not match schema", async () => {
|
|
126
145
|
const fs = await createNodeishMemoryFs()
|
|
127
|
-
await fs.
|
|
146
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
147
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({}))
|
|
128
148
|
|
|
129
149
|
const project = await loadProject({
|
|
130
|
-
settingsFilePath: "
|
|
150
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
131
151
|
nodeishFs: fs,
|
|
132
152
|
_import,
|
|
133
153
|
})
|
|
@@ -137,9 +157,10 @@ describe("initialization", () => {
|
|
|
137
157
|
|
|
138
158
|
it("should return the parsed settings", async () => {
|
|
139
159
|
const fs = await createNodeishMemoryFs()
|
|
140
|
-
await fs.
|
|
160
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
161
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
141
162
|
const project = await loadProject({
|
|
142
|
-
settingsFilePath: "
|
|
163
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
143
164
|
nodeishFs: fs,
|
|
144
165
|
_import,
|
|
145
166
|
})
|
|
@@ -150,22 +171,27 @@ describe("initialization", () => {
|
|
|
150
171
|
it("should not re-write the settings to disk when initializing", async () => {
|
|
151
172
|
const fs = await createNodeishMemoryFs()
|
|
152
173
|
const settingsWithDeifferentFormatting = JSON.stringify(settings, undefined, 4)
|
|
153
|
-
await fs.
|
|
174
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
175
|
+
await fs.writeFile("/user/project/project.inlang.json", settingsWithDeifferentFormatting)
|
|
154
176
|
|
|
155
177
|
const project = await loadProject({
|
|
156
|
-
settingsFilePath: "
|
|
178
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
157
179
|
nodeishFs: fs,
|
|
158
180
|
_import,
|
|
159
181
|
})
|
|
160
182
|
|
|
161
|
-
const settingsOnDisk = await fs.readFile("
|
|
183
|
+
const settingsOnDisk = await fs.readFile("/user/project/project.inlang.json", {
|
|
184
|
+
encoding: "utf-8",
|
|
185
|
+
})
|
|
162
186
|
expect(settingsOnDisk).toBe(settingsWithDeifferentFormatting)
|
|
163
187
|
|
|
164
188
|
project.setSettings(project.settings())
|
|
165
189
|
// TODO: how can we await `setsettings` correctly
|
|
166
190
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
167
191
|
|
|
168
|
-
const newsettingsOnDisk = await fs.readFile("
|
|
192
|
+
const newsettingsOnDisk = await fs.readFile("/user/project/project.inlang.json", {
|
|
193
|
+
encoding: "utf-8",
|
|
194
|
+
})
|
|
169
195
|
expect(newsettingsOnDisk).not.toBe(settingsWithDeifferentFormatting)
|
|
170
196
|
})
|
|
171
197
|
})
|
|
@@ -178,10 +204,11 @@ describe("initialization", () => {
|
|
|
178
204
|
} satisfies InlangModule)
|
|
179
205
|
|
|
180
206
|
const fs = createNodeishMemoryFs()
|
|
181
|
-
await fs.
|
|
207
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
208
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
182
209
|
|
|
183
210
|
const project = await loadProject({
|
|
184
|
-
settingsFilePath: "
|
|
211
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
185
212
|
nodeishFs: fs,
|
|
186
213
|
_import: $badImport,
|
|
187
214
|
})
|
|
@@ -210,9 +237,10 @@ describe("functionality", () => {
|
|
|
210
237
|
describe("settings", () => {
|
|
211
238
|
it("should return the settings", async () => {
|
|
212
239
|
const fs = await createNodeishMemoryFs()
|
|
213
|
-
await fs.
|
|
240
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
241
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
214
242
|
const project = await loadProject({
|
|
215
|
-
settingsFilePath: "
|
|
243
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
216
244
|
nodeishFs: fs,
|
|
217
245
|
_import,
|
|
218
246
|
})
|
|
@@ -222,9 +250,10 @@ describe("functionality", () => {
|
|
|
222
250
|
|
|
223
251
|
it("should set a new settings", async () => {
|
|
224
252
|
const fs = await createNodeishMemoryFs()
|
|
225
|
-
await fs.
|
|
253
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
254
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
226
255
|
const project = await loadProject({
|
|
227
|
-
settingsFilePath: "
|
|
256
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
228
257
|
nodeishFs: fs,
|
|
229
258
|
_import,
|
|
230
259
|
})
|
|
@@ -247,9 +276,10 @@ describe("functionality", () => {
|
|
|
247
276
|
describe("setSettings", () => {
|
|
248
277
|
it("should fail if settings is not valid", async () => {
|
|
249
278
|
const fs = await createNodeishMemoryFs()
|
|
250
|
-
await fs.
|
|
279
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
280
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
251
281
|
const project = await loadProject({
|
|
252
|
-
settingsFilePath: "
|
|
282
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
253
283
|
nodeishFs: fs,
|
|
254
284
|
_import,
|
|
255
285
|
})
|
|
@@ -261,14 +291,15 @@ describe("functionality", () => {
|
|
|
261
291
|
|
|
262
292
|
it("should write settings to disk", async () => {
|
|
263
293
|
const fs = await createNodeishMemoryFs()
|
|
264
|
-
await fs.
|
|
294
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
295
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
265
296
|
const project = await loadProject({
|
|
266
|
-
settingsFilePath: "
|
|
297
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
267
298
|
nodeishFs: fs,
|
|
268
299
|
_import,
|
|
269
300
|
})
|
|
270
301
|
|
|
271
|
-
const before = await fs.readFile("
|
|
302
|
+
const before = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" })
|
|
272
303
|
expect(before).toBeDefined()
|
|
273
304
|
|
|
274
305
|
const result = project.setSettings({ ...settings, languageTags: [] })
|
|
@@ -278,7 +309,7 @@ describe("functionality", () => {
|
|
|
278
309
|
// TODO: how to wait for fs.writeFile to finish?
|
|
279
310
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
280
311
|
|
|
281
|
-
const after = await fs.readFile("
|
|
312
|
+
const after = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" })
|
|
282
313
|
expect(after).toBeDefined()
|
|
283
314
|
expect(after).not.toBe(before)
|
|
284
315
|
})
|
|
@@ -292,9 +323,10 @@ describe("functionality", () => {
|
|
|
292
323
|
languageTags: ["en"],
|
|
293
324
|
modules: ["plugin.js", "lintRule.js"],
|
|
294
325
|
}
|
|
295
|
-
await fs.
|
|
326
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
327
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
296
328
|
const project = await loadProject({
|
|
297
|
-
settingsFilePath: "
|
|
329
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
298
330
|
nodeishFs: fs,
|
|
299
331
|
_import,
|
|
300
332
|
})
|
|
@@ -324,10 +356,11 @@ describe("functionality", () => {
|
|
|
324
356
|
modules: ["plugin.js", "lintRule.js"],
|
|
325
357
|
}
|
|
326
358
|
|
|
327
|
-
await fs.
|
|
359
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
360
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
328
361
|
|
|
329
362
|
const project = await loadProject({
|
|
330
|
-
settingsFilePath: "
|
|
363
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
331
364
|
nodeishFs: fs,
|
|
332
365
|
_import,
|
|
333
366
|
})
|
|
@@ -357,8 +390,9 @@ describe("functionality", () => {
|
|
|
357
390
|
saveMessages: () => undefined,
|
|
358
391
|
}
|
|
359
392
|
const fs = await createNodeishMemoryFs()
|
|
393
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
360
394
|
await fs.writeFile(
|
|
361
|
-
"
|
|
395
|
+
"/user/project/project.inlang.json",
|
|
362
396
|
JSON.stringify({
|
|
363
397
|
sourceLanguageTag: "en",
|
|
364
398
|
languageTags: ["en"],
|
|
@@ -372,7 +406,7 @@ describe("functionality", () => {
|
|
|
372
406
|
} satisfies InlangModule
|
|
373
407
|
}
|
|
374
408
|
const project = await loadProject({
|
|
375
|
-
settingsFilePath: "
|
|
409
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
376
410
|
nodeishFs: fs,
|
|
377
411
|
_import,
|
|
378
412
|
})
|
|
@@ -405,8 +439,9 @@ describe("functionality", () => {
|
|
|
405
439
|
saveMessages: () => undefined,
|
|
406
440
|
}
|
|
407
441
|
const fs = await createNodeishMemoryFs()
|
|
442
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
408
443
|
await fs.writeFile(
|
|
409
|
-
"
|
|
444
|
+
"/user/project/project.inlang.json",
|
|
410
445
|
JSON.stringify({
|
|
411
446
|
sourceLanguageTag: "en",
|
|
412
447
|
languageTags: ["en"],
|
|
@@ -420,7 +455,7 @@ describe("functionality", () => {
|
|
|
420
455
|
}
|
|
421
456
|
|
|
422
457
|
const project = await loadProject({
|
|
423
|
-
settingsFilePath: "
|
|
458
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
424
459
|
nodeishFs: fs,
|
|
425
460
|
_import,
|
|
426
461
|
})
|
|
@@ -436,9 +471,10 @@ describe("functionality", () => {
|
|
|
436
471
|
describe("errors", () => {
|
|
437
472
|
it("should return the errors", async () => {
|
|
438
473
|
const fs = await createNodeishMemoryFs()
|
|
439
|
-
await fs.
|
|
474
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
475
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
440
476
|
const project = await loadProject({
|
|
441
|
-
settingsFilePath: "
|
|
477
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
442
478
|
nodeishFs: fs,
|
|
443
479
|
_import,
|
|
444
480
|
})
|
|
@@ -451,9 +487,10 @@ describe("functionality", () => {
|
|
|
451
487
|
describe("customApi", () => {
|
|
452
488
|
it("should return the app specific api", async () => {
|
|
453
489
|
const fs = await createNodeishMemoryFs()
|
|
454
|
-
await fs.
|
|
490
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
491
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
455
492
|
const project = await loadProject({
|
|
456
|
-
settingsFilePath: "
|
|
493
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
457
494
|
nodeishFs: fs,
|
|
458
495
|
_import,
|
|
459
496
|
})
|
|
@@ -467,9 +504,10 @@ describe("functionality", () => {
|
|
|
467
504
|
describe("messages", () => {
|
|
468
505
|
it("should return the messages", async () => {
|
|
469
506
|
const fs = await createNodeishMemoryFs()
|
|
470
|
-
await fs.
|
|
507
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
508
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
471
509
|
const project = await loadProject({
|
|
472
|
-
settingsFilePath: "
|
|
510
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
473
511
|
nodeishFs: fs,
|
|
474
512
|
_import,
|
|
475
513
|
})
|
|
@@ -491,7 +529,8 @@ describe("functionality", () => {
|
|
|
491
529
|
},
|
|
492
530
|
}
|
|
493
531
|
|
|
494
|
-
await fs.
|
|
532
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
533
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
495
534
|
|
|
496
535
|
await fs.mkdir("./resources")
|
|
497
536
|
|
|
@@ -512,7 +551,7 @@ describe("functionality", () => {
|
|
|
512
551
|
}
|
|
513
552
|
|
|
514
553
|
const project = await loadProject({
|
|
515
|
-
settingsFilePath: "
|
|
554
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
516
555
|
nodeishFs: fs,
|
|
517
556
|
_import,
|
|
518
557
|
})
|
|
@@ -639,14 +678,79 @@ describe("functionality", () => {
|
|
|
639
678
|
},
|
|
640
679
|
])
|
|
641
680
|
})
|
|
681
|
+
|
|
682
|
+
/*
|
|
683
|
+
* Passing all messages to saveMessages() simplifies plugins by an order of magnitude.
|
|
684
|
+
*
|
|
685
|
+
* The alternative would be to pass only the messages that changed to saveMessages().
|
|
686
|
+
* But, this would require plugins to maintain a separate data structure of messages
|
|
687
|
+
* and create optimizations, leading to (unjustified) complexity for plugin authors.
|
|
688
|
+
*
|
|
689
|
+
* Pros:
|
|
690
|
+
* - plugins don't need to transform the data (time complexity).
|
|
691
|
+
* - plugins don't to maintain a separate data structure (space complexity).
|
|
692
|
+
* - plugin authors don't need to deal with optimizations (ecosystem complexity).
|
|
693
|
+
*
|
|
694
|
+
* Cons:
|
|
695
|
+
* - Might be slow for a large number of messages. The requirement hasn't popped up yet though.
|
|
696
|
+
*/
|
|
697
|
+
it("should pass all messages, regardless of which message changed, to saveMessages()", async () => {
|
|
698
|
+
const fs = createNodeishMemoryFs()
|
|
699
|
+
|
|
700
|
+
const settings: ProjectSettings = {
|
|
701
|
+
sourceLanguageTag: "en",
|
|
702
|
+
languageTags: ["en", "de"],
|
|
703
|
+
modules: ["plugin.js"],
|
|
704
|
+
"plugin.project.json": {
|
|
705
|
+
pathPattern: "./resources/{languageTag}.json",
|
|
706
|
+
},
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
710
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
711
|
+
|
|
712
|
+
const mockSaveFn = vi.fn()
|
|
713
|
+
|
|
714
|
+
const _mockPlugin: Plugin = {
|
|
715
|
+
id: "plugin.project.json",
|
|
716
|
+
description: "Mock plugin description",
|
|
717
|
+
displayName: "Mock Plugin",
|
|
718
|
+
loadMessages: () => [
|
|
719
|
+
createMessage("first", { en: "first message" }),
|
|
720
|
+
createMessage("second", { en: "second message" }),
|
|
721
|
+
createMessage("third", { en: "third message" }),
|
|
722
|
+
],
|
|
723
|
+
saveMessages: mockSaveFn,
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const _import = async () => {
|
|
727
|
+
return {
|
|
728
|
+
default: _mockPlugin,
|
|
729
|
+
} satisfies InlangModule
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
const project = await loadProject({
|
|
733
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
734
|
+
nodeishFs: fs,
|
|
735
|
+
_import,
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
project.query.messages.create({ data: createMessage("fourth", { en: "fourth message" }) })
|
|
739
|
+
|
|
740
|
+
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
741
|
+
|
|
742
|
+
expect(mockSaveFn.mock.calls.length).toBe(1)
|
|
743
|
+
expect(mockSaveFn.mock.calls[0][0].messages).toHaveLength(4)
|
|
744
|
+
})
|
|
642
745
|
})
|
|
643
746
|
|
|
644
747
|
describe("lint", () => {
|
|
645
748
|
it.todo("should throw if lint reports are not initialized yet", async () => {
|
|
646
749
|
const fs = await createNodeishMemoryFs()
|
|
647
|
-
await fs.
|
|
750
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
751
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
648
752
|
const project = await loadProject({
|
|
649
|
-
settingsFilePath: "
|
|
753
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
650
754
|
nodeishFs: fs,
|
|
651
755
|
_import,
|
|
652
756
|
})
|
|
@@ -665,9 +769,10 @@ describe("functionality", () => {
|
|
|
665
769
|
modules: ["lintRule.js"],
|
|
666
770
|
}
|
|
667
771
|
const fs = createNodeishMemoryFs()
|
|
668
|
-
await fs.
|
|
772
|
+
await fs.mkdir("/user/project", { recursive: true })
|
|
773
|
+
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
669
774
|
const project = await loadProject({
|
|
670
|
-
settingsFilePath: "
|
|
775
|
+
settingsFilePath: "/user/project/project.inlang.json",
|
|
671
776
|
nodeishFs: fs,
|
|
672
777
|
_import: async () => ({
|
|
673
778
|
default: mockMessageLintRule,
|