/
ChainNodeParser.ts
49 lines (42 loc) · 1.8 KB
/
ChainNodeParser.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
import ts from "typescript";
import { UnknownNodeError } from "./Error/UnknownNodeError";
import { MutableParser } from "./MutableParser";
import { Context } from "./NodeParser";
import { SubNodeParser } from "./SubNodeParser";
import { BaseType } from "./Type/BaseType";
import { ReferenceType } from "./Type/ReferenceType";
export class ChainNodeParser implements SubNodeParser, MutableParser {
protected readonly typeCaches = new WeakMap<ts.Node, Map<string, BaseType>>();
public constructor(protected typeChecker: ts.TypeChecker, protected nodeParsers: SubNodeParser[]) {}
public addNodeParser(nodeParser: SubNodeParser): this {
this.nodeParsers.push(nodeParser);
return this;
}
public supportsNode(node: ts.Node): boolean {
return this.nodeParsers.some((nodeParser) => nodeParser.supportsNode(node));
}
public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType {
let typeCache = this.typeCaches.get(node);
if (typeCache == null) {
typeCache = new Map<string, BaseType>();
this.typeCaches.set(node, typeCache);
}
const contextCacheKey = context.getCacheKey();
let type = typeCache.get(contextCacheKey);
if (!type) {
type = this.getNodeParser(node, context).createType(node, context, reference);
if (!(type instanceof ReferenceType)) {
typeCache.set(contextCacheKey, type);
}
}
return type;
}
protected getNodeParser(node: ts.Node, context: Context): SubNodeParser {
for (const nodeParser of this.nodeParsers) {
if (nodeParser.supportsNode(node)) {
return nodeParser;
}
}
throw new UnknownNodeError(node, context.getReference());
}
}