private emitTypeInternal()

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 };
  }