@gtkx/cli 1.6.0 → 2.0.0-beta.10

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 (578) hide show
  1. package/README.md +47 -44
  2. package/bin/gtkx-dev-runner.js +5 -1
  3. package/bin/gtkx.js +5 -1
  4. package/dist/builder.d.ts +1 -0
  5. package/dist/builder.d.ts.map +1 -1
  6. package/dist/builder.js +44 -12
  7. package/dist/builder.js.map +1 -1
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +14 -2
  11. package/dist/cli.js.map +1 -1
  12. package/dist/codegen/config-dependencies.d.ts +3 -0
  13. package/dist/codegen/config-dependencies.d.ts.map +1 -0
  14. package/dist/codegen/config-dependencies.js +355 -0
  15. package/dist/codegen/config-dependencies.js.map +1 -0
  16. package/dist/codegen/freshness.d.ts.map +1 -1
  17. package/dist/codegen/freshness.js +49 -16
  18. package/dist/codegen/freshness.js.map +1 -1
  19. package/dist/codegen/reference.d.ts.map +1 -1
  20. package/dist/codegen/reference.js +2 -7
  21. package/dist/codegen/reference.js.map +1 -1
  22. package/dist/codegen/report.d.ts.map +1 -1
  23. package/dist/codegen/report.js +5 -16
  24. package/dist/codegen/report.js.map +1 -1
  25. package/dist/codegen/run-codegen.d.ts +9 -8
  26. package/dist/codegen/run-codegen.d.ts.map +1 -1
  27. package/dist/codegen/run-codegen.js +60 -113
  28. package/dist/codegen/run-codegen.js.map +1 -1
  29. package/dist/codegen/store-resolver.d.ts +3 -2
  30. package/dist/codegen/store-resolver.d.ts.map +1 -1
  31. package/dist/codegen/store-resolver.js +14 -20
  32. package/dist/codegen/store-resolver.js.map +1 -1
  33. package/dist/commands/build.d.ts +5 -0
  34. package/dist/commands/build.d.ts.map +1 -1
  35. package/dist/commands/build.js +83 -10
  36. package/dist/commands/build.js.map +1 -1
  37. package/dist/commands/cleanup.d.ts +9 -0
  38. package/dist/commands/cleanup.d.ts.map +1 -0
  39. package/dist/commands/cleanup.js +42 -0
  40. package/dist/commands/cleanup.js.map +1 -0
  41. package/dist/commands/codegen.d.ts +1 -0
  42. package/dist/commands/codegen.d.ts.map +1 -1
  43. package/dist/commands/codegen.js +6 -5
  44. package/dist/commands/codegen.js.map +1 -1
  45. package/dist/commands/deploy.d.ts +5 -0
  46. package/dist/commands/deploy.d.ts.map +1 -1
  47. package/dist/commands/deploy.js +10 -2
  48. package/dist/commands/deploy.js.map +1 -1
  49. package/dist/commands/dev.d.ts +9 -0
  50. package/dist/commands/dev.d.ts.map +1 -1
  51. package/dist/commands/dev.js +31 -4
  52. package/dist/commands/dev.js.map +1 -1
  53. package/dist/commands/docs.d.ts.map +1 -1
  54. package/dist/commands/docs.js +6 -15
  55. package/dist/commands/docs.js.map +1 -1
  56. package/dist/deploy/depends.d.ts.map +1 -1
  57. package/dist/deploy/depends.js +24 -2
  58. package/dist/deploy/depends.js.map +1 -1
  59. package/dist/deploy/download.d.ts +7 -3
  60. package/dist/deploy/download.d.ts.map +1 -1
  61. package/dist/deploy/download.js +19 -20
  62. package/dist/deploy/download.js.map +1 -1
  63. package/dist/deploy/freedesktop/copyright.d.ts.map +1 -1
  64. package/dist/deploy/freedesktop/copyright.js +2 -13
  65. package/dist/deploy/freedesktop/copyright.js.map +1 -1
  66. package/dist/deploy/freedesktop/metainfo.d.ts.map +1 -1
  67. package/dist/deploy/freedesktop/metainfo.js +41 -2
  68. package/dist/deploy/freedesktop/metainfo.js.map +1 -1
  69. package/dist/deploy/freedesktop/validate.d.ts.map +1 -1
  70. package/dist/deploy/freedesktop/validate.js +58 -14
  71. package/dist/deploy/freedesktop/validate.js.map +1 -1
  72. package/dist/deploy/freedesktop/xml.d.ts.map +1 -1
  73. package/dist/deploy/freedesktop/xml.js +21 -25
  74. package/dist/deploy/freedesktop/xml.js.map +1 -1
  75. package/dist/deploy/native-addon.d.ts +5 -0
  76. package/dist/deploy/native-addon.d.ts.map +1 -0
  77. package/dist/deploy/native-addon.js +134 -0
  78. package/dist/deploy/native-addon.js.map +1 -0
  79. package/dist/deploy/nfpm/config.d.ts +3 -2
  80. package/dist/deploy/nfpm/config.d.ts.map +1 -1
  81. package/dist/deploy/nfpm/config.js +7 -4
  82. package/dist/deploy/nfpm/config.js.map +1 -1
  83. package/dist/deploy/nfpm/contents.d.ts.map +1 -1
  84. package/dist/deploy/nfpm/contents.js +8 -0
  85. package/dist/deploy/nfpm/contents.js.map +1 -1
  86. package/dist/deploy/node-runtime/download.js +2 -2
  87. package/dist/deploy/node-runtime/download.js.map +1 -1
  88. package/dist/deploy/node-runtime/elf.d.ts +4 -1
  89. package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
  90. package/dist/deploy/node-runtime/elf.js +34 -5
  91. package/dist/deploy/node-runtime/elf.js.map +1 -1
  92. package/dist/deploy/node-runtime/guard.d.ts.map +1 -1
  93. package/dist/deploy/node-runtime/guard.js +7 -14
  94. package/dist/deploy/node-runtime/guard.js.map +1 -1
  95. package/dist/deploy/node-runtime/index.d.ts +3 -1
  96. package/dist/deploy/node-runtime/index.d.ts.map +1 -1
  97. package/dist/deploy/node-runtime/index.js +103 -10
  98. package/dist/deploy/node-runtime/index.js.map +1 -1
  99. package/dist/deploy/node-runtime/license.d.ts.map +1 -1
  100. package/dist/deploy/node-runtime/license.js +2 -9
  101. package/dist/deploy/node-runtime/license.js.map +1 -1
  102. package/dist/deploy/node-runtime/sonames.d.ts +5 -0
  103. package/dist/deploy/node-runtime/sonames.d.ts.map +1 -0
  104. package/dist/deploy/node-runtime/sonames.js +13 -0
  105. package/dist/deploy/node-runtime/sonames.js.map +1 -0
  106. package/dist/deploy/notices/node-runtime.js +2 -2
  107. package/dist/deploy/notices/node-runtime.js.map +1 -1
  108. package/dist/deploy/notices/packages.d.ts.map +1 -1
  109. package/dist/deploy/notices/packages.js +3 -10
  110. package/dist/deploy/notices/packages.js.map +1 -1
  111. package/dist/deploy/payload/copy-tree.d.ts.map +1 -1
  112. package/dist/deploy/payload/copy-tree.js +3 -3
  113. package/dist/deploy/payload/copy-tree.js.map +1 -1
  114. package/dist/deploy/payload/launcher.d.ts.map +1 -1
  115. package/dist/deploy/payload/launcher.js +14 -1
  116. package/dist/deploy/payload/launcher.js.map +1 -1
  117. package/dist/deploy/payload/stage.d.ts +2 -1
  118. package/dist/deploy/payload/stage.d.ts.map +1 -1
  119. package/dist/deploy/payload/stage.js +47 -8
  120. package/dist/deploy/payload/stage.js.map +1 -1
  121. package/dist/deploy/run-deploy.d.ts +2 -0
  122. package/dist/deploy/run-deploy.d.ts.map +1 -1
  123. package/dist/deploy/run-deploy.js +197 -52
  124. package/dist/deploy/run-deploy.js.map +1 -1
  125. package/dist/deploy/settings/arch.d.ts +9 -3
  126. package/dist/deploy/settings/arch.d.ts.map +1 -1
  127. package/dist/deploy/settings/arch.js +27 -6
  128. package/dist/deploy/settings/arch.js.map +1 -1
  129. package/dist/deploy/settings/build-manifest.d.ts +6 -1
  130. package/dist/deploy/settings/build-manifest.d.ts.map +1 -1
  131. package/dist/deploy/settings/build-manifest.js +17 -17
  132. package/dist/deploy/settings/build-manifest.js.map +1 -1
  133. package/dist/deploy/settings/extra-files.d.ts +1 -1
  134. package/dist/deploy/settings/extra-files.d.ts.map +1 -1
  135. package/dist/deploy/settings/extra-files.js +25 -3
  136. package/dist/deploy/settings/extra-files.js.map +1 -1
  137. package/dist/deploy/settings/index.d.ts +3 -1
  138. package/dist/deploy/settings/index.d.ts.map +1 -1
  139. package/dist/deploy/settings/index.js +4 -2
  140. package/dist/deploy/settings/index.js.map +1 -1
  141. package/dist/deploy/settings/libraries.d.ts.map +1 -1
  142. package/dist/deploy/settings/libraries.js +3 -19
  143. package/dist/deploy/settings/libraries.js.map +1 -1
  144. package/dist/deploy/settings/paths.d.ts +4 -3
  145. package/dist/deploy/settings/paths.d.ts.map +1 -1
  146. package/dist/deploy/settings/paths.js +118 -19
  147. package/dist/deploy/settings/paths.js.map +1 -1
  148. package/dist/deploy/settings/screenshots.d.ts.map +1 -1
  149. package/dist/deploy/settings/screenshots.js +6 -31
  150. package/dist/deploy/settings/screenshots.js.map +1 -1
  151. package/dist/deploy/targets/appimage.d.ts.map +1 -1
  152. package/dist/deploy/targets/appimage.js +1 -0
  153. package/dist/deploy/targets/appimage.js.map +1 -1
  154. package/dist/deploy/targets/flatpak-pnpm.js +4 -4
  155. package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
  156. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
  157. package/dist/deploy/targets/flatpak-source.js +17 -6
  158. package/dist/deploy/targets/flatpak-source.js.map +1 -1
  159. package/dist/deploy/targets/flatpak-sources.js +1 -1
  160. package/dist/deploy/targets/flatpak-sources.js.map +1 -1
  161. package/dist/deploy/targets/flatpak.d.ts.map +1 -1
  162. package/dist/deploy/targets/flatpak.js +1 -0
  163. package/dist/deploy/targets/flatpak.js.map +1 -1
  164. package/dist/deploy/targets/nfpm-target.d.ts.map +1 -1
  165. package/dist/deploy/targets/nfpm-target.js +13 -7
  166. package/dist/deploy/targets/nfpm-target.js.map +1 -1
  167. package/dist/deploy/types.d.ts +5 -2
  168. package/dist/deploy/types.d.ts.map +1 -1
  169. package/dist/deploy/types.js.map +1 -1
  170. package/dist/deploy/vendored/appimagetool.js +2 -2
  171. package/dist/deploy/vendored/appimagetool.js.map +1 -1
  172. package/dist/deploy/vendored/nfpm.js +1 -1
  173. package/dist/deploy/vendored/nfpm.js.map +1 -1
  174. package/dist/dev/catalog-writes.d.ts +8 -0
  175. package/dist/dev/catalog-writes.d.ts.map +1 -0
  176. package/dist/dev/catalog-writes.js +26 -0
  177. package/dist/dev/catalog-writes.js.map +1 -0
  178. package/dist/dev/entry-env.d.ts +2 -1
  179. package/dist/dev/entry-env.d.ts.map +1 -1
  180. package/dist/dev/entry-env.js +2 -1
  181. package/dist/dev/entry-env.js.map +1 -1
  182. package/dist/dev/font-dir.d.ts +3 -0
  183. package/dist/dev/font-dir.d.ts.map +1 -0
  184. package/dist/dev/font-dir.js +9 -0
  185. package/dist/dev/font-dir.js.map +1 -0
  186. package/dist/dev/headless.d.ts +3 -0
  187. package/dist/dev/headless.d.ts.map +1 -0
  188. package/dist/dev/headless.js +35 -0
  189. package/dist/dev/headless.js.map +1 -0
  190. package/dist/dev/runner-deps.d.ts +1 -1
  191. package/dist/dev/runner-deps.d.ts.map +1 -1
  192. package/dist/dev/runner-deps.js +12 -7
  193. package/dist/dev/runner-deps.js.map +1 -1
  194. package/dist/dev/runner-main.d.ts.map +1 -1
  195. package/dist/dev/runner-main.js +11 -5
  196. package/dist/dev/runner-main.js.map +1 -1
  197. package/dist/dev/runner.d.ts +2 -0
  198. package/dist/dev/runner.d.ts.map +1 -1
  199. package/dist/dev/runner.js +26 -7
  200. package/dist/dev/runner.js.map +1 -1
  201. package/dist/dev/schema-dir.d.ts +1 -1
  202. package/dist/dev/schema-dir.d.ts.map +1 -1
  203. package/dist/dev/schema-dir.js +2 -4
  204. package/dist/dev/schema-dir.js.map +1 -1
  205. package/dist/dev/supervisor.d.ts +3 -1
  206. package/dist/dev/supervisor.d.ts.map +1 -1
  207. package/dist/dev/supervisor.js +132 -29
  208. package/dist/dev/supervisor.js.map +1 -1
  209. package/dist/dev/vite-dev-server.d.ts +1 -1
  210. package/dist/dev/vite-dev-server.d.ts.map +1 -1
  211. package/dist/dev/vite-dev-server.js +14 -2
  212. package/dist/dev/vite-dev-server.js.map +1 -1
  213. package/dist/dev/watch-ignore.d.ts +3 -0
  214. package/dist/dev/watch-ignore.d.ts.map +1 -0
  215. package/dist/dev/watch-ignore.js +11 -0
  216. package/dist/dev/watch-ignore.js.map +1 -0
  217. package/dist/i18n/catalogs.d.ts +6 -2
  218. package/dist/i18n/catalogs.d.ts.map +1 -1
  219. package/dist/i18n/catalogs.js +12 -8
  220. package/dist/i18n/catalogs.js.map +1 -1
  221. package/dist/i18n/metadata-templates.d.ts.map +1 -1
  222. package/dist/i18n/metadata-templates.js +2 -1
  223. package/dist/i18n/metadata-templates.js.map +1 -1
  224. package/dist/i18n/source-messages.d.ts +5 -21
  225. package/dist/i18n/source-messages.d.ts.map +1 -1
  226. package/dist/i18n/source-messages.js +1037 -92
  227. package/dist/i18n/source-messages.js.map +1 -1
  228. package/dist/i18n/types.d.ts +6 -7
  229. package/dist/i18n/types.d.ts.map +1 -1
  230. package/dist/i18n/types.js +83 -96
  231. package/dist/i18n/types.js.map +1 -1
  232. package/dist/internal/agent-rules.d.ts.map +1 -1
  233. package/dist/internal/agent-rules.js +7 -2
  234. package/dist/internal/agent-rules.js.map +1 -1
  235. package/dist/internal/banner.d.ts +4 -2
  236. package/dist/internal/banner.d.ts.map +1 -1
  237. package/dist/internal/banner.js +19 -5
  238. package/dist/internal/banner.js.map +1 -1
  239. package/dist/internal/build-manifest.d.ts +5 -2
  240. package/dist/internal/build-manifest.d.ts.map +1 -1
  241. package/dist/internal/build-manifest.js +15 -2
  242. package/dist/internal/build-manifest.js.map +1 -1
  243. package/dist/internal/build-output.d.ts +8 -0
  244. package/dist/internal/build-output.d.ts.map +1 -0
  245. package/dist/internal/build-output.js +116 -0
  246. package/dist/internal/build-output.js.map +1 -0
  247. package/dist/internal/cache-root.d.ts +3 -0
  248. package/dist/internal/cache-root.d.ts.map +1 -0
  249. package/dist/internal/cache-root.js +9 -0
  250. package/dist/internal/cache-root.js.map +1 -0
  251. package/dist/internal/compile-cache-store.d.ts +4 -0
  252. package/dist/internal/compile-cache-store.d.ts.map +1 -0
  253. package/dist/internal/compile-cache-store.js +41 -0
  254. package/dist/internal/compile-cache-store.js.map +1 -0
  255. package/dist/internal/compile-cache.d.ts +4 -0
  256. package/dist/internal/compile-cache.d.ts.map +1 -0
  257. package/dist/internal/compile-cache.js +16 -0
  258. package/dist/internal/compile-cache.js.map +1 -0
  259. package/dist/internal/deploy-out-dir.d.ts +4 -0
  260. package/dist/internal/deploy-out-dir.d.ts.map +1 -0
  261. package/dist/internal/deploy-out-dir.js +5 -0
  262. package/dist/internal/deploy-out-dir.js.map +1 -0
  263. package/dist/internal/docs-elements.d.ts +1 -0
  264. package/dist/internal/docs-elements.d.ts.map +1 -1
  265. package/dist/internal/docs-elements.js +6 -5
  266. package/dist/internal/docs-elements.js.map +1 -1
  267. package/dist/internal/entry-arg.d.ts +4 -1
  268. package/dist/internal/entry-arg.d.ts.map +1 -1
  269. package/dist/internal/entry-arg.js +7 -1
  270. package/dist/internal/entry-arg.js.map +1 -1
  271. package/dist/internal/errors.d.ts +2 -1
  272. package/dist/internal/errors.d.ts.map +1 -1
  273. package/dist/internal/errors.js +1 -1
  274. package/dist/internal/errors.js.map +1 -1
  275. package/dist/internal/font-path.d.ts +4 -0
  276. package/dist/internal/font-path.d.ts.map +1 -0
  277. package/dist/internal/font-path.js +12 -0
  278. package/dist/internal/font-path.js.map +1 -0
  279. package/dist/internal/font-staging.d.ts +6 -0
  280. package/dist/internal/font-staging.d.ts.map +1 -0
  281. package/dist/internal/font-staging.js +94 -0
  282. package/dist/internal/font-staging.js.map +1 -0
  283. package/dist/internal/icon-path.d.ts.map +1 -1
  284. package/dist/internal/icon-path.js +5 -16
  285. package/dist/internal/icon-path.js.map +1 -1
  286. package/dist/internal/icon-staging.d.ts +3 -0
  287. package/dist/internal/icon-staging.d.ts.map +1 -0
  288. package/dist/internal/icon-staging.js +40 -0
  289. package/dist/internal/icon-staging.js.map +1 -0
  290. package/dist/internal/import-scan.d.ts +4 -0
  291. package/dist/internal/import-scan.d.ts.map +1 -0
  292. package/dist/internal/import-scan.js +138 -0
  293. package/dist/internal/import-scan.js.map +1 -0
  294. package/dist/internal/module-hash.d.ts +3 -0
  295. package/dist/internal/module-hash.d.ts.map +1 -0
  296. package/dist/internal/module-hash.js +19 -0
  297. package/dist/internal/module-hash.js.map +1 -0
  298. package/dist/internal/output-directory.d.ts +15 -0
  299. package/dist/internal/output-directory.d.ts.map +1 -0
  300. package/dist/internal/output-directory.js +490 -0
  301. package/dist/internal/output-directory.js.map +1 -0
  302. package/dist/internal/parent-process.d.ts +12 -0
  303. package/dist/internal/parent-process.d.ts.map +1 -0
  304. package/dist/internal/parent-process.js +74 -0
  305. package/dist/internal/parent-process.js.map +1 -0
  306. package/dist/internal/prepare-project.d.ts +3 -0
  307. package/dist/internal/prepare-project.d.ts.map +1 -1
  308. package/dist/internal/prepare-project.js +9 -3
  309. package/dist/internal/prepare-project.js.map +1 -1
  310. package/dist/internal/react-compiler-cache.d.ts +13 -0
  311. package/dist/internal/react-compiler-cache.d.ts.map +1 -0
  312. package/dist/internal/react-compiler-cache.js +182 -0
  313. package/dist/internal/react-compiler-cache.js.map +1 -0
  314. package/dist/internal/source-imports.d.ts +7 -2
  315. package/dist/internal/source-imports.d.ts.map +1 -1
  316. package/dist/internal/source-imports.js +38 -49
  317. package/dist/internal/source-imports.js.map +1 -1
  318. package/dist/internal/staging-file.d.ts +5 -0
  319. package/dist/internal/staging-file.d.ts.map +1 -0
  320. package/dist/internal/staging-file.js +35 -0
  321. package/dist/internal/staging-file.js.map +1 -0
  322. package/dist/internal/xdg-banner.d.ts +4 -0
  323. package/dist/internal/xdg-banner.d.ts.map +1 -0
  324. package/dist/internal/xdg-banner.js +11 -0
  325. package/dist/internal/xdg-banner.js.map +1 -0
  326. package/dist/internal/xdg-data-dirs.d.ts +2 -1
  327. package/dist/internal/xdg-data-dirs.d.ts.map +1 -1
  328. package/dist/internal/xdg-data-dirs.js +1 -1
  329. package/dist/internal/xdg-data-dirs.js.map +1 -1
  330. package/dist/mcp/client.js +2 -2
  331. package/dist/mcp/client.js.map +1 -1
  332. package/dist/settings/render.d.ts +0 -1
  333. package/dist/settings/render.d.ts.map +1 -1
  334. package/dist/settings/render.js +1 -11
  335. package/dist/settings/render.js.map +1 -1
  336. package/dist/settings/schema.d.ts +2 -2
  337. package/dist/settings/schema.d.ts.map +1 -1
  338. package/dist/settings/schema.js +24 -70
  339. package/dist/settings/schema.js.map +1 -1
  340. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  341. package/dist/vite-plugins/asset-extensions.js +2 -0
  342. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  343. package/dist/vite-plugins/asset-imports.d.ts +1 -2
  344. package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
  345. package/dist/vite-plugins/asset-imports.js +36 -35
  346. package/dist/vite-plugins/asset-imports.js.map +1 -1
  347. package/dist/vite-plugins/asset-specifier.d.ts +5 -3
  348. package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
  349. package/dist/vite-plugins/asset-specifier.js +10 -4
  350. package/dist/vite-plugins/asset-specifier.js.map +1 -1
  351. package/dist/vite-plugins/build-manifest.d.ts +5 -1
  352. package/dist/vite-plugins/build-manifest.d.ts.map +1 -1
  353. package/dist/vite-plugins/build-manifest.js +2 -1
  354. package/dist/vite-plugins/build-manifest.js.map +1 -1
  355. package/dist/vite-plugins/built-url.d.ts.map +1 -1
  356. package/dist/vite-plugins/built-url.js +5 -2
  357. package/dist/vite-plugins/built-url.js.map +1 -1
  358. package/dist/vite-plugins/css.d.ts.map +1 -1
  359. package/dist/vite-plugins/css.js +13 -5
  360. package/dist/vite-plugins/css.js.map +1 -1
  361. package/dist/vite-plugins/ensure-store.d.ts +1 -1
  362. package/dist/vite-plugins/ensure-store.d.ts.map +1 -1
  363. package/dist/vite-plugins/ensure-store.js +2 -2
  364. package/dist/vite-plugins/ensure-store.js.map +1 -1
  365. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +6 -1
  366. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -1
  367. package/dist/vite-plugins/fast-refresh/refresh-filter.js +3 -1
  368. package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -1
  369. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -1
  370. package/dist/vite-plugins/fast-refresh/swc-refresh.js +23 -14
  371. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -1
  372. package/dist/vite-plugins/font-name.d.ts +3 -0
  373. package/dist/vite-plugins/font-name.d.ts.map +1 -0
  374. package/dist/vite-plugins/font-name.js +406 -0
  375. package/dist/vite-plugins/font-name.js.map +1 -0
  376. package/dist/vite-plugins/font-worker-env.d.ts +4 -0
  377. package/dist/vite-plugins/font-worker-env.d.ts.map +1 -0
  378. package/dist/vite-plugins/font-worker-env.js +19 -0
  379. package/dist/vite-plugins/font-worker-env.js.map +1 -0
  380. package/dist/vite-plugins/font.d.ts +4 -0
  381. package/dist/vite-plugins/font.d.ts.map +1 -0
  382. package/dist/vite-plugins/font.js +111 -0
  383. package/dist/vite-plugins/font.js.map +1 -0
  384. package/dist/vite-plugins/i18n.d.ts +11 -2
  385. package/dist/vite-plugins/i18n.d.ts.map +1 -1
  386. package/dist/vite-plugins/i18n.js +75 -8
  387. package/dist/vite-plugins/i18n.js.map +1 -1
  388. package/dist/vite-plugins/icon-worker-env.d.ts +4 -0
  389. package/dist/vite-plugins/icon-worker-env.d.ts.map +1 -0
  390. package/dist/vite-plugins/icon-worker-env.js +23 -0
  391. package/dist/vite-plugins/icon-worker-env.js.map +1 -0
  392. package/dist/vite-plugins/icons.d.ts.map +1 -1
  393. package/dist/vite-plugins/icons.js +4 -9
  394. package/dist/vite-plugins/icons.js.map +1 -1
  395. package/dist/vite-plugins/index.d.ts +10 -1
  396. package/dist/vite-plugins/index.d.ts.map +1 -1
  397. package/dist/vite-plugins/index.js +19 -7
  398. package/dist/vite-plugins/index.js.map +1 -1
  399. package/dist/vite-plugins/native.d.ts.map +1 -1
  400. package/dist/vite-plugins/native.js +0 -4
  401. package/dist/vite-plugins/native.js.map +1 -1
  402. package/dist/vite-plugins/react-compiler.d.ts.map +1 -1
  403. package/dist/vite-plugins/react-compiler.js +57 -18
  404. package/dist/vite-plugins/react-compiler.js.map +1 -1
  405. package/dist/vite-plugins/resource-shared.d.ts +3 -1
  406. package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
  407. package/dist/vite-plugins/resource-shared.js +3 -1
  408. package/dist/vite-plugins/resource-shared.js.map +1 -1
  409. package/dist/vite-plugins/resources.d.ts.map +1 -1
  410. package/dist/vite-plugins/resources.js +40 -102
  411. package/dist/vite-plugins/resources.js.map +1 -1
  412. package/dist/vite-plugins/self-contained.d.ts.map +1 -1
  413. package/dist/vite-plugins/self-contained.js +159 -158
  414. package/dist/vite-plugins/self-contained.js.map +1 -1
  415. package/dist/vite-plugins/settings-worker-env.d.ts +1 -1
  416. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
  417. package/dist/vite-plugins/settings-worker-env.js +5 -7
  418. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  419. package/dist/vite-plugins/settings.d.ts +1 -2
  420. package/dist/vite-plugins/settings.d.ts.map +1 -1
  421. package/dist/vite-plugins/settings.js +32 -27
  422. package/dist/vite-plugins/settings.js.map +1 -1
  423. package/dist/vite-plugins/store-links.d.ts.map +1 -1
  424. package/dist/vite-plugins/store-links.js +9 -5
  425. package/dist/vite-plugins/store-links.js.map +1 -1
  426. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
  427. package/dist/vite-plugins/undeclared-library.js +25 -25
  428. package/dist/vite-plugins/undeclared-library.js.map +1 -1
  429. package/dist/vite-plugins/worker.d.ts.map +1 -1
  430. package/dist/vite-plugins/worker.js +21 -14
  431. package/dist/vite-plugins/worker.js.map +1 -1
  432. package/dist/vitest-plugin.d.ts +4 -3
  433. package/dist/vitest-plugin.d.ts.map +1 -1
  434. package/dist/vitest-plugin.js +12 -8
  435. package/dist/vitest-plugin.js.map +1 -1
  436. package/env.d.ts +9 -0
  437. package/package.json +28 -17
  438. package/src/builder.ts +45 -12
  439. package/src/cli.ts +15 -2
  440. package/src/codegen/config-dependencies.ts +470 -0
  441. package/src/codegen/freshness.ts +70 -17
  442. package/src/codegen/reference.ts +2 -8
  443. package/src/codegen/report.ts +5 -21
  444. package/src/codegen/run-codegen.ts +73 -160
  445. package/src/codegen/store-resolver.ts +16 -27
  446. package/src/commands/build.ts +13 -2
  447. package/src/commands/cleanup.ts +48 -0
  448. package/src/commands/codegen.ts +6 -5
  449. package/src/commands/deploy.ts +10 -2
  450. package/src/commands/dev.ts +45 -4
  451. package/src/commands/docs.ts +6 -17
  452. package/src/deploy/depends.ts +30 -3
  453. package/src/deploy/download.ts +33 -24
  454. package/src/deploy/freedesktop/copyright.ts +2 -14
  455. package/src/deploy/freedesktop/metainfo.ts +73 -21
  456. package/src/deploy/freedesktop/validate.ts +80 -15
  457. package/src/deploy/freedesktop/xml.ts +24 -32
  458. package/src/deploy/native-addon.ts +183 -0
  459. package/src/deploy/nfpm/config.ts +13 -4
  460. package/src/deploy/nfpm/contents.ts +8 -0
  461. package/src/deploy/node-runtime/download.ts +2 -2
  462. package/src/deploy/node-runtime/elf.ts +46 -5
  463. package/src/deploy/node-runtime/guard.ts +10 -14
  464. package/src/deploy/node-runtime/index.ts +148 -12
  465. package/src/deploy/node-runtime/license.ts +2 -8
  466. package/src/deploy/node-runtime/sonames.ts +17 -0
  467. package/src/deploy/notices/node-runtime.ts +2 -2
  468. package/src/deploy/notices/packages.ts +3 -11
  469. package/src/deploy/payload/copy-tree.ts +3 -4
  470. package/src/deploy/payload/launcher.ts +20 -1
  471. package/src/deploy/payload/stage.ts +78 -11
  472. package/src/deploy/run-deploy.ts +227 -72
  473. package/src/deploy/settings/arch.ts +40 -8
  474. package/src/deploy/settings/build-manifest.ts +30 -17
  475. package/src/deploy/settings/extra-files.ts +30 -4
  476. package/src/deploy/settings/index.ts +7 -2
  477. package/src/deploy/settings/libraries.ts +2 -22
  478. package/src/deploy/settings/paths.ts +78 -21
  479. package/src/deploy/settings/screenshots.ts +8 -46
  480. package/src/deploy/targets/appimage.ts +1 -0
  481. package/src/deploy/targets/flatpak-pnpm.ts +4 -4
  482. package/src/deploy/targets/flatpak-source.ts +19 -6
  483. package/src/deploy/targets/flatpak-sources.ts +1 -1
  484. package/src/deploy/targets/flatpak.ts +1 -0
  485. package/src/deploy/targets/nfpm-target.ts +14 -6
  486. package/src/deploy/types.ts +5 -1
  487. package/src/deploy/vendored/appimagetool.ts +2 -2
  488. package/src/deploy/vendored/nfpm.ts +1 -1
  489. package/src/dev/catalog-writes.ts +35 -0
  490. package/src/dev/entry-env.ts +2 -1
  491. package/src/dev/font-dir.ts +11 -0
  492. package/src/dev/headless.ts +40 -0
  493. package/src/dev/runner-deps.ts +20 -7
  494. package/src/dev/runner-main.ts +13 -5
  495. package/src/dev/runner.ts +37 -7
  496. package/src/dev/schema-dir.ts +2 -4
  497. package/src/dev/supervisor.ts +183 -32
  498. package/src/dev/vite-dev-server.ts +20 -2
  499. package/src/dev/watch-ignore.ts +16 -0
  500. package/src/i18n/catalogs.ts +23 -9
  501. package/src/i18n/metadata-templates.ts +2 -1
  502. package/src/i18n/source-messages.ts +1641 -262
  503. package/src/i18n/types.ts +97 -131
  504. package/src/internal/agent-rules.ts +7 -2
  505. package/src/internal/banner.ts +27 -6
  506. package/src/internal/build-manifest.ts +25 -1
  507. package/src/internal/build-output.ts +171 -0
  508. package/src/internal/cache-root.ts +12 -0
  509. package/src/internal/compile-cache-store.ts +50 -0
  510. package/src/internal/compile-cache.ts +20 -0
  511. package/src/internal/deploy-out-dir.ts +8 -0
  512. package/src/internal/docs-elements.ts +11 -5
  513. package/src/internal/entry-arg.ts +8 -1
  514. package/src/internal/errors.ts +1 -1
  515. package/src/internal/font-path.ts +15 -0
  516. package/src/internal/font-staging.ts +131 -0
  517. package/src/internal/icon-path.ts +6 -19
  518. package/src/internal/icon-staging.ts +58 -0
  519. package/src/internal/import-scan.ts +206 -0
  520. package/src/internal/module-hash.ts +22 -0
  521. package/src/internal/output-directory.ts +699 -0
  522. package/src/internal/parent-process.ts +110 -0
  523. package/src/internal/prepare-project.ts +11 -5
  524. package/src/internal/react-compiler-cache.ts +246 -0
  525. package/src/internal/source-imports.ts +64 -55
  526. package/src/internal/staging-file.ts +42 -0
  527. package/src/internal/xdg-banner.ts +13 -0
  528. package/src/internal/xdg-data-dirs.ts +1 -1
  529. package/src/mcp/client.ts +2 -2
  530. package/src/settings/render.ts +1 -13
  531. package/src/settings/schema.ts +23 -91
  532. package/src/vite-plugins/asset-extensions.ts +2 -0
  533. package/src/vite-plugins/asset-imports.ts +39 -45
  534. package/src/vite-plugins/asset-specifier.ts +17 -5
  535. package/src/vite-plugins/build-manifest.ts +7 -1
  536. package/src/vite-plugins/built-url.ts +6 -2
  537. package/src/vite-plugins/css.ts +16 -5
  538. package/src/vite-plugins/ensure-store.ts +2 -2
  539. package/src/vite-plugins/fast-refresh/refresh-filter.ts +10 -1
  540. package/src/vite-plugins/fast-refresh/swc-refresh.ts +33 -14
  541. package/src/vite-plugins/font-name.ts +582 -0
  542. package/src/vite-plugins/font-worker-env.ts +25 -0
  543. package/src/vite-plugins/font.ts +180 -0
  544. package/src/vite-plugins/i18n.ts +123 -11
  545. package/src/vite-plugins/icon-worker-env.ts +36 -0
  546. package/src/vite-plugins/icons.ts +4 -10
  547. package/src/vite-plugins/index.ts +36 -13
  548. package/src/vite-plugins/native.ts +0 -5
  549. package/src/vite-plugins/react-compiler.ts +83 -19
  550. package/src/vite-plugins/resource-shared.ts +4 -0
  551. package/src/vite-plugins/resources.ts +47 -144
  552. package/src/vite-plugins/self-contained.ts +184 -185
  553. package/src/vite-plugins/settings-worker-env.ts +5 -7
  554. package/src/vite-plugins/settings.ts +44 -33
  555. package/src/vite-plugins/store-links.ts +10 -5
  556. package/src/vite-plugins/undeclared-library.ts +30 -32
  557. package/src/vite-plugins/worker.ts +31 -16
  558. package/src/vitest-plugin.ts +12 -8
  559. package/dist/i18n/binding-extractor.d.ts +0 -30
  560. package/dist/i18n/binding-extractor.d.ts.map +0 -1
  561. package/dist/i18n/binding-extractor.js +0 -1324
  562. package/dist/i18n/binding-extractor.js.map +0 -1
  563. package/dist/i18n/extractor-plugin.d.ts +0 -8
  564. package/dist/i18n/extractor-plugin.d.ts.map +0 -1
  565. package/dist/i18n/extractor-plugin.js +0 -247
  566. package/dist/i18n/extractor-plugin.js.map +0 -1
  567. package/dist/internal/data-dir.d.ts +0 -4
  568. package/dist/internal/data-dir.d.ts.map +0 -1
  569. package/dist/internal/data-dir.js +0 -52
  570. package/dist/internal/data-dir.js.map +0 -1
  571. package/dist/vite-plugins/animated.d.ts +0 -5
  572. package/dist/vite-plugins/animated.d.ts.map +0 -1
  573. package/dist/vite-plugins/animated.js +0 -325
  574. package/dist/vite-plugins/animated.js.map +0 -1
  575. package/src/i18n/binding-extractor.ts +0 -1969
  576. package/src/i18n/extractor-plugin.ts +0 -413
  577. package/src/internal/data-dir.ts +0 -70
  578. package/src/vite-plugins/animated.ts +0 -486
@@ -1,14 +1,106 @@
1
- import { findKeys } from "i18next-cli";
1
+ import { parseSync as parseBabelSync, traverse, types } from "@babel/core";
2
+ import { isPathInside, isPathWithin, toPosixPath } from "@gtkx/utils";
3
+ import { runExtractor } from "i18next-cli";
2
4
  import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
3
- import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
6
+ import { parseSync, Visitor } from "vite";
4
7
  import { runCliTool } from "../internal/run-cli-tool.js";
8
+ import { sourceLanguage } from "../internal/source-imports.js";
5
9
  import { replaceCatalogTemplate } from "./catalog-template.js";
6
- import { gtkxExtractorPlugin } from "./extractor-plugin.js";
7
10
  import { metadataTemplateFiles } from "./metadata-templates.js";
11
+ import { clearI18nResources, i18nToolkitConfig } from "./types.js";
8
12
  const CONTEXT_SEPARATOR = "\u{4}";
9
13
  const DEFAULT_NAMESPACE = "translation";
10
14
  const POTFILES_FILENAME = "POTFILES.in";
11
15
  const SYNTHETIC_FILENAME = "messages.js";
16
+ const UNSUPPORTED_PLURAL_OPTION = /^defaultValue_(few|many|two|zero)$/u;
17
+ const STATIC_SOURCE_OPTION_NAMES = new Set([
18
+ "context",
19
+ "defaultValue",
20
+ "defaultValue_one",
21
+ "defaultValue_other",
22
+ "keyPrefix",
23
+ ]);
24
+ const NESTED_CONTEXT = /["']?context["']?\s*:\s*(?:"([^"]*)"|'([^']*)')/u;
25
+ const NESTED_COUNT = /["']?count["']?\s*:/u;
26
+ const NESTED_STRUCTURE_TOKEN = /"[^"]*"|'[^']*'|[()]/gu;
27
+ const TRANSLATION_MODULES = new Set(["@gtkx/i18n", "i18next"]);
28
+ const TRANS_ELEMENTS = new Set(["Trans", "TransWithoutContext"]);
29
+ const STATIC_KEY_WRAPPER_TYPES = new Set([
30
+ "ParenthesizedExpression",
31
+ "TSAsExpression",
32
+ "TSSatisfiesExpression",
33
+ "TSTypeAssertion",
34
+ "TSNonNullExpression",
35
+ ]);
36
+ class SourceExtractionError extends Error {
37
+ }
38
+ const sourceErrorMessage = (error) => {
39
+ if (!(error instanceof Error)) {
40
+ return String(error);
41
+ }
42
+ if ("code" in error &&
43
+ error.code === "BABEL_PARSE_ERROR") {
44
+ const separator = error.message.indexOf(": ");
45
+ if (separator !== -1) {
46
+ return error.message.slice(separator + 2);
47
+ }
48
+ }
49
+ return error.message;
50
+ };
51
+ const projectSourcePath = (root, path) => {
52
+ const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);
53
+ return toPosixPath(isPathInside(root, absolute) ? relative(root, absolute) : path);
54
+ };
55
+ const sourceExtractionError = (root, path, point, error) => {
56
+ if (error instanceof SourceExtractionError) {
57
+ return error;
58
+ }
59
+ const file = projectSourcePath(root, path);
60
+ const location = point === null
61
+ ? file
62
+ : `${file}:${String(point.line)}:${String(point.column + 1)}`;
63
+ return new SourceExtractionError(`${location}: ${sourceErrorMessage(error)}`, { cause: error });
64
+ };
65
+ const locatablePoint = (node) => {
66
+ const location = node.loc?.start;
67
+ return location === undefined ? null : { column: location.column, line: location.line };
68
+ };
69
+ const isSourcePoint = (value) => typeof value === "object" &&
70
+ value !== null &&
71
+ "column" in value &&
72
+ typeof value.column === "number" &&
73
+ "line" in value &&
74
+ typeof value.line === "number";
75
+ const errorSourcePoint = (error) => {
76
+ if (typeof error !== "object" || error === null) {
77
+ return null;
78
+ }
79
+ if ("loc" in error && isSourcePoint(error.loc)) {
80
+ return error.loc;
81
+ }
82
+ return "location" in error && isSourcePoint(error.location) ? error.location : null;
83
+ };
84
+ const atSourceNode = (root, path, node, operation) => {
85
+ try {
86
+ return operation();
87
+ }
88
+ catch (error) {
89
+ throw sourceExtractionError(root, path, locatablePoint(node), error);
90
+ }
91
+ };
92
+ const atExtractedLocation = (root, locations, operation) => {
93
+ const location = locations.find((candidate) => candidate.line !== undefined && candidate.column !== undefined);
94
+ if (location?.line === undefined || location.column === undefined) {
95
+ return operation();
96
+ }
97
+ try {
98
+ return operation();
99
+ }
100
+ catch (error) {
101
+ throw sourceExtractionError(root, location.file, { column: location.column, line: location.line }, error);
102
+ }
103
+ };
12
104
  const quietLogger = () => {
13
105
  const reports = [];
14
106
  return {
@@ -27,29 +119,6 @@ const quietLogger = () => {
27
119
  },
28
120
  };
29
121
  };
30
- const extractorConfig = (sourceFiles) => {
31
- const integration = gtkxExtractorPlugin();
32
- return {
33
- locales: ["en"],
34
- plugins: [integration.plugin],
35
- extract: {
36
- input: sourceFiles,
37
- output: "unused/{{language}}/{{namespace}}.json",
38
- contextSeparator: CONTEXT_SEPARATOR,
39
- defaultNS: DEFAULT_NAMESPACE,
40
- disablePlurals: false,
41
- extractFromComments: false,
42
- functions: [],
43
- generateBasePluralForms: false,
44
- keySeparator: ".",
45
- nsSeparator: false,
46
- pluralSeparator: "_",
47
- transComponents: integration.transComponents,
48
- useTranslationNames: [],
49
- warnOnConflicts: "error",
50
- },
51
- };
52
- };
53
122
  const splitContext = (key) => {
54
123
  const index = key.lastIndexOf(CONTEXT_SEPARATOR);
55
124
  if (index === -1) {
@@ -75,27 +144,30 @@ const normalizedLocations = (locations) => {
75
144
  return unique.values().toArray().toSorted(compareLocations);
76
145
  };
77
146
  const pointSource = (entry, msgid) => {
78
- if (entry.explicitDefault !== true || typeof entry.defaultValue !== "string") {
147
+ if (typeof entry.defaultValue !== "string") {
79
148
  return msgid;
80
149
  }
81
- return entry.defaultValue;
150
+ if (entry.explicitDefault === true) {
151
+ return entry.defaultValue;
152
+ }
153
+ return entry.defaultValue === msgid || msgid.endsWith(`.${entry.defaultValue}`)
154
+ ? msgid
155
+ : entry.defaultValue;
82
156
  };
83
157
  const pointMessage = (entry) => {
84
158
  const { context, msgid } = splitContext(entry.key);
85
159
  validateIdentity(context, msgid);
86
- const isDefaultExplicit = entry.explicitDefault === true;
87
160
  const singular = pointSource(entry, msgid);
88
161
  if (singular.length === 0) {
89
162
  throw new Error("Translation source strings cannot be empty");
90
163
  }
91
164
  return {
92
165
  context,
93
- kind: isDefaultExplicit ? "default" : "point",
94
166
  locations: normalizedLocations(entry.locations ?? []),
95
- msgid,
96
167
  namespace: namespaceFor(entry),
97
168
  plural: null,
98
169
  singular,
170
+ sourceKey: msgid,
99
171
  };
100
172
  };
101
173
  const expandedPlural = (entry) => {
@@ -117,10 +189,10 @@ const expandedPlural = (entry) => {
117
189
  },
118
190
  };
119
191
  };
120
- const groupedPlurals = (entries) => {
192
+ const groupedPlurals = (root, entries) => {
121
193
  const groups = new Map();
122
194
  for (const entry of entries) {
123
- const { baseKey, variant } = expandedPlural(entry);
195
+ const { baseKey, variant } = atExtractedLocation(root, entry.locations ?? [], () => expandedPlural(entry));
124
196
  const namespace = namespaceFor(entry);
125
197
  const key = `${namespace}\0${baseKey}`;
126
198
  const group = groups.get(key) ?? { baseKey, namespace, variants: [] };
@@ -145,33 +217,33 @@ const pluralMessage = ({ baseKey, namespace, variants }) => {
145
217
  const { one, other } = pairedVariants(variants);
146
218
  const { context, msgid } = splitContext(baseKey);
147
219
  validateIdentity(context, msgid);
148
- const hasStableKey = one.defaultValue !== other.defaultValue;
149
- const singular = hasStableKey ? one.defaultValue : msgid;
220
+ const singular = one.defaultValue;
150
221
  const plural = other.defaultValue;
151
222
  if (singular === plural || singular.length === 0 || plural.length === 0) {
152
223
  throw new Error("GNU gettext plural source strings must be distinct and non-empty");
153
224
  }
154
225
  return {
155
226
  context,
156
- kind: hasStableKey ? "pluralDefaults" : "plural",
157
227
  locations: normalizedLocations(variants.flatMap((variant) => variant.locations)),
158
- msgid,
159
228
  namespace,
160
229
  plural,
161
230
  singular,
231
+ sourceKey: msgid,
162
232
  };
163
233
  };
164
- const pluralMessages = (entries) => groupedPlurals(entries).map((group) => pluralMessage(group));
234
+ const pluralMessages = (root, entries) => groupedPlurals(root, entries).map((group) => atExtractedLocation(root, group.variants.flatMap((variant) => variant.locations), () => pluralMessage(group)));
165
235
  const assertCardinal = (entry) => {
166
236
  if (entry.isOrdinal === true) {
167
237
  throw new Error("GNU gettext catalogs do not support i18next ordinal plurals");
168
238
  }
169
239
  };
170
- const sourceMessages = (entries) => {
240
+ const sourceMessages = (root, entries) => {
171
241
  const points = [];
172
242
  const plurals = [];
173
243
  for (const entry of entries) {
174
- assertCardinal(entry);
244
+ atExtractedLocation(root, entry.locations ?? [], () => {
245
+ assertCardinal(entry);
246
+ });
175
247
  if (entry.isExpandedPlural === true) {
176
248
  plurals.push(entry);
177
249
  continue;
@@ -181,44 +253,936 @@ const sourceMessages = (entries) => {
181
253
  }
182
254
  points.push(entry);
183
255
  }
184
- return [...points.map((entry) => pointMessage(entry)), ...pluralMessages(plurals)];
256
+ return [
257
+ ...points.map((entry) => atExtractedLocation(root, entry.locations ?? [], () => pointMessage(entry))),
258
+ ...pluralMessages(root, plurals),
259
+ ];
185
260
  };
186
261
  const compareMessages = (left, right) => left.namespace.localeCompare(right.namespace) ||
187
262
  (left.context ?? "").localeCompare(right.context ?? "") ||
188
- left.msgid.localeCompare(right.msgid) ||
189
263
  left.singular.localeCompare(right.singular) ||
190
264
  (left.plural ?? "").localeCompare(right.plural ?? "");
265
+ const inferLocations = (message, sources) => {
266
+ if (message.locations.length > 0) {
267
+ return message;
268
+ }
269
+ const locations = [];
270
+ for (const [file, source] of sources) {
271
+ const index = source.indexOf(message.sourceKey);
272
+ if (index !== -1) {
273
+ locations.push({ file, line: source.slice(0, index).split("\n").length });
274
+ }
275
+ }
276
+ return { ...message, locations };
277
+ };
191
278
  const normalizedSourceFiles = (root, paths) => {
192
279
  const files = paths
193
280
  .map((path) => resolve(root, path))
194
- .filter((path) => {
195
- const projectPath = relative(root, path);
196
- return projectPath !== ".." && !projectPath.startsWith(`..${sep}`) && !isAbsolute(projectPath);
197
- });
281
+ .filter((path) => isPathWithin(root, path));
198
282
  return new Set(files).values().toArray().toSorted((left, right) => left.localeCompare(right));
199
283
  };
200
- const findSourceMessages = async (sourceFiles) => {
284
+ const isStaticKeyWrapper = (key) => STATIC_KEY_WRAPPER_TYPES.has(key.type);
285
+ const unwrapStaticWrapper = (node) => isStaticKeyWrapper(node) ? unwrapStaticWrapper(node.expression) : node;
286
+ const isStaticTranslationKey = (key) => {
287
+ if (key === undefined || key === null) {
288
+ return false;
289
+ }
290
+ if (key.type === "Literal") {
291
+ return typeof key.value === "string";
292
+ }
293
+ if (key.type === "TemplateLiteral") {
294
+ return key.expressions.length === 0;
295
+ }
296
+ if (key.type === "ParenthesizedExpression") {
297
+ return false;
298
+ }
299
+ if (isStaticKeyWrapper(key)) {
300
+ return isStaticTranslationKey(key.expression);
301
+ }
302
+ return false;
303
+ };
304
+ const assertStaticTranslationKey = (key) => {
305
+ if (!isStaticTranslationKey(key)) {
306
+ throw new Error("Translation keys must be string literals");
307
+ }
308
+ };
309
+ const propertyName = (property) => {
310
+ if (!property.computed && property.key.type === "Identifier") {
311
+ return property.key.name;
312
+ }
313
+ return property.key.type === "Literal" && typeof property.key.value === "string"
314
+ ? property.key.value
315
+ : null;
316
+ };
317
+ const assertSupportedOptionProperty = (property) => {
318
+ if (property.type === "SpreadElement") {
319
+ throw new Error("Translation extraction requires explicit option properties");
320
+ }
321
+ const name = propertyName(property);
322
+ if (name === null) {
323
+ throw new Error("Translation extraction requires static option property names");
324
+ }
325
+ if (UNSUPPORTED_PLURAL_OPTION.test(name)) {
326
+ throw new Error("GNU gettext accepts one singular and one plural source string");
327
+ }
328
+ if (STATIC_SOURCE_OPTION_NAMES.has(name)) {
329
+ assertStaticTranslationKey(property.value);
330
+ }
331
+ };
332
+ const assertSupportedOptionObject = (options) => {
333
+ if (options === null || options === undefined) {
334
+ return;
335
+ }
336
+ if (isStaticKeyWrapper(options) && unwrapStaticWrapper(options).type === "ObjectExpression") {
337
+ throw new Error("Translation option objects cannot be wrapped in another expression");
338
+ }
339
+ if (options.type !== "ObjectExpression") {
340
+ throw new Error("Translation option objects must be inline object literals");
341
+ }
342
+ for (const property of options.properties) {
343
+ assertSupportedOptionProperty(property);
344
+ }
345
+ };
346
+ const namedImportedBinding = (path, source) => {
347
+ if (!path.isImportSpecifier() || path.node.importKind === "type") {
348
+ return null;
349
+ }
350
+ const imported = path.node.imported;
351
+ return {
352
+ imported: types.isIdentifier(imported) ? imported.name : imported.value,
353
+ local: path.node.local.name,
354
+ source,
355
+ style: "named",
356
+ };
357
+ };
358
+ const defaultImportedBinding = (path, source) => path.isImportDefaultSpecifier()
359
+ ? { imported: "default", local: path.node.local.name, source, style: "default" }
360
+ : null;
361
+ const namespaceImportedBinding = (path, source) => path.isImportNamespaceSpecifier()
362
+ ? { imported: "*", local: path.node.local.name, source, style: "namespace" }
363
+ : null;
364
+ const importedBinding = (binding) => {
365
+ if (binding === undefined) {
366
+ return null;
367
+ }
368
+ const path = binding.path;
369
+ const declaration = path.parentPath;
370
+ if (!declaration.isImportDeclaration() || declaration.node.importKind === "type") {
371
+ return null;
372
+ }
373
+ const source = declaration.node.source.value;
374
+ return namedImportedBinding(path, source) ??
375
+ defaultImportedBinding(path, source) ??
376
+ namespaceImportedBinding(path, source);
377
+ };
378
+ const babelPropertyName = (property) => {
379
+ const key = property.key;
380
+ if (!property.computed && types.isIdentifier(key)) {
381
+ return key.name;
382
+ }
383
+ return types.isStringLiteral(key) ? key.value : null;
384
+ };
385
+ const isBoundIdentifier = (node, name) => {
386
+ if (types.isIdentifier(node)) {
387
+ return node.name === name;
388
+ }
389
+ if (types.isAssignmentPattern(node)) {
390
+ return types.isIdentifier(node.left) && node.left.name === name;
391
+ }
392
+ return false;
393
+ };
394
+ const isHookPatternBinding = (pattern, name) => {
395
+ if (types.isObjectPattern(pattern)) {
396
+ return pattern.properties.some((property) => types.isObjectProperty(property) &&
397
+ babelPropertyName(property) === "t" &&
398
+ isBoundIdentifier(property.value, name));
399
+ }
400
+ if (types.isArrayPattern(pattern)) {
401
+ return isBoundIdentifier(pattern.elements[0] ?? null, name);
402
+ }
403
+ return false;
404
+ };
405
+ const importedTranslationHook = (scope, call) => {
406
+ if (!types.isIdentifier(call.callee)) {
407
+ return null;
408
+ }
409
+ const imported = importedBinding(scope.getBinding(call.callee.name));
410
+ return imported?.imported === "useTranslation" && TRANSLATION_MODULES.has(imported.source)
411
+ ? imported
412
+ : null;
413
+ };
414
+ const translationHookBinding = (binding) => {
415
+ const path = binding.path;
416
+ if (!path.isVariableDeclarator()) {
417
+ return null;
418
+ }
419
+ const pattern = path.node.id;
420
+ const initializer = path.node.init;
421
+ if (!isHookPatternBinding(pattern, binding.identifier.name) ||
422
+ !types.isCallExpression(initializer)) {
423
+ return null;
424
+ }
425
+ const imported = importedTranslationHook(path.scope, initializer);
426
+ if (imported === null) {
427
+ return null;
428
+ }
429
+ return { call: initializer, isCanonical: imported.local === "useTranslation" };
430
+ };
431
+ const importedTranslationFunctionKind = (imported) => {
432
+ if (imported?.imported !== "t" || !TRANSLATION_MODULES.has(imported.source)) {
433
+ return null;
434
+ }
435
+ return imported.local === "t" ? "canonical" : "alias";
436
+ };
437
+ const hookTranslationFunctionKind = (binding) => {
438
+ if (binding === undefined) {
439
+ return null;
440
+ }
441
+ const hook = translationHookBinding(binding);
442
+ if (hook === null) {
443
+ return null;
444
+ }
445
+ return binding.identifier.name === "t" && hook.isCanonical ? "canonical" : "alias";
446
+ };
447
+ const directTranslationFunctionKind = (scope, name) => {
448
+ const binding = scope.getBinding(name);
449
+ return importedTranslationFunctionKind(importedBinding(binding)) ?? hookTranslationFunctionKind(binding);
450
+ };
451
+ const babelMemberName = (member) => {
452
+ const property = member.property;
453
+ if (member.computed) {
454
+ return types.isStringLiteral(property) ? property.value : null;
455
+ }
456
+ return types.isIdentifier(property) ? property.name : null;
457
+ };
458
+ const isImportedTranslationObject = (scope, object) => {
459
+ if (!types.isIdentifier(object)) {
460
+ return false;
461
+ }
462
+ const imported = importedBinding(scope.getBinding(object.name));
463
+ return imported !== null &&
464
+ TRANSLATION_MODULES.has(imported.source) &&
465
+ (imported.style === "namespace" || (imported.source === "i18next" && imported.imported === "default"));
466
+ };
467
+ const constantVariableDeclarator = (binding) => {
468
+ const path = binding.path;
469
+ const declaration = path.parentPath;
470
+ if (!path.isVariableDeclarator() ||
471
+ !declaration.isVariableDeclaration() ||
472
+ declaration.node.kind !== "const") {
473
+ return null;
474
+ }
475
+ return path;
476
+ };
477
+ const isTranslationHookResultBinding = (binding) => {
478
+ if (binding === undefined) {
479
+ return false;
480
+ }
481
+ const path = constantVariableDeclarator(binding);
482
+ const initializer = path?.node.init;
483
+ return path !== null &&
484
+ types.isIdentifier(path.node.id) &&
485
+ types.isCallExpression(initializer) &&
486
+ importedTranslationHook(path.scope, initializer) !== null;
487
+ };
488
+ const isHookTranslationMember = (scope, member) => {
489
+ if (babelMemberName(member) !== "t") {
490
+ return false;
491
+ }
492
+ const object = member.object;
493
+ if (types.isCallExpression(object)) {
494
+ return importedTranslationHook(scope, object) !== null;
495
+ }
496
+ return types.isIdentifier(object) && isTranslationHookResultBinding(scope.getBinding(object.name));
497
+ };
498
+ const isTranslationMember = (scope, member) => babelMemberName(member) === "t" &&
499
+ (isImportedTranslationObject(scope, member.object) || isHookTranslationMember(scope, member));
500
+ const isDirectTranslationFunction = (scope, node) => types.isIdentifier(node) && directTranslationFunctionKind(scope, node.name) !== null;
501
+ const isTranslationFunctionValue = (scope, node) => {
502
+ if (isDirectTranslationFunction(scope, node)) {
503
+ return true;
504
+ }
505
+ return (types.isMemberExpression(node) || types.isOptionalMemberExpression(node)) &&
506
+ isTranslationMember(scope, node);
507
+ };
508
+ const isTranslationBindCall = (scope, node) => {
509
+ if (!types.isCallExpression(node) || !types.isMemberExpression(node.callee)) {
510
+ return false;
511
+ }
512
+ return babelMemberName(node.callee) === "bind" &&
513
+ isTranslationFunctionValue(scope, node.callee.object);
514
+ };
515
+ const isTranslationObjectPatternAlias = (path, binding) => {
516
+ const pattern = path.node.id;
517
+ const initializer = path.node.init;
518
+ if (!types.isObjectPattern(pattern) ||
519
+ !isHookPatternBinding(pattern, binding.identifier.name) ||
520
+ !types.isIdentifier(initializer)) {
521
+ return false;
522
+ }
523
+ return isImportedTranslationObject(path.scope, initializer) ||
524
+ isTranslationHookResultBinding(path.scope.getBinding(initializer.name));
525
+ };
526
+ const isTranslationAliasBinding = (binding) => {
527
+ if (binding === undefined) {
528
+ return false;
529
+ }
530
+ const path = constantVariableDeclarator(binding);
531
+ if (path === null) {
532
+ return false;
533
+ }
534
+ if (isTranslationObjectPatternAlias(path, binding)) {
535
+ return true;
536
+ }
537
+ const initializer = path.node.init;
538
+ return types.isIdentifier(path.node.id) &&
539
+ initializer !== null &&
540
+ initializer !== undefined &&
541
+ (isTranslationFunctionValue(path.scope, initializer) || isTranslationBindCall(path.scope, initializer));
542
+ };
543
+ const translationFunctionKind = (scope, name) => {
544
+ const direct = directTranslationFunctionKind(scope, name);
545
+ if (direct !== null) {
546
+ return direct;
547
+ }
548
+ return isTranslationAliasBinding(scope.getBinding(name)) ? "alias" : null;
549
+ };
550
+ const translationElementKind = (path, name) => {
551
+ const imported = importedBinding(path.scope.getBinding(name));
552
+ if (imported?.source !== "@gtkx/i18n" || !TRANS_ELEMENTS.has(imported.imported)) {
553
+ return null;
554
+ }
555
+ return imported.local === imported.imported ? "canonical" : "alias";
556
+ };
557
+ const nodeStart = (path) => {
558
+ const start = path.node.start;
559
+ if (start === null || start === undefined) {
560
+ throw new Error("Translation extraction could not locate a source expression");
561
+ }
562
+ return start;
563
+ };
564
+ const registerSourceMask = (node, references) => {
565
+ const { start, end } = node;
566
+ if (start === null || start === undefined || end === null || end === undefined) {
567
+ throw new Error("Translation extraction could not locate a source expression");
568
+ }
569
+ references.masks.push({ start, end });
570
+ };
571
+ const sourceLocationKey = (line, column) => `${String(line)}:${String(column)}`;
572
+ const sourcePoint = (node) => {
573
+ return locatablePoint(node);
574
+ };
575
+ const registerSourceLocation = (node, references) => {
576
+ const point = sourcePoint(node);
577
+ if (point !== null) {
578
+ references.locations.set(sourceLocationKey(point.line, point.column), point);
579
+ }
580
+ return point;
581
+ };
582
+ const babelStaticKey = (node) => {
583
+ if (node === null || node === undefined) {
584
+ return null;
585
+ }
586
+ if (types.isStringLiteral(node)) {
587
+ return node.value;
588
+ }
589
+ if (types.isTemplateLiteral(node) && node.expressions.length === 0) {
590
+ return node.quasis[0]?.value.cooked ?? null;
591
+ }
592
+ if (types.isParenthesizedExpression(node) ||
593
+ types.isTSAsExpression(node) ||
594
+ types.isTSSatisfiesExpression(node) ||
595
+ types.isTSTypeAssertion(node) ||
596
+ types.isTSNonNullExpression(node)) {
597
+ return babelStaticKey(node.expression);
598
+ }
599
+ return null;
600
+ };
601
+ const babelObjectExpression = (node) => {
602
+ if (node === null || node === undefined) {
603
+ return null;
604
+ }
605
+ if (types.isObjectExpression(node)) {
606
+ return node;
607
+ }
608
+ if (types.isParenthesizedExpression(node) ||
609
+ types.isTSAsExpression(node) ||
610
+ types.isTSSatisfiesExpression(node) ||
611
+ types.isTSTypeAssertion(node) ||
612
+ types.isTSNonNullExpression(node)) {
613
+ return babelObjectExpression(node.expression);
614
+ }
615
+ return null;
616
+ };
617
+ const babelNamedProperty = (object, name) => {
618
+ if (object === null) {
619
+ return null;
620
+ }
621
+ for (const property of object.properties) {
622
+ if (types.isObjectProperty(property) && babelPropertyName(property) === name) {
623
+ return property;
624
+ }
625
+ }
626
+ return null;
627
+ };
628
+ const babelStringProperty = (object, name) => {
629
+ const property = babelNamedProperty(object, name);
630
+ if (property === null) {
631
+ return null;
632
+ }
633
+ const value = babelStaticKey(property.value);
634
+ if (value === null) {
635
+ throw new Error(`Translation ${name} values must be string literals`);
636
+ }
637
+ return value;
638
+ };
639
+ const callOptions = (call) => babelObjectExpression(call.arguments[1]) ?? babelObjectExpression(call.arguments[2]);
640
+ const hookKeyPrefix = (callee) => {
641
+ const binding = callee.scope.getBinding(callee.node.name);
642
+ const hook = binding === undefined ? null : translationHookBinding(binding);
643
+ return babelStringProperty(hook === null ? null : babelObjectExpression(hook.call.arguments[1]), "keyPrefix") ?? "";
644
+ };
645
+ const prefixedTranslationKey = (prefix, key) => {
646
+ if (prefix.length === 0) {
647
+ return key;
648
+ }
649
+ return prefix.endsWith(".") ? `${prefix}${key}` : `${prefix}.${key}`;
650
+ };
651
+ const extractedEntryKey = (call, keyPrefix) => {
652
+ const key = babelStaticKey(call.arguments[0]);
653
+ if (key === null) {
654
+ return null;
655
+ }
656
+ const options = callOptions(call);
657
+ const callPrefix = babelStringProperty(options, "keyPrefix");
658
+ if (callPrefix === "" && keyPrefix.length > 0) {
659
+ throw new Error("An empty call keyPrefix cannot override a hook keyPrefix during extraction");
660
+ }
661
+ const selectedPrefix = callPrefix ?? keyPrefix;
662
+ const prefixed = prefixedTranslationKey(selectedPrefix, key);
663
+ const context = babelStringProperty(options, "context");
664
+ return context === null ? prefixed : `${prefixed}${CONTEXT_SEPARATOR}${context}`;
665
+ };
666
+ const registerEntryLocation = (key, point, references) => {
667
+ if (key === null || point === null) {
668
+ return;
669
+ }
670
+ const locations = references.entryLocations.get(key) ?? [];
671
+ locations.push(point);
672
+ references.entryLocations.set(key, locations);
673
+ };
674
+ const registerCallReference = (callPath, references, keyPrefix) => {
675
+ references.calls.add(nodeStart(callPath));
676
+ const firstArgument = callPath.node.arguments[0];
677
+ const point = registerSourceLocation(firstArgument ?? callPath.node, references);
678
+ if (point !== null) {
679
+ references.sourcePoints.set(nodeStart(callPath), point);
680
+ }
681
+ registerEntryLocation(extractedEntryKey(callPath.node, keyPrefix), point, references);
682
+ };
683
+ const parserPlugins = (lang) => [
684
+ "decorators",
685
+ ...(lang === "ts" || lang === "tsx" ? ["typescript"] : []),
686
+ ...(lang === "jsx" || lang === "tsx" ? ["jsx"] : []),
687
+ ];
688
+ const parseTranslationReferences = (root, path, source, lang) => {
689
+ try {
690
+ return parseBabelSync(source, {
691
+ ast: true,
692
+ babelrc: false,
693
+ configFile: false,
694
+ filename: projectSourcePath(root, path),
695
+ parserOpts: { createParenthesizedExpressions: true, plugins: parserPlugins(lang) },
696
+ sourceType: "module",
697
+ });
698
+ }
699
+ catch (error) {
700
+ throw sourceExtractionError(root, path, errorSourcePoint(error), error);
701
+ }
702
+ };
703
+ const registerIdentifierTranslationCall = (callPath, callee, references) => {
704
+ if (!callee.isIdentifier()) {
705
+ return;
706
+ }
707
+ const kind = translationFunctionKind(callee.scope, callee.node.name);
708
+ if (kind === "alias") {
709
+ throw new Error("Translation calls must use the imported name t");
710
+ }
711
+ if (kind === "canonical") {
712
+ registerCallReference(callPath, references, hookKeyPrefix(callee));
713
+ }
714
+ else if (callee.node.name === "t") {
715
+ registerSourceMask(callee.node, references);
716
+ }
717
+ };
718
+ const registerTranslationCall = (callPath, references) => {
719
+ assertSupportedWrappedCallee(callPath);
720
+ const callee = callPath.get("callee");
721
+ if (callee.isIdentifier()) {
722
+ registerIdentifierTranslationCall(callPath, callee, references);
723
+ return;
724
+ }
725
+ if (callee.isMemberExpression() && isTranslationMember(callee.scope, callee.node)) {
726
+ throw new Error("Translation calls must use the named t export");
727
+ }
728
+ };
729
+ const unwrapTranslationCallee = (node) => {
730
+ if (types.isParenthesizedExpression(node) ||
731
+ types.isTSAsExpression(node) ||
732
+ types.isTSSatisfiesExpression(node) ||
733
+ types.isTSTypeAssertion(node) ||
734
+ types.isTSNonNullExpression(node)) {
735
+ return unwrapTranslationCallee(node.expression);
736
+ }
737
+ return node;
738
+ };
739
+ const isTranslationCallee = (scope, node) => {
740
+ if (types.isIdentifier(node)) {
741
+ return translationFunctionKind(scope, node.name) !== null;
742
+ }
743
+ return (types.isMemberExpression(node) || types.isOptionalMemberExpression(node)) &&
744
+ isTranslationMember(scope, node);
745
+ };
746
+ const assertSupportedWrappedCallee = (callPath) => {
747
+ const callee = callPath.node.callee;
748
+ const unwrapped = unwrapTranslationCallee(callee);
749
+ if (unwrapped !== callee && isTranslationCallee(callPath.scope, unwrapped)) {
750
+ throw new Error("Translation call expressions cannot wrap their callee");
751
+ }
752
+ };
753
+ const assertSupportedOptionalCall = (callPath) => {
754
+ const callee = unwrapTranslationCallee(callPath.node.callee);
755
+ if (isTranslationCallee(callPath.scope, callee)) {
756
+ throw new Error("Translation calls cannot use optional chaining");
757
+ }
758
+ };
759
+ const assertUnsupportedTranslationTag = (tagPath) => {
760
+ const tag = unwrapTranslationCallee(tagPath.node.tag);
761
+ if (isTranslationCallee(tagPath.scope, tag)) {
762
+ throw new Error("Translation calls cannot use tagged-template syntax");
763
+ }
764
+ };
765
+ const registerUnrecognizedElementMasks = (elementPath, name, references) => {
766
+ registerSourceMask(name.node, references);
767
+ const parent = elementPath.parentPath.node;
768
+ const closingName = types.isJSXElement(parent) ? parent.closingElement?.name : null;
769
+ if (types.isJSXIdentifier(closingName)) {
770
+ registerSourceMask(closingName, references);
771
+ }
772
+ };
773
+ const registerElementReference = (elementPath, references) => {
774
+ const start = nodeStart(elementPath);
775
+ const point = registerSourceLocation(elementPath.node, references);
776
+ references.elements.add(start);
777
+ if (point !== null) {
778
+ references.sourcePoints.set(start, point);
779
+ }
780
+ };
781
+ const registerTranslationElement = (elementPath, references) => {
782
+ const name = elementPath.get("name");
783
+ if (!name.isJSXIdentifier()) {
784
+ return;
785
+ }
786
+ const kind = translationElementKind(name, name.node.name);
787
+ if (kind === "alias") {
788
+ throw new Error("Translation components must use their imported names");
789
+ }
790
+ if (kind === "canonical") {
791
+ registerElementReference(elementPath, references);
792
+ }
793
+ else if (TRANS_ELEMENTS.has(name.node.name)) {
794
+ registerUnrecognizedElementMasks(elementPath, name, references);
795
+ }
796
+ };
797
+ const maskUnrecognizedTranslations = (source, references) => {
798
+ let masked = source;
799
+ const masks = references.masks.toSorted((left, right) => right.start - left.start);
800
+ for (const { start, end } of masks) {
801
+ masked = `${masked.slice(0, start)}${"_".repeat(end - start)}${masked.slice(end)}`;
802
+ }
803
+ return masked;
804
+ };
805
+ const translationReferences = (root, path, source, lang) => {
806
+ const parsed = parseTranslationReferences(root, path, source, lang);
807
+ if (parsed === null) {
808
+ throw new Error(`Translation extraction could not parse ${path}`);
809
+ }
810
+ const references = {
811
+ calls: new Set(),
812
+ elements: new Set(),
813
+ entryLocations: new Map(),
814
+ locations: new Map(),
815
+ masks: [],
816
+ sourcePoints: new Map(),
817
+ };
818
+ traverse(parsed, {
819
+ CallExpression(callPath) {
820
+ atSourceNode(root, path, callPath.node, () => {
821
+ registerTranslationCall(callPath, references);
822
+ });
823
+ },
824
+ JSXOpeningElement(elementPath) {
825
+ atSourceNode(root, path, elementPath.node, () => {
826
+ registerTranslationElement(elementPath, references);
827
+ });
828
+ },
829
+ OptionalCallExpression(callPath) {
830
+ atSourceNode(root, path, callPath.node, () => {
831
+ assertSupportedOptionalCall(callPath);
832
+ });
833
+ },
834
+ TaggedTemplateExpression(tagPath) {
835
+ atSourceNode(root, path, tagPath.node, () => {
836
+ assertUnsupportedTranslationTag(tagPath);
837
+ });
838
+ },
839
+ });
840
+ return references;
841
+ };
842
+ const assertSupportedTranslationCall = (node, references) => {
843
+ if (!references.calls.has(node.start)) {
844
+ return;
845
+ }
846
+ assertStaticTranslationKey(node.arguments[0]);
847
+ assertSupportedTranslationOptions(node.arguments[1], node.arguments[2]);
848
+ };
849
+ const assertSupportedTranslationOptions = (second, third) => {
850
+ if (third !== undefined && third !== null) {
851
+ assertStaticTranslationKey(second);
852
+ assertSupportedOptionObject(third);
853
+ return;
854
+ }
855
+ if (second === undefined || second === null || isStaticTranslationKey(second)) {
856
+ return;
857
+ }
858
+ assertSupportedOptionObject(second);
859
+ };
860
+ const isNamedJsxAttribute = (attribute, name) => attribute.name.type === "JSXIdentifier" && attribute.name.name === name;
861
+ const assertSupportedTransKey = (attribute) => {
862
+ if (!isNamedJsxAttribute(attribute, "i18nKey")) {
863
+ return;
864
+ }
865
+ const key = attribute.value?.type === "JSXExpressionContainer"
866
+ ? attribute.value.expression
867
+ : attribute.value;
868
+ assertStaticTranslationKey(key);
869
+ };
870
+ const assertSupportedTransStringAttribute = (attribute, name) => {
871
+ if (!isNamedJsxAttribute(attribute, name)) {
872
+ return;
873
+ }
874
+ const value = attribute.value?.type === "JSXExpressionContainer"
875
+ ? attribute.value.expression
876
+ : attribute.value;
877
+ assertStaticTranslationKey(value);
878
+ };
879
+ const assertSupportedTransOptions = (attribute) => {
880
+ if (isNamedJsxAttribute(attribute, "tOptions") && attribute.value?.type === "JSXExpressionContainer") {
881
+ assertSupportedOptionObject(attribute.value.expression);
882
+ }
883
+ };
884
+ const assertSupportedTransAttribute = (attribute) => {
885
+ if (attribute.type === "JSXSpreadAttribute") {
886
+ throw new Error("Translation extraction requires explicit component properties");
887
+ }
888
+ assertSupportedTransKey(attribute);
889
+ assertSupportedTransStringAttribute(attribute, "context");
890
+ assertSupportedTransStringAttribute(attribute, "defaults");
891
+ assertSupportedTransOptions(attribute);
892
+ };
893
+ const assertSupportedTransElement = (node, references) => {
894
+ if (!references.elements.has(node.start)) {
895
+ return;
896
+ }
897
+ for (const attribute of node.attributes) {
898
+ assertSupportedTransAttribute(attribute);
899
+ }
900
+ };
901
+ const assertSupportedTranslationSyntax = (root, path, source) => {
902
+ const lang = sourceLanguage(path);
903
+ if (lang === undefined) {
904
+ return {
905
+ calls: new Set(),
906
+ elements: new Set(),
907
+ entryLocations: new Map(),
908
+ locations: new Map(),
909
+ masks: [],
910
+ sourcePoints: new Map(),
911
+ };
912
+ }
913
+ let parsed;
914
+ try {
915
+ parsed = parseSync(projectSourcePath(root, path), source, { lang });
916
+ }
917
+ catch (error) {
918
+ throw sourceExtractionError(root, path, errorSourcePoint(error), error);
919
+ }
920
+ const references = translationReferences(root, path, source, lang);
921
+ new Visitor({
922
+ CallExpression(node) {
923
+ try {
924
+ assertSupportedTranslationCall(node, references);
925
+ }
926
+ catch (error) {
927
+ throw sourceExtractionError(root, path, references.sourcePoints.get(node.start) ?? null, error);
928
+ }
929
+ },
930
+ JSXOpeningElement(node) {
931
+ try {
932
+ assertSupportedTransElement(node, references);
933
+ }
934
+ catch (error) {
935
+ throw sourceExtractionError(root, path, references.sourcePoints.get(node.start) ?? null, error);
936
+ }
937
+ },
938
+ }).visit(parsed.program);
939
+ return references;
940
+ };
941
+ const extractedLocationFile = (root, file) => resolve(root, file);
942
+ const isRecognizedLocation = (root, references, location) => {
943
+ if (location.line === undefined || location.column === undefined) {
944
+ return false;
945
+ }
946
+ const sourceReferences = references.get(extractedLocationFile(root, location.file));
947
+ return sourceReferences?.locations.has(sourceLocationKey(location.line, location.column)) === true;
948
+ };
949
+ const recognizedKeyLocations = (references, extractedKey) => {
950
+ const locations = [];
951
+ for (const [file, sourceReferences] of references) {
952
+ const points = sourceReferences.entryLocations.get(extractedKey) ?? [];
953
+ for (const point of points) {
954
+ locations.push({ file, column: point.column, line: point.line });
955
+ }
956
+ }
957
+ return locations;
958
+ };
959
+ const recognizedEntry = (root, references, entry) => {
960
+ const extractedLocations = entry.locations ?? [];
961
+ const locations = extractedLocations.length === 0
962
+ ? recognizedKeyLocations(references, entry.key)
963
+ : extractedLocations.filter((location) => isRecognizedLocation(root, references, location));
964
+ return locations.length === 0 ? null : { ...entry, locations };
965
+ };
966
+ const quotedNestedReferenceParts = (content, quote) => {
967
+ const end = content.indexOf(quote, 1);
968
+ return end === -1
969
+ ? null
970
+ : { base: content.slice(1, end), options: content.slice(end + 1) };
971
+ };
972
+ const nestedReferenceParts = (value) => {
973
+ const content = value.trim();
974
+ const quote = content[0];
975
+ if (quote === "\"" || quote === "'") {
976
+ return quotedNestedReferenceParts(content, quote);
977
+ }
978
+ const separator = content.indexOf(",");
979
+ const base = (separator === -1 ? content : content.slice(0, separator)).trim();
980
+ return base.length === 0
981
+ ? null
982
+ : { base, options: separator === -1 ? "" : content.slice(separator + 1) };
983
+ };
984
+ const nestedReferenceContext = (options) => {
985
+ const match = NESTED_CONTEXT.exec(options);
986
+ const context = match?.[1] ?? match?.[2] ?? null;
987
+ return context === null || context.length === 0 ? null : context;
988
+ };
989
+ const adjustedParenthesisDepth = (character, depth) => {
990
+ if (character === "(") {
991
+ return depth + 1;
992
+ }
993
+ return character === ")" ? depth - 1 : depth;
994
+ };
995
+ const nestedReferenceEnd = (text, start) => {
996
+ let depth = 0;
997
+ const tokens = text.slice(start).matchAll(NESTED_STRUCTURE_TOKEN);
998
+ for (const token of tokens) {
999
+ const character = token[0];
1000
+ if (character === ")" && depth === 0) {
1001
+ return start + token.index;
1002
+ }
1003
+ depth = adjustedParenthesisDepth(character, depth);
1004
+ }
1005
+ return -1;
1006
+ };
1007
+ const nestedReferenceContents = (text) => {
1008
+ const contents = [];
1009
+ let offset = 0;
1010
+ while (offset < text.length) {
1011
+ const prefix = text.indexOf("$t(", offset);
1012
+ if (prefix === -1) {
1013
+ break;
1014
+ }
1015
+ const start = prefix + 3;
1016
+ const end = nestedReferenceEnd(text, start);
1017
+ if (end === -1) {
1018
+ break;
1019
+ }
1020
+ contents.push(text.slice(start, end));
1021
+ offset = end + 1;
1022
+ }
1023
+ return contents;
1024
+ };
1025
+ const nestedPluralKeys = (base, context) => {
1026
+ const pluralBase = context === null ? base : `${base}${CONTEXT_SEPARATOR}${context}`;
1027
+ return [`${pluralBase}_one`, `${pluralBase}_other`];
1028
+ };
1029
+ const nestedReferenceKeys = (content) => {
1030
+ const parts = nestedReferenceParts(content);
1031
+ if (parts === null) {
1032
+ return [];
1033
+ }
1034
+ const context = nestedReferenceContext(parts.options);
1035
+ const contextual = context === null
1036
+ ? []
1037
+ : [`${parts.base}_${context}`, `${parts.base}${CONTEXT_SEPARATOR}${context}`];
1038
+ return NESTED_COUNT.test(parts.options)
1039
+ ? [parts.base, ...contextual, ...nestedPluralKeys(parts.base, context)]
1040
+ : [parts.base, ...contextual];
1041
+ };
1042
+ const nestedEntryKeys = (text) => {
1043
+ const keys = new Set();
1044
+ for (const content of nestedReferenceContents(text)) {
1045
+ for (const key of nestedReferenceKeys(content)) {
1046
+ keys.add(key);
1047
+ }
1048
+ }
1049
+ return keys;
1050
+ };
1051
+ const registerNestedKeyLocations = (root, references, key, locations) => {
1052
+ for (const location of locations) {
1053
+ if (location.line === undefined || location.column === undefined) {
1054
+ continue;
1055
+ }
1056
+ const sourceReferences = references.get(resolve(root, location.file));
1057
+ if (sourceReferences !== undefined) {
1058
+ registerEntryLocation(key, { column: location.column, line: location.line }, sourceReferences);
1059
+ }
1060
+ }
1061
+ };
1062
+ const registerNestedTextLocations = (root, references, text, locations) => {
1063
+ for (const key of nestedEntryKeys(text)) {
1064
+ registerNestedKeyLocations(root, references, key, locations);
1065
+ }
1066
+ };
1067
+ const registerNestedEntryLocations = (root, references, entry, locations) => {
1068
+ registerNestedTextLocations(root, references, entry.key, locations);
1069
+ if (typeof entry.defaultValue === "string") {
1070
+ registerNestedTextLocations(root, references, entry.defaultValue, locations);
1071
+ }
1072
+ };
1073
+ const didRegisterNestedLocationPass = (root, references, entries, processed) => {
1074
+ let didRegister = false;
1075
+ for (const [mapKey, entry] of entries) {
1076
+ if (processed.has(mapKey)) {
1077
+ continue;
1078
+ }
1079
+ const recognized = recognizedEntry(root, references, entry);
1080
+ if (recognized !== null) {
1081
+ processed.add(mapKey);
1082
+ registerNestedEntryLocations(root, references, entry, recognized.locations ?? []);
1083
+ didRegister = true;
1084
+ }
1085
+ }
1086
+ return didRegister;
1087
+ };
1088
+ const registerNestedLocations = (root, references, entries) => {
1089
+ const processed = new Set();
1090
+ let hasRegisteredLocations = true;
1091
+ while (hasRegisteredLocations) {
1092
+ hasRegisteredLocations = didRegisterNestedLocationPass(root, references, entries, processed);
1093
+ }
1094
+ };
1095
+ const retainRecognizedEntries = (root, references, entries) => {
1096
+ for (const [mapKey, entry] of entries) {
1097
+ const recognized = recognizedEntry(root, references, entry);
1098
+ if (recognized === null) {
1099
+ entries.delete(mapKey);
1100
+ }
1101
+ else {
1102
+ entries.set(mapKey, recognized);
1103
+ }
1104
+ }
1105
+ };
1106
+ const fileSourcePointKey = (file, line, column) => `${file}\0${sourceLocationKey(line, column)}`;
1107
+ const registerExtractedSourcePoint = (root, points, location) => {
1108
+ if (location.line !== undefined && location.column !== undefined) {
1109
+ points.add(fileSourcePointKey(resolve(root, location.file), location.line, location.column));
1110
+ }
1111
+ };
1112
+ const extractedSourcePoints = (root, entries) => {
1113
+ const points = new Set();
1114
+ for (const entry of entries.values()) {
1115
+ const locations = entry.locations ?? [];
1116
+ for (const location of locations) {
1117
+ registerExtractedSourcePoint(root, points, location);
1118
+ }
1119
+ }
1120
+ return points;
1121
+ };
1122
+ const missingSourcePoint = (file, references, extracted) => {
1123
+ for (const [location, point] of references.locations) {
1124
+ if (!extracted.has(`${file}\0${location}`)) {
1125
+ return point;
1126
+ }
1127
+ }
1128
+ return null;
1129
+ };
1130
+ const assertAllReferencesExtracted = (root, references, entries) => {
1131
+ const extracted = extractedSourcePoints(root, entries);
1132
+ for (const [file, sourceReferences] of references) {
1133
+ const point = missingSourcePoint(file, sourceReferences, extracted);
1134
+ if (point !== null) {
1135
+ throw sourceExtractionError(root, file, point, new Error("A translation expression could not be extracted safely"));
1136
+ }
1137
+ }
1138
+ };
1139
+ const findSourceMessages = async (root, sourceFiles) => {
201
1140
  if (sourceFiles.length === 0) {
1141
+ clearI18nResources(root);
202
1142
  return [];
203
1143
  }
204
- const fileErrors = [];
1144
+ const sources = new Map(sourceFiles.map((file) => [file, readFileSync(file, "utf8")]));
1145
+ const references = new Map();
1146
+ for (const [file, source] of sources) {
1147
+ references.set(file, assertSupportedTranslationSyntax(root, file, source));
1148
+ }
1149
+ let extracted;
205
1150
  const { logger, reports } = quietLogger();
206
- const { allKeys } = await findKeys(extractorConfig(sourceFiles), logger, fileErrors);
207
- if (fileErrors.length > 0 || reports.length > 0) {
208
- throw new Error([...fileErrors, ...reports].join("\n"));
1151
+ const capture = {
1152
+ name: "gtkx-gettext",
1153
+ onLoad(code, path) {
1154
+ const sourceReferences = references.get(resolve(root, path));
1155
+ return sourceReferences === undefined
1156
+ ? code
1157
+ : maskUnrecognizedTranslations(code, sourceReferences);
1158
+ },
1159
+ onEnd(keys) {
1160
+ registerNestedLocations(root, references, keys);
1161
+ retainRecognizedEntries(root, references, keys);
1162
+ assertAllReferencesExtracted(root, references, keys);
1163
+ extracted = keys;
1164
+ },
1165
+ };
1166
+ const result = await runExtractor(i18nToolkitConfig(root, sourceFiles, [capture]), {
1167
+ logger,
1168
+ quiet: true,
1169
+ syncPrimaryWithDefaults: true,
1170
+ trustDerivedDefaults: true,
1171
+ });
1172
+ if (extracted === undefined || reports.length > 0 || result.hasErrors) {
1173
+ throw new Error(reports.join("\n") || "i18next extraction failed");
209
1174
  }
210
- return sourceMessages(allKeys.values().toArray()).toSorted(compareMessages);
1175
+ return sourceMessages(root, extracted.values().toArray())
1176
+ .map((message) => inferLocations(message, sources))
1177
+ .toSorted(compareMessages);
211
1178
  };
212
1179
  const projectPath = (root, path) => {
213
1180
  const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);
214
1181
  const projectRelative = relative(root, absolute);
215
- if (projectRelative === "" ||
216
- projectRelative === ".." ||
217
- projectRelative.startsWith(`..${sep}`) ||
218
- isAbsolute(projectRelative)) {
1182
+ if (!isPathInside(root, absolute)) {
219
1183
  return null;
220
1184
  }
221
- return projectRelative.replaceAll("\\", "/");
1185
+ return toPosixPath(projectRelative);
222
1186
  };
223
1187
  const writePotfiles = (project, sourceFiles) => {
224
1188
  const paths = sourceFiles
@@ -241,7 +1205,6 @@ const renderCatalogCall = (message) => {
241
1205
  ? `gettext(${msgid});`
242
1206
  : `pgettext(${JSON.stringify(message.context)}, ${msgid});`;
243
1207
  };
244
- const readSources = (sourceFiles) => new Map(sourceFiles.map((path) => [path, readFileSync(path, "utf8")]));
245
1208
  const locatedOwners = (project, message) => {
246
1209
  const owners = [];
247
1210
  for (const location of message.locations) {
@@ -253,30 +1216,14 @@ const locatedOwners = (project, message) => {
253
1216
  const unique = new Map(owners.map((owner) => [`${owner.path}\0${String(owner.line)}`, owner]));
254
1217
  return unique.values().toArray();
255
1218
  };
256
- const inferredOwner = (project, message, sources) => {
257
- for (const [path, source] of sources) {
258
- const index = source.indexOf(message.msgid);
259
- if (index !== -1) {
260
- return {
261
- path: projectPath(project.root, path) ?? SYNTHETIC_FILENAME,
262
- line: source.slice(0, index).split("\n").length,
263
- };
264
- }
265
- }
266
- return null;
267
- };
268
- const sourceOwners = (project, message, sources) => {
1219
+ const sourceOwners = (project, message) => {
269
1220
  const located = locatedOwners(project, message);
270
- if (located.length > 0) {
271
- return located;
272
- }
273
- return [inferredOwner(project, message, sources) ?? { path: SYNTHETIC_FILENAME, line: undefined }];
1221
+ return located.length > 0 ? located : [{ path: SYNTHETIC_FILENAME, line: undefined }];
274
1222
  };
275
- const syntheticEntries = (project, messages, sourceFiles) => {
276
- const sources = readSources(sourceFiles);
1223
+ const syntheticEntries = (project, messages) => {
277
1224
  const entries = new Map();
278
1225
  for (const message of messages) {
279
- for (const owner of sourceOwners(project, message, sources)) {
1226
+ for (const owner of sourceOwners(project, message)) {
280
1227
  const owned = entries.get(owner.path) ?? [];
281
1228
  owned.push({ call: renderCatalogCall(message), line: owner.line });
282
1229
  entries.set(owner.path, owned);
@@ -314,8 +1261,8 @@ const renderSyntheticSource = (entries) => {
314
1261
  }
315
1262
  return `${lines.join("\n")}\n`;
316
1263
  };
317
- const writeSyntheticSources = (workDir, project, messages, sourceFiles) => {
318
- const entries = syntheticEntries(project, messages, sourceFiles);
1264
+ const writeSyntheticSources = (workDir, project, messages) => {
1265
+ const entries = syntheticEntries(project, messages);
319
1266
  const paths = [];
320
1267
  for (const [path, owned] of entries) {
321
1268
  const target = join(workDir, path);
@@ -327,8 +1274,8 @@ const writeSyntheticSources = (workDir, project, messages, sourceFiles) => {
327
1274
  writeFileSync(potfiles, `${paths.toSorted((left, right) => left.localeCompare(right)).join("\n")}\n`);
328
1275
  return potfiles;
329
1276
  };
330
- const extractSourceMessages = ({ project, messages, sourceFiles, output, workDir }) => {
331
- const potfilesPath = writeSyntheticSources(workDir, project, messages, sourceFiles);
1277
+ const extractSourceMessages = ({ project, messages, output, workDir }) => {
1278
+ const potfilesPath = writeSyntheticSources(workDir, project, messages);
332
1279
  runCliTool({
333
1280
  tool: "xgettext",
334
1281
  args: [
@@ -365,7 +1312,7 @@ const joinMetadataFragment = (output, fragment) => {
365
1312
  target: output,
366
1313
  });
367
1314
  };
368
- const extractCatalogTemplate = ({ project, messages, sourceFiles, shouldPreserveMetadataMessages, output = resolve(project.poDir, `${project.domain}.pot`), }) => {
1315
+ const extractCatalogTemplate = ({ project, messages, shouldPreserveMetadataMessages, output = resolve(project.poDir, `${project.domain}.pot`), }) => {
369
1316
  const workDir = mkdtempSync(join(project.poDir, ".gtkx-i18n-"));
370
1317
  const source = join(workDir, "source.pot");
371
1318
  const hasPreviousTemplate = existsSync(output);
@@ -373,11 +1320,11 @@ const extractCatalogTemplate = ({ project, messages, sourceFiles, shouldPreserve
373
1320
  if (shouldPreserveMetadataMessages && hasPreviousTemplate) {
374
1321
  const fragment = join(workDir, "metadata.pot");
375
1322
  extractMetadataFragment(project, output, fragment);
376
- extractSourceMessages({ project, messages, sourceFiles, output: source, workDir });
1323
+ extractSourceMessages({ project, messages, output: source, workDir });
377
1324
  joinMetadataFragment(source, fragment);
378
1325
  }
379
1326
  else {
380
- extractSourceMessages({ project, messages, sourceFiles, output: source, workDir });
1327
+ extractSourceMessages({ project, messages, output: source, workDir });
381
1328
  }
382
1329
  replaceCatalogTemplate(source, output);
383
1330
  }
@@ -387,17 +1334,15 @@ const extractCatalogTemplate = ({ project, messages, sourceFiles, shouldPreserve
387
1334
  };
388
1335
  const extractSourceCatalogTo = async (project, paths, output) => {
389
1336
  const sourceFiles = normalizedSourceFiles(project.root, paths);
390
- const messages = await findSourceMessages(sourceFiles);
1337
+ const messages = await findSourceMessages(project.root, sourceFiles);
391
1338
  writePotfiles(project, sourceFiles);
392
- extractCatalogTemplate({ project, messages, sourceFiles, shouldPreserveMetadataMessages: false, output });
393
- return { messages, sourceFiles };
1339
+ extractCatalogTemplate({ project, messages, shouldPreserveMetadataMessages: false, output });
394
1340
  };
395
1341
  const extractSourceCatalog = async (project, paths, shouldPreserveMetadataMessages = true) => {
396
1342
  const sourceFiles = normalizedSourceFiles(project.root, paths);
397
- const messages = await findSourceMessages(sourceFiles);
1343
+ const messages = await findSourceMessages(project.root, sourceFiles);
398
1344
  writePotfiles(project, sourceFiles);
399
- extractCatalogTemplate({ project, messages, sourceFiles, shouldPreserveMetadataMessages });
400
- return { messages, sourceFiles };
1345
+ extractCatalogTemplate({ project, messages, shouldPreserveMetadataMessages });
401
1346
  };
402
- export { extractSourceCatalog, extractSourceCatalogTo };
1347
+ export { extractSourceCatalog, extractSourceCatalogTo, SourceExtractionError };
403
1348
  //# sourceMappingURL=source-messages.js.map