@inlang/paraglide-js 2.26.0 → 2.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/bundler-plugins/per-locale-build/index.js +14 -7
- package/dist/bundler-plugins/per-locale-build/index.js.map +1 -1
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +237 -4
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
- package/dist/bundler-plugins/unplugin.d.ts +1 -1
- package/dist/bundler-plugins/unplugin.js +79 -10
- package/dist/bundler-plugins/unplugin.js.map +1 -1
- package/dist/bundler-plugins/unplugin.test.js +334 -1
- package/dist/bundler-plugins/unplugin.test.js.map +1 -1
- package/dist/bundler-plugins/vite.js +2 -1
- package/dist/bundler-plugins/vite.js.map +1 -1
- package/dist/bundler-plugins/vite.test.js +1 -1
- package/dist/bundler-plugins/vite.test.js.map +1 -1
- package/dist/cli/commands/compile/command.js +13 -0
- package/dist/cli/commands/compile/command.js.map +1 -1
- package/dist/cli/commands/compile/command.test.js +87 -3
- package/dist/cli/commands/compile/command.test.js.map +1 -1
- package/dist/cli/commands/init/command.d.ts +5 -0
- package/dist/cli/commands/init/command.js +216 -44
- package/dist/cli/commands/init/command.js.map +1 -1
- package/dist/cli/commands/init/command.test.d.ts +1 -0
- package/dist/cli/commands/init/command.test.js +123 -0
- package/dist/cli/commands/init/command.test.js.map +1 -0
- package/dist/cli/defaults.js +2 -2
- package/dist/cli/defaults.js.map +1 -1
- package/dist/cli/init-options.d.ts +11 -0
- package/dist/cli/init-options.js +2 -0
- package/dist/cli/init-options.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.d.ts +19 -0
- package/dist/cli/steps/add-inlang-check.js +60 -0
- package/dist/cli/steps/add-inlang-check.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
- package/dist/cli/steps/add-inlang-check.test.js +88 -0
- package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
- package/dist/cli/steps/add-message-lint.d.ts +34 -0
- package/dist/cli/steps/add-message-lint.js +105 -0
- package/dist/cli/steps/add-message-lint.js.map +1 -0
- package/dist/cli/steps/add-message-lint.test.d.ts +1 -0
- package/dist/cli/steps/add-message-lint.test.js +74 -0
- package/dist/cli/steps/add-message-lint.test.js.map +1 -0
- package/dist/cli/steps/add-vite-plugin.d.ts +18 -0
- package/dist/cli/steps/add-vite-plugin.js +34 -6
- package/dist/cli/steps/add-vite-plugin.js.map +1 -1
- package/dist/cli/steps/add-vite-plugin.test.js +25 -9
- package/dist/cli/steps/add-vite-plugin.test.js.map +1 -1
- package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
- package/dist/cli/steps/agents-md-suggestion.js +19 -0
- package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
- package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
- package/dist/cli/steps/check-for-uncomitted-changes.d.ts +3 -0
- package/dist/cli/steps/check-for-uncomitted-changes.js +15 -3
- package/dist/cli/steps/check-for-uncomitted-changes.js.map +1 -1
- package/dist/cli/steps/detect-bundler.d.ts +1 -0
- package/dist/cli/steps/detect-bundler.js +7 -1
- package/dist/cli/steps/detect-bundler.js.map +1 -1
- package/dist/cli/steps/initialize-inlang-project.d.ts +4 -3
- package/dist/cli/steps/initialize-inlang-project.js +60 -157
- package/dist/cli/steps/initialize-inlang-project.js.map +1 -1
- package/dist/cli/steps/maybe-add-machine-translation.d.ts +4 -0
- package/dist/cli/steps/maybe-add-machine-translation.js +14 -8
- package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.d.ts +2 -0
- package/dist/cli/steps/maybe-add-sherlock.js +13 -7
- package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.test.d.ts +1 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js +44 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js.map +1 -0
- package/dist/cli/steps/prompt-for-outdir.d.ts +2 -0
- package/dist/cli/steps/prompt-for-outdir.js +4 -0
- package/dist/cli/steps/prompt-for-outdir.js.map +1 -1
- package/dist/cli/steps/update-package-json.js +8 -13
- package/dist/cli/steps/update-package-json.js.map +1 -1
- package/dist/cli/steps/update-ts-config.d.ts +6 -0
- package/dist/cli/steps/update-ts-config.js +27 -4
- package/dist/cli/steps/update-ts-config.js.map +1 -1
- package/dist/cli/utils.d.ts +11 -0
- package/dist/cli/utils.js +21 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/utils.test.d.ts +1 -0
- package/dist/cli/utils.test.js +16 -0
- package/dist/cli/utils.test.js.map +1 -0
- package/dist/compiler/compile-annotation.d.ts +48 -1
- package/dist/compiler/compile-annotation.js +243 -10
- package/dist/compiler/compile-annotation.js.map +1 -1
- package/dist/compiler/compile-bundle.d.ts +7 -2
- package/dist/compiler/compile-bundle.js +97 -3
- package/dist/compiler/compile-bundle.js.map +1 -1
- package/dist/compiler/compile-bundle.test.js +232 -19
- package/dist/compiler/compile-bundle.test.js.map +1 -1
- package/dist/compiler/compile-lifecycle.test.d.ts +1 -0
- package/dist/compiler/compile-lifecycle.test.js +69 -0
- package/dist/compiler/compile-lifecycle.test.js.map +1 -0
- package/dist/compiler/compile-local-variable.d.ts +3 -0
- package/dist/compiler/compile-local-variable.js +5 -2
- package/dist/compiler/compile-local-variable.js.map +1 -1
- package/dist/compiler/compile-local-variable.test.js +55 -15
- package/dist/compiler/compile-local-variable.test.js.map +1 -1
- package/dist/compiler/compile-message.d.ts +29 -1
- package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
- package/dist/compiler/compile-message.exact-number.test.js +786 -0
- package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
- package/dist/compiler/compile-message.js +162 -66
- package/dist/compiler/compile-message.js.map +1 -1
- package/dist/compiler/compile-message.locals.test.d.ts +1 -0
- package/dist/compiler/compile-message.locals.test.js +498 -0
- package/dist/compiler/compile-message.locals.test.js.map +1 -0
- package/dist/compiler/compile-message.test.js +113 -22
- package/dist/compiler/compile-message.test.js.map +1 -1
- package/dist/compiler/compile-pattern.d.ts +5 -0
- package/dist/compiler/compile-pattern.js +6 -18
- package/dist/compiler/compile-pattern.js.map +1 -1
- package/dist/compiler/compile-pattern.test.js +169 -5
- package/dist/compiler/compile-pattern.test.js.map +1 -1
- package/dist/compiler/compile-project.js +5 -1
- package/dist/compiler/compile-project.js.map +1 -1
- package/dist/compiler/compile-project.test.js +1260 -185
- package/dist/compiler/compile-project.test.js.map +1 -1
- package/dist/compiler/compile.js +36 -17
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/compile.test.js +71 -1
- package/dist/compiler/compile.test.js.map +1 -1
- package/dist/compiler/compiler-options.d.ts +41 -0
- package/dist/compiler/compiler-options.js.map +1 -1
- package/dist/compiler/create-readme.d.ts +4 -1
- package/dist/compiler/create-readme.js +33 -125
- package/dist/compiler/create-readme.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
- package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.test.js +4 -4
- package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/index.js +1 -1
- package/dist/compiler/index.js.map +1 -1
- package/dist/compiler/input-alias.d.ts +21 -0
- package/dist/compiler/input-alias.js +42 -0
- package/dist/compiler/input-alias.js.map +1 -0
- package/dist/compiler/input-alias.test.d.ts +1 -0
- package/dist/compiler/input-alias.test.js +58 -0
- package/dist/compiler/input-alias.test.js.map +1 -0
- package/dist/compiler/message-locals.d.ts +46 -0
- package/dist/compiler/message-locals.js +129 -0
- package/dist/compiler/message-locals.js.map +1 -0
- package/dist/compiler/output-structure/locale-modules.js +7 -1
- package/dist/compiler/output-structure/locale-modules.js.map +1 -1
- package/dist/compiler/output-structure/locale-modules.test.js +35 -0
- package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +6 -4
- package/dist/compiler/output-structure/message-modules.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.test.js +35 -0
- package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
- package/dist/compiler/registry.d.ts +12 -0
- package/dist/compiler/registry.js +158 -31
- package/dist/compiler/registry.js.map +1 -1
- package/dist/compiler/registry.test.d.ts +1 -0
- package/dist/compiler/registry.test.js +291 -0
- package/dist/compiler/registry.test.js.map +1 -0
- package/dist/compiler/runtime/create-runtime.d.ts +2 -0
- package/dist/compiler/runtime/create-runtime.js +9 -0
- package/dist/compiler/runtime/create-runtime.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js +8 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js +26 -0
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.js +47 -5
- package/dist/compiler/runtime/extract-locale-from-header.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.test.js +58 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.js.map +1 -1
- package/dist/compiler/runtime/get-locale.js +7 -1
- package/dist/compiler/runtime/get-locale.js.map +1 -1
- package/dist/compiler/runtime/get-locale.test.js +95 -0
- package/dist/compiler/runtime/get-locale.test.js.map +1 -1
- package/dist/compiler/runtime/localize-href.d.ts +8 -0
- package/dist/compiler/runtime/localize-href.js +60 -0
- package/dist/compiler/runtime/localize-href.js.map +1 -1
- package/dist/compiler/runtime/localize-href.test.js +227 -1
- package/dist/compiler/runtime/localize-href.test.js.map +1 -1
- package/dist/compiler/runtime/set-locale.js +24 -6
- package/dist/compiler/runtime/set-locale.js.map +1 -1
- package/dist/compiler/runtime/set-locale.test.js +182 -0
- package/dist/compiler/runtime/set-locale.test.js.map +1 -1
- package/dist/compiler/runtime/type.d.ts +2 -0
- package/dist/compiler/runtime/type.js.map +1 -1
- package/dist/compiler/runtime/type.test.js +34 -0
- package/dist/compiler/runtime/type.test.js.map +1 -1
- package/dist/compiler/runtime/variables.d.ts +2 -0
- package/dist/compiler/runtime/variables.js +7 -0
- package/dist/compiler/runtime/variables.js.map +1 -1
- package/dist/compiler/server/create-server-file.js +24 -0
- package/dist/compiler/server/create-server-file.js.map +1 -1
- package/dist/compiler/server/create-server-file.test.js +8 -2
- package/dist/compiler/server/create-server-file.test.js.map +1 -1
- package/dist/compiler/server/middleware.d.ts +8 -2
- package/dist/compiler/server/middleware.js +204 -11
- package/dist/compiler/server/middleware.js.map +1 -1
- package/dist/compiler/server/middleware.test.js +750 -3
- package/dist/compiler/server/middleware.test.js.map +1 -1
- package/dist/eslint/index.d.ts +4 -0
- package/dist/eslint/index.js +8 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.d.ts +3 -0
- package/dist/eslint/no-dynamic-message-access.js +150 -0
- package/dist/eslint/no-dynamic-message-access.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.test.d.ts +1 -0
- package/dist/eslint/no-dynamic-message-access.test.js +126 -0
- package/dist/eslint/no-dynamic-message-access.test.js.map +1 -0
- package/dist/eslint/oxlint.test.d.ts +1 -0
- package/dist/eslint/oxlint.test.js +64 -0
- package/dist/eslint/oxlint.test.js.map +1 -0
- package/dist/services/config/config-schema.d.ts +2 -0
- package/dist/services/config/config-schema.js +2 -0
- package/dist/services/config/config-schema.js.map +1 -1
- package/dist/services/config/load-paraglide-config.test.js +12 -0
- package/dist/services/config/load-paraglide-config.test.js.map +1 -1
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/env-variables/index.js.map +1 -1
- package/dist/services/file-handling/write-output.bench.js +51 -11
- package/dist/services/file-handling/write-output.bench.js.map +1 -1
- package/dist/services/file-handling/write-output.js +60 -20
- package/dist/services/file-handling/write-output.js.map +1 -1
- package/dist/services/file-handling/write-output.test.js +175 -0
- package/dist/services/file-handling/write-output.test.js.map +1 -1
- package/package.json +15 -5
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { toRelativeDisplayPath, shellArgument, } from "../utils.js";
|
|
2
|
+
import { updatePackageJson } from "./update-package-json.js";
|
|
3
|
+
/**
|
|
4
|
+
* The `@inlang/cli` range `init` adds. 3.4.0 introduced `inlang check`.
|
|
5
|
+
*/
|
|
6
|
+
export const INLANG_CLI_VERSION_RANGE = "^3.4.0";
|
|
7
|
+
export const CHECK_SCRIPT_NAME = "check:i18n";
|
|
8
|
+
/**
|
|
9
|
+
* Adds `@inlang/cli` to the devDependencies (if not present) and a
|
|
10
|
+
* `check:i18n` script that runs `inlang check` (if no script of that name
|
|
11
|
+
* exists).
|
|
12
|
+
*/
|
|
13
|
+
export const addInlangCheck = async (ctx) => {
|
|
14
|
+
const projectPath = toRelativeDisplayPath(ctx.root, ctx.projectPath);
|
|
15
|
+
let existingCli;
|
|
16
|
+
let addedCli = false;
|
|
17
|
+
let addedScript = false;
|
|
18
|
+
await updatePackageJson({
|
|
19
|
+
devDependencies: async (devDeps) => {
|
|
20
|
+
existingCli = devDeps["@inlang/cli"];
|
|
21
|
+
if (existingCli !== undefined)
|
|
22
|
+
return devDeps;
|
|
23
|
+
addedCli = true;
|
|
24
|
+
return { ...devDeps, "@inlang/cli": INLANG_CLI_VERSION_RANGE };
|
|
25
|
+
},
|
|
26
|
+
scripts: async (scripts) => {
|
|
27
|
+
if (scripts[CHECK_SCRIPT_NAME] !== undefined)
|
|
28
|
+
return scripts;
|
|
29
|
+
addedScript = true;
|
|
30
|
+
return {
|
|
31
|
+
...scripts,
|
|
32
|
+
[CHECK_SCRIPT_NAME]: `inlang check --project ${shellArgument("./" + projectPath)}`,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
})(ctx);
|
|
36
|
+
if (addedCli) {
|
|
37
|
+
ctx.logger.success(`Added @inlang/cli ${INLANG_CLI_VERSION_RANGE} to the devDependencies in package.json.`);
|
|
38
|
+
}
|
|
39
|
+
if (addedScript) {
|
|
40
|
+
ctx.logger.success(`Added a ${CHECK_SCRIPT_NAME} script that checks the translations to package.json.`);
|
|
41
|
+
}
|
|
42
|
+
if (existingCli !== undefined && mayBeOlderThan3_4(existingCli)) {
|
|
43
|
+
ctx.logger.warn(`\`inlang check\` needs @inlang/cli 3.4.0 or later. Your package.json has "${existingCli}". Update it to "${INLANG_CLI_VERSION_RANGE}".`);
|
|
44
|
+
}
|
|
45
|
+
return ctx;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Whether a version range may resolve to an `@inlang/cli` before 3.4.0,
|
|
49
|
+
* judged by the first version it names (`^3.0.0`, `3.2.0`, `~2.1.0`).
|
|
50
|
+
* Ranges without a version (`latest`, `*`, `workspace:*`) are trusted.
|
|
51
|
+
*/
|
|
52
|
+
function mayBeOlderThan3_4(range) {
|
|
53
|
+
const match = range.match(/(\d+)\.(\d+)/);
|
|
54
|
+
if (!match)
|
|
55
|
+
return false;
|
|
56
|
+
const major = Number(match[1]);
|
|
57
|
+
const minor = Number(match[2]);
|
|
58
|
+
return major < 3 || (major === 3 && minor < 4);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=add-inlang-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-inlang-check.js","sourceRoot":"","sources":["../../../src/cli/steps/add-inlang-check.ts"],"names":[],"mappings":"AACA,OAAO,EACN,qBAAqB,EACrB,aAAa,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,QAAQ,CAAC;AAEjD,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GASvB,KAAK,EAAE,GAAG,EAAE,EAAE;IACjB,MAAM,WAAW,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACrE,IAAI,WAA+B,CAAC;IACpC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,MAAM,iBAAiB,CAAC;QACvB,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAClC,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;YACrC,IAAI,WAAW,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC;YAC9C,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,CAAC;QAChE,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC1B,IAAI,OAAO,CAAC,iBAAiB,CAAC,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC;YAC7D,WAAW,GAAG,IAAI,CAAC;YACnB,OAAO;gBACN,GAAG,OAAO;gBACV,CAAC,iBAAiB,CAAC,EAAE,0BAA0B,aAAa,CAAC,IAAI,GAAG,WAAW,CAAC,EAAE;aAClF,CAAC;QACH,CAAC;KACD,CAAC,CAAC,GAAG,CAAC,CAAC;IAER,IAAI,QAAQ,EAAE,CAAC;QACd,GAAG,CAAC,MAAM,CAAC,OAAO,CACjB,qBAAqB,wBAAwB,0CAA0C,CACvF,CAAC;IACH,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QACjB,GAAG,CAAC,MAAM,CAAC,OAAO,CACjB,WAAW,iBAAiB,uDAAuD,CACnF,CAAC;IACH,CAAC;IACD,IAAI,WAAW,KAAK,SAAS,IAAI,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC;QACjE,GAAG,CAAC,MAAM,CAAC,IAAI,CACd,6EAA6E,WAAW,oBAAoB,wBAAwB,IAAI,CACxI,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACZ,CAAC,CAAC;AAEF;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC","sourcesContent":["import type { Logger } from \"../../services/logger/index.js\";\nimport {\n\ttoRelativeDisplayPath,\n\tshellArgument,\n\ttype CliStep,\n} from \"../utils.js\";\nimport { updatePackageJson } from \"./update-package-json.js\";\n\n/**\n * The `@inlang/cli` range `init` adds. 3.4.0 introduced `inlang check`.\n */\nexport const INLANG_CLI_VERSION_RANGE = \"^3.4.0\";\n\nexport const CHECK_SCRIPT_NAME = \"check:i18n\";\n\n/**\n * Adds `@inlang/cli` to the devDependencies (if not present) and a\n * `check:i18n` script that runs `inlang check` (if no script of that name\n * exists).\n */\nexport const addInlangCheck: CliStep<\n\t{\n\t\tfs: typeof import(\"node:fs/promises\");\n\t\tlogger: Logger;\n\t\tprojectPath: string;\n\t\troot: string;\n\t\tpackageJsonPath: string;\n\t},\n\tunknown\n> = async (ctx) => {\n\tconst projectPath = toRelativeDisplayPath(ctx.root, ctx.projectPath);\n\tlet existingCli: string | undefined;\n\tlet addedCli = false;\n\tlet addedScript = false;\n\n\tawait updatePackageJson({\n\t\tdevDependencies: async (devDeps) => {\n\t\t\texistingCli = devDeps[\"@inlang/cli\"];\n\t\t\tif (existingCli !== undefined) return devDeps;\n\t\t\taddedCli = true;\n\t\t\treturn { ...devDeps, \"@inlang/cli\": INLANG_CLI_VERSION_RANGE };\n\t\t},\n\t\tscripts: async (scripts) => {\n\t\t\tif (scripts[CHECK_SCRIPT_NAME] !== undefined) return scripts;\n\t\t\taddedScript = true;\n\t\t\treturn {\n\t\t\t\t...scripts,\n\t\t\t\t[CHECK_SCRIPT_NAME]: `inlang check --project ${shellArgument(\"./\" + projectPath)}`,\n\t\t\t};\n\t\t},\n\t})(ctx);\n\n\tif (addedCli) {\n\t\tctx.logger.success(\n\t\t\t`Added @inlang/cli ${INLANG_CLI_VERSION_RANGE} to the devDependencies in package.json.`\n\t\t);\n\t}\n\tif (addedScript) {\n\t\tctx.logger.success(\n\t\t\t`Added a ${CHECK_SCRIPT_NAME} script that checks the translations to package.json.`\n\t\t);\n\t}\n\tif (existingCli !== undefined && mayBeOlderThan3_4(existingCli)) {\n\t\tctx.logger.warn(\n\t\t\t`\\`inlang check\\` needs @inlang/cli 3.4.0 or later. Your package.json has \"${existingCli}\". Update it to \"${INLANG_CLI_VERSION_RANGE}\".`\n\t\t);\n\t}\n\n\treturn ctx;\n};\n\n/**\n * Whether a version range may resolve to an `@inlang/cli` before 3.4.0,\n * judged by the first version it names (`^3.0.0`, `3.2.0`, `~2.1.0`).\n * Ranges without a version (`latest`, `*`, `workspace:*`) are trusted.\n */\nfunction mayBeOlderThan3_4(range: string): boolean {\n\tconst match = range.match(/(\\d+)\\.(\\d+)/);\n\tif (!match) return false;\n\tconst major = Number(match[1]);\n\tconst minor = Number(match[2]);\n\treturn major < 3 || (major === 3 && minor < 4);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { afterEach, beforeEach, expect, test, vi } from "vitest";
|
|
2
|
+
import { memfs } from "memfs";
|
|
3
|
+
import { addInlangCheck } from "./add-inlang-check.js";
|
|
4
|
+
import { Logger } from "../../services/logger/index.js";
|
|
5
|
+
const originalCwd = process.cwd;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
process.cwd = (() => "/");
|
|
8
|
+
});
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
process.cwd = originalCwd;
|
|
11
|
+
});
|
|
12
|
+
async function runAddInlangCheck(packageJson) {
|
|
13
|
+
const fs = memfs({ "/package.json": JSON.stringify(packageJson, null, 2) })
|
|
14
|
+
.fs;
|
|
15
|
+
const logger = new Logger({ silent: true, prefix: false });
|
|
16
|
+
const success = vi.spyOn(logger, "success");
|
|
17
|
+
const warn = vi.spyOn(logger, "warn");
|
|
18
|
+
await addInlangCheck({
|
|
19
|
+
fs: fs.promises,
|
|
20
|
+
logger,
|
|
21
|
+
projectPath: "./project.inlang",
|
|
22
|
+
root: "/",
|
|
23
|
+
packageJsonPath: "/package.json",
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
pkg: JSON.parse(await fs.promises.readFile("/package.json", "utf-8")),
|
|
27
|
+
logged: success.mock.calls.map(([message]) => message),
|
|
28
|
+
warned: warn.mock.calls.map(([message]) => String(message)),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
test("adds @inlang/cli and a check:i18n script", async () => {
|
|
32
|
+
const { pkg, logged, warned } = await runAddInlangCheck({
|
|
33
|
+
scripts: { build: "vite build" },
|
|
34
|
+
devDependencies: { vite: "^6.0.0" },
|
|
35
|
+
});
|
|
36
|
+
expect(pkg.devDependencies).toEqual({
|
|
37
|
+
vite: "^6.0.0",
|
|
38
|
+
"@inlang/cli": "^3.4.0",
|
|
39
|
+
});
|
|
40
|
+
expect(pkg.scripts).toEqual({
|
|
41
|
+
build: "vite build",
|
|
42
|
+
"check:i18n": "inlang check --project ./project.inlang",
|
|
43
|
+
});
|
|
44
|
+
expect(logged).toHaveLength(2);
|
|
45
|
+
expect(warned).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
test("adds devDependencies and scripts to a package.json without them", async () => {
|
|
48
|
+
const { pkg } = await runAddInlangCheck({ name: "app" });
|
|
49
|
+
expect(pkg.devDependencies).toEqual({ "@inlang/cli": "^3.4.0" });
|
|
50
|
+
expect(pkg.scripts).toEqual({
|
|
51
|
+
"check:i18n": "inlang check --project ./project.inlang",
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
test("keeps an existing @inlang/cli version and check:i18n script", async () => {
|
|
55
|
+
const { pkg, logged, warned } = await runAddInlangCheck({
|
|
56
|
+
scripts: { "check:i18n": "my-own-check" },
|
|
57
|
+
devDependencies: { "@inlang/cli": "3.5.0" },
|
|
58
|
+
});
|
|
59
|
+
expect(pkg.devDependencies).toEqual({ "@inlang/cli": "3.5.0" });
|
|
60
|
+
expect(pkg.scripts).toEqual({ "check:i18n": "my-own-check" });
|
|
61
|
+
expect(logged).toEqual([]);
|
|
62
|
+
expect(warned).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
test("adds only the script when @inlang/cli is present, and warns about a CLI before 3.4.0", async () => {
|
|
65
|
+
const { pkg, logged, warned } = await runAddInlangCheck({
|
|
66
|
+
devDependencies: { "@inlang/cli": "3.2.0" },
|
|
67
|
+
});
|
|
68
|
+
expect(pkg.devDependencies).toEqual({ "@inlang/cli": "3.2.0" });
|
|
69
|
+
expect(pkg.scripts).toEqual({
|
|
70
|
+
"check:i18n": "inlang check --project ./project.inlang",
|
|
71
|
+
});
|
|
72
|
+
expect(logged).toEqual([
|
|
73
|
+
"Added a check:i18n script that checks the translations to package.json.",
|
|
74
|
+
]);
|
|
75
|
+
expect(warned).toHaveLength(1);
|
|
76
|
+
expect(warned[0]).toContain("needs @inlang/cli 3.4.0 or later");
|
|
77
|
+
});
|
|
78
|
+
test("adds only @inlang/cli when the check:i18n script exists", async () => {
|
|
79
|
+
const { pkg, logged } = await runAddInlangCheck({
|
|
80
|
+
scripts: { "check:i18n": "my-own-check" },
|
|
81
|
+
});
|
|
82
|
+
expect(pkg.devDependencies).toEqual({ "@inlang/cli": "^3.4.0" });
|
|
83
|
+
expect(pkg.scripts).toEqual({ "check:i18n": "my-own-check" });
|
|
84
|
+
expect(logged).toEqual([
|
|
85
|
+
"Added @inlang/cli ^3.4.0 to the devDependencies in package.json.",
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=add-inlang-check.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-inlang-check.test.js","sourceRoot":"","sources":["../../../src/cli/steps/add-inlang-check.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAExD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;AAChC,UAAU,CAAC,GAAG,EAAE;IACf,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAuB,CAAC;AACjD,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACd,OAAO,CAAC,GAAG,GAAG,WAAW,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,iBAAiB,CAAC,WAAoC;IACpE,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACzE,EAAyC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,cAAc,CAAC;QACpB,EAAE,EAAE,EAAE,CAAC,QAAQ;QACf,MAAM;QACN,WAAW,EAAE,kBAAkB;QAC/B,IAAI,EAAE,GAAG;QACT,eAAe,EAAE,eAAe;KAChC,CAAC,CAAC;IACH,OAAO;QACN,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACrE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;QACtD,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;KAC3D,CAAC;AACH,CAAC;AAED,IAAI,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;IAC3D,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC;QACvD,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE;QAChC,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACnC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC;QACnC,IAAI,EAAE,QAAQ;QACd,aAAa,EAAE,QAAQ;KACvB,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QAC3B,KAAK,EAAE,YAAY;QACnB,YAAY,EAAE,yCAAyC;KACvD,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;IAClF,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,iBAAiB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEzD,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QAC3B,YAAY,EAAE,yCAAyC;KACvD,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;IAC9E,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC;QACvD,OAAO,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE;QACzC,eAAe,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE;KAC3C,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC,CAAC;IAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;IACvG,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC;QACvD,eAAe,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE;KAC3C,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QAC3B,YAAY,EAAE,yCAAyC;KACvD,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;QACtB,yEAAyE;KACzE,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;AACjE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;IAC1E,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,iBAAiB,CAAC;QAC/C,OAAO,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE;KACzC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC,CAAC;IAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;QACtB,kEAAkE;KAClE,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, beforeEach, expect, test, vi } from \"vitest\";\nimport { memfs } from \"memfs\";\nimport { addInlangCheck } from \"./add-inlang-check.js\";\nimport { Logger } from \"../../services/logger/index.js\";\n\nconst originalCwd = process.cwd;\nbeforeEach(() => {\n\tprocess.cwd = (() => \"/\") as typeof process.cwd;\n});\nafterEach(() => {\n\tprocess.cwd = originalCwd;\n});\n\nasync function runAddInlangCheck(packageJson: Record<string, unknown>) {\n\tconst fs = memfs({ \"/package.json\": JSON.stringify(packageJson, null, 2) })\n\t\t.fs as unknown as typeof import(\"node:fs\");\n\tconst logger = new Logger({ silent: true, prefix: false });\n\tconst success = vi.spyOn(logger, \"success\");\n\tconst warn = vi.spyOn(logger, \"warn\");\n\tawait addInlangCheck({\n\t\tfs: fs.promises,\n\t\tlogger,\n\t\tprojectPath: \"./project.inlang\",\n\t\troot: \"/\",\n\t\tpackageJsonPath: \"/package.json\",\n\t});\n\treturn {\n\t\tpkg: JSON.parse(await fs.promises.readFile(\"/package.json\", \"utf-8\")),\n\t\tlogged: success.mock.calls.map(([message]) => message),\n\t\twarned: warn.mock.calls.map(([message]) => String(message)),\n\t};\n}\n\ntest(\"adds @inlang/cli and a check:i18n script\", async () => {\n\tconst { pkg, logged, warned } = await runAddInlangCheck({\n\t\tscripts: { build: \"vite build\" },\n\t\tdevDependencies: { vite: \"^6.0.0\" },\n\t});\n\n\texpect(pkg.devDependencies).toEqual({\n\t\tvite: \"^6.0.0\",\n\t\t\"@inlang/cli\": \"^3.4.0\",\n\t});\n\texpect(pkg.scripts).toEqual({\n\t\tbuild: \"vite build\",\n\t\t\"check:i18n\": \"inlang check --project ./project.inlang\",\n\t});\n\texpect(logged).toHaveLength(2);\n\texpect(warned).toEqual([]);\n});\n\ntest(\"adds devDependencies and scripts to a package.json without them\", async () => {\n\tconst { pkg } = await runAddInlangCheck({ name: \"app\" });\n\n\texpect(pkg.devDependencies).toEqual({ \"@inlang/cli\": \"^3.4.0\" });\n\texpect(pkg.scripts).toEqual({\n\t\t\"check:i18n\": \"inlang check --project ./project.inlang\",\n\t});\n});\n\ntest(\"keeps an existing @inlang/cli version and check:i18n script\", async () => {\n\tconst { pkg, logged, warned } = await runAddInlangCheck({\n\t\tscripts: { \"check:i18n\": \"my-own-check\" },\n\t\tdevDependencies: { \"@inlang/cli\": \"3.5.0\" },\n\t});\n\n\texpect(pkg.devDependencies).toEqual({ \"@inlang/cli\": \"3.5.0\" });\n\texpect(pkg.scripts).toEqual({ \"check:i18n\": \"my-own-check\" });\n\texpect(logged).toEqual([]);\n\texpect(warned).toEqual([]);\n});\n\ntest(\"adds only the script when @inlang/cli is present, and warns about a CLI before 3.4.0\", async () => {\n\tconst { pkg, logged, warned } = await runAddInlangCheck({\n\t\tdevDependencies: { \"@inlang/cli\": \"3.2.0\" },\n\t});\n\n\texpect(pkg.devDependencies).toEqual({ \"@inlang/cli\": \"3.2.0\" });\n\texpect(pkg.scripts).toEqual({\n\t\t\"check:i18n\": \"inlang check --project ./project.inlang\",\n\t});\n\texpect(logged).toEqual([\n\t\t\"Added a check:i18n script that checks the translations to package.json.\",\n\t]);\n\texpect(warned).toHaveLength(1);\n\texpect(warned[0]).toContain(\"needs @inlang/cli 3.4.0 or later\");\n});\n\ntest(\"adds only @inlang/cli when the check:i18n script exists\", async () => {\n\tconst { pkg, logged } = await runAddInlangCheck({\n\t\tscripts: { \"check:i18n\": \"my-own-check\" },\n\t});\n\n\texpect(pkg.devDependencies).toEqual({ \"@inlang/cli\": \"^3.4.0\" });\n\texpect(pkg.scripts).toEqual({ \"check:i18n\": \"my-own-check\" });\n\texpect(logged).toEqual([\n\t\t\"Added @inlang/cli ^3.4.0 to the devDependencies in package.json.\",\n\t]);\n});\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type fs from "node:fs/promises";
|
|
2
|
+
import type { Logger } from "../../services/logger/index.js";
|
|
3
|
+
export type MessageLint = "none" | "eslint" | "oxlint";
|
|
4
|
+
export declare function chooseMessageLint(ctx: {
|
|
5
|
+
interactive: boolean;
|
|
6
|
+
lint?: MessageLint;
|
|
7
|
+
}): Promise<MessageLint>;
|
|
8
|
+
export declare function messageLintConfig(lint: Exclude<MessageLint, "none">, outdir: string): {
|
|
9
|
+
filename: string;
|
|
10
|
+
source: string;
|
|
11
|
+
command: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function preflightMessageLint(ctx: {
|
|
14
|
+
fs: typeof fs;
|
|
15
|
+
root: string;
|
|
16
|
+
packageJsonPath: string;
|
|
17
|
+
outdir: string;
|
|
18
|
+
lint: MessageLint;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
export declare function addMessageLint(ctx: {
|
|
21
|
+
fs: typeof fs;
|
|
22
|
+
root: string;
|
|
23
|
+
packageJsonPath: string;
|
|
24
|
+
outdir: string;
|
|
25
|
+
logger: Logger;
|
|
26
|
+
lint: MessageLint;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
fs: typeof fs;
|
|
29
|
+
root: string;
|
|
30
|
+
packageJsonPath: string;
|
|
31
|
+
outdir: string;
|
|
32
|
+
logger: Logger;
|
|
33
|
+
lint: MessageLint;
|
|
34
|
+
}>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import nodePath from "node:path";
|
|
2
|
+
import { promptSelection } from "../utils.js";
|
|
3
|
+
import { updatePackageJson } from "./update-package-json.js";
|
|
4
|
+
export async function chooseMessageLint(ctx) {
|
|
5
|
+
if (ctx.lint)
|
|
6
|
+
return ctx.lint;
|
|
7
|
+
if (!ctx.interactive)
|
|
8
|
+
return "none";
|
|
9
|
+
return promptSelection("Set up linting to guard message tree-shaking?", {
|
|
10
|
+
initial: "none",
|
|
11
|
+
options: [
|
|
12
|
+
{ label: "Skip", value: "none" },
|
|
13
|
+
{ label: "ESLint", value: "eslint" },
|
|
14
|
+
{ label: "Oxlint", value: "oxlint" },
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export function messageLintConfig(lint, outdir) {
|
|
19
|
+
const directory = nodePath.basename(outdir);
|
|
20
|
+
const rule = ["error", { messageModuleDirectories: [directory] }];
|
|
21
|
+
if (lint === "oxlint")
|
|
22
|
+
return {
|
|
23
|
+
filename: ".oxlintrc.paraglide.json",
|
|
24
|
+
source: JSON.stringify({
|
|
25
|
+
plugins: [],
|
|
26
|
+
jsPlugins: [
|
|
27
|
+
{ name: "paraglide", specifier: "@inlang/paraglide-js/eslint" },
|
|
28
|
+
],
|
|
29
|
+
ignorePatterns: [outdir.replace(/^\.\//, "") + "/**"],
|
|
30
|
+
rules: { "paraglide/no-dynamic-message-access": rule },
|
|
31
|
+
}, null, 2) + "\n",
|
|
32
|
+
command: "oxlint --config ./.oxlintrc.paraglide.json .",
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
filename: "eslint.paraglide.config.mjs",
|
|
36
|
+
source: `import paraglide from "@inlang/paraglide-js/eslint";
|
|
37
|
+
import tsParser from "@typescript-eslint/parser";
|
|
38
|
+
|
|
39
|
+
export default [
|
|
40
|
+
{ ignores: [${JSON.stringify(outdir.replace(/^\.\//, "") + "/**")}, "node_modules/**"] },
|
|
41
|
+
{
|
|
42
|
+
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],
|
|
43
|
+
languageOptions: { parser: tsParser, parserOptions: { ecmaFeatures: { jsx: true } } },
|
|
44
|
+
plugins: { paraglide },
|
|
45
|
+
rules: { "paraglide/no-dynamic-message-access": ${JSON.stringify(rule)} },
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
`,
|
|
49
|
+
command: "eslint --config ./eslint.paraglide.config.mjs .",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export async function preflightMessageLint(ctx) {
|
|
53
|
+
if (ctx.lint === "none")
|
|
54
|
+
return;
|
|
55
|
+
const config = messageLintConfig(ctx.lint, ctx.outdir);
|
|
56
|
+
const pkg = JSON.parse(await ctx.fs.readFile(ctx.packageJsonPath, "utf8"));
|
|
57
|
+
if (pkg.scripts?.["lint:i18n"] && pkg.scripts["lint:i18n"] !== config.command)
|
|
58
|
+
throw new Error("An unrelated lint:i18n script exists. Rename it before setting up message linting.");
|
|
59
|
+
const existing = await ctx.fs
|
|
60
|
+
.readFile(nodePath.join(ctx.root, config.filename), "utf8")
|
|
61
|
+
.catch((error) => {
|
|
62
|
+
if (error.code === "ENOENT")
|
|
63
|
+
return undefined;
|
|
64
|
+
throw error;
|
|
65
|
+
});
|
|
66
|
+
if (existing !== undefined && existing !== config.source)
|
|
67
|
+
throw new Error(`${config.filename} already exists with different content; it will not be overwritten.`);
|
|
68
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
69
|
+
const parserMajor = String(deps["@typescript-eslint/parser"] ?? "").match(/^(?:[~^]|>=)?(\d+)/)?.[1];
|
|
70
|
+
if (ctx.lint === "eslint" && parserMajor && Number(parserMajor) < 8)
|
|
71
|
+
throw new Error("Message lint setup requires @typescript-eslint/parser 8 or later. Update the existing dependency first.");
|
|
72
|
+
const major = String(deps.eslint ?? "").match(/^(?:[~^]|>=)?(\d+)/)?.[1];
|
|
73
|
+
if (ctx.lint === "eslint" && major && Number(major) < 9)
|
|
74
|
+
throw new Error("Message linting requires ESLint 9 or 10. Update the existing ESLint dependency first.");
|
|
75
|
+
const oxVersion = String(deps.oxlint ?? "").match(/^(?:[~^]|>=)?(\d+)\.(\d+)/);
|
|
76
|
+
if (ctx.lint === "oxlint" &&
|
|
77
|
+
oxVersion &&
|
|
78
|
+
Number(oxVersion[1]) === 1 &&
|
|
79
|
+
Number(oxVersion[2]) < 88)
|
|
80
|
+
throw new Error("Message lint setup requires Oxlint 1.88 or later. Update the existing dependency first.");
|
|
81
|
+
}
|
|
82
|
+
export async function addMessageLint(ctx) {
|
|
83
|
+
if (ctx.lint === "none")
|
|
84
|
+
return ctx;
|
|
85
|
+
await preflightMessageLint(ctx);
|
|
86
|
+
const config = messageLintConfig(ctx.lint, ctx.outdir);
|
|
87
|
+
await ctx.fs.writeFile(nodePath.join(ctx.root, config.filename), config.source);
|
|
88
|
+
await updatePackageJson({
|
|
89
|
+
devDependencies: async (deps) => {
|
|
90
|
+
const pkg = JSON.parse(await ctx.fs.readFile(ctx.packageJsonPath, "utf8"));
|
|
91
|
+
const known = { ...pkg.dependencies, ...deps };
|
|
92
|
+
const needed = ctx.lint === "eslint"
|
|
93
|
+
? { eslint: "^9.39.2", "@typescript-eslint/parser": "^8.71.2" }
|
|
94
|
+
: { oxlint: "^1.88.0" };
|
|
95
|
+
return {
|
|
96
|
+
...deps,
|
|
97
|
+
...Object.fromEntries(Object.entries(needed).filter(([name]) => !known[name])),
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
scripts: async (scripts) => ({ ...scripts, "lint:i18n": config.command }),
|
|
101
|
+
})(ctx);
|
|
102
|
+
ctx.logger.success(`Added ${ctx.lint} message linting. After installing dependencies, run npm run lint:i18n. Existing lint configurations are unchanged.`);
|
|
103
|
+
return ctx;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=add-message-lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-message-lint.js","sourceRoot":"","sources":["../../../src/cli/steps/add-message-lint.ts"],"names":[],"mappings":"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","sourcesContent":["import type fs from \"node:fs/promises\";\nimport nodePath from \"node:path\";\nimport { promptSelection } from \"../utils.js\";\nimport type { Logger } from \"../../services/logger/index.js\";\nimport { updatePackageJson } from \"./update-package-json.js\";\n\nexport type MessageLint = \"none\" | \"eslint\" | \"oxlint\";\nexport async function chooseMessageLint(ctx: {\n\tinteractive: boolean;\n\tlint?: MessageLint;\n}): Promise<MessageLint> {\n\tif (ctx.lint) return ctx.lint;\n\tif (!ctx.interactive) return \"none\";\n\treturn promptSelection(\"Set up linting to guard message tree-shaking?\", {\n\t\tinitial: \"none\",\n\t\toptions: [\n\t\t\t{ label: \"Skip\", value: \"none\" },\n\t\t\t{ label: \"ESLint\", value: \"eslint\" },\n\t\t\t{ label: \"Oxlint\", value: \"oxlint\" },\n\t\t],\n\t});\n}\n\nexport function messageLintConfig(\n\tlint: Exclude<MessageLint, \"none\">,\n\toutdir: string\n): { filename: string; source: string; command: string } {\n\tconst directory = nodePath.basename(outdir);\n\tconst rule = [\"error\", { messageModuleDirectories: [directory] }];\n\tif (lint === \"oxlint\")\n\t\treturn {\n\t\t\tfilename: \".oxlintrc.paraglide.json\",\n\t\t\tsource:\n\t\t\t\tJSON.stringify(\n\t\t\t\t\t{\n\t\t\t\t\t\tplugins: [],\n\t\t\t\t\t\tjsPlugins: [\n\t\t\t\t\t\t\t{ name: \"paraglide\", specifier: \"@inlang/paraglide-js/eslint\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t\tignorePatterns: [outdir.replace(/^\\.\\//, \"\") + \"/**\"],\n\t\t\t\t\t\trules: { \"paraglide/no-dynamic-message-access\": rule },\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2\n\t\t\t\t) + \"\\n\",\n\t\t\tcommand: \"oxlint --config ./.oxlintrc.paraglide.json .\",\n\t\t};\n\treturn {\n\t\tfilename: \"eslint.paraglide.config.mjs\",\n\t\tsource: `import paraglide from \"@inlang/paraglide-js/eslint\";\nimport tsParser from \"@typescript-eslint/parser\";\n\nexport default [\n { ignores: [${JSON.stringify(outdir.replace(/^\\.\\//, \"\") + \"/**\")}, \"node_modules/**\"] },\n {\n files: [\"**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}\"],\n languageOptions: { parser: tsParser, parserOptions: { ecmaFeatures: { jsx: true } } },\n plugins: { paraglide },\n rules: { \"paraglide/no-dynamic-message-access\": ${JSON.stringify(rule)} },\n },\n];\n`,\n\t\tcommand: \"eslint --config ./eslint.paraglide.config.mjs .\",\n\t};\n}\n\nexport async function preflightMessageLint(ctx: {\n\tfs: typeof fs;\n\troot: string;\n\tpackageJsonPath: string;\n\toutdir: string;\n\tlint: MessageLint;\n}) {\n\tif (ctx.lint === \"none\") return;\n\tconst config = messageLintConfig(ctx.lint, ctx.outdir);\n\tconst pkg = JSON.parse(await ctx.fs.readFile(ctx.packageJsonPath, \"utf8\"));\n\tif (pkg.scripts?.[\"lint:i18n\"] && pkg.scripts[\"lint:i18n\"] !== config.command)\n\t\tthrow new Error(\n\t\t\t\"An unrelated lint:i18n script exists. Rename it before setting up message linting.\"\n\t\t);\n\tconst existing = await ctx.fs\n\t\t.readFile(nodePath.join(ctx.root, config.filename), \"utf8\")\n\t\t.catch((error: NodeJS.ErrnoException) => {\n\t\t\tif (error.code === \"ENOENT\") return undefined;\n\t\t\tthrow error;\n\t\t});\n\tif (existing !== undefined && existing !== config.source)\n\t\tthrow new Error(\n\t\t\t`${config.filename} already exists with different content; it will not be overwritten.`\n\t\t);\n\tconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\tconst parserMajor = String(deps[\"@typescript-eslint/parser\"] ?? \"\").match(\n\t\t/^(?:[~^]|>=)?(\\d+)/\n\t)?.[1];\n\tif (ctx.lint === \"eslint\" && parserMajor && Number(parserMajor) < 8)\n\t\tthrow new Error(\n\t\t\t\"Message lint setup requires @typescript-eslint/parser 8 or later. Update the existing dependency first.\"\n\t\t);\n\tconst major = String(deps.eslint ?? \"\").match(/^(?:[~^]|>=)?(\\d+)/)?.[1];\n\tif (ctx.lint === \"eslint\" && major && Number(major) < 9)\n\t\tthrow new Error(\n\t\t\t\"Message linting requires ESLint 9 or 10. Update the existing ESLint dependency first.\"\n\t\t);\n\tconst oxVersion = String(deps.oxlint ?? \"\").match(\n\t\t/^(?:[~^]|>=)?(\\d+)\\.(\\d+)/\n\t);\n\tif (\n\t\tctx.lint === \"oxlint\" &&\n\t\toxVersion &&\n\t\tNumber(oxVersion[1]) === 1 &&\n\t\tNumber(oxVersion[2]) < 88\n\t)\n\t\tthrow new Error(\n\t\t\t\"Message lint setup requires Oxlint 1.88 or later. Update the existing dependency first.\"\n\t\t);\n}\n\nexport async function addMessageLint(ctx: {\n\tfs: typeof fs;\n\troot: string;\n\tpackageJsonPath: string;\n\toutdir: string;\n\tlogger: Logger;\n\tlint: MessageLint;\n}) {\n\tif (ctx.lint === \"none\") return ctx;\n\tawait preflightMessageLint(ctx);\n\tconst config = messageLintConfig(ctx.lint, ctx.outdir);\n\tawait ctx.fs.writeFile(\n\t\tnodePath.join(ctx.root, config.filename),\n\t\tconfig.source\n\t);\n\tawait updatePackageJson({\n\t\tdevDependencies: async (deps) => {\n\t\t\tconst pkg = JSON.parse(\n\t\t\t\tawait ctx.fs.readFile(ctx.packageJsonPath, \"utf8\")\n\t\t\t);\n\t\t\tconst known = { ...pkg.dependencies, ...deps };\n\t\t\tconst needed =\n\t\t\t\tctx.lint === \"eslint\"\n\t\t\t\t\t? { eslint: \"^9.39.2\", \"@typescript-eslint/parser\": \"^8.71.2\" }\n\t\t\t\t\t: { oxlint: \"^1.88.0\" };\n\t\t\treturn {\n\t\t\t\t...deps,\n\t\t\t\t...Object.fromEntries(\n\t\t\t\t\tObject.entries(needed).filter(([name]) => !known[name])\n\t\t\t\t),\n\t\t\t};\n\t\t},\n\t\tscripts: async (scripts) => ({ ...scripts, \"lint:i18n\": config.command }),\n\t})(ctx);\n\tctx.logger.success(\n\t\t`Added ${ctx.lint} message linting. After installing dependencies, run npm run lint:i18n. Existing lint configurations are unchanged.`\n\t);\n\treturn ctx;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { test, expect } from "vitest";
|
|
2
|
+
import { mkdtemp, writeFile, readFile, rm } from "node:fs/promises";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { addMessageLint, preflightMessageLint } from "./add-message-lint.js";
|
|
7
|
+
import { Logger } from "../../services/logger/index.js";
|
|
8
|
+
for (const lint of ["eslint", "oxlint"])
|
|
9
|
+
test(`${lint} setup is optional, additive and repeatable`, async () => {
|
|
10
|
+
const root = await mkdtemp(join(tmpdir(), "paraglide-lint-init-"));
|
|
11
|
+
try {
|
|
12
|
+
const packageJsonPath = join(root, "package.json");
|
|
13
|
+
const configPath = join(root, lint === "eslint" ? "eslint.config.mjs" : ".oxlintrc.json");
|
|
14
|
+
const original = "// existing config sentinel\n";
|
|
15
|
+
await writeFile(configPath, original);
|
|
16
|
+
await writeFile(packageJsonPath, JSON.stringify({
|
|
17
|
+
scripts: { lint: "existing-lint" },
|
|
18
|
+
devDependencies: lint === "eslint" ? { eslint: "^10.0.0" } : { oxlint: "^1.88.0" },
|
|
19
|
+
}));
|
|
20
|
+
const ctx = {
|
|
21
|
+
fs,
|
|
22
|
+
root,
|
|
23
|
+
packageJsonPath,
|
|
24
|
+
outdir: "./src/i18n",
|
|
25
|
+
lint,
|
|
26
|
+
logger: new Logger({ silent: true, prefix: false }),
|
|
27
|
+
};
|
|
28
|
+
await addMessageLint(ctx);
|
|
29
|
+
const first = await readFile(packageJsonPath, "utf8");
|
|
30
|
+
await addMessageLint(ctx);
|
|
31
|
+
expect(await readFile(packageJsonPath, "utf8")).toBe(first);
|
|
32
|
+
expect(await readFile(configPath, "utf8")).toBe(original);
|
|
33
|
+
const pkg = JSON.parse(first);
|
|
34
|
+
expect(pkg.scripts.lint).toBe("existing-lint");
|
|
35
|
+
expect(pkg.scripts["lint:i18n"]).toContain(lint === "eslint"
|
|
36
|
+
? "eslint.paraglide.config.mjs"
|
|
37
|
+
: ".oxlintrc.paraglide.json");
|
|
38
|
+
expect(pkg.devDependencies[lint]).toBe(lint === "eslint" ? "^10.0.0" : "^1.88.0");
|
|
39
|
+
const generated = await readFile(join(root, lint === "eslint"
|
|
40
|
+
? "eslint.paraglide.config.mjs"
|
|
41
|
+
: ".oxlintrc.paraglide.json"), "utf8");
|
|
42
|
+
expect(generated).toContain("messageModuleDirectories");
|
|
43
|
+
expect(generated).toContain("i18n");
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await rm(root, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
test("lint conflicts fail before writing dependencies or replacing files", async () => {
|
|
50
|
+
const root = await mkdtemp(join(tmpdir(), "paraglide-lint-conflict-"));
|
|
51
|
+
try {
|
|
52
|
+
const packageJsonPath = join(root, "package.json");
|
|
53
|
+
const before = JSON.stringify({ scripts: { "lint:i18n": "custom-tool" } });
|
|
54
|
+
await writeFile(packageJsonPath, before);
|
|
55
|
+
const ctx = {
|
|
56
|
+
fs,
|
|
57
|
+
root,
|
|
58
|
+
packageJsonPath,
|
|
59
|
+
outdir: "./src/paraglide",
|
|
60
|
+
lint: "eslint",
|
|
61
|
+
logger: new Logger({ silent: true, prefix: false }),
|
|
62
|
+
};
|
|
63
|
+
await expect(preflightMessageLint(ctx)).rejects.toThrow("unrelated lint:i18n");
|
|
64
|
+
expect(await readFile(packageJsonPath, "utf8")).toBe(before);
|
|
65
|
+
await writeFile(packageJsonPath, "{}");
|
|
66
|
+
await writeFile(join(root, "eslint.paraglide.config.mjs"), "custom sentinel");
|
|
67
|
+
await expect(addMessageLint(ctx)).rejects.toThrow("not be overwritten");
|
|
68
|
+
expect(await readFile(join(root, "eslint.paraglide.config.mjs"), "utf8")).toBe("custom sentinel");
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await rm(root, { recursive: true, force: true });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=add-message-lint.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-message-lint.test.js","sourceRoot":"","sources":["../../../src/cli/steps/add-message-lint.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { test, expect } from \"vitest\";\nimport { mkdtemp, writeFile, readFile, rm } from \"node:fs/promises\";\nimport fs from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { addMessageLint, preflightMessageLint } from \"./add-message-lint.js\";\nimport { Logger } from \"../../services/logger/index.js\";\n\nfor (const lint of [\"eslint\", \"oxlint\"] as const)\n\ttest(`${lint} setup is optional, additive and repeatable`, async () => {\n\t\tconst root = await mkdtemp(join(tmpdir(), \"paraglide-lint-init-\"));\n\t\ttry {\n\t\t\tconst packageJsonPath = join(root, \"package.json\");\n\t\t\tconst configPath = join(\n\t\t\t\troot,\n\t\t\t\tlint === \"eslint\" ? \"eslint.config.mjs\" : \".oxlintrc.json\"\n\t\t\t);\n\t\t\tconst original = \"// existing config sentinel\\n\";\n\t\t\tawait writeFile(configPath, original);\n\t\t\tawait writeFile(\n\t\t\t\tpackageJsonPath,\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tscripts: { lint: \"existing-lint\" },\n\t\t\t\t\tdevDependencies:\n\t\t\t\t\t\tlint === \"eslint\" ? { eslint: \"^10.0.0\" } : { oxlint: \"^1.88.0\" },\n\t\t\t\t})\n\t\t\t);\n\t\t\tconst ctx = {\n\t\t\t\tfs,\n\t\t\t\troot,\n\t\t\t\tpackageJsonPath,\n\t\t\t\toutdir: \"./src/i18n\",\n\t\t\t\tlint,\n\t\t\t\tlogger: new Logger({ silent: true, prefix: false }),\n\t\t\t};\n\t\t\tawait addMessageLint(ctx);\n\t\t\tconst first = await readFile(packageJsonPath, \"utf8\");\n\t\t\tawait addMessageLint(ctx);\n\t\t\texpect(await readFile(packageJsonPath, \"utf8\")).toBe(first);\n\t\t\texpect(await readFile(configPath, \"utf8\")).toBe(original);\n\t\t\tconst pkg = JSON.parse(first);\n\t\t\texpect(pkg.scripts.lint).toBe(\"existing-lint\");\n\t\t\texpect(pkg.scripts[\"lint:i18n\"]).toContain(\n\t\t\t\tlint === \"eslint\"\n\t\t\t\t\t? \"eslint.paraglide.config.mjs\"\n\t\t\t\t\t: \".oxlintrc.paraglide.json\"\n\t\t\t);\n\t\t\texpect(pkg.devDependencies[lint]).toBe(\n\t\t\t\tlint === \"eslint\" ? \"^10.0.0\" : \"^1.88.0\"\n\t\t\t);\n\t\t\tconst generated = await readFile(\n\t\t\t\tjoin(\n\t\t\t\t\troot,\n\t\t\t\t\tlint === \"eslint\"\n\t\t\t\t\t\t? \"eslint.paraglide.config.mjs\"\n\t\t\t\t\t\t: \".oxlintrc.paraglide.json\"\n\t\t\t\t),\n\t\t\t\t\"utf8\"\n\t\t\t);\n\t\t\texpect(generated).toContain(\"messageModuleDirectories\");\n\t\t\texpect(generated).toContain(\"i18n\");\n\t\t} finally {\n\t\t\tawait rm(root, { recursive: true, force: true });\n\t\t}\n\t});\n\ntest(\"lint conflicts fail before writing dependencies or replacing files\", async () => {\n\tconst root = await mkdtemp(join(tmpdir(), \"paraglide-lint-conflict-\"));\n\ttry {\n\t\tconst packageJsonPath = join(root, \"package.json\");\n\t\tconst before = JSON.stringify({ scripts: { \"lint:i18n\": \"custom-tool\" } });\n\t\tawait writeFile(packageJsonPath, before);\n\t\tconst ctx = {\n\t\t\tfs,\n\t\t\troot,\n\t\t\tpackageJsonPath,\n\t\t\toutdir: \"./src/paraglide\",\n\t\t\tlint: \"eslint\" as const,\n\t\t\tlogger: new Logger({ silent: true, prefix: false }),\n\t\t};\n\t\tawait expect(preflightMessageLint(ctx)).rejects.toThrow(\n\t\t\t\"unrelated lint:i18n\"\n\t\t);\n\t\texpect(await readFile(packageJsonPath, \"utf8\")).toBe(before);\n\t\tawait writeFile(packageJsonPath, \"{}\");\n\t\tawait writeFile(\n\t\t\tjoin(root, \"eslint.paraglide.config.mjs\"),\n\t\t\t\"custom sentinel\"\n\t\t);\n\t\tawait expect(addMessageLint(ctx)).rejects.toThrow(\"not be overwritten\");\n\t\texpect(\n\t\t\tawait readFile(join(root, \"eslint.paraglide.config.mjs\"), \"utf8\")\n\t\t).toBe(\"custom sentinel\");\n\t} finally {\n\t\tawait rm(root, { recursive: true, force: true });\n\t}\n});\n"]}
|
|
@@ -7,3 +7,21 @@ export declare const addVitePlugin: CliStep<{
|
|
|
7
7
|
logger?: Logger;
|
|
8
8
|
configPath: string;
|
|
9
9
|
}, unknown>;
|
|
10
|
+
type UpdateResult = {
|
|
11
|
+
ok: true;
|
|
12
|
+
updated: string;
|
|
13
|
+
reason?: undefined;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
reason: string;
|
|
17
|
+
updated?: undefined;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* @private Only exported for testings
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateViteConfig(args: {
|
|
23
|
+
config: string;
|
|
24
|
+
projectPath: string;
|
|
25
|
+
outdir: string;
|
|
26
|
+
}): UpdateResult;
|
|
27
|
+
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import JSON5 from "json5";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
export const addVitePlugin = async (ctx) => {
|
|
2
4
|
try {
|
|
3
5
|
const fileContent = await ctx.fs.readFile(ctx.configPath, {
|
|
@@ -8,6 +10,8 @@ export const addVitePlugin = async (ctx) => {
|
|
|
8
10
|
projectPath: ctx.projectPath,
|
|
9
11
|
outdir: ctx.outdir,
|
|
10
12
|
});
|
|
13
|
+
if (result.reason === "Already present")
|
|
14
|
+
return ctx;
|
|
11
15
|
if (result.ok) {
|
|
12
16
|
await ctx.fs.writeFile(ctx.configPath, result.updated);
|
|
13
17
|
ctx.logger?.success("Added the Paraglide JS vite plugin to the vite config.");
|
|
@@ -32,12 +36,36 @@ export const addVitePlugin = async (ctx) => {
|
|
|
32
36
|
/**
|
|
33
37
|
* @private Only exported for testings
|
|
34
38
|
*/
|
|
35
|
-
function updateViteConfig(args) {
|
|
39
|
+
export function updateViteConfig(args) {
|
|
36
40
|
if (args.config.includes("@inlang/paraglide-js")) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
const call = args.config.match(/\bparaglideVitePlugin\s*\(\s*\{([\s\S]*?)\}\s*\)/);
|
|
42
|
+
if (!call)
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
reason: "Existing Paraglide import needs manual plugin integration",
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
const options = JSON5.parse("{" + call[1] + "}");
|
|
49
|
+
if (typeof options.project !== "string" ||
|
|
50
|
+
typeof options.outdir !== "string")
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
reason: "Existing plugin paths must be configured explicitly",
|
|
54
|
+
};
|
|
55
|
+
if (path.resolve(options.project) !== path.resolve(args.projectPath) ||
|
|
56
|
+
path.resolve(options.outdir) !== path.resolve(args.outdir))
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
reason: "Existing Vite plugin paths differ from the requested project/outdir",
|
|
60
|
+
};
|
|
61
|
+
return { ok: false, reason: "Already present" };
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
reason: "Existing Vite plugin options cannot be verified automatically",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
41
69
|
}
|
|
42
70
|
const PLUGINS_REGEX = /plugins\s*:\s*\[/g;
|
|
43
71
|
const match = PLUGINS_REGEX.exec(args.config);
|
|
@@ -52,7 +80,7 @@ function updateViteConfig(args) {
|
|
|
52
80
|
const after = args.config.slice(endIndex);
|
|
53
81
|
const updatedConfig = "import { paraglideVitePlugin } from '@inlang/paraglide-js'\n" +
|
|
54
82
|
before +
|
|
55
|
-
`paraglideVitePlugin({ project:
|
|
83
|
+
`paraglideVitePlugin({ project: ${JSON.stringify(args.projectPath)}, outdir: ${JSON.stringify(args.outdir)} }),` +
|
|
56
84
|
after;
|
|
57
85
|
return {
|
|
58
86
|
ok: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-vite-plugin.js","sourceRoot":"","sources":["../../../src/cli/steps/add-vite-plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add-vite-plugin.js","sourceRoot":"","sources":["../../../src/cli/steps/add-vite-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import JSON5 from \"json5\";\nimport path from \"node:path\";\nimport type { Logger } from \"../../services/logger/index.js\";\nimport type { CliStep } from \"../utils.js\";\n\nexport const addVitePlugin: CliStep<\n\t{\n\t\tfs: typeof import(\"node:fs/promises\");\n\t\tprojectPath: string;\n\t\toutdir: string;\n\t\tlogger?: Logger;\n\t\tconfigPath: string;\n\t},\n\tunknown\n> = async (ctx) => {\n\ttry {\n\t\tconst fileContent = await ctx.fs.readFile(ctx.configPath, {\n\t\t\tencoding: \"utf-8\",\n\t\t});\n\n\t\tconst result = updateViteConfig({\n\t\t\tconfig: fileContent,\n\t\t\tprojectPath: ctx.projectPath,\n\t\t\toutdir: ctx.outdir,\n\t\t});\n\t\tif (result.reason === \"Already present\") return ctx;\n\t\tif (result.ok) {\n\t\t\tawait ctx.fs.writeFile(ctx.configPath, result.updated);\n\t\t\tctx.logger?.success(\n\t\t\t\t\"Added the Paraglide JS vite plugin to the vite config.\"\n\t\t\t);\n\t\t} else {\n\t\t\tconst msg = [\n\t\t\t\t\"Failed to add the Paraglide JS vite plugin in vite.config.js.\",\n\t\t\t\t\"Reason: \" + result.reason,\n\t\t\t\t\"\",\n\t\t\t\t\"Please add the plugin manually.\",\n\t\t\t].join(\"\\n\");\n\n\t\t\tctx.logger?.warn(msg);\n\t\t\treturn ctx;\n\t\t}\n\t} catch {\n\t\tctx.logger?.error(\n\t\t\t`Failed to add the Paraglide JS vite plugin to ${ctx.configPath}.`\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\treturn ctx;\n};\n\ntype UpdateResult =\n\t| {\n\t\t\tok: true;\n\t\t\tupdated: string;\n\t\t\treason?: undefined;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\treason: string;\n\t\t\tupdated?: undefined;\n\t };\n\n/**\n * @private Only exported for testings\n */\nexport function updateViteConfig(args: {\n\tconfig: string;\n\tprojectPath: string;\n\toutdir: string;\n}): UpdateResult {\n\tif (args.config.includes(\"@inlang/paraglide-js\")) {\n\t\tconst call = args.config.match(\n\t\t\t/\\bparaglideVitePlugin\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)/\n\t\t);\n\t\tif (!call)\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"Existing Paraglide import needs manual plugin integration\",\n\t\t\t};\n\t\ttry {\n\t\t\tconst options = JSON5.parse(\"{\" + call[1] + \"}\");\n\t\t\tif (\n\t\t\t\ttypeof options.project !== \"string\" ||\n\t\t\t\ttypeof options.outdir !== \"string\"\n\t\t\t)\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: \"Existing plugin paths must be configured explicitly\",\n\t\t\t\t};\n\t\t\tif (\n\t\t\t\tpath.resolve(options.project) !== path.resolve(args.projectPath) ||\n\t\t\t\tpath.resolve(options.outdir) !== path.resolve(args.outdir)\n\t\t\t)\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason:\n\t\t\t\t\t\t\"Existing Vite plugin paths differ from the requested project/outdir\",\n\t\t\t\t};\n\t\t\treturn { ok: false, reason: \"Already present\" };\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"Existing Vite plugin options cannot be verified automatically\",\n\t\t\t};\n\t\t}\n\t}\n\n\tconst PLUGINS_REGEX = /plugins\\s*:\\s*\\[/g;\n\tconst match = PLUGINS_REGEX.exec(args.config);\n\n\tif (!match) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"Could not find the plugins array\",\n\t\t};\n\t}\n\n\tconst endIndex = match.index + match[0].length;\n\tconst before = args.config.slice(0, endIndex);\n\tconst after = args.config.slice(endIndex);\n\n\tconst updatedConfig =\n\t\t\"import { paraglideVitePlugin } from '@inlang/paraglide-js'\\n\" +\n\t\tbefore +\n\t\t`paraglideVitePlugin({ project: ${JSON.stringify(args.projectPath)}, outdir: ${JSON.stringify(args.outdir)} }),` +\n\t\tafter;\n\n\treturn {\n\t\tok: true,\n\t\tupdated: updatedConfig,\n\t};\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect, test } from "vitest";
|
|
2
|
-
import { addVitePlugin } from "./add-vite-plugin.js";
|
|
2
|
+
import { addVitePlugin, updateViteConfig } from "./add-vite-plugin.js";
|
|
3
3
|
import { memfs } from "memfs";
|
|
4
4
|
test("updates a vite.config.ts", async () => {
|
|
5
5
|
const config = `import { sveltekit } from "@sveltejs/kit/vite"
|
|
@@ -22,15 +22,15 @@ export default defineConfig({
|
|
|
22
22
|
encoding: "utf-8",
|
|
23
23
|
});
|
|
24
24
|
expect(updatedConfig).toMatchInlineSnapshot(`
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
"import { paraglideVitePlugin } from '@inlang/paraglide-js'
|
|
26
|
+
import { sveltekit } from "@sveltejs/kit/vite"
|
|
27
|
+
import { defineConfig } from "vite"
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
plugins: [paraglideVitePlugin({ project: "./project.inlang", outdir: "./src/paraglide" }),sveltekit()],
|
|
31
|
+
})
|
|
32
|
+
"
|
|
33
|
+
`);
|
|
34
34
|
});
|
|
35
35
|
test("doesn't update configs where the paraglide plugin is already present", async () => {
|
|
36
36
|
const config = `
|
|
@@ -67,4 +67,20 @@ test("doesn't update configs where the paraglide plugin is already present", asy
|
|
|
67
67
|
});
|
|
68
68
|
expect(updatedConfig).toMatch(config);
|
|
69
69
|
});
|
|
70
|
+
test("existing integration must match requested paths before unattended reuse", () => {
|
|
71
|
+
const config = 'import {paraglideVitePlugin} from "@inlang/paraglide-js"; export default {plugins:[paraglideVitePlugin({project:"./project.inlang",outdir:"./src/paraglide"})]}';
|
|
72
|
+
expect(updateViteConfig({
|
|
73
|
+
config,
|
|
74
|
+
projectPath: "./project.inlang",
|
|
75
|
+
outdir: "./src/different",
|
|
76
|
+
})).toMatchObject({
|
|
77
|
+
ok: false,
|
|
78
|
+
reason: "Existing Vite plugin paths differ from the requested project/outdir",
|
|
79
|
+
});
|
|
80
|
+
expect(updateViteConfig({
|
|
81
|
+
config: 'import {compile} from "@inlang/paraglide-js"; export default {plugins:[]}',
|
|
82
|
+
projectPath: "./project.inlang",
|
|
83
|
+
outdir: "./src/paraglide",
|
|
84
|
+
})).toMatchObject({ ok: false });
|
|
85
|
+
});
|
|
70
86
|
//# sourceMappingURL=add-vite-plugin.test.js.map
|