-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
could-implement.ts
58 lines (55 loc) · 1.5 KB
/
could-implement.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
/**
* @license Use of this source code is governed by an MIT-style license that
* can be found in the LICENSE file at https://github.com/cartant/tsutils-etc
*/
import * as ts from "typescript";
export function couldImplement(
type: ts.Type,
name: string | RegExp,
qualified?: {
name: RegExp;
typeChecker: ts.TypeChecker;
}
): boolean {
const { symbol } = type;
if (symbol) {
const { valueDeclaration } = symbol;
if (valueDeclaration && ts.isClassDeclaration(valueDeclaration)) {
const { heritageClauses } = valueDeclaration;
if (heritageClauses) {
const implemented = heritageClauses.some(
({ token, types }) =>
token === ts.SyntaxKind.ImplementsKeyword &&
types.some((node) => isMatchingNode(node, name, qualified))
);
if (implemented) {
return true;
}
}
}
}
return false;
}
function isMatchingNode(
node: ts.ExpressionWithTypeArguments,
name: string | RegExp,
qualified?: {
name: RegExp;
typeChecker: ts.TypeChecker;
}
): boolean {
const { expression } = node;
if (qualified) {
const type = qualified.typeChecker.getTypeAtLocation(expression);
if (type) {
const qualifiedName = qualified.typeChecker.getFullyQualifiedName(
type.symbol
);
if (!qualified.name.test(qualifiedName)) {
return false;
}
}
}
const text = expression.getText();
return typeof name === "string" ? text === name : Boolean(text.match(name));
}