in src/typespec-aaz/src/convertor.ts [774:955]
function convertModel2CMDObjectSchemaBase(
context: AAZSchemaEmitterContext,
model: Model,
): CMDObjectSchemaBase | CMDClsSchemaBase | undefined {
const payloadModel = context.metadateInfo.getEffectivePayloadType(model, context.visibility) as Model;
if (isArrayModelType(context.program, payloadModel)) {
return undefined;
}
let pending;
if (context.supportClsSchema) {
pending = context.pendingSchemas.getOrAdd(payloadModel, context.visibility, () => ({
type: payloadModel,
visibility: context.visibility,
ref: context.refs.getOrAdd(payloadModel, context.visibility, () => new Ref()),
count: 0,
}));
pending.count++;
if (pending.count > 1) {
return {
type: new ClsType(pending),
} as CMDClsSchemaBase;
}
}
// const name = getOpenAPITypeName(context.program, type, context.typeNameOptions);
let object: CMDObjectSchemaBase = {
type: "object",
cls: pending?.ref,
};
const properties: Record<string, CMDSchema> = {};
// inherit from base model
if (payloadModel.baseModel) {
const baseSchema = convert2CMDSchemaBase(
{
...context,
supportClsSchema: false,
},
payloadModel.baseModel,
);
if (baseSchema) {
Object.assign(object, baseSchema, { cls: pending?.ref });
}
const discriminatorInfo = getDiscriminatorInfo(context, payloadModel);
if (discriminatorInfo) {
// directly use child definition instead of polymorphism.
// So the value for discriminator property is const.
// filter prop in object.props by discriminatorInfo.propertyName and set its const value
const prop = object.props!.find((prop) => prop.name === discriminatorInfo.propertyName)!;
prop.const = true;
prop.default = {
value: discriminatorInfo.value,
};
object.discriminators = undefined;
}
if (object.props) {
for (const prop of object.props) {
properties[prop.name] = prop;
}
object.props = undefined;
}
}
const discriminator = getDiscriminator(context.program, payloadModel);
for (const prop of payloadModel.properties.values()) {
if (isNeverType(prop.type)) {
// If the property has a type of 'never', don't include it in the schema
continue;
}
if (!context.metadateInfo.isPayloadProperty(prop, context.visibility)) {
continue;
}
const jsonName = getJsonName(context, prop);
let schema = convert2CMDSchema(
{
...context,
supportClsSchema: true,
},
prop,
jsonName,
);
if (schema) {
if (!context.metadateInfo.isOptional(prop, context.visibility) || prop.name === discriminator?.propertyName) {
schema.required = true;
}
if (isReadonlyProperty(context.program, prop)) {
schema.readOnly = true;
if (schema.required) {
// read_only property is not required
// console.log("Ignore requirement of the read only property: ", schema.name)
schema.required = false;
}
}
if (shouldClientFlatten(context, prop)) {
if (schema.type === "object") {
schema = {
...schema,
clientFlatten: true,
} as CMDObjectSchema;
} else if (schema.type instanceof ClsType) {
schema = {
...schema,
clientFlatten: true,
} as CMDClsSchema;
}
}
properties[schema.name] = schema;
}
}
if (discriminator) {
const { propertyName } = discriminator;
console.assert(object.discriminators === undefined, "Discriminator should be undefined.");
// Push discriminator into base type, but only if it is not already there
if (!payloadModel.properties.get(propertyName)) {
const discriminatorProperty: CMDStringSchema = {
name: propertyName,
type: "string",
required: true,
description: `Discriminator property for ${payloadModel.name}.`,
};
properties[propertyName] = discriminatorProperty;
}
const derivedModels = payloadModel.derivedModels.filter(includeDerivedModel);
for (const child of derivedModels) {
const childDiscriminatorValue = getDiscriminatorInfo(context, child);
if (childDiscriminatorValue) {
const disc = convertModel2CMDObjectDiscriminator(context, child, childDiscriminatorValue);
if (disc) {
object.discriminators ??= [];
object.discriminators.push(disc);
}
}
}
}
if (isRecordModelType(context.program, payloadModel)) {
object.additionalProps = {
item: convert2CMDSchemaBase(
{
...context,
supportClsSchema: true,
},
payloadModel.indexer.value,
),
};
}
if (isAzureResourceOverall(context, payloadModel) && properties.location) {
properties.location = {
...(properties.location as CMDStringSchema),
type: "ResourceLocation",
} as CMDResourceLocationSchema;
}
if (properties.userAssignedIdentities && properties.type) {
object = {
...object,
type: "IdentityObject",
} as CMDIdentityObjectSchemaBase;
}
if (Object.keys(properties).length > 0) {
object.props = Object.values(properties).filter((prop) => !isEmptiedSchema(prop));
if (object.props.length === 0) {
object.props = undefined;
}
}
if (pending) {
pending.schema = object;
}
return object;
}