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