in src/type-generator.ts [170:263]
private emitTypeInternal(typeName: string, def?: JSONSchema4, structFqn: string = typeName): EmittedType {
if (!def) {
def = this.definitions[typeName];
if (!def) {
throw new Error(`unable to find schema definition for ${typeName}`);
}
}
// callers expect that emit a type named `typeName` so we can't change it here
// but at least we can verify it's correct.
if (TypeGenerator.normalizeTypeName(typeName) !== typeName) {
throw new Error(`${typeName} must be normalized before calling emitType`);
}
if (structFqn.startsWith(DEFINITIONS_PREFIX)) {
structFqn = structFqn.substring(DEFINITIONS_PREFIX.length);
}
if (this.isExcluded(structFqn)) {
throw new Error(`Type ${structFqn} cannot be added since it matches one of the exclusion patterns`);
}
// complex type
if (def.$ref) {
return this.typeForRef(def);
}
// unions (unless this is a struct, and then we just ignore the constraints)
if (def.oneOf || def.anyOf) {
const asUnion = this.tryEmitUnion(typeName, def, structFqn);
if (asUnion) {
return asUnion;
}
// carry on, we can't represent this schema as a union (yet?)
}
// dates
if (def.format === 'date-time') {
if (def.type && def.type !== 'string') {
throw new Error('date-time must be a string');
}
return { type: 'Date', toJson: x => `${x}?.toISOString()` };
}
// enums
if (def.enum && Array.isArray(def.enum) && def.enum.length > 0 && !def.enum.find(x => typeof(x) !== 'string')) {
if (def.type && def.type !== 'string') {
throw new Error('only "string" enums are supported');
}
return this.emitEnum(typeName, def, structFqn);
}
// struct
if (def.properties) {
if (def.type && def.type !== 'object') {
throw new Error('for "properties", if "type" is specified it has to be an "object"');
}
return this.emitStruct(typeName, def, structFqn);
}
// map
if (def.additionalProperties && typeof(def.additionalProperties) === 'object') {
if (def.type && def.type !== 'object') {
throw new Error('for "additionalProperties", if "type" is specified it has to be an "object"');
}
const et = this.typeForProperty(typeName, def.additionalProperties);
const toJson = (x: string) => `((${x}) === undefined) ? undefined : (Object.entries(${x}).reduce((r, i) => (i[1] === undefined) ? r : ({ ...r, [i[0]]: ${et.toJson('i[1]') } }), {}))`;
return { type: `{ [key: string]: ${et.type} }`, toJson };
}
switch (def.type) {
case 'string':
return { type: 'string', toJson: x => x };
case 'number':
case 'integer':
return { type: 'number', toJson: x => x };
case 'boolean':
return { type: 'boolean', toJson: (x) => x };
case 'array': {
return this.emitArray(typeName, def);
}
}
return { type: 'any', toJson: x => x };
}