UNPKG

@miyagi/core

Version:

miyagi is a component development tool for JavaScript template engines.

260 lines (240 loc) 7.91 kB
const path = require("path"); const fs = require("fs"); const jsonToYaml = require("js-yaml"); const log = require("../logger.js"); const helpers = require("../helpers.js"); const { messages } = require("../config.json"); /** * Module for creating component files based on the configuration cli params * * @module generatorComponent * @param {object} cliParams - the cli params object * @param {object} config - the user configuration object */ module.exports = async function componentGenerator(cliParams, config) { const commands = cliParams._.slice(1); if (commands.length === 0) { log("error", messages.generator.noComponentNameDefined); return; } const [componentNameWithFolder] = commands; createComponentFolder(componentNameWithFolder) .then(async () => { await createComponentFiles( config.files, componentNameWithFolder, cliParams ); log("success", messages.generator.done); }) .catch(() => { log( "error", messages.generator.unknownError.replace( "{{name}}", componentNameWithFolder ) ); }); /** * Returns an array with file names, if necessary filtered based on args * * @param {object} fileNames - an object with file names for the component * @param {object} args - the cli args * @returns {Array} all file paths that should be created */ function getFiles(fileNames, args) { if (args) { if (args.skip) { const files = []; const entries = Object.entries(fileNames); for (const [alias, name] of entries) { if (!args.skip.includes(alias)) { files.push(name); } } return files; } if (args.only) { return args.only.map((entry) => fileNames[entry]); } return Object.values(fileNames); } return Object.values(fileNames); } /** * Returns the dummy content for a component file * * @param {string} fileType - the file type that should be created * @param {object} filesConfig - the files object from the user congiguration object * @returns {string} dummy file content based on the given file type */ function getDummyFileContent(fileType, filesConfig) { let str; switch (fileType) { case "mocks": { const data = { $variants: [ { $name: "", }, ], }; if (filesConfig.mocks.extension === "yaml") { str = jsonToYaml.dump(data); } else { str = `${JSON.stringify(data, null, 2)}\n`; } } break; case "info": { const data = { name: "", }; if (filesConfig.info.extension === "yaml") { str = jsonToYaml.dump(data); } else { str = `${JSON.stringify(data, null, 2)}\n`; } } break; case "schema": { const data = { $schema: "http://json-schema.org/draft-07/schema", $id: "", required: [], properties: {}, }; if (filesConfig.schema.extension === "yaml") { str = jsonToYaml.dump(data); } else { str = `${JSON.stringify(data, null, 2)}\n`; } } break; default: str = ""; } return str; } /** * Creates the component files * * @param {object} filesConfig - the files configuration from the user configuration object * @param {string} componentPath - the path of the component folder * @param {object} args - the cli args * @returns {Promise} gets resolved when all files have been created */ function createComponentFiles(filesConfig, componentPath, args) { const componentName = path.basename(componentPath); const fileNames = getFileNames(filesConfig, componentName); const files = getFiles(fileNames, args); const entries = Object.entries(fileNames); const promises = []; for (const [type, file] of entries) { if (files.includes(file)) { promises.push( new Promise((resolve) => { const fullFilePath = path.join( process.env.INIT_CWD || process.cwd(), componentPath, file ); fs.writeFile( fullFilePath, getDummyFileContent(type, filesConfig), { flag: "wx" }, function createComponentFilesCallback(err) { if (err) { if (err.code === "EEXIST") { log( "warn", messages.generator.fileAlreadyExists.replace( "{{name}}", fullFilePath ) ); } else if (err.code !== "ENOENT") { log( "error", messages.generator.unknownError.replace( "{{name}}", fullFilePath ) ); } } resolve(); } ); }) ); } } return Promise.all(promises); } /** * Returns an object with the file names for a given component name * * @param {object} filesConfig - the files configuration from the user configuration object * @param {string} componentName - the name of the component * @returns {object} all file names based on the user configuration */ function getFileNames(filesConfig, componentName) { return { tpl: `${helpers.getResolvedFileName( filesConfig.templates.name, componentName )}.${filesConfig.templates.extension}`, mocks: `${filesConfig.mocks.name}.${filesConfig.mocks.extension}`, docs: `${filesConfig.docs.name}.${filesConfig.docs.extension}`, info: `${filesConfig.info.name}.${filesConfig.info.extension}`, css: `${helpers.getResolvedFileName( filesConfig.css.name, componentName )}.${filesConfig.css.extension}`, js: `${helpers.getResolvedFileName(filesConfig.js.name, componentName)}.${ filesConfig.js.extension }`, schema: `${filesConfig.schema.name}.${filesConfig.schema.extension}`, }; } /** * Creates the component folder * * @param {string} folder - component folder path that should be created * @returns {Promise} gets resolved when the folder has been created */ function createComponentFolder(folder) { return new Promise((resolve, reject) => { fs.mkdir( /* * When using `yarn/npm miyagi new …`, `process.env.INIT_CWD` equals * the current working directory, so also subdirectories of where * the package.json is located. In this case `process.cwd()` always * equals the root directory though. * When using node directly, `process.env.INIT_CWD` is not available, * but `process.cwd()` is always the current working directory, so * also subdirectories. * So, if INIT_CWD is available, we know it is the directory the user * cd'ed into, if it not available, then we use process.cwd(), which * in that case is also the directory the user cd'ed into. * It is important that we let the user create a component from their * current working directory, so they can benefit from autocompletion. */ path.join(process.env.INIT_CWD || process.cwd(), folder), { recursive: true }, function createComponentCallback(err) { if (err) { reject(err); } else { resolve(); } } ); }); } };