/
misc.ts
129 lines (116 loc) · 3.17 KB
/
misc.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
/**
* @fileoverview Really small utility functions that didn't deserve their own files
*/
import {
AST_NODE_TYPES,
TSESLint,
TSESTree,
} from '@typescript-eslint/experimental-utils';
/**
* Check if the context file name is *.d.ts or *.d.tsx
*/
export function isDefinitionFile(fileName: string) {
return /\.d\.tsx?$/i.test(fileName || '');
}
/**
* Upper cases the first character or the string
*/
export function upperCaseFirst(str: string) {
return str[0].toUpperCase() + str.slice(1);
}
type InferOptionsTypeFromRuleNever<T> = T extends TSESLint.RuleModule<
never,
infer TOptions
>
? TOptions
: unknown;
/**
* Uses type inference to fetch the TOptions type from the given RuleModule
*/
export type InferOptionsTypeFromRule<T> = T extends TSESLint.RuleModule<
any,
infer TOptions
>
? TOptions
: InferOptionsTypeFromRuleNever<T>;
/**
* Uses type inference to fetch the TMessageIds type from the given RuleModule
*/
export type InferMessageIdsTypeFromRule<T> = T extends TSESLint.RuleModule<
infer TMessageIds,
any
>
? TMessageIds
: unknown;
/**
* Gets a string name representation of the given PropertyName node
*/
export function getNameFromPropertyName(
propertyName: TSESTree.PropertyName,
): string {
if (propertyName.type === AST_NODE_TYPES.Identifier) {
return propertyName.name;
}
return `${propertyName.value}`;
}
/** Return true if both parameters are equal. */
export type Equal<T> = (a: T, b: T) => boolean;
export function arraysAreEqual<T>(
a: T[] | undefined,
b: T[] | undefined,
eq: (a: T, b: T) => boolean,
): boolean {
return (
a === b ||
(a !== undefined &&
b !== undefined &&
a.length === b.length &&
a.every((x, idx) => eq(x, b[idx])))
);
}
/** Returns the first non-`undefined` result. */
export function findFirstResult<T, U>(
inputs: T[],
getResult: (t: T) => U | undefined,
): U | undefined {
for (const element of inputs) {
const result = getResult(element);
if (result !== undefined) {
return result;
}
}
return undefined;
}
/**
* Gets a string name representation of the name of the given MethodDefinition
* or ClassProperty node, with handling for computed property names.
*/
export function getNameFromClassMember(
methodDefinition: TSESTree.MethodDefinition | TSESTree.ClassProperty,
sourceCode: TSESLint.SourceCode,
): string {
if (keyCanBeReadAsPropertyName(methodDefinition.key)) {
return getNameFromPropertyName(methodDefinition.key);
}
return sourceCode.text.slice(...methodDefinition.key.range);
}
/**
* This covers both actual property names, as well as computed properties that are either
* an identifier or a literal at the top level.
*/
function keyCanBeReadAsPropertyName(
node: TSESTree.Expression,
): node is TSESTree.PropertyName {
return (
node.type === AST_NODE_TYPES.Literal ||
node.type === AST_NODE_TYPES.Identifier
);
}
export type ExcludeKeys<
TObj extends Record<string, any>,
TKeys extends keyof TObj
> = { [k in Exclude<keyof TObj, TKeys>]: TObj[k] };
export type RequireKeys<
TObj extends Record<string, any>,
TKeys extends keyof TObj
> = ExcludeKeys<TObj, TKeys> & { [k in TKeys]-?: Exclude<TObj[k], undefined> };