ts-json-schema-generator
Version:
Generate JSON schema from your Typescript sources
63 lines (52 loc) • 2.11 kB
text/typescript
import type ts from "typescript";
import { UnhandledError, UnknownNodeError } from "./Error/Errors.js";
import type { MutableParser } from "./MutableParser.js";
import type { Context } from "./NodeParser.js";
import type { SubNodeParser } from "./SubNodeParser.js";
import type { BaseType } from "./Type/BaseType.js";
import { ReferenceType } from "./Type/ReferenceType.js";
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) {
try {
type = this.getNodeParser(node).createType(node, context, reference);
} catch (error) {
throw UnhandledError.from("Unhandled error while creating Base Type.", node, error);
}
if (!(type instanceof ReferenceType)) {
typeCache.set(contextCacheKey, type);
}
}
if (!type) {
throw new UnknownNodeError(node);
}
return type;
}
protected getNodeParser(node: ts.Node): SubNodeParser {
for (const nodeParser of this.nodeParsers) {
if (nodeParser.supportsNode(node)) {
return nodeParser;
}
}
throw new UnknownNodeError(node);
}
}