in packages/extensions/modelerfour/src/modeler/modelerfour.ts [1090:1340]
private processSchemaImpl(schema: OpenAPI.Schema, name: string): Schema {
if (this.trap.has(schema)) {
throw new Error(
`RECURSING! Saw schema ${schema.title || schema["x-ms-metadata"]?.name || name} more than once.`,
);
}
this.trap.add(schema);
// handle enums differently early
if (isSchemaAnEnum(schema, this.input)) {
return this.processChoiceSchema(name, schema);
}
if (isSchemaBinary(schema)) {
// handle inconsistency in file format handling.
this.session.warning(
`'The schema ${schema?.["x-ms-metadata"]?.name || name} with 'type: ${schema.type}', format: ${
schema.format
}' will be treated as a binary blob for binary media types.`,
["Modeler", "Superflous type information"],
schema,
);
schema.type = OpenAPI.JsonType.String;
schema.format = StringFormat.Binary;
}
// if they haven't set the schema.type then we're going to have to guess what
// they meant to do.
switch (schema.type) {
case undefined:
case null:
if (schema.properties) {
// if the model has properties, then we're going to assume they meant to say JsonType.object
// but we're going to warn them anyway.
this.session.warning(
`The schema '${
schema?.["x-ms-metadata"]?.name || name
}' with an undefined type and declared properties is a bit ambiguous. This has been auto-corrected to 'type:object'`,
["Modeler", "MissingType"],
schema,
);
schema.type = OpenAPI.JsonType.Object;
break;
}
if (schema.additionalProperties) {
// this looks like it's going to be a dictionary
// we'll mark it as object and let the processObjectSchema sort it out.
this.session.warning(
`The schema '${
schema?.["x-ms-metadata"]?.name || name
}' with an undefined type and additionalProperties is a bit ambiguous. This has been auto-corrected to 'type:object'`,
["Modeler"],
schema,
);
schema.type = OpenAPI.JsonType.Object;
break;
}
if (schema.allOf || schema.anyOf || schema.oneOf) {
// The schema does not have properties or additionalProperties, but it does have allOf/anyOf/oneOf.
// The prior logic auto-corrected this to type: object, but that's not always appropriate.
// Check the child schemas and bypass the auto-correct if any are clearly not type: object.
// Return true if the schema has an explicit type that is not type: object.
const notTypeObject = (e: Refable<OpenAPI.Schema>): boolean => {
const s = this.resolve(e).instance;
return !!s.type && s.type !== OpenAPI.JsonType.Object;
};
let bypassAutoCorrect = schema.allOf && schema.allOf.some(notTypeObject);
bypassAutoCorrect ||= schema.anyOf && schema.anyOf.some(notTypeObject);
bypassAutoCorrect ||= schema.oneOf && schema.oneOf.some(notTypeObject);
if (!bypassAutoCorrect) {
this.session.warning(
`The schema '${
schema?.["x-ms-metadata"]?.name || name
}' with an undefined type and 'allOf'/'anyOf'/'oneOf' is a bit ambiguous. This has been auto-corrected to 'type:object'`,
["Modeler", "MissingType"],
schema,
);
schema.type = OpenAPI.JsonType.Object;
break;
}
}
{
// no type info at all!?
// const err = `The schema '${name}' has no type or format information whatsoever. ${this.location(schema)}`;
this.session.warning(
`The schema '${
schema?.["x-ms-metadata"]?.name || name
}' has no type or format information whatsoever. ${this.location(schema)}`,
["Modeler", "MissingType"],
schema,
);
// throw Error(err);
return this.anySchema;
}
}
// ok, figure out what kind of schema this is.
switch (schema.type) {
case JsonType.Array:
switch (schema.format) {
case undefined:
return this.processArraySchema(name, schema);
default:
this.session.error(
`Array schema '${schema?.["x-ms-metadata"]?.name || name}' with unknown format: '${
schema.format
} ' is not valid`,
["Modeler"],
schema,
);
}
break;
case JsonType.Boolean:
switch (schema.format) {
case undefined:
return this.processBooleanSchema(name, schema);
default:
this.session.error(
`Boolean schema '${name}' with unknown format: '${schema.format}' is not valid`,
["Modeler"],
schema,
);
}
break;
case JsonType.Integer:
schema.format = schema.format ? schema.format.toLowerCase() : schema.format;
switch (schema.format) {
case IntegerFormat.UnixTime:
return this.processUnixTimeSchema(name, schema);
case IntegerFormat.Int64:
case IntegerFormat.Int32:
case IntegerFormat.None:
case undefined:
return this.processIntegerSchema(name, schema);
case NumberFormat.Double:
case NumberFormat.Float:
case NumberFormat.Decimal:
return this.processNumberSchema(name, schema);
default:
// According to the OpenAPI v3 spec, an unexpected format should be ignored,
// so treat this as an `integer` with no format.
this.session.warning(
`Integer schema '${name}' with unknown format: '${schema.format}' is not valid. Treating it as 'int32'.`,
["Modeler", "UnknownFormatType"],
schema,
);
return this.processIntegerSchema(name, schema);
}
case JsonType.Number:
switch (schema.format) {
case undefined:
case NumberFormat.None:
case NumberFormat.Double:
case NumberFormat.Float:
case NumberFormat.Decimal:
return this.processNumberSchema(name, schema);
case IntegerFormat.Int64:
case IntegerFormat.Int32:
return this.processIntegerSchema(name, schema);
default:
this.session.warning(
`Number schema '${name}' with unknown format: '${schema.format}'. Will ignore.`,
["Modeler", "UnknownFormatType"],
schema,
);
return this.processIntegerSchema(name, schema);
}
break;
case JsonType.Object:
return this.processObjectSchema(name, schema);
case JsonType.String:
switch (schema.format) {
// member should be byte array
// on wire format should be base64url
case StringFormat.Base64Url:
case StringFormat.Byte:
case StringFormat.Certificate:
return this.processByteArraySchema(name, schema);
case StringFormat.Binary:
// represent as a binary
// wire format is stream of bytes
// This is actually a different kind of response or request
// and should not be treated as a trivial 'type'
return this.processBinarySchema(name, schema);
case StringFormat.Char:
// a single character
return this.processCharacterSchema(name, schema);
case StringFormat.Date:
return this.processDateSchema(name, schema);
case StringFormat.Time:
return this.processTimeSchema(name, schema);
case StringFormat.DateTime:
case StringFormat.DateTimeRfc1123:
return this.processDateTimeSchema(name, schema);
case StringFormat.Duration:
return this.processDurationSchema(name, schema);
case StringFormat.Uuid:
return this.processUuidSchema(name, schema);
case StringFormat.Url:
case StringFormat.Uri:
return this.processUriSchema(name, schema);
case StringFormat.ArmId:
return this.processArmId(name, schema);
case StringFormat.Password:
return this.processCredentialSchema(name, schema);
case StringFormat.OData:
return this.processOdataSchema(name, schema);
case StringFormat.None:
case undefined:
case null:
return this.processStringSchema(name, schema);
default:
// console.error(`String schema '${name}' with unknown format: '${schema.format}' is treated as simple string.`);
return this.processStringSchema(name, schema);
// this.session.error(`String schema '${name}' with unknown format: '${schema.format}' is not valid`, ['Modeler'], schema);
}
}
this.session.error(
`The model ${name} does not have a recognized schema type '${schema.type}' ${JSON.stringify(schema)} `,
["Modeler", "UnknownSchemaType"],
);
throw new Error(`Unrecognized schema type:'${schema.type}' / format: ${schema.format} ${JSON.stringify(schema)} `);
}