@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
@@ -1,17 +1,11 @@
1
- import { isRecord, sortStringsBy, warn } from "@gtkx/utils";
2
- import { existsSync, readFileSync, realpathSync } from "node:fs";
1
+ import { sortStringsBy, warn } from "@gtkx/utils";
2
+ import { existsSync, realpathSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
+ import type { RecordedPackage } from "../../internal/build-manifest.js";
4
5
  import type { DeploySettings } from "../types.js";
5
- import { BUNDLED_PACKAGES_FILENAME } from "../../vite-plugins/bundled-packages.js";
6
6
  import { type PackageManifest, readPackageManifest } from "../settings/package-manifest.js";
7
7
  import { copyrightLines, licenseTextIn } from "./text.js";
8
8
 
9
- type RecordedPackage = {
10
- name: string;
11
- version: string | null;
12
- dir: string;
13
- };
14
-
15
9
  type BundledPackage = {
16
10
  name: string;
17
11
  version: string | null;
@@ -36,38 +30,6 @@ const realPath = (path: string): string => {
36
30
  }
37
31
  };
38
32
 
39
- const optionalString = (value: unknown): string | null => (typeof value === "string" ? value : null);
40
-
41
- const recordedPackage = (entry: unknown): RecordedPackage | null => {
42
- if (!isRecord(entry) || typeof entry.name !== "string" || typeof entry.dir !== "string") {
43
- return null;
44
- }
45
-
46
- return { name: entry.name, version: optionalString(entry.version), dir: entry.dir };
47
- };
48
-
49
- const recordedList = (value: unknown): RecordedPackage[] => {
50
- if (!Array.isArray(value)) {
51
- return [];
52
- }
53
-
54
- const entries: unknown[] = value;
55
-
56
- return entries.map((entry) => recordedPackage(entry)).filter((entry) => entry !== null);
57
- };
58
-
59
- const readRecordedPackages = (settings: DeploySettings): RecordedPackage[] => {
60
- const path = join(settings.paths.dist, BUNDLED_PACKAGES_FILENAME);
61
-
62
- if (!existsSync(path)) {
63
- throw new Error(`Cannot deploy: ${path} is missing. Run \`gtkx build\` first.`);
64
- }
65
-
66
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
67
-
68
- return recordedList(isRecord(parsed) ? parsed.packages : null);
69
- };
70
-
71
33
  const authorLine = (manifest: PackageManifest): string[] => {
72
34
  const { name, email } = manifest.author;
73
35
 
@@ -151,10 +113,10 @@ const warnMissing = (entries: BundledPackage[]): void => {
151
113
  );
152
114
  };
153
115
 
154
- const bundledPackages = (settings: DeploySettings): BundledPackage[] => {
116
+ const bundledPackages = (settings: DeploySettings, recorded: RecordedPackage[]): BundledPackage[] => {
155
117
  const root = realPath(settings.paths.root);
156
118
 
157
- const entries = readRecordedPackages(settings)
119
+ const entries = recorded
158
120
  .map((entry) => ({ entry, dir: resolve(settings.paths.dist, entry.dir) }))
159
121
  .filter(({ dir }) => realPath(dir) !== root)
160
122
  .map(({ entry, dir }) => packageIn(entry, dir));
@@ -1,53 +1,82 @@
1
- import { basename, join } from "node:path";
1
+ import { join } from "node:path";
2
2
  import type { DeploySettings, StagedFile } from "../types.js";
3
+ import { relativeIconPath } from "../../internal/icon-path.js";
3
4
  import { listFilesRecursive } from "../../internal/list-files.js";
4
5
  import { copyInto } from "./copy-tree.js";
5
6
 
7
+ type ApplicationIconVariant = {
8
+ effectivePixels: number;
9
+ scalable: boolean;
10
+ };
11
+
6
12
  const ICON_EXTENSIONS = [".svg", ".png", ".xpm"];
7
13
  const SHARE_ICONS = "share/icons";
8
- const SCALABLE_DIR = "hicolor/scalable/apps";
9
- const SIZE_PATTERN = /^(?<width>[1-9]\d{0,3})x(?<height>[1-9]\d{0,3})$/;
10
- const SIZE_SEPARATORS = /[-_.]/;
11
-
12
- const isApplicationIcon = (settings: DeploySettings, rel: string): boolean =>
13
- ICON_EXTENSIONS.some((extension) => basename(rel) === `${settings.applicationId}${extension}`);
14
+ const SIZE_PATTERN = /^(?<width>[1-9]\d{0,3})x(?<height>[1-9]\d{0,3})(?:@(?<scale>[1-9]\d*))?$/;
14
15
 
15
- const getSquareSize = (token: string): number | null => {
16
+ const getSquareSize = (token: string): { pixels: number; scale: number } | null => {
16
17
  const groups = SIZE_PATTERN.exec(token)?.groups;
17
18
 
18
19
  if (groups === undefined || groups.width !== groups.height) {
19
20
  return null;
20
21
  }
21
22
 
22
- return Number(groups.width);
23
+ const pixels = Number(groups.width);
24
+ const scale = Number(groups.scale ?? "1");
25
+
26
+ return Number.isSafeInteger(pixels * scale) ? { pixels, scale } : null;
27
+ };
28
+
29
+ const isIconThemeSize = (segment: string | undefined): boolean =>
30
+ segment === "scalable" || segment === "symbolic" ||
31
+ (segment !== undefined && getSquareSize(segment) !== null);
32
+
33
+ const iconExtension = (applicationId: string, filename: string | undefined): string | undefined =>
34
+ ICON_EXTENSIONS.find((candidate) => filename === `${applicationId}${candidate}`);
35
+
36
+ const isApplicationIconLayout = (segments: (string | undefined)[]): boolean => {
37
+ const [share, icons, theme, size, context] = segments;
38
+
39
+ return share === "share" &&
40
+ icons === "icons" &&
41
+ theme === "hicolor" &&
42
+ context === "apps" &&
43
+ isIconThemeSize(size);
23
44
  };
24
45
 
25
- const firstSquareSize = (tokens: string[]): number | null =>
26
- tokens.map((token) => getSquareSize(token)).find((size) => size !== null) ?? null;
46
+ const classifyApplicationIcon = (applicationId: string, rel: string): ApplicationIconVariant | null => {
47
+ const segments = rel.split(/[\\/]/);
48
+
49
+ if (segments.length !== 6) {
50
+ return null;
51
+ }
27
52
 
28
- const getIconSize = (rel: string): number | null => firstSquareSize(rel.split("/").slice(0, -1));
53
+ const size = segments[3];
54
+ const filename = segments[5];
55
+ const extension = iconExtension(applicationId, filename);
29
56
 
30
- const themeDirFor = (file: string): string => {
31
- if (file.endsWith(".svg")) {
32
- return SCALABLE_DIR;
57
+ if (extension === undefined || !isApplicationIconLayout(segments)) {
58
+ return null;
33
59
  }
34
60
 
35
- const size = firstSquareSize(basename(file).split(SIZE_SEPARATORS));
61
+ const square = size === undefined ? null : getSquareSize(size);
36
62
 
37
- return size === null ? SCALABLE_DIR : `hicolor/${String(size)}x${String(size)}/apps`;
63
+ return {
64
+ effectivePixels: square === null ? 0 : square.pixels * square.scale,
65
+ scalable: extension === ".svg",
66
+ };
38
67
  };
39
68
 
40
- const stageIconTree = (root: string, iconsDir: string): StagedFile[] =>
41
- listFilesRecursive(iconsDir).map((file) => copyInto(root, join(SHARE_ICONS, file.rel), file.absPath));
69
+ const isApplicationIcon = (settings: DeploySettings, rel: string): boolean =>
70
+ classifyApplicationIcon(settings.applicationId, rel) !== null;
42
71
 
43
- const iconPathFor = (settings: DeploySettings, iconFile: string): string => {
44
- const extension = ICON_EXTENSIONS.find((candidate) => iconFile.endsWith(candidate)) ?? ".png";
72
+ const stageIconTree = (root: string, themePath: string): StagedFile[] =>
73
+ listFilesRecursive(themePath).map((file) => copyInto(root, join(SHARE_ICONS, file.rel), file.absPath));
45
74
 
46
- return join(themeDirFor(iconFile), `${settings.applicationId}${extension}`);
47
- };
75
+ const iconPathFor = (settings: DeploySettings, iconPath: string): string =>
76
+ relativeIconPath(settings.applicationId, iconPath);
48
77
 
49
- const stageIconFile = (settings: DeploySettings, root: string, iconFile: string): StagedFile[] =>
50
- [copyInto(root, join(SHARE_ICONS, iconPathFor(settings, iconFile)), iconFile)];
78
+ const stageIconFile = (settings: DeploySettings, root: string, iconPath: string): StagedFile[] =>
79
+ [copyInto(root, join(SHARE_ICONS, iconPathFor(settings, iconPath)), iconPath)];
51
80
 
52
81
  const assertApplicationIcon = (settings: DeploySettings, staged: StagedFile[]): void => {
53
82
  if (staged.some((file) => isApplicationIcon(settings, file.rel))) {
@@ -55,26 +84,27 @@ const assertApplicationIcon = (settings: DeploySettings, staged: StagedFile[]):
55
84
  }
56
85
 
57
86
  throw new Error(
58
- `Cannot deploy without an application icon: no ${settings.applicationId}.svg or ` +
59
- `${settings.applicationId}.png under ${settings.paths.iconsDir ?? "the project's icon directory"}. ` +
87
+ "Cannot deploy without a usable application icon: the configured theme must contain " +
88
+ `${settings.applicationId}.svg, ${settings.applicationId}.png, or ${settings.applicationId}.xpm ` +
89
+ "under hicolor/<size>/apps. " +
60
90
  "The desktop entry names " +
61
91
  `"${settings.applicationId}" as its icon, so the file has to match. ` +
62
- `Add ${settings.paths.dataDir ?? "data"}/icons/hicolor/scalable/apps/${settings.applicationId}.svg, ` +
63
- "or point `deploy.icons` at one.",
92
+ "Set `applicationIcon` to a theme directory containing " +
93
+ `hicolor/scalable/apps/${settings.applicationId}.svg, or point it at a single icon file.`,
64
94
  );
65
95
  };
66
96
 
67
97
  const stageIcons = (settings: DeploySettings, root: string): StagedFile[] => {
68
- const { iconsDir, iconFile } = settings.paths;
98
+ const source = settings.paths.applicationIcon;
69
99
 
70
- if (iconFile !== null) {
71
- return stageIconFile(settings, root, iconFile);
100
+ if (source.kind === "file") {
101
+ return stageIconFile(settings, root, source.path);
72
102
  }
73
103
 
74
- const staged = iconsDir === null ? [] : stageIconTree(root, iconsDir);
104
+ const staged = source.kind === "theme" ? stageIconTree(root, source.path) : [];
75
105
  assertApplicationIcon(settings, staged);
76
106
 
77
107
  return staged;
78
108
  };
79
109
 
80
- export { getIconSize, iconPathFor, stageIcons };
110
+ export { classifyApplicationIcon, iconPathFor, stageIcons, type ApplicationIconVariant };
@@ -18,6 +18,8 @@ const renderLauncher = (settings: DeploySettings): string => {
18
18
  "set -e",
19
19
  'self=$(readlink -f "$0")',
20
20
  'prefix=$(dirname "$(dirname "$self")")',
21
+ 'GTKX_LOCALE_DIR="$prefix/share/locale"',
22
+ "export GTKX_LOCALE_DIR",
21
23
  ...(shouldUseCompileCache ? compileCacheLines(settings.binaryName) : []),
22
24
  `exec "${libDir}/${NODE_FILENAME}" "${libDir}/${BUNDLE_FILENAME}" "$@"`,
23
25
  "",
@@ -2,12 +2,12 @@ import { sortStringsBy } from "@gtkx/utils";
2
2
  import { existsSync, rmSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
4
  import type { DeploySettings, DeployTargetName, NodeRuntime, NoticeSection, StagedFile } from "../types.js";
5
+ import { LOCALE_DIRNAME } from "../../i18n/catalogs.js";
6
+ import { BUILD_MANIFEST_FILENAME } from "../../internal/build-manifest.js";
5
7
  import { listFilesRecursive } from "../../internal/list-files.js";
6
- import { BUNDLED_PACKAGES_FILENAME } from "../../vite-plugins/bundled-packages.js";
7
8
  import { BUNDLE_FILENAME } from "../../vite-plugins/esm-extension.js";
8
9
  import { renderCopyright } from "../freedesktop/copyright.js";
9
10
  import { renderDbusService } from "../freedesktop/dbus-service.js";
10
- import { renderDesktopEntry } from "../freedesktop/desktop-entry.js";
11
11
  import { renderNotices } from "../notices/render.js";
12
12
  import { copyInto, EXECUTABLE_MODE, executableModeFor, writeInto } from "./copy-tree.js";
13
13
  import { stageIcons } from "./icons.js";
@@ -27,6 +27,7 @@ type StagedMetadata = {
27
27
  };
28
28
 
29
29
  const DIST_ICONS_DIR = "icons";
30
+ const LEGACY_PACKAGES_MANIFEST_FILENAME = "gtkx-packages.json";
30
31
  const NOTICES_FILENAME = "THIRD-PARTY-NOTICES";
31
32
  const NODE_LICENSE_FILENAME = "LICENSE";
32
33
  const SHARE_APPLICATIONS = "share/applications";
@@ -35,6 +36,7 @@ const SHARE_MIME_PACKAGES = "share/mime/packages";
35
36
  const SHARE_DOC = "share/doc";
36
37
  const SHARE_LICENSES = "share/licenses";
37
38
  const SHARE_DBUS_SERVICES = "share/dbus-1/services";
39
+ const SHARE_LOCALE = `share/${LOCALE_DIRNAME}`;
38
40
 
39
41
  const PREFIX_FOR: Record<DeployTargetName, string> = {
40
42
  appimage: "/usr",
@@ -48,7 +50,11 @@ const licenseDirFor = (settings: DeploySettings): string => `${SHARE_LICENSES}/$
48
50
  const licenseDestination = (settings: DeploySettings): string => `${licenseDirFor(settings)}/LICENSE`;
49
51
  const noticesDestination = (settings: DeploySettings): string => `${licenseDirFor(settings)}/${NOTICES_FILENAME}`;
50
52
  const isIconAsset = (rel: string): boolean => rel === DIST_ICONS_DIR || rel.startsWith(`${DIST_ICONS_DIR}/`);
51
- const isBuildMetadata = (rel: string): boolean => rel === BUNDLED_PACKAGES_FILENAME;
53
+
54
+ const isBuildMetadata = (rel: string): boolean =>
55
+ rel === BUILD_MANIFEST_FILENAME || rel === LEGACY_PACKAGES_MANIFEST_FILENAME;
56
+
57
+ const isLocaleAsset = (rel: string): boolean => rel === LOCALE_DIRNAME || rel.startsWith(`${LOCALE_DIRNAME}/`);
52
58
 
53
59
  const nodeLicenseDestination = (settings: DeploySettings): string =>
54
60
  `${licenseDirFor(settings)}/${NODE_FILENAME}/${NODE_LICENSE_FILENAME}`;
@@ -61,10 +67,14 @@ const stageRuntimeFiles = (settings: DeploySettings, root: string): StagedFile[]
61
67
  }
62
68
 
63
69
  return listFilesRecursive(dist)
64
- .filter((file) => !isIconAsset(file.rel) && !isBuildMetadata(file.rel))
70
+ .filter((file) => !isIconAsset(file.rel) && !isBuildMetadata(file.rel) && !isLocaleAsset(file.rel))
65
71
  .map((file) => copyInto(root, join(libDirFor(settings), file.rel), file.absPath));
66
72
  };
67
73
 
74
+ const stageCatalogs = (settings: DeploySettings, root: string): StagedFile[] =>
75
+ listFilesRecursive(join(settings.paths.dist, LOCALE_DIRNAME))
76
+ .map((file) => copyInto(root, join(SHARE_LOCALE, file.rel), file.absPath));
77
+
68
78
  const stageNodeBinary = (settings: DeploySettings, root: string, node: NodeRuntime | null): StagedFile[] =>
69
79
  node === null ? [] : [copyInto(root, join(libDirFor(settings), NODE_FILENAME), node.path, EXECUTABLE_MODE)];
70
80
 
@@ -101,6 +111,7 @@ const stagePayload = ({ settings, node, metadata }: StageRequest): StagedFile[]
101
111
  writeInto(root, join("bin", settings.binaryName), renderLauncher(settings), EXECUTABLE_MODE),
102
112
  ...stageNodeBinary(settings, root, node),
103
113
  ...stageRuntimeFiles(settings, root),
114
+ ...stageCatalogs(settings, root),
104
115
  ...stageMetadata(settings, root, metadata),
105
116
  ...stageIcons(settings, root),
106
117
  ...stageSchemas(settings, root),
@@ -108,7 +119,18 @@ const stagePayload = ({ settings, node, metadata }: StageRequest): StagedFile[]
108
119
  ]);
109
120
  };
110
121
 
111
- const stageActivation = (settings: DeploySettings, root: string, target: DeployTargetName): StagedFile[] => {
122
+ const withoutDbusActivation = (desktopEntry: string): string =>
123
+ desktopEntry
124
+ .split("\n")
125
+ .filter((line) => line !== "DBusActivatable=true")
126
+ .join("\n");
127
+
128
+ const stageActivation = (
129
+ settings: DeploySettings,
130
+ root: string,
131
+ target: DeployTargetName,
132
+ metadata: StagedMetadata,
133
+ ): StagedFile[] => {
112
134
  if (!settings.isDbusActivatable) {
113
135
  return [];
114
136
  }
@@ -117,7 +139,7 @@ const stageActivation = (settings: DeploySettings, root: string, target: DeployT
117
139
  return [writeInto(
118
140
  root,
119
141
  join(SHARE_APPLICATIONS, `${settings.applicationId}.desktop`),
120
- renderDesktopEntry({ ...settings, isDbusActivatable: false }),
142
+ withoutDbusActivation(metadata.desktopEntry),
121
143
  )];
122
144
  }
123
145
 
@@ -128,11 +150,16 @@ const stageActivation = (settings: DeploySettings, root: string, target: DeployT
128
150
  )];
129
151
  };
130
152
 
131
- const stageOverlay = (settings: DeploySettings, target: DeployTargetName, notices: NoticeSection[]): StagedFile[] => {
153
+ const stageOverlay = (
154
+ settings: DeploySettings,
155
+ target: DeployTargetName,
156
+ notices: NoticeSection[],
157
+ metadata: StagedMetadata,
158
+ ): StagedFile[] => {
132
159
  const root = join(settings.paths.overlay, target);
133
160
  rmSync(root, { recursive: true, force: true, maxRetries: 5 });
134
161
  const licenseFile = settings.paths.licenseFile;
135
- const activation = stageActivation(settings, root, target);
162
+ const activation = stageActivation(settings, root, target, metadata);
136
163
 
137
164
  if (target === "deb") {
138
165
  return [
@@ -151,11 +178,12 @@ const stageOverlay = (settings: DeploySettings, target: DeployTargetName, notice
151
178
  const stageOverlays = (
152
179
  settings: DeploySettings,
153
180
  notices: NoticeSection[],
181
+ metadata: StagedMetadata,
154
182
  ): Record<DeployTargetName, StagedFile[]> => ({
155
- appimage: stageOverlay(settings, "appimage", notices),
156
- deb: stageOverlay(settings, "deb", notices),
157
- flatpak: stageOverlay(settings, "flatpak", notices),
158
- rpm: stageOverlay(settings, "rpm", notices),
183
+ appimage: stageOverlay(settings, "appimage", notices, metadata),
184
+ deb: stageOverlay(settings, "deb", notices, metadata),
185
+ flatpak: stageOverlay(settings, "flatpak", notices, metadata),
186
+ rpm: stageOverlay(settings, "rpm", notices, metadata),
159
187
  });
160
188
 
161
189
  export {