@inlang/paraglide-js 2.0.0-beta.20 → 2.0.0-beta.21

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.
Files changed (53) hide show
  1. package/dist/bundler-plugins/rollup.d.ts +1 -1
  2. package/dist/bundler-plugins/rollup.d.ts.map +1 -1
  3. package/dist/bundler-plugins/unplugin.d.ts.map +1 -1
  4. package/dist/bundler-plugins/unplugin.js +10 -17
  5. package/dist/compiler/compile-bundle.d.ts.map +1 -1
  6. package/dist/compiler/compile-bundle.js +9 -21
  7. package/dist/compiler/compile-bundle.test.js +62 -39
  8. package/dist/compiler/compile-message.d.ts.map +1 -1
  9. package/dist/compiler/compile-message.js +5 -2
  10. package/dist/compiler/compile-message.test.js +23 -0
  11. package/dist/compiler/compile-project.test.js +26 -0
  12. package/dist/compiler/compile.d.ts +6 -3
  13. package/dist/compiler/compile.d.ts.map +1 -1
  14. package/dist/compiler/compile.js +6 -2
  15. package/dist/compiler/compile.test.js +6 -2
  16. package/dist/compiler/compiler-options.d.ts +1 -1
  17. package/dist/compiler/compiler-options.js +1 -1
  18. package/dist/compiler/output-structure/locale-modules.d.ts.map +1 -1
  19. package/dist/compiler/output-structure/locale-modules.js +6 -5
  20. package/dist/compiler/output-structure/message-modules.d.ts.map +1 -1
  21. package/dist/compiler/output-structure/message-modules.js +37 -24
  22. package/dist/compiler/output-structure/message-modules.test.js +48 -0
  23. package/dist/compiler/runtime/create-runtime.d.ts.map +1 -1
  24. package/dist/compiler/runtime/create-runtime.js +6 -3
  25. package/dist/compiler/runtime/extract-locale-from-url.d.ts +2 -2
  26. package/dist/compiler/runtime/extract-locale-from-url.d.ts.map +1 -1
  27. package/dist/compiler/runtime/extract-locale-from-url.js +24 -2
  28. package/dist/compiler/runtime/extract-locale-from-url.test.js +12 -0
  29. package/dist/compiler/runtime/localize-href.d.ts +63 -27
  30. package/dist/compiler/runtime/localize-href.d.ts.map +1 -1
  31. package/dist/compiler/runtime/localize-href.js +64 -38
  32. package/dist/compiler/runtime/localize-url.d.ts +80 -8
  33. package/dist/compiler/runtime/localize-url.d.ts.map +1 -1
  34. package/dist/compiler/runtime/localize-url.js +146 -16
  35. package/dist/compiler/runtime/localize-url.test.js +84 -0
  36. package/dist/compiler/runtime/server-middleware.d.ts +1 -3
  37. package/dist/compiler/runtime/server-middleware.d.ts.map +1 -1
  38. package/dist/compiler/runtime/server-middleware.js +1 -3
  39. package/dist/compiler/runtime/variables.d.ts +1 -0
  40. package/dist/compiler/runtime/variables.d.ts.map +1 -1
  41. package/dist/compiler/runtime/variables.js +1 -0
  42. package/dist/compiler/safe-module-id.d.ts +8 -0
  43. package/dist/compiler/safe-module-id.d.ts.map +1 -0
  44. package/dist/compiler/safe-module-id.js +71 -0
  45. package/dist/compiler/safe-module-id.test.d.ts +2 -0
  46. package/dist/compiler/safe-module-id.test.d.ts.map +1 -0
  47. package/dist/compiler/safe-module-id.test.js +27 -0
  48. package/dist/services/env-variables/index.js +1 -1
  49. package/dist/services/file-handling/write-output.d.ts +1 -1
  50. package/dist/services/file-handling/write-output.d.ts.map +1 -1
  51. package/dist/services/file-handling/write-output.js +1 -1
  52. package/dist/services/file-handling/write-output.test.js +2 -1
  53. package/package.json +3 -3
@@ -1,38 +1,149 @@
1
- import { urlPatterns } from "./variables.js";
1
+ import { extractLocaleFromUrl } from "./extract-locale-from-url.js";
2
+ import { getLocale } from "./get-locale.js";
3
+ import { getUrlOrigin } from "./get-url-origin.js";
4
+ import { isLocale } from "./is-locale.js";
5
+ import { baseLocale, TREE_SHAKE_DEFAULT_URL_PATTERN_USED, urlPatterns, } from "./variables.js";
2
6
  /**
3
- * Localizes a URL to a specific locale using the new namedGroups API.
4
- * @param {string | URL} url - The URL to localize.
5
- * @param {Object} options - Options containing the target locale.
6
- * @param {string} options.locale - The target locale.
7
- * @returns {URL} - The localized URL.
7
+ * Lower-level URL localization function, primarily used in server contexts.
8
+ *
9
+ * This function is designed for server-side usage where you need precise control
10
+ * over URL localization, such as in middleware or request handlers. It works with
11
+ * URL objects and always returns absolute URLs.
12
+ *
13
+ * For client-side UI components, use `localizeHref()` instead, which provides
14
+ * a more convenient API with relative paths and automatic locale detection.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // Server middleware example
19
+ * app.use((req, res, next) => {
20
+ * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);
21
+ * const localized = localizeUrl(url, { locale: "de" });
22
+ *
23
+ * if (localized.href !== url.href) {
24
+ * return res.redirect(localized.href);
25
+ * }
26
+ * next();
27
+ * });
28
+ * ```
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Using with URL patterns
33
+ * const url = new URL("https://example.com/about");
34
+ * localizeUrl(url, { locale: "de" });
35
+ * // => URL("https://example.com/de/about")
36
+ *
37
+ * // Using with domain-based localization
38
+ * const url = new URL("https://example.com/store");
39
+ * localizeUrl(url, { locale: "de" });
40
+ * // => URL("https://de.example.com/store")
41
+ * ```
42
+ *
43
+ * @param {string | URL} url - The URL to localize. If string, must be absolute.
44
+ * @param {Object} [options] - Options for localization
45
+ * @param {string} [options.locale] - Target locale. If not provided, uses getLocale()
46
+ * @returns {URL} The localized URL, always absolute
8
47
  */
9
48
  export function localizeUrl(url, options) {
10
- const urlObj = new URL(url);
49
+ if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
50
+ return localizeUrlDefaultPattern(url, options);
51
+ }
52
+ const locale = options?.locale ?? getLocale();
53
+ const urlObj = typeof url === "string" ? new URL(url) : url;
54
+ const search = urlObj.search;
11
55
  for (const element of urlPatterns) {
12
56
  const pattern = new URLPattern(element.pattern);
13
57
  const match = pattern.exec(urlObj.href);
14
58
  if (match) {
15
59
  /** @type {Record<string, string | null >} */
16
60
  const overrides = {};
17
- for (const [groupName, value] of Object.entries(element.localizedNamedGroups?.[options.locale] ?? {})) {
61
+ for (const [groupName, value] of Object.entries(element.localizedNamedGroups?.[locale] ?? {})) {
18
62
  overrides[groupName] = value;
19
63
  }
20
64
  const groups = {
21
65
  ...aggregateGroups(match),
22
66
  ...overrides,
23
67
  };
24
- return fillPattern(element.pattern, groups);
68
+ return fillPattern(element.pattern, groups, search);
25
69
  }
26
70
  }
27
71
  throw new Error(`No match found for ${url}`);
28
72
  }
29
73
  /**
30
- * De-localizes a URL.
74
+ * https://github.com/opral/inlang-paraglide-js/issues/381
75
+ *
76
+ * @param {string | URL} url
77
+ * @param {Object} [options]
78
+ * @param {string} [options.locale]
79
+ * @returns {URL}
80
+ */
81
+ function localizeUrlDefaultPattern(url, options) {
82
+ const urlObj = typeof url === "string" ? new URL(url, getUrlOrigin()) : new URL(url);
83
+ const locale = options?.locale ?? getLocale();
84
+ const currentLocale = extractLocaleFromUrl(urlObj);
85
+ // If current locale matches target locale, no change needed
86
+ if (currentLocale === locale) {
87
+ return urlObj;
88
+ }
89
+ const pathSegments = urlObj.pathname.split("/").filter(Boolean);
90
+ // If current path starts with a locale, remove it
91
+ if (pathSegments.length > 0 && isLocale(pathSegments[0])) {
92
+ pathSegments.shift();
93
+ }
94
+ // For base locale, don't add prefix
95
+ if (locale === baseLocale) {
96
+ urlObj.pathname = "/" + pathSegments.join("/");
97
+ }
98
+ else {
99
+ // For other locales, add prefix
100
+ urlObj.pathname = "/" + locale + "/" + pathSegments.join("/");
101
+ }
102
+ return urlObj;
103
+ }
104
+ /**
105
+ * Low-level URL de-localization function, primarily used in server contexts.
106
+ *
107
+ * This function is designed for server-side usage where you need precise control
108
+ * over URL de-localization, such as in middleware or request handlers. It works with
109
+ * URL objects and always returns absolute URLs.
110
+ *
111
+ * For client-side UI components, use `deLocalizeHref()` instead, which provides
112
+ * a more convenient API with relative paths.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * // Server middleware example
117
+ * app.use((req, res, next) => {
118
+ * const url = new URL(req.url, `${req.protocol}://${req.headers.host}`);
119
+ * const baseUrl = deLocalizeUrl(url);
120
+ *
121
+ * // Store the base URL for later use
122
+ * req.baseUrl = baseUrl;
123
+ * next();
124
+ * });
125
+ * ```
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * // Using with URL patterns
130
+ * const url = new URL("https://example.com/de/about");
131
+ * deLocalizeUrl(url); // => URL("https://example.com/about")
31
132
  *
32
- * @type {(url: string | URL) => URL}
133
+ * // Using with domain-based localization
134
+ * const url = new URL("https://de.example.com/store");
135
+ * deLocalizeUrl(url); // => URL("https://example.com/store")
136
+ * ```
137
+ *
138
+ * @param {string | URL} url - The URL to de-localize. If string, must be absolute.
139
+ * @returns {URL} The de-localized URL, always absolute
33
140
  */
34
141
  export function deLocalizeUrl(url) {
35
- const urlObj = new URL(url);
142
+ if (TREE_SHAKE_DEFAULT_URL_PATTERN_USED) {
143
+ return deLocalizeUrlDefaultPattern(url);
144
+ }
145
+ const urlObj = new URL(url, getUrlOrigin());
146
+ const search = urlObj.search;
36
147
  for (const element of urlPatterns) {
37
148
  const pattern = new URLPattern(element.pattern);
38
149
  const match = pattern.exec(urlObj.href);
@@ -46,11 +157,25 @@ export function deLocalizeUrl(url) {
46
157
  ...aggregateGroups(match),
47
158
  ...overrides,
48
159
  };
49
- return fillPattern(element.pattern, groups);
160
+ return fillPattern(element.pattern, groups, search);
50
161
  }
51
162
  }
52
163
  throw new Error(`No match found for ${url}`);
53
164
  }
165
+ /**
166
+ * De-localizes a URL using the default pattern (/:locale/*)
167
+ * @param {string|URL} url
168
+ * @returns {URL}
169
+ */
170
+ function deLocalizeUrlDefaultPattern(url) {
171
+ const urlObj = typeof url === "string" ? new URL(url, getUrlOrigin()) : new URL(url);
172
+ const pathSegments = urlObj.pathname.split("/").filter(Boolean);
173
+ // If first segment is a locale, remove it
174
+ if (pathSegments.length > 0 && isLocale(pathSegments[0])) {
175
+ urlObj.pathname = "/" + pathSegments.slice(1).join("/");
176
+ }
177
+ return urlObj;
178
+ }
54
179
  /**
55
180
  * Fills a URL pattern with values for named groups, supporting all URLPattern-style modifiers:
56
181
  *
@@ -67,9 +192,10 @@ export function deLocalizeUrl(url) {
67
192
  *
68
193
  * @param {string} pattern - The URL pattern containing named groups.
69
194
  * @param {Record<string, string | null | undefined>} values - Object of values for named groups.
195
+ * @param {string} [search] - Optional search (query) parameters to preserve
70
196
  * @returns {URL} - The constructed URL with named groups filled.
71
197
  */
72
- function fillPattern(pattern, values) {
198
+ function fillPattern(pattern, values, search) {
73
199
  const filled = pattern.replace(/(\/?):([a-zA-Z0-9_]+)(\([^)]*\))?([?+*]?)/g, (_, slash, name, __, modifier) => {
74
200
  const value = values[name];
75
201
  if (value === null) {
@@ -93,13 +219,17 @@ function fillPattern(pattern, values) {
93
219
  }
94
220
  return `${slash}${value}`;
95
221
  });
96
- return new URL(filled);
222
+ const url = new URL(filled);
223
+ if (search) {
224
+ url.search = search;
225
+ }
226
+ return url;
97
227
  }
98
228
  /**
99
229
  * Aggregates named groups from various parts of the URLPattern match result.
100
230
  *
101
231
  *
102
- * @type {(match: URLPatternResult) => Record<string, string | null | undefined>}
232
+ * @type {(match: any) => Record<string, string | null | undefined>}
103
233
  */
104
234
  export function aggregateGroups(match) {
105
235
  return {
@@ -202,3 +202,87 @@ test("localhost with portname", async () => {
202
202
  expect(runtime.deLocalizeUrl(new URL("http://localhost:5173/")).href).toBe("http://localhost:5173/");
203
203
  expect(runtime.deLocalizeUrl(new URL("https://localhost:5173/de")).href).toBe("https://localhost:5173/");
204
204
  });
205
+ test("it keeps the query parameters", async () => {
206
+ const runtime = await createRuntimeForTesting({
207
+ baseLocale: "en",
208
+ locales: ["en", "de"],
209
+ compilerOptions: {
210
+ strategy: ["url"],
211
+ urlPatterns: [
212
+ {
213
+ pattern: "https://:domain(.*)/:locale(de)?/:path*",
214
+ deLocalizedNamedGroups: { locale: null },
215
+ localizedNamedGroups: {
216
+ en: { locale: null },
217
+ de: { locale: "de" },
218
+ },
219
+ },
220
+ ],
221
+ },
222
+ });
223
+ expect(runtime.localizeUrl("https://example.com/about?foo=bar&baz=qux", {
224
+ locale: "de",
225
+ }).href).toBe("https://example.com/de/about?foo=bar&baz=qux");
226
+ expect(runtime.deLocalizeUrl("https://example.com/de/about?foo=bar&baz=qux").href).toBe("https://example.com/about?foo=bar&baz=qux");
227
+ });
228
+ test("uses getLocale when no locale is provided", async () => {
229
+ const runtime = await createRuntimeForTesting({
230
+ baseLocale: "en",
231
+ locales: ["en", "de"],
232
+ compilerOptions: {
233
+ strategy: ["url"],
234
+ urlPatterns: [
235
+ {
236
+ pattern: "https://:domain(.*)/:locale(de|en)?/:path(.*)?",
237
+ deLocalizedNamedGroups: { locale: null },
238
+ localizedNamedGroups: {
239
+ en: { locale: "en" },
240
+ de: { locale: "de" },
241
+ },
242
+ },
243
+ ],
244
+ },
245
+ });
246
+ // Override getLocale to return German
247
+ runtime.overwriteGetLocale(() => "de");
248
+ expect(runtime.getLocale()).toBe("de");
249
+ // Should use "de" from getLocale since no locale provided
250
+ expect(runtime.localizeUrl("https://example.com/about").href).toBe("https://example.com/de/about");
251
+ // Should still use explicit locale when provided
252
+ expect(runtime.localizeUrl("https://example.com/about", { locale: "en" }).href).toBe("https://example.com/en/about");
253
+ });
254
+ // https://github.com/opral/inlang-paraglide-js/issues/381
255
+ test.each([
256
+ // empty url pattern will set TREE_SHAKE_DEFAULT_ULR_PATTERN_USED to true
257
+ {},
258
+ // real default url pattern to align behaviour
259
+ {
260
+ urlPatterns: [
261
+ {
262
+ pattern: ":protocol://:domain(.*)::port?/:locale(de|fr)?/:path(.*)?",
263
+ deLocalizedNamedGroups: { locale: null },
264
+ localizedNamedGroups: {
265
+ en: { locale: null },
266
+ de: { locale: "de" },
267
+ fr: { locale: "fr" },
268
+ },
269
+ },
270
+ ],
271
+ },
272
+ ])("default url pattern", async (compilerOptions) => {
273
+ const runtime = await createRuntimeForTesting({
274
+ baseLocale: "en",
275
+ locales: ["en", "de"],
276
+ compilerOptions,
277
+ });
278
+ runtime.overwriteGetLocale(() => "en");
279
+ expect(runtime.localizeUrl("https://example.com/about").href).toBe("https://example.com/about");
280
+ runtime.overwriteGetLocale(() => "de");
281
+ expect(runtime.localizeUrl("https://example.com/").href).toBe("https://example.com/de/");
282
+ expect(runtime.localizeUrl("https://example.com/about").href).toBe("https://example.com/de/about");
283
+ // Should still use explicit locale when provided
284
+ expect(runtime.localizeUrl("https://example.com/about", { locale: "de" }).href).toBe("https://example.com/de/about");
285
+ expect(runtime.localizeUrl("https://example.com/about", { locale: "en" }).href).toBe("https://example.com/about");
286
+ expect(runtime.deLocalizeUrl("https://example.com/de/about").href).toBe("https://example.com/about");
287
+ expect(runtime.deLocalizeUrl("https://example.com/about").href).toBe("https://example.com/about");
288
+ });
@@ -18,7 +18,7 @@
18
18
  * @param {(args: { request: Request, locale: Locale }) => T | Promise<T>} resolve - Function to handle the request
19
19
  *
20
20
  * @returns {Promise<Response | any>} Returns either:
21
- * - A {@link Response} object (302 redirect) if URL localization is needed
21
+ * - A `Response` object (302 redirect) if URL localization is needed
22
22
  * - The result of the resolve function if no redirect is required
23
23
  *
24
24
  * @example
@@ -42,8 +42,6 @@
42
42
  * });
43
43
  * });
44
44
  * ```
45
- *
46
- * @see {@link https://inlang.com/documentation/paraglide-js/server-middleware|Server Middleware Documentation}
47
45
  */
48
46
  export function serverMiddleware<T>(request: Request, resolve: (args: {
49
47
  request: Request;
@@ -1 +1 @@
1
- {"version":3,"file":"server-middleware.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/server-middleware.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,iCAjCa,CAAC,WAEH,OAAO,WACP,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAE5D,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,CA2DnC"}
1
+ {"version":3,"file":"server-middleware.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/server-middleware.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,iCA/Ba,CAAC,WAEH,OAAO,WACP,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAE5D,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,CAyDnC"}
@@ -32,7 +32,7 @@ let serverMiddlewareAsyncStorage = undefined;
32
32
  * @param {(args: { request: Request, locale: Locale }) => T | Promise<T>} resolve - Function to handle the request
33
33
  *
34
34
  * @returns {Promise<Response | any>} Returns either:
35
- * - A {@link Response} object (302 redirect) if URL localization is needed
35
+ * - A `Response` object (302 redirect) if URL localization is needed
36
36
  * - The result of the resolve function if no redirect is required
37
37
  *
38
38
  * @example
@@ -56,8 +56,6 @@ let serverMiddlewareAsyncStorage = undefined;
56
56
  * });
57
57
  * });
58
58
  * ```
59
- *
60
- * @see {@link https://inlang.com/documentation/paraglide-js/server-middleware|Server Middleware Documentation}
61
59
  */
62
60
  export async function serverMiddleware(request, resolve) {
63
61
  if (!serverMiddlewareAsyncStorage) {
@@ -36,4 +36,5 @@ export const TREE_SHAKE_COOKIE_STRATEGY_USED: false;
36
36
  export const TREE_SHAKE_URL_STRATEGY_USED: false;
37
37
  export const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED: false;
38
38
  export const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED: false;
39
+ export const TREE_SHAKE_DEFAULT_URL_PATTERN_USED: false;
39
40
  //# sourceMappingURL=variables.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/variables.js"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,yBAA0B,IAAI,CAAC;AAE/B;;;;;;;GAOG;AACH,4CAA2D;AAE3D,qBAAqB;AACrB,yBADW,MAAM,CACyB;AAE1C;;GAEG;AACH,uBAFU,KAAK,CAAC,QAAQ,GAAG,YAAY,GAAG,gBAAgB,GAAG,KAAK,GAAG,mBAAmB,CAAC,CAE9C;AAE3C;;;;GAIG;AACH,0BAFU,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;CAAE,CAAC,CAElI;AAE9B,8CAA+C,KAAK,CAAC;AAErD,2CAA4C,KAAK,CAAC;AAElD,uDAAwD,KAAK,CAAC;AAE9D,0DAA2D,KAAK,CAAC"}
1
+ {"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../../../src/compiler/runtime/variables.js"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,yBAA0B,IAAI,CAAC;AAE/B;;;;;;;GAOG;AACH,4CAA2D;AAE3D,qBAAqB;AACrB,yBADW,MAAM,CACyB;AAE1C;;GAEG;AACH,uBAFU,KAAK,CAAC,QAAQ,GAAG,YAAY,GAAG,gBAAgB,GAAG,KAAK,GAAG,mBAAmB,CAAC,CAE9C;AAE3C;;;;GAIG;AACH,0BAFU,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;CAAE,CAAC,CAElI;AAE9B,8CAA+C,KAAK,CAAC;AAErD,2CAA4C,KAAK,CAAC;AAElD,uDAAwD,KAAK,CAAC;AAE9D,0DAA2D,KAAK,CAAC;AAEjE,kDAAmD,KAAK,CAAC"}
@@ -32,3 +32,4 @@ export const TREE_SHAKE_COOKIE_STRATEGY_USED = false;
32
32
  export const TREE_SHAKE_URL_STRATEGY_USED = false;
33
33
  export const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = false;
34
34
  export const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;
35
+ export const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = false;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Turns an unsafe module id like `helloWorld🍌` into a safe one like `helloworld__`.
3
+ *
4
+ * Mainly exists to support https://github.com/opral/inlang-paraglide-js/issues/285
5
+ */
6
+ export declare function toSafeModuleId(id: string): string;
7
+ export declare function isSafeModuleId(id: string): boolean;
8
+ //# sourceMappingURL=safe-module-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-module-id.d.ts","sourceRoot":"","sources":["../../src/compiler/safe-module-id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAElD"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Turns an unsafe module id like `helloWorld🍌` into a safe one like `helloworld__`.
3
+ *
4
+ * Mainly exists to support https://github.com/opral/inlang-paraglide-js/issues/285
5
+ */
6
+ export function toSafeModuleId(id) {
7
+ const result = id.toLowerCase().replace(/[^a-z0-9_]/g, "_");
8
+ const startsWithNumber = result[0]?.match(/[0-9]/);
9
+ if (startsWithNumber) {
10
+ return "_" + result;
11
+ }
12
+ else if (reservedJsKeywords.includes(result)) {
13
+ return "_" + result;
14
+ }
15
+ return result;
16
+ }
17
+ export function isSafeModuleId(id) {
18
+ return toSafeModuleId(id) === id;
19
+ }
20
+ const reservedJsKeywords = [
21
+ "break",
22
+ "case",
23
+ "catch",
24
+ "class",
25
+ "const",
26
+ "continue",
27
+ "debugger",
28
+ "default",
29
+ "delete",
30
+ "do",
31
+ "else",
32
+ "export",
33
+ "extends",
34
+ "false",
35
+ "finally",
36
+ "for",
37
+ "function",
38
+ "if",
39
+ "import",
40
+ "in",
41
+ "instanceof",
42
+ "new",
43
+ "null",
44
+ "return",
45
+ "super",
46
+ "switch",
47
+ "this",
48
+ "throw",
49
+ "true",
50
+ "try",
51
+ "typeof",
52
+ "var",
53
+ "void",
54
+ "while",
55
+ "with",
56
+ //Strict mode reserved keywords
57
+ "let",
58
+ "static",
59
+ "yield",
60
+ "await",
61
+ //Reserved keywords for future use
62
+ "enum",
63
+ "implements",
64
+ "interface",
65
+ "package",
66
+ "private",
67
+ "protected",
68
+ "public",
69
+ // https://github.com/opral/inlang-paraglide-js/issues/331
70
+ "then",
71
+ ];
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=safe-module-id.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-module-id.test.d.ts","sourceRoot":"","sources":["../../src/compiler/safe-module-id.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import { test, expect } from "vitest";
2
+ import { toSafeModuleId } from "./safe-module-id.js";
3
+ test("handles emojis (because why not)", () => {
4
+ expect(toSafeModuleId("helloWorld🍌")).toBe("helloworld__");
5
+ });
6
+ // https://github.com/opral/inlang-paraglide-js/issues/395
7
+ test("makes everything lowercase", () => {
8
+ expect(toSafeModuleId("HelloWorld")).toBe("helloworld");
9
+ });
10
+ test('escapes "-" to "_"', () => {
11
+ expect(toSafeModuleId("de-DE-bavaria")).toBe("de_de_bavaria");
12
+ });
13
+ test("prefixes with _ if it starts with a number", () => {
14
+ expect(toSafeModuleId("123")).toBe("_123");
15
+ });
16
+ test("handles $ signs", () => {
17
+ expect(toSafeModuleId("default_e$")).toBe("default_e_");
18
+ });
19
+ test("handles . dots", () => {
20
+ expect(toSafeModuleId("hello.world.nested")).toBe("hello_world_nested");
21
+ });
22
+ test("transforms js reserved keywords", async () => {
23
+ expect(toSafeModuleId("import")).toBe("_import");
24
+ expect(toSafeModuleId("let")).toBe("_let");
25
+ // https://github.com/opral/inlang-paraglide-js/issues/331
26
+ expect(toSafeModuleId("then")).toBe("_then");
27
+ });
@@ -1,5 +1,5 @@
1
1
  export const ENV_VARIABLES = {
2
2
  PARJS_APP_ID: "library.inlang.paraglideJs",
3
3
  PARJS_POSTHOG_TOKEN: "phc_m5yJZCxjOGxF8CJvP5sQ3H0d76xpnLrsmiZHduT4jDz",
4
- PARJS_PACKAGE_VERSION: "2.0.0-beta.19",
4
+ PARJS_PACKAGE_VERSION: "2.0.0-beta.21",
5
5
  };
@@ -4,5 +4,5 @@ export declare function writeOutput(args: {
4
4
  output: Record<string, string>;
5
5
  fs: typeof nodeFs;
6
6
  previousOutputHashes?: Record<string, string>;
7
- }): Promise<Record<string, string> | undefined>;
7
+ }): Promise<Record<string, string>>;
8
8
  //# sourceMappingURL=write-output.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-output.d.ts","sourceRoot":"","sources":["../../../src/services/file-handling/write-output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAE3C,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,EAAE,EAAE,OAAO,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,+CA4CA"}
1
+ {"version":3,"file":"write-output.d.ts","sourceRoot":"","sources":["../../../src/services/file-handling/write-output.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAE3C,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,EAAE,EAAE,OAAO,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,mCA4CA"}
@@ -10,7 +10,7 @@ export async function writeOutput(args) {
10
10
  }
11
11
  }
12
12
  if (changedFiles.size === 0) {
13
- return;
13
+ return currentOutputHashes;
14
14
  }
15
15
  // disabled because of https://github.com/opral/inlang-paraglide-js/issues/350
16
16
  // // clear the output directory
@@ -51,12 +51,13 @@ it("should only write once if the output hasn't changed", async () => {
51
51
  output: { "test.txt": "test" },
52
52
  fs,
53
53
  });
54
- await writeOutput({
54
+ const hashes2 = await writeOutput({
55
55
  directory: "/output",
56
56
  output: { "test.txt": "test" },
57
57
  fs,
58
58
  previousOutputHashes: hashes,
59
59
  });
60
+ expect(hashes).toEqual(hashes2);
60
61
  expect(await fs.readFile("/output/test.txt", { encoding: "utf-8" })).toBe("test");
61
62
  expect(fs.writeFile).toHaveBeenCalledTimes(1);
62
63
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inlang/paraglide-js",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.20",
4
+ "version": "2.0.0-beta.21",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -49,9 +49,9 @@
49
49
  "typescript": "^5.7.3",
50
50
  "typescript-eslint": "^8.20.0",
51
51
  "vitest": "2.1.8",
52
- "@inlang/paraglide-js": "2.0.0-beta.20",
52
+ "@inlang/paraglide-js": "2.0.0-beta.21",
53
53
  "@opral/tsconfig": "1.1.0",
54
- "@inlang/plugin-message-format": "3.2.1"
54
+ "@inlang/plugin-message-format": "4.0.0"
55
55
  },
56
56
  "keywords": [
57
57
  "inlang",