ts-json-schema-generator
Version:
Generate JSON schema from your Typescript sources
102 lines (83 loc) • 2.61 kB
text/typescript
import json5 from "json5";
import ts from "typescript";
import { AnnotationsReader } from "../AnnotationsReader";
import { Annotations } from "../Type/AnnotatedType";
import { symbolAtNode } from "../Utils/symbolAtNode";
export class BasicAnnotationsReader implements AnnotationsReader {
private static textTags = new Set<string>([
"title",
"description",
"format",
"pattern",
// New since draft-07:
"$comment",
"contentMediaType",
"contentEncoding",
]);
private static jsonTags = new Set<string>([
"minimum",
"exclusiveMinimum",
"maximum",
"exclusiveMaximum",
"multipleOf",
"minLength",
"maxLength",
"minProperties",
"maxProperties",
"minItems",
"maxItems",
"uniqueItems",
"propertyNames",
"contains",
"const",
"examples",
"default",
// New since draft-07:
"if",
"then",
"else",
"readOnly",
"writeOnly",
// New since draft 2019-09:
"deprecated",
]);
public constructor(private extraTags?: Set<string>) {}
public getAnnotations(node: ts.Node): Annotations | undefined {
const symbol = symbolAtNode(node);
if (!symbol) {
return undefined;
}
const jsDocTags: ts.JSDocTagInfo[] = symbol.getJsDocTags();
if (!jsDocTags || !jsDocTags.length) {
return undefined;
}
const annotations = jsDocTags.reduce((result: Annotations, jsDocTag) => {
const value = this.parseJsDocTag(jsDocTag);
if (value !== undefined) {
result[jsDocTag.name] = value;
}
return result;
}, {});
return Object.keys(annotations).length ? annotations : undefined;
}
private parseJsDocTag(jsDocTag: ts.JSDocTagInfo): any {
const text = (jsDocTag.text ?? []).map((part) => part.text).join("");
if (BasicAnnotationsReader.textTags.has(jsDocTag.name)) {
return text;
} else if (BasicAnnotationsReader.jsonTags.has(jsDocTag.name)) {
return this.parseJson(text);
} else if (this.extraTags?.has(jsDocTag.name)) {
return this.parseJson(text) ?? text;
} else {
// Unknown jsDoc tag.
return undefined;
}
}
private parseJson(value: string): any {
try {
return json5.parse(value);
} catch (e) {
return undefined;
}
}
}