dilswer
Version:
Blazingly fast data validation library with TypeScript integration.
371 lines (369 loc) • 13.9 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
// src/ts-type-generator/to-ts-type.ts
import { BaseType } from "../data-types/base-type.mjs";
import { TypeKindNames } from "../data-types/type-kind-names.mjs";
import { EnumType } from "../data-types/types/enum.mjs";
import { EnumMemberType } from "../data-types/types/enum-member.mjs";
import { StringMatchingType } from "../data-types/types/string-matching.mjs";
import { TsFileScope } from "./file-scope.mjs";
import { NameGenerator } from "./name-generator.mjs";
import { TsArrayBuilder } from "./type-builders/array-builder.mjs";
import { TsDictBuilder } from "./type-builders/dictionary-builder.mjs";
import { TsEnumBuilder } from "./type-builders/enum-builder.mjs";
import { TsEnumMemberBuilder } from "./type-builders/enum-member-builder.mjs";
import { TsExternalTypeReference } from "./type-builders/external-type-reference.mjs";
import { TsInstanceOfBuilder } from "./type-builders/instanceof-builder.mjs";
import { TsIntersectionBuilder } from "./type-builders/intersection-builder.mjs";
import { TsLiteralBuilder } from "./type-builders/literal-builder.mjs";
import { TsRecordBuilder } from "./type-builders/record-builder.mjs";
import { TsSetBuilder } from "./type-builders/set-builder.mjs";
import { TsBooleanBuilder } from "./type-builders/simple-types/boolean-builder.mjs";
import { TsFunctionBuilder } from "./type-builders/simple-types/function-builder.mjs";
import { TsNullBuilder } from "./type-builders/simple-types/null-builder.mjs";
import { TsNumberBuilder } from "./type-builders/simple-types/number-builder.mjs";
import { TsStringBuilder } from "./type-builders/simple-types/string-builder.mjs";
import { TsSymbolBuilder } from "./type-builders/simple-types/symbol-builder.mjs";
import { TsUndefinedBuilder } from "./type-builders/simple-types/undefined-builder.mjs";
import { TsUnknownBuilder } from "./type-builders/simple-types/unknown-builder.mjs";
import { TsStringMatchingBuilder } from "./type-builders/string-matching-builder.mjs";
import { TsTupleBuilder } from "./type-builders/tuple-builder.mjs";
import { TsNamedReference } from "./type-builders/type-reference.mjs";
import { TsUnionBuilder } from "./type-builders/union-builder.mjs";
import { capitalize } from "../utilities/capitalize.mjs";
var ExternalTypeImportProxy = class {
constructor(ext) {
this.ext = ext;
__publicField(this, "_resolvedName");
__publicField(this, "_importName");
if (ext.valueImport == true) {
this._resolvedName = `typeof ${ext.typeName}`;
} else {
this._resolvedName = ext.typeName;
}
if (ext.originalName && ext.originalName !== ext.typeName) {
this._importName = `${ext.originalName} as ${ext.typeName}`;
} else {
this._importName = ext.typeName;
}
}
get path() {
return this.ext.path;
}
get typeName() {
return this._resolvedName;
}
get originalName() {
return this.ext.originalName;
}
get valueImport() {
return this.ext.valueImport;
}
get importName() {
return this._importName;
}
};
var DataTypeTsGenerator = class {
constructor(options) {
this.options = options;
__publicField(this, "fileScope");
__publicField(this, "getExternalTypeImport", function(_) {
return void 0;
});
/**
* Adds the given builder to the exports of the file scope if
* the builder meets the criteria, and returns the given
* builder or the Reference builder, if the builder was added
* to the exports.
*/
__publicField(this, "addFileExportAndResolveBuilder", function(builder) {
return builder;
});
__publicField(this, "circulars", /* @__PURE__ */ new Map());
this.fileScope = new TsFileScope(options);
if (options.getExternalTypeImport) {
this.getExternalTypeImport = (type) => {
const ext = options.getExternalTypeImport(type);
if (ext) {
return new ExternalTypeImportProxy(ext);
}
};
}
switch (options.mode) {
case "fully-expanded":
this.addFileExportAndResolveBuilder = function(builder) {
return this.fileScope.addTypeExport(builder);
};
break;
case "named-expanded":
this.addFileExportAndResolveBuilder = function(builder) {
if (builder.isTitled) {
return this.fileScope.addTypeExport(builder);
}
return builder;
};
break;
}
}
tsAddMetadataToBuilder(builder, type) {
const metadata = BaseType.getOriginalMetadata(type);
if (metadata.title) {
builder.setIsTitled(true);
builder.setName(metadata.title);
}
if (metadata.description) {
builder.setDescription(metadata.description);
}
return metadata;
}
parseFunctionType(type) {
const externalImport = this.getExternalTypeImport(type);
if (externalImport) {
this.fileScope.addTypeImport(externalImport);
const builder2 = new TsExternalTypeReference(externalImport.typeName);
this.tsAddMetadataToBuilder(builder2, type);
return this.addFileExportAndResolveBuilder(builder2);
}
const builder = new TsFunctionBuilder();
this.tsAddMetadataToBuilder(builder, type);
return builder;
}
parsePrimitive(type) {
let builder;
switch (type.simpleType) {
case "string":
case "stringinteger":
case "stringnumeral":
builder = new TsStringBuilder();
break;
case "number":
case "integer":
builder = new TsNumberBuilder();
break;
case "boolean":
builder = new TsBooleanBuilder();
break;
case "symbol":
builder = new TsSymbolBuilder();
break;
case "undefined":
builder = new TsUndefinedBuilder();
break;
case "unknown":
builder = new TsUnknownBuilder();
break;
case "null":
builder = new TsNullBuilder();
break;
case "function":
return this.parseFunctionType(type);
}
this.tsAddMetadataToBuilder(builder, type);
return builder;
}
parseArrayOf(type, children = []) {
const builder = new TsArrayBuilder();
this.tsAddMetadataToBuilder(builder, type);
builder.setTypes(children);
return this.addFileExportAndResolveBuilder(builder);
}
parseTuple(type, children = []) {
const builder = new TsTupleBuilder();
this.tsAddMetadataToBuilder(builder, type);
builder.setTypes(children);
return this.addFileExportAndResolveBuilder(builder);
}
parseRecordOf(type, children = []) {
const builder = new TsRecordBuilder();
this.tsAddMetadataToBuilder(builder, type);
for (let i = 0; i < (children == null ? void 0 : children.length); i++) {
const child = children[i];
builder.addProperty(child.propertyName, child.child, child.required);
}
return this.addFileExportAndResolveBuilder(builder);
}
parseDict(type, children = []) {
const builder = new TsDictBuilder();
this.tsAddMetadataToBuilder(builder, type);
builder.setTypes(children);
return this.addFileExportAndResolveBuilder(builder);
}
parseSetOf(type, children = []) {
const builder = new TsSetBuilder();
this.tsAddMetadataToBuilder(builder, type);
builder.setTypes(children);
return this.addFileExportAndResolveBuilder(builder);
}
parseOneOf(type, children) {
const builder = new TsUnionBuilder();
this.tsAddMetadataToBuilder(builder, type);
builder.setTypes(children);
return this.addFileExportAndResolveBuilder(builder);
}
parseAllOf(type, children) {
const builder = new TsIntersectionBuilder();
this.tsAddMetadataToBuilder(builder, type);
builder.setTypes(children);
return this.addFileExportAndResolveBuilder(builder);
}
parseLiteral(type) {
const builder = new TsLiteralBuilder(type.literal);
this.tsAddMetadataToBuilder(builder, type);
return builder;
}
parseEnum(type) {
const metadata = EnumType.getOriginalMetadata(type);
let typeName = metadata.enumName;
const externalImport = this.getExternalTypeImport(type);
if (externalImport) {
this.fileScope.addTypeImport(externalImport);
typeName = externalImport.typeName;
}
if (!typeName) {
throw new Error(
"Enum name is not defined. To be able to parse an Enum DataType `enumName` must be defined."
);
}
const builder = new TsEnumBuilder(typeName);
this.tsAddMetadataToBuilder(builder, type);
return builder;
}
parseEnumMember(type) {
var _a;
const metadata = EnumMemberType.getOriginalMetadata(type);
const externalImport = this.getExternalTypeImport(type);
const typeName = (_a = metadata.enumName) != null ? _a : externalImport == null ? void 0 : externalImport.typeName;
if (!typeName || !metadata.memberName) {
throw new Error(
"Enum name, or enum member name is not defined. To be able to parse an EnumMember DataType into Typescript definition `memberName` and `enumName` must be defined."
);
}
if (externalImport) {
this.fileScope.addTypeImport(externalImport);
}
const builder = new TsEnumMemberBuilder(typeName, metadata.memberName);
this.tsAddMetadataToBuilder(builder, type);
return builder;
}
parseInstanceOf(type) {
const constructor = type.instanceOf;
let typeName = constructor.name;
const externalImport = this.getExternalTypeImport(type);
if (externalImport) {
this.fileScope.addTypeImport(externalImport);
typeName = externalImport.typeName;
}
const builder = new TsInstanceOfBuilder(typeName);
this.tsAddMetadataToBuilder(builder, type);
if (builder.getName() === typeName) {
builder.setName(`Alias${capitalize(builder.getName())}`);
}
return this.addFileExportAndResolveBuilder(builder);
}
parseCustom(type) {
const externalImport = this.getExternalTypeImport(type);
if (externalImport) {
this.fileScope.addTypeImport(externalImport);
const builder2 = new TsExternalTypeReference(externalImport.typeName);
this.tsAddMetadataToBuilder(builder2, type);
return this.addFileExportAndResolveBuilder(builder2);
}
const builder = new TsUnknownBuilder();
this.tsAddMetadataToBuilder(builder, type);
return builder;
}
parseStringMatching(type) {
const { tsPattern } = StringMatchingType.getOriginalMetadata(type);
const builder = new TsStringMatchingBuilder(tsPattern);
this.tsAddMetadataToBuilder(builder, type);
return this.addFileExportAndResolveBuilder(builder);
}
parseCircular(type, children) {
const childType = type.type;
const [actualType] = children;
if (this.circulars.has(childType)) {
const name = this.circulars.get(childType);
actualType.setName(name);
return this.fileScope.addTypeExport(actualType, name);
}
return actualType;
}
parseCircularRef(type) {
var _a;
const referencedType = type._getReferencedType();
const metadata = BaseType.getOriginalMetadata(referencedType);
const title = metadata.title;
if (this.circulars.has(referencedType)) {
return new TsNamedReference(this.circulars.get(referencedType));
}
if (title) {
const typeName2 = NameGenerator.generate(title);
this.circulars.set(referencedType, typeName2);
return new TsNamedReference(typeName2);
}
const typeName = NameGenerator.generate(
(_a = TypeKindNames.get(referencedType.kind)) != null ? _a : "Circular"
);
this.circulars.set(referencedType, typeName);
return new TsNamedReference(typeName);
}
visit(type, children) {
switch (type.kind) {
case "simple":
return this.parsePrimitive(type);
case "array":
return this.parseArrayOf(type, children);
case "tuple":
return this.parseTuple(type, children);
case "record":
return this.parseRecordOf(type, children);
case "dictionary":
return this.parseDict(type, children);
case "set":
return this.parseSetOf(type, children);
case "union":
return this.parseOneOf(type, children);
case "intersection":
return this.parseAllOf(type, children);
case "literal":
return this.parseLiteral(type);
case "enumUnion":
return this.parseEnum(type);
case "enumMember":
return this.parseEnumMember(type);
case "instanceOf":
return this.parseInstanceOf(type);
case "custom":
return this.parseCustom(type);
case "stringMatching":
return this.parseStringMatching(type);
case "circular":
return this.parseCircular(type, children);
case "circularRef":
return this.parseCircularRef(type);
}
}
};
var toTsType = (dataType, options) => {
var _a, _b, _c, _d;
try {
const opt = {
mode: (_a = options == null ? void 0 : options.mode) != null ? _a : "compact",
exports: (_b = options == null ? void 0 : options.exports) != null ? _b : "main",
declaration: (_c = options == null ? void 0 : options.declaration) != null ? _c : false,
onDuplicateName: (_d = options == null ? void 0 : options.onDuplicateName) != null ? _d : "error",
getExternalTypeImport: options == null ? void 0 : options.getExternalTypeImport
};
const generator = new DataTypeTsGenerator(opt);
const rootBuilder = dataType._acceptVisitor(generator);
generator.fileScope.addRootType(rootBuilder);
return generator.fileScope.build();
} finally {
NameGenerator.clear();
}
};
export {
ExternalTypeImportProxy,
toTsType
};