create-zenith 1.3.18 → 1.3.19
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 +17 -1
- package/dist/cli.js +119 -42
- package/dist/index.js +119 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ 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
|
+
- **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
21
|
|
|
22
22
|
## Quick Start
|
|
23
23
|
|
|
@@ -40,6 +40,21 @@ pnpm create zenith
|
|
|
40
40
|
| `-h, --help` | Show usage information |
|
|
41
41
|
| `-v, --version` | Show version number |
|
|
42
42
|
|
|
43
|
+
## Optional Tooling Contract
|
|
44
|
+
|
|
45
|
+
During scaffold, `create-zenith` asks whether to include:
|
|
46
|
+
|
|
47
|
+
- ESLint
|
|
48
|
+
- Prettier
|
|
49
|
+
- TypeScript path aliases
|
|
50
|
+
|
|
51
|
+
Tooling behavior is strict:
|
|
52
|
+
|
|
53
|
+
- If you enable ESLint, the project gets `eslint.config.js`, lint scripts, and matching ESLint dependencies.
|
|
54
|
+
- If you disable ESLint, the project contains zero ESLint references.
|
|
55
|
+
- If you enable Prettier, the project gets `.prettierrc`, `.prettierignore`, a format script, and the Prettier dependency.
|
|
56
|
+
- If you disable Prettier, the project contains zero Prettier references.
|
|
57
|
+
|
|
43
58
|
## Beta Version Pinning
|
|
44
59
|
|
|
45
60
|
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,6 +65,7 @@ If you see version mismatches after install, delete `node_modules` and `package-
|
|
|
50
65
|
|
|
51
66
|
- Generated apps now depend on `@zenithbuild/core@latest` so new installs track the current stable framework release.
|
|
52
67
|
- Template downloads now resolve from `zenithbuild/framework`, which is the active monorepo source of truth.
|
|
68
|
+
- ESLint and Prettier are now feature overlays, so opting out leaves no stray config or dependency references in the scaffolded app.
|
|
53
69
|
- Verified scaffold → install → build coverage lives in `tests/template-regression.spec.mjs`.
|
|
54
70
|
|
|
55
71
|
## Development
|
package/dist/cli.js
CHANGED
|
@@ -2819,6 +2819,72 @@ var log = {
|
|
|
2819
2819
|
message: (message) => getUiMode(process).plain ? console.log(message) : M2.message(message)
|
|
2820
2820
|
};
|
|
2821
2821
|
|
|
2822
|
+
// src/template-features.ts
|
|
2823
|
+
var FEATURE_DEFINITIONS = {
|
|
2824
|
+
eslint: {
|
|
2825
|
+
templatePath: "templates/features/eslint",
|
|
2826
|
+
packagePatch: {
|
|
2827
|
+
scripts: {
|
|
2828
|
+
lint: "eslint ."
|
|
2829
|
+
},
|
|
2830
|
+
devDependencies: {
|
|
2831
|
+
eslint: "^9.39.2",
|
|
2832
|
+
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
2833
|
+
"@typescript-eslint/parser": "^8.53.0"
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
},
|
|
2837
|
+
prettier: {
|
|
2838
|
+
templatePath: "templates/features/prettier",
|
|
2839
|
+
packagePatch: {
|
|
2840
|
+
scripts: {
|
|
2841
|
+
format: "prettier --write ."
|
|
2842
|
+
},
|
|
2843
|
+
devDependencies: {
|
|
2844
|
+
prettier: "^3.7.4"
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
};
|
|
2849
|
+
function mergeRecord(target, patch) {
|
|
2850
|
+
if (!patch) {
|
|
2851
|
+
return target;
|
|
2852
|
+
}
|
|
2853
|
+
return { ...target || {}, ...patch };
|
|
2854
|
+
}
|
|
2855
|
+
function selectedTemplateFeaturePaths(options) {
|
|
2856
|
+
const paths = [];
|
|
2857
|
+
if (options.eslint) {
|
|
2858
|
+
paths.push(FEATURE_DEFINITIONS.eslint.templatePath);
|
|
2859
|
+
}
|
|
2860
|
+
if (options.prettier) {
|
|
2861
|
+
paths.push(FEATURE_DEFINITIONS.prettier.templatePath);
|
|
2862
|
+
}
|
|
2863
|
+
return paths;
|
|
2864
|
+
}
|
|
2865
|
+
function applyPackageFeatures(manifest, options) {
|
|
2866
|
+
const nextManifest = {
|
|
2867
|
+
...manifest,
|
|
2868
|
+
scripts: { ...manifest.scripts || {} },
|
|
2869
|
+
devDependencies: { ...manifest.devDependencies || {} }
|
|
2870
|
+
};
|
|
2871
|
+
for (const featureName of Object.keys(FEATURE_DEFINITIONS)) {
|
|
2872
|
+
if (!options[featureName]) {
|
|
2873
|
+
continue;
|
|
2874
|
+
}
|
|
2875
|
+
const patch = FEATURE_DEFINITIONS[featureName].packagePatch;
|
|
2876
|
+
nextManifest.scripts = mergeRecord(nextManifest.scripts, patch.scripts);
|
|
2877
|
+
nextManifest.devDependencies = mergeRecord(nextManifest.devDependencies, patch.devDependencies);
|
|
2878
|
+
}
|
|
2879
|
+
if (nextManifest.scripts && Object.keys(nextManifest.scripts).length === 0) {
|
|
2880
|
+
delete nextManifest.scripts;
|
|
2881
|
+
}
|
|
2882
|
+
if (nextManifest.devDependencies && Object.keys(nextManifest.devDependencies).length === 0) {
|
|
2883
|
+
delete nextManifest.devDependencies;
|
|
2884
|
+
}
|
|
2885
|
+
return nextManifest;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2822
2888
|
// src/index.ts
|
|
2823
2889
|
var GITHUB_REPO = "zenithbuild/framework";
|
|
2824
2890
|
var DEFAULT_TEMPLATE = "examples/starter";
|
|
@@ -2845,6 +2911,15 @@ function resolveLocalTemplatePath(templatePath) {
|
|
|
2845
2911
|
const candidate = path.resolve(__dirname2, "..", templatePath);
|
|
2846
2912
|
return fs.existsSync(candidate) ? candidate : null;
|
|
2847
2913
|
}
|
|
2914
|
+
function copyDirectoryContents(sourceDir, targetDir) {
|
|
2915
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
2916
|
+
for (const entry of fs.readdirSync(sourceDir)) {
|
|
2917
|
+
fs.cpSync(path.join(sourceDir, entry), path.join(targetDir, entry), {
|
|
2918
|
+
recursive: true,
|
|
2919
|
+
force: true
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2848
2923
|
function detectPackageManager() {
|
|
2849
2924
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
2850
2925
|
if (userAgent.includes("bun"))
|
|
@@ -2875,16 +2950,22 @@ function hasGit() {
|
|
|
2875
2950
|
return false;
|
|
2876
2951
|
}
|
|
2877
2952
|
}
|
|
2878
|
-
async function downloadTemplate(targetDir,
|
|
2879
|
-
const
|
|
2953
|
+
async function downloadTemplate(targetDir, templatePaths) {
|
|
2954
|
+
const localTemplatePaths = templatePaths.map((templatePath) => ({
|
|
2955
|
+
templatePath,
|
|
2956
|
+
localPath: resolveLocalTemplatePath(templatePath)
|
|
2957
|
+
}));
|
|
2880
2958
|
const forceLocal = process.env.CREATE_ZENITH_TEMPLATE_MODE === "local" || flagEnabled2(process.env.CREATE_ZENITH_OFFLINE);
|
|
2881
2959
|
const preferLocal = process.env.CREATE_ZENITH_PREFER_LOCAL !== "0";
|
|
2882
|
-
if (
|
|
2883
|
-
|
|
2960
|
+
if (localTemplatePaths.every((entry) => entry.localPath) && (forceLocal || preferLocal)) {
|
|
2961
|
+
for (const entry of localTemplatePaths) {
|
|
2962
|
+
copyDirectoryContents(entry.localPath, targetDir);
|
|
2963
|
+
}
|
|
2884
2964
|
return;
|
|
2885
2965
|
}
|
|
2886
|
-
if (forceLocal
|
|
2887
|
-
|
|
2966
|
+
if (forceLocal) {
|
|
2967
|
+
const missingPath = localTemplatePaths.find((entry) => !entry.localPath)?.templatePath;
|
|
2968
|
+
throw new Error(`Local template not found: ${missingPath}`);
|
|
2888
2969
|
}
|
|
2889
2970
|
const tempDir = path.join(os2.tmpdir(), `zenith-template-${Date.now()}`);
|
|
2890
2971
|
try {
|
|
@@ -2892,13 +2973,15 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2892
2973
|
execSync(`git clone --depth 1 --filter=blob:none --sparse https://github.com/${GITHUB_REPO}.git "${tempDir}"`, {
|
|
2893
2974
|
stdio: "pipe"
|
|
2894
2975
|
});
|
|
2895
|
-
const
|
|
2896
|
-
execSync(`git sparse-checkout set ${
|
|
2976
|
+
const repoTemplatePaths = templatePaths.map((templatePath) => `packages/create-zenith/${templatePath}`);
|
|
2977
|
+
execSync(`git sparse-checkout set ${repoTemplatePaths.join(" ")}`, {
|
|
2897
2978
|
cwd: tempDir,
|
|
2898
2979
|
stdio: "pipe"
|
|
2899
2980
|
});
|
|
2900
|
-
const
|
|
2901
|
-
|
|
2981
|
+
for (const repoTemplatePath of repoTemplatePaths) {
|
|
2982
|
+
const templateSource = path.join(tempDir, repoTemplatePath);
|
|
2983
|
+
copyDirectoryContents(templateSource, targetDir);
|
|
2984
|
+
}
|
|
2902
2985
|
} else {
|
|
2903
2986
|
const tarballUrl = `https://github.com/${GITHUB_REPO}/archive/refs/heads/main.tar.gz`;
|
|
2904
2987
|
const tarballPath = path.join(os2.tmpdir(), `zenith-${Date.now()}.tar.gz`);
|
|
@@ -2909,8 +2992,10 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2909
2992
|
if (!extractedDir) {
|
|
2910
2993
|
throw new Error("Failed to extract template from GitHub");
|
|
2911
2994
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2995
|
+
for (const templatePath of templatePaths) {
|
|
2996
|
+
const templateSource = path.join(tempDir, extractedDir, "packages/create-zenith", templatePath);
|
|
2997
|
+
copyDirectoryContents(templateSource, targetDir);
|
|
2998
|
+
}
|
|
2914
2999
|
fs.unlinkSync(tarballPath);
|
|
2915
3000
|
}
|
|
2916
3001
|
} finally {
|
|
@@ -2919,7 +3004,17 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2919
3004
|
}
|
|
2920
3005
|
}
|
|
2921
3006
|
}
|
|
3007
|
+
function readOptionOverride(name) {
|
|
3008
|
+
const value = process.env[name];
|
|
3009
|
+
if (value == null || value.trim() === "") {
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
3012
|
+
return flagEnabled2(value);
|
|
3013
|
+
}
|
|
2922
3014
|
async function gatherOptions(providedName, withTailwind) {
|
|
3015
|
+
const eslintOverride = readOptionOverride("CREATE_ZENITH_ESLINT");
|
|
3016
|
+
const prettierOverride = readOptionOverride("CREATE_ZENITH_PRETTIER");
|
|
3017
|
+
const pathAliasOverride = readOptionOverride("CREATE_ZENITH_PATH_ALIAS");
|
|
2923
3018
|
let name = providedName;
|
|
2924
3019
|
if (!name) {
|
|
2925
3020
|
const nameResult = await text({
|
|
@@ -2957,9 +3052,9 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2957
3052
|
log.info("Non-interactive mode detected, using defaults...");
|
|
2958
3053
|
return {
|
|
2959
3054
|
name,
|
|
2960
|
-
eslint: true,
|
|
2961
|
-
prettier: true,
|
|
2962
|
-
pathAlias: true,
|
|
3055
|
+
eslint: eslintOverride ?? true,
|
|
3056
|
+
prettier: prettierOverride ?? true,
|
|
3057
|
+
pathAlias: pathAliasOverride ?? true,
|
|
2963
3058
|
tailwind: withTailwind ?? false
|
|
2964
3059
|
};
|
|
2965
3060
|
}
|
|
@@ -2969,23 +3064,23 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2969
3064
|
});
|
|
2970
3065
|
if (isCancel(tailwindResult))
|
|
2971
3066
|
handleCancel();
|
|
2972
|
-
const eslintResult = await confirm({
|
|
3067
|
+
const eslintResult = eslintOverride ?? await confirm({
|
|
2973
3068
|
message: "Add ESLint for code linting?",
|
|
2974
3069
|
initialValue: true
|
|
2975
3070
|
});
|
|
2976
|
-
if (isCancel(eslintResult))
|
|
3071
|
+
if (eslintOverride === undefined && isCancel(eslintResult))
|
|
2977
3072
|
handleCancel();
|
|
2978
|
-
const prettierResult = await confirm({
|
|
3073
|
+
const prettierResult = prettierOverride ?? await confirm({
|
|
2979
3074
|
message: "Add Prettier for code formatting?",
|
|
2980
3075
|
initialValue: true
|
|
2981
3076
|
});
|
|
2982
|
-
if (isCancel(prettierResult))
|
|
3077
|
+
if (prettierOverride === undefined && isCancel(prettierResult))
|
|
2983
3078
|
handleCancel();
|
|
2984
|
-
const pathAliasResult = await confirm({
|
|
3079
|
+
const pathAliasResult = pathAliasOverride ?? await confirm({
|
|
2985
3080
|
message: "Add TypeScript path alias (@/*)?",
|
|
2986
3081
|
initialValue: true
|
|
2987
3082
|
});
|
|
2988
|
-
if (isCancel(pathAliasResult))
|
|
3083
|
+
if (pathAliasOverride === undefined && isCancel(pathAliasResult))
|
|
2989
3084
|
handleCancel();
|
|
2990
3085
|
return {
|
|
2991
3086
|
name,
|
|
@@ -2998,31 +3093,13 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2998
3093
|
async function createProject(options) {
|
|
2999
3094
|
const targetDir = path.resolve(process.cwd(), options.name);
|
|
3000
3095
|
const templatePath = options.tailwind ? TAILWIND_TEMPLATE : DEFAULT_TEMPLATE;
|
|
3001
|
-
|
|
3096
|
+
const templateFeaturePaths = selectedTemplateFeaturePaths(options);
|
|
3097
|
+
await downloadTemplate(targetDir, [templatePath, ...templateFeaturePaths]);
|
|
3002
3098
|
const pkgPath = path.join(targetDir, "package.json");
|
|
3003
3099
|
if (fs.existsSync(pkgPath)) {
|
|
3004
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
3100
|
+
const pkg = applyPackageFeatures(JSON.parse(fs.readFileSync(pkgPath, "utf8")), options);
|
|
3005
3101
|
pkg.name = options.name;
|
|
3006
3102
|
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
3103
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
|
|
3027
3104
|
}
|
|
3028
3105
|
const tsconfigPath = path.join(targetDir, "tsconfig.json");
|
package/dist/index.js
CHANGED
|
@@ -2818,6 +2818,72 @@ var log = {
|
|
|
2818
2818
|
message: (message) => getUiMode(process).plain ? console.log(message) : M2.message(message)
|
|
2819
2819
|
};
|
|
2820
2820
|
|
|
2821
|
+
// src/template-features.ts
|
|
2822
|
+
var FEATURE_DEFINITIONS = {
|
|
2823
|
+
eslint: {
|
|
2824
|
+
templatePath: "templates/features/eslint",
|
|
2825
|
+
packagePatch: {
|
|
2826
|
+
scripts: {
|
|
2827
|
+
lint: "eslint ."
|
|
2828
|
+
},
|
|
2829
|
+
devDependencies: {
|
|
2830
|
+
eslint: "^9.39.2",
|
|
2831
|
+
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
2832
|
+
"@typescript-eslint/parser": "^8.53.0"
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
},
|
|
2836
|
+
prettier: {
|
|
2837
|
+
templatePath: "templates/features/prettier",
|
|
2838
|
+
packagePatch: {
|
|
2839
|
+
scripts: {
|
|
2840
|
+
format: "prettier --write ."
|
|
2841
|
+
},
|
|
2842
|
+
devDependencies: {
|
|
2843
|
+
prettier: "^3.7.4"
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
function mergeRecord(target, patch) {
|
|
2849
|
+
if (!patch) {
|
|
2850
|
+
return target;
|
|
2851
|
+
}
|
|
2852
|
+
return { ...target || {}, ...patch };
|
|
2853
|
+
}
|
|
2854
|
+
function selectedTemplateFeaturePaths(options) {
|
|
2855
|
+
const paths = [];
|
|
2856
|
+
if (options.eslint) {
|
|
2857
|
+
paths.push(FEATURE_DEFINITIONS.eslint.templatePath);
|
|
2858
|
+
}
|
|
2859
|
+
if (options.prettier) {
|
|
2860
|
+
paths.push(FEATURE_DEFINITIONS.prettier.templatePath);
|
|
2861
|
+
}
|
|
2862
|
+
return paths;
|
|
2863
|
+
}
|
|
2864
|
+
function applyPackageFeatures(manifest, options) {
|
|
2865
|
+
const nextManifest = {
|
|
2866
|
+
...manifest,
|
|
2867
|
+
scripts: { ...manifest.scripts || {} },
|
|
2868
|
+
devDependencies: { ...manifest.devDependencies || {} }
|
|
2869
|
+
};
|
|
2870
|
+
for (const featureName of Object.keys(FEATURE_DEFINITIONS)) {
|
|
2871
|
+
if (!options[featureName]) {
|
|
2872
|
+
continue;
|
|
2873
|
+
}
|
|
2874
|
+
const patch = FEATURE_DEFINITIONS[featureName].packagePatch;
|
|
2875
|
+
nextManifest.scripts = mergeRecord(nextManifest.scripts, patch.scripts);
|
|
2876
|
+
nextManifest.devDependencies = mergeRecord(nextManifest.devDependencies, patch.devDependencies);
|
|
2877
|
+
}
|
|
2878
|
+
if (nextManifest.scripts && Object.keys(nextManifest.scripts).length === 0) {
|
|
2879
|
+
delete nextManifest.scripts;
|
|
2880
|
+
}
|
|
2881
|
+
if (nextManifest.devDependencies && Object.keys(nextManifest.devDependencies).length === 0) {
|
|
2882
|
+
delete nextManifest.devDependencies;
|
|
2883
|
+
}
|
|
2884
|
+
return nextManifest;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2821
2887
|
// src/index.ts
|
|
2822
2888
|
var GITHUB_REPO = "zenithbuild/framework";
|
|
2823
2889
|
var DEFAULT_TEMPLATE = "examples/starter";
|
|
@@ -2844,6 +2910,15 @@ function resolveLocalTemplatePath(templatePath) {
|
|
|
2844
2910
|
const candidate = path.resolve(__dirname2, "..", templatePath);
|
|
2845
2911
|
return fs.existsSync(candidate) ? candidate : null;
|
|
2846
2912
|
}
|
|
2913
|
+
function copyDirectoryContents(sourceDir, targetDir) {
|
|
2914
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
2915
|
+
for (const entry of fs.readdirSync(sourceDir)) {
|
|
2916
|
+
fs.cpSync(path.join(sourceDir, entry), path.join(targetDir, entry), {
|
|
2917
|
+
recursive: true,
|
|
2918
|
+
force: true
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2847
2922
|
function detectPackageManager() {
|
|
2848
2923
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
2849
2924
|
if (userAgent.includes("bun"))
|
|
@@ -2874,16 +2949,22 @@ function hasGit() {
|
|
|
2874
2949
|
return false;
|
|
2875
2950
|
}
|
|
2876
2951
|
}
|
|
2877
|
-
async function downloadTemplate(targetDir,
|
|
2878
|
-
const
|
|
2952
|
+
async function downloadTemplate(targetDir, templatePaths) {
|
|
2953
|
+
const localTemplatePaths = templatePaths.map((templatePath) => ({
|
|
2954
|
+
templatePath,
|
|
2955
|
+
localPath: resolveLocalTemplatePath(templatePath)
|
|
2956
|
+
}));
|
|
2879
2957
|
const forceLocal = process.env.CREATE_ZENITH_TEMPLATE_MODE === "local" || flagEnabled2(process.env.CREATE_ZENITH_OFFLINE);
|
|
2880
2958
|
const preferLocal = process.env.CREATE_ZENITH_PREFER_LOCAL !== "0";
|
|
2881
|
-
if (
|
|
2882
|
-
|
|
2959
|
+
if (localTemplatePaths.every((entry) => entry.localPath) && (forceLocal || preferLocal)) {
|
|
2960
|
+
for (const entry of localTemplatePaths) {
|
|
2961
|
+
copyDirectoryContents(entry.localPath, targetDir);
|
|
2962
|
+
}
|
|
2883
2963
|
return;
|
|
2884
2964
|
}
|
|
2885
|
-
if (forceLocal
|
|
2886
|
-
|
|
2965
|
+
if (forceLocal) {
|
|
2966
|
+
const missingPath = localTemplatePaths.find((entry) => !entry.localPath)?.templatePath;
|
|
2967
|
+
throw new Error(`Local template not found: ${missingPath}`);
|
|
2887
2968
|
}
|
|
2888
2969
|
const tempDir = path.join(os2.tmpdir(), `zenith-template-${Date.now()}`);
|
|
2889
2970
|
try {
|
|
@@ -2891,13 +2972,15 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2891
2972
|
execSync(`git clone --depth 1 --filter=blob:none --sparse https://github.com/${GITHUB_REPO}.git "${tempDir}"`, {
|
|
2892
2973
|
stdio: "pipe"
|
|
2893
2974
|
});
|
|
2894
|
-
const
|
|
2895
|
-
execSync(`git sparse-checkout set ${
|
|
2975
|
+
const repoTemplatePaths = templatePaths.map((templatePath) => `packages/create-zenith/${templatePath}`);
|
|
2976
|
+
execSync(`git sparse-checkout set ${repoTemplatePaths.join(" ")}`, {
|
|
2896
2977
|
cwd: tempDir,
|
|
2897
2978
|
stdio: "pipe"
|
|
2898
2979
|
});
|
|
2899
|
-
const
|
|
2900
|
-
|
|
2980
|
+
for (const repoTemplatePath of repoTemplatePaths) {
|
|
2981
|
+
const templateSource = path.join(tempDir, repoTemplatePath);
|
|
2982
|
+
copyDirectoryContents(templateSource, targetDir);
|
|
2983
|
+
}
|
|
2901
2984
|
} else {
|
|
2902
2985
|
const tarballUrl = `https://github.com/${GITHUB_REPO}/archive/refs/heads/main.tar.gz`;
|
|
2903
2986
|
const tarballPath = path.join(os2.tmpdir(), `zenith-${Date.now()}.tar.gz`);
|
|
@@ -2908,8 +2991,10 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2908
2991
|
if (!extractedDir) {
|
|
2909
2992
|
throw new Error("Failed to extract template from GitHub");
|
|
2910
2993
|
}
|
|
2911
|
-
|
|
2912
|
-
|
|
2994
|
+
for (const templatePath of templatePaths) {
|
|
2995
|
+
const templateSource = path.join(tempDir, extractedDir, "packages/create-zenith", templatePath);
|
|
2996
|
+
copyDirectoryContents(templateSource, targetDir);
|
|
2997
|
+
}
|
|
2913
2998
|
fs.unlinkSync(tarballPath);
|
|
2914
2999
|
}
|
|
2915
3000
|
} finally {
|
|
@@ -2918,7 +3003,17 @@ async function downloadTemplate(targetDir, templatePath) {
|
|
|
2918
3003
|
}
|
|
2919
3004
|
}
|
|
2920
3005
|
}
|
|
3006
|
+
function readOptionOverride(name) {
|
|
3007
|
+
const value = process.env[name];
|
|
3008
|
+
if (value == null || value.trim() === "") {
|
|
3009
|
+
return;
|
|
3010
|
+
}
|
|
3011
|
+
return flagEnabled2(value);
|
|
3012
|
+
}
|
|
2921
3013
|
async function gatherOptions(providedName, withTailwind) {
|
|
3014
|
+
const eslintOverride = readOptionOverride("CREATE_ZENITH_ESLINT");
|
|
3015
|
+
const prettierOverride = readOptionOverride("CREATE_ZENITH_PRETTIER");
|
|
3016
|
+
const pathAliasOverride = readOptionOverride("CREATE_ZENITH_PATH_ALIAS");
|
|
2922
3017
|
let name = providedName;
|
|
2923
3018
|
if (!name) {
|
|
2924
3019
|
const nameResult = await text({
|
|
@@ -2956,9 +3051,9 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2956
3051
|
log.info("Non-interactive mode detected, using defaults...");
|
|
2957
3052
|
return {
|
|
2958
3053
|
name,
|
|
2959
|
-
eslint: true,
|
|
2960
|
-
prettier: true,
|
|
2961
|
-
pathAlias: true,
|
|
3054
|
+
eslint: eslintOverride ?? true,
|
|
3055
|
+
prettier: prettierOverride ?? true,
|
|
3056
|
+
pathAlias: pathAliasOverride ?? true,
|
|
2962
3057
|
tailwind: withTailwind ?? false
|
|
2963
3058
|
};
|
|
2964
3059
|
}
|
|
@@ -2968,23 +3063,23 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2968
3063
|
});
|
|
2969
3064
|
if (isCancel(tailwindResult))
|
|
2970
3065
|
handleCancel();
|
|
2971
|
-
const eslintResult = await confirm({
|
|
3066
|
+
const eslintResult = eslintOverride ?? await confirm({
|
|
2972
3067
|
message: "Add ESLint for code linting?",
|
|
2973
3068
|
initialValue: true
|
|
2974
3069
|
});
|
|
2975
|
-
if (isCancel(eslintResult))
|
|
3070
|
+
if (eslintOverride === undefined && isCancel(eslintResult))
|
|
2976
3071
|
handleCancel();
|
|
2977
|
-
const prettierResult = await confirm({
|
|
3072
|
+
const prettierResult = prettierOverride ?? await confirm({
|
|
2978
3073
|
message: "Add Prettier for code formatting?",
|
|
2979
3074
|
initialValue: true
|
|
2980
3075
|
});
|
|
2981
|
-
if (isCancel(prettierResult))
|
|
3076
|
+
if (prettierOverride === undefined && isCancel(prettierResult))
|
|
2982
3077
|
handleCancel();
|
|
2983
|
-
const pathAliasResult = await confirm({
|
|
3078
|
+
const pathAliasResult = pathAliasOverride ?? await confirm({
|
|
2984
3079
|
message: "Add TypeScript path alias (@/*)?",
|
|
2985
3080
|
initialValue: true
|
|
2986
3081
|
});
|
|
2987
|
-
if (isCancel(pathAliasResult))
|
|
3082
|
+
if (pathAliasOverride === undefined && isCancel(pathAliasResult))
|
|
2988
3083
|
handleCancel();
|
|
2989
3084
|
return {
|
|
2990
3085
|
name,
|
|
@@ -2997,31 +3092,13 @@ async function gatherOptions(providedName, withTailwind) {
|
|
|
2997
3092
|
async function createProject(options) {
|
|
2998
3093
|
const targetDir = path.resolve(process.cwd(), options.name);
|
|
2999
3094
|
const templatePath = options.tailwind ? TAILWIND_TEMPLATE : DEFAULT_TEMPLATE;
|
|
3000
|
-
|
|
3095
|
+
const templateFeaturePaths = selectedTemplateFeaturePaths(options);
|
|
3096
|
+
await downloadTemplate(targetDir, [templatePath, ...templateFeaturePaths]);
|
|
3001
3097
|
const pkgPath = path.join(targetDir, "package.json");
|
|
3002
3098
|
if (fs.existsSync(pkgPath)) {
|
|
3003
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
3099
|
+
const pkg = applyPackageFeatures(JSON.parse(fs.readFileSync(pkgPath, "utf8")), options);
|
|
3004
3100
|
pkg.name = options.name;
|
|
3005
3101
|
pkg.version = "0.1.0";
|
|
3006
|
-
if (!options.eslint) {
|
|
3007
|
-
delete pkg.devDependencies?.["eslint"];
|
|
3008
|
-
delete pkg.devDependencies?.["@typescript-eslint/eslint-plugin"];
|
|
3009
|
-
delete pkg.devDependencies?.["@typescript-eslint/parser"];
|
|
3010
|
-
delete pkg.scripts?.lint;
|
|
3011
|
-
const eslintPath = path.join(targetDir, ".eslintrc.json");
|
|
3012
|
-
if (fs.existsSync(eslintPath))
|
|
3013
|
-
fs.unlinkSync(eslintPath);
|
|
3014
|
-
}
|
|
3015
|
-
if (!options.prettier) {
|
|
3016
|
-
delete pkg.devDependencies?.["prettier"];
|
|
3017
|
-
delete pkg.scripts?.format;
|
|
3018
|
-
const prettierRc = path.join(targetDir, ".prettierrc");
|
|
3019
|
-
const prettierIgnore = path.join(targetDir, ".prettierignore");
|
|
3020
|
-
if (fs.existsSync(prettierRc))
|
|
3021
|
-
fs.unlinkSync(prettierRc);
|
|
3022
|
-
if (fs.existsSync(prettierIgnore))
|
|
3023
|
-
fs.unlinkSync(prettierIgnore);
|
|
3024
|
-
}
|
|
3025
3102
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
|
|
3026
3103
|
}
|
|
3027
3104
|
const tsconfigPath = path.join(targetDir, "tsconfig.json");
|