@gtkx/cli 0.6.0 → 0.7.0
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/create.js +50 -46
- package/package.json +4 -4
package/dist/create.js
CHANGED
|
@@ -573,7 +573,7 @@ const generateExamplesMd = () => {
|
|
|
573
573
|
### Basic App with State
|
|
574
574
|
|
|
575
575
|
\`\`\`tsx
|
|
576
|
-
import
|
|
576
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
577
577
|
import { ApplicationWindow, Box, Label, quit } from "@gtkx/react";
|
|
578
578
|
import { useCallback, useState } from "react";
|
|
579
579
|
|
|
@@ -602,7 +602,7 @@ export const App = () => {
|
|
|
602
602
|
|
|
603
603
|
return (
|
|
604
604
|
<ApplicationWindow title="Todo App" defaultWidth={400} defaultHeight={500} onCloseRequest={quit}>
|
|
605
|
-
<Box orientation={Orientation.VERTICAL} spacing={16} marginTop={16} marginStart={16} marginEnd={16}>
|
|
605
|
+
<Box orientation={Gtk.Orientation.VERTICAL} spacing={16} marginTop={16} marginStart={16} marginEnd={16}>
|
|
606
606
|
<Label label="Todo App" />
|
|
607
607
|
</Box>
|
|
608
608
|
</ApplicationWindow>
|
|
@@ -751,8 +751,8 @@ const MenuDemo = () => {
|
|
|
751
751
|
### List Item Component
|
|
752
752
|
|
|
753
753
|
\`\`\`tsx
|
|
754
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
754
755
|
import { Box, Button, CheckButton, Label } from "@gtkx/react";
|
|
755
|
-
import { Orientation } from "@gtkx/ffi/gtk";
|
|
756
756
|
|
|
757
757
|
interface Todo {
|
|
758
758
|
id: number;
|
|
@@ -767,7 +767,7 @@ interface TodoItemProps {
|
|
|
767
767
|
}
|
|
768
768
|
|
|
769
769
|
export const TodoItem = ({ todo, onToggle, onDelete }: TodoItemProps) => (
|
|
770
|
-
<Box orientation={Orientation.HORIZONTAL} spacing={8}>
|
|
770
|
+
<Box orientation={Gtk.Orientation.HORIZONTAL} spacing={8}>
|
|
771
771
|
<CheckButton active={todo.completed} onToggled={() => onToggle(todo.id)} />
|
|
772
772
|
<Label label={todo.text} hexpand cssClasses={todo.completed ? ["dim-label"] : []} />
|
|
773
773
|
<Button iconName="edit-delete-symbolic" onClicked={() => onDelete(todo.id)} cssClasses={["flat"]} />
|
|
@@ -786,7 +786,7 @@ import { strict as assert } from "node:assert";`;
|
|
|
786
786
|
const afterEachFn = testing === "node" ? "after" : "afterEach";
|
|
787
787
|
const assertion = testing === "node" ? `assert.ok(button, "Button should be rendered");` : `expect(button).toBeDefined();`;
|
|
788
788
|
return `${imports}
|
|
789
|
-
import
|
|
789
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
790
790
|
import { cleanup, render, screen } from "@gtkx/testing";
|
|
791
791
|
import App from "../src/app.js";
|
|
792
792
|
|
|
@@ -797,7 +797,7 @@ ${afterEachFn}(async () => {
|
|
|
797
797
|
describe("App", () => {
|
|
798
798
|
it("renders the increment button", async () => {
|
|
799
799
|
await render(<App />, { wrapper: false });
|
|
800
|
-
const button = await screen.findByRole(AccessibleRole.BUTTON, { name: "Increment" });
|
|
800
|
+
const button = await screen.findByRole(Gtk.AccessibleRole.BUTTON, { name: "Increment" });
|
|
801
801
|
${assertion}
|
|
802
802
|
});
|
|
803
803
|
});
|
|
@@ -882,15 +882,16 @@ const suggestAppId = (name) => {
|
|
|
882
882
|
const sanitized = name.replace(/-/g, "");
|
|
883
883
|
return `org.gtkx.${sanitized}`;
|
|
884
884
|
};
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
885
|
+
const checkCancelled = (value) => {
|
|
886
|
+
if (p.isCancel(value)) {
|
|
887
|
+
p.cancel("Operation cancelled");
|
|
888
|
+
process.exit(0);
|
|
889
|
+
}
|
|
890
|
+
return value;
|
|
891
|
+
};
|
|
892
|
+
const promptForOptions = async (options) => {
|
|
892
893
|
const name = options.name ??
|
|
893
|
-
(await p.text({
|
|
894
|
+
checkCancelled(await p.text({
|
|
894
895
|
message: "Project name",
|
|
895
896
|
placeholder: "my-app",
|
|
896
897
|
validate: (value) => {
|
|
@@ -905,13 +906,9 @@ export const createApp = async (options = {}) => {
|
|
|
905
906
|
return undefined;
|
|
906
907
|
},
|
|
907
908
|
}));
|
|
908
|
-
if (p.isCancel(name)) {
|
|
909
|
-
p.cancel("Operation cancelled");
|
|
910
|
-
process.exit(0);
|
|
911
|
-
}
|
|
912
909
|
const defaultAppId = suggestAppId(name);
|
|
913
910
|
const appId = options.appId ??
|
|
914
|
-
(await p.text({
|
|
911
|
+
checkCancelled(await p.text({
|
|
915
912
|
message: "App ID",
|
|
916
913
|
placeholder: defaultAppId,
|
|
917
914
|
initialValue: defaultAppId,
|
|
@@ -924,12 +921,8 @@ export const createApp = async (options = {}) => {
|
|
|
924
921
|
return undefined;
|
|
925
922
|
},
|
|
926
923
|
}));
|
|
927
|
-
if (p.isCancel(appId)) {
|
|
928
|
-
p.cancel("Operation cancelled");
|
|
929
|
-
process.exit(0);
|
|
930
|
-
}
|
|
931
924
|
const packageManager = options.packageManager ??
|
|
932
|
-
(await p.select({
|
|
925
|
+
checkCancelled(await p.select({
|
|
933
926
|
message: "Package manager",
|
|
934
927
|
options: [
|
|
935
928
|
{ value: "pnpm", label: "pnpm", hint: "recommended" },
|
|
@@ -939,12 +932,8 @@ export const createApp = async (options = {}) => {
|
|
|
939
932
|
],
|
|
940
933
|
initialValue: "pnpm",
|
|
941
934
|
}));
|
|
942
|
-
if (p.isCancel(packageManager)) {
|
|
943
|
-
p.cancel("Operation cancelled");
|
|
944
|
-
process.exit(0);
|
|
945
|
-
}
|
|
946
935
|
const testing = options.testing ??
|
|
947
|
-
(await p.select({
|
|
936
|
+
checkCancelled(await p.select({
|
|
948
937
|
message: "Testing framework",
|
|
949
938
|
options: [
|
|
950
939
|
{ value: "vitest", label: "Vitest", hint: "recommended" },
|
|
@@ -954,22 +943,15 @@ export const createApp = async (options = {}) => {
|
|
|
954
943
|
],
|
|
955
944
|
initialValue: "vitest",
|
|
956
945
|
}));
|
|
957
|
-
if (p.isCancel(testing)) {
|
|
958
|
-
p.cancel("Operation cancelled");
|
|
959
|
-
process.exit(0);
|
|
960
|
-
}
|
|
961
946
|
const claudeSkills = options.claudeSkills ??
|
|
962
|
-
(await p.confirm({
|
|
947
|
+
checkCancelled(await p.confirm({
|
|
963
948
|
message: "Include Claude Code skills?",
|
|
964
949
|
initialValue: true,
|
|
965
950
|
}));
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
}
|
|
970
|
-
const projectPath = resolve(process.cwd(), name);
|
|
971
|
-
const s = p.spinner();
|
|
972
|
-
s.start("Creating project structure...");
|
|
951
|
+
return { name, appId, packageManager, testing, claudeSkills };
|
|
952
|
+
};
|
|
953
|
+
const scaffoldProject = (projectPath, resolved) => {
|
|
954
|
+
const { name, appId, testing, claudeSkills } = resolved;
|
|
973
955
|
mkdirSync(projectPath, { recursive: true });
|
|
974
956
|
mkdirSync(join(projectPath, "src"), { recursive: true });
|
|
975
957
|
if (testing !== "none") {
|
|
@@ -998,9 +980,8 @@ export const createApp = async (options = {}) => {
|
|
|
998
980
|
else if (testing === "node") {
|
|
999
981
|
writeFileSync(join(projectPath, "tests", "app.test.tsx"), generateExampleTest(testing));
|
|
1000
982
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
installSpinner.start("Installing dependencies...");
|
|
983
|
+
};
|
|
984
|
+
const getDevDependencies = (testing) => {
|
|
1004
985
|
const devDeps = [...DEV_DEPENDENCIES];
|
|
1005
986
|
if (testing !== "none") {
|
|
1006
987
|
devDeps.push(...TESTING_DEV_DEPENDENCIES[testing]);
|
|
@@ -1008,6 +989,11 @@ export const createApp = async (options = {}) => {
|
|
|
1008
989
|
devDeps.push("tsx");
|
|
1009
990
|
}
|
|
1010
991
|
}
|
|
992
|
+
return devDeps;
|
|
993
|
+
};
|
|
994
|
+
const installDependencies = async (projectPath, name, packageManager, devDeps) => {
|
|
995
|
+
const installSpinner = p.spinner();
|
|
996
|
+
installSpinner.start("Installing dependencies...");
|
|
1011
997
|
try {
|
|
1012
998
|
const addCmd = getAddCommand(packageManager, DEPENDENCIES, false);
|
|
1013
999
|
await runCommand(addCmd, projectPath);
|
|
@@ -1023,9 +1009,10 @@ export const createApp = async (options = {}) => {
|
|
|
1023
1009
|
p.log.info(` ${getAddCommand(packageManager, DEPENDENCIES, false)}`);
|
|
1024
1010
|
p.log.info(` ${getAddCommand(packageManager, devDeps, true)}`);
|
|
1025
1011
|
}
|
|
1012
|
+
};
|
|
1013
|
+
const printNextSteps = (name, packageManager, testing) => {
|
|
1026
1014
|
const runCmd = getRunCommand(packageManager);
|
|
1027
|
-
const nextSteps = `cd ${name}
|
|
1028
|
-
${runCmd}`;
|
|
1015
|
+
const nextSteps = `cd ${name}\n${runCmd}`;
|
|
1029
1016
|
const testingNote = testing !== "none"
|
|
1030
1017
|
? `
|
|
1031
1018
|
|
|
@@ -1035,3 +1022,20 @@ To run tests, you need xvfb installed:
|
|
|
1035
1022
|
: "";
|
|
1036
1023
|
p.note(`${nextSteps}${testingNote}`, "Next steps");
|
|
1037
1024
|
};
|
|
1025
|
+
/**
|
|
1026
|
+
* Creates a new GTKX application with interactive prompts.
|
|
1027
|
+
* Scaffolds project structure, installs dependencies, and sets up configuration.
|
|
1028
|
+
* @param options - Pre-filled options to skip interactive prompts
|
|
1029
|
+
*/
|
|
1030
|
+
export const createApp = async (options = {}) => {
|
|
1031
|
+
p.intro("Create GTKX App");
|
|
1032
|
+
const resolved = await promptForOptions(options);
|
|
1033
|
+
const projectPath = resolve(process.cwd(), resolved.name);
|
|
1034
|
+
const s = p.spinner();
|
|
1035
|
+
s.start("Creating project structure...");
|
|
1036
|
+
scaffoldProject(projectPath, resolved);
|
|
1037
|
+
s.stop("Project structure created!");
|
|
1038
|
+
const devDeps = getDevDependencies(resolved.testing);
|
|
1039
|
+
await installDependencies(projectPath, resolved.name, resolved.packageManager, devDeps);
|
|
1040
|
+
printNextSteps(resolved.name, resolved.packageManager, resolved.testing);
|
|
1041
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "CLI for GTKX - create and develop GTK4 React applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtk",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"@clack/prompts": "0.11.0",
|
|
47
47
|
"@vitejs/plugin-react": "5.1.2",
|
|
48
48
|
"citty": "0.1.6",
|
|
49
|
-
"vite": "7.
|
|
50
|
-
"@gtkx/
|
|
51
|
-
"@gtkx/
|
|
49
|
+
"vite": "7.3.0",
|
|
50
|
+
"@gtkx/react": "0.7.0",
|
|
51
|
+
"@gtkx/ffi": "0.7.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"react": "^19"
|