@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.
- package/README.md +173 -0
- package/bin/gtkx-dev-runner.js +9 -0
- package/dist/builder.d.ts +5 -52
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +24 -57
- package/dist/builder.js.map +1 -1
- package/dist/cli.d.ts +1 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +24 -122
- package/dist/cli.js.map +1 -1
- package/dist/codegen/freshness.d.ts +11 -0
- package/dist/codegen/freshness.d.ts.map +1 -0
- package/dist/codegen/freshness.js +45 -0
- package/dist/codegen/freshness.js.map +1 -0
- package/dist/codegen/report.d.ts +4 -0
- package/dist/codegen/report.d.ts.map +1 -0
- package/dist/codegen/report.js +18 -0
- package/dist/codegen/report.js.map +1 -0
- package/dist/codegen/run-codegen.d.ts +35 -0
- package/dist/codegen/run-codegen.d.ts.map +1 -0
- package/dist/codegen/run-codegen.js +162 -0
- package/dist/codegen/run-codegen.js.map +1 -0
- package/dist/codegen/store-resolver.d.ts +24 -0
- package/dist/codegen/store-resolver.d.ts.map +1 -0
- package/dist/codegen/store-resolver.js +72 -0
- package/dist/codegen/store-resolver.js.map +1 -0
- package/dist/commands/build.d.ts +10 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +34 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/codegen.d.ts +10 -0
- package/dist/commands/codegen.d.ts.map +1 -0
- package/dist/commands/codegen.js +42 -0
- package/dist/commands/codegen.js.map +1 -0
- package/dist/commands/dev.d.ts +6 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +22 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/docs.d.ts +20 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +74 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/dev/icon-dir.d.ts +3 -0
- package/dist/dev/icon-dir.d.ts.map +1 -0
- package/dist/dev/icon-dir.js +16 -0
- package/dist/dev/icon-dir.js.map +1 -0
- package/dist/dev/refresh-tracker.d.ts +7 -0
- package/dist/dev/refresh-tracker.d.ts.map +1 -0
- package/dist/dev/refresh-tracker.js +19 -0
- package/dist/dev/refresh-tracker.js.map +1 -0
- package/dist/dev/runner-deps.d.ts +4 -0
- package/dist/dev/runner-deps.d.ts.map +1 -0
- package/dist/dev/runner-deps.js +55 -0
- package/dist/dev/runner-deps.js.map +1 -0
- package/dist/dev/runner-main.d.ts +3 -0
- package/dist/dev/runner-main.d.ts.map +1 -0
- package/dist/dev/runner-main.js +29 -0
- package/dist/dev/runner-main.js.map +1 -0
- package/dist/dev/runner.d.ts +24 -0
- package/dist/dev/runner.d.ts.map +1 -0
- package/dist/dev/runner.js +119 -0
- package/dist/dev/runner.js.map +1 -0
- package/dist/dev/schema-dir.d.ts +3 -0
- package/dist/dev/schema-dir.d.ts.map +1 -0
- package/dist/dev/schema-dir.js +12 -0
- package/dist/dev/schema-dir.js.map +1 -0
- package/dist/dev/supervisor.d.ts +18 -0
- package/dist/dev/supervisor.d.ts.map +1 -0
- package/dist/dev/supervisor.js +182 -0
- package/dist/dev/supervisor.js.map +1 -0
- package/dist/dev/vite-dev-server.d.ts +21 -0
- package/dist/dev/vite-dev-server.d.ts.map +1 -0
- package/dist/dev/vite-dev-server.js +13 -0
- package/dist/dev/vite-dev-server.js.map +1 -0
- package/dist/internal/banner.d.ts +4 -0
- package/dist/internal/banner.d.ts.map +1 -0
- package/dist/internal/banner.js +9 -0
- package/dist/internal/banner.js.map +1 -0
- package/dist/internal/data-dir.d.ts +4 -0
- package/dist/internal/data-dir.d.ts.map +1 -0
- package/dist/internal/data-dir.js +52 -0
- package/dist/internal/data-dir.js.map +1 -0
- package/dist/internal/entry-arg.d.ts +20 -0
- package/dist/internal/entry-arg.d.ts.map +1 -0
- package/dist/internal/entry-arg.js +36 -0
- package/dist/internal/entry-arg.js.map +1 -0
- package/dist/internal/errors.d.ts +5 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +29 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/list-files.d.ts +7 -0
- package/dist/internal/list-files.d.ts.map +1 -0
- package/dist/internal/list-files.js +15 -0
- package/dist/internal/list-files.js.map +1 -0
- package/dist/internal/resolve-cli-tool.d.ts +3 -0
- package/dist/internal/resolve-cli-tool.d.ts.map +1 -0
- package/dist/internal/resolve-cli-tool.js +27 -0
- package/dist/internal/resolve-cli-tool.js.map +1 -0
- package/dist/internal/staging-dir.d.ts +4 -0
- package/dist/internal/staging-dir.d.ts.map +1 -0
- package/dist/internal/staging-dir.js +17 -0
- package/dist/internal/staging-dir.js.map +1 -0
- package/dist/internal/xdg-data-dirs.d.ts +3 -0
- package/dist/internal/xdg-data-dirs.d.ts.map +1 -0
- package/dist/internal/xdg-data-dirs.js +10 -0
- package/dist/internal/xdg-data-dirs.js.map +1 -0
- package/dist/mcp/client.d.ts +28 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +182 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/handlers.d.ts +9 -0
- package/dist/mcp/handlers.d.ts.map +1 -0
- package/dist/mcp/handlers.js +147 -0
- package/dist/mcp/handlers.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +34 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/serialize-widget.d.ts +10 -0
- package/dist/mcp/serialize-widget.d.ts.map +1 -0
- package/dist/mcp/serialize-widget.js +23 -0
- package/dist/mcp/serialize-widget.js.map +1 -0
- package/dist/mcp/testing-loader.d.ts +5 -0
- package/dist/mcp/testing-loader.d.ts.map +1 -0
- package/dist/mcp/testing-loader.js +47 -0
- package/dist/mcp/testing-loader.js.map +1 -0
- package/dist/mcp/widget-registry.d.ts +14 -0
- package/dist/mcp/widget-registry.d.ts.map +1 -0
- package/dist/mcp/widget-registry.js +39 -0
- package/dist/mcp/widget-registry.js.map +1 -0
- package/dist/refresh-globals.d.ts +2 -0
- package/dist/refresh-globals.d.ts.map +1 -0
- package/dist/refresh-globals.js +8 -0
- package/dist/refresh-globals.js.map +1 -0
- package/dist/refresh-runtime.d.ts +10 -26
- package/dist/refresh-runtime.d.ts.map +1 -1
- package/dist/refresh-runtime.js +26 -48
- package/dist/refresh-runtime.js.map +1 -1
- package/dist/settings/compile.d.ts +3 -0
- package/dist/settings/compile.d.ts.map +1 -0
- package/dist/settings/compile.js +21 -0
- package/dist/settings/compile.js.map +1 -0
- package/dist/settings/parser.d.ts +24 -0
- package/dist/settings/parser.d.ts.map +1 -0
- package/dist/settings/parser.js +121 -0
- package/dist/settings/parser.js.map +1 -0
- package/dist/settings/render.d.ts +5 -0
- package/dist/settings/render.d.ts.map +1 -0
- package/dist/settings/render.js +122 -0
- package/dist/settings/render.js.map +1 -0
- package/dist/settings/schema.d.ts +13 -0
- package/dist/settings/schema.d.ts.map +1 -0
- package/dist/settings/schema.js +121 -0
- package/dist/settings/schema.js.map +1 -0
- package/dist/vite-plugins/asset-extensions.d.ts +5 -0
- package/dist/vite-plugins/asset-extensions.d.ts.map +1 -0
- package/dist/vite-plugins/asset-extensions.js +28 -0
- package/dist/vite-plugins/asset-extensions.js.map +1 -0
- package/dist/vite-plugins/built-url.d.ts +4 -0
- package/dist/vite-plugins/built-url.d.ts.map +1 -0
- package/dist/vite-plugins/built-url.js +36 -0
- package/dist/vite-plugins/built-url.js.map +1 -0
- package/dist/vite-plugins/css.d.ts +4 -0
- package/dist/vite-plugins/css.d.ts.map +1 -0
- package/dist/vite-plugins/css.js +38 -0
- package/dist/vite-plugins/css.js.map +1 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +8 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.js +19 -0
- package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +6 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.js +70 -0
- package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -0
- package/dist/vite-plugins/icons.d.ts +4 -0
- package/dist/vite-plugins/icons.d.ts.map +1 -0
- package/dist/vite-plugins/icons.js +51 -0
- package/dist/vite-plugins/icons.js.map +1 -0
- package/dist/vite-plugins/index.d.ts +4 -0
- package/dist/vite-plugins/index.d.ts.map +1 -0
- package/dist/vite-plugins/index.js +22 -0
- package/dist/vite-plugins/index.js.map +1 -0
- package/dist/vite-plugins/native.d.ts +4 -0
- package/dist/vite-plugins/native.d.ts.map +1 -0
- package/dist/vite-plugins/native.js +62 -0
- package/dist/vite-plugins/native.js.map +1 -0
- package/dist/vite-plugins/react-compiler.d.ts +5 -0
- package/dist/vite-plugins/react-compiler.d.ts.map +1 -0
- package/dist/vite-plugins/react-compiler.js +62 -0
- package/dist/vite-plugins/react-compiler.js.map +1 -0
- package/dist/vite-plugins/react-dom-prebundle.d.ts +4 -0
- package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -0
- package/dist/vite-plugins/react-dom-prebundle.js +12 -0
- package/dist/vite-plugins/react-dom-prebundle.js.map +1 -0
- package/dist/vite-plugins/resource-init-module.d.ts +6 -0
- package/dist/vite-plugins/resource-init-module.d.ts.map +1 -0
- package/dist/vite-plugins/resource-init-module.js +51 -0
- package/dist/vite-plugins/resource-init-module.js.map +1 -0
- package/dist/vite-plugins/resource-shared.d.ts +8 -0
- package/dist/vite-plugins/resource-shared.d.ts.map +1 -0
- package/dist/vite-plugins/resource-shared.js +28 -0
- package/dist/vite-plugins/resource-shared.js.map +1 -0
- package/dist/vite-plugins/resources.d.ts +5 -0
- package/dist/vite-plugins/resources.d.ts.map +1 -0
- package/dist/vite-plugins/resources.js +260 -0
- package/dist/vite-plugins/resources.js.map +1 -0
- package/dist/vite-plugins/settings-worker-env.d.ts +4 -0
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -0
- package/dist/vite-plugins/settings-worker-env.js +23 -0
- package/dist/vite-plugins/settings-worker-env.js.map +1 -0
- package/dist/vite-plugins/settings.d.ts +4 -0
- package/dist/vite-plugins/settings.d.ts.map +1 -0
- package/dist/vite-plugins/settings.js +214 -0
- package/dist/vite-plugins/settings.js.map +1 -0
- package/dist/vite-plugins/strip-query.d.ts +3 -0
- package/dist/vite-plugins/strip-query.d.ts.map +1 -0
- package/dist/vite-plugins/strip-query.js +6 -0
- package/dist/vite-plugins/strip-query.js.map +1 -0
- package/dist/vite-plugins/undeclared-library.d.ts +4 -0
- package/dist/vite-plugins/undeclared-library.d.ts.map +1 -0
- package/dist/vite-plugins/undeclared-library.js +50 -0
- package/dist/vite-plugins/undeclared-library.js.map +1 -0
- package/dist/vite-plugins/virtual-module.d.ts +22 -0
- package/dist/vite-plugins/virtual-module.d.ts.map +1 -0
- package/dist/vite-plugins/virtual-module.js +20 -0
- package/dist/vite-plugins/virtual-module.js.map +1 -0
- package/dist/vitest-plugin.d.ts +10 -0
- package/dist/vitest-plugin.d.ts.map +1 -0
- package/dist/vitest-plugin.js +12 -0
- package/dist/vitest-plugin.js.map +1 -0
- package/env.d.ts +91 -8
- package/package.json +30 -38
- package/src/babel-modules.d.ts +11 -0
- package/src/builder.ts +31 -86
- package/src/cli.ts +42 -0
- package/src/codegen/freshness.ts +65 -0
- package/src/codegen/report.ts +28 -0
- package/src/codegen/run-codegen.ts +260 -0
- package/src/codegen/store-resolver.ts +116 -0
- package/src/commands/build.ts +38 -0
- package/src/commands/codegen.ts +49 -0
- package/src/commands/dev.ts +24 -0
- package/src/commands/docs.ts +95 -0
- package/src/dev/icon-dir.ts +21 -0
- package/src/dev/refresh-tracker.ts +25 -0
- package/src/dev/runner-deps.ts +65 -0
- package/src/dev/runner-main.ts +34 -0
- package/src/dev/runner.ts +185 -0
- package/src/dev/schema-dir.ts +16 -0
- package/src/dev/supervisor.ts +276 -0
- package/src/dev/vite-dev-server.ts +36 -0
- package/src/internal/banner.ts +13 -0
- package/src/internal/data-dir.ts +70 -0
- package/src/internal/entry-arg.ts +46 -0
- package/src/internal/errors.ts +36 -0
- package/src/internal/list-files.ts +23 -0
- package/src/internal/resolve-cli-tool.ts +37 -0
- package/src/internal/staging-dir.ts +19 -0
- package/src/internal/xdg-data-dirs.ts +13 -0
- package/src/mcp/client.ts +235 -0
- package/src/mcp/handlers.ts +213 -0
- package/src/mcp/index.ts +46 -0
- package/src/mcp/serialize-widget.ts +41 -0
- package/src/mcp/testing-loader.ts +73 -0
- package/src/mcp/widget-registry.ts +49 -0
- package/src/refresh-globals.ts +10 -0
- package/src/refresh-runtime.ts +30 -55
- package/src/settings/compile.ts +22 -0
- package/src/settings/parser.ts +193 -0
- package/src/settings/render.ts +167 -0
- package/src/settings/schema.ts +169 -0
- package/src/vite-plugins/asset-extensions.ts +29 -0
- package/src/vite-plugins/built-url.ts +50 -0
- package/src/vite-plugins/css.ts +53 -0
- package/src/vite-plugins/fast-refresh/refresh-filter.ts +26 -0
- package/src/vite-plugins/fast-refresh/swc-refresh.ts +92 -0
- package/src/vite-plugins/icons.ts +74 -0
- package/src/vite-plugins/index.ts +25 -0
- package/src/vite-plugins/native.ts +83 -0
- package/src/vite-plugins/react-compiler.ts +84 -0
- package/src/vite-plugins/react-dom-prebundle.ts +17 -0
- package/src/vite-plugins/resource-init-module.ts +57 -0
- package/src/vite-plugins/resource-shared.ts +40 -0
- package/src/vite-plugins/resources.ts +366 -0
- package/src/vite-plugins/settings-worker-env.ts +30 -0
- package/src/vite-plugins/settings.ts +286 -0
- package/src/vite-plugins/strip-query.ts +7 -0
- package/src/vite-plugins/undeclared-library.ts +78 -0
- package/src/vite-plugins/virtual-module.ts +44 -0
- package/src/vitest-plugin.ts +13 -0
- package/dist/create.d.ts +0 -55
- package/dist/create.d.ts.map +0 -1
- package/dist/create.js +0 -236
- package/dist/create.js.map +0 -1
- package/dist/dev-server.d.ts +0 -37
- package/dist/dev-server.d.ts.map +0 -1
- package/dist/dev-server.js +0 -130
- package/dist/dev-server.js.map +0 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -31
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -430
- package/dist/mcp-client.js.map +0 -1
- package/dist/templates.d.ts +0 -9
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js +0 -16
- package/dist/templates.js.map +0 -1
- package/dist/vite-plugin-gtkx-assets.d.ts +0 -20
- package/dist/vite-plugin-gtkx-assets.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-assets.js +0 -57
- package/dist/vite-plugin-gtkx-assets.js.map +0 -1
- package/dist/vite-plugin-gtkx-built-url.d.ts +0 -18
- package/dist/vite-plugin-gtkx-built-url.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-built-url.js +0 -43
- package/dist/vite-plugin-gtkx-built-url.js.map +0 -1
- package/dist/vite-plugin-gtkx-gsettings.d.ts +0 -28
- package/dist/vite-plugin-gtkx-gsettings.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-gsettings.js +0 -147
- package/dist/vite-plugin-gtkx-gsettings.js.map +0 -1
- package/dist/vite-plugin-gtkx-native.d.ts +0 -14
- package/dist/vite-plugin-gtkx-native.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-native.js +0 -53
- package/dist/vite-plugin-gtkx-native.js.map +0 -1
- package/dist/vite-plugin-gtkx-refresh.d.ts +0 -8
- package/dist/vite-plugin-gtkx-refresh.d.ts.map +0 -1
- package/dist/vite-plugin-gtkx-refresh.js +0 -37
- package/dist/vite-plugin-gtkx-refresh.js.map +0 -1
- package/dist/vite-plugin-swc-ssr-refresh.d.ts +0 -8
- package/dist/vite-plugin-swc-ssr-refresh.d.ts.map +0 -1
- package/dist/vite-plugin-swc-ssr-refresh.js +0 -46
- package/dist/vite-plugin-swc-ssr-refresh.js.map +0 -1
- package/src/cli.tsx +0 -154
- package/src/create.ts +0 -326
- package/src/dev-server.tsx +0 -162
- package/src/index.ts +0 -3
- package/src/mcp-client.ts +0 -518
- package/src/templates.ts +0 -26
- package/src/vite-plugin-gtkx-assets.ts +0 -69
- package/src/vite-plugin-gtkx-built-url.ts +0 -48
- package/src/vite-plugin-gtkx-gsettings.ts +0 -168
- package/src/vite-plugin-gtkx-native.ts +0 -64
- package/src/vite-plugin-gtkx-refresh.ts +0 -54
- package/src/vite-plugin-swc-ssr-refresh.ts +0 -61
- package/templates/claude/EXAMPLES.md.ejs +0 -744
- package/templates/claude/SKILL.md.ejs +0 -93
- package/templates/claude/WIDGETS.md.ejs +0 -820
- package/templates/config/vitest.config.ts.ejs +0 -11
- package/templates/gitignore.ejs +0 -4
- package/templates/package.json.ejs +0 -16
- package/templates/src/app.tsx.ejs +0 -32
- package/templates/src/dev.tsx.ejs +0 -5
- package/templates/src/gtkx-env.d.ts.ejs +0 -1
- package/templates/src/index.tsx.ejs +0 -5
- package/templates/tests/app.test.tsx.ejs +0 -16
- package/templates/tsconfig.json.ejs +0 -14
package/src/refresh-runtime.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
16
|
-
* @returns
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
57
|
-
* @returns `true`
|
|
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
|
-
|
|
61
|
-
|
|
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
|
|
67
|
-
|
|
37
|
+
if (!isComponentExport(key, moduleExports[key])) {
|
|
38
|
+
return false;
|
|
68
39
|
}
|
|
40
|
+
}
|
|
69
41
|
|
|
70
|
-
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
71
44
|
|
|
72
|
-
|
|
73
|
-
|
|
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).
|
|
54
|
+
return Object.keys(moduleExports).some((k) => k !== "__esModule");
|
|
78
55
|
}
|
|
79
56
|
|
|
80
57
|
/**
|
|
81
|
-
*
|
|
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
|
-
|
|
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 };
|