appium 2.0.0-beta.17 → 2.0.0-beta.20
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 +0 -0
- package/build/lib/appium.js +84 -69
- package/build/lib/cli/argparse-actions.js +1 -1
- package/build/lib/cli/args.js +87 -223
- package/build/lib/cli/extension-command.js +2 -2
- package/build/lib/cli/extension.js +14 -6
- package/build/lib/cli/parser.js +142 -106
- package/build/lib/cli/utils.js +1 -1
- package/build/lib/config-file.js +141 -0
- package/build/lib/config.js +42 -64
- package/build/lib/driver-config.js +41 -20
- package/build/lib/drivers.js +1 -1
- package/build/lib/ext-config-io.js +165 -0
- package/build/lib/extension-config.js +110 -60
- package/build/lib/grid-register.js +19 -21
- package/build/lib/logsink.js +1 -1
- package/build/lib/main.js +135 -72
- package/build/lib/plugin-config.js +17 -8
- package/build/lib/schema/appium-config-schema.js +252 -0
- package/build/lib/schema/arg-spec.js +120 -0
- package/build/lib/schema/cli-args.js +173 -0
- package/build/lib/schema/cli-transformers.js +76 -0
- package/build/lib/schema/index.js +36 -0
- package/build/lib/schema/keywords.js +62 -0
- package/build/lib/schema/schema.js +357 -0
- package/build/lib/utils.js +26 -35
- package/lib/appium-config.schema.json +277 -0
- package/lib/appium.js +99 -75
- package/lib/cli/args.js +138 -335
- package/lib/cli/extension-command.js +7 -6
- package/lib/cli/extension.js +12 -4
- package/lib/cli/parser.js +248 -96
- package/lib/config-file.js +227 -0
- package/lib/config.js +71 -61
- package/lib/driver-config.js +66 -11
- package/lib/ext-config-io.js +287 -0
- package/lib/extension-config.js +209 -66
- package/lib/grid-register.js +24 -21
- package/lib/main.js +139 -68
- package/lib/plugin-config.js +32 -2
- package/lib/schema/appium-config-schema.js +286 -0
- package/lib/schema/arg-spec.js +218 -0
- package/lib/schema/cli-args.js +273 -0
- package/lib/schema/cli-transformers.js +123 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/keywords.js +119 -0
- package/lib/schema/schema.js +577 -0
- package/lib/utils.js +29 -52
- package/package.json +16 -11
- package/types/appium-config.d.ts +197 -0
- package/types/types.d.ts +201 -0
- package/build/lib/cli/parser-helpers.js +0 -106
- package/lib/cli/parser-helpers.js +0 -106
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import logger from './logger';
|
|
3
|
-
import { processCapabilities, PROTOCOLS
|
|
3
|
+
import { processCapabilities, PROTOCOLS } from '@appium/base-driver';
|
|
4
4
|
import { fs } from '@appium/support';
|
|
5
5
|
|
|
6
6
|
const W3C_APPIUM_PREFIX = 'appium';
|
|
@@ -33,55 +33,6 @@ function inspectObject (args) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
/**
|
|
37
|
-
* Given a set of CLI args and the name of a driver or plugin, extract those args for that plugin
|
|
38
|
-
* @param {Object} extensionArgs - arguments of the form {[extName]: {[argName]: [argValue]}}
|
|
39
|
-
* @param {string} extensionName - the name of the extension
|
|
40
|
-
* @return {Object} the arg object for that extension alone
|
|
41
|
-
*/
|
|
42
|
-
function getExtensionArgs (extensionArgs, extensionName) {
|
|
43
|
-
if (!_.has(extensionArgs, extensionName)) {
|
|
44
|
-
return {};
|
|
45
|
-
}
|
|
46
|
-
if (!_.isPlainObject(extensionArgs[extensionName])) {
|
|
47
|
-
throw new TypeError(`Driver or plugin arguments must be plain objects`);
|
|
48
|
-
}
|
|
49
|
-
return extensionArgs[extensionName];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Given a set of args and a set of constraints, throw an error if any args are not mentioned in
|
|
55
|
-
* the set of constraints
|
|
56
|
-
* @param {Object} extensionArgs the args
|
|
57
|
-
* @param {Object} argsConstraints the constraints object
|
|
58
|
-
* @throws {Error} if any args were not recognized
|
|
59
|
-
*/
|
|
60
|
-
function ensureNoUnknownArgs (extensionArgs, argsConstraints) {
|
|
61
|
-
const knownArgNames = Object.keys(argsConstraints);
|
|
62
|
-
const unknownArgs = _.difference(Object.keys(extensionArgs), knownArgNames);
|
|
63
|
-
if (unknownArgs.length > 0) {
|
|
64
|
-
throw new Error(`Some arguments were not recognized: ${JSON.stringify(unknownArgs)}. ` +
|
|
65
|
-
`Are you sure they are in the list of supported args? ${JSON.stringify(knownArgNames)}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Takes in a set of driver/plugin args passed in by user, and arg constraints
|
|
71
|
-
* and throws an error if any arg is unknown or of the incorrect type
|
|
72
|
-
*
|
|
73
|
-
* @param {object} extensionArgs - Driver or Plugin specific args
|
|
74
|
-
* @param {object} argsConstraints - Constraints for arguments
|
|
75
|
-
* @throws {Error} if any args are not recognized or are of an invalid type
|
|
76
|
-
*/
|
|
77
|
-
function validateExtensionArgs (extensionArgs, argsConstraints) {
|
|
78
|
-
if (!_.isEmpty(extensionArgs) && !_.isEmpty(argsConstraints)) {
|
|
79
|
-
ensureNoUnknownArgs(extensionArgs, argsConstraints);
|
|
80
|
-
validateArgs(extensionArgs, argsConstraints);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
36
|
/**
|
|
86
37
|
* Takes the caps that were provided in the request and translates them
|
|
87
38
|
* into caps that can be used by the inner drivers.
|
|
@@ -267,8 +218,34 @@ function pullSettings (caps) {
|
|
|
267
218
|
|
|
268
219
|
const rootDir = fs.findRoot(__dirname);
|
|
269
220
|
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* A Map where you can set properties, but only once. And you can't remove anything. So there.
|
|
224
|
+
* @template K,V
|
|
225
|
+
* @extends {Map<K,V>}
|
|
226
|
+
*/
|
|
227
|
+
class ReadonlyMap extends Map {
|
|
228
|
+
/**
|
|
229
|
+
* @param {K} key
|
|
230
|
+
* @param {V} value
|
|
231
|
+
*/
|
|
232
|
+
set (key, value) {
|
|
233
|
+
if (this.has(key)) {
|
|
234
|
+
throw new Error(`${key} is already set`);
|
|
235
|
+
}
|
|
236
|
+
return super.set(key, value);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
delete (key) {
|
|
240
|
+
throw new Error(`${key} cannot be deleted`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
clear () {
|
|
244
|
+
throw new Error(`Cannot clear ReadonlyMap`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
270
248
|
export {
|
|
271
249
|
inspectObject, parseCapsForInnerDriver, insertAppiumPrefixes, rootDir,
|
|
272
|
-
getPackageVersion, pullSettings, removeAppiumPrefixes,
|
|
273
|
-
validateExtensionArgs
|
|
250
|
+
getPackageVersion, pullSettings, removeAppiumPrefixes, ReadonlyMap
|
|
274
251
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.20",
|
|
4
4
|
"description": "Automation for Apps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"bin",
|
|
33
33
|
"lib",
|
|
34
34
|
"build/lib",
|
|
35
|
-
"postinstall.js"
|
|
35
|
+
"postinstall.js",
|
|
36
|
+
"types"
|
|
36
37
|
],
|
|
37
38
|
"scripts": {
|
|
38
39
|
"generate-docs": "gulp transpile && node ./build/commands-yml/parse.js",
|
|
@@ -43,17 +44,21 @@
|
|
|
43
44
|
"zip-and-upload": "npm run zip && npm run upload"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@appium/base-driver": "^8.
|
|
47
|
-
"@appium/base-plugin": "1.
|
|
48
|
-
"@appium/support": "^2.
|
|
49
|
-
"@babel/runtime": "7.
|
|
47
|
+
"@appium/base-driver": "^8.2.0",
|
|
48
|
+
"@appium/base-plugin": "1.8.0",
|
|
49
|
+
"@appium/support": "^2.55.1",
|
|
50
|
+
"@babel/runtime": "7.16.3",
|
|
51
|
+
"@sidvind/better-ajv-errors": "0.9.2",
|
|
52
|
+
"ajv": "8.8.0",
|
|
53
|
+
"ajv-formats": "2.1.1",
|
|
50
54
|
"argparse": "2.0.1",
|
|
51
55
|
"async-lock": "1.3.0",
|
|
52
|
-
"asyncbox": "2.9.
|
|
53
|
-
"axios": "0.
|
|
56
|
+
"asyncbox": "2.9.2",
|
|
57
|
+
"axios": "0.24.0",
|
|
54
58
|
"bluebird": "3.7.2",
|
|
55
59
|
"continuation-local-storage": "3.2.1",
|
|
56
60
|
"find-up": "5.0.0",
|
|
61
|
+
"lilconfig": "2.0.4",
|
|
57
62
|
"lodash": "4.17.21",
|
|
58
63
|
"longjohn": "0.2.12",
|
|
59
64
|
"npmlog": "5.0.1",
|
|
@@ -66,8 +71,8 @@
|
|
|
66
71
|
"yaml": "1.10.2"
|
|
67
72
|
},
|
|
68
73
|
"devDependencies": {
|
|
69
|
-
"@appium/fake-driver": "^3.0
|
|
70
|
-
"@appium/gulp-plugins": "^5.5.
|
|
74
|
+
"@appium/fake-driver": "^3.2.0",
|
|
75
|
+
"@appium/gulp-plugins": "^5.5.5"
|
|
71
76
|
},
|
|
72
77
|
"engines": {
|
|
73
78
|
"node": ">=12",
|
|
@@ -78,5 +83,5 @@
|
|
|
78
83
|
"tag": "next"
|
|
79
84
|
},
|
|
80
85
|
"homepage": "https://appium.io",
|
|
81
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "d7882a15eeca9992c5310b53811855f9ccaae36b"
|
|
82
87
|
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/**
|
|
3
|
+
* This file was automatically generated by json-schema-to-typescript.
|
|
4
|
+
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
|
5
|
+
* and run json-schema-to-typescript to regenerate this file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* IP address to listen on
|
|
10
|
+
*/
|
|
11
|
+
export type AddressConfig = string;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the Appium server should allow web browser connections from any host
|
|
14
|
+
*/
|
|
15
|
+
export type AllowCorsConfig = boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Set which insecure features are allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Note that features defined via "deny-insecure" will be disabled, even if also listed here. If string, a path to a text file containing policy or a comma-delimited list.
|
|
18
|
+
*/
|
|
19
|
+
export type AllowInsecureConfig = string[];
|
|
20
|
+
/**
|
|
21
|
+
* Base path to use as the prefix for all webdriver routes running on the server
|
|
22
|
+
*/
|
|
23
|
+
export type BasePathConfig = string;
|
|
24
|
+
/**
|
|
25
|
+
* Callback IP address (default: same as "address")
|
|
26
|
+
*/
|
|
27
|
+
export type CallbackAddressConfig = string;
|
|
28
|
+
/**
|
|
29
|
+
* Callback port (default: same as "port")
|
|
30
|
+
*/
|
|
31
|
+
export type CallbackPortConfig = number;
|
|
32
|
+
/**
|
|
33
|
+
* Add exaggerated spacing in logs to help with visual inspection
|
|
34
|
+
*/
|
|
35
|
+
export type DebugLogSpacingConfig = boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Set which insecure features are not allowed to run in this server's sessions. Features are defined on a driver level; see documentation for more details. Features listed here will not be enabled even if also listed in "allow-insecure", and even if "relaxed-security" is enabled. If string, a path to a text file containing policy or a comma-delimited list.
|
|
38
|
+
*/
|
|
39
|
+
export type DenyInsecureConfig = string[];
|
|
40
|
+
/**
|
|
41
|
+
* Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. A value of 0 disables the timeout.
|
|
42
|
+
*/
|
|
43
|
+
export type KeepAliveTimeoutConfig = number;
|
|
44
|
+
/**
|
|
45
|
+
* Use local timezone for timestamps
|
|
46
|
+
*/
|
|
47
|
+
export type LocalTimezoneConfig = boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Also send log output to this file
|
|
50
|
+
*/
|
|
51
|
+
export type LogConfig = string;
|
|
52
|
+
/**
|
|
53
|
+
* One or more log filtering rules
|
|
54
|
+
*/
|
|
55
|
+
export type LogFiltersConfig = string[];
|
|
56
|
+
/**
|
|
57
|
+
* Log level (console[:file])
|
|
58
|
+
*/
|
|
59
|
+
export type LogLevelConfig =
|
|
60
|
+
| "info"
|
|
61
|
+
| "info:debug"
|
|
62
|
+
| "info:info"
|
|
63
|
+
| "info:warn"
|
|
64
|
+
| "info:error"
|
|
65
|
+
| "warn"
|
|
66
|
+
| "warn:debug"
|
|
67
|
+
| "warn:info"
|
|
68
|
+
| "warn:warn"
|
|
69
|
+
| "warn:error"
|
|
70
|
+
| "error"
|
|
71
|
+
| "error:debug"
|
|
72
|
+
| "error:info"
|
|
73
|
+
| "error:warn"
|
|
74
|
+
| "error:error"
|
|
75
|
+
| "debug"
|
|
76
|
+
| "debug:debug"
|
|
77
|
+
| "debug:info"
|
|
78
|
+
| "debug:warn"
|
|
79
|
+
| "debug:error";
|
|
80
|
+
/**
|
|
81
|
+
* Do not use color in console output
|
|
82
|
+
*/
|
|
83
|
+
export type LogNoColorsConfig = boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Show timestamps in console output
|
|
86
|
+
*/
|
|
87
|
+
export type LogTimestampConfig = boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Add long stack traces to log entries. Recommended for debugging only.
|
|
90
|
+
*/
|
|
91
|
+
export type LongStacktraceConfig = boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Do not check that needed files are readable and/or writable
|
|
94
|
+
*/
|
|
95
|
+
export type NoPermsCheckConfig = boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Port to listen on
|
|
98
|
+
*/
|
|
99
|
+
export type PortConfig = number;
|
|
100
|
+
/**
|
|
101
|
+
* Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it's not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using "deny-insecure"
|
|
102
|
+
*/
|
|
103
|
+
export type RelaxedSecurityConfig = boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Enables session override (clobbering)
|
|
106
|
+
*/
|
|
107
|
+
export type SessionOverrideConfig = boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device
|
|
110
|
+
*/
|
|
111
|
+
export type StrictCapsConfig = boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Absolute path to directory Appium can use to manage temp files. Defaults to C:\Windows\Temp on Windows and /tmp otherwise.
|
|
114
|
+
*/
|
|
115
|
+
export type TmpConfig = string;
|
|
116
|
+
/**
|
|
117
|
+
* Absolute path to directory Appium can use to save iOS instrument traces; defaults to <tmp>/appium-instruments
|
|
118
|
+
*/
|
|
119
|
+
export type TraceDirConfig = string;
|
|
120
|
+
/**
|
|
121
|
+
* A list of drivers to activate. By default, all installed drivers will be activated.
|
|
122
|
+
*/
|
|
123
|
+
export type UseDriversConfig = string[];
|
|
124
|
+
/**
|
|
125
|
+
* A list of plugins to activate. To activate all plugins, the value should be an array with a single item "all".
|
|
126
|
+
*/
|
|
127
|
+
export type UsePluginsConfig = string[];
|
|
128
|
+
/**
|
|
129
|
+
* Also send log output to this http listener
|
|
130
|
+
*/
|
|
131
|
+
export type WebhookConfig = string;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A schema for Appium configuration files
|
|
135
|
+
*/
|
|
136
|
+
export interface AppiumConfiguration {
|
|
137
|
+
server?: ServerConfig;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Configuration when running Appium as a server
|
|
141
|
+
*/
|
|
142
|
+
export interface ServerConfig {
|
|
143
|
+
address?: AddressConfig;
|
|
144
|
+
"allow-cors"?: AllowCorsConfig;
|
|
145
|
+
"allow-insecure"?: AllowInsecureConfig;
|
|
146
|
+
"base-path"?: BasePathConfig;
|
|
147
|
+
"callback-address"?: CallbackAddressConfig;
|
|
148
|
+
"callback-port"?: CallbackPortConfig;
|
|
149
|
+
"debug-log-spacing"?: DebugLogSpacingConfig;
|
|
150
|
+
"default-capabilities"?: DefaultCapabilitiesConfig;
|
|
151
|
+
"deny-insecure"?: DenyInsecureConfig;
|
|
152
|
+
driver?: DriverConfig;
|
|
153
|
+
"keep-alive-timeout"?: KeepAliveTimeoutConfig;
|
|
154
|
+
"local-timezone"?: LocalTimezoneConfig;
|
|
155
|
+
log?: LogConfig;
|
|
156
|
+
"log-filters"?: LogFiltersConfig;
|
|
157
|
+
"log-level"?: LogLevelConfig;
|
|
158
|
+
"log-no-colors"?: LogNoColorsConfig;
|
|
159
|
+
"log-timestamp"?: LogTimestampConfig;
|
|
160
|
+
"long-stacktrace"?: LongStacktraceConfig;
|
|
161
|
+
"no-perms-check"?: NoPermsCheckConfig;
|
|
162
|
+
nodeconfig?: NodeconfigConfig;
|
|
163
|
+
plugin?: PluginConfig;
|
|
164
|
+
port?: PortConfig;
|
|
165
|
+
"relaxed-security"?: RelaxedSecurityConfig;
|
|
166
|
+
"session-override"?: SessionOverrideConfig;
|
|
167
|
+
"strict-caps"?: StrictCapsConfig;
|
|
168
|
+
tmp?: TmpConfig;
|
|
169
|
+
"trace-dir"?: TraceDirConfig;
|
|
170
|
+
"use-drivers"?: UseDriversConfig;
|
|
171
|
+
"use-plugins"?: UsePluginsConfig;
|
|
172
|
+
webhook?: WebhookConfig;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. If a string, a path to a JSON file containing the capabilities, or raw JSON.
|
|
176
|
+
*/
|
|
177
|
+
export interface DefaultCapabilitiesConfig {
|
|
178
|
+
[k: string]: unknown;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Driver-specific configuration. Keys should correspond to driver package names
|
|
182
|
+
*/
|
|
183
|
+
export interface DriverConfig {
|
|
184
|
+
[k: string]: unknown;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself
|
|
188
|
+
*/
|
|
189
|
+
export interface NodeconfigConfig {
|
|
190
|
+
[k: string]: unknown;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Plugin-specific configuration. Keys should correspond to plugin package names
|
|
194
|
+
*/
|
|
195
|
+
export interface PluginConfig {
|
|
196
|
+
[k: string]: unknown;
|
|
197
|
+
}
|
package/types/types.d.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {transformers} from '../lib/schema/cli-transformers';
|
|
2
|
+
import {SERVER_SUBCOMMAND} from '../lib/cli/parser';
|
|
3
|
+
import {
|
|
4
|
+
DRIVER_TYPE as DRIVER_SUBCOMMAND,
|
|
5
|
+
PLUGIN_TYPE as PLUGIN_SUBCOMMAND,
|
|
6
|
+
} from '../lib/ext-config-io';
|
|
7
|
+
import appiumConfigSchema from '../lib/schema/appium-config-schema';
|
|
8
|
+
import {AppiumConfiguration, ServerConfig} from './appium-config';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Converts a kebab-cased string into a camel-cased string.
|
|
12
|
+
*/
|
|
13
|
+
export type KebabToCamel<S extends string> =
|
|
14
|
+
S extends `${infer P1}-${infer P2}${infer P3}`
|
|
15
|
+
? `${Lowercase<P1>}${Uppercase<P2>}${KebabToCamel<P3>}`
|
|
16
|
+
: Lowercase<S>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Converts an object with kebab-cased keys into camel-cased keys.
|
|
20
|
+
*/
|
|
21
|
+
type ObjectToCamel<T> = {
|
|
22
|
+
[K in keyof T as KebabToCamel<string & K>]: T[K] extends Record<string, any>
|
|
23
|
+
? KeysToCamelCase<T[K]>
|
|
24
|
+
: T[K];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Converts an object or array to have camel-cased keys.
|
|
29
|
+
*/
|
|
30
|
+
export type KeysToCamelCase<T> = {
|
|
31
|
+
[K in keyof T as KebabToCamel<string & K>]: T[K] extends Array<any>
|
|
32
|
+
? KeysToCamelCase<T[K][number]>[]
|
|
33
|
+
: ObjectToCamel<T[K]>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The Appium configuration as it would be in a configuration file.
|
|
38
|
+
*/
|
|
39
|
+
export type AppiumConfig = Partial<AppiumConfiguration>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Certain properties have an `appiumCliDest` prop, which affects the shape of
|
|
43
|
+
* {@link ParsedArgs}. This type helps recognize these properties.
|
|
44
|
+
*
|
|
45
|
+
* See `../lib/schema/keywords` for definition of `appiumCliDest`.
|
|
46
|
+
*/
|
|
47
|
+
interface WithDest {
|
|
48
|
+
appiumCliDest: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Some properties have a `default` prop, which means practically they will not
|
|
53
|
+
* be `undefined` upon parsing.
|
|
54
|
+
*
|
|
55
|
+
* We use this to ensure that the {@link ParsedArgs} makes guarantees
|
|
56
|
+
* about the presence of properties.
|
|
57
|
+
*/
|
|
58
|
+
interface WithDefault {
|
|
59
|
+
default: any;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface WithCliTransformer {
|
|
63
|
+
appiumCliTransformer: keyof typeof transformers;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface WithTypeArray {
|
|
67
|
+
type: 'array';
|
|
68
|
+
}
|
|
69
|
+
interface WithTypeObject {
|
|
70
|
+
type: 'object';
|
|
71
|
+
}
|
|
72
|
+
type WithTransformer = WithCliTransformer | WithTypeArray | WithTypeObject;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Derive the "constant" type of the server properties from the schema.
|
|
76
|
+
*/
|
|
77
|
+
type AppiumServerSchema =
|
|
78
|
+
typeof appiumConfigSchema['properties']['server']['properties'];
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Properties of `T` with keys `appiumCliDest` prop _or_ just camel-cased.
|
|
82
|
+
*/
|
|
83
|
+
type NormalizedServerConfig = {
|
|
84
|
+
[Prop in keyof ServerConfigMapping as AppiumServerSchema[Prop] extends WithDest
|
|
85
|
+
? AppiumServerSchema[Prop]['appiumCliDest']
|
|
86
|
+
: KebabToCamel<Prop>]: ServerConfig[Prop];
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* "Normalized" config, which is like the flattened config (camel-cased keys),
|
|
91
|
+
* but not flattened.
|
|
92
|
+
*/
|
|
93
|
+
export type NormalizedAppiumConfig = {
|
|
94
|
+
server: NormalizedServerConfig;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Utility type to associate {@link AppiumServerSchema} with
|
|
99
|
+
* {@link ServerConfig}.
|
|
100
|
+
*/
|
|
101
|
+
type ServerConfigMapping = {
|
|
102
|
+
[Prop in keyof Required<ServerConfig>]: AppiumServerSchema[Prop];
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* This type checks if `appiumCliDest` is present in the object via
|
|
107
|
+
* {@link WithDest}, and uses the _value_ of that property for the key name;
|
|
108
|
+
* otherwise uses the camel-cased value of the key name.
|
|
109
|
+
*/
|
|
110
|
+
type SetKeyForProp<Prop extends keyof ServerConfigMapping> =
|
|
111
|
+
AppiumServerSchema[Prop] extends WithDest
|
|
112
|
+
? AppiumServerSchema[Prop]['appiumCliDest']
|
|
113
|
+
: KebabToCamel<Prop>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Checks for the existence of default values, and ensures those properties will
|
|
117
|
+
* be defined (eliminate `| undefined` from the type).
|
|
118
|
+
*/
|
|
119
|
+
type DefaultForProp<Prop extends keyof ServerConfigMapping> =
|
|
120
|
+
AppiumServerSchema[Prop] extends WithDefault
|
|
121
|
+
? NonNullable<ServerConfig[Prop]>
|
|
122
|
+
: ServerConfig[Prop];
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The final shape of the parsed CLI arguments.
|
|
126
|
+
*/
|
|
127
|
+
type ParsedArgsFromConfig = {
|
|
128
|
+
[Prop in keyof ServerConfigMapping as SetKeyForProp<Prop>]: DefaultForProp<Prop>;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Possible subcommands for the `appium` CLI.
|
|
133
|
+
*/
|
|
134
|
+
type CliSubCommands =
|
|
135
|
+
| typeof SERVER_SUBCOMMAND
|
|
136
|
+
| typeof DRIVER_SUBCOMMAND
|
|
137
|
+
| typeof PLUGIN_SUBCOMMAND;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Possible subcommands of {@link DRIVER_SUBCOMMAND} or
|
|
141
|
+
* {@link PLUGIN_SUBCOMMAND}.
|
|
142
|
+
*/
|
|
143
|
+
type CliExtensionSubcommands =
|
|
144
|
+
| 'list'
|
|
145
|
+
| 'install'
|
|
146
|
+
| 'uninstall'
|
|
147
|
+
| 'update'
|
|
148
|
+
| 'run';
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Random stuff that may appear in the parsed args which has no equivalent in a
|
|
152
|
+
* config file.
|
|
153
|
+
*/
|
|
154
|
+
interface MoreArgs {
|
|
155
|
+
/**
|
|
156
|
+
* Path to config file, if any
|
|
157
|
+
*/
|
|
158
|
+
configFile: string;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* If true, show the build info and exit
|
|
162
|
+
*/
|
|
163
|
+
showConfig: boolean;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* If true, open a REPL
|
|
167
|
+
*/
|
|
168
|
+
shell: boolean;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* If true, throw on error instead of exit. Not supported via CLI, but rather
|
|
172
|
+
* only programmatic usage.
|
|
173
|
+
*/
|
|
174
|
+
throwInsteadOfExit: boolean;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Possible subcommands
|
|
178
|
+
*/
|
|
179
|
+
subcommand:
|
|
180
|
+
| typeof DRIVER_SUBCOMMAND
|
|
181
|
+
| typeof PLUGIN_SUBCOMMAND
|
|
182
|
+
| typeof SERVER_SUBCOMMAND;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Subcommands of `driver` subcommand
|
|
186
|
+
*/
|
|
187
|
+
driverCommand: CliExtensionSubcommands;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Subcommands of `plugin` subcommand
|
|
191
|
+
*/
|
|
192
|
+
pluginCommand: CliExtensionSubcommands;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The Appium configuration as a flattened object, parsed via CLI args _and_ any
|
|
197
|
+
* CLI args unsupported by the config file.
|
|
198
|
+
* @todo Does not make any assumptions about property names derived from
|
|
199
|
+
* extensions.
|
|
200
|
+
*/
|
|
201
|
+
export type ParsedArgs = ParsedArgsFromConfig & Partial<MoreArgs>;
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.parseSecurityFeatures = parseSecurityFeatures;
|
|
9
|
-
exports.parseJsonStringOrFile = parseJsonStringOrFile;
|
|
10
|
-
exports.parseInstallTypes = parseInstallTypes;
|
|
11
|
-
exports.parsePluginNames = parsePluginNames;
|
|
12
|
-
exports.parseDriverNames = parseDriverNames;
|
|
13
|
-
|
|
14
|
-
require("source-map-support/register");
|
|
15
|
-
|
|
16
|
-
var _fs = _interopRequireDefault(require("fs"));
|
|
17
|
-
|
|
18
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
19
|
-
|
|
20
|
-
var _extensionConfig = require("../extension-config");
|
|
21
|
-
|
|
22
|
-
function parseSecurityFeatures(features) {
|
|
23
|
-
const splitter = (splitOn, str) => `${str}`.split(splitOn).map(s => s.trim()).filter(Boolean);
|
|
24
|
-
|
|
25
|
-
let parsedFeatures;
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
parsedFeatures = splitter(',', features);
|
|
29
|
-
} catch (err) {
|
|
30
|
-
throw new TypeError('Could not parse value of --allow/deny-insecure. Should be ' + 'a list of strings separated by commas, or a path to a file ' + 'listing one feature name per line.');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (parsedFeatures.length === 1 && _fs.default.existsSync(parsedFeatures[0])) {
|
|
34
|
-
try {
|
|
35
|
-
const fileFeatures = _fs.default.readFileSync(parsedFeatures[0], 'utf8');
|
|
36
|
-
|
|
37
|
-
parsedFeatures = splitter('\n', fileFeatures);
|
|
38
|
-
} catch (err) {
|
|
39
|
-
throw new TypeError(`Attempted to read --allow/deny-insecure feature names ` + `from file ${parsedFeatures[0]} but got error: ${err.message}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return parsedFeatures;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function parseDriverNames(names) {
|
|
47
|
-
if (!_lodash.default.isString(names)) {
|
|
48
|
-
throw new TypeError('To parse driver names, names must be a CSV string');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
return names.split(',').map(s => s.trim()).filter(Boolean);
|
|
53
|
-
} catch (err) {
|
|
54
|
-
throw new TypeError('Could not parse value of --drivers. Should be a list of driver names ' + 'separated by commas. Driver names are those found when running `appium ' + 'driver list`');
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function parsePluginNames(names) {
|
|
59
|
-
if (!_lodash.default.isString(names)) {
|
|
60
|
-
throw new TypeError('To parse plugin names, names must be a CSV string');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
return names.split(',').map(s => s.trim()).filter(Boolean);
|
|
65
|
-
} catch (err) {
|
|
66
|
-
throw new TypeError('Could not parse value of --plugins. Should be a list of plugin names ' + 'separated by commas. Plugin names are those found when running `appium ' + 'plugin list`');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function parseJsonStringOrFile(capsOrPath) {
|
|
71
|
-
let caps = capsOrPath;
|
|
72
|
-
let loadedFromFile = false;
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
if (_lodash.default.isString(capsOrPath) && _fs.default.statSync(capsOrPath).isFile()) {
|
|
76
|
-
caps = _fs.default.readFileSync(capsOrPath, 'utf8');
|
|
77
|
-
loadedFromFile = true;
|
|
78
|
-
}
|
|
79
|
-
} catch (err) {}
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const result = JSON.parse(caps);
|
|
83
|
-
|
|
84
|
-
if (!_lodash.default.isPlainObject(result)) {
|
|
85
|
-
throw new Error(`'${_lodash.default.truncate(result, {
|
|
86
|
-
length: 100
|
|
87
|
-
})}' is not an object`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return result;
|
|
91
|
-
} catch (e) {
|
|
92
|
-
const msg = loadedFromFile ? `The provided value of '${capsOrPath}' must be a valid JSON` : `The provided value must be a valid JSON`;
|
|
93
|
-
throw new TypeError(`${msg}. Original error: ${e.message}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function parseInstallTypes(source) {
|
|
98
|
-
if (!_lodash.default.includes(_extensionConfig.INSTALL_TYPES, source)) {
|
|
99
|
-
throw `Argument to --source was '${source}', which is not a valid ` + `driver source type. It must be one of ${JSON.stringify(_extensionConfig.INSTALL_TYPES)}`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return source;
|
|
103
|
-
}require('source-map-support').install();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9jbGkvcGFyc2VyLWhlbHBlcnMuanMiXSwibmFtZXMiOlsicGFyc2VTZWN1cml0eUZlYXR1cmVzIiwiZmVhdHVyZXMiLCJzcGxpdHRlciIsInNwbGl0T24iLCJzdHIiLCJzcGxpdCIsIm1hcCIsInMiLCJ0cmltIiwiZmlsdGVyIiwiQm9vbGVhbiIsInBhcnNlZEZlYXR1cmVzIiwiZXJyIiwiVHlwZUVycm9yIiwibGVuZ3RoIiwiZnMiLCJleGlzdHNTeW5jIiwiZmlsZUZlYXR1cmVzIiwicmVhZEZpbGVTeW5jIiwibWVzc2FnZSIsInBhcnNlRHJpdmVyTmFtZXMiLCJuYW1lcyIsIl8iLCJpc1N0cmluZyIsInBhcnNlUGx1Z2luTmFtZXMiLCJwYXJzZUpzb25TdHJpbmdPckZpbGUiLCJjYXBzT3JQYXRoIiwiY2FwcyIsImxvYWRlZEZyb21GaWxlIiwic3RhdFN5bmMiLCJpc0ZpbGUiLCJyZXN1bHQiLCJKU09OIiwicGFyc2UiLCJpc1BsYWluT2JqZWN0IiwiRXJyb3IiLCJ0cnVuY2F0ZSIsImUiLCJtc2ciLCJwYXJzZUluc3RhbGxUeXBlcyIsInNvdXJjZSIsImluY2x1ZGVzIiwiSU5TVEFMTF9UWVBFUyIsInN0cmluZ2lmeSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBR0EsU0FBU0EscUJBQVQsQ0FBZ0NDLFFBQWhDLEVBQTBDO0FBQ3hDLFFBQU1DLFFBQVEsR0FBRyxDQUFDQyxPQUFELEVBQVVDLEdBQVYsS0FBbUIsR0FBRUEsR0FBSSxFQUFQLENBQVNDLEtBQVQsQ0FBZUYsT0FBZixFQUNoQ0csR0FEZ0MsQ0FDM0JDLENBQUQsSUFBT0EsQ0FBQyxDQUFDQyxJQUFGLEVBRHFCLEVBRWhDQyxNQUZnQyxDQUV6QkMsT0FGeUIsQ0FBbkM7O0FBR0EsTUFBSUMsY0FBSjs7QUFDQSxNQUFJO0FBQ0ZBLElBQUFBLGNBQWMsR0FBR1QsUUFBUSxDQUFDLEdBQUQsRUFBTUQsUUFBTixDQUF6QjtBQUNELEdBRkQsQ0FF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QU9NLENBQVAsRUFBVTtBQUNWLFVBQU1DLEdBQUcsR0FBR1YsY0FBYyxHQUNyQiwwQkFBeUJGLFVBQVcsd0JBRGYsR0FFckIseUNBRkw7QUFHQSxVQUFNLElBQUliLFNBQUosQ0FBZSxHQUFFeUIsR0FBSSxxQkFBb0JELENBQUMsQ0FBQ2xCLE9BQVEsRUFBbkQsQ0FBTjtBQUNEO0FBQ0Y7O0FBRUQsU0FBU29CLGlCQUFULENBQTRCQyxNQUE1QixFQUFvQztBQUNsQyxNQUFJLENBQUNsQixnQkFBRW1CLFFBQUYsQ0FBV0MsOEJBQVgsRUFBMEJGLE1BQTFCLENBQUwsRUFBd0M7QUFDdEMsVUFBTyw2QkFBNEJBLE1BQU8sMEJBQXBDLEdBQ0MseUNBQXdDUixJQUFJLENBQUNXLFNBQUwsQ0FBZUQsOEJBQWYsQ0FBOEIsRUFEN0U7QUFFRDs7QUFFRCxTQUFPRixNQUFQO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSAnZnMnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IElOU1RBTExfVFlQRVMgfSBmcm9tICcuLi9leHRlbnNpb24tY29uZmlnJztcblxuLy8gc2VydmVyQXJncyB3aWxsIGJlIGFkZGVkIHRvIHRoZSBgc2VydmVyYCAoZGVmYXVsdCkgc3ViY29tbWFuZFxuZnVuY3Rpb24gcGFyc2VTZWN1cml0eUZlYXR1cmVzIChmZWF0dXJlcykge1xuICBjb25zdCBzcGxpdHRlciA9IChzcGxpdE9uLCBzdHIpID0+IGAke3N0cn1gLnNwbGl0KHNwbGl0T24pXG4gICAgLm1hcCgocykgPT4gcy50cmltKCkpXG4gICAgLmZpbHRlcihCb29sZWFuKTtcbiAgbGV0IHBhcnNlZEZlYXR1cmVzO1xuICB0cnkge1xuICAgIHBhcnNlZEZlYXR1cmVzID0gc3BsaXR0ZXIoJywnLCBmZWF0dXJlcyk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0NvdWxkIG5vdCBwYXJzZSB2YWx1ZSBvZiAtLWFsbG93L2RlbnktaW5zZWN1cmUuIFNob3VsZCBiZSAnICtcbiAgICAgICdhIGxpc3Qgb2Ygc3RyaW5ncyBzZXBhcmF0ZWQgYnkgY29tbWFzLCBvciBhIHBhdGggdG8gYSBmaWxlICcgK1xuICAgICAgJ2xpc3Rpbmcgb25lIGZlYXR1cmUgbmFtZSBwZXIgbGluZS4nKTtcbiAgfVxuXG4gIGlmIChwYXJzZWRGZWF0dXJlcy5sZW5ndGggPT09IDEgJiYgZnMuZXhpc3RzU3luYyhwYXJzZWRGZWF0dXJlc1swXSkpIHtcbiAgICAvLyB3ZSBtaWdodCBoYXZlIGEgZmlsZSB3aGljaCBpcyBhIGxpc3Qgb2YgZmVhdHVyZXNcbiAgICB0cnkge1xuICAgICAgY29uc3QgZmlsZUZlYXR1cmVzID0gZnMucmVhZEZpbGVTeW5jKHBhcnNlZEZlYXR1cmVzWzBdLCAndXRmOCcpO1xuICAgICAgcGFyc2VkRmVhdHVyZXMgPSBzcGxpdHRlcignXFxuJywgZmlsZUZlYXR1cmVzKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYEF0dGVtcHRlZCB0byByZWFkIC0tYWxsb3cvZGVueS1pbnNlY3VyZSBmZWF0dXJlIG5hbWVzIGAgK1xuICAgICAgICBgZnJvbSBmaWxlICR7cGFyc2VkRmVhdHVyZXNbMF19IGJ1dCBnb3QgZXJyb3I6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHBhcnNlZEZlYXR1cmVzO1xufVxuXG5mdW5jdGlvbiBwYXJzZURyaXZlck5hbWVzIChuYW1lcykge1xuICBpZiAoIV8uaXNTdHJpbmcobmFtZXMpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVG8gcGFyc2UgZHJpdmVyIG5hbWVzLCBuYW1lcyBtdXN0IGJlIGEgQ1NWIHN0cmluZycpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICByZXR1cm4gbmFtZXMuc3BsaXQoJywnKS5tYXAoKHMpID0+IHMudHJpbSgpKS5maWx0ZXIoQm9vbGVhbik7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0NvdWxkIG5vdCBwYXJzZSB2YWx1ZSBvZiAtLWRyaXZlcnMuIFNob3VsZCBiZSBhIGxpc3Qgb2YgZHJpdmVyIG5hbWVzICcgK1xuICAgICAgICAgICAgICAgICAgICAnc2VwYXJhdGVkIGJ5IGNvbW1hcy4gRHJpdmVyIG5hbWVzIGFyZSB0aG9zZSBmb3VuZCB3aGVuIHJ1bm5pbmcgYGFwcGl1bSAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2RyaXZlciBsaXN0YCcpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlUGx1Z2luTmFtZXMgKG5hbWVzKSB7XG4gIGlmICghXy5pc1N0cmluZyhuYW1lcykpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUbyBwYXJzZSBwbHVnaW4gbmFtZXMsIG5hbWVzIG11c3QgYmUgYSBDU1Ygc3RyaW5nJyk7XG4gIH1cblxuICB0cnkge1xuICAgIHJldHVybiBuYW1lcy5zcGxpdCgnLCcpLm1hcCgocykgPT4gcy50cmltKCkpLmZpbHRlcihCb29sZWFuKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQ291bGQgbm90IHBhcnNlIHZhbHVlIG9mIC0tcGx1Z2lucy4gU2hvdWxkIGJlIGEgbGlzdCBvZiBwbHVnaW4gbmFtZXMgJyArXG4gICAgICAgICAgICAgICAgICAgICdzZXBhcmF0ZWQgYnkgY29tbWFzLiBQbHVnaW4gbmFtZXMgYXJlIHRob3NlIGZvdW5kIHdoZW4gcnVubmluZyBgYXBwaXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAncGx1Z2luIGxpc3RgJyk7XG4gIH1cbn1cblxuZnVuY3Rpb24gcGFyc2VKc29uU3RyaW5nT3JGaWxlIChjYXBzT3JQYXRoKSB7XG4gIGxldCBjYXBzID0gY2Fwc09yUGF0aDtcbiAgbGV0IGxvYWRlZEZyb21GaWxlID0gZmFsc2U7XG4gIHRyeSB7XG4gICAgLy8gdXNlIHN5bmNocm9ub3VzIGZpbGUgYWNjZXNzLCBhcyBgYXJncGFyc2VgIHByb3ZpZGVzIG5vIHdheSBvZiBlaXRoZXJcbiAgICAvLyBhd2FpdGluZyBvciB1c2luZyBjYWxsYmFja3MuIFRoaXMgc3RlcCBoYXBwZW5zIGluIHN0YXJ0dXAsIGluIHdoYXQgaXNcbiAgICAvLyBlZmZlY3RpdmVseSBjb21tYW5kLWxpbmUgY29kZSwgc28gbm90aGluZyBpcyBibG9ja2VkIGluIHRlcm1zIG9mXG4gICAgLy8gc2Vzc2lvbnMsIHNvIGhvbGRpbmcgdXAgdGhlIGV2ZW50IGxvb3AgZG9lcyBub3QgaW5jdXIgdGhlIHVzdWFsXG4gICAgLy8gZHJhd2JhY2tzLlxuICAgIGlmIChfLmlzU3RyaW5nKGNhcHNPclBhdGgpICYmIGZzLnN0YXRTeW5jKGNhcHNPclBhdGgpLmlzRmlsZSgpKSB7XG4gICAgICBjYXBzID0gZnMucmVhZEZpbGVTeW5jKGNhcHNPclBhdGgsICd1dGY4Jyk7XG4gICAgICBsb2FkZWRGcm9tRmlsZSA9IHRydWU7XG4gICAgfVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICAvLyBub3QgYSBmaWxlLCBvciBub3QgcmVhZGFibGVcbiAgfVxuICB0cnkge1xuICAgIGNvbnN0IHJlc3VsdCA9IEpTT04ucGFyc2UoY2Fwcyk7XG4gICAgaWYgKCFfLmlzUGxhaW5PYmplY3QocmVzdWx0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGAnJHtfLnRydW5jYXRlKHJlc3VsdCwge2xlbmd0aDogMTAwfSl9JyBpcyBub3QgYW4gb2JqZWN0YCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zdCBtc2cgPSBsb2FkZWRGcm9tRmlsZVxuICAgICAgPyBgVGhlIHByb3ZpZGVkIHZhbHVlIG9mICcke2NhcHNPclBhdGh9JyBtdXN0IGJlIGEgdmFsaWQgSlNPTmBcbiAgICAgIDogYFRoZSBwcm92aWRlZCB2YWx1ZSBtdXN0IGJlIGEgdmFsaWQgSlNPTmA7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHttc2d9LiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gcGFyc2VJbnN0YWxsVHlwZXMgKHNvdXJjZSkge1xuICBpZiAoIV8uaW5jbHVkZXMoSU5TVEFMTF9UWVBFUywgc291cmNlKSkge1xuICAgIHRocm93IGBBcmd1bWVudCB0byAtLXNvdXJjZSB3YXMgJyR7c291cmNlfScsIHdoaWNoIGlzIG5vdCBhIHZhbGlkIGAgK1xuICAgICAgICAgIGBkcml2ZXIgc291cmNlIHR5cGUuIEl0IG11c3QgYmUgb25lIG9mICR7SlNPTi5zdHJpbmdpZnkoSU5TVEFMTF9UWVBFUyl9YDtcbiAgfVxuXG4gIHJldHVybiBzb3VyY2U7XG59XG5cbmV4cG9ydCB7XG4gIHBhcnNlU2VjdXJpdHlGZWF0dXJlcyxcbiAgcGFyc2VKc29uU3RyaW5nT3JGaWxlLFxuICBwYXJzZUluc3RhbGxUeXBlcyxcbiAgcGFyc2VQbHVnaW5OYW1lcyxcbiAgcGFyc2VEcml2ZXJOYW1lcyxcbn07XG4iXSwiZmlsZSI6ImxpYi9jbGkvcGFyc2VyLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4ifQ==
|