@gtkx/cli 1.0.0-rc.1 → 1.0.0-rc.2

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 (286) hide show
  1. package/dist/builder.d.ts +3 -2
  2. package/dist/builder.d.ts.map +1 -1
  3. package/dist/builder.js +2 -1
  4. package/dist/builder.js.map +1 -1
  5. package/dist/cli.d.ts +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +21 -6
  8. package/dist/cli.js.map +1 -1
  9. package/dist/codegen/freshness.d.ts +5 -5
  10. package/dist/codegen/freshness.d.ts.map +1 -1
  11. package/dist/codegen/freshness.js +26 -23
  12. package/dist/codegen/freshness.js.map +1 -1
  13. package/dist/codegen/report.d.ts +2 -1
  14. package/dist/codegen/report.d.ts.map +1 -1
  15. package/dist/codegen/report.js +4 -2
  16. package/dist/codegen/report.js.map +1 -1
  17. package/dist/codegen/run-codegen.d.ts +8 -8
  18. package/dist/codegen/run-codegen.d.ts.map +1 -1
  19. package/dist/codegen/run-codegen.js +72 -43
  20. package/dist/codegen/run-codegen.js.map +1 -1
  21. package/dist/codegen/store-resolver.d.ts +8 -5
  22. package/dist/codegen/store-resolver.d.ts.map +1 -1
  23. package/dist/codegen/store-resolver.js +26 -6
  24. package/dist/codegen/store-resolver.js.map +1 -1
  25. package/dist/commands/build.d.ts +4 -3
  26. package/dist/commands/build.d.ts.map +1 -1
  27. package/dist/commands/build.js +2 -1
  28. package/dist/commands/build.js.map +1 -1
  29. package/dist/commands/codegen.d.ts +2 -1
  30. package/dist/commands/codegen.d.ts.map +1 -1
  31. package/dist/commands/codegen.js +6 -4
  32. package/dist/commands/codegen.js.map +1 -1
  33. package/dist/commands/dev.d.ts +2 -1
  34. package/dist/commands/dev.d.ts.map +1 -1
  35. package/dist/commands/dev.js +2 -1
  36. package/dist/commands/dev.js.map +1 -1
  37. package/dist/commands/docs.d.ts +2 -1
  38. package/dist/commands/docs.d.ts.map +1 -1
  39. package/dist/commands/docs.js +22 -7
  40. package/dist/commands/docs.js.map +1 -1
  41. package/dist/dev/icon-dir.d.ts +2 -1
  42. package/dist/dev/icon-dir.d.ts.map +1 -1
  43. package/dist/dev/icon-dir.js +6 -3
  44. package/dist/dev/icon-dir.js.map +1 -1
  45. package/dist/dev/refresh-tracker.d.ts +5 -4
  46. package/dist/dev/refresh-tracker.d.ts.map +1 -1
  47. package/dist/dev/refresh-tracker.js +6 -5
  48. package/dist/dev/refresh-tracker.js.map +1 -1
  49. package/dist/dev/runner-deps.d.ts +2 -1
  50. package/dist/dev/runner-deps.d.ts.map +1 -1
  51. package/dist/dev/runner-deps.js +20 -4
  52. package/dist/dev/runner-deps.js.map +1 -1
  53. package/dist/dev/runner-main.d.ts +2 -1
  54. package/dist/dev/runner-main.d.ts.map +1 -1
  55. package/dist/dev/runner-main.js +3 -2
  56. package/dist/dev/runner-main.js.map +1 -1
  57. package/dist/dev/runner.d.ts +6 -5
  58. package/dist/dev/runner.d.ts.map +1 -1
  59. package/dist/dev/runner.js +69 -38
  60. package/dist/dev/runner.js.map +1 -1
  61. package/dist/dev/schema-dir.d.ts +2 -1
  62. package/dist/dev/schema-dir.d.ts.map +1 -1
  63. package/dist/dev/schema-dir.js +4 -2
  64. package/dist/dev/schema-dir.js.map +1 -1
  65. package/dist/dev/supervisor.d.ts +7 -6
  66. package/dist/dev/supervisor.d.ts.map +1 -1
  67. package/dist/dev/supervisor.js +107 -67
  68. package/dist/dev/supervisor.js.map +1 -1
  69. package/dist/dev/vite-dev-server.d.ts +3 -3
  70. package/dist/dev/vite-dev-server.d.ts.map +1 -1
  71. package/dist/dev/vite-dev-server.js +2 -1
  72. package/dist/dev/vite-dev-server.js.map +1 -1
  73. package/dist/internal/banner.d.ts +2 -1
  74. package/dist/internal/banner.d.ts.map +1 -1
  75. package/dist/internal/banner.js +2 -1
  76. package/dist/internal/banner.js.map +1 -1
  77. package/dist/internal/data-dir.d.ts +3 -2
  78. package/dist/internal/data-dir.d.ts.map +1 -1
  79. package/dist/internal/data-dir.js +29 -14
  80. package/dist/internal/data-dir.js.map +1 -1
  81. package/dist/internal/entry-arg.d.ts +5 -4
  82. package/dist/internal/entry-arg.d.ts.map +1 -1
  83. package/dist/internal/entry-arg.js +10 -7
  84. package/dist/internal/entry-arg.js.map +1 -1
  85. package/dist/internal/errors.d.ts +3 -2
  86. package/dist/internal/errors.d.ts.map +1 -1
  87. package/dist/internal/errors.js +7 -5
  88. package/dist/internal/errors.js.map +1 -1
  89. package/dist/internal/list-files.d.ts +3 -2
  90. package/dist/internal/list-files.d.ts.map +1 -1
  91. package/dist/internal/list-files.js +5 -3
  92. package/dist/internal/list-files.js.map +1 -1
  93. package/dist/internal/resolve-cli-tool.d.ts +2 -1
  94. package/dist/internal/resolve-cli-tool.d.ts.map +1 -1
  95. package/dist/internal/resolve-cli-tool.js +17 -10
  96. package/dist/internal/resolve-cli-tool.js.map +1 -1
  97. package/dist/internal/staging-dir.d.ts +3 -2
  98. package/dist/internal/staging-dir.d.ts.map +1 -1
  99. package/dist/internal/staging-dir.js +3 -2
  100. package/dist/internal/staging-dir.js.map +1 -1
  101. package/dist/internal/xdg-data-dirs.d.ts +2 -1
  102. package/dist/internal/xdg-data-dirs.d.ts.map +1 -1
  103. package/dist/internal/xdg-data-dirs.js +4 -2
  104. package/dist/internal/xdg-data-dirs.js.map +1 -1
  105. package/dist/mcp/client.d.ts +9 -4
  106. package/dist/mcp/client.d.ts.map +1 -1
  107. package/dist/mcp/client.js +106 -81
  108. package/dist/mcp/client.js.map +1 -1
  109. package/dist/mcp/handlers.d.ts +3 -2
  110. package/dist/mcp/handlers.d.ts.map +1 -1
  111. package/dist/mcp/handlers.js +89 -61
  112. package/dist/mcp/handlers.js.map +1 -1
  113. package/dist/mcp/index.d.ts +2 -2
  114. package/dist/mcp/index.d.ts.map +1 -1
  115. package/dist/mcp/index.js +30 -13
  116. package/dist/mcp/index.js.map +1 -1
  117. package/dist/mcp/serialize-widget.d.ts +3 -3
  118. package/dist/mcp/serialize-widget.d.ts.map +1 -1
  119. package/dist/mcp/serialize-widget.js +9 -6
  120. package/dist/mcp/serialize-widget.js.map +1 -1
  121. package/dist/mcp/testing-loader.d.ts +3 -4
  122. package/dist/mcp/testing-loader.d.ts.map +1 -1
  123. package/dist/mcp/testing-loader.js +43 -21
  124. package/dist/mcp/testing-loader.js.map +1 -1
  125. package/dist/mcp/widget-registry.d.ts +3 -2
  126. package/dist/mcp/widget-registry.d.ts.map +1 -1
  127. package/dist/mcp/widget-registry.js +4 -3
  128. package/dist/mcp/widget-registry.js.map +1 -1
  129. package/dist/refresh-globals.d.ts +2 -0
  130. package/dist/refresh-globals.d.ts.map +1 -0
  131. package/dist/refresh-globals.js +8 -0
  132. package/dist/refresh-globals.js.map +1 -0
  133. package/dist/refresh-runtime.d.ts +5 -11
  134. package/dist/refresh-runtime.d.ts.map +1 -1
  135. package/dist/refresh-runtime.js +16 -14
  136. package/dist/refresh-runtime.js.map +1 -1
  137. package/dist/settings/compile.d.ts +2 -1
  138. package/dist/settings/compile.d.ts.map +1 -1
  139. package/dist/settings/compile.js +6 -4
  140. package/dist/settings/compile.js.map +1 -1
  141. package/dist/settings/parser.d.ts +6 -5
  142. package/dist/settings/parser.d.ts.map +1 -1
  143. package/dist/settings/parser.js +26 -22
  144. package/dist/settings/parser.js.map +1 -1
  145. package/dist/settings/render.d.ts +3 -2
  146. package/dist/settings/render.d.ts.map +1 -1
  147. package/dist/settings/render.js +38 -64
  148. package/dist/settings/render.js.map +1 -1
  149. package/dist/settings/schema.d.ts +8 -8
  150. package/dist/settings/schema.d.ts.map +1 -1
  151. package/dist/settings/schema.js +61 -43
  152. package/dist/settings/schema.js.map +1 -1
  153. package/dist/vite-plugins/asset-extensions.d.ts +4 -3
  154. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  155. package/dist/vite-plugins/asset-extensions.js +4 -3
  156. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  157. package/dist/vite-plugins/built-url.d.ts +2 -1
  158. package/dist/vite-plugins/built-url.d.ts.map +1 -1
  159. package/dist/vite-plugins/built-url.js +19 -13
  160. package/dist/vite-plugins/built-url.js.map +1 -1
  161. package/dist/vite-plugins/css.d.ts +2 -1
  162. package/dist/vite-plugins/css.d.ts.map +1 -1
  163. package/dist/vite-plugins/css.js +23 -15
  164. package/dist/vite-plugins/css.js.map +1 -1
  165. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +5 -4
  166. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -1
  167. package/dist/vite-plugins/fast-refresh/refresh-filter.js +11 -7
  168. package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -1
  169. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +4 -3
  170. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -1
  171. package/dist/vite-plugins/fast-refresh/swc-refresh.js +45 -41
  172. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -1
  173. package/dist/vite-plugins/icons.d.ts +2 -1
  174. package/dist/vite-plugins/icons.d.ts.map +1 -1
  175. package/dist/vite-plugins/icons.js +24 -20
  176. package/dist/vite-plugins/icons.js.map +1 -1
  177. package/dist/vite-plugins/index.d.ts +2 -1
  178. package/dist/vite-plugins/index.d.ts.map +1 -1
  179. package/dist/vite-plugins/index.js +3 -2
  180. package/dist/vite-plugins/index.js.map +1 -1
  181. package/dist/vite-plugins/native.d.ts +2 -1
  182. package/dist/vite-plugins/native.d.ts.map +1 -1
  183. package/dist/vite-plugins/native.js +6 -4
  184. package/dist/vite-plugins/native.js.map +1 -1
  185. package/dist/vite-plugins/react-compiler.d.ts +3 -2
  186. package/dist/vite-plugins/react-compiler.d.ts.map +1 -1
  187. package/dist/vite-plugins/react-compiler.js +26 -20
  188. package/dist/vite-plugins/react-compiler.js.map +1 -1
  189. package/dist/vite-plugins/react-dom-prebundle.d.ts +2 -1
  190. package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -1
  191. package/dist/vite-plugins/react-dom-prebundle.js +2 -1
  192. package/dist/vite-plugins/react-dom-prebundle.js.map +1 -1
  193. package/dist/vite-plugins/resource-init-module.d.ts +2 -1
  194. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -1
  195. package/dist/vite-plugins/resource-init-module.js +39 -38
  196. package/dist/vite-plugins/resource-init-module.js.map +1 -1
  197. package/dist/vite-plugins/resource-shared.d.ts +7 -5
  198. package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
  199. package/dist/vite-plugins/resource-shared.js +17 -10
  200. package/dist/vite-plugins/resource-shared.js.map +1 -1
  201. package/dist/vite-plugins/resources.d.ts +3 -2
  202. package/dist/vite-plugins/resources.d.ts.map +1 -1
  203. package/dist/vite-plugins/resources.js +94 -54
  204. package/dist/vite-plugins/resources.js.map +1 -1
  205. package/dist/vite-plugins/settings-worker-env.d.ts +2 -1
  206. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
  207. package/dist/vite-plugins/settings-worker-env.js +4 -2
  208. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  209. package/dist/vite-plugins/settings.d.ts +2 -1
  210. package/dist/vite-plugins/settings.d.ts.map +1 -1
  211. package/dist/vite-plugins/settings.js +56 -32
  212. package/dist/vite-plugins/settings.js.map +1 -1
  213. package/dist/vite-plugins/strip-query.d.ts +3 -0
  214. package/dist/vite-plugins/strip-query.d.ts.map +1 -0
  215. package/dist/vite-plugins/strip-query.js +6 -0
  216. package/dist/vite-plugins/strip-query.js.map +1 -0
  217. package/dist/vite-plugins/undeclared-library.d.ts +2 -1
  218. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
  219. package/dist/vite-plugins/undeclared-library.js +8 -5
  220. package/dist/vite-plugins/undeclared-library.js.map +1 -1
  221. package/dist/vite-plugins/virtual-module.d.ts +2 -2
  222. package/dist/vite-plugins/virtual-module.d.ts.map +1 -1
  223. package/dist/vite-plugins/virtual-module.js +5 -3
  224. package/dist/vite-plugins/virtual-module.js.map +1 -1
  225. package/dist/vitest-plugin.d.ts.map +1 -1
  226. package/dist/vitest-plugin.js.map +1 -1
  227. package/env.d.ts +21 -61
  228. package/package.json +12 -14
  229. package/src/babel-modules.d.ts +0 -2
  230. package/src/builder.ts +7 -6
  231. package/src/cli.ts +26 -6
  232. package/src/codegen/freshness.ts +38 -25
  233. package/src/codegen/report.ts +10 -2
  234. package/src/codegen/run-codegen.ts +135 -60
  235. package/src/codegen/store-resolver.ts +56 -15
  236. package/src/commands/build.ts +3 -2
  237. package/src/commands/codegen.ts +9 -4
  238. package/src/commands/dev.ts +3 -4
  239. package/src/commands/docs.ts +36 -7
  240. package/src/dev/icon-dir.ts +13 -3
  241. package/src/dev/refresh-tracker.ts +12 -8
  242. package/src/dev/runner-deps.ts +30 -7
  243. package/src/dev/runner-main.ts +4 -3
  244. package/src/dev/runner.ts +100 -41
  245. package/src/dev/schema-dir.ts +7 -2
  246. package/src/dev/supervisor.ts +169 -71
  247. package/src/dev/vite-dev-server.ts +4 -2
  248. package/src/internal/banner.ts +5 -1
  249. package/src/internal/data-dir.ts +47 -16
  250. package/src/internal/entry-arg.ts +16 -8
  251. package/src/internal/errors.ts +15 -7
  252. package/src/internal/list-files.ts +10 -4
  253. package/src/internal/resolve-cli-tool.ts +28 -12
  254. package/src/internal/staging-dir.ts +5 -2
  255. package/src/internal/xdg-data-dirs.ts +8 -2
  256. package/src/mcp/client.ts +143 -85
  257. package/src/mcp/handlers.ts +126 -69
  258. package/src/mcp/index.ts +38 -14
  259. package/src/mcp/serialize-widget.ts +15 -8
  260. package/src/mcp/testing-loader.ts +64 -23
  261. package/src/mcp/widget-registry.ts +11 -5
  262. package/src/refresh-globals.ts +10 -0
  263. package/src/refresh-runtime.ts +20 -16
  264. package/src/settings/compile.ts +7 -4
  265. package/src/settings/parser.ts +69 -30
  266. package/src/settings/render.ts +66 -66
  267. package/src/settings/schema.ts +100 -46
  268. package/src/vite-plugins/asset-extensions.ts +4 -3
  269. package/src/vite-plugins/built-url.ts +30 -15
  270. package/src/vite-plugins/css.ts +35 -20
  271. package/src/vite-plugins/fast-refresh/refresh-filter.ts +18 -10
  272. package/src/vite-plugins/fast-refresh/swc-refresh.ts +60 -47
  273. package/src/vite-plugins/icons.ts +40 -24
  274. package/src/vite-plugins/index.ts +6 -3
  275. package/src/vite-plugins/native.ts +14 -5
  276. package/src/vite-plugins/react-compiler.ts +44 -30
  277. package/src/vite-plugins/react-dom-prebundle.ts +4 -1
  278. package/src/vite-plugins/resource-init-module.ts +41 -38
  279. package/src/vite-plugins/resource-shared.ts +27 -14
  280. package/src/vite-plugins/resources.ts +153 -59
  281. package/src/vite-plugins/settings-worker-env.ts +7 -2
  282. package/src/vite-plugins/settings.ts +107 -42
  283. package/src/vite-plugins/strip-query.ts +7 -0
  284. package/src/vite-plugins/undeclared-library.ts +21 -12
  285. package/src/vite-plugins/virtual-module.ts +9 -2
  286. package/src/vitest-plugin.ts +1 -2
@@ -2,19 +2,27 @@ import type { RunCodegenResult } from "./run-codegen.js";
2
2
 
3
3
  const PREFIX = "codegen: ";
4
4
 
5
- export const formatCodegenResult = (result: RunCodegenResult, totalMs: number): string[] => {
5
+ const formatCodegenResult = (result: RunCodegenResult, totalMs: number): string[] => {
6
6
  const details: string[] = [];
7
+
7
8
  if (result.configFile) {
8
9
  details.push(`config=${result.configFile}`);
9
10
  }
11
+
10
12
  if (result.libraries) {
11
13
  details.push(`libraries=${result.libraries.join(", ")}`);
12
14
  }
15
+
13
16
  if (result.girPath) {
14
17
  details.push(`girPath=${result.girPath.join(":")}`);
15
18
  }
19
+
16
20
  details.push(
17
- `${result.namespaces} namespaces, ${result.intrinsicElements} intrinsic elements in ${result.duration}ms (total ${totalMs}ms)`,
21
+ `${String(result.namespaces)} namespaces, ${String(result.intrinsicElements)} intrinsic elements ` +
22
+ `in ${String(result.duration)}ms (total ${String(totalMs)}ms)`,
18
23
  );
24
+
19
25
  return details.map((detail) => PREFIX + detail);
20
26
  };
27
+
28
+ export { formatCodegenResult };
@@ -1,14 +1,15 @@
1
- import { rmSync } from "node:fs";
2
- import { resolve } from "node:path";
3
1
  import { runCodegen as runCodegenCore } from "@gtkx/codegen";
4
- import { type Config, type ElementProp, loadConfig } from "@gtkx/config";
2
+ import { type Config, loadConfig } from "@gtkx/config";
3
+ import { resolveLazyElements } from "@gtkx/config/internal";
5
4
  import { info } from "@gtkx/utils";
5
+ import { rmSync } from "node:fs";
6
+ import { resolve } from "node:path";
6
7
  import { resolveDataDir } from "../internal/data-dir.js";
7
8
  import { emitSchemaEnv } from "../settings/schema.js";
8
9
  import { type CodegenInputs, isCodegenStale, resolveCodegenInputs } from "./freshness.js";
9
10
  import { type CodegenStore, resolveCodegenContext } from "./store-resolver.js";
10
11
 
11
- export type RunCodegenOptions = {
12
+ type RunCodegenOptions = {
12
13
  cwd?: string;
13
14
  mode?: string | undefined;
14
15
  force?: boolean;
@@ -21,7 +22,7 @@ type LoadedConfig = {
21
22
  configFile: string | undefined;
22
23
  };
23
24
 
24
- export type RunCodegenResult = {
25
+ type RunCodegenResult = {
25
26
  regenerated: boolean;
26
27
  namespaces: number;
27
28
  intrinsicElements: number;
@@ -31,6 +32,27 @@ export type RunCodegenResult = {
31
32
  libraries?: string[] | undefined;
32
33
  };
33
34
 
35
+ type CodegenOptionsInput = {
36
+ store: CodegenStore;
37
+ libraries: string[];
38
+ girPath: string[];
39
+ elements: Config["elements"];
40
+ };
41
+
42
+ type PreparedCodegen = CodegenInputs & { force: boolean };
43
+
44
+ type RunOptionsInput = {
45
+ root: string;
46
+ mode: string | undefined;
47
+ inputs: CodegenInputs | null;
48
+ resolved: LoadedConfig;
49
+ };
50
+
51
+ const GIR_PATH_MISSING_MESSAGE =
52
+ "No GIR search paths available. Install gobject-introspection " +
53
+ "(Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), " +
54
+ "or set `girPath` in gtkx.config.ts.";
55
+
34
56
  const removeSharedStoreShadow = (cwd: string): void => {
35
57
  for (const path of [
36
58
  resolve(cwd, "node_modules/.gtkx/gi"),
@@ -42,67 +64,89 @@ const removeSharedStoreShadow = (cwd: string): void => {
42
64
  }
43
65
  };
44
66
 
45
- type CodegenOptionsInput = {
46
- store: CodegenStore;
47
- libraries: string[];
48
- girPath: string[];
49
- elementProps: Record<string, ElementProp[]>;
50
- };
67
+ const userModuleExports = (
68
+ elements: Config["elements"],
69
+ key: "component" | "props",
70
+ ): Record<string, { module: string; export: string }> =>
71
+ Object.fromEntries(
72
+ Object.entries(elements?.config ?? {}).flatMap(([type, entry]) => {
73
+ const ref = entry[key];
74
+
75
+ return ref === undefined ? [] : [[type, ref] as const];
76
+ }),
77
+ );
51
78
 
52
- const codegenOptions = ({ store, libraries, girPath, elementProps }: CodegenOptionsInput) => ({
79
+ const codegenOptions = ({ store, libraries, girPath, elements }: CodegenOptionsInput) => ({
53
80
  libraries,
54
81
  girPath,
55
- elementProps,
56
82
  gi: {
57
83
  storeDir: store.giStoreDir,
58
84
  linkDir: store.giLinkDir,
59
85
  version: store.runtimeVersion,
60
86
  },
61
87
  jsx:
62
- store.react !== null
63
- ? {
64
- storeDir: store.jsxStoreDir,
65
- linkDir: store.jsxLinkDir,
66
- version: store.react.version,
67
- }
68
- : undefined,
88
+ store.react === null
89
+ ? undefined
90
+ : {
91
+ storeDir: store.jsxStoreDir,
92
+ linkDir: store.jsxLinkDir,
93
+ version: store.react.version,
94
+ },
95
+ reactSubexports: store.react?.subexports ?? [],
96
+ userComponents: userModuleExports(elements, "component"),
97
+ userProps: userModuleExports(elements, "props"),
98
+ userLazyElements: resolveLazyElements(elements),
69
99
  });
70
100
 
71
- export const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenResult> => {
72
- const cwd = options.cwd ?? process.cwd();
73
-
74
- const { config, configFile } = options.resolved ?? (await loadConfig(cwd, { mode: options.mode }));
101
+ const disabledCodegenResult = (configFile: string | undefined): RunCodegenResult => ({
102
+ regenerated: false,
103
+ namespaces: 0,
104
+ intrinsicElements: 0,
105
+ duration: 0,
106
+ girPath: [],
107
+ configFile,
108
+ libraries: [],
109
+ });
75
110
 
76
- if (config.codegen === false) {
77
- removeSharedStoreShadow(cwd);
78
- return {
79
- regenerated: false,
80
- namespaces: 0,
81
- intrinsicElements: 0,
82
- duration: 0,
83
- girPath: [],
84
- configFile,
85
- libraries: [],
86
- };
111
+ const clearGeneratedStores = (store: CodegenStore): void => {
112
+ for (const path of [store.giStoreDir, store.giLinkDir, store.jsxStoreDir, store.jsxLinkDir]) {
113
+ rmSync(path, { recursive: true, force: true });
87
114
  }
115
+ };
116
+
117
+ const resolveLoadedConfig = async (options: RunCodegenOptions, cwd: string): Promise<LoadedConfig> =>
118
+ options.resolved ?? (await loadConfig(cwd, { mode: options.mode }));
88
119
 
89
- const { girPath, libraries, elementProps, store } = options.inputs ?? resolveCodegenInputs(cwd, config);
120
+ const prepareCodegen = (options: RunCodegenOptions, cwd: string, config: Config): PreparedCodegen => {
121
+ const { girPath, libraries, store } = options.inputs ?? resolveCodegenInputs(cwd, config);
90
122
 
91
123
  if (girPath.length === 0) {
92
- throw new Error(
93
- "No GIR search paths available. Install gobject-introspection (Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.",
94
- );
124
+ throw new Error(GIR_PATH_MISSING_MESSAGE);
95
125
  }
96
126
 
97
- const force = options.force === true || isCodegenStale({ girPath, libraries, elementProps, store });
127
+ const isForce = options.force === true || isCodegenStale({ girPath, libraries, store });
128
+
129
+ return { girPath, libraries, store, force: isForce };
130
+ };
131
+
132
+ const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCodegenResult> => {
133
+ const cwd = options.cwd ?? process.cwd();
134
+ const { config, configFile } = await resolveLoadedConfig(options, cwd);
135
+
136
+ if (config.codegen === false) {
137
+ removeSharedStoreShadow(cwd);
138
+
139
+ return disabledCodegenResult(configFile);
140
+ }
141
+
142
+ const { girPath, libraries, store, force } = prepareCodegen(options, cwd, config);
143
+
98
144
  if (options.force) {
99
- for (const path of [store.giStoreDir, store.giLinkDir, store.jsxStoreDir, store.jsxLinkDir]) {
100
- rmSync(path, { recursive: true, force: true });
101
- }
145
+ clearGeneratedStores(store);
102
146
  }
103
147
 
104
148
  const result = await runCodegenCore({
105
- ...codegenOptions({ store, libraries, girPath, elementProps }),
149
+ ...codegenOptions({ store, libraries, girPath, elements: config.elements }),
106
150
  force,
107
151
  });
108
152
 
@@ -117,19 +161,18 @@ export const runCodegen = async (options: RunCodegenOptions = {}): Promise<RunCo
117
161
  };
118
162
  };
119
163
 
120
- export const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> => {
164
+ const isCodegenDisabled = async (cwd: string, mode?: string): Promise<boolean> => {
121
165
  try {
122
166
  const { config } = await loadConfig(cwd, { mode });
167
+
123
168
  return config.codegen === false;
124
169
  } catch {
125
170
  return false;
126
171
  }
127
172
  };
128
173
 
129
- export const syncSchemaEnv = (cwd: string): void => {
130
- const dataDir = resolveDataDir(cwd);
131
- if (dataDir === null) return;
132
- emitSchemaEnv(cwd, dataDir);
174
+ const syncSchemaEnv = (cwd: string): void => {
175
+ emitSchemaEnv(cwd, resolveDataDir(cwd));
133
176
  };
134
177
 
135
178
  const resolveInputsOrNull = (cwd: string, config: Config): CodegenInputs | null => {
@@ -140,7 +183,25 @@ const resolveInputsOrNull = (cwd: string, config: Config): CodegenInputs | null
140
183
  }
141
184
  };
142
185
 
143
- export const ensureGenerated = async (
186
+ const maybeAnnounceStale = (announce: boolean | undefined, inputs: CodegenInputs | null): void => {
187
+ if (!announce) {
188
+ return;
189
+ }
190
+
191
+ if (inputs === null || isCodegenStale(inputs)) {
192
+ info("generated bindings missing; running codegen...");
193
+ }
194
+ };
195
+
196
+ const getRunOptions = ({ root, mode, inputs, resolved }: RunOptionsInput): RunCodegenOptions => {
197
+ if (inputs === null) {
198
+ return { cwd: root, mode, resolved };
199
+ }
200
+
201
+ return { cwd: root, mode, inputs, resolved };
202
+ };
203
+
204
+ const ensureGenerated = async (
144
205
  cwd: string,
145
206
  options: { announce?: boolean; mode?: string } = {},
146
207
  ): Promise<boolean> => {
@@ -149,33 +210,37 @@ export const ensureGenerated = async (
149
210
  }
150
211
 
151
212
  const context = await resolveCodegenContext(cwd, options.mode);
213
+
152
214
  if (!context) {
153
215
  return false;
154
216
  }
217
+
155
218
  syncSchemaEnv(cwd);
219
+
156
220
  if (context.config.codegen === false) {
157
221
  removeSharedStoreShadow(context.root);
222
+
158
223
  return false;
159
224
  }
225
+
160
226
  const inputs = resolveInputsOrNull(context.root, context.config);
161
- if (options.announce && (inputs === null || isCodegenStale(inputs))) {
162
- info("generated bindings missing; running codegen...");
163
- }
227
+ maybeAnnounceStale(options.announce, inputs);
164
228
  const resolved = { config: context.config, configFile: context.configFile };
165
- const result = await runCodegen(
166
- inputs === null
167
- ? { cwd: context.root, mode: options.mode, resolved }
168
- : { cwd: context.root, mode: options.mode, inputs, resolved },
169
- );
229
+ const result = await runCodegen(getRunOptions({ root: context.root, mode: options.mode, inputs, resolved }));
230
+
170
231
  return result.regenerated;
171
232
  };
172
233
 
173
- export const resolveConfigWatch = async (
234
+ const resolveConfigWatch = async (
174
235
  cwd: string,
175
236
  mode?: string,
176
237
  ): Promise<{ paths: string[]; regenerate: () => Promise<void> } | undefined> => {
177
238
  const { configFile, root } = await loadConfig(cwd, { mode });
178
- if (configFile === undefined) return undefined;
239
+
240
+ if (configFile === undefined) {
241
+ return undefined;
242
+ }
243
+
179
244
  return {
180
245
  paths: [resolve(root, configFile)],
181
246
  regenerate: async () => {
@@ -183,3 +248,13 @@ export const resolveConfigWatch = async (
183
248
  },
184
249
  };
185
250
  };
251
+
252
+ export {
253
+ runCodegen,
254
+ isCodegenDisabled,
255
+ syncSchemaEnv,
256
+ ensureGenerated,
257
+ resolveConfigWatch,
258
+ type RunCodegenOptions,
259
+ type RunCodegenResult,
260
+ };
@@ -1,10 +1,10 @@
1
+ import { type Config, loadConfig } from "@gtkx/config";
1
2
  import { existsSync, readFileSync, realpathSync } from "node:fs";
2
3
  import { createRequire } from "node:module";
3
4
  import { dirname, join } from "node:path";
4
5
  import { pathToFileURL } from "node:url";
5
- import { type Config, loadConfig } from "@gtkx/config";
6
6
 
7
- export type CodegenStore = {
7
+ type CodegenStore = {
8
8
  giStoreDir: string;
9
9
  giLinkDir: string;
10
10
  jsxStoreDir: string;
@@ -15,61 +15,102 @@ export type CodegenStore = {
15
15
 
16
16
  type CodegenReactPackage = {
17
17
  version: string;
18
+ subexports: string[];
18
19
  };
19
20
 
20
21
  type ResolvedPackage = { dir: string; version: string };
21
22
 
23
+ type CodegenContext = {
24
+ root: string;
25
+ config: Config;
26
+ configFile: string | undefined;
27
+ };
28
+
22
29
  const readVersion = (packageJsonPath: string): string => {
23
30
  const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { version?: string };
31
+
24
32
  return parsed.version ?? "0.0.0";
25
33
  };
26
34
 
35
+ const readSubexports = (packageDir: string): string[] => {
36
+ const parsed = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8")) as {
37
+ exports?: Record<string, unknown>;
38
+ };
39
+
40
+ return Object.keys(parsed.exports ?? {})
41
+ .filter((key) => key.startsWith("./") && key !== "./package.json")
42
+ .map((key) => key.slice(2));
43
+ };
44
+
45
+ /** Resolves the `@gtkx/react` subexport names for a project without requiring runtime/native to be installed. */
46
+ const resolveReactSubexports = (dir: string): string[] => {
47
+ const require = createRequire(pathToFileURL(join(dir, "__gtkx_resolver__.js")).href);
48
+ const react = resolvePackage(require, dir, "@gtkx/react");
49
+
50
+ return react === null ? [] : readSubexports(react.dir);
51
+ };
52
+
27
53
  const resolvePackage = (require: NodeJS.Require, dir: string, packageName: string): ResolvedPackage | null => {
28
54
  try {
29
55
  const real = realpathSync(require.resolve(`${packageName}/package.json`));
56
+
30
57
  return { dir: dirname(real), version: readVersion(real) };
31
58
  } catch {
32
59
  const unscoped = packageName.replace(/^@[^/]+\//, "");
33
60
  const workspacePkg = join(dir, "packages", unscoped, "package.json");
34
- if (!existsSync(workspacePkg)) return null;
61
+
62
+ if (!existsSync(workspacePkg)) {
63
+ return null;
64
+ }
65
+
35
66
  const real = realpathSync(workspacePkg);
67
+
36
68
  return { dir: dirname(real), version: readVersion(real) };
37
69
  }
38
70
  };
39
71
 
40
- export const resolveCodegenStore = (dir: string): CodegenStore => {
72
+ const resolveCodegenStore = (dir: string): CodegenStore => {
41
73
  const require = createRequire(pathToFileURL(join(dir, "__gtkx_resolver__.js")).href);
42
-
43
74
  const runtime = resolvePackage(require, dir, "@gtkx/runtime");
75
+
44
76
  if (runtime === null) {
45
77
  throw new Error("Cannot resolve @gtkx/runtime from the project; is it installed?");
46
78
  }
79
+
47
80
  const native = resolvePackage(require, dir, "@gtkx/native");
81
+
48
82
  if (native === null) {
49
83
  throw new Error("Cannot resolve @gtkx/native from the project; is it installed?");
50
84
  }
85
+
51
86
  const react = resolvePackage(require, dir, "@gtkx/react");
52
87
  const reactRuntime = resolvePackage(require, dir, "react");
53
-
54
88
  const nodeModules = join(dir, "node_modules");
89
+
55
90
  return {
56
91
  giStoreDir: join(nodeModules, ".gtkx", "gi"),
57
92
  giLinkDir: join(nodeModules, "@gtkx", "gi"),
58
93
  jsxStoreDir: join(nodeModules, ".gtkx", "jsx"),
59
94
  jsxLinkDir: join(nodeModules, "@gtkx", "jsx"),
60
95
  runtimeVersion: runtime.version,
61
- react: react !== null && reactRuntime !== null ? { version: react.version } : null,
96
+ react:
97
+ react !== null && reactRuntime !== null
98
+ ? {
99
+ version: react.version,
100
+ subexports: readSubexports(react.dir),
101
+ }
102
+ : null,
62
103
  };
63
104
  };
64
105
 
65
- export type CodegenContext = {
66
- root: string;
67
- config: Config;
68
- configFile: string | undefined;
69
- };
70
-
71
- export const resolveCodegenContext = async (cwd: string, mode?: string): Promise<CodegenContext | null> => {
106
+ const resolveCodegenContext = async (cwd: string, mode?: string): Promise<CodegenContext | null> => {
72
107
  const { config, configFile } = await loadConfig(cwd, { mode });
73
- if (configFile === undefined) return null;
108
+
109
+ if (configFile === undefined) {
110
+ return null;
111
+ }
112
+
74
113
  return { root: cwd, config, configFile };
75
114
  };
115
+
116
+ export { resolveReactSubexports, resolveCodegenStore, resolveCodegenContext, type CodegenStore, type CodegenContext };
@@ -6,7 +6,7 @@ import { entryArg, resolveEntry } from "../internal/entry-arg.js";
6
6
 
7
7
  const BUILD_MODE = "production";
8
8
 
9
- export const build = defineCommand({
9
+ const build = defineCommand({
10
10
  meta: {
11
11
  name: "build",
12
12
  description: "Build application for production",
@@ -21,7 +21,6 @@ export const build = defineCommand({
21
21
  async run({ args }) {
22
22
  const { cwd, entry } = resolveEntry(args);
23
23
  info(`Building ${entry}`);
24
-
25
24
  await ensureGenerated(cwd, { announce: true, mode: BUILD_MODE });
26
25
 
27
26
  await buildApp({
@@ -35,3 +34,5 @@ export const build = defineCommand({
35
34
  info("Build complete: dist/bundle.js");
36
35
  },
37
36
  });
37
+
38
+ export { build };
@@ -4,7 +4,7 @@ import { formatCodegenResult } from "../codegen/report.js";
4
4
  import { ensureGenerated, isCodegenDisabled, runCodegen, syncSchemaEnv } from "../codegen/run-codegen.js";
5
5
  import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
6
6
 
7
- export const codegen = defineCommand({
7
+ const codegen = defineCommand({
8
8
  meta: {
9
9
  name: "codegen",
10
10
  description: "Generate TypeScript bindings for the GIR libraries declared in gtkx.config.ts",
@@ -24,21 +24,26 @@ export const codegen = defineCommand({
24
24
  await runCodegen({ cwd });
25
25
  syncSchemaEnv(cwd);
26
26
  info("codegen: disabled for this project; reusing an installed binding store");
27
+
27
28
  return;
28
29
  }
29
30
 
30
31
  if (!args.force) {
31
- const ran = await ensureGenerated(cwd);
32
- info(ran ? "codegen: regenerated stale bindings" : "codegen: bindings up to date");
32
+ const isRan = await ensureGenerated(cwd);
33
+ info(isRan ? "codegen: regenerated stale bindings" : "codegen: bindings up to date");
34
+
33
35
  return;
34
36
  }
35
37
 
36
38
  const startedAt = Date.now();
37
39
  const result = await runCodegen({ cwd, force: true });
38
40
  syncSchemaEnv(cwd);
41
+ const lines = formatCodegenResult(result, Date.now() - startedAt);
39
42
 
40
- for (const line of formatCodegenResult(result, Date.now() - startedAt)) {
43
+ for (const line of lines) {
41
44
  info(line);
42
45
  }
43
46
  },
44
47
  });
48
+
49
+ export { codegen };
@@ -5,7 +5,7 @@ import { entryArg, resolveEntry } from "../internal/entry-arg.js";
5
5
 
6
6
  const DEV_MODE = "development";
7
7
 
8
- export const dev = defineCommand({
8
+ const dev = defineCommand({
9
9
  meta: {
10
10
  name: "dev",
11
11
  description: "Start development server with HMR",
@@ -15,11 +15,10 @@ export const dev = defineCommand({
15
15
  },
16
16
  async run({ args }) {
17
17
  const { cwd, entry: entryPath } = resolveEntry(args);
18
-
19
18
  await ensureGenerated(cwd, { announce: true, mode: DEV_MODE });
20
-
21
19
  const watch: DevWatch | undefined = await resolveConfigWatch(cwd, DEV_MODE);
22
-
23
20
  await runDevSupervisor(entryPath, cwd, watch);
24
21
  },
25
22
  });
23
+
24
+ export { dev };
@@ -1,11 +1,13 @@
1
- import { resolve } from "node:path";
2
- import { resolveGirPath, resolveLibraries, writeDocs } from "@gtkx/codegen";
1
+ import { type ElementProps, readBuiltinElements, resolveGirPath, resolveLibraries, writeDocs } from "@gtkx/codegen";
3
2
  import { loadConfig } from "@gtkx/config";
4
3
  import { info } from "@gtkx/utils";
5
4
  import { defineCommand } from "citty";
5
+ import { existsSync } from "node:fs";
6
+ import { join, resolve } from "node:path";
7
+ import { resolveReactSubexports } from "../codegen/store-resolver.js";
6
8
  import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
7
9
 
8
- export const docs = defineCommand({
10
+ const docs = defineCommand({
9
11
  meta: {
10
12
  name: "docs",
11
13
  description:
@@ -32,35 +34,62 @@ export const docs = defineCommand({
32
34
  async run({ args }) {
33
35
  const cwd = resolveCwd(args);
34
36
  const { config } = await loadConfig(cwd);
37
+
35
38
  if (config.codegen === false) {
36
39
  throw new Error(
37
- "codegen is disabled for this project, so there are no GIR libraries to document. Remove `codegen: false` from gtkx.config.ts to use `gtkx docs`.",
40
+ "codegen is disabled for this project, so there are no GIR libraries to document. " +
41
+ "Remove `codegen: false` from gtkx.config.ts to use `gtkx docs`.",
38
42
  );
39
43
  }
44
+
40
45
  const girPath = resolveGirPath(config.girPath);
46
+
41
47
  if (girPath.length === 0) {
42
48
  throw new Error(
43
- "No GIR search paths available. Install gobject-introspection (Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.",
49
+ "No GIR search paths available. Install gobject-introspection " +
50
+ "(Linux: `sudo dnf install gobject-introspection-devel` or " +
51
+ "`sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.",
44
52
  );
45
53
  }
54
+
46
55
  const libraries = resolveLibraries(config.libraries, girPath);
47
56
  const startedAt = Date.now();
48
57
  const outDir = resolve(cwd, args.out);
58
+
49
59
  const { regenerated, namespaces } = writeDocs({
50
60
  libraries,
51
61
  girPath,
52
62
  outDir,
53
63
  basePath: args["base-path"],
54
- elementProps: config.elementProps ?? {},
64
+ props: await resolveDocsProps(cwd),
55
65
  force: args.force,
56
66
  });
67
+
57
68
  if (!regenerated) {
58
69
  info(`docs: pages in ${outDir} are up to date`);
70
+
59
71
  return;
60
72
  }
73
+
61
74
  const count = namespaces.reduce((total, namespace) => total + namespace.elements.length, 0);
75
+
62
76
  info(
63
- `docs: wrote ${count} element pages across ${namespaces.length} namespaces to ${outDir} in ${Date.now() - startedAt}ms`,
77
+ `docs: wrote ${String(count)} element pages across ${String(namespaces.length)} namespaces ` +
78
+ `to ${outDir} in ${String(Date.now() - startedAt)}ms`,
64
79
  );
65
80
  },
66
81
  });
82
+
83
+ const resolveDocsProps = async (cwd: string): Promise<ElementProps> => {
84
+ const giStoreDir = join(cwd, "node_modules", ".gtkx", "gi");
85
+
86
+ if (!existsSync(giStoreDir)) {
87
+ return {};
88
+ }
89
+
90
+ const { props } = await readBuiltinElements(resolveReactSubexports(cwd), giStoreDir);
91
+
92
+ return props;
93
+ };
94
+
95
+ export { docs };
@@ -2,10 +2,20 @@ import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
4
4
 
5
- export const prepareDevIconDir = (root: string, dataDir: string | null): string | null => {
6
- if (dataDir === null) return null;
5
+ const prepareDevIconDir = (root: string, dataDir: string | null): string | null => {
6
+ if (dataDir === null) {
7
+ return null;
8
+ }
9
+
7
10
  const shareDir = join(root, dataDir);
8
- if (!existsSync(join(shareDir, "icons"))) return null;
11
+
12
+ if (!existsSync(join(shareDir, "icons"))) {
13
+ return null;
14
+ }
15
+
9
16
  process.env.XDG_DATA_DIRS = prependXdgDataDir(shareDir, process.env.XDG_DATA_DIRS);
17
+
10
18
  return shareDir;
11
19
  };
20
+
21
+ export { prepareDevIconDir };
@@ -1,21 +1,25 @@
1
- export type RefreshTracker = {
2
- performRefresh(): void;
3
- isRefreshing(): boolean;
1
+ type RefreshTracker = {
2
+ performRefresh: () => void;
3
+ isRefreshing: () => boolean;
4
4
  };
5
5
 
6
- export const createRefreshTracker = (performRefresh: () => void): RefreshTracker => {
7
- let refreshing = false;
6
+ const createRefreshTracker = (performRefresh: () => void): RefreshTracker => {
7
+ let isRefreshing = false;
8
+
8
9
  return {
9
10
  performRefresh: () => {
10
- refreshing = true;
11
+ isRefreshing = true;
12
+
11
13
  try {
12
14
  performRefresh();
13
15
  } finally {
14
16
  setTimeout(() => {
15
- refreshing = false;
17
+ isRefreshing = false;
16
18
  }, 0);
17
19
  }
18
20
  },
19
- isRefreshing: () => refreshing,
21
+ isRefreshing: () => isRefreshing,
20
22
  };
21
23
  };
24
+
25
+ export { createRefreshTracker, type RefreshTracker };