feat(create): wire CLI entry and create command pipeline

Made-with: Cursor
This commit is contained in:
zuiidea
2026-04-14 22:36:11 +08:00
parent a26e7f717e
commit c872f80e55
2 changed files with 176 additions and 2 deletions
+77 -2
View File
@@ -1,2 +1,77 @@
#!/usr/bin/env node
console.log("create-antd-admin stub");
import { readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { Command, Option } from "commander";
import pc from "picocolors";
import { runCreate } from "./commands/create.js";
import { EXIT_ERROR, EXIT_SIGINT } from "./constants.js";
import { CliError } from "./errors.js";
const pkg = JSON.parse(
readFileSync(
path.join(path.dirname(fileURLToPath(import.meta.url)), "../package.json"),
"utf8"
)
) as { version: string };
const program = new Command();
program
.name("create-antd-admin")
.description("Create an Antd Admin app from official examples")
.version(pkg.version, "-v, --version")
.argument("[project-directory]", "Directory for the new project")
.option("-e, --example <name|url>", "Example name or template URL")
.option("--example-path <path>", "Path inside repo when URL is ambiguous")
.addOption(
new Option("-m, --package-manager <pm>", "Package manager").choices([
"npm",
"yarn",
"pnpm",
"bun",
])
)
.option("--skip-install", "Skip installing dependencies", false)
.option("--skip-transforms", "Skip code transforms", false)
.option("--no-git", "Skip git repository initialization")
.action(
async (
projectDirectory: string | undefined,
cmdOpts: {
example?: string;
examplePath?: string;
packageManager?: "npm" | "yarn" | "pnpm" | "bun";
skipInstall?: boolean;
skipTransforms?: boolean;
git?: boolean;
}
) => {
try {
await runCreate({
projectDirectory,
example: cmdOpts.example,
examplePath: cmdOpts.examplePath,
packageManager: cmdOpts.packageManager,
skipInstall: Boolean(cmdOpts.skipInstall),
skipTransforms: Boolean(cmdOpts.skipTransforms),
git: cmdOpts.git !== false,
});
} catch (e) {
if (e instanceof CliError) {
console.error(pc.red(e.message));
process.exit(e.exitCode);
}
console.error(e);
process.exit(EXIT_ERROR);
}
}
);
process.on("SIGINT", () => {
process.exit(EXIT_SIGINT);
});
program.parseAsync(process.argv).catch((e) => {
console.error(e);
process.exit(EXIT_ERROR);
});
+99
View File
@@ -0,0 +1,99 @@
import fsSync from "node:fs";
import path from "node:path";
import pc from "picocolors";
import { assertValidExample, loadExamplesManifest } from "../examples.js";
import { downloadExampleToTemp } from "../download.js";
import { installDependencies } from "../install.js";
import {
detectAvailableManagers,
type PackageManagerName,
} from "../package-manager.js";
import { resolveTargetRoot } from "../paths.js";
import {
promptExample,
promptPackageManager,
promptPackageName,
promptTargetDir,
} from "../prompts.js";
import { resolveExampleSource } from "../resolve-example-source.js";
import { tryGitInit } from "../git.js";
import { runTransforms } from "../transforms/run-transforms.js";
export async function runCreate(
opts: Omit<import("../types.js").CreateCliOptions, "git"> & {
projectDirectory?: string;
git?: boolean;
}
): Promise<void> {
const cwd = process.cwd();
const manifest = loadExamplesManifest();
const exampleTrim = opts.example?.trim();
const example = exampleTrim
? exampleTrim
: await promptExample(manifest);
if (!/^https?:\/\//i.test(example)) {
assertValidExample(example, manifest);
}
const projectDirRaw = opts.projectDirectory?.trim();
const projectDir = projectDirRaw
? projectDirRaw
: await promptTargetDir();
const targetRoot = resolveTargetRoot(cwd, projectDir);
fsSync.mkdirSync(targetRoot, { recursive: true });
const defaultPkgName =
projectDir === "."
? (() => {
const normalized = path
.basename(cwd)
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
return normalized || "antd-admin-app";
})()
: path.basename(targetRoot);
const packageName = await promptPackageName(defaultPkgName);
const packageManager: PackageManagerName =
opts.packageManager ??
(await promptPackageManager(detectAvailableManagers()));
if (opts.skipTransforms && opts.packageManager) {
console.warn(
pc.yellow(
"--skip-transforms was used with an explicit package manager; package.json name may not be updated before install."
)
);
}
const { gigetSource } = resolveExampleSource({
example,
examplePath: opts.examplePath,
});
const tmp = await downloadExampleToTemp(gigetSource);
try {
fsSync.cpSync(tmp, targetRoot, { recursive: true, dereference: true });
} finally {
fsSync.rmSync(tmp, { recursive: true, force: true });
}
await runTransforms({
projectRoot: targetRoot,
packageName,
skip: opts.skipTransforms,
});
if (!opts.skipInstall) {
installDependencies(targetRoot, packageManager);
}
tryGitInit(targetRoot, opts.git !== false);
console.log(pc.green(`Success! Project created at ${targetRoot}`));
}