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

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 +10 -10
  18. package/dist/codegen/run-codegen.d.ts.map +1 -1
  19. package/dist/codegen/run-codegen.js +72 -47
  20. package/dist/codegen/run-codegen.js.map +1 -1
  21. package/dist/codegen/store-resolver.d.ts +9 -6
  22. package/dist/codegen/store-resolver.d.ts.map +1 -1
  23. package/dist/codegen/store-resolver.js +24 -7
  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 +25 -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 +4 -3
  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 +95 -55
  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 +3 -1
  218. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
  219. package/dist/vite-plugins/undeclared-library.js +11 -8
  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 +39 -26
  233. package/src/codegen/report.ts +10 -2
  234. package/src/codegen/run-codegen.ts +131 -66
  235. package/src/codegen/store-resolver.ts +52 -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 +47 -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 +7 -4
  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 +154 -60
  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 +26 -16
  285. package/src/vite-plugins/virtual-module.ts +9 -2
  286. package/src/vitest-plugin.ts +1 -2
@@ -1,11 +1,22 @@
1
- import { resolve } from "node:path";
2
- import { resolveGirPath, resolveLibraries, writeDocs } from "@gtkx/codegen";
1
+ import {
2
+ type ElementProps,
3
+ mergeOmitProps,
4
+ type OmittedProps,
5
+ readBuiltinElements,
6
+ resolveGirPath,
7
+ resolveLibraries,
8
+ writeDocs,
9
+ } from "@gtkx/codegen";
3
10
  import { loadConfig } from "@gtkx/config";
11
+ import { resolveOmitProps } from "@gtkx/config/internal";
4
12
  import { info } from "@gtkx/utils";
5
13
  import { defineCommand } from "citty";
14
+ import { existsSync } from "node:fs";
15
+ import { join, resolve } from "node:path";
16
+ import { resolveReactSubexports } from "../codegen/store-resolver.js";
6
17
  import { cwdArg, resolveCwd } from "../internal/entry-arg.js";
7
18
 
8
- export const docs = defineCommand({
19
+ const docs = defineCommand({
9
20
  meta: {
10
21
  name: "docs",
11
22
  description:
@@ -32,35 +43,64 @@ export const docs = defineCommand({
32
43
  async run({ args }) {
33
44
  const cwd = resolveCwd(args);
34
45
  const { config } = await loadConfig(cwd);
46
+
35
47
  if (config.codegen === false) {
36
48
  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`.",
49
+ "codegen is disabled for this project, so there are no GIR libraries to document. " +
50
+ "Remove `codegen: false` from gtkx.config.ts to use `gtkx docs`.",
38
51
  );
39
52
  }
53
+
40
54
  const girPath = resolveGirPath(config.girPath);
55
+
41
56
  if (girPath.length === 0) {
42
57
  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.",
58
+ "No GIR search paths available. Install gobject-introspection " +
59
+ "(Linux: `sudo dnf install gobject-introspection-devel` or " +
60
+ "`sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.",
44
61
  );
45
62
  }
63
+
46
64
  const libraries = resolveLibraries(config.libraries, girPath);
47
65
  const startedAt = Date.now();
48
66
  const outDir = resolve(cwd, args.out);
67
+ const builtin = await resolveDocsElements(cwd);
68
+
49
69
  const { regenerated, namespaces } = writeDocs({
50
70
  libraries,
51
71
  girPath,
52
72
  outDir,
53
73
  basePath: args["base-path"],
54
- elementProps: config.elementProps ?? {},
74
+ props: builtin.props,
75
+ omitProps: mergeOmitProps(builtin.omitProps, resolveOmitProps(config.elements)),
55
76
  force: args.force,
56
77
  });
78
+
57
79
  if (!regenerated) {
58
80
  info(`docs: pages in ${outDir} are up to date`);
81
+
59
82
  return;
60
83
  }
84
+
61
85
  const count = namespaces.reduce((total, namespace) => total + namespace.elements.length, 0);
86
+
62
87
  info(
63
- `docs: wrote ${count} element pages across ${namespaces.length} namespaces to ${outDir} in ${Date.now() - startedAt}ms`,
88
+ `docs: wrote ${String(count)} element pages across ${String(namespaces.length)} namespaces ` +
89
+ `to ${outDir} in ${String(Date.now() - startedAt)}ms`,
64
90
  );
65
91
  },
66
92
  });
93
+
94
+ const resolveDocsElements = async (cwd: string): Promise<{ props: ElementProps; omitProps: OmittedProps }> => {
95
+ const giStoreDir = join(cwd, "node_modules", ".gtkx", "gi");
96
+
97
+ if (!existsSync(giStoreDir)) {
98
+ return { props: {}, omitProps: {} };
99
+ }
100
+
101
+ const { props, omitProps } = await readBuiltinElements(resolveReactSubexports(cwd), giStoreDir);
102
+
103
+ return { props, omitProps };
104
+ };
105
+
106
+ 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 };
@@ -1,26 +1,44 @@
1
1
  import { loadConfig } from "@gtkx/config";
2
2
  import * as Gio from "@gtkx/gi/gio";
3
- import type * as Gtk from "@gtkx/gi/gtk";
4
3
  import { quitApplication } from "@gtkx/runtime";
5
4
  import { info, installGracefulShutdown } from "@gtkx/utils";
6
5
  import { createServer } from "vite";
6
+ import type { DevRunnerDeps } from "./runner.js";
7
7
  import { startMcpClient, stopMcpClient } from "../mcp/index.js";
8
8
  import { setTestingModuleLoader } from "../mcp/testing-loader.js";
9
9
  import { isRefreshBoundary, performRefresh } from "../refresh-runtime.js";
10
10
  import { gtkxFastRefresh } from "../vite-plugins/fast-refresh/swc-refresh.js";
11
11
  import { gtkxVitePlugins } from "../vite-plugins/index.js";
12
12
  import { gtkxReactDomPrebundle } from "../vite-plugins/react-dom-prebundle.js";
13
- import type { DevRunnerDeps } from "./runner.js";
14
13
 
15
14
  const DEV_MODE = "development";
15
+ const APPLICATION_POLL_INTERVAL_MS = 50;
16
+
17
+ const currentApplicationId = (): string | null => Gio.Application.getDefault()?.applicationId ?? null;
18
+
19
+ const waitForApplicationId = async (timeoutMs: number): Promise<string | null> => {
20
+ const deadline = Date.now() + timeoutMs;
21
+ let applicationId = currentApplicationId();
22
+
23
+ while (applicationId === null && Date.now() < deadline) {
24
+ await new Promise((resolve) => setTimeout(resolve, APPLICATION_POLL_INTERVAL_MS));
25
+ applicationId = currentApplicationId();
26
+ }
27
+
28
+ return applicationId;
29
+ };
16
30
 
17
- export const defaultDevRunnerDeps = (): DevRunnerDeps => ({
31
+ const defaultDevRunnerDeps = (): DevRunnerDeps => ({
18
32
  createServer,
19
- getApplicationId: () => Gio.Application.getDefault()?.applicationId ?? null,
20
- getConfiguredApplicationId: async (root: string) =>
21
- (await loadConfig(root, { mode: DEV_MODE })).config.applicationId,
33
+ waitForApplicationId,
34
+ getConfiguredApplicationId: async (root: string) => {
35
+ const loaded = await loadConfig(root, { mode: DEV_MODE });
36
+
37
+ return loaded.config.applicationId;
38
+ },
22
39
  startMcpClient: (applicationId, loadAppModule) => {
23
40
  setTestingModuleLoader(() => loadAppModule("@gtkx/testing") as Promise<typeof import("@gtkx/testing")>);
41
+
24
42
  return startMcpClient(applicationId);
25
43
  },
26
44
  stopMcpClient,
@@ -32,7 +50,10 @@ export const defaultDevRunnerDeps = (): DevRunnerDeps => ({
32
50
  },
33
51
  quitDefaultApplication: () => {
34
52
  const application = Gio.Application.getDefault();
35
- if (application) quitApplication(application as Gtk.Application);
53
+
54
+ if (application) {
55
+ quitApplication(application);
56
+ }
36
57
  },
37
58
  performRefresh,
38
59
  isRefreshBoundary,
@@ -40,3 +61,5 @@ export const defaultDevRunnerDeps = (): DevRunnerDeps => ({
40
61
  log: info,
41
62
  exit: (code: number): never => process.exit(code),
42
63
  });
64
+
65
+ export { defaultDevRunnerDeps };
@@ -1,5 +1,5 @@
1
- import { resolve } from "node:path";
2
1
  import { error } from "@gtkx/utils";
2
+ import { resolve } from "node:path";
3
3
  import { resolveDataDir } from "../internal/data-dir.js";
4
4
  import { prepareDevIconDir } from "./icon-dir.js";
5
5
  import { createDevRunner } from "./runner.js";
@@ -7,7 +7,7 @@ import { prepareDevSchemaDir } from "./schema-dir.js";
7
7
 
8
8
  const ENTRY_ARG_INDEX = 2;
9
9
 
10
- export const main = async (): Promise<void> => {
10
+ const main = async (): Promise<void> => {
11
11
  if (process.channel) {
12
12
  process.once("disconnect", () => {
13
13
  process.exit(0);
@@ -25,9 +25,10 @@ export const main = async (): Promise<void> => {
25
25
  const dataDir = resolveDataDir(cwd);
26
26
  prepareDevSchemaDir(cwd, dataDir);
27
27
  prepareDevIconDir(cwd, dataDir);
28
-
29
28
  const entryPath = resolve(cwd, entryArg);
30
29
  const { defaultDevRunnerDeps } = await import("./runner-deps.js");
31
30
  const runner = createDevRunner(defaultDevRunnerDeps());
32
31
  await runner.run(entryPath);
33
32
  };
33
+
34
+ export { main };
package/src/dev/runner.ts CHANGED
@@ -1,14 +1,12 @@
1
- import { error } from "@gtkx/utils";
2
1
  import type { InlineConfig, Plugin } from "vite";
3
- import { createRefreshTracker } from "./refresh-tracker.js";
2
+ import { error } from "@gtkx/utils";
3
+ import { createRefreshTracker, type RefreshTracker } from "./refresh-tracker.js";
4
4
  import { RESTART_EXIT_CODE } from "./supervisor.js";
5
5
  import { createDevServerConfig, type DevServer } from "./vite-dev-server.js";
6
6
 
7
- export type { DevServer } from "./vite-dev-server.js";
8
-
9
- export type DevRunnerDeps = {
7
+ type DevRunnerDeps = {
10
8
  createServer(config: InlineConfig): Promise<DevServer>;
11
- getApplicationId(): string | null;
9
+ waitForApplicationId(timeoutMs: number): Promise<string | null>;
12
10
  getConfiguredApplicationId(root: string): Promise<string | undefined>;
13
11
  startMcpClient(
14
12
  applicationId: string,
@@ -18,7 +16,7 @@ export type DevRunnerDeps = {
18
16
  watchApplicationShutdown(onShutdown: () => void): void;
19
17
  installShutdownHandlers(onSignal: () => void | Promise<void>): void;
20
18
  quitDefaultApplication(): void;
21
- performRefresh(): void;
19
+ performRefresh: () => void;
22
20
  isRefreshBoundary(module: Record<string, unknown>): boolean;
23
21
  plugins(): Plugin[];
24
22
  log(message: string): void;
@@ -29,91 +27,149 @@ type DevRunner = {
29
27
  run(entryPath: string): Promise<void>;
30
28
  };
31
29
 
30
+ type ShutdownController = {
31
+ isShuttingDown: () => boolean;
32
+ shutdown: (quitApplication: () => void) => Promise<void>;
33
+ };
34
+
35
+ const APPLICATION_MOUNT_TIMEOUT_MS = 10_000;
36
+
32
37
  const requestRestart = async (server: DevServer, deps: DevRunnerDeps): Promise<never> => {
33
38
  deps.log("Full restart (process restart)");
34
39
  await server.close();
40
+
35
41
  return deps.exit(RESTART_EXIT_CODE);
36
42
  };
37
43
 
38
44
  const handleFileChange = async (server: DevServer, deps: DevRunnerDeps, changedPath: string): Promise<void> => {
39
45
  const module = server.moduleGraph.getModuleById(changedPath);
40
- if (!module) return;
41
46
 
42
- deps.log(`File changed: ${changedPath}`);
47
+ if (!module) {
48
+ return;
49
+ }
43
50
 
51
+ deps.log(`File changed: ${changedPath}`);
44
52
  const loadedExports = module.ssrModule;
53
+
45
54
  if (loadedExports && !deps.isRefreshBoundary(loadedExports)) {
46
55
  await requestRestart(server, deps);
56
+
47
57
  return;
48
58
  }
49
59
 
50
60
  server.moduleGraph.invalidateModule(module);
61
+
51
62
  for (const importer of module.importers) {
52
63
  server.moduleGraph.invalidateModule(importer);
53
64
  }
54
65
 
55
66
  const newMod = await server.ssrLoadModule(changedPath);
67
+
56
68
  if (deps.isRefreshBoundary(newMod)) {
57
69
  deps.log("Running Fast Refresh...");
58
70
  deps.performRefresh();
59
71
  deps.log("Fast Refresh complete");
72
+
60
73
  return;
61
74
  }
62
75
 
63
76
  await requestRestart(server, deps);
64
77
  };
65
78
 
66
- export const createDevRunner = (deps: DevRunnerDeps): DevRunner => ({
67
- async run(entryPath: string): Promise<void> {
68
- const root = process.cwd();
69
- const server = await deps.createServer(createDevServerConfig(root, deps.plugins()));
79
+ const createShutdownController = (server: DevServer, deps: DevRunnerDeps): ShutdownController => {
80
+ let isShuttingDown = false;
70
81
 
71
- const refreshTracker = createRefreshTracker(deps.performRefresh);
72
- const refreshTrackingDeps: DevRunnerDeps = { ...deps, performRefresh: refreshTracker.performRefresh };
82
+ return {
83
+ isShuttingDown: () => isShuttingDown,
84
+ shutdown: async (quitApplication: () => void): Promise<void> => {
85
+ if (isShuttingDown) {
86
+ return;
87
+ }
73
88
 
74
- let isShuttingDown = false;
75
- const shutdown = async (quitApplication: () => void): Promise<void> => {
76
- if (isShuttingDown) return;
77
89
  isShuttingDown = true;
78
90
  quitApplication();
79
91
  deps.stopMcpClient();
80
92
  await server.close();
93
+ },
94
+ };
95
+ };
96
+
97
+ const reloadChangedFile = async (server: DevServer, deps: DevRunnerDeps, changedPath: string): Promise<void> => {
98
+ try {
99
+ await handleFileChange(server, deps, changedPath);
100
+ } catch (error_) {
101
+ error("Hot reload failed:", error_);
102
+ }
103
+ };
104
+
105
+ const onFileChange =
106
+ (server: DevServer, deps: DevRunnerDeps, controller: ShutdownController): ((changedPath: string) => void) =>
107
+ (changedPath) => {
108
+ if (controller.isShuttingDown()) {
109
+ return;
110
+ }
111
+
112
+ void reloadChangedFile(server, deps, changedPath);
81
113
  };
82
114
 
83
- deps.installShutdownHandlers(async () => {
84
- if (isShuttingDown) return;
115
+ const onShutdownSignal =
116
+ (deps: DevRunnerDeps, controller: ShutdownController): (() => Promise<void>) =>
117
+ async () => {
118
+ if (controller.isShuttingDown()) {
119
+ return;
120
+ }
121
+
85
122
  deps.log("Received shutdown signal - stopping dev runner...");
86
- await shutdown(() => deps.quitDefaultApplication());
87
- });
88
123
 
89
- server.watcher.on("change", (changedPath) => {
90
- if (isShuttingDown) return;
91
- handleFileChange(server, refreshTrackingDeps, changedPath).catch((cause) => {
92
- error("Hot reload failed:", cause);
124
+ await controller.shutdown(() => {
125
+ deps.quitDefaultApplication();
93
126
  });
94
- });
127
+ };
95
128
 
96
- deps.log(`Loading entry: ${entryPath}`);
97
- await server.ssrLoadModule(entryPath);
129
+ const closeAndExit = async (deps: DevRunnerDeps, controller: ShutdownController): Promise<never> => {
130
+ try {
131
+ await controller.shutdown((): void => undefined);
132
+ } catch (error_) {
133
+ error("Error closing server:", error_);
134
+
135
+ return deps.exit(1);
136
+ }
137
+
138
+ return deps.exit(0);
139
+ };
140
+
141
+ const onApplicationShutdown =
142
+ (deps: DevRunnerDeps, refreshTracker: RefreshTracker, controller: ShutdownController): (() => void) =>
143
+ () => {
144
+ if (controller.isShuttingDown()) {
145
+ return;
146
+ }
98
147
 
99
- deps.watchApplicationShutdown(() => {
100
- if (isShuttingDown) return;
101
148
  if (refreshTracker.isRefreshing()) {
102
149
  deps.log("Application unmounted during Fast Refresh - restarting dev runner...");
150
+
103
151
  return deps.exit(RESTART_EXIT_CODE);
104
152
  }
153
+
105
154
  deps.log("Application quit - stopping dev runner...");
106
- shutdown(() => {}).then(
107
- () => deps.exit(0),
108
- (cause: unknown) => {
109
- error("Error closing server:", cause);
110
- return deps.exit(1);
111
- },
112
- );
113
- });
114
-
115
- const liveApplicationId = deps.getApplicationId();
155
+ void closeAndExit(deps, controller);
156
+ };
157
+
158
+ const createDevRunner = (deps: DevRunnerDeps): DevRunner => ({
159
+ async run(entryPath: string): Promise<void> {
160
+ const root = process.cwd();
161
+ const server = await deps.createServer(createDevServerConfig(root, deps.plugins()));
162
+ const refreshTracker = createRefreshTracker(deps.performRefresh);
163
+ const refreshTrackingDeps: DevRunnerDeps = { ...deps, performRefresh: refreshTracker.performRefresh };
164
+ const controller = createShutdownController(server, deps);
165
+ deps.installShutdownHandlers(onShutdownSignal(deps, controller));
166
+ server.watcher.on("change", onFileChange(server, refreshTrackingDeps, controller));
167
+ deps.log(`Loading entry: ${entryPath}`);
168
+ await server.ssrLoadModule(entryPath);
169
+ const liveApplicationId = await deps.waitForApplicationId(APPLICATION_MOUNT_TIMEOUT_MS);
170
+
116
171
  if (liveApplicationId) {
172
+ deps.watchApplicationShutdown(onApplicationShutdown(deps, refreshTracker, controller));
117
173
  const applicationId = (await deps.getConfiguredApplicationId(root)) ?? liveApplicationId;
118
174
  deps.log(`Connected application ID: ${applicationId}`);
119
175
  await deps.startMcpClient(applicationId, (id) => server.ssrLoadModule(id));
@@ -124,3 +180,6 @@ export const createDevRunner = (deps: DevRunnerDeps): DevRunner => ({
124
180
  deps.log("HMR enabled - watching for changes...");
125
181
  },
126
182
  });
183
+
184
+ export type { DevServer } from "./vite-dev-server.js";
185
+ export { createDevRunner, type DevRunnerDeps };
@@ -1,11 +1,16 @@
1
1
  import { prependSchemaDir, stageAndCompileProjectSchemas } from "../settings/schema.js";
2
2
 
3
- export const prepareDevSchemaDir = (root: string, dataDir: string | null): string | null => {
3
+ const prepareDevSchemaDir = (root: string, dataDir: string | null): string | null => {
4
4
  const dir = stageAndCompileProjectSchemas(root, dataDir);
5
- if (dir === null) return null;
5
+
6
+ if (dir === null) {
7
+ return null;
8
+ }
6
9
 
7
10
  process.env.GTKX_DEV_SCHEMA_DIR = dir;
8
11
  process.env.GSETTINGS_SCHEMA_DIR = prependSchemaDir(dir, process.env.GSETTINGS_SCHEMA_DIR);
9
12
 
10
13
  return dir;
11
14
  };
15
+
16
+ export { prepareDevSchemaDir };