@percy/cli-command 1.0.0-beta.7 → 1.0.0-beta.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -47
- package/bin/readme +51 -0
- package/dist/command.js +209 -52
- package/dist/flags.js +88 -47
- package/dist/help.js +262 -0
- package/dist/index.js +18 -4
- package/dist/legacy.js +176 -0
- package/dist/parse.js +426 -0
- package/package.json +23 -20
- package/types/index.d.ts +0 -45
package/README.md
CHANGED
|
@@ -1,60 +1,193 @@
|
|
|
1
1
|
# @percy/cli-command
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Percy CLI command parser and runner.
|
|
4
|
+
|
|
5
|
+
- [Usage](#usage)
|
|
6
|
+
- [Options](#options)
|
|
7
|
+
- [Args](#args)
|
|
8
|
+
- [Flags](#flags)
|
|
9
|
+
- [Percy](#percy)
|
|
6
10
|
|
|
7
11
|
## Usage
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
13
|
+
The `command` function accepts a name, definition, and callback and returns a runner function that
|
|
14
|
+
accepts an array of command-line arguments.
|
|
15
|
+
|
|
16
|
+
``` js
|
|
17
|
+
const { command } = require('@percy/cli-command');
|
|
18
|
+
|
|
19
|
+
// example command runner
|
|
20
|
+
const example = command('example', {
|
|
21
|
+
description: 'Example command description',
|
|
22
|
+
// positional arguments
|
|
23
|
+
args: [
|
|
24
|
+
{ name: 'one' }
|
|
25
|
+
],
|
|
26
|
+
// flags and options
|
|
27
|
+
flags: [
|
|
28
|
+
{ name: 'foo' }, // boolean by default
|
|
29
|
+
{ name: 'bar', type: 'string' }
|
|
30
|
+
],
|
|
31
|
+
// shows in help output
|
|
32
|
+
examples: [
|
|
33
|
+
// $0 will be replaced by the command name
|
|
34
|
+
'$0 --foo --bar baz qux'
|
|
35
|
+
]
|
|
36
|
+
}, ({ flags, args }) => {
|
|
37
|
+
// see below for other available properties
|
|
38
|
+
console.log({ flags, args });
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// remove the script name from argv
|
|
42
|
+
example(process.argv.slice(2));
|
|
29
43
|
```
|
|
30
44
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
other Percy CLI plugins (defaults shown).
|
|
35
|
-
|
|
36
|
-
``` yaml
|
|
37
|
-
version: 2
|
|
38
|
-
snapshot:
|
|
39
|
-
widths: [375, 1280]
|
|
40
|
-
minHeight: 1024
|
|
41
|
-
percyCSS: ''
|
|
42
|
-
requestHeaders: {}
|
|
43
|
-
discovery:
|
|
44
|
-
allowedHostnames: []
|
|
45
|
-
networkIdleTimeout: 100
|
|
46
|
-
disableAssetCache: false
|
|
47
|
-
concurrency: 5
|
|
45
|
+
``` shell
|
|
46
|
+
$ node ./example --foo --bar baz qux
|
|
47
|
+
{ flags: { foo: true, bar: 'baz' }, args: { one: 'qux' } }
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
## Options
|
|
51
|
+
|
|
52
|
+
Only a command `name` is required. However, without any other options, a command will only show the
|
|
53
|
+
default help output with global flags. A command's `callback` will be called when the resulting
|
|
54
|
+
command runner is invoked with an array of command-line arguments. How those arguments are
|
|
55
|
+
interpreted and parsed is defined by the command's `definition`.
|
|
56
|
+
|
|
57
|
+
- `name` — The command name shown in help output, also used to match nested commands.
|
|
58
|
+
- `definition` — A command definition object defines various options to control help output, the
|
|
59
|
+
arguments parser, and other percy options.
|
|
60
|
+
- `description` — The command description shown in help output.
|
|
61
|
+
- `usage` — Custom command usage shown in help output.
|
|
62
|
+
- `examples` — An array of example strings to show in help output.
|
|
63
|
+
- `version` — A version string to display via a `-V, --version` flag.
|
|
64
|
+
- `commands` — An array or function returning an array of nested subcommands.
|
|
65
|
+
- `flags` — Optional flag arguments accepted by the command ([see below](#flags)).
|
|
66
|
+
- `args` — Positional arguments accepted by the command ([see below](#args)).
|
|
67
|
+
- `percy` — Enable creation of a core percy instance ([see below](#percy)).
|
|
68
|
+
- `config` — Automatic percy config registration ([see below](#percy)).
|
|
69
|
+
- `loose` — Push unknown arguments to `argv`. A string value will log as a warning when unknown
|
|
70
|
+
arguments are first encountered by the parser.
|
|
71
|
+
- `exitOnError` — Call `process.exit()` if the command encounters an error while running.
|
|
72
|
+
- `callback` — The command callback invoked after the runner is called with command-line arguments
|
|
73
|
+
and after those arguments are interpreted by the internal parser.
|
|
74
|
+
|
|
75
|
+
The `callback` argument can be a function, an async function, or an async generator function. Given
|
|
76
|
+
an async generator function, the command becomes cancelable via process interruption and is able to
|
|
77
|
+
clean up after itself using traditional try-catch error handling.
|
|
78
|
+
|
|
79
|
+
The `callback` function is invoked with a single argument containing various contextual properties
|
|
80
|
+
according to the command definition:
|
|
81
|
+
|
|
82
|
+
- `flags` — An object containing key-value pairs of flag arguments interpreted by the parser as
|
|
83
|
+
determined by the flag's respective definition ([see below](#flags)).
|
|
84
|
+
- `args` — An object containing key-value pairs of positional arguments interpreted by the parser as
|
|
85
|
+
determined by the arg's respective definition ([see below](#args)).
|
|
86
|
+
- `argv` — An array of unknown arguments that were not parsed due to either the `loose` option or
|
|
87
|
+
the presence of an end-of-arguments delimiter (`--`).
|
|
88
|
+
- `percy` — An instance of `@percy/core` only present when a corresponding `percy` definition option
|
|
89
|
+
is provided ([see below](#percy)).
|
|
90
|
+
- `log` — A `@percy/logger` group namespaced under the command's `name`. The initial loglevel is
|
|
91
|
+
optionally determined by various global logging flags (`--verbose`, `--silent`, `--quiet`).
|
|
92
|
+
- `exit` — Utility function to stop the execution of a command from within the runner. Accepts
|
|
93
|
+
an exit code (default `1`) and an exit reason (default `'EEXIT: ${exitCode}'`). The function will
|
|
94
|
+
throw an error which can be handled, or let bubble where the presence of `exitOnError` will cause
|
|
95
|
+
the process to exit with the provided exit code.
|
|
96
|
+
|
|
97
|
+
### Flags
|
|
98
|
+
|
|
99
|
+
Each flag definition must contain either a `name` or a `short` option. By default, all flags will be
|
|
100
|
+
interpreted as boolean flags and will produce an error if a value is provided. Setting the `type`
|
|
101
|
+
option to anything other than `'boolean'` will allow providing command-line values and error if one
|
|
102
|
+
_is not_ provided.
|
|
103
|
+
|
|
104
|
+
- `name` — The flag name (i.e. `--flag-name`).
|
|
105
|
+
- `short` — The flag short character (i.e. `-s`).
|
|
106
|
+
- `type` — The flag type as displayed in help output.
|
|
107
|
+
- `default` — The flag's default value when not provided.
|
|
108
|
+
- `parse` — A function used to parse any provided flag value.
|
|
109
|
+
- `validate` — A function that should throw an error when the provided flag value is invalid.
|
|
110
|
+
- `attribute` — A string or function returning a string to set the value at on the `callback`
|
|
111
|
+
argument's `flags` property. Defaults to the camelcase `name` or `short` character.
|
|
112
|
+
- `percyrc` — A string to map this flag to percy config options ([see below](#percy)).
|
|
113
|
+
- `deprecated` — A boolean, string, or tuple used to warn about a deprecated flag and optionally map
|
|
114
|
+
it to an alternate flag ([see below](#deprecations)).
|
|
115
|
+
|
|
116
|
+
### Args
|
|
117
|
+
|
|
118
|
+
Positional args correspond to their definition index, so the arg definition at index `0` will match
|
|
119
|
+
the first provided command-line argument that is not a flag or subcommand. By default, positional
|
|
120
|
+
args are optional, but can be configured to be required or have default values.
|
|
51
121
|
|
|
52
|
-
|
|
53
|
-
`
|
|
122
|
+
- `name` — The arg name shown in help output.
|
|
123
|
+
- `required` — Indicate that this flag is required, which causes an error when not provided.
|
|
124
|
+
- `default` — The arg's default value when not provided.
|
|
125
|
+
- `parse` — A function used to parse the provided argument.
|
|
126
|
+
- `validate` — A function that should throw an error when the provided argument is invalid.
|
|
127
|
+
- `attribute` — A string or function returning a string to set the value at on the `callback`
|
|
128
|
+
argument's `args` property. Defaults to camelcase `name`.
|
|
129
|
+
- `percyrc` — A string to map this arg to percy config options ([see below](#percy)).
|
|
130
|
+
- `deprecated` — A boolean, string, or tuple used to warn about a deprecated arg and optionally map
|
|
131
|
+
it to a flag ([see below](#deprecations)).
|
|
132
|
+
|
|
133
|
+
#### Deprecations
|
|
134
|
+
|
|
135
|
+
When the `deprecated` option is `true` and the flag or positional arg has been provided by
|
|
136
|
+
command-line arguments, a deprecation warning will be logged. A string value indicates the version
|
|
137
|
+
in which this argument will be removed and is reflected in the deprecation message.
|
|
138
|
+
|
|
139
|
+
<details>
|
|
140
|
+
<summary>Remapping deprecated arguments</summary><br>
|
|
141
|
+
|
|
142
|
+
When providing a tuple, the version is the first option of the tuple, while the second option can be
|
|
143
|
+
an alternate flag to use, or a recommendation message to display when the deprecation warning is
|
|
144
|
+
logged. Given an alternate flag, the value will be automatically mapped to the corresponding flag's
|
|
145
|
+
attribute name on the `callback` argument's `flags` property.
|
|
54
146
|
|
|
55
147
|
``` js
|
|
56
|
-
'
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
148
|
+
{ name: 'foo', deprecated: true }
|
|
149
|
+
// [percy] Warning: The '--foo' option will be removed in a future release.
|
|
150
|
+
|
|
151
|
+
{ name: 'foo', deprecated: 'v2.0.0' }
|
|
152
|
+
// [percy] Warning: The '--foo' option will be removed in v2.0.0.
|
|
153
|
+
|
|
154
|
+
{ name: 'foo', deprecated: ['v2.0.0', '--bar'] }
|
|
155
|
+
// [percy] Warning: The '--foo' option will be removed in v2.0.0. Use '--bar' instead.
|
|
156
|
+
|
|
157
|
+
{ name: 'foo', deprecated: ['v2.0.0', 'Use the config file option instead.'] }
|
|
158
|
+
// [percy] Warning: The '--foo' option will be removed in v2.0.0. Use the config file option instead.
|
|
60
159
|
```
|
|
160
|
+
</details>
|
|
161
|
+
|
|
162
|
+
### Percy
|
|
163
|
+
|
|
164
|
+
The `percy` definition option accepts an object consisting of `@percy/core` options. The presence of
|
|
165
|
+
this option will add shared percy flags to accepted command-line arguments and provide the command
|
|
166
|
+
callback with a percy instance initialized with the provided options.
|
|
167
|
+
|
|
168
|
+
When the `percy` definition option is `true`, shared percy flags will not be accepted, but a default
|
|
169
|
+
percy instance will still be provided to the command callback when run. Regardless of the `percy`
|
|
170
|
+
option, if the environment variable `PERCY_ENABLE` is `0`, the callback _will not_ receive a percy
|
|
171
|
+
instance (and can act accordingly).
|
|
172
|
+
|
|
173
|
+
- `percy` — Enables creation of a `@percy/core` instance initialized with provided options.
|
|
174
|
+
- `discoveryFlags` — When `false` prevents percy discovery flags from being accepted, but will
|
|
175
|
+
still allow other percy flags such as `--config` and `--dry-run`.
|
|
176
|
+
- `...` — All other options are passed along to the new percy instance.
|
|
177
|
+
|
|
178
|
+
#### Config
|
|
179
|
+
|
|
180
|
+
Acceptable percy config file options can be extended before the file is loaded via
|
|
181
|
+
`PercyConfig.addSchema()` and `PercyConfig.addMigration()`. These functions can be called before the
|
|
182
|
+
command is run to achieve the same effect as including them in the command definition. However, the
|
|
183
|
+
presence of a `percy` definition option will also signal `@percy/core` config schemas and migrations
|
|
184
|
+
to be automatically registered before the following options are registered.
|
|
185
|
+
|
|
186
|
+
- `config` — Percy config schemas and migrations to register while creating the command runner.
|
|
187
|
+
- `schemas` — An array of percy config schemas to automatically register.
|
|
188
|
+
- `migrations` — An array of percy config migrations to automatically register.
|
|
189
|
+
|
|
190
|
+
Additionally, flags and positional arguments that define a `percyrc` option will have their
|
|
191
|
+
associated values mapped to a corresponding `percy` property that is used when initializing a
|
|
192
|
+
`@percy/core` instance. Provided options are validated against config schemas and are made available
|
|
193
|
+
on the command callback argument's `percy.config` property.
|
package/bin/readme
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { formatHelp } = require('@percy/cli-command/dist/help');
|
|
6
|
+
|
|
7
|
+
const CWD = process.cwd();
|
|
8
|
+
const README = path.join(CWD, 'README.md');
|
|
9
|
+
|
|
10
|
+
const HELP_USAGE = /^(.*)?(usage:.*)$/gis;
|
|
11
|
+
const CMDS_TMPL = /(<!-- commands -->)(.*)(<!-- commandsstop -->)/is;
|
|
12
|
+
|
|
13
|
+
async function generateReadmeCommands(pkg) {
|
|
14
|
+
if (!pkg['@percy/cli']?.commands) return '';
|
|
15
|
+
|
|
16
|
+
let sections = [];
|
|
17
|
+
let toc = [];
|
|
18
|
+
|
|
19
|
+
for (let cmdPath of pkg['@percy/cli'].commands) {
|
|
20
|
+
let { default: command } = require(path.join(CWD, cmdPath));
|
|
21
|
+
command = { ...command, parent: { name: 'percy' } };
|
|
22
|
+
|
|
23
|
+
for (let cmd of [command, ...(command.definition.commands || [])]) {
|
|
24
|
+
if (!cmd.callback) continue;
|
|
25
|
+
if (cmd !== command) cmd = { ...cmd, parent: command };
|
|
26
|
+
if (cmd.parent.parent) cmd.name = `${cmd.parent.name}:${cmd.name}`;
|
|
27
|
+
|
|
28
|
+
let title = `\`percy ${cmd.name}\``;
|
|
29
|
+
let slug = title.slice(1, -1).replace(/\s/g, '-').replace(/:/g, '');
|
|
30
|
+
toc.push(`* [${title}](#${slug})`);
|
|
31
|
+
|
|
32
|
+
let help = await formatHelp(cmd);
|
|
33
|
+
help = help.replace(HELP_USAGE, '$1```\n$2```');
|
|
34
|
+
sections.push(`### ${title}\n\n${help}\n`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return [
|
|
39
|
+
toc.join('\n'),
|
|
40
|
+
sections.join('\n')
|
|
41
|
+
].join('\n\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function updatePackageReadme() {
|
|
45
|
+
let pkg = require(path.join(CWD, 'package.json'));
|
|
46
|
+
let content = fs.readFileSync(README, 'utf8')
|
|
47
|
+
.replace(CMDS_TMPL, `$1\n${await generateReadmeCommands(pkg)}$3`)
|
|
48
|
+
fs.writeFileSync(README, content);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
updatePackageReadme();
|
package/dist/command.js
CHANGED
|
@@ -3,81 +3,238 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.command = command;
|
|
6
7
|
exports.default = void 0;
|
|
7
8
|
|
|
8
|
-
var
|
|
9
|
+
var _logger = _interopRequireDefault(require("@percy/logger"));
|
|
9
10
|
|
|
10
11
|
var _config = _interopRequireDefault(require("@percy/config"));
|
|
11
12
|
|
|
12
|
-
var
|
|
13
|
+
var _utils = require("@percy/config/dist/utils");
|
|
14
|
+
|
|
15
|
+
var CoreConfig = _interopRequireWildcard(require("@percy/core/dist/config"));
|
|
16
|
+
|
|
17
|
+
var builtInFlags = _interopRequireWildcard(require("./flags"));
|
|
18
|
+
|
|
19
|
+
var _help = _interopRequireDefault(require("./help"));
|
|
20
|
+
|
|
21
|
+
var _parse = _interopRequireDefault(require("./parse"));
|
|
13
22
|
|
|
14
23
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
// from. Provides common #init() and #catch() methods and provides other methods
|
|
18
|
-
// for loading configuration and checking if Percy is enabled.
|
|
19
|
-
class PercyCommand extends _command.default {
|
|
20
|
-
// Initialize flags, args, the loglevel, and attach process handlers to allow
|
|
21
|
-
// commands to seemlessly cleanup on interupt or termination
|
|
22
|
-
init() {
|
|
23
|
-
let {
|
|
24
|
-
args,
|
|
25
|
-
flags
|
|
26
|
-
} = this.parse();
|
|
27
|
-
this.flags = flags;
|
|
28
|
-
this.args = args; // sets the log level from verbose, quiet, and silent flags
|
|
25
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
31
28
|
|
|
29
|
+
// Copies a command definition and adds built-in flags and config options.
|
|
30
|
+
function withBuiltIns(definition) {
|
|
31
|
+
var _def$flags, _def$config$schemas, _def$config$migration;
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
let def = { ...definition
|
|
34
|
+
};
|
|
35
|
+
def.flags = [...((_def$flags = def.flags) !== null && _def$flags !== void 0 ? _def$flags : [])]; // ensure built-ins aren't already overridden
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
let addDedupedFlag = flag => {
|
|
38
|
+
if (!def.flags.find(f => f.name === flag.name)) {
|
|
39
|
+
let short = def.flags.find(f => f.short === flag.short);
|
|
40
|
+
def.flags.push(short ? (0, _utils.del)({ ...flag
|
|
41
|
+
}, 'short') : flag);
|
|
42
|
+
}
|
|
43
|
+
}; // add percy specific built-in flags
|
|
39
44
|
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// oclif exit method actually throws an error, don't log it
|
|
47
|
-
if (!err.oclif || err.code !== 'EEXIT') _logger.default.error(err);
|
|
48
|
-
throw err;
|
|
46
|
+
if (def.percy && def.percy !== true) {
|
|
47
|
+
builtInFlags.PERCY.forEach(addDedupedFlag); // maybe include percy discovery flags
|
|
48
|
+
|
|
49
|
+
if (def.percy.discoveryFlags !== false) {
|
|
50
|
+
builtInFlags.DISCOVERY.forEach(addDedupedFlag);
|
|
49
51
|
}
|
|
50
|
-
} //
|
|
52
|
+
} // always add global built-in flags
|
|
51
53
|
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
return process.env.PERCY_ENABLE !== '0';
|
|
55
|
-
} // Parses command flags and maps them to config options according to their
|
|
56
|
-
// respective `percyrc` parameter. The flag input is then merged with options
|
|
57
|
-
// loaded from a config file and default config options. The PERCY_TOKEN
|
|
58
|
-
// environment variable is also included as a convenience.
|
|
55
|
+
builtInFlags.GLOBAL.forEach(addDedupedFlag); // copy any existing config before adding to it
|
|
59
56
|
|
|
57
|
+
def.config = { ...def.config
|
|
58
|
+
};
|
|
59
|
+
def.config.schemas = [...((_def$config$schemas = def.config.schemas) !== null && _def$config$schemas !== void 0 ? _def$config$schemas : [])];
|
|
60
|
+
def.config.migrations = [...((_def$config$migration = def.config.migrations) !== null && _def$config$migration !== void 0 ? _def$config$migration : [])]; // add percy specific built-in config options
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
if (def.percy) {
|
|
63
|
+
def.config.schemas.unshift(...CoreConfig.schemas);
|
|
64
|
+
def.config.migrations.unshift(...CoreConfig.migrations);
|
|
65
|
+
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
return def;
|
|
68
|
+
} // Calls the provided callback and handles callback cancelation when process signals are
|
|
69
|
+
// triggered. If the provided callback returns a generator, it will automatically run and throw
|
|
70
|
+
// an error when canceled to be able to gracefully handle it's own cancelation.
|
|
68
71
|
|
|
69
|
-
let last = i === paths.length - 1;
|
|
70
|
-
target[key] = last ? this.flags[name] : (_target$key = target[key]) !== null && _target$key !== void 0 ? _target$key : {};
|
|
71
|
-
return last ? conf : target[key];
|
|
72
|
-
}, conf)) !== null && _flag$percyrc$split$r !== void 0 ? _flag$percyrc$split$r : conf;
|
|
73
|
-
}, {}); // will also validate config and log warnings
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
async function handleProcessSignals(callback) {
|
|
74
|
+
let signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
75
|
+
let signalError; // keep track of signal handlers for cleanup
|
|
76
|
+
|
|
77
|
+
let signalHandlers = signals.map(signal => {
|
|
78
|
+
let handler = () => {
|
|
79
|
+
signalError = Object.assign(new Error(signal), {
|
|
80
|
+
canceled: true,
|
|
81
|
+
exitCode: 0,
|
|
82
|
+
signal
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
process.on(signal, handler);
|
|
87
|
+
return [signal, handler];
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
// maybe async function
|
|
92
|
+
let gen = await callback(); // run any returned generator
|
|
93
|
+
|
|
94
|
+
if (typeof (gen === null || gen === void 0 ? void 0 : gen.next) === 'function' && (typeof gen[Symbol.iterator] === 'function' || typeof gen[Symbol.asyncIterator] === 'function')) {
|
|
95
|
+
let result = await gen.next();
|
|
96
|
+
|
|
97
|
+
while (!result.done) {
|
|
98
|
+
result = signalError ? await gen.throw(signalError) : await gen.next(result.value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} finally {
|
|
102
|
+
// always cleanup
|
|
103
|
+
for (let [signal, handler] of signalHandlers) {
|
|
104
|
+
process.off(signal, handler);
|
|
105
|
+
}
|
|
79
106
|
}
|
|
107
|
+
} // Helper to throw an error with an exit code and optional reason message
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
function exit(exitCode, reason = '') {
|
|
111
|
+
let err = reason instanceof Error ? reason : new Error(reason);
|
|
112
|
+
throw Object.assign(err, {
|
|
113
|
+
exitCode
|
|
114
|
+
});
|
|
115
|
+
} // Runs the parsed command callback with a contextual argument consisting of specific parsed input
|
|
116
|
+
// and other common command helpers and properties.
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
async function runCommandWithContext(parsed) {
|
|
120
|
+
let {
|
|
121
|
+
command,
|
|
122
|
+
flags,
|
|
123
|
+
args,
|
|
124
|
+
argv,
|
|
125
|
+
log
|
|
126
|
+
} = parsed; // include flags, args, argv, logger, exit helper, and env info
|
|
127
|
+
|
|
128
|
+
let context = {
|
|
129
|
+
flags,
|
|
130
|
+
args,
|
|
131
|
+
argv,
|
|
132
|
+
log,
|
|
133
|
+
exit
|
|
134
|
+
};
|
|
135
|
+
let env = context.env = process.env;
|
|
136
|
+
let def = command.definition; // automatically include a preconfigured percy instance
|
|
137
|
+
|
|
138
|
+
if (def.percy) {
|
|
139
|
+
let {
|
|
140
|
+
Percy
|
|
141
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('@percy/core'))); // set defaults and prune preconfiguraton options
|
|
142
|
+
|
|
143
|
+
let conf = (0, _utils.del)({
|
|
144
|
+
server: false,
|
|
145
|
+
...def.percy
|
|
146
|
+
}, 'discoveryFlags');
|
|
147
|
+
Object.defineProperty(context, 'percy', {
|
|
148
|
+
configurable: true,
|
|
149
|
+
|
|
150
|
+
get() {
|
|
151
|
+
// percy is disabled, do not return an instance
|
|
152
|
+
if (env.PERCY_ENABLE === '0') return; // redefine the context property once configured
|
|
153
|
+
|
|
154
|
+
Object.defineProperty(context, 'percy', {
|
|
155
|
+
// map and merge percy arguments with config options
|
|
156
|
+
value: new Percy([...parsed.operators.entries()].reduce((conf, [opt, value]) => opt.percyrc ? (0, _utils.set)(conf, opt.percyrc, value) : conf, conf))
|
|
157
|
+
});
|
|
158
|
+
return context.percy;
|
|
159
|
+
}
|
|
80
160
|
|
|
161
|
+
});
|
|
162
|
+
} // wrap and bind the parsed command callback
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
await handleProcessSignals(command.callback.bind(null, context));
|
|
166
|
+
} // Returns a command runner function that when run will parse provided command-line options and run
|
|
167
|
+
// the parsed command callback. The returned runner will automatically output version and help
|
|
168
|
+
// information when requested, and handle any thrown errors exiting when appropriate.
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
function command(name, definition, callback) {
|
|
172
|
+
definition = withBuiltIns(definition); // auto register config schemas and migrations
|
|
173
|
+
|
|
174
|
+
_config.default.addSchema(definition.config.schemas);
|
|
175
|
+
|
|
176
|
+
_config.default.addMigration(definition.config.migrations);
|
|
177
|
+
|
|
178
|
+
async function runner(argv = []) {
|
|
179
|
+
// reset loglevel for testing
|
|
180
|
+
_logger.default.loglevel('info');
|
|
181
|
+
|
|
182
|
+
let log = (0, _logger.default)('cli');
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
// parse input
|
|
186
|
+
let parsed = await (0, _parse.default)(runner, argv);
|
|
187
|
+
|
|
188
|
+
if (parsed.version) {
|
|
189
|
+
// version requested
|
|
190
|
+
log.stdout.write(parsed.command.definition.version + '\n');
|
|
191
|
+
} else if (parsed.help || !parsed.command.callback) {
|
|
192
|
+
// command help requested
|
|
193
|
+
log.stdout.write((await (0, _help.default)(parsed.command)) + '\n');
|
|
194
|
+
} else {
|
|
195
|
+
// run command callback
|
|
196
|
+
await runCommandWithContext(parsed);
|
|
197
|
+
}
|
|
198
|
+
} catch (err) {
|
|
199
|
+
// auto log unhandled error messages
|
|
200
|
+
if (err.message && !err.signal) {
|
|
201
|
+
if (err.exitCode === 0) log.warn(err.message);else log.error(err);
|
|
202
|
+
} // exit when appropriate
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
if (err.exitCode !== 0) {
|
|
206
|
+
var _err$exitCode;
|
|
207
|
+
|
|
208
|
+
(_err$exitCode = err.exitCode) !== null && _err$exitCode !== void 0 ? _err$exitCode : err.exitCode = 1;
|
|
209
|
+
err.message || (err.message = `EEXIT: ${err.exitCode}`);
|
|
210
|
+
|
|
211
|
+
if (definition.exitOnError) {
|
|
212
|
+
process.exit(err.exitCode);
|
|
213
|
+
} // re-throw when not exiting
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} // define command meta information
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
Object.defineProperties(runner, {
|
|
223
|
+
name: {
|
|
224
|
+
enumerable: true,
|
|
225
|
+
value: name
|
|
226
|
+
},
|
|
227
|
+
definition: {
|
|
228
|
+
enumerable: true,
|
|
229
|
+
value: definition
|
|
230
|
+
},
|
|
231
|
+
callback: {
|
|
232
|
+
enumerable: true,
|
|
233
|
+
value: callback
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return runner;
|
|
81
237
|
}
|
|
82
238
|
|
|
83
|
-
|
|
239
|
+
var _default = command;
|
|
240
|
+
exports.default = _default;
|