create-gtkx 2.0.0-beta.1 → 2.0.0-beta.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/command.d.ts +9 -1
- package/dist/command.d.ts.map +1 -1
- package/dist/command.js +13 -1
- package/dist/command.js.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +10 -4
- package/dist/manifest.js.map +1 -1
- package/dist/package-managers.d.ts +3 -0
- package/dist/package-managers.d.ts.map +1 -1
- package/dist/package-managers.js +24 -3
- package/dist/package-managers.js.map +1 -1
- package/dist/scaffolder.d.ts +2 -0
- package/dist/scaffolder.d.ts.map +1 -1
- package/dist/scaffolder.js +161 -36
- package/dist/scaffolder.js.map +1 -1
- package/dist/templates/gtkx.config.ts.ejs +2 -3
- package/dist/templates/mise.toml.ejs +2 -0
- package/dist/templates/src/app.tsx.ejs +1 -1
- package/dist/templates.d.ts +1 -1
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js.map +1 -1
- package/package.json +3 -3
- package/src/command.ts +15 -1
- package/src/manifest.ts +10 -4
- package/src/package-managers.ts +24 -3
- package/src/scaffolder.ts +214 -41
- package/src/templates/gtkx.config.ts.ejs +2 -3
- package/src/templates/mise.toml.ejs +2 -0
- package/src/templates/src/app.tsx.ejs +1 -1
- package/src/templates.ts +1 -1
package/dist/command.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ declare const scaffoldCommand: import("citty").CommandDef<{
|
|
|
8
8
|
readonly type: "string";
|
|
9
9
|
readonly description: "Application ID (e.g., com.example.myapp)";
|
|
10
10
|
};
|
|
11
|
+
readonly "display-name": {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
readonly description: "Application display name (e.g., My App)";
|
|
14
|
+
};
|
|
11
15
|
readonly "package-manager": {
|
|
12
16
|
readonly type: "string";
|
|
13
17
|
readonly alias: "p";
|
|
@@ -34,7 +38,11 @@ declare const scaffoldCommand: import("citty").CommandDef<{
|
|
|
34
38
|
readonly overwrite: {
|
|
35
39
|
readonly type: "boolean";
|
|
36
40
|
readonly alias: "f";
|
|
37
|
-
readonly description: "
|
|
41
|
+
readonly description: "Replace scaffold files in a non-empty target directory when running without prompts";
|
|
42
|
+
};
|
|
43
|
+
readonly "skip-install": {
|
|
44
|
+
readonly type: "boolean";
|
|
45
|
+
readonly description: "Create the project without installing dependencies";
|
|
38
46
|
};
|
|
39
47
|
}>;
|
|
40
48
|
export { scaffoldCommand };
|
package/dist/command.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAqBA,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuDnB,CAAC;AAmCH,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/command.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
+
import { assertSupportedNodeVersion } from "@gtkx/config/internal";
|
|
2
3
|
import { errorMessage } from "@gtkx/utils";
|
|
3
4
|
import { defineCommand } from "citty";
|
|
4
5
|
import { OperationCanceledError, ScaffoldAbortedError } from "./errors.js";
|
|
@@ -19,6 +20,10 @@ const scaffoldCommand = defineCommand({
|
|
|
19
20
|
type: "string",
|
|
20
21
|
description: "Application ID (e.g., com.example.myapp)",
|
|
21
22
|
},
|
|
23
|
+
"display-name": {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Application display name (e.g., My App)",
|
|
26
|
+
},
|
|
22
27
|
"package-manager": {
|
|
23
28
|
type: "string",
|
|
24
29
|
alias: "p",
|
|
@@ -46,7 +51,11 @@ const scaffoldCommand = defineCommand({
|
|
|
46
51
|
overwrite: {
|
|
47
52
|
type: "boolean",
|
|
48
53
|
alias: "f",
|
|
49
|
-
description: "
|
|
54
|
+
description: "Replace scaffold files in a non-empty target directory when running without prompts",
|
|
55
|
+
},
|
|
56
|
+
"skip-install": {
|
|
57
|
+
type: "boolean",
|
|
58
|
+
description: "Create the project without installing dependencies",
|
|
50
59
|
},
|
|
51
60
|
},
|
|
52
61
|
run: ({ args }) => runCreate(args),
|
|
@@ -63,14 +72,17 @@ const settleScaffoldFailure = (error) => {
|
|
|
63
72
|
const runCreate = async (args) => {
|
|
64
73
|
const isInteractive = args["no-interactive"] || args.yes ? false : process.stdin.isTTY;
|
|
65
74
|
try {
|
|
75
|
+
assertSupportedNodeVersion();
|
|
66
76
|
await scaffold({
|
|
67
77
|
name: args.name,
|
|
68
78
|
applicationId: args["application-id"],
|
|
79
|
+
displayName: args["display-name"],
|
|
69
80
|
packageManager: args["package-manager"],
|
|
70
81
|
isTypescript: args.typescript,
|
|
71
82
|
shouldIncludeTesting: args.vitest,
|
|
72
83
|
isInteractive,
|
|
73
84
|
shouldOverwrite: args.overwrite,
|
|
85
|
+
shouldInstallDependencies: args["skip-install"] !== true,
|
|
74
86
|
});
|
|
75
87
|
}
|
|
76
88
|
catch (error) {
|
package/dist/command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"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","sourcesContent":["import * as p from \"@clack/prompts\";\nimport { assertSupportedNodeVersion } from \"@gtkx/config/internal\";\nimport { errorMessage } from \"@gtkx/utils\";\nimport { defineCommand } from \"citty\";\nimport { OperationCanceledError, ScaffoldAbortedError } from \"./errors.js\";\nimport { PACKAGE_MANAGER_FLAG_DESCRIPTION } from \"./package-managers.js\";\nimport { scaffold } from \"./scaffolder.js\";\n\ntype CreateCommandArgs = {\n name?: string | undefined;\n \"application-id\"?: string | undefined;\n \"display-name\"?: string | undefined;\n \"package-manager\"?: string | undefined;\n typescript?: boolean | undefined;\n vitest?: boolean | undefined;\n yes?: boolean | undefined;\n \"no-interactive\"?: boolean | undefined;\n overwrite?: boolean | undefined;\n \"skip-install\"?: boolean | undefined;\n};\n\nconst scaffoldCommand = defineCommand({\n meta: {\n name: \"create\",\n description: \"Create a new GTKX application\",\n },\n args: {\n name: {\n type: \"positional\",\n description: \"Target directory or project name (e.g. my-app, ., apps/my-app)\",\n required: false,\n },\n \"application-id\": {\n type: \"string\",\n description: \"Application ID (e.g., com.example.myapp)\",\n },\n \"display-name\": {\n type: \"string\",\n description: \"Application display name (e.g., My App)\",\n },\n \"package-manager\": {\n type: \"string\",\n alias: \"p\",\n description: PACKAGE_MANAGER_FLAG_DESCRIPTION,\n },\n typescript: {\n type: \"boolean\",\n negativeDescription: \"Scaffold the application in JavaScript instead of TypeScript\",\n description: \"Scaffold the application in TypeScript\",\n },\n vitest: {\n type: \"boolean\",\n description: \"Include a Vitest testing setup\",\n },\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Skip prompts and accept defaults for unspecified options\",\n },\n \"no-interactive\": {\n type: \"boolean\",\n description:\n \"Run without prompts, using the default for every option not passed on the command line \" +\n \"(same as --yes)\",\n },\n overwrite: {\n type: \"boolean\",\n alias: \"f\",\n description: \"Replace scaffold files in a non-empty target directory when running without prompts\",\n },\n \"skip-install\": {\n type: \"boolean\",\n description: \"Create the project without installing dependencies\",\n },\n },\n run: ({ args }) => runCreate(args),\n});\n\nconst settleScaffoldFailure = (error: unknown): void => {\n if (error instanceof OperationCanceledError) {\n return;\n }\n\n if (!(error instanceof ScaffoldAbortedError)) {\n p.log.error(errorMessage(error));\n }\n\n process.exitCode = 1;\n};\n\nconst runCreate = async (args: CreateCommandArgs): Promise<void> => {\n const isInteractive = args[\"no-interactive\"] || args.yes ? false : process.stdin.isTTY;\n\n try {\n assertSupportedNodeVersion();\n await scaffold({\n name: args.name,\n applicationId: args[\"application-id\"],\n displayName: args[\"display-name\"],\n packageManager: args[\"package-manager\"],\n isTypescript: args.typescript,\n shouldIncludeTesting: args.vitest,\n isInteractive,\n shouldOverwrite: args.overwrite,\n shouldInstallDependencies: args[\"skip-install\"] !== true,\n });\n } catch (error) {\n settleScaffoldFailure(error);\n }\n};\n\nexport { scaffoldCommand };\n"]}
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAMA,QAAA,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAAG,IAY3F,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/manifest.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
const PACKAGE_JSON_FILE = "package.json";
|
|
4
5
|
const updateManifest = (root, mutate) => {
|
|
5
6
|
const manifestPath = join(root, PACKAGE_JSON_FILE);
|
|
6
7
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
7
8
|
mutate(manifest);
|
|
8
|
-
const pendingPath =
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const pendingPath = join(root, `.package-${randomUUID()}.json`);
|
|
10
|
+
try {
|
|
11
|
+
writeFileSync(pendingPath, `${JSON.stringify(manifest, null, 4)}\n`, { flag: "wx", mode: 0o600 });
|
|
12
|
+
renameSync(pendingPath, manifestPath);
|
|
13
|
+
}
|
|
14
|
+
finally {
|
|
15
|
+
rmSync(pendingPath, { force: true });
|
|
16
|
+
}
|
|
11
17
|
};
|
|
12
18
|
export { updateManifest };
|
|
13
19
|
//# sourceMappingURL=manifest.js.map
|
package/dist/manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEzC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAE,MAAmD,EAAQ,EAAE;IAC/F,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAA4B,CAAC;IAC3F,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,UAAU,EAAE,OAAO,CAAC,CAAC;IAEhE,IAAI,CAAC;QACD,aAAa,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClG,UAAU,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC1C,CAAC;YAAS,CAAC;QACP,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;AACL,CAAC,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst PACKAGE_JSON_FILE = \"package.json\";\n\nconst updateManifest = (root: string, mutate: (manifest: Record<string, unknown>) => void): void => {\n const manifestPath = join(root, PACKAGE_JSON_FILE);\n const manifest = JSON.parse(readFileSync(manifestPath, \"utf8\")) as Record<string, unknown>;\n mutate(manifest);\n const pendingPath = join(root, `.package-${randomUUID()}.json`);\n\n try {\n writeFileSync(pendingPath, `${JSON.stringify(manifest, null, 4)}\\n`, { flag: \"wx\", mode: 0o600 });\n renameSync(pendingPath, manifestPath);\n } finally {\n rmSync(pendingPath, { force: true });\n }\n};\n\nexport { updateManifest };\n"]}
|
|
@@ -4,18 +4,21 @@ declare const PACKAGE_MANAGERS: readonly [{
|
|
|
4
4
|
readonly label: "pnpm";
|
|
5
5
|
readonly devCommand: "pnpm dev";
|
|
6
6
|
readonly addCommand: "pnpm add";
|
|
7
|
+
readonly installCommand: "pnpm install";
|
|
7
8
|
readonly isRecommended: true;
|
|
8
9
|
}, {
|
|
9
10
|
readonly value: "npm";
|
|
10
11
|
readonly label: "npm";
|
|
11
12
|
readonly devCommand: "npm run dev";
|
|
12
13
|
readonly addCommand: "npm install";
|
|
14
|
+
readonly installCommand: "npm install";
|
|
13
15
|
readonly isRecommended: false;
|
|
14
16
|
}, {
|
|
15
17
|
readonly value: "yarn";
|
|
16
18
|
readonly label: "yarn";
|
|
17
19
|
readonly devCommand: "yarn dev";
|
|
18
20
|
readonly addCommand: "yarn add";
|
|
21
|
+
readonly installCommand: "yarn install";
|
|
19
22
|
readonly isRecommended: false;
|
|
20
23
|
}];
|
|
21
24
|
declare const PACKAGE_MANAGER_VALUES: PackageManager[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-managers.d.ts","sourceRoot":"","sources":["../src/package-managers.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;AAEjE,QAAA,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"package-managers.d.ts","sourceRoot":"","sources":["../src/package-managers.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;AAEjE,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;EAyBZ,CAAC;AAEX,QAAA,MAAM,sBAAsB,EAAE,cAAc,EAAqD,CAAC;AAClG,QAAA,MAAM,gCAAgC,QAA2D,CAAC;AAElG,QAAA,MAAM,qBAAqB,GAAI,MAAM,MAAM,KAAG,IAAI,IAAI,cACC,CAAC;AAExD,OAAO,EACH,gBAAgB,EAChB,gCAAgC,EAChC,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,cAAc,GACtB,CAAC"}
|
package/dist/package-managers.js
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
const PACKAGE_MANAGERS = [
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
{
|
|
3
|
+
value: "pnpm",
|
|
4
|
+
label: "pnpm",
|
|
5
|
+
devCommand: "pnpm dev",
|
|
6
|
+
addCommand: "pnpm add",
|
|
7
|
+
installCommand: "pnpm install",
|
|
8
|
+
isRecommended: true,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
value: "npm",
|
|
12
|
+
label: "npm",
|
|
13
|
+
devCommand: "npm run dev",
|
|
14
|
+
addCommand: "npm install",
|
|
15
|
+
installCommand: "npm install",
|
|
16
|
+
isRecommended: false,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: "yarn",
|
|
20
|
+
label: "yarn",
|
|
21
|
+
devCommand: "yarn dev",
|
|
22
|
+
addCommand: "yarn add",
|
|
23
|
+
installCommand: "yarn install",
|
|
24
|
+
isRecommended: false,
|
|
25
|
+
},
|
|
5
26
|
];
|
|
6
27
|
const PACKAGE_MANAGER_VALUES = PACKAGE_MANAGERS.map((manager) => manager.value);
|
|
7
28
|
const PACKAGE_MANAGER_FLAG_DESCRIPTION = `Package manager (${PACKAGE_MANAGER_VALUES.join(", ")})`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-managers.js","sourceRoot":"","sources":["../src/package-managers.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG;IACrB,
|
|
1
|
+
{"version":3,"file":"package-managers.js","sourceRoot":"","sources":["../src/package-managers.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG;IACrB;QACI,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,MAAM;QACb,UAAU,EAAE,UAAU;QACtB,UAAU,EAAE,UAAU;QACtB,cAAc,EAAE,cAAc;QAC9B,aAAa,EAAE,IAAI;KACtB;IACD;QACI,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,KAAK;QACZ,UAAU,EAAE,aAAa;QACzB,UAAU,EAAE,aAAa;QACzB,cAAc,EAAE,aAAa;QAC7B,aAAa,EAAE,KAAK;KACvB;IACD;QACI,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,MAAM;QACb,UAAU,EAAE,UAAU;QACtB,UAAU,EAAE,UAAU;QACtB,cAAc,EAAE,cAAc;QAC9B,aAAa,EAAE,KAAK;KACvB;CACK,CAAC;AAEX,MAAM,sBAAsB,GAAqB,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAClG,MAAM,gCAAgC,GAAG,oBAAoB,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAElG,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAA0B,EAAE,CAClE,sBAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAExD,OAAO,EACH,gBAAgB,EAChB,gCAAgC,EAChC,sBAAsB,EACtB,qBAAqB,GAExB,CAAC","sourcesContent":["type PackageManager = (typeof PACKAGE_MANAGERS)[number][\"value\"];\n\nconst PACKAGE_MANAGERS = [\n {\n value: \"pnpm\",\n label: \"pnpm\",\n devCommand: \"pnpm dev\",\n addCommand: \"pnpm add\",\n installCommand: \"pnpm install\",\n isRecommended: true,\n },\n {\n value: \"npm\",\n label: \"npm\",\n devCommand: \"npm run dev\",\n addCommand: \"npm install\",\n installCommand: \"npm install\",\n isRecommended: false,\n },\n {\n value: \"yarn\",\n label: \"yarn\",\n devCommand: \"yarn dev\",\n addCommand: \"yarn add\",\n installCommand: \"yarn install\",\n isRecommended: false,\n },\n] as const;\n\nconst PACKAGE_MANAGER_VALUES: PackageManager[] = PACKAGE_MANAGERS.map((manager) => manager.value);\nconst PACKAGE_MANAGER_FLAG_DESCRIPTION = `Package manager (${PACKAGE_MANAGER_VALUES.join(\", \")})`;\n\nconst isKnownPackageManager = (name: string): name is PackageManager =>\n (PACKAGE_MANAGER_VALUES as string[]).includes(name);\n\nexport {\n PACKAGE_MANAGERS,\n PACKAGE_MANAGER_FLAG_DESCRIPTION,\n PACKAGE_MANAGER_VALUES,\n isKnownPackageManager,\n type PackageManager,\n};\n"]}
|
package/dist/scaffolder.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
type CreateOptions = {
|
|
2
2
|
name?: string | undefined;
|
|
3
3
|
applicationId?: string | undefined;
|
|
4
|
+
displayName?: string | undefined;
|
|
4
5
|
packageManager?: string | undefined;
|
|
5
6
|
isTypescript?: boolean | undefined;
|
|
6
7
|
shouldIncludeTesting?: boolean | undefined;
|
|
7
8
|
isInteractive?: boolean | undefined;
|
|
8
9
|
shouldOverwrite?: boolean | undefined;
|
|
10
|
+
shouldInstallDependencies?: boolean | undefined;
|
|
9
11
|
};
|
|
10
12
|
declare const scaffold: (options?: CreateOptions) => Promise<void>;
|
|
11
13
|
export { scaffold };
|
package/dist/scaffolder.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffolder.d.ts","sourceRoot":"","sources":["../src/scaffolder.ts"],"names":[],"mappings":"AAsBA,KAAK,aAAa,GAAG;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"scaffolder.d.ts","sourceRoot":"","sources":["../src/scaffolder.ts"],"names":[],"mappings":"AAsBA,KAAK,aAAa,GAAG;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnD,CAAC;AA4tBF,QAAA,MAAM,QAAQ,GAAU,UAAS,aAAkB,KAAG,OAAO,CAAC,IAAI,CAejE,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/scaffolder.js
CHANGED
|
@@ -2,8 +2,8 @@ import * as p from "@clack/prompts";
|
|
|
2
2
|
import { APPLICATION_ID_MAX_LENGTH, isValidApplicationId } from "@gtkx/config/internal";
|
|
3
3
|
import { errorMessage, tryResolveExecutable, upperFirst } from "@gtkx/utils";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
|
-
import { mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
5
|
+
import { lstatSync, mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
7
7
|
import { addDependency, detectPackageManager as nypmDetectPackageManager } from "nypm";
|
|
8
8
|
import { x } from "tinyexec";
|
|
9
9
|
import packageManifest from "../package.json" with { type: "json" };
|
|
@@ -25,6 +25,7 @@ const TYPESCRIPT_DEV_DEPENDENCIES = ["@types/node", "@types/react", "typescript"
|
|
|
25
25
|
const TESTING_DEV_DEPENDENCIES = ["@gtkx/testing", "vitest"];
|
|
26
26
|
const DEV_COMMAND = Object.fromEntries(PACKAGE_MANAGERS.map((manager) => [manager.value, manager.devCommand]));
|
|
27
27
|
const ADD_COMMAND = Object.fromEntries(PACKAGE_MANAGERS.map((manager) => [manager.value, manager.addCommand]));
|
|
28
|
+
const INSTALL_COMMAND = Object.fromEntries(PACKAGE_MANAGERS.map((manager) => [manager.value, manager.installCommand]));
|
|
28
29
|
const INHERITED_SCRIPT_POLICY_VARS = ["npm_config_allow_scripts", "npm_config_allow-scripts"];
|
|
29
30
|
const TESTING_TEMPLATES = new Set(["vitest.config.ts", "tests/app.test.tsx"]);
|
|
30
31
|
const TYPESCRIPT_TEMPLATES = new Set(["tsconfig.json", "src/gtkx-env.d.ts"]);
|
|
@@ -39,7 +40,7 @@ const APPLICATION_ID_PREFIX = "com.";
|
|
|
39
40
|
const APPLICATION_ID_SUFFIX = ".app";
|
|
40
41
|
const APPLICATION_ID_SEGMENT_LIMIT = APPLICATION_ID_MAX_LENGTH - APPLICATION_ID_PREFIX.length -
|
|
41
42
|
APPLICATION_ID_SUFFIX.length;
|
|
42
|
-
const
|
|
43
|
+
const displayNameFromProjectName = (name) => name.split("-").map((part) => upperFirst(part)).join(" ");
|
|
43
44
|
const gitConfigValue = (key) => {
|
|
44
45
|
const git = tryResolveExecutable("git");
|
|
45
46
|
if (git === undefined) {
|
|
@@ -71,6 +72,10 @@ const isDirEmpty = (dir) => {
|
|
|
71
72
|
const entries = readdirSync(dir);
|
|
72
73
|
return entries.length === 0 || (entries.length === 1 && entries[0] === ".git");
|
|
73
74
|
};
|
|
75
|
+
const shouldInitializeGit = (root) => {
|
|
76
|
+
const entry = lstatSync(root, { throwIfNoEntry: false });
|
|
77
|
+
return entry === undefined || (entry.isDirectory() && readdirSync(root).length === 0);
|
|
78
|
+
};
|
|
74
79
|
const getDevDependencies = ({ isTypescript, shouldIncludeTesting, }) => {
|
|
75
80
|
const devDeps = [...DEV_DEPENDENCIES];
|
|
76
81
|
if (isTypescript) {
|
|
@@ -100,6 +105,13 @@ const validateProjectName = (value) => {
|
|
|
100
105
|
const validateApplicationIdFormat = (value) => isValidApplicationId(value) ? undefined : APPLICATION_ID_FORMAT_ERROR;
|
|
101
106
|
const validateApplicationIdInput = (value) => value ? validateApplicationIdFormat(value) : "Application ID is required";
|
|
102
107
|
const validateApplicationIdAnswer = (value) => value ? validateApplicationIdFormat(value) : undefined;
|
|
108
|
+
const validateDisplayName = (value) => {
|
|
109
|
+
if (value === undefined || value.trim().length === 0) {
|
|
110
|
+
return "Display name is required";
|
|
111
|
+
}
|
|
112
|
+
return value.includes("\n") || value.includes("\r") ? "Display name must be a single line" : undefined;
|
|
113
|
+
};
|
|
114
|
+
const validateDisplayNameAnswer = (value) => value ? validateDisplayName(value) : undefined;
|
|
103
115
|
const fail = (message) => {
|
|
104
116
|
p.log.error(message);
|
|
105
117
|
throw new ScaffoldAbortedError(message);
|
|
@@ -134,6 +146,15 @@ const promptApplicationId = async (name) => {
|
|
|
134
146
|
validate: validateApplicationIdAnswer,
|
|
135
147
|
}));
|
|
136
148
|
};
|
|
149
|
+
const promptDisplayName = async (name) => {
|
|
150
|
+
const defaultDisplayName = displayNameFromProjectName(name);
|
|
151
|
+
return guardCancellation(await p.text({
|
|
152
|
+
message: "Display name",
|
|
153
|
+
placeholder: defaultDisplayName,
|
|
154
|
+
defaultValue: defaultDisplayName,
|
|
155
|
+
validate: validateDisplayNameAnswer,
|
|
156
|
+
}));
|
|
157
|
+
};
|
|
137
158
|
const packageManagerOption = (manager, detected) => {
|
|
138
159
|
let hint;
|
|
139
160
|
if (detected === manager.value) {
|
|
@@ -166,38 +187,30 @@ const isOptionEnabled = async (value, isInteractive, message) => value ??
|
|
|
166
187
|
(isInteractive
|
|
167
188
|
? guardCancellation(await p.confirm({ message, initialValue: true }))
|
|
168
189
|
: true);
|
|
169
|
-
const emptyDir = (root) => {
|
|
170
|
-
for (const entry of readdirSync(root)) {
|
|
171
|
-
if (entry === ".git") {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
rmSync(join(root, entry), { recursive: true, force: true });
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
190
|
const shouldOverwriteDirectory = async (target, options) => {
|
|
178
191
|
if (!options.isInteractive) {
|
|
179
192
|
return options.shouldOverwrite === true;
|
|
180
193
|
}
|
|
181
194
|
return guardCancellation(await p.confirm({
|
|
182
|
-
message: `Directory "${target}" is not empty.
|
|
195
|
+
message: `Directory "${target}" is not empty. Replace scaffold files?`,
|
|
183
196
|
initialValue: false,
|
|
184
197
|
}));
|
|
185
198
|
};
|
|
186
|
-
const
|
|
199
|
+
const validateTargetAvailability = async (root, target, options) => {
|
|
187
200
|
const stats = statSync(root, { throwIfNoEntry: false });
|
|
188
201
|
if (stats === undefined) {
|
|
189
|
-
return
|
|
202
|
+
return;
|
|
190
203
|
}
|
|
191
204
|
if (!stats.isDirectory()) {
|
|
192
205
|
return fail(`Target "${target}" is not a directory`);
|
|
193
206
|
}
|
|
194
207
|
if (isDirEmpty(root)) {
|
|
195
|
-
return
|
|
208
|
+
return;
|
|
196
209
|
}
|
|
197
210
|
if (await shouldOverwriteDirectory(target, options)) {
|
|
198
|
-
return
|
|
211
|
+
return;
|
|
199
212
|
}
|
|
200
|
-
|
|
213
|
+
fail(`Directory "${target}" is not empty`);
|
|
201
214
|
};
|
|
202
215
|
const resolveTarget = async (options) => {
|
|
203
216
|
if (options.name === undefined && options.isInteractive) {
|
|
@@ -213,6 +226,12 @@ const resolveApplicationId = async (options, name) => {
|
|
|
213
226
|
const error = validateApplicationIdInput(applicationId);
|
|
214
227
|
return error === undefined ? applicationId : fail(error);
|
|
215
228
|
};
|
|
229
|
+
const resolveDisplayName = async (options, name) => {
|
|
230
|
+
const value = options.displayName ??
|
|
231
|
+
(options.isInteractive ? await promptDisplayName(name) : displayNameFromProjectName(name));
|
|
232
|
+
const error = validateDisplayName(value);
|
|
233
|
+
return error === undefined ? value.trim() : fail(error);
|
|
234
|
+
};
|
|
216
235
|
const resolvePackageManager = async (requested, options) => {
|
|
217
236
|
if (requested !== undefined) {
|
|
218
237
|
return requested;
|
|
@@ -226,10 +245,12 @@ const resolveOptions = async (options) => {
|
|
|
226
245
|
const requested = requestedPackageManager(options.packageManager);
|
|
227
246
|
const target = await resolveTarget(options);
|
|
228
247
|
const name = deriveProjectName(target);
|
|
248
|
+
const displayName = await resolveDisplayName(options, name);
|
|
229
249
|
const applicationId = await resolveApplicationId(options, name);
|
|
230
250
|
const root = resolve(process.cwd(), target);
|
|
231
251
|
const isCurrentDirectory = root === process.cwd();
|
|
232
|
-
const
|
|
252
|
+
const shouldInitialize = shouldInitializeGit(root);
|
|
253
|
+
await validateTargetAvailability(root, target, options);
|
|
233
254
|
const packageManager = await resolvePackageManager(requested, options);
|
|
234
255
|
const isTypescript = await isOptionEnabled(options.isTypescript, options.isInteractive, "Use TypeScript?");
|
|
235
256
|
const shouldIncludeTesting = await isOptionEnabled(options.shouldIncludeTesting, options.isInteractive, "Include testing setup (Vitest)?");
|
|
@@ -238,11 +259,13 @@ const resolveOptions = async (options) => {
|
|
|
238
259
|
root,
|
|
239
260
|
isCurrentDirectory,
|
|
240
261
|
name,
|
|
262
|
+
displayName,
|
|
241
263
|
applicationId,
|
|
242
264
|
packageManager,
|
|
243
265
|
isTypescript,
|
|
244
266
|
shouldIncludeTesting,
|
|
245
|
-
|
|
267
|
+
shouldInitializeGit: shouldInitialize,
|
|
268
|
+
shouldInstallDependencies: options.shouldInstallDependencies !== false,
|
|
246
269
|
};
|
|
247
270
|
};
|
|
248
271
|
const isTemplateIncluded = (templateRelativePath, resolved) => {
|
|
@@ -263,22 +286,98 @@ const destinationPath = (template, resolved) => {
|
|
|
263
286
|
const templateContext = (resolved) => ({
|
|
264
287
|
name: resolved.name,
|
|
265
288
|
applicationId: resolved.applicationId,
|
|
266
|
-
|
|
289
|
+
displayName: resolved.displayName,
|
|
267
290
|
shouldIncludeTesting: resolved.shouldIncludeTesting,
|
|
268
291
|
isTypescript: resolved.isTypescript,
|
|
269
292
|
importExtension: resolved.isTypescript ? ".js" : ".jsx",
|
|
270
|
-
developerName: gitConfigValue("user.name") ??
|
|
293
|
+
developerName: gitConfigValue("user.name") ?? resolved.displayName,
|
|
271
294
|
developerEmail: gitConfigValue("user.email"),
|
|
272
295
|
});
|
|
273
|
-
const
|
|
296
|
+
const replaceTemplateDestination = (destination) => {
|
|
297
|
+
const entry = lstatSync(destination, { throwIfNoEntry: false });
|
|
298
|
+
if (entry === undefined) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (!entry.isFile() && !entry.isSymbolicLink()) {
|
|
302
|
+
fail(`Cannot replace scaffold file because its destination is not a file: ${destination}`);
|
|
303
|
+
}
|
|
304
|
+
rmSync(destination, { force: true });
|
|
305
|
+
};
|
|
306
|
+
const projectRelativeDestination = (root, destination) => {
|
|
307
|
+
const relativePath = relative(root, destination);
|
|
308
|
+
const isOutsideProject = relativePath.length === 0 || relativePath.startsWith(`..${sep}`) ||
|
|
309
|
+
isAbsolute(relativePath);
|
|
310
|
+
if (isOutsideProject) {
|
|
311
|
+
fail(`Scaffold destination is outside the project: ${destination}`);
|
|
312
|
+
}
|
|
313
|
+
return relativePath;
|
|
314
|
+
};
|
|
315
|
+
const assertRootIsNotSymbolicLink = (root) => {
|
|
316
|
+
const rootEntry = lstatSync(root, { throwIfNoEntry: false });
|
|
317
|
+
if (rootEntry?.isSymbolicLink()) {
|
|
318
|
+
fail(`Cannot scaffold through a symbolic link: ${root}`);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
const assertSafeAncestor = (ancestor) => {
|
|
322
|
+
const entry = lstatSync(ancestor, { throwIfNoEntry: false });
|
|
323
|
+
if (entry?.isSymbolicLink()) {
|
|
324
|
+
fail(`Cannot scaffold through a symbolic link: ${ancestor}`);
|
|
325
|
+
}
|
|
326
|
+
if (entry !== undefined && !entry.isDirectory()) {
|
|
327
|
+
fail(`Cannot scaffold through a non-directory path: ${ancestor}`);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
const assertSafeAncestors = (root, relativePath) => {
|
|
331
|
+
let ancestor = root;
|
|
332
|
+
const segments = relativePath.split(sep);
|
|
333
|
+
const ancestorSegments = segments.slice(0, -1);
|
|
334
|
+
for (const segment of ancestorSegments) {
|
|
335
|
+
ancestor = join(ancestor, segment);
|
|
336
|
+
assertSafeAncestor(ancestor);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
const assertReplaceableDestination = (destination) => {
|
|
340
|
+
const entry = lstatSync(destination, { throwIfNoEntry: false });
|
|
341
|
+
const isReplaceable = entry === undefined || entry.isFile() || entry.isSymbolicLink();
|
|
342
|
+
if (!isReplaceable) {
|
|
343
|
+
fail(`Cannot replace scaffold file because its destination is not a file: ${destination}`);
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
const assertSafeDestination = (root, destination) => {
|
|
347
|
+
const relativePath = projectRelativeDestination(root, destination);
|
|
348
|
+
assertRootIsNotSymbolicLink(root);
|
|
349
|
+
assertSafeAncestors(root, relativePath);
|
|
350
|
+
assertReplaceableDestination(destination);
|
|
351
|
+
};
|
|
352
|
+
const plannedScaffoldFiles = async (root, resolved) => {
|
|
274
353
|
const context = templateContext(resolved);
|
|
354
|
+
const files = [];
|
|
275
355
|
for (const template of listTemplates()) {
|
|
276
|
-
if (
|
|
277
|
-
|
|
356
|
+
if (isTemplateIncluded(template, resolved)) {
|
|
357
|
+
files.push({
|
|
358
|
+
destination: join(root, destinationPath(template, resolved)),
|
|
359
|
+
contents: await renderFile(template, context),
|
|
360
|
+
});
|
|
278
361
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
362
|
+
}
|
|
363
|
+
return files;
|
|
364
|
+
};
|
|
365
|
+
const auxiliaryDestinations = (root, resolved) => [
|
|
366
|
+
...(resolved.packageManager === "pnpm" ? [join(root, "pnpm-workspace.yaml")] : []),
|
|
367
|
+
...(resolved.isTypescript ? [join(root, "node_modules", ".gtkx", "env.d.ts")] : []),
|
|
368
|
+
];
|
|
369
|
+
const scaffoldProject = async (root, resolved) => {
|
|
370
|
+
const files = await plannedScaffoldFiles(root, resolved);
|
|
371
|
+
const destinations = [...files.map((file) => file.destination), ...auxiliaryDestinations(root, resolved)];
|
|
372
|
+
for (const destination of destinations) {
|
|
373
|
+
assertSafeDestination(root, destination);
|
|
374
|
+
}
|
|
375
|
+
for (const destination of destinations) {
|
|
376
|
+
replaceTemplateDestination(destination);
|
|
377
|
+
}
|
|
378
|
+
for (const file of files) {
|
|
379
|
+
mkdirSync(dirname(file.destination), { recursive: true });
|
|
380
|
+
writeFileSync(file.destination, file.contents);
|
|
282
381
|
}
|
|
283
382
|
if (resolved.shouldIncludeTesting) {
|
|
284
383
|
updateManifest(root, (manifest) => {
|
|
@@ -309,6 +408,13 @@ const installDependencies = async (options) => {
|
|
|
309
408
|
});
|
|
310
409
|
};
|
|
311
410
|
const pin = (names) => names.map((dependency) => dependency.startsWith("@gtkx/") ? `${dependency}@^${selfVersion}` : dependency);
|
|
411
|
+
const dependencyVersions = (names) => Object.fromEntries(names.map((dependency) => [dependency, dependency.startsWith("@gtkx/") ? `^${selfVersion}` : "latest"]));
|
|
412
|
+
const writeDependencies = (root, devDependencies) => {
|
|
413
|
+
updateManifest(root, (manifest) => {
|
|
414
|
+
manifest.dependencies = dependencyVersions(DEPENDENCIES);
|
|
415
|
+
manifest.devDependencies = dependencyVersions(devDependencies);
|
|
416
|
+
});
|
|
417
|
+
};
|
|
312
418
|
const formatRecovery = ({ resolved, devDependencies }) => {
|
|
313
419
|
const add = ADD_COMMAND[resolved.packageManager];
|
|
314
420
|
const steps = [
|
|
@@ -361,7 +467,23 @@ const writeInitialEnvModule = (root) => {
|
|
|
361
467
|
mkdirSync(storeDir, { recursive: true });
|
|
362
468
|
writeFileSync(join(storeDir, "env.d.ts"), `${GTKX_ENV_MODULE_HEADER}\n`);
|
|
363
469
|
};
|
|
364
|
-
const
|
|
470
|
+
const isInsideGitRepository = (root) => {
|
|
471
|
+
const git = tryResolveExecutable("git");
|
|
472
|
+
if (git === undefined) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
try {
|
|
476
|
+
execFileSync(git, ["-C", root, "rev-parse", "--show-toplevel"], { stdio: "ignore" });
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const initializeGitRepo = async (root, shouldInitialize) => {
|
|
484
|
+
if (!shouldInitialize || isInsideGitRepository(root)) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
365
487
|
const spinner = p.spinner();
|
|
366
488
|
spinner.start("Initializing git repository...");
|
|
367
489
|
try {
|
|
@@ -378,8 +500,9 @@ const initializeGitRepo = async (root) => {
|
|
|
378
500
|
const printNextSteps = (resolved) => {
|
|
379
501
|
const devCmd = DEV_COMMAND[resolved.packageManager];
|
|
380
502
|
const cdStep = resolved.isCurrentDirectory ? "" : `cd ${resolved.target}\n`;
|
|
503
|
+
const installStep = resolved.shouldInstallDependencies ? "" : `${INSTALL_COMMAND[resolved.packageManager]}\n`;
|
|
381
504
|
const testingNote = resolved.shouldIncludeTesting ? HEADLESS_COMPOSITOR_NOTE : "";
|
|
382
|
-
p.note(`${cdStep}${devCmd}${testingNote}`, "Next steps");
|
|
505
|
+
p.note(`${cdStep}${installStep}${devCmd}${testingNote}`, "Next steps");
|
|
383
506
|
};
|
|
384
507
|
const createProjectStructure = async (root, resolved) => {
|
|
385
508
|
await runWithSpinner({
|
|
@@ -388,11 +511,11 @@ const createProjectStructure = async (root, resolved) => {
|
|
|
388
511
|
failed: "Failed to create the project structure",
|
|
389
512
|
run: async () => {
|
|
390
513
|
mkdirSync(root, { recursive: true });
|
|
391
|
-
if (resolved.shouldEmptyTarget) {
|
|
392
|
-
emptyDir(root);
|
|
393
|
-
}
|
|
394
514
|
await scaffoldProject(root, resolved);
|
|
395
515
|
writeBuildAllowance(root, resolved.packageManager);
|
|
516
|
+
if (resolved.isTypescript) {
|
|
517
|
+
writeInitialEnvModule(root);
|
|
518
|
+
}
|
|
396
519
|
},
|
|
397
520
|
});
|
|
398
521
|
};
|
|
@@ -402,11 +525,13 @@ const scaffold = async (options = {}) => {
|
|
|
402
525
|
const { root } = resolved;
|
|
403
526
|
const devDeps = getDevDependencies(resolved);
|
|
404
527
|
await createProjectStructure(root, resolved);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
528
|
+
if (resolved.shouldInstallDependencies) {
|
|
529
|
+
await installAllDependencies({ resolved, devDependencies: devDeps });
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
writeDependencies(root, devDeps);
|
|
408
533
|
}
|
|
409
|
-
await initializeGitRepo(root);
|
|
534
|
+
await initializeGitRepo(root, resolved.shouldInitializeGit);
|
|
410
535
|
printNextSteps(resolved);
|
|
411
536
|
};
|
|
412
537
|
export { scaffold };
|