neon-cli
Version:
Build and load native Rust/Neon modules.
256 lines (255 loc) • 11.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const inquirer_1 = require("inquirer");
const path_1 = __importDefault(require("path"));
const handlebars_1 = __importDefault(require("handlebars"));
const semver_1 = __importDefault(require("semver"));
const style = __importStar(require("../style"));
const validateLicense = require("validate-npm-package-license");
const validateName = require("validate-npm-package-name");
const JSON = __importStar(require("ts-typed-json"));
const git_config_1 = __importDefault(require("git-config"));
const { readFile, stat } = fs_1.promises;
const ROOT_DIR = path_1.default.resolve(__dirname, "..", "..");
const TEMPLATES_DIR = path_1.default.resolve(ROOT_DIR, "templates");
const NEON_CLI_VERSION = JSON.asString(JSON.asObject(JSON.loadSync(path_1.default.resolve(ROOT_DIR, "package.json"))).version);
function compile(filename) {
return __awaiter(this, void 0, void 0, function* () {
let source = yield readFile(path_1.default.resolve(TEMPLATES_DIR, filename), {
encoding: "utf8",
});
return handlebars_1.default.compile(source, { noEscape: true });
});
}
const GITIGNORE_TEMPLATE = compile(".gitignore.hbs");
const CARGO_TEMPLATE = compile("Cargo.toml.hbs");
const NPM_TEMPLATE = compile("package.json.hbs");
const INDEXJS_TEMPLATE = compile("index.js.hbs");
const LIBRS_TEMPLATE = compile("lib.rs.hbs");
const README_TEMPLATE = compile("README.md.hbs");
const BUILDRS_TEMPLATE = compile("build.rs.hbs");
function guessAuthor() {
return __awaiter(this, void 0, void 0, function* () {
let author = {
name: process.env.USER || process.env.USERNAME,
email: undefined,
};
try {
let config = git_config_1.default.sync();
if (config.user.name) {
author.name = config.user.name;
}
if (config.user.email) {
author.email = config.user.email;
}
return author;
}
catch (e) {
return author;
}
});
}
function parseNeonVersion(flag) {
return __awaiter(this, void 0, void 0, function* () {
if (!flag) {
return { type: "version", value: NEON_CLI_VERSION };
}
if (semver_1.default.valid(flag)) {
return { type: "version", value: flag };
}
if (semver_1.default.validRange(flag)) {
return { type: "range", value: flag };
}
let stats = yield stat(flag);
if (!stats.isDirectory()) {
throw new Error("Specified path to Neon is not a directory");
}
return { type: path_1.default.isAbsolute(flag) ? "absolute" : "relative", value: flag };
});
}
function wizard(pwd, name, neon, features, noDefaultFeatures) {
return __awaiter(this, void 0, void 0, function* () {
let warning = "WARN: `neon new` is deprecated. To create a new project use `npm init neon my-project`.";
let banner = "".padStart(warning.length + 4, "#");
console.warn(`${banner}\n# ${warning} #\n${banner}\n`);
let its = validateName(name);
if (!its.validForNewPackages) {
let errors = (its.errors || []).concat(its.warnings || []);
throw new Error("Sorry, " + errors.join(" and ") + ".");
}
// check for a scoped name
let scoped = name.match(/@([^\/]+)\/(.*)/);
let [, scope, local] = scoped
? scoped
: [, null, name];
console.log("This utility will walk you through creating the " +
style.project(name) +
" Neon project.");
console.log("It only covers the most common items, and tries to guess sensible defaults.");
console.log();
console.log("Press ^C at any time to quit.");
let root = path_1.default.resolve(pwd, local);
let guess = yield guessAuthor();
let answers = yield (0, inquirer_1.prompt)([
{
type: "input",
name: "version",
message: "version",
default: "0.1.0",
validate: function (input) {
if (semver_1.default.valid(input)) {
return true;
}
return "Invalid version: " + input;
},
},
{ type: "input", name: "description", message: "description" },
{
type: "input",
name: "node",
message: "node entry point",
default: "lib/index.js",
},
{ type: "input", name: "git", message: "git repository" },
{ type: "input", name: "author", message: "author", default: guess.name },
{ type: "input", name: "email", message: "email", default: guess.email },
{
type: "input",
name: "license",
message: "license",
default: "MIT",
validate: function (input) {
let its = validateLicense(input);
if (its.validForNewPackages) {
return true;
}
let errors = its.warnings || [];
return "Sorry, " + errors.join(" and ") + ".";
},
},
]);
answers.name = {
npm: {
full: name,
scope: scope,
local: local,
},
cargo: {
external: local,
internal: local.replace(/-/g, "_"),
},
};
answers.description = escapeQuotes(answers.description);
answers.git = encodeURI(answers.git);
answers.author = escapeQuotes(answers.author);
let neonVersion = yield parseNeonVersion(neon);
let simple = (neonVersion.type === "version" || neonVersion.type === "range") &&
!features &&
!noDefaultFeatures;
let libs = { simple, noDefaultFeatures };
if (neonVersion.type === "relative") {
let neon = path_1.default.relative(path_1.default.join(name, "native"), neonVersion.value);
libs.paths = {
neon: JSON.stringify(neon),
"neon-build": JSON.stringify(path_1.default.join(neon, "crates", "neon-build")),
};
}
else if (neonVersion.type === "absolute") {
libs.paths = {
neon: JSON.stringify(neonVersion.value),
"neon-build": JSON.stringify(path_1.default.resolve(neonVersion.value, "crates", "neon-build")),
};
}
else {
libs.version = JSON.stringify(neonVersion.value);
}
if (features) {
libs.features = features.split(/\s+/).map(JSON.stringify);
}
let cli = JSON.stringify(neonVersion.type === "version"
? "^" + neonVersion.value
: neonVersion.type === "relative"
? "file:" + path_1.default.join(path_1.default.relative(name, neonVersion.value), "cli")
: neonVersion.type === "absolute"
? "file:" + path_1.default.resolve(neonVersion.value, "cli")
: neonVersion.value);
let ctx = {
project: answers,
neon: { cli, libs },
};
let lib = path_1.default.resolve(root, path_1.default.dirname(answers.node));
let native_ = path_1.default.resolve(root, "native");
let src = path_1.default.resolve(native_, "src");
(0, fs_1.mkdirSync)(lib, { recursive: true });
(0, fs_1.mkdirSync)(src, { recursive: true });
(0, fs_1.writeFileSync)(path_1.default.resolve(root, ".gitignore"), (yield GITIGNORE_TEMPLATE)(ctx), { flag: "wx" });
(0, fs_1.writeFileSync)(path_1.default.resolve(root, "package.json"), (yield NPM_TEMPLATE)(ctx), {
flag: "wx",
});
(0, fs_1.writeFileSync)(path_1.default.resolve(native_, "Cargo.toml"), (yield CARGO_TEMPLATE)(ctx), { flag: "wx" });
(0, fs_1.writeFileSync)(path_1.default.resolve(root, "README.md"), (yield README_TEMPLATE)(ctx), {
flag: "wx",
});
(0, fs_1.writeFileSync)(path_1.default.resolve(root, answers.node), (yield INDEXJS_TEMPLATE)(ctx), { flag: "wx" });
(0, fs_1.writeFileSync)(path_1.default.resolve(src, "lib.rs"), (yield LIBRS_TEMPLATE)(ctx), {
flag: "wx",
});
(0, fs_1.writeFileSync)(path_1.default.resolve(native_, "build.rs"), (yield BUILDRS_TEMPLATE)(ctx), { flag: "wx" });
let relativeRoot = path_1.default.relative(pwd, root);
let relativeNode = path_1.default.relative(pwd, path_1.default.resolve(root, answers.node));
let relativeRust = path_1.default.relative(pwd, path_1.default.resolve(src, "lib.rs"));
console.log();
console.log("Woo-hoo! Your Neon project has been created in: " +
style.path(relativeRoot));
console.log();
console.log("The main Node entry point is at: " + style.path(relativeNode));
console.log("The main Rust entry point is at: " + style.path(relativeRust));
console.log();
console.log("To build your project, just run " +
style.command("npm install") +
" from within the " +
style.path(relativeRoot) +
" directory.");
console.log("Then you can test it out with " +
style.command("node -e 'require(\"./\")'") +
".");
console.log();
console.log("Happy hacking!");
});
}
exports.default = wizard;
function escapeQuotes(str) {
return str.replace(/"/g, '\\"');
}