@duetds/date-picker
Version:
Duet Date Picker is an open source version of Duet Design System’s accessible date picker.
224 lines (179 loc) • 6.72 kB
JavaScript
;
exports.__esModule = true;
exports.setup = setup;
exports.getServers = getServers;
exports.teardown = teardown;
exports.JestDevServerError = exports.ERROR_NO_COMMAND = exports.ERROR_PORT_USED = exports.ERROR_TIMEOUT = void 0;
var _stream = _interopRequireDefault(require("stream"));
var _net = _interopRequireDefault(require("net"));
var _chalk = _interopRequireDefault(require("chalk"));
var _spawnd = _interopRequireDefault(require("spawnd"));
var _cwd = _interopRequireDefault(require("cwd"));
var _waitOn = _interopRequireDefault(require("wait-on"));
var _findProcess = _interopRequireDefault(require("find-process"));
var _util = require("util");
var _treeKill = _interopRequireDefault(require("tree-kill"));
var _prompts = _interopRequireDefault(require("prompts"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const DEFAULT_CONFIG = {
debug: false,
options: {},
launchTimeout: 5000,
host: 'localhost',
port: null,
protocol: 'tcp',
usedPortAction: 'ask',
waitOnScheme: {}
};
const pTreeKill = (0, _util.promisify)(_treeKill.default);
const serverLogPrefixer = new _stream.default.Transform({
transform(chunk, encoding, callback) {
this.push(_chalk.default.magentaBright(`[Jest Dev server] ${chunk.toString()}`));
callback();
}
});
const ERROR_TIMEOUT = 'ERROR_TIMEOUT';
exports.ERROR_TIMEOUT = ERROR_TIMEOUT;
const ERROR_PORT_USED = 'ERROR_PORT_USED';
exports.ERROR_PORT_USED = ERROR_PORT_USED;
const ERROR_NO_COMMAND = 'ERROR_NO_COMMAND';
exports.ERROR_NO_COMMAND = ERROR_NO_COMMAND;
class JestDevServerError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
exports.JestDevServerError = JestDevServerError;
const servers = [];
function logProcDetection(proc, port) {
console.log(_chalk.default.blue(`🕵️ Detecting a process "${proc.name}" running on port "${port}"`));
}
async function killProc(proc) {
console.log(_chalk.default.yellow(`Killing process ${proc.name}...`));
await pTreeKill(proc.pid);
console.log(_chalk.default.green(`Successfully killed process ${proc.name}`));
}
function runServer(config = {}, index) {
if (!config.command) {
throw new JestDevServerError('You must define a `command`', ERROR_NO_COMMAND);
}
servers[index] = (0, _spawnd.default)(config.command, _extends({
shell: true,
env: process.env,
cwd: (0, _cwd.default)()
}, config.options));
if (config.debug) {
// eslint-disable-next-line no-console
console.log(_chalk.default.magentaBright('\nJest dev-server output:'));
servers[index].stdout.pipe(serverLogPrefixer).pipe(process.stdout);
}
}
async function outOfStin(block) {
const {
stdin
} = process;
const listeners = stdin.listeners('data');
const result = await block();
listeners.forEach(listener => stdin.on('data', listener));
stdin.setRawMode(true);
stdin.setEncoding('utf8');
stdin.resume();
return result;
}
function getIsPortTaken(config) {
let server;
const cleanupAndReturn = result => new Promise(resolve => server.once('close', () => resolve(result)).close());
return new Promise((resolve, reject) => {
server = _net.default.createServer().once('error', err => err.code === 'EADDRINUSE' ? resolve(cleanupAndReturn(true)) : reject()).once('listening', () => resolve(cleanupAndReturn(false))).listen(config.port, config.host);
});
}
async function setup(providedConfigs) {
// Compatible with older versions
const configs = Array.isArray(providedConfigs) ? providedConfigs : [providedConfigs];
await Promise.all(configs.map((providedConfig, index) => setupJestServer(providedConfig, index)));
}
async function setupJestServer(providedConfig, index) {
const config = _extends({}, DEFAULT_CONFIG, {}, providedConfig);
const usedPortHandlers = {
error() {
throw new JestDevServerError(`Port ${config.port} is in use`, ERROR_PORT_USED);
},
async kill() {
console.log('');
console.log(`Killing process listening to ${config.port}. On linux, this may require you to enter your password.`);
const [portProcess] = await (0, _findProcess.default)('port', config.port);
logProcDetection(portProcess, config.port);
await killProc(portProcess);
},
async ask() {
console.log('');
const answers = await outOfStin(() => (0, _prompts.default)({
type: 'confirm',
name: 'kill',
message: `Another process is listening on ${config.port}. Should I kill it for you? On linux, this may require you to enter your password.`,
initial: true
}));
if (answers.kill) {
const [portProcess] = await (0, _findProcess.default)('port', config.port);
logProcDetection(portProcess, config.port);
await killProc(portProcess);
} else {
process.exit(1);
}
},
ignore() {}
};
const usedPortHandler = usedPortHandlers[config.usedPortAction];
if (!usedPortHandler) {
const availableActions = Object.keys(usedPortHandlers).map(action => `\`${action}\``).join(', ');
throw new JestDevServerError(`Invalid \`usedPortAction\`, only ${availableActions} are possible`);
}
if (config.port) {
const isPortTaken = await getIsPortTaken(config);
if (isPortTaken) {
await usedPortHandler();
}
if (config.usedPortAction === 'ignore' && isPortTaken) {
console.log('');
console.log('Port is already taken. Assuming server is already running.');
} else {
runServer(config, index);
}
} else {
runServer(config, index);
}
if (config.port) {
const {
launchTimeout,
protocol,
host,
port,
waitOnScheme
} = config;
let url = '';
if (protocol === 'tcp' || protocol === 'socket') {
url = `${protocol}:${host}:${port}`;
} else {
url = `${protocol}://${host}:${port}`;
}
const opts = _extends({
resources: [url],
timeout: launchTimeout
}, waitOnScheme);
try {
await (0, _waitOn.default)(opts);
} catch (err) {
throw new JestDevServerError(`Server has taken more than ${launchTimeout}ms to start.`, ERROR_TIMEOUT);
}
}
}
function getServers() {
return servers;
}
async function teardown() {
if (servers.length) {
await Promise.all(servers.map(server => server.destroy()));
}
}