create-zenith 1.3.18 → 1.3.20
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 +24 -1
- package/dist/cli.js +297 -60
- package/dist/index.js +297 -60
- package/package.json +4 -4
- package/templates/basic/LICENSE +21 -0
- package/templates/basic/README.md +11 -0
- package/templates/basic/package.json +18 -0
- package/templates/basic/src/layouts/DefaultLayout.zen +20 -0
- package/templates/basic/src/pages/index.zen +24 -0
- package/templates/basic/src/public/logo.svg +601 -0
- package/templates/basic/src/styles/global.css +61 -0
- package/templates/basic/tsconfig.json +30 -0
- package/templates/basic/zenith.config.js +5 -0
- package/templates/css/LICENSE +21 -0
- package/templates/css/README.md +11 -0
- package/templates/css/package.json +18 -0
- package/templates/css/src/layouts/DefaultLayout.zen +26 -0
- package/templates/css/src/pages/about.zen +19 -0
- package/templates/css/src/pages/blog.zen +19 -0
- package/templates/css/src/pages/docs.zen +19 -0
- package/templates/css/src/pages/index.zen +26 -0
- package/templates/css/src/public/logo.svg +601 -0
- package/templates/css/src/styles/global.css +66 -0
- package/templates/css/tsconfig.json +30 -0
- package/templates/css/zenith.config.js +4 -0
- package/templates/features/eslint/eslint.config.js +30 -0
- package/templates/features/prettier/.prettierignore +3 -0
- package/templates/features/prettier/.prettierrc +7 -0
- package/templates/tailwind/LICENSE +21 -0
- package/templates/tailwind/README.md +11 -0
- package/templates/tailwind/package.json +20 -0
- package/templates/tailwind/src/layouts/DefaultLayout.zen +28 -0
- package/templates/tailwind/src/pages/about.zen +20 -0
- package/templates/tailwind/src/pages/blog.zen +19 -0
- package/templates/tailwind/src/pages/docs.zen +19 -0
- package/templates/tailwind/src/pages/index.zen +31 -0
- package/templates/tailwind/src/public/logo.svg +601 -0
- package/templates/tailwind/src/styles/globals.css +3 -0
- package/templates/tailwind/tsconfig.json +30 -0
- package/templates/tailwind/zenith.config.js +4 -0
package/README.md
CHANGED
|
@@ -17,7 +17,8 @@ The official CLI for scaffolding new Zenith applications. Fast, animated, and de
|
|
|
17
17
|
- **Interactive UX**: Built with `@clack/prompts` for intuitive arrow-key navigation and clear visual indicators.
|
|
18
18
|
- **Reliable Fallbacks**: Automatically detects CI environments and non-TTY pipes to provide clean, static output.
|
|
19
19
|
- **Smart Detection**: automatically detects your preferred package manager (Bun, pnpm, Yarn, or npm).
|
|
20
|
-
- **
|
|
20
|
+
- **Template Authority**: Scaffold generation now reads only from `templates/` (`basic`, `css`, `tailwind`), which is the single source of truth for starter projects.
|
|
21
|
+
- **Tool-Agnostic Output**: ESLint, Prettier, and TypeScript path aliases are opt-in. If you answer `No`, the generated project contains no scripts, dependencies, config files, or ignore files for that tool.
|
|
21
22
|
|
|
22
23
|
## Quick Start
|
|
23
24
|
|
|
@@ -40,6 +41,21 @@ pnpm create zenith
|
|
|
40
41
|
| `-h, --help` | Show usage information |
|
|
41
42
|
| `-v, --version` | Show version number |
|
|
42
43
|
|
|
44
|
+
## Optional Tooling Contract
|
|
45
|
+
|
|
46
|
+
During scaffold, `create-zenith` asks whether to include:
|
|
47
|
+
|
|
48
|
+
- ESLint
|
|
49
|
+
- Prettier
|
|
50
|
+
- TypeScript path aliases
|
|
51
|
+
|
|
52
|
+
Tooling behavior is strict:
|
|
53
|
+
|
|
54
|
+
- If you enable ESLint, the project gets `eslint.config.js`, lint scripts, and matching ESLint dependencies.
|
|
55
|
+
- If you disable ESLint, the project contains zero ESLint references.
|
|
56
|
+
- If you enable Prettier, the project gets `.prettierrc`, `.prettierignore`, a format script, and the Prettier dependency.
|
|
57
|
+
- If you disable Prettier, the project contains zero Prettier references.
|
|
58
|
+
|
|
43
59
|
## Beta Version Pinning
|
|
44
60
|
|
|
45
61
|
Zenith beta currently pins `@zenithbuild/core` to `0.5.0-beta.2.20` and leaf packages (compiler, cli, runtime, router, bundler) to `0.5.0-beta.2.20`. This is intentional — core contains the CLI entry point and may bump independently for bin/CLI fixes without touching the engine.
|
|
@@ -50,8 +66,15 @@ If you see version mismatches after install, delete `node_modules` and `package-
|
|
|
50
66
|
|
|
51
67
|
- Generated apps now depend on `@zenithbuild/core@latest` so new installs track the current stable framework release.
|
|
52
68
|
- Template downloads now resolve from `zenithbuild/framework`, which is the active monorepo source of truth.
|
|
69
|
+
- Starter templates now live under `templates/`, and the scaffolder no longer depends on `examples/`.
|
|
70
|
+
- ESLint and Prettier are now feature overlays, so opting out leaves no stray config or dependency references in the scaffolded app.
|
|
53
71
|
- Verified scaffold → install → build coverage lives in `tests/template-regression.spec.mjs`.
|
|
54
72
|
|
|
73
|
+
## Templates vs Examples
|
|
74
|
+
|
|
75
|
+
- `templates/` is authoritative for scaffolding.
|
|
76
|
+
- `examples/` is demo-only when present and is not part of the scaffold source of truth.
|
|
77
|
+
|
|
55
78
|
## Development
|
|
56
79
|
|
|
57
80
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -2553,6 +2553,33 @@ class dD extends x {
|
|
|
2553
2553
|
}
|
|
2554
2554
|
var A;
|
|
2555
2555
|
A = new WeakMap;
|
|
2556
|
+
var OD = Object.defineProperty;
|
|
2557
|
+
var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
|
|
2558
|
+
var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
|
|
2559
|
+
|
|
2560
|
+
class LD extends x {
|
|
2561
|
+
constructor(u) {
|
|
2562
|
+
super(u, false), J(this, "options"), J(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: t }) => t === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
|
|
2563
|
+
switch (t) {
|
|
2564
|
+
case "left":
|
|
2565
|
+
case "up":
|
|
2566
|
+
this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
|
|
2567
|
+
break;
|
|
2568
|
+
case "down":
|
|
2569
|
+
case "right":
|
|
2570
|
+
this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
|
|
2571
|
+
break;
|
|
2572
|
+
}
|
|
2573
|
+
this.changeValue();
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
get _value() {
|
|
2577
|
+
return this.options[this.cursor];
|
|
2578
|
+
}
|
|
2579
|
+
changeValue() {
|
|
2580
|
+
this.value = this._value.value;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2556
2583
|
class RD extends x {
|
|
2557
2584
|
get valueWithCursor() {
|
|
2558
2585
|
if (this.state === "submit")
|
|
@@ -2615,6 +2642,16 @@ var b2 = (t) => {
|
|
|
2615
2642
|
return import_picocolors3.default.green(C);
|
|
2616
2643
|
}
|
|
2617
2644
|
};
|
|
2645
|
+
var G2 = (t) => {
|
|
2646
|
+
const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
|
|
2647
|
+
let l2 = 0;
|
|
2648
|
+
n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
|
|
2649
|
+
const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
|
|
2650
|
+
return r2.slice(l2, l2 + a).map((p2, v2, f) => {
|
|
2651
|
+
const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
|
|
2652
|
+
return j2 || E ? import_picocolors3.default.dim("...") : i(p2, v2 + l2 === n);
|
|
2653
|
+
});
|
|
2654
|
+
};
|
|
2618
2655
|
var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
|
|
2619
2656
|
const n = `${import_picocolors3.default.gray(o)}
|
|
2620
2657
|
${b2(this.state)} ${t.message}
|
|
@@ -2655,6 +2692,38 @@ ${import_picocolors3.default.cyan(d2)}
|
|
|
2655
2692
|
}
|
|
2656
2693
|
} }).prompt();
|
|
2657
2694
|
};
|
|
2695
|
+
var ve = (t) => {
|
|
2696
|
+
const n = (r2, i) => {
|
|
2697
|
+
const s = r2.label ?? String(r2.value);
|
|
2698
|
+
switch (i) {
|
|
2699
|
+
case "selected":
|
|
2700
|
+
return `${import_picocolors3.default.dim(s)}`;
|
|
2701
|
+
case "active":
|
|
2702
|
+
return `${import_picocolors3.default.green(k2)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}`;
|
|
2703
|
+
case "cancelled":
|
|
2704
|
+
return `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}`;
|
|
2705
|
+
default:
|
|
2706
|
+
return `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(s)}`;
|
|
2707
|
+
}
|
|
2708
|
+
};
|
|
2709
|
+
return new LD({ options: t.options, initialValue: t.initialValue, render() {
|
|
2710
|
+
const r2 = `${import_picocolors3.default.gray(o)}
|
|
2711
|
+
${b2(this.state)} ${t.message}
|
|
2712
|
+
`;
|
|
2713
|
+
switch (this.state) {
|
|
2714
|
+
case "submit":
|
|
2715
|
+
return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
|
|
2716
|
+
case "cancel":
|
|
2717
|
+
return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
|
|
2718
|
+
${import_picocolors3.default.gray(o)}`;
|
|
2719
|
+
default:
|
|
2720
|
+
return `${r2}${import_picocolors3.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
|
|
2721
|
+
${import_picocolors3.default.cyan(o)} `)}
|
|
2722
|
+
${import_picocolors3.default.cyan(d2)}
|
|
2723
|
+
`;
|
|
2724
|
+
}
|
|
2725
|
+
} }).prompt();
|
|
2726
|
+
};
|
|
2658
2727
|
var xe = (t = "") => {
|
|
2659
2728
|
process.stdout.write(`${import_picocolors3.default.gray(d2)} ${import_picocolors3.default.red(t)}
|
|
2660
2729
|
|
|
@@ -2687,7 +2756,7 @@ var M2 = { message: (t = "", { symbol: n = import_picocolors3.default.gray(o) }
|
|
|
2687
2756
|
}, error: (t) => {
|
|
2688
2757
|
M2.message(t, { symbol: import_picocolors3.default.red(K2) });
|
|
2689
2758
|
} };
|
|
2690
|
-
var
|
|
2759
|
+
var J2 = `${import_picocolors3.default.gray(o)} `;
|
|
2691
2760
|
var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
2692
2761
|
const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
|
|
2693
2762
|
let s, c, a = false, l2 = "", $2, g2 = performance.now();
|
|
@@ -2777,6 +2846,12 @@ async function confirm(opts) {
|
|
|
2777
2846
|
initialValue: opts.initialValue ?? true
|
|
2778
2847
|
});
|
|
2779
2848
|
}
|
|
2849
|
+
async function select(opts) {
|
|
2850
|
+
if (!isTTY()) {
|
|
2851
|
+
return opts.initialValue || opts.options[0]?.value;
|
|
2852
|
+
}
|
|
2853
|
+
return await ve(opts);
|
|
2854
|
+
}
|
|
2780
2855
|
function isCancel(value) {
|
|
2781
2856
|
return pD(value);
|
|
2782
2857
|
}
|
|
@@ -2819,10 +2894,124 @@ var log = {
|
|
|
2819
2894
|
message: (message) => getUiMode(process).plain ? console.log(message) : M2.message(message)
|
|
2820
2895
|
};
|
|
2821
2896
|
|
|
2897
|
+
// src/template-features.ts
|
|
2898
|
+
var FEATURE_DEFINITIONS = {
|
|
2899
|
+
eslint: {
|
|
2900
|
+
templatePath: "templates/features/eslint",
|
|
2901
|
+
packagePatch: {
|
|
2902
|
+
scripts: {
|
|
2903
|
+
lint: "eslint ."
|
|
2904
|
+
},
|
|
2905
|
+
devDependencies: {
|
|
2906
|
+
eslint: "^9.39.2",
|
|
2907
|
+
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
2908
|
+
"@typescript-eslint/parser": "^8.53.0"
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
},
|
|
2912
|
+
prettier: {
|
|
2913
|
+
templatePath: "templates/features/prettier",
|
|
2914
|
+
packagePatch: {
|
|
2915
|
+
scripts: {
|
|
2916
|
+
format: "prettier --write ."
|
|
2917
|
+
},
|
|
2918
|
+
devDependencies: {
|
|
2919
|
+
prettier: "^3.7.4"
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
};
|
|
2924
|
+
function mergeRecord(target, patch) {
|
|
2925
|
+
if (!patch) {
|
|
2926
|
+
return target;
|
|
2927
|
+
}
|
|
2928
|
+
return { ...target || {}, ...patch };
|
|
2929
|
+
}
|
|
2930
|
+
function selectedTemplateFeaturePaths(options) {
|
|
2931
|
+
const paths = [];
|
|
2932
|
+
if (options.eslint) {
|
|
2933
|
+
paths.push(FEATURE_DEFINITIONS.eslint.templatePath);
|
|
2934
|
+
}
|
|
2935
|
+
if (options.prettier) {
|
|
2936
|
+
paths.push(FEATURE_DEFINITIONS.prettier.templatePath);
|
|
2937
|
+
}
|
|
2938
|
+
return paths;
|
|
2939
|
+
}
|
|
2940
|
+
function applyPackageFeatures(manifest, options) {
|
|
2941
|
+
const nextManifest = {
|
|
2942
|
+
...manifest,
|
|
2943
|
+
scripts: { ...manifest.scripts || {} },
|
|
2944
|
+
devDependencies: { ...manifest.devDependencies || {} }
|
|
2945
|
+
};
|
|
2946
|
+
for (const featureName of Object.keys(FEATURE_DEFINITIONS)) {
|
|
2947
|
+
if (!options[featureName]) {
|
|
2948
|
+
continue;
|
|
2949
|
+
}
|
|
2950
|
+
const patch = FEATURE_DEFINITIONS[featureName].packagePatch;
|
|
2951
|
+
nextManifest.scripts = mergeRecord(nextManifest.scripts, patch.scripts);
|
|
2952
|
+
nextManifest.devDependencies = mergeRecord(nextManifest.devDependencies, patch.devDependencies);
|
|
2953
|
+
}
|
|
2954
|
+
if (nextManifest.scripts && Object.keys(nextManifest.scripts).length === 0) {
|
|
2955
|
+
delete nextManifest.scripts;
|
|
2956
|
+
}
|
|
2957
|
+
if (nextManifest.devDependencies && Object.keys(nextManifest.devDependencies).length === 0) {
|
|
2958
|
+
delete nextManifest.devDependencies;
|
|
2959
|
+
}
|
|
2960
|
+
return nextManifest;
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
// src/templates.ts
|
|
2964
|
+
var DEFAULT_TEMPLATE = "css";
|
|
2965
|
+
var TEMPLATE_DEFINITIONS = {
|
|
2966
|
+
basic: {
|
|
2967
|
+
name: "basic",
|
|
2968
|
+
label: "Basic",
|
|
2969
|
+
hint: "Blank starter with a single page and minimal CSS",
|
|
2970
|
+
templatePath: "templates/basic",
|
|
2971
|
+
usesTailwind: false
|
|
2972
|
+
},
|
|
2973
|
+
css: {
|
|
2974
|
+
name: "css",
|
|
2975
|
+
label: "CSS",
|
|
2976
|
+
hint: "Multi-page starter with a small curated CSS setup",
|
|
2977
|
+
templatePath: "templates/css",
|
|
2978
|
+
usesTailwind: false
|
|
2979
|
+
},
|
|
2980
|
+
tailwind: {
|
|
2981
|
+
name: "tailwind",
|
|
2982
|
+
label: "Tailwind",
|
|
2983
|
+
hint: "Multi-page starter with Tailwind enabled",
|
|
2984
|
+
templatePath: "templates/tailwind",
|
|
2985
|
+
usesTailwind: true
|
|
2986
|
+
}
|
|
2987
|
+
};
|
|
2988
|
+
var TEMPLATE_ALIASES = {
|
|
2989
|
+
starter: "css",
|
|
2990
|
+
"starter-tailwindcss": "tailwind"
|
|
2991
|
+
};
|
|
2992
|
+
function resolveTemplateName(value) {
|
|
2993
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
2994
|
+
if (!normalized) {
|
|
2995
|
+
return null;
|
|
2996
|
+
}
|
|
2997
|
+
if (normalized in TEMPLATE_DEFINITIONS) {
|
|
2998
|
+
return normalized;
|
|
2999
|
+
}
|
|
3000
|
+
return TEMPLATE_ALIASES[normalized] || null;
|
|
3001
|
+
}
|
|
3002
|
+
function getTemplateDefinition(templateName) {
|
|
3003
|
+
return TEMPLATE_DEFINITIONS[templateName];
|
|
3004
|
+
}
|
|
3005
|
+
function templateSelectOptions() {
|
|
3006
|
+
return Object.values(TEMPLATE_DEFINITIONS).map((definition) => ({
|
|
3007
|
+
value: definition.name,
|
|
3008
|
+
label: definition.label,
|
|
3009
|
+
hint: definition.hint
|
|
3010
|
+
}));
|
|
3011
|
+
}
|
|
3012
|
+
|
|
2822
3013
|
// src/index.ts
|
|
2823
3014
|
var GITHUB_REPO = "zenithbuild/framework";
|
|
2824
|
-
var DEFAULT_TEMPLATE = "examples/starter";
|
|
2825
|
-
var TAILWIND_TEMPLATE = "examples/starter-tailwindcss";
|
|
2826
3015
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
2827
3016
|
var __dirname2 = path.dirname(__filename2);
|
|
2828
3017
|
function getCliVersion() {
|
|
@@ -2845,6 +3034,15 @@ function resolveLocalTemplatePath(templatePath) {
|
|
|
2845
3034
|
const candidate = path.resolve(__dirname2, "..", templatePath);
|
|
2846
3035
|
return fs.existsSync(candidate) ? candidate : null;
|
|
2847
3036
|
}
|
|
3037
|
+
function copyDirectoryContents(sourceDir, targetDir) {
|
|
3038
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
3039
|
+
for (const entry of fs.readdirSync(sourceDir)) {
|
|
3040
|
+
fs.cpSync(path.join(sourceDir, entry), path.join(targetDir, entry), {
|
|
3041
|
+
recursive: true,
|
|
3042
|
+
force: true
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
2848
3046
|
function detectPackageManager() {
|
|
2849
3047
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
2850
3048
|
if (userAgent.includes("bun"))
|
|
@@ -2875,16 +3073,22 @@ function hasGit() {
|
|
|
2875
3073
|
return false;
|
|
2876
3074
|
}
|
|
2877
3075
|
}
|
|
2878
|
-
async function downloadTemplate(targetDir,
|
|
2879
|
-
const
|
|
3076
|
+
async function downloadTemplate(targetDir, templatePaths) {
|
|
3077
|
+
const localTemplatePaths = templatePaths.map((templatePath) => ({
|
|
3078
|
+
templatePath,
|
|
3079
|
+
localPath: resolveLocalTemplatePath(templatePath)
|
|
3080
|
+
}));
|
|
2880
3081
|
const forceLocal = process.env.CREATE_ZENITH_TEMPLATE_MODE === "local" || flagEnabled2(process.env.CREATE_ZENITH_OFFLINE);
|
|
2881
3082
|
const preferLocal = process.env.CREATE_ZENITH_PREFER_LOCAL !== "0";
|
|
2882
|
-
if (
|
|
2883
|
-
|
|
3083
|
+
if (localTemplatePaths.every((entry) => entry.localPath) && (forceLocal || preferLocal)) {
|
|
3084
|
+
for (const entry of localTemplatePaths) {
|
|
3085
|
+
copyDirectoryContents(entry.localPath, targetDir);
|
|
3086
|
+
}
|
|
2884
3087
|
return;
|
|
2885
3088
|
}
|
|
2886
|
-
if (forceLocal
|
|
2887
|
-
|
|
3089
|
+
if (forceLocal) {
|
|
3090
|
+
const missingPath = localTemplatePaths.find((entry) => !entry.localPath)?.templatePath;
|
|
3091
|
+
throw new Error(`Local template not found: ${missingPath}`);
|
|
2888
3092
|
}
|
|
2889
3093
|
const tempDir = path.join(os2.tmpdir(), `zenith-template-${Date.now()}`);
|
|
2890
3094
|
try {
|
|
@@ -2892,13 +3096,15 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2892
3096
|
execSync(`git clone --depth 1 --filter=blob:none --sparse https://github.com/${GITHUB_REPO}.git "${tempDir}"`, {
|
|
2893
3097
|
stdio: "pipe"
|
|
2894
3098
|
});
|
|
2895
|
-
const
|
|
2896
|
-
execSync(`git sparse-checkout set ${
|
|
3099
|
+
const repoTemplatePaths = templatePaths.map((templatePath) => `packages/create-zenith/${templatePath}`);
|
|
3100
|
+
execSync(`git sparse-checkout set ${repoTemplatePaths.join(" ")}`, {
|
|
2897
3101
|
cwd: tempDir,
|
|
2898
3102
|
stdio: "pipe"
|
|
2899
3103
|
});
|
|
2900
|
-
const
|
|
2901
|
-
|
|
3104
|
+
for (const repoTemplatePath of repoTemplatePaths) {
|
|
3105
|
+
const templateSource = path.join(tempDir, repoTemplatePath);
|
|
3106
|
+
copyDirectoryContents(templateSource, targetDir);
|
|
3107
|
+
}
|
|
2902
3108
|
} else {
|
|
2903
3109
|
const tarballUrl = `https://github.com/${GITHUB_REPO}/archive/refs/heads/main.tar.gz`;
|
|
2904
3110
|
const tarballPath = path.join(os2.tmpdir(), `zenith-${Date.now()}.tar.gz`);
|
|
@@ -2909,8 +3115,10 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2909
3115
|
if (!extractedDir) {
|
|
2910
3116
|
throw new Error("Failed to extract template from GitHub");
|
|
2911
3117
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
3118
|
+
for (const templatePath of templatePaths) {
|
|
3119
|
+
const templateSource = path.join(tempDir, extractedDir, "packages/create-zenith", templatePath);
|
|
3120
|
+
copyDirectoryContents(templateSource, targetDir);
|
|
3121
|
+
}
|
|
2914
3122
|
fs.unlinkSync(tarballPath);
|
|
2915
3123
|
}
|
|
2916
3124
|
} finally {
|
|
@@ -2919,7 +3127,30 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2919
3127
|
}
|
|
2920
3128
|
}
|
|
2921
3129
|
}
|
|
2922
|
-
|
|
3130
|
+
function readOptionOverride(name) {
|
|
3131
|
+
const value = process.env[name];
|
|
3132
|
+
if (value == null || value.trim() === "") {
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
return flagEnabled2(value);
|
|
3136
|
+
}
|
|
3137
|
+
function readTemplateOverride(name) {
|
|
3138
|
+
const value = process.env[name];
|
|
3139
|
+
if (value == null || value.trim() === "") {
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
const templateName = resolveTemplateName(value);
|
|
3143
|
+
if (!templateName) {
|
|
3144
|
+
throw new Error(`Unsupported template "${value}". Use basic, css, or tailwind.`);
|
|
3145
|
+
}
|
|
3146
|
+
return templateName;
|
|
3147
|
+
}
|
|
3148
|
+
async function gatherOptions(providedName, requestedTemplate) {
|
|
3149
|
+
const eslintOverride = readOptionOverride("CREATE_ZENITH_ESLINT");
|
|
3150
|
+
const prettierOverride = readOptionOverride("CREATE_ZENITH_PRETTIER");
|
|
3151
|
+
const pathAliasOverride = readOptionOverride("CREATE_ZENITH_PATH_ALIAS");
|
|
3152
|
+
const templateOverride = readTemplateOverride("CREATE_ZENITH_TEMPLATE");
|
|
3153
|
+
const selectedTemplate = requestedTemplate || templateOverride || DEFAULT_TEMPLATE;
|
|
2923
3154
|
let name = providedName;
|
|
2924
3155
|
if (!name) {
|
|
2925
3156
|
const nameResult = await text({
|
|
@@ -2957,72 +3188,56 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2957
3188
|
log.info("Non-interactive mode detected, using defaults...");
|
|
2958
3189
|
return {
|
|
2959
3190
|
name,
|
|
2960
|
-
eslint: true,
|
|
2961
|
-
prettier: true,
|
|
2962
|
-
pathAlias: true,
|
|
2963
|
-
|
|
3191
|
+
eslint: eslintOverride ?? true,
|
|
3192
|
+
prettier: prettierOverride ?? true,
|
|
3193
|
+
pathAlias: pathAliasOverride ?? true,
|
|
3194
|
+
template: selectedTemplate
|
|
2964
3195
|
};
|
|
2965
3196
|
}
|
|
2966
|
-
const
|
|
2967
|
-
message: "
|
|
2968
|
-
|
|
3197
|
+
const templateResult = requestedTemplate ?? templateOverride ?? await select({
|
|
3198
|
+
message: "Choose a starter template",
|
|
3199
|
+
options: templateSelectOptions(),
|
|
3200
|
+
initialValue: DEFAULT_TEMPLATE
|
|
2969
3201
|
});
|
|
2970
|
-
if (isCancel(
|
|
3202
|
+
if (requestedTemplate === undefined && templateOverride === undefined && isCancel(templateResult)) {
|
|
2971
3203
|
handleCancel();
|
|
2972
|
-
|
|
3204
|
+
}
|
|
3205
|
+
const eslintResult = eslintOverride ?? await confirm({
|
|
2973
3206
|
message: "Add ESLint for code linting?",
|
|
2974
3207
|
initialValue: true
|
|
2975
3208
|
});
|
|
2976
|
-
if (isCancel(eslintResult))
|
|
3209
|
+
if (eslintOverride === undefined && isCancel(eslintResult))
|
|
2977
3210
|
handleCancel();
|
|
2978
|
-
const prettierResult = await confirm({
|
|
3211
|
+
const prettierResult = prettierOverride ?? await confirm({
|
|
2979
3212
|
message: "Add Prettier for code formatting?",
|
|
2980
3213
|
initialValue: true
|
|
2981
3214
|
});
|
|
2982
|
-
if (isCancel(prettierResult))
|
|
3215
|
+
if (prettierOverride === undefined && isCancel(prettierResult))
|
|
2983
3216
|
handleCancel();
|
|
2984
|
-
const pathAliasResult = await confirm({
|
|
3217
|
+
const pathAliasResult = pathAliasOverride ?? await confirm({
|
|
2985
3218
|
message: "Add TypeScript path alias (@/*)?",
|
|
2986
3219
|
initialValue: true
|
|
2987
3220
|
});
|
|
2988
|
-
if (isCancel(pathAliasResult))
|
|
3221
|
+
if (pathAliasOverride === undefined && isCancel(pathAliasResult))
|
|
2989
3222
|
handleCancel();
|
|
2990
3223
|
return {
|
|
2991
3224
|
name,
|
|
2992
3225
|
eslint: eslintResult,
|
|
2993
3226
|
prettier: prettierResult,
|
|
2994
3227
|
pathAlias: pathAliasResult,
|
|
2995
|
-
|
|
3228
|
+
template: templateResult
|
|
2996
3229
|
};
|
|
2997
3230
|
}
|
|
2998
3231
|
async function createProject(options) {
|
|
2999
3232
|
const targetDir = path.resolve(process.cwd(), options.name);
|
|
3000
|
-
const templatePath = options.
|
|
3001
|
-
|
|
3233
|
+
const templatePath = getTemplateDefinition(options.template).templatePath;
|
|
3234
|
+
const templateFeaturePaths = selectedTemplateFeaturePaths(options);
|
|
3235
|
+
await downloadTemplate(targetDir, [templatePath, ...templateFeaturePaths]);
|
|
3002
3236
|
const pkgPath = path.join(targetDir, "package.json");
|
|
3003
3237
|
if (fs.existsSync(pkgPath)) {
|
|
3004
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
3238
|
+
const pkg = applyPackageFeatures(JSON.parse(fs.readFileSync(pkgPath, "utf8")), options);
|
|
3005
3239
|
pkg.name = options.name;
|
|
3006
3240
|
pkg.version = "0.1.0";
|
|
3007
|
-
if (!options.eslint) {
|
|
3008
|
-
delete pkg.devDependencies?.["eslint"];
|
|
3009
|
-
delete pkg.devDependencies?.["@typescript-eslint/eslint-plugin"];
|
|
3010
|
-
delete pkg.devDependencies?.["@typescript-eslint/parser"];
|
|
3011
|
-
delete pkg.scripts?.lint;
|
|
3012
|
-
const eslintPath = path.join(targetDir, ".eslintrc.json");
|
|
3013
|
-
if (fs.existsSync(eslintPath))
|
|
3014
|
-
fs.unlinkSync(eslintPath);
|
|
3015
|
-
}
|
|
3016
|
-
if (!options.prettier) {
|
|
3017
|
-
delete pkg.devDependencies?.["prettier"];
|
|
3018
|
-
delete pkg.scripts?.format;
|
|
3019
|
-
const prettierRc = path.join(targetDir, ".prettierrc");
|
|
3020
|
-
const prettierIgnore = path.join(targetDir, ".prettierignore");
|
|
3021
|
-
if (fs.existsSync(prettierRc))
|
|
3022
|
-
fs.unlinkSync(prettierRc);
|
|
3023
|
-
if (fs.existsSync(prettierIgnore))
|
|
3024
|
-
fs.unlinkSync(prettierIgnore);
|
|
3025
|
-
}
|
|
3026
3241
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
|
|
3027
3242
|
}
|
|
3028
3243
|
const tsconfigPath = path.join(targetDir, "tsconfig.json");
|
|
@@ -3040,10 +3255,10 @@ async function createProject(options) {
|
|
|
3040
3255
|
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 4));
|
|
3041
3256
|
}
|
|
3042
3257
|
}
|
|
3043
|
-
async function create(appName,
|
|
3258
|
+
async function create(appName, requestedTemplate) {
|
|
3044
3259
|
await intro();
|
|
3045
|
-
const options = await gatherOptions(appName,
|
|
3046
|
-
const templateLabel = options.
|
|
3260
|
+
const options = await gatherOptions(appName, requestedTemplate);
|
|
3261
|
+
const templateLabel = getTemplateDefinition(options.template).name;
|
|
3047
3262
|
showScaffoldSummary(options.name, templateLabel);
|
|
3048
3263
|
console.log("");
|
|
3049
3264
|
log.step(`Creating ${bold(options.name)}...`);
|
|
@@ -3088,7 +3303,8 @@ if (args.includes("--help") || args.includes("-h")) {
|
|
|
3088
3303
|
console.log("Options:");
|
|
3089
3304
|
console.log(" -h, --help Show this help message");
|
|
3090
3305
|
console.log(" -v, --version Show version number");
|
|
3091
|
-
console.log(" --
|
|
3306
|
+
console.log(" --template <name> Choose template: basic, css, or tailwind");
|
|
3307
|
+
console.log(" --with-tailwind Alias for --template tailwind");
|
|
3092
3308
|
console.log("");
|
|
3093
3309
|
console.log("Examples:");
|
|
3094
3310
|
console.log(" npx create-zenith my-app");
|
|
@@ -3101,9 +3317,30 @@ if (args.includes("--version") || args.includes("-v")) {
|
|
|
3101
3317
|
console.log(`create-zenith ${VERSION}`);
|
|
3102
3318
|
process.exit(0);
|
|
3103
3319
|
}
|
|
3104
|
-
var projectName
|
|
3105
|
-
var
|
|
3106
|
-
|
|
3320
|
+
var projectName;
|
|
3321
|
+
var requestedTemplate;
|
|
3322
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
3323
|
+
const arg = args[index];
|
|
3324
|
+
if (arg === "--with-tailwind") {
|
|
3325
|
+
requestedTemplate = "tailwind";
|
|
3326
|
+
continue;
|
|
3327
|
+
}
|
|
3328
|
+
if (arg === "--template") {
|
|
3329
|
+
const templateValue = args[index + 1];
|
|
3330
|
+
const templateName = resolveTemplateName(templateValue);
|
|
3331
|
+
if (!templateName) {
|
|
3332
|
+
error(`Unsupported template "${templateValue || ""}". Use basic, css, or tailwind.`);
|
|
3333
|
+
process.exit(1);
|
|
3334
|
+
}
|
|
3335
|
+
requestedTemplate = templateName;
|
|
3336
|
+
index += 1;
|
|
3337
|
+
continue;
|
|
3338
|
+
}
|
|
3339
|
+
if (!arg.startsWith("-") && !projectName) {
|
|
3340
|
+
projectName = arg;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
create(projectName, requestedTemplate).catch((err) => {
|
|
3107
3344
|
const mode = getUiMode(process);
|
|
3108
3345
|
if (mode.plain) {
|
|
3109
3346
|
console.log("ERROR: SCAFFOLD_ERROR");
|