@inlang/sdk 0.18.0 → 0.19.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 (31) hide show
  1. package/dist/adapter/solidAdapter.test.js +16 -15
  2. package/dist/createNodeishFsWithAbsolutePaths.d.ts +2 -2
  3. package/dist/createNodeishFsWithAbsolutePaths.d.ts.map +1 -1
  4. package/dist/createNodeishFsWithAbsolutePaths.js +4 -4
  5. package/dist/createNodeishFsWithAbsolutePaths.test.js +4 -4
  6. package/dist/createNodeishFsWithWatcher.d.ts +1 -1
  7. package/dist/createNodeishFsWithWatcher.d.ts.map +1 -1
  8. package/dist/createNodeishFsWithWatcher.js +6 -4
  9. package/dist/isAbsolutePath.test.js +1 -1
  10. package/dist/loadProject.d.ts +4 -4
  11. package/dist/loadProject.d.ts.map +1 -1
  12. package/dist/loadProject.js +23 -17
  13. package/dist/loadProject.test.js +108 -75
  14. package/dist/migrations/migrateToDirectory.d.ts +10 -0
  15. package/dist/migrations/migrateToDirectory.d.ts.map +1 -0
  16. package/dist/migrations/migrateToDirectory.js +46 -0
  17. package/dist/migrations/migrateToDirectory.test.d.ts +2 -0
  18. package/dist/migrations/migrateToDirectory.test.d.ts.map +1 -0
  19. package/dist/migrations/migrateToDirectory.test.js +48 -0
  20. package/dist/resolve-modules/validateModuleSettings.test.js +1 -1
  21. package/package.json +56 -56
  22. package/src/adapter/solidAdapter.test.ts +16 -15
  23. package/src/createNodeishFsWithAbsolutePaths.test.ts +4 -4
  24. package/src/createNodeishFsWithAbsolutePaths.ts +5 -5
  25. package/src/createNodeishFsWithWatcher.ts +6 -4
  26. package/src/isAbsolutePath.test.ts +1 -1
  27. package/src/loadProject.test.ts +116 -75
  28. package/src/loadProject.ts +36 -22
  29. package/src/migrations/migrateToDirectory.test.ts +54 -0
  30. package/src/migrations/migrateToDirectory.ts +59 -0
  31. package/src/resolve-modules/validateModuleSettings.test.ts +1 -1
@@ -72,10 +72,10 @@ const $import = async (name) => ({
72
72
  describe("config", () => {
73
73
  it("should react to changes in config", async () => {
74
74
  const fs = createNodeishMemoryFs();
75
- await fs.mkdir("/user/project", { recursive: true });
76
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config));
75
+ await fs.mkdir("/user/project.inlang", { recursive: true });
76
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config));
77
77
  const project = solidAdapter(await loadProject({
78
- settingsFilePath: "/user/project/project.inlang.json",
78
+ projectPath: "/user/project.inlang",
79
79
  nodeishFs: fs,
80
80
  _import: $import,
81
81
  }), { from });
@@ -96,10 +96,10 @@ describe("config", () => {
96
96
  describe("installed", () => {
97
97
  it("react to changes that are unrelated to installed items", async () => {
98
98
  const fs = createNodeishMemoryFs();
99
- await fs.mkdir("/user/project", { recursive: true });
100
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config));
99
+ await fs.mkdir("/user/project.inlang", { recursive: true });
100
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config));
101
101
  const project = solidAdapter(await loadProject({
102
- settingsFilePath: "/user/project/project.inlang.json",
102
+ projectPath: "/user/project.inlang",
103
103
  nodeishFs: fs,
104
104
  _import: $import,
105
105
  }), { from });
@@ -149,10 +149,10 @@ describe("messages", () => {
149
149
  saveMessages: () => undefined,
150
150
  };
151
151
  const mockImport = async () => ({ default: mockPlugin });
152
- await fs.mkdir("/user/project", { recursive: true });
153
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(mockConfig));
152
+ await fs.mkdir("/user/project.inlang.inlang", { recursive: true });
153
+ await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(mockConfig));
154
154
  const project = solidAdapter(await loadProject({
155
- settingsFilePath: "/user/project/project.inlang.json",
155
+ projectPath: "/user/project.inlang.inlang",
156
156
  nodeishFs: fs,
157
157
  _import: mockImport,
158
158
  }), { from });
@@ -170,10 +170,10 @@ describe("messages", () => {
170
170
  });
171
171
  it("should react to changes in messages", async () => {
172
172
  const fs = createNodeishMemoryFs();
173
- await fs.mkdir("/user/project", { recursive: true });
174
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config));
173
+ await fs.mkdir("/user/project.inlang.inlang", { recursive: true });
174
+ await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(config));
175
175
  const project = solidAdapter(await loadProject({
176
- settingsFilePath: "/user/project/project.inlang.json",
176
+ projectPath: "/user/project.inlang.inlang",
177
177
  nodeishFs: fs,
178
178
  _import: $import,
179
179
  }), { from });
@@ -216,9 +216,10 @@ describe("lint", () => {
216
216
  it.todo("should react to changes in config", async () => {
217
217
  await createRoot(async () => {
218
218
  const fs = createNodeishMemoryFs();
219
- await fs.writeFile("./project.config.json", JSON.stringify(config));
219
+ await fs.mkdir("./project.inlang", { recursive: true });
220
+ await fs.writeFile("./project.inlang/settings.json", JSON.stringify(config));
220
221
  const project = solidAdapter(await loadProject({
221
- settingsFilePath: "./project.config.json",
222
+ projectPath: "./project.inlang",
222
223
  nodeishFs: fs,
223
224
  _import: $import,
224
225
  }), { from });
@@ -245,7 +246,7 @@ describe("lint", () => {
245
246
  const fs = createNodeishMemoryFs();
246
247
  await fs.writeFile("./project.config.json", JSON.stringify(config));
247
248
  const project = solidAdapter(await loadProject({
248
- settingsFilePath: "./project.config.json",
249
+ projectPath: "./project.config.json",
249
250
  nodeishFs: fs,
250
251
  _import: $import,
251
252
  }), { from });
@@ -3,10 +3,10 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin";
3
3
  * Wraps the nodeish filesystem subset with a function that intercepts paths
4
4
  * and prepends the base path.
5
5
  *
6
- * The paths are resolved from the `settingsFilePath` argument.
6
+ * The paths are resolved from the `projectPath` argument.
7
7
  */
8
8
  export declare const createNodeishFsWithAbsolutePaths: (args: {
9
- settingsFilePath: string;
9
+ projectPath: string;
10
10
  nodeishFs: NodeishFilesystemSubset;
11
11
  }) => NodeishFilesystemSubset;
12
12
  //# sourceMappingURL=createNodeishFsWithAbsolutePaths.d.ts.map
@@ -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;AAI7D;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,SAAU;IACtD,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,uBAAuB,CAAA;CAClC,KAAG,uBA6BH,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,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,uBAAuB,CAAA;CAClC,KAAG,uBA6BH,CAAA"}
@@ -4,15 +4,15 @@ import { isAbsolutePath } from "./isAbsolutePath.js";
4
4
  * Wraps the nodeish filesystem subset with a function that intercepts paths
5
5
  * and prepends the base path.
6
6
  *
7
- * The paths are resolved from the `settingsFilePath` argument.
7
+ * The paths are resolved from the `projectPath` argument.
8
8
  */
9
9
  export const createNodeishFsWithAbsolutePaths = (args) => {
10
- if (!isAbsolutePath(args.settingsFilePath)) {
11
- throw new Error(`Expected an absolute path but received "${args.settingsFilePath}".`);
10
+ if (!isAbsolutePath(args.projectPath)) {
11
+ throw new Error(`Expected an absolute path but received "${args.projectPath}".`);
12
12
  }
13
13
  // get the base path of the settings file by
14
14
  // removing the file name from the path
15
- const basePath = normalizePath(args.settingsFilePath).split("/").slice(0, -1).join("/");
15
+ const basePath = normalizePath(args.projectPath).split("/").slice(0, -1).join("/");
16
16
  const makeAbsolute = (path) => {
17
17
  if (isAbsolutePath(path)) {
18
18
  return normalizePath(path);
@@ -1,11 +1,11 @@
1
1
  import { it, expect, vi } from "vitest";
2
2
  import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js";
3
- it("throws an error if settingsFilePath is not an absolute path", () => {
3
+ it("throws an error if projectPath is not an absolute path", () => {
4
4
  const relativePath = "relative/path";
5
- expect(() => createNodeishFsWithAbsolutePaths({ settingsFilePath: relativePath, nodeishFs: {} })).toThrow();
5
+ expect(() => createNodeishFsWithAbsolutePaths({ projectPath: relativePath, nodeishFs: {} })).toThrow();
6
6
  });
7
7
  it("intercepts paths correctly for readFile", async () => {
8
- const settingsFilePath = `/Users/samuel/Documents/paraglide/example/project.inlang.json`;
8
+ const projectPath = `/Users/samuel/Documents/paraglide/example/project.inlang`;
9
9
  const filePaths = [
10
10
  ["file.txt", `/Users/samuel/Documents/paraglide/example/file.txt`],
11
11
  ["./file.txt", `/Users/samuel/Documents/paraglide/example/file.txt`],
@@ -23,7 +23,7 @@ it("intercepts paths correctly for readFile", async () => {
23
23
  watch: vi.fn(),
24
24
  };
25
25
  const interceptedFs = createNodeishFsWithAbsolutePaths({
26
- settingsFilePath,
26
+ projectPath,
27
27
  nodeishFs: mockNodeishFs,
28
28
  });
29
29
  for (const [path, expectedPath] of filePaths) {
@@ -3,7 +3,7 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin";
3
3
  * Wraps the nodeish filesystem subset with a function that intercepts paths
4
4
  * and prepends the base path.
5
5
  *
6
- * The paths are resolved from the `settingsFilePath` argument.
6
+ * The paths are resolved from the `projectPath` argument.
7
7
  */
8
8
  export declare const createNodeishFsWithWatcher: (args: {
9
9
  nodeishFs: NodeishFilesystemSubset;
@@ -1 +1 @@
1
- {"version":3,"file":"createNodeishFsWithWatcher.d.ts","sourceRoot":"","sources":["../src/createNodeishFsWithWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,SAAU;IAChD,SAAS,EAAE,uBAAuB,CAAA;IAClC,cAAc,EAAE,MAAM,IAAI,CAAA;CAC1B,KAAG,uBA4CH,CAAA"}
1
+ {"version":3,"file":"createNodeishFsWithWatcher.d.ts","sourceRoot":"","sources":["../src/createNodeishFsWithWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,SAAU;IAChD,SAAS,EAAE,uBAAuB,CAAA;IAClC,cAAc,EAAE,MAAM,IAAI,CAAA;CAC1B,KAAG,uBA8CH,CAAA"}
@@ -2,7 +2,7 @@
2
2
  * Wraps the nodeish filesystem subset with a function that intercepts paths
3
3
  * and prepends the base path.
4
4
  *
5
- * The paths are resolved from the `settingsFilePath` argument.
5
+ * The paths are resolved from the `projectPath` argument.
6
6
  */
7
7
  export const createNodeishFsWithWatcher = (args) => {
8
8
  const pathList = [];
@@ -14,9 +14,11 @@ export const createNodeishFsWithWatcher = (args) => {
14
14
  signal: abortController.signal,
15
15
  persistent: false,
16
16
  });
17
- //eslint-disable-next-line @typescript-eslint/no-unused-vars
18
- for await (const event of watcher) {
19
- args.updateMessages();
17
+ if (watcher) {
18
+ //eslint-disable-next-line @typescript-eslint/no-unused-vars
19
+ for await (const event of watcher) {
20
+ args.updateMessages();
21
+ }
20
22
  }
21
23
  }
22
24
  catch (err) {
@@ -8,7 +8,7 @@ describe("isAbsolutePath", () => {
8
8
  });
9
9
  it("should correctly identify Windows absolute paths", () => {
10
10
  assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt"));
11
- assert.isTrue(isAbsolutePath("C:/Users/user/project/project.inlang.json"));
11
+ assert.isTrue(isAbsolutePath("C:/Users/user/project.inlang/settings.json"));
12
12
  assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt"));
13
13
  });
14
14
  it("should handle edge cases", () => {
@@ -1,10 +1,10 @@
1
1
  import type { InlangProject, Subscribable } from "./api.js";
2
2
  import { type ImportFunction } from "./resolve-modules/index.js";
3
- import { type NodeishFilesystemSubset } from "./versionedInterfaces.js";
3
+ import { type NodeishFilesystem } from "@lix-js/fs";
4
4
  /**
5
5
  * Creates an inlang instance.
6
6
  *
7
- * @param settingsFilePath - Absolute path to the inlang settings file.
7
+ * @param projectPath - Absolute path to the inlang settings file.
8
8
  * @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
9
9
  * @param _import - Use `_import` to pass a custom import function for testing,
10
10
  * and supporting legacy resolvedModules such as CJS.
@@ -12,8 +12,8 @@ import { type NodeishFilesystemSubset } from "./versionedInterfaces.js";
12
12
  *
13
13
  */
14
14
  export declare const loadProject: (args: {
15
- settingsFilePath: string;
16
- nodeishFs: NodeishFilesystemSubset;
15
+ projectPath: string;
16
+ nodeishFs: NodeishFilesystem;
17
17
  _import?: ImportFunction | undefined;
18
18
  _capture?: ((id: string, props: Record<string, unknown>) => void) | undefined;
19
19
  }) => Promise<InlangProject>;
@@ -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,CAsNxB,CAAA;AAuHD,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;AAkBhF,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOlE;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW;iBACV,MAAM;eACR,iBAAiB;;qBAEZ,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;MAC5D,QAAQ,aAAa,CAkOxB,CAAA;AAwHD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
@@ -12,11 +12,12 @@ import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsoluteP
12
12
  import { normalizePath } from "@lix-js/fs";
13
13
  import { isAbsolutePath } from "./isAbsolutePath.js";
14
14
  import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js";
15
+ import { maybeMigrateToDirectory } from "./migrations/migrateToDirectory.js";
15
16
  const settingsCompiler = TypeCompiler.Compile(ProjectSettings);
16
17
  /**
17
18
  * Creates an inlang instance.
18
19
  *
19
- * @param settingsFilePath - Absolute path to the inlang settings file.
20
+ * @param projectPath - Absolute path to the inlang settings file.
20
21
  * @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
21
22
  * @param _import - Use `_import` to pass a custom import function for testing,
22
23
  * and supporting legacy resolvedModules such as CJS.
@@ -24,25 +25,30 @@ const settingsCompiler = TypeCompiler.Compile(ProjectSettings);
24
25
  *
25
26
  */
26
27
  export const loadProject = async (args) => {
28
+ const projectPath = normalizePath(args.projectPath);
29
+ // -- migrate if outdated ------------------------------------------------
30
+ await maybeMigrateToDirectory({ nodeishFs: args.nodeishFs, projectPath });
27
31
  // -- validation --------------------------------------------------------
28
- //! the only place where throwing is acceptable because the project
29
- //! won't even be loaded. do not throw anywhere else. otherwise, apps
30
- //! can't handle errors gracefully.
31
- if (!isAbsolutePath(args.settingsFilePath)) {
32
- throw new LoadProjectInvalidArgument(`Expected an absolute path but received "${args.settingsFilePath}".`, { argument: "settingsFilePath" });
32
+ // the only place where throwing is acceptable because the project
33
+ // won't even be loaded. do not throw anywhere else. otherwise, apps
34
+ // can't handle errors gracefully.
35
+ if (!isAbsolutePath(args.projectPath)) {
36
+ throw new LoadProjectInvalidArgument(`Expected an absolute path but received "${args.projectPath}".`, { argument: "projectPath" });
37
+ }
38
+ else if (/[^\\/]+\.inlang$/.test(projectPath) === false) {
39
+ throw new LoadProjectInvalidArgument(`Expected a path ending in "{name}.inlang" but received "${projectPath}".\n\nValid examples: \n- "/path/to/micky-mouse.inlang"\n- "/path/to/green-elephant.inlang\n`, { argument: "projectPath" });
33
40
  }
34
- const settingsFilePath = normalizePath(args.settingsFilePath);
35
41
  // -- load project ------------------------------------------------------
36
42
  return await createRoot(async () => {
37
43
  const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable();
38
44
  const nodeishFs = createNodeishFsWithAbsolutePaths({
39
- settingsFilePath,
45
+ projectPath,
40
46
  nodeishFs: args.nodeishFs,
41
47
  });
42
48
  // -- settings ------------------------------------------------------------
43
49
  const [settings, _setSettings] = createSignal();
44
50
  createEffect(() => {
45
- loadSettings({ settingsFilePath, nodeishFs })
51
+ loadSettings({ settingsFilePath: projectPath + "/settings.json", nodeishFs })
46
52
  .then((settings) => {
47
53
  setSettings(settings);
48
54
  // rename settings to get a convenient access to the data in Posthog
@@ -54,7 +60,7 @@ export const loadProject = async (args) => {
54
60
  });
55
61
  });
56
62
  // TODO: create FS watcher and update settings on change
57
- const writeSettingsToDisk = skipFirst((settings) => _writeSettingsToDisk({ nodeishFs, settings }));
63
+ const writeSettingsToDisk = skipFirst((settings) => _writeSettingsToDisk({ nodeishFs, settings, projectPath }));
58
64
  const setSettings = (settings) => {
59
65
  try {
60
66
  const validatedSettings = parseSettings(settings);
@@ -158,12 +164,12 @@ export const loadProject = async (args) => {
158
164
  cause: err,
159
165
  });
160
166
  }
161
- // if (
162
- // newMessages.length !== 0 &&
163
- // JSON.stringify(newMessages) !== JSON.stringify(messages())
164
- // ) {
165
- // setMessages(newMessages)
166
- // }
167
+ const abortController = new AbortController();
168
+ if (newMessages.length !== 0 &&
169
+ JSON.stringify(newMessages) !== JSON.stringify(messages()) &&
170
+ nodeishFs.watch("/", { signal: abortController.signal }) === undefined) {
171
+ setMessages(newMessages);
172
+ }
167
173
  }, { atBegin: false }));
168
174
  createEffect(() => {
169
175
  debouncedSave(messagesQuery.getAll());
@@ -240,7 +246,7 @@ const _writeSettingsToDisk = async (args) => {
240
246
  if (serializeSettingsError) {
241
247
  throw serializeSettingsError;
242
248
  }
243
- const { error: writeSettingsError } = await tryCatch(async () => args.nodeishFs.writeFile("./project.inlang.json", serializedSettings));
249
+ const { error: writeSettingsError } = await tryCatch(async () => args.nodeishFs.writeFile(args.projectPath + "/settings.json", serializedSettings));
244
250
  if (writeSettingsError) {
245
251
  throw writeSettingsError;
246
252
  }