UNPKG

@mason-api/cli

Version:

CLI assistant for Mason builder

153 lines (139 loc) 6.79 kB
import _ from 'lodash'; import colors from 'colors/safe'; import path from 'path'; import spawn from 'child_process'; import { formats, getDatasourceIds } from '@mason-api/generator'; import { getAPIKey, getIdToken, getUserId } from './login'; import { fetchProjects, prompt, promptChoice } from '../utils'; export const command = 'guide'; export const desc = 'Guide through template generation'; export const handler = async (argv) => { console.log(colors.bold('Welcome to Mason wizard!')); console.log(`It will guide you through a process to generate static templates out of your components to be used with a server-side application`); const idToken = await getIdToken(); const apiKey = await getAPIKey(false); const userId = await getUserId(false); console.log(colors.bold('\nWhich format would you like to use?')); const format = await promptChoice('Format: ', 'format name', { html: 'Static HTML', ejs: 'EJS (JavaScript)', pug: 'PUG (JavaScript)', php: 'PHP native templating (PHP)', twig: 'TWIG (PHP)', erb: 'ERB (Ruby)', haml: 'HAML (Ruby)', handlebars: 'Handlebars', mustache: 'Mustache', }); console.log(colors.bold('\nWhich project would you like to work with?')); const projects = await fetchProjects(idToken, argv.verbose); const projectId = await promptChoice('Project: ', 'project id', _.mapValues( _.keyBy(_.filter(projects, p => !p.isArchived && _.findIndex(p.members, ['id', userId]) > -1), 'id'), project => project.name, )); const project = _.find(projects, ['id', projectId]); console.log(colors.bold(`\nWhich ${colors.italic('published')} component would you like to generate templates for?`)); const componentId = (await promptChoice( 'Component: ', 'component id', _.mapValues(_.keyBy(project.publishedComponents, 'id'), component => component.name), 'Leave blank to generate templates for all components', )) || '*'; const component = _.find(project.components, ['id', componentId]); let page = ''; if (component) { if (_.keys(_.get(component, 'config.data', []).length) > 1) { console.log(colors.bold(`\nWhich ${colors.italic('published')} component would you like to generate templates for?`)); page = (await promptChoice( 'Page: ', 'page name', _.mapValues(_.keyBy(_.keys(component.config.data)), _.startCase), 'Leave blank to generate templates for all pages', )) || '*'; } else { page = 'default'; } } const params = []; // if (componentId === '*' || page === '*') { console.log(colors.bold('\nProvide an output directory for the generated files ')); console.log(colors.italic(colors.gray('Leave blank to place files in the current directory'))); const outputDir = _.trim(await prompt('Output: ')) || '.'; params.push(`-o ${outputDir}`); // } if (format !== 'html') { console.log('\nWe\'re almost there!'); console.log(colors.bold('Would you like to adjust settings specific to generated templates?')); console.log(colors.gray(colors.italic('Example: setting prefix for data paths, embedding data into a template, toggling safe mode'))); if (!_.startsWith(_.toLower(await prompt(`${colors.bold('y')}/n: `)), 'n')) { const components = component ? [component] : project.publishedComponents; const datasourceIds = []; _.forEach(components, (comp) => { _.forEach(_.get(comp, 'config.data'), (page, name) => { _.forEach(getDatasourceIds(comp.config, name), (datasourceId) => { if (!_.includes(datasourceIds, datasourceId)) { datasourceIds.push(datasourceId); } }); }); }); const datasources = _.compact(_.map(datasourceIds, id => project.datasources[id])); if (datasources.length) { console.log(colors.bold('\nShould some of datasources be embedded into template directly?')); console.log('Datasources in component turn into loops and variables in the template.'); console.log('Data for those variables needs to be provided when template is rendered.'); console.log('You can pick certain datasources to inline their data into template statically.'); console.log('Chosen templates use the following datasources:'); const embedded = (await promptChoice( 'Page: ', 'page name', _.mapValues(_.keyBy(datasources, 'id'), datasource => datasource.name || datasource.id), 'Leave blank, choose one, or provide multiple choices separated with comma (e.g. 1,2)', true, )) || ''; if (embedded.length) { params.push(`--embed-data=${_.join(embedded, ' ')}`); } } const chosenFormat = formats[format]; const formatOptions = _.get(chosenFormat, 'options', {}); // eslint-disable-next-line for (const optionName in formatOptions) { const option = formatOptions[optionName]; console.log(colors.bold(`\n${option.description}`)); if (option.before) { console.log(colors.gray('Before: '), option.before({})); console.log(colors.gray('After: '), option.after({})); } if (typeof option.defaultValue === 'boolean') { const optionPrompt = option.defaultValue ? `${colors.bold('y')}/n: ` : `y/${colors.bold('n')}: `; const optionValue = await prompt(optionPrompt); if (optionValue) { const optionTrue = _.startsWith(_.toLower(optionValue), 'y'); if (option.defaultValue !== optionTrue) { params.push(`--${_.kebabCase(optionName)}=${optionTrue}`); } } } else { const optionValue = await prompt(`${_.startCase(optionName)}: `); if (optionValue) { params.push(`--${_.kebabCase(optionName)}=${optionValue}`); } } } } } params.push(`-k ${apiKey}`); console.log(colors.bold('\nGenerated command: ')); console.log(colors.italic(colors.gray('Use this command next time to avoid going through wizard again\nFor example you can use this as a part of your build process'))); const argList = [format, projectId, componentId, page, ...params]; const args = _.join(_.compact(argList), ' '); console.log(colors.green(`mason ${_.replace(args, '*', '\\*')}`)); console.log(colors.bold('\nExecute command now?')); console.log(colors.gray(`It will output to ${colors.white(path.resolve(__dirname, outputDir))} directory.`)); if (!_.startsWith(_.trim(await prompt(`${colors.bold('y')}/n: `)), 'n')) { const { spawn } = require('child_process'); yargs.parse(`generate ${args}`); } };