@gtkx/cli 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/README.md +5 -4
  2. package/dist/builder.d.ts +1 -1
  3. package/dist/builder.d.ts.map +1 -1
  4. package/dist/builder.js +6 -6
  5. package/dist/builder.js.map +1 -1
  6. package/dist/codegen/run-codegen.d.ts +3 -2
  7. package/dist/codegen/run-codegen.d.ts.map +1 -1
  8. package/dist/codegen/run-codegen.js +41 -12
  9. package/dist/codegen/run-codegen.js.map +1 -1
  10. package/dist/commands/build.d.ts +0 -4
  11. package/dist/commands/build.d.ts.map +1 -1
  12. package/dist/commands/build.js +0 -5
  13. package/dist/commands/build.js.map +1 -1
  14. package/dist/commands/codegen.d.ts.map +1 -1
  15. package/dist/commands/codegen.js +2 -4
  16. package/dist/commands/codegen.js.map +1 -1
  17. package/dist/deploy/depends.d.ts +2 -2
  18. package/dist/deploy/depends.d.ts.map +1 -1
  19. package/dist/deploy/depends.js +30 -15
  20. package/dist/deploy/depends.js.map +1 -1
  21. package/dist/deploy/freedesktop/localize.d.ts +6 -0
  22. package/dist/deploy/freedesktop/localize.d.ts.map +1 -0
  23. package/dist/deploy/freedesktop/localize.js +107 -0
  24. package/dist/deploy/freedesktop/localize.js.map +1 -0
  25. package/dist/deploy/install-hints.d.ts.map +1 -1
  26. package/dist/deploy/install-hints.js +5 -0
  27. package/dist/deploy/install-hints.js.map +1 -1
  28. package/dist/deploy/nfpm/config.js +1 -1
  29. package/dist/deploy/nfpm/config.js.map +1 -1
  30. package/dist/deploy/node-runtime/elf.d.ts +1 -1
  31. package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
  32. package/dist/deploy/node-runtime/elf.js +2 -2
  33. package/dist/deploy/node-runtime/elf.js.map +1 -1
  34. package/dist/deploy/node-runtime/index.js +2 -2
  35. package/dist/deploy/node-runtime/index.js.map +1 -1
  36. package/dist/deploy/notices/collect.d.ts +3 -1
  37. package/dist/deploy/notices/collect.d.ts.map +1 -1
  38. package/dist/deploy/notices/collect.js +2 -2
  39. package/dist/deploy/notices/collect.js.map +1 -1
  40. package/dist/deploy/notices/packages.d.ts +2 -1
  41. package/dist/deploy/notices/packages.d.ts.map +1 -1
  42. package/dist/deploy/notices/packages.js +4 -27
  43. package/dist/deploy/notices/packages.js.map +1 -1
  44. package/dist/deploy/payload/icons.d.ts +7 -3
  45. package/dist/deploy/payload/icons.d.ts.map +1 -1
  46. package/dist/deploy/payload/icons.js +46 -28
  47. package/dist/deploy/payload/icons.js.map +1 -1
  48. package/dist/deploy/payload/launcher.d.ts.map +1 -1
  49. package/dist/deploy/payload/launcher.js +2 -0
  50. package/dist/deploy/payload/launcher.js.map +1 -1
  51. package/dist/deploy/payload/stage.d.ts +1 -1
  52. package/dist/deploy/payload/stage.d.ts.map +1 -1
  53. package/dist/deploy/payload/stage.js +23 -13
  54. package/dist/deploy/payload/stage.js.map +1 -1
  55. package/dist/deploy/run-deploy.d.ts.map +1 -1
  56. package/dist/deploy/run-deploy.js +149 -25
  57. package/dist/deploy/run-deploy.js.map +1 -1
  58. package/dist/deploy/settings/build-manifest.d.ts +9 -0
  59. package/dist/deploy/settings/build-manifest.d.ts.map +1 -0
  60. package/dist/deploy/settings/build-manifest.js +80 -0
  61. package/dist/deploy/settings/build-manifest.js.map +1 -0
  62. package/dist/deploy/settings/index.d.ts.map +1 -1
  63. package/dist/deploy/settings/index.js +9 -3
  64. package/dist/deploy/settings/index.js.map +1 -1
  65. package/dist/deploy/settings/libraries.d.ts +8 -0
  66. package/dist/deploy/settings/libraries.d.ts.map +1 -0
  67. package/dist/deploy/settings/libraries.js +39 -0
  68. package/dist/deploy/settings/libraries.js.map +1 -0
  69. package/dist/deploy/settings/paths.d.ts +3 -0
  70. package/dist/deploy/settings/paths.d.ts.map +1 -1
  71. package/dist/deploy/settings/paths.js +6 -32
  72. package/dist/deploy/settings/paths.js.map +1 -1
  73. package/dist/deploy/targets/appimage.d.ts.map +1 -1
  74. package/dist/deploy/targets/appimage.js +19 -13
  75. package/dist/deploy/targets/appimage.js.map +1 -1
  76. package/dist/deploy/targets/flatpak-manifest.d.ts +2 -1
  77. package/dist/deploy/targets/flatpak-manifest.d.ts.map +1 -1
  78. package/dist/deploy/targets/flatpak-manifest.js +5 -1
  79. package/dist/deploy/targets/flatpak-manifest.js.map +1 -1
  80. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
  81. package/dist/deploy/targets/flatpak-source.js +30 -16
  82. package/dist/deploy/targets/flatpak-source.js.map +1 -1
  83. package/dist/deploy/tools.d.ts +6 -1
  84. package/dist/deploy/tools.d.ts.map +1 -1
  85. package/dist/deploy/tools.js +26 -1
  86. package/dist/deploy/tools.js.map +1 -1
  87. package/dist/deploy/types.d.ts +4 -4
  88. package/dist/deploy/types.d.ts.map +1 -1
  89. package/dist/deploy/types.js.map +1 -1
  90. package/dist/dev/icon-dir.d.ts +1 -1
  91. package/dist/dev/icon-dir.d.ts.map +1 -1
  92. package/dist/dev/icon-dir.js +20 -7
  93. package/dist/dev/icon-dir.js.map +1 -1
  94. package/dist/dev/locale-dir.d.ts +3 -0
  95. package/dist/dev/locale-dir.d.ts.map +1 -0
  96. package/dist/dev/locale-dir.js +17 -0
  97. package/dist/dev/locale-dir.js.map +1 -0
  98. package/dist/dev/runner-deps.d.ts.map +1 -1
  99. package/dist/dev/runner-deps.js +5 -1
  100. package/dist/dev/runner-deps.js.map +1 -1
  101. package/dist/dev/runner-main.d.ts.map +1 -1
  102. package/dist/dev/runner-main.js +6 -4
  103. package/dist/dev/runner-main.js.map +1 -1
  104. package/dist/dev/runner.d.ts +1 -1
  105. package/dist/dev/runner.d.ts.map +1 -1
  106. package/dist/dev/runner.js +7 -1
  107. package/dist/dev/runner.js.map +1 -1
  108. package/dist/dev/schema-dir.d.ts +1 -1
  109. package/dist/dev/schema-dir.d.ts.map +1 -1
  110. package/dist/dev/schema-dir.js +3 -1
  111. package/dist/dev/schema-dir.js.map +1 -1
  112. package/dist/dev/vite-dev-server.d.ts +1 -0
  113. package/dist/dev/vite-dev-server.d.ts.map +1 -1
  114. package/dist/dev/vite-dev-server.js.map +1 -1
  115. package/dist/i18n/binding-extractor.d.ts +30 -0
  116. package/dist/i18n/binding-extractor.d.ts.map +1 -0
  117. package/dist/i18n/binding-extractor.js +1324 -0
  118. package/dist/i18n/binding-extractor.js.map +1 -0
  119. package/dist/i18n/catalog-template.d.ts +3 -0
  120. package/dist/i18n/catalog-template.d.ts.map +1 -0
  121. package/dist/i18n/catalog-template.js +18 -0
  122. package/dist/i18n/catalog-template.js.map +1 -0
  123. package/dist/i18n/catalogs.d.ts +21 -0
  124. package/dist/i18n/catalogs.d.ts.map +1 -0
  125. package/dist/i18n/catalogs.js +139 -0
  126. package/dist/i18n/catalogs.js.map +1 -0
  127. package/dist/i18n/extractor-plugin.d.ts +8 -0
  128. package/dist/i18n/extractor-plugin.d.ts.map +1 -0
  129. package/dist/i18n/extractor-plugin.js +247 -0
  130. package/dist/i18n/extractor-plugin.js.map +1 -0
  131. package/dist/i18n/metadata-templates.d.ts +11 -0
  132. package/dist/i18n/metadata-templates.d.ts.map +1 -0
  133. package/dist/i18n/metadata-templates.js +11 -0
  134. package/dist/i18n/metadata-templates.js.map +1 -0
  135. package/dist/i18n/source-messages.d.ts +23 -0
  136. package/dist/i18n/source-messages.d.ts.map +1 -0
  137. package/dist/i18n/source-messages.js +403 -0
  138. package/dist/i18n/source-messages.js.map +1 -0
  139. package/dist/i18n/types.d.ts +10 -0
  140. package/dist/i18n/types.d.ts.map +1 -0
  141. package/dist/i18n/types.js +108 -0
  142. package/dist/i18n/types.js.map +1 -0
  143. package/dist/internal/build-manifest.d.ts +20 -0
  144. package/dist/internal/build-manifest.d.ts.map +1 -0
  145. package/dist/internal/build-manifest.js +6 -0
  146. package/dist/internal/build-manifest.js.map +1 -0
  147. package/dist/internal/icon-path.d.ts +13 -0
  148. package/dist/internal/icon-path.d.ts.map +1 -0
  149. package/dist/internal/icon-path.js +86 -0
  150. package/dist/internal/icon-path.js.map +1 -0
  151. package/dist/internal/source-imports.d.ts +12 -0
  152. package/dist/internal/source-imports.d.ts.map +1 -0
  153. package/dist/internal/source-imports.js +123 -0
  154. package/dist/internal/source-imports.js.map +1 -0
  155. package/dist/mcp/client.d.ts +0 -1
  156. package/dist/mcp/client.d.ts.map +1 -1
  157. package/dist/mcp/client.js +11 -39
  158. package/dist/mcp/client.js.map +1 -1
  159. package/dist/mcp/handlers.d.ts +2 -1
  160. package/dist/mcp/handlers.d.ts.map +1 -1
  161. package/dist/mcp/handlers.js.map +1 -1
  162. package/dist/mcp/widget-properties.d.ts.map +1 -1
  163. package/dist/mcp/widget-properties.js +3 -12
  164. package/dist/mcp/widget-properties.js.map +1 -1
  165. package/dist/settings/render.d.ts +10 -1
  166. package/dist/settings/render.d.ts.map +1 -1
  167. package/dist/settings/render.js +78 -20
  168. package/dist/settings/render.js.map +1 -1
  169. package/dist/settings/schema.d.ts +4 -3
  170. package/dist/settings/schema.d.ts.map +1 -1
  171. package/dist/settings/schema.js +124 -15
  172. package/dist/settings/schema.js.map +1 -1
  173. package/dist/vite-plugins/asset-emitter.d.ts +1 -1
  174. package/dist/vite-plugins/asset-emitter.d.ts.map +1 -1
  175. package/dist/vite-plugins/asset-emitter.js.map +1 -1
  176. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  177. package/dist/vite-plugins/asset-extensions.js +1 -0
  178. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  179. package/dist/vite-plugins/asset-imports.d.ts +2 -1
  180. package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
  181. package/dist/vite-plugins/asset-imports.js +39 -28
  182. package/dist/vite-plugins/asset-imports.js.map +1 -1
  183. package/dist/vite-plugins/asset-specifier.d.ts +13 -1
  184. package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
  185. package/dist/vite-plugins/asset-specifier.js +39 -1
  186. package/dist/vite-plugins/asset-specifier.js.map +1 -1
  187. package/dist/vite-plugins/build-manifest.d.ts +5 -0
  188. package/dist/vite-plugins/build-manifest.d.ts.map +1 -0
  189. package/dist/vite-plugins/{bundled-packages.js → build-manifest.js} +20 -14
  190. package/dist/vite-plugins/build-manifest.js.map +1 -0
  191. package/dist/vite-plugins/built-url.d.ts +1 -1
  192. package/dist/vite-plugins/built-url.d.ts.map +1 -1
  193. package/dist/vite-plugins/built-url.js +37 -24
  194. package/dist/vite-plugins/built-url.js.map +1 -1
  195. package/dist/vite-plugins/i18n.d.ts +5 -0
  196. package/dist/vite-plugins/i18n.d.ts.map +1 -0
  197. package/dist/vite-plugins/i18n.js +88 -0
  198. package/dist/vite-plugins/i18n.js.map +1 -0
  199. package/dist/vite-plugins/icons.d.ts +2 -1
  200. package/dist/vite-plugins/icons.d.ts.map +1 -1
  201. package/dist/vite-plugins/icons.js +25 -12
  202. package/dist/vite-plugins/icons.js.map +1 -1
  203. package/dist/vite-plugins/index.d.ts +2 -1
  204. package/dist/vite-plugins/index.d.ts.map +1 -1
  205. package/dist/vite-plugins/index.js +9 -5
  206. package/dist/vite-plugins/index.js.map +1 -1
  207. package/dist/vite-plugins/native.d.ts.map +1 -1
  208. package/dist/vite-plugins/native.js +23 -4
  209. package/dist/vite-plugins/native.js.map +1 -1
  210. package/dist/vite-plugins/resource-init-module.d.ts +7 -3
  211. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -1
  212. package/dist/vite-plugins/resource-init-module.js +39 -14
  213. package/dist/vite-plugins/resource-init-module.js.map +1 -1
  214. package/dist/vite-plugins/resource-shared.d.ts +3 -1
  215. package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
  216. package/dist/vite-plugins/resource-shared.js +3 -1
  217. package/dist/vite-plugins/resource-shared.js.map +1 -1
  218. package/dist/vite-plugins/resources.d.ts +1 -1
  219. package/dist/vite-plugins/resources.d.ts.map +1 -1
  220. package/dist/vite-plugins/resources.js +877 -86
  221. package/dist/vite-plugins/resources.js.map +1 -1
  222. package/dist/vite-plugins/self-contained.d.ts.map +1 -1
  223. package/dist/vite-plugins/self-contained.js +128 -135
  224. package/dist/vite-plugins/self-contained.js.map +1 -1
  225. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
  226. package/dist/vite-plugins/settings-worker-env.js +6 -3
  227. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  228. package/dist/vite-plugins/settings.d.ts +3 -1
  229. package/dist/vite-plugins/settings.d.ts.map +1 -1
  230. package/dist/vite-plugins/settings.js +63 -23
  231. package/dist/vite-plugins/settings.js.map +1 -1
  232. package/env.d.ts +11 -192
  233. package/package.json +11 -10
  234. package/src/builder.ts +7 -7
  235. package/src/codegen/run-codegen.ts +64 -15
  236. package/src/commands/build.ts +0 -5
  237. package/src/commands/codegen.ts +2 -4
  238. package/src/deploy/depends.ts +47 -18
  239. package/src/deploy/freedesktop/localize.ts +144 -0
  240. package/src/deploy/install-hints.ts +5 -0
  241. package/src/deploy/nfpm/config.ts +1 -1
  242. package/src/deploy/node-runtime/elf.ts +3 -3
  243. package/src/deploy/node-runtime/index.ts +2 -2
  244. package/src/deploy/notices/collect.ts +4 -2
  245. package/src/deploy/notices/packages.ts +5 -43
  246. package/src/deploy/payload/icons.ts +64 -34
  247. package/src/deploy/payload/launcher.ts +2 -0
  248. package/src/deploy/payload/stage.ts +40 -12
  249. package/src/deploy/run-deploy.ts +214 -24
  250. package/src/deploy/settings/build-manifest.ts +122 -0
  251. package/src/deploy/settings/index.ts +9 -4
  252. package/src/deploy/settings/libraries.ts +57 -0
  253. package/src/deploy/settings/paths.ts +10 -47
  254. package/src/deploy/targets/appimage.ts +32 -15
  255. package/src/deploy/targets/flatpak-manifest.ts +7 -1
  256. package/src/deploy/targets/flatpak-source.ts +42 -20
  257. package/src/deploy/tools.ts +35 -0
  258. package/src/deploy/types.ts +4 -4
  259. package/src/dev/icon-dir.ts +31 -7
  260. package/src/dev/locale-dir.ts +22 -0
  261. package/src/dev/runner-deps.ts +5 -1
  262. package/src/dev/runner-main.ts +6 -4
  263. package/src/dev/runner.ts +10 -2
  264. package/src/dev/schema-dir.ts +3 -1
  265. package/src/dev/vite-dev-server.ts +1 -0
  266. package/src/i18n/binding-extractor.ts +1969 -0
  267. package/src/i18n/catalog-template.ts +24 -0
  268. package/src/i18n/catalogs.ts +216 -0
  269. package/src/i18n/extractor-plugin.ts +413 -0
  270. package/src/i18n/metadata-templates.ts +29 -0
  271. package/src/i18n/source-messages.ts +608 -0
  272. package/src/i18n/types.ts +154 -0
  273. package/src/internal/build-manifest.ts +32 -0
  274. package/src/internal/icon-path.ts +127 -0
  275. package/src/internal/source-imports.ts +171 -0
  276. package/src/mcp/client.ts +17 -44
  277. package/src/mcp/handlers.ts +7 -6
  278. package/src/mcp/widget-properties.ts +3 -14
  279. package/src/settings/render.ts +113 -21
  280. package/src/settings/schema.ts +192 -17
  281. package/src/vite-plugins/asset-emitter.ts +1 -1
  282. package/src/vite-plugins/asset-extensions.ts +1 -0
  283. package/src/vite-plugins/asset-imports.ts +62 -33
  284. package/src/vite-plugins/asset-specifier.ts +73 -1
  285. package/src/vite-plugins/{bundled-packages.ts → build-manifest.ts} +30 -19
  286. package/src/vite-plugins/built-url.ts +49 -28
  287. package/src/vite-plugins/i18n.ts +146 -0
  288. package/src/vite-plugins/icons.ts +33 -14
  289. package/src/vite-plugins/index.ts +15 -5
  290. package/src/vite-plugins/native.ts +31 -4
  291. package/src/vite-plugins/resource-init-module.ts +44 -15
  292. package/src/vite-plugins/resource-shared.ts +4 -0
  293. package/src/vite-plugins/resources.ts +1397 -100
  294. package/src/vite-plugins/self-contained.ts +150 -169
  295. package/src/vite-plugins/settings-worker-env.ts +7 -3
  296. package/src/vite-plugins/settings.ts +89 -21
  297. package/dist/vite-plugins/bundled-packages.d.ts +0 -5
  298. package/dist/vite-plugins/bundled-packages.d.ts.map +0 -1
  299. package/dist/vite-plugins/bundled-packages.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gtkx/cli",
3
- "version": "1.3.0",
4
- "description": "Command-line tool and Vite plugin stack that scaffolds, develops, builds, and documents GTKX applications",
3
+ "version": "1.5.0",
4
+ "description": "GTK app toolchain for React: scaffold, dev server, build, docs.",
5
5
  "keywords": [
6
6
  "gtkx",
7
7
  "gtk",
@@ -70,22 +70,23 @@
70
70
  "babel-plugin-react-compiler": "^1.0.0",
71
71
  "citty": "^0.2.2",
72
72
  "fast-xml-parser": "^5.11.0",
73
+ "i18next-cli": "1.71.3",
73
74
  "react-refresh": "^0.18.0",
74
75
  "vite": "^8.2.2",
75
76
  "yaml": "^2.9.0",
76
- "@gtkx/config": "1.3.0",
77
- "@gtkx/codegen": "1.3.0",
78
- "@gtkx/runtime": "1.3.0",
79
- "@gtkx/mcp": "1.3.0",
80
- "@gtkx/utils": "1.3.0",
81
- "@gtkx/vitest": "1.3.0",
82
- "create-gtkx": "1.3.0"
77
+ "@gtkx/codegen": "1.5.0",
78
+ "@gtkx/mcp": "1.5.0",
79
+ "@gtkx/runtime": "1.5.0",
80
+ "@gtkx/config": "1.5.0",
81
+ "@gtkx/utils": "1.5.0",
82
+ "@gtkx/vitest": "1.5.0",
83
+ "create-gtkx": "1.5.0"
83
84
  },
84
85
  "devDependencies": {
85
86
  "@types/babel__core": "^7.20.5",
86
87
  "@types/react-refresh": "^0.14.7",
87
88
  "vitest": "^4.1.11",
88
- "@gtkx/testing": "1.3.0"
89
+ "@gtkx/testing": "1.5.0"
89
90
  },
90
91
  "peerDependencies": {
91
92
  "react": "^19"
package/src/builder.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { join, posix } from "node:path";
2
2
  import { type InlineConfig, mergeConfig, build as viteBuild } from "vite";
3
- import { gtkxBuiltUrl } from "./vite-plugins/built-url.js";
4
- import { gtkxBundledPackages } from "./vite-plugins/bundled-packages.js";
3
+ import { createBuildManifestCollector } from "./internal/build-manifest.js";
4
+ import { gtkxBuildManifest } from "./vite-plugins/build-manifest.js";
5
5
  import { BUNDLE_FILENAME, ESM_EXTENSION } from "./vite-plugins/esm-extension.js";
6
6
  import { gtkxVitePlugins } from "./vite-plugins/index.js";
7
7
  import { gtkxNative } from "./vite-plugins/native.js";
@@ -10,7 +10,7 @@ import { gtkxWorker } from "./vite-plugins/worker.js";
10
10
 
11
11
  type BuildOptions = {
12
12
  entry: string;
13
- assetBase?: string | undefined;
13
+ shouldPreserveI18nMetadata?: boolean | undefined;
14
14
  vite?: InlineConfig | undefined;
15
15
  };
16
16
 
@@ -33,17 +33,17 @@ const buildDefaults: InlineConfig = {
33
33
  };
34
34
 
35
35
  const build = async (options: BuildOptions): Promise<string> => {
36
- const { entry, assetBase, vite: viteConfig } = options;
36
+ const { entry, shouldPreserveI18nMetadata = true, vite: viteConfig } = options;
37
37
  const root = viteConfig?.root ?? process.cwd();
38
38
  const assetsDir = viteConfig?.build?.assetsDir ?? DEFAULT_ASSETS_DIR;
39
+ const buildManifest = createBuildManifestCollector();
39
40
 
40
41
  const forced: InlineConfig = {
41
42
  plugins: [
42
- ...gtkxVitePlugins(BUILD_MODE),
43
+ ...gtkxVitePlugins(BUILD_MODE, entry, buildManifest, shouldPreserveI18nMetadata),
43
44
  gtkxWorker(),
44
- gtkxBuiltUrl(assetBase),
45
45
  gtkxNative(root),
46
- gtkxBundledPackages(root),
46
+ gtkxBuildManifest(root, buildManifest),
47
47
  gtkxSelfContained(),
48
48
  ],
49
49
  build: {
@@ -8,9 +8,13 @@ import {
8
8
  resolveOmittedProps,
9
9
  } from "@gtkx/config/internal";
10
10
  import { info, warn } from "@gtkx/utils";
11
- import { rmSync } from "node:fs";
12
- import { resolve } from "node:path";
11
+ import { existsSync, rmSync } from "node:fs";
12
+ import { join, resolve } from "node:path";
13
+ import { resolveCatalogProject, synchronizeCatalogs } from "../i18n/catalogs.js";
14
+ import { extractSourceCatalog } from "../i18n/source-messages.js";
15
+ import { emitI18nTypes } from "../i18n/types.js";
13
16
  import { resolveDataDir } from "../internal/data-dir.js";
17
+ import { discoverSourceFiles } from "../internal/source-imports.js";
14
18
  import { emitSchemaEnv } from "../settings/schema.js";
15
19
  import { type CodegenInputs, isCodegenStale, resolveCodegenInputs } from "./freshness.js";
16
20
  import { type CodegenContext, type CodegenStore, resolveCodegenContext } from "./store-resolver.js";
@@ -21,6 +25,7 @@ type RunCodegenOptions = {
21
25
  isForced?: boolean;
22
26
  inputs?: CodegenInputs;
23
27
  resolved?: LoadedConfig;
28
+ shouldPreserveI18nMetadata?: boolean | undefined;
24
29
  };
25
30
 
26
31
  type LoadedConfig = {
@@ -52,13 +57,19 @@ type CodegenOptionsInput = {
52
57
  };
53
58
 
54
59
  type PreparedCodegen = CodegenInputs & { isForced: boolean };
55
- type EnsureGeneratedOptions = { shouldAnnounce?: boolean; mode?: string };
60
+
61
+ type EnsureGeneratedOptions = {
62
+ shouldAnnounce?: boolean;
63
+ mode?: string;
64
+ shouldPreserveI18nMetadata?: boolean | undefined;
65
+ };
56
66
 
57
67
  type RunOptionsInput = {
58
68
  root: string;
59
69
  mode: string | undefined;
60
70
  inputs: CodegenInputs | null;
61
71
  resolved: LoadedConfig;
72
+ shouldPreserveI18nMetadata: boolean | undefined;
62
73
  };
63
74
 
64
75
  const GIR_PATH_MISSING_MESSAGE =
@@ -156,6 +167,8 @@ const prepareCodegen = (options: RunCodegenOptions, cwd: string, config: Config)
156
167
  const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenResult> => {
157
168
  const cwd = options.cwd ?? process.cwd();
158
169
  const { config, configFile } = await resolveLoadedConfig(options, cwd);
170
+ await syncI18n(cwd, config.applicationId, options.shouldPreserveI18nMetadata);
171
+ syncSchemaEnv(cwd, config.future?.v2ResourceImports === true);
159
172
 
160
173
  if (config.codegen === false) {
161
174
  removeShadowingStores(cwd);
@@ -198,6 +211,26 @@ const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenRe
198
211
  };
199
212
  };
200
213
 
214
+ const syncI18n = async (
215
+ root: string,
216
+ applicationId: string,
217
+ shouldPreserveMetadataMessages = true,
218
+ ): Promise<void> => {
219
+ const project = resolveCatalogProject(root, applicationId);
220
+
221
+ if (project === null) {
222
+ emitI18nTypes(root, [], false);
223
+
224
+ return;
225
+ }
226
+
227
+ const srcDir = join(root, "src");
228
+ const sourceFiles = discoverSourceFiles(existsSync(srcDir) ? srcDir : root);
229
+ const catalog = await extractSourceCatalog(project, sourceFiles, shouldPreserveMetadataMessages);
230
+ synchronizeCatalogs(project);
231
+ emitI18nTypes(root, catalog.messages);
232
+ };
233
+
201
234
  const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> => {
202
235
  try {
203
236
  const { config } = await loadConfig(cwd, { mode });
@@ -208,8 +241,9 @@ const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> =
208
241
  }
209
242
  };
210
243
 
211
- const syncSchemaEnv = (cwd: string): void => {
212
- emitSchemaEnv(cwd, resolveDataDir(cwd));
244
+ const syncSchemaEnv = (cwd: string, isV2ResourceImports = false): void => {
245
+ const dataDir = isV2ResourceImports ? null : resolveDataDir(cwd);
246
+ emitSchemaEnv(cwd, dataDir, isV2ResourceImports);
213
247
  };
214
248
 
215
249
  const resolveInputsOrNull = (cwd: string, config: Config): CodegenInputs | null => {
@@ -230,12 +264,18 @@ const maybeAnnounceStale = (shouldAnnounce: boolean | undefined, inputs: Codegen
230
264
  }
231
265
  };
232
266
 
233
- const getRunOptions = ({ root, mode, inputs, resolved }: RunOptionsInput): RunCodegenOptions => {
267
+ const getRunOptions = ({
268
+ root,
269
+ mode,
270
+ inputs,
271
+ resolved,
272
+ shouldPreserveI18nMetadata,
273
+ }: RunOptionsInput): RunCodegenOptions => {
234
274
  if (inputs === null) {
235
- return { cwd: root, mode, resolved };
275
+ return { cwd: root, mode, resolved, shouldPreserveI18nMetadata };
236
276
  }
237
277
 
238
- return { cwd: root, mode, inputs, resolved };
278
+ return { cwd: root, mode, inputs, resolved, shouldPreserveI18nMetadata };
239
279
  };
240
280
 
241
281
  const isPreflightSkipped = (options: EnsureGeneratedOptions): boolean =>
@@ -243,18 +283,28 @@ const isPreflightSkipped = (options: EnsureGeneratedOptions): boolean =>
243
283
 
244
284
  /* eslint-disable-next-line unicorn/consistent-boolean-name -- the boolean reports whether codegen ran */
245
285
  const generate = async (context: CodegenContext, options: EnsureGeneratedOptions): Promise<boolean> => {
246
- syncSchemaEnv(context.root);
247
-
248
286
  if (context.config.codegen === false) {
249
- removeShadowingStores(context.root);
250
-
251
- return false;
287
+ const result = await runCodegen({
288
+ cwd: context.root,
289
+ mode: options.mode,
290
+ resolved: { config: context.config, configFile: context.configFile },
291
+ shouldPreserveI18nMetadata: options.shouldPreserveI18nMetadata,
292
+ });
293
+
294
+ return result.isRegenerated;
252
295
  }
253
296
 
254
297
  const inputs = resolveInputsOrNull(context.root, context.config);
255
298
  maybeAnnounceStale(options.shouldAnnounce, inputs);
256
299
  const resolved = { config: context.config, configFile: context.configFile };
257
- const result = await runCodegen(getRunOptions({ root: context.root, mode: options.mode, inputs, resolved }));
300
+
301
+ const result = await runCodegen(getRunOptions({
302
+ root: context.root,
303
+ mode: options.mode,
304
+ inputs,
305
+ resolved,
306
+ shouldPreserveI18nMetadata: options.shouldPreserveI18nMetadata,
307
+ }));
258
308
 
259
309
  return result.isRegenerated;
260
310
  };
@@ -286,7 +336,6 @@ const resolveConfigWatch = async (
286
336
  export {
287
337
  runCodegen,
288
338
  isCodegenDisabled,
289
- syncSchemaEnv,
290
339
  ensureGenerated,
291
340
  ensureGeneratedIn,
292
341
  resolveConfigWatch,
@@ -13,10 +13,6 @@ const build = defineCommand({
13
13
  },
14
14
  args: {
15
15
  ...entryArg,
16
- "asset-base": {
17
- type: "string",
18
- description: "Asset base path relative to executable directory (e.g., ../share/my-app)",
19
- },
20
16
  },
21
17
  async run({ args }) {
22
18
  const { cwd, entry } = await prepareProject(args, BUILD_MODE);
@@ -24,7 +20,6 @@ const build = defineCommand({
24
20
 
25
21
  const bundlePath = await buildApp({
26
22
  entry,
27
- assetBase: args["asset-base"],
28
23
  vite: {
29
24
  root: cwd,
30
25
  },
@@ -1,7 +1,7 @@
1
1
  import { info } from "@gtkx/utils";
2
2
  import { defineCommand } from "citty";
3
3
  import { formatCodegenResult } from "../codegen/report.js";
4
- import { ensureGenerated, isCodegenDisabled, runCodegen, syncSchemaEnv } from "../codegen/run-codegen.js";
4
+ import { ensureGenerated, isCodegenDisabled, runCodegen } from "../codegen/run-codegen.js";
5
5
  import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
6
6
 
7
7
  const FORCED_WHILE_DISABLED_MESSAGE =
@@ -12,7 +12,7 @@ const FORCED_WHILE_DISABLED_MESSAGE =
12
12
  const codegen = defineCommand({
13
13
  meta: {
14
14
  name: "codegen",
15
- description: "Generate TypeScript bindings for the GIR libraries declared in gtkx.config.ts",
15
+ description: "Generate project bindings, translation catalogs, and TypeScript declarations",
16
16
  },
17
17
  args: {
18
18
  force: {
@@ -29,7 +29,6 @@ const codegen = defineCommand({
29
29
 
30
30
  if (isDisabled) {
31
31
  await runCodegen({ cwd });
32
- syncSchemaEnv(cwd);
33
32
  info("codegen: disabled for this project; reusing an installed binding store");
34
33
 
35
34
  return;
@@ -44,7 +43,6 @@ const codegen = defineCommand({
44
43
 
45
44
  const startedAt = Date.now();
46
45
  const result = await runCodegen({ cwd, isForced: true });
47
- syncSchemaEnv(cwd);
48
46
  const lines = formatCodegenResult(result, Date.now() - startedAt);
49
47
 
50
48
  for (const line of lines) {
@@ -1,41 +1,70 @@
1
- import type { DeployConfig } from "./types.js";
1
+ import type { DeploySettings } from "./types.js";
2
2
 
3
3
  type Relations = {
4
4
  deb: string[];
5
5
  rpm: string[];
6
6
  };
7
7
 
8
- const GLES_SONAME = "libGLESv2.so.2()(64bit)";
8
+ type LibraryPackages = {
9
+ deb: string;
10
+ rpm: string;
11
+ extra: Relations;
12
+ };
13
+
14
+ const SONAME_SUFFIX = "()(64bit)";
15
+ const GLES_SONAME = `libGLESv2.so.2${SONAME_SUFFIX}`;
16
+ const NO_EXTRA: Relations = { deb: [], rpm: [] };
9
17
 
10
18
  const BASE_DEPENDS: Relations = {
11
19
  deb: ["hicolor-icon-theme", "adwaita-icon-theme", "gsettings-desktop-schemas"],
12
20
  rpm: ["hicolor-icon-theme", "adwaita-icon-theme", "gsettings-desktop-schemas"],
13
21
  };
14
22
 
15
- const DEPENDS_BY_LIBRARY: Record<string, Relations> = {
16
- "Adw-1": { deb: ["libadwaita-1-0"], rpm: ["libadwaita"] },
17
- "Gtk-4.0": { deb: ["libgtk-4-1"], rpm: ["gtk4", GLES_SONAME] },
18
- "GtkSource-5": { deb: ["libgtksourceview-5-0"], rpm: ["gtksourceview5"] },
19
- "WebKit-6.0": { deb: ["libwebkitgtk-6.0-4"], rpm: ["webkitgtk6.0"] },
23
+ const DEPENDS_BY_LIBRARY: Record<string, LibraryPackages> = {
24
+ "Adw-1": { deb: "libadwaita-1-0", rpm: "libadwaita", extra: NO_EXTRA },
25
+ "Gtk-4.0": { deb: "libgtk-4-1", rpm: "gtk4", extra: { deb: [], rpm: [GLES_SONAME] } },
20
26
  };
21
27
 
22
- const libraryDepends = (libraries: string[]): Relations => ({
23
- deb: libraries.flatMap((library) => DEPENDS_BY_LIBRARY[library]?.deb ?? []),
24
- rpm: libraries.flatMap((library) => DEPENDS_BY_LIBRARY[library]?.rpm ?? []),
25
- });
28
+ const debRelation = (name: string, minimum: string | undefined): string =>
29
+ minimum === undefined ? name : `${name} (>= ${minimum})`;
30
+
31
+ const rpmRelation = (name: string, minimum: string | undefined): string =>
32
+ minimum === undefined ? name : `${name} >= ${minimum}`;
33
+
34
+ const libraryDepends = (settings: DeploySettings): Relations => {
35
+ const deb: string[] = [];
36
+ const rpm: string[] = [];
37
+
38
+ for (const library of settings.libraries) {
39
+ const packages = DEPENDS_BY_LIBRARY[library];
40
+
41
+ if (packages === undefined) {
42
+ continue;
43
+ }
44
+
45
+ const minimum = settings.minimumLibraryVersions[library];
46
+ deb.push(debRelation(packages.deb, minimum), ...packages.extra.deb);
47
+ rpm.push(rpmRelation(packages.rpm, minimum), ...packages.extra.rpm);
48
+ }
49
+
50
+ return { deb, rpm };
51
+ };
26
52
 
27
- const glibcDepends = (glibcFloor: string | null): Relations =>
28
- glibcFloor === null ? { deb: [], rpm: [] } : { deb: [`libc6 (>= ${glibcFloor})`], rpm: [`glibc >= ${glibcFloor}`] };
53
+ const glibcDepends = (glibcMinimum: string | null): Relations =>
54
+ glibcMinimum === null
55
+ ? { deb: [], rpm: [] }
56
+ : { deb: [debRelation("libc6", glibcMinimum)], rpm: [rpmRelation("glibc", glibcMinimum)] };
29
57
 
30
58
  const dedupe = (entries: string[]): string[] => [...new Set(entries)];
31
59
 
32
- const resolveDepends = (deploy: DeployConfig, libraries: string[], glibcFloor: string | null): Relations => {
33
- const fromLibraries = libraryDepends(libraries);
34
- const fromGlibc = glibcDepends(glibcFloor);
60
+ const resolveDepends = (settings: DeploySettings, glibcMinimum: string | null): Relations => {
61
+ const fromLibraries = libraryDepends(settings);
62
+ const fromGlibc = glibcDepends(glibcMinimum);
63
+ const extra = settings.deploy.depends ?? {};
35
64
 
36
65
  return {
37
- deb: dedupe([...fromLibraries.deb, ...BASE_DEPENDS.deb, ...fromGlibc.deb, ...(deploy.depends?.deb ?? [])]),
38
- rpm: dedupe([...fromLibraries.rpm, ...BASE_DEPENDS.rpm, ...fromGlibc.rpm, ...(deploy.depends?.rpm ?? [])]),
66
+ deb: dedupe([...fromLibraries.deb, ...BASE_DEPENDS.deb, ...fromGlibc.deb, ...(extra.deb ?? [])]),
67
+ rpm: dedupe([...fromLibraries.rpm, ...BASE_DEPENDS.rpm, ...fromGlibc.rpm, ...(extra.rpm ?? [])]),
39
68
  };
40
69
  };
41
70
 
@@ -0,0 +1,144 @@
1
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import type { CatalogProject } from "../../i18n/catalogs.js";
5
+ import type { StagedMetadata } from "../payload/stage.js";
6
+ import { metadataTemplateFile, type MetadataTemplateKind } from "../../i18n/metadata-templates.js";
7
+ import { runCliTool } from "../../internal/run-cli-tool.js";
8
+
9
+ type MergeMode = "--desktop" | "--xml";
10
+
11
+ type MergeRequest = {
12
+ mode: MergeMode;
13
+ stem: string;
14
+ extension: string;
15
+ template: string;
16
+ };
17
+
18
+ type MetadataTemplate = {
19
+ contents: string;
20
+ path: string;
21
+ relativePath: string;
22
+ };
23
+
24
+ const metadataTemplates = (project: CatalogProject, metadata: StagedMetadata): MetadataTemplate[] => {
25
+ const template = (kind: MetadataTemplateKind, contents: string): MetadataTemplate => {
26
+ const { path, relativePath } = metadataTemplateFile(project, kind);
27
+
28
+ return { contents, path, relativePath };
29
+ };
30
+
31
+ return [
32
+ template("desktop", metadata.desktopEntry),
33
+ template("metainfo.xml", metadata.metainfo),
34
+ ...(metadata.mimePackage === null ? [] : [template("mime.xml", metadata.mimePackage)]),
35
+ ];
36
+ };
37
+
38
+ const mergeCatalogs = (project: CatalogProject, workDir: string, request: MergeRequest): string => {
39
+ const { extension, mode, stem, template } = request;
40
+ let current = join(workDir, `${stem}-source${extension}`);
41
+ writeFileSync(current, template);
42
+
43
+ for (const [index, catalog] of project.catalogs.entries()) {
44
+ const output = join(workDir, `${stem}-${String(index)}${extension}`);
45
+
46
+ runCliTool({
47
+ tool: "msgfmt",
48
+ args: [
49
+ mode,
50
+ `--template=${current}`,
51
+ `--locale=${catalog.locale}`,
52
+ `--output-file=${output}`,
53
+ catalog.path,
54
+ ],
55
+ target: catalog.path,
56
+ });
57
+
58
+ current = output;
59
+ }
60
+
61
+ return readFileSync(current, "utf8");
62
+ };
63
+
64
+ const localizeMetadata = (metadata: StagedMetadata, project: CatalogProject | null): StagedMetadata => {
65
+ if (project === null || project.catalogs.length === 0) {
66
+ return metadata;
67
+ }
68
+
69
+ const workDir = mkdtempSync(join(tmpdir(), "gtkx-deploy-metadata-"));
70
+
71
+ try {
72
+ return {
73
+ desktopEntry: mergeCatalogs(project, workDir, {
74
+ mode: "--desktop",
75
+ stem: "application",
76
+ extension: ".desktop",
77
+ template: metadata.desktopEntry,
78
+ }),
79
+ metainfo: mergeCatalogs(project, workDir, {
80
+ mode: "--xml",
81
+ stem: "metainfo",
82
+ extension: ".metainfo.xml",
83
+ template: metadata.metainfo,
84
+ }),
85
+ mimePackage: metadata.mimePackage === null
86
+ ? null
87
+ : mergeCatalogs(project, workDir, {
88
+ mode: "--xml",
89
+ stem: "mime",
90
+ extension: ".xml",
91
+ template: metadata.mimePackage,
92
+ }),
93
+ };
94
+ } finally {
95
+ rmSync(workDir, { recursive: true, force: true });
96
+ }
97
+ };
98
+
99
+ const extractMetadataMessages = (
100
+ metadata: StagedMetadata,
101
+ project: CatalogProject,
102
+ catalogTemplate?: string,
103
+ ): void => {
104
+ const potPath = catalogTemplate ?? join(project.poDir, `${project.domain}.pot`);
105
+
106
+ if (!existsSync(potPath)) {
107
+ throw new Error(`Cannot add the generated metadata to the missing catalog template: ${potPath}`);
108
+ }
109
+
110
+ const templates = metadataTemplates(project, metadata);
111
+ const firstTemplate = templates[0];
112
+
113
+ if (firstTemplate === undefined) {
114
+ throw new Error("Cannot extract metadata messages without a generated template");
115
+ }
116
+
117
+ const metadataDir = dirname(firstTemplate.path);
118
+ mkdirSync(metadataDir, { recursive: true });
119
+
120
+ try {
121
+ for (const template of templates) {
122
+ writeFileSync(template.path, template.contents);
123
+ }
124
+
125
+ runCliTool({
126
+ tool: "xgettext",
127
+ args: [
128
+ "--join-existing",
129
+ "--force-po",
130
+ "--from-code=UTF-8",
131
+ `--output=${potPath}`,
132
+ ...templates.map((template) => template.relativePath),
133
+ ],
134
+ target: potPath,
135
+ options: { cwd: project.root },
136
+ });
137
+ } finally {
138
+ for (const template of templates) {
139
+ rmSync(template.path, { force: true });
140
+ }
141
+ }
142
+ };
143
+
144
+ export { extractMetadataMessages, localizeMetadata };
@@ -43,8 +43,13 @@ const PACKAGE_FOR_TOOL: Record<string, FamilyPackages> = {
43
43
  fedora: "flatpak-builder",
44
44
  suse: "flatpak-builder",
45
45
  },
46
+ msgfmt: { arch: "gettext", debian: "gettext", fedora: "gettext", suse: "gettext-tools" },
47
+ msginit: { arch: "gettext", debian: "gettext", fedora: "gettext", suse: "gettext-tools" },
48
+ msggrep: { arch: "gettext", debian: "gettext", fedora: "gettext", suse: "gettext-tools" },
49
+ msgmerge: { arch: "gettext", debian: "gettext", fedora: "gettext", suse: "gettext-tools" },
46
50
  strip: { arch: "binutils", debian: "binutils", fedora: "binutils", suse: "binutils" },
47
51
  tar: { arch: "tar", debian: "tar", fedora: "tar", suse: "tar" },
52
+ xgettext: { arch: "gettext", debian: "gettext", fedora: "gettext", suse: "gettext-tools" },
48
53
  };
49
54
 
50
55
  const GENERATOR_SOURCE = "git+https://github.com/flatpak/flatpak-builder-tools.git#subdirectory=node";
@@ -125,7 +125,7 @@ const descriptionFor = (settings: DeploySettings, packager: NfpmPackager): strin
125
125
  const renderNfpmConfig = (payload: DeployPayload, packager: NfpmPackager): NfpmConfig => {
126
126
  const settings = payload.settings;
127
127
  const isRpm = packager === "rpm";
128
- const depends = resolveDepends(settings.deploy, settings.libraries, payload.node?.glibcFloor ?? null);
128
+ const depends = resolveDepends(settings, payload.node?.glibcMinimum ?? null);
129
129
 
130
130
  return {
131
131
  name: packageNameFor(settings, packager),
@@ -8,7 +8,7 @@ type ElfSection = {
8
8
 
9
9
  type ElfInfo = {
10
10
  needed: string[];
11
- glibcFloor: string | null;
11
+ glibcMinimum: string | null;
12
12
  };
13
13
 
14
14
  type DynamicEntry = {
@@ -117,7 +117,7 @@ const highestVersion = (versions: number[][]): number[] | null => {
117
117
  const formatVersion = (version: number[] | null): string | null =>
118
118
  version === null ? null : `${String(version[0] ?? 0)}.${String(version[1] ?? 0)}`;
119
119
 
120
- const readGlibcFloor = (strings: Buffer): string | null => {
120
+ const readGlibcMinimum = (strings: Buffer): string | null => {
121
121
  const found = strings
122
122
  .toString("latin1")
123
123
  .matchAll(GLIBC_VERSION)
@@ -138,7 +138,7 @@ const readElfInfo = (path: string): ElfInfo => {
138
138
 
139
139
  return {
140
140
  needed: readNeeded(buffer, sectionFor(sections, ".dynamic"), strings),
141
- glibcFloor: readGlibcFloor(strings),
141
+ glibcMinimum: readGlibcMinimum(strings),
142
142
  };
143
143
  };
144
144
 
@@ -78,9 +78,9 @@ const resolveNodeRuntime = async (settings: DeploySettings): Promise<NodeRuntime
78
78
  const staged = await stageFromSource(settings, version, source);
79
79
  const isStripped = node.shouldStrip === false ? false : didStripBinary(staged.path);
80
80
  const elf = readElfInfo(staged.path);
81
- info(`Bundled Node.js v${version} (${megabytes(staged.path)} MiB, glibc >= ${elf.glibcFloor ?? "unknown"})`);
81
+ info(`Bundled Node.js v${version} (${megabytes(staged.path)} MiB, glibc >= ${elf.glibcMinimum ?? "unknown"})`);
82
82
 
83
- return { ...staged, version, glibcFloor: elf.glibcFloor, isStripped };
83
+ return { ...staged, version, glibcMinimum: elf.glibcMinimum, isStripped };
84
84
  };
85
85
 
86
86
  export { resolveNodeRuntime, sourcePathFor };
@@ -1,3 +1,4 @@
1
+ import type { RecordedPackage } from "../../internal/build-manifest.js";
1
2
  import type { DeploySettings, NodeRuntime, NoticeSection } from "../types.js";
2
3
  import { dependencyNotices } from "./dependencies.js";
3
4
  import { gtkxNotices } from "./gtkx.js";
@@ -8,10 +9,11 @@ import { bundledPackages } from "./packages.js";
8
9
  type NoticeRequest = {
9
10
  settings: DeploySettings;
10
11
  node: NodeRuntime | null;
12
+ packages: RecordedPackage[];
11
13
  };
12
14
 
13
- const collectNotices = ({ settings, node }: NoticeRequest): NoticeSection[] => {
14
- const packages = bundledPackages(settings);
15
+ const collectNotices = ({ settings, node, packages: recordedPackages }: NoticeRequest): NoticeSection[] => {
16
+ const packages = bundledPackages(settings, recordedPackages);
15
17
 
16
18
  const sections = [
17
19
  nodeNotices(settings, node),