UNPKG

@coat/cli

Version:

TODO: See #3

196 lines (183 loc) 8.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.create = create; var _fsExtra = _interopRequireDefault(require("fs-extra")); var _path = _interopRequireDefault(require("path")); var _execa = _interopRequireDefault(require("execa")); var _ora = _interopRequireDefault(require("ora")); var _chalk = _interopRequireDefault(require("chalk")); var _getProjectName = require("./get-project-name"); var _getTemplateInfo = require("./get-template-info"); var _constants = require("../constants"); var _json = require("../file-types/json"); var _addInitialCommit = require("./add-initial-commit"); var _printCreateCustomizationHelp = require("./print-create-customization-help"); var _getCoatHeader = require("../bin/get-coat-header"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Creates and generates a new coat project. * * @param options.template The template that should be used for the new project * @param options.directory The optional path to the directory that should be used * @param options.projectName The optional project name that has been provided */ async function create({ template, directory, projectName }) { // Print the coat logo and header console.log((0, _getCoatHeader.getCoatHeader)()); const directoryInputSanitized = directory === null || directory === void 0 ? void 0 : directory.trim(); const projectNameInputSanitized = projectName === null || projectName === void 0 ? void 0 : projectName.trim(); // Resolve the target directory and project name for the new coat project // from the cli arguments if they are available let targetCwd; let usableProjectName; if (!directoryInputSanitized) { // No input for the target directory has been provided, // therefore the user should be prompted for a project name that // will be used as the target directory. // // The projectNameInput argument will be ignored, since it could have // only been passed via an edge case, e.g. when running // `coat create template "" my-project` which should not be supported. usableProjectName = await (0, _getProjectName.getProjectName)(); // The project name should be used as the target directory in the current // working directory targetCwd = _path.default.join(process.cwd(), usableProjectName); } else { if (_path.default.isAbsolute(directoryInputSanitized)) { // If the directory input is a valid absolute path, it should be used directly targetCwd = directoryInputSanitized; } else { // Otherwise, the directory input should be treated as a relative path // to the current working directory targetCwd = _path.default.join(process.cwd(), directoryInputSanitized); } if (projectNameInputSanitized) { usableProjectName = projectNameInputSanitized; } else { // Retrieve the trailing folder name of the target directory to use it // as the project name const suggestedProjectName = _path.default.basename(targetCwd); if (suggestedProjectName === directoryInputSanitized) { // If the suggested project name matches the directory input argument // it should be used directly without prompting the user. // // This should be the most common scenario where create is run like // `coat create template my-project` // where both the directoryInput and suggested project name are "my-project" usableProjectName = suggestedProjectName; } else { // If the suggested project name does not directly match the directory input, // the user should be prompted for a project name and with the trailing folder // name as the suggestion. // // This will likely be a scenario where the user calls coat create like: // (process.cwd = /usr/source/some-project) // `coat create template .` // -> suggested project name will be some-project usableProjectName = await (0, _getProjectName.getProjectName)(suggestedProjectName); } } } // Check if a coat manifest file already exists in the project let coatManifestExists = false; try { await _fsExtra.default.readFile(_path.default.join(targetCwd, _constants.COAT_MANIFEST_FILENAME)); // If this line is reached the coat manifest file already exists coatManifestExists = true; } catch (error) { if (error.code !== "ENOENT") { // If the error is not due to a missing file, but e.g. due // to missing permissions it should be thrown to the user throw error; } // The coat manifest file does not exist in the target directory } if (coatManifestExists) { console.error(`A coat manifest file already exists in the target directory.\n\nPlease install the template manually via npm and add the name of the template to the existing coat manifest file.`); throw new Error("coat manifest file already exists"); } // Check if a package.json file already exists // in the target directory, otherwise create it let previousPackageJson; try { const previousPackageJsonRaw = await _fsExtra.default.readFile(_path.default.join(targetCwd, _constants.PACKAGE_JSON_FILENAME), "utf-8"); previousPackageJson = JSON.parse(previousPackageJsonRaw); } catch (error) { if (error.code !== "ENOENT") { // If the error is not due to a missing file, but e.g. due // to missing permissions it should be thrown to the user throw error; } // package.json does not exit in the target directory } if (!previousPackageJson) { const packageJson = { name: usableProjectName, version: "1.0.0" }; // Create the package.json file inside the // target directory. await _fsExtra.default.outputFile(_path.default.join(targetCwd, _constants.PACKAGE_JSON_FILENAME), // package.json does not need to be styled, since npm // will alter and format it while installing dependencies JSON.stringify(packageJson)); previousPackageJson = packageJson; } console.log((0, _chalk.default)`\nCreating a new {cyan coat} project in {green ${targetCwd}}\n`); // Print getting started guidance for customization (0, _printCreateCustomizationHelp.printCreateCustomizationHelp)(); console.log((0, _chalk.default)`{cyan coat} will install the project template and its dependencies into the project directory.\nThis might take a couple of minutes.\n`); const installSpinner = (0, _ora.default)("Installing template into project directory\n").start(); try { // Run npm install to install the template and its dependencies await (0, _execa.default)("npm", ["install", "--save-exact", "--save-dev", template], { cwd: targetCwd }); // We need to retrieve the correct template name, // since the template string that has been passed // to coat create could also be a local file path, // GitHub URL or npm tag const templateInfo = await (0, _getTemplateInfo.getTemplateInfo)(targetCwd, previousPackageJson, template, installSpinner); installSpinner.succeed(); // Write the coat manifest file const coatManifest = { name: usableProjectName, extends: templateInfo.name }; await _fsExtra.default.writeFile(_path.default.join(targetCwd, _constants.COAT_MANIFEST_FILENAME), (0, _json.polish)(coatManifest, _constants.COAT_MANIFEST_FILENAME)); } catch (error) { installSpinner.fail(); // Re-throw error to provide feedback to the user throw error; } // Run setup and sync commands in the project directory // // The current coat process is respawned to use a local // @coat/cli in case it is available after installing // the template, since templates should have a peerDependency // on the cli. // // The setup step will be triggered automatically by running sync await (0, _execa.default)(process.argv[0], [process.argv[1], "sync"], { cwd: targetCwd, stdio: "inherit" }); // Initialize a git repository and add an initial commit // if the project was not created in an existing git repository await (0, _addInitialCommit.addInitialCommit)(targetCwd); console.log((0, _chalk.default)`🎊 Your new {cyan coat} project has been successfully created! 🎊\n`); const relativePath = _path.default.relative(process.cwd(), targetCwd); // Only log if relativePath exists, i.e. the user is in a different // directory than the project target directory if (relativePath) { console.log((0, _chalk.default)`Get started by changing into your project folder: {cyan cd ${relativePath}}`); } console.log((0, _chalk.default)`You can ensure your generated files are up to date by running: {cyan coat sync}\n`); console.log("⚡️ Happy hacking! ⚡️\n"); }