@fewer/cli
Version:
The CLI to scaffold and perform operations for Fewer.
128 lines • 5.75 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const mkdirp_1 = __importDefault(require("mkdirp"));
const path_1 = __importDefault(require("path"));
const execa_1 = __importDefault(require("execa"));
const ejs_1 = __importDefault(require("ejs"));
const util_1 = require("util");
const enquirer_1 = __importDefault(require("enquirer"));
const prettier_1 = __importDefault(require("prettier"));
const sortBy_1 = __importDefault(require("lodash/sortBy"));
const getConfig_1 = __importDefault(require("./getConfig"));
const cwd = process.cwd();
const statAsync = util_1.promisify(fs_1.default.stat);
const writeFileAsync = util_1.promisify(fs_1.default.writeFile);
const mkdirpAsync = util_1.promisify(mkdirp_1.default);
const readdirAsync = util_1.promisify(fs_1.default.readdir);
async function hasFileOrDir(filename) {
try {
await statAsync(path_1.default.join(cwd, filename));
return true;
}
catch (e) {
return false;
}
}
const isProject = () => hasFileOrDir('package.json');
const isTSProject = () => hasFileOrDir('tsconfig.json');
async function ensureProject(warn, error) {
const config = await getConfig_1.default();
if (!(await isProject())) {
error('We were not able to resolve the current project. Ensure that you are in a directory containing a "package.json" file and try again.', { exit: 1 });
}
// TODO: Add flags on the command to optionally validate this stuff.
if (!(await hasFileOrDir(config.src))) {
error(`We were not able to find the source directory "${config.src}". You can use the "src" parameter in your Fewer configuration file to tell the CLI where your source files are located.`, { exit: 1 });
}
if (config.typescript) {
if (!(await isTSProject())) {
warn('We did not detect a TypeScript configuration file (tsconfig.json). TypeScript is recommend.');
const confirm = await prompt({
type: 'confirm',
message: 'Would you like to continue without TypeScript?',
});
if (!confirm) {
error('Re-run `fewer init` once your have initialized TypeScript in your project.', { exit: 1 });
}
}
}
}
exports.ensureProject = ensureProject;
function hasDependency(dep) {
const pkg = require(path_1.default.join(cwd, 'package.json'));
return !!pkg.dependencies[dep] || !!pkg.devDependencies[dep];
}
exports.hasDependency = hasDependency;
async function installPackages(warn, ...packages) {
const manager = await prompt({
type: 'select',
message: 'Which package manager should be used to install new dependencies?',
choices: ['npm', 'yarn', 'skip dependencies'],
});
if (manager === 'npm') {
await execa_1.default('npm', ['install', ...packages]);
}
else if (manager === 'yarn') {
await execa_1.default('yarn', ['add', ...packages]);
}
else {
warn(`The following dependencies are required to run, but were not installed: ${packages.join(', ')}`);
}
}
exports.installPackages = installPackages;
async function prompt(options) {
try {
const responses = await enquirer_1.default.prompt(Object.assign({ name: 'question' }, options));
return Object.values(responses)[0];
}
catch (e) {
process.exit(1);
}
}
exports.prompt = prompt;
async function createDirectory(directory) {
await mkdirpAsync(path_1.default.join(cwd, directory));
}
exports.createDirectory = createDirectory;
async function createFileWithContents(fileName, contents) {
await writeFileAsync(path_1.default.join(cwd, fileName), contents);
}
exports.createFileWithContents = createFileWithContents;
async function createFile(template, fileName, data, cjs) {
let fileContents = await ejs_1.default.renderFile(path_1.default.join(__dirname, '..', 'templates', `${template}.ejs`), data, { async: true });
if (cjs) {
fileContents = toCJS(fileContents);
}
const outputFilePath = path_1.default.join(cwd, fileName);
const prettierConfig = await prettier_1.default.resolveConfig(outputFilePath);
await writeFileAsync(outputFilePath, prettier_1.default.format(fileContents, Object.assign({ filepath: outputFilePath }, prettierConfig)));
}
exports.createFile = createFile;
async function getMigrations() {
const config = await getConfig_1.default();
// TODO: Store project root somewhere (read-pkg-up?) so that I don't need to do cwd garbage:
const migrationFiles = await readdirAsync(path_1.default.resolve(cwd, config.migrations));
return sortBy_1.default(migrationFiles.filter(filename => !filename.startsWith('.'))).map(filename => path_1.default.join(cwd, config.migrations, filename));
}
exports.getMigrations = getMigrations;
function resolve(from, to) {
const relativePath = path_1.default.relative(path_1.default.dirname(from), path_1.default.join(path_1.default.dirname(to), path_1.default.basename(to, path_1.default.extname(to))));
if (!relativePath.startsWith('.')) {
return `./${relativePath}`;
}
return relativePath;
}
exports.resolve = resolve;
// A quick-and-dirty way to convert a file to from ESM to CJS. This is intentionally
// not perfect, and only is designed to work with the templates included here.
function toCJS(contents) {
return contents
.replace('export default', 'module.exports =')
.replace(/import (.*?) from (.*?);/g, 'const $1 = require($2);');
}
exports.toCJS = toCJS;
//# sourceMappingURL=utils.js.map