Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support including imported types in user-defined tagged unions #13728

Merged
merged 2 commits into from Mar 27, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -3,6 +3,7 @@

using System.Diagnostics.CodeAnalysis;
using Bicep.Core.Diagnostics;
using Bicep.Core.UnitTests;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -643,5 +644,134 @@ public void DiscriminatedObjectUnions_SelfCycle_Inline_Optional()
}
"""));
}

[TestMethod]
public void Issue_13661()
{
var result = CompilationHelper.Compile(
("main.bicep", """
import * as t1 from 'app1.spec.bicep'
import * as t2 from 'app2.spec.bicep'

@discriminator('Name')
type ApiDef = (t1.Api1Def | t2.Api2Def)?

param Name string
param APIs ApiDef[]

output test string = '${Name}-${APIs}'
"""),
("app1.spec.bicep", """
@export()
type Api1Def = {
Name: 'Api1'
Settings: {
CustomSetting1: string
CustomSetting2: string
}
}
"""),
("app2.spec.bicep", """
@export()
type Api2Def = {
Name: 'Api2'
Settings: {
CustomSetting3: string
}
}
"""));

result.Template.Should().NotBeNull();
result.Template.Should().HaveJsonAtPath("definitions.ApiDef.discriminator", """
{
"propertyName": "Name",
"mapping": {
"Api1": {
"$ref": "#/definitions/_1.Api1Def"
},
"Api2": {
"$ref": "#/definitions/_2.Api2Def"
}
}
}
""");
}

[TestMethod]
public void User_defined_discriminated_objects_can_amend_resource_derived_discriminated_unions()
{
var result = CompilationHelper.Compile(
new ServiceBuilder().WithFeatureOverrides(new(TestContext, ResourceDerivedTypesEnabled: true)),
"""
@discriminator('computeType')
type taggedUnion = resource<'Microsoft.MachineLearningServices/workspaces/computes@2020-04-01'>.properties
| { computeType: 'foo', bar: string }
""");

result.Template.Should().NotBeNull();
result.Template.Should().HaveJsonAtPath("definitions.taggedUnion.discriminator", """
{
"propertyName": "computeType",
"mapping": {
"DataFactory": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/DataFactory"
}
},
"Databricks": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/Databricks"
}
},
"VirtualMachine": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/VirtualMachine"
}
},
"AmlCompute": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/AmlCompute"
}
},
"AKS": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/AKS"
}
},
"HDInsight": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/HDInsight"
}
},
"DataLakeAnalytics": {
"type": "object",
"metadata": {
"__bicep_resource_derived_type!": "Microsoft.MachineLearningServices/workspaces/computes@2020-04-01#properties/properties/discriminator/mapping/DataLakeAnalytics"
}
},
"foo": {
"type": "object",
"properties": {
"computeType": {
"type": "string",
"allowedValues": [
"foo"
]
},
"bar": {
"type": "string"
}
}
}
}
}
""");
}
}
}
Expand Up @@ -510,24 +510,6 @@ type discriminatedUnion1 = typeA | typeB
//@ }
//@ }
//@ },
//@ "a": {
//@ "$ref": "#/definitions/typeA"
//@ },
//@ "b": {
//@ "$ref": "#/definitions/typeB"
//@ },
//@ "a": {
//@ "$ref": "#/definitions/typeA"
//@ },
//@ "b": {
//@ "$ref": "#/definitions/typeB"
//@ },
//@ "a": {
//@ "$ref": "#/definitions/typeA"
//@ },
//@ "b": {
//@ "$ref": "#/definitions/typeB"
//@ },

@discriminator('type')
type discriminatedUnion2 = { type: 'c', value: string } | { type: 'd', value: bool }
Expand Down Expand Up @@ -659,6 +641,12 @@ type discriminatedUnion3 = discriminatedUnion1 | discriminatedUnion2 | { type: '
//@ "discriminator": {
//@ "propertyName": "type",
//@ "mapping": {
//@ "a": {
//@ "$ref": "#/definitions/typeA"
//@ },
//@ "b": {
//@ "$ref": "#/definitions/typeB"
//@ },
//@ "e": {
//@ "type": "object",
//@ "properties": {
Expand All @@ -684,6 +672,12 @@ type discriminatedUnion4 = discriminatedUnion1 | (discriminatedUnion2 | typeE)
//@ "discriminator": {
//@ "propertyName": "type",
//@ "mapping": {
//@ "a": {
//@ "$ref": "#/definitions/typeA"
//@ },
//@ "b": {
//@ "$ref": "#/definitions/typeB"
//@ },
//@ "e": {
//@ "$ref": "#/definitions/typeE"
//@ }
Expand Down Expand Up @@ -855,6 +849,12 @@ type inlineDiscriminatedUnion3 = {
//@ "discriminator": {
//@ "propertyName": "type",
//@ "mapping": {
//@ "a": {
//@ "$ref": "#/definitions/typeA"
//@ },
//@ "b": {
//@ "$ref": "#/definitions/typeB"
//@ },
//@ }
//@ }
//@ }
Expand Down
Expand Up @@ -292,13 +292,28 @@ public void Supports_pointers_to_partial_resource_body_types()
ImmutableArray.Create<ITypeReference>(new ObjectType("dictionary",
TypeSymbolValidationFlags.Default,
ImmutableArray<TypeProperty>.Empty,
TypeFactory.CreateArrayType(targetType))),
TypeFactory.CreateArrayType(new DiscriminatedObjectType("taggedUnion",
TypeSymbolValidationFlags.Default,
"type",
ImmutableArray.Create<ITypeReference>(
new ObjectType("fooVariant",
TypeSymbolValidationFlags.Default,
ImmutableArray.Create(
new TypeProperty("type", TypeFactory.CreateStringLiteralType("foo")),
new TypeProperty("property", LanguageConstants.Int)),
null),
new ObjectType("barVariant",
TypeSymbolValidationFlags.Default,
ImmutableArray.Create(
new TypeProperty("type", TypeFactory.CreateStringLiteralType("bar")),
new TypeProperty("property", targetType)),
null)))))),
TypeSymbolValidationFlags.Default))),
null);
var (sut, unhydratedTypeRef) = SetupResolver(hydrated);

UnresolvedResourceDerivedType unresolved = new(unhydratedTypeRef,
ImmutableArray.Create("properties", "property", "prefixItems", "0", "additionalProperties", "items"),
ImmutableArray.Create("properties", "property", "prefixItems", "0", "additionalProperties", "items", "discriminator", "mapping", "bar", "properties", "property"),
LanguageConstants.Any);

var bound = sut.ResolveResourceDerivedTypes(unresolved);
Expand Down