UNPKG

@acot/cli

Version:
434 lines (433 loc) 13.7 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 path_1 = __importDefault(require("path")); const util_1 = require("util"); const url_1 = require("url"); const chalk_1 = __importDefault(require("chalk")); const enquirer_1 = __importDefault(require("enquirer")); const execa_1 = __importDefault(require("execa")); const listr_1 = __importDefault(require("listr")); const node_emoji_1 = require("node-emoji"); const prettier_1 = __importDefault(require("prettier")); const isURL_1 = __importDefault(require("validator/lib/isURL")); const find_chrome_1 = require("@acot/find-chrome"); const command_1 = require("../command"); const logging_1 = require("../logging"); const writeFile = (0, util_1.promisify)(fs_1.default.writeFile); const FORMATS = [ { name: 'javascript', message: 'JavaScript', hint: 'acot.config.js' }, { name: 'json', message: 'JSON', hint: '.acotrc.json' }, ]; const NPM_CLIENTS = ['npm', 'yarn']; const prompt = async (option) => { const opts = option; const res = await enquirer_1.default.prompt(opts); return res[opts.name]; }; const assertWith = (value, validator) => { const res = validator(value); if (typeof res === 'string') { throw new TypeError(res); } }; const validateOrigin = (value) => { const val = value.trim(); if (!val) { return 'Required!'; } if (!(0, isURL_1.default)(val, { protocols: ['http', 'https'], require_protocol: true, require_tld: false, })) { return 'URL Origin must be valid URL. (e.g. https://example.com)'; } return true; }; const validateFormat = (value) => { const val = value.trim(); const names = FORMATS.map((o) => o.name); if (!names.includes(val)) { return `Config file format must be one of the following: ${names.join(', ')}`; } return true; }; const validateNpmClient = (value) => { const val = value.trim(); if (NPM_CLIENTS.includes(val)) { return `npm client must be one of the following: ${NPM_CLIENTS.join(', ')}`; } return true; }; const isPuppeteerInstalled = async () => { return (await (0, find_chrome_1.findChrome)({ channel: 'puppeteer' })) !== null; }; const isYarnExists = async () => { try { await execa_1.default.command('yarn --version', { stdio: 'ignore' }); return true; } catch (e) { return false; } }; const promptUserIfNeeded = async (defaults) => { const result = { origin: '', server: '', command: null, useConfig: false, runner: '', format: '', installPuppeteer: false, npmClient: '', }; if (defaults.origin !== undefined) { result.origin = defaults.origin.trim(); } else { result.origin = await prompt({ type: 'input', name: 'origin', message: 'What is the origin for the audit target?', validate: validateOrigin, result(value) { return value.trim().replace(/\/$/, ''); }, }); } if (defaults.server !== undefined) { result.server = defaults.server; } else { result.server = await prompt({ type: 'select', name: 'server', message: 'What kind of server do you want to connect to?', choices: [ { name: 'exiting', message: 'Existing server', hint: '(e.g. "https://example.com")', }, { name: 'command', message: 'Launch server via command', hint: '(e.g. "npm start")', }, ], }); } if (defaults.command !== undefined) { result.command = defaults.command.trim(); } else if (result.server === 'command') { result.command = await prompt({ type: 'input', name: 'command', message: 'What is the command to start the server?', validate(value) { const val = value.trim(); if (!val) { return 'Required'; } return true; }, result(value) { return value.trim(); }, }); } if (defaults.useConfig !== undefined) { result.useConfig = defaults.useConfig; } else { result.useConfig = await prompt({ type: 'toggle', name: 'useConfig', message: 'Do you want to use the config recommended by acot?', initial: 1, }); } if (defaults.runner !== undefined) { result.runner = defaults.runner; } else { result.runner = await prompt({ type: 'select', name: 'runner', message: 'Which runner do you want to use?', choices: [ { name: 'default', message: 'Default Runner', }, { name: '@acot/sitemap', message: 'Sitemap Runner', }, { name: '@acot/storybook', message: 'Storybook Runner', }, ], result(value) { return value === 'default' ? '' : value; }, }); } if (defaults.format !== undefined) { result.format = defaults.format.trim(); } else { result.format = await prompt({ type: 'select', name: 'format', message: 'Which format do you prefer for the config file?', choices: FORMATS, initial: 0, validate: validateFormat, }); } if (defaults.installPuppeteer !== undefined) { result.installPuppeteer = defaults.installPuppeteer; } else { const puppeteerInstalled = await isPuppeteerInstalled(); if (puppeteerInstalled) { result.installPuppeteer = false; } else { result.installPuppeteer = await prompt({ type: 'toggle', name: 'installPuppeteer', message: 'Do you want to install Puppeteer as a dependency?', initial: 1, }); } } if (defaults.npmClient !== undefined) { result.npmClient = defaults.npmClient.trim(); } else { const shoudPackageInstall = result.useConfig || result.runner !== '' || result.installPuppeteer; const yarnExists = await isYarnExists(); if (shoudPackageInstall) { if (yarnExists) { result.npmClient = await prompt({ type: 'select', name: 'npmClient', message: 'Which is the npm client used to install the dependent packages?', choices: NPM_CLIENTS, initial: 0, validate: validateNpmClient, }); } else { result.npmClient = NPM_CLIENTS[0]; } } } return result; }; const result2string = (result) => { const config = {}; if (result.useConfig) { config.extends = ['@acot']; } if (result.command) { config.connection = { command: result.command, }; } switch (result.runner) { case '@acot/sitemap': { config.runner = { uses: result.runner, with: { source: new url_1.URL('/sitemap.xml', result.origin).toString(), }, }; break; } case '@acot/storybook': { config.runner = { uses: result.runner, }; break; } } config.origin = result.origin; if (result.runner === '') { config.paths = ['/']; } const content = JSON.stringify(config, null, ' '); switch (result.format) { case 'javascript': { return prettier_1.default.format(`module.exports = ${content}`, { parser: 'babel', semi: true, singleQuote: true, trailingComma: 'all', }); } case 'json': { return prettier_1.default.format(content, { parser: 'json', }); } default: throw new Error('Invalid config format'); } }; exports.default = (0, command_1.createCommand)({ name: 'init', summary: 'Building a config file and installing dependent packages.', args: {}, options: { origin: { type: 'string', alias: 'o', description: 'Audit server base URL.', }, command: { type: 'string', alias: 'C', description: 'Command to launch the local server.', }, 'use-recommended-config': { type: 'boolean', description: 'Use the config recommended by acot.', }, runner: { type: 'string', alias: 'r', description: 'Runner to use for audit.', }, format: { type: 'string', alias: 's', description: 'Format to use for the configuration file.', }, 'install-puppeteer': { type: 'boolean', description: 'Install Puppeteer as a dependency.', }, 'no-install-puppeteer': { type: 'boolean', description: 'Not install Puppeteer as a dependency.', }, 'npm-client': { type: 'string', description: 'npm client to use for dependent packages installations. (npm or yarn)', }, }, })(async ({ cwd, logger, args }) => { // collect configuration data const defaults = {}; if (args.origin) { defaults.origin = args.origin; assertWith(defaults.origin, validateOrigin); } if (args.command) { defaults.server = 'command'; defaults.command = args.command; } if (args['use-recommended-config']) { defaults.useConfig = true; } if (args.runner) { defaults.runner = args.runner; } if (args.format) { defaults.format = args.format; assertWith(defaults.format, validateFormat); } if (args['install-puppeteer']) { defaults.installPuppeteer = true; } else if (args['no-install-puppeteer']) { defaults.installPuppeteer = false; } if (args['npm-client']) { defaults.npmClient = args['npm-client']; assertWith(defaults.npmClient, validateNpmClient); } let result; try { result = await promptUserIfNeeded(defaults); } catch (e) { // cancel if (typeof e === 'string' && e === '') { return 0; } throw e; } (0, logging_1.debug)('prompt result:', result); // tasks const tasks = new listr_1.default([ { title: 'Create config file', task: () => { const content = result2string(result); let filepath = ''; switch (result.format) { case 'javascript': filepath = path_1.default.resolve(cwd, 'acot.config.js'); break; case 'json': filepath = path_1.default.resolve(cwd, '.acotrc.json'); break; } return writeFile(filepath, content, 'utf8'); }, }, { title: `Install package dependencies with ${result.npmClient}`, enabled: () => !!(result.useConfig || result.runner || result.installPuppeteer), task: () => { const deps = []; if (result.useConfig) { deps.push('@acot/acot-config'); } if (result.installPuppeteer) { deps.push('puppeteer'); } switch (result.runner) { case '@acot/sitemap': deps.push('@acot/acot-runner-sitemap'); break; case '@acot/storybook': deps.push('@acot/acot-runner-storybook'); break; } switch (result.npmClient) { case 'npm': return (0, execa_1.default)('npm', ['install', '-D', ...deps]); case 'yarn': return (0, execa_1.default)('yarn', ['add', '-D', ...deps]); default: throw new Error('Invalid npm client'); } }, }, ]); logger.print(''); logger.print((0, chalk_1.default) `{gray.bold (Setup acot)}`); await tasks.run(); logger.print([ '', (0, node_emoji_1.emojify)((0, chalk_1.default) `{bold Welcome to acot!} :tada:`), '', (0, chalk_1.default) `You can start taking the first step in making your site accessible with \`{cyan.bold $ npx acot run}\`.`, 'We hope that acot will help you with your accessibility efforts.', 'Enjoy!', '', ].join('\n')); return 0; });