@@ -176,6 +176,8 @@ export let constantSchemaForApiVersion: ConstantSchema | undefined;
176176export const schemaCache = new Map < Type , Schema > ( ) ;
177177// Add this to the modelSet to avoid circular reference
178178export const modelSet = new Set < Type > ( ) ;
179+ // For the models that are delayed to be set, currently the only case is the model that is derived from the model with discriminator
180+ export const delayedModelSet = new Set < Type > ( ) ;
179181export function getSchemaForApiVersion ( dpgContext : SdkContext , typeInput : Type ) {
180182 if ( constantSchemaForApiVersion ) {
181183 return constantSchemaForApiVersion ;
@@ -568,7 +570,10 @@ function getSchemaForUnionVariant(
568570 variant : UnionVariant ,
569571 options ?: GetSchemaOptions
570572) : Schema {
571- return getSchemaForType ( dpgContext , variant , options ) ;
573+ const schema = new ConstantSchema ( variant . name . toString ( ) , getDoc ( dpgContext . program , variant ) || "" ) ;
574+ schema . valueType = getSchemaForType ( dpgContext , variant . type , options ) ;
575+ schema . value = new ConstantValue ( variant . name . toString ( ) ) ;
576+ return schema ;
572577}
573578
574579// An openapi "string" can be defined in several different ways in typespec
@@ -582,6 +587,9 @@ function isOasString(type: Type): boolean {
582587 } else if ( type . kind === "Union" ) {
583588 // A union where all variants are an OasString
584589 return type . options . every ( ( o ) => isOasString ( o ) ) ;
590+ } else if ( type . kind === "UnionVariant" ) {
591+ // A union variant where the type is an OasString
592+ return isOasString ( type . type ) ;
585593 }
586594 return false ;
587595}
@@ -591,7 +599,8 @@ function isStringLiteral(type: Type): boolean {
591599 type . kind === "String" ||
592600 ( type . kind === "Union" && type . options . every ( ( o ) => o . kind === "String" ) ) ||
593601 ( type . kind === "EnumMember" &&
594- typeof ( type . value ?? type . name ) === "string" )
602+ typeof ( type . value ?? type . name ) === "string" ) ||
603+ ( type . kind === "UnionVariant" && type . type . kind === "String" )
595604 ) ;
596605}
597606
@@ -761,6 +770,23 @@ function getSchemaForModel(
761770 // NameType.Interface,
762771 // true /** shouldGuard */
763772 // );
773+ // by xiaogang, skip ArmResourceBase
774+ if ( model . baseModel && model . baseModel . name !== "ArmResourceBase" ) {
775+ modelSchema . parents = {
776+ all : [
777+ getSchemaForType ( dpgContext , model . baseModel , {
778+ usage,
779+ needRef : true
780+ } )
781+ ] ,
782+ immediate : [
783+ getSchemaForType ( dpgContext , model . baseModel , {
784+ usage,
785+ needRef : true
786+ } )
787+ ]
788+ } ;
789+ }
764790 modelSchema . language . default . name = pascalCase ( deconstruct ( modelSchema . language . default . name ) ) ;
765791 if ( isRecordModelType ( program , model ) ) {
766792 return getSchemaForRecordModel ( dpgContext , model , { usage } ) ;
@@ -814,50 +840,41 @@ function getSchemaForModel(
814840 const derivedModels = model . derivedModels . filter ( ( dm ) => {
815841 return includeDerivedModel ( dm , discriminator ? false : needRef ) ;
816842 } ) ;
817- if ( derivedModels . length > 0 ) {
818- modelSchema . children = {
819- all : [ ] ,
820- immediate : [ ]
821- } ;
822- }
843+
823844 for ( const child of derivedModels ) {
824- const childSchema = getSchemaForType ( dpgContext , child , {
825- usage,
826- needRef : true
827- } ) ;
828- for ( const [ name , prop ] of child . properties ) {
829- if ( name === discriminator ?. propertyName ) {
830- const propSchema = getSchemaForType ( dpgContext , prop . type , {
831- usage,
832- needRef : ! isAnonymousModelType ( prop . type ) ,
833- relevantProperty : prop
834- } ) ;
835- childSchema . discriminatorValue = propSchema . type . replace ( / " / g, "" ) ;
836- break ;
837- }
838- }
839- modelSchema . children ?. all ?. push ( childSchema ) ;
840- modelSchema . children ?. immediate ?. push ( childSchema ) ;
845+ // Delay schema generation of those models to avoiding circular reference
846+ delayedModelSet . add ( child ) ;
847+ // const childSchema = getSchemaForType(dpgContext, child, {
848+ // usage,
849+ // needRef: true
850+ // });
851+ // for (const [name, prop] of child.properties) {
852+ // if (name === discriminator?.propertyName) {
853+ // const propSchema = getSchemaForType(dpgContext, prop.type, {
854+ // usage,
855+ // needRef: !isAnonymousModelType(prop.type),
856+ // relevantProperty: prop
857+ // });
858+ // childSchema.discriminatorValue = propSchema.type.replace(/"/g, "");
859+ // break;
860+ // }
861+ // }
862+ // modelSchema.children?.all?.push(childSchema);
863+ // modelSchema.children?.immediate?.push(childSchema);
841864 }
842865
843866 // Enable option `isPolyParent` and discriminator only when it has valid children
844867 if (
845868 discriminator &&
846- modelSchema ?. children ?. all ?. length &&
847- modelSchema ?. children ?. all ? .length > 0
869+ derivedModels &&
870+ derivedModels . length > 0
848871 ) {
849872 if ( ! validateDiscriminator ( program , discriminator , derivedModels ) ) {
850873 // appropriate diagnostic is generated in the validate function
851874 return { } ;
852875 }
853876
854877 const { propertyName } = discriminator ;
855- // ToDo polymorphism by xiaogang
856- // modelSchema.discriminator = {
857- // name: propertyName,
858- // type: "string",
859- // description: `Discriminator property for ${model.name}.`
860- // };
861878 modelSchema . discriminatorValue = propertyName ;
862879 // ToDo: need to confirm whether still need this.
863880 // modelSchema.isPolyParent = true;
@@ -926,8 +943,23 @@ function getSchemaForModel(
926943 property . extensions = property . extensions || { } ;
927944 property . extensions [ 'circle-ref' ] = pascalCase ( deconstruct ( prop . type . name ) ) ;
928945 }
929-
930- modelSchema . properties . push ( property ) ;
946+ let isDiscriminatorInChild = false ;
947+ if ( modelSchema . parents && modelSchema . parents . all ) {
948+ modelSchema . parents . all . forEach ( ( parent ) => {
949+ if ( parent . type === "object" && ( < ObjectSchema > parent ) . discriminator ?. property . serializedName === propName ) {
950+ isDiscriminatorInChild = true ;
951+ }
952+ } ) ;
953+ }
954+ if ( ! isDiscriminatorInChild ) {
955+ modelSchema . properties . push ( property ) ;
956+ } else {
957+ modelSchema . discriminatorValue = ( < ConstantSchema > propSchema ) . value . value ;
958+ }
959+ if ( discriminator && propName === discriminator . propertyName ) {
960+ property . isDiscriminator = true ;
961+ modelSchema . discriminator = new M4Discriminator ( property ) ;
962+ }
931963 // if this property is a discriminator property, remove it to keep autorest validation happy
932964 //const { propertyName } = getDiscriminator(program, model) || {};
933965 // ToDo: by xiaoang, skip polymorphism for the time being.
@@ -973,33 +1005,20 @@ function getSchemaForModel(
9731005 // modelSchema.properties = modelSchema.properties?.filter(p => p.language.default.name != name);
9741006 // modelSchema.properties.push(newPropSchema);
9751007 }
976- // by xiaogang, skip ArmResourceBase
977- if ( model . baseModel && model . baseModel . name !== "ArmResourceBase" ) {
978- modelSchema . parents = {
979- all : [
980- getSchemaForType ( dpgContext , model . baseModel , {
981- usage,
982- needRef : true
983- } )
984- ] ,
985- immediate : [
986- getSchemaForType ( dpgContext , model . baseModel , {
987- usage,
988- needRef : true
989- } )
990- ]
991- } ;
992- }
1008+
9931009 return modelSchema ;
9941010}
9951011// Map an typespec type to an OA schema. Returns undefined when the resulting
9961012// OA schema is just a regular object schema.
9971013function getSchemaForLiteral ( type : Type ) : any {
1014+ // ToDo: by xiaogang, need to implement other kinds as String
9981015 switch ( type . kind ) {
9991016 case "Number" :
10001017 return { type : `${ type . value } ` , isConstant : true } ;
1001- case "String" :
1002- return { type : `"${ type . value } "` , isConstant : true } ;
1018+ case "String" : {
1019+ const schema = new StringSchema ( type . value , "" ) ;
1020+ return schema ;
1021+ }
10031022 case "Boolean" :
10041023 return { type : `${ type . value } ` , isConstant : true } ;
10051024 }
0 commit comments