@inlang/paraglide-js 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundler-plugins/vite.d.ts +1 -1
- package/dist/bundler-plugins/vite.d.ts.map +1 -1
- package/dist/cli/steps/update-ts-config.d.ts +13 -0
- package/dist/cli/steps/update-ts-config.d.ts.map +1 -1
- package/dist/cli/steps/update-ts-config.js +131 -16
- package/dist/cli/steps/update-ts-config.test.d.ts +2 -0
- package/dist/cli/steps/update-ts-config.test.d.ts.map +1 -0
- package/dist/cli/steps/update-ts-config.test.js +59 -0
- package/dist/compiler/output-file.d.ts +6 -0
- package/dist/compiler/output-file.d.ts.map +1 -0
- package/dist/compiler/output-file.js +1 -0
- package/dist/compiler/output-structure/message-modules.d.ts.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +26 -4
- package/dist/compiler/output-structure/message-modules.test.js +42 -0
- package/dist/compiler/runtime/assert-is-locale.d.ts.map +1 -1
- package/dist/compiler/runtime/assert-is-locale.js +7 -3
- package/dist/compiler/runtime/assert-is-locale.test.js +33 -2
- package/dist/compiler/runtime/is-locale.d.ts.map +1 -1
- package/dist/compiler/runtime/is-locale.js +5 -1
- package/dist/compiler/runtime/is-locale.test.d.ts +2 -0
- package/dist/compiler/runtime/is-locale.test.d.ts.map +1 -0
- package/dist/compiler/runtime/is-locale.test.js +31 -0
- package/dist/services/env-variables/index.js +1 -1
- package/package.json +5 -5
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const paraglideVitePlugin: (options: import("../index.js").CompilerOptions) => import("
|
|
1
|
+
export declare const paraglideVitePlugin: (options: import("../index.js").CompilerOptions) => import("unplugin").VitePlugin<any> | import("unplugin").VitePlugin<any>[];
|
|
2
2
|
//# sourceMappingURL=vite.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../src/bundler-plugins/vite.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,+
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../src/bundler-plugins/vite.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,+HAAoC,CAAC"}
|
|
@@ -11,4 +11,17 @@ export declare const maybeUpdateTsConfigAllowJs: CliStep<{
|
|
|
11
11
|
fs: typeof import("node:fs/promises");
|
|
12
12
|
logger: Logger;
|
|
13
13
|
}, unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* Recursively checks whether allowJs is enabled in the provided tsconfig or any
|
|
16
|
+
* referenced configuration files.
|
|
17
|
+
*
|
|
18
|
+
* @param tsconfigPath The path to the tsconfig to inspect.
|
|
19
|
+
* @param fs The file system used to read the configs.
|
|
20
|
+
* @param visited A set of already inspected files to avoid circular lookups.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* await hasAllowJsEnabled("./tsconfig.json", fs);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare const hasAllowJsEnabled: (tsconfigPath: string, fs: typeof import("node:fs/promises"), visited?: Set<string>) => Promise<boolean>;
|
|
14
27
|
//# sourceMappingURL=update-ts-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-ts-config.d.ts","sourceRoot":"","sources":["../../../src/cli/steps/update-ts-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"update-ts-config.d.ts","sourceRoot":"","sources":["../../../src/cli/steps/update-ts-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAS7D,eAAO,MAAM,mBAAmB,EAAE,OAAO,CACxC;IAAE,EAAE,EAAE,cAAc,kBAAkB,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzD,OAAO,CAKP,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,OAAO,CAC/C;IAAE,EAAE,EAAE,cAAc,kBAAkB,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzD,OAAO,CA6CP,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAC7B,cAAc,MAAM,EACpB,IAAI,cAAc,kBAAkB,CAAC,EACrC,UAAS,GAAG,CAAC,MAAM,CAAa,KAC9B,OAAO,CAAC,OAAO,CA4CjB,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { prompt } from "../utils.js";
|
|
2
2
|
import JSON5 from "json5";
|
|
3
3
|
import { pathExists } from "../../services/file-handling/exists.js";
|
|
4
|
-
|
|
4
|
+
import nodePath from "node:path";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
5
7
|
export const maybeUpdateTsConfig = async (ctx) => {
|
|
6
8
|
const ctx1 = await maybeUpdateTsConfigAllowJs(ctx);
|
|
7
9
|
return ctx1;
|
|
@@ -14,10 +16,7 @@ export const maybeUpdateTsConfigAllowJs = async (ctx) => {
|
|
|
14
16
|
if ((await pathExists("./tsconfig.json", ctx.fs)) === false) {
|
|
15
17
|
return ctx;
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
// tsconfig allows comments ... FML
|
|
19
|
-
let tsconfig = JSON5.parse(file);
|
|
20
|
-
if (tsconfig.compilerOptions?.allowJs === true) {
|
|
19
|
+
if (await hasAllowJsEnabled("./tsconfig.json", ctx.fs)) {
|
|
21
20
|
// all clear, allowJs is already set to true
|
|
22
21
|
return ctx;
|
|
23
22
|
}
|
|
@@ -38,17 +37,7 @@ export const maybeUpdateTsConfigAllowJs = async (ctx) => {
|
|
|
38
37
|
ctx.logger.warn("Continuing without adjusting the tsconfig.json. This may lead to type errors.");
|
|
39
38
|
return ctx;
|
|
40
39
|
}
|
|
41
|
-
|
|
42
|
-
// just trust that it's correct.
|
|
43
|
-
if (tsconfig.extends) {
|
|
44
|
-
isValid = true;
|
|
45
|
-
return ctx;
|
|
46
|
-
}
|
|
47
|
-
const file = await ctx.fs.readFile("./tsconfig.json", {
|
|
48
|
-
encoding: "utf-8",
|
|
49
|
-
});
|
|
50
|
-
tsconfig = JSON5.parse(file);
|
|
51
|
-
if (tsconfig?.compilerOptions?.allowJs === true) {
|
|
40
|
+
if (await hasAllowJsEnabled("./tsconfig.json", ctx.fs)) {
|
|
52
41
|
isValid = true;
|
|
53
42
|
return ctx;
|
|
54
43
|
}
|
|
@@ -58,6 +47,132 @@ export const maybeUpdateTsConfigAllowJs = async (ctx) => {
|
|
|
58
47
|
}
|
|
59
48
|
return ctx;
|
|
60
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Recursively checks whether allowJs is enabled in the provided tsconfig or any
|
|
52
|
+
* referenced configuration files.
|
|
53
|
+
*
|
|
54
|
+
* @param tsconfigPath The path to the tsconfig to inspect.
|
|
55
|
+
* @param fs The file system used to read the configs.
|
|
56
|
+
* @param visited A set of already inspected files to avoid circular lookups.
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* await hasAllowJsEnabled("./tsconfig.json", fs);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const hasAllowJsEnabled = async (tsconfigPath, fs, visited = new Set()) => {
|
|
63
|
+
const normalizedPath = normalizeConfigPath(tsconfigPath);
|
|
64
|
+
if (visited.has(normalizedPath)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
visited.add(normalizedPath);
|
|
68
|
+
const file = await fs.readFile(normalizedPath, { encoding: "utf-8" });
|
|
69
|
+
const tsconfig = JSON5.parse(file);
|
|
70
|
+
if (tsconfig?.compilerOptions?.allowJs === true) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const baseDir = nodePath.dirname(normalizedPath);
|
|
74
|
+
const extendCandidates = Array.isArray(tsconfig?.extends)
|
|
75
|
+
? tsconfig.extends
|
|
76
|
+
: tsconfig?.extends
|
|
77
|
+
? [tsconfig.extends]
|
|
78
|
+
: [];
|
|
79
|
+
for (const candidate of extendCandidates) {
|
|
80
|
+
if (typeof candidate !== "string")
|
|
81
|
+
continue;
|
|
82
|
+
const resolved = await resolveExtendedConfig(candidate, baseDir, fs);
|
|
83
|
+
if (resolved && (await hasAllowJsEnabled(resolved, fs, visited))) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (Array.isArray(tsconfig?.references)) {
|
|
88
|
+
for (const reference of tsconfig.references) {
|
|
89
|
+
const referencePath = reference?.path;
|
|
90
|
+
if (typeof referencePath !== "string")
|
|
91
|
+
continue;
|
|
92
|
+
const resolved = await resolveReferenceConfig(referencePath, baseDir, fs);
|
|
93
|
+
if (resolved && (await hasAllowJsEnabled(resolved, fs, visited))) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Normalizes a tsconfig path to an absolute path.
|
|
102
|
+
*/
|
|
103
|
+
const normalizeConfigPath = (configPath) => {
|
|
104
|
+
return nodePath.isAbsolute(configPath)
|
|
105
|
+
? configPath
|
|
106
|
+
: nodePath.resolve(process.cwd(), configPath);
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Resolves the extended tsconfig path relative to the base config.
|
|
110
|
+
*/
|
|
111
|
+
const resolveExtendedConfig = async (extendsSpecifier, baseDir, fs) => {
|
|
112
|
+
const candidates = new Set();
|
|
113
|
+
const resolvedBase = nodePath.isAbsolute(extendsSpecifier)
|
|
114
|
+
? extendsSpecifier
|
|
115
|
+
: nodePath.resolve(baseDir, extendsSpecifier);
|
|
116
|
+
candidates.add(resolvedBase);
|
|
117
|
+
if (nodePath.extname(resolvedBase) === "") {
|
|
118
|
+
candidates.add(`${resolvedBase}.json`);
|
|
119
|
+
candidates.add(nodePath.join(resolvedBase, "tsconfig.json"));
|
|
120
|
+
}
|
|
121
|
+
for (const candidate of candidates) {
|
|
122
|
+
if (await pathExists(candidate, fs)) {
|
|
123
|
+
return candidate;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
return require.resolve(extendsSpecifier, { paths: [baseDir] });
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
if (extendsSpecifier.endsWith(".json") === false) {
|
|
131
|
+
try {
|
|
132
|
+
return require.resolve(`${extendsSpecifier}.json`, {
|
|
133
|
+
paths: [baseDir],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Resolves the tsconfig referenced through the `references` property.
|
|
145
|
+
*/
|
|
146
|
+
const resolveReferenceConfig = async (referenceSpecifier, baseDir, fs) => {
|
|
147
|
+
const candidates = new Set();
|
|
148
|
+
const resolvedBase = nodePath.isAbsolute(referenceSpecifier)
|
|
149
|
+
? referenceSpecifier
|
|
150
|
+
: nodePath.resolve(baseDir, referenceSpecifier);
|
|
151
|
+
candidates.add(resolvedBase);
|
|
152
|
+
if (nodePath.extname(resolvedBase) === "") {
|
|
153
|
+
candidates.add(`${resolvedBase}.json`);
|
|
154
|
+
candidates.add(nodePath.join(resolvedBase, "tsconfig.json"));
|
|
155
|
+
}
|
|
156
|
+
for (const candidate of candidates) {
|
|
157
|
+
if (await pathExists(candidate, fs)) {
|
|
158
|
+
try {
|
|
159
|
+
const stats = await fs.stat(candidate);
|
|
160
|
+
if (stats.isDirectory()) {
|
|
161
|
+
const directoryConfig = nodePath.join(candidate, "tsconfig.json");
|
|
162
|
+
if (await pathExists(directoryConfig, fs)) {
|
|
163
|
+
return directoryConfig;
|
|
164
|
+
}
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// ignore, we'll continue checking other candidates
|
|
170
|
+
}
|
|
171
|
+
return candidate;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
};
|
|
61
176
|
// /**
|
|
62
177
|
// * Ensures that the moduleResolution compiler option is set to "bundler" or similar in the tsconfig.json.
|
|
63
178
|
// *
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-ts-config.test.d.ts","sourceRoot":"","sources":["../../../src/cli/steps/update-ts-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { expect, test, vi } from "vitest";
|
|
2
|
+
import { memfs } from "memfs";
|
|
3
|
+
import { maybeUpdateTsConfigAllowJs } from "./update-ts-config.js";
|
|
4
|
+
import { Logger } from "../../services/logger/index.js";
|
|
5
|
+
const setCwd = (cwd) => {
|
|
6
|
+
const original = process.cwd;
|
|
7
|
+
process.cwd = (() => cwd);
|
|
8
|
+
return () => {
|
|
9
|
+
process.cwd = original;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
// Regression coverage for https://github.com/opral/inlang-paraglide-js/issues/560
|
|
13
|
+
test("skips prompting when allowJs is set in a referenced tsconfig", async () => {
|
|
14
|
+
const fs = memfs({
|
|
15
|
+
"/tsconfig.json": JSON.stringify({
|
|
16
|
+
references: [{ path: "./tsconfig.app.json" }],
|
|
17
|
+
}),
|
|
18
|
+
"/tsconfig.app.json": JSON.stringify({
|
|
19
|
+
compilerOptions: { allowJs: true },
|
|
20
|
+
}),
|
|
21
|
+
}).fs;
|
|
22
|
+
const restoreCwd = setCwd("/");
|
|
23
|
+
const logger = new Logger({ silent: true, prefix: false });
|
|
24
|
+
const infoSpy = vi.spyOn(logger, "info");
|
|
25
|
+
try {
|
|
26
|
+
await maybeUpdateTsConfigAllowJs({
|
|
27
|
+
fs: fs.promises,
|
|
28
|
+
logger,
|
|
29
|
+
});
|
|
30
|
+
expect(infoSpy).not.toHaveBeenCalled();
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
restoreCwd();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
// Regression coverage for https://github.com/opral/inlang-paraglide-js/issues/560
|
|
37
|
+
test("skips prompting when allowJs is provided via extends", async () => {
|
|
38
|
+
const fs = memfs({
|
|
39
|
+
"/tsconfig.json": JSON.stringify({
|
|
40
|
+
extends: "./tsconfig.base.json",
|
|
41
|
+
}),
|
|
42
|
+
"/tsconfig.base.json": JSON.stringify({
|
|
43
|
+
compilerOptions: { allowJs: true },
|
|
44
|
+
}),
|
|
45
|
+
}).fs;
|
|
46
|
+
const restoreCwd = setCwd("/");
|
|
47
|
+
const logger = new Logger({ silent: true, prefix: false });
|
|
48
|
+
const infoSpy = vi.spyOn(logger, "info");
|
|
49
|
+
try {
|
|
50
|
+
await maybeUpdateTsConfigAllowJs({
|
|
51
|
+
fs: fs.promises,
|
|
52
|
+
logger,
|
|
53
|
+
});
|
|
54
|
+
expect(infoSpy).not.toHaveBeenCalled();
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
restoreCwd();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-file.d.ts","sourceRoot":"","sources":["../../src/compiler/output-file.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-modules.d.ts","sourceRoot":"","sources":["../../../src/compiler/output-structure/message-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAKvE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAE1E;AAED,wBAAgB,cAAc,CAC7B,eAAe,EAAE,0BAA0B,EAAE,EAC7C,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC,EACzD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"message-modules.d.ts","sourceRoot":"","sources":["../../../src/compiler/output-structure/message-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAKvE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAE1E;AAED,wBAAgB,cAAc,CAC7B,eAAe,EAAE,0BAA0B,EAAE,EAC7C,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC,EACzD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+GxB"}
|
|
@@ -31,19 +31,41 @@ export function generateOutput(compiledBundles, settings, fallbackMap) {
|
|
|
31
31
|
}
|
|
32
32
|
// add the fallbacks (needs to be done after the messages to avoid referencing
|
|
33
33
|
// the message before they are defined)
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const needsFallbackSet = new Set(needsFallback);
|
|
35
|
+
const emittedFallbacks = new Set();
|
|
36
|
+
const emittingFallbacks = new Set();
|
|
37
|
+
/**
|
|
38
|
+
* Emits the fallback definition for a locale ensuring that dependent fallbacks
|
|
39
|
+
* are declared beforehand.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* emitFallback("fr-ca");
|
|
43
|
+
*/
|
|
44
|
+
const emitFallback = (locale) => {
|
|
45
|
+
if (emittedFallbacks.has(locale))
|
|
46
|
+
return;
|
|
47
|
+
if (emittingFallbacks.has(locale))
|
|
48
|
+
return;
|
|
49
|
+
emittingFallbacks.add(locale);
|
|
36
50
|
const safeLocale = toSafeModuleId(locale);
|
|
37
51
|
const fallbackLocale = fallbackMap[locale];
|
|
52
|
+
if (fallbackLocale &&
|
|
53
|
+
needsFallbackSet.has(fallbackLocale) &&
|
|
54
|
+
!compiledBundle.messages[fallbackLocale]) {
|
|
55
|
+
emitFallback(fallbackLocale);
|
|
56
|
+
}
|
|
38
57
|
if (fallbackLocale) {
|
|
39
58
|
const safeFallbackLocale = toSafeModuleId(fallbackLocale);
|
|
40
|
-
// take the fallback locale
|
|
41
59
|
messages.push(`/** @type {(inputs: ${inputsType(inputs)}) => string} */\nconst ${safeLocale}_${safeModuleId} = ${safeFallbackLocale}_${safeModuleId};`);
|
|
42
60
|
}
|
|
43
61
|
else {
|
|
44
|
-
// fallback to just the bundle id
|
|
45
62
|
messages.push(`/** @type {(inputs: ${inputsType(inputs)}) => string} */\nconst ${safeLocale}_${safeModuleId} = () => '${escapeForSingleQuoteString(bundleId)}'`);
|
|
46
63
|
}
|
|
64
|
+
emittingFallbacks.delete(locale);
|
|
65
|
+
emittedFallbacks.add(locale);
|
|
66
|
+
};
|
|
67
|
+
for (const locale of needsFallback) {
|
|
68
|
+
emitFallback(locale);
|
|
47
69
|
}
|
|
48
70
|
output[filename] = messages.join("\n\n") + "\n\n" + output[filename];
|
|
49
71
|
// add the imports
|
|
@@ -75,3 +75,45 @@ test("handles case senstivity by creating directories and files only in lowercas
|
|
|
75
75
|
expect(output).toHaveProperty("messages/happyelephant2.js");
|
|
76
76
|
expect(output).not.toHaveProperty("messages/HappyElephant.js");
|
|
77
77
|
});
|
|
78
|
+
// Regression test for https://github.com/opral/inlang-paraglide-js/issues/507
|
|
79
|
+
test("emits fallback definitions after their dependencies", () => {
|
|
80
|
+
const resources = [
|
|
81
|
+
{
|
|
82
|
+
bundle: {
|
|
83
|
+
code: "export const admin_tasks = (inputs) => inputs;",
|
|
84
|
+
node: {
|
|
85
|
+
id: "admin_tasks",
|
|
86
|
+
declarations: [],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
messages: {
|
|
90
|
+
en: {
|
|
91
|
+
code: '/** @type {(inputs: {}) => string} */ () => "admin"',
|
|
92
|
+
node: {},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
const settings = {
|
|
98
|
+
locales: ["fr-ca", "fr", "en"],
|
|
99
|
+
baseLocale: "en",
|
|
100
|
+
};
|
|
101
|
+
const fallbackMap = {
|
|
102
|
+
"fr-ca": "fr",
|
|
103
|
+
fr: "en",
|
|
104
|
+
en: undefined,
|
|
105
|
+
};
|
|
106
|
+
const output = generateOutput(resources, settings, fallbackMap);
|
|
107
|
+
const file = output["messages/admin_tasks.js"];
|
|
108
|
+
expect(file).toBeDefined();
|
|
109
|
+
if (!file) {
|
|
110
|
+
throw new Error("messages/admin_tasks.js should have been generated");
|
|
111
|
+
}
|
|
112
|
+
expect(file).toContain("const fr_admin_tasks = en_admin_tasks;");
|
|
113
|
+
expect(file).toContain("const fr_ca_admin_tasks = fr_admin_tasks;");
|
|
114
|
+
const frIndex = file.indexOf("const fr_admin_tasks");
|
|
115
|
+
const frCaIndex = file.indexOf("const fr_ca_admin_tasks");
|
|
116
|
+
expect(frIndex).toBeGreaterThan(-1);
|
|
117
|
+
expect(frCaIndex).toBeGreaterThan(-1);
|
|
118
|
+
expect(frIndex).toBeLessThan(frCaIndex);
|
|
119
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-is-locale.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/assert-is-locale.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assert-is-locale.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/assert-is-locale.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,sCAJW,GAAG,GACD,MAAM,CAiBlB"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isLocale } from "./is-locale.js";
|
|
2
1
|
import { locales } from "./variables.js";
|
|
3
2
|
/**
|
|
4
3
|
* Asserts that the input is a locale.
|
|
@@ -8,8 +7,13 @@ import { locales } from "./variables.js";
|
|
|
8
7
|
* @throws {Error} If the input is not a locale.
|
|
9
8
|
*/
|
|
10
9
|
export function assertIsLocale(input) {
|
|
11
|
-
if (
|
|
10
|
+
if (typeof input !== "string") {
|
|
11
|
+
throw new Error(`Invalid locale: ${input}. Expected a string.`);
|
|
12
|
+
}
|
|
13
|
+
const lowerInput = input.toLowerCase();
|
|
14
|
+
const matchedLocale = locales.find((item) => item.toLowerCase() === lowerInput);
|
|
15
|
+
if (!matchedLocale) {
|
|
12
16
|
throw new Error(`Invalid locale: ${input}. Expected one of: ${locales.join(", ")}`);
|
|
13
17
|
}
|
|
14
|
-
return
|
|
18
|
+
return matchedLocale;
|
|
15
19
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { test, expect } from "vitest";
|
|
2
|
-
import { createParaglide } from "../create-paraglide.js";
|
|
3
1
|
import { newProject } from "@inlang/sdk";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
import { createParaglide } from "../create-paraglide.js";
|
|
4
4
|
test("throws if the locale is not available", async () => {
|
|
5
5
|
const runtime = await createParaglide({
|
|
6
6
|
blob: await newProject({
|
|
@@ -12,6 +12,21 @@ test("throws if the locale is not available", async () => {
|
|
|
12
12
|
});
|
|
13
13
|
expect(() => runtime.assertIsLocale("es")).toThrow();
|
|
14
14
|
});
|
|
15
|
+
test("throws for non-string inputs", async () => {
|
|
16
|
+
const runtime = await createParaglide({
|
|
17
|
+
blob: await newProject({
|
|
18
|
+
settings: {
|
|
19
|
+
baseLocale: "en",
|
|
20
|
+
locales: ["en", "de"],
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
expect(() => runtime.assertIsLocale(null)).toThrow();
|
|
25
|
+
expect(() => runtime.assertIsLocale(undefined)).toThrow();
|
|
26
|
+
expect(() => runtime.assertIsLocale(123)).toThrow();
|
|
27
|
+
expect(() => runtime.assertIsLocale({})).toThrow();
|
|
28
|
+
expect(() => runtime.assertIsLocale([])).toThrow();
|
|
29
|
+
});
|
|
15
30
|
test("passes if the locale is available", async () => {
|
|
16
31
|
const runtime = await createParaglide({
|
|
17
32
|
blob: await newProject({
|
|
@@ -37,3 +52,19 @@ test("the return value is a Locale", async () => {
|
|
|
37
52
|
// in the ambient type definition
|
|
38
53
|
locale;
|
|
39
54
|
});
|
|
55
|
+
test("is case-insensitive", async () => {
|
|
56
|
+
const runtime = await createParaglide({
|
|
57
|
+
blob: await newProject({
|
|
58
|
+
settings: {
|
|
59
|
+
baseLocale: "en",
|
|
60
|
+
locales: ["en", "pt-BR", "de-ch"],
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
expect(() => runtime.assertIsLocale("EN")).not.toThrow();
|
|
65
|
+
expect(() => runtime.assertIsLocale("pt-br")).not.toThrow();
|
|
66
|
+
expect(() => runtime.assertIsLocale("de-CH")).not.toThrow();
|
|
67
|
+
expect(runtime.assertIsLocale("EN")).toBe("en");
|
|
68
|
+
expect(runtime.assertIsLocale("pT-bR")).toBe("pt-BR");
|
|
69
|
+
expect(runtime.assertIsLocale("de-CH")).toBe("de-ch");
|
|
70
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-locale.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/is-locale.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,iCAHW,GAAG,GACD,MAAM,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"is-locale.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/is-locale.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,iCAHW,GAAG,GACD,MAAM,IAAI,MAAM,CAO5B"}
|
|
@@ -13,5 +13,9 @@ import { locales } from "./variables.js";
|
|
|
13
13
|
* @returns {locale is Locale}
|
|
14
14
|
*/
|
|
15
15
|
export function isLocale(locale) {
|
|
16
|
-
|
|
16
|
+
if (typeof locale !== "string")
|
|
17
|
+
return false;
|
|
18
|
+
return !locale
|
|
19
|
+
? false
|
|
20
|
+
: locales.some((item) => item.toLowerCase() === locale.toLowerCase());
|
|
17
21
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-locale.test.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/is-locale.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { newProject } from "@inlang/sdk";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
import { createParaglide } from "../create-paraglide.js";
|
|
4
|
+
const runtime = await createParaglide({
|
|
5
|
+
blob: await newProject({
|
|
6
|
+
settings: {
|
|
7
|
+
baseLocale: "en",
|
|
8
|
+
locales: ["en", "pt-BR", "de-ch"],
|
|
9
|
+
},
|
|
10
|
+
}),
|
|
11
|
+
});
|
|
12
|
+
test("returns true for exact matches", () => {
|
|
13
|
+
expect(runtime.isLocale("pt-BR")).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
test("is case-insensitive", () => {
|
|
16
|
+
expect(runtime.isLocale("EN")).toBe(true);
|
|
17
|
+
expect(runtime.isLocale("pt-br")).toBe(true);
|
|
18
|
+
expect(runtime.isLocale("de-CH")).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
test("returns false for non-existent locales", () => {
|
|
21
|
+
expect(runtime.isLocale("es")).toBe(false);
|
|
22
|
+
expect(runtime.isLocale("xx")).toBe(false);
|
|
23
|
+
expect(runtime.isLocale("")).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
test("returns false for non-string inputs", () => {
|
|
26
|
+
expect(runtime.isLocale(null)).toBe(false);
|
|
27
|
+
expect(runtime.isLocale(undefined)).toBe(false);
|
|
28
|
+
expect(runtime.isLocale(123)).toBe(false);
|
|
29
|
+
expect(runtime.isLocale({})).toBe(false);
|
|
30
|
+
expect(runtime.isLocale([])).toBe(false);
|
|
31
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/paraglide-js",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"./urlpattern-polyfill": "./dist/urlpattern-polyfill/index.js"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@inlang/sdk": "2.4.9",
|
|
30
29
|
"commander": "11.1.0",
|
|
31
30
|
"consola": "3.4.0",
|
|
32
31
|
"json5": "2.2.3",
|
|
33
32
|
"unplugin": "^2.1.2",
|
|
34
33
|
"urlpattern-polyfill": "^10.0.0",
|
|
35
|
-
"@inlang/recommend-sherlock": "0.2.1"
|
|
34
|
+
"@inlang/recommend-sherlock": "0.2.1",
|
|
35
|
+
"@inlang/sdk": "2.4.9"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@rollup/plugin-virtual": "3.0.2",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"typedoc-plugin-missing-exports": "4.0.0",
|
|
49
49
|
"typescript": "5.8.3",
|
|
50
50
|
"vitest": "3.1.4",
|
|
51
|
-
"@
|
|
52
|
-
"@
|
|
51
|
+
"@opral/tsconfig": "1.1.0",
|
|
52
|
+
"@inlang/plugin-message-format": "4.0.0"
|
|
53
53
|
},
|
|
54
54
|
"keywords": [
|
|
55
55
|
"inlang",
|