@inlang/sdk 0.18.0 → 0.20.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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/adapter/solidAdapter.test.js +16 -15
  3. package/dist/createMessageLintReportsQuery.d.ts +2 -3
  4. package/dist/createMessageLintReportsQuery.d.ts.map +1 -1
  5. package/dist/createMessageLintReportsQuery.js +42 -21
  6. package/dist/createNodeishFsWithAbsolutePaths.d.ts +2 -2
  7. package/dist/createNodeishFsWithAbsolutePaths.d.ts.map +1 -1
  8. package/dist/createNodeishFsWithAbsolutePaths.js +4 -4
  9. package/dist/createNodeishFsWithAbsolutePaths.test.js +4 -4
  10. package/dist/createNodeishFsWithWatcher.d.ts +1 -1
  11. package/dist/createNodeishFsWithWatcher.d.ts.map +1 -1
  12. package/dist/createNodeishFsWithWatcher.js +6 -4
  13. package/dist/generateProjectId.d.ts +3 -0
  14. package/dist/generateProjectId.d.ts.map +1 -0
  15. package/dist/generateProjectId.js +11 -0
  16. package/dist/generateProjectId.test.d.ts +2 -0
  17. package/dist/generateProjectId.test.d.ts.map +1 -0
  18. package/dist/generateProjectId.test.js +18 -0
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -0
  22. package/dist/isAbsolutePath.test.js +1 -1
  23. package/dist/listProjects.d.ts +5 -0
  24. package/dist/listProjects.d.ts.map +1 -0
  25. package/dist/listProjects.js +31 -0
  26. package/dist/listProjects.test.d.ts +2 -0
  27. package/dist/listProjects.test.d.ts.map +1 -0
  28. package/dist/listProjects.test.js +56 -0
  29. package/dist/loadProject.d.ts +6 -4
  30. package/dist/loadProject.d.ts.map +1 -1
  31. package/dist/loadProject.js +58 -22
  32. package/dist/loadProject.test.js +157 -75
  33. package/dist/migrations/migrateToDirectory.d.ts +10 -0
  34. package/dist/migrations/migrateToDirectory.d.ts.map +1 -0
  35. package/dist/migrations/migrateToDirectory.js +46 -0
  36. package/dist/migrations/migrateToDirectory.test.d.ts +2 -0
  37. package/dist/migrations/migrateToDirectory.test.d.ts.map +1 -0
  38. package/dist/migrations/migrateToDirectory.test.js +48 -0
  39. package/dist/resolve-modules/validateModuleSettings.test.js +1 -1
  40. package/package.json +57 -56
  41. package/src/adapter/solidAdapter.test.ts +16 -15
  42. package/src/createMessageLintReportsQuery.ts +57 -28
  43. package/src/createNodeishFsWithAbsolutePaths.test.ts +4 -4
  44. package/src/createNodeishFsWithAbsolutePaths.ts +5 -5
  45. package/src/createNodeishFsWithWatcher.ts +6 -4
  46. package/src/generateProjectId.test.ts +22 -0
  47. package/src/generateProjectId.ts +14 -0
  48. package/src/index.ts +1 -0
  49. package/src/isAbsolutePath.test.ts +1 -1
  50. package/src/listProjects.test.ts +69 -0
  51. package/src/listProjects.ts +39 -0
  52. package/src/loadProject.test.ts +182 -76
  53. package/src/loadProject.ts +77 -28
  54. package/src/migrations/migrateToDirectory.test.ts +54 -0
  55. package/src/migrations/migrateToDirectory.ts +59 -0
  56. package/src/resolve-modules/validateModuleSettings.test.ts +1 -1
@@ -12,11 +12,13 @@ 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";
16
+ import { generateProjectId } from "./generateProjectId.js";
15
17
  const settingsCompiler = TypeCompiler.Compile(ProjectSettings);
16
18
  /**
17
19
  * Creates an inlang instance.
18
20
  *
19
- * @param settingsFilePath - Absolute path to the inlang settings file.
21
+ * @param projectPath - Absolute path to the inlang settings file.
20
22
  * @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
21
23
  * @param _import - Use `_import` to pass a custom import function for testing,
22
24
  * and supporting legacy resolvedModules such as CJS.
@@ -24,37 +26,69 @@ const settingsCompiler = TypeCompiler.Compile(ProjectSettings);
24
26
  *
25
27
  */
26
28
  export const loadProject = async (args) => {
29
+ const projectPath = normalizePath(args.projectPath);
30
+ // -- migrate if outdated ------------------------------------------------
31
+ await maybeMigrateToDirectory({ nodeishFs: args.nodeishFs, projectPath });
27
32
  // -- 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" });
33
+ // the only place where throwing is acceptable because the project
34
+ // won't even be loaded. do not throw anywhere else. otherwise, apps
35
+ // can't handle errors gracefully.
36
+ if (!isAbsolutePath(args.projectPath)) {
37
+ throw new LoadProjectInvalidArgument(`Expected an absolute path but received "${args.projectPath}".`, { argument: "projectPath" });
38
+ }
39
+ else if (/[^\\/]+\.inlang$/.test(projectPath) === false) {
40
+ 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
41
  }
34
- const settingsFilePath = normalizePath(args.settingsFilePath);
35
42
  // -- load project ------------------------------------------------------
43
+ let idError;
36
44
  return await createRoot(async () => {
37
45
  const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable();
38
46
  const nodeishFs = createNodeishFsWithAbsolutePaths({
39
- settingsFilePath,
47
+ projectPath,
40
48
  nodeishFs: args.nodeishFs,
41
49
  });
50
+ let projectId;
51
+ try {
52
+ projectId = await nodeishFs.readFile(projectPath + "/project_id", {
53
+ encoding: "utf-8",
54
+ });
55
+ }
56
+ catch (error) {
57
+ // @ts-ignore
58
+ if (error.code === "ENOENT") {
59
+ if (args.repo) {
60
+ projectId = await generateProjectId(args.repo, projectPath);
61
+ if (projectId) {
62
+ await nodeishFs.writeFile(projectPath + "/project_id", projectId);
63
+ }
64
+ }
65
+ }
66
+ else {
67
+ idError = error;
68
+ }
69
+ }
42
70
  // -- settings ------------------------------------------------------------
43
71
  const [settings, _setSettings] = createSignal();
44
72
  createEffect(() => {
45
- loadSettings({ settingsFilePath, nodeishFs })
73
+ // TODO:
74
+ // if (projectId) {
75
+ // telemetryBrowser.group("project", projectId, {
76
+ // name: projectId,
77
+ // })
78
+ // }
79
+ loadSettings({ settingsFilePath: projectPath + "/settings.json", nodeishFs })
46
80
  .then((settings) => {
47
81
  setSettings(settings);
48
82
  // rename settings to get a convenient access to the data in Posthog
49
83
  const project_settings = settings;
50
- args._capture?.("SDK used settings", { project_settings });
84
+ args._capture?.("SDK used settings", { project_settings, group: projectId });
51
85
  })
52
86
  .catch((err) => {
53
87
  markInitAsFailed(err);
54
88
  });
55
89
  });
56
90
  // TODO: create FS watcher and update settings on change
57
- const writeSettingsToDisk = skipFirst((settings) => _writeSettingsToDisk({ nodeishFs, settings }));
91
+ const writeSettingsToDisk = skipFirst((settings) => _writeSettingsToDisk({ nodeishFs, settings, projectPath }));
58
92
  const setSettings = (settings) => {
59
93
  try {
60
94
  const validatedSettings = parseSettings(settings);
@@ -84,11 +118,10 @@ export const loadProject = async (args) => {
84
118
  // -- messages ----------------------------------------------------------
85
119
  let settingsValue;
86
120
  createEffect(() => (settingsValue = settings())); // workaround to not run effects twice (e.g. settings change + modules change) (I'm sure there exists a solid way of doing this, but I haven't found it yet)
121
+ // please don't use this as source of truth, use the query instead
122
+ // needed for granular linting
87
123
  const [messages, setMessages] = createSignal();
88
124
  createEffect(() => {
89
- const conf = settings();
90
- if (!conf)
91
- return;
92
125
  const _resolvedModules = resolvedModules();
93
126
  if (!_resolvedModules)
94
127
  return;
@@ -142,8 +175,10 @@ export const loadProject = async (args) => {
142
175
  };
143
176
  // -- app ---------------------------------------------------------------
144
177
  const initializeError = await initialized.catch((error) => error);
178
+ const abortController = new AbortController();
179
+ const hasWatcher = nodeishFs.watch("/", { signal: abortController.signal }) !== undefined;
145
180
  const messagesQuery = createMessagesQuery(() => messages() || []);
146
- const lintReportsQuery = createMessageLintReportsQuery(messages, settings, installedMessageLintRules, resolvedModules);
181
+ const lintReportsQuery = createMessageLintReportsQuery(messagesQuery, settings, installedMessageLintRules, resolvedModules, hasWatcher);
147
182
  const debouncedSave = skipFirst(debounce(500, async (newMessages) => {
148
183
  try {
149
184
  if (JSON.stringify(newMessages) !== JSON.stringify(messages())) {
@@ -158,12 +193,12 @@ export const loadProject = async (args) => {
158
193
  cause: err,
159
194
  });
160
195
  }
161
- // if (
162
- // newMessages.length !== 0 &&
163
- // JSON.stringify(newMessages) !== JSON.stringify(messages())
164
- // ) {
165
- // setMessages(newMessages)
166
- // }
196
+ const abortController = new AbortController();
197
+ if (newMessages.length !== 0 &&
198
+ JSON.stringify(newMessages) !== JSON.stringify(messages()) &&
199
+ nodeishFs.watch("/", { signal: abortController.signal }) !== undefined) {
200
+ setMessages(newMessages);
201
+ }
167
202
  }, { atBegin: false }));
168
203
  createEffect(() => {
169
204
  debouncedSave(messagesQuery.getAll());
@@ -175,6 +210,7 @@ export const loadProject = async (args) => {
175
210
  },
176
211
  errors: createSubscribable(() => [
177
212
  ...(initializeError ? [initializeError] : []),
213
+ ...(idError ? [idError] : []),
178
214
  ...(resolvedModules() ? resolvedModules().errors : []),
179
215
  // have a query error exposed
180
216
  //...(lintErrors() ?? []),
@@ -240,7 +276,7 @@ const _writeSettingsToDisk = async (args) => {
240
276
  if (serializeSettingsError) {
241
277
  throw serializeSettingsError;
242
278
  }
243
- const { error: writeSettingsError } = await tryCatch(async () => args.nodeishFs.writeFile("./project.inlang.json", serializedSettings));
279
+ const { error: writeSettingsError } = await tryCatch(async () => args.nodeishFs.writeFile(args.projectPath + "/settings.json", serializedSettings));
244
280
  if (writeSettingsError) {
245
281
  throw writeSettingsError;
246
282
  }
@@ -5,6 +5,7 @@ import { LoadProjectInvalidArgument, ProjectSettingsFileJSONSyntaxError, Project
5
5
  import { createNodeishMemoryFs, normalizePath } from "@lix-js/fs";
6
6
  import { createMessage } from "./test-utilities/createMessage.js";
7
7
  import { tryCatch } from "@inlang/result";
8
+ import { mockRepo } from "@lix-js/client";
8
9
  // ------------------------------------------------------------------------------------------------
9
10
  const getValue = (subscribable) => {
10
11
  let value;
@@ -80,23 +81,102 @@ const _import = async (name) => ({
80
81
  default: name === "plugin.js" ? mockPlugin : mockMessageLintRule,
81
82
  });
82
83
  // ------------------------------------------------------------------------------------------------
84
+ /**
85
+ * Dear Developers,
86
+ *
87
+ * Inlang projects (folders) are not like .vscode, .git, or .github folders. Treat em
88
+ * like files: they can be renamed and moved around.
89
+ */
90
+ it("should throw if a project (path) does not have a name", async () => {
91
+ const fs = createNodeishMemoryFs();
92
+ const project = await tryCatch(() => loadProject({
93
+ projectPath: "/source-code/.inlang",
94
+ nodeishFs: fs,
95
+ _import,
96
+ }));
97
+ expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument);
98
+ });
99
+ it("should throw if a project path does not end with .inlang", async () => {
100
+ const fs = createNodeishMemoryFs();
101
+ const invalidPaths = [
102
+ "/source-code/frontend.inlang/settings",
103
+ "/source-code/frontend.inlang/settings.json",
104
+ "/source-code/frontend.inlang.md",
105
+ ];
106
+ for (const invalidPath of invalidPaths) {
107
+ const project = await tryCatch(() => loadProject({
108
+ projectPath: invalidPath,
109
+ nodeishFs: fs,
110
+ _import,
111
+ }));
112
+ expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument);
113
+ }
114
+ });
83
115
  describe("initialization", () => {
84
- it("should throw if settingsFilePath is not an absolute path", async () => {
116
+ it("should throw if projectPath is not an absolute path", async () => {
85
117
  const fs = createNodeishMemoryFs();
86
118
  const result = await tryCatch(() => loadProject({
87
- settingsFilePath: "relative/path",
119
+ projectPath: "relative/path",
88
120
  nodeishFs: fs,
89
121
  _import,
90
122
  }));
91
123
  expect(result.error).toBeInstanceOf(LoadProjectInvalidArgument);
92
124
  expect(result.data).toBeUndefined();
93
125
  });
126
+ it("should generate projectId on missing projectid", async () => {
127
+ const repo = await mockRepo();
128
+ const existing = await repo.nodeishFs
129
+ .readFile("/project.inlang/project_id", {
130
+ encoding: "utf-8",
131
+ })
132
+ .catch((error) => {
133
+ return { error };
134
+ });
135
+ // @ts-ignore
136
+ expect(existing.error.code).toBe("ENOENT");
137
+ const result = await tryCatch(() => loadProject({
138
+ projectPath: "/project.inlang",
139
+ nodeishFs: repo.nodeishFs,
140
+ repo,
141
+ _import,
142
+ }));
143
+ const newId = await repo.nodeishFs
144
+ .readFile("/project.inlang/project_id", {
145
+ encoding: "utf-8",
146
+ })
147
+ .catch((error) => {
148
+ return { error };
149
+ });
150
+ expect(newId).toBe("7cd6c2b7cf12febf99496408917123fdfe158b6bc442914f5fb42aa74346bd50");
151
+ expect(result.error).toBeUndefined();
152
+ expect(result.data).toBeDefined();
153
+ });
154
+ it("should reuse projectId on existing projectid", async () => {
155
+ const repo = await mockRepo();
156
+ repo.nodeishFs.writeFile("/project.inlang/project_id", "testId");
157
+ const result = await tryCatch(() => loadProject({
158
+ projectPath: "/project.inlang",
159
+ nodeishFs: repo.nodeishFs,
160
+ repo,
161
+ _import,
162
+ }));
163
+ const newId = await repo.nodeishFs
164
+ .readFile("/project.inlang/project_id", {
165
+ encoding: "utf-8",
166
+ })
167
+ .catch((error) => {
168
+ return { error };
169
+ });
170
+ expect(newId).toBe("testId");
171
+ expect(result.error).toBeUndefined();
172
+ expect(result.data).toBeDefined();
173
+ });
94
174
  it("should resolve from a windows path", async () => {
95
175
  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));
176
+ fs.mkdir("C:\\Users\\user\\project.inlang", { recursive: true });
177
+ fs.writeFile("C:\\Users\\user\\project.inlang\\settings.json", JSON.stringify(settings));
98
178
  const result = await tryCatch(() => loadProject({
99
- settingsFilePath: "C:\\Users\\user\\project\\project.inlang.json",
179
+ projectPath: "C:\\Users\\user\\project.inlang",
100
180
  nodeishFs: fs,
101
181
  _import,
102
182
  }));
@@ -108,7 +188,7 @@ describe("initialization", () => {
108
188
  const fs = createNodeishMemoryFs();
109
189
  fs.mkdir("/user/project", { recursive: true });
110
190
  const project = await loadProject({
111
- settingsFilePath: "/user/project/test.json",
191
+ projectPath: "/user/non-existend-project.inlang",
112
192
  nodeishFs: fs,
113
193
  _import,
114
194
  });
@@ -116,10 +196,10 @@ describe("initialization", () => {
116
196
  });
117
197
  it("should return an error if settings file is not a valid JSON", async () => {
118
198
  const fs = await createNodeishMemoryFs();
119
- await fs.mkdir("/user/project", { recursive: true });
120
- await fs.writeFile("/user/project/project.inlang.json", "invalid json");
199
+ await fs.mkdir("/user/project.inlang", { recursive: true });
200
+ await fs.writeFile("/user/project.inlang/settings.json", "invalid json");
121
201
  const project = await loadProject({
122
- settingsFilePath: "/user/project/project.inlang.json",
202
+ projectPath: "/user/project.inlang",
123
203
  nodeishFs: fs,
124
204
  _import,
125
205
  });
@@ -127,10 +207,10 @@ describe("initialization", () => {
127
207
  });
128
208
  it("should return an error if settings file is does not match schema", async () => {
129
209
  const fs = await createNodeishMemoryFs();
130
- await fs.mkdir("/user/project", { recursive: true });
131
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({}));
210
+ await fs.mkdir("/user/project.inlang", { recursive: true });
211
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({}));
132
212
  const project = await loadProject({
133
- settingsFilePath: "/user/project/project.inlang.json",
213
+ projectPath: "/user/project.inlang",
134
214
  nodeishFs: fs,
135
215
  _import,
136
216
  });
@@ -138,10 +218,10 @@ describe("initialization", () => {
138
218
  });
139
219
  it("should return the parsed settings", async () => {
140
220
  const fs = await createNodeishMemoryFs();
141
- await fs.mkdir("/user/project", { recursive: true });
142
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
221
+ await fs.mkdir("/user/project.inlang", { recursive: true });
222
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
143
223
  const project = await loadProject({
144
- settingsFilePath: "/user/project/project.inlang.json",
224
+ projectPath: "/user/project.inlang",
145
225
  nodeishFs: fs,
146
226
  _import,
147
227
  });
@@ -150,21 +230,21 @@ describe("initialization", () => {
150
230
  it("should not re-write the settings to disk when initializing", async () => {
151
231
  const fs = await createNodeishMemoryFs();
152
232
  const settingsWithDeifferentFormatting = JSON.stringify(settings, undefined, 4);
153
- await fs.mkdir("/user/project", { recursive: true });
154
- await fs.writeFile("/user/project/project.inlang.json", settingsWithDeifferentFormatting);
233
+ await fs.mkdir("/user/project.inlang", { recursive: true });
234
+ await fs.writeFile("/user/project.inlang/settings.json", settingsWithDeifferentFormatting);
155
235
  const project = await loadProject({
156
- settingsFilePath: "/user/project/project.inlang.json",
236
+ projectPath: "/user/project.inlang",
157
237
  nodeishFs: fs,
158
238
  _import,
159
239
  });
160
- const settingsOnDisk = await fs.readFile("/user/project/project.inlang.json", {
240
+ const settingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", {
161
241
  encoding: "utf-8",
162
242
  });
163
243
  expect(settingsOnDisk).toBe(settingsWithDeifferentFormatting);
164
244
  project.setSettings(project.settings());
165
245
  // TODO: how can we await `setsettings` correctly
166
246
  await new Promise((resolve) => setTimeout(resolve, 0));
167
- const newsettingsOnDisk = await fs.readFile("/user/project/project.inlang.json", {
247
+ const newsettingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", {
168
248
  encoding: "utf-8",
169
249
  });
170
250
  expect(newsettingsOnDisk).not.toBe(settingsWithDeifferentFormatting);
@@ -176,10 +256,10 @@ describe("initialization", () => {
176
256
  default: {},
177
257
  });
178
258
  const fs = createNodeishMemoryFs();
179
- await fs.mkdir("/user/project", { recursive: true });
180
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
259
+ await fs.mkdir("/user/project.inlang", { recursive: true });
260
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
181
261
  const project = await loadProject({
182
- settingsFilePath: "/user/project/project.inlang.json",
262
+ projectPath: "/user/project.inlang",
183
263
  nodeishFs: fs,
184
264
  _import: $badImport,
185
265
  });
@@ -204,10 +284,10 @@ describe("functionality", () => {
204
284
  describe("settings", () => {
205
285
  it("should return the settings", async () => {
206
286
  const fs = await createNodeishMemoryFs();
207
- await fs.mkdir("/user/project", { recursive: true });
208
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
287
+ await fs.mkdir("/user/project.inlang", { recursive: true });
288
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
209
289
  const project = await loadProject({
210
- settingsFilePath: "/user/project/project.inlang.json",
290
+ projectPath: "/user/project.inlang",
211
291
  nodeishFs: fs,
212
292
  _import,
213
293
  });
@@ -215,10 +295,10 @@ describe("functionality", () => {
215
295
  });
216
296
  it("should set a new settings", async () => {
217
297
  const fs = await createNodeishMemoryFs();
218
- await fs.mkdir("/user/project", { recursive: true });
219
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
298
+ await fs.mkdir("/user/project.inlang", { recursive: true });
299
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
220
300
  const project = await loadProject({
221
- settingsFilePath: "/user/project/project.inlang.json",
301
+ projectPath: "/user/project.inlang",
222
302
  nodeishFs: fs,
223
303
  _import,
224
304
  });
@@ -235,12 +315,12 @@ describe("functionality", () => {
235
315
  });
236
316
  });
237
317
  describe("setSettings", () => {
238
- it("should fail if settings is not valid", async () => {
318
+ it("should fail if settings are not valid", async () => {
239
319
  const fs = await createNodeishMemoryFs();
240
- await fs.mkdir("/user/project", { recursive: true });
241
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
320
+ await fs.mkdir("/user/project.inlang", { recursive: true });
321
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
242
322
  const project = await loadProject({
243
- settingsFilePath: "/user/project/project.inlang.json",
323
+ projectPath: "/user/project.inlang",
244
324
  nodeishFs: fs,
245
325
  _import,
246
326
  });
@@ -250,15 +330,15 @@ describe("functionality", () => {
250
330
  });
251
331
  it("should throw an error if sourceLanguageTag is not in languageTags", async () => {
252
332
  const fs = await createNodeishMemoryFs();
253
- await fs.mkdir("/user/project", { recursive: true });
333
+ await fs.mkdir("/user/project.inlang", { recursive: true });
254
334
  const settings = {
255
335
  sourceLanguageTag: "en",
256
336
  languageTags: ["de"],
257
337
  modules: [],
258
338
  };
259
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
339
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
260
340
  const project = await loadProject({
261
- settingsFilePath: "/user/project/project.inlang.json",
341
+ projectPath: "/user/project.inlang",
262
342
  nodeishFs: fs,
263
343
  _import,
264
344
  });
@@ -267,21 +347,21 @@ describe("functionality", () => {
267
347
  });
268
348
  it("should write settings to disk", async () => {
269
349
  const fs = await createNodeishMemoryFs();
270
- await fs.mkdir("/user/project", { recursive: true });
271
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
350
+ await fs.mkdir("/user/project.inlang", { recursive: true });
351
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
272
352
  const project = await loadProject({
273
- settingsFilePath: "/user/project/project.inlang.json",
353
+ projectPath: "/user/project.inlang",
274
354
  nodeishFs: fs,
275
355
  _import,
276
356
  });
277
- const before = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" });
357
+ const before = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" });
278
358
  expect(before).toBeDefined();
279
- const result = project.setSettings({ ...settings, languageTags: ["en"] });
359
+ const result = project.setSettings({ ...settings, languageTags: ["en", "nl", "de"] });
280
360
  expect(result.data).toBeUndefined();
281
361
  expect(result.error).toBeUndefined();
282
362
  // TODO: how to wait for fs.writeFile to finish?
283
- await new Promise((resolve) => setTimeout(resolve, 0));
284
- const after = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" });
363
+ await new Promise((resolve) => setTimeout(resolve, 50));
364
+ const after = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" });
285
365
  expect(after).toBeDefined();
286
366
  expect(after).not.toBe(before);
287
367
  });
@@ -294,10 +374,10 @@ describe("functionality", () => {
294
374
  languageTags: ["en"],
295
375
  modules: ["plugin.js", "lintRule.js"],
296
376
  };
297
- await fs.mkdir("/user/project", { recursive: true });
298
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
377
+ await fs.mkdir("/user/project.inlang", { recursive: true });
378
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
299
379
  const project = await loadProject({
300
- settingsFilePath: "/user/project/project.inlang.json",
380
+ projectPath: "/user/project.inlang",
301
381
  nodeishFs: fs,
302
382
  _import,
303
383
  });
@@ -322,10 +402,10 @@ describe("functionality", () => {
322
402
  languageTags: ["en"],
323
403
  modules: ["plugin.js", "lintRule.js"],
324
404
  };
325
- await fs.mkdir("/user/project", { recursive: true });
326
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
405
+ await fs.mkdir("/user/project.inlang", { recursive: true });
406
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
327
407
  const project = await loadProject({
328
- settingsFilePath: "/user/project/project.inlang.json",
408
+ projectPath: "/user/project.inlang",
329
409
  nodeishFs: fs,
330
410
  _import,
331
411
  });
@@ -353,8 +433,8 @@ describe("functionality", () => {
353
433
  saveMessages: () => undefined,
354
434
  };
355
435
  const fs = await createNodeishMemoryFs();
356
- await fs.mkdir("/user/project", { recursive: true });
357
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({
436
+ await fs.mkdir("/user/project.inlang", { recursive: true });
437
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({
358
438
  sourceLanguageTag: "en",
359
439
  languageTags: ["en"],
360
440
  modules: ["plugin.js", "lintRule.js"],
@@ -365,7 +445,7 @@ describe("functionality", () => {
365
445
  };
366
446
  };
367
447
  const project = await loadProject({
368
- settingsFilePath: "/user/project/project.inlang.json",
448
+ projectPath: "/user/project.inlang",
369
449
  nodeishFs: fs,
370
450
  _import,
371
451
  });
@@ -395,8 +475,8 @@ describe("functionality", () => {
395
475
  saveMessages: () => undefined,
396
476
  };
397
477
  const fs = await createNodeishMemoryFs();
398
- await fs.mkdir("/user/project", { recursive: true });
399
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({
478
+ await fs.mkdir("/user/project.inlang", { recursive: true });
479
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({
400
480
  sourceLanguageTag: "en",
401
481
  languageTags: ["en"],
402
482
  modules: ["plugin.js", "lintRule.js"],
@@ -407,7 +487,7 @@ describe("functionality", () => {
407
487
  };
408
488
  };
409
489
  const project = await loadProject({
410
- settingsFilePath: "/user/project/project.inlang.json",
490
+ projectPath: "/user/project.inlang",
411
491
  nodeishFs: fs,
412
492
  _import,
413
493
  });
@@ -418,10 +498,10 @@ describe("functionality", () => {
418
498
  describe("errors", () => {
419
499
  it("should return the errors", async () => {
420
500
  const fs = await createNodeishMemoryFs();
421
- await fs.mkdir("/user/project", { recursive: true });
422
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
501
+ await fs.mkdir("/user/project.inlang", { recursive: true });
502
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
423
503
  const project = await loadProject({
424
- settingsFilePath: "/user/project/project.inlang.json",
504
+ projectPath: "/user/project.inlang",
425
505
  nodeishFs: fs,
426
506
  _import,
427
507
  });
@@ -433,10 +513,10 @@ describe("functionality", () => {
433
513
  describe("customApi", () => {
434
514
  it("should return the app specific api", async () => {
435
515
  const fs = await createNodeishMemoryFs();
436
- await fs.mkdir("/user/project", { recursive: true });
437
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
516
+ await fs.mkdir("/user/project.inlang", { recursive: true });
517
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
438
518
  const project = await loadProject({
439
- settingsFilePath: "/user/project/project.inlang.json",
519
+ projectPath: "/user/project.inlang",
440
520
  nodeishFs: fs,
441
521
  _import,
442
522
  });
@@ -448,10 +528,10 @@ describe("functionality", () => {
448
528
  describe("messages", () => {
449
529
  it("should return the messages", async () => {
450
530
  const fs = await createNodeishMemoryFs();
451
- await fs.mkdir("/user/project", { recursive: true });
452
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
531
+ await fs.mkdir("/user/project.inlang", { recursive: true });
532
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
453
533
  const project = await loadProject({
454
- settingsFilePath: "/user/project/project.inlang.json",
534
+ projectPath: "/user/project.inlang",
455
535
  nodeishFs: fs,
456
536
  _import,
457
537
  });
@@ -469,8 +549,8 @@ describe("functionality", () => {
469
549
  pathPattern: "./resources/{languageTag}.json",
470
550
  },
471
551
  };
472
- await fs.mkdir("/user/project", { recursive: true });
473
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
552
+ await fs.mkdir("/user/project.inlang", { recursive: true });
553
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
474
554
  await fs.mkdir("./resources");
475
555
  const mockSaveFn = vi.fn();
476
556
  const _mockPlugin = {
@@ -486,7 +566,7 @@ describe("functionality", () => {
486
566
  };
487
567
  };
488
568
  const project = await loadProject({
489
- settingsFilePath: "/user/project/project.inlang.json",
569
+ projectPath: "/user/project.inlang",
490
570
  nodeishFs: fs,
491
571
  _import,
492
572
  });
@@ -631,7 +711,8 @@ describe("functionality", () => {
631
711
  pathPattern: "./resources/{languageTag}.json",
632
712
  },
633
713
  };
634
- await fs.writeFile("./project.inlang.json", JSON.stringify(settings));
714
+ await fs.mkdir("./project.inlang", { recursive: true });
715
+ await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings));
635
716
  const mockSaveFn = vi.fn();
636
717
  const _mockPlugin = {
637
718
  id: "plugin.placeholder.name",
@@ -650,7 +731,7 @@ describe("functionality", () => {
650
731
  };
651
732
  };
652
733
  const project = await loadProject({
653
- settingsFilePath: "/project.inlang.json",
734
+ projectPath: "/project.inlang",
654
735
  nodeishFs: fs,
655
736
  _import,
656
737
  });
@@ -666,7 +747,7 @@ describe("functionality", () => {
666
747
  await fs.mkdir("/user/project", { recursive: true });
667
748
  await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
668
749
  const project = await loadProject({
669
- settingsFilePath: "/user/project/project.inlang.json",
750
+ projectPath: "/user/project/project.inlang.json",
670
751
  nodeishFs: fs,
671
752
  _import,
672
753
  });
@@ -686,10 +767,10 @@ describe("functionality", () => {
686
767
  modules: ["lintRule.js"],
687
768
  };
688
769
  const fs = createNodeishMemoryFs();
689
- await fs.mkdir("/user/project", { recursive: true });
690
- await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings));
770
+ await fs.mkdir("/user/project.inlang", { recursive: true });
771
+ await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings));
691
772
  const project = await loadProject({
692
- settingsFilePath: "/user/project/project.inlang.json",
773
+ projectPath: "/user/project.inlang",
693
774
  nodeishFs: fs,
694
775
  _import: async () => ({
695
776
  default: mockMessageLintRule,
@@ -743,10 +824,11 @@ describe("functionality", () => {
743
824
  filePath: "./messages.json",
744
825
  },
745
826
  };
746
- await fs.writeFile("./project.inlang.json", JSON.stringify(settings));
827
+ await fs.mkdir("./project.inlang", { recursive: true });
828
+ await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings));
747
829
  // establish watcher
748
830
  const project = await loadProject({
749
- settingsFilePath: normalizePath("/project.inlang.json"),
831
+ projectPath: normalizePath("/project.inlang"),
750
832
  nodeishFs: fs,
751
833
  _import: async () => ({
752
834
  default: mockMessageFormatPlugin,
@@ -0,0 +1,10 @@
1
+ import type { NodeishFilesystem } from "@lix-js/fs";
2
+ /**
3
+ * Migrates to the new project directory structure
4
+ * https://github.com/inlang/monorepo/issues/1678
5
+ */
6
+ export declare const maybeMigrateToDirectory: (args: {
7
+ nodeishFs: NodeishFilesystem;
8
+ projectPath: string;
9
+ }) => Promise<void>;
10
+ //# sourceMappingURL=migrateToDirectory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateToDirectory.d.ts","sourceRoot":"","sources":["../../src/migrations/migrateToDirectory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,SAAgB;IACnD,SAAS,EAAE,iBAAiB,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;CACnB,kBA0BA,CAAA"}