create-ckb-js-vm-app
Version:
CLI tool to quickly bootstrap CKB on-chain script with ckb-js-vm.
260 lines ā¢ 10.8 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.install = install;
const commander_1 = require("commander");
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const update_check_1 = __importDefault(require("update-check"));
const prompts_1 = __importDefault(require("prompts"));
const picocolors_1 = require("picocolors");
const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
const child_process_1 = require("child_process");
const config_1 = require("./config");
const packageJson = require(path_1.default.join(__dirname, "../package.json"));
let projectName = "";
const handleSigTerm = () => process.exit(0);
process.on("SIGINT", handleSigTerm);
process.on("SIGTERM", handleSigTerm);
const onPromptState = (state) => {
if (state.aborted) {
// If we don't re-enable the terminal cursor before exiting
// the program, the cursor will remain hidden
process.stdout.write("\x1B[?25h");
process.stdout.write("\n");
process.exit(1);
}
};
const program = new commander_1.Command(packageJson.name)
.version(packageJson.version, "-v, --version", `Output the current version of ${packageJson.name}.`)
.argument("[directory]")
.usage("[directory] [options]")
.helpOption("-h, --help", "Display this help message.")
.option("--skip-install", "Explicitly tell the CLI to skip installing packages.")
.action((name) => {
// Commander does not implicitly support negated options. When they are used
// by the user they will be interpreted as the positional argument (name) in
// the action handler. See https://github.com/tj/commander.js/pull/1355
if (name && !name.startsWith("--no-")) {
projectName = name;
}
})
.allowUnknownOption()
.parse(process.argv);
const opts = program.opts();
const packageManager = getPkgManager();
function validateNpmName(name) {
const nameValidation = (0, validate_npm_package_name_1.default)(name);
if (nameValidation.validForNewPackages) {
return { valid: true };
}
return {
valid: false,
problems: [
...(nameValidation.errors || []),
...(nameValidation.warnings || []),
],
};
}
function getPkgManager() {
return "pnpm";
}
function isFolderEmpty(folderPath) {
const files = fs_extra_1.default.readdirSync(folderPath);
return files.length === 0;
}
async function install(packageManager) {
const args = ["install"];
return new Promise((resolve, reject) => {
const child = (0, child_process_1.spawn)(packageManager, args, {
stdio: "inherit",
env: {
...process.env,
ADBLOCK: "1",
// we set NODE_ENV to development as pnpm skips dev
// dependencies when production
NODE_ENV: "development",
DISABLE_OPENCOLLECTIVE: "1",
},
});
child.on("close", (code) => {
if (code !== 0) {
reject({ command: `${packageManager} ${args.join(" ")}` });
return;
}
resolve();
});
});
}
function updatePackageJson1(projectPath) {
const packageJsonPath = path_1.default.join(projectPath, "packages/on-chain-script/package.json");
let json = "";
if (fs_extra_1.default.pathExistsSync(packageJsonPath)) {
try {
json = fs_extra_1.default.readJsonSync(packageJsonPath);
json.name = projectName;
json.devDependencies["ckb-testtool"] = config_1.testtoolVersion;
json.dependencies["@ckb-js-std/bindings"] = config_1.bindingVersion;
json.dependencies["@ckb-js-std/core"] = config_1.coreVersion;
fs_extra_1.default.writeJsonSync(packageJsonPath, json, { spaces: 2 });
console.log((0, picocolors_1.green)(`Updated ${projectName}/package.json.`));
}
catch (error) {
console.error((0, picocolors_1.red)(`Failed to update packages/on-chain-script/package.json: ${error.message}`));
process.exit(1);
}
}
else {
console.error((0, picocolors_1.red)(`Could not find packages/on-chain-script/package.json in the template. Make sure your template includes a package.json.`));
process.exit(1);
}
}
function updatePackageJson2(projectPath) {
const packageJsonPath = path_1.default.join(projectPath, "packages/on-chain-script-tests/package.json");
let json = "";
if (fs_extra_1.default.pathExistsSync(packageJsonPath)) {
try {
json = fs_extra_1.default.readJsonSync(packageJsonPath);
json.name = projectName;
json.devDependencies["ckb-testtool"] = config_1.testtoolVersion;
json.devDependencies["@ckb-ccc/core"] = config_1.cccCoreVersion;
fs_extra_1.default.writeJsonSync(packageJsonPath, json, { spaces: 2 });
console.log((0, picocolors_1.green)(`Updated ${projectName}/package.json.`));
}
catch (error) {
console.error((0, picocolors_1.red)(`Failed to update packages/on-chain-script/package.json: ${error.message}`));
process.exit(1);
}
}
else {
console.error((0, picocolors_1.red)(`Could not find packages/on-chain-script/package.json in the template. Make sure your template includes a package.json.`));
process.exit(1);
}
}
async function run() {
var _a;
console.log();
if (projectName && typeof projectName === "string") {
projectName = projectName.trim();
}
if (!projectName) {
const res = await (0, prompts_1.default)({
onState: onPromptState,
type: "text",
name: "path",
message: "What is your project named?",
initial: "my-ckb-script",
validate: (name) => {
var _a;
const validation = validateNpmName(path_1.default.basename(path_1.default.resolve(name)));
if (validation.valid) {
return true;
}
return ("Invalid project name: " +
(((_a = validation.problems) === null || _a === void 0 ? void 0 : _a[0]) || "Unknown validation error"));
},
});
if (typeof res.path === "string") {
projectName = res.path.trim();
}
}
if (!projectName) {
console.log("\nPlease specify the project directory:\n" +
` ${(0, picocolors_1.cyan)(program.name())} ${(0, picocolors_1.green)("<project-directory>")}\n` +
"For example:\n" +
` ${(0, picocolors_1.cyan)(program.name())} ${(0, picocolors_1.green)("my-ckb-script")}\n\n` +
`Run ${(0, picocolors_1.cyan)(`${program.name()} --help`)} to see all options.`);
process.exit(1);
}
const appPath = path_1.default.resolve(projectName);
const appName = path_1.default.basename(appPath);
const validation = validateNpmName(appName);
if (!validation.valid) {
console.error(`Could not create a project called ${(0, picocolors_1.red)(`"${appName}"`)} because of npm naming restrictions:`);
(_a = validation.problems) === null || _a === void 0 ? void 0 : _a.forEach((p) => console.error(` ${(0, picocolors_1.red)((0, picocolors_1.bold)("*"))} ${p}`));
process.exit(1);
}
if (fs_extra_1.default.pathExistsSync(appPath) && !isFolderEmpty(appPath)) {
console.error(`Could not create a project called ${(0, picocolors_1.red)(`"${appName}"`)} because a project with the same name already exists.`);
process.exit(1);
}
console.log((0, picocolors_1.bold)(`Using ${packageManager}.`));
const templatePath = path_1.default.join(__dirname, `../templates`);
if (!fs_extra_1.default.pathExistsSync(templatePath)) {
console.error(`Could not find a template`);
console.error(`\n š®āšØ Project ${projectName} created failed!\n`);
process.exit(1);
}
const originalDirectory = process.cwd();
const projectPath = path_1.default.join(originalDirectory, projectName);
fs_extra_1.default.ensureDirSync(projectPath);
fs_extra_1.default.copySync(templatePath, projectPath);
updatePackageJson1(projectName);
updatePackageJson2(projectName);
console.log(`\nš Project ${projectName} created!\n`);
if (opts.skipInstall) {
console.log("Skip install the dependencies, we suggest that you begin by typing:");
console.log();
console.log((0, picocolors_1.cyan)(" cd"), projectName);
console.log(` ${(0, picocolors_1.cyan)(`${packageManager} install`)}`);
console.log();
}
else {
console.log("\nInstalling dependencies:");
console.log();
console.log("Installing packages. This might take a couple of minutes.");
console.log();
process.chdir(appPath);
await install(packageManager);
console.log("Packages installed.");
console.log();
}
console.log(`${(0, picocolors_1.green)("Success!")} Created ${projectName} at ${projectPath}`);
console.log();
}
const update = (0, update_check_1.default)(packageJson).catch(() => null);
async function notifyUpdate() {
try {
const updateInfo = await update;
if (updateInfo === null || updateInfo === void 0 ? void 0 : updateInfo.latest) {
const global = {
pnpm: "pnpm add -g",
};
const updateMessage = `${global[packageManager]} ${packageJson.name}`;
console.log((0, picocolors_1.yellow)((0, picocolors_1.bold)(`A new version of \`${packageJson.name}\` is available!`)) +
"\n" +
"You can update by running: " +
(0, picocolors_1.cyan)(updateMessage) +
"\n");
}
process.exit(0);
}
catch (_a) {
// ignore error
}
}
async function exit(reason) {
console.log();
console.log("Aborting installation.");
if (reason.command) {
console.log(` ${(0, picocolors_1.cyan)(reason.command)} has failed.`);
}
else {
console.log((0, picocolors_1.red)("Unexpected error. Please report it as a bug:") + "\n", reason);
}
console.log();
await notifyUpdate();
process.exit(1);
}
(async () => {
try {
await run();
await notifyUpdate();
}
catch (error) {
await exit(error);
}
})();
//# sourceMappingURL=index.js.map
;