@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.
Files changed (225) hide show
  1. package/README.md +11 -1
  2. package/dist/bundler-plugins/per-locale-build/index.js +14 -7
  3. package/dist/bundler-plugins/per-locale-build/index.js.map +1 -1
  4. package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +237 -4
  5. package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
  6. package/dist/bundler-plugins/unplugin.d.ts +1 -1
  7. package/dist/bundler-plugins/unplugin.js +79 -10
  8. package/dist/bundler-plugins/unplugin.js.map +1 -1
  9. package/dist/bundler-plugins/unplugin.test.js +334 -1
  10. package/dist/bundler-plugins/unplugin.test.js.map +1 -1
  11. package/dist/bundler-plugins/vite.js +2 -1
  12. package/dist/bundler-plugins/vite.js.map +1 -1
  13. package/dist/bundler-plugins/vite.test.js +1 -1
  14. package/dist/bundler-plugins/vite.test.js.map +1 -1
  15. package/dist/cli/commands/compile/command.js +13 -0
  16. package/dist/cli/commands/compile/command.js.map +1 -1
  17. package/dist/cli/commands/compile/command.test.js +87 -3
  18. package/dist/cli/commands/compile/command.test.js.map +1 -1
  19. package/dist/cli/commands/init/command.d.ts +5 -0
  20. package/dist/cli/commands/init/command.js +216 -44
  21. package/dist/cli/commands/init/command.js.map +1 -1
  22. package/dist/cli/commands/init/command.test.d.ts +1 -0
  23. package/dist/cli/commands/init/command.test.js +123 -0
  24. package/dist/cli/commands/init/command.test.js.map +1 -0
  25. package/dist/cli/defaults.js +2 -2
  26. package/dist/cli/defaults.js.map +1 -1
  27. package/dist/cli/init-options.d.ts +11 -0
  28. package/dist/cli/init-options.js +2 -0
  29. package/dist/cli/init-options.js.map +1 -0
  30. package/dist/cli/steps/add-inlang-check.d.ts +19 -0
  31. package/dist/cli/steps/add-inlang-check.js +60 -0
  32. package/dist/cli/steps/add-inlang-check.js.map +1 -0
  33. package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
  34. package/dist/cli/steps/add-inlang-check.test.js +88 -0
  35. package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
  36. package/dist/cli/steps/add-message-lint.d.ts +34 -0
  37. package/dist/cli/steps/add-message-lint.js +105 -0
  38. package/dist/cli/steps/add-message-lint.js.map +1 -0
  39. package/dist/cli/steps/add-message-lint.test.d.ts +1 -0
  40. package/dist/cli/steps/add-message-lint.test.js +74 -0
  41. package/dist/cli/steps/add-message-lint.test.js.map +1 -0
  42. package/dist/cli/steps/add-vite-plugin.d.ts +18 -0
  43. package/dist/cli/steps/add-vite-plugin.js +34 -6
  44. package/dist/cli/steps/add-vite-plugin.js.map +1 -1
  45. package/dist/cli/steps/add-vite-plugin.test.js +25 -9
  46. package/dist/cli/steps/add-vite-plugin.test.js.map +1 -1
  47. package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
  48. package/dist/cli/steps/agents-md-suggestion.js +19 -0
  49. package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
  50. package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
  51. package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
  52. package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
  53. package/dist/cli/steps/check-for-uncomitted-changes.d.ts +3 -0
  54. package/dist/cli/steps/check-for-uncomitted-changes.js +15 -3
  55. package/dist/cli/steps/check-for-uncomitted-changes.js.map +1 -1
  56. package/dist/cli/steps/detect-bundler.d.ts +1 -0
  57. package/dist/cli/steps/detect-bundler.js +7 -1
  58. package/dist/cli/steps/detect-bundler.js.map +1 -1
  59. package/dist/cli/steps/initialize-inlang-project.d.ts +4 -3
  60. package/dist/cli/steps/initialize-inlang-project.js +60 -157
  61. package/dist/cli/steps/initialize-inlang-project.js.map +1 -1
  62. package/dist/cli/steps/maybe-add-machine-translation.d.ts +4 -0
  63. package/dist/cli/steps/maybe-add-machine-translation.js +14 -8
  64. package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
  65. package/dist/cli/steps/maybe-add-sherlock.d.ts +2 -0
  66. package/dist/cli/steps/maybe-add-sherlock.js +13 -7
  67. package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
  68. package/dist/cli/steps/maybe-add-sherlock.test.d.ts +1 -0
  69. package/dist/cli/steps/maybe-add-sherlock.test.js +44 -0
  70. package/dist/cli/steps/maybe-add-sherlock.test.js.map +1 -0
  71. package/dist/cli/steps/prompt-for-outdir.d.ts +2 -0
  72. package/dist/cli/steps/prompt-for-outdir.js +4 -0
  73. package/dist/cli/steps/prompt-for-outdir.js.map +1 -1
  74. package/dist/cli/steps/update-package-json.js +8 -13
  75. package/dist/cli/steps/update-package-json.js.map +1 -1
  76. package/dist/cli/steps/update-ts-config.d.ts +6 -0
  77. package/dist/cli/steps/update-ts-config.js +27 -4
  78. package/dist/cli/steps/update-ts-config.js.map +1 -1
  79. package/dist/cli/utils.d.ts +11 -0
  80. package/dist/cli/utils.js +21 -0
  81. package/dist/cli/utils.js.map +1 -1
  82. package/dist/cli/utils.test.d.ts +1 -0
  83. package/dist/cli/utils.test.js +16 -0
  84. package/dist/cli/utils.test.js.map +1 -0
  85. package/dist/compiler/compile-annotation.d.ts +48 -1
  86. package/dist/compiler/compile-annotation.js +243 -10
  87. package/dist/compiler/compile-annotation.js.map +1 -1
  88. package/dist/compiler/compile-bundle.d.ts +7 -2
  89. package/dist/compiler/compile-bundle.js +97 -3
  90. package/dist/compiler/compile-bundle.js.map +1 -1
  91. package/dist/compiler/compile-bundle.test.js +232 -19
  92. package/dist/compiler/compile-bundle.test.js.map +1 -1
  93. package/dist/compiler/compile-lifecycle.test.d.ts +1 -0
  94. package/dist/compiler/compile-lifecycle.test.js +69 -0
  95. package/dist/compiler/compile-lifecycle.test.js.map +1 -0
  96. package/dist/compiler/compile-local-variable.d.ts +3 -0
  97. package/dist/compiler/compile-local-variable.js +5 -2
  98. package/dist/compiler/compile-local-variable.js.map +1 -1
  99. package/dist/compiler/compile-local-variable.test.js +55 -15
  100. package/dist/compiler/compile-local-variable.test.js.map +1 -1
  101. package/dist/compiler/compile-message.d.ts +29 -1
  102. package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
  103. package/dist/compiler/compile-message.exact-number.test.js +786 -0
  104. package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
  105. package/dist/compiler/compile-message.js +162 -66
  106. package/dist/compiler/compile-message.js.map +1 -1
  107. package/dist/compiler/compile-message.locals.test.d.ts +1 -0
  108. package/dist/compiler/compile-message.locals.test.js +498 -0
  109. package/dist/compiler/compile-message.locals.test.js.map +1 -0
  110. package/dist/compiler/compile-message.test.js +113 -22
  111. package/dist/compiler/compile-message.test.js.map +1 -1
  112. package/dist/compiler/compile-pattern.d.ts +5 -0
  113. package/dist/compiler/compile-pattern.js +6 -18
  114. package/dist/compiler/compile-pattern.js.map +1 -1
  115. package/dist/compiler/compile-pattern.test.js +169 -5
  116. package/dist/compiler/compile-pattern.test.js.map +1 -1
  117. package/dist/compiler/compile-project.js +5 -1
  118. package/dist/compiler/compile-project.js.map +1 -1
  119. package/dist/compiler/compile-project.test.js +1260 -185
  120. package/dist/compiler/compile-project.test.js.map +1 -1
  121. package/dist/compiler/compile.js +36 -17
  122. package/dist/compiler/compile.js.map +1 -1
  123. package/dist/compiler/compile.test.js +71 -1
  124. package/dist/compiler/compile.test.js.map +1 -1
  125. package/dist/compiler/compiler-options.d.ts +41 -0
  126. package/dist/compiler/compiler-options.js.map +1 -1
  127. package/dist/compiler/create-readme.d.ts +4 -1
  128. package/dist/compiler/create-readme.js +33 -125
  129. package/dist/compiler/create-readme.js.map +1 -1
  130. package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
  131. package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
  132. package/dist/compiler/emit-ts-declarations.test.js +4 -4
  133. package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
  134. package/dist/compiler/index.d.ts +1 -1
  135. package/dist/compiler/index.js +1 -1
  136. package/dist/compiler/index.js.map +1 -1
  137. package/dist/compiler/input-alias.d.ts +21 -0
  138. package/dist/compiler/input-alias.js +42 -0
  139. package/dist/compiler/input-alias.js.map +1 -0
  140. package/dist/compiler/input-alias.test.d.ts +1 -0
  141. package/dist/compiler/input-alias.test.js +58 -0
  142. package/dist/compiler/input-alias.test.js.map +1 -0
  143. package/dist/compiler/message-locals.d.ts +46 -0
  144. package/dist/compiler/message-locals.js +129 -0
  145. package/dist/compiler/message-locals.js.map +1 -0
  146. package/dist/compiler/output-structure/locale-modules.js +7 -1
  147. package/dist/compiler/output-structure/locale-modules.js.map +1 -1
  148. package/dist/compiler/output-structure/locale-modules.test.js +35 -0
  149. package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
  150. package/dist/compiler/output-structure/message-modules.js +6 -4
  151. package/dist/compiler/output-structure/message-modules.js.map +1 -1
  152. package/dist/compiler/output-structure/message-modules.test.js +35 -0
  153. package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
  154. package/dist/compiler/registry.d.ts +12 -0
  155. package/dist/compiler/registry.js +158 -31
  156. package/dist/compiler/registry.js.map +1 -1
  157. package/dist/compiler/registry.test.d.ts +1 -0
  158. package/dist/compiler/registry.test.js +291 -0
  159. package/dist/compiler/registry.test.js.map +1 -0
  160. package/dist/compiler/runtime/create-runtime.d.ts +2 -0
  161. package/dist/compiler/runtime/create-runtime.js +9 -0
  162. package/dist/compiler/runtime/create-runtime.js.map +1 -1
  163. package/dist/compiler/runtime/extract-locale-from-cookie.js +8 -1
  164. package/dist/compiler/runtime/extract-locale-from-cookie.js.map +1 -1
  165. package/dist/compiler/runtime/extract-locale-from-cookie.test.js +26 -0
  166. package/dist/compiler/runtime/extract-locale-from-cookie.test.js.map +1 -1
  167. package/dist/compiler/runtime/extract-locale-from-header.js +47 -5
  168. package/dist/compiler/runtime/extract-locale-from-header.js.map +1 -1
  169. package/dist/compiler/runtime/extract-locale-from-header.test.js +58 -0
  170. package/dist/compiler/runtime/extract-locale-from-header.test.js.map +1 -1
  171. package/dist/compiler/runtime/get-locale.js +7 -1
  172. package/dist/compiler/runtime/get-locale.js.map +1 -1
  173. package/dist/compiler/runtime/get-locale.test.js +95 -0
  174. package/dist/compiler/runtime/get-locale.test.js.map +1 -1
  175. package/dist/compiler/runtime/localize-href.d.ts +8 -0
  176. package/dist/compiler/runtime/localize-href.js +60 -0
  177. package/dist/compiler/runtime/localize-href.js.map +1 -1
  178. package/dist/compiler/runtime/localize-href.test.js +227 -1
  179. package/dist/compiler/runtime/localize-href.test.js.map +1 -1
  180. package/dist/compiler/runtime/set-locale.js +24 -6
  181. package/dist/compiler/runtime/set-locale.js.map +1 -1
  182. package/dist/compiler/runtime/set-locale.test.js +182 -0
  183. package/dist/compiler/runtime/set-locale.test.js.map +1 -1
  184. package/dist/compiler/runtime/type.d.ts +2 -0
  185. package/dist/compiler/runtime/type.js.map +1 -1
  186. package/dist/compiler/runtime/type.test.js +34 -0
  187. package/dist/compiler/runtime/type.test.js.map +1 -1
  188. package/dist/compiler/runtime/variables.d.ts +2 -0
  189. package/dist/compiler/runtime/variables.js +7 -0
  190. package/dist/compiler/runtime/variables.js.map +1 -1
  191. package/dist/compiler/server/create-server-file.js +24 -0
  192. package/dist/compiler/server/create-server-file.js.map +1 -1
  193. package/dist/compiler/server/create-server-file.test.js +8 -2
  194. package/dist/compiler/server/create-server-file.test.js.map +1 -1
  195. package/dist/compiler/server/middleware.d.ts +8 -2
  196. package/dist/compiler/server/middleware.js +204 -11
  197. package/dist/compiler/server/middleware.js.map +1 -1
  198. package/dist/compiler/server/middleware.test.js +750 -3
  199. package/dist/compiler/server/middleware.test.js.map +1 -1
  200. package/dist/eslint/index.d.ts +4 -0
  201. package/dist/eslint/index.js +8 -0
  202. package/dist/eslint/index.js.map +1 -0
  203. package/dist/eslint/no-dynamic-message-access.d.ts +3 -0
  204. package/dist/eslint/no-dynamic-message-access.js +150 -0
  205. package/dist/eslint/no-dynamic-message-access.js.map +1 -0
  206. package/dist/eslint/no-dynamic-message-access.test.d.ts +1 -0
  207. package/dist/eslint/no-dynamic-message-access.test.js +126 -0
  208. package/dist/eslint/no-dynamic-message-access.test.js.map +1 -0
  209. package/dist/eslint/oxlint.test.d.ts +1 -0
  210. package/dist/eslint/oxlint.test.js +64 -0
  211. package/dist/eslint/oxlint.test.js.map +1 -0
  212. package/dist/services/config/config-schema.d.ts +2 -0
  213. package/dist/services/config/config-schema.js +2 -0
  214. package/dist/services/config/config-schema.js.map +1 -1
  215. package/dist/services/config/load-paraglide-config.test.js +12 -0
  216. package/dist/services/config/load-paraglide-config.test.js.map +1 -1
  217. package/dist/services/env-variables/index.js +1 -1
  218. package/dist/services/env-variables/index.js.map +1 -1
  219. package/dist/services/file-handling/write-output.bench.js +51 -11
  220. package/dist/services/file-handling/write-output.bench.js.map +1 -1
  221. package/dist/services/file-handling/write-output.js +60 -20
  222. package/dist/services/file-handling/write-output.js.map +1 -1
  223. package/dist/services/file-handling/write-output.test.js +175 -0
  224. package/dist/services/file-handling/write-output.test.js.map +1 -1
  225. package/package.json +15 -5
@@ -1,43 +1,47 @@
1
1
  /**
2
2
  * Creates the README.md content for the compiled output.
3
3
  *
4
- * This helps LLMs understand the compiled Paraglide JS output.
4
+ * The README tells coding agents what this generated folder is, what to edit
5
+ * instead, and where inlang tooling ends and Paraglide JS begins.
5
6
  * See https://llmstxt.org/ for the format guidelines.
6
7
  */
7
8
  export function createReadme(args) {
8
9
  const compiledFromLine = args.projectPath
9
10
  ? `\nCompiled from: \`${args.projectPath}\`\n`
10
11
  : "";
12
+ const projectPath = args.projectPath ?? "./project.inlang";
13
+ const gitignoreNote = args.gitignored === false
14
+ ? ""
15
+ : " This folder is git-ignored (see `.gitignore`), so don't commit it.";
11
16
  return `# Paraglide JS Compiled Output
12
17
 
13
- > Auto-generated i18n message functions. Import \`messages.js\` to use translated strings.
18
+ > Generated by [Paraglide JS](https://paraglidejs.com). Do not edit: every file here is overwritten on the next compile.
14
19
  ${compiledFromLine}
15
-
16
20
  ## What is this folder?
17
21
 
18
- This folder contains compiled [Paraglide JS](https://github.com/opral/paraglide-js) output. Paraglide JS compiles your translation messages into tree-shakeable JavaScript functions.
22
+ Paraglide JS is a compiler-based i18n library. It compiles an [inlang](https://inlang.com) project into typesafe message functions. Messages and params are type-checked, unused messages are tree-shaken out of the bundle, and the runtime includes locale detection and localized URLs. It targets Vite-based apps (React, TanStack Start/Router, SvelteKit, Vue, Solid, Astro, ...) and has plugins for other bundlers. It also compiles standalone with its CLI (\`npx @inlang/paraglide-js compile\`), without a bundler.
23
+
24
+ ## Edit the source, not this folder
19
25
 
20
- ## At a glance
26
+ - **Text and translations:** the translation files of the inlang project (see \`pathPattern\` in \`${projectPath}/settings.json\`, for example \`messages/{locale}.json\`). Add, rename and fix messages there.
27
+ - **Locales and file format:** \`${projectPath}/settings.json\`.
28
+ - **Compiler options** (\`strategy\`, \`outdir\`, ...): the bundler plugin options or \`${projectPath}/paraglide.config.*\`.
29
+ - **Regenerate:** the bundler plugin (for example \`paraglideVitePlugin\`) recompiles on dev and build. Without a bundler, run \`npx @inlang/paraglide-js compile --project ${projectPath} --outdir <this folder>\`.${gitignoreNote}
21
30
 
22
- Purpose:
23
- - This folder stores compiled i18n message functions.
24
- - Source translations live outside this folder in your inlang project.
31
+ If a new message has no \`m.*\` function yet, the output is stale: recompile (for example, restart the dev server).
25
32
 
26
- Safe to import:
27
- - \`messages.js\` — all message functions
28
- - \`runtime.js\` — locale utilities
29
- - \`server.js\` — server-side middleware
33
+ ## inlang vs. Paraglide JS
30
34
 
31
- Do not edit:
32
- - All files in this folder are auto-generated.
33
- - Changes will be overwritten on next compilation.
35
+ - **inlang** owns the localization project: messages, translation files, \`settings.json\`, plugins, and the tooling around them. Use the inlang CLI for [checks](https://inlang.com/m/2qj2w8pu/app-inlang-cli#check) (\`npx @inlang/cli check --project ${projectPath}\` finds missing translations and unused messages) and [machine translation](https://inlang.com/m/2qj2w8pu/app-inlang-cli#machine-translate). Translators can use [Fink](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor), designers [Parrot](https://inlang.com/m/gkrpgoir/app-parrot-figmaPlugin) in Figma, and developers [Sherlock](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) in VS Code. The project folder has its own README.
36
+ - **Paraglide JS** owns this folder: message functions, the locale runtime, and server middleware.
37
+ - The file format (inlang message format, i18next, ICU MessageFormat, ...) is an inlang plugin. Switching formats doesn't change your \`m.*\` calls. See [file formats](https://paraglidejs.com/file-formats). Switching to a runtime library such as i18next gives up the compiled typesafety and tree-shaking; inlang's checks, machine translation and editors keep working through a format plugin. See the [comparison](https://paraglidejs.com/comparison).
34
38
 
35
39
  \`\`\`
36
40
  paraglide/
37
41
  ├── messages.js # Message exports (import this)
38
42
  ├── messages/ # Individual message functions
39
43
  ├── runtime.js # Locale detection & configuration
40
- ├── registry.js # Formatting utilities (plural, number, datetime, relativetime)
44
+ ├── registry.js # Formatters for plural, number, datetime, date, time, relativetime, icu:pound
41
45
  ├── server.js # Server-side middleware
42
46
  └── .gitignore # Marks folder as generated
43
47
  \`\`\`
@@ -45,129 +49,33 @@ paraglide/
45
49
  ## Usage
46
50
 
47
51
  \`\`\`js
48
- import * as m from "./paraglide/messages.js";
49
-
50
- // Messages are functions that return localized strings
51
- m.hello_world(); // "Hello, World!" (in current locale)
52
- m.greeting({ name: "Sam" }); // "Hello, Sam!"
52
+ import { m } from "./paraglide/messages.js";
53
53
 
54
- // Override locale per-call
55
- m.hello_world({}, { locale: "de" }); // "Hallo, Welt!"
54
+ m.hello_world(); // "Hello, World!" (current locale)
55
+ m.greeting({ name: "Sam" }); // "Hello, Sam!"
56
56
  m.greeting({ name: "Sam" }, { locale: "de" }); // "Hallo, Sam!"
57
57
  \`\`\`
58
58
 
59
- ## Runtime API
60
-
61
- \`\`\`js
62
- import { getLocale, getTextDirection, setLocale, locales, baseLocale } from "./paraglide/runtime.js";
63
-
64
- getLocale(); // Current locale, e.g., "en"
65
- getTextDirection(); // "ltr" | "rtl" for current locale
66
- setLocale("de"); // Set locale
67
- locales; // Available locales, e.g., ["en", "de", "fr"]
68
- baseLocale; // Default locale, e.g., "en"
69
- \`\`\`
70
-
71
- ## Strategy
72
-
73
- The strategy determines how the current locale is detected and persisted:
74
-
75
- - **Cookie**: Stores locale preference in a cookie.
76
- - **URL**: Derives locale from URL patterns (e.g., \`/en/about\`, \`en.example.com\`).
77
- - **GlobalVariable**: Uses a global variable (client-side only).
78
- - **BaseLocale**: Always returns the base locale.
79
-
80
- Strategies can be combined. The order defines precedence:
81
-
82
59
  \`\`\`js
83
- await compile({
84
- project: "./project.inlang",
85
- outdir: "./src/paraglide",
86
- strategy: ["url", "cookie", "baseLocale"],
87
- });
88
- \`\`\`
89
-
90
- See the [strategy documentation](https://paraglidejs.com/strategy) for details.
91
-
92
- ## Markup (Rich Text)
93
-
94
- Messages can contain markup tags for bold, links, and other inline elements. Translators control where tags appear; developers control how they render.
95
-
96
- Important:
97
- - Tag names are app-defined. There is no built-in list of HTML tags.
98
- - \`{#b}...{/b}\` does not automatically render as \`<b>...</b>\`.
99
- - Renderers/snippets are looked up by the same tag name used in the message.
100
-
101
- ### Message syntax
102
-
103
- \`\`\`json
104
- {
105
- "cta": "{#link to=|/docs| rel=$relationship @track}Read the docs{/link}",
106
- "welcome": "{#b}Hi {name}{/b}{#icon/}"
107
- }
108
- \`\`\`
109
-
110
- - \`{#tagName}\` opens a tag, \`{/tagName}\` closes it.
111
- - \`{#tagName/}\` creates a standalone tag.
112
- - Options: \`to=|/docs|\` or \`rel=$relationship\` (accessed via \`options.*\`).
113
- - Attributes: \`@track\` or \`@variant=|hero|\` (accessed via \`attributes.*\`).
114
-
115
- This is the default inlang message syntax. Paraglide's message format is plugin-based — you can use [ICU MessageFormat 1](https://inlang.com/m/p7c8m1d2/plugin-inlang-icu-messageformat-1), [i18next](https://inlang.com/m/3i8bor92/plugin-inlang-i18next), or other [plugins](https://inlang.com/c/plugins) instead.
116
-
117
- ### Rendering markup
118
-
119
- Calling the message function still returns **plain text** (markup stripped):
120
-
121
- \`\`\`js
122
- m.cta({ relationship: "noopener" }); // "Read the docs"
123
- \`\`\`
124
-
125
- To render markup, use the framework adapter or the low-level \`parts()\` API:
126
-
127
- \`\`\`js
128
- const parts = m.cta.parts({ relationship: "noopener" });
129
- // [
130
- // { type: "markup-start", name: "link", options: { to: "/docs", rel: "noopener" }, attributes: { track: true } },
131
- // { type: "text", value: "Read the docs" },
132
- // { type: "markup-end", name: "link" }
133
- // ]
134
- \`\`\`
135
-
136
- Framework adapters provide a \`<ParaglideMessage>\` component that accepts markup renderers:
137
-
138
- - \`@inlang/paraglide-js-react\`
139
- - \`@inlang/paraglide-js-vue\`
140
- - \`@inlang/paraglide-js-svelte\`
141
- - \`@inlang/paraglide-js-solid\`
142
-
143
- \`\`\`jsx
144
- import { ParaglideMessage } from "@inlang/paraglide-js-react"; // or -vue, -svelte, -solid
60
+ import { getLocale, setLocale, locales, baseLocale, getTextDirection } from "./paraglide/runtime.js";
145
61
 
146
- <ParaglideMessage
147
- message={m.welcome}
148
- inputs={{ name: "Ada" }}
149
- markup={{
150
- b: ({ children }) => <b>{children}</b>,
151
- icon: () => <span aria-hidden="true" className="icon-wave" />,
152
- }}
153
- />
62
+ getLocale(); // e.g. "en"
63
+ setLocale("de"); // reloads the page by default; pass { reload: false } to skip
64
+ locales; // e.g. ["en", "de"]
65
+ getTextDirection(); // "ltr" | "rtl"
154
66
  \`\`\`
155
67
 
156
- The available renderer/snippet names come from the message itself. You can inspect them through \`message.parts()\`, and TypeScript uses the same names to type-check your markup renderers.
68
+ ## Strategy and localized URLs
157
69
 
158
- See the [markup documentation](https://paraglidejs.com/markup) for details.
70
+ The compiler option \`strategy\` is an ordered list of how the locale is detected and stored; the first strategy that resolves a locale wins (default \`["cookie", "globalVariable", "baseLocale"]\`). Options include \`"url"\` (localized URLs such as \`/de/about\`), \`"cookie"\`, \`"localStorage"\`, \`"preferredLanguage"\`, \`"globalVariable"\`, \`"baseLocale"\` and \`"custom-*"\`. See [strategy](https://paraglidejs.com/strategy) and [i18n routing](https://paraglidejs.com/i18n-routing).
159
71
 
160
- ## Key concepts
72
+ ## Markup
161
73
 
162
- - **Tree-shakeable**: Each message is a function, enabling [up to 70% smaller i18n bundle sizes](https://paraglidejs.com/benchmark) than traditional i18n libraries.
163
- - **Typesafe**: Full TypeScript/JSDoc support with autocomplete.
164
- - **Variants**: Messages can have variants for pluralization, gender, etc.
165
- - **Fallbacks**: Missing translations fall back to the base locale.
74
+ Messages can contain markup such as \`{#link to=|/docs|}Read the docs{/link}\`. Calling the message returns plain text. To render markup, use \`m.key.parts()\` or the \`<ParaglideMessage>\` component from \`@inlang/paraglide-js-react\`, \`-vue\`, \`-svelte\` or \`-solid\`. Tag names are app-defined, so \`{#b}\` does not render \`<b>\` on its own. See [markup](https://paraglidejs.com/markup).
166
75
 
167
76
  ## Links
168
77
 
169
- - [Paraglide JS Documentation](https://paraglidejs.com)
170
- - [Source Repository](https://github.com/opral/paraglide-js)
78
+ - [Paraglide JS documentation](https://paraglidejs.com) and [basics](https://paraglidejs.com/basics)
171
79
  `;
172
80
  }
173
81
  //# sourceMappingURL=create-readme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-readme.js","sourceRoot":"","sources":["../../src/compiler/create-readme.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAA8B;IAC1D,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW;QACxC,CAAC,CAAC,sBAAsB,IAAI,CAAC,WAAW,MAAM;QAC9C,CAAC,CAAC,EAAE,CAAC;IAEN,OAAO;;;EAGN,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6JjB,CAAC;AACF,CAAC","sourcesContent":["/**\n * Creates the README.md content for the compiled output.\n *\n * This helps LLMs understand the compiled Paraglide JS output.\n * See https://llmstxt.org/ for the format guidelines.\n */\nexport function createReadme(args: { projectPath?: string }): string {\n\tconst compiledFromLine = args.projectPath\n\t\t? `\\nCompiled from: \\`${args.projectPath}\\`\\n`\n\t\t: \"\";\n\n\treturn `# Paraglide JS Compiled Output\n\n> Auto-generated i18n message functions. Import \\`messages.js\\` to use translated strings.\n${compiledFromLine}\n\n## What is this folder?\n\nThis folder contains compiled [Paraglide JS](https://github.com/opral/paraglide-js) output. Paraglide JS compiles your translation messages into tree-shakeable JavaScript functions.\n\n## At a glance\n\nPurpose:\n- This folder stores compiled i18n message functions.\n- Source translations live outside this folder in your inlang project.\n\nSafe to import:\n- \\`messages.js\\` — all message functions\n- \\`runtime.js\\` — locale utilities\n- \\`server.js\\` — server-side middleware\n\nDo not edit:\n- All files in this folder are auto-generated.\n- Changes will be overwritten on next compilation.\n\n\\`\\`\\`\nparaglide/\n├── messages.js # Message exports (import this)\n├── messages/ # Individual message functions\n├── runtime.js # Locale detection & configuration\n├── registry.js # Formatting utilities (plural, number, datetime, relativetime)\n├── server.js # Server-side middleware\n└── .gitignore # Marks folder as generated\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`js\nimport * as m from \"./paraglide/messages.js\";\n\n// Messages are functions that return localized strings\nm.hello_world(); // \"Hello, World!\" (in current locale)\nm.greeting({ name: \"Sam\" }); // \"Hello, Sam!\"\n\n// Override locale per-call\nm.hello_world({}, { locale: \"de\" }); // \"Hallo, Welt!\"\nm.greeting({ name: \"Sam\" }, { locale: \"de\" }); // \"Hallo, Sam!\"\n\\`\\`\\`\n\n## Runtime API\n\n\\`\\`\\`js\nimport { getLocale, getTextDirection, setLocale, locales, baseLocale } from \"./paraglide/runtime.js\";\n\ngetLocale(); // Current locale, e.g., \"en\"\ngetTextDirection(); // \"ltr\" | \"rtl\" for current locale\nsetLocale(\"de\"); // Set locale\nlocales; // Available locales, e.g., [\"en\", \"de\", \"fr\"]\nbaseLocale; // Default locale, e.g., \"en\"\n\\`\\`\\`\n\n## Strategy\n\nThe strategy determines how the current locale is detected and persisted:\n\n- **Cookie**: Stores locale preference in a cookie.\n- **URL**: Derives locale from URL patterns (e.g., \\`/en/about\\`, \\`en.example.com\\`).\n- **GlobalVariable**: Uses a global variable (client-side only).\n- **BaseLocale**: Always returns the base locale.\n\nStrategies can be combined. The order defines precedence:\n\n\\`\\`\\`js\nawait compile({\n project: \"./project.inlang\",\n outdir: \"./src/paraglide\",\n strategy: [\"url\", \"cookie\", \"baseLocale\"],\n});\n\\`\\`\\`\n\nSee the [strategy documentation](https://paraglidejs.com/strategy) for details.\n\n## Markup (Rich Text)\n\nMessages can contain markup tags for bold, links, and other inline elements. Translators control where tags appear; developers control how they render.\n\nImportant:\n- Tag names are app-defined. There is no built-in list of HTML tags.\n- \\`{#b}...{/b}\\` does not automatically render as \\`<b>...</b>\\`.\n- Renderers/snippets are looked up by the same tag name used in the message.\n\n### Message syntax\n\n\\`\\`\\`json\n{\n \"cta\": \"{#link to=|/docs| rel=$relationship @track}Read the docs{/link}\",\n \"welcome\": \"{#b}Hi {name}{/b}{#icon/}\"\n}\n\\`\\`\\`\n\n- \\`{#tagName}\\` opens a tag, \\`{/tagName}\\` closes it.\n- \\`{#tagName/}\\` creates a standalone tag.\n- Options: \\`to=|/docs|\\` or \\`rel=$relationship\\` (accessed via \\`options.*\\`).\n- Attributes: \\`@track\\` or \\`@variant=|hero|\\` (accessed via \\`attributes.*\\`).\n\nThis is the default inlang message syntax. Paraglide's message format is plugin-based — you can use [ICU MessageFormat 1](https://inlang.com/m/p7c8m1d2/plugin-inlang-icu-messageformat-1), [i18next](https://inlang.com/m/3i8bor92/plugin-inlang-i18next), or other [plugins](https://inlang.com/c/plugins) instead.\n\n### Rendering markup\n\nCalling the message function still returns **plain text** (markup stripped):\n\n\\`\\`\\`js\nm.cta({ relationship: \"noopener\" }); // \"Read the docs\"\n\\`\\`\\`\n\nTo render markup, use the framework adapter or the low-level \\`parts()\\` API:\n\n\\`\\`\\`js\nconst parts = m.cta.parts({ relationship: \"noopener\" });\n// [\n// { type: \"markup-start\", name: \"link\", options: { to: \"/docs\", rel: \"noopener\" }, attributes: { track: true } },\n// { type: \"text\", value: \"Read the docs\" },\n// { type: \"markup-end\", name: \"link\" }\n// ]\n\\`\\`\\`\n\nFramework adapters provide a \\`<ParaglideMessage>\\` component that accepts markup renderers:\n\n- \\`@inlang/paraglide-js-react\\`\n- \\`@inlang/paraglide-js-vue\\`\n- \\`@inlang/paraglide-js-svelte\\`\n- \\`@inlang/paraglide-js-solid\\`\n\n\\`\\`\\`jsx\nimport { ParaglideMessage } from \"@inlang/paraglide-js-react\"; // or -vue, -svelte, -solid\n\n<ParaglideMessage\n message={m.welcome}\n inputs={{ name: \"Ada\" }}\n markup={{\n b: ({ children }) => <b>{children}</b>,\n icon: () => <span aria-hidden=\"true\" className=\"icon-wave\" />,\n }}\n/>\n\\`\\`\\`\n\nThe available renderer/snippet names come from the message itself. You can inspect them through \\`message.parts()\\`, and TypeScript uses the same names to type-check your markup renderers.\n\nSee the [markup documentation](https://paraglidejs.com/markup) for details.\n\n## Key concepts\n\n- **Tree-shakeable**: Each message is a function, enabling [up to 70% smaller i18n bundle sizes](https://paraglidejs.com/benchmark) than traditional i18n libraries.\n- **Typesafe**: Full TypeScript/JSDoc support with autocomplete.\n- **Variants**: Messages can have variants for pluralization, gender, etc.\n- **Fallbacks**: Missing translations fall back to the base locale.\n\n## Links\n\n- [Paraglide JS Documentation](https://paraglidejs.com)\n- [Source Repository](https://github.com/opral/paraglide-js)\n`;\n}\n"]}
1
+ {"version":3,"file":"create-readme.js","sourceRoot":"","sources":["../../src/compiler/create-readme.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAI5B;IACA,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW;QACxC,CAAC,CAAC,sBAAsB,IAAI,CAAC,WAAW,MAAM;QAC9C,CAAC,CAAC,EAAE,CAAC;IACN,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC3D,MAAM,aAAa,GAClB,IAAI,CAAC,UAAU,KAAK,KAAK;QACxB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,qEAAqE,CAAC;IAE1E,OAAO;;;EAGN,gBAAgB;;;;;;;qGAOmF,WAAW;mCAC7E,WAAW;0FAC4C,WAAW;8KACyE,WAAW,6BAA6B,aAAa;;;;;;2PAMwB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CrQ,CAAC;AACF,CAAC","sourcesContent":["/**\n * Creates the README.md content for the compiled output.\n *\n * The README tells coding agents what this generated folder is, what to edit\n * instead, and where inlang tooling ends and Paraglide JS begins.\n * See https://llmstxt.org/ for the format guidelines.\n */\nexport function createReadme(args: {\n\tprojectPath?: string;\n\t/** Whether the output also contains a `.gitignore` that ignores it. */\n\tgitignored?: boolean;\n}): string {\n\tconst compiledFromLine = args.projectPath\n\t\t? `\\nCompiled from: \\`${args.projectPath}\\`\\n`\n\t\t: \"\";\n\tconst projectPath = args.projectPath ?? \"./project.inlang\";\n\tconst gitignoreNote =\n\t\targs.gitignored === false\n\t\t\t? \"\"\n\t\t\t: \" This folder is git-ignored (see `.gitignore`), so don't commit it.\";\n\n\treturn `# Paraglide JS Compiled Output\n\n> Generated by [Paraglide JS](https://paraglidejs.com). Do not edit: every file here is overwritten on the next compile.\n${compiledFromLine}\n## What is this folder?\n\nParaglide JS is a compiler-based i18n library. It compiles an [inlang](https://inlang.com) project into typesafe message functions. Messages and params are type-checked, unused messages are tree-shaken out of the bundle, and the runtime includes locale detection and localized URLs. It targets Vite-based apps (React, TanStack Start/Router, SvelteKit, Vue, Solid, Astro, ...) and has plugins for other bundlers. It also compiles standalone with its CLI (\\`npx @inlang/paraglide-js compile\\`), without a bundler.\n\n## Edit the source, not this folder\n\n- **Text and translations:** the translation files of the inlang project (see \\`pathPattern\\` in \\`${projectPath}/settings.json\\`, for example \\`messages/{locale}.json\\`). Add, rename and fix messages there.\n- **Locales and file format:** \\`${projectPath}/settings.json\\`.\n- **Compiler options** (\\`strategy\\`, \\`outdir\\`, ...): the bundler plugin options or \\`${projectPath}/paraglide.config.*\\`.\n- **Regenerate:** the bundler plugin (for example \\`paraglideVitePlugin\\`) recompiles on dev and build. Without a bundler, run \\`npx @inlang/paraglide-js compile --project ${projectPath} --outdir <this folder>\\`.${gitignoreNote}\n\nIf a new message has no \\`m.*\\` function yet, the output is stale: recompile (for example, restart the dev server).\n\n## inlang vs. Paraglide JS\n\n- **inlang** owns the localization project: messages, translation files, \\`settings.json\\`, plugins, and the tooling around them. Use the inlang CLI for [checks](https://inlang.com/m/2qj2w8pu/app-inlang-cli#check) (\\`npx @inlang/cli check --project ${projectPath}\\` finds missing translations and unused messages) and [machine translation](https://inlang.com/m/2qj2w8pu/app-inlang-cli#machine-translate). Translators can use [Fink](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor), designers [Parrot](https://inlang.com/m/gkrpgoir/app-parrot-figmaPlugin) in Figma, and developers [Sherlock](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) in VS Code. The project folder has its own README.\n- **Paraglide JS** owns this folder: message functions, the locale runtime, and server middleware.\n- The file format (inlang message format, i18next, ICU MessageFormat, ...) is an inlang plugin. Switching formats doesn't change your \\`m.*\\` calls. See [file formats](https://paraglidejs.com/file-formats). Switching to a runtime library such as i18next gives up the compiled typesafety and tree-shaking; inlang's checks, machine translation and editors keep working through a format plugin. See the [comparison](https://paraglidejs.com/comparison).\n\n\\`\\`\\`\nparaglide/\n├── messages.js # Message exports (import this)\n├── messages/ # Individual message functions\n├── runtime.js # Locale detection & configuration\n├── registry.js # Formatters for plural, number, datetime, date, time, relativetime, icu:pound\n├── server.js # Server-side middleware\n└── .gitignore # Marks folder as generated\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`js\nimport { m } from \"./paraglide/messages.js\";\n\nm.hello_world(); // \"Hello, World!\" (current locale)\nm.greeting({ name: \"Sam\" }); // \"Hello, Sam!\"\nm.greeting({ name: \"Sam\" }, { locale: \"de\" }); // \"Hallo, Sam!\"\n\\`\\`\\`\n\n\\`\\`\\`js\nimport { getLocale, setLocale, locales, baseLocale, getTextDirection } from \"./paraglide/runtime.js\";\n\ngetLocale(); // e.g. \"en\"\nsetLocale(\"de\"); // reloads the page by default; pass { reload: false } to skip\nlocales; // e.g. [\"en\", \"de\"]\ngetTextDirection(); // \"ltr\" | \"rtl\"\n\\`\\`\\`\n\n## Strategy and localized URLs\n\nThe compiler option \\`strategy\\` is an ordered list of how the locale is detected and stored; the first strategy that resolves a locale wins (default \\`[\"cookie\", \"globalVariable\", \"baseLocale\"]\\`). Options include \\`\"url\"\\` (localized URLs such as \\`/de/about\\`), \\`\"cookie\"\\`, \\`\"localStorage\"\\`, \\`\"preferredLanguage\"\\`, \\`\"globalVariable\"\\`, \\`\"baseLocale\"\\` and \\`\"custom-*\"\\`. See [strategy](https://paraglidejs.com/strategy) and [i18n routing](https://paraglidejs.com/i18n-routing).\n\n## Markup\n\nMessages can contain markup such as \\`{#link to=|/docs|}Read the docs{/link}\\`. Calling the message returns plain text. To render markup, use \\`m.key.parts()\\` or the \\`<ParaglideMessage>\\` component from \\`@inlang/paraglide-js-react\\`, \\`-vue\\`, \\`-svelte\\` or \\`-solid\\`. Tag names are app-defined, so \\`{#b}\\` does not render \\`<b>\\` on its own. See [markup](https://paraglidejs.com/markup).\n\n## Links\n\n- [Paraglide JS documentation](https://paraglidejs.com) and [basics](https://paraglidejs.com/basics)\n`;\n}\n"]}
@@ -33,13 +33,13 @@ test("emitTsDeclarations uses the compiler API for a default-only interop shape
33
33
  messages: [
34
34
  {
35
35
  id: "greeting.hello_en",
36
- bundleId: "greeting.hello",
36
+ bundle_id: "greeting.hello",
37
37
  locale: "en",
38
38
  selectors: [],
39
39
  variants: [
40
40
  {
41
41
  id: "greeting.hello_en_variant",
42
- messageId: "greeting.hello",
42
+ message_id: "greeting.hello",
43
43
  matches: [],
44
44
  pattern: [{ type: "text", value: "Hello" }],
45
45
  },
@@ -1 +1 @@
1
- {"version":3,"file":"emit-ts-declarations.interop.test.js","sourceRoot":"","sources":["../../src/compiler/emit-ts-declarations.interop.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAEN,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,GACV,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,oEAAoE;AACpE,wEAAwE;AACxE,sEAAsE;AACtE,sEAAsE;AACtE,yEAAyE;AACzE,2DAA2D;AAC3D,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,8CAA8C;AAC9C,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAChC,MAAM,MAAM,GACX,MAAM,EAAE,CAAC,YAAY,CAA8B,YAAY,CAAC,CAAC;IAClE,OAAO;QACN,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,SAAS;KACxB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2FAA2F,EAAE,KAAK,IAAI,EAAE;IAC5G,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC;QACzC,IAAI,EAAE,MAAM,UAAU,CAAC;YACtB,QAAQ,EAAE;gBACT,OAAO,EAAE,CAAC,IAAI,CAAC;gBACf,UAAU,EAAE,IAAI;aAChB;SACD,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,GAAiB;QAC5B,EAAE,EAAE,gBAAgB;QACpB,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE;YACT;gBACC,EAAE,EAAE,mBAAmB;gBACvB,QAAQ,EAAE,gBAAgB;gBAC1B,MAAM,EAAE,IAAI;gBACZ,SAAS,EAAE,EAAE;gBACb,QAAQ,EAAE;oBACT;wBACC,EAAE,EAAE,2BAA2B;wBAC/B,SAAS,EAAE,gBAAgB;wBAC3B,OAAO,EAAE,EAAE;wBACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;qBAC3C;iBACD;aACD;SACD;KACD,CAAC;IACF,MAAM,kBAAkB,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QACnC,OAAO;QACP,eAAe,EAAE;YAChB,kBAAkB,EAAE,IAAI;SACxB;KACD,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CACvD,gDAAgD,CAChD,CAAC;AACH,CAAC,CAAC,CAAC","sourcesContent":["import { expect, test, vi } from \"vitest\";\nimport {\n\ttype BundleNested,\n\tinsertBundleNested,\n\tloadProjectInMemory,\n\tnewProject,\n} from \"@inlang/sdk\";\nimport { compileProject } from \"./compile-project.js\";\n\n// Bundlers and CJS interop can deliver the `typescript` module in a\n// default-only shape (`{ default: ts }` without hoisted named exports).\n// TypeScript 5/6 in that shape must still be routed to the in-process\n// compiler API: the CLI fallback intended for TypeScript 7+ would run\n// TypeScript 5's `tsc`, whose declaration emitter produces syntactically\n// invalid unquoted export aliases (`export { x as a.b }`).\n//\n// `createProgram: undefined` is stubbed explicitly because vitest wraps\n// factory mocks in a proxy that throws on missing exports, while a real\n// default-only namespace returns `undefined`.\nvi.mock(\"typescript\", async () => {\n\tconst actual =\n\t\tawait vi.importActual<typeof import(\"typescript\")>(\"typescript\");\n\treturn {\n\t\tdefault: actual,\n\t\tcreateProgram: undefined,\n\t};\n});\n\ntest(\"emitTsDeclarations uses the compiler API for a default-only interop shape of TypeScript 5\", async () => {\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t},\n\t\t}),\n\t});\n\n\tconst bundle: BundleNested = {\n\t\tid: \"greeting.hello\",\n\t\tdeclarations: [],\n\t\tmessages: [\n\t\t\t{\n\t\t\t\tid: \"greeting.hello_en\",\n\t\t\t\tbundleId: \"greeting.hello\",\n\t\t\t\tlocale: \"en\",\n\t\t\t\tselectors: [],\n\t\t\t\tvariants: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"greeting.hello_en_variant\",\n\t\t\t\t\t\tmessageId: \"greeting.hello\",\n\t\t\t\t\t\tmatches: [],\n\t\t\t\t\t\tpattern: [{ type: \"text\", value: \"Hello\" }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\tawait insertBundleNested(project.db, bundle);\n\n\tconst output = await compileProject({\n\t\tproject,\n\t\tcompilerOptions: {\n\t\t\temitTsDeclarations: true,\n\t\t},\n\t});\n\n\texpect(output).toHaveProperty(\"runtime.d.ts\");\n\t// the quoted alias distinguishes the two paths: TypeScript 5's CLI would\n\t// emit the invalid `export { greeting_hello as greeting.hello }` instead\n\texpect(output[\"messages/greeting_hello.d.ts\"]).toContain(\n\t\t`export { greeting_hello as \"greeting.hello\" };`\n\t);\n});\n"]}
1
+ {"version":3,"file":"emit-ts-declarations.interop.test.js","sourceRoot":"","sources":["../../src/compiler/emit-ts-declarations.interop.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAEN,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,GACV,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,oEAAoE;AACpE,wEAAwE;AACxE,sEAAsE;AACtE,sEAAsE;AACtE,yEAAyE;AACzE,2DAA2D;AAC3D,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,8CAA8C;AAC9C,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAChC,MAAM,MAAM,GACX,MAAM,EAAE,CAAC,YAAY,CAA8B,YAAY,CAAC,CAAC;IAClE,OAAO;QACN,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,SAAS;KACxB,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2FAA2F,EAAE,KAAK,IAAI,EAAE;IAC5G,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC;QACzC,IAAI,EAAE,MAAM,UAAU,CAAC;YACtB,QAAQ,EAAE;gBACT,OAAO,EAAE,CAAC,IAAI,CAAC;gBACf,UAAU,EAAE,IAAI;aAChB;SACD,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,GAAiB;QAC5B,EAAE,EAAE,gBAAgB;QACpB,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE;YACT;gBACC,EAAE,EAAE,mBAAmB;gBACvB,SAAS,EAAE,gBAAgB;gBAC3B,MAAM,EAAE,IAAI;gBACZ,SAAS,EAAE,EAAE;gBACb,QAAQ,EAAE;oBACT;wBACC,EAAE,EAAE,2BAA2B;wBAC/B,UAAU,EAAE,gBAAgB;wBAC5B,OAAO,EAAE,EAAE;wBACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;qBAC3C;iBACD;aACD;SACD;KACD,CAAC;IACF,MAAM,kBAAkB,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QACnC,OAAO;QACP,eAAe,EAAE;YAChB,kBAAkB,EAAE,IAAI;SACxB;KACD,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CACvD,gDAAgD,CAChD,CAAC;AACH,CAAC,CAAC,CAAC","sourcesContent":["import { expect, test, vi } from \"vitest\";\nimport {\n\ttype BundleNested,\n\tinsertBundleNested,\n\tloadProjectInMemory,\n\tnewProject,\n} from \"@inlang/sdk\";\nimport { compileProject } from \"./compile-project.js\";\n\n// Bundlers and CJS interop can deliver the `typescript` module in a\n// default-only shape (`{ default: ts }` without hoisted named exports).\n// TypeScript 5/6 in that shape must still be routed to the in-process\n// compiler API: the CLI fallback intended for TypeScript 7+ would run\n// TypeScript 5's `tsc`, whose declaration emitter produces syntactically\n// invalid unquoted export aliases (`export { x as a.b }`).\n//\n// `createProgram: undefined` is stubbed explicitly because vitest wraps\n// factory mocks in a proxy that throws on missing exports, while a real\n// default-only namespace returns `undefined`.\nvi.mock(\"typescript\", async () => {\n\tconst actual =\n\t\tawait vi.importActual<typeof import(\"typescript\")>(\"typescript\");\n\treturn {\n\t\tdefault: actual,\n\t\tcreateProgram: undefined,\n\t};\n});\n\ntest(\"emitTsDeclarations uses the compiler API for a default-only interop shape of TypeScript 5\", async () => {\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t},\n\t\t}),\n\t});\n\n\tconst bundle: BundleNested = {\n\t\tid: \"greeting.hello\",\n\t\tdeclarations: [],\n\t\tmessages: [\n\t\t\t{\n\t\t\t\tid: \"greeting.hello_en\",\n\t\t\t\tbundle_id: \"greeting.hello\",\n\t\t\t\tlocale: \"en\",\n\t\t\t\tselectors: [],\n\t\t\t\tvariants: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"greeting.hello_en_variant\",\n\t\t\t\t\t\tmessage_id: \"greeting.hello\",\n\t\t\t\t\t\tmatches: [],\n\t\t\t\t\t\tpattern: [{ type: \"text\", value: \"Hello\" }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\tawait insertBundleNested(project.db, bundle);\n\n\tconst output = await compileProject({\n\t\tproject,\n\t\tcompilerOptions: {\n\t\t\temitTsDeclarations: true,\n\t\t},\n\t});\n\n\texpect(output).toHaveProperty(\"runtime.d.ts\");\n\t// the quoted alias distinguishes the two paths: TypeScript 5's CLI would\n\t// emit the invalid `export { greeting_hello as greeting.hello }` instead\n\texpect(output[\"messages/greeting_hello.d.ts\"]).toContain(\n\t\t`export { greeting_hello as \"greeting.hello\" };`\n\t);\n});\n"]}
@@ -59,13 +59,13 @@ async function newProjectWithMessages() {
59
59
  messages: [
60
60
  {
61
61
  id: "greeting.hello_en",
62
- bundleId: "greeting.hello",
62
+ bundle_id: "greeting.hello",
63
63
  locale: "en",
64
64
  selectors: [],
65
65
  variants: [
66
66
  {
67
67
  id: "greeting.hello_en_variant",
68
- messageId: "greeting.hello",
68
+ message_id: "greeting.hello",
69
69
  matches: [],
70
70
  pattern: [{ type: "text", value: "Hello" }],
71
71
  },
@@ -80,13 +80,13 @@ async function newProjectWithMessages() {
80
80
  messages: [
81
81
  {
82
82
  id: "balance_en",
83
- bundleId: "balance",
83
+ bundle_id: "balance",
84
84
  locale: "en",
85
85
  selectors: [],
86
86
  variants: [
87
87
  {
88
88
  id: "balance_en_variant",
89
- messageId: "balance",
89
+ message_id: "balance",
90
90
  matches: [],
91
91
  pattern: [
92
92
  { type: "text", value: "You have " },
@@ -1 +1 @@
1
- {"version":3,"file":"emit-ts-declarations.test.js","sourceRoot":"","sources":["../../src/compiler/emit-ts-declarations.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { beforeEach, expect, test, vi } from \"vitest\";\nimport { createProject as typescriptProject, ts } from \"@ts-morph/bootstrap\";\nimport {\n\ttype BundleNested,\n\tinsertBundleNested,\n\tloadProjectInMemory,\n\tnewProject,\n} from \"@inlang/sdk\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { compileProject } from \"./compile-project.js\";\n\n// TypeScript 7 (the Go-based compiler, npm `latest` since 7.0.2) no longer\n// ships the in-process compiler API. Its main entry point only exports\n// `version` and `versionMajorMinor` — no `createProgram`, no `ScriptTarget`,\n// no `ModuleKind`. Emitting declarations must go through the `tsc` CLI\n// instead. https://github.com/opral/paraglide-js/issues/711\n//\n// The repo's own `typescript` dev dependency stays on 5.x for the existing\n// tests; this file swaps in the aliased TypeScript 7 package to simulate a\n// user who upgraded.\n//\n// Note: vitest wraps factory mocks in a proxy that throws on missing exports.\n// The real TypeScript 7 module returns `undefined` for them instead, so the\n// classic compiler API surface is stubbed out explicitly to mirror that.\nvi.mock(\"typescript\", async () => {\n\tconst actual =\n\t\tawait vi.importActual<typeof import(\"typescript-go\")>(\"typescript-go\");\n\treturn {\n\t\t...actual,\n\t\tcreateProgram: undefined,\n\t\tcreateCompilerHost: undefined,\n\t\tcreateSourceFile: undefined,\n\t\tScriptTarget: undefined,\n\t\tScriptKind: undefined,\n\t\tModuleKind: undefined,\n\t\tModuleResolutionKind: undefined,\n\t};\n});\n\n// In production, the `typescript` module and the `tsc` CLI resolve to the\n// same package. In this test the module is mocked with the TypeScript 7\n// alias, so the CLI resolution must point at that alias too — otherwise it\n// would find the repo's TypeScript 5 dev dependency. Mutable so the error\n// path can be tested with a broken resolution.\nconst tscResolution = vi.hoisted(() => ({ tscJsPath: \"\" }));\n\nvi.mock(\"./resolve-tsc-js-path.js\", () => ({\n\tresolveTscJsPath: () => tscResolution.tscJsPath,\n}));\n\nconst typescriptGoTscJsPath = path.join(\n\tpath.dirname(\n\t\tcreateRequire(import.meta.url).resolve(\"typescript-go/package.json\")\n\t),\n\t\"lib\",\n\t\"tsc.js\"\n);\n\nbeforeEach(() => {\n\ttscResolution.tscJsPath = typescriptGoTscJsPath;\n});\n\nasync function newProjectWithMessages() {\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t},\n\t\t}),\n\t});\n\n\t// a message id that is not a valid JS identifier -> quoted export alias\n\tconst quotedAliasBundle: BundleNested = {\n\t\tid: \"greeting.hello\",\n\t\tdeclarations: [],\n\t\tmessages: [\n\t\t\t{\n\t\t\t\tid: \"greeting.hello_en\",\n\t\t\t\tbundleId: \"greeting.hello\",\n\t\t\t\tlocale: \"en\",\n\t\t\t\tselectors: [],\n\t\t\t\tvariants: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"greeting.hello_en_variant\",\n\t\t\t\t\t\tmessageId: \"greeting.hello\",\n\t\t\t\t\t\tmatches: [],\n\t\t\t\t\t\tpattern: [{ type: \"text\", value: \"Hello\" }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\t// a message with an input so the declarations carry a typed parameter\n\tconst parameterizedBundle: BundleNested = {\n\t\tid: \"balance\",\n\t\tdeclarations: [{ type: \"input-variable\", name: \"amount\" }],\n\t\tmessages: [\n\t\t\t{\n\t\t\t\tid: \"balance_en\",\n\t\t\t\tbundleId: \"balance\",\n\t\t\t\tlocale: \"en\",\n\t\t\t\tselectors: [],\n\t\t\t\tvariants: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"balance_en_variant\",\n\t\t\t\t\t\tmessageId: \"balance\",\n\t\t\t\t\t\tmatches: [],\n\t\t\t\t\t\tpattern: [\n\t\t\t\t\t\t\t{ type: \"text\", value: \"You have \" },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"expression\",\n\t\t\t\t\t\t\t\targ: { type: \"variable-reference\", name: \"amount\" },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ type: \"text\", value: \" coins.\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tawait insertBundleNested(project.db, quotedAliasBundle);\n\tawait insertBundleNested(project.db, parameterizedBundle);\n\treturn project;\n}\n\ntest(\"emitTsDeclarations works with TypeScript 7 (tsgo)\", async () => {\n\tconst project = await newProjectWithMessages();\n\n\tfor (const outputStructure of [\n\t\t\"message-modules\",\n\t\t\"locale-modules\",\n\t] as const) {\n\t\tconst output = await compileProject({\n\t\t\tproject,\n\t\t\tcompilerOptions: {\n\t\t\t\temitTsDeclarations: true,\n\t\t\t\toutputStructure,\n\t\t\t\t// path-traversing keys (incl. Windows separators) must be\n\t\t\t\t// silently skipped like on the compiler-API path — neither\n\t\t\t\t// escaping the temp dir nor failing the completeness check\n\t\t\t\tadditionalFiles: {\n\t\t\t\t\t\"../escape.js\": \"export const escape = 1;\",\n\t\t\t\t\t\"foo\\\\..\\\\..\\\\escape.js\": \"export const escape = 1;\",\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\texpect(output[\"../escape.d.ts\"]).toBeUndefined();\n\t\texpect(output[\"foo\\\\..\\\\..\\\\escape.d.ts\"]).toBeUndefined();\n\n\t\texpect(output).toHaveProperty(\"runtime.d.ts\");\n\t\texpect(output).toHaveProperty(\"messages.d.ts\");\n\t\texpect(output).toHaveProperty(\"registry.d.ts\");\n\t\texpect(output[\"runtime.d.ts\"]).toContain(\"getLocale\");\n\n\t\t// TypeScript 5's declaration emitter drops the quotes around export\n\t\t// aliases that are not valid identifiers (worked around by a custom\n\t\t// transformer on the compiler-API path); tsgo emits them correctly.\n\t\tconst declarationFile =\n\t\t\toutputStructure === \"message-modules\"\n\t\t\t\t? \"messages/greeting_hello.d.ts\"\n\t\t\t\t: \"messages/_index.d.ts\";\n\n\t\texpect(output[declarationFile]).toContain(`as \"greeting.hello\"`);\n\n\t\t// the emitted declarations must typecheck for a consumer\n\t\t// (@ts-morph/bootstrap bundles its own compiler and is unaffected\n\t\t// by the TypeScript 7 mock above)\n\t\tconst tsProject = await typescriptProject({\n\t\t\tuseInMemoryFileSystem: true,\n\t\t\tcompilerOptions: {\n\t\t\t\tmodule: ts.ModuleKind.Node16,\n\t\t\t\tmoduleResolution: ts.ModuleResolutionKind.Node16,\n\t\t\t\tstrict: true,\n\t\t\t},\n\t\t});\n\n\t\tfor (const [fileName, code] of Object.entries(output)) {\n\t\t\tif (fileName.endsWith(\".d.ts\")) {\n\t\t\t\ttsProject.createSourceFile(fileName, code);\n\t\t\t}\n\t\t}\n\n\t\ttsProject.createSourceFile(\n\t\t\t\"test.ts\",\n\t\t\t`\n\t\t\t\timport { \"greeting.hello\" as greetingHello, balance } from \"./messages.js\";\n\n\t\t\t\tgreetingHello() satisfies string;\n\t\t\t\tbalance({ amount: 5 }) satisfies string;\n\t\t\t`\n\t\t);\n\n\t\tconst program = tsProject.createProgram();\n\t\tconst diagnostics = ts.getPreEmitDiagnostics(program);\n\t\tfor (const diagnostic of diagnostics) {\n\t\t\tconsole.error(diagnostic.messageText, diagnostic.file?.fileName);\n\t\t}\n\t\texpect(diagnostics.length).toEqual(0);\n\t}\n});\n\ntest(\"emitTsDeclarations throws a descriptive error when the tsc CLI produces no declarations\", async () => {\n\ttscResolution.tscJsPath = path.join(\n\t\tpath.dirname(typescriptGoTscJsPath),\n\t\t\"does-not-exist.js\"\n\t);\n\n\tconst project = await newProjectWithMessages();\n\n\tawait expect(\n\t\tcompileProject({\n\t\t\tproject,\n\t\t\tcompilerOptions: {\n\t\t\t\temitTsDeclarations: true,\n\t\t\t},\n\t\t})\n\t).rejects.toThrow(/did not produce a declaration file for every compiled/);\n});\n"]}
1
+ {"version":3,"file":"emit-ts-declarations.test.js","sourceRoot":"","sources":["../../src/compiler/emit-ts-declarations.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { beforeEach, expect, test, vi } from \"vitest\";\nimport { createProject as typescriptProject, ts } from \"@ts-morph/bootstrap\";\nimport {\n\ttype BundleNested,\n\tinsertBundleNested,\n\tloadProjectInMemory,\n\tnewProject,\n} from \"@inlang/sdk\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { compileProject } from \"./compile-project.js\";\n\n// TypeScript 7 (the Go-based compiler, npm `latest` since 7.0.2) no longer\n// ships the in-process compiler API. Its main entry point only exports\n// `version` and `versionMajorMinor` — no `createProgram`, no `ScriptTarget`,\n// no `ModuleKind`. Emitting declarations must go through the `tsc` CLI\n// instead. https://github.com/opral/paraglide-js/issues/711\n//\n// The repo's own `typescript` dev dependency stays on 5.x for the existing\n// tests; this file swaps in the aliased TypeScript 7 package to simulate a\n// user who upgraded.\n//\n// Note: vitest wraps factory mocks in a proxy that throws on missing exports.\n// The real TypeScript 7 module returns `undefined` for them instead, so the\n// classic compiler API surface is stubbed out explicitly to mirror that.\nvi.mock(\"typescript\", async () => {\n\tconst actual =\n\t\tawait vi.importActual<typeof import(\"typescript-go\")>(\"typescript-go\");\n\treturn {\n\t\t...actual,\n\t\tcreateProgram: undefined,\n\t\tcreateCompilerHost: undefined,\n\t\tcreateSourceFile: undefined,\n\t\tScriptTarget: undefined,\n\t\tScriptKind: undefined,\n\t\tModuleKind: undefined,\n\t\tModuleResolutionKind: undefined,\n\t};\n});\n\n// In production, the `typescript` module and the `tsc` CLI resolve to the\n// same package. In this test the module is mocked with the TypeScript 7\n// alias, so the CLI resolution must point at that alias too — otherwise it\n// would find the repo's TypeScript 5 dev dependency. Mutable so the error\n// path can be tested with a broken resolution.\nconst tscResolution = vi.hoisted(() => ({ tscJsPath: \"\" }));\n\nvi.mock(\"./resolve-tsc-js-path.js\", () => ({\n\tresolveTscJsPath: () => tscResolution.tscJsPath,\n}));\n\nconst typescriptGoTscJsPath = path.join(\n\tpath.dirname(\n\t\tcreateRequire(import.meta.url).resolve(\"typescript-go/package.json\")\n\t),\n\t\"lib\",\n\t\"tsc.js\"\n);\n\nbeforeEach(() => {\n\ttscResolution.tscJsPath = typescriptGoTscJsPath;\n});\n\nasync function newProjectWithMessages() {\n\tconst project = await loadProjectInMemory({\n\t\tblob: await newProject({\n\t\t\tsettings: {\n\t\t\t\tlocales: [\"en\"],\n\t\t\t\tbaseLocale: \"en\",\n\t\t\t},\n\t\t}),\n\t});\n\n\t// a message id that is not a valid JS identifier -> quoted export alias\n\tconst quotedAliasBundle: BundleNested = {\n\t\tid: \"greeting.hello\",\n\t\tdeclarations: [],\n\t\tmessages: [\n\t\t\t{\n\t\t\t\tid: \"greeting.hello_en\",\n\t\t\t\tbundle_id: \"greeting.hello\",\n\t\t\t\tlocale: \"en\",\n\t\t\t\tselectors: [],\n\t\t\t\tvariants: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"greeting.hello_en_variant\",\n\t\t\t\t\t\tmessage_id: \"greeting.hello\",\n\t\t\t\t\t\tmatches: [],\n\t\t\t\t\t\tpattern: [{ type: \"text\", value: \"Hello\" }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\t// a message with an input so the declarations carry a typed parameter\n\tconst parameterizedBundle: BundleNested = {\n\t\tid: \"balance\",\n\t\tdeclarations: [{ type: \"input-variable\", name: \"amount\" }],\n\t\tmessages: [\n\t\t\t{\n\t\t\t\tid: \"balance_en\",\n\t\t\t\tbundle_id: \"balance\",\n\t\t\t\tlocale: \"en\",\n\t\t\t\tselectors: [],\n\t\t\t\tvariants: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"balance_en_variant\",\n\t\t\t\t\t\tmessage_id: \"balance\",\n\t\t\t\t\t\tmatches: [],\n\t\t\t\t\t\tpattern: [\n\t\t\t\t\t\t\t{ type: \"text\", value: \"You have \" },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"expression\",\n\t\t\t\t\t\t\t\targ: { type: \"variable-reference\", name: \"amount\" },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ type: \"text\", value: \" coins.\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t};\n\n\tawait insertBundleNested(project.db, quotedAliasBundle);\n\tawait insertBundleNested(project.db, parameterizedBundle);\n\treturn project;\n}\n\ntest(\"emitTsDeclarations works with TypeScript 7 (tsgo)\", async () => {\n\tconst project = await newProjectWithMessages();\n\n\tfor (const outputStructure of [\n\t\t\"message-modules\",\n\t\t\"locale-modules\",\n\t] as const) {\n\t\tconst output = await compileProject({\n\t\t\tproject,\n\t\t\tcompilerOptions: {\n\t\t\t\temitTsDeclarations: true,\n\t\t\t\toutputStructure,\n\t\t\t\t// path-traversing keys (incl. Windows separators) must be\n\t\t\t\t// silently skipped like on the compiler-API path — neither\n\t\t\t\t// escaping the temp dir nor failing the completeness check\n\t\t\t\tadditionalFiles: {\n\t\t\t\t\t\"../escape.js\": \"export const escape = 1;\",\n\t\t\t\t\t\"foo\\\\..\\\\..\\\\escape.js\": \"export const escape = 1;\",\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\texpect(output[\"../escape.d.ts\"]).toBeUndefined();\n\t\texpect(output[\"foo\\\\..\\\\..\\\\escape.d.ts\"]).toBeUndefined();\n\n\t\texpect(output).toHaveProperty(\"runtime.d.ts\");\n\t\texpect(output).toHaveProperty(\"messages.d.ts\");\n\t\texpect(output).toHaveProperty(\"registry.d.ts\");\n\t\texpect(output[\"runtime.d.ts\"]).toContain(\"getLocale\");\n\n\t\t// TypeScript 5's declaration emitter drops the quotes around export\n\t\t// aliases that are not valid identifiers (worked around by a custom\n\t\t// transformer on the compiler-API path); tsgo emits them correctly.\n\t\tconst declarationFile =\n\t\t\toutputStructure === \"message-modules\"\n\t\t\t\t? \"messages/greeting_hello.d.ts\"\n\t\t\t\t: \"messages/_index.d.ts\";\n\n\t\texpect(output[declarationFile]).toContain(`as \"greeting.hello\"`);\n\n\t\t// the emitted declarations must typecheck for a consumer\n\t\t// (@ts-morph/bootstrap bundles its own compiler and is unaffected\n\t\t// by the TypeScript 7 mock above)\n\t\tconst tsProject = await typescriptProject({\n\t\t\tuseInMemoryFileSystem: true,\n\t\t\tcompilerOptions: {\n\t\t\t\tmodule: ts.ModuleKind.Node16,\n\t\t\t\tmoduleResolution: ts.ModuleResolutionKind.Node16,\n\t\t\t\tstrict: true,\n\t\t\t},\n\t\t});\n\n\t\tfor (const [fileName, code] of Object.entries(output)) {\n\t\t\tif (fileName.endsWith(\".d.ts\")) {\n\t\t\t\ttsProject.createSourceFile(fileName, code);\n\t\t\t}\n\t\t}\n\n\t\ttsProject.createSourceFile(\n\t\t\t\"test.ts\",\n\t\t\t`\n\t\t\t\timport { \"greeting.hello\" as greetingHello, balance } from \"./messages.js\";\n\n\t\t\t\tgreetingHello() satisfies string;\n\t\t\t\tbalance({ amount: 5 }) satisfies string;\n\t\t\t`\n\t\t);\n\n\t\tconst program = tsProject.createProgram();\n\t\tconst diagnostics = ts.getPreEmitDiagnostics(program);\n\t\tfor (const diagnostic of diagnostics) {\n\t\t\tconsole.error(diagnostic.messageText, diagnostic.file?.fileName);\n\t\t}\n\t\texpect(diagnostics.length).toEqual(0);\n\t}\n});\n\ntest(\"emitTsDeclarations throws a descriptive error when the tsc CLI produces no declarations\", async () => {\n\ttscResolution.tscJsPath = path.join(\n\t\tpath.dirname(typescriptGoTscJsPath),\n\t\t\"does-not-exist.js\"\n\t);\n\n\tconst project = await newProjectWithMessages();\n\n\tawait expect(\n\t\tcompileProject({\n\t\t\tproject,\n\t\t\tcompilerOptions: {\n\t\t\t\temitTsDeclarations: true,\n\t\t\t},\n\t\t})\n\t).rejects.toThrow(/did not produce a declaration file for every compiled/);\n});\n"]}
@@ -5,7 +5,7 @@ export type { ServerRuntime } from "./server/type.js";
5
5
  export { compile } from "./compile.js";
6
6
  export { compileProject } from "./compile-project.js";
7
7
  export { compileBundle } from "./compile-bundle.js";
8
- export { compileMessage } from "./compile-message.js";
8
+ export { compileMessage, type CompilableMessage, type CompilableVariant, } from "./compile-message.js";
9
9
  export { compilePattern } from "./compile-pattern.js";
10
10
  export { writeOutput } from "../services/file-handling/write-output.js";
11
11
  export { createParaglide } from "./create-paraglide.js";
@@ -2,7 +2,7 @@ export { defaultCompilerOptions, } from "./compiler-options.js";
2
2
  export { compile } from "./compile.js";
3
3
  export { compileProject } from "./compile-project.js";
4
4
  export { compileBundle } from "./compile-bundle.js";
5
- export { compileMessage } from "./compile-message.js";
5
+ export { compileMessage, } from "./compile-message.js";
6
6
  export { compilePattern } from "./compile-pattern.js";
7
7
  export { writeOutput } from "../services/file-handling/write-output.js";
8
8
  export { createParaglide } from "./create-paraglide.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,sBAAsB,GAEtB,MAAM,uBAAuB,CAAC;AAgB/B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export {\n\tdefaultCompilerOptions,\n\ttype CompilerOptions,\n} from \"./compiler-options.js\";\nexport type {\n\tLocalizedString,\n\tMessagePart,\n\tMessageMarkupAttribute,\n\tMessageMarkupOption,\n\tMessageMarkupAttributes,\n\tMessageMarkupOptions,\n\tMessageMarkupTag,\n\tMessageMarkupSchema,\n\tMessageMetadata,\n\tMessageBundleFunction,\n\tMessageFunction,\n} from \"./types.js\";\nexport type { Runtime } from \"./runtime/type.js\";\nexport type { ServerRuntime } from \"./server/type.js\";\nexport { compile } from \"./compile.js\";\nexport { compileProject } from \"./compile-project.js\";\nexport { compileBundle } from \"./compile-bundle.js\";\nexport { compileMessage } from \"./compile-message.js\";\nexport { compilePattern } from \"./compile-pattern.js\";\nexport { writeOutput } from \"../services/file-handling/write-output.js\";\nexport { createParaglide } from \"./create-paraglide.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,sBAAsB,GAEtB,MAAM,uBAAuB,CAAC;AAgB/B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACN,cAAc,GAGd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["export {\n\tdefaultCompilerOptions,\n\ttype CompilerOptions,\n} from \"./compiler-options.js\";\nexport type {\n\tLocalizedString,\n\tMessagePart,\n\tMessageMarkupAttribute,\n\tMessageMarkupOption,\n\tMessageMarkupAttributes,\n\tMessageMarkupOptions,\n\tMessageMarkupTag,\n\tMessageMarkupSchema,\n\tMessageMetadata,\n\tMessageBundleFunction,\n\tMessageFunction,\n} from \"./types.js\";\nexport type { Runtime } from \"./runtime/type.js\";\nexport type { ServerRuntime } from \"./server/type.js\";\nexport { compile } from \"./compile.js\";\nexport { compileProject } from \"./compile-project.js\";\nexport { compileBundle } from \"./compile-bundle.js\";\nexport {\n\tcompileMessage,\n\ttype CompilableMessage,\n\ttype CompilableVariant,\n} from \"./compile-message.js\";\nexport { compilePattern } from \"./compile-pattern.js\";\nexport { writeOutput } from \"../services/file-handling/write-output.js\";\nexport { createParaglide } from \"./create-paraglide.js\";\n"]}
@@ -0,0 +1,21 @@
1
+ import type { Declaration } from "@inlang/sdk";
2
+ /**
3
+ * Returns the name of the input a variable holds the unmodified value of, or
4
+ * `undefined` if the variable can hold anything else.
5
+ *
6
+ * Inputs resolve to themselves. A local variable resolves to an input when it
7
+ * is an un-annotated reference to an input, directly or through a chain of
8
+ * un-annotated local variables. Annotated locals (`:plural`, `:number`, ...)
9
+ * and literal values do not resolve, because their value is not the input.
10
+ *
11
+ * Message selectors use this to match aliases like the ones ICU MessageFormat 1
12
+ * imports produce for exact number cases (`=0`) the same way as the input:
13
+ *
14
+ * @example
15
+ * // .input {$count}
16
+ * // .local countPluralExact = {$count}
17
+ * // .local countPlural = {$count :plural}
18
+ * resolveInputAlias("countPluralExact", declarations) // "count"
19
+ * resolveInputAlias("countPlural", declarations) // undefined
20
+ */
21
+ export declare function resolveInputAlias(name: string, declarations: readonly Declaration[]): string | undefined;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Returns the name of the input a variable holds the unmodified value of, or
3
+ * `undefined` if the variable can hold anything else.
4
+ *
5
+ * Inputs resolve to themselves. A local variable resolves to an input when it
6
+ * is an un-annotated reference to an input, directly or through a chain of
7
+ * un-annotated local variables. Annotated locals (`:plural`, `:number`, ...)
8
+ * and literal values do not resolve, because their value is not the input.
9
+ *
10
+ * Message selectors use this to match aliases like the ones ICU MessageFormat 1
11
+ * imports produce for exact number cases (`=0`) the same way as the input:
12
+ *
13
+ * @example
14
+ * // .input {$count}
15
+ * // .local countPluralExact = {$count}
16
+ * // .local countPlural = {$count :plural}
17
+ * resolveInputAlias("countPluralExact", declarations) // "count"
18
+ * resolveInputAlias("countPlural", declarations) // undefined
19
+ */
20
+ export function resolveInputAlias(name, declarations) {
21
+ const visited = new Set();
22
+ let current = name;
23
+ while (!visited.has(current)) {
24
+ visited.add(current);
25
+ // first declaration wins, consistent with compileVariableAccess()
26
+ const declaration = declarations.find((candidate) => candidate.name === current);
27
+ if (!declaration) {
28
+ return undefined;
29
+ }
30
+ if (declaration.type === "input-variable") {
31
+ return declaration.name;
32
+ }
33
+ if (declaration.value.annotation ||
34
+ declaration.value.arg.type !== "variable-reference") {
35
+ return undefined;
36
+ }
37
+ current = declaration.value.arg.name;
38
+ }
39
+ // cyclic local variable references
40
+ return undefined;
41
+ }
42
+ //# sourceMappingURL=input-alias.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-alias.js","sourceRoot":"","sources":["../../src/compiler/input-alias.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,iBAAiB,CAChC,IAAY,EACZ,YAAoC;IAEpC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,kEAAkE;QAClE,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CACpC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO,CACzC,CAAC;QACF,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC3C,OAAO,WAAW,CAAC,IAAI,CAAC;QACzB,CAAC;QACD,IACC,WAAW,CAAC,KAAK,CAAC,UAAU;YAC5B,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,oBAAoB,EAClD,CAAC;YACF,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACtC,CAAC;IAED,mCAAmC;IACnC,OAAO,SAAS,CAAC;AAClB,CAAC","sourcesContent":["import type { Declaration } from \"@inlang/sdk\";\n\n/**\n * Returns the name of the input a variable holds the unmodified value of, or\n * `undefined` if the variable can hold anything else.\n *\n * Inputs resolve to themselves. A local variable resolves to an input when it\n * is an un-annotated reference to an input, directly or through a chain of\n * un-annotated local variables. Annotated locals (`:plural`, `:number`, ...)\n * and literal values do not resolve, because their value is not the input.\n *\n * Message selectors use this to match aliases like the ones ICU MessageFormat 1\n * imports produce for exact number cases (`=0`) the same way as the input:\n *\n * @example\n * // .input {$count}\n * // .local countPluralExact = {$count}\n * // .local countPlural = {$count :plural}\n * resolveInputAlias(\"countPluralExact\", declarations) // \"count\"\n * resolveInputAlias(\"countPlural\", declarations) // undefined\n */\nexport function resolveInputAlias(\n\tname: string,\n\tdeclarations: readonly Declaration[]\n): string | undefined {\n\tconst visited = new Set<string>();\n\tlet current = name;\n\n\twhile (!visited.has(current)) {\n\t\tvisited.add(current);\n\t\t// first declaration wins, consistent with compileVariableAccess()\n\t\tconst declaration = declarations.find(\n\t\t\t(candidate) => candidate.name === current\n\t\t);\n\t\tif (!declaration) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (declaration.type === \"input-variable\") {\n\t\t\treturn declaration.name;\n\t\t}\n\t\tif (\n\t\t\tdeclaration.value.annotation ||\n\t\t\tdeclaration.value.arg.type !== \"variable-reference\"\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\tcurrent = declaration.value.arg.name;\n\t}\n\n\t// cyclic local variable references\n\treturn undefined;\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ import { expect, test } from "vitest";
2
+ import { resolveInputAlias } from "./input-alias.js";
3
+ const alias = (name, target) => ({
4
+ type: "local-variable",
5
+ name,
6
+ value: {
7
+ type: "expression",
8
+ arg: { type: "variable-reference", name: target },
9
+ },
10
+ });
11
+ test("resolves inputs and chains of un-annotated aliases to the input", () => {
12
+ const declarations = [
13
+ { type: "input-variable", name: "count" },
14
+ alias("a", "count"),
15
+ alias("b", "a"),
16
+ ];
17
+ expect(resolveInputAlias("count", declarations)).toBe("count");
18
+ expect(resolveInputAlias("a", declarations)).toBe("count");
19
+ expect(resolveInputAlias("b", declarations)).toBe("count");
20
+ });
21
+ test("does not resolve annotated locals, literals, aliases of them, or undeclared names", () => {
22
+ const declarations = [
23
+ { type: "input-variable", name: "count" },
24
+ {
25
+ type: "local-variable",
26
+ name: "countPlural",
27
+ value: {
28
+ type: "expression",
29
+ arg: { type: "variable-reference", name: "count" },
30
+ annotation: { type: "function-reference", name: "plural", options: [] },
31
+ },
32
+ },
33
+ alias("pluralAlias", "countPlural"),
34
+ {
35
+ type: "local-variable",
36
+ name: "constant",
37
+ value: { type: "expression", arg: { type: "literal", value: "0" } },
38
+ },
39
+ alias("undeclaredAlias", "missing"),
40
+ ];
41
+ expect(resolveInputAlias("countPlural", declarations)).toBeUndefined();
42
+ expect(resolveInputAlias("pluralAlias", declarations)).toBeUndefined();
43
+ expect(resolveInputAlias("constant", declarations)).toBeUndefined();
44
+ expect(resolveInputAlias("undeclaredAlias", declarations)).toBeUndefined();
45
+ expect(resolveInputAlias("missing", declarations)).toBeUndefined();
46
+ });
47
+ test("terminates on cyclic aliases", () => {
48
+ const declarations = [
49
+ alias("self", "self"),
50
+ alias("a", "b"),
51
+ alias("b", "c"),
52
+ alias("c", "a"),
53
+ ];
54
+ expect(resolveInputAlias("self", declarations)).toBeUndefined();
55
+ expect(resolveInputAlias("a", declarations)).toBeUndefined();
56
+ expect(resolveInputAlias("c", declarations)).toBeUndefined();
57
+ });
58
+ //# sourceMappingURL=input-alias.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-alias.test.js","sourceRoot":"","sources":["../../src/compiler/input-alias.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, test } from \"vitest\";\nimport type { Declaration } from \"@inlang/sdk\";\nimport { resolveInputAlias } from \"./input-alias.js\";\n\nconst alias = (name: string, target: string): Declaration => ({\n\ttype: \"local-variable\",\n\tname,\n\tvalue: {\n\t\ttype: \"expression\",\n\t\targ: { type: \"variable-reference\", name: target },\n\t},\n});\n\ntest(\"resolves inputs and chains of un-annotated aliases to the input\", () => {\n\tconst declarations: Declaration[] = [\n\t\t{ type: \"input-variable\", name: \"count\" },\n\t\talias(\"a\", \"count\"),\n\t\talias(\"b\", \"a\"),\n\t];\n\n\texpect(resolveInputAlias(\"count\", declarations)).toBe(\"count\");\n\texpect(resolveInputAlias(\"a\", declarations)).toBe(\"count\");\n\texpect(resolveInputAlias(\"b\", declarations)).toBe(\"count\");\n});\n\ntest(\"does not resolve annotated locals, literals, aliases of them, or undeclared names\", () => {\n\tconst declarations: Declaration[] = [\n\t\t{ type: \"input-variable\", name: \"count\" },\n\t\t{\n\t\t\ttype: \"local-variable\",\n\t\t\tname: \"countPlural\",\n\t\t\tvalue: {\n\t\t\t\ttype: \"expression\",\n\t\t\t\targ: { type: \"variable-reference\", name: \"count\" },\n\t\t\t\tannotation: { type: \"function-reference\", name: \"plural\", options: [] },\n\t\t\t},\n\t\t},\n\t\talias(\"pluralAlias\", \"countPlural\"),\n\t\t{\n\t\t\ttype: \"local-variable\",\n\t\t\tname: \"constant\",\n\t\t\tvalue: { type: \"expression\", arg: { type: \"literal\", value: \"0\" } },\n\t\t},\n\t\talias(\"undeclaredAlias\", \"missing\"),\n\t];\n\n\texpect(resolveInputAlias(\"countPlural\", declarations)).toBeUndefined();\n\texpect(resolveInputAlias(\"pluralAlias\", declarations)).toBeUndefined();\n\texpect(resolveInputAlias(\"constant\", declarations)).toBeUndefined();\n\texpect(resolveInputAlias(\"undeclaredAlias\", declarations)).toBeUndefined();\n\texpect(resolveInputAlias(\"missing\", declarations)).toBeUndefined();\n});\n\ntest(\"terminates on cyclic aliases\", () => {\n\tconst declarations: Declaration[] = [\n\t\talias(\"self\", \"self\"),\n\t\talias(\"a\", \"b\"),\n\t\talias(\"b\", \"c\"),\n\t\talias(\"c\", \"a\"),\n\t];\n\n\texpect(resolveInputAlias(\"self\", declarations)).toBeUndefined();\n\texpect(resolveInputAlias(\"a\", declarations)).toBeUndefined();\n\texpect(resolveInputAlias(\"c\", declarations)).toBeUndefined();\n});\n"]}
@@ -0,0 +1,46 @@
1
+ import type { Declaration, LocalVariable, Pattern } from "@inlang/sdk";
2
+ import type { CompilePatternMode } from "./compile-pattern.js";
3
+ /**
4
+ * Returns the names of the variables a compiled pattern reads.
5
+ *
6
+ * Mirrors what `compilePattern()` emits: expression arguments, the options of
7
+ * registry function annotations (unknown annotations are dropped from the
8
+ * output), and in `parts` mode the options of markup.
9
+ */
10
+ export declare function patternVariableReferences(pattern: Pattern, mode: CompilePatternMode): string[];
11
+ /**
12
+ * Returns the names of the variables a compiled local variable reads.
13
+ *
14
+ * Mirrors what `compileLocalVariable()` emits: the argument and the options
15
+ * of a registry function annotation (unknown annotations are dropped).
16
+ */
17
+ export declare function localVariableReferences(declaration: LocalVariable): string[];
18
+ /**
19
+ * Resolves the local variables a message function has to declare.
20
+ *
21
+ * Starting from the variables the function body reads (patterns, match
22
+ * conditions), it follows local variables to the variables they read in turn
23
+ * and returns only the locals that are read, ordered so that every local is
24
+ * declared after the locals it reads. Locals the message does not read are
25
+ * left out, so the output passes `noUnusedLocals`.
26
+ *
27
+ * Throws if a read variable is not declared, or if locals reference each
28
+ * other in a cycle, because the emitted code would throw a `ReferenceError`
29
+ * at runtime.
30
+ *
31
+ * @example
32
+ * // .input {$count}
33
+ * // .local countPlural = {$count :plural}
34
+ * // .local countPluralExact = {$count}
35
+ * resolveMessageLocals({ reads: ["countPlural"], ... })
36
+ * // { locals: [countPlural], readsInput: true }
37
+ */
38
+ export declare function resolveMessageLocals(args: {
39
+ reads: Iterable<string>;
40
+ declarations: readonly Declaration[];
41
+ bundleId: string;
42
+ locale: string;
43
+ }): {
44
+ locals: LocalVariable[];
45
+ readsInput: boolean;
46
+ };