@gtkx/cli 0.21.0 → 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 (358) hide show
  1. package/README.md +173 -0
  2. package/bin/gtkx-dev-runner.js +9 -0
  3. package/dist/builder.d.ts +5 -52
  4. package/dist/builder.d.ts.map +1 -1
  5. package/dist/builder.js +24 -57
  6. package/dist/builder.js.map +1 -1
  7. package/dist/cli.d.ts +1 -2
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +24 -122
  10. package/dist/cli.js.map +1 -1
  11. package/dist/codegen/freshness.d.ts +11 -0
  12. package/dist/codegen/freshness.d.ts.map +1 -0
  13. package/dist/codegen/freshness.js +45 -0
  14. package/dist/codegen/freshness.js.map +1 -0
  15. package/dist/codegen/report.d.ts +4 -0
  16. package/dist/codegen/report.d.ts.map +1 -0
  17. package/dist/codegen/report.js +18 -0
  18. package/dist/codegen/report.js.map +1 -0
  19. package/dist/codegen/run-codegen.d.ts +35 -0
  20. package/dist/codegen/run-codegen.d.ts.map +1 -0
  21. package/dist/codegen/run-codegen.js +162 -0
  22. package/dist/codegen/run-codegen.js.map +1 -0
  23. package/dist/codegen/store-resolver.d.ts +24 -0
  24. package/dist/codegen/store-resolver.d.ts.map +1 -0
  25. package/dist/codegen/store-resolver.js +72 -0
  26. package/dist/codegen/store-resolver.js.map +1 -0
  27. package/dist/commands/build.d.ts +10 -0
  28. package/dist/commands/build.d.ts.map +1 -0
  29. package/dist/commands/build.js +34 -0
  30. package/dist/commands/build.js.map +1 -0
  31. package/dist/commands/codegen.d.ts +10 -0
  32. package/dist/commands/codegen.d.ts.map +1 -0
  33. package/dist/commands/codegen.js +42 -0
  34. package/dist/commands/codegen.js.map +1 -0
  35. package/dist/commands/dev.d.ts +6 -0
  36. package/dist/commands/dev.d.ts.map +1 -0
  37. package/dist/commands/dev.js +22 -0
  38. package/dist/commands/dev.js.map +1 -0
  39. package/dist/commands/docs.d.ts +20 -0
  40. package/dist/commands/docs.d.ts.map +1 -0
  41. package/dist/commands/docs.js +74 -0
  42. package/dist/commands/docs.js.map +1 -0
  43. package/dist/dev/icon-dir.d.ts +3 -0
  44. package/dist/dev/icon-dir.d.ts.map +1 -0
  45. package/dist/dev/icon-dir.js +16 -0
  46. package/dist/dev/icon-dir.js.map +1 -0
  47. package/dist/dev/refresh-tracker.d.ts +7 -0
  48. package/dist/dev/refresh-tracker.d.ts.map +1 -0
  49. package/dist/dev/refresh-tracker.js +19 -0
  50. package/dist/dev/refresh-tracker.js.map +1 -0
  51. package/dist/dev/runner-deps.d.ts +4 -0
  52. package/dist/dev/runner-deps.d.ts.map +1 -0
  53. package/dist/dev/runner-deps.js +55 -0
  54. package/dist/dev/runner-deps.js.map +1 -0
  55. package/dist/dev/runner-main.d.ts +3 -0
  56. package/dist/dev/runner-main.d.ts.map +1 -0
  57. package/dist/dev/runner-main.js +29 -0
  58. package/dist/dev/runner-main.js.map +1 -0
  59. package/dist/dev/runner.d.ts +24 -0
  60. package/dist/dev/runner.d.ts.map +1 -0
  61. package/dist/dev/runner.js +119 -0
  62. package/dist/dev/runner.js.map +1 -0
  63. package/dist/dev/schema-dir.d.ts +3 -0
  64. package/dist/dev/schema-dir.d.ts.map +1 -0
  65. package/dist/dev/schema-dir.js +12 -0
  66. package/dist/dev/schema-dir.js.map +1 -0
  67. package/dist/dev/supervisor.d.ts +18 -0
  68. package/dist/dev/supervisor.d.ts.map +1 -0
  69. package/dist/dev/supervisor.js +182 -0
  70. package/dist/dev/supervisor.js.map +1 -0
  71. package/dist/dev/vite-dev-server.d.ts +21 -0
  72. package/dist/dev/vite-dev-server.d.ts.map +1 -0
  73. package/dist/dev/vite-dev-server.js +13 -0
  74. package/dist/dev/vite-dev-server.js.map +1 -0
  75. package/dist/internal/banner.d.ts +4 -0
  76. package/dist/internal/banner.d.ts.map +1 -0
  77. package/dist/internal/banner.js +9 -0
  78. package/dist/internal/banner.js.map +1 -0
  79. package/dist/internal/data-dir.d.ts +4 -0
  80. package/dist/internal/data-dir.d.ts.map +1 -0
  81. package/dist/internal/data-dir.js +52 -0
  82. package/dist/internal/data-dir.js.map +1 -0
  83. package/dist/internal/entry-arg.d.ts +20 -0
  84. package/dist/internal/entry-arg.d.ts.map +1 -0
  85. package/dist/internal/entry-arg.js +36 -0
  86. package/dist/internal/entry-arg.js.map +1 -0
  87. package/dist/internal/errors.d.ts +5 -0
  88. package/dist/internal/errors.d.ts.map +1 -0
  89. package/dist/internal/errors.js +29 -0
  90. package/dist/internal/errors.js.map +1 -0
  91. package/dist/internal/list-files.d.ts +7 -0
  92. package/dist/internal/list-files.d.ts.map +1 -0
  93. package/dist/internal/list-files.js +15 -0
  94. package/dist/internal/list-files.js.map +1 -0
  95. package/dist/internal/resolve-cli-tool.d.ts +3 -0
  96. package/dist/internal/resolve-cli-tool.d.ts.map +1 -0
  97. package/dist/internal/resolve-cli-tool.js +27 -0
  98. package/dist/internal/resolve-cli-tool.js.map +1 -0
  99. package/dist/internal/staging-dir.d.ts +4 -0
  100. package/dist/internal/staging-dir.d.ts.map +1 -0
  101. package/dist/internal/staging-dir.js +17 -0
  102. package/dist/internal/staging-dir.js.map +1 -0
  103. package/dist/internal/xdg-data-dirs.d.ts +3 -0
  104. package/dist/internal/xdg-data-dirs.d.ts.map +1 -0
  105. package/dist/internal/xdg-data-dirs.js +10 -0
  106. package/dist/internal/xdg-data-dirs.js.map +1 -0
  107. package/dist/mcp/client.d.ts +28 -0
  108. package/dist/mcp/client.d.ts.map +1 -0
  109. package/dist/mcp/client.js +182 -0
  110. package/dist/mcp/client.js.map +1 -0
  111. package/dist/mcp/handlers.d.ts +9 -0
  112. package/dist/mcp/handlers.d.ts.map +1 -0
  113. package/dist/mcp/handlers.js +147 -0
  114. package/dist/mcp/handlers.js.map +1 -0
  115. package/dist/mcp/index.d.ts +4 -0
  116. package/dist/mcp/index.d.ts.map +1 -0
  117. package/dist/mcp/index.js +34 -0
  118. package/dist/mcp/index.js.map +1 -0
  119. package/dist/mcp/serialize-widget.d.ts +10 -0
  120. package/dist/mcp/serialize-widget.d.ts.map +1 -0
  121. package/dist/mcp/serialize-widget.js +23 -0
  122. package/dist/mcp/serialize-widget.js.map +1 -0
  123. package/dist/mcp/testing-loader.d.ts +5 -0
  124. package/dist/mcp/testing-loader.d.ts.map +1 -0
  125. package/dist/mcp/testing-loader.js +47 -0
  126. package/dist/mcp/testing-loader.js.map +1 -0
  127. package/dist/mcp/widget-registry.d.ts +14 -0
  128. package/dist/mcp/widget-registry.d.ts.map +1 -0
  129. package/dist/mcp/widget-registry.js +39 -0
  130. package/dist/mcp/widget-registry.js.map +1 -0
  131. package/dist/refresh-globals.d.ts +2 -0
  132. package/dist/refresh-globals.d.ts.map +1 -0
  133. package/dist/refresh-globals.js +8 -0
  134. package/dist/refresh-globals.js.map +1 -0
  135. package/dist/refresh-runtime.d.ts +10 -26
  136. package/dist/refresh-runtime.d.ts.map +1 -1
  137. package/dist/refresh-runtime.js +26 -48
  138. package/dist/refresh-runtime.js.map +1 -1
  139. package/dist/settings/compile.d.ts +3 -0
  140. package/dist/settings/compile.d.ts.map +1 -0
  141. package/dist/settings/compile.js +21 -0
  142. package/dist/settings/compile.js.map +1 -0
  143. package/dist/settings/parser.d.ts +24 -0
  144. package/dist/settings/parser.d.ts.map +1 -0
  145. package/dist/settings/parser.js +121 -0
  146. package/dist/settings/parser.js.map +1 -0
  147. package/dist/settings/render.d.ts +5 -0
  148. package/dist/settings/render.d.ts.map +1 -0
  149. package/dist/settings/render.js +122 -0
  150. package/dist/settings/render.js.map +1 -0
  151. package/dist/settings/schema.d.ts +13 -0
  152. package/dist/settings/schema.d.ts.map +1 -0
  153. package/dist/settings/schema.js +121 -0
  154. package/dist/settings/schema.js.map +1 -0
  155. package/dist/vite-plugins/asset-extensions.d.ts +5 -0
  156. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -0
  157. package/dist/vite-plugins/asset-extensions.js +28 -0
  158. package/dist/vite-plugins/asset-extensions.js.map +1 -0
  159. package/dist/vite-plugins/built-url.d.ts +4 -0
  160. package/dist/vite-plugins/built-url.d.ts.map +1 -0
  161. package/dist/vite-plugins/built-url.js +36 -0
  162. package/dist/vite-plugins/built-url.js.map +1 -0
  163. package/dist/vite-plugins/css.d.ts +4 -0
  164. package/dist/vite-plugins/css.d.ts.map +1 -0
  165. package/dist/vite-plugins/css.js +38 -0
  166. package/dist/vite-plugins/css.js.map +1 -0
  167. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +8 -0
  168. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -0
  169. package/dist/vite-plugins/fast-refresh/refresh-filter.js +19 -0
  170. package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -0
  171. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +6 -0
  172. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -0
  173. package/dist/vite-plugins/fast-refresh/swc-refresh.js +70 -0
  174. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -0
  175. package/dist/vite-plugins/icons.d.ts +4 -0
  176. package/dist/vite-plugins/icons.d.ts.map +1 -0
  177. package/dist/vite-plugins/icons.js +51 -0
  178. package/dist/vite-plugins/icons.js.map +1 -0
  179. package/dist/vite-plugins/index.d.ts +4 -0
  180. package/dist/vite-plugins/index.d.ts.map +1 -0
  181. package/dist/vite-plugins/index.js +22 -0
  182. package/dist/vite-plugins/index.js.map +1 -0
  183. package/dist/vite-plugins/native.d.ts +4 -0
  184. package/dist/vite-plugins/native.d.ts.map +1 -0
  185. package/dist/vite-plugins/native.js +62 -0
  186. package/dist/vite-plugins/native.js.map +1 -0
  187. package/dist/vite-plugins/react-compiler.d.ts +5 -0
  188. package/dist/vite-plugins/react-compiler.d.ts.map +1 -0
  189. package/dist/vite-plugins/react-compiler.js +62 -0
  190. package/dist/vite-plugins/react-compiler.js.map +1 -0
  191. package/dist/vite-plugins/react-dom-prebundle.d.ts +4 -0
  192. package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -0
  193. package/dist/vite-plugins/react-dom-prebundle.js +12 -0
  194. package/dist/vite-plugins/react-dom-prebundle.js.map +1 -0
  195. package/dist/vite-plugins/resource-init-module.d.ts +6 -0
  196. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -0
  197. package/dist/vite-plugins/resource-init-module.js +51 -0
  198. package/dist/vite-plugins/resource-init-module.js.map +1 -0
  199. package/dist/vite-plugins/resource-shared.d.ts +8 -0
  200. package/dist/vite-plugins/resource-shared.d.ts.map +1 -0
  201. package/dist/vite-plugins/resource-shared.js +28 -0
  202. package/dist/vite-plugins/resource-shared.js.map +1 -0
  203. package/dist/vite-plugins/resources.d.ts +5 -0
  204. package/dist/vite-plugins/resources.d.ts.map +1 -0
  205. package/dist/vite-plugins/resources.js +260 -0
  206. package/dist/vite-plugins/resources.js.map +1 -0
  207. package/dist/vite-plugins/settings-worker-env.d.ts +4 -0
  208. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -0
  209. package/dist/vite-plugins/settings-worker-env.js +23 -0
  210. package/dist/vite-plugins/settings-worker-env.js.map +1 -0
  211. package/dist/vite-plugins/settings.d.ts +4 -0
  212. package/dist/vite-plugins/settings.d.ts.map +1 -0
  213. package/dist/vite-plugins/settings.js +214 -0
  214. package/dist/vite-plugins/settings.js.map +1 -0
  215. package/dist/vite-plugins/strip-query.d.ts +3 -0
  216. package/dist/vite-plugins/strip-query.d.ts.map +1 -0
  217. package/dist/vite-plugins/strip-query.js +6 -0
  218. package/dist/vite-plugins/strip-query.js.map +1 -0
  219. package/dist/vite-plugins/undeclared-library.d.ts +4 -0
  220. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -0
  221. package/dist/vite-plugins/undeclared-library.js +50 -0
  222. package/dist/vite-plugins/undeclared-library.js.map +1 -0
  223. package/dist/vite-plugins/virtual-module.d.ts +22 -0
  224. package/dist/vite-plugins/virtual-module.d.ts.map +1 -0
  225. package/dist/vite-plugins/virtual-module.js +20 -0
  226. package/dist/vite-plugins/virtual-module.js.map +1 -0
  227. package/dist/vitest-plugin.d.ts +10 -0
  228. package/dist/vitest-plugin.d.ts.map +1 -0
  229. package/dist/vitest-plugin.js +12 -0
  230. package/dist/vitest-plugin.js.map +1 -0
  231. package/env.d.ts +91 -8
  232. package/package.json +30 -38
  233. package/src/babel-modules.d.ts +11 -0
  234. package/src/builder.ts +31 -86
  235. package/src/cli.ts +42 -0
  236. package/src/codegen/freshness.ts +65 -0
  237. package/src/codegen/report.ts +28 -0
  238. package/src/codegen/run-codegen.ts +260 -0
  239. package/src/codegen/store-resolver.ts +116 -0
  240. package/src/commands/build.ts +38 -0
  241. package/src/commands/codegen.ts +49 -0
  242. package/src/commands/dev.ts +24 -0
  243. package/src/commands/docs.ts +95 -0
  244. package/src/dev/icon-dir.ts +21 -0
  245. package/src/dev/refresh-tracker.ts +25 -0
  246. package/src/dev/runner-deps.ts +65 -0
  247. package/src/dev/runner-main.ts +34 -0
  248. package/src/dev/runner.ts +185 -0
  249. package/src/dev/schema-dir.ts +16 -0
  250. package/src/dev/supervisor.ts +276 -0
  251. package/src/dev/vite-dev-server.ts +36 -0
  252. package/src/internal/banner.ts +13 -0
  253. package/src/internal/data-dir.ts +70 -0
  254. package/src/internal/entry-arg.ts +46 -0
  255. package/src/internal/errors.ts +36 -0
  256. package/src/internal/list-files.ts +23 -0
  257. package/src/internal/resolve-cli-tool.ts +37 -0
  258. package/src/internal/staging-dir.ts +19 -0
  259. package/src/internal/xdg-data-dirs.ts +13 -0
  260. package/src/mcp/client.ts +235 -0
  261. package/src/mcp/handlers.ts +213 -0
  262. package/src/mcp/index.ts +46 -0
  263. package/src/mcp/serialize-widget.ts +41 -0
  264. package/src/mcp/testing-loader.ts +73 -0
  265. package/src/mcp/widget-registry.ts +49 -0
  266. package/src/refresh-globals.ts +10 -0
  267. package/src/refresh-runtime.ts +30 -55
  268. package/src/settings/compile.ts +22 -0
  269. package/src/settings/parser.ts +193 -0
  270. package/src/settings/render.ts +167 -0
  271. package/src/settings/schema.ts +169 -0
  272. package/src/vite-plugins/asset-extensions.ts +29 -0
  273. package/src/vite-plugins/built-url.ts +50 -0
  274. package/src/vite-plugins/css.ts +53 -0
  275. package/src/vite-plugins/fast-refresh/refresh-filter.ts +26 -0
  276. package/src/vite-plugins/fast-refresh/swc-refresh.ts +92 -0
  277. package/src/vite-plugins/icons.ts +74 -0
  278. package/src/vite-plugins/index.ts +25 -0
  279. package/src/vite-plugins/native.ts +83 -0
  280. package/src/vite-plugins/react-compiler.ts +84 -0
  281. package/src/vite-plugins/react-dom-prebundle.ts +17 -0
  282. package/src/vite-plugins/resource-init-module.ts +57 -0
  283. package/src/vite-plugins/resource-shared.ts +40 -0
  284. package/src/vite-plugins/resources.ts +366 -0
  285. package/src/vite-plugins/settings-worker-env.ts +30 -0
  286. package/src/vite-plugins/settings.ts +286 -0
  287. package/src/vite-plugins/strip-query.ts +7 -0
  288. package/src/vite-plugins/undeclared-library.ts +78 -0
  289. package/src/vite-plugins/virtual-module.ts +44 -0
  290. package/src/vitest-plugin.ts +13 -0
  291. package/dist/create.d.ts +0 -55
  292. package/dist/create.d.ts.map +0 -1
  293. package/dist/create.js +0 -236
  294. package/dist/create.js.map +0 -1
  295. package/dist/dev-server.d.ts +0 -37
  296. package/dist/dev-server.d.ts.map +0 -1
  297. package/dist/dev-server.js +0 -130
  298. package/dist/dev-server.js.map +0 -1
  299. package/dist/index.d.ts +0 -4
  300. package/dist/index.d.ts.map +0 -1
  301. package/dist/index.js +0 -4
  302. package/dist/index.js.map +0 -1
  303. package/dist/mcp-client.d.ts +0 -31
  304. package/dist/mcp-client.d.ts.map +0 -1
  305. package/dist/mcp-client.js +0 -430
  306. package/dist/mcp-client.js.map +0 -1
  307. package/dist/templates.d.ts +0 -9
  308. package/dist/templates.d.ts.map +0 -1
  309. package/dist/templates.js +0 -16
  310. package/dist/templates.js.map +0 -1
  311. package/dist/vite-plugin-gtkx-assets.d.ts +0 -20
  312. package/dist/vite-plugin-gtkx-assets.d.ts.map +0 -1
  313. package/dist/vite-plugin-gtkx-assets.js +0 -57
  314. package/dist/vite-plugin-gtkx-assets.js.map +0 -1
  315. package/dist/vite-plugin-gtkx-built-url.d.ts +0 -18
  316. package/dist/vite-plugin-gtkx-built-url.d.ts.map +0 -1
  317. package/dist/vite-plugin-gtkx-built-url.js +0 -43
  318. package/dist/vite-plugin-gtkx-built-url.js.map +0 -1
  319. package/dist/vite-plugin-gtkx-gsettings.d.ts +0 -28
  320. package/dist/vite-plugin-gtkx-gsettings.d.ts.map +0 -1
  321. package/dist/vite-plugin-gtkx-gsettings.js +0 -147
  322. package/dist/vite-plugin-gtkx-gsettings.js.map +0 -1
  323. package/dist/vite-plugin-gtkx-native.d.ts +0 -14
  324. package/dist/vite-plugin-gtkx-native.d.ts.map +0 -1
  325. package/dist/vite-plugin-gtkx-native.js +0 -53
  326. package/dist/vite-plugin-gtkx-native.js.map +0 -1
  327. package/dist/vite-plugin-gtkx-refresh.d.ts +0 -8
  328. package/dist/vite-plugin-gtkx-refresh.d.ts.map +0 -1
  329. package/dist/vite-plugin-gtkx-refresh.js +0 -37
  330. package/dist/vite-plugin-gtkx-refresh.js.map +0 -1
  331. package/dist/vite-plugin-swc-ssr-refresh.d.ts +0 -8
  332. package/dist/vite-plugin-swc-ssr-refresh.d.ts.map +0 -1
  333. package/dist/vite-plugin-swc-ssr-refresh.js +0 -46
  334. package/dist/vite-plugin-swc-ssr-refresh.js.map +0 -1
  335. package/src/cli.tsx +0 -154
  336. package/src/create.ts +0 -326
  337. package/src/dev-server.tsx +0 -162
  338. package/src/index.ts +0 -3
  339. package/src/mcp-client.ts +0 -518
  340. package/src/templates.ts +0 -26
  341. package/src/vite-plugin-gtkx-assets.ts +0 -69
  342. package/src/vite-plugin-gtkx-built-url.ts +0 -48
  343. package/src/vite-plugin-gtkx-gsettings.ts +0 -168
  344. package/src/vite-plugin-gtkx-native.ts +0 -64
  345. package/src/vite-plugin-gtkx-refresh.ts +0 -54
  346. package/src/vite-plugin-swc-ssr-refresh.ts +0 -61
  347. package/templates/claude/EXAMPLES.md.ejs +0 -744
  348. package/templates/claude/SKILL.md.ejs +0 -93
  349. package/templates/claude/WIDGETS.md.ejs +0 -820
  350. package/templates/config/vitest.config.ts.ejs +0 -11
  351. package/templates/gitignore.ejs +0 -4
  352. package/templates/package.json.ejs +0 -16
  353. package/templates/src/app.tsx.ejs +0 -32
  354. package/templates/src/dev.tsx.ejs +0 -5
  355. package/templates/src/gtkx-env.d.ts.ejs +0 -1
  356. package/templates/src/index.tsx.ejs +0 -5
  357. package/templates/tests/app.test.tsx.ejs +0 -16
  358. package/templates/tsconfig.json.ejs +0 -14
@@ -1,22 +1,16 @@
1
1
  import RefreshRuntime from "react-refresh/runtime";
2
+ import "./refresh-globals.js";
2
3
 
3
4
  type ComponentType = (...args: unknown[]) => unknown;
4
5
 
5
- RefreshRuntime.injectIntoGlobalHook(globalThis);
6
- globalThis.$RefreshReg$ = () => {};
7
- globalThis.$RefreshSig$ = () => (type: unknown) => type;
8
-
9
6
  /**
10
- * Creates registration functions for a module's React components.
11
- *
12
- * Used internally by the Vite plugin to register components
13
- * for React Fast Refresh.
7
+ * Builds the per-module `$RefreshReg$` and `$RefreshSig$` hooks that React Refresh
8
+ * transformed code expects, scoping every registered component to the given module.
14
9
  *
15
- * @param moduleId - Unique identifier for the module
16
- * @returns Registration functions for the module
17
- * @internal
10
+ * @param moduleId Identifier used to namespace registered component types so they are unique across modules.
11
+ * @returns An object with `$RefreshReg$` and `$RefreshSig$` to install as module-local globals.
18
12
  */
19
- export function createModuleRegistration(moduleId: string): {
13
+ function createModuleRegistration(moduleId: string): {
20
14
  $RefreshReg$: (type: ComponentType, id: string) => void;
21
15
  $RefreshSig$: typeof RefreshRuntime.createSignatureFunctionForTransform;
22
16
  } {
@@ -28,62 +22,43 @@ export function createModuleRegistration(moduleId: string): {
28
22
  };
29
23
  }
30
24
 
31
- function isLikelyComponentType(value: unknown): boolean {
32
- if (typeof value !== "function") {
33
- return false;
34
- }
35
-
36
- const func = value as { $$typeof?: symbol };
37
-
38
- if (func.$$typeof === Symbol.for("react.memo") || func.$$typeof === Symbol.for("react.forward_ref")) {
39
- return true;
40
- }
41
-
42
- const name = (value as { name?: string }).name;
43
- if (typeof name === "string" && /^[A-Z]/.test(name)) {
44
- return true;
45
- }
46
-
47
- return false;
48
- }
49
-
50
25
  /**
51
- * Checks if a module's exports form a React Refresh boundary.
52
- *
53
- * A module is a refresh boundary if all its exports are React components,
54
- * allowing for fast refresh without full page reload.
26
+ * Determines whether a module can act as a React Refresh boundary, meaning every one of
27
+ * its exports (ignoring `__esModule`) looks like a React component type.
55
28
  *
56
- * @param moduleExports - The module's exports object
57
- * @returns `true` if the module can be fast-refreshed
58
- * @internal
29
+ * @param moduleExports The module's export object to inspect.
30
+ * @returns `true` when the module qualifies as a refresh boundary, `false` otherwise.
59
31
  */
60
- export function isReactRefreshBoundary(moduleExports: Record<string, unknown>): boolean {
61
- if (RefreshRuntime.isLikelyComponentType(moduleExports)) {
62
- return true;
63
- }
32
+ const isComponentExport = (key: string, value: unknown): boolean =>
33
+ key === "__esModule" || RefreshRuntime.isLikelyComponentType(value);
64
34
 
35
+ const areAllExportsComponents = (moduleExports: Record<string, unknown>): boolean => {
65
36
  for (const key in moduleExports) {
66
- if (key === "__esModule") {
67
- continue;
37
+ if (!isComponentExport(key, moduleExports[key])) {
38
+ return false;
68
39
  }
40
+ }
69
41
 
70
- const value = moduleExports[key];
42
+ return true;
43
+ };
71
44
 
72
- if (!isLikelyComponentType(value)) {
73
- return false;
74
- }
45
+ function isRefreshBoundary(moduleExports: Record<string, unknown>): boolean {
46
+ if (RefreshRuntime.isLikelyComponentType(moduleExports)) {
47
+ return true;
48
+ }
49
+
50
+ if (!areAllExportsComponents(moduleExports)) {
51
+ return false;
75
52
  }
76
53
 
77
- return Object.keys(moduleExports).filter((k) => k !== "__esModule").length > 0;
54
+ return Object.keys(moduleExports).some((k) => k !== "__esModule");
78
55
  }
79
56
 
80
57
  /**
81
- * Triggers React Fast Refresh to re-render components.
82
- *
83
- * Called after module updates when all exports are React components.
84
- *
85
- * @internal
58
+ * Applies all pending React Refresh updates, re-rendering components whose modules have changed.
86
59
  */
87
- export function performRefresh(): void {
60
+ function performRefresh(): void {
88
61
  RefreshRuntime.performReactRefresh();
89
62
  }
63
+
64
+ export { createModuleRegistration, isRefreshBoundary, performRefresh };
@@ -0,0 +1,22 @@
1
+ import { formatChildProcessError } from "@gtkx/utils";
2
+ import { execFileSync } from "node:child_process";
3
+ import { resolveCliTool } from "../internal/resolve-cli-tool.js";
4
+
5
+ const SCHEMA_COMPILER = "glib-compile-schemas";
6
+ const SCHEMA_COMPILE_TIMEOUT_MS = 30_000;
7
+
8
+ const compileSchemas = (dir: string): void => {
9
+ try {
10
+ execFileSync(resolveCliTool(SCHEMA_COMPILER), ["--strict", dir], {
11
+ stdio: ["ignore", "pipe", "pipe"],
12
+ timeout: SCHEMA_COMPILE_TIMEOUT_MS,
13
+ encoding: "utf8",
14
+ });
15
+ } catch (error) {
16
+ const details = formatChildProcessError(error);
17
+ const suffix = details ? `:\n${details}` : "";
18
+ throw new Error(`glib-compile-schemas failed for ${dir}${suffix}`, { cause: error });
19
+ }
20
+ };
21
+
22
+ export { compileSchemas };
@@ -0,0 +1,193 @@
1
+ import { XMLParser } from "fast-xml-parser";
2
+
3
+ type ParsedKey = {
4
+ name: string;
5
+ variantType: string | null;
6
+ enumId: string | null;
7
+ flagsId: string | null;
8
+ choices: string[];
9
+ summary: string | null;
10
+ };
11
+
12
+ type ParsedSchema = {
13
+ id: string;
14
+ path: string | null;
15
+ keys: ParsedKey[];
16
+ };
17
+
18
+ type ParsedSchemaFile = {
19
+ fileName: string;
20
+ schemas: ParsedSchema[];
21
+ enums: Map<string, string[]>;
22
+ flags: Map<string, string[]>;
23
+ };
24
+
25
+ type RawNode = Record<string, unknown>;
26
+
27
+ type RawSchema = {
28
+ id: string;
29
+ path: string | null;
30
+ extendsId: string | null;
31
+ keys: ParsedKey[];
32
+ };
33
+
34
+ type MergeContext = {
35
+ byId: Map<string, RawSchema>;
36
+ merged: Map<string, ParsedKey>;
37
+ visited: Set<string>;
38
+ };
39
+
40
+ const MULTI_TAGS: Set<string> = new Set(["schema", "key", "enum", "flags", "value", "choice"]);
41
+
42
+ const PARSER = new XMLParser({
43
+ ignoreAttributes: false,
44
+ attributeNamePrefix: "@_",
45
+ parseAttributeValue: false,
46
+ parseTagValue: false,
47
+ trimValues: true,
48
+ isArray: (name) => MULTI_TAGS.has(name),
49
+ });
50
+
51
+ const isRawNode = (value: unknown): value is RawNode => typeof value === "object" && value !== null;
52
+
53
+ const attr = (node: RawNode, name: string): string | null => {
54
+ const value = node[`@_${name}`];
55
+
56
+ return typeof value === "string" ? value : null;
57
+ };
58
+
59
+ const text = (node: RawNode, name: string): string | null => {
60
+ const value = node[name];
61
+
62
+ return typeof value === "string" && value.length > 0 ? value : null;
63
+ };
64
+
65
+ const children = (node: RawNode, name: string): RawNode[] => {
66
+ const value = node[name];
67
+
68
+ if (!Array.isArray(value)) {
69
+ return [];
70
+ }
71
+
72
+ return value.filter(isRawNode);
73
+ };
74
+
75
+ const parseNicks = (definition: RawNode): string[] =>
76
+ children(definition, "value")
77
+ .map((value) => attr(value, "nick"))
78
+ .filter((nick): nick is string => nick !== null);
79
+
80
+ const parseDefinitions = (schemalist: RawNode, tag: string): Map<string, string[]> => {
81
+ const definitions: Map<string, string[]> = new Map();
82
+
83
+ for (const definition of children(schemalist, tag)) {
84
+ const id = attr(definition, "id");
85
+
86
+ if (id !== null) {
87
+ definitions.set(id, parseNicks(definition));
88
+ }
89
+ }
90
+
91
+ return definitions;
92
+ };
93
+
94
+ const parseChoices = (key: RawNode): string[] => {
95
+ const choices = key.choices;
96
+
97
+ if (!isRawNode(choices)) {
98
+ return [];
99
+ }
100
+
101
+ return children(choices, "choice")
102
+ .map((choice) => attr(choice, "value"))
103
+ .filter((value): value is string => value !== null);
104
+ };
105
+
106
+ const parseKey = (key: RawNode, fileName: string): ParsedKey => {
107
+ const name = attr(key, "name");
108
+
109
+ if (name === null) {
110
+ throw new SchemaParseError(`A <key> in ${fileName} has no name attribute`);
111
+ }
112
+
113
+ return {
114
+ name,
115
+ variantType: attr(key, "type"),
116
+ enumId: attr(key, "enum"),
117
+ flagsId: attr(key, "flags"),
118
+ choices: parseChoices(key),
119
+ summary: text(key, "summary"),
120
+ };
121
+ };
122
+
123
+ const parseRawSchema = (schema: RawNode, fileName: string): RawSchema => {
124
+ const id = attr(schema, "id");
125
+
126
+ if (id === null) {
127
+ throw new SchemaParseError(`A <schema> in ${fileName} has no id attribute`);
128
+ }
129
+
130
+ return {
131
+ id,
132
+ path: attr(schema, "path"),
133
+ extendsId: attr(schema, "extends"),
134
+ keys: children(schema, "key").map((key) => parseKey(key, fileName)),
135
+ };
136
+ };
137
+
138
+ const collectInheritedKeys = (context: MergeContext, current: RawSchema): void => {
139
+ if (context.visited.has(current.id)) {
140
+ return;
141
+ }
142
+
143
+ context.visited.add(current.id);
144
+ const parent = current.extendsId === null ? undefined : context.byId.get(current.extendsId);
145
+
146
+ if (parent !== undefined) {
147
+ collectInheritedKeys(context, parent);
148
+ }
149
+
150
+ for (const key of current.keys) {
151
+ context.merged.set(key.name, key);
152
+ }
153
+ };
154
+
155
+ const mergeInheritedKeys = (schema: RawSchema, byId: Map<string, RawSchema>): ParsedKey[] => {
156
+ const context: MergeContext = { byId, merged: new Map(), visited: new Set() };
157
+ collectInheritedKeys(context, schema);
158
+
159
+ return context.merged.values().toArray();
160
+ };
161
+
162
+ const parseSchemaXml = (xml: string, fileName: string): ParsedSchemaFile => {
163
+ let document: unknown;
164
+
165
+ try {
166
+ document = PARSER.parse(xml);
167
+ } catch (error) {
168
+ throw new SchemaParseError(`Failed to parse ${fileName} as XML: ${String(error)}`, { cause: error });
169
+ }
170
+
171
+ if (!isRawNode(document) || !("schemalist" in document)) {
172
+ throw new SchemaParseError(`${fileName} has no <schemalist> root element`);
173
+ }
174
+
175
+ const schemalist = isRawNode(document.schemalist) ? document.schemalist : {};
176
+ const rawSchemas = children(schemalist, "schema").map((schema) => parseRawSchema(schema, fileName));
177
+ const byId = new Map(rawSchemas.map((schema) => [schema.id, schema]));
178
+
179
+ return {
180
+ fileName,
181
+ schemas: rawSchemas.map((schema) => ({
182
+ id: schema.id,
183
+ path: schema.path,
184
+ keys: mergeInheritedKeys(schema, byId),
185
+ })),
186
+ enums: parseDefinitions(schemalist, "enum"),
187
+ flags: parseDefinitions(schemalist, "flags"),
188
+ };
189
+ };
190
+
191
+ class SchemaParseError extends Error {}
192
+
193
+ export { parseSchemaXml, SchemaParseError, type ParsedKey, type ParsedSchema, type ParsedSchemaFile };
@@ -0,0 +1,167 @@
1
+ import { upperFirst } from "@gtkx/utils";
2
+ import type { ParsedKey, ParsedSchema, ParsedSchemaFile } from "./parser.js";
3
+
4
+ const GTKX_ENV_MODULE_HEADER = `/**
5
+ * GSettings schema modules generated by GTKX from the project's
6
+ * \`.gschema.xml\` files. Regenerated by \`gtkx codegen\`, \`gtkx dev\`, and
7
+ * \`gtkx build\`; do not edit.
8
+ */`;
9
+
10
+ const ENUM_KIND = "enum";
11
+ const FLAGS_KIND = "flags";
12
+
13
+ const toJsStringLiteral = (value: string): string =>
14
+ JSON.stringify(value).replaceAll("\u{2028}", String.raw`\u2028`).replaceAll("\u{2029}", String.raw`\u2029`);
15
+
16
+ const getExportName = (schemaId: string): string => schemaId.replaceAll(".", "_");
17
+
18
+ const runtimeKindForKey = (key: ParsedKey): string => {
19
+ if (key.enumId !== null) {
20
+ return ENUM_KIND;
21
+ }
22
+
23
+ if (key.flagsId !== null) {
24
+ return FLAGS_KIND;
25
+ }
26
+
27
+ return key.variantType ?? "";
28
+ };
29
+
30
+ const getRuntimeKeys = (schema: ParsedSchema): string => {
31
+ const entries = schema.keys.map(
32
+ (key) => `${toJsStringLiteral(key.name)}: ${toJsStringLiteral(runtimeKindForKey(key))}`,
33
+ );
34
+
35
+ return `{ ${entries.join(", ")} }`;
36
+ };
37
+
38
+ const renderRuntimeModule = (file: ParsedSchemaFile): string => {
39
+ const lines: string[] = [];
40
+
41
+ for (const [index, schema] of file.schemas.entries()) {
42
+ const keysName = `keys_${String(index)}`;
43
+ const id = toJsStringLiteral(schema.id);
44
+ lines.push(`const ${keysName} = ${getRuntimeKeys(schema)};`);
45
+
46
+ if (schema.path === null) {
47
+ lines.push(
48
+ `export const ${getExportName(schema.id)} = { id: ${id}, keys: ${keysName}, ` +
49
+ `at: (path) => ({ id: ${id}, path, keys: ${keysName} }) };`,
50
+ );
51
+ } else {
52
+ lines.push(`export const ${getExportName(schema.id)} = { id: ${id}, path: null, keys: ${keysName} };`);
53
+ }
54
+ }
55
+
56
+ const first = file.schemas[0];
57
+
58
+ if (first !== undefined) {
59
+ lines.push(`export default ${getExportName(first.id)};`);
60
+ }
61
+
62
+ return lines.join("\n");
63
+ };
64
+
65
+ const sanitizeSummary = (summary: string): string => summary.replaceAll("*/", String.raw`*\/`);
66
+
67
+ const allocateInterfaceName = (schemaId: string, usedNames: Set<string>): string => {
68
+ const base = `${schemaId
69
+ .split(/[^a-zA-Z0-9]+/)
70
+ .filter((part) => part.length > 0)
71
+ .map((part) => upperFirst(part))
72
+ .join("")}Keys`;
73
+
74
+ let name = base;
75
+ let suffix = 2;
76
+
77
+ while (usedNames.has(name)) {
78
+ name = `${base}${String(suffix)}`;
79
+ suffix += 1;
80
+ }
81
+
82
+ usedNames.add(name);
83
+
84
+ return name;
85
+ };
86
+
87
+ const renderKeysType = (name: string, schema: ParsedSchema): string[] => {
88
+ const lines = [` type ${name} = {`];
89
+
90
+ for (const key of schema.keys) {
91
+ if (key.summary !== null) {
92
+ lines.push(` /** ${sanitizeSummary(key.summary)} */`);
93
+ }
94
+
95
+ lines.push(` ${toJsStringLiteral(key.name)}: ${toJsStringLiteral(runtimeKindForKey(key))};`);
96
+ }
97
+
98
+ lines.push(" };");
99
+
100
+ return lines;
101
+ };
102
+
103
+ const boundRefTypeLines = (interfaceName: string, indent: string): string[] => [
104
+ `${indent}id: string;`,
105
+ `${indent}path: string | null;`,
106
+ `${indent}keys: ${interfaceName};`,
107
+ ];
108
+
109
+ const renderSchemaConst = (schema: ParsedSchema, interfaceName: string): string[] => {
110
+ const exportName = getExportName(schema.id);
111
+
112
+ if (schema.path !== null) {
113
+ return [
114
+ ` const ${exportName}: {`,
115
+ ` id: ${toJsStringLiteral(schema.id)};`,
116
+ ...boundRefTypeLines(interfaceName, " ".repeat(8)).slice(1),
117
+ " };",
118
+ ];
119
+ }
120
+
121
+ return [
122
+ ` const ${exportName}: {`,
123
+ ` id: ${JSON.stringify(schema.id)};`,
124
+ ` keys: ${interfaceName};`,
125
+ " at(path: string): {",
126
+ ...boundRefTypeLines(interfaceName, " ".repeat(12)),
127
+ " };",
128
+ " };",
129
+ ];
130
+ };
131
+
132
+ const renderFileModule = (file: ParsedSchemaFile, usedNames: Set<string>): string[] => {
133
+ const lines = [`declare module "${file.fileName}" {`];
134
+ const exportNames: string[] = [];
135
+
136
+ for (const [index, schema] of file.schemas.entries()) {
137
+ if (index > 0) {
138
+ lines.push("");
139
+ }
140
+
141
+ const interfaceName = allocateInterfaceName(schema.id, usedNames);
142
+ lines.push(...renderKeysType(interfaceName, schema), "", ...renderSchemaConst(schema, interfaceName));
143
+ exportNames.push(getExportName(schema.id));
144
+ }
145
+
146
+ const [firstExport] = exportNames;
147
+
148
+ if (firstExport !== undefined) {
149
+ lines.push("", ` export { ${exportNames.join(", ")} };`, ` export default ${firstExport};`);
150
+ }
151
+
152
+ lines.push("}");
153
+
154
+ return lines;
155
+ };
156
+
157
+ const renderEnvModule = (files: ParsedSchemaFile[]): string => {
158
+ const usedNames: Set<string> = new Set();
159
+
160
+ const blocks = files
161
+ .filter((file) => file.schemas.length > 0)
162
+ .map((file) => renderFileModule(file, usedNames).join("\n"));
163
+
164
+ return `${[GTKX_ENV_MODULE_HEADER, ...blocks].join("\n\n")}\n`;
165
+ };
166
+
167
+ export { renderRuntimeModule, renderEnvModule };
@@ -0,0 +1,169 @@
1
+ import { sortStrings, warn } from "@gtkx/utils";
2
+ import { createHash } from "node:crypto";
3
+ import { copyFileSync, type Dirent, mkdirSync, mkdtempSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { dirname, join, relative } from "node:path";
6
+ import { DATA_IMPORT_PREFIX } from "../internal/data-dir.js";
7
+ import { removeTempDir } from "../internal/staging-dir.js";
8
+ import { compileSchemas } from "./compile.js";
9
+ import { type ParsedSchemaFile, parseSchemaXml, SchemaParseError } from "./parser.js";
10
+ import { renderEnvModule } from "./render.js";
11
+
12
+ type SchemaEnvResult = {
13
+ path: string;
14
+ written: boolean;
15
+ };
16
+
17
+ const SCHEMA_SUFFIX = ".gschema.xml";
18
+ const STAGED_NAME_LENGTH = 16;
19
+
20
+ const prependSchemaDir = (dir: string, existing: string | undefined): string => {
21
+ if (existing === undefined || existing.length === 0) {
22
+ return dir;
23
+ }
24
+
25
+ if (existing.split(":").includes(dir)) {
26
+ return existing;
27
+ }
28
+
29
+ return `${dir}:${existing}`;
30
+ };
31
+
32
+ const stagedSchemaName = (filePath: string): string =>
33
+ `${createHash("sha1").update(filePath).digest("hex").slice(0, STAGED_NAME_LENGTH)}${SCHEMA_SUFFIX}`;
34
+
35
+ const stageSchema = (dir: string, filePath: string): void => {
36
+ copyFileSync(filePath, join(dir, stagedSchemaName(filePath)));
37
+ };
38
+
39
+ const toForwardSlashes = (value: string): string => value.replaceAll(/[/\\]/g, "/");
40
+
41
+ const getModuleSpecifier = (dataDirAbs: string, filePath: string): string =>
42
+ `${DATA_IMPORT_PREFIX}/${toForwardSlashes(relative(dataDirAbs, filePath))}`;
43
+
44
+ const readVisibleEntries = (dir: string): Dirent[] => {
45
+ try {
46
+ return readdirSync(dir, { withFileTypes: true }).filter((entry) => !entry.name.startsWith("."));
47
+ } catch {
48
+ return [];
49
+ }
50
+ };
51
+
52
+ const isSchemaFile = (entry: Dirent): boolean => entry.isFile() && entry.name.endsWith(SCHEMA_SUFFIX);
53
+
54
+ const collectSchemaFiles = (dir: string, found: string[]): void => {
55
+ for (const entry of readVisibleEntries(dir)) {
56
+ const full = join(dir, entry.name);
57
+
58
+ if (entry.isDirectory()) {
59
+ collectSchemaFiles(full, found);
60
+ } else if (isSchemaFile(entry)) {
61
+ found.push(full);
62
+ }
63
+ }
64
+ };
65
+
66
+ const findSchemaFiles = (dataDir: string): string[] => {
67
+ const found: string[] = [];
68
+ collectSchemaFiles(dataDir, found);
69
+
70
+ return sortStrings(found);
71
+ };
72
+
73
+ const stageAndCompileProjectSchemas = (root: string, dataDir: string | null): string | null => {
74
+ if (dataDir === null) {
75
+ return null;
76
+ }
77
+
78
+ const schemaFiles = findSchemaFiles(join(root, dataDir));
79
+
80
+ if (schemaFiles.length === 0) {
81
+ return null;
82
+ }
83
+
84
+ const dir = mkdtempSync(join(tmpdir(), "gtkx-schemas-"));
85
+
86
+ for (const filePath of schemaFiles) {
87
+ stageSchema(dir, filePath);
88
+ }
89
+
90
+ compileSchemas(dir);
91
+
92
+ process.once("exit", () => {
93
+ removeTempDir(dir);
94
+ });
95
+
96
+ return dir;
97
+ };
98
+
99
+ const schemaEnvPath = (rootDir: string): string => join(rootDir, "node_modules", ".gtkx", "env.d.ts");
100
+
101
+ const parseSchemaFileOrWarn = (filePath: string, dataDirAbs: string): ParsedSchemaFile | null => {
102
+ const specifier = getModuleSpecifier(dataDirAbs, filePath);
103
+
104
+ try {
105
+ return parseSchemaXml(readFileSync(filePath, "utf8"), specifier);
106
+ } catch (error) {
107
+ if (!(error instanceof SchemaParseError)) {
108
+ throw error;
109
+ }
110
+
111
+ warn(`Skipping ${filePath} in schema type generation: ${error.message}`);
112
+
113
+ return null;
114
+ }
115
+ };
116
+
117
+ const parseProjectSchemas = (schemaFiles: string[], dataDirAbs: string): ParsedSchemaFile[] => {
118
+ const parsed: ParsedSchemaFile[] = [];
119
+
120
+ for (const filePath of schemaFiles) {
121
+ const result = parseSchemaFileOrWarn(filePath, dataDirAbs);
122
+
123
+ if (result !== null) {
124
+ parsed.push(result);
125
+ }
126
+ }
127
+
128
+ return parsed;
129
+ };
130
+
131
+ const readFileOrNull = (path: string): string | null => {
132
+ try {
133
+ return readFileSync(path, "utf8");
134
+ } catch {
135
+ return null;
136
+ }
137
+ };
138
+
139
+ const didWriteChanges = (path: string, content: string): boolean => {
140
+ if (readFileOrNull(path) === content) {
141
+ return false;
142
+ }
143
+
144
+ mkdirSync(dirname(path), { recursive: true });
145
+ writeFileSync(path, content);
146
+
147
+ return true;
148
+ };
149
+
150
+ const emitSchemaEnv = (rootDir: string, dataDir: string | null): SchemaEnvResult => {
151
+ const dataDirAbs = dataDir === null ? null : join(rootDir, dataDir);
152
+ const schemaFiles = dataDirAbs === null ? [] : findSchemaFiles(dataDirAbs);
153
+ const parsed = dataDirAbs === null ? [] : parseProjectSchemas(schemaFiles, dataDirAbs);
154
+ const content = renderEnvModule(parsed);
155
+ const path = schemaEnvPath(rootDir);
156
+ const isWritten = didWriteChanges(path, content);
157
+
158
+ return { path, written: isWritten };
159
+ };
160
+
161
+ export {
162
+ SCHEMA_SUFFIX,
163
+ prependSchemaDir,
164
+ stageSchema,
165
+ findSchemaFiles,
166
+ stageAndCompileProjectSchemas,
167
+ schemaEnvPath,
168
+ emitSchemaEnv,
169
+ };
@@ -0,0 +1,29 @@
1
+ const ASSET_EXTENSIONS = [
2
+ "png",
3
+ "jpg",
4
+ "jpeg",
5
+ "gif",
6
+ "svg",
7
+ "webp",
8
+ "webm",
9
+ "mp4",
10
+ "ogg",
11
+ "mp3",
12
+ "wav",
13
+ "flac",
14
+ "aac",
15
+ "woff",
16
+ "woff2",
17
+ "eot",
18
+ "ttf",
19
+ "otf",
20
+ "ico",
21
+ "avif",
22
+ "data",
23
+ "gpa",
24
+ ];
25
+
26
+ const ASSET_RE = new RegExp(String.raw`\.(?:${ASSET_EXTENSIONS.join("|")})$`, "i");
27
+ const ASSET_PATH_RE = new RegExp(String.raw`\.(?:${ASSET_EXTENSIONS.join("|")})(?:\?.*)?$`, "i");
28
+
29
+ export { ASSET_EXTENSIONS, ASSET_RE, ASSET_PATH_RE };