@acot/cli
Version:
More accessible web, all over the world.
434 lines (433 loc) • 13.7 kB
JavaScript
"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;
});