@inlang/sdk
Advanced tools
Comparing version 0.18.0 to 0.19.0
@@ -75,6 +75,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
const fs = createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config)); | ||
const project = solidAdapter(await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -100,6 +100,6 @@ _import: $import, | ||
const fs = createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config)); | ||
const project = solidAdapter(await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -154,6 +154,6 @@ _import: $import, | ||
const mockImport = async () => ({ default: mockPlugin }); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(mockConfig)); | ||
await fs.mkdir("/user/project.inlang.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(mockConfig)); | ||
const project = solidAdapter(await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang.inlang", | ||
nodeishFs: fs, | ||
@@ -176,6 +176,6 @@ _import: mockImport, | ||
const fs = createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config)); | ||
await fs.mkdir("/user/project.inlang.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(config)); | ||
const project = solidAdapter(await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang.inlang", | ||
nodeishFs: fs, | ||
@@ -223,5 +223,6 @@ _import: $import, | ||
const fs = createNodeishMemoryFs(); | ||
await fs.writeFile("./project.config.json", JSON.stringify(config)); | ||
await fs.mkdir("./project.inlang", { recursive: true }); | ||
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(config)); | ||
const project = solidAdapter(await loadProject({ | ||
settingsFilePath: "./project.config.json", | ||
projectPath: "./project.inlang", | ||
nodeishFs: fs, | ||
@@ -253,3 +254,3 @@ _import: $import, | ||
const project = solidAdapter(await loadProject({ | ||
settingsFilePath: "./project.config.json", | ||
projectPath: "./project.config.json", | ||
nodeishFs: fs, | ||
@@ -256,0 +257,0 @@ _import: $import, |
@@ -6,8 +6,8 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin"; | ||
* | ||
* The paths are resolved from the `settingsFilePath` argument. | ||
* The paths are resolved from the `projectPath` argument. | ||
*/ | ||
export declare const createNodeishFsWithAbsolutePaths: (args: { | ||
settingsFilePath: string; | ||
projectPath: string; | ||
nodeishFs: NodeishFilesystemSubset; | ||
}) => NodeishFilesystemSubset; | ||
//# sourceMappingURL=createNodeishFsWithAbsolutePaths.d.ts.map |
@@ -7,11 +7,11 @@ import { normalizePath } from "@lix-js/fs"; | ||
* | ||
* The paths are resolved from the `settingsFilePath` argument. | ||
* The paths are resolved from the `projectPath` argument. | ||
*/ | ||
export const createNodeishFsWithAbsolutePaths = (args) => { | ||
if (!isAbsolutePath(args.settingsFilePath)) { | ||
throw new Error(`Expected an absolute path but received "${args.settingsFilePath}".`); | ||
if (!isAbsolutePath(args.projectPath)) { | ||
throw new Error(`Expected an absolute path but received "${args.projectPath}".`); | ||
} | ||
// get the base path of the settings file by | ||
// removing the file name from the path | ||
const basePath = normalizePath(args.settingsFilePath).split("/").slice(0, -1).join("/"); | ||
const basePath = normalizePath(args.projectPath).split("/").slice(0, -1).join("/"); | ||
const makeAbsolute = (path) => { | ||
@@ -18,0 +18,0 @@ if (isAbsolutePath(path)) { |
import { it, expect, vi } from "vitest"; | ||
import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js"; | ||
it("throws an error if settingsFilePath is not an absolute path", () => { | ||
it("throws an error if projectPath is not an absolute path", () => { | ||
const relativePath = "relative/path"; | ||
expect(() => createNodeishFsWithAbsolutePaths({ settingsFilePath: relativePath, nodeishFs: {} })).toThrow(); | ||
expect(() => createNodeishFsWithAbsolutePaths({ projectPath: relativePath, nodeishFs: {} })).toThrow(); | ||
}); | ||
it("intercepts paths correctly for readFile", async () => { | ||
const settingsFilePath = `/Users/samuel/Documents/paraglide/example/project.inlang.json`; | ||
const projectPath = `/Users/samuel/Documents/paraglide/example/project.inlang`; | ||
const filePaths = [ | ||
@@ -26,3 +26,3 @@ ["file.txt", `/Users/samuel/Documents/paraglide/example/file.txt`], | ||
const interceptedFs = createNodeishFsWithAbsolutePaths({ | ||
settingsFilePath, | ||
projectPath, | ||
nodeishFs: mockNodeishFs, | ||
@@ -29,0 +29,0 @@ }); |
@@ -6,3 +6,3 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin"; | ||
* | ||
* The paths are resolved from the `settingsFilePath` argument. | ||
* The paths are resolved from the `projectPath` argument. | ||
*/ | ||
@@ -9,0 +9,0 @@ export declare const createNodeishFsWithWatcher: (args: { |
@@ -5,3 +5,3 @@ /** | ||
* | ||
* The paths are resolved from the `settingsFilePath` argument. | ||
* The paths are resolved from the `projectPath` argument. | ||
*/ | ||
@@ -18,5 +18,7 @@ export const createNodeishFsWithWatcher = (args) => { | ||
}); | ||
//eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for await (const event of watcher) { | ||
args.updateMessages(); | ||
if (watcher) { | ||
//eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for await (const event of watcher) { | ||
args.updateMessages(); | ||
} | ||
} | ||
@@ -23,0 +25,0 @@ } |
@@ -11,3 +11,3 @@ import { assert, describe, it } from "vitest"; | ||
assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt")); | ||
assert.isTrue(isAbsolutePath("C:/Users/user/project/project.inlang.json")); | ||
assert.isTrue(isAbsolutePath("C:/Users/user/project.inlang/settings.json")); | ||
assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt")); | ||
@@ -14,0 +14,0 @@ }); |
import type { InlangProject, Subscribable } from "./api.js"; | ||
import { type ImportFunction } from "./resolve-modules/index.js"; | ||
import { type NodeishFilesystemSubset } from "./versionedInterfaces.js"; | ||
import { type NodeishFilesystem } from "@lix-js/fs"; | ||
/** | ||
* Creates an inlang instance. | ||
* | ||
* @param settingsFilePath - Absolute path to the inlang settings file. | ||
* @param projectPath - Absolute path to the inlang settings file. | ||
* @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface. | ||
@@ -15,4 +15,4 @@ * @param _import - Use `_import` to pass a custom import function for testing, | ||
export declare const loadProject: (args: { | ||
settingsFilePath: string; | ||
nodeishFs: NodeishFilesystemSubset; | ||
projectPath: string; | ||
nodeishFs: NodeishFilesystem; | ||
_import?: ImportFunction | undefined; | ||
@@ -19,0 +19,0 @@ _capture?: ((id: string, props: Record<string, unknown>) => void) | undefined; |
@@ -15,2 +15,3 @@ import { resolveModules } from "./resolve-modules/index.js"; | ||
import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js"; | ||
import { maybeMigrateToDirectory } from "./migrations/migrateToDirectory.js"; | ||
const settingsCompiler = TypeCompiler.Compile(ProjectSettings); | ||
@@ -20,3 +21,3 @@ /** | ||
* | ||
* @param settingsFilePath - Absolute path to the inlang settings file. | ||
* @param projectPath - Absolute path to the inlang settings file. | ||
* @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface. | ||
@@ -29,10 +30,15 @@ * @param _import - Use `_import` to pass a custom import function for testing, | ||
export const loadProject = async (args) => { | ||
const projectPath = normalizePath(args.projectPath); | ||
// -- migrate if outdated ------------------------------------------------ | ||
await maybeMigrateToDirectory({ nodeishFs: args.nodeishFs, projectPath }); | ||
// -- validation -------------------------------------------------------- | ||
//! the only place where throwing is acceptable because the project | ||
//! won't even be loaded. do not throw anywhere else. otherwise, apps | ||
//! can't handle errors gracefully. | ||
if (!isAbsolutePath(args.settingsFilePath)) { | ||
throw new LoadProjectInvalidArgument(`Expected an absolute path but received "${args.settingsFilePath}".`, { argument: "settingsFilePath" }); | ||
// the only place where throwing is acceptable because the project | ||
// won't even be loaded. do not throw anywhere else. otherwise, apps | ||
// can't handle errors gracefully. | ||
if (!isAbsolutePath(args.projectPath)) { | ||
throw new LoadProjectInvalidArgument(`Expected an absolute path but received "${args.projectPath}".`, { argument: "projectPath" }); | ||
} | ||
const settingsFilePath = normalizePath(args.settingsFilePath); | ||
else if (/[^\\/]+\.inlang$/.test(projectPath) === false) { | ||
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" }); | ||
} | ||
// -- load project ------------------------------------------------------ | ||
@@ -42,3 +48,3 @@ return await createRoot(async () => { | ||
const nodeishFs = createNodeishFsWithAbsolutePaths({ | ||
settingsFilePath, | ||
projectPath, | ||
nodeishFs: args.nodeishFs, | ||
@@ -49,3 +55,3 @@ }); | ||
createEffect(() => { | ||
loadSettings({ settingsFilePath, nodeishFs }) | ||
loadSettings({ settingsFilePath: projectPath + "/settings.json", nodeishFs }) | ||
.then((settings) => { | ||
@@ -62,3 +68,3 @@ setSettings(settings); | ||
// TODO: create FS watcher and update settings on change | ||
const writeSettingsToDisk = skipFirst((settings) => _writeSettingsToDisk({ nodeishFs, settings })); | ||
const writeSettingsToDisk = skipFirst((settings) => _writeSettingsToDisk({ nodeishFs, settings, projectPath })); | ||
const setSettings = (settings) => { | ||
@@ -167,8 +173,8 @@ try { | ||
} | ||
// if ( | ||
// newMessages.length !== 0 && | ||
// JSON.stringify(newMessages) !== JSON.stringify(messages()) | ||
// ) { | ||
// setMessages(newMessages) | ||
// } | ||
const abortController = new AbortController(); | ||
if (newMessages.length !== 0 && | ||
JSON.stringify(newMessages) !== JSON.stringify(messages()) && | ||
nodeishFs.watch("/", { signal: abortController.signal }) === undefined) { | ||
setMessages(newMessages); | ||
} | ||
}, { atBegin: false })); | ||
@@ -250,3 +256,3 @@ createEffect(() => { | ||
} | ||
const { error: writeSettingsError } = await tryCatch(async () => args.nodeishFs.writeFile("./project.inlang.json", serializedSettings)); | ||
const { error: writeSettingsError } = await tryCatch(async () => args.nodeishFs.writeFile(args.projectPath + "/settings.json", serializedSettings)); | ||
if (writeSettingsError) { | ||
@@ -253,0 +259,0 @@ throw writeSettingsError; |
@@ -83,7 +83,38 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
// ------------------------------------------------------------------------------------------------ | ||
/** | ||
* Dear Developers, | ||
* | ||
* Inlang projects (folders) are not like .vscode, .git, or .github folders. Treat em | ||
* like files: they can be renamed and moved around. | ||
*/ | ||
it("should throw if a project (path) does not have a name", async () => { | ||
const fs = createNodeishMemoryFs(); | ||
const project = await tryCatch(() => loadProject({ | ||
projectPath: "/source-code/.inlang", | ||
nodeishFs: fs, | ||
_import, | ||
})); | ||
expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument); | ||
}); | ||
it("should throw if a project path does not end with .inlang", async () => { | ||
const fs = createNodeishMemoryFs(); | ||
const invalidPaths = [ | ||
"/source-code/frontend.inlang/settings", | ||
"/source-code/frontend.inlang/settings.json", | ||
"/source-code/frontend.inlang.md", | ||
]; | ||
for (const invalidPath of invalidPaths) { | ||
const project = await tryCatch(() => loadProject({ | ||
projectPath: invalidPath, | ||
nodeishFs: fs, | ||
_import, | ||
})); | ||
expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument); | ||
} | ||
}); | ||
describe("initialization", () => { | ||
it("should throw if settingsFilePath is not an absolute path", async () => { | ||
it("should throw if projectPath is not an absolute path", async () => { | ||
const fs = createNodeishMemoryFs(); | ||
const result = await tryCatch(() => loadProject({ | ||
settingsFilePath: "relative/path", | ||
projectPath: "relative/path", | ||
nodeishFs: fs, | ||
@@ -97,6 +128,6 @@ _import, | ||
const fs = createNodeishMemoryFs(); | ||
fs.mkdir("C:\\Users\\user\\project", { recursive: true }); | ||
fs.writeFile("C:\\Users\\user\\project\\project.inlang.json", JSON.stringify(settings)); | ||
fs.mkdir("C:\\Users\\user\\project.inlang", { recursive: true }); | ||
fs.writeFile("C:\\Users\\user\\project.inlang\\settings.json", JSON.stringify(settings)); | ||
const result = await tryCatch(() => loadProject({ | ||
settingsFilePath: "C:\\Users\\user\\project\\project.inlang.json", | ||
projectPath: "C:\\Users\\user\\project.inlang", | ||
nodeishFs: fs, | ||
@@ -113,3 +144,3 @@ _import, | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/test.json", | ||
projectPath: "/user/non-existend-project.inlang", | ||
nodeishFs: fs, | ||
@@ -122,6 +153,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", "invalid json"); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", "invalid json"); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -134,6 +165,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({})); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({})); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -146,6 +177,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -159,10 +190,10 @@ _import, | ||
const settingsWithDeifferentFormatting = JSON.stringify(settings, undefined, 4); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", settingsWithDeifferentFormatting); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", settingsWithDeifferentFormatting); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
_import, | ||
}); | ||
const settingsOnDisk = await fs.readFile("/user/project/project.inlang.json", { | ||
const settingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", { | ||
encoding: "utf-8", | ||
@@ -174,3 +205,3 @@ }); | ||
await new Promise((resolve) => setTimeout(resolve, 0)); | ||
const newsettingsOnDisk = await fs.readFile("/user/project/project.inlang.json", { | ||
const newsettingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", { | ||
encoding: "utf-8", | ||
@@ -187,6 +218,6 @@ }); | ||
const fs = createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -216,6 +247,6 @@ _import: $badImport, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -228,6 +259,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -249,8 +280,8 @@ _import, | ||
describe("setSettings", () => { | ||
it("should fail if settings is not valid", async () => { | ||
it("should fail if settings are not valid", async () => { | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -265,3 +296,3 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
const settings = { | ||
@@ -272,5 +303,5 @@ sourceLanguageTag: "en", | ||
}; | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -284,17 +315,17 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
_import, | ||
}); | ||
const before = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" }); | ||
const before = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" }); | ||
expect(before).toBeDefined(); | ||
const result = project.setSettings({ ...settings, languageTags: ["en"] }); | ||
const result = project.setSettings({ ...settings, languageTags: ["en", "nl", "de"] }); | ||
expect(result.data).toBeUndefined(); | ||
expect(result.error).toBeUndefined(); | ||
// TODO: how to wait for fs.writeFile to finish? | ||
await new Promise((resolve) => setTimeout(resolve, 0)); | ||
const after = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" }); | ||
await new Promise((resolve) => setTimeout(resolve, 50)); | ||
const after = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" }); | ||
expect(after).toBeDefined(); | ||
@@ -312,6 +343,6 @@ expect(after).not.toBe(before); | ||
}; | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -341,6 +372,6 @@ _import, | ||
}; | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -373,4 +404,4 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({ | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({ | ||
sourceLanguageTag: "en", | ||
@@ -386,3 +417,3 @@ languageTags: ["en"], | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -417,4 +448,4 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({ | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({ | ||
sourceLanguageTag: "en", | ||
@@ -430,3 +461,3 @@ languageTags: ["en"], | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -442,6 +473,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -458,6 +489,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -474,6 +505,6 @@ _import, | ||
const fs = await createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -496,4 +527,4 @@ _import, | ||
}; | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
await fs.mkdir("./resources"); | ||
@@ -514,3 +545,3 @@ const mockSaveFn = vi.fn(); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -660,3 +691,4 @@ _import, | ||
}; | ||
await fs.writeFile("./project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("./project.inlang", { recursive: true }); | ||
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings)); | ||
const mockSaveFn = vi.fn(); | ||
@@ -680,3 +712,3 @@ const _mockPlugin = { | ||
const project = await loadProject({ | ||
settingsFilePath: "/project.inlang.json", | ||
projectPath: "/project.inlang", | ||
nodeishFs: fs, | ||
@@ -697,3 +729,3 @@ _import, | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project/project.inlang.json", | ||
nodeishFs: fs, | ||
@@ -718,6 +750,6 @@ _import, | ||
const fs = createNodeishMemoryFs(); | ||
await fs.mkdir("/user/project", { recursive: true }); | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("/user/project.inlang", { recursive: true }); | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)); | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -776,6 +808,7 @@ _import: async () => ({ | ||
}; | ||
await fs.writeFile("./project.inlang.json", JSON.stringify(settings)); | ||
await fs.mkdir("./project.inlang", { recursive: true }); | ||
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings)); | ||
// establish watcher | ||
const project = await loadProject({ | ||
settingsFilePath: normalizePath("/project.inlang.json"), | ||
projectPath: normalizePath("/project.inlang"), | ||
nodeishFs: fs, | ||
@@ -782,0 +815,0 @@ _import: async () => ({ |
/* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
import { expect, test } from "vitest"; | ||
import { Plugin, MessageLintRule } from "@inlang/sdk"; | ||
import { Plugin, MessageLintRule } from "../index.js"; | ||
// import { createNodeishMemoryFs } from "@lix-js/fs" | ||
@@ -5,0 +5,0 @@ import { Type } from "@sinclair/typebox"; |
112
package.json
{ | ||
"name": "@inlang/sdk", | ||
"type": "module", | ||
"version": "0.18.0", | ||
"license": "Apache-2.0", | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"exports": { | ||
".": "./dist/index.js", | ||
"./test-utilities": "./dist/test-utilities/index.js", | ||
"./lint": "./dist/lint/index.js", | ||
"./messages": "./dist/messages/index.js" | ||
}, | ||
"files": [ | ||
"./dist", | ||
"./src" | ||
], | ||
"scripts": { | ||
"build": "tsc --build", | ||
"dev": "tsc --watch", | ||
"test": "tsc --noEmit && vitest run --passWithNoTests --coverage", | ||
"lint": "eslint ./src --fix", | ||
"format": "prettier ./src --write", | ||
"clean": "rm -rf ./dist ./node_modules" | ||
}, | ||
"engines": { | ||
"node": ">=18.0.0" | ||
}, | ||
"dependencies": { | ||
"@inlang/json-types": "*", | ||
"@inlang/translatable": "*", | ||
"@inlang/message-lint-rule": "*", | ||
"@inlang/module": "*", | ||
"@inlang/language-tag": "*", | ||
"@inlang/message": "*", | ||
"@inlang/plugin": "*", | ||
"@inlang/project-settings": "*", | ||
"@inlang/result": "*", | ||
"@lix-js/fs": "*", | ||
"@sinclair/typebox": "^0.31.17", | ||
"deepmerge-ts": "^5.1.0", | ||
"solid-js": "1.6.12", | ||
"throttle-debounce": "5.0.0", | ||
"dedent": "1.5.1" | ||
}, | ||
"devDependencies": { | ||
"@lix-js/fs": "*", | ||
"@types/throttle-debounce": "5.0.0", | ||
"@vitest/coverage-v8": "^0.33.0", | ||
"jsdom": "22.1.0", | ||
"patch-package": "6.5.1", | ||
"tsd": "^0.25.0", | ||
"typescript": "5.2.2", | ||
"vitest": "^0.33.0" | ||
} | ||
} | ||
"name": "@inlang/sdk", | ||
"type": "module", | ||
"version": "0.19.0", | ||
"license": "Apache-2.0", | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"exports": { | ||
".": "./dist/index.js", | ||
"./test-utilities": "./dist/test-utilities/index.js", | ||
"./lint": "./dist/lint/index.js", | ||
"./messages": "./dist/messages/index.js" | ||
}, | ||
"files": [ | ||
"./dist", | ||
"./src" | ||
], | ||
"engines": { | ||
"node": ">=18.0.0" | ||
}, | ||
"dependencies": { | ||
"@sinclair/typebox": "^0.31.17", | ||
"deepmerge-ts": "^5.1.0", | ||
"solid-js": "1.6.12", | ||
"throttle-debounce": "5.0.0", | ||
"dedent": "1.5.1", | ||
"@inlang/json-types": "1.1.0", | ||
"@inlang/message-lint-rule": "1.4.0", | ||
"@inlang/translatable": "1.2.0", | ||
"@inlang/module": "1.2.0", | ||
"@inlang/language-tag": "1.2.0", | ||
"@inlang/message": "2.0.0", | ||
"@inlang/plugin": "2.4.0", | ||
"@inlang/result": "1.1.0", | ||
"@inlang/project-settings": "2.2.0", | ||
"@lix-js/fs": "0.4.0" | ||
}, | ||
"devDependencies": { | ||
"@types/throttle-debounce": "5.0.0", | ||
"@vitest/coverage-v8": "^0.33.0", | ||
"jsdom": "22.1.0", | ||
"patch-package": "6.5.1", | ||
"tsd": "^0.25.0", | ||
"typescript": "5.2.2", | ||
"vitest": "^0.33.0", | ||
"@lix-js/fs": "0.4.0" | ||
}, | ||
"scripts": { | ||
"build": "tsc --build", | ||
"dev": "tsc --watch", | ||
"test": "tsc --noEmit && vitest run --passWithNoTests --coverage", | ||
"lint": "eslint ./src --fix", | ||
"format": "prettier ./src --write", | ||
"clean": "rm -rf ./dist ./node_modules" | ||
} | ||
} |
@@ -93,7 +93,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
const fs = createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config)) | ||
const project = solidAdapter( | ||
await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -127,7 +127,7 @@ _import: $import, | ||
const fs = createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(config)) | ||
const project = solidAdapter( | ||
await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -193,7 +193,7 @@ _import: $import, | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(mockConfig)) | ||
await fs.mkdir("/user/project.inlang.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(mockConfig)) | ||
const project = solidAdapter( | ||
await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang.inlang", | ||
nodeishFs: fs, | ||
@@ -224,7 +224,7 @@ _import: mockImport, | ||
const fs = createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(config)) | ||
await fs.mkdir("/user/project.inlang.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang.inlang/settings.json", JSON.stringify(config)) | ||
const project = solidAdapter( | ||
await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang.inlang", | ||
nodeishFs: fs, | ||
@@ -287,6 +287,7 @@ _import: $import, | ||
const fs = createNodeishMemoryFs() | ||
await fs.writeFile("./project.config.json", JSON.stringify(config)) | ||
await fs.mkdir("./project.inlang", { recursive: true }) | ||
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(config)) | ||
const project = solidAdapter( | ||
await loadProject({ | ||
settingsFilePath: "./project.config.json", | ||
projectPath: "./project.inlang", | ||
nodeishFs: fs, | ||
@@ -329,3 +330,3 @@ _import: $import, | ||
await loadProject({ | ||
settingsFilePath: "./project.config.json", | ||
projectPath: "./project.config.json", | ||
nodeishFs: fs, | ||
@@ -332,0 +333,0 @@ _import: $import, |
@@ -5,7 +5,7 @@ import { it, expect, vi } from "vitest" | ||
it("throws an error if settingsFilePath is not an absolute path", () => { | ||
it("throws an error if projectPath is not an absolute path", () => { | ||
const relativePath = "relative/path" | ||
expect(() => | ||
createNodeishFsWithAbsolutePaths({ settingsFilePath: relativePath, nodeishFs: {} as any }) | ||
createNodeishFsWithAbsolutePaths({ projectPath: relativePath, nodeishFs: {} as any }) | ||
).toThrow() | ||
@@ -15,3 +15,3 @@ }) | ||
it("intercepts paths correctly for readFile", async () => { | ||
const settingsFilePath = `/Users/samuel/Documents/paraglide/example/project.inlang.json` | ||
const projectPath = `/Users/samuel/Documents/paraglide/example/project.inlang` | ||
@@ -37,3 +37,3 @@ const filePaths = [ | ||
const interceptedFs = createNodeishFsWithAbsolutePaths({ | ||
settingsFilePath, | ||
projectPath, | ||
nodeishFs: mockNodeishFs, | ||
@@ -40,0 +40,0 @@ }) |
@@ -9,10 +9,10 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin" | ||
* | ||
* The paths are resolved from the `settingsFilePath` argument. | ||
* The paths are resolved from the `projectPath` argument. | ||
*/ | ||
export const createNodeishFsWithAbsolutePaths = (args: { | ||
settingsFilePath: string | ||
projectPath: string | ||
nodeishFs: NodeishFilesystemSubset | ||
}): NodeishFilesystemSubset => { | ||
if (!isAbsolutePath(args.settingsFilePath)) { | ||
throw new Error(`Expected an absolute path but received "${args.settingsFilePath}".`) | ||
if (!isAbsolutePath(args.projectPath)) { | ||
throw new Error(`Expected an absolute path but received "${args.projectPath}".`) | ||
} | ||
@@ -22,3 +22,3 @@ | ||
// removing the file name from the path | ||
const basePath = normalizePath(args.settingsFilePath).split("/").slice(0, -1).join("/") | ||
const basePath = normalizePath(args.projectPath).split("/").slice(0, -1).join("/") | ||
@@ -25,0 +25,0 @@ const makeAbsolute = (path: string) => { |
@@ -7,3 +7,3 @@ import type { NodeishFilesystemSubset } from "@inlang/plugin" | ||
* | ||
* The paths are resolved from the `settingsFilePath` argument. | ||
* The paths are resolved from the `projectPath` argument. | ||
*/ | ||
@@ -24,5 +24,7 @@ export const createNodeishFsWithWatcher = (args: { | ||
}) | ||
//eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for await (const event of watcher) { | ||
args.updateMessages() | ||
if (watcher) { | ||
//eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for await (const event of watcher) { | ||
args.updateMessages() | ||
} | ||
} | ||
@@ -29,0 +31,0 @@ } catch (err: any) { |
@@ -13,3 +13,3 @@ import { assert, describe, it } from "vitest" | ||
assert.isTrue(isAbsolutePath("C:\\Users\\User\\Documents\\File.txt")) | ||
assert.isTrue(isAbsolutePath("C:/Users/user/project/project.inlang.json")) | ||
assert.isTrue(isAbsolutePath("C:/Users/user/project.inlang/settings.json")) | ||
assert.isFalse(isAbsolutePath("Projects\\Project1\\source\\file.txt")) | ||
@@ -16,0 +16,0 @@ }) |
@@ -108,4 +108,43 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
/** | ||
* Dear Developers, | ||
* | ||
* Inlang projects (folders) are not like .vscode, .git, or .github folders. Treat em | ||
* like files: they can be renamed and moved around. | ||
*/ | ||
it("should throw if a project (path) does not have a name", async () => { | ||
const fs = createNodeishMemoryFs() | ||
const project = await tryCatch(() => | ||
loadProject({ | ||
projectPath: "/source-code/.inlang", | ||
nodeishFs: fs, | ||
_import, | ||
}) | ||
) | ||
expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument) | ||
}) | ||
it("should throw if a project path does not end with .inlang", async () => { | ||
const fs = createNodeishMemoryFs() | ||
const invalidPaths = [ | ||
"/source-code/frontend.inlang/settings", | ||
"/source-code/frontend.inlang/settings.json", | ||
"/source-code/frontend.inlang.md", | ||
] | ||
for (const invalidPath of invalidPaths) { | ||
const project = await tryCatch(() => | ||
loadProject({ | ||
projectPath: invalidPath, | ||
nodeishFs: fs, | ||
_import, | ||
}) | ||
) | ||
expect(project.error).toBeInstanceOf(LoadProjectInvalidArgument) | ||
} | ||
}) | ||
describe("initialization", () => { | ||
it("should throw if settingsFilePath is not an absolute path", async () => { | ||
it("should throw if projectPath is not an absolute path", async () => { | ||
const fs = createNodeishMemoryFs() | ||
@@ -115,3 +154,3 @@ | ||
loadProject({ | ||
settingsFilePath: "relative/path", | ||
projectPath: "relative/path", | ||
nodeishFs: fs, | ||
@@ -127,8 +166,8 @@ _import, | ||
const fs = createNodeishMemoryFs() | ||
fs.mkdir("C:\\Users\\user\\project", { recursive: true }) | ||
fs.writeFile("C:\\Users\\user\\project\\project.inlang.json", JSON.stringify(settings)) | ||
fs.mkdir("C:\\Users\\user\\project.inlang", { recursive: true }) | ||
fs.writeFile("C:\\Users\\user\\project.inlang\\settings.json", JSON.stringify(settings)) | ||
const result = await tryCatch(() => | ||
loadProject({ | ||
settingsFilePath: "C:\\Users\\user\\project\\project.inlang.json", | ||
projectPath: "C:\\Users\\user\\project.inlang", | ||
nodeishFs: fs, | ||
@@ -149,3 +188,3 @@ _import, | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/test.json", | ||
projectPath: "/user/non-existend-project.inlang", | ||
nodeishFs: fs, | ||
@@ -160,7 +199,7 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", "invalid json") | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", "invalid json") | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -175,7 +214,7 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify({})) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify({})) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -190,6 +229,6 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -205,7 +244,7 @@ _import, | ||
const settingsWithDeifferentFormatting = JSON.stringify(settings, undefined, 4) | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", settingsWithDeifferentFormatting) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", settingsWithDeifferentFormatting) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -215,3 +254,3 @@ _import, | ||
const settingsOnDisk = await fs.readFile("/user/project/project.inlang.json", { | ||
const settingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", { | ||
encoding: "utf-8", | ||
@@ -225,3 +264,3 @@ }) | ||
const newsettingsOnDisk = await fs.readFile("/user/project/project.inlang.json", { | ||
const newsettingsOnDisk = await fs.readFile("/user/project.inlang/settings.json", { | ||
encoding: "utf-8", | ||
@@ -241,7 +280,7 @@ }) | ||
const fs = createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -275,6 +314,6 @@ _import: $badImport, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -289,6 +328,6 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -314,8 +353,8 @@ _import, | ||
describe("setSettings", () => { | ||
it("should fail if settings is not valid", async () => { | ||
it("should fail if settings are not valid", async () => { | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -332,3 +371,3 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
@@ -341,6 +380,6 @@ const settings: ProjectSettings = { | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -356,6 +395,6 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -365,6 +404,6 @@ _import, | ||
const before = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" }) | ||
const before = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" }) | ||
expect(before).toBeDefined() | ||
const result = project.setSettings({ ...settings, languageTags: ["en"] }) | ||
const result = project.setSettings({ ...settings, languageTags: ["en", "nl", "de"] }) | ||
expect(result.data).toBeUndefined() | ||
@@ -374,5 +413,5 @@ expect(result.error).toBeUndefined() | ||
// TODO: how to wait for fs.writeFile to finish? | ||
await new Promise((resolve) => setTimeout(resolve, 0)) | ||
await new Promise((resolve) => setTimeout(resolve, 50)) | ||
const after = await fs.readFile("/user/project/project.inlang.json", { encoding: "utf-8" }) | ||
const after = await fs.readFile("/user/project.inlang/settings.json", { encoding: "utf-8" }) | ||
expect(after).toBeDefined() | ||
@@ -391,6 +430,6 @@ expect(after).not.toBe(before) | ||
} | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -425,7 +464,7 @@ _import, | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -461,5 +500,5 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile( | ||
"/user/project/project.inlang.json", | ||
"/user/project.inlang/settings.json", | ||
JSON.stringify({ | ||
@@ -478,3 +517,3 @@ sourceLanguageTag: "en", | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -514,5 +553,5 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile( | ||
"/user/project/project.inlang.json", | ||
"/user/project.inlang/settings.json", | ||
JSON.stringify({ | ||
@@ -531,3 +570,3 @@ sourceLanguageTag: "en", | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -548,6 +587,6 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -565,6 +604,6 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -583,6 +622,6 @@ _import, | ||
const fs = await createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -609,4 +648,4 @@ _import, | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
@@ -633,3 +672,3 @@ await fs.mkdir("./resources") | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -789,3 +828,4 @@ _import, | ||
await fs.writeFile("./project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("./project.inlang", { recursive: true }) | ||
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings)) | ||
@@ -814,3 +854,3 @@ const mockSaveFn = vi.fn() | ||
const project = await loadProject({ | ||
settingsFilePath: "/project.inlang.json", | ||
projectPath: "/project.inlang", | ||
nodeishFs: fs, | ||
@@ -835,3 +875,3 @@ _import, | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project/project.inlang.json", | ||
nodeishFs: fs, | ||
@@ -855,6 +895,6 @@ _import, | ||
const fs = createNodeishMemoryFs() | ||
await fs.mkdir("/user/project", { recursive: true }) | ||
await fs.writeFile("/user/project/project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("/user/project.inlang", { recursive: true }) | ||
await fs.writeFile("/user/project.inlang/settings.json", JSON.stringify(settings)) | ||
const project = await loadProject({ | ||
settingsFilePath: "/user/project/project.inlang.json", | ||
projectPath: "/user/project.inlang", | ||
nodeishFs: fs, | ||
@@ -921,7 +961,8 @@ _import: async () => ({ | ||
await fs.writeFile("./project.inlang.json", JSON.stringify(settings)) | ||
await fs.mkdir("./project.inlang", { recursive: true }) | ||
await fs.writeFile("./project.inlang/settings.json", JSON.stringify(settings)) | ||
// establish watcher | ||
const project = await loadProject({ | ||
settingsFilePath: normalizePath("/project.inlang.json"), | ||
projectPath: normalizePath("/project.inlang"), | ||
nodeishFs: fs, | ||
@@ -928,0 +969,0 @@ _import: async () => ({ |
@@ -26,5 +26,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
import { createNodeishFsWithAbsolutePaths } from "./createNodeishFsWithAbsolutePaths.js" | ||
import { normalizePath } from "@lix-js/fs" | ||
import { normalizePath, type NodeishFilesystem } from "@lix-js/fs" | ||
import { isAbsolutePath } from "./isAbsolutePath.js" | ||
import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js" | ||
import { maybeMigrateToDirectory } from "./migrations/migrateToDirectory.js" | ||
@@ -36,3 +37,3 @@ const settingsCompiler = TypeCompiler.Compile(ProjectSettings) | ||
* | ||
* @param settingsFilePath - Absolute path to the inlang settings file. | ||
* @param projectPath - Absolute path to the inlang settings file. | ||
* @param nodeishFs - Filesystem that implements the NodeishFilesystemSubset interface. | ||
@@ -45,20 +46,30 @@ * @param _import - Use `_import` to pass a custom import function for testing, | ||
export const loadProject = async (args: { | ||
settingsFilePath: string | ||
nodeishFs: NodeishFilesystemSubset | ||
projectPath: string | ||
nodeishFs: NodeishFilesystem | ||
_import?: ImportFunction | ||
_capture?: (id: string, props: Record<string, unknown>) => void | ||
}): Promise<InlangProject> => { | ||
const projectPath = normalizePath(args.projectPath) | ||
// -- migrate if outdated ------------------------------------------------ | ||
await maybeMigrateToDirectory({ nodeishFs: args.nodeishFs, projectPath }) | ||
// -- validation -------------------------------------------------------- | ||
//! the only place where throwing is acceptable because the project | ||
//! won't even be loaded. do not throw anywhere else. otherwise, apps | ||
//! can't handle errors gracefully. | ||
if (!isAbsolutePath(args.settingsFilePath)) { | ||
// the only place where throwing is acceptable because the project | ||
// won't even be loaded. do not throw anywhere else. otherwise, apps | ||
// can't handle errors gracefully. | ||
if (!isAbsolutePath(args.projectPath)) { | ||
throw new LoadProjectInvalidArgument( | ||
`Expected an absolute path but received "${args.settingsFilePath}".`, | ||
{ argument: "settingsFilePath" } | ||
`Expected an absolute path but received "${args.projectPath}".`, | ||
{ argument: "projectPath" } | ||
) | ||
} else if (/[^\\/]+\.inlang$/.test(projectPath) === false) { | ||
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" } | ||
) | ||
} | ||
const settingsFilePath = normalizePath(args.settingsFilePath) | ||
// -- load project ------------------------------------------------------ | ||
@@ -68,3 +79,3 @@ return await createRoot(async () => { | ||
const nodeishFs = createNodeishFsWithAbsolutePaths({ | ||
settingsFilePath, | ||
projectPath, | ||
nodeishFs: args.nodeishFs, | ||
@@ -77,3 +88,3 @@ }) | ||
createEffect(() => { | ||
loadSettings({ settingsFilePath, nodeishFs }) | ||
loadSettings({ settingsFilePath: projectPath + "/settings.json", nodeishFs }) | ||
.then((settings) => { | ||
@@ -92,3 +103,3 @@ setSettings(settings) | ||
const writeSettingsToDisk = skipFirst((settings: ProjectSettings) => | ||
_writeSettingsToDisk({ nodeishFs, settings }) | ||
_writeSettingsToDisk({ nodeishFs, settings, projectPath }) | ||
) | ||
@@ -232,8 +243,10 @@ | ||
} | ||
// if ( | ||
// newMessages.length !== 0 && | ||
// JSON.stringify(newMessages) !== JSON.stringify(messages()) | ||
// ) { | ||
// setMessages(newMessages) | ||
// } | ||
const abortController = new AbortController() | ||
if ( | ||
newMessages.length !== 0 && | ||
JSON.stringify(newMessages) !== JSON.stringify(messages()) && | ||
nodeishFs.watch("/", { signal: abortController.signal }) === undefined | ||
) { | ||
setMessages(newMessages) | ||
} | ||
}, | ||
@@ -330,2 +343,3 @@ { atBegin: false } | ||
const _writeSettingsToDisk = async (args: { | ||
projectPath: string | ||
nodeishFs: NodeishFilesystemSubset | ||
@@ -343,3 +357,3 @@ settings: ProjectSettings | ||
const { error: writeSettingsError } = await tryCatch(async () => | ||
args.nodeishFs.writeFile("./project.inlang.json", serializedSettings) | ||
args.nodeishFs.writeFile(args.projectPath + "/settings.json", serializedSettings) | ||
) | ||
@@ -346,0 +360,0 @@ |
/* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
import { expect, test } from "vitest" | ||
import { Plugin, MessageLintRule } from "@inlang/sdk" | ||
import { Plugin, MessageLintRule } from "../index.js" | ||
// import { createNodeishMemoryFs } from "@lix-js/fs" | ||
@@ -5,0 +5,0 @@ import { Type } from "@sinclair/typebox" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 10 instances in 1 package
395726
214
10158
0
+ Added@inlang/language-tag@1.2.0(transitive)
+ Added@inlang/message@2.0.0(transitive)
+ Added@inlang/message-lint-rule@1.4.0(transitive)
+ Added@inlang/module@1.2.0(transitive)
+ Added@inlang/plugin@2.4.0(transitive)
+ Added@inlang/project-settings@2.2.0(transitive)
+ Added@inlang/translatable@1.2.0(transitive)
+ Added@lix-js/fs@0.4.0(transitive)
+ Addedjs-base64@3.7.7(transitive)
- Removed@inlang/language-tag@1.5.1(transitive)
- Removed@inlang/message@2.1.0(transitive)
- Removed@inlang/message-lint-rule@1.4.7(transitive)
- Removed@inlang/module@1.2.14(transitive)
- Removed@inlang/plugin@2.4.14(transitive)
- Removed@inlang/project-settings@2.4.2(transitive)
- Removed@inlang/translatable@1.3.1(transitive)
- Removed@lix-js/fs@2.2.0(transitive)
- Removedtypescript@5.2.2(transitive)
Updated@inlang/json-types@1.1.0
Updated@inlang/language-tag@1.2.0
Updated@inlang/message@2.0.0
Updated@inlang/module@1.2.0
Updated@inlang/plugin@2.4.0
Updated@inlang/result@1.1.0
Updated@inlang/translatable@1.2.0
Updated@lix-js/fs@0.4.0