function convertModel2CMDObjectSchemaBase()

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