-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
/
removeTypeDuplicates.ts
94 lines (78 loc) 路 2.12 KB
/
removeTypeDuplicates.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
import {
isIdentifier,
isTSAnyKeyword,
isTSTypeReference,
isTSUnionType,
isTSBaseType,
} from "../../validators/generated";
import type * as t from "../..";
function getQualifiedName(node: t.TSTypeReference["typeName"]) {
return isIdentifier(node)
? node.name
: `${node.right.name}.${getQualifiedName(node.left)}`;
}
/**
* Dedupe type annotations.
*/
export default function removeTypeDuplicates(
nodes: Array<t.TSType>,
): Array<t.TSType> {
const generics = new Map<string, t.TSTypeReference>();
const bases = new Map<t.TSBaseType["type"], t.TSBaseType>();
// store union type groups to circular references
const typeGroups = new Set<t.TSType[]>();
const types = [];
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (!node) continue;
// detect duplicates
if (types.indexOf(node) >= 0) {
continue;
}
// this type matches anything
if (isTSAnyKeyword(node)) {
return [node];
}
// Analogue of FlowBaseAnnotation
if (isTSBaseType(node)) {
bases.set(node.type, node);
continue;
}
if (isTSUnionType(node)) {
if (!typeGroups.has(node.types)) {
nodes.push(...node.types);
typeGroups.add(node.types);
}
continue;
}
// todo: support merging tuples: number[]
if (isTSTypeReference(node) && node.typeParameters) {
const name = getQualifiedName(node.typeName);
if (generics.has(name)) {
let existing: t.TypeScript = generics.get(name);
if (existing.typeParameters) {
if (node.typeParameters) {
existing.typeParameters.params = removeTypeDuplicates(
existing.typeParameters.params.concat(node.typeParameters.params),
);
}
} else {
existing = node.typeParameters;
}
} else {
generics.set(name, node);
}
continue;
}
types.push(node);
}
// add back in bases
for (const [, baseType] of bases) {
types.push(baseType);
}
// add back in generics
for (const [, genericName] of generics) {
types.push(genericName);
}
return types;
}