@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.
- package/dist/adapter/solidAdapter.test.js +16 -15
- package/dist/createNodeishFsWithAbsolutePaths.d.ts +2 -2
- package/dist/createNodeishFsWithAbsolutePaths.d.ts.map +1 -1
- package/dist/createNodeishFsWithAbsolutePaths.js +4 -4
- package/dist/createNodeishFsWithAbsolutePaths.test.js +4 -4
- package/dist/createNodeishFsWithWatcher.d.ts +1 -1
- package/dist/createNodeishFsWithWatcher.d.ts.map +1 -1
- package/dist/createNodeishFsWithWatcher.js +6 -4
- package/dist/isAbsolutePath.test.js +1 -1
- package/dist/loadProject.d.ts +4 -4
- package/dist/loadProject.d.ts.map +1 -1
- package/dist/loadProject.js +23 -17
- package/dist/loadProject.test.js +108 -75
- package/dist/migrations/migrateToDirectory.d.ts +10 -0
- package/dist/migrations/migrateToDirectory.d.ts.map +1 -0
- package/dist/migrations/migrateToDirectory.js +46 -0
- package/dist/migrations/migrateToDirectory.test.d.ts +2 -0
- package/dist/migrations/migrateToDirectory.test.d.ts.map +1 -0
- package/dist/migrations/migrateToDirectory.test.js +48 -0
- package/dist/resolve-modules/validateModuleSettings.test.js +1 -1
- package/package.json +56 -56
- package/src/adapter/solidAdapter.test.ts +16 -15
- package/src/createNodeishFsWithAbsolutePaths.test.ts +4 -4
- package/src/createNodeishFsWithAbsolutePaths.ts +5 -5
- package/src/createNodeishFsWithWatcher.ts +6 -4
- package/src/isAbsolutePath.test.ts +1 -1
- package/src/loadProject.test.ts +116 -75
- package/src/loadProject.ts +36 -22
- package/src/migrations/migrateToDirectory.test.ts +54 -0
- package/src/migrations/migrateToDirectory.ts +59 -0
- package/src/resolve-modules/validateModuleSettings.test.ts +1 -1
package/src/loadProject.test.ts
CHANGED
|
@@ -105,13 +105,52 @@ const _import: ImportFunction = async (name) =>
|
|
|
105
105
|
|
|
106
106
|
// ------------------------------------------------------------------------------------------------
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Dear Developers,
|
|
110
|
+
*
|
|
111
|
+
* Inlang projects (folders) are not like .vscode, .git, or .github folders. Treat em
|
|
112
|
+
* like files: they can be renamed and moved around.
|
|
113
|
+
*/
|
|
114
|
+
it("should throw if a project (path) does not have a name", async () => {
|
|
115
|
+
const fs = createNodeishMemoryFs()
|
|
116
|
+
const project = await tryCatch(() =>
|
|
117
|
+
loadProject({
|
|
118
|
+
projectPath: "/source-code/.inlang",
|
|
119
|
+
nodeishFs: fs,
|
|
120
|
+
_import,
|
|
121
|
+
})
|
|
122
|
+
)
|
|
123
|
+
expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it("should throw if a project path does not end with .inlang", async () => {
|
|
127
|
+
const fs = createNodeishMemoryFs()
|
|
128
|
+
|
|
129
|
+
const invalidPaths = [
|
|
130
|
+
"/source-code/frontend.inlang/settings",
|
|
131
|
+
"/source-code/frontend.inlang/settings.json",
|
|
132
|
+
"/source-code/frontend.inlang.md",
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
for (const invalidPath of invalidPaths) {
|
|
136
|
+
const project = await tryCatch(() =>
|
|
137
|
+
loadProject({
|
|
138
|
+
projectPath: invalidPath,
|
|
139
|
+
nodeishFs: fs,
|
|
140
|
+
_import,
|
|
141
|
+
})
|
|
142
|
+
)
|
|
143
|
+
expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument)
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
|
|
108
147
|
describe("initialization", () => {
|
|
109
|
-
it("should throw if
|
|
148
|
+
it("should throw if projectPath is not an absolute path", async () => {
|
|
110
149
|
const fs = createNodeishMemoryFs()
|
|
111
150
|
|
|
112
151
|
const result = await tryCatch(() =>
|
|
113
152
|
loadProject({
|
|
114
|
-
|
|
153
|
+
projectPath: "relative/path",
|
|
115
154
|
nodeishFs: fs,
|
|
116
155
|
_import,
|
|
117
156
|
})
|
|
@@ -122,12 +161,12 @@ describe("initialization", () => {
|
|
|
122
161
|
|
|
123
162
|
it("should resolve from a windows path", async () => {
|
|
124
163
|
const fs = createNodeishMemoryFs()
|
|
125
|
-
fs.mkdir("C:\\Users\\user\\project", { recursive: true })
|
|
126
|
-
fs.writeFile("C:\\Users\\user\\project
|
|
164
|
+
fs.mkdir("C:\\Users\\user\\project.inlang", { recursive: true })
|
|
165
|
+
fs.writeFile("C:\\Users\\user\\project.inlang\\settings.json", JSON.stringify(settings))
|
|
127
166
|
|
|
128
167
|
const result = await tryCatch(() =>
|
|
129
168
|
loadProject({
|
|
130
|
-
|
|
169
|
+
projectPath: "C:\\Users\\user\\project.inlang",
|
|
131
170
|
nodeishFs: fs,
|
|
132
171
|
_import,
|
|
133
172
|
})
|
|
@@ -143,7 +182,7 @@ describe("initialization", () => {
|
|
|
143
182
|
fs.mkdir("/user/project", { recursive: true })
|
|
144
183
|
|
|
145
184
|
const project = await loadProject({
|
|
146
|
-
|
|
185
|
+
projectPath: "/user/non-existend-project.inlang",
|
|
147
186
|
nodeishFs: fs,
|
|
148
187
|
_import,
|
|
149
188
|
})
|
|
@@ -153,11 +192,11 @@ describe("initialization", () => {
|
|
|
153
192
|
|
|
154
193
|
it("should return an error if settings file is not a valid JSON", async () => {
|
|
155
194
|
const fs = await createNodeishMemoryFs()
|
|
156
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
157
|
-
await fs.writeFile("/user/project
|
|
195
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
196
|
+
await fs.writeFile("/user/project.inlang/settings.json", "invalid json")
|
|
158
197
|
|
|
159
198
|
const project = await loadProject({
|
|
160
|
-
|
|
199
|
+
projectPath: "/user/project.inlang",
|
|
161
200
|
nodeishFs: fs,
|
|
162
201
|
_import,
|
|
163
202
|
})
|
|
@@ -167,11 +206,11 @@ describe("initialization", () => {
|
|
|
167
206
|
|
|
168
207
|
it("should return an error if settings file is does not match schema", async () => {
|
|
169
208
|
const fs = await createNodeishMemoryFs()
|
|
170
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
171
|
-
await fs.writeFile("/user/project
|
|
209
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
210
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({}))
|
|
172
211
|
|
|
173
212
|
const project = await loadProject({
|
|
174
|
-
|
|
213
|
+
projectPath: "/user/project.inlang",
|
|
175
214
|
nodeishFs: fs,
|
|
176
215
|
_import,
|
|
177
216
|
})
|
|
@@ -181,10 +220,10 @@ describe("initialization", () => {
|
|
|
181
220
|
|
|
182
221
|
it("should return the parsed settings", async () => {
|
|
183
222
|
const fs = await createNodeishMemoryFs()
|
|
184
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
185
|
-
await fs.writeFile("/user/project
|
|
223
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
224
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
186
225
|
const project = await loadProject({
|
|
187
|
-
|
|
226
|
+
projectPath: "/user/project.inlang",
|
|
188
227
|
nodeishFs: fs,
|
|
189
228
|
_import,
|
|
190
229
|
})
|
|
@@ -195,16 +234,16 @@ describe("initialization", () => {
|
|
|
195
234
|
it("should not re-write the settings to disk when initializing", async () => {
|
|
196
235
|
const fs = await createNodeishMemoryFs()
|
|
197
236
|
const settingsWithDeifferentFormatting = JSON.stringify(settings, undefined, 4)
|
|
198
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
199
|
-
await fs.writeFile("/user/project
|
|
237
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
238
|
+
await fs.writeFile("/user/project.inlang/settings.json", settingsWithDeifferentFormatting)
|
|
200
239
|
|
|
201
240
|
const project = await loadProject({
|
|
202
|
-
|
|
241
|
+
projectPath: "/user/project.inlang",
|
|
203
242
|
nodeishFs: fs,
|
|
204
243
|
_import,
|
|
205
244
|
})
|
|
206
245
|
|
|
207
|
-
const settingsOnDisk = await fs.readFile("/user/project
|
|
246
|
+
const settingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", {
|
|
208
247
|
encoding: "utf-8",
|
|
209
248
|
})
|
|
210
249
|
expect(settingsOnDisk).toBe(settingsWithDeifferentFormatting)
|
|
@@ -213,7 +252,7 @@ describe("initialization", () => {
|
|
|
213
252
|
// TODO: how can we await `setsettings` correctly
|
|
214
253
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
215
254
|
|
|
216
|
-
const newsettingsOnDisk = await fs.readFile("/user/project
|
|
255
|
+
const newsettingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", {
|
|
217
256
|
encoding: "utf-8",
|
|
218
257
|
})
|
|
219
258
|
expect(newsettingsOnDisk).not.toBe(settingsWithDeifferentFormatting)
|
|
@@ -228,11 +267,11 @@ describe("initialization", () => {
|
|
|
228
267
|
} satisfies InlangModule)
|
|
229
268
|
|
|
230
269
|
const fs = createNodeishMemoryFs()
|
|
231
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
232
|
-
await fs.writeFile("/user/project
|
|
270
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
271
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
233
272
|
|
|
234
273
|
const project = await loadProject({
|
|
235
|
-
|
|
274
|
+
projectPath: "/user/project.inlang",
|
|
236
275
|
nodeishFs: fs,
|
|
237
276
|
_import: $badImport,
|
|
238
277
|
})
|
|
@@ -261,10 +300,10 @@ describe("functionality", () => {
|
|
|
261
300
|
describe("settings", () => {
|
|
262
301
|
it("should return the settings", async () => {
|
|
263
302
|
const fs = await createNodeishMemoryFs()
|
|
264
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
265
|
-
await fs.writeFile("/user/project
|
|
303
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
304
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
266
305
|
const project = await loadProject({
|
|
267
|
-
|
|
306
|
+
projectPath: "/user/project.inlang",
|
|
268
307
|
nodeishFs: fs,
|
|
269
308
|
_import,
|
|
270
309
|
})
|
|
@@ -274,10 +313,10 @@ describe("functionality", () => {
|
|
|
274
313
|
|
|
275
314
|
it("should set a new settings", async () => {
|
|
276
315
|
const fs = await createNodeishMemoryFs()
|
|
277
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
278
|
-
await fs.writeFile("/user/project
|
|
316
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
317
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
279
318
|
const project = await loadProject({
|
|
280
|
-
|
|
319
|
+
projectPath: "/user/project.inlang",
|
|
281
320
|
nodeishFs: fs,
|
|
282
321
|
_import,
|
|
283
322
|
})
|
|
@@ -298,12 +337,12 @@ describe("functionality", () => {
|
|
|
298
337
|
})
|
|
299
338
|
|
|
300
339
|
describe("setSettings", () => {
|
|
301
|
-
it("should fail if settings
|
|
340
|
+
it("should fail if settings are not valid", async () => {
|
|
302
341
|
const fs = await createNodeishMemoryFs()
|
|
303
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
304
|
-
await fs.writeFile("/user/project
|
|
342
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
343
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
305
344
|
const project = await loadProject({
|
|
306
|
-
|
|
345
|
+
projectPath: "/user/project.inlang",
|
|
307
346
|
nodeishFs: fs,
|
|
308
347
|
_import,
|
|
309
348
|
})
|
|
@@ -315,7 +354,7 @@ describe("functionality", () => {
|
|
|
315
354
|
|
|
316
355
|
it("should throw an error if sourceLanguageTag is not in languageTags", async () => {
|
|
317
356
|
const fs = await createNodeishMemoryFs()
|
|
318
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
357
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
319
358
|
|
|
320
359
|
const settings: ProjectSettings = {
|
|
321
360
|
sourceLanguageTag: "en",
|
|
@@ -323,10 +362,10 @@ describe("functionality", () => {
|
|
|
323
362
|
modules: [],
|
|
324
363
|
}
|
|
325
364
|
|
|
326
|
-
await fs.writeFile("/user/project
|
|
365
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
327
366
|
|
|
328
367
|
const project = await loadProject({
|
|
329
|
-
|
|
368
|
+
projectPath: "/user/project.inlang",
|
|
330
369
|
nodeishFs: fs,
|
|
331
370
|
_import,
|
|
332
371
|
})
|
|
@@ -337,25 +376,25 @@ describe("functionality", () => {
|
|
|
337
376
|
|
|
338
377
|
it("should write settings to disk", async () => {
|
|
339
378
|
const fs = await createNodeishMemoryFs()
|
|
340
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
341
|
-
await fs.writeFile("/user/project
|
|
379
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
380
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
342
381
|
const project = await loadProject({
|
|
343
|
-
|
|
382
|
+
projectPath: "/user/project.inlang",
|
|
344
383
|
nodeishFs: fs,
|
|
345
384
|
_import,
|
|
346
385
|
})
|
|
347
386
|
|
|
348
|
-
const before = await fs.readFile("/user/project
|
|
387
|
+
const before = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" })
|
|
349
388
|
expect(before).toBeDefined()
|
|
350
389
|
|
|
351
|
-
const result = project.setSettings({ ...settings, languageTags: ["en"] })
|
|
390
|
+
const result = project.setSettings({ ...settings, languageTags: ["en", "nl", "de"] })
|
|
352
391
|
expect(result.data).toBeUndefined()
|
|
353
392
|
expect(result.error).toBeUndefined()
|
|
354
393
|
|
|
355
394
|
// TODO: how to wait for fs.writeFile to finish?
|
|
356
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
395
|
+
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
357
396
|
|
|
358
|
-
const after = await fs.readFile("/user/project
|
|
397
|
+
const after = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" })
|
|
359
398
|
expect(after).toBeDefined()
|
|
360
399
|
expect(after).not.toBe(before)
|
|
361
400
|
})
|
|
@@ -369,10 +408,10 @@ describe("functionality", () => {
|
|
|
369
408
|
languageTags: ["en"],
|
|
370
409
|
modules: ["plugin.js", "lintRule.js"],
|
|
371
410
|
}
|
|
372
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
373
|
-
await fs.writeFile("/user/project
|
|
411
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
412
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
374
413
|
const project = await loadProject({
|
|
375
|
-
|
|
414
|
+
projectPath: "/user/project.inlang",
|
|
376
415
|
nodeishFs: fs,
|
|
377
416
|
_import,
|
|
378
417
|
})
|
|
@@ -402,11 +441,11 @@ describe("functionality", () => {
|
|
|
402
441
|
modules: ["plugin.js", "lintRule.js"],
|
|
403
442
|
}
|
|
404
443
|
|
|
405
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
406
|
-
await fs.writeFile("/user/project
|
|
444
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
445
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
407
446
|
|
|
408
447
|
const project = await loadProject({
|
|
409
|
-
|
|
448
|
+
projectPath: "/user/project.inlang",
|
|
410
449
|
nodeishFs: fs,
|
|
411
450
|
_import,
|
|
412
451
|
})
|
|
@@ -437,9 +476,9 @@ describe("functionality", () => {
|
|
|
437
476
|
saveMessages: () => undefined,
|
|
438
477
|
}
|
|
439
478
|
const fs = await createNodeishMemoryFs()
|
|
440
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
479
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
441
480
|
await fs.writeFile(
|
|
442
|
-
"/user/project
|
|
481
|
+
"/user/project.inlang/settings.json",
|
|
443
482
|
JSON.stringify({
|
|
444
483
|
sourceLanguageTag: "en",
|
|
445
484
|
languageTags: ["en"],
|
|
@@ -453,7 +492,7 @@ describe("functionality", () => {
|
|
|
453
492
|
} satisfies InlangModule
|
|
454
493
|
}
|
|
455
494
|
const project = await loadProject({
|
|
456
|
-
|
|
495
|
+
projectPath: "/user/project.inlang",
|
|
457
496
|
nodeishFs: fs,
|
|
458
497
|
_import,
|
|
459
498
|
})
|
|
@@ -488,9 +527,9 @@ describe("functionality", () => {
|
|
|
488
527
|
saveMessages: () => undefined,
|
|
489
528
|
}
|
|
490
529
|
const fs = await createNodeishMemoryFs()
|
|
491
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
530
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
492
531
|
await fs.writeFile(
|
|
493
|
-
"/user/project
|
|
532
|
+
"/user/project.inlang/settings.json",
|
|
494
533
|
JSON.stringify({
|
|
495
534
|
sourceLanguageTag: "en",
|
|
496
535
|
languageTags: ["en"],
|
|
@@ -504,7 +543,7 @@ describe("functionality", () => {
|
|
|
504
543
|
}
|
|
505
544
|
|
|
506
545
|
const project = await loadProject({
|
|
507
|
-
|
|
546
|
+
projectPath: "/user/project.inlang",
|
|
508
547
|
nodeishFs: fs,
|
|
509
548
|
_import,
|
|
510
549
|
})
|
|
@@ -520,10 +559,10 @@ describe("functionality", () => {
|
|
|
520
559
|
describe("errors", () => {
|
|
521
560
|
it("should return the errors", async () => {
|
|
522
561
|
const fs = await createNodeishMemoryFs()
|
|
523
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
524
|
-
await fs.writeFile("/user/project
|
|
562
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
563
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
525
564
|
const project = await loadProject({
|
|
526
|
-
|
|
565
|
+
projectPath: "/user/project.inlang",
|
|
527
566
|
nodeishFs: fs,
|
|
528
567
|
_import,
|
|
529
568
|
})
|
|
@@ -536,10 +575,10 @@ describe("functionality", () => {
|
|
|
536
575
|
describe("customApi", () => {
|
|
537
576
|
it("should return the app specific api", async () => {
|
|
538
577
|
const fs = await createNodeishMemoryFs()
|
|
539
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
540
|
-
await fs.writeFile("/user/project
|
|
578
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
579
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
541
580
|
const project = await loadProject({
|
|
542
|
-
|
|
581
|
+
projectPath: "/user/project.inlang",
|
|
543
582
|
nodeishFs: fs,
|
|
544
583
|
_import,
|
|
545
584
|
})
|
|
@@ -553,10 +592,10 @@ describe("functionality", () => {
|
|
|
553
592
|
describe("messages", () => {
|
|
554
593
|
it("should return the messages", async () => {
|
|
555
594
|
const fs = await createNodeishMemoryFs()
|
|
556
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
557
|
-
await fs.writeFile("/user/project
|
|
595
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
596
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
558
597
|
const project = await loadProject({
|
|
559
|
-
|
|
598
|
+
projectPath: "/user/project.inlang",
|
|
560
599
|
nodeishFs: fs,
|
|
561
600
|
_import,
|
|
562
601
|
})
|
|
@@ -578,8 +617,8 @@ describe("functionality", () => {
|
|
|
578
617
|
},
|
|
579
618
|
}
|
|
580
619
|
|
|
581
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
582
|
-
await fs.writeFile("/user/project
|
|
620
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
621
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
583
622
|
|
|
584
623
|
await fs.mkdir("./resources")
|
|
585
624
|
|
|
@@ -601,7 +640,7 @@ describe("functionality", () => {
|
|
|
601
640
|
}
|
|
602
641
|
|
|
603
642
|
const project = await loadProject({
|
|
604
|
-
|
|
643
|
+
projectPath: "/user/project.inlang",
|
|
605
644
|
nodeishFs: fs,
|
|
606
645
|
_import,
|
|
607
646
|
})
|
|
@@ -756,7 +795,8 @@ describe("functionality", () => {
|
|
|
756
795
|
},
|
|
757
796
|
}
|
|
758
797
|
|
|
759
|
-
await fs.
|
|
798
|
+
await fs.mkdir("./project.inlang", { recursive: true })
|
|
799
|
+
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings))
|
|
760
800
|
|
|
761
801
|
const mockSaveFn = vi.fn()
|
|
762
802
|
|
|
@@ -780,7 +820,7 @@ describe("functionality", () => {
|
|
|
780
820
|
}
|
|
781
821
|
|
|
782
822
|
const project = await loadProject({
|
|
783
|
-
|
|
823
|
+
projectPath: "/project.inlang",
|
|
784
824
|
nodeishFs: fs,
|
|
785
825
|
_import,
|
|
786
826
|
})
|
|
@@ -800,7 +840,7 @@ describe("functionality", () => {
|
|
|
800
840
|
await fs.mkdir("/user/project", { recursive: true })
|
|
801
841
|
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings))
|
|
802
842
|
const project = await loadProject({
|
|
803
|
-
|
|
843
|
+
projectPath: "/user/project/project.inlang.json",
|
|
804
844
|
nodeishFs: fs,
|
|
805
845
|
_import,
|
|
806
846
|
})
|
|
@@ -819,10 +859,10 @@ describe("functionality", () => {
|
|
|
819
859
|
modules: ["lintRule.js"],
|
|
820
860
|
}
|
|
821
861
|
const fs = createNodeishMemoryFs()
|
|
822
|
-
await fs.mkdir("/user/project", { recursive: true })
|
|
823
|
-
await fs.writeFile("/user/project
|
|
862
|
+
await fs.mkdir("/user/project.inlang", { recursive: true })
|
|
863
|
+
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings))
|
|
824
864
|
const project = await loadProject({
|
|
825
|
-
|
|
865
|
+
projectPath: "/user/project.inlang",
|
|
826
866
|
nodeishFs: fs,
|
|
827
867
|
_import: async () => ({
|
|
828
868
|
default: mockMessageLintRule,
|
|
@@ -884,11 +924,12 @@ describe("functionality", () => {
|
|
|
884
924
|
},
|
|
885
925
|
}
|
|
886
926
|
|
|
887
|
-
await fs.
|
|
927
|
+
await fs.mkdir("./project.inlang", { recursive: true })
|
|
928
|
+
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings))
|
|
888
929
|
|
|
889
930
|
// establish watcher
|
|
890
931
|
const project = await loadProject({
|
|
891
|
-
|
|
932
|
+
projectPath: normalizePath("/project.inlang"),
|
|
892
933
|
nodeishFs: fs,
|
|
893
934
|
_import: async () => ({
|
|
894
935
|
default: mockMessageFormatPlugin,
|
package/src/loadProject.ts
CHANGED
|
@@ -23,16 +23,17 @@ import { ProjectSettings, Message, type NodeishFilesystemSubset } from "./versio
|
|
|
23
23
|
import { tryCatch, type Result } from "@inlang/result"
|
|
24
24
|
import { migrateIfOutdated } from "@inlang/project-settings/migration"
|
|
25
25
|
import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js"
|
|
26
|
-
import { normalizePath } from "@lix-js/fs"
|
|
26
|
+
import { normalizePath, type NodeishFilesystem } from "@lix-js/fs"
|
|
27
27
|
import { isAbsolutePath } from "./isAbsolutePath.js"
|
|
28
28
|
import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js"
|
|
29
|
+
import { maybeMigrateToDirectory } from "./migrations/migrateToDirectory.js"
|
|
29
30
|
|
|
30
31
|
const settingsCompiler = TypeCompiler.Compile(ProjectSettings)
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Creates an inlang instance.
|
|
34
35
|
*
|
|
35
|
-
* @param
|
|
36
|
+
* @param projectPath - Absolute path to the inlang settings file.
|
|
36
37
|
* @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface.
|
|
37
38
|
* @param _import - Use `_import` to pass a custom import function for testing,
|
|
38
39
|
* and supporting legacy resolvedModules such as CJS.
|
|
@@ -40,29 +41,39 @@ const settingsCompiler = TypeCompiler.Compile(ProjectSettings)
|
|
|
40
41
|
*
|
|
41
42
|
*/
|
|
42
43
|
export const loadProject = async (args: {
|
|
43
|
-
|
|
44
|
-
nodeishFs:
|
|
44
|
+
projectPath: string
|
|
45
|
+
nodeishFs: NodeishFilesystem
|
|
45
46
|
_import?: ImportFunction
|
|
46
47
|
_capture?: (id: string, props: Record<string, unknown>) => void
|
|
47
48
|
}): Promise<InlangProject> => {
|
|
49
|
+
const projectPath = normalizePath(args.projectPath)
|
|
50
|
+
|
|
51
|
+
// -- migrate if outdated ------------------------------------------------
|
|
52
|
+
|
|
53
|
+
await maybeMigrateToDirectory({ nodeishFs: args.nodeishFs, projectPath })
|
|
54
|
+
|
|
48
55
|
// -- validation --------------------------------------------------------
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
// the only place where throwing is acceptable because the project
|
|
57
|
+
// won't even be loaded. do not throw anywhere else. otherwise, apps
|
|
58
|
+
// can't handle errors gracefully.
|
|
59
|
+
|
|
60
|
+
if (!isAbsolutePath(args.projectPath)) {
|
|
61
|
+
throw new LoadProjectInvalidArgument(
|
|
62
|
+
`Expected an absolute path but received "${args.projectPath}".`,
|
|
63
|
+
{ argument: "projectPath" }
|
|
64
|
+
)
|
|
65
|
+
} else if (/[^\\/]+\.inlang$/.test(projectPath) === false) {
|
|
53
66
|
throw new LoadProjectInvalidArgument(
|
|
54
|
-
`Expected
|
|
55
|
-
{ argument: "
|
|
67
|
+
`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`,
|
|
68
|
+
{ argument: "projectPath" }
|
|
56
69
|
)
|
|
57
70
|
}
|
|
58
71
|
|
|
59
|
-
const settingsFilePath = normalizePath(args.settingsFilePath)
|
|
60
|
-
|
|
61
72
|
// -- load project ------------------------------------------------------
|
|
62
73
|
return await createRoot(async () => {
|
|
63
74
|
const [initialized, markInitAsComplete, markInitAsFailed] = createAwaitable()
|
|
64
75
|
const nodeishFs = createNodeishFsWithAbsolutePaths({
|
|
65
|
-
|
|
76
|
+
projectPath,
|
|
66
77
|
nodeishFs: args.nodeishFs,
|
|
67
78
|
})
|
|
68
79
|
|
|
@@ -70,7 +81,7 @@ export const loadProject = async (args: {
|
|
|
70
81
|
|
|
71
82
|
const [settings, _setSettings] = createSignal<ProjectSettings>()
|
|
72
83
|
createEffect(() => {
|
|
73
|
-
loadSettings({ settingsFilePath, nodeishFs })
|
|
84
|
+
loadSettings({ settingsFilePath: projectPath + "/settings.json", nodeishFs })
|
|
74
85
|
.then((settings) => {
|
|
75
86
|
setSettings(settings)
|
|
76
87
|
// rename settings to get a convenient access to the data in Posthog
|
|
@@ -84,7 +95,7 @@ export const loadProject = async (args: {
|
|
|
84
95
|
// TODO: create FS watcher and update settings on change
|
|
85
96
|
|
|
86
97
|
const writeSettingsToDisk = skipFirst((settings: ProjectSettings) =>
|
|
87
|
-
_writeSettingsToDisk({ nodeishFs, settings })
|
|
98
|
+
_writeSettingsToDisk({ nodeishFs, settings, projectPath })
|
|
88
99
|
)
|
|
89
100
|
|
|
90
101
|
const setSettings = (settings: ProjectSettings): Result<void, ProjectSettingsInvalidError> => {
|
|
@@ -223,12 +234,14 @@ export const loadProject = async (args: {
|
|
|
223
234
|
cause: err,
|
|
224
235
|
})
|
|
225
236
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
const abortController = new AbortController()
|
|
238
|
+
if (
|
|
239
|
+
newMessages.length !== 0 &&
|
|
240
|
+
JSON.stringify(newMessages) !== JSON.stringify(messages()) &&
|
|
241
|
+
nodeishFs.watch("/", { signal: abortController.signal }) === undefined
|
|
242
|
+
) {
|
|
243
|
+
setMessages(newMessages)
|
|
244
|
+
}
|
|
232
245
|
},
|
|
233
246
|
{ atBegin: false }
|
|
234
247
|
)
|
|
@@ -320,6 +333,7 @@ const parseSettings = (settings: unknown) => {
|
|
|
320
333
|
}
|
|
321
334
|
|
|
322
335
|
const _writeSettingsToDisk = async (args: {
|
|
336
|
+
projectPath: string
|
|
323
337
|
nodeishFs: NodeishFilesystemSubset
|
|
324
338
|
settings: ProjectSettings
|
|
325
339
|
}) => {
|
|
@@ -332,7 +346,7 @@ const _writeSettingsToDisk = async (args: {
|
|
|
332
346
|
}
|
|
333
347
|
|
|
334
348
|
const { error: writeSettingsError } = await tryCatch(async () =>
|
|
335
|
-
args.nodeishFs.writeFile("
|
|
349
|
+
args.nodeishFs.writeFile(args.projectPath + "/settings.json", serializedSettings)
|
|
336
350
|
)
|
|
337
351
|
|
|
338
352
|
if (writeSettingsError) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { test, expect, vi } from "vitest"
|
|
2
|
+
import { maybeMigrateToDirectory } from "./migrateToDirectory.js"
|
|
3
|
+
import { createNodeishMemoryFs } from "@lix-js/fs"
|
|
4
|
+
import type { ProjectSettings } from "@inlang/project-settings"
|
|
5
|
+
|
|
6
|
+
test("it should return if the settings file has an error (let loadProject handle it)", async () => {
|
|
7
|
+
const projectPath = "./project.inlang"
|
|
8
|
+
const mockFs = {
|
|
9
|
+
stat: vi.fn(() => {}),
|
|
10
|
+
readFile: vi.fn(() => {
|
|
11
|
+
throw Error()
|
|
12
|
+
}),
|
|
13
|
+
}
|
|
14
|
+
await maybeMigrateToDirectory({ nodeishFs: mockFs as any, projectPath })
|
|
15
|
+
// something goes wrong in readFile
|
|
16
|
+
expect(mockFs.readFile).toHaveBeenCalled()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("it should create the project directory if it does not exist and a project settings file exists", async () => {
|
|
20
|
+
const projectPath = "./project.inlang"
|
|
21
|
+
const mockFs = {
|
|
22
|
+
readFile: vi.fn(
|
|
23
|
+
() => `{
|
|
24
|
+
"sourceLanguageTag": "en",
|
|
25
|
+
"languageTags": ["en", "de"],
|
|
26
|
+
"modules": []
|
|
27
|
+
}`
|
|
28
|
+
),
|
|
29
|
+
stat: vi.fn(() => {
|
|
30
|
+
throw Error()
|
|
31
|
+
}),
|
|
32
|
+
mkdir: vi.fn(),
|
|
33
|
+
writeFile: vi.fn(),
|
|
34
|
+
}
|
|
35
|
+
await maybeMigrateToDirectory({ nodeishFs: mockFs as any, projectPath })
|
|
36
|
+
expect(mockFs.mkdir).toHaveBeenCalled()
|
|
37
|
+
expect(mockFs.writeFile).toHaveBeenCalled()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test("it should write the settings file to the new path", async () => {
|
|
41
|
+
const fs = createNodeishMemoryFs()
|
|
42
|
+
const mockSettings: ProjectSettings = {
|
|
43
|
+
sourceLanguageTag: "en",
|
|
44
|
+
languageTags: ["en", "de"],
|
|
45
|
+
modules: [],
|
|
46
|
+
}
|
|
47
|
+
await fs.writeFile("./project.inlang.json", JSON.stringify(mockSettings))
|
|
48
|
+
await maybeMigrateToDirectory({ nodeishFs: fs, projectPath: "./project.inlang" })
|
|
49
|
+
const migratedSettingsFile = await fs.readFile("./project.inlang/settings.json", {
|
|
50
|
+
encoding: "utf-8",
|
|
51
|
+
})
|
|
52
|
+
expect(migratedSettingsFile).toEqual(JSON.stringify(mockSettings))
|
|
53
|
+
expect(await fs.stat("./project.inlang.README.md")).toBeDefined()
|
|
54
|
+
})
|