@inlang/sdk 2.10.0 → 2.10.1

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.
@@ -75,7 +75,8 @@ export type ExportFile = {
75
75
  * use it to pass information to the writer. For example, a plugin that
76
76
  * supports a namespaced `pathPattern` (`Record<namespace, pattern>`)
77
77
  * provides `{ namespace }` so that `saveProjectToDirectory` can resolve
78
- * the pattern each exported file belongs to.
78
+ * the pattern each exported file belongs to. Plugins can also provide
79
+ * `{ pathPattern }` to override the configured pattern for one file.
79
80
  *
80
81
  * https://github.com/opral/inlang/issues/4356
81
82
  */
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"/","sources":["project/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACjC;;;;;OAKG;IACH,OAAO,EAAE,kBAAkB,CAAC;IAC5B,EAAE,EAAE;QACH;;;WAGG;QACH,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KAC3B,CAAC;IACF,OAAO,EAAE;QACR,GAAG,EAAE,MAAM,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;KAC5C,CAAC;IACF,MAAM,EAAE;QACP,GAAG,EAAE,MAAM,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;KACrC,CAAC;IACF,QAAQ,EAAE;QACT,GAAG,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;QACpC,GAAG,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAClD,CAAC;IACF,GAAG,EAAE,GAAG,CAAC;IACT,WAAW,EAAE,CAAC,IAAI,EAAE;QACnB,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,EAAE,UAAU,EAAE,CAAC;KACpB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,WAAW,EAAE,CAAC,IAAI,EAAE;QACnB,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;KAC/B,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,OAAO,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,OAAO,EAAE,UAAU,CAAC;IACpB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK;IAC/D,WAAW,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"/","sources":["project/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACjC;;;;;OAKG;IACH,OAAO,EAAE,kBAAkB,CAAC;IAC5B,EAAE,EAAE;QACH;;;WAGG;QACH,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KAC3B,CAAC;IACF,OAAO,EAAE;QACR,GAAG,EAAE,MAAM,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;KAC5C,CAAC;IACF,MAAM,EAAE;QACP,GAAG,EAAE,MAAM,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;KACrC,CAAC;IACF,QAAQ,EAAE;QACT,GAAG,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;QACpC,GAAG,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAClD,CAAC;IACF,GAAG,EAAE,GAAG,CAAC;IACT,WAAW,EAAE,CAAC,IAAI,EAAE;QACnB,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,EAAE,UAAU,EAAE,CAAC;KACpB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,WAAW,EAAE,CAAC,IAAI,EAAE;QACnB,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;KAC/B,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,OAAO,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,OAAO,EAAE,UAAU,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK;IAC/D,WAAW,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"/","sources":["project/api.ts"],"names":[],"mappings":"","sourcesContent":["import type { Kysely } from \"kysely\";\nimport type { InlangDatabaseSchema } from \"../database/schema.js\";\nimport type { InlangPlugin } from \"../plugin/schema.js\";\nimport type { ProjectSettings } from \"../json-schema/settings.js\";\nimport type { Lix } from \"@lix-js/sdk\";\nimport type { SqliteWasmDatabase } from \"sqlite-wasm-kysely\";\n\nexport type InlangProject = {\n\tdb: Kysely<InlangDatabaseSchema>;\n\t/**\n\t * @deprecated Don't use this. Only an internal hack to unblock\n\t * fink v2.\n\t *\n\t * TODO remove this\n\t */\n\t_sqlite: SqliteWasmDatabase;\n\tid: {\n\t\t/**\n\t\t * Stable for packed `.inlang` files. For unpacked projects loaded from a\n\t\t * directory, the id is unstable because `project_id` is not persisted.\n\t\t */\n\t\tget: () => Promise<string>;\n\t};\n\tplugins: {\n\t\tget: () => Promise<readonly InlangPlugin[]>;\n\t};\n\terrors: {\n\t\tget: () => Promise<readonly Error[]>;\n\t};\n\tsettings: {\n\t\tget: () => Promise<ProjectSettings>;\n\t\tset: (settings: ProjectSettings) => Promise<void>;\n\t};\n\tlix: Lix;\n\timportFiles: (args: {\n\t\tpluginKey: InlangPlugin[\"key\"];\n\t\tfiles: ImportFile[];\n\t}) => Promise<void>;\n\texportFiles: (args: {\n\t\tpluginKey: InlangPlugin[\"key\"];\n\t}) => Promise<ExportFile[]>;\n\tclose: () => Promise<void>;\n\ttoBlob: () => Promise<Blob>;\n};\n\nexport type ImportFile = {\n\t/** The locale of the resource file */\n\tlocale: string;\n\t/** The binary content of the resource */\n\tcontent: Uint8Array;\n\t/**\n\t * The metadata of the file to be imported.\n\t *\n\t * Used to store additional information that is accessible in `importFiles` via `toBeImportedFilesMetadata`.\n\t * https://github.com/opral/inlang/issues/218\n\t */\n\ttoBeImportedFilesMetadata?: Record<string, any>;\n};\n\nexport type ExportFile = {\n\t/** The locale of the resource file */\n\tlocale: string;\n\t/**\n\t * The name of the file.\n\t *\n\t * @example\n\t * \"en.json\"\n\t * \"common-de.json\"\n\t *\n\t */\n\tname: string;\n\t/** The binary content of the resource */\n\tcontent: Uint8Array;\n\t/**\n\t * Metadata of the exported file.\n\t *\n\t * The counterpart of `ImportFile.toBeImportedFilesMetadata`. Plugins can\n\t * use it to pass information to the writer. For example, a plugin that\n\t * supports a namespaced `pathPattern` (`Record<namespace, pattern>`)\n\t * provides `{ namespace }` so that `saveProjectToDirectory` can resolve\n\t * the pattern each exported file belongs to.\n\t *\n\t * https://github.com/opral/inlang/issues/4356\n\t */\n\tmetadata?: Record<string, any>;\n};\n\n/**\n * Minimal RxJS compatible (generic) subscription type.\n */\nexport type Subscription<T> = (callback: (value: T) => void) => {\n\tunsubscribe: () => void;\n};\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"/","sources":["project/api.ts"],"names":[],"mappings":"","sourcesContent":["import type { Kysely } from \"kysely\";\nimport type { InlangDatabaseSchema } from \"../database/schema.js\";\nimport type { InlangPlugin } from \"../plugin/schema.js\";\nimport type { ProjectSettings } from \"../json-schema/settings.js\";\nimport type { Lix } from \"@lix-js/sdk\";\nimport type { SqliteWasmDatabase } from \"sqlite-wasm-kysely\";\n\nexport type InlangProject = {\n\tdb: Kysely<InlangDatabaseSchema>;\n\t/**\n\t * @deprecated Don't use this. Only an internal hack to unblock\n\t * fink v2.\n\t *\n\t * TODO remove this\n\t */\n\t_sqlite: SqliteWasmDatabase;\n\tid: {\n\t\t/**\n\t\t * Stable for packed `.inlang` files. For unpacked projects loaded from a\n\t\t * directory, the id is unstable because `project_id` is not persisted.\n\t\t */\n\t\tget: () => Promise<string>;\n\t};\n\tplugins: {\n\t\tget: () => Promise<readonly InlangPlugin[]>;\n\t};\n\terrors: {\n\t\tget: () => Promise<readonly Error[]>;\n\t};\n\tsettings: {\n\t\tget: () => Promise<ProjectSettings>;\n\t\tset: (settings: ProjectSettings) => Promise<void>;\n\t};\n\tlix: Lix;\n\timportFiles: (args: {\n\t\tpluginKey: InlangPlugin[\"key\"];\n\t\tfiles: ImportFile[];\n\t}) => Promise<void>;\n\texportFiles: (args: {\n\t\tpluginKey: InlangPlugin[\"key\"];\n\t}) => Promise<ExportFile[]>;\n\tclose: () => Promise<void>;\n\ttoBlob: () => Promise<Blob>;\n};\n\nexport type ImportFile = {\n\t/** The locale of the resource file */\n\tlocale: string;\n\t/** The binary content of the resource */\n\tcontent: Uint8Array;\n\t/**\n\t * The metadata of the file to be imported.\n\t *\n\t * Used to store additional information that is accessible in `importFiles` via `toBeImportedFilesMetadata`.\n\t * https://github.com/opral/inlang/issues/218\n\t */\n\ttoBeImportedFilesMetadata?: Record<string, any>;\n};\n\nexport type ExportFile = {\n\t/** The locale of the resource file */\n\tlocale: string;\n\t/**\n\t * The name of the file.\n\t *\n\t * @example\n\t * \"en.json\"\n\t * \"common-de.json\"\n\t *\n\t */\n\tname: string;\n\t/** The binary content of the resource */\n\tcontent: Uint8Array;\n\t/**\n\t * Metadata of the exported file.\n\t *\n\t * The counterpart of `ImportFile.toBeImportedFilesMetadata`. Plugins can\n\t * use it to pass information to the writer. For example, a plugin that\n\t * supports a namespaced `pathPattern` (`Record<namespace, pattern>`)\n\t * provides `{ namespace }` so that `saveProjectToDirectory` can resolve\n\t * the pattern each exported file belongs to. Plugins can also provide\n\t * `{ pathPattern }` to override the configured pattern for one file.\n\t *\n\t * https://github.com/opral/inlang/issues/4356\n\t */\n\tmetadata?: Record<string, any>;\n};\n\n/**\n * Minimal RxJS compatible (generic) subscription type.\n */\nexport type Subscription<T> = (callback: (value: T) => void) => {\n\tunsubscribe: () => void;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"saveProjectToDirectory.d.ts","sourceRoot":"/","sources":["project/saveProjectToDirectory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAmB9C,KAAK,aAAa,GAAG,OAAO,EAAE,GAAG,OAAO,MAAM,CAAC;AA2B/C;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IAClD;;;;OAIG;IACH,EAAE,EAAE,aAAa,CAAC;IAClB;;OAEG;IACH,OAAO,EAAE,aAAa,CAAC;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwKhB"}
1
+ {"version":3,"file":"saveProjectToDirectory.d.ts","sourceRoot":"/","sources":["project/saveProjectToDirectory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAmB9C,KAAK,aAAa,GAAG,OAAO,EAAE,GAAG,OAAO,MAAM,CAAC;AA2B/C;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IAClD;;;;OAIG;IACH,EAAE,EAAE,aAAa,CAAC;IAClB;;OAEG;IACH,OAAO,EAAE,aAAa,CAAC;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0KhB"}
@@ -128,7 +128,10 @@ export async function saveProjectToDirectory(args) {
128
128
  // mapping namespaces to patterns (e.g. plugin-i18next).
129
129
  // https://github.com/opral/inlang/issues/4356
130
130
  let targetPaths;
131
- if (typeof pathPattern === "string") {
131
+ if (typeof file.metadata?.["pathPattern"] === "string") {
132
+ targetPaths = [resolvePattern(file.metadata["pathPattern"])];
133
+ }
134
+ else if (typeof pathPattern === "string") {
132
135
  targetPaths = [resolvePattern(pathPattern)];
133
136
  }
134
137
  else if (Array.isArray(pathPattern)) {
@@ -1 +1 @@
1
- {"version":3,"file":"saveProjectToDirectory.js","sourceRoot":"/","sources":["project/saveProjectToDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import type nodeFs from \"node:fs\";\nimport type fs from \"node:fs/promises\";\nimport type { InlangProject } from \"./api.js\";\nimport path from \"node:path\";\nimport { toMessageV1 } from \"../json-schema/old-v1-message/toMessageV1.js\";\nimport { absolutePathFromProject, withAbsolutePaths } from \"./path-helpers.js\";\nimport { detectJsonFormatting } from \"../utilities/detectJsonFormatting.js\";\nimport { selectBundleNested } from \"../query-utilities/selectBundleNested.js\";\nimport { README_CONTENT } from \"./README_CONTENT.js\";\nimport { ENV_VARIABLES } from \"../services/env-variables/index.js\";\nimport { compareSemver, pickHighestVersion, readProjectMeta } from \"./meta.js\";\n\nasync function fileExists(fsModule: typeof fs, filePath: string) {\n\ttry {\n\t\tawait fsModule.stat(filePath);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\ntype SaveProjectFs = typeof fs | typeof nodeFs;\n\nfunction getPromisesFs(fsModule: SaveProjectFs): typeof fs {\n\treturn \"promises\" in fsModule ? fsModule.promises : fsModule;\n}\n\nasync function assertTranslationDataCanBeExported(project: InlangProject) {\n\tconst plugins = await project.plugins.get();\n\tconst hasExporter = plugins.some(\n\t\t(plugin) => plugin.exportFiles || plugin.saveMessages\n\t);\n\tif (hasExporter) {\n\t\treturn;\n\t}\n\n\tconst [bundle, message, variant] = await Promise.all([\n\t\tproject.db.selectFrom(\"bundle\").select(\"id\").limit(1).executeTakeFirst(),\n\t\tproject.db.selectFrom(\"message\").select(\"id\").limit(1).executeTakeFirst(),\n\t\tproject.db.selectFrom(\"variant\").select(\"id\").limit(1).executeTakeFirst(),\n\t]);\n\tif (bundle || message || variant) {\n\t\tthrow new Error(\n\t\t\t\"saveProjectToDirectory cannot write bundles, messages, or variants without an import/export plugin. Add a plugin to settings.modules/providePlugins, or save the canonical .inlang file with project.toBlob().\"\n\t\t);\n\t}\n}\n\n/**\n * Saves a project to a directory.\n *\n * Writes all project files to disk and runs exporters to generate\n * resource files (e.g., JSON translation files).\n *\n * @example\n * await saveProjectToDirectory({\n * fs: await import(\"node:fs\"),\n * project,\n * path: \"./project.inlang\",\n * });\n */\nexport async function saveProjectToDirectory(args: {\n\t/**\n\t * The file system module to use for writing files.\n\t *\n\t * Accepts either `node:fs` or `node:fs/promises`.\n\t */\n\tfs: SaveProjectFs;\n\t/**\n\t * The inlang project to save.\n\t */\n\tproject: InlangProject;\n\t/**\n\t * The path to the inlang project directory. Must end with `.inlang`.\n\t */\n\tpath: string;\n\t/**\n\t * If `true`, skips running exporters and only writes internal project files.\n\t *\n\t * Useful when you only want to update project metadata without\n\t * regenerating resource files.\n\t */\n\tskipExporting?: boolean;\n}): Promise<void> {\n\tif (args.path.endsWith(\".inlang\") === false) {\n\t\tthrow new Error(\"The path must end with .inlang\");\n\t}\n\tif (!args.skipExporting) {\n\t\tawait assertTranslationDataCanBeExported(args.project);\n\t}\n\tconst fsModule = getPromisesFs(args.fs);\n\n\tconst files = await args.project.lix.db\n\t\t.selectFrom(\"file\")\n\t\t.selectAll()\n\t\t.execute();\n\n\tconst gitignoreContent = new TextEncoder().encode(\n\t\t\"# IF GIT SHOWED THAT THIS FILE CHANGED\\n#\\n# 1. RUN THE FOLLOWING COMMAND\\n#\\n# ---\\n# git rm --cached '**/*.inlang/.gitignore'\\n# ---\\n#\\n# 2. COMMIT THE CHANGE\\n#\\n# ---\\n# git commit -m \\\"fix: remove tracked .gitignore from inlang project\\\"\\n# ---\\n#\\n# Inlang handles the gitignore itself starting with version ^2.5.\\n#\\n# everything is ignored except settings.json\\n*\\n!settings.json\"\n\t);\n\n\tconst existingMeta = await readProjectMeta({\n\t\tfs: fsModule,\n\t\tprojectPath: args.path,\n\t});\n\tconst highestSdkVersion =\n\t\tpickHighestVersion([\n\t\t\texistingMeta?.highestSdkVersion,\n\t\t\tENV_VARIABLES.SDK_VERSION,\n\t\t]) ?? ENV_VARIABLES.SDK_VERSION;\n\tconst shouldWriteMetadata = (() => {\n\t\tconst comparison = compareSemver(\n\t\t\thighestSdkVersion,\n\t\t\tENV_VARIABLES.SDK_VERSION\n\t\t);\n\t\treturn comparison === null || comparison <= 0;\n\t})();\n\tconst readmePath = path.join(args.path, \"README.md\");\n\tconst gitignorePath = path.join(args.path, \".gitignore\");\n\tconst shouldWriteReadme =\n\t\tshouldWriteMetadata || !(await fileExists(fsModule, readmePath));\n\tconst shouldWriteGitignore =\n\t\tshouldWriteMetadata || !(await fileExists(fsModule, gitignorePath));\n\n\t// write all files to the directory\n\tfor (const file of files) {\n\t\tif (file.path.endsWith(\"db.sqlite\") || file.path === \"/project_id\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst p = path.join(args.path, file.path);\n\t\tawait fsModule.mkdir(path.dirname(p), { recursive: true });\n\t\tawait fsModule.writeFile(p, new Uint8Array(file.data));\n\t}\n\n\tif (shouldWriteGitignore) {\n\t\tawait fsModule.writeFile(gitignorePath, gitignoreContent);\n\t}\n\n\tif (shouldWriteReadme) {\n\t\t// Write README.md for coding agents\n\t\tawait fsModule.writeFile(\n\t\t\treadmePath,\n\t\t\tnew TextEncoder().encode(README_CONTENT)\n\t\t);\n\t}\n\n\tif (shouldWriteMetadata) {\n\t\tconst metaContent = JSON.stringify({ highestSdkVersion }, null, 2);\n\t\tawait fsModule.writeFile(\n\t\t\tpath.join(args.path, \".meta.json\"),\n\t\t\tnew TextEncoder().encode(metaContent)\n\t\t);\n\t}\n\n\tif (args.skipExporting) {\n\t\treturn;\n\t}\n\n\t// run exporters\n\tconst plugins = await args.project.plugins.get();\n\tconst settings = await args.project.settings.get();\n\n\tfor (const plugin of plugins) {\n\t\tif (plugin.exportFiles) {\n\t\t\tconst bundles = await args.project.db\n\t\t\t\t.selectFrom(\"bundle\")\n\t\t\t\t.selectAll()\n\t\t\t\t.execute();\n\t\t\tconst messages = await args.project.db\n\t\t\t\t.selectFrom(\"message\")\n\t\t\t\t.selectAll()\n\t\t\t\t.execute();\n\t\t\tconst variants = await args.project.db\n\t\t\t\t.selectFrom(\"variant\")\n\t\t\t\t.selectAll()\n\t\t\t\t.execute();\n\t\t\tconst files = await plugin.exportFiles({\n\t\t\t\tbundles,\n\t\t\t\tmessages,\n\t\t\t\tvariants,\n\t\t\t\tsettings,\n\t\t\t});\n\t\t\tfor (const file of files) {\n\t\t\t\tconst pathPattern = settings[plugin.key]?.pathPattern;\n\n\t\t\t\tconst resolvePattern = (pattern: string) =>\n\t\t\t\t\tabsolutePathFromProject(\n\t\t\t\t\t\targs.path,\n\t\t\t\t\t\tpattern.replace(/\\{(languageTag|locale)\\}/g, file.locale)\n\t\t\t\t\t);\n\n\t\t\t\t// pathPattern can be a string, an array of strings, or a record\n\t\t\t\t// mapping namespaces to patterns (e.g. plugin-i18next).\n\t\t\t\t// https://github.com/opral/inlang/issues/4356\n\t\t\t\tlet targetPaths: string[];\n\t\t\t\tif (typeof pathPattern === \"string\") {\n\t\t\t\t\ttargetPaths = [resolvePattern(pathPattern)];\n\t\t\t\t} else if (Array.isArray(pathPattern)) {\n\t\t\t\t\t// an empty array writes nothing\n\t\t\t\t\ttargetPaths = pathPattern.map(resolvePattern);\n\t\t\t\t} else if (typeof pathPattern === \"object\" && pathPattern !== null) {\n\t\t\t\t\tconst namespace = file.metadata?.[\"namespace\"];\n\t\t\t\t\tconst namespacePattern = namespace\n\t\t\t\t\t\t? pathPattern[namespace]\n\t\t\t\t\t\t: undefined;\n\t\t\t\t\t// no pattern for this file (plugin didn't provide namespace\n\t\t\t\t\t// metadata or the namespace is unknown) -> fall back to file.name\n\t\t\t\t\ttargetPaths =\n\t\t\t\t\t\ttypeof namespacePattern === \"string\"\n\t\t\t\t\t\t\t? [resolvePattern(namespacePattern)]\n\t\t\t\t\t\t\t: [absolutePathFromProject(args.path, file.name)];\n\t\t\t\t} else {\n\t\t\t\t\ttargetPaths = [absolutePathFromProject(args.path, file.name)];\n\t\t\t\t}\n\n\t\t\t\tfor (const p of targetPaths) {\n\t\t\t\t\tawait fsModule.mkdir(path.dirname(p), { recursive: true });\n\t\t\t\t\tif (p.endsWith(\".json\")) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst existing = await fsModule.readFile(p, \"utf-8\");\n\t\t\t\t\t\t\tconst stringify = detectJsonFormatting(existing);\n\t\t\t\t\t\t\tawait fsModule.writeFile(\n\t\t\t\t\t\t\t\tp,\n\t\t\t\t\t\t\t\tnew TextEncoder().encode(\n\t\t\t\t\t\t\t\t\tstringify(JSON.parse(new TextDecoder().decode(file.content)))\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// write the file to disk (json doesn't exist yet)\n\t\t\t\t\t\t\t// yeah ugly duplication of write file but it works.\n\t\t\t\t\t\t\tawait fsModule.writeFile(p, new Uint8Array(file.content));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait fsModule.writeFile(p, new Uint8Array(file.content));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// old legacy remove with v3\n\t\telse if (plugin.saveMessages) {\n\t\t\t// in-efficient re-qeuery but it's a legacy function that will be removed.\n\t\t\t// the effort of adjusting the code to not re-query is not worth it.\n\t\t\tconst bundlesNested = await selectBundleNested(args.project.db).execute();\n\t\t\tawait plugin.saveMessages({\n\t\t\t\tmessages: bundlesNested.map((b) => toMessageV1(b)),\n\t\t\t\t// @ts-expect-error - legacy\n\t\t\t\tnodeishFs: withAbsolutePaths(fsModule, args.path),\n\t\t\t\tsettings,\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"saveProjectToDirectory.js","sourceRoot":"/","sources":["project/saveProjectToDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import type nodeFs from \"node:fs\";\nimport type fs from \"node:fs/promises\";\nimport type { InlangProject } from \"./api.js\";\nimport path from \"node:path\";\nimport { toMessageV1 } from \"../json-schema/old-v1-message/toMessageV1.js\";\nimport { absolutePathFromProject, withAbsolutePaths } from \"./path-helpers.js\";\nimport { detectJsonFormatting } from \"../utilities/detectJsonFormatting.js\";\nimport { selectBundleNested } from \"../query-utilities/selectBundleNested.js\";\nimport { README_CONTENT } from \"./README_CONTENT.js\";\nimport { ENV_VARIABLES } from \"../services/env-variables/index.js\";\nimport { compareSemver, pickHighestVersion, readProjectMeta } from \"./meta.js\";\n\nasync function fileExists(fsModule: typeof fs, filePath: string) {\n\ttry {\n\t\tawait fsModule.stat(filePath);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\ntype SaveProjectFs = typeof fs | typeof nodeFs;\n\nfunction getPromisesFs(fsModule: SaveProjectFs): typeof fs {\n\treturn \"promises\" in fsModule ? fsModule.promises : fsModule;\n}\n\nasync function assertTranslationDataCanBeExported(project: InlangProject) {\n\tconst plugins = await project.plugins.get();\n\tconst hasExporter = plugins.some(\n\t\t(plugin) => plugin.exportFiles || plugin.saveMessages\n\t);\n\tif (hasExporter) {\n\t\treturn;\n\t}\n\n\tconst [bundle, message, variant] = await Promise.all([\n\t\tproject.db.selectFrom(\"bundle\").select(\"id\").limit(1).executeTakeFirst(),\n\t\tproject.db.selectFrom(\"message\").select(\"id\").limit(1).executeTakeFirst(),\n\t\tproject.db.selectFrom(\"variant\").select(\"id\").limit(1).executeTakeFirst(),\n\t]);\n\tif (bundle || message || variant) {\n\t\tthrow new Error(\n\t\t\t\"saveProjectToDirectory cannot write bundles, messages, or variants without an import/export plugin. Add a plugin to settings.modules/providePlugins, or save the canonical .inlang file with project.toBlob().\"\n\t\t);\n\t}\n}\n\n/**\n * Saves a project to a directory.\n *\n * Writes all project files to disk and runs exporters to generate\n * resource files (e.g., JSON translation files).\n *\n * @example\n * await saveProjectToDirectory({\n * fs: await import(\"node:fs\"),\n * project,\n * path: \"./project.inlang\",\n * });\n */\nexport async function saveProjectToDirectory(args: {\n\t/**\n\t * The file system module to use for writing files.\n\t *\n\t * Accepts either `node:fs` or `node:fs/promises`.\n\t */\n\tfs: SaveProjectFs;\n\t/**\n\t * The inlang project to save.\n\t */\n\tproject: InlangProject;\n\t/**\n\t * The path to the inlang project directory. Must end with `.inlang`.\n\t */\n\tpath: string;\n\t/**\n\t * If `true`, skips running exporters and only writes internal project files.\n\t *\n\t * Useful when you only want to update project metadata without\n\t * regenerating resource files.\n\t */\n\tskipExporting?: boolean;\n}): Promise<void> {\n\tif (args.path.endsWith(\".inlang\") === false) {\n\t\tthrow new Error(\"The path must end with .inlang\");\n\t}\n\tif (!args.skipExporting) {\n\t\tawait assertTranslationDataCanBeExported(args.project);\n\t}\n\tconst fsModule = getPromisesFs(args.fs);\n\n\tconst files = await args.project.lix.db\n\t\t.selectFrom(\"file\")\n\t\t.selectAll()\n\t\t.execute();\n\n\tconst gitignoreContent = new TextEncoder().encode(\n\t\t\"# IF GIT SHOWED THAT THIS FILE CHANGED\\n#\\n# 1. RUN THE FOLLOWING COMMAND\\n#\\n# ---\\n# git rm --cached '**/*.inlang/.gitignore'\\n# ---\\n#\\n# 2. COMMIT THE CHANGE\\n#\\n# ---\\n# git commit -m \\\"fix: remove tracked .gitignore from inlang project\\\"\\n# ---\\n#\\n# Inlang handles the gitignore itself starting with version ^2.5.\\n#\\n# everything is ignored except settings.json\\n*\\n!settings.json\"\n\t);\n\n\tconst existingMeta = await readProjectMeta({\n\t\tfs: fsModule,\n\t\tprojectPath: args.path,\n\t});\n\tconst highestSdkVersion =\n\t\tpickHighestVersion([\n\t\t\texistingMeta?.highestSdkVersion,\n\t\t\tENV_VARIABLES.SDK_VERSION,\n\t\t]) ?? ENV_VARIABLES.SDK_VERSION;\n\tconst shouldWriteMetadata = (() => {\n\t\tconst comparison = compareSemver(\n\t\t\thighestSdkVersion,\n\t\t\tENV_VARIABLES.SDK_VERSION\n\t\t);\n\t\treturn comparison === null || comparison <= 0;\n\t})();\n\tconst readmePath = path.join(args.path, \"README.md\");\n\tconst gitignorePath = path.join(args.path, \".gitignore\");\n\tconst shouldWriteReadme =\n\t\tshouldWriteMetadata || !(await fileExists(fsModule, readmePath));\n\tconst shouldWriteGitignore =\n\t\tshouldWriteMetadata || !(await fileExists(fsModule, gitignorePath));\n\n\t// write all files to the directory\n\tfor (const file of files) {\n\t\tif (file.path.endsWith(\"db.sqlite\") || file.path === \"/project_id\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst p = path.join(args.path, file.path);\n\t\tawait fsModule.mkdir(path.dirname(p), { recursive: true });\n\t\tawait fsModule.writeFile(p, new Uint8Array(file.data));\n\t}\n\n\tif (shouldWriteGitignore) {\n\t\tawait fsModule.writeFile(gitignorePath, gitignoreContent);\n\t}\n\n\tif (shouldWriteReadme) {\n\t\t// Write README.md for coding agents\n\t\tawait fsModule.writeFile(\n\t\t\treadmePath,\n\t\t\tnew TextEncoder().encode(README_CONTENT)\n\t\t);\n\t}\n\n\tif (shouldWriteMetadata) {\n\t\tconst metaContent = JSON.stringify({ highestSdkVersion }, null, 2);\n\t\tawait fsModule.writeFile(\n\t\t\tpath.join(args.path, \".meta.json\"),\n\t\t\tnew TextEncoder().encode(metaContent)\n\t\t);\n\t}\n\n\tif (args.skipExporting) {\n\t\treturn;\n\t}\n\n\t// run exporters\n\tconst plugins = await args.project.plugins.get();\n\tconst settings = await args.project.settings.get();\n\n\tfor (const plugin of plugins) {\n\t\tif (plugin.exportFiles) {\n\t\t\tconst bundles = await args.project.db\n\t\t\t\t.selectFrom(\"bundle\")\n\t\t\t\t.selectAll()\n\t\t\t\t.execute();\n\t\t\tconst messages = await args.project.db\n\t\t\t\t.selectFrom(\"message\")\n\t\t\t\t.selectAll()\n\t\t\t\t.execute();\n\t\t\tconst variants = await args.project.db\n\t\t\t\t.selectFrom(\"variant\")\n\t\t\t\t.selectAll()\n\t\t\t\t.execute();\n\t\t\tconst files = await plugin.exportFiles({\n\t\t\t\tbundles,\n\t\t\t\tmessages,\n\t\t\t\tvariants,\n\t\t\t\tsettings,\n\t\t\t});\n\t\t\tfor (const file of files) {\n\t\t\t\tconst pathPattern = settings[plugin.key]?.pathPattern;\n\n\t\t\t\tconst resolvePattern = (pattern: string) =>\n\t\t\t\t\tabsolutePathFromProject(\n\t\t\t\t\t\targs.path,\n\t\t\t\t\t\tpattern.replace(/\\{(languageTag|locale)\\}/g, file.locale)\n\t\t\t\t\t);\n\n\t\t\t\t// pathPattern can be a string, an array of strings, or a record\n\t\t\t\t// mapping namespaces to patterns (e.g. plugin-i18next).\n\t\t\t\t// https://github.com/opral/inlang/issues/4356\n\t\t\t\tlet targetPaths: string[];\n\t\t\t\tif (typeof file.metadata?.[\"pathPattern\"] === \"string\") {\n\t\t\t\t\ttargetPaths = [resolvePattern(file.metadata[\"pathPattern\"])];\n\t\t\t\t} else if (typeof pathPattern === \"string\") {\n\t\t\t\t\ttargetPaths = [resolvePattern(pathPattern)];\n\t\t\t\t} else if (Array.isArray(pathPattern)) {\n\t\t\t\t\t// an empty array writes nothing\n\t\t\t\t\ttargetPaths = pathPattern.map(resolvePattern);\n\t\t\t\t} else if (typeof pathPattern === \"object\" && pathPattern !== null) {\n\t\t\t\t\tconst namespace = file.metadata?.[\"namespace\"];\n\t\t\t\t\tconst namespacePattern = namespace\n\t\t\t\t\t\t? pathPattern[namespace]\n\t\t\t\t\t\t: undefined;\n\t\t\t\t\t// no pattern for this file (plugin didn't provide namespace\n\t\t\t\t\t// metadata or the namespace is unknown) -> fall back to file.name\n\t\t\t\t\ttargetPaths =\n\t\t\t\t\t\ttypeof namespacePattern === \"string\"\n\t\t\t\t\t\t\t? [resolvePattern(namespacePattern)]\n\t\t\t\t\t\t\t: [absolutePathFromProject(args.path, file.name)];\n\t\t\t\t} else {\n\t\t\t\t\ttargetPaths = [absolutePathFromProject(args.path, file.name)];\n\t\t\t\t}\n\n\t\t\t\tfor (const p of targetPaths) {\n\t\t\t\t\tawait fsModule.mkdir(path.dirname(p), { recursive: true });\n\t\t\t\t\tif (p.endsWith(\".json\")) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst existing = await fsModule.readFile(p, \"utf-8\");\n\t\t\t\t\t\t\tconst stringify = detectJsonFormatting(existing);\n\t\t\t\t\t\t\tawait fsModule.writeFile(\n\t\t\t\t\t\t\t\tp,\n\t\t\t\t\t\t\t\tnew TextEncoder().encode(\n\t\t\t\t\t\t\t\t\tstringify(JSON.parse(new TextDecoder().decode(file.content)))\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// write the file to disk (json doesn't exist yet)\n\t\t\t\t\t\t\t// yeah ugly duplication of write file but it works.\n\t\t\t\t\t\t\tawait fsModule.writeFile(p, new Uint8Array(file.content));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait fsModule.writeFile(p, new Uint8Array(file.content));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// old legacy remove with v3\n\t\telse if (plugin.saveMessages) {\n\t\t\t// in-efficient re-qeuery but it's a legacy function that will be removed.\n\t\t\t// the effort of adjusting the code to not re-query is not worth it.\n\t\t\tconst bundlesNested = await selectBundleNested(args.project.db).execute();\n\t\t\tawait plugin.saveMessages({\n\t\t\t\tmessages: bundlesNested.map((b) => toMessageV1(b)),\n\t\t\t\t// @ts-expect-error - legacy\n\t\t\t\tnodeishFs: withAbsolutePaths(fsModule, args.path),\n\t\t\t\tsettings,\n\t\t\t});\n\t\t}\n\t}\n}\n"]}
@@ -213,6 +213,47 @@ test("resolves a namespaced pathPattern object via export file metadata", async
213
213
  expect(JSON.parse(common)).toEqual({ hello: "Hello" });
214
214
  expect(JSON.parse(app)).toEqual({ title: "My app" });
215
215
  });
216
+ test("resolves an export file pathPattern metadata override", async () => {
217
+ const volume = Volume.fromJSON({});
218
+ const mockPlugin = {
219
+ key: "mock",
220
+ exportFiles: async () => [
221
+ {
222
+ locale: "en",
223
+ name: "en.json",
224
+ content: new TextEncoder().encode(JSON.stringify({ hello: "Hello" })),
225
+ metadata: { pathPattern: "./main.json" },
226
+ },
227
+ {
228
+ locale: "de",
229
+ name: "de.json",
230
+ content: new TextEncoder().encode(JSON.stringify({ hello: "Hallo" })),
231
+ },
232
+ ],
233
+ };
234
+ const project = await loadProjectInMemory({
235
+ blob: await newProject({
236
+ settings: {
237
+ baseLocale: "en",
238
+ locales: ["en", "de"],
239
+ modules: [],
240
+ mock: {
241
+ pathPattern: "./{locale}.json",
242
+ },
243
+ },
244
+ }),
245
+ providePlugins: [mockPlugin],
246
+ });
247
+ await saveProjectToDirectory({
248
+ fs: volume,
249
+ project,
250
+ path: "/foo/bar.inlang",
251
+ });
252
+ const source = await volume.promises.readFile("/foo/main.json", "utf-8");
253
+ const target = await volume.promises.readFile("/foo/de.json", "utf-8");
254
+ expect(JSON.parse(source)).toEqual({ hello: "Hello" });
255
+ expect(JSON.parse(target)).toEqual({ hello: "Hallo" });
256
+ });
216
257
  // old plugin versions don't provide namespace metadata. falling back to
217
258
  // file.name is better than throwing "pathPattern.replace is not a function"
218
259
  // https://github.com/opral/inlang/issues/4356
@@ -1 +1 @@
1
- {"version":3,"file":"saveProjectToDirectory.test.js","sourceRoot":"/","sources":["project/saveProjectToDirectory.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect, vi } from \"vitest\";\nimport { saveProjectToDirectory } from \"./saveProjectToDirectory.js\";\nimport { Volume } from \"memfs\";\nimport { loadProjectInMemory } from \"./loadProjectInMemory.js\";\nimport { newProject } from \"./newProject.js\";\nimport type { InlangPlugin } from \"../plugin/schema.js\";\nimport type { Bundle, NewMessage, Variant } from \"../database/schema.js\";\nimport { loadProjectFromDirectory } from \"./loadProjectFromDirectory.js\";\nimport { selectBundleNested } from \"../query-utilities/selectBundleNested.js\";\nimport type { ProjectSettings } from \"../json-schema/settings.js\";\nimport type { MessageV1 } from \"../json-schema/old-v1-message/schemaV1.js\";\nimport { ENV_VARIABLES } from \"../services/env-variables/index.js\";\n\ntest(\"it should throw if the path doesn't end with .inlang\", async () => {\n\tawait expect(() =>\n\t\tsaveProjectToDirectory({\n\t\t\tfs: {} as any,\n\t\t\tproject: {} as any,\n\t\t\tpath: \"/foo/bar\",\n\t\t})\n\t).rejects.toThrowError(\"The path must end with .inlang\");\n});\n\ntest(\"it should overwrite all files to the directory except the db.sqlite file\", async () => {\n\tconst mockFs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/settings.json\": JSON.stringify({\n\t\t\tbaseLocale: \"en\",\n\t\t\tlocales: [\"en\"],\n\t\t}),\n\t}).promises as any;\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"mock\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: mockFs,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst files = await mockFs.readdir(\"/foo/bar.inlang\");\n\tconst updatedSettingsFile = await mockFs.readFile(\n\t\t\"/foo/bar.inlang/settings.json\",\n\t\t\"utf-8\"\n\t);\n\tconst updatedSettings = JSON.parse(updatedSettingsFile);\n\n\t// only testing known files at the time of the test.\n\t// this test should be updated for files that should NOT\n\t// be contained in the directory in the future\n\texpect(files).toContain(\"settings.json\");\n\texpect(files).not.toContain(\"db.sqlite\");\n\texpect(updatedSettings.baseLocale).toBe(\"en\");\n\texpect(updatedSettings.locales).toEqual([\"en\", \"fr\", \"mock\"]);\n});\n\ntest(\"accepts the node:fs style module with a promises namespace\", async () => {\n\tconst volume = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst settings = await volume.promises.readFile(\n\t\t\"/foo/bar.inlang/settings.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(settings as string).locales).toEqual([\"en\"]);\n});\n\ntest(\"creates exporter target directories from pathPattern\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"fallback.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ greeting: \"Hi\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: \"./messages/{locale}.json\",\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait project.db\n\t\t.insertInto(\"bundle\")\n\t\t.values({ id: \"greeting\", declarations: [] })\n\t\t.execute();\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst exported = await volume.promises.readFile(\n\t\t\"/foo/messages/en.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(exported as string)).toEqual({ greeting: \"Hi\" });\n});\n\ntest(\"writes exported files to every pattern of a pathPattern array\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ greeting: \"Hi\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: [\"./messages/{locale}.json\", \"./backup/{locale}.json\"],\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst messages = await volume.promises.readFile(\n\t\t\"/foo/messages/en.json\",\n\t\t\"utf-8\"\n\t);\n\tconst backup = await volume.promises.readFile(\"/foo/backup/en.json\", \"utf-8\");\n\texpect(JSON.parse(messages as string)).toEqual({ greeting: \"Hi\" });\n\texpect(JSON.parse(backup as string)).toEqual({ greeting: \"Hi\" });\n});\n\ntest(\"an empty pathPattern array writes nothing\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ greeting: \"Hi\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: [],\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst files = await volume.promises.readdir(\"/foo\");\n\texpect(files).not.toContain(\"en.json\");\n});\n\n// https://github.com/opral/inlang/issues/4356\ntest(\"resolves a namespaced pathPattern object via export file metadata\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"common-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\tmetadata: { namespace: \"common\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"app-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ title: \"My app\" })),\n\t\t\t\tmetadata: { namespace: \"app\" },\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: {\n\t\t\t\t\t\tcommon: \"./{locale}/common.json\",\n\t\t\t\t\t\tapp: \"./{locale}/app.json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst common = await volume.promises.readFile(\"/foo/en/common.json\", \"utf-8\");\n\tconst app = await volume.promises.readFile(\"/foo/en/app.json\", \"utf-8\");\n\texpect(JSON.parse(common as string)).toEqual({ hello: \"Hello\" });\n\texpect(JSON.parse(app as string)).toEqual({ title: \"My app\" });\n});\n\n// old plugin versions don't provide namespace metadata. falling back to\n// file.name is better than throwing \"pathPattern.replace is not a function\"\n// https://github.com/opral/inlang/issues/4356\ntest(\"falls back to the file name when a namespaced pathPattern can't be resolved\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"common-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\t// no metadata, like plugin versions that predate ExportFile.metadata\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: {\n\t\t\t\t\t\tcommon: \"./{locale}/common.json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst fallback = await volume.promises.readFile(\n\t\t\"/foo/common-en.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(fallback as string)).toEqual({ hello: \"Hello\" });\n});\n\n// https://github.com/opral/inlang/issues/4356\ntest(\"falls back to the file name when the namespace is missing from the pathPattern object\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"stray-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\tmetadata: { namespace: \"stray\" },\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: {\n\t\t\t\t\t\tcommon: \"./{locale}/common.json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst fallback = await volume.promises.readFile(\"/foo/stray-en.json\", \"utf-8\");\n\texpect(JSON.parse(fallback as string)).toEqual({ hello: \"Hello\" });\n});\n\n// Users were confused by project_id, and without sync a stable id is rarely needed.\ntest(\"it should not write project_id to disk\", async () => {\n\tconst mockFs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/settings.json\": JSON.stringify({\n\t\t\tbaseLocale: \"en\",\n\t\t\tlocales: [\"en\"],\n\t\t}),\n\t}).promises as any;\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: mockFs,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst files = await mockFs.readdir(\"/foo/bar.inlang\");\n\n\texpect(files).not.toContain(\"project_id\");\n});\n\ntest(\"a roundtrip should work\", async () => {\n\tconst bundles: Bundle[] = [{ id: \"mock-bundle\", declarations: [] }];\n\tconst messages: NewMessage[] = [{ bundleId: \"mock-bundle\", locale: \"en\" }];\n\tconst variants: Variant[] = [];\n\n\tconst volume = Volume.fromJSON({\n\t\t\"/mock-file.json\": JSON.stringify({ bundles, messages, variants }),\n\t});\n\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock-plugin\",\n\t\ttoBeImportedFiles: async () => {\n\t\t\treturn [{ path: \"/mock-file.json\", locale: \"mock\" }];\n\t\t},\n\t\timportFiles: async ({ files }) => {\n\t\t\tconst { bundles, messages, variants } = JSON.parse(\n\t\t\t\tnew TextDecoder().decode(files[0]?.content)\n\t\t\t);\n\t\t\treturn { bundles, messages, variants };\n\t\t},\n\t\texportFiles: async ({ bundles }) => {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify(bundles)),\n\t\t\t\t\tname: \"mock-file.json\",\n\t\t\t\t\tlocale: \"mock\",\n\t\t\t\t},\n\t\t\t];\n\t\t},\n\t};\n\n\tconst exportFilesSpy = vi.spyOn(mockPlugin, \"exportFiles\");\n\tconst importFilesSpy = vi.spyOn(mockPlugin, \"importFiles\");\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait project.db.insertInto(\"bundle\").values(bundles).execute();\n\tawait project.db.insertInto(\"message\").values(messages).execute();\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\t// const fileTree = volume.toJSON();\n\n\texpect(exportFilesSpy).toHaveBeenCalled();\n\texpect(importFilesSpy).not.toHaveBeenCalled();\n\n\t// TODO deactivated since mockBundleNested no longer contains the id of the messages\n\t// expect(fileTree).toEqual(\n\t// \texpect.objectContaining({\n\t// \t\t\"/foo/mock-file.json\": JSON.stringify([mockBundleNested]),\n\t// \t})\n\t// );\n\n\t// testing roundtrip\n\n\tconst project2 = await loadProjectFromDirectory({\n\t\tfs: volume as any,\n\t\tpath: \"/foo/bar.inlang\",\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\texpect(mockPlugin.importFiles).toHaveBeenCalled();\n\n\tconst bundlesAfter = await project2.db\n\t\t.selectFrom(\"bundle\")\n\t\t.selectAll()\n\t\t.execute();\n\tconst messagesAfter = await project2.db\n\t\t.selectFrom(\"message\")\n\t\t.selectAll()\n\t\t.execute();\n\tconst variantsAfter = await project2.db\n\t\t.selectFrom(\"variant\")\n\t\t.selectAll()\n\t\t.execute();\n\n\texpect(bundlesAfter).lengthOf(1);\n\texpect(messagesAfter).lengthOf(1);\n\texpect(variantsAfter).lengthOf(0);\n\n\texpect(bundlesAfter[0]).toStrictEqual(expect.objectContaining(bundles[0]));\n\texpect(messagesAfter[0]).toStrictEqual(\n\t\texpect.objectContaining(messagesAfter[0])\n\t);\n});\n\ntest.todo(\n\t\"a roundtrip with legacy load and save messages should work\",\n\tasync () => {\n\t\tconst mockMessageV1: MessageV1 = {\n\t\t\tid: \"mock-legacy-message\",\n\t\t\talias: {},\n\t\t\tselectors: [],\n\t\t\tvariants: [\n\t\t\t\t{\n\t\t\t\t\tlanguageTag: \"en\",\n\t\t\t\t\tmatch: [],\n\t\t\t\t\tpattern: [{ type: \"Text\", value: \"Hello from legacy message\" }],\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\n\t\tconst volume = Volume.fromJSON({\n\t\t\t\"/foo/bar.inlang/settings.json\": JSON.stringify({\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t} satisfies ProjectSettings),\n\t\t\t\"/foo/i18n/en.json\": JSON.stringify([mockMessageV1]),\n\t\t});\n\n\t\tconst mockPlugin: InlangPlugin = {\n\t\t\tid: \"mock-legacy-plugin\",\n\t\t\tkey: \"mock-legacy-plugin\",\n\t\t\tloadMessages: async ({ nodeishFs }) => {\n\t\t\t\t// expecting `loadMessages` to transform the relative path\n\t\t\t\t// to an absolute path `./i18n/en.json` -> `/foo/i18n/en.json`\n\t\t\t\tconst file = await nodeishFs.readFile(\"./i18n/en.json\", {\n\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t});\n\t\t\t\treturn JSON.parse(file as string);\n\t\t\t},\n\t\t\tsaveMessages: async ({ messages, nodeishFs }) => {\n\t\t\t\tawait nodeishFs.writeFile(\n\t\t\t\t\t\"./i18n/en.json\",\n\t\t\t\t\tnew TextEncoder().encode(JSON.stringify(messages))\n\t\t\t\t\t\t.buffer as ArrayBuffer\n\t\t\t\t);\n\t\t\t},\n\t\t};\n\n\t\tconst loadMessagesSpy = vi.spyOn(mockPlugin, \"loadMessages\");\n\t\tconst saveMessagesSpy = vi.spyOn(mockPlugin, \"saveMessages\");\n\n\t\tconst project = await loadProjectFromDirectory({\n\t\t\tfs: volume as any,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t\tprovidePlugins: [mockPlugin],\n\t\t});\n\n\t\texpect(loadMessagesSpy).toHaveBeenCalled();\n\t\texpect(saveMessagesSpy).not.toHaveBeenCalled();\n\n\t\tconst bundles1 = await selectBundleNested(project.db).execute();\n\n\t\texpect(bundles1[0]?.messages).lengthOf(1);\n\t\texpect(bundles1[0]?.messages[0]?.variants).toEqual([\n\t\t\texpect.objectContaining({\n\t\t\t\tpattern: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\tvalue: \"Hello from legacy message\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}),\n\t\t]);\n\n\t\t// await project.db\n\t\t// \t.updateTable(\"variant\")\n\t\t// \t.set({\n\t\t// \t\tpattern: [{ type: \"text\", value: \"Updated message\" }],\n\t\t// \t})\n\t\t// \t.where(\"id\", \"=\", bundles1[0]?.messages[0]?.variants[0]?.id as string)\n\t\t// \t.execute();\n\n\t\t// testing the saveMessages function by removing the en.json file\n\t\tawait volume.promises.rm(\"/foo/i18n/en.json\");\n\n\t\tawait saveProjectToDirectory({\n\t\t\tfs: volume.promises as any,\n\t\t\tproject,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t});\n\n\t\texpect(saveMessagesSpy).toHaveBeenCalled();\n\n\t\tconst fileTree = volume.toJSON();\n\t\tconst parsed = JSON.parse(fileTree[\"/foo/i18n/en.json\"] as string);\n\n\t\texpect(parsed).toEqual(expect.objectContaining([mockMessageV1]));\n\n\t\t// testing roundtrip\n\n\t\tconst project2 = await loadProjectFromDirectory({\n\t\t\tfs: volume as any,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t\tprovidePlugins: [mockPlugin],\n\t\t});\n\n\t\tconst bundles2 = await selectBundleNested(project2.db).execute();\n\n\t\t// TODO deactivated since the ids must not be equal for separate imports - matching happens on language and matcher now\n\t\texpect(bundles1).toStrictEqual(bundles2);\n\t}\n);\n\ntest(\"it should preserve the formatting of existing json resource files\", async () => {\n\tconst mockJson =\n\t\tJSON.stringify(\n\t\t\t{ key: \"value\" },\n\t\t\tundefined,\n\t\t\t// tab spacing\n\t\t\t\"\\t\"\n\t\t) +\n\t\t// ends with new line\n\t\t\"\\n\";\n\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tname: \"en.json\",\n\t\t\t\t\t// no beautified json\n\t\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ key: \"value\" })),\n\t\t\t\t\tlocale: \"en\",\n\t\t\t\t},\n\t\t\t];\n\t\t},\n\t};\n\n\tconst volume = Volume.fromJSON({\n\t\t\"/foo/project.inlang/settings.json\": JSON.stringify({\n\t\t\tbaseLocale: \"en\",\n\t\t\tlocales: [\"en\"],\n\t\t} satisfies ProjectSettings),\n\t\t\"/foo/en.json\": mockJson,\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t});\n\n\tconst fileAfterSave = await volume.promises.readFile(\"/foo/en.json\", \"utf-8\");\n\texpect(fileAfterSave).toBe(mockJson);\n});\n\ntest(\"adds a gitignore file if it doesn't exist\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n});\n\ntest(\"emits a README.md file for coding agents\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\texpect(readme).toContain(\"## What is this folder?\");\n\texpect(readme).toContain(\"@inlang/sdk\");\n});\n\ntest(\"emits a .meta.json file with the sdk version\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst metaRaw = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.meta.json\",\n\t\t\"utf-8\"\n\t);\n\tconst meta = JSON.parse(\n\t\ttypeof metaRaw === \"string\" ? metaRaw : metaRaw.toString()\n\t);\n\texpect(meta.highestSdkVersion).toBe(ENV_VARIABLES.SDK_VERSION);\n});\n\ntest(\"throws when saving translation data to a directory without an exporter plugin\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait project.db\n\t\t.insertInto(\"bundle\")\n\t\t.values({ id: \"greeting\", declarations: [] })\n\t\t.execute();\n\n\tawait expect(\n\t\tsaveProjectToDirectory({\n\t\t\tfs: fs.promises as any,\n\t\t\tproject,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t})\n\t).rejects.toThrow(\n\t\t\"saveProjectToDirectory cannot write bundles, messages, or variants without an import/export plugin\"\n\t);\n});\n\ntest(\"updates an existing README.md file\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/README.md\": \"custom readme\",\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\texpect(readme).not.toContain(\"custom readme\");\n});\n\ntest(\"does not overwrite README.md or .gitignore when meta has a higher sdk version\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/.meta.json\": JSON.stringify({\n\t\t\thighestSdkVersion: \"99.0.0\",\n\t\t}),\n\t\t\"/foo/bar.inlang/README.md\": \"custom readme\",\n\t\t\"/foo/bar.inlang/.gitignore\": \"custom gitignore\",\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\tconst metaRaw = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.meta.json\",\n\t\t\"utf-8\"\n\t);\n\tconst meta = JSON.parse(\n\t\ttypeof metaRaw === \"string\" ? metaRaw : metaRaw.toString()\n\t);\n\texpect(readme).toBe(\"custom readme\");\n\texpect(gitignore).toBe(\"custom gitignore\");\n\texpect(meta.highestSdkVersion).toBe(\"99.0.0\");\n});\n\ntest(\"recreates missing README.md and .gitignore when meta has a higher sdk version\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/.meta.json\": JSON.stringify({\n\t\t\thighestSdkVersion: \"99.0.0\",\n\t\t}),\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\tconst metaRaw = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.meta.json\",\n\t\t\"utf-8\"\n\t);\n\tconst meta = JSON.parse(\n\t\ttypeof metaRaw === \"string\" ? metaRaw : metaRaw.toString()\n\t);\n\n\texpect(readme).toContain(\"## What is this folder?\");\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n\texpect(meta.highestSdkVersion).toBe(\"99.0.0\");\n});\n\ntest(\"README.md is gitignored\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\texpect(gitignore).toContain(\"# everything is ignored except settings.json\");\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n\texpect(gitignore).not.toContain(\"!README.md\");\n});\n\ntest(\"overwrites existing .gitignore with generated entries\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/.gitignore\": \"custom\\nnode_modules\",\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n});\n\ntest(\"uses exportFiles when both exportFiles and saveMessages are defined\", async () => {\n\tconst exportFilesSpy = vi.fn().mockResolvedValue([]);\n\tconst saveMessagesSpy = vi.fn();\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: exportFilesSpy,\n\t\tsaveMessages: saveMessagesSpy,\n\t};\n\tconst volume = Volume.fromJSON({});\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t});\n\texpect(exportFilesSpy).toHaveBeenCalled();\n\texpect(saveMessagesSpy).not.toHaveBeenCalled();\n});\n\ntest(\"skipExporting prevents exporters from running\", async () => {\n\tconst exportFilesSpy = vi.fn().mockResolvedValue([]);\n\tconst saveMessagesSpy = vi.fn();\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: exportFilesSpy,\n\t\tsaveMessages: saveMessagesSpy,\n\t};\n\tconst volume = Volume.fromJSON({});\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t\tskipExporting: true,\n\t});\n\texpect(exportFilesSpy).not.toHaveBeenCalled();\n\texpect(saveMessagesSpy).not.toHaveBeenCalled();\n});\n\ntest(\"uses saveMessages when exportFiles is not defined\", async () => {\n\tconst saveMessagesSpy = vi.fn().mockResolvedValue([]);\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\tsaveMessages: saveMessagesSpy,\n\t};\n\tconst volume = Volume.fromJSON({});\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t});\n\texpect(saveMessagesSpy).toHaveBeenCalled();\n});\n"]}
1
+ {"version":3,"file":"saveProjectToDirectory.test.js","sourceRoot":"/","sources":["project/saveProjectToDirectory.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect, vi } from \"vitest\";\nimport { saveProjectToDirectory } from \"./saveProjectToDirectory.js\";\nimport { Volume } from \"memfs\";\nimport { loadProjectInMemory } from \"./loadProjectInMemory.js\";\nimport { newProject } from \"./newProject.js\";\nimport type { InlangPlugin } from \"../plugin/schema.js\";\nimport type { Bundle, NewMessage, Variant } from \"../database/schema.js\";\nimport { loadProjectFromDirectory } from \"./loadProjectFromDirectory.js\";\nimport { selectBundleNested } from \"../query-utilities/selectBundleNested.js\";\nimport type { ProjectSettings } from \"../json-schema/settings.js\";\nimport type { MessageV1 } from \"../json-schema/old-v1-message/schemaV1.js\";\nimport { ENV_VARIABLES } from \"../services/env-variables/index.js\";\n\ntest(\"it should throw if the path doesn't end with .inlang\", async () => {\n\tawait expect(() =>\n\t\tsaveProjectToDirectory({\n\t\t\tfs: {} as any,\n\t\t\tproject: {} as any,\n\t\t\tpath: \"/foo/bar\",\n\t\t})\n\t).rejects.toThrowError(\"The path must end with .inlang\");\n});\n\ntest(\"it should overwrite all files to the directory except the db.sqlite file\", async () => {\n\tconst mockFs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/settings.json\": JSON.stringify({\n\t\t\tbaseLocale: \"en\",\n\t\t\tlocales: [\"en\"],\n\t\t}),\n\t}).promises as any;\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\", \"mock\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: mockFs,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst files = await mockFs.readdir(\"/foo/bar.inlang\");\n\tconst updatedSettingsFile = await mockFs.readFile(\n\t\t\"/foo/bar.inlang/settings.json\",\n\t\t\"utf-8\"\n\t);\n\tconst updatedSettings = JSON.parse(updatedSettingsFile);\n\n\t// only testing known files at the time of the test.\n\t// this test should be updated for files that should NOT\n\t// be contained in the directory in the future\n\texpect(files).toContain(\"settings.json\");\n\texpect(files).not.toContain(\"db.sqlite\");\n\texpect(updatedSettings.baseLocale).toBe(\"en\");\n\texpect(updatedSettings.locales).toEqual([\"en\", \"fr\", \"mock\"]);\n});\n\ntest(\"accepts the node:fs style module with a promises namespace\", async () => {\n\tconst volume = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst settings = await volume.promises.readFile(\n\t\t\"/foo/bar.inlang/settings.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(settings as string).locales).toEqual([\"en\"]);\n});\n\ntest(\"creates exporter target directories from pathPattern\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"fallback.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ greeting: \"Hi\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: \"./messages/{locale}.json\",\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait project.db\n\t\t.insertInto(\"bundle\")\n\t\t.values({ id: \"greeting\", declarations: [] })\n\t\t.execute();\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst exported = await volume.promises.readFile(\n\t\t\"/foo/messages/en.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(exported as string)).toEqual({ greeting: \"Hi\" });\n});\n\ntest(\"writes exported files to every pattern of a pathPattern array\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ greeting: \"Hi\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: [\"./messages/{locale}.json\", \"./backup/{locale}.json\"],\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst messages = await volume.promises.readFile(\n\t\t\"/foo/messages/en.json\",\n\t\t\"utf-8\"\n\t);\n\tconst backup = await volume.promises.readFile(\"/foo/backup/en.json\", \"utf-8\");\n\texpect(JSON.parse(messages as string)).toEqual({ greeting: \"Hi\" });\n\texpect(JSON.parse(backup as string)).toEqual({ greeting: \"Hi\" });\n});\n\ntest(\"an empty pathPattern array writes nothing\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ greeting: \"Hi\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: [],\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst files = await volume.promises.readdir(\"/foo\");\n\texpect(files).not.toContain(\"en.json\");\n});\n\n// https://github.com/opral/inlang/issues/4356\ntest(\"resolves a namespaced pathPattern object via export file metadata\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"common-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\tmetadata: { namespace: \"common\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"app-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ title: \"My app\" })),\n\t\t\t\tmetadata: { namespace: \"app\" },\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: {\n\t\t\t\t\t\tcommon: \"./{locale}/common.json\",\n\t\t\t\t\t\tapp: \"./{locale}/app.json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst common = await volume.promises.readFile(\"/foo/en/common.json\", \"utf-8\");\n\tconst app = await volume.promises.readFile(\"/foo/en/app.json\", \"utf-8\");\n\texpect(JSON.parse(common as string)).toEqual({ hello: \"Hello\" });\n\texpect(JSON.parse(app as string)).toEqual({ title: \"My app\" });\n});\n\ntest(\"resolves an export file pathPattern metadata override\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\tmetadata: { pathPattern: \"./main.json\" },\n\t\t\t},\n\t\t\t{\n\t\t\t\tlocale: \"de\",\n\t\t\t\tname: \"de.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hallo\" })),\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"de\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: \"./{locale}.json\",\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst source = await volume.promises.readFile(\"/foo/main.json\", \"utf-8\");\n\tconst target = await volume.promises.readFile(\"/foo/de.json\", \"utf-8\");\n\texpect(JSON.parse(source as string)).toEqual({ hello: \"Hello\" });\n\texpect(JSON.parse(target as string)).toEqual({ hello: \"Hallo\" });\n});\n\n// old plugin versions don't provide namespace metadata. falling back to\n// file.name is better than throwing \"pathPattern.replace is not a function\"\n// https://github.com/opral/inlang/issues/4356\ntest(\"falls back to the file name when a namespaced pathPattern can't be resolved\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"common-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\t// no metadata, like plugin versions that predate ExportFile.metadata\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: {\n\t\t\t\t\t\tcommon: \"./{locale}/common.json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst fallback = await volume.promises.readFile(\n\t\t\"/foo/common-en.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(fallback as string)).toEqual({ hello: \"Hello\" });\n});\n\n// https://github.com/opral/inlang/issues/4356\ntest(\"falls back to the file name when the namespace is missing from the pathPattern object\", async () => {\n\tconst volume = Volume.fromJSON({});\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => [\n\t\t\t{\n\t\t\t\tlocale: \"en\",\n\t\t\t\tname: \"stray-en.json\",\n\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ hello: \"Hello\" })),\n\t\t\t\tmetadata: { namespace: \"stray\" },\n\t\t\t},\n\t\t],\n\t};\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tmodules: [],\n\t\t\t\tmock: {\n\t\t\t\t\tpathPattern: {\n\t\t\t\t\t\tcommon: \"./{locale}/common.json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst fallback = await volume.promises.readFile(\n\t\t\"/foo/stray-en.json\",\n\t\t\"utf-8\"\n\t);\n\texpect(JSON.parse(fallback as string)).toEqual({ hello: \"Hello\" });\n});\n\n// Users were confused by project_id, and without sync a stable id is rarely needed.\ntest(\"it should not write project_id to disk\", async () => {\n\tconst mockFs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/settings.json\": JSON.stringify({\n\t\t\tbaseLocale: \"en\",\n\t\t\tlocales: [\"en\"],\n\t\t}),\n\t}).promises as any;\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\", \"fr\"],\n\t\t\t},\n\t\t}),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: mockFs,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst files = await mockFs.readdir(\"/foo/bar.inlang\");\n\n\texpect(files).not.toContain(\"project_id\");\n});\n\ntest(\"a roundtrip should work\", async () => {\n\tconst bundles: Bundle[] = [{ id: \"mock-bundle\", declarations: [] }];\n\tconst messages: NewMessage[] = [{ bundleId: \"mock-bundle\", locale: \"en\" }];\n\tconst variants: Variant[] = [];\n\n\tconst volume = Volume.fromJSON({\n\t\t\"/mock-file.json\": JSON.stringify({ bundles, messages, variants }),\n\t});\n\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock-plugin\",\n\t\ttoBeImportedFiles: async () => {\n\t\t\treturn [{ path: \"/mock-file.json\", locale: \"mock\" }];\n\t\t},\n\t\timportFiles: async ({ files }) => {\n\t\t\tconst { bundles, messages, variants } = JSON.parse(\n\t\t\t\tnew TextDecoder().decode(files[0]?.content)\n\t\t\t);\n\t\t\treturn { bundles, messages, variants };\n\t\t},\n\t\texportFiles: async ({ bundles }) => {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify(bundles)),\n\t\t\t\t\tname: \"mock-file.json\",\n\t\t\t\t\tlocale: \"mock\",\n\t\t\t\t},\n\t\t\t];\n\t\t},\n\t};\n\n\tconst exportFilesSpy = vi.spyOn(mockPlugin, \"exportFiles\");\n\tconst importFilesSpy = vi.spyOn(mockPlugin, \"importFiles\");\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait project.db.insertInto(\"bundle\").values(bundles).execute();\n\tawait project.db.insertInto(\"message\").values(messages).execute();\n\n\tawait saveProjectToDirectory({\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\t// const fileTree = volume.toJSON();\n\n\texpect(exportFilesSpy).toHaveBeenCalled();\n\texpect(importFilesSpy).not.toHaveBeenCalled();\n\n\t// TODO deactivated since mockBundleNested no longer contains the id of the messages\n\t// expect(fileTree).toEqual(\n\t// \texpect.objectContaining({\n\t// \t\t\"/foo/mock-file.json\": JSON.stringify([mockBundleNested]),\n\t// \t})\n\t// );\n\n\t// testing roundtrip\n\n\tconst project2 = await loadProjectFromDirectory({\n\t\tfs: volume as any,\n\t\tpath: \"/foo/bar.inlang\",\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\texpect(mockPlugin.importFiles).toHaveBeenCalled();\n\n\tconst bundlesAfter = await project2.db\n\t\t.selectFrom(\"bundle\")\n\t\t.selectAll()\n\t\t.execute();\n\tconst messagesAfter = await project2.db\n\t\t.selectFrom(\"message\")\n\t\t.selectAll()\n\t\t.execute();\n\tconst variantsAfter = await project2.db\n\t\t.selectFrom(\"variant\")\n\t\t.selectAll()\n\t\t.execute();\n\n\texpect(bundlesAfter).lengthOf(1);\n\texpect(messagesAfter).lengthOf(1);\n\texpect(variantsAfter).lengthOf(0);\n\n\texpect(bundlesAfter[0]).toStrictEqual(expect.objectContaining(bundles[0]));\n\texpect(messagesAfter[0]).toStrictEqual(\n\t\texpect.objectContaining(messagesAfter[0])\n\t);\n});\n\ntest.todo(\n\t\"a roundtrip with legacy load and save messages should work\",\n\tasync () => {\n\t\tconst mockMessageV1: MessageV1 = {\n\t\t\tid: \"mock-legacy-message\",\n\t\t\talias: {},\n\t\t\tselectors: [],\n\t\t\tvariants: [\n\t\t\t\t{\n\t\t\t\t\tlanguageTag: \"en\",\n\t\t\t\t\tmatch: [],\n\t\t\t\t\tpattern: [{ type: \"Text\", value: \"Hello from legacy message\" }],\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\n\t\tconst volume = Volume.fromJSON({\n\t\t\t\"/foo/bar.inlang/settings.json\": JSON.stringify({\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t\tlocales: [\"en\"],\n\t\t\t} satisfies ProjectSettings),\n\t\t\t\"/foo/i18n/en.json\": JSON.stringify([mockMessageV1]),\n\t\t});\n\n\t\tconst mockPlugin: InlangPlugin = {\n\t\t\tid: \"mock-legacy-plugin\",\n\t\t\tkey: \"mock-legacy-plugin\",\n\t\t\tloadMessages: async ({ nodeishFs }) => {\n\t\t\t\t// expecting `loadMessages` to transform the relative path\n\t\t\t\t// to an absolute path `./i18n/en.json` -> `/foo/i18n/en.json`\n\t\t\t\tconst file = await nodeishFs.readFile(\"./i18n/en.json\", {\n\t\t\t\t\tencoding: \"utf-8\",\n\t\t\t\t});\n\t\t\t\treturn JSON.parse(file as string);\n\t\t\t},\n\t\t\tsaveMessages: async ({ messages, nodeishFs }) => {\n\t\t\t\tawait nodeishFs.writeFile(\n\t\t\t\t\t\"./i18n/en.json\",\n\t\t\t\t\tnew TextEncoder().encode(JSON.stringify(messages))\n\t\t\t\t\t\t.buffer as ArrayBuffer\n\t\t\t\t);\n\t\t\t},\n\t\t};\n\n\t\tconst loadMessagesSpy = vi.spyOn(mockPlugin, \"loadMessages\");\n\t\tconst saveMessagesSpy = vi.spyOn(mockPlugin, \"saveMessages\");\n\n\t\tconst project = await loadProjectFromDirectory({\n\t\t\tfs: volume as any,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t\tprovidePlugins: [mockPlugin],\n\t\t});\n\n\t\texpect(loadMessagesSpy).toHaveBeenCalled();\n\t\texpect(saveMessagesSpy).not.toHaveBeenCalled();\n\n\t\tconst bundles1 = await selectBundleNested(project.db).execute();\n\n\t\texpect(bundles1[0]?.messages).lengthOf(1);\n\t\texpect(bundles1[0]?.messages[0]?.variants).toEqual([\n\t\t\texpect.objectContaining({\n\t\t\t\tpattern: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\tvalue: \"Hello from legacy message\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}),\n\t\t]);\n\n\t\t// await project.db\n\t\t// \t.updateTable(\"variant\")\n\t\t// \t.set({\n\t\t// \t\tpattern: [{ type: \"text\", value: \"Updated message\" }],\n\t\t// \t})\n\t\t// \t.where(\"id\", \"=\", bundles1[0]?.messages[0]?.variants[0]?.id as string)\n\t\t// \t.execute();\n\n\t\t// testing the saveMessages function by removing the en.json file\n\t\tawait volume.promises.rm(\"/foo/i18n/en.json\");\n\n\t\tawait saveProjectToDirectory({\n\t\t\tfs: volume.promises as any,\n\t\t\tproject,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t});\n\n\t\texpect(saveMessagesSpy).toHaveBeenCalled();\n\n\t\tconst fileTree = volume.toJSON();\n\t\tconst parsed = JSON.parse(fileTree[\"/foo/i18n/en.json\"] as string);\n\n\t\texpect(parsed).toEqual(expect.objectContaining([mockMessageV1]));\n\n\t\t// testing roundtrip\n\n\t\tconst project2 = await loadProjectFromDirectory({\n\t\t\tfs: volume as any,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t\tprovidePlugins: [mockPlugin],\n\t\t});\n\n\t\tconst bundles2 = await selectBundleNested(project2.db).execute();\n\n\t\t// TODO deactivated since the ids must not be equal for separate imports - matching happens on language and matcher now\n\t\texpect(bundles1).toStrictEqual(bundles2);\n\t}\n);\n\ntest(\"it should preserve the formatting of existing json resource files\", async () => {\n\tconst mockJson =\n\t\tJSON.stringify(\n\t\t\t{ key: \"value\" },\n\t\t\tundefined,\n\t\t\t// tab spacing\n\t\t\t\"\\t\"\n\t\t) +\n\t\t// ends with new line\n\t\t\"\\n\";\n\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: async () => {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tname: \"en.json\",\n\t\t\t\t\t// no beautified json\n\t\t\t\t\tcontent: new TextEncoder().encode(JSON.stringify({ key: \"value\" })),\n\t\t\t\t\tlocale: \"en\",\n\t\t\t\t},\n\t\t\t];\n\t\t},\n\t};\n\n\tconst volume = Volume.fromJSON({\n\t\t\"/foo/project.inlang/settings.json\": JSON.stringify({\n\t\t\tbaseLocale: \"en\",\n\t\t\tlocales: [\"en\"],\n\t\t} satisfies ProjectSettings),\n\t\t\"/foo/en.json\": mockJson,\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t});\n\n\tconst fileAfterSave = await volume.promises.readFile(\"/foo/en.json\", \"utf-8\");\n\texpect(fileAfterSave).toBe(mockJson);\n});\n\ntest(\"adds a gitignore file if it doesn't exist\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n});\n\ntest(\"emits a README.md file for coding agents\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\texpect(readme).toContain(\"## What is this folder?\");\n\texpect(readme).toContain(\"@inlang/sdk\");\n});\n\ntest(\"emits a .meta.json file with the sdk version\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst metaRaw = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.meta.json\",\n\t\t\"utf-8\"\n\t);\n\tconst meta = JSON.parse(\n\t\ttypeof metaRaw === \"string\" ? metaRaw : metaRaw.toString()\n\t);\n\texpect(meta.highestSdkVersion).toBe(ENV_VARIABLES.SDK_VERSION);\n});\n\ntest(\"throws when saving translation data to a directory without an exporter plugin\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait project.db\n\t\t.insertInto(\"bundle\")\n\t\t.values({ id: \"greeting\", declarations: [] })\n\t\t.execute();\n\n\tawait expect(\n\t\tsaveProjectToDirectory({\n\t\t\tfs: fs.promises as any,\n\t\t\tproject,\n\t\t\tpath: \"/foo/bar.inlang\",\n\t\t})\n\t).rejects.toThrow(\n\t\t\"saveProjectToDirectory cannot write bundles, messages, or variants without an import/export plugin\"\n\t);\n});\n\ntest(\"updates an existing README.md file\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/README.md\": \"custom readme\",\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\texpect(readme).not.toContain(\"custom readme\");\n});\n\ntest(\"does not overwrite README.md or .gitignore when meta has a higher sdk version\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/.meta.json\": JSON.stringify({\n\t\t\thighestSdkVersion: \"99.0.0\",\n\t\t}),\n\t\t\"/foo/bar.inlang/README.md\": \"custom readme\",\n\t\t\"/foo/bar.inlang/.gitignore\": \"custom gitignore\",\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\tconst metaRaw = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.meta.json\",\n\t\t\"utf-8\"\n\t);\n\tconst meta = JSON.parse(\n\t\ttypeof metaRaw === \"string\" ? metaRaw : metaRaw.toString()\n\t);\n\texpect(readme).toBe(\"custom readme\");\n\texpect(gitignore).toBe(\"custom gitignore\");\n\texpect(meta.highestSdkVersion).toBe(\"99.0.0\");\n});\n\ntest(\"recreates missing README.md and .gitignore when meta has a higher sdk version\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/.meta.json\": JSON.stringify({\n\t\t\thighestSdkVersion: \"99.0.0\",\n\t\t}),\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst readme = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/README.md\",\n\t\t\"utf-8\"\n\t);\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\tconst metaRaw = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.meta.json\",\n\t\t\"utf-8\"\n\t);\n\tconst meta = JSON.parse(\n\t\ttypeof metaRaw === \"string\" ? metaRaw : metaRaw.toString()\n\t);\n\n\texpect(readme).toContain(\"## What is this folder?\");\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n\texpect(meta.highestSdkVersion).toBe(\"99.0.0\");\n});\n\ntest(\"README.md is gitignored\", async () => {\n\tconst fs = Volume.fromJSON({});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\texpect(gitignore).toContain(\"# everything is ignored except settings.json\");\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n\texpect(gitignore).not.toContain(\"!README.md\");\n});\n\ntest(\"overwrites existing .gitignore with generated entries\", async () => {\n\tconst fs = Volume.fromJSON({\n\t\t\"/foo/bar.inlang/.gitignore\": \"custom\\nnode_modules\",\n\t});\n\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t});\n\n\tawait saveProjectToDirectory({\n\t\tfs: fs.promises as any,\n\t\tproject,\n\t\tpath: \"/foo/bar.inlang\",\n\t});\n\n\tconst gitignore = await fs.promises.readFile(\n\t\t\"/foo/bar.inlang/.gitignore\",\n\t\t\"utf-8\"\n\t);\n\texpect(gitignore).toContain(\"*\");\n\texpect(gitignore).toContain(\"!settings.json\");\n});\n\ntest(\"uses exportFiles when both exportFiles and saveMessages are defined\", async () => {\n\tconst exportFilesSpy = vi.fn().mockResolvedValue([]);\n\tconst saveMessagesSpy = vi.fn();\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: exportFilesSpy,\n\t\tsaveMessages: saveMessagesSpy,\n\t};\n\tconst volume = Volume.fromJSON({});\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t});\n\texpect(exportFilesSpy).toHaveBeenCalled();\n\texpect(saveMessagesSpy).not.toHaveBeenCalled();\n});\n\ntest(\"skipExporting prevents exporters from running\", async () => {\n\tconst exportFilesSpy = vi.fn().mockResolvedValue([]);\n\tconst saveMessagesSpy = vi.fn();\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\texportFiles: exportFilesSpy,\n\t\tsaveMessages: saveMessagesSpy,\n\t};\n\tconst volume = Volume.fromJSON({});\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t\tskipExporting: true,\n\t});\n\texpect(exportFilesSpy).not.toHaveBeenCalled();\n\texpect(saveMessagesSpy).not.toHaveBeenCalled();\n});\n\ntest(\"uses saveMessages when exportFiles is not defined\", async () => {\n\tconst saveMessagesSpy = vi.fn().mockResolvedValue([]);\n\tconst mockPlugin: InlangPlugin = {\n\t\tkey: \"mock\",\n\t\tsaveMessages: saveMessagesSpy,\n\t};\n\tconst volume = Volume.fromJSON({});\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject(),\n\t\tprovidePlugins: [mockPlugin],\n\t});\n\tawait saveProjectToDirectory({\n\t\tpath: \"/foo/project.inlang\",\n\t\tfs: volume.promises as any,\n\t\tproject,\n\t});\n\texpect(saveMessagesSpy).toHaveBeenCalled();\n});\n"]}
@@ -1,5 +1,5 @@
1
1
  export const ENV_VARIABLES = {
2
2
  PUBLIC_INLANG_SDK_SENTRY_DSN: undefined,
3
- SDK_VERSION: "2.10.0",
3
+ SDK_VERSION: "2.10.1",
4
4
  };
5
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"/","sources":["services/env-variables/index.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,4BAA4B,EAAE,SAAS;IACvC,WAAW,EAAE,QAAQ;CACrB,CAAA","sourcesContent":["\nexport const ENV_VARIABLES = {\n\tPUBLIC_INLANG_SDK_SENTRY_DSN: undefined,\n\tSDK_VERSION: \"2.10.0\",\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"/","sources":["services/env-variables/index.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,4BAA4B,EAAE,SAAS;IACvC,WAAW,EAAE,QAAQ;CACrB,CAAA","sourcesContent":["\nexport const ENV_VARIABLES = {\n\tPUBLIC_INLANG_SDK_SENTRY_DSN: undefined,\n\tSDK_VERSION: \"2.10.1\",\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inlang/sdk",
3
- "version": "2.10.0",
3
+ "version": "2.10.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -78,7 +78,8 @@ export type ExportFile = {
78
78
  * use it to pass information to the writer. For example, a plugin that
79
79
  * supports a namespaced `pathPattern` (`Record<namespace, pattern>`)
80
80
  * provides `{ namespace }` so that `saveProjectToDirectory` can resolve
81
- * the pattern each exported file belongs to.
81
+ * the pattern each exported file belongs to. Plugins can also provide
82
+ * `{ pathPattern }` to override the configured pattern for one file.
82
83
  *
83
84
  * https://github.com/opral/inlang/issues/4356
84
85
  */
@@ -259,6 +259,51 @@ test("resolves a namespaced pathPattern object via export file metadata", async
259
259
  expect(JSON.parse(app as string)).toEqual({ title: "My app" });
260
260
  });
261
261
 
262
+ test("resolves an export file pathPattern metadata override", async () => {
263
+ const volume = Volume.fromJSON({});
264
+ const mockPlugin: InlangPlugin = {
265
+ key: "mock",
266
+ exportFiles: async () => [
267
+ {
268
+ locale: "en",
269
+ name: "en.json",
270
+ content: new TextEncoder().encode(JSON.stringify({ hello: "Hello" })),
271
+ metadata: { pathPattern: "./main.json" },
272
+ },
273
+ {
274
+ locale: "de",
275
+ name: "de.json",
276
+ content: new TextEncoder().encode(JSON.stringify({ hello: "Hallo" })),
277
+ },
278
+ ],
279
+ };
280
+
281
+ const project = await loadProjectInMemory({
282
+ blob: await newProject({
283
+ settings: {
284
+ baseLocale: "en",
285
+ locales: ["en", "de"],
286
+ modules: [],
287
+ mock: {
288
+ pathPattern: "./{locale}.json",
289
+ },
290
+ },
291
+ }),
292
+ providePlugins: [mockPlugin],
293
+ });
294
+
295
+ await saveProjectToDirectory({
296
+ fs: volume as any,
297
+ project,
298
+ path: "/foo/bar.inlang",
299
+ });
300
+
301
+ const source = await volume.promises.readFile("/foo/main.json", "utf-8");
302
+ const target = await volume.promises.readFile("/foo/de.json", "utf-8");
303
+ expect(JSON.parse(source as string)).toEqual({ hello: "Hello" });
304
+ expect(JSON.parse(target as string)).toEqual({ hello: "Hallo" });
305
+ });
306
+
262
307
  // old plugin versions don't provide namespace metadata. falling back to
263
308
  // file.name is better than throwing "pathPattern.replace is not a function"
264
309
  // https://github.com/opral/inlang/issues/4356
@@ -342,7 +387,10 @@ test("falls back to the file name when the namespace is missing from the pathPat
342
387
  path: "/foo/bar.inlang",
343
388
  });
344
389
 
345
- const fallback = await volume.promises.readFile("/foo/stray-en.json", "utf-8");
390
+ const fallback = await volume.promises.readFile(
391
+ "/foo/stray-en.json",
392
+ "utf-8"
393
+ );
346
394
  expect(JSON.parse(fallback as string)).toEqual({ hello: "Hello" });
347
395
  });
348
396
 
@@ -193,7 +193,9 @@ export async function saveProjectToDirectory(args: {
193
193
  // mapping namespaces to patterns (e.g. plugin-i18next).
194
194
  // https://github.com/opral/inlang/issues/4356
195
195
  let targetPaths: string[];
196
- if (typeof pathPattern === "string") {
196
+ if (typeof file.metadata?.["pathPattern"] === "string") {
197
+ targetPaths = [resolvePattern(file.metadata["pathPattern"])];
198
+ } else if (typeof pathPattern === "string") {
197
199
  targetPaths = [resolvePattern(pathPattern)];
198
200
  } else if (Array.isArray(pathPattern)) {
199
201
  // an empty array writes nothing