appium 2.0.0-beta.24 → 2.0.0-beta.27
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/build/lib/appium-config.schema.json +278 -0
- package/build/lib/appium.js +45 -66
- package/build/lib/cli/args.js +19 -39
- package/build/lib/cli/driver-command.js +5 -9
- package/build/lib/cli/extension-command.js +73 -64
- package/build/lib/cli/extension.js +10 -23
- package/build/lib/cli/parser.js +9 -19
- package/build/lib/cli/plugin-command.js +5 -9
- package/build/lib/cli/utils.js +2 -4
- package/build/lib/config-file.js +5 -10
- package/build/lib/config.js +50 -20
- package/build/lib/constants.js +60 -0
- package/build/lib/extension/driver-config.js +190 -0
- package/build/lib/extension/extension-config.js +297 -0
- package/build/lib/extension/index.js +77 -0
- package/build/lib/extension/manifest.js +246 -0
- package/build/lib/extension/package-changed.js +68 -0
- package/build/lib/extension/plugin-config.js +87 -0
- package/build/lib/grid-register.js +2 -4
- package/build/lib/logger.js +2 -4
- package/build/lib/logsink.js +2 -4
- package/build/lib/main.js +42 -71
- package/build/lib/schema/appium-config-schema.js +2 -4
- package/build/lib/schema/arg-spec.js +11 -14
- package/build/lib/schema/cli-args.js +2 -4
- package/build/lib/schema/cli-transformers.js +2 -4
- package/build/lib/schema/index.js +2 -4
- package/build/lib/schema/keywords.js +2 -4
- package/build/lib/schema/schema.js +61 -37
- package/build/lib/utils.js +1 -32
- package/lib/appium.js +50 -68
- package/lib/cli/args.js +19 -23
- package/lib/cli/driver-command.js +10 -2
- package/lib/cli/extension-command.js +216 -135
- package/lib/cli/extension.js +7 -15
- package/lib/cli/parser.js +6 -14
- package/lib/cli/plugin-command.js +1 -2
- package/lib/config-file.js +12 -15
- package/lib/config.js +55 -24
- package/lib/constants.js +79 -0
- package/lib/extension/driver-config.js +230 -0
- package/lib/extension/extension-config.js +459 -0
- package/lib/extension/index.js +103 -0
- package/lib/extension/manifest.js +590 -0
- package/lib/extension/package-changed.js +64 -0
- package/lib/extension/plugin-config.js +111 -0
- package/lib/grid-register.js +4 -4
- package/lib/main.js +57 -93
- package/lib/schema/arg-spec.js +3 -3
- package/lib/schema/cli-args.js +1 -0
- package/lib/schema/keywords.js +1 -1
- package/lib/schema/schema.js +67 -29
- package/lib/utils.js +2 -32
- package/package.json +29 -21
- package/{postinstall.js → scripts/postinstall.js} +1 -1
- package/types/types.d.ts +70 -31
- package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
- package/build/check-npm-pack-files.js +0 -23
- package/build/commands-yml/parse.js +0 -319
- package/build/commands-yml/validator.js +0 -130
- package/build/index.js +0 -19
- package/build/lib/cli/npm.js +0 -220
- package/build/lib/driver-config.js +0 -100
- package/build/lib/drivers.js +0 -100
- package/build/lib/ext-config-io.js +0 -165
- package/build/lib/extension-config.js +0 -320
- package/build/lib/plugin-config.js +0 -69
- package/build/lib/plugins.js +0 -18
- package/build/postinstall.js +0 -90
- package/build/test/cli/cli-e2e-specs.js +0 -221
- package/build/test/cli/cli-helpers.js +0 -86
- package/build/test/cli/cli-specs.js +0 -71
- package/build/test/cli/fixtures/test-driver/package.json +0 -27
- package/build/test/cli/schema-args-specs.js +0 -48
- package/build/test/cli/schema-e2e-specs.js +0 -47
- package/build/test/config-e2e-specs.js +0 -112
- package/build/test/config-file-e2e-specs.js +0 -209
- package/build/test/config-file-specs.js +0 -281
- package/build/test/config-specs.js +0 -246
- package/build/test/driver-e2e-specs.js +0 -435
- package/build/test/driver-specs.js +0 -386
- package/build/test/ext-config-io-specs.js +0 -181
- package/build/test/extension-config-specs.js +0 -365
- package/build/test/fixtures/allow-feat.txt +0 -5
- package/build/test/fixtures/caps.json +0 -3
- package/build/test/fixtures/config/allow-insecure.txt +0 -3
- package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
- package/build/test/fixtures/config/appium.config.bad.json +0 -32
- package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
- package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
- package/build/test/fixtures/config/appium.config.good.js +0 -40
- package/build/test/fixtures/config/appium.config.good.json +0 -33
- package/build/test/fixtures/config/appium.config.good.yaml +0 -30
- package/build/test/fixtures/config/appium.config.invalid.json +0 -31
- package/build/test/fixtures/config/appium.config.security-array.json +0 -5
- package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
- package/build/test/fixtures/config/appium.config.security-path.json +0 -5
- package/build/test/fixtures/config/driver-fake.config.json +0 -8
- package/build/test/fixtures/config/nodeconfig.json +0 -3
- package/build/test/fixtures/config/plugin-fake.config.json +0 -0
- package/build/test/fixtures/default-args.js +0 -35
- package/build/test/fixtures/deny-feat.txt +0 -5
- package/build/test/fixtures/driver.schema.js +0 -20
- package/build/test/fixtures/extensions.yaml +0 -27
- package/build/test/fixtures/flattened-schema.js +0 -532
- package/build/test/fixtures/plugin.schema.js +0 -20
- package/build/test/fixtures/schema-with-extensions.js +0 -28
- package/build/test/grid-register-specs.js +0 -74
- package/build/test/helpers.js +0 -75
- package/build/test/logger-specs.js +0 -76
- package/build/test/npm-specs.js +0 -20
- package/build/test/parser-specs.js +0 -319
- package/build/test/plugin-e2e-specs.js +0 -316
- package/build/test/schema/arg-spec-specs.js +0 -70
- package/build/test/schema/cli-args-specs.js +0 -408
- package/build/test/schema/schema-specs.js +0 -407
- package/build/test/utils-specs.js +0 -288
- package/lib/cli/npm.js +0 -251
- package/lib/driver-config.js +0 -101
- package/lib/drivers.js +0 -84
- package/lib/ext-config-io.js +0 -287
- package/lib/extension-config.js +0 -366
- package/lib/plugin-config.js +0 -63
- package/lib/plugins.js +0 -13
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
require("source-map-support/register");
|
|
6
|
-
|
|
7
|
-
var _utils = require("../lib/utils");
|
|
8
|
-
|
|
9
|
-
var _helpers = require("./helpers");
|
|
10
|
-
|
|
11
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
12
|
-
|
|
13
|
-
var _colors = require("@dabh/colors");
|
|
14
|
-
|
|
15
|
-
var _sinon = _interopRequireDefault(require("sinon"));
|
|
16
|
-
|
|
17
|
-
var _logger = _interopRequireDefault(require("../lib/logger"));
|
|
18
|
-
|
|
19
|
-
describe('utils', function () {
|
|
20
|
-
describe('parseCapsForInnerDriver()', function () {
|
|
21
|
-
it('should return an error if only JSONWP provided', function () {
|
|
22
|
-
let {
|
|
23
|
-
error,
|
|
24
|
-
protocol
|
|
25
|
-
} = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS);
|
|
26
|
-
protocol.should.equal('W3C');
|
|
27
|
-
error.message.should.match(/W3C/);
|
|
28
|
-
});
|
|
29
|
-
it('should return W3C caps unchanged if only W3C caps were provided', function () {
|
|
30
|
-
let {
|
|
31
|
-
desiredCaps,
|
|
32
|
-
processedJsonwpCapabilities,
|
|
33
|
-
processedW3CCapabilities,
|
|
34
|
-
protocol
|
|
35
|
-
} = (0, _utils.parseCapsForInnerDriver)(undefined, _helpers.W3C_CAPS);
|
|
36
|
-
desiredCaps.should.deep.equal(_helpers.BASE_CAPS);
|
|
37
|
-
should.not.exist(processedJsonwpCapabilities);
|
|
38
|
-
processedW3CCapabilities.should.deep.equal(_helpers.W3C_CAPS);
|
|
39
|
-
protocol.should.equal('W3C');
|
|
40
|
-
});
|
|
41
|
-
it('should return JSONWP and W3C caps if both were provided', function () {
|
|
42
|
-
let {
|
|
43
|
-
desiredCaps,
|
|
44
|
-
processedJsonwpCapabilities,
|
|
45
|
-
processedW3CCapabilities,
|
|
46
|
-
protocol
|
|
47
|
-
} = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, _helpers.W3C_CAPS);
|
|
48
|
-
desiredCaps.should.deep.equal(_helpers.BASE_CAPS);
|
|
49
|
-
processedJsonwpCapabilities.should.deep.equal(_helpers.BASE_CAPS);
|
|
50
|
-
processedW3CCapabilities.should.deep.equal(_helpers.W3C_CAPS);
|
|
51
|
-
protocol.should.equal('W3C');
|
|
52
|
-
});
|
|
53
|
-
it('should include default capabilities in results', function () {
|
|
54
|
-
const defaultW3CCaps = {
|
|
55
|
-
'appium:foo': 'bar',
|
|
56
|
-
'appium:baz': 'bla'
|
|
57
|
-
};
|
|
58
|
-
const expectedDefaultCaps = {
|
|
59
|
-
foo: 'bar',
|
|
60
|
-
baz: 'bla'
|
|
61
|
-
};
|
|
62
|
-
const {
|
|
63
|
-
desiredCaps,
|
|
64
|
-
processedJsonwpCapabilities,
|
|
65
|
-
processedW3CCapabilities
|
|
66
|
-
} = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, _helpers.W3C_CAPS, {}, defaultW3CCaps);
|
|
67
|
-
desiredCaps.should.deep.equal({ ...expectedDefaultCaps,
|
|
68
|
-
..._helpers.BASE_CAPS
|
|
69
|
-
});
|
|
70
|
-
processedJsonwpCapabilities.should.deep.equal({ ...expectedDefaultCaps,
|
|
71
|
-
..._helpers.BASE_CAPS
|
|
72
|
-
});
|
|
73
|
-
processedW3CCapabilities.alwaysMatch.should.deep.equal({ ...(0, _utils.insertAppiumPrefixes)(expectedDefaultCaps),
|
|
74
|
-
...(0, _utils.insertAppiumPrefixes)(_helpers.BASE_CAPS)
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
it('should allow valid default capabilities', function () {
|
|
78
|
-
const res = (0, _utils.parseCapsForInnerDriver)(null, _helpers.W3C_CAPS, {}, {
|
|
79
|
-
'appium:foo': 'bar2'
|
|
80
|
-
});
|
|
81
|
-
res.processedW3CCapabilities.alwaysMatch['appium:foo'].should.eql('bar2');
|
|
82
|
-
});
|
|
83
|
-
it('should not allow invalid default capabilities', function () {
|
|
84
|
-
const res = (0, _utils.parseCapsForInnerDriver)(null, _helpers.W3C_CAPS, {}, {
|
|
85
|
-
foo: 'bar',
|
|
86
|
-
'appium:foo2': 'bar2'
|
|
87
|
-
});
|
|
88
|
-
res.error.should.eql({
|
|
89
|
-
jsonwpCode: 61,
|
|
90
|
-
error: 'invalid argument',
|
|
91
|
-
w3cStatus: 400,
|
|
92
|
-
_stacktrace: null
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
it('should reject if W3C caps are not passing constraints', function () {
|
|
96
|
-
const err = (0, _utils.parseCapsForInnerDriver)(undefined, _helpers.W3C_CAPS, {
|
|
97
|
-
hello: {
|
|
98
|
-
presence: true
|
|
99
|
-
}
|
|
100
|
-
}).error;
|
|
101
|
-
err.message.should.match(/'hello' can't be blank/);
|
|
102
|
-
_lodash.default.isError(err).should.be.true;
|
|
103
|
-
});
|
|
104
|
-
it('should only accept W3C caps that have passing constraints', function () {
|
|
105
|
-
let w3cCaps = { ..._helpers.W3C_CAPS,
|
|
106
|
-
firstMatch: [{
|
|
107
|
-
foo: 'bar'
|
|
108
|
-
}, {
|
|
109
|
-
'appium:hello': 'world'
|
|
110
|
-
}]
|
|
111
|
-
};
|
|
112
|
-
(0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, w3cCaps, {
|
|
113
|
-
hello: {
|
|
114
|
-
presence: true
|
|
115
|
-
}
|
|
116
|
-
}).error.should.eql({
|
|
117
|
-
jsonwpCode: 61,
|
|
118
|
-
error: 'invalid argument',
|
|
119
|
-
w3cStatus: 400,
|
|
120
|
-
_stacktrace: null
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
it('should add appium prefixes to W3C caps that are not standard in W3C', function () {
|
|
124
|
-
(0, _utils.parseCapsForInnerDriver)(undefined, {
|
|
125
|
-
alwaysMatch: {
|
|
126
|
-
platformName: 'Fake',
|
|
127
|
-
propertyName: 'PROP_NAME'
|
|
128
|
-
}
|
|
129
|
-
}).error.error.should.includes('invalid argument');
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
describe('removeAppiumPrefixes()', function () {
|
|
133
|
-
it('should remove appium prefixes from cap names', function () {
|
|
134
|
-
(0, _utils.removeAppiumPrefixes)({
|
|
135
|
-
'appium:cap1': 'value1',
|
|
136
|
-
'ms:cap2': 'value2',
|
|
137
|
-
someCap: 'someCap'
|
|
138
|
-
}).should.eql({
|
|
139
|
-
'cap1': 'value1',
|
|
140
|
-
'ms:cap2': 'value2',
|
|
141
|
-
someCap: 'someCap'
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
describe('insertAppiumPrefixes()', function () {
|
|
146
|
-
it('should apply prefixes to non-standard capabilities', function () {
|
|
147
|
-
(0, _utils.insertAppiumPrefixes)({
|
|
148
|
-
someCap: 'someCap'
|
|
149
|
-
}).should.deep.equal({
|
|
150
|
-
'appium:someCap': 'someCap'
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
it('should not apply prefixes to standard capabilities', function () {
|
|
154
|
-
(0, _utils.insertAppiumPrefixes)({
|
|
155
|
-
browserName: 'BrowserName',
|
|
156
|
-
platformName: 'PlatformName'
|
|
157
|
-
}).should.deep.equal({
|
|
158
|
-
browserName: 'BrowserName',
|
|
159
|
-
platformName: 'PlatformName'
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
it('should not apply prefixes to capabilities that already have a prefix', function () {
|
|
163
|
-
(0, _utils.insertAppiumPrefixes)({
|
|
164
|
-
'appium:someCap': 'someCap',
|
|
165
|
-
'moz:someOtherCap': 'someOtherCap'
|
|
166
|
-
}).should.deep.equal({
|
|
167
|
-
'appium:someCap': 'someCap',
|
|
168
|
-
'moz:someOtherCap': 'someOtherCap'
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
it('should apply prefixes to non-prefixed, non-standard capabilities; should not apply prefixes to any other capabilities', function () {
|
|
172
|
-
(0, _utils.insertAppiumPrefixes)({
|
|
173
|
-
'appium:someCap': 'someCap',
|
|
174
|
-
'moz:someOtherCap': 'someOtherCap',
|
|
175
|
-
browserName: 'BrowserName',
|
|
176
|
-
platformName: 'PlatformName',
|
|
177
|
-
someOtherCap: 'someOtherCap',
|
|
178
|
-
yetAnotherCap: 'yetAnotherCap'
|
|
179
|
-
}).should.deep.equal({
|
|
180
|
-
'appium:someCap': 'someCap',
|
|
181
|
-
'moz:someOtherCap': 'someOtherCap',
|
|
182
|
-
browserName: 'BrowserName',
|
|
183
|
-
platformName: 'PlatformName',
|
|
184
|
-
'appium:someOtherCap': 'someOtherCap',
|
|
185
|
-
'appium:yetAnotherCap': 'yetAnotherCap'
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
describe('pullSettings()', function () {
|
|
190
|
-
it('should pull settings from caps', function () {
|
|
191
|
-
const caps = {
|
|
192
|
-
platformName: 'foo',
|
|
193
|
-
browserName: 'bar',
|
|
194
|
-
'settings[settingName]': 'baz',
|
|
195
|
-
'settings[settingName2]': 'baz2'
|
|
196
|
-
};
|
|
197
|
-
const settings = (0, _utils.pullSettings)(caps);
|
|
198
|
-
settings.should.eql({
|
|
199
|
-
settingName: 'baz',
|
|
200
|
-
settingName2: 'baz2'
|
|
201
|
-
});
|
|
202
|
-
caps.should.eql({
|
|
203
|
-
platformName: 'foo',
|
|
204
|
-
browserName: 'bar'
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
it('should pull settings dict if object values are present in caps', function () {
|
|
208
|
-
const caps = {
|
|
209
|
-
platformName: 'foo',
|
|
210
|
-
browserName: 'bar',
|
|
211
|
-
'settings[settingName]': {
|
|
212
|
-
key: 'baz'
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
const settings = (0, _utils.pullSettings)(caps);
|
|
216
|
-
settings.should.eql({
|
|
217
|
-
settingName: {
|
|
218
|
-
key: 'baz'
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
caps.should.eql({
|
|
222
|
-
platformName: 'foo',
|
|
223
|
-
browserName: 'bar'
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
it('should pull empty dict if no settings are present in caps', function () {
|
|
227
|
-
const caps = {
|
|
228
|
-
platformName: 'foo',
|
|
229
|
-
browserName: 'bar',
|
|
230
|
-
'setting[settingName]': 'baz'
|
|
231
|
-
};
|
|
232
|
-
const settings = (0, _utils.pullSettings)(caps);
|
|
233
|
-
settings.should.eql({});
|
|
234
|
-
caps.should.eql({
|
|
235
|
-
platformName: 'foo',
|
|
236
|
-
browserName: 'bar',
|
|
237
|
-
'setting[settingName]': 'baz'
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
it('should pull empty dict if caps are empty', function () {
|
|
241
|
-
const caps = {};
|
|
242
|
-
const settings = (0, _utils.pullSettings)(caps);
|
|
243
|
-
settings.should.eql({});
|
|
244
|
-
caps.should.eql({});
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
describe('ReadonlyMap', function () {
|
|
248
|
-
it('should allow writing', function () {
|
|
249
|
-
const map = new _utils.ReadonlyMap();
|
|
250
|
-
(() => map.set('foo', 'bar')).should.not.throw();
|
|
251
|
-
});
|
|
252
|
-
it('should allow reading', function () {
|
|
253
|
-
const map = new _utils.ReadonlyMap([['foo', 'bar']]);
|
|
254
|
-
(() => map.get('foo')).should.not.throw();
|
|
255
|
-
});
|
|
256
|
-
it('should not allow deletion', function () {
|
|
257
|
-
const map = new _utils.ReadonlyMap([['foo', 'bar']]);
|
|
258
|
-
map.delete('foo').should.be.false;
|
|
259
|
-
});
|
|
260
|
-
it('should not allow clearing', function () {
|
|
261
|
-
const map = new _utils.ReadonlyMap([['foo', 'bar']]);
|
|
262
|
-
(() => map.clear()).should.throw();
|
|
263
|
-
});
|
|
264
|
-
it('should not allow updating', function () {
|
|
265
|
-
const map = new _utils.ReadonlyMap([['foo', 'bar']]);
|
|
266
|
-
(() => map.set('foo', 'baz')).should.throw();
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
describe('inspect()', function () {
|
|
270
|
-
let sandbox;
|
|
271
|
-
beforeEach(function () {
|
|
272
|
-
sandbox = _sinon.default.createSandbox();
|
|
273
|
-
sandbox.spy(_logger.default, 'info');
|
|
274
|
-
});
|
|
275
|
-
afterEach(function () {
|
|
276
|
-
sandbox.restore();
|
|
277
|
-
});
|
|
278
|
-
it('should log the result of inspecting a value', function () {
|
|
279
|
-
(0, _utils.inspect)({
|
|
280
|
-
foo: 'bar'
|
|
281
|
-
});
|
|
282
|
-
(0, _colors.stripColors)(_logger.default.info.firstCall.firstArg).should.equal('{ foo: \'bar\' }');
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
});require('source-map-support').install();
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvdXRpbHMtc3BlY3MuanMiXSwibmFtZXMiOlsiZGVzY3JpYmUiLCJpdCIsImVycm9yIiwicHJvdG9jb2wiLCJCQVNFX0NBUFMiLCJzaG91bGQiLCJlcXVhbCIsIm1lc3NhZ2UiLCJtYXRjaCIsImRlc2lyZWRDYXBzIiwicHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzIiwicHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzIiwidW5kZWZpbmVkIiwiVzNDX0NBUFMiLCJkZWVwIiwibm90IiwiZXhpc3QiLCJkZWZhdWx0VzNDQ2FwcyIsImV4cGVjdGVkRGVmYXVsdENhcHMiLCJmb28iLCJiYXoiLCJhbHdheXNNYXRjaCIsInJlcyIsImVxbCIsImpzb253cENvZGUiLCJ3M2NTdGF0dXMiLCJfc3RhY2t0cmFjZSIsImVyciIsImhlbGxvIiwicHJlc2VuY2UiLCJfIiwiaXNFcnJvciIsImJlIiwidHJ1ZSIsInczY0NhcHMiLCJmaXJzdE1hdGNoIiwicGxhdGZvcm1OYW1lIiwicHJvcGVydHlOYW1lIiwiaW5jbHVkZXMiLCJzb21lQ2FwIiwiYnJvd3Nlck5hbWUiLCJzb21lT3RoZXJDYXAiLCJ5ZXRBbm90aGVyQ2FwIiwiY2FwcyIsInNldHRpbmdzIiwic2V0dGluZ05hbWUiLCJzZXR0aW5nTmFtZTIiLCJrZXkiLCJtYXAiLCJSZWFkb25seU1hcCIsInNldCIsInRocm93IiwiZ2V0IiwiZGVsZXRlIiwiZmFsc2UiLCJjbGVhciIsInNhbmRib3giLCJiZWZvcmVFYWNoIiwic2lub24iLCJjcmVhdGVTYW5kYm94Iiwic3B5IiwibG9nZ2VyIiwiYWZ0ZXJFYWNoIiwicmVzdG9yZSIsImluZm8iLCJmaXJzdENhbGwiLCJmaXJzdEFyZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0FBSUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBRUFBLFFBQVEsQ0FBQyxPQUFELEVBQVUsWUFBWTtBQUM1QkEsRUFBQUEsUUFBUSxDQUFDLDJCQUFELEVBQThCLFlBQVk7QUFD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QywyQkFBRCxFQUE4QixZQUFZO0FBQzFDLFlBQU0rQyxHQUFHLEdBQUcsSUFBSUMsa0JBQUosQ0FBZ0IsQ0FBQyxDQUFDLEtBQUQsRUFBUSxLQUFSLENBQUQsQ0FBaEIsQ0FBWjtBQUNBLE9BQUMsTUFBTUQsR0FBRyxDQUFDRSxHQUFKLENBQVEsS0FBUixFQUFlLEtBQWYsQ0FBUCxFQUE4QjdDLE1BQTlCLENBQXFDOEMsS0FBckM7QUFDRCxLQUhDLENBQUY7QUFJRCxHQTFCTyxDQUFSO0FBNEJBbkQsRUFBQUEsUUFBUSxDQUFDLFdBQUQsRUFBYyxZQUFZO0FBS2hDLFFBQUl3RCxPQUFKO0FBQ0FDLElBQUFBLFVBQVUsQ0FBQyxZQUFZO0FBQ3JCRCxNQUFBQSxPQUFPLEdBQUdFLGVBQU1DLGFBQU4sRUFBVjtBQUNBSCxNQUFBQSxPQUFPLENBQUNJLEdBQVIsQ0FBWUMsZUFBWixFQUFvQixNQUFwQjtBQUNELEtBSFMsQ0FBVjtBQUtBQyxJQUFBQSxTQUFTLENBQUMsWUFBWTtBQUNwQk4sTUFBQUEsT0FBTyxDQUFDTyxPQUFSO0FBQ0QsS0FGUSxDQUFUO0FBSUE5RCxJQUFBQSxFQUFFLENBQUMsNkNBQUQsRUFBZ0QsWUFBWTtBQUM1RCwwQkFBUTtBQUFDa0IsUUFBQUEsR0FBRyxFQUFFO0FBQU4sT0FBUjtBQUNBLCtCQUFxRDBDLGdCQUFPRyxJQUFSLENBQWNDLFNBQWQsQ0FBd0JDLFFBQTVFLEVBQ0c3RCxNQURILENBQ1VDLEtBRFYsQ0FDZ0Isa0JBRGhCO0FBRUQsS0FKQyxDQUFGO0FBS0QsR0FwQk8sQ0FBUjtBQXFCRCxDQTdQTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIsIGluc2VydEFwcGl1bVByZWZpeGVzLCBwdWxsU2V0dGluZ3MsXG4gIHJlbW92ZUFwcGl1bVByZWZpeGVzLCBSZWFkb25seU1hcCwgaW5zcGVjdFxufSBmcm9tICcuLi9saWIvdXRpbHMnO1xuaW1wb3J0IHsgQkFTRV9DQVBTLCBXM0NfQ0FQUyB9IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgc3RyaXBDb2xvcnMgfSBmcm9tICdAZGFiaC9jb2xvcnMnO1xuaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBsb2dnZXIgZnJvbSAnLi4vbGliL2xvZ2dlcic7XG5cbmRlc2NyaWJlKCd1dGlscycsIGZ1bmN0aW9uICgpIHtcbiAgZGVzY3JpYmUoJ3BhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gYW4gZXJyb3IgaWYgb25seSBKU09OV1AgcHJvdmlkZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQge2Vycm9yLCBwcm90b2NvbH0gPSBwYXJzZUNhcHNGb3JJbm5lckRyaXZlcihCQVNFX0NBUFMpO1xuICAgICAgcHJvdG9jb2wuc2hvdWxkLmVxdWFsKCdXM0MnKTtcbiAgICAgIGVycm9yLm1lc3NhZ2Uuc2hvdWxkLm1hdGNoKC9XM0MvKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHJldHVybiBXM0MgY2FwcyB1bmNoYW5nZWQgaWYgb25seSBXM0MgY2FwcyB3ZXJlIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHtkZXNpcmVkQ2FwcywgcHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzLCBwcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMsIHByb3RvY29sfSA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKHVuZGVmaW5lZCwgVzNDX0NBUFMpO1xuICAgICAgZGVzaXJlZENhcHMuc2hvdWxkLmRlZXAuZXF1YWwoQkFTRV9DQVBTKTtcbiAgICAgIHNob3VsZC5ub3QuZXhpc3QocHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzKTtcbiAgICAgIHByb2Nlc3NlZFczQ0NhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbChXM0NfQ0FQUyk7XG4gICAgICBwcm90b2NvbC5zaG91bGQuZXF1YWwoJ1czQycpO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgcmV0dXJuIEpTT05XUCBhbmQgVzNDIGNhcHMgaWYgYm90aCB3ZXJlIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHtkZXNpcmVkQ2FwcywgcHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzLCBwcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMsIHByb3RvY29sfSA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKEJBU0VfQ0FQUywgVzNDX0NBUFMpO1xuICAgICAgZGVzaXJlZENhcHMuc2hvdWxkLmRlZXAuZXF1YWwoQkFTRV9DQVBTKTtcbiAgICAgIHByb2Nlc3NlZEpzb253cENhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbChCQVNFX0NBUFMpO1xuICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzLnNob3VsZC5kZWVwLmVxdWFsKFczQ19DQVBTKTtcbiAgICAgIHByb3RvY29sLnNob3VsZC5lcXVhbCgnVzNDJyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBpbmNsdWRlIGRlZmF1bHQgY2FwYWJpbGl0aWVzIGluIHJlc3VsdHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBkZWZhdWx0VzNDQ2FwcyA9IHtcbiAgICAgICAgJ2FwcGl1bTpmb28nOiAnYmFyJyxcbiAgICAgICAgJ2FwcGl1bTpiYXonOiAnYmxhJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBleHBlY3RlZERlZmF1bHRDYXBzID0ge1xuICAgICAgICBmb286ICdiYXInLFxuICAgICAgICBiYXo6ICdibGEnLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZGVzaXJlZENhcHMsXG4gICAgICAgIHByb2Nlc3NlZEpzb253cENhcGFiaWxpdGllcyxcbiAgICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzXG4gICAgICB9ID0gcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIoQkFTRV9DQVBTLCBXM0NfQ0FQUywge30sIGRlZmF1bHRXM0NDYXBzKTtcbiAgICAgIGRlc2lyZWRDYXBzLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgLi4uZXhwZWN0ZWREZWZhdWx0Q2FwcyxcbiAgICAgICAgLi4uQkFTRV9DQVBTLFxuICAgICAgfSk7XG4gICAgICBwcm9jZXNzZWRKc29ud3BDYXBhYmlsaXRpZXMuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAuLi5leHBlY3RlZERlZmF1bHRDYXBzLFxuICAgICAgICAuLi5CQVNFX0NBUFNcbiAgICAgIH0pO1xuICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzLmFsd2F5c01hdGNoLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgLi4uaW5zZXJ0QXBwaXVtUHJlZml4ZXMoZXhwZWN0ZWREZWZhdWx0Q2FwcyksXG4gICAgICAgIC4uLmluc2VydEFwcGl1bVByZWZpeGVzKEJBU0VfQ0FQUylcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgYWxsb3cgdmFsaWQgZGVmYXVsdCBjYXBhYmlsaXRpZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXMgPSBwYXJzZUNhcHNGb3JJbm5lckRyaXZlcihudWxsLCBXM0NfQ0FQUywge30sIHtcbiAgICAgICAgJ2FwcGl1bTpmb28nOiAnYmFyMicsXG4gICAgICB9KTtcbiAgICAgIHJlcy5wcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMuYWx3YXlzTWF0Y2hbJ2FwcGl1bTpmb28nXS5zaG91bGQuZXFsKCdiYXIyJyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgaW52YWxpZCBkZWZhdWx0IGNhcGFiaWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlcyA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKG51bGwsIFczQ19DQVBTLCB7fSwge1xuICAgICAgICBmb286ICdiYXInLCAnYXBwaXVtOmZvbzInOiAnYmFyMicsXG4gICAgICB9KTtcbiAgICAgIHJlcy5lcnJvci5zaG91bGQuZXFsKHtcbiAgICAgICAganNvbndwQ29kZTogNjEsIGVycm9yOiAnaW52YWxpZCBhcmd1bWVudCcsIHczY1N0YXR1czogNDAwLCBfc3RhY2t0cmFjZTogbnVsbFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCByZWplY3QgaWYgVzNDIGNhcHMgYXJlIG5vdCBwYXNzaW5nIGNvbnN0cmFpbnRzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXJyID0gcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIodW5kZWZpbmVkLCBXM0NfQ0FQUywge2hlbGxvOiB7cHJlc2VuY2U6IHRydWV9fSkuZXJyb3I7XG4gICAgICBlcnIubWVzc2FnZS5zaG91bGQubWF0Y2goLydoZWxsbycgY2FuJ3QgYmUgYmxhbmsvKTtcbiAgICAgIF8uaXNFcnJvcihlcnIpLnNob3VsZC5iZS50cnVlO1xuXG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBvbmx5IGFjY2VwdCBXM0MgY2FwcyB0aGF0IGhhdmUgcGFzc2luZyBjb25zdHJhaW50cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCB3M2NDYXBzID0ge1xuICAgICAgICAuLi5XM0NfQ0FQUyxcbiAgICAgICAgZmlyc3RNYXRjaDogW1xuICAgICAgICAgIHtmb286ICdiYXInfSxcbiAgICAgICAgICB7J2FwcGl1bTpoZWxsbyc6ICd3b3JsZCd9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICAgIHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKEJBU0VfQ0FQUywgdzNjQ2Fwcywge2hlbGxvOiB7cHJlc2VuY2U6IHRydWV9fSkuZXJyb3Iuc2hvdWxkLmVxbCh7XG4gICAgICAgIGpzb253cENvZGU6IDYxLCBlcnJvcjogJ2ludmFsaWQgYXJndW1lbnQnLCB3M2NTdGF0dXM6IDQwMCwgX3N0YWNrdHJhY2U6IG51bGxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgYWRkIGFwcGl1bSBwcmVmaXhlcyB0byBXM0MgY2FwcyB0aGF0IGFyZSBub3Qgc3RhbmRhcmQgaW4gVzNDJywgZnVuY3Rpb24gKCkge1xuICAgICAgcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIodW5kZWZpbmVkLCB7XG4gICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgcGxhdGZvcm1OYW1lOiAnRmFrZScsXG4gICAgICAgICAgcHJvcGVydHlOYW1lOiAnUFJPUF9OQU1FJyxcbiAgICAgICAgfSxcbiAgICAgIH0pLmVycm9yLmVycm9yLnNob3VsZC5pbmNsdWRlcygnaW52YWxpZCBhcmd1bWVudCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncmVtb3ZlQXBwaXVtUHJlZml4ZXMoKScsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIHJlbW92ZSBhcHBpdW0gcHJlZml4ZXMgZnJvbSBjYXAgbmFtZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZW1vdmVBcHBpdW1QcmVmaXhlcyh7XG4gICAgICAgICdhcHBpdW06Y2FwMSc6ICd2YWx1ZTEnLFxuICAgICAgICAnbXM6Y2FwMic6ICd2YWx1ZTInLFxuICAgICAgICBzb21lQ2FwOiAnc29tZUNhcCcsXG4gICAgICB9KS5zaG91bGQuZXFsKHtcbiAgICAgICAgJ2NhcDEnOiAndmFsdWUxJyxcbiAgICAgICAgJ21zOmNhcDInOiAndmFsdWUyJyxcbiAgICAgICAgc29tZUNhcDogJ3NvbWVDYXAnLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdpbnNlcnRBcHBpdW1QcmVmaXhlcygpJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgYXBwbHkgcHJlZml4ZXMgdG8gbm9uLXN0YW5kYXJkIGNhcGFiaWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGluc2VydEFwcGl1bVByZWZpeGVzKHtcbiAgICAgICAgc29tZUNhcDogJ3NvbWVDYXAnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIG5vdCBhcHBseSBwcmVmaXhlcyB0byBzdGFuZGFyZCBjYXBhYmlsaXRpZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnNlcnRBcHBpdW1QcmVmaXhlcyh7XG4gICAgICAgIGJyb3dzZXJOYW1lOiAnQnJvd3Nlck5hbWUnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdQbGF0Zm9ybU5hbWUnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICBicm93c2VyTmFtZTogJ0Jyb3dzZXJOYW1lJyxcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnUGxhdGZvcm1OYW1lJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgbm90IGFwcGx5IHByZWZpeGVzIHRvIGNhcGFiaWxpdGllcyB0aGF0IGFscmVhZHkgaGF2ZSBhIHByZWZpeCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGluc2VydEFwcGl1bVByZWZpeGVzKHtcbiAgICAgICAgJ2FwcGl1bTpzb21lQ2FwJzogJ3NvbWVDYXAnLFxuICAgICAgICAnbW96OnNvbWVPdGhlckNhcCc6ICdzb21lT3RoZXJDYXAnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICAgICdtb3o6c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGFwcGx5IHByZWZpeGVzIHRvIG5vbi1wcmVmaXhlZCwgbm9uLXN0YW5kYXJkIGNhcGFiaWxpdGllczsgc2hvdWxkIG5vdCBhcHBseSBwcmVmaXhlcyB0byBhbnkgb3RoZXIgY2FwYWJpbGl0aWVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgaW5zZXJ0QXBwaXVtUHJlZml4ZXMoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICAgICdtb3o6c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnQnJvd3Nlck5hbWUnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdQbGF0Zm9ybU5hbWUnLFxuICAgICAgICBzb21lT3RoZXJDYXA6ICdzb21lT3RoZXJDYXAnLFxuICAgICAgICB5ZXRBbm90aGVyQ2FwOiAneWV0QW5vdGhlckNhcCcsXG4gICAgICB9KS5zaG91bGQuZGVlcC5lcXVhbCh7XG4gICAgICAgICdhcHBpdW06c29tZUNhcCc6ICdzb21lQ2FwJyxcbiAgICAgICAgJ21vejpzb21lT3RoZXJDYXAnOiAnc29tZU90aGVyQ2FwJyxcbiAgICAgICAgYnJvd3Nlck5hbWU6ICdCcm93c2VyTmFtZScsXG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ1BsYXRmb3JtTmFtZScsXG4gICAgICAgICdhcHBpdW06c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICAgICdhcHBpdW06eWV0QW5vdGhlckNhcCc6ICd5ZXRBbm90aGVyQ2FwJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncHVsbFNldHRpbmdzKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBwdWxsIHNldHRpbmdzIGZyb20gY2FwcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdzW3NldHRpbmdOYW1lXSc6ICdiYXonLFxuICAgICAgICAnc2V0dGluZ3Nbc2V0dGluZ05hbWUyXSc6ICdiYXoyJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBzZXR0aW5ncyA9IHB1bGxTZXR0aW5ncyhjYXBzKTtcbiAgICAgIHNldHRpbmdzLnNob3VsZC5lcWwoe1xuICAgICAgICBzZXR0aW5nTmFtZTogJ2JheicsXG4gICAgICAgIHNldHRpbmdOYW1lMjogJ2JhejInLFxuICAgICAgfSk7XG4gICAgICBjYXBzLnNob3VsZC5lcWwoe1xuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdmb28nLFxuICAgICAgICBicm93c2VyTmFtZTogJ2JhcicsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHB1bGwgc2V0dGluZ3MgZGljdCBpZiBvYmplY3QgdmFsdWVzIGFyZSBwcmVzZW50IGluIGNhcHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBjYXBzID0ge1xuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdmb28nLFxuICAgICAgICBicm93c2VyTmFtZTogJ2JhcicsXG4gICAgICAgICdzZXR0aW5nc1tzZXR0aW5nTmFtZV0nOiB7a2V5OiAnYmF6J30sXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2V0dGluZ3MgPSBwdWxsU2V0dGluZ3MoY2Fwcyk7XG4gICAgICBzZXR0aW5ncy5zaG91bGQuZXFsKHtcbiAgICAgICAgc2V0dGluZ05hbWU6IHtrZXk6ICdiYXonfSxcbiAgICAgIH0pO1xuICAgICAgY2Fwcy5zaG91bGQuZXFsKHtcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnZm9vJyxcbiAgICAgICAgYnJvd3Nlck5hbWU6ICdiYXInLFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBwdWxsIGVtcHR5IGRpY3QgaWYgbm8gc2V0dGluZ3MgYXJlIHByZXNlbnQgaW4gY2FwcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdbc2V0dGluZ05hbWVdJzogJ2JheicsXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2V0dGluZ3MgPSBwdWxsU2V0dGluZ3MoY2Fwcyk7XG4gICAgICBzZXR0aW5ncy5zaG91bGQuZXFsKHt9KTtcbiAgICAgIGNhcHMuc2hvdWxkLmVxbCh7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdbc2V0dGluZ05hbWVdJzogJ2JheicsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHB1bGwgZW1wdHkgZGljdCBpZiBjYXBzIGFyZSBlbXB0eScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7fTtcbiAgICAgIGNvbnN0IHNldHRpbmdzID0gcHVsbFNldHRpbmdzKGNhcHMpO1xuICAgICAgc2V0dGluZ3Muc2hvdWxkLmVxbCh7fSk7XG4gICAgICBjYXBzLnNob3VsZC5lcWwoe30pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnUmVhZG9ubHlNYXAnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBhbGxvdyB3cml0aW5nJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgbWFwID0gbmV3IFJlYWRvbmx5TWFwKCk7XG4gICAgICAoKCkgPT4gbWFwLnNldCgnZm9vJywgJ2JhcicpKS5zaG91bGQubm90LnRocm93KCk7XG5cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWxsb3cgcmVhZGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuZ2V0KCdmb28nKSkuc2hvdWxkLm5vdC50aHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgZGVsZXRpb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBtYXAgPSBuZXcgUmVhZG9ubHlNYXAoW1snZm9vJywgJ2JhciddXSk7XG4gICAgICBtYXAuZGVsZXRlKCdmb28nKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyBjbGVhcmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuY2xlYXIoKSkuc2hvdWxkLnRocm93KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyB1cGRhdGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuc2V0KCdmb28nLCAnYmF6JykpLnNob3VsZC50aHJvdygpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnaW5zcGVjdCgpJywgZnVuY3Rpb24gKCkge1xuXG4gICAgLyoqXG4gICAgICogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblNhbmRib3h9XG4gICAgICovXG4gICAgbGV0IHNhbmRib3g7XG4gICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBzYW5kYm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgICAgc2FuZGJveC5zcHkobG9nZ2VyLCAnaW5mbycpO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHNhbmRib3gucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBsb2cgdGhlIHJlc3VsdCBvZiBpbnNwZWN0aW5nIGEgdmFsdWUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnNwZWN0KHtmb286ICdiYXInfSk7XG4gICAgICBzdHJpcENvbG9ycygvKiogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblN0dWJ9ICovKGxvZ2dlci5pbmZvKS5maXJzdENhbGwuZmlyc3RBcmcpXG4gICAgICAgIC5zaG91bGQuZXF1YWwoJ3sgZm9vOiBcXCdiYXJcXCcgfScpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl0sImZpbGUiOiJ0ZXN0L3V0aWxzLXNwZWNzLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=
|
package/lib/cli/npm.js
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import semver from 'semver';
|
|
5
|
-
import { exec } from 'teen_process';
|
|
6
|
-
import { fs, mkdirp, util, system } from '@appium/support';
|
|
7
|
-
|
|
8
|
-
const INSTALL_LOCKFILE = '.appium.install.lock';
|
|
9
|
-
const LINK_LOCKFILE = '.appium.link.lock';
|
|
10
|
-
|
|
11
|
-
export default class NPM {
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} appiumHome
|
|
15
|
-
*/
|
|
16
|
-
constructor (appiumHome) {
|
|
17
|
-
/** @type {string} */
|
|
18
|
-
this.appiumHome = appiumHome;
|
|
19
|
-
}
|
|
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
|
-
*/
|
|
30
|
-
async exec (cmd, args, opts, execOpts = {}) {
|
|
31
|
-
let { cwd, json, lockFile } = opts;
|
|
32
|
-
if (!cwd) {
|
|
33
|
-
cwd = this.appiumHome;
|
|
34
|
-
}
|
|
35
|
-
// ensure the directory we want to install inside of exists
|
|
36
|
-
await mkdirp(cwd);
|
|
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
|
-
|
|
46
|
-
// make sure we perform the current operation in cwd
|
|
47
|
-
execOpts = {...execOpts, cwd};
|
|
48
|
-
|
|
49
|
-
args.unshift(cmd);
|
|
50
|
-
if (json) {
|
|
51
|
-
args.push('--json');
|
|
52
|
-
}
|
|
53
|
-
const npmCmd = system.isWindows() ? 'npm.cmd' : 'npm';
|
|
54
|
-
let runner = async () => await exec(npmCmd, args, execOpts);
|
|
55
|
-
if (lockFile) {
|
|
56
|
-
const acquireLock = util.getLockFileGuard(path.resolve(cwd, lockFile));
|
|
57
|
-
const _runner = runner;
|
|
58
|
-
runner = async () => await acquireLock(_runner);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let ret;
|
|
62
|
-
try {
|
|
63
|
-
const {stdout, stderr, code} = await runner();
|
|
64
|
-
ret = /** @type {TeenProcessExecResult} */({stdout, stderr, code});
|
|
65
|
-
// if possible, parse NPM's json output. During NPM install 3rd-party
|
|
66
|
-
// packages can write to stdout, so sometimes the json output can't be
|
|
67
|
-
// guaranteed to be parseable
|
|
68
|
-
try {
|
|
69
|
-
ret.json = JSON.parse(stdout);
|
|
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;
|
|
75
|
-
}
|
|
76
|
-
return ret;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* @param {string} pkg
|
|
81
|
-
*/
|
|
82
|
-
async getLatestVersion (pkg) {
|
|
83
|
-
return (await this.exec('view', [pkg, 'dist-tags'], {
|
|
84
|
-
json: true
|
|
85
|
-
})).json?.latest;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @param {string} pkg
|
|
90
|
-
* @param {string} curVersion
|
|
91
|
-
*/
|
|
92
|
-
async getLatestSafeUpgradeVersion (pkg, curVersion) {
|
|
93
|
-
const allVersions = (await this.exec('view', [pkg, 'versions'], {
|
|
94
|
-
json: true
|
|
95
|
-
})).json;
|
|
96
|
-
return this.getLatestSafeUpgradeFromVersions(curVersion, allVersions);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Given a current version and a list of all versions for a package, return the version which is
|
|
101
|
-
* the highest safely-upgradable version (meaning not crossing any major revision boundaries, and
|
|
102
|
-
* not including any alpha/beta/rc versions)
|
|
103
|
-
*
|
|
104
|
-
* @param {string} curVersion - the current version of a package
|
|
105
|
-
* @param {Array<string>} allVersions - a list of version strings
|
|
106
|
-
*
|
|
107
|
-
* @return {string|null} - the highest safely-upgradable version, or null if there isn't one
|
|
108
|
-
*/
|
|
109
|
-
getLatestSafeUpgradeFromVersions (curVersion, allVersions) {
|
|
110
|
-
let safeUpgradeVer = null;
|
|
111
|
-
const curSemver = semver.parse(curVersion);
|
|
112
|
-
if (curSemver === null) {
|
|
113
|
-
throw new Error(`Could not parse current version '${curVersion}'`);
|
|
114
|
-
}
|
|
115
|
-
for (const testVer of allVersions) {
|
|
116
|
-
const testSemver = semver.parse(testVer);
|
|
117
|
-
if (testSemver === null) {
|
|
118
|
-
throw new Error(`Could not parse version to test against: '${testVer}'`);
|
|
119
|
-
}
|
|
120
|
-
// if the test version is a prerelease, ignore it
|
|
121
|
-
if (testSemver.prerelease.length > 0) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
// if the current version is later than the test version, skip this test version
|
|
125
|
-
if (curSemver.compare(testSemver) === 1) {
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
// if the test version is newer, but crosses a major revision boundary, also skip it
|
|
129
|
-
if (testSemver.major > curSemver.major) {
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
// otherwise this version is safe to upgrade to. But there might be multiple ones of this
|
|
133
|
-
// kind, so keep iterating and keeping the highest
|
|
134
|
-
if (safeUpgradeVer === null || testSemver.compare(safeUpgradeVer) === 1) {
|
|
135
|
-
safeUpgradeVer = testSemver;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (safeUpgradeVer) {
|
|
139
|
-
safeUpgradeVer = safeUpgradeVer.format();
|
|
140
|
-
}
|
|
141
|
-
return safeUpgradeVer;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
*
|
|
146
|
-
* @param {{pkgDir: string, pkgName: string, pkgVer?: string}} param0
|
|
147
|
-
* @returns {Promise<import('type-fest').PackageJson>}
|
|
148
|
-
*/
|
|
149
|
-
async installPackage ({pkgDir, pkgName, pkgVer}) {
|
|
150
|
-
const res = await this.exec('install', [
|
|
151
|
-
'--no-save',
|
|
152
|
-
'--no-package-lock',
|
|
153
|
-
pkgVer ? `${pkgName}@${pkgVer}` : pkgName
|
|
154
|
-
], {
|
|
155
|
-
cwd: pkgDir,
|
|
156
|
-
json: true,
|
|
157
|
-
lockFile: INSTALL_LOCKFILE
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
if (res.json) {
|
|
161
|
-
// we parsed a valid json response, so if we got an error here, return that
|
|
162
|
-
// message straightaway
|
|
163
|
-
if (res.json.error) {
|
|
164
|
-
throw new Error(res.json.error);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Now read package data from the installed package to return, and make sure
|
|
169
|
-
// everything got installed ok. Remember, pkgName might end up with a / in it due to an npm
|
|
170
|
-
// org, so if so, that will get correctly exploded into multiple directories, by path.resolve here
|
|
171
|
-
// (even on Windows!)
|
|
172
|
-
const pkgJson = path.resolve(pkgDir, 'node_modules', pkgName, 'package.json');
|
|
173
|
-
try {
|
|
174
|
-
return require(pkgJson);
|
|
175
|
-
} catch {
|
|
176
|
-
throw new Error('The package was not downloaded correctly; its package.json ' +
|
|
177
|
-
'did not exist or was unreadable. We looked for it at ' +
|
|
178
|
-
pkgJson);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @param {string} pkgPath
|
|
184
|
-
*/
|
|
185
|
-
async linkPackage (pkgPath) {
|
|
186
|
-
// from the path alone we don't know the npm package name, so we need to
|
|
187
|
-
// look in package.json
|
|
188
|
-
let pkgName;
|
|
189
|
-
try {
|
|
190
|
-
pkgName = require(path.resolve(pkgPath, 'package.json')).name;
|
|
191
|
-
} catch {
|
|
192
|
-
throw new Error('Could not find package.json inside the package path ' +
|
|
193
|
-
`provided: ${pkgPath}`);
|
|
194
|
-
}
|
|
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
|
-
|
|
200
|
-
const pkgHome = path.resolve(this.appiumHome, pkgName);
|
|
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});
|
|
204
|
-
if (res.json && res.json.error) {
|
|
205
|
-
throw new Error(res.json.error);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// now ensure it was linked to the correct place
|
|
209
|
-
try {
|
|
210
|
-
return require(path.resolve(pkgHome, 'node_modules', pkgName, 'package.json'));
|
|
211
|
-
} catch {
|
|
212
|
-
throw new Error('The package was not linked correctly; its package.json ' +
|
|
213
|
-
'did not exist or was unreadable');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @param {string} pkgDir
|
|
219
|
-
* @param {string} pkg
|
|
220
|
-
*/
|
|
221
|
-
async uninstallPackage (pkgDir, pkg) {
|
|
222
|
-
await this.exec('uninstall', [pkg], {
|
|
223
|
-
cwd: pkgDir,
|
|
224
|
-
lockFile: INSTALL_LOCKFILE
|
|
225
|
-
});
|
|
226
|
-
}
|
|
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
|
-
*/
|
package/lib/driver-config.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import _ from 'lodash';
|
|
4
|
-
import ExtensionConfig from './extension-config';
|
|
5
|
-
import { DRIVER_TYPE } from './ext-config-io';
|
|
6
|
-
|
|
7
|
-
export default class DriverConfig extends ExtensionConfig {
|
|
8
|
-
/**
|
|
9
|
-
* A mapping of `APPIUM_HOME` values to {@link DriverConfig} instances.
|
|
10
|
-
* Each `APPIUM_HOME` should only have one associated `DriverConfig` instance.
|
|
11
|
-
* @type {Record<string,DriverConfig>}
|
|
12
|
-
* @private
|
|
13
|
-
*/
|
|
14
|
-
static _instances = {};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Call {@link DriverConfig.getInstance} instead.
|
|
18
|
-
* @private
|
|
19
|
-
* @param {string} appiumHome
|
|
20
|
-
* @param {(...args: any[]) => void} [logFn]
|
|
21
|
-
*/
|
|
22
|
-
constructor (appiumHome, logFn) {
|
|
23
|
-
super(appiumHome, DRIVER_TYPE, logFn);
|
|
24
|
-
/** @type {Set<string>} */
|
|
25
|
-
this.knownAutomationNames = new Set();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async read () {
|
|
29
|
-
this.knownAutomationNames.clear();
|
|
30
|
-
return await super.read();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Creates or gets an instance of {@link DriverConfig} based value of `appiumHome`
|
|
35
|
-
* @param {string} appiumHome - `APPIUM_HOME` path
|
|
36
|
-
* @param {(...args: any[]) => void} [logFn] - Optional logging function
|
|
37
|
-
* @returns {DriverConfig}
|
|
38
|
-
*/
|
|
39
|
-
static getInstance (appiumHome, logFn) {
|
|
40
|
-
const instance = DriverConfig._instances[appiumHome] ?? new DriverConfig(appiumHome, logFn);
|
|
41
|
-
DriverConfig._instances[appiumHome] = instance;
|
|
42
|
-
return instance;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
*
|
|
47
|
-
* @param {object} extData
|
|
48
|
-
* @param {string} extName
|
|
49
|
-
* @returns {import('./extension-config').Problem[]}
|
|
50
|
-
*/
|
|
51
|
-
// eslint-disable-next-line no-unused-vars
|
|
52
|
-
getConfigProblems (extData, extName) {
|
|
53
|
-
const problems = [];
|
|
54
|
-
const {platformNames, automationName} = extData;
|
|
55
|
-
|
|
56
|
-
if (!_.isArray(platformNames)) {
|
|
57
|
-
problems.push({
|
|
58
|
-
err: 'Missing or incorrect supported platformNames list.',
|
|
59
|
-
val: platformNames
|
|
60
|
-
});
|
|
61
|
-
} else {
|
|
62
|
-
if (_.isEmpty(platformNames)) {
|
|
63
|
-
problems.push({
|
|
64
|
-
err: 'Empty platformNames list.',
|
|
65
|
-
val: platformNames
|
|
66
|
-
});
|
|
67
|
-
} else {
|
|
68
|
-
for (const pName of platformNames) {
|
|
69
|
-
if (!_.isString(pName)) {
|
|
70
|
-
problems.push({err: 'Incorrectly formatted platformName.', val: pName});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (!_.isString(automationName)) {
|
|
77
|
-
problems.push({err: 'Missing or incorrect automationName', val: automationName});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (this.knownAutomationNames.has(automationName)) {
|
|
81
|
-
problems.push({
|
|
82
|
-
err: 'Multiple drivers claim support for the same automationName',
|
|
83
|
-
val: automationName
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// should we retain the name at the end of this function, once we've checked there are no problems?
|
|
88
|
-
this.knownAutomationNames.add(automationName);
|
|
89
|
-
|
|
90
|
-
return problems;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* @param {string} driverName
|
|
95
|
-
* @param {object} extData
|
|
96
|
-
*/
|
|
97
|
-
extensionDesc (driverName, {version, automationName}) {
|
|
98
|
-
return `${driverName}@${version} (automationName '${automationName}')`;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|