@gtkx/cli 1.0.0 → 1.2.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 (458) hide show
  1. package/README.md +1 -1
  2. package/dist/builder.d.ts +1 -1
  3. package/dist/builder.d.ts.map +1 -1
  4. package/dist/builder.js +20 -3
  5. package/dist/builder.js.map +1 -1
  6. package/dist/cli.js +6 -2
  7. package/dist/cli.js.map +1 -1
  8. package/dist/codegen/freshness.js +2 -2
  9. package/dist/codegen/freshness.js.map +1 -1
  10. package/dist/codegen/report.d.ts.map +1 -1
  11. package/dist/codegen/report.js +3 -0
  12. package/dist/codegen/report.js.map +1 -1
  13. package/dist/codegen/run-codegen.d.ts +9 -5
  14. package/dist/codegen/run-codegen.d.ts.map +1 -1
  15. package/dist/codegen/run-codegen.js +31 -20
  16. package/dist/codegen/run-codegen.js.map +1 -1
  17. package/dist/codegen/store-resolver.d.ts +1 -1
  18. package/dist/codegen/store-resolver.d.ts.map +1 -1
  19. package/dist/codegen/store-resolver.js.map +1 -1
  20. package/dist/commands/build.d.ts.map +1 -1
  21. package/dist/commands/build.js +5 -6
  22. package/dist/commands/build.js.map +1 -1
  23. package/dist/commands/codegen.d.ts.map +1 -1
  24. package/dist/commands/codegen.js +11 -1
  25. package/dist/commands/codegen.js.map +1 -1
  26. package/dist/commands/deploy.d.ts +22 -0
  27. package/dist/commands/deploy.d.ts.map +1 -0
  28. package/dist/commands/deploy.js +44 -0
  29. package/dist/commands/deploy.js.map +1 -0
  30. package/dist/commands/dev.d.ts.map +1 -1
  31. package/dist/commands/dev.js +4 -4
  32. package/dist/commands/dev.js.map +1 -1
  33. package/dist/commands/docs.d.ts +2 -2
  34. package/dist/commands/docs.d.ts.map +1 -1
  35. package/dist/commands/docs.js +28 -4
  36. package/dist/commands/docs.js.map +1 -1
  37. package/dist/deploy/depends.d.ts +8 -0
  38. package/dist/deploy/depends.d.ts.map +1 -0
  39. package/dist/deploy/depends.js +27 -0
  40. package/dist/deploy/depends.js.map +1 -0
  41. package/dist/deploy/download.d.ts +20 -0
  42. package/dist/deploy/download.d.ts.map +1 -0
  43. package/dist/deploy/download.js +98 -0
  44. package/dist/deploy/download.js.map +1 -0
  45. package/dist/deploy/freedesktop/copyright.d.ts +4 -0
  46. package/dist/deploy/freedesktop/copyright.d.ts.map +1 -0
  47. package/dist/deploy/freedesktop/copyright.js +33 -0
  48. package/dist/deploy/freedesktop/copyright.js.map +1 -0
  49. package/dist/deploy/freedesktop/dbus-service.d.ts +4 -0
  50. package/dist/deploy/freedesktop/dbus-service.d.ts.map +1 -0
  51. package/dist/deploy/freedesktop/dbus-service.js +15 -0
  52. package/dist/deploy/freedesktop/dbus-service.js.map +1 -0
  53. package/dist/deploy/freedesktop/desktop-entry.d.ts +4 -0
  54. package/dist/deploy/freedesktop/desktop-entry.d.ts.map +1 -0
  55. package/dist/deploy/freedesktop/desktop-entry.js +73 -0
  56. package/dist/deploy/freedesktop/desktop-entry.js.map +1 -0
  57. package/dist/deploy/freedesktop/ini.d.ts +7 -0
  58. package/dist/deploy/freedesktop/ini.d.ts.map +1 -0
  59. package/dist/deploy/freedesktop/ini.js +22 -0
  60. package/dist/deploy/freedesktop/ini.js.map +1 -0
  61. package/dist/deploy/freedesktop/metainfo-sections.d.ts +13 -0
  62. package/dist/deploy/freedesktop/metainfo-sections.d.ts.map +1 -0
  63. package/dist/deploy/freedesktop/metainfo-sections.js +73 -0
  64. package/dist/deploy/freedesktop/metainfo-sections.js.map +1 -0
  65. package/dist/deploy/freedesktop/metainfo.d.ts +4 -0
  66. package/dist/deploy/freedesktop/metainfo.d.ts.map +1 -0
  67. package/dist/deploy/freedesktop/metainfo.js +29 -0
  68. package/dist/deploy/freedesktop/metainfo.js.map +1 -0
  69. package/dist/deploy/freedesktop/mime-package.d.ts +4 -0
  70. package/dist/deploy/freedesktop/mime-package.d.ts.map +1 -0
  71. package/dist/deploy/freedesktop/mime-package.js +16 -0
  72. package/dist/deploy/freedesktop/mime-package.js.map +1 -0
  73. package/dist/deploy/freedesktop/validate.d.ts +4 -0
  74. package/dist/deploy/freedesktop/validate.d.ts.map +1 -0
  75. package/dist/deploy/freedesktop/validate.js +81 -0
  76. package/dist/deploy/freedesktop/validate.js.map +1 -0
  77. package/dist/deploy/freedesktop/xml.d.ts +11 -0
  78. package/dist/deploy/freedesktop/xml.d.ts.map +1 -0
  79. package/dist/deploy/freedesktop/xml.js +33 -0
  80. package/dist/deploy/freedesktop/xml.js.map +1 -0
  81. package/dist/deploy/git.d.ts +4 -0
  82. package/dist/deploy/git.d.ts.map +1 -0
  83. package/dist/deploy/git.js +17 -0
  84. package/dist/deploy/git.js.map +1 -0
  85. package/dist/deploy/install-hints.d.ts +5 -0
  86. package/dist/deploy/install-hints.d.ts.map +1 -0
  87. package/dist/deploy/install-hints.js +88 -0
  88. package/dist/deploy/install-hints.js.map +1 -0
  89. package/dist/deploy/nfpm/config.d.ts +8 -0
  90. package/dist/deploy/nfpm/config.d.ts.map +1 -0
  91. package/dist/deploy/nfpm/config.js +119 -0
  92. package/dist/deploy/nfpm/config.js.map +1 -0
  93. package/dist/deploy/nfpm/contents.d.ts +12 -0
  94. package/dist/deploy/nfpm/contents.d.ts.map +1 -0
  95. package/dist/deploy/nfpm/contents.js +48 -0
  96. package/dist/deploy/nfpm/contents.js.map +1 -0
  97. package/dist/deploy/nfpm/description.d.ts +5 -0
  98. package/dist/deploy/nfpm/description.d.ts.map +1 -0
  99. package/dist/deploy/nfpm/description.js +5 -0
  100. package/dist/deploy/nfpm/description.js.map +1 -0
  101. package/dist/deploy/nfpm/optional.d.ts +5 -0
  102. package/dist/deploy/nfpm/optional.d.ts.map +1 -0
  103. package/dist/deploy/nfpm/optional.js +4 -0
  104. package/dist/deploy/nfpm/optional.js.map +1 -0
  105. package/dist/deploy/nfpm/pack.d.ts +5 -0
  106. package/dist/deploy/nfpm/pack.d.ts.map +1 -0
  107. package/dist/deploy/nfpm/pack.js +32 -0
  108. package/dist/deploy/nfpm/pack.js.map +1 -0
  109. package/dist/deploy/node-runtime/download.d.ts +3 -0
  110. package/dist/deploy/node-runtime/download.d.ts.map +1 -0
  111. package/dist/deploy/node-runtime/download.js +39 -0
  112. package/dist/deploy/node-runtime/download.js.map +1 -0
  113. package/dist/deploy/node-runtime/elf.d.ts +7 -0
  114. package/dist/deploy/node-runtime/elf.d.ts.map +1 -0
  115. package/dist/deploy/node-runtime/elf.js +100 -0
  116. package/dist/deploy/node-runtime/elf.js.map +1 -0
  117. package/dist/deploy/node-runtime/guard.d.ts +4 -0
  118. package/dist/deploy/node-runtime/guard.d.ts.map +1 -0
  119. package/dist/deploy/node-runtime/guard.js +22 -0
  120. package/dist/deploy/node-runtime/guard.js.map +1 -0
  121. package/dist/deploy/node-runtime/index.d.ts +4 -0
  122. package/dist/deploy/node-runtime/index.d.ts.map +1 -0
  123. package/dist/deploy/node-runtime/index.js +61 -0
  124. package/dist/deploy/node-runtime/index.js.map +1 -0
  125. package/dist/deploy/payload/copy-tree.d.ts +7 -0
  126. package/dist/deploy/payload/copy-tree.d.ts.map +1 -0
  127. package/dist/deploy/payload/copy-tree.js +36 -0
  128. package/dist/deploy/payload/copy-tree.js.map +1 -0
  129. package/dist/deploy/payload/icons.d.ts +6 -0
  130. package/dist/deploy/payload/icons.d.ts.map +1 -0
  131. package/dist/deploy/payload/icons.js +53 -0
  132. package/dist/deploy/payload/icons.js.map +1 -0
  133. package/dist/deploy/payload/launcher.d.ts +5 -0
  134. package/dist/deploy/payload/launcher.d.ts.map +1 -0
  135. package/dist/deploy/payload/launcher.js +22 -0
  136. package/dist/deploy/payload/launcher.js.map +1 -0
  137. package/dist/deploy/payload/schemas.d.ts +4 -0
  138. package/dist/deploy/payload/schemas.d.ts.map +1 -0
  139. package/dist/deploy/payload/schemas.js +17 -0
  140. package/dist/deploy/payload/schemas.js.map +1 -0
  141. package/dist/deploy/payload/stage.d.ts +15 -0
  142. package/dist/deploy/payload/stage.d.ts.map +1 -0
  143. package/dist/deploy/payload/stage.js +100 -0
  144. package/dist/deploy/payload/stage.js.map +1 -0
  145. package/dist/deploy/registry.d.ts +7 -0
  146. package/dist/deploy/registry.d.ts.map +1 -0
  147. package/dist/deploy/registry.js +30 -0
  148. package/dist/deploy/registry.js.map +1 -0
  149. package/dist/deploy/run-deploy.d.ts +11 -0
  150. package/dist/deploy/run-deploy.d.ts.map +1 -0
  151. package/dist/deploy/run-deploy.js +157 -0
  152. package/dist/deploy/run-deploy.js.map +1 -0
  153. package/dist/deploy/settings/arch.d.ts +4 -0
  154. package/dist/deploy/settings/arch.d.ts.map +1 -0
  155. package/dist/deploy/settings/arch.js +13 -0
  156. package/dist/deploy/settings/arch.js.map +1 -0
  157. package/dist/deploy/settings/categories.d.ts +4 -0
  158. package/dist/deploy/settings/categories.d.ts.map +1 -0
  159. package/dist/deploy/settings/categories.js +29 -0
  160. package/dist/deploy/settings/categories.js.map +1 -0
  161. package/dist/deploy/settings/exec.d.ts +6 -0
  162. package/dist/deploy/settings/exec.d.ts.map +1 -0
  163. package/dist/deploy/settings/exec.js +20 -0
  164. package/dist/deploy/settings/exec.js.map +1 -0
  165. package/dist/deploy/settings/identity.d.ts +18 -0
  166. package/dist/deploy/settings/identity.d.ts.map +1 -0
  167. package/dist/deploy/settings/identity.js +73 -0
  168. package/dist/deploy/settings/identity.js.map +1 -0
  169. package/dist/deploy/settings/index.d.ts +11 -0
  170. package/dist/deploy/settings/index.d.ts.map +1 -0
  171. package/dist/deploy/settings/index.js +103 -0
  172. package/dist/deploy/settings/index.js.map +1 -0
  173. package/dist/deploy/settings/package-manifest.d.ts +16 -0
  174. package/dist/deploy/settings/package-manifest.d.ts.map +1 -0
  175. package/dist/deploy/settings/package-manifest.js +42 -0
  176. package/dist/deploy/settings/package-manifest.js.map +1 -0
  177. package/dist/deploy/settings/paths.d.ts +9 -0
  178. package/dist/deploy/settings/paths.d.ts.map +1 -0
  179. package/dist/deploy/settings/paths.js +82 -0
  180. package/dist/deploy/settings/paths.js.map +1 -0
  181. package/dist/deploy/settings/screenshots.d.ts +8 -0
  182. package/dist/deploy/settings/screenshots.d.ts.map +1 -0
  183. package/dist/deploy/settings/screenshots.js +79 -0
  184. package/dist/deploy/settings/screenshots.js.map +1 -0
  185. package/dist/deploy/settings/starter.d.ts +4 -0
  186. package/dist/deploy/settings/starter.d.ts.map +1 -0
  187. package/dist/deploy/settings/starter.js +28 -0
  188. package/dist/deploy/settings/starter.js.map +1 -0
  189. package/dist/deploy/settings/version.d.ts +9 -0
  190. package/dist/deploy/settings/version.d.ts.map +1 -0
  191. package/dist/deploy/settings/version.js +37 -0
  192. package/dist/deploy/settings/version.js.map +1 -0
  193. package/dist/deploy/targets/appimage.d.ts +4 -0
  194. package/dist/deploy/targets/appimage.d.ts.map +1 -0
  195. package/dist/deploy/targets/appimage.js +105 -0
  196. package/dist/deploy/targets/appimage.js.map +1 -0
  197. package/dist/deploy/targets/deb.d.ts +4 -0
  198. package/dist/deploy/targets/deb.d.ts.map +1 -0
  199. package/dist/deploy/targets/deb.js +4 -0
  200. package/dist/deploy/targets/deb.js.map +1 -0
  201. package/dist/deploy/targets/flatpak-manifest.d.ts +6 -0
  202. package/dist/deploy/targets/flatpak-manifest.d.ts.map +1 -0
  203. package/dist/deploy/targets/flatpak-manifest.js +48 -0
  204. package/dist/deploy/targets/flatpak-manifest.js.map +1 -0
  205. package/dist/deploy/targets/flatpak-pnpm.d.ts +15 -0
  206. package/dist/deploy/targets/flatpak-pnpm.d.ts.map +1 -0
  207. package/dist/deploy/targets/flatpak-pnpm.js +69 -0
  208. package/dist/deploy/targets/flatpak-pnpm.js.map +1 -0
  209. package/dist/deploy/targets/flatpak-prebuilt.d.ts +8 -0
  210. package/dist/deploy/targets/flatpak-prebuilt.d.ts.map +1 -0
  211. package/dist/deploy/targets/flatpak-prebuilt.js +43 -0
  212. package/dist/deploy/targets/flatpak-prebuilt.js.map +1 -0
  213. package/dist/deploy/targets/flatpak-source.d.ts +5 -0
  214. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -0
  215. package/dist/deploy/targets/flatpak-source.js +119 -0
  216. package/dist/deploy/targets/flatpak-source.js.map +1 -0
  217. package/dist/deploy/targets/flatpak-sources.d.ts +19 -0
  218. package/dist/deploy/targets/flatpak-sources.d.ts.map +1 -0
  219. package/dist/deploy/targets/flatpak-sources.js +122 -0
  220. package/dist/deploy/targets/flatpak-sources.js.map +1 -0
  221. package/dist/deploy/targets/flatpak.d.ts +4 -0
  222. package/dist/deploy/targets/flatpak.d.ts.map +1 -0
  223. package/dist/deploy/targets/flatpak.js +113 -0
  224. package/dist/deploy/targets/flatpak.js.map +1 -0
  225. package/dist/deploy/targets/nfpm-target.d.ts +5 -0
  226. package/dist/deploy/targets/nfpm-target.d.ts.map +1 -0
  227. package/dist/deploy/targets/nfpm-target.js +26 -0
  228. package/dist/deploy/targets/nfpm-target.js.map +1 -0
  229. package/dist/deploy/targets/rpm.d.ts +4 -0
  230. package/dist/deploy/targets/rpm.d.ts.map +1 -0
  231. package/dist/deploy/targets/rpm.js +4 -0
  232. package/dist/deploy/targets/rpm.js.map +1 -0
  233. package/dist/deploy/tools.d.ts +20 -0
  234. package/dist/deploy/tools.d.ts.map +1 -0
  235. package/dist/deploy/tools.js +106 -0
  236. package/dist/deploy/tools.js.map +1 -0
  237. package/dist/deploy/types.d.ts +140 -0
  238. package/dist/deploy/types.d.ts.map +1 -0
  239. package/dist/deploy/types.js +2 -0
  240. package/dist/deploy/types.js.map +1 -0
  241. package/dist/deploy/vendored/appimagetool.d.ts +7 -0
  242. package/dist/deploy/vendored/appimagetool.d.ts.map +1 -0
  243. package/dist/deploy/vendored/appimagetool.js +42 -0
  244. package/dist/deploy/vendored/appimagetool.js.map +1 -0
  245. package/dist/deploy/vendored/nfpm.d.ts +3 -0
  246. package/dist/deploy/vendored/nfpm.d.ts.map +1 -0
  247. package/dist/deploy/vendored/nfpm.js +60 -0
  248. package/dist/deploy/vendored/nfpm.js.map +1 -0
  249. package/dist/dev/change-queue.d.ts +11 -0
  250. package/dist/dev/change-queue.d.ts.map +1 -0
  251. package/dist/dev/change-queue.js +34 -0
  252. package/dist/dev/change-queue.js.map +1 -0
  253. package/dist/dev/failure-tracker.d.ts +10 -0
  254. package/dist/dev/failure-tracker.d.ts.map +1 -0
  255. package/dist/dev/failure-tracker.js +61 -0
  256. package/dist/dev/failure-tracker.js.map +1 -0
  257. package/dist/dev/missing-import.d.ts +4 -0
  258. package/dist/dev/missing-import.d.ts.map +1 -0
  259. package/dist/dev/missing-import.js +23 -0
  260. package/dist/dev/missing-import.js.map +1 -0
  261. package/dist/dev/runner-deps.d.ts.map +1 -1
  262. package/dist/dev/runner-deps.js +25 -6
  263. package/dist/dev/runner-deps.js.map +1 -1
  264. package/dist/dev/runner.d.ts +8 -4
  265. package/dist/dev/runner.d.ts.map +1 -1
  266. package/dist/dev/runner.js +334 -66
  267. package/dist/dev/runner.js.map +1 -1
  268. package/dist/dev/supervisor.d.ts +1 -2
  269. package/dist/dev/supervisor.d.ts.map +1 -1
  270. package/dist/dev/supervisor.js +1 -1
  271. package/dist/dev/supervisor.js.map +1 -1
  272. package/dist/dev/vite-dev-server.d.ts +13 -2
  273. package/dist/dev/vite-dev-server.d.ts.map +1 -1
  274. package/dist/dev/vite-dev-server.js +30 -2
  275. package/dist/dev/vite-dev-server.js.map +1 -1
  276. package/dist/internal/entry-arg.d.ts +1 -7
  277. package/dist/internal/entry-arg.d.ts.map +1 -1
  278. package/dist/internal/entry-arg.js +18 -11
  279. package/dist/internal/entry-arg.js.map +1 -1
  280. package/dist/internal/module-loads.d.ts +7 -0
  281. package/dist/internal/module-loads.d.ts.map +1 -0
  282. package/dist/internal/module-loads.js +21 -0
  283. package/dist/internal/module-loads.js.map +1 -0
  284. package/dist/internal/prepare-project.d.ts +16 -0
  285. package/dist/internal/prepare-project.d.ts.map +1 -0
  286. package/dist/internal/prepare-project.js +15 -0
  287. package/dist/internal/prepare-project.js.map +1 -0
  288. package/dist/internal/run-cli-tool.d.ts +2 -1
  289. package/dist/internal/run-cli-tool.d.ts.map +1 -1
  290. package/dist/internal/run-cli-tool.js +15 -6
  291. package/dist/internal/run-cli-tool.js.map +1 -1
  292. package/dist/internal/staging-dir.d.ts +8 -1
  293. package/dist/internal/staging-dir.d.ts.map +1 -1
  294. package/dist/internal/staging-dir.js +38 -2
  295. package/dist/internal/staging-dir.js.map +1 -1
  296. package/dist/mcp/serialize-widget.d.ts +2 -1
  297. package/dist/mcp/serialize-widget.d.ts.map +1 -1
  298. package/dist/mcp/serialize-widget.js +1 -1
  299. package/dist/mcp/serialize-widget.js.map +1 -1
  300. package/dist/mcp/testing-loader.d.ts +5 -2
  301. package/dist/mcp/testing-loader.d.ts.map +1 -1
  302. package/dist/mcp/testing-loader.js +7 -3
  303. package/dist/mcp/testing-loader.js.map +1 -1
  304. package/dist/refresh-runtime.d.ts +2 -1
  305. package/dist/refresh-runtime.d.ts.map +1 -1
  306. package/dist/refresh-runtime.js +32 -2
  307. package/dist/refresh-runtime.js.map +1 -1
  308. package/dist/settings/schema.d.ts +1 -2
  309. package/dist/settings/schema.d.ts.map +1 -1
  310. package/dist/settings/schema.js +1 -1
  311. package/dist/settings/schema.js.map +1 -1
  312. package/dist/vite-plugins/asset-extensions.d.ts +2 -1
  313. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  314. package/dist/vite-plugins/asset-extensions.js +2 -1
  315. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  316. package/dist/vite-plugins/asset-imports.d.ts +4 -0
  317. package/dist/vite-plugins/asset-imports.d.ts.map +1 -0
  318. package/dist/vite-plugins/asset-imports.js +88 -0
  319. package/dist/vite-plugins/asset-imports.js.map +1 -0
  320. package/dist/vite-plugins/asset-specifier.d.ts +5 -0
  321. package/dist/vite-plugins/asset-specifier.d.ts.map +1 -0
  322. package/dist/vite-plugins/asset-specifier.js +7 -0
  323. package/dist/vite-plugins/asset-specifier.js.map +1 -0
  324. package/dist/vite-plugins/esm-extension.d.ts +4 -0
  325. package/dist/vite-plugins/esm-extension.d.ts.map +1 -0
  326. package/dist/vite-plugins/esm-extension.js +4 -0
  327. package/dist/vite-plugins/esm-extension.js.map +1 -0
  328. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +1 -3
  329. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -1
  330. package/dist/vite-plugins/fast-refresh/swc-refresh.js +1 -1
  331. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -1
  332. package/dist/vite-plugins/index.d.ts.map +1 -1
  333. package/dist/vite-plugins/index.js +4 -0
  334. package/dist/vite-plugins/index.js.map +1 -1
  335. package/dist/vite-plugins/resource-shared.d.ts +2 -1
  336. package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
  337. package/dist/vite-plugins/resource-shared.js +2 -1
  338. package/dist/vite-plugins/resource-shared.js.map +1 -1
  339. package/dist/vite-plugins/resources.d.ts.map +1 -1
  340. package/dist/vite-plugins/resources.js +30 -29
  341. package/dist/vite-plugins/resources.js.map +1 -1
  342. package/dist/vite-plugins/self-contained.d.ts +4 -0
  343. package/dist/vite-plugins/self-contained.d.ts.map +1 -0
  344. package/dist/vite-plugins/self-contained.js +244 -0
  345. package/dist/vite-plugins/self-contained.js.map +1 -0
  346. package/dist/vite-plugins/settings.d.ts.map +1 -1
  347. package/dist/vite-plugins/settings.js +19 -40
  348. package/dist/vite-plugins/settings.js.map +1 -1
  349. package/dist/vite-plugins/store-links.d.ts +4 -0
  350. package/dist/vite-plugins/store-links.d.ts.map +1 -0
  351. package/dist/vite-plugins/store-links.js +19 -0
  352. package/dist/vite-plugins/store-links.js.map +1 -0
  353. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
  354. package/dist/vite-plugins/undeclared-library.js +51 -12
  355. package/dist/vite-plugins/undeclared-library.js.map +1 -1
  356. package/dist/vite-plugins/worker.d.ts.map +1 -1
  357. package/dist/vite-plugins/worker.js +3 -1
  358. package/dist/vite-plugins/worker.js.map +1 -1
  359. package/env.d.ts +106 -25
  360. package/package.json +20 -13
  361. package/src/builder.ts +22 -4
  362. package/src/cli.ts +7 -2
  363. package/src/codegen/freshness.ts +2 -2
  364. package/src/codegen/report.ts +4 -0
  365. package/src/codegen/run-codegen.ts +48 -24
  366. package/src/codegen/store-resolver.ts +1 -1
  367. package/src/commands/build.ts +5 -6
  368. package/src/commands/codegen.ts +14 -1
  369. package/src/commands/deploy.ts +47 -0
  370. package/src/commands/dev.ts +4 -4
  371. package/src/commands/docs.ts +40 -4
  372. package/src/deploy/depends.ts +42 -0
  373. package/src/deploy/download.ts +148 -0
  374. package/src/deploy/freedesktop/copyright.ts +41 -0
  375. package/src/deploy/freedesktop/dbus-service.ts +19 -0
  376. package/src/deploy/freedesktop/desktop-entry.ts +102 -0
  377. package/src/deploy/freedesktop/ini.ts +39 -0
  378. package/src/deploy/freedesktop/metainfo-sections.ts +116 -0
  379. package/src/deploy/freedesktop/metainfo.ts +46 -0
  380. package/src/deploy/freedesktop/mime-package.ts +28 -0
  381. package/src/deploy/freedesktop/validate.ts +124 -0
  382. package/src/deploy/freedesktop/xml.ts +53 -0
  383. package/src/deploy/git.ts +20 -0
  384. package/src/deploy/install-hints.ts +111 -0
  385. package/src/deploy/nfpm/config.ts +153 -0
  386. package/src/deploy/nfpm/contents.ts +69 -0
  387. package/src/deploy/nfpm/description.ts +11 -0
  388. package/src/deploy/nfpm/optional.ts +8 -0
  389. package/src/deploy/nfpm/pack.ts +44 -0
  390. package/src/deploy/node-runtime/download.ts +48 -0
  391. package/src/deploy/node-runtime/elf.ts +145 -0
  392. package/src/deploy/node-runtime/guard.ts +29 -0
  393. package/src/deploy/node-runtime/index.ts +80 -0
  394. package/src/deploy/payload/copy-tree.ts +51 -0
  395. package/src/deploy/payload/icons.ts +80 -0
  396. package/src/deploy/payload/launcher.ts +27 -0
  397. package/src/deploy/payload/schemas.ts +27 -0
  398. package/src/deploy/payload/stage.ts +145 -0
  399. package/src/deploy/registry.ts +40 -0
  400. package/src/deploy/run-deploy.ts +241 -0
  401. package/src/deploy/settings/arch.ts +18 -0
  402. package/src/deploy/settings/categories.ts +39 -0
  403. package/src/deploy/settings/exec.ts +29 -0
  404. package/src/deploy/settings/identity.ts +133 -0
  405. package/src/deploy/settings/index.ts +189 -0
  406. package/src/deploy/settings/package-manifest.ts +68 -0
  407. package/src/deploy/settings/paths.ts +115 -0
  408. package/src/deploy/settings/screenshots.ts +125 -0
  409. package/src/deploy/settings/starter.ts +41 -0
  410. package/src/deploy/settings/version.ts +59 -0
  411. package/src/deploy/targets/appimage.ts +140 -0
  412. package/src/deploy/targets/deb.ts +6 -0
  413. package/src/deploy/targets/flatpak-manifest.ts +61 -0
  414. package/src/deploy/targets/flatpak-pnpm.ts +115 -0
  415. package/src/deploy/targets/flatpak-prebuilt.ts +59 -0
  416. package/src/deploy/targets/flatpak-source.ts +181 -0
  417. package/src/deploy/targets/flatpak-sources.ts +198 -0
  418. package/src/deploy/targets/flatpak.ts +144 -0
  419. package/src/deploy/targets/nfpm-target.ts +33 -0
  420. package/src/deploy/targets/rpm.ts +6 -0
  421. package/src/deploy/tools.ts +156 -0
  422. package/src/deploy/types.ts +174 -0
  423. package/src/deploy/vendored/appimagetool.ts +57 -0
  424. package/src/deploy/vendored/nfpm.ts +79 -0
  425. package/src/dev/change-queue.ts +59 -0
  426. package/src/dev/failure-tracker.ts +92 -0
  427. package/src/dev/missing-import.ts +32 -0
  428. package/src/dev/runner-deps.ts +34 -6
  429. package/src/dev/runner.ts +506 -102
  430. package/src/dev/supervisor.ts +0 -3
  431. package/src/dev/vite-dev-server.ts +54 -3
  432. package/src/internal/entry-arg.ts +25 -11
  433. package/src/internal/module-loads.ts +32 -0
  434. package/src/internal/prepare-project.ts +23 -0
  435. package/src/internal/run-cli-tool.ts +22 -6
  436. package/src/internal/staging-dir.ts +57 -2
  437. package/src/mcp/serialize-widget.ts +3 -2
  438. package/src/mcp/testing-loader.ts +19 -4
  439. package/src/refresh-runtime.ts +48 -2
  440. package/src/settings/schema.ts +0 -1
  441. package/src/vite-plugins/asset-extensions.ts +2 -1
  442. package/src/vite-plugins/asset-imports.ts +134 -0
  443. package/src/vite-plugins/asset-specifier.ts +9 -0
  444. package/src/vite-plugins/esm-extension.ts +4 -0
  445. package/src/vite-plugins/fast-refresh/swc-refresh.ts +1 -1
  446. package/src/vite-plugins/index.ts +4 -0
  447. package/src/vite-plugins/resource-shared.ts +2 -0
  448. package/src/vite-plugins/resources.ts +33 -33
  449. package/src/vite-plugins/self-contained.ts +352 -0
  450. package/src/vite-plugins/settings.ts +21 -48
  451. package/src/vite-plugins/store-links.ts +25 -0
  452. package/src/vite-plugins/undeclared-library.ts +74 -12
  453. package/src/vite-plugins/worker.ts +4 -1
  454. package/dist/internal.d.ts +0 -3
  455. package/dist/internal.d.ts.map +0 -1
  456. package/dist/internal.js +0 -3
  457. package/dist/internal.js.map +0 -1
  458. package/src/internal.ts +0 -2
@@ -0,0 +1,148 @@
1
+ import { info, warn } from "@gtkx/utils";
2
+ import { createHash } from "node:crypto";
3
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+
7
+ type DigestRequest = {
8
+ url: string;
9
+ dest: string;
10
+ assetName: string;
11
+ subject: string;
12
+ };
13
+
14
+ type DownloadRequest = {
15
+ url: string;
16
+ dest: string;
17
+ label: string;
18
+ sha256: string;
19
+ freshSha256?: (() => Promise<string>) | undefined;
20
+ mode?: number | undefined;
21
+ };
22
+
23
+ const CACHE_NAMESPACE = "gtkx";
24
+ const DIGEST_PATTERN = /^[\da-f]{64}$/;
25
+
26
+ const cacheRoot = (): string => {
27
+ const base = process.env.XDG_CACHE_HOME;
28
+
29
+ return join(base !== undefined && base.length > 0 ? base : join(homedir(), ".cache"), CACHE_NAMESPACE);
30
+ };
31
+
32
+ const cacheDir = (segments: string[]): string => {
33
+ const dir = join(cacheRoot(), ...segments);
34
+ mkdirSync(dir, { recursive: true });
35
+
36
+ return dir;
37
+ };
38
+
39
+ const getDigest = (contents: Buffer): string => createHash("sha256").update(contents).digest("hex");
40
+
41
+ const assertDigest = (url: string, contents: Buffer, expected: string): void => {
42
+ const actual = getDigest(contents);
43
+
44
+ if (actual !== expected) {
45
+ throw new Error(`Checksum mismatch for ${url}\n expected ${expected}\n received ${actual}`);
46
+ }
47
+ };
48
+
49
+ const fetchBytes = async (url: string): Promise<Buffer> => {
50
+ const response = await fetch(url);
51
+
52
+ if (!response.ok) {
53
+ throw new Error(`Cannot download ${url}: HTTP ${String(response.status)} ${response.statusText}`);
54
+ }
55
+
56
+ return Buffer.from(await response.arrayBuffer());
57
+ };
58
+
59
+ const fetchText = async (url: string): Promise<string> => {
60
+ const bytes = await fetchBytes(url);
61
+
62
+ return bytes.toString("utf8");
63
+ };
64
+
65
+ const readCachedDigest = (dest: string): string | undefined => {
66
+ try {
67
+ const cached = readFileSync(dest, "utf8").trim();
68
+
69
+ return DIGEST_PATTERN.test(cached) ? cached : undefined;
70
+ } catch {
71
+ return undefined;
72
+ }
73
+ };
74
+
75
+ const writeAtomically = (dest: string, contents: string): void => {
76
+ const staging = `${dest}.partial`;
77
+ writeFileSync(staging, contents);
78
+ renameSync(staging, dest);
79
+ };
80
+
81
+ const publishedDigest = async (request: DigestRequest): Promise<string> => {
82
+ const checksums = await fetchText(request.url);
83
+ const digest = digestFromChecksums(checksums, request.assetName, request.subject);
84
+
85
+ if (!DIGEST_PATTERN.test(digest)) {
86
+ throw new Error(`${request.subject} published a malformed checksum for ${request.assetName}: "${digest}"`);
87
+ }
88
+
89
+ writeAtomically(request.dest, digest);
90
+
91
+ return digest;
92
+ };
93
+
94
+ const cachedDigest = async (request: DigestRequest): Promise<string> => {
95
+ const cached = readCachedDigest(request.dest);
96
+
97
+ return cached ?? publishedDigest(request);
98
+ };
99
+
100
+ const isCacheUsable = (dest: string, sha256: string): boolean => {
101
+ if (!existsSync(dest)) {
102
+ return false;
103
+ }
104
+
105
+ if (getDigest(readFileSync(dest)) === sha256) {
106
+ return true;
107
+ }
108
+
109
+ warn(`Discarding the cached ${dest}: its checksum no longer matches`);
110
+
111
+ return false;
112
+ };
113
+
114
+ const downloadFile = async (request: DownloadRequest): Promise<string> => {
115
+ const { url, dest, label, sha256, mode } = request;
116
+
117
+ if (isCacheUsable(dest, sha256)) {
118
+ return dest;
119
+ }
120
+
121
+ info(`Downloading ${label}`);
122
+ const expected = request.freshSha256 === undefined ? sha256 : await request.freshSha256();
123
+ const contents = await fetchBytes(url);
124
+ assertDigest(url, contents, expected);
125
+ const staging = `${dest}.partial`;
126
+ writeFileSync(staging, contents);
127
+
128
+ if (mode !== undefined) {
129
+ chmodSync(staging, mode);
130
+ }
131
+
132
+ renameSync(staging, dest);
133
+
134
+ return dest;
135
+ };
136
+
137
+ const digestFromChecksums = (checksums: string, assetName: string, subject: string): string => {
138
+ const line = checksums.split("\n").find((entry) => entry.trim().endsWith(` ${assetName}`));
139
+ const digest = line?.trim().split(/\s+/, 1)[0];
140
+
141
+ if (digest === undefined) {
142
+ throw new Error(`${subject} publishes no checksum for ${assetName}`);
143
+ }
144
+
145
+ return digest;
146
+ };
147
+
148
+ export { cacheDir, cachedDigest, type DigestRequest, downloadFile, publishedDigest };
@@ -0,0 +1,41 @@
1
+ import { readFileSync } from "node:fs";
2
+ import type { DeploySettings } from "../types.js";
3
+
4
+ const FORMAT_URL = "https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/";
5
+ const CONTINUATION_BLANK = " .";
6
+
7
+ const indentLicenseBody = (body: string): string[] =>
8
+ body
9
+ .split("\n")
10
+ .map((line) => (line.trim().length === 0 ? CONTINUATION_BLANK : ` ${line}`));
11
+
12
+ const licenseBody = (licenseFile: string | null): string[] => {
13
+ if (licenseFile === null) {
14
+ return [];
15
+ }
16
+
17
+ try {
18
+ return indentLicenseBody(readFileSync(licenseFile, "utf8").trimEnd());
19
+ } catch {
20
+ return [];
21
+ }
22
+ };
23
+
24
+ const headerLines = (settings: DeploySettings): string[] => [
25
+ `Format: ${FORMAT_URL}`,
26
+ `Upstream-Name: ${settings.name}`,
27
+ ...(settings.homepage === null ? [] : [`Source: ${settings.homepage}`]),
28
+ ];
29
+
30
+ const renderCopyright = (settings: DeploySettings): string =>
31
+ [
32
+ ...headerLines(settings),
33
+ "",
34
+ "Files: *",
35
+ `Copyright: ${settings.copyright}`,
36
+ `License: ${settings.license}`,
37
+ ...licenseBody(settings.paths.licenseFile),
38
+ "",
39
+ ].join("\n");
40
+
41
+ export { renderCopyright };
@@ -0,0 +1,19 @@
1
+ import { posix } from "node:path";
2
+ import type { DeploySettings } from "../types.js";
3
+ import { renderIni } from "./ini.js";
4
+
5
+ const SERVICE_GROUP = "D-BUS Service";
6
+ const SERVICE_FLAG = "--gapplication-service";
7
+
8
+ const renderDbusService = (settings: DeploySettings, prefix: string): string =>
9
+ renderIni([
10
+ {
11
+ name: SERVICE_GROUP,
12
+ entries: [
13
+ ["Name", settings.applicationId],
14
+ ["Exec", `${posix.join(prefix, "bin", settings.binaryName)} ${SERVICE_FLAG}`],
15
+ ],
16
+ },
17
+ ]);
18
+
19
+ export { renderDbusService };
@@ -0,0 +1,102 @@
1
+ import type { DeployDesktopAction, DeploySettings } from "../types.js";
2
+ import { type IniGroup, renderIni } from "./ini.js";
3
+
4
+ type Entries = [string, string | string[]][];
5
+
6
+ const DESKTOP_ENTRY_GROUP = "Desktop Entry";
7
+ const EXEC_QUOTED_CHARACTERS = /["`$\\]/g;
8
+ const EXEC_RESERVED_CHARACTERS = /[\s"'\\><~|&;$*?#()`]/;
9
+
10
+ const RESERVED_KEYS = new Map([
11
+ ["DBusActivatable", "use `deploy.isDbusActivatable` instead"],
12
+ ["Version", "it names the desktop entry spec version, not the application's"],
13
+ ]);
14
+
15
+ const quoteExecToken = (token: string): string => {
16
+ const escaped = token.replaceAll("%", "%%");
17
+
18
+ if (!EXEC_RESERVED_CHARACTERS.test(escaped)) {
19
+ return escaped;
20
+ }
21
+
22
+ const quoted = escaped.replaceAll(EXEC_QUOTED_CHARACTERS, (character) => `\\${character}`);
23
+
24
+ return `"${quoted}"`;
25
+ };
26
+
27
+ const execLine = (settings: DeploySettings): string =>
28
+ [
29
+ ...[settings.binaryName, ...settings.execArgs].map((part) => quoteExecToken(part)),
30
+ settings.execToken ?? "",
31
+ ]
32
+ .filter((part) => part.length > 0)
33
+ .join(" ");
34
+
35
+ const optionalEntry = (key: string, value: string | null): Entries => (value === null ? [] : [[key, value]]);
36
+ const listEntry = (key: string, values: string[]): Entries => (values.length === 0 ? [] : [[key, values]]);
37
+
38
+ const assertNoReservedOverrides = (settings: DeploySettings): void => {
39
+ for (const key of Object.keys(settings.desktopEntry)) {
40
+ const remedy = RESERVED_KEYS.get(key);
41
+
42
+ if (remedy !== undefined) {
43
+ throw new Error(`Cannot set "${key}" through \`deploy.desktopEntry\`: gtkx deploy writes it, ${remedy}`);
44
+ }
45
+ }
46
+ };
47
+
48
+ const baseEntries = (settings: DeploySettings): Entries => [
49
+ ["Type", "Application"],
50
+ ["Name", settings.name],
51
+ ...optionalEntry("GenericName", settings.genericName),
52
+ ["Comment", settings.summary],
53
+ ["Exec", execLine(settings)],
54
+ ["Icon", settings.applicationId],
55
+ ["Terminal", "false"],
56
+ ...listEntry("Categories", settings.categories),
57
+ ...listEntry("Keywords", settings.keywords),
58
+ ...listEntry("MimeType", settings.mimeTypes),
59
+ ["StartupNotify", "true"],
60
+ ["StartupWMClass", settings.applicationId],
61
+ ];
62
+
63
+ const actionEntries = (settings: DeploySettings): Entries =>
64
+ settings.desktopActions.length === 0 ? [] : [["Actions", settings.desktopActions.map((action) => action.id)]];
65
+
66
+ const activationEntries = (settings: DeploySettings): Entries =>
67
+ settings.isDbusActivatable ? [["DBusActivatable", "true"]] : [];
68
+
69
+ const actionGroup = (settings: DeploySettings, action: DeployDesktopAction): IniGroup => ({
70
+ name: `Desktop Action ${action.id}`,
71
+ entries: [
72
+ ["Name", action.name],
73
+ ["Exec", [settings.binaryName, ...action.args].map((part) => quoteExecToken(part)).join(" ")],
74
+ ...optionalEntry("Icon", action.icon),
75
+ ],
76
+ });
77
+
78
+ const mergeEntries = (entries: Entries, overrides: Entries): Entries => {
79
+ const merged = new Map(entries);
80
+
81
+ for (const [key, value] of overrides) {
82
+ merged.set(key, value);
83
+ }
84
+
85
+ return merged.entries().toArray();
86
+ };
87
+
88
+ const renderDesktopEntry = (settings: DeploySettings): string => {
89
+ assertNoReservedOverrides(settings);
90
+
91
+ const main: IniGroup = {
92
+ name: DESKTOP_ENTRY_GROUP,
93
+ entries: mergeEntries(
94
+ [...baseEntries(settings), ...actionEntries(settings), ...activationEntries(settings)],
95
+ Object.entries(settings.desktopEntry),
96
+ ),
97
+ };
98
+
99
+ return renderIni([main, ...settings.desktopActions.map((action) => actionGroup(settings, action))]);
100
+ };
101
+
102
+ export { renderDesktopEntry };
@@ -0,0 +1,39 @@
1
+ type IniGroup = {
2
+ name: string;
3
+ entries: [string, string | string[]][];
4
+ };
5
+
6
+ const FORBIDDEN_VALUE_CHARACTERS = /[\n\r]/;
7
+
8
+ const assertValue = (key: string, value: string): void => {
9
+ if (FORBIDDEN_VALUE_CHARACTERS.test(value)) {
10
+ throw new Error(`Cannot write "${key}" into a desktop entry: its value contains a line break`);
11
+ }
12
+ };
13
+
14
+ const escapeValue = (key: string, value: string): string => {
15
+ assertValue(key, value);
16
+
17
+ return value.replaceAll("\\", "\\\\");
18
+ };
19
+
20
+ const escapeListItem = (key: string, value: string): string => escapeValue(key, value).replaceAll(";", String.raw`\;`);
21
+
22
+ const renderList = (key: string, values: string[]): string =>
23
+ values.length === 0 ? "" : `${values.map((item) => escapeListItem(key, item)).join(";")};`;
24
+
25
+ const renderValue = (key: string, value: string | string[]): string =>
26
+ Array.isArray(value) ? renderList(key, value) : escapeValue(key, value);
27
+
28
+ const renderEntry = ([key, value]: [string, string | string[]]): string => `${key}=${renderValue(key, value)}`;
29
+
30
+ const renderGroup = (group: IniGroup): string[] => [
31
+ `[${group.name}]`,
32
+ ...group.entries.map((entry) => renderEntry(entry)),
33
+ ];
34
+
35
+ const renderIni = (groups: IniGroup[]): string =>
36
+ [...groups.flatMap((group, index) => (index === 0 ? renderGroup(group) : ["", ...renderGroup(group)])), ""]
37
+ .join("\n");
38
+
39
+ export { type IniGroup, renderIni };
@@ -0,0 +1,116 @@
1
+ import type { DeployRelease, DeploySettings } from "../types.js";
2
+ import { element, text, type XmlNode } from "./xml.js";
3
+
4
+ const CONTENT_RATING_TYPE = "oars-1.1";
5
+ const DEFAULT_SCREENSHOT_TYPE = "default";
6
+ const PRIMARY_COLOR = "primary";
7
+
8
+ const developerSection = (settings: DeploySettings): XmlNode[] => {
9
+ const attributes = settings.developer.id === null ? {} : { id: settings.developer.id };
10
+
11
+ return [element("developer", attributes, [text("name", settings.developer.name)])];
12
+ };
13
+
14
+ const descriptionSection = (settings: DeploySettings): XmlNode[] => [
15
+ element("description", {}, settings.description.map((paragraph) => text("p", paragraph))),
16
+ ];
17
+
18
+ const providesSection = (settings: DeploySettings): XmlNode[] => [
19
+ element("provides", {}, [
20
+ text("binary", settings.binaryName),
21
+ ...settings.mimeTypes.map((mimeType) => text("mediatype", mimeType)),
22
+ ]),
23
+ ];
24
+
25
+ const listSection = (tag: string, itemTag: string, values: string[]): XmlNode[] =>
26
+ values.length === 0 ? [] : [element(tag, {}, values.map((value) => text(itemTag, value)))];
27
+
28
+ const urlsSection = (settings: DeploySettings): XmlNode[] => {
29
+ const homepage = settings.homepage === null ? [] : [{ tag: "homepage", url: settings.homepage }];
30
+ const rest = Object.entries(settings.urls).map(([tag, url]) => ({ tag, url }));
31
+
32
+ return [...homepage, ...rest].map((entry) => ({ tag: "url", attributes: { type: entry.tag }, text: entry.url }));
33
+ };
34
+
35
+ const screenshotsSection = (settings: DeploySettings): XmlNode[] => {
36
+ if (settings.screenshots.length === 0) {
37
+ return [];
38
+ }
39
+
40
+ const entries = settings.screenshots.map((screenshot) =>
41
+ element(
42
+ "screenshot",
43
+ screenshot.isDefault ? { type: DEFAULT_SCREENSHOT_TYPE } : {},
44
+ [
45
+ text("image", screenshot.url),
46
+ ...(screenshot.caption === null ? [] : [text("caption", screenshot.caption)]),
47
+ ],
48
+ ));
49
+
50
+ return [element("screenshots", {}, entries)];
51
+ };
52
+
53
+ const releaseAttributes = (release: DeployRelease): Record<string, string> => ({
54
+ version: release.version,
55
+ date: release.date,
56
+ ...(release.type !== null && { type: release.type }),
57
+ ...(release.urgency !== null && { urgency: release.urgency }),
58
+ });
59
+
60
+ const releaseChildren = (release: DeployRelease): XmlNode[] => [
61
+ ...(release.url === null ? [] : [{ tag: "url", attributes: { type: "details" }, text: release.url }]),
62
+ ...(release.notes.length === 0
63
+ ? []
64
+ : [element("description", {}, release.notes.map((note) => text("p", note)))]),
65
+ ];
66
+
67
+ const releasesSection = (settings: DeploySettings): XmlNode[] => {
68
+ if (settings.releases.length === 0) {
69
+ return [];
70
+ }
71
+
72
+ const entries = settings.releases.map((release) =>
73
+ element("release", releaseAttributes(release), releaseChildren(release)));
74
+
75
+ return [element("releases", {}, entries)];
76
+ };
77
+
78
+ const contentRatingSection = (settings: DeploySettings): XmlNode[] => [
79
+ element(
80
+ "content_rating",
81
+ { type: CONTENT_RATING_TYPE },
82
+ Object.entries(settings.contentRating).map(([id, intensity]) => ({
83
+ tag: "content_attribute",
84
+ attributes: { id },
85
+ text: intensity,
86
+ })),
87
+ ),
88
+ ];
89
+
90
+ const brandingSection = (settings: DeploySettings): XmlNode[] => {
91
+ const branding = settings.branding;
92
+
93
+ if (branding === null) {
94
+ return [];
95
+ }
96
+
97
+ const color = (scheme: string, value: string): XmlNode => ({
98
+ tag: "color",
99
+ attributes: { type: PRIMARY_COLOR, scheme_preference: scheme },
100
+ text: value,
101
+ });
102
+
103
+ return [element("branding", {}, [color("light", branding.light), color("dark", branding.dark)])];
104
+ };
105
+
106
+ export {
107
+ brandingSection,
108
+ contentRatingSection,
109
+ descriptionSection,
110
+ developerSection,
111
+ listSection,
112
+ providesSection,
113
+ releasesSection,
114
+ screenshotsSection,
115
+ urlsSection,
116
+ };
@@ -0,0 +1,46 @@
1
+ import type { DeploySettings } from "../types.js";
2
+ import {
3
+ brandingSection,
4
+ contentRatingSection,
5
+ descriptionSection,
6
+ developerSection,
7
+ listSection,
8
+ providesSection,
9
+ releasesSection,
10
+ screenshotsSection,
11
+ urlsSection,
12
+ } from "./metainfo-sections.js";
13
+ import { element, renderDocument, text, type XmlNode } from "./xml.js";
14
+
15
+ const COMPONENT_TYPE = "desktop-application";
16
+ const DESKTOP_SUFFIX = ".desktop";
17
+
18
+ const launchable = (applicationId: string): XmlNode => ({
19
+ tag: "launchable",
20
+ attributes: { type: "desktop-id" },
21
+ text: `${applicationId}${DESKTOP_SUFFIX}`,
22
+ });
23
+
24
+ const renderMetainfo = (settings: DeploySettings): string =>
25
+ renderDocument(
26
+ element("component", { type: COMPONENT_TYPE }, [
27
+ text("id", settings.applicationId),
28
+ text("name", settings.name),
29
+ text("summary", settings.summary),
30
+ text("metadata_license", settings.metadataLicense),
31
+ text("project_license", settings.license),
32
+ ...developerSection(settings),
33
+ ...descriptionSection(settings),
34
+ launchable(settings.applicationId),
35
+ ...providesSection(settings),
36
+ ...listSection("categories", "category", settings.categories),
37
+ ...listSection("keywords", "keyword", settings.keywords),
38
+ ...urlsSection(settings),
39
+ ...screenshotsSection(settings),
40
+ ...releasesSection(settings),
41
+ ...contentRatingSection(settings),
42
+ ...brandingSection(settings),
43
+ ]),
44
+ );
45
+
46
+ export { renderMetainfo };
@@ -0,0 +1,28 @@
1
+ import type { DeployFileAssociation, DeploySettings } from "../types.js";
2
+ import { element, renderDocument, text, type XmlNode } from "./xml.js";
3
+
4
+ /* eslint-disable-next-line sonarjs/no-clear-text-protocols, unicorn/prefer-https --
5
+ An XML namespace is a fixed identifier, not a URL to fetch: shared-mime-info only recognizes this exact string. */
6
+ const MIME_INFO_NAMESPACE = "http://www.freedesktop.org/standards/shared-mime-info";
7
+
8
+ const mimeTypeNode = (association: DeployFileAssociation): XmlNode =>
9
+ element("mime-type", { type: association.mimeType }, [
10
+ ...(association.description === null ? [] : [text("comment", association.description)]),
11
+ { tag: "glob", attributes: { pattern: `*.${association.extension}` } },
12
+ ]);
13
+
14
+ const renderMimePackage = (settings: DeploySettings): string | null => {
15
+ if (settings.fileAssociations.length === 0) {
16
+ return null;
17
+ }
18
+
19
+ return renderDocument(
20
+ element(
21
+ "mime-info",
22
+ { xmlns: MIME_INFO_NAMESPACE },
23
+ settings.fileAssociations.map((entry) => mimeTypeNode(entry)),
24
+ ),
25
+ );
26
+ };
27
+
28
+ export { renderMimePackage };
@@ -0,0 +1,124 @@
1
+ import { resolveExecutable, sortStrings, warn } from "@gtkx/utils";
2
+ import { spawnSync } from "node:child_process";
3
+
4
+ type ToolResult = {
5
+ output: string;
6
+ status: number;
7
+ };
8
+
9
+ type MetainfoResult = {
10
+ subject: string;
11
+ output: string;
12
+ status: number;
13
+ errors: string[];
14
+ warnings: string[];
15
+ areWarningsFatal: boolean;
16
+ };
17
+
18
+ type ToolRequest = {
19
+ tool: string;
20
+ args: string[];
21
+ subject: string;
22
+ };
23
+
24
+ const DIAGNOSTIC = /^(?<severity>[EIPW]): \S+ (?<rule>[\w-]+)/;
25
+ const ERROR_SEVERITY = "E";
26
+ const WARNING_SEVERITY = "W";
27
+ const INFO_SEVERITY = "I";
28
+
29
+ const REMEDY_FOR_RULE: Record<string, string> = {
30
+ "component-summary-missing": "set `deploy.summary`",
31
+ "description-first-para-too-short": "open `deploy.description` with a paragraph longer than 80 characters",
32
+ "developer-info-missing": "set `deploy.developer.name`",
33
+ "metainfo-legacy-path": "this file is generated; report it as a gtkx bug",
34
+ "summary-has-dot-suffix": "drop the trailing period from `deploy.summary`",
35
+ "summary-too-long": "shorten `deploy.summary`",
36
+ "url-homepage-missing": "set `deploy.homepage`, or `homepage` in package.json",
37
+ };
38
+
39
+ const runTool = ({ tool, args, subject }: ToolRequest): ToolResult => {
40
+ const result = spawnSync(resolveExecutable(tool), args, { encoding: "utf8" });
41
+
42
+ if (result.error !== undefined) {
43
+ throw new Error(`${subject} could not be validated: ${result.error.message}`, { cause: result.error });
44
+ }
45
+
46
+ return { output: [result.stdout, result.stderr].join("\n").trim(), status: result.status ?? 0 };
47
+ };
48
+
49
+ const rulesIn = (output: string, severities: string[]): string[] =>
50
+ output
51
+ .split("\n")
52
+ .map((line) => DIAGNOSTIC.exec(line)?.groups)
53
+ .filter((groups) => groups !== undefined && severities.includes(groups.severity ?? ""))
54
+ .map((groups) => groups?.rule ?? "");
55
+
56
+ const remedyLines = (rules: string[]): string[] => {
57
+ const remedies = sortStrings([...new Set(rules)])
58
+ .filter((rule) => REMEDY_FOR_RULE[rule] !== undefined)
59
+ .map((rule) => ` ${rule}: ${REMEDY_FOR_RULE[rule] ?? ""}`);
60
+
61
+ return remedies.length === 0 ? [] : ["", "Fix it in gtkx.config.ts:", ...remedies];
62
+ };
63
+
64
+ const invalid = (subject: string, output: string, rules: string[]): Error =>
65
+ new Error([`${subject} is not valid:`, output.length > 0 ? output : "no output", ...remedyLines(rules)].join("\n"));
66
+
67
+ const isFatalResult = ({ status, errors, warnings, areWarningsFatal }: MetainfoResult): boolean => {
68
+ if (errors.length > 0) {
69
+ return true;
70
+ }
71
+
72
+ if (areWarningsFatal && warnings.length > 0) {
73
+ return true;
74
+ }
75
+
76
+ return status !== 0 && warnings.length === 0;
77
+ };
78
+
79
+ const assertNotFatal = (result: MetainfoResult): void => {
80
+ if (isFatalResult(result)) {
81
+ throw invalid(result.subject, result.output, [...result.errors, ...result.warnings]);
82
+ }
83
+ };
84
+
85
+ const describeRule = (rule: string): string => {
86
+ const remedy = REMEDY_FOR_RULE[rule];
87
+
88
+ return remedy === undefined ? rule : `${rule} — ${remedy}`;
89
+ };
90
+
91
+ const reportDiagnostics = (subject: string, rules: string[]): void => {
92
+ for (const rule of rules) {
93
+ warn(`${subject}: ${describeRule(rule)}`);
94
+ }
95
+ };
96
+
97
+ const validateDesktopEntry = (path: string): void => {
98
+ const { output, status } = runTool({
99
+ tool: "desktop-file-validate",
100
+ args: [path],
101
+ subject: "The desktop entry",
102
+ });
103
+
104
+ if (status !== 0 || output.length > 0) {
105
+ throw invalid("The desktop entry", output, []);
106
+ }
107
+ };
108
+
109
+ const validateMetainfo = (path: string, areWarningsFatal: boolean): void => {
110
+ const subject = "The AppStream metainfo";
111
+
112
+ const { output, status } = runTool({
113
+ tool: "appstreamcli",
114
+ args: ["validate", "--no-net", "--explain", path],
115
+ subject,
116
+ });
117
+
118
+ const errors = rulesIn(output, [ERROR_SEVERITY]);
119
+ const warnings = rulesIn(output, [WARNING_SEVERITY]);
120
+ assertNotFatal({ subject, output, status, errors, warnings, areWarningsFatal });
121
+ reportDiagnostics(subject, [...warnings, ...rulesIn(output, [INFO_SEVERITY])]);
122
+ };
123
+
124
+ export { validateDesktopEntry, validateMetainfo };