@inlang/sdk 0.12.0 → 0.14.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.
Files changed (32) hide show
  1. package/dist/adapter/solidAdapter.test.js +5 -5
  2. package/dist/createNodeishFsWithAbsolutePaths.d.ts +0 -1
  3. package/dist/createNodeishFsWithAbsolutePaths.d.ts.map +1 -1
  4. package/dist/createNodeishFsWithAbsolutePaths.js +5 -5
  5. package/dist/isAbsolutePath.d.ts +2 -0
  6. package/dist/isAbsolutePath.d.ts.map +1 -0
  7. package/dist/isAbsolutePath.js +4 -0
  8. package/dist/isAbsolutePath.test.d.ts +2 -0
  9. package/dist/isAbsolutePath.test.d.ts.map +1 -0
  10. package/dist/isAbsolutePath.test.js +20 -0
  11. package/dist/loadProject.d.ts.map +1 -1
  12. package/dist/loadProject.js +24 -4
  13. package/dist/loadProject.test.js +34 -6
  14. package/dist/resolve-modules/plugins/errors.d.ts +0 -5
  15. package/dist/resolve-modules/plugins/errors.d.ts.map +1 -1
  16. package/dist/resolve-modules/plugins/errors.js +0 -6
  17. package/dist/resolve-modules/plugins/resolvePlugins.d.ts.map +1 -1
  18. package/dist/resolve-modules/plugins/resolvePlugins.js +1 -12
  19. package/dist/resolve-modules/plugins/resolvePlugins.test.js +1 -15
  20. package/dist/resolve-modules/plugins/types.d.ts +2 -2
  21. package/dist/resolve-modules/plugins/types.d.ts.map +1 -1
  22. package/package.json +2 -2
  23. package/src/adapter/solidAdapter.test.ts +7 -5
  24. package/src/createNodeishFsWithAbsolutePaths.ts +5 -6
  25. package/src/isAbsolutePath.test.ts +23 -0
  26. package/src/isAbsolutePath.ts +5 -0
  27. package/src/loadProject.test.ts +44 -6
  28. package/src/loadProject.ts +29 -7
  29. package/src/resolve-modules/plugins/errors.ts +0 -7
  30. package/src/resolve-modules/plugins/resolvePlugins.test.ts +0 -18
  31. package/src/resolve-modules/plugins/resolvePlugins.ts +0 -15
  32. package/src/resolve-modules/plugins/types.ts +0 -2
@@ -88,7 +88,7 @@ describe("config", () => {
88
88
  const newConfig = { ...project.settings(), languageTags: ["en", "de"] };
89
89
  project.setSettings(newConfig);
90
90
  // TODO: how can we await `setConfig` correctly
91
- await new Promise((resolve) => setTimeout(resolve, 0));
91
+ await new Promise((resolve) => setTimeout(resolve, 510));
92
92
  expect(counter).toBe(2); // 2 times because effect creation + set
93
93
  expect(project.settings()).toStrictEqual(newConfig);
94
94
  });
@@ -162,11 +162,11 @@ describe("messages", () => {
162
162
  counter += 1;
163
163
  });
164
164
  expect(Object.values(project.query.messages.getAll()).length).toBe(2);
165
- project.setSettings({ ...project.settings(), languageTags: [] });
165
+ project.setSettings({ ...project.settings(), languageTags: ["en"] });
166
166
  // TODO: how can we await `setConfig` correctly
167
- await new Promise((resolve) => setTimeout(resolve, 0));
168
- expect(counter).toBe(2); // 2 times because effect creation + set
169
- expect(Object.values(project.query.messages.getAll()).length).toBe(0);
167
+ await new Promise((resolve) => setTimeout(resolve, 510));
168
+ expect(counter).toBe(1); // 2 times because effect creation + set
169
+ expect(Object.values(project.query.messages.getAll()).length).toBe(2);
170
170
  });
171
171
  it("should react to changes in messages", async () => {
172
172
  const fs = createNodeishMemoryFs();
@@ -1,5 +1,4 @@
1
1
  import type { NodeishFilesystemSubset } from "@inlang/plugin";
2
- export declare const isAbsolutePath: (path: string) => boolean;
3
2
  /**
4
3
  * Wraps the nodeish filesystem subset with a function that intercepts paths
5
4
  * and prepends the base path.
@@ -1 +1 @@
1
- {"version":3,"file":"createNodeishFsWithAbsolutePaths.d.ts","sourceRoot":"","sources":["../src/createNodeishFsWithAbsolutePaths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAG7D,eAAO,MAAM,cAAc,SAAU,MAAM,YAAwB,CAAA;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,SAAU;IACtD,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,uBAAuB,CAAA;CAClC,KAAG,uBAyBH,CAAA"}
1
+ {"version":3,"file":"createNodeishFsWithAbsolutePaths.d.ts","sourceRoot":"","sources":["../src/createNodeishFsWithAbsolutePaths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAI7D;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,SAAU;IACtD,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,uBAAuB,CAAA;CAClC,KAAG,uBAyBH,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { normalizePath } from "@lix-js/fs";
2
- export const isAbsolutePath = (path) => /^[/\\]/.test(path);
2
+ import { isAbsolutePath } from "./isAbsolutePath.js";
3
3
  /**
4
4
  * Wraps the nodeish filesystem subset with a function that intercepts paths
5
5
  * and prepends the base path.
@@ -8,16 +8,16 @@ export const isAbsolutePath = (path) => /^[/\\]/.test(path);
8
8
  */
9
9
  export const createNodeishFsWithAbsolutePaths = (args) => {
10
10
  if (!isAbsolutePath(args.settingsFilePath)) {
11
- throw new Error("The argument `settingsFilePath` must be an absolute path.");
11
+ throw new Error(`Expected an absolute path but received "${args.settingsFilePath}".`);
12
12
  }
13
13
  // get the base path of the settings file by
14
14
  // removing the file name from the path
15
- const bathPath = args.settingsFilePath.split("/").slice(0, -1).join("/");
15
+ const basePath = normalizePath(args.settingsFilePath).split("/").slice(0, -1).join("/");
16
16
  const makeAbsolute = (path) => {
17
17
  if (isAbsolutePath(path)) {
18
- return path;
18
+ return normalizePath(path);
19
19
  }
20
- return normalizePath(bathPath + "/" + path);
20
+ return normalizePath(basePath + "/" + path);
21
21
  };
22
22
  return {
23
23
  // @ts-expect-error
@@ -0,0 +1,2 @@
1
+ export declare const isAbsolutePath: (path: string) => boolean;
2
+ //# sourceMappingURL=isAbsolutePath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isAbsolutePath.d.ts","sourceRoot":"","sources":["../src/isAbsolutePath.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,SAAU,MAAM,YAI1C,CAAA"}
@@ -0,0 +1,4 @@
1
+ export const isAbsolutePath = (path) => {
2
+ const matchPosixAndWindowsAbsolutePaths = /^(?:[A-Za-z]:\\(?:[^\\]+\\)*[^\\]+|[A-Za-z]:\/(?:[^/]+\/)*[^/]+|\/(?:[^/]+\/)*[^/]+)$/;
3
+ return matchPosixAndWindowsAbsolutePaths.test(path);
4
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=isAbsolutePath.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isAbsolutePath.test.d.ts","sourceRoot":"","sources":["../src/isAbsolutePath.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import { assert, describe, it } from "vitest";
2
+ import { isAbsolutePath } from "./isAbsolutePath.js";
3
+ describe("isAbsolutePath", () => {
4
+ it("should correctly identify Unix absolute paths", () => {
5
+ assert.isTrue(isAbsolutePath("/home/user/documents/file.txt"));
6
+ assert.isTrue(isAbsolutePath("/usr/local/bin/script.sh"));
7
+ assert.isFalse(isAbsolutePath("relative/path/to/file.txt"));
8
+ });
9
+ it("should correctly identify Windows absolute paths", () => {
10
+ assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt"));
11
+ assert.isTrue(isAbsolutePath("C:/Users/user/project/project.inlang.json"));
12
+ assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt"));
13
+ });
14
+ it("should handle edge cases", () => {
15
+ assert.isFalse(isAbsolutePath("")); // Empty path should return false
16
+ assert.isFalse(isAbsolutePath("relative/path/../file.txt")); // Relative path with ".." should return false
17
+ assert.isFalse(isAbsolutePath("../relative/path/to/file.txt"));
18
+ assert.isFalse(isAbsolutePath("./relative/path/to/file.txt"));
19
+ });
20
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"loadProject.d.ts","sourceRoot":"","sources":["../src/loadProject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EAGb,YAAY,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,4BAA4B,CAAA;AAchF,OAAO,EAA4B,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAUjG;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW;sBACL,MAAM;eACb,uBAAuB;;qBAElB,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;MAC5D,QAAQ,aAAa,CAkMxB,CAAA;AAqGD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
1
+ {"version":3,"file":"loadProject.d.ts","sourceRoot":"","sources":["../src/loadProject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EAGb,YAAY,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,4BAA4B,CAAA;AAchF,OAAO,EAA4B,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AASjG;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW;sBACL,MAAM;eACb,uBAAuB;;qBAElB,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;MAC5D,QAAQ,aAAa,CAuMxB,CAAA;AAuHD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
@@ -1,5 +1,5 @@
1
1
  import { resolveModules } from "./resolve-modules/index.js";
2
- import { TypeCompiler } from "@sinclair/typebox/compiler";
2
+ import { TypeCompiler, ValueErrorType } from "@sinclair/typebox/compiler";
3
3
  import { ProjectSettingsFileJSONSyntaxError, ProjectSettingsFileNotFoundError, ProjectSettingsInvalidError, PluginLoadMessagesError, PluginSaveMessagesError, LoadProjectInvalidArgument, } from "./errors.js";
4
4
  import { createRoot, createSignal, createEffect } from "./reactivity/solid.js";
5
5
  import { createMessagesQuery } from "./createMessagesQuery.js";
@@ -8,7 +8,9 @@ import { createMessageLintReportsQuery } from "./createMessageLintReportsQuery.j
8
8
  import { ProjectSettings, Message } from "./versionedInterfaces.js";
9
9
  import { tryCatch } from "@inlang/result";
10
10
  import { migrateIfOutdated } from "@inlang/project-settings/migration";
11
- import { createNodeishFsWithAbsolutePaths, isAbsolutePath, } from "./createNodeishFsWithAbsolutePaths.js";
11
+ import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js";
12
+ import { normalizePath } from "@lix-js/fs";
13
+ import { isAbsolutePath } from "./isAbsolutePath.js";
12
14
  const settingsCompiler = TypeCompiler.Compile(ProjectSettings);
13
15
  /**
14
16
  * Creates an inlang instance.
@@ -28,14 +30,18 @@ export const loadProject = async (args) => {
28
30
  if (!isAbsolutePath(args.settingsFilePath)) {
29
31
  throw new LoadProjectInvalidArgument(`Expected an absolute path but received "${args.settingsFilePath}".`, { argument: "settingsFilePath" });
30
32
  }
33
+ const settingsFilePath = normalizePath(args.settingsFilePath);
31
34
  // -- load project ------------------------------------------------------
32
35
  return await createRoot(async () => {
33
36
  const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable();
34
- const nodeishFs = createNodeishFsWithAbsolutePaths(args);
37
+ const nodeishFs = createNodeishFsWithAbsolutePaths({
38
+ settingsFilePath,
39
+ nodeishFs: args.nodeishFs,
40
+ });
35
41
  // -- settings ------------------------------------------------------------
36
42
  const [settings, _setSettings] = createSignal();
37
43
  createEffect(() => {
38
- loadSettings({ settingsFilePath: args.settingsFilePath, nodeishFs })
44
+ loadSettings({ settingsFilePath, nodeishFs })
39
45
  .then((settings) => {
40
46
  setSettings(settings);
41
47
  // rename settings to get a convenient access to the data in Posthog
@@ -196,6 +202,20 @@ const parseSettings = (settings) => {
196
202
  });
197
203
  }
198
204
  }
205
+ const { sourceLanguageTag, languageTags } = settings;
206
+ if (!languageTags.includes(sourceLanguageTag)) {
207
+ throw new ProjectSettingsInvalidError({
208
+ errors: [
209
+ {
210
+ message: `The sourceLanguageTag "${sourceLanguageTag}" is not included in the languageTags "${languageTags.join('", "')}". Please add it to the languageTags.`,
211
+ type: ValueErrorType.String,
212
+ schema: ProjectSettings,
213
+ value: sourceLanguageTag,
214
+ path: "sourceLanguageTag",
215
+ },
216
+ ],
217
+ });
218
+ }
199
219
  return withMigration;
200
220
  };
201
221
  const _writeSettingsToDisk = async (args) => {
@@ -91,6 +91,18 @@ describe("initialization", () => {
91
91
  expect(result.error).toBeInstanceOf(LoadProjectInvalidArgument);
92
92
  expect(result.data).toBeUndefined();
93
93
  });
94
+ it("should resolve from a windows path", async () => {
95
+ const fs = createNodeishMemoryFs();
96
+ fs.mkdir("C:\\Users\\user\\project", { recursive: true });
97
+ fs.writeFile("C:\\Users\\user\\project\\project.inlang.json", JSON.stringify(settings));
98
+ const result = await tryCatch(() => loadProject({
99
+ settingsFilePath: "C:\\Users\\user\\project\\project.inlang.json",
100
+ nodeishFs: fs,
101
+ _import,
102
+ }));
103
+ expect(result.error).toBeUndefined();
104
+ expect(result.data).toBeDefined();
105
+ });
94
106
  describe("settings", () => {
95
107
  it("should return an error if settings file is not found", async () => {
96
108
  const fs = createNodeishMemoryFs();
@@ -236,6 +248,23 @@ describe("functionality", () => {
236
248
  expect(result.data).toBeUndefined();
237
249
  expect(result.error).toBeInstanceOf(ProjectSettingsInvalidError);
238
250
  });
251
+ it("should throw an error if sourceLanguageTag is not in languageTags", async () => {
252
+ const fs = await createNodeishMemoryFs();
253
+ await fs.mkdir("/user/project", { recursive: true });
254
+ const settings = {
255
+ sourceLanguageTag: "en",
256
+ languageTags: ["de"],
257
+ modules: [],
258
+ };
259
+ await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
260
+ const project = await loadProject({
261
+ settingsFilePath: "/user/project/project.inlang.json",
262
+ nodeishFs: fs,
263
+ _import,
264
+ });
265
+ expect(project.errors()).toHaveLength(1);
266
+ expect(project.errors()[0]).toBeInstanceOf(ProjectSettingsInvalidError);
267
+ });
239
268
  it("should write settings to disk", async () => {
240
269
  const fs = await createNodeishMemoryFs();
241
270
  await fs.mkdir("/user/project", { recursive: true });
@@ -247,7 +276,7 @@ describe("functionality", () => {
247
276
  });
248
277
  const before = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" });
249
278
  expect(before).toBeDefined();
250
- const result = project.setSettings({ ...settings, languageTags: [] });
279
+ const result = project.setSettings({ ...settings, languageTags: ["en"] });
251
280
  expect(result.data).toBeUndefined();
252
281
  expect(result.error).toBeUndefined();
253
282
  // TODO: how to wait for fs.writeFile to finish?
@@ -598,15 +627,14 @@ describe("functionality", () => {
598
627
  sourceLanguageTag: "en",
599
628
  languageTags: ["en", "de"],
600
629
  modules: ["plugin.js"],
601
- "plugin.project.json": {
630
+ "plugin.placeholder.name": {
602
631
  pathPattern: "./resources/{languageTag}.json",
603
632
  },
604
633
  };
605
- await fs.mkdir("/user/project", { recursive: true });
606
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
634
+ await fs.writeFile("./project.inlang.json", JSON.stringify(settings));
607
635
  const mockSaveFn = vi.fn();
608
636
  const _mockPlugin = {
609
- id: "plugin.project.json",
637
+ id: "plugin.placeholder.name",
610
638
  description: "Mock plugin description",
611
639
  displayName: "Mock Plugin",
612
640
  loadMessages: () => [
@@ -622,7 +650,7 @@ describe("functionality", () => {
622
650
  };
623
651
  };
624
652
  const project = await loadProject({
625
- settingsFilePath: "/user/project/project.inlang.json",
653
+ settingsFilePath: "/project.inlang.json",
626
654
  nodeishFs: fs,
627
655
  _import,
628
656
  });
@@ -5,11 +5,6 @@ export declare class PluginHasInvalidIdError extends Error {
5
5
  id: Plugin["id"];
6
6
  });
7
7
  }
8
- export declare class PluginUsesReservedNamespaceError extends Error {
9
- constructor(options: {
10
- id: Plugin["id"];
11
- });
12
- }
13
8
  export declare class PluginHasInvalidSchemaError extends Error {
14
9
  constructor(options: {
15
10
  id: Plugin["id"];
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE1D,qBAAa,uBAAwB,SAAQ,KAAK;gBACrC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAMzC;AAED,qBAAa,gCAAiC,SAAQ,KAAK;gBAC9C,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAIzC;AAED,qBAAa,2BAA4B,SAAQ,KAAK;gBACzC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE;CAQ/D;AAED,qBAAa,6CAA8C,SAAQ,KAAK;gBAC3D,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAMzC;AAED,qBAAa,6CAA8C,SAAQ,KAAK;gBAC3D,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAMzC;AAED,qBAAa,mCAAoC,SAAQ,KAAK;gBACjD,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAA;KAAE;CAIvE;AAED,qBAAa,0CAA2C,SAAQ,KAAK;;CAOpE"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/resolve-modules/plugins/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE1D,qBAAa,uBAAwB,SAAQ,KAAK;gBACrC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAMzC;AAED,qBAAa,2BAA4B,SAAQ,KAAK;gBACzC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE;CAQ/D;AAED,qBAAa,6CAA8C,SAAQ,KAAK;gBAC3D,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAMzC;AAED,qBAAa,6CAA8C,SAAQ,KAAK;gBAC3D,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;KAAE;CAMzC;AAED,qBAAa,mCAAoC,SAAQ,KAAK;gBACjD,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAA;KAAE;CAIvE;AAED,qBAAa,0CAA2C,SAAQ,KAAK;;CAOpE"}
@@ -4,12 +4,6 @@ export class PluginHasInvalidIdError extends Error {
4
4
  this.name = "PluginHasInvalidIdError";
5
5
  }
6
6
  }
7
- export class PluginUsesReservedNamespaceError extends Error {
8
- constructor(options) {
9
- super(`Plugin ${options.id} uses reserved namespace 'inlang'.`);
10
- this.name = "PluginUsesReservedNamespaceError";
11
- }
12
- }
13
7
  export class PluginHasInvalidSchemaError extends Error {
14
8
  constructor(options) {
15
9
  super(`Plugin "${options.id}" has an invalid schema:\n\n${options.errors
@@ -1 +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;AAuBxD,eAAO,MAAM,cAAc,EAAE,sBAqH5B,CAAA"}
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;AAiBxD,eAAO,MAAM,cAAc,EAAE,sBA4G5B,CAAA"}
@@ -1,13 +1,8 @@
1
1
  import { Plugin } from "@inlang/plugin";
2
- import { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginsDoNotProvideLoadOrSaveMessagesError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, PluginUsesReservedNamespaceError, } from "./errors.js";
2
+ import { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginsDoNotProvideLoadOrSaveMessagesError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, } from "./errors.js";
3
3
  import { deepmerge } from "deepmerge-ts";
4
4
  import { TypeCompiler } from "@sinclair/typebox/compiler";
5
5
  import { tryCatch } from "@inlang/result";
6
- const whitelistedPlugins = [
7
- "plugin.inlang.json",
8
- "plugin.inlang.i18next",
9
- "plugin.inlang.paraglideJs",
10
- ];
11
6
  // @ts-ignore - type mismatch error
12
7
  const PluginCompiler = TypeCompiler.Compile(Plugin);
13
8
  export const resolvePlugins = async (args) => {
@@ -29,12 +24,6 @@ export const resolvePlugins = async (args) => {
29
24
  if (hasInvalidId) {
30
25
  result.errors.push(new PluginHasInvalidIdError({ id: plugin.id }));
31
26
  }
32
- // -- USES RESERVED NAMESPACE --
33
- if (plugin.id.includes("inlang") && !whitelistedPlugins.includes(plugin.id)) {
34
- result.errors.push(new PluginUsesReservedNamespaceError({
35
- id: plugin.id,
36
- }));
37
- }
38
27
  // -- USES INVALID SCHEMA --
39
28
  if (errors.length > 0) {
40
29
  result.errors.push(new PluginHasInvalidSchemaError({
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
2
  import { describe, expect, it } from "vitest";
3
3
  import { resolvePlugins } from "./resolvePlugins.js";
4
- import { PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginUsesReservedNamespaceError, PluginReturnedInvalidCustomApiError, PluginHasInvalidSchemaError, PluginsDoNotProvideLoadOrSaveMessagesError, } from "./errors.js";
4
+ import { PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginReturnedInvalidCustomApiError, PluginHasInvalidSchemaError, PluginsDoNotProvideLoadOrSaveMessagesError, } from "./errors.js";
5
5
  it("should return an error if a plugin uses an invalid id", async () => {
6
6
  const mockPlugin = {
7
7
  // @ts-expect-error - invalid id
@@ -37,20 +37,6 @@ it("should return an error if a plugin uses APIs that are not available", async
37
37
  });
38
38
  expect(resolved.errors[0]).toBeInstanceOf(PluginHasInvalidSchemaError);
39
39
  });
40
- it("should not initialize a plugin that uses the 'inlang' namespace except for inlang whitelisted plugins", async () => {
41
- const mockPlugin = {
42
- id: "plugin.inlang.notWhitelisted",
43
- description: { en: "My plugin description" },
44
- displayName: { en: "My plugin" },
45
- loadMessages: () => undefined,
46
- };
47
- const resolved = await resolvePlugins({
48
- plugins: [mockPlugin],
49
- settings: {},
50
- nodeishFs: {},
51
- });
52
- expect(resolved.errors[0]).toBeInstanceOf(PluginUsesReservedNamespaceError);
53
- });
54
40
  it("should expose the project settings including the plugin settings", async () => {
55
41
  const settings = {
56
42
  sourceLanguageTag: "en",
@@ -1,5 +1,5 @@
1
1
  import type { NodeishFilesystem } from "@lix-js/fs";
2
- import type { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, PluginUsesReservedNamespaceError, PluginsDoNotProvideLoadOrSaveMessagesError } from "./errors.js";
2
+ import type { PluginReturnedInvalidCustomApiError, PluginLoadMessagesFunctionAlreadyDefinedError, PluginSaveMessagesFunctionAlreadyDefinedError, PluginHasInvalidIdError, PluginHasInvalidSchemaError, PluginsDoNotProvideLoadOrSaveMessagesError } from "./errors.js";
3
3
  import type { Message } from "@inlang/message";
4
4
  import type { CustomApiInlangIdeExtension, Plugin } from "@inlang/plugin";
5
5
  import type { ProjectSettings } from "@inlang/project-settings";
@@ -18,7 +18,7 @@ export type ResolvePluginsFunction = (args: {
18
18
  nodeishFs: NodeishFilesystemSubset;
19
19
  }) => Promise<{
20
20
  data: ResolvedPluginApi;
21
- errors: Array<PluginReturnedInvalidCustomApiError | PluginLoadMessagesFunctionAlreadyDefinedError | PluginSaveMessagesFunctionAlreadyDefinedError | PluginHasInvalidIdError | PluginHasInvalidSchemaError | PluginUsesReservedNamespaceError | PluginsDoNotProvideLoadOrSaveMessagesError>;
21
+ errors: Array<PluginReturnedInvalidCustomApiError | PluginLoadMessagesFunctionAlreadyDefinedError | PluginSaveMessagesFunctionAlreadyDefinedError | PluginHasInvalidIdError | PluginHasInvalidSchemaError | PluginsDoNotProvideLoadOrSaveMessagesError>;
22
22
  }>;
23
23
  /**
24
24
  * The API after resolving the plugins.
@@ -1 +1 @@
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"}
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,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,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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inlang/sdk",
3
3
  "type": "module",
4
- "version": "0.12.0",
4
+ "version": "0.14.0",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -38,7 +38,7 @@
38
38
  "@inlang/project-settings": "*",
39
39
  "@inlang/result": "*",
40
40
  "@lix-js/fs": "*",
41
- "@sinclair/typebox": "^0.31.0",
41
+ "@sinclair/typebox": "^0.31.17",
42
42
  "deepmerge-ts": "^5.1.0",
43
43
  "solid-js": "1.6.12",
44
44
  "throttle-debounce": "5.0.0",
@@ -109,8 +109,10 @@ describe("config", () => {
109
109
  const newConfig = { ...project.settings()!, languageTags: ["en", "de"] }
110
110
 
111
111
  project.setSettings(newConfig)
112
+
112
113
  // TODO: how can we await `setConfig` correctly
113
- await new Promise((resolve) => setTimeout(resolve, 0))
114
+ await new Promise((resolve) => setTimeout(resolve, 510))
115
+
114
116
  expect(counter).toBe(2) // 2 times because effect creation + set
115
117
  expect(project.settings()).toStrictEqual(newConfig)
116
118
  })
@@ -202,13 +204,13 @@ describe("messages", () => {
202
204
 
203
205
  expect(Object.values(project.query.messages.getAll()).length).toBe(2)
204
206
 
205
- project.setSettings({ ...project.settings()!, languageTags: [] })
207
+ project.setSettings({ ...project.settings()!, languageTags: ["en"] })
206
208
 
207
209
  // TODO: how can we await `setConfig` correctly
208
- await new Promise((resolve) => setTimeout(resolve, 0))
210
+ await new Promise((resolve) => setTimeout(resolve, 510))
209
211
 
210
- expect(counter).toBe(2) // 2 times because effect creation + set
211
- expect(Object.values(project.query.messages.getAll()).length).toBe(0)
212
+ expect(counter).toBe(1) // 2 times because effect creation + set
213
+ expect(Object.values(project.query.messages.getAll()).length).toBe(2)
212
214
  })
213
215
 
214
216
  it("should react to changes in messages", async () => {
@@ -1,7 +1,6 @@
1
1
  import type { NodeishFilesystemSubset } from "@inlang/plugin"
2
2
  import { normalizePath } from "@lix-js/fs"
3
-
4
- export const isAbsolutePath = (path: string) => /^[/\\]/.test(path)
3
+ import { isAbsolutePath } from "./isAbsolutePath.js"
5
4
 
6
5
  /**
7
6
  * Wraps the nodeish filesystem subset with a function that intercepts paths
@@ -14,19 +13,19 @@ export const createNodeishFsWithAbsolutePaths = (args: {
14
13
  nodeishFs: NodeishFilesystemSubset
15
14
  }): NodeishFilesystemSubset => {
16
15
  if (!isAbsolutePath(args.settingsFilePath)) {
17
- throw new Error("The argument `settingsFilePath` must be an absolute path.")
16
+ throw new Error(`Expected an absolute path but received "${args.settingsFilePath}".`)
18
17
  }
19
18
 
20
19
  // get the base path of the settings file by
21
20
  // removing the file name from the path
22
- const bathPath = args.settingsFilePath.split("/").slice(0, -1).join("/")
21
+ const basePath = normalizePath(args.settingsFilePath).split("/").slice(0, -1).join("/")
23
22
 
24
23
  const makeAbsolute = (path: string) => {
25
24
  if (isAbsolutePath(path)) {
26
- return path
25
+ return normalizePath(path)
27
26
  }
28
27
 
29
- return normalizePath(bathPath + "/" + path)
28
+ return normalizePath(basePath + "/" + path)
30
29
  }
31
30
 
32
31
  return {
@@ -0,0 +1,23 @@
1
+ import { assert, describe, it } from "vitest"
2
+ import { isAbsolutePath } from "./isAbsolutePath.js"
3
+
4
+ describe("isAbsolutePath", () => {
5
+ it("should correctly identify Unix absolute paths", () => {
6
+ assert.isTrue(isAbsolutePath("/home/user/documents/file.txt"))
7
+ assert.isTrue(isAbsolutePath("/usr/local/bin/script.sh"))
8
+ assert.isFalse(isAbsolutePath("relative/path/to/file.txt"))
9
+ })
10
+
11
+ it("should correctly identify Windows absolute paths", () => {
12
+ assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt"))
13
+ assert.isTrue(isAbsolutePath("C:/Users/user/project/project.inlang.json"))
14
+ assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt"))
15
+ })
16
+
17
+ it("should handle edge cases", () => {
18
+ assert.isFalse(isAbsolutePath("")) // Empty path should return false
19
+ assert.isFalse(isAbsolutePath("relative/path/../file.txt")) // Relative path with ".." should return false
20
+ assert.isFalse(isAbsolutePath("../relative/path/to/file.txt"))
21
+ assert.isFalse(isAbsolutePath("./relative/path/to/file.txt"))
22
+ })
23
+ })
@@ -0,0 +1,5 @@
1
+ export const isAbsolutePath = (path: string) => {
2
+ const matchPosixAndWindowsAbsolutePaths =
3
+ /^(?:[A-Za-z]:\\(?:[^\\]+\\)*[^\\]+|[A-Za-z]:\/(?:[^/]+\/)*[^/]+|\/(?:[^/]+\/)*[^/]+)$/
4
+ return matchPosixAndWindowsAbsolutePaths.test(path)
5
+ }
@@ -113,6 +113,23 @@ describe("initialization", () => {
113
113
  expect(result.data).toBeUndefined()
114
114
  })
115
115
 
116
+ it("should resolve from a windows path", async () => {
117
+ const fs = createNodeishMemoryFs()
118
+ fs.mkdir("C:\\Users\\user\\project", { recursive: true })
119
+ fs.writeFile("C:\\Users\\user\\project\\project.inlang.json", JSON.stringify(settings))
120
+
121
+ const result = await tryCatch(() =>
122
+ loadProject({
123
+ settingsFilePath: "C:\\Users\\user\\project\\project.inlang.json",
124
+ nodeishFs: fs,
125
+ _import,
126
+ })
127
+ )
128
+
129
+ expect(result.error).toBeUndefined()
130
+ expect(result.data).toBeDefined()
131
+ })
132
+
116
133
  describe("settings", () => {
117
134
  it("should return an error if settings file is not found", async () => {
118
135
  const fs = createNodeishMemoryFs()
@@ -289,6 +306,28 @@ describe("functionality", () => {
289
306
  expect(result.error).toBeInstanceOf(ProjectSettingsInvalidError)
290
307
  })
291
308
 
309
+ it("should throw an error if sourceLanguageTag is not in languageTags", async () => {
310
+ const fs = await createNodeishMemoryFs()
311
+ await fs.mkdir("/user/project", { recursive: true })
312
+
313
+ const settings: ProjectSettings = {
314
+ sourceLanguageTag: "en",
315
+ languageTags: ["de"],
316
+ modules: [],
317
+ }
318
+
319
+ await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
320
+
321
+ const project = await loadProject({
322
+ settingsFilePath: "/user/project/project.inlang.json",
323
+ nodeishFs: fs,
324
+ _import,
325
+ })
326
+
327
+ expect(project.errors()).toHaveLength(1)
328
+ expect(project.errors()![0]).toBeInstanceOf(ProjectSettingsInvalidError)
329
+ })
330
+
292
331
  it("should write settings to disk", async () => {
293
332
  const fs = await createNodeishMemoryFs()
294
333
  await fs.mkdir("/user/project", { recursive: true })
@@ -302,7 +341,7 @@ describe("functionality", () => {
302
341
  const before = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" })
303
342
  expect(before).toBeDefined()
304
343
 
305
- const result = project.setSettings({ ...settings, languageTags: [] })
344
+ const result = project.setSettings({ ...settings, languageTags: ["en"] })
306
345
  expect(result.data).toBeUndefined()
307
346
  expect(result.error).toBeUndefined()
308
347
 
@@ -701,18 +740,17 @@ describe("functionality", () => {
701
740
  sourceLanguageTag: "en",
702
741
  languageTags: ["en", "de"],
703
742
  modules: ["plugin.js"],
704
- "plugin.project.json": {
743
+ "plugin.placeholder.name": {
705
744
  pathPattern: "./resources/{languageTag}.json",
706
745
  },
707
746
  }
708
747
 
709
- await fs.mkdir("/user/project", { recursive: true })
710
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
748
+ await fs.writeFile("./project.inlang.json", JSON.stringify(settings))
711
749
 
712
750
  const mockSaveFn = vi.fn()
713
751
 
714
752
  const _mockPlugin: Plugin = {
715
- id: "plugin.project.json",
753
+ id: "plugin.placeholder.name",
716
754
  description: "Mock plugin description",
717
755
  displayName: "Mock Plugin",
718
756
  loadMessages: () => [
@@ -730,7 +768,7 @@ describe("functionality", () => {
730
768
  }
731
769
 
732
770
  const project = await loadProject({
733
- settingsFilePath: "/user/project/project.inlang.json",
771
+ settingsFilePath: "/project.inlang.json",
734
772
  nodeishFs: fs,
735
773
  _import,
736
774
  })
@@ -6,7 +6,7 @@ import type {
6
6
  Subscribable,
7
7
  } from "./api.js"
8
8
  import { type ImportFunction, resolveModules } from "./resolve-modules/index.js"
9
- import { TypeCompiler } from "@sinclair/typebox/compiler"
9
+ import { TypeCompiler, ValueErrorType } from "@sinclair/typebox/compiler"
10
10
  import {
11
11
  ProjectSettingsFileJSONSyntaxError,
12
12
  ProjectSettingsFileNotFoundError,
@@ -22,10 +22,9 @@ import { createMessageLintReportsQuery } from "./createMessageLintReportsQuery.j
22
22
  import { ProjectSettings, Message, type NodeishFilesystemSubset } from "./versionedInterfaces.js"
23
23
  import { tryCatch, type Result } from "@inlang/result"
24
24
  import { migrateIfOutdated } from "@inlang/project-settings/migration"
25
- import {
26
- createNodeishFsWithAbsolutePaths,
27
- isAbsolutePath,
28
- } from "./createNodeishFsWithAbsolutePaths.js"
25
+ import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js"
26
+ import { normalizePath } from "@lix-js/fs"
27
+ import { isAbsolutePath } from "./isAbsolutePath.js"
29
28
 
30
29
  const settingsCompiler = TypeCompiler.Compile(ProjectSettings)
31
30
 
@@ -56,16 +55,21 @@ export const loadProject = async (args: {
56
55
  )
57
56
  }
58
57
 
58
+ const settingsFilePath = normalizePath(args.settingsFilePath)
59
+
59
60
  // -- load project ------------------------------------------------------
60
61
  return await createRoot(async () => {
61
62
  const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable()
62
- const nodeishFs = createNodeishFsWithAbsolutePaths(args)
63
+ const nodeishFs = createNodeishFsWithAbsolutePaths({
64
+ settingsFilePath,
65
+ nodeishFs: args.nodeishFs,
66
+ })
63
67
 
64
68
  // -- settings ------------------------------------------------------------
65
69
 
66
70
  const [settings, _setSettings] = createSignal<ProjectSettings>()
67
71
  createEffect(() => {
68
- loadSettings({ settingsFilePath: args.settingsFilePath, nodeishFs })
72
+ loadSettings({ settingsFilePath, nodeishFs })
69
73
  .then((settings) => {
70
74
  setSettings(settings)
71
75
  // rename settings to get a convenient access to the data in Posthog
@@ -278,6 +282,24 @@ const parseSettings = (settings: unknown) => {
278
282
  })
279
283
  }
280
284
  }
285
+
286
+ const { sourceLanguageTag, languageTags } = settings as ProjectSettings
287
+ if (!languageTags.includes(sourceLanguageTag)) {
288
+ throw new ProjectSettingsInvalidError({
289
+ errors: [
290
+ {
291
+ message: `The sourceLanguageTag "${sourceLanguageTag}" is not included in the languageTags "${languageTags.join(
292
+ '", "'
293
+ )}". Please add it to the languageTags.`,
294
+ type: ValueErrorType.String,
295
+ schema: ProjectSettings,
296
+ value: sourceLanguageTag,
297
+ path: "sourceLanguageTag",
298
+ },
299
+ ],
300
+ })
301
+ }
302
+
281
303
  return withMigration
282
304
  }
283
305
 
@@ -10,13 +10,6 @@ export class PluginHasInvalidIdError extends Error {
10
10
  }
11
11
  }
12
12
 
13
- export class PluginUsesReservedNamespaceError extends Error {
14
- constructor(options: { id: Plugin["id"] }) {
15
- super(`Plugin ${options.id} uses reserved namespace 'inlang'.`)
16
- this.name = "PluginUsesReservedNamespaceError"
17
- }
18
- }
19
-
20
13
  export class PluginHasInvalidSchemaError extends Error {
21
14
  constructor(options: { id: Plugin["id"]; errors: ValueError[] }) {
22
15
  super(
@@ -5,7 +5,6 @@ import {
5
5
  PluginLoadMessagesFunctionAlreadyDefinedError,
6
6
  PluginSaveMessagesFunctionAlreadyDefinedError,
7
7
  PluginHasInvalidIdError,
8
- PluginUsesReservedNamespaceError,
9
8
  PluginReturnedInvalidCustomApiError,
10
9
  PluginHasInvalidSchemaError,
11
10
  PluginsDoNotProvideLoadOrSaveMessagesError,
@@ -54,23 +53,6 @@ it("should return an error if a plugin uses APIs that are not available", async
54
53
  expect(resolved.errors[0]).toBeInstanceOf(PluginHasInvalidSchemaError)
55
54
  })
56
55
 
57
- it("should not initialize a plugin that uses the 'inlang' namespace except for inlang whitelisted plugins", async () => {
58
- const mockPlugin: Plugin = {
59
- id: "plugin.inlang.notWhitelisted",
60
- description: { en: "My plugin description" },
61
- displayName: { en: "My plugin" },
62
- loadMessages: () => undefined as any,
63
- }
64
-
65
- const resolved = await resolvePlugins({
66
- plugins: [mockPlugin],
67
- settings: {} as any,
68
- nodeishFs: {} as any,
69
- })
70
-
71
- expect(resolved.errors[0]).toBeInstanceOf(PluginUsesReservedNamespaceError)
72
- })
73
-
74
56
  it("should expose the project settings including the plugin settings", async () => {
75
57
  const settings: ProjectSettings = {
76
58
  sourceLanguageTag: "en",
@@ -8,17 +8,11 @@ import {
8
8
  PluginsDoNotProvideLoadOrSaveMessagesError,
9
9
  PluginHasInvalidIdError,
10
10
  PluginHasInvalidSchemaError,
11
- PluginUsesReservedNamespaceError,
12
11
  } from "./errors.js"
13
12
  import { deepmerge } from "deepmerge-ts"
14
13
  import { TypeCompiler } from "@sinclair/typebox/compiler"
15
14
  import { tryCatch } from "@inlang/result"
16
15
 
17
- const whitelistedPlugins = [
18
- "plugin.inlang.json",
19
- "plugin.inlang.i18next",
20
- "plugin.inlang.paraglideJs",
21
- ]
22
16
  // @ts-ignore - type mismatch error
23
17
  const PluginCompiler = TypeCompiler.Compile(Plugin)
24
18
 
@@ -45,15 +39,6 @@ export const resolvePlugins: ResolvePluginsFunction = async (args) => {
45
39
  result.errors.push(new PluginHasInvalidIdError({ id: plugin.id }))
46
40
  }
47
41
 
48
- // -- USES RESERVED NAMESPACE --
49
- if (plugin.id.includes("inlang") && !whitelistedPlugins.includes(plugin.id)) {
50
- result.errors.push(
51
- new PluginUsesReservedNamespaceError({
52
- id: plugin.id,
53
- })
54
- )
55
- }
56
-
57
42
  // -- USES INVALID SCHEMA --
58
43
  if (errors.length > 0) {
59
44
  result.errors.push(
@@ -5,7 +5,6 @@ import type {
5
5
  PluginSaveMessagesFunctionAlreadyDefinedError,
6
6
  PluginHasInvalidIdError,
7
7
  PluginHasInvalidSchemaError,
8
- PluginUsesReservedNamespaceError,
9
8
  PluginsDoNotProvideLoadOrSaveMessagesError,
10
9
  } from "./errors.js"
11
10
  import type { Message } from "@inlang/message"
@@ -37,7 +36,6 @@ export type ResolvePluginsFunction = (args: {
37
36
  | PluginSaveMessagesFunctionAlreadyDefinedError
38
37
  | PluginHasInvalidIdError
39
38
  | PluginHasInvalidSchemaError
40
- | PluginUsesReservedNamespaceError
41
39
  | PluginsDoNotProvideLoadOrSaveMessagesError
42
40
  >
43
41
  }>