-
-
Notifications
You must be signed in to change notification settings - Fork 6k
/
guards.ts
325 lines (297 loc) · 10.4 KB
/
guards.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/**
* A bunch of type guards. Because here is a place to put all of them.
* @module
*/
import {
DeclarationReflection,
LiteralType,
ProjectReflection,
ReferenceType,
Reflection,
ReflectionKind,
ReflectionType,
SignatureReflection,
TupleType,
TypeOperatorType,
} from 'typedoc';
import {
NAME_BUILTIN_COMMAND_MODULE,
NAME_COMMAND,
NAME_EXECUTE_METHOD_MAP,
NAME_EXTERNAL_DRIVER,
NAME_METHOD_MAP,
NAME_NEW_METHOD_MAP,
NAME_PARAMS,
NAME_PAYLOAD_PARAMS,
NAME_TYPES_MODULE,
} from './converter';
import {
AppiumTypesReflection,
AsyncMethodDeclarationReflection,
BaseDriverDeclarationReflection,
CallSignatureReflection,
CallSignatureReflectionWithArity,
ClassDeclarationReflection,
CommandPropDeclarationReflection,
DeclarationReflectionWithReflectedType,
ExecMethodDeclarationReflection,
ExecMethodDefParamsPropDeclarationReflection,
ExternalDriverDeclarationReflection,
HTTPMethodDeclarationReflection,
InterfaceDeclarationReflection,
MethodDefParamNamesDeclarationReflection,
MethodDefParamsPropDeclarationReflection,
MethodMapDeclarationReflection,
PropDeclarationReflection,
} from './converter/types';
import {AllowedHttpMethod, ExecMethodData, ParentReflection} from './model';
/**
* Set of HTTP methods allowed by WebDriver; see {@linkcode AllowedHttpMethod}
*/
const ALLOWED_HTTP_METHODS: Readonly<Set<AllowedHttpMethod>> = new Set([
'GET',
'POST',
'DELETE',
] as const);
/**
* Type guard for {@linkcode DeclarationReflection}
* @param value any value
*/
export function isDeclarationReflection(value: any): value is DeclarationReflection {
return value instanceof DeclarationReflection;
}
export function isParentReflection(value: any): value is ParentReflection {
return value instanceof DeclarationReflection || value instanceof ProjectReflection;
}
export function isAppiumTypesReflection(value: any): value is AppiumTypesReflection {
return isParentReflection(value) && value.name === NAME_TYPES_MODULE;
}
/**
* Type guard for {@linkcode ReflectionType}
* @param value any value
*/
export function isReflectionType(value: any): value is ReflectionType {
return value instanceof ReflectionType;
}
/**
* Type guard for {@linkcode TypeOperatorType}
* @param value any value
*/
export function isTypeOperatorType(value: any): value is TypeOperatorType {
return value instanceof TypeOperatorType;
}
/**
* Type guard for {@linkcode LiteralType}
* @param value any value
*/
export function isLiteralType(value: any): value is LiteralType {
return value instanceof LiteralType;
}
/**
* Type guard for {@linkcode TupleType}
* @param value any value
*/
export function isTupleType(value: any): value is TupleType {
return value instanceof TupleType;
}
/**
* Type guard for a {@linkcode DeclarationReflectionWithReflectedType} corresponding to
* the `executeMethodMap` static property of an extension class.
* @param value any
*/
export function isExecMethodDefReflection(value: any): value is ExecMethodDeclarationReflection {
return (
isReflectionWithReflectedType(value) &&
value.name === NAME_EXECUTE_METHOD_MAP &&
value.flags.isStatic
);
}
/**
* Type guard for a {@linkcode MethodDefParamNamesDeclarationReflection} corresponding to a list of required or optional parameters within a command or execute method definition.
* @param value any value
*/
export function isMethodDefParamNamesDeclarationReflection(
value: any
): value is MethodDefParamNamesDeclarationReflection {
return (
isDeclarationReflection(value) &&
value.kindOf(ReflectionKind.Property) &&
isTypeOperatorType(value.type) &&
isTupleType(value.type.target) &&
value.type.target.elements.every(isLiteralType)
);
}
/**
* Type guard for a {@linkcode PropDeclarationReflection} corresponding to some property of a constant object.
* @param value any value
*/
export function isRoutePropDeclarationReflection(value: any): value is PropDeclarationReflection {
return isReflectionWithReflectedType(value) && isPropertyKind(value);
}
/**
* Type guard for a {@linkcode BaseDriverDeclarationReflection} corresponding to the `@appium/base-driver` module (_not_ the class).
* @param value any value
*/
export function isBaseDriverDeclarationReflection(
value: any
): value is BaseDriverDeclarationReflection {
return (
isParentReflection(value) &&
value.name === NAME_BUILTIN_COMMAND_MODULE &&
value.kindOf(ReflectionKind.Module | ReflectionKind.Project)
);
}
/**
* Type guard for a property of an object (a {@linkcode Reflection} having kind {@linkcode ReflectionKind.Property}).
* @param value any value
*/
export function isPropertyKind(value: any) {
return value instanceof Reflection && value.kindOf(ReflectionKind.Property);
}
/**
* Type guard for a {@linkcode MethodMapDeclarationReflection} corresponding to the `newMethodMap` static property of an extension class _or_ the `METHOD_MAP` export within `@appium/base-driver`.
*
* Note that the type does not care about the `isStatic` flag, but this guard does.
* @param value any value
*/
export function isMethodMapDeclarationReflection(
value: any
): value is MethodMapDeclarationReflection {
return (
isReflectionWithReflectedType(value) &&
((value.name === NAME_NEW_METHOD_MAP && value.flags.isStatic) || value.name === NAME_METHOD_MAP)
);
}
/**
* Type guard for a {@linkcode DeclarationReflectionWithReflectedType} a declaration reflection having a reflection type.
*
* I don't know what that means, exactly, but there it is.
* @param value any value
*/
export function isReflectionWithReflectedType(
value: any
): value is DeclarationReflectionWithReflectedType {
return isDeclarationReflection(value) && isReflectionType(value.type);
}
export function isHTTPMethodDeclarationReflection(
value: any
): value is HTTPMethodDeclarationReflection {
return (
isReflectionWithReflectedType(value) && isPropertyKind(value) && isAllowedHTTPMethod(value.name)
);
}
/**
* Type guard for an {@linkcode AllowedHttpMethod}
*
* @param value any value
*/
export function isAllowedHTTPMethod(value: any): value is AllowedHttpMethod {
return ALLOWED_HTTP_METHODS.has(value);
}
/**
* Type guard for a {@linkcode CommandPropDeclarationReflection} corresponding to the `command` property of a {@linkcode @appium/types#MethodDef} object contained within a {@linkcode @appium/types#MethodMap}.
* @param value any value
*/
export function isCommandPropDeclarationReflection(
value: any
): value is CommandPropDeclarationReflection {
return isDeclarationReflection(value) && isLiteralType(value.type) && value.name === NAME_COMMAND;
}
/**
* Type guard for a {@linkcode ExecMethodData} derived from a {@linkcode @appium/types#ExecuteMethodMap} object.
* @param value any value
*/
export function isExecMethodData(value: any): value is ExecMethodData {
return value && typeof value === 'object' && value.script;
}
/**
* Type guard for a {@linkcode MethodDefParamsPropDeclarationReflection} corresponding to the `params` prop of a `MethodDef`
* @param value any value
*/
export function isMethodDefParamsPropDeclarationReflection(
value: any
): value is MethodDefParamsPropDeclarationReflection {
return isReflectionWithReflectedType(value) && value.name === NAME_PARAMS;
}
/**
* Type guard for a {@linkcode ExecMethodDefParamsPropDeclarationReflection} corresponding to the `payloadParams` prop of an `ExecuteMethodDef`.
* @param value any value
*/
export function isExecMethodDefParamsPropDeclarationReflection(
value: any
): value is ExecMethodDefParamsPropDeclarationReflection {
return isReflectionWithReflectedType(value) && value.name === NAME_PAYLOAD_PARAMS;
}
/**
* Type guard for a {@linkcode InterfaceDeclarationReflection} corresponding to a TS interface.
* @param value any value
*/
export function isInterfaceDeclarationReflection(
value: any
): value is InterfaceDeclarationReflection {
return isDeclarationReflection(value) && value.kindOf(ReflectionKind.Interface);
}
/**
* Type guard for a {@linkcode ExternalDriverDeclarationReflection} which is the `ExternalDriver`
* interface defined in `@appium/types`.
* @param value any value
*/
export function isExternalDriverDeclarationReflection(
value: any
): value is ExternalDriverDeclarationReflection {
return isInterfaceDeclarationReflection(value) && value.name === NAME_EXTERNAL_DRIVER;
}
/**
* Type guard for an {@linkcode AsyncMethodDeclarationReflection}, which is _potentially_ a method
* for a command. Not all async methods in driver classes are mapped to commands, of course!
*
* A command method cannot be static, but it can be an actual (async) function or a reference to an
* (async) function; just depends how the code is written. Either way, this asserts there's a
* call signature returning a `Promise`.
* @param value
*/
export function isAsyncMethodDeclarationReflection(
value: any
): value is AsyncMethodDeclarationReflection {
if (
!isDeclarationReflection(value) ||
!value.kindOf(ReflectionKind.Method | ReflectionKind.Property) ||
value.flags.isStatic
) {
return false;
}
const signatures =
(value.type instanceof ReflectionType ? value.type.declaration.signatures : value.signatures) ??
[];
return Boolean(
signatures.find((sig) => sig.type instanceof ReferenceType && sig.type.name === 'Promise')
);
}
/**
* Type guard for a {@linkcode ClassDeclarationReflection} which is just a {@linkcode DeclarationReflection}
* with a `kind` of {@linkcode ReflectionKind.Class}.
* @param value any value
*/
export function isClassDeclarationReflection(value: any): value is ClassDeclarationReflection {
return Boolean(isDeclarationReflection(value) && value.kindOf(ReflectionKind.Class));
}
/**
* Type guard for a {@linkcode CallSignatureReflection} which is just a
* {@linkcode SignatureReflection} with kind {@linkcode ReflectionKind.CallSignature}.
* @param value any value
*/
export function isCallSignatureReflection(value: any): value is CallSignatureReflection {
return Boolean(
value instanceof SignatureReflection && value.kindOf(ReflectionKind.CallSignature)
);
}
/**
* Type guard for a {@linkcode CallSignatureReflectionWithArity}, which is a
* {@linkcode CallSignatureReflection} with an arity greater than zero.
* @param value any value
*/
export function isCallSignatureReflectionWithArity(
value: any
): value is CallSignatureReflectionWithArity {
return Boolean(isCallSignatureReflection(value) && value.parameters?.length);
}