appium 2.0.0-beta.2 → 2.0.0-beta.23
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 +9 -9
- package/build/check-npm-pack-files.js +23 -0
- package/build/commands-yml/parse.js +319 -0
- package/build/commands-yml/validator.js +130 -0
- package/build/index.js +19 -0
- package/build/lib/appium-config.schema.json +0 -0
- package/build/lib/appium.js +160 -53
- package/build/lib/cli/args.js +115 -279
- package/build/lib/cli/driver-command.js +11 -1
- package/build/lib/cli/extension-command.js +60 -8
- package/build/lib/cli/extension.js +30 -7
- package/build/lib/cli/npm.js +43 -29
- package/build/lib/cli/parser.js +156 -89
- package/build/lib/cli/plugin-command.js +11 -1
- package/build/lib/cli/utils.js +29 -3
- package/build/lib/config-file.js +141 -0
- package/build/lib/config.js +53 -65
- package/build/lib/driver-config.js +42 -19
- package/build/lib/drivers.js +8 -4
- package/build/lib/ext-config-io.js +165 -0
- package/build/lib/extension-config.js +130 -61
- package/build/lib/grid-register.js +22 -24
- package/build/lib/logger.js +3 -3
- package/build/lib/logsink.js +11 -13
- package/build/lib/main.js +197 -77
- package/build/lib/plugin-config.js +21 -11
- package/build/lib/plugins.js +4 -2
- package/build/lib/schema/appium-config-schema.js +253 -0
- package/build/lib/schema/arg-spec.js +120 -0
- package/build/lib/schema/cli-args.js +188 -0
- package/build/lib/schema/cli-transformers.js +76 -0
- package/build/lib/schema/index.js +36 -0
- package/build/lib/schema/keywords.js +72 -0
- package/build/lib/schema/schema.js +357 -0
- package/build/lib/utils.js +44 -99
- package/build/postinstall.js +90 -0
- package/build/test/cli/cli-e2e-specs.js +221 -0
- package/build/test/cli/cli-helpers.js +86 -0
- package/build/test/cli/cli-specs.js +71 -0
- package/build/test/cli/fixtures/test-driver/package.json +27 -0
- package/build/test/cli/schema-args-specs.js +48 -0
- package/build/test/cli/schema-e2e-specs.js +47 -0
- package/build/test/config-e2e-specs.js +112 -0
- package/build/test/config-file-e2e-specs.js +209 -0
- package/build/test/config-file-specs.js +281 -0
- package/build/test/config-specs.js +159 -0
- package/build/test/driver-e2e-specs.js +435 -0
- package/build/test/driver-specs.js +321 -0
- package/build/test/ext-config-io-specs.js +181 -0
- package/build/test/extension-config-specs.js +365 -0
- package/build/test/fixtures/allow-feat.txt +5 -0
- package/build/test/fixtures/caps.json +3 -0
- package/build/test/fixtures/config/allow-insecure.txt +3 -0
- package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +5 -0
- package/build/test/fixtures/config/appium.config.bad.json +32 -0
- package/build/test/fixtures/config/appium.config.ext-good.json +9 -0
- package/build/test/fixtures/config/appium.config.ext-unknown-props.json +10 -0
- package/build/test/fixtures/config/appium.config.good.js +40 -0
- package/build/test/fixtures/config/appium.config.good.json +33 -0
- package/build/test/fixtures/config/appium.config.good.yaml +30 -0
- package/build/test/fixtures/config/appium.config.invalid.json +31 -0
- package/build/test/fixtures/config/appium.config.security-array.json +5 -0
- package/build/test/fixtures/config/appium.config.security-delimited.json +5 -0
- package/build/test/fixtures/config/appium.config.security-path.json +5 -0
- package/build/test/fixtures/config/driver-fake.config.json +8 -0
- package/build/test/fixtures/config/nodeconfig.json +3 -0
- package/build/test/fixtures/config/plugin-fake.config.json +0 -0
- package/build/test/fixtures/default-args.js +35 -0
- package/build/test/fixtures/deny-feat.txt +5 -0
- package/build/test/fixtures/driver.schema.js +20 -0
- package/build/test/fixtures/extensions.yaml +27 -0
- package/build/test/fixtures/flattened-schema.js +504 -0
- package/build/test/fixtures/plugin.schema.js +20 -0
- package/build/test/fixtures/schema-with-extensions.js +28 -0
- package/build/test/grid-register-specs.js +74 -0
- package/build/test/helpers.js +75 -0
- package/build/test/logger-specs.js +76 -0
- package/build/test/npm-specs.js +20 -0
- package/build/test/parser-specs.js +314 -0
- package/build/test/plugin-e2e-specs.js +316 -0
- package/build/test/schema/arg-spec-specs.js +70 -0
- package/build/test/schema/cli-args-specs.js +431 -0
- package/build/test/schema/schema-specs.js +389 -0
- package/build/test/utils-specs.js +266 -0
- package/index.js +11 -0
- package/lib/appium-config.schema.json +278 -0
- package/lib/appium.js +207 -65
- package/lib/cli/args.js +174 -375
- package/lib/cli/driver-command.js +4 -0
- package/lib/cli/extension-command.js +70 -5
- package/lib/cli/extension.js +25 -5
- package/lib/cli/npm.js +86 -18
- package/lib/cli/parser.js +257 -79
- package/lib/cli/plugin-command.js +4 -0
- package/lib/cli/utils.js +21 -1
- package/lib/config-file.js +227 -0
- package/lib/config.js +84 -63
- package/lib/driver-config.js +66 -11
- package/lib/drivers.js +4 -1
- package/lib/ext-config-io.js +287 -0
- package/lib/extension-config.js +225 -67
- package/lib/grid-register.js +27 -24
- package/lib/logger.js +1 -1
- package/lib/logsink.js +10 -7
- package/lib/main.js +214 -77
- package/lib/plugin-config.js +35 -6
- package/lib/plugins.js +1 -0
- package/lib/schema/appium-config-schema.js +287 -0
- package/lib/schema/arg-spec.js +222 -0
- package/lib/schema/cli-args.js +285 -0
- package/lib/schema/cli-transformers.js +123 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/keywords.js +135 -0
- package/lib/schema/schema.js +577 -0
- package/lib/utils.js +42 -88
- package/package.json +55 -84
- package/postinstall.js +71 -0
- package/types/appium-config.d.ts +197 -0
- package/types/types.d.ts +201 -0
- package/CHANGELOG.md +0 -3515
- package/build/lib/cli/parser-helpers.js +0 -82
- package/lib/cli/parser-helpers.js +0 -79
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import NPM from './npm';
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import { fs, util } from 'appium
|
|
7
|
-
import { log, spinWith } from './utils';
|
|
6
|
+
import { fs, util } from '@appium/support';
|
|
7
|
+
import { log, spinWith, RingBuffer } from './utils';
|
|
8
|
+
import { SubProcess} from 'teen_process';
|
|
8
9
|
import { INSTALL_TYPE_NPM, INSTALL_TYPE_GIT, INSTALL_TYPE_GITHUB,
|
|
9
10
|
INSTALL_TYPE_LOCAL } from '../extension-config';
|
|
10
11
|
|
|
@@ -482,8 +483,72 @@ export default class ExtensionCommand {
|
|
|
482
483
|
*/
|
|
483
484
|
async updateExtension (ext, version) {
|
|
484
485
|
const {pkgName} = this.config.installedExtensions[ext];
|
|
485
|
-
await this.
|
|
486
|
-
this.
|
|
487
|
-
|
|
486
|
+
await fs.rimraf(this.config.getInstallPath(ext));
|
|
487
|
+
const extData = await this.installViaNpm({ext, pkgName, pkgVer: version});
|
|
488
|
+
delete extData[`${this.type}Name`];
|
|
489
|
+
await this.config.updateExtension(ext, extData);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Runs a script cached inside the "scripts" field under "appium"
|
|
494
|
+
* inside of the driver/plugins "package.json" file. Will throw
|
|
495
|
+
* an error if the driver/plugin does not contain a "scripts" field
|
|
496
|
+
* underneath the "appium" field in its package.json, if the
|
|
497
|
+
* "scripts" field is not a plain object, or if the scriptName is
|
|
498
|
+
* not found within "scripts" object.
|
|
499
|
+
*
|
|
500
|
+
* @param {string} ext - name of the extension to run a script from
|
|
501
|
+
* @param {string} scriptName - name of the script to run
|
|
502
|
+
* @return {RunOutput}
|
|
503
|
+
*/
|
|
504
|
+
async run ({ext, scriptName}) {
|
|
505
|
+
if (!_.has(this.config.installedExtensions, ext)) {
|
|
506
|
+
throw new Error(`please install the ${this.type} first`);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const extConfig = this.config.installedExtensions[ext];
|
|
510
|
+
|
|
511
|
+
if (!_.has(extConfig, 'scripts')) {
|
|
512
|
+
throw new Error(`The ${this.type} named '${ext}' does not contain the ` +
|
|
513
|
+
`"scripts" field underneath the "appium" field in its package.json`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const extScripts = extConfig.scripts;
|
|
517
|
+
|
|
518
|
+
if (!_.isPlainObject(extScripts)) {
|
|
519
|
+
throw new Error(`The ${this.type} named '${ext}' "scripts" field must be a plain object`);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (!_.has(extScripts, scriptName)) {
|
|
523
|
+
throw new Error(`The ${this.type} named '${ext}' does not support the script: '${scriptName}'`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const runner = new SubProcess(process.execPath, [extScripts[scriptName]], {
|
|
527
|
+
cwd: this.config.getExtensionRequirePath(ext)
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
const output = new RingBuffer(50);
|
|
531
|
+
|
|
532
|
+
runner.on('stream-line', (line) => {
|
|
533
|
+
output.enqueue(line);
|
|
534
|
+
log(this.isJsonOutput, line);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
await runner.start(0);
|
|
538
|
+
|
|
539
|
+
try {
|
|
540
|
+
await runner.join();
|
|
541
|
+
log(this.isJsonOutput, `${scriptName} successfully ran`.green);
|
|
542
|
+
return {output: output.getBuff()};
|
|
543
|
+
} catch (err) {
|
|
544
|
+
log(this.isJsonOutput, `Encountered an error when running '${scriptName}': ${err.message}`.red);
|
|
545
|
+
return {error: err.message, output: output.getBuff()};
|
|
546
|
+
}
|
|
488
547
|
}
|
|
489
548
|
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* @typedef {Object} RunOutput
|
|
552
|
+
* @property {string|undefined} error - error message if script ran unsuccessfully, otherwise undefined
|
|
553
|
+
* @property {string[]} output - script output
|
|
554
|
+
*/
|
package/lib/cli/extension.js
CHANGED
|
@@ -6,6 +6,7 @@ import DriverConfig from '../driver-config';
|
|
|
6
6
|
import PluginConfig from '../plugin-config';
|
|
7
7
|
import { DRIVER_TYPE } from '../extension-config';
|
|
8
8
|
import { errAndQuit, log, JSON_SPACES } from './utils';
|
|
9
|
+
import { APPIUM_HOME } from './args';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Run a subcommand of the 'appium driver' type. Each subcommand has its own set of arguments which
|
|
@@ -13,25 +14,44 @@ import { errAndQuit, log, JSON_SPACES } from './utils';
|
|
|
13
14
|
*
|
|
14
15
|
* @param {Object} args - JS object where the key is the parameter name (as defined in
|
|
15
16
|
* driver-parser.js)
|
|
17
|
+
* @param {import('../ext-config-io').ExtensionType} type - Extension type
|
|
18
|
+
* @oaram {ExtensionConfig} [configObject] - Extension config object, if we have one
|
|
16
19
|
*/
|
|
17
|
-
async function runExtensionCommand (args, type) {
|
|
20
|
+
async function runExtensionCommand (args, type, configObject) {
|
|
18
21
|
// TODO driver config file should be locked while any of these commands are
|
|
19
22
|
// running to prevent weird situations
|
|
20
23
|
let jsonResult = null;
|
|
21
|
-
const
|
|
24
|
+
const extCmd = args[`${type}Command`];
|
|
25
|
+
if (!extCmd) {
|
|
26
|
+
throw new TypeError(`Cannot call ${type} command without a subcommand like 'install'`);
|
|
27
|
+
}
|
|
28
|
+
let {json, suppressOutput} = args;
|
|
29
|
+
if (suppressOutput) {
|
|
30
|
+
json = true;
|
|
31
|
+
}
|
|
22
32
|
const logFn = (msg) => log(json, msg);
|
|
23
|
-
|
|
33
|
+
let config;
|
|
34
|
+
if (configObject) {
|
|
35
|
+
config = configObject;
|
|
36
|
+
config.log = logFn;
|
|
37
|
+
} else {
|
|
38
|
+
config = (type === DRIVER_TYPE ? DriverConfig : PluginConfig).getInstance(APPIUM_HOME, logFn);
|
|
39
|
+
}
|
|
24
40
|
const CommandClass = type === DRIVER_TYPE ? DriverCommand : PluginCommand;
|
|
25
|
-
const config = new ConfigClass(appiumHome, logFn);
|
|
26
41
|
const cmd = new CommandClass({config, json});
|
|
27
42
|
try {
|
|
28
43
|
await config.read();
|
|
29
44
|
jsonResult = await cmd.execute(args);
|
|
30
45
|
} catch (err) {
|
|
46
|
+
// in the suppress output case, we are calling this function internally and should
|
|
47
|
+
// just throw instead of printing an error and ending the process
|
|
48
|
+
if (suppressOutput) {
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
31
51
|
errAndQuit(json, err);
|
|
32
52
|
}
|
|
33
53
|
|
|
34
|
-
if (json) {
|
|
54
|
+
if (json && !suppressOutput) {
|
|
35
55
|
console.log(JSON.stringify(jsonResult, null, JSON_SPACES));
|
|
36
56
|
}
|
|
37
57
|
|
package/lib/cli/npm.js
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import semver from 'semver';
|
|
4
5
|
import { exec } from 'teen_process';
|
|
5
|
-
import { mkdirp, util } from 'appium
|
|
6
|
+
import { fs, mkdirp, util, system } from '@appium/support';
|
|
6
7
|
|
|
7
8
|
const INSTALL_LOCKFILE = '.appium.install.lock';
|
|
8
9
|
const LINK_LOCKFILE = '.appium.link.lock';
|
|
9
10
|
|
|
10
11
|
export default class NPM {
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} appiumHome
|
|
15
|
+
*/
|
|
12
16
|
constructor (appiumHome) {
|
|
17
|
+
/** @type {string} */
|
|
13
18
|
this.appiumHome = appiumHome;
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Execute `npm` with given args.
|
|
23
|
+
*
|
|
24
|
+
* If the process exits with a nonzero code, the contents of `STDOUT` and `STDERR` will be in the
|
|
25
|
+
* `message` of the {@link TeenProcessExecError} rejected.
|
|
26
|
+
* @param {string} cmd
|
|
27
|
+
* @param {string[]} args
|
|
28
|
+
* @param {{ json?: boolean; cwd?: string; lockFile?: string; }} opts
|
|
29
|
+
*/
|
|
16
30
|
async exec (cmd, args, opts, execOpts = {}) {
|
|
17
31
|
let { cwd, json, lockFile } = opts;
|
|
18
32
|
if (!cwd) {
|
|
@@ -21,40 +35,60 @@ export default class NPM {
|
|
|
21
35
|
// ensure the directory we want to install inside of exists
|
|
22
36
|
await mkdirp(cwd);
|
|
23
37
|
|
|
38
|
+
// not only this, this directory needs a 'package.json' inside of it, otherwise, if any
|
|
39
|
+
// directory in the filesystem tree ABOVE cwd happens to have a package.json or a node_modules
|
|
40
|
+
// dir in it, NPM will install the module up there instead (silly NPM)
|
|
41
|
+
const dummyPkgJson = path.resolve(cwd, 'package.json');
|
|
42
|
+
if (!await fs.exists(dummyPkgJson)) {
|
|
43
|
+
await fs.writeFile(dummyPkgJson, '{}');
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
// make sure we perform the current operation in cwd
|
|
25
47
|
execOpts = {...execOpts, cwd};
|
|
26
48
|
|
|
27
49
|
args.unshift(cmd);
|
|
28
50
|
if (json) {
|
|
29
|
-
args.push('
|
|
51
|
+
args.push('--json');
|
|
30
52
|
}
|
|
31
|
-
|
|
53
|
+
const npmCmd = system.isWindows() ? 'npm.cmd' : 'npm';
|
|
54
|
+
let runner = async () => await exec(npmCmd, args, execOpts);
|
|
32
55
|
if (lockFile) {
|
|
33
56
|
const acquireLock = util.getLockFileGuard(path.resolve(cwd, lockFile));
|
|
34
57
|
const _runner = runner;
|
|
35
58
|
runner = async () => await acquireLock(_runner);
|
|
36
59
|
}
|
|
37
|
-
const {stdout, stderr, code} = await runner();
|
|
38
|
-
const ret = {stdout, stderr, code, json: null};
|
|
39
60
|
|
|
40
|
-
|
|
61
|
+
let ret;
|
|
62
|
+
try {
|
|
63
|
+
const {stdout, stderr, code} = await runner();
|
|
64
|
+
ret = /** @type {TeenProcessExecResult} */({stdout, stderr, code});
|
|
41
65
|
// if possible, parse NPM's json output. During NPM install 3rd-party
|
|
42
66
|
// packages can write to stdout, so sometimes the json output can't be
|
|
43
67
|
// guaranteed to be parseable
|
|
44
68
|
try {
|
|
45
69
|
ret.json = JSON.parse(stdout);
|
|
46
70
|
} catch (ign) {}
|
|
71
|
+
} catch (e) {
|
|
72
|
+
const {stdout, stderr, code} = /** @type {TeenProcessExecError} */(e);
|
|
73
|
+
const err = new Error(`npm command '${cmd} ${args.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`);
|
|
74
|
+
throw err;
|
|
47
75
|
}
|
|
48
|
-
|
|
49
76
|
return ret;
|
|
50
77
|
}
|
|
51
78
|
|
|
79
|
+
/**
|
|
80
|
+
* @param {string} pkg
|
|
81
|
+
*/
|
|
52
82
|
async getLatestVersion (pkg) {
|
|
53
83
|
return (await this.exec('view', [pkg, 'dist-tags'], {
|
|
54
84
|
json: true
|
|
55
|
-
})).json
|
|
85
|
+
})).json?.latest;
|
|
56
86
|
}
|
|
57
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @param {string} pkg
|
|
90
|
+
* @param {string} curVersion
|
|
91
|
+
*/
|
|
58
92
|
async getLatestSafeUpgradeVersion (pkg, curVersion) {
|
|
59
93
|
const allVersions = (await this.exec('view', [pkg, 'versions'], {
|
|
60
94
|
json: true
|
|
@@ -107,6 +141,11 @@ export default class NPM {
|
|
|
107
141
|
return safeUpgradeVer;
|
|
108
142
|
}
|
|
109
143
|
|
|
144
|
+
/**
|
|
145
|
+
*
|
|
146
|
+
* @param {{pkgDir: string, pkgName: string, pkgVer?: string}} param0
|
|
147
|
+
* @returns {Promise<import('type-fest').PackageJson>}
|
|
148
|
+
*/
|
|
110
149
|
async installPackage ({pkgDir, pkgName, pkgVer}) {
|
|
111
150
|
const res = await this.exec('install', [
|
|
112
151
|
'--no-save',
|
|
@@ -124,14 +163,6 @@ export default class NPM {
|
|
|
124
163
|
if (res.json.error) {
|
|
125
164
|
throw new Error(res.json.error);
|
|
126
165
|
}
|
|
127
|
-
|
|
128
|
-
// if we tried to install a package via git/github, we might not have been
|
|
129
|
-
// certain of the package name, so if we can retrieve it unambiguously from
|
|
130
|
-
// the json report of the install, do so
|
|
131
|
-
const names = _.uniq([...res.json.added, ...res.json.updated].map((x) => x.name));
|
|
132
|
-
if (names.length === 1) {
|
|
133
|
-
pkgName = names[0];
|
|
134
|
-
}
|
|
135
166
|
}
|
|
136
167
|
|
|
137
168
|
// Now read package data from the installed package to return, and make sure
|
|
@@ -148,6 +179,9 @@ export default class NPM {
|
|
|
148
179
|
}
|
|
149
180
|
}
|
|
150
181
|
|
|
182
|
+
/**
|
|
183
|
+
* @param {string} pkgPath
|
|
184
|
+
*/
|
|
151
185
|
async linkPackage (pkgPath) {
|
|
152
186
|
// from the path alone we don't know the npm package name, so we need to
|
|
153
187
|
// look in package.json
|
|
@@ -159,8 +193,14 @@ export default class NPM {
|
|
|
159
193
|
`provided: ${pkgPath}`);
|
|
160
194
|
}
|
|
161
195
|
|
|
196
|
+
// this is added to handle commands with relative paths
|
|
197
|
+
// ie: "node . driver install --source=local ../fake-driver"
|
|
198
|
+
pkgPath = path.resolve(process.cwd(), pkgPath);
|
|
199
|
+
|
|
162
200
|
const pkgHome = path.resolve(this.appiumHome, pkgName);
|
|
163
|
-
|
|
201
|
+
|
|
202
|
+
// call link with --no-package-lock to ensure no corruption while installing local packages
|
|
203
|
+
const res = await this.exec('link', ['--no-package-lock', pkgPath], {cwd: pkgHome, lockFile: LINK_LOCKFILE});
|
|
164
204
|
if (res.json && res.json.error) {
|
|
165
205
|
throw new Error(res.json.error);
|
|
166
206
|
}
|
|
@@ -174,6 +214,10 @@ export default class NPM {
|
|
|
174
214
|
}
|
|
175
215
|
}
|
|
176
216
|
|
|
217
|
+
/**
|
|
218
|
+
* @param {string} pkgDir
|
|
219
|
+
* @param {string} pkg
|
|
220
|
+
*/
|
|
177
221
|
async uninstallPackage (pkgDir, pkg) {
|
|
178
222
|
await this.exec('uninstall', [pkg], {
|
|
179
223
|
cwd: pkgDir,
|
|
@@ -181,3 +225,27 @@ export default class NPM {
|
|
|
181
225
|
});
|
|
182
226
|
}
|
|
183
227
|
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Result from a non-zero-exit execution of `appium`
|
|
232
|
+
* @typedef {Object} TeenProcessExecResult
|
|
233
|
+
* @property {string} stdout - Stdout
|
|
234
|
+
* @property {string} stderr - Stderr
|
|
235
|
+
* @property {number?} code - Exit code
|
|
236
|
+
* @property {any} json - JSON parsed from stdout
|
|
237
|
+
*/
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Extra props `teen_process.exec` adds to its error objects
|
|
241
|
+
* @typedef {Object} TeenProcessExecErrorProps
|
|
242
|
+
* @property {string} stdout - STDOUT
|
|
243
|
+
* @property {string} stderr - STDERR
|
|
244
|
+
* @property {number?} code - Exit code
|
|
245
|
+
*/
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Error thrown by `teen_process.exec`
|
|
250
|
+
* @typedef {Error & TeenProcessExecErrorProps} TeenProcessExecError
|
|
251
|
+
*/
|