Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@
"cwd": "${workspaceFolder}/src/generator",
"preLaunchTask": "build autorest.bicep"
},
{
"name": "Test autorest.bicep",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": [
"test"
],
"cwd": "${workspaceFolder}/src/autorest.bicep",
"preLaunchTask": "build autorest.bicep"
},
{
"type": "node",
"request": "attach",
Expand All @@ -50,4 +61,4 @@
"description": "Pick a specific base path to generate types for"
}
]
}
}
36 changes: 33 additions & 3 deletions src/autorest.bicep/src/type-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,29 @@ export function generateTypes(host: AutorestExtensionHost, definition: ProviderD
}
}

function getObjectName(putSchema: ObjectSchema | undefined, getSchema: ObjectSchema | undefined) {
const putName = putSchema ? getSerializedName(putSchema) : undefined;
const getName = getSchema ? getSerializedName(getSchema) : undefined;

if (putSchema) {
if (getSchema) {
if (putName !== getName) {
return {
syntheticObject: true,
definitionName: `${putName}Or${getName}`,
};
}
}

return {syntheticObject: false, definitionName: putName};
}

return {syntheticObject: false, definitionName: getName};
}

function parseObjectType(putSchema: ObjectSchema | undefined, getSchema: ObjectSchema | undefined, includeBaseProperties: boolean) {
const combinedSchema = combineAndThrowIfNull(putSchema, getSchema);
const definitionName = getSerializedName(combinedSchema);
const {syntheticObject, definitionName} = getObjectName(putSchema, getSchema);

if (includeBaseProperties && namedDefinitions[definitionName]) {
// if we're building a discriminated subtype, we're going to be missing the base properties
Expand All @@ -451,7 +471,17 @@ export function generateTypes(host: AutorestExtensionHost, definition: ProviderD
namedDefinitions[definitionName] = definition;
}

for (const { propertyName, putProperty, getProperty } of getObjectTypeProperties(putSchema, getSchema, includeBaseProperties)) {
// Only make a distinction between what's defined on PUT vs GET if we're dealing with a synthetic object or a discriminated subtype.
// If the schema on both PUT and GET is the same named object (or if one of the two is undefined),
// use the combined schema as both GET and PUT schemata to prevent ReadOnly/WriteOnly flags from trickling down
// to object properties (which is problematic if shapes are reused across resources)
//
// For discriminated subtypes, Bicep's type system does not have a great way to communicate which variants are available on read vs write, but this
// can be communicated on variant properties. NB: `putSchema` and `getSchema` will only be different in a discriminated subtype if the discriminated
// object was synthetic.
const [schemaForPut, schemaForGet] = syntheticObject || !includeBaseProperties ? [putSchema, getSchema] : [combinedSchema, combinedSchema];

for (const { propertyName, putProperty, getProperty } of getObjectTypeProperties(schemaForPut, schemaForGet, includeBaseProperties)) {
const propertyDefinition = parseType(putProperty?.schema, getProperty?.schema);
if (propertyDefinition) {
const description = getPropertyDescription(putProperty, getProperty);
Expand All @@ -463,7 +493,7 @@ export function generateTypes(host: AutorestExtensionHost, definition: ProviderD
if (combinedSchema.discriminator) {
const discriminatedObjectType = factory.lookupType(definition) as DiscriminatedObjectType;

handlePolymorphicType(discriminatedObjectType, putSchema, getSchema);
handlePolymorphicType(discriminatedObjectType, schemaForPut, schemaForGet);
}

return definition;
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"1":{"Kind":1}},{"1":{"Kind":2}},{"1":{"Kind":3}},{"1":{"Kind":4}},{"1":{"Kind":5}},{"1":{"Kind":6}},{"1":{"Kind":7}},{"1":{"Kind":8}},{"6":{"Value":"Test.Rp1/testType1"}},{"6":{"Value":"2021-10-31"}},{"2":{"Name":"Test.Rp1/testType1","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":8,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":9,"Flags":10,"Description":"The resource api version"},"properties":{"Type":11,"Flags":0,"Description":"TestType1 properties"},"tags":{"Type":25,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":26,"Flags":2,"Description":"Azure Resource Manager metadata containing createdBy and modifiedBy information."}}}},{"2":{"Name":"TestType1Properties","Properties":{"basicString":{"Type":4,"Flags":0,"Description":"Description for a basic string property."},"stringEnum":{"Type":14,"Flags":0,"Description":"Description for a basic enum property."},"skuTier":{"Type":19,"Flags":0,"Description":"This field is required to be implemented by the Resource Provider if the service has more than one tier, but is not required on a PUT."},"encryptionProperties":{"Type":20,"Flags":0,"Description":"TestType1 encryption properties"}}}},{"6":{"Value":"Foo"}},{"6":{"Value":"Bar"}},{"5":{"Elements":[12,13,4]}},{"6":{"Value":"Free"}},{"6":{"Value":"Basic"}},{"6":{"Value":"Standard"}},{"6":{"Value":"Premium"}},{"5":{"Elements":[15,16,17,18]}},{"2":{"Name":"EncryptionProperties","Properties":{"status":{"Type":23,"Flags":0,"Description":"Indicates whether or not the encryption is enabled for container registry."},"keyVaultProperties":{"Type":24,"Flags":0,"Description":"Key vault properties."}}}},{"6":{"Value":"enabled"}},{"6":{"Value":"disabled"}},{"5":{"Elements":[21,22,4]}},{"2":{"Name":"KeyVaultProperties","Properties":{"keyIdentifier":{"Type":4,"Flags":0,"Description":"Key vault uri to access the encryption key."},"identity":{"Type":4,"Flags":0,"Description":"The client ID of the identity which will be used to access key vault."}}}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":31,"Flags":0,"Description":"The type of identity that created the resource."},"createdAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource creation (UTC)."},"lastModifiedBy":{"Type":4,"Flags":0,"Description":"The identity that last modified the resource."},"lastModifiedByType":{"Type":36,"Flags":0,"Description":"The type of identity that last modified the resource."},"lastModifiedAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource last modification (UTC)"}}}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[27,28,29,30,4]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[32,33,34,35,4]}},{"4":{"Name":"Test.Rp1/testType1@2021-10-31","ScopeType":8,"Body":10}},{"2":{"Name":"FoosRequest","Properties":{"someString":{"Type":4,"Flags":5,"Description":"The foo request string"}}}},{"2":{"Name":"FoosResponse","Properties":{"someString":{"Type":4,"Flags":2,"Description":"The foo response string"}}}},{"8":{"Name":"listFoos","ResourceType":"Test.Rp1/testType1","ApiVersion":"2021-10-31","Output":39,"Input":38}},{"3":{"ItemType":39}},{"8":{"Name":"listArrayOfFoos","ResourceType":"Test.Rp1/testType1","ApiVersion":"2021-10-31","Output":41}}]
[{"1":{"Kind":1}},{"1":{"Kind":2}},{"1":{"Kind":3}},{"1":{"Kind":4}},{"1":{"Kind":5}},{"1":{"Kind":6}},{"1":{"Kind":7}},{"1":{"Kind":8}},{"6":{"Value":"Test.Rp1/testType1"}},{"6":{"Value":"2021-10-31"}},{"2":{"Name":"Test.Rp1/testType1","Properties":{"id":{"Type":4,"Flags":10,"Description":"The resource id"},"name":{"Type":4,"Flags":9,"Description":"The resource name"},"type":{"Type":8,"Flags":10,"Description":"The resource type"},"apiVersion":{"Type":9,"Flags":10,"Description":"The resource api version"},"properties":{"Type":11,"Flags":0,"Description":"The resource properties."},"tags":{"Type":26,"Flags":0,"Description":"Resource tags."},"location":{"Type":4,"Flags":1,"Description":"The geo-location where the resource lives"},"systemData":{"Type":27,"Flags":2,"Description":"Azure Resource Manager metadata containing createdBy and modifiedBy information."}}}},{"2":{"Name":"TestType1CreateOrUpdatePropertiesOrTestType1Properties","Properties":{"basicString":{"Type":4,"Flags":0,"Description":"Description for a basic string property."},"stringEnum":{"Type":14,"Flags":0,"Description":"Description for a basic enum property."},"skuTier":{"Type":19,"Flags":0,"Description":"This field is required to be implemented by the Resource Provider if the service has more than one tier, but is not required on a PUT."},"encryptionProperties":{"Type":20,"Flags":0,"Description":"TestType1 encryption properties"},"locationData":{"Type":25,"Flags":2,"Description":"Metadata pertaining to the geographic location of the resource."}}}},{"6":{"Value":"Foo"}},{"6":{"Value":"Bar"}},{"5":{"Elements":[12,13,4]}},{"6":{"Value":"Free"}},{"6":{"Value":"Basic"}},{"6":{"Value":"Standard"}},{"6":{"Value":"Premium"}},{"5":{"Elements":[15,16,17,18]}},{"2":{"Name":"EncryptionProperties","Properties":{"status":{"Type":23,"Flags":0,"Description":"Indicates whether or not the encryption is enabled for container registry."},"keyVaultProperties":{"Type":24,"Flags":0,"Description":"Key vault properties."}}}},{"6":{"Value":"enabled"}},{"6":{"Value":"disabled"}},{"5":{"Elements":[21,22,4]}},{"2":{"Name":"KeyVaultProperties","Properties":{"keyIdentifier":{"Type":4,"Flags":0,"Description":"Key vault uri to access the encryption key."},"identity":{"Type":4,"Flags":0,"Description":"The client ID of the identity which will be used to access key vault."}}}},{"2":{"Name":"LocationData","Properties":{"name":{"Type":4,"Flags":1,"Description":"A canonical name for the geographic or physical location."},"city":{"Type":4,"Flags":0,"Description":"The city or locality where the resource is located."},"district":{"Type":4,"Flags":0,"Description":"The district, state, or province where the resource is located."},"countryOrRegion":{"Type":4,"Flags":0,"Description":"The country or region where the resource is located"}}}},{"2":{"Name":"TrackedResourceTags","Properties":{},"AdditionalProperties":4}},{"2":{"Name":"SystemData","Properties":{"createdBy":{"Type":4,"Flags":0,"Description":"The identity that created the resource."},"createdByType":{"Type":32,"Flags":0,"Description":"The type of identity that created the resource."},"createdAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource creation (UTC)."},"lastModifiedBy":{"Type":4,"Flags":0,"Description":"The identity that last modified the resource."},"lastModifiedByType":{"Type":37,"Flags":0,"Description":"The type of identity that last modified the resource."},"lastModifiedAt":{"Type":4,"Flags":0,"Description":"The timestamp of resource last modification (UTC)"}}}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[28,29,30,31,4]}},{"6":{"Value":"User"}},{"6":{"Value":"Application"}},{"6":{"Value":"ManagedIdentity"}},{"6":{"Value":"Key"}},{"5":{"Elements":[33,34,35,36,4]}},{"4":{"Name":"Test.Rp1/testType1@2021-10-31","ScopeType":8,"Body":10}},{"2":{"Name":"FoosRequest","Properties":{"someString":{"Type":4,"Flags":1,"Description":"The foo request string"},"locationData":{"Type":25,"Flags":0,"Description":"Metadata pertaining to the geographic location of the resource."}}}},{"2":{"Name":"FoosResponse","Properties":{"someString":{"Type":4,"Flags":0,"Description":"The foo response string"}}}},{"8":{"Name":"listFoos","ResourceType":"Test.Rp1/testType1","ApiVersion":"2021-10-31","Output":40,"Input":39}},{"3":{"ItemType":40}},{"8":{"Name":"listArrayOfFoos","ResourceType":"Test.Rp1/testType1","ApiVersion":"2021-10-31","Output":42}}]
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* **id**: string (ReadOnly, DeployTimeConstant): The resource id
* **location**: string (Required): The geo-location where the resource lives
* **name**: string (Required, DeployTimeConstant): The resource name
* **properties**: [TestType1Properties](#testtype1properties): TestType1 properties
* **properties**: [TestType1CreateOrUpdatePropertiesOrTestType1Properties](#testtype1createorupdatepropertiesortesttype1properties): The resource properties.
* **systemData**: [SystemData](#systemdata) (ReadOnly): Azure Resource Manager metadata containing createdBy and modifiedBy information.
* **tags**: [TrackedResourceTags](#trackedresourcetags): Resource tags.
* **type**: 'Test.Rp1/testType1' (ReadOnly, DeployTimeConstant): The resource type
Expand All @@ -30,21 +30,29 @@

## FoosRequest
### Properties
* **someString**: string (Required, WriteOnly): The foo request string
* **locationData**: [LocationData](#locationdata): Metadata pertaining to the geographic location of the resource.
* **someString**: string (Required): The foo request string

## FoosResponse
### Properties
* **someString**: string (ReadOnly): The foo response string
* **someString**: string: The foo response string

## FoosResponse
### Properties
* **someString**: string (ReadOnly): The foo response string
* **someString**: string: The foo response string

## KeyVaultProperties
### Properties
* **identity**: string: The client ID of the identity which will be used to access key vault.
* **keyIdentifier**: string: Key vault uri to access the encryption key.

## LocationData
### Properties
* **city**: string: The city or locality where the resource is located.
* **countryOrRegion**: string: The country or region where the resource is located
* **district**: string: The district, state, or province where the resource is located.
* **name**: string (Required): A canonical name for the geographic or physical location.

## SystemData
### Properties
* **createdAt**: string: The timestamp of resource creation (UTC).
Expand All @@ -54,10 +62,11 @@
* **lastModifiedBy**: string: The identity that last modified the resource.
* **lastModifiedByType**: 'Application' | 'Key' | 'ManagedIdentity' | 'User' | string: The type of identity that last modified the resource.

## TestType1Properties
## TestType1CreateOrUpdatePropertiesOrTestType1Properties
### Properties
* **basicString**: string: Description for a basic string property.
* **encryptionProperties**: [EncryptionProperties](#encryptionproperties): TestType1 encryption properties
* **locationData**: [LocationData](#locationdata) (ReadOnly): Metadata pertaining to the geographic location of the resource.
* **skuTier**: 'Basic' | 'Free' | 'Premium' | 'Standard': This field is required to be implemented by the Resource Provider if the service has more than one tier, but is not required on a PUT.
* **stringEnum**: 'Bar' | 'Foo' | string: Description for a basic enum property.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,22 @@
"type": "object",
"description": "The testType1 resource."
},
"TestType1Properties": {
"description": "TestType1 properties",
"TestType1Input": {
"allOf": [
{
"$ref": "../../../../../common-types/resource-management/v3/types.json#/definitions/TrackedResource"
}
],
"type": "object",
"properties": {
"properties": {
"$ref": "#/definitions/TestType1CreateOrUpdateProperties",
"description": "The resource properties.",
"x-ms-client-flatten": true
}
}
},
"TestType1CreateOrUpdateProperties": {
"properties": {
"basicString": {
"type": "string",
Expand Down Expand Up @@ -81,6 +95,18 @@
}
}
},
"TestType1Properties": {
"allOf": [
{
"$ref": "#/definitions/TestType1CreateOrUpdateProperties"
}
],
"properties": {
"locationData": {
"$ref": "../../../../../common-types/resource-management/v3/types.json#/definitions/locationData"
}
}
},
"FoosResponse": {
"properties": {
"someString": {
Expand All @@ -94,6 +120,9 @@
"someString": {
"type": "string",
"description": "The foo request string"
},
"locationData": {
"$ref": "../../../../../common-types/resource-management/v3/types.json#/definitions/locationData"
}
},
"required": [
Expand Down Expand Up @@ -204,7 +233,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/TestType1"
"$ref": "#/definitions/TestType1Input"
},
"description": "The request parameters"
},
Expand Down