UNPKG

7.7 kBJavaScriptView Raw
1#!/usr/bin/env node
2"use strict";
3/* eslint no-sync:0, no-inner-declarations:0 */
4var __importDefault = (this && this.__importDefault) || function (mod) {
5 return (mod && mod.__esModule) ? mod : { "default": mod };
6};
7Object.defineProperty(exports, "__esModule", { value: true });
8// local
9const index_js_1 = require("./index.js");
10const util_js_1 = require("./util.js");
11// external
12const version_range_1 = __importDefault(require("version-range"));
13const minimist_1 = __importDefault(require("minimist"));
14const text_table_1 = __importDefault(require("text-table"));
15const string_width_1 = __importDefault(require("string-width"));
16const logger_clearable_1 = __importDefault(require("logger-clearable"));
17const spinner_title_1 = __importDefault(require("spinner-title"));
18const fs_readable_1 = require("@bevry/fs-readable");
19const wait_1 = __importDefault(require("@bevry/wait"));
20const json_1 = require("@bevry/json");
21const nodejs_versions_1 = require("@bevry/nodejs-versions");
22const filedirname_1 = __importDefault(require("filedirname"));
23const [file, dir] = (0, filedirname_1.default)();
24// builtin
25const node_process_1 = __importDefault(require("node:process"));
26const node_path_1 = require("node:path");
27// prepare
28const spinner = null;
29async function parse() {
30 // parse the cli flags/arguments
31 const cli = (0, minimist_1.default)(node_process_1.default.argv.slice(2), {
32 '--': true,
33 alias: {
34 h: 'help',
35 j: 'json',
36 n: 'node',
37 s: 'serial',
38 },
39 string: ['node', 'spinner'],
40 // boolean: ['json', 'serial', 'verbose'], <-- this defaults to false instead of null, preventing accurate fallbacks
41 });
42 if (cli.help) {
43 // output help and exit
44 node_process_1.default.stdout.write([
45 'Usage:',
46 '',
47 ' -n/--node [version]: Add a Node.js version to test',
48 ' -s/--serial: Run tests serially, one after the other',
49 ' -j/--json: Output the test results as JSON',
50 ' --spinner [spinner] Which spinner to use in the title bar',
51 ' --verbose: Report details about all statuses, not just failures',
52 ' --version: Output the version of Testen',
53 ' --help: Output this help',
54 ' -- [command]: The test command you expect',
55 '',
56 ].join('\n'));
57 return null;
58 }
59 if (cli.version) {
60 // output version and exit
61 const testenPackage = await (0, json_1.readJSON)((0, node_path_1.join)(dir, 'package.json'));
62 node_process_1.default.stdout.write(testenPackage.version + '\n');
63 return null;
64 }
65 // return configuration from cli
66 const cliTestenConfig = {};
67 if (cli.node)
68 cliTestenConfig.node =
69 Array.isArray(cli.node) && cli.node.length === 1 ? cli.node[0] : cli.node;
70 if (cli['--'] && cli['--'].join(''))
71 cliTestenConfig.command = cli['--'].join(' ');
72 if (cli.spinner != null)
73 cliTestenConfig.spinner = cli.spinner;
74 if (cli.serial != null)
75 cliTestenConfig.serial = cli.serial;
76 if (cli.json != null)
77 cliTestenConfig.json = cli.json;
78 if (cli.verbose != null)
79 cliTestenConfig.verbose = cli.verbose;
80 return cliTestenConfig;
81}
82async function testen(customTestenConfig = {}) {
83 // fetch the user package configuration
84 const cwd = node_process_1.default.cwd();
85 const userPackagePath = `${cwd}/package.json`;
86 const userPackage = (await (0, fs_readable_1.isReadable)(userPackagePath))
87 ? await (0, json_1.readJSON)(userPackagePath)
88 : {};
89 // merge the default, package, and custom configuration
90 const testenConfig = Object.assign({
91 node: (userPackage.engines && userPackage.engines.node) || '',
92 command: 'npm test',
93 spinner: 'monkey',
94 serial: false,
95 json: false,
96 verbose: false,
97 }, userPackage.testen || {}, customTestenConfig);
98 // parse node versions
99 const nodeVersions = [];
100 if (Array.isArray(testenConfig.node) && testenConfig.node.length) {
101 // specific versions
102 nodeVersions.push(...testenConfig.node);
103 }
104 else if (testenConfig.node && /^[\d\w.-]+$/.test(testenConfig.node)) {
105 // specific version
106 nodeVersions.push(testenConfig.node);
107 }
108 else if (testenConfig.node) {
109 // range
110 await (0, nodejs_versions_1.preloadNodeVersions)();
111 nodeVersions.push(...(0, nodejs_versions_1.filterSignificantNodeVersions)({
112 maintainedOrLTS: true,
113 released: true,
114 }).filter((version) => (0, version_range_1.default)(version, testenConfig.node)));
115 }
116 else {
117 nodeVersions.push('current', 'stable', 'system');
118 }
119 if (!nodeVersions || !nodeVersions.length) {
120 throw new Error('No node versions specified');
121 }
122 // create the testen instance
123 const listeners = [];
124 let interval = null;
125 let spinner = null;
126 if (!testenConfig.json) {
127 // create and start spinner
128 spinner = new spinner_title_1.default({
129 style: testenConfig.spinner,
130 interval: 1000,
131 });
132 spinner.start();
133 // prepare the logging, note that logger-clearable uses setImmediate, so requires a wait
134 const logger = new logger_clearable_1.default();
135 function table(result) {
136 return (0, text_table_1.default)(result, { stringLength: string_width_1.default });
137 }
138 function refresh(versions) {
139 const messages = [];
140 versions.array.forEach(function (V) {
141 if (V.success === false || testenConfig.verbose) {
142 messages.push(V.message);
143 }
144 });
145 if (messages.length) {
146 return ('\n' + messages.join('\n\n') + '\n\n' + table(versions.table) + '\n\n');
147 }
148 else {
149 return '\n' + table(versions.table) + '\n\n';
150 }
151 }
152 /* eslint-disable-next-line no-inner-declarations */
153 function refresher() {
154 /* eslint-disable-next-line no-use-before-define */
155 logger.queue(() => refresh(versions));
156 }
157 interval = setInterval(refresher, 1000);
158 listeners.push(refresher);
159 }
160 const versions = new index_js_1.Versions(nodeVersions, listeners);
161 // run
162 await versions.load();
163 await versions.install();
164 await versions.test(testenConfig.command, testenConfig.serial);
165 // output and cleanup
166 if (testenConfig.json) {
167 // output json
168 node_process_1.default.stdout.write(JSON.stringify(versions.json, null, ' '));
169 }
170 else {
171 // output already occurred via listeners
172 // cleanup our listeners
173 if (interval) {
174 clearInterval(interval); // stop the refresh interval
175 interval = null;
176 }
177 spinner.stop(); // stop the spinner
178 await (0, wait_1.default)(0); // wait for the logger to finish
179 }
180 // return versions instance
181 return versions;
182}
183// start the cli
184Promise.resolve()
185 .then(parse)
186 .then(async function (cliTestenConfig = null) {
187 if (cliTestenConfig) {
188 const versions = await testen(cliTestenConfig);
189 node_process_1.default.exitCode = versions.success ? 0 : 1;
190 }
191})
192 .catch(function (err) {
193 if (spinner)
194 spinner.stop();
195 node_process_1.default.stderr.write((err.stack || err.message || err).toString());
196 node_process_1.default.exitCode = (0, util_js_1.parseExitCode)(err.code) || 2;
197});