UNPKG

@fewer/cli

Version:

The CLI to scaffold and perform operations for Fewer.

128 lines 5.75 kB
"use strict"; 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