appium 3.2.2 → 3.3.0
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/cli/args.d.ts +16 -12
- package/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +15 -35
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/driver-command.d.ts +51 -93
- package/build/lib/cli/driver-command.d.ts.map +1 -1
- package/build/lib/cli/driver-command.js +11 -66
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.d.ts +211 -415
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +384 -653
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/extension.d.ts +11 -16
- package/build/lib/cli/extension.d.ts.map +1 -1
- package/build/lib/cli/extension.js +10 -28
- package/build/lib/cli/extension.js.map +1 -1
- package/build/lib/cli/parser.d.ts +40 -69
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +24 -59
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/plugin-command.d.ts +50 -90
- package/build/lib/cli/plugin-command.d.ts.map +1 -1
- package/build/lib/cli/plugin-command.js +11 -63
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/cli/setup-command.d.ts +21 -26
- package/build/lib/cli/setup-command.d.ts.map +1 -1
- package/build/lib/cli/setup-command.js +13 -55
- package/build/lib/cli/setup-command.js.map +1 -1
- package/build/lib/cli/utils.d.ts +27 -29
- package/build/lib/cli/utils.d.ts.map +1 -1
- package/build/lib/cli/utils.js +29 -31
- package/build/lib/cli/utils.js.map +1 -1
- package/build/lib/config-file.d.ts +24 -67
- package/build/lib/config-file.d.ts.map +1 -1
- package/build/lib/config-file.js +56 -115
- package/build/lib/config-file.js.map +1 -1
- package/build/lib/config.d.ts +42 -44
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +75 -107
- package/build/lib/config.js.map +1 -1
- package/build/lib/constants.d.ts +23 -23
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +10 -15
- package/build/lib/constants.js.map +1 -1
- package/build/lib/doctor/doctor.d.ts +40 -57
- package/build/lib/doctor/doctor.d.ts.map +1 -1
- package/build/lib/doctor/doctor.js +29 -60
- package/build/lib/doctor/doctor.js.map +1 -1
- package/build/lib/grid-register.d.ts +32 -7
- package/build/lib/grid-register.d.ts.map +1 -1
- package/build/lib/grid-register.js +84 -48
- package/build/lib/grid-register.js.map +1 -1
- package/build/lib/logsink.d.ts +13 -22
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +48 -103
- package/build/lib/logsink.js.map +1 -1
- package/build/lib/main.js +1 -1
- package/build/lib/main.js.map +1 -1
- package/build/lib/schema/arg-spec.d.ts +32 -107
- package/build/lib/schema/arg-spec.d.ts.map +1 -1
- package/build/lib/schema/arg-spec.js +11 -107
- package/build/lib/schema/arg-spec.js.map +1 -1
- package/build/lib/schema/cli-args.d.ts +3 -15
- package/build/lib/schema/cli-args.d.ts.map +1 -1
- package/build/lib/schema/cli-args.js +15 -105
- package/build/lib/schema/cli-args.js.map +1 -1
- package/build/lib/schema/cli-transformers.d.ts +15 -12
- package/build/lib/schema/cli-transformers.d.ts.map +1 -1
- package/build/lib/schema/cli-transformers.js +15 -45
- package/build/lib/schema/cli-transformers.js.map +1 -1
- package/build/lib/schema/index.d.ts +2 -2
- package/build/lib/schema/index.d.ts.map +1 -1
- package/build/lib/schema/index.js.map +1 -1
- package/build/lib/schema/keywords.d.ts +12 -20
- package/build/lib/schema/keywords.d.ts.map +1 -1
- package/build/lib/schema/keywords.js +6 -51
- package/build/lib/schema/keywords.js.map +1 -1
- package/build/lib/schema/schema.d.ts +106 -231
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +75 -345
- package/build/lib/schema/schema.js.map +1 -1
- package/build/lib/utils.d.ts +59 -238
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +55 -207
- package/build/lib/utils.js.map +1 -1
- package/lib/cli/{args.js → args.ts} +40 -51
- package/lib/cli/driver-command.ts +122 -0
- package/lib/cli/{extension-command.js → extension-command.ts} +610 -689
- package/lib/cli/extension.ts +65 -0
- package/lib/cli/{parser.js → parser.ts} +48 -71
- package/lib/cli/plugin-command.ts +117 -0
- package/lib/cli/{setup-command.js → setup-command.ts} +57 -72
- package/lib/cli/utils.ts +97 -0
- package/lib/config-file.ts +212 -0
- package/lib/{config.js → config.ts} +129 -141
- package/lib/{constants.js → constants.ts} +30 -41
- package/lib/doctor/{doctor.js → doctor.ts} +81 -91
- package/lib/grid-register.ts +250 -0
- package/lib/{logsink.js → logsink.ts} +91 -137
- package/lib/main.js +1 -1
- package/lib/schema/arg-spec.ts +131 -0
- package/lib/schema/cli-args.ts +171 -0
- package/lib/schema/cli-transformers.ts +83 -0
- package/lib/schema/keywords.ts +96 -0
- package/lib/schema/schema.ts +449 -0
- package/lib/utils.ts +404 -0
- package/package.json +16 -16
- package/lib/cli/driver-command.js +0 -174
- package/lib/cli/extension.js +0 -74
- package/lib/cli/plugin-command.js +0 -164
- package/lib/cli/utils.js +0 -91
- package/lib/config-file.js +0 -228
- package/lib/grid-register.js +0 -146
- package/lib/schema/arg-spec.js +0 -229
- package/lib/schema/cli-args.js +0 -254
- package/lib/schema/cli-transformers.js +0 -113
- package/lib/schema/keywords.js +0 -136
- package/lib/schema/schema.js +0 -725
- package/lib/utils.js +0 -512
- /package/lib/schema/{index.js → index.ts} +0 -0
|
@@ -1,22 +1,26 @@
|
|
|
1
|
+
import type {ParsedArgs} from 'appium/types';
|
|
2
|
+
import type {MessageObject} from '@appium/logger';
|
|
3
|
+
import type {Logger, Logform} from 'winston';
|
|
4
|
+
import type Transport from 'winston-transport';
|
|
1
5
|
import globalLog from '@appium/logger';
|
|
2
6
|
import {createLogger, format, transports} from 'winston';
|
|
3
7
|
import {fs} from '@appium/support';
|
|
4
8
|
import _ from 'lodash';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
9
|
+
import {adler32} from './utils';
|
|
10
|
+
import {LRUCache} from 'lru-cache';
|
|
7
11
|
|
|
8
12
|
const LEVELS_MAP = {
|
|
9
13
|
debug: 4,
|
|
10
14
|
info: 3,
|
|
11
15
|
warn: 2,
|
|
12
16
|
error: 1,
|
|
13
|
-
};
|
|
17
|
+
} as const;
|
|
14
18
|
const COLORS_MAP = {
|
|
15
19
|
info: 'cyan',
|
|
16
20
|
debug: 'grey',
|
|
17
21
|
warn: 'yellow',
|
|
18
22
|
error: 'red',
|
|
19
|
-
};
|
|
23
|
+
} as const;
|
|
20
24
|
const TO_WINSTON_LEVELS_MAP = {
|
|
21
25
|
silly: 'debug',
|
|
22
26
|
verbose: 'debug',
|
|
@@ -25,49 +29,48 @@ const TO_WINSTON_LEVELS_MAP = {
|
|
|
25
29
|
http: 'info',
|
|
26
30
|
warn: 'warn',
|
|
27
31
|
error: 'error',
|
|
28
|
-
};
|
|
32
|
+
} as const;
|
|
29
33
|
const COLOR_CODE_PATTERN = /\u001b\[(\d+(;\d+)*)?m/g; // eslint-disable-line no-control-regex
|
|
30
34
|
|
|
31
35
|
// https://www.ditig.com/publications/256-colors-cheat-sheet
|
|
32
36
|
const MIN_COLOR = 17;
|
|
33
37
|
const MAX_COLOR = 231;
|
|
34
|
-
|
|
35
|
-
const COLORS_CACHE = new LRUCache({
|
|
38
|
+
const COLORS_CACHE = new LRUCache<string, number>({
|
|
36
39
|
max: 1024,
|
|
37
40
|
ttl: 1000 * 60 * 60 * 24, // expire after 24 hours
|
|
38
41
|
updateAgeOnGet: true,
|
|
39
42
|
});
|
|
40
43
|
|
|
41
44
|
// npmlog is used only for emitting, we use winston for output (global is set by support)
|
|
42
|
-
|
|
43
|
-
let log = null;
|
|
45
|
+
let log: Logger | null = null;
|
|
44
46
|
|
|
45
47
|
/**
|
|
48
|
+
* Initialize the log sink from parsed CLI/server args.
|
|
49
|
+
* Sets up Winston transports (console, optional file, optional webhook) and forwards
|
|
50
|
+
* npmlog messages to them. Call this before other logging setup.
|
|
46
51
|
*
|
|
47
|
-
* @param
|
|
48
|
-
* @returns {Promise<void>}
|
|
52
|
+
* @param args - Parsed server/CLI arguments (e.g. `loglevel`, `logFile`, `webhook`).
|
|
49
53
|
*/
|
|
50
|
-
export async function init(args) {
|
|
54
|
+
export async function init(args: ParsedArgs): Promise<void> {
|
|
51
55
|
globalLog.level = 'silent';
|
|
52
56
|
|
|
53
57
|
// clean up in case we have initiated before since npmlog is a global object
|
|
54
58
|
clear();
|
|
55
59
|
|
|
56
|
-
const
|
|
57
|
-
const transportNames = new Set(
|
|
60
|
+
const transportList = await createTransports(args);
|
|
61
|
+
const transportNames = new Set(transportList.map((tr) => tr.constructor.name));
|
|
58
62
|
log = createLogger({
|
|
59
|
-
transports,
|
|
63
|
+
transports: transportList,
|
|
60
64
|
levels: LEVELS_MAP,
|
|
61
65
|
handleExceptions: true,
|
|
62
|
-
exitOnError: false
|
|
66
|
+
exitOnError: false,
|
|
63
67
|
});
|
|
64
68
|
|
|
65
|
-
const reportedLoggerErrors = new Set();
|
|
69
|
+
const reportedLoggerErrors = new Set<string>();
|
|
66
70
|
// Capture logs emitted via npmlog and pass them through winston
|
|
67
|
-
globalLog.on('log', (
|
|
71
|
+
globalLog.on('log', ({level, message, prefix}: MessageObject) => {
|
|
68
72
|
const {sessionSignature} = globalLog.asyncStorage.getStore() ?? {};
|
|
69
|
-
|
|
70
|
-
const prefixes = [];
|
|
73
|
+
const prefixes: string[] = [];
|
|
71
74
|
if (sessionSignature) {
|
|
72
75
|
prefixes.push(sessionSignature);
|
|
73
76
|
}
|
|
@@ -78,24 +81,26 @@ export async function init(args) {
|
|
|
78
81
|
if (!_.isEmpty(prefixes)) {
|
|
79
82
|
const finalPrefix = prefixes
|
|
80
83
|
.map(toDecoratedPrefix)
|
|
81
|
-
.map((pfx) => isLogColorEnabled(args) ? colorizePrefix(pfx) : pfx)
|
|
84
|
+
.map((pfx) => (isLogColorEnabled(args) ? colorizePrefix(pfx) : pfx))
|
|
82
85
|
.join('');
|
|
83
86
|
msg = `${finalPrefix} ${msg}`;
|
|
84
87
|
}
|
|
85
88
|
const winstonLevel = TO_WINSTON_LEVELS_MAP[level] || 'info';
|
|
86
89
|
try {
|
|
87
|
-
|
|
90
|
+
(log as Logger)[winstonLevel as keyof Logger](msg);
|
|
88
91
|
if (_.isFunction(args.logHandler)) {
|
|
89
92
|
args.logHandler(level, msg);
|
|
90
93
|
}
|
|
91
94
|
} catch (e) {
|
|
92
|
-
|
|
95
|
+
const err = e as Error;
|
|
96
|
+
if (!reportedLoggerErrors.has(err.message) && process.stderr.writable) {
|
|
93
97
|
// eslint-disable-next-line no-console
|
|
94
98
|
console.error(
|
|
95
99
|
`The log message '${_.truncate(msg, {length: 30})}' cannot be written into ` +
|
|
96
|
-
|
|
100
|
+
`one or more requested destinations: ${[...transportNames].join(', ')}. ` +
|
|
101
|
+
`Original error: ${err.message}`
|
|
97
102
|
);
|
|
98
|
-
reportedLoggerErrors.add(
|
|
103
|
+
reportedLoggerErrors.add(err.message);
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
});
|
|
@@ -104,37 +109,21 @@ export async function init(args) {
|
|
|
104
109
|
}
|
|
105
110
|
|
|
106
111
|
/**
|
|
107
|
-
*
|
|
112
|
+
* Clear the log sink and remove global log listeners.
|
|
113
|
+
* Safe to call before re-initializing with `init`.
|
|
108
114
|
*/
|
|
109
|
-
export function clear() {
|
|
115
|
+
export function clear(): void {
|
|
110
116
|
log?.clear();
|
|
111
117
|
globalLog.removeAllListeners('log');
|
|
112
118
|
}
|
|
113
119
|
|
|
114
|
-
//
|
|
115
|
-
const colorizeFormat = format.colorize({
|
|
116
|
-
colors: COLORS_MAP,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Strip the color marking within messages
|
|
120
|
-
const stripColorFormat = format(function stripColor(info) {
|
|
121
|
-
return {
|
|
122
|
-
...info,
|
|
123
|
-
level: stripColorCodes(info.level),
|
|
124
|
-
message: _.isString(info.message) ? stripColorCodes(info.message) : info.message,
|
|
125
|
-
};
|
|
126
|
-
})();
|
|
120
|
+
// #region private helpers
|
|
127
121
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
*/
|
|
134
|
-
function createConsoleTransport(args, logLvl) {
|
|
135
|
-
/** @type {AppiumConsoleTransportOptions} */
|
|
136
|
-
const opt = {
|
|
137
|
-
name: 'console',
|
|
122
|
+
function createConsoleTransport(
|
|
123
|
+
args: ParsedArgs,
|
|
124
|
+
logLvl: string
|
|
125
|
+
): transports.ConsoleTransportInstance {
|
|
126
|
+
const opt: transports.ConsoleTransportOptions = {
|
|
138
127
|
level: logLvl,
|
|
139
128
|
stderrLevels: ['error'],
|
|
140
129
|
format: format.combine(
|
|
@@ -146,16 +135,11 @@ function createConsoleTransport(args, logLvl) {
|
|
|
146
135
|
return new transports.Console(opt);
|
|
147
136
|
}
|
|
148
137
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
*/
|
|
155
|
-
function createFileTransport(args, logLvl) {
|
|
156
|
-
/** @type {AppiumFileTransportOptions} */
|
|
157
|
-
const opt = {
|
|
158
|
-
name: 'file',
|
|
138
|
+
function createFileTransport(
|
|
139
|
+
args: ParsedArgs,
|
|
140
|
+
logLvl: string
|
|
141
|
+
): transports.FileTransportInstance {
|
|
142
|
+
const opt: transports.FileTransportOptions = {
|
|
159
143
|
filename: args.logFile,
|
|
160
144
|
maxFiles: 1,
|
|
161
145
|
level: logLvl,
|
|
@@ -168,13 +152,10 @@ function createFileTransport(args, logLvl) {
|
|
|
168
152
|
return new transports.File(opt);
|
|
169
153
|
}
|
|
170
154
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
* @returns {transports.HttpTransportInstance}
|
|
176
|
-
*/
|
|
177
|
-
function createHttpTransport(args, logLvl) {
|
|
155
|
+
function createHttpTransport(
|
|
156
|
+
args: ParsedArgs,
|
|
157
|
+
logLvl: string
|
|
158
|
+
): transports.HttpTransportInstance {
|
|
178
159
|
let host = '127.0.0.1';
|
|
179
160
|
let port = 9003;
|
|
180
161
|
|
|
@@ -184,32 +165,20 @@ function createHttpTransport(args, logLvl) {
|
|
|
184
165
|
port = parseInt(hostAndPort[1], 10);
|
|
185
166
|
}
|
|
186
167
|
|
|
187
|
-
|
|
188
|
-
const opt = {
|
|
189
|
-
name: 'http',
|
|
168
|
+
const opt: transports.HttpTransportOptions = {
|
|
190
169
|
host,
|
|
191
170
|
port,
|
|
192
171
|
path: '/',
|
|
193
172
|
level: logLvl,
|
|
194
|
-
format: format.combine(
|
|
195
|
-
stripColorFormat,
|
|
196
|
-
formatLog(args, false),
|
|
197
|
-
),
|
|
173
|
+
format: format.combine(stripColorFormat, formatLog(args, false)),
|
|
198
174
|
};
|
|
199
175
|
return new transports.Http(opt);
|
|
200
176
|
}
|
|
201
177
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
*/
|
|
207
|
-
async function createTransports(args) {
|
|
208
|
-
const transports = [];
|
|
209
|
-
/** @type {string} */
|
|
210
|
-
let consoleLogLevel;
|
|
211
|
-
/** @type {string} */
|
|
212
|
-
let fileLogLevel;
|
|
178
|
+
async function createTransports(args: ParsedArgs): Promise<Transport[]> {
|
|
179
|
+
const transportList: Transport[] = [];
|
|
180
|
+
let consoleLogLevel: string;
|
|
181
|
+
let fileLogLevel: string;
|
|
213
182
|
|
|
214
183
|
// Server args are normalized in main so we only see dest form (`loglevel`).
|
|
215
184
|
// Fall back to schema default so Winston never sees undefined.
|
|
@@ -223,7 +192,7 @@ async function createTransports(args) {
|
|
|
223
192
|
consoleLogLevel = fileLogLevel = rawLogLevel;
|
|
224
193
|
}
|
|
225
194
|
|
|
226
|
-
|
|
195
|
+
transportList.push(createConsoleTransport(args, consoleLogLevel));
|
|
227
196
|
|
|
228
197
|
if (args.logFile) {
|
|
229
198
|
try {
|
|
@@ -234,36 +203,34 @@ async function createTransports(args) {
|
|
|
234
203
|
await fs.unlink(args.logFile);
|
|
235
204
|
}
|
|
236
205
|
|
|
237
|
-
|
|
206
|
+
transportList.push(createFileTransport(args, fileLogLevel));
|
|
238
207
|
} catch (e) {
|
|
208
|
+
const err = e as Error;
|
|
239
209
|
// eslint-disable-next-line no-console
|
|
240
210
|
console.log(
|
|
241
|
-
`Tried to attach logging to file '${args.logFile}' but an error ` +
|
|
211
|
+
`Tried to attach logging to file '${args.logFile}' but an error ` +
|
|
212
|
+
`occurred: ${err.message}`
|
|
242
213
|
);
|
|
243
214
|
}
|
|
244
215
|
}
|
|
245
216
|
|
|
246
217
|
if (args.webhook) {
|
|
247
218
|
try {
|
|
248
|
-
|
|
219
|
+
transportList.push(createHttpTransport(args, fileLogLevel));
|
|
249
220
|
} catch (e) {
|
|
221
|
+
const err = e as Error;
|
|
250
222
|
// eslint-disable-next-line no-console
|
|
251
223
|
console.log(
|
|
252
224
|
`Tried to attach logging to Http at ${args.webhook} but ` +
|
|
253
|
-
`an error occurred: ${
|
|
225
|
+
`an error occurred: ${err.message}`
|
|
254
226
|
);
|
|
255
227
|
}
|
|
256
228
|
}
|
|
257
229
|
|
|
258
|
-
return
|
|
230
|
+
return transportList;
|
|
259
231
|
}
|
|
260
232
|
|
|
261
|
-
|
|
262
|
-
*
|
|
263
|
-
* @param {string} text
|
|
264
|
-
* @returns {string}
|
|
265
|
-
*/
|
|
266
|
-
function toDecoratedPrefix(text) {
|
|
233
|
+
function toDecoratedPrefix(text: string): string {
|
|
267
234
|
return `[${text}]`;
|
|
268
235
|
}
|
|
269
236
|
|
|
@@ -271,27 +238,19 @@ function toDecoratedPrefix(text) {
|
|
|
271
238
|
* Selects the color of the text in terminal from the MIN_COLOR..MAX_COLOR
|
|
272
239
|
* range. We use adler32 hashing to ensure that equal prefixes would always have
|
|
273
240
|
* same colors.
|
|
274
|
-
*
|
|
275
|
-
* @param {string} text Initial text
|
|
276
|
-
* @returns {string} Colorized text (with pseudocode cchars added)
|
|
277
241
|
*/
|
|
278
|
-
function colorizePrefix(text) {
|
|
242
|
+
function colorizePrefix(text: string): string {
|
|
279
243
|
let colorIndex = COLORS_CACHE.get(text);
|
|
280
244
|
if (!colorIndex) {
|
|
281
245
|
const hash = adler32(text);
|
|
282
|
-
colorIndex = MIN_COLOR + hash % (MAX_COLOR - MIN_COLOR);
|
|
246
|
+
colorIndex = MIN_COLOR + (hash % (MAX_COLOR - MIN_COLOR));
|
|
283
247
|
COLORS_CACHE.set(text, colorIndex);
|
|
284
248
|
}
|
|
285
249
|
return `\x1b[38;5;${colorIndex}m${text}\x1b[0m`;
|
|
286
250
|
}
|
|
287
251
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
* @param {boolean} targetConsole
|
|
291
|
-
* @returns {import('logform').Format}
|
|
292
|
-
*/
|
|
293
|
-
function formatLog(args, targetConsole) {
|
|
294
|
-
if (['json', 'pretty_json'].includes(args.logFormat)) {
|
|
252
|
+
function formatLog(args: ParsedArgs, targetConsole: boolean): Logform.Format {
|
|
253
|
+
if (['json', 'pretty_json'].includes(args.logFormat ?? '')) {
|
|
295
254
|
return format.combine(
|
|
296
255
|
format((info) => {
|
|
297
256
|
const infoCopy = {...info};
|
|
@@ -311,7 +270,7 @@ function formatLog(args, targetConsole) {
|
|
|
311
270
|
);
|
|
312
271
|
}
|
|
313
272
|
|
|
314
|
-
return format.printf((info) => {
|
|
273
|
+
return format.printf((info: {timestamp?: string; message?: unknown}) => {
|
|
315
274
|
if (targetConsole) {
|
|
316
275
|
return `${args.logTimestamp ? `${info.timestamp} - ` : ''}${info.message}`;
|
|
317
276
|
}
|
|
@@ -319,13 +278,8 @@ function formatLog(args, targetConsole) {
|
|
|
319
278
|
});
|
|
320
279
|
}
|
|
321
280
|
|
|
322
|
-
/**
|
|
323
|
-
|
|
324
|
-
*
|
|
325
|
-
* @param {ParsedArgs} args
|
|
326
|
-
* @returns {import('logform').Format}
|
|
327
|
-
*/
|
|
328
|
-
function formatTimestamp(args) {
|
|
281
|
+
/** Add the timestamp in the correct format to the log info object. */
|
|
282
|
+
function formatTimestamp(args: ParsedArgs): Logform.Format {
|
|
329
283
|
return format.timestamp({
|
|
330
284
|
format() {
|
|
331
285
|
let date = new Date();
|
|
@@ -338,31 +292,31 @@ function formatTimestamp(args) {
|
|
|
338
292
|
});
|
|
339
293
|
}
|
|
340
294
|
|
|
295
|
+
// set the custom colors
|
|
296
|
+
const colorizeFormat = format.colorize({
|
|
297
|
+
colors: COLORS_MAP,
|
|
298
|
+
});
|
|
299
|
+
|
|
341
300
|
/**
|
|
342
|
-
* Strips color control codes from
|
|
301
|
+
* Strips ANSI color control codes from a string.
|
|
343
302
|
*
|
|
344
|
-
* @param
|
|
345
|
-
* @returns
|
|
303
|
+
* @param text - String that may contain escape codes (e.g. `\u001b[31m`).
|
|
304
|
+
* @returns The string with all color codes removed.
|
|
346
305
|
*/
|
|
347
|
-
export function stripColorCodes(text) {
|
|
306
|
+
export function stripColorCodes(text: string): string {
|
|
348
307
|
return text.replace(COLOR_CODE_PATTERN, '');
|
|
349
308
|
}
|
|
350
309
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
310
|
+
// Strip the color marking within messages (depends on stripColorCodes)
|
|
311
|
+
const stripColorFormat = format(function stripColor(info: {level: string; message: unknown; [key: string]: unknown}) {
|
|
312
|
+
return {
|
|
313
|
+
...info,
|
|
314
|
+
level: stripColorCodes(info.level),
|
|
315
|
+
message: _.isString(info.message) ? stripColorCodes(info.message) : info.message,
|
|
316
|
+
};
|
|
317
|
+
})();
|
|
318
|
+
|
|
319
|
+
function isLogColorEnabled(args: ParsedArgs): boolean {
|
|
357
320
|
return !args.logNoColors && args.logFormat === 'text';
|
|
358
321
|
}
|
|
359
|
-
|
|
360
|
-
export default init;
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* @typedef {import('appium/types').ParsedArgs} ParsedArgs
|
|
364
|
-
* @typedef {import('@appium/logger').MessageObject} MessageObject
|
|
365
|
-
* @typedef {transports.ConsoleTransportOptions & {name: string}} AppiumConsoleTransportOptions
|
|
366
|
-
* @typedef {transports.FileTransportOptions & {name: string}} AppiumFileTransportOptions
|
|
367
|
-
* @typedef {transports.HttpTransportOptions & {name: string}} AppiumHttpTransportOptions
|
|
368
|
-
*/
|
|
322
|
+
// #endregion
|
package/lib/main.js
CHANGED
|
@@ -443,7 +443,7 @@ async function main(args) {
|
|
|
443
443
|
}
|
|
444
444
|
appiumDriver.server = server;
|
|
445
445
|
try {
|
|
446
|
-
// configure as node on
|
|
446
|
+
// configure as node on Selenium Grid 3 hub, if necessary
|
|
447
447
|
// falsy values should not cause this to run
|
|
448
448
|
if (parsedArgs.nodeconfig) {
|
|
449
449
|
await registerNode(
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import type {ExtensionType} from '@appium/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The original ID of the Appium config schema.
|
|
6
|
+
* We use this in the CLI to convert it to `argparse` options.
|
|
7
|
+
*/
|
|
8
|
+
export const APPIUM_CONFIG_SCHEMA_ID = 'appium.json';
|
|
9
|
+
/**
|
|
10
|
+
* The schema prop containing server-related options. Everything in here
|
|
11
|
+
* is "native" to Appium.
|
|
12
|
+
*/
|
|
13
|
+
export const SERVER_PROP_NAME = 'server';
|
|
14
|
+
const SCHEMA_ID_REGEXP = /^(?<extType>.+?)-(?<normalizedExtName>.+)\.json$/;
|
|
15
|
+
const PROPERTIES = 'properties';
|
|
16
|
+
|
|
17
|
+
export interface ArgSpecOptions<D = unknown> {
|
|
18
|
+
extName?: string;
|
|
19
|
+
extType?: ExtensionType;
|
|
20
|
+
dest?: string;
|
|
21
|
+
defaultValue?: D;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* An `ArgSpec` is a class representing metadata about an argument (or config
|
|
26
|
+
* option) used for cross-referencing.
|
|
27
|
+
*
|
|
28
|
+
* This class has no instance methods beyond stringification and is effectively
|
|
29
|
+
* a read-only struct.
|
|
30
|
+
*/
|
|
31
|
+
export class ArgSpec<D = unknown> {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly extType?: ExtensionType;
|
|
34
|
+
readonly extName?: string;
|
|
35
|
+
readonly ref: string;
|
|
36
|
+
readonly arg: string;
|
|
37
|
+
readonly dest: string;
|
|
38
|
+
readonly rawDest: string;
|
|
39
|
+
readonly defaultValue?: D;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Builds computed fields and assigns them to the instance.
|
|
43
|
+
* Use {@link ArgSpec.create} instead of `new ArgSpec()`.
|
|
44
|
+
*/
|
|
45
|
+
constructor(name: string, {extType, extName, dest, defaultValue}: ArgSpecOptions<D> = {}) {
|
|
46
|
+
const arg = ArgSpec.toArg(name, extType, extName);
|
|
47
|
+
const ref = ArgSpec.toSchemaRef(name, extType, extName);
|
|
48
|
+
const rawDest = _.camelCase(dest ?? name);
|
|
49
|
+
const destKeypath = extType && extName ? [extType, extName, rawDest].join('.') : rawDest;
|
|
50
|
+
|
|
51
|
+
this.defaultValue = defaultValue;
|
|
52
|
+
this.name = name;
|
|
53
|
+
this.extType = extType;
|
|
54
|
+
this.extName = extName;
|
|
55
|
+
this.arg = arg;
|
|
56
|
+
this.dest = destKeypath;
|
|
57
|
+
this.ref = ref;
|
|
58
|
+
this.rawDest = rawDest;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Return the schema ID (`$id`) for the argument given the parameters.
|
|
63
|
+
*/
|
|
64
|
+
static toSchemaRef(name: string, extType?: ExtensionType, extName?: string): string {
|
|
65
|
+
const baseRef = ArgSpec.toSchemaBaseRef(extType, extName);
|
|
66
|
+
if (extType && extName) {
|
|
67
|
+
return [`${baseRef}#`, PROPERTIES, name].join('/');
|
|
68
|
+
}
|
|
69
|
+
return [`${baseRef}#`, PROPERTIES, SERVER_PROP_NAME, PROPERTIES, name].join('/');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Return the root schema ID for an extension or Appium base schema.
|
|
74
|
+
*/
|
|
75
|
+
static toSchemaBaseRef(extType?: ExtensionType, extName?: string): string {
|
|
76
|
+
if (extType && extName) {
|
|
77
|
+
return `${extType}-${ArgSpec.toNormalizedExtName(extName)}.json`;
|
|
78
|
+
}
|
|
79
|
+
return APPIUM_CONFIG_SCHEMA_ID;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Return the unique CLI argument key for the argument.
|
|
84
|
+
*/
|
|
85
|
+
static toArg(name: string, extType?: ExtensionType, extName?: string): string {
|
|
86
|
+
const properName = _.kebabCase(name.replace(/^--?/, ''));
|
|
87
|
+
if (extType && extName) {
|
|
88
|
+
return [extType, _.kebabCase(extName), properName].join('-');
|
|
89
|
+
}
|
|
90
|
+
return properName;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Normalizes a raw extension name (not including type).
|
|
95
|
+
*/
|
|
96
|
+
static toNormalizedExtName(extName: string): string {
|
|
97
|
+
return _.kebabCase(extName);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Parse root schema ID (`<extType>-<normalizedExtName>.json`) to extension info.
|
|
102
|
+
*/
|
|
103
|
+
static extensionInfoFromRootSchemaId(
|
|
104
|
+
schemaId: string
|
|
105
|
+
): {extType?: ExtensionType; normalizedExtName?: string} {
|
|
106
|
+
const matches = schemaId.match(SCHEMA_ID_REGEXP);
|
|
107
|
+
if (matches?.groups) {
|
|
108
|
+
const {extType, normalizedExtName} = matches.groups as {
|
|
109
|
+
extType: ExtensionType;
|
|
110
|
+
normalizedExtName: string;
|
|
111
|
+
};
|
|
112
|
+
return {extType, normalizedExtName};
|
|
113
|
+
}
|
|
114
|
+
return {};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Creates a frozen `ArgSpec`.
|
|
119
|
+
*/
|
|
120
|
+
static create<D = unknown>(name: string, opts?: ArgSpecOptions<D>): Readonly<ArgSpec<D>> {
|
|
121
|
+
return Object.freeze(new ArgSpec(name, opts));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
toString(): string {
|
|
125
|
+
let str = `[ArgSpec] ${this.name} (${this.ref})`;
|
|
126
|
+
if (this.extType && this.extName) {
|
|
127
|
+
str += ` (ext: ${this.extType}/${this.extName})`;
|
|
128
|
+
}
|
|
129
|
+
return str;
|
|
130
|
+
}
|
|
131
|
+
}
|