Hello everyone, this gist is going to describe the canonical behavior of unions and enums.
Here's the conclusion that Laurent and I have come to. Once there is agreement across languages, we will be adding cadl-ranch tests to solidify this behavior.
- Anonymous unions are always exposed as unions
- Named unions are always exposed as enums
- If there is a base type included anywhere at any level, it's extensible (non-fixed)
- Otherwise, it's a regular enum (fixed)
- Named unions also flatten all entries (including other enums and named unions) into itself, collapsing the hierarchy
Notes
isFixed means non-extensible. This doc completely follows the new semantic for what is determined as a fixed vs. non-fixed enum. It doesn't take azure or unbranded into account
All anonymous unions will be generated as unions.
model Test {
color: "red" | "blue" | string;
}
const enums = getAllModels(sdkContext).filter(x => x.kind === "enum");
strictEqual(enums.length, 0);
const colorTcgcProperty = {
kind: "property",
type: {
kind: "union",
name: undefined,
generatedName: "TestColor",
values: [
{
kind: "constant",
value: "red",
},
{
kind: "constant",
value: "blue",
},
{
kind: "string",
}
],
}
}
model Test {
color: "red" | "blue";
}
const enums = getAllModels.filter(x => x.kind === "enum");
strictEqual(enums.length, 0);
const colorTcgcProperty = {
kind: "property",
type: {
kind: "union",
name: undefined,
generatedName: "TestColor",
values: [
{
kind: "constant",
value: "red",
},
{
kind: "constant",
value: "blue",
},
],
}
}
enum LR {
left,
right,
}
enum UD {
up,
down,
}
model Test {
orientation: LR | UD;
}
const enums = getAllModels(sdkContext).find(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["LR", "UD"])
const orientationTcgcOutput = {
kind: "property",
type: {
kind: "union",
name: undefined,
generatedName: "TestOrientation",
values: [
{
kind: "enum",
name: "LR",
isFixed: true,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
}
],
},
{
kind: "enum",
name: "UD",
isFixed: true,
values: [
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
}
],
},
]
}
}
All named unions will be generated as enums. This involves flattening out enums if they are the values in a named union.
union Colors {
red: "red",
blue: "blue",
string
}
model Test {
color: Colors,
}
const enums = getAllModels(sdkContext).filter(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Colors"]);
const colorTcgcProperty = {
kind: "property",
type: {
kind: "enum",
name: Colors,
generatedName: undefined,
isFixed: false,
values: [
{
kind: "enumvalue",
value: "red",
},
{
kind: "enumvalue",
value: "blue",
},
],
}
}
union Colors {
red: "red",
blue: "blue",
}
model Test {
color: Colors,
}
const enums = getAllModels(sdkContext).filter(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Colors"]);
const colorTcgcProperty = {
kind: "property",
type: {
kind: "enum",
name: Colors,
isFixed: true,
values: [
{
kind: "enumvalue",
name: "red",
value: "red",
},
{
kind: "enumvalue",
name: "blue",
value: "blue",
},
],
}
}
enum LR {
left,
right,
}
enum UD {
up,
down,
}
union Orientation {
lr: LR,
ud: UD,
string,
}
model Test {
orientation: Orientation;
}
const enums = getAllModels(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Orientation"]);
const orientationTcgcProperty = {
kind: "property",
type: {
kind: "enum",
name: "Orientation",
isFixed: false,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
},
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
},
],
}
}
enum LR {
left,
right,
}
enum UD {
up,
down,
}
union Orientation {
lr: LR,
ud: UD,
}
model Test {
orientation: Orientation;
}
const enums = getAllModels(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Orientation"]);
const orientationTcgcProperty = {
kind: "property",
type: {
kind: "enum",
name: "Orientation",
isFixed: true,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
},
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
},
],
}
}
union LR {
left,
right,
string, // just LR is listed as extensible
}
union UD {
up,
down,
}
union Orientation {
lr: LR,
ud: UD,
}
model Test {
orientation: Orientation;
}
const enums = getAllModels(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Orientation"]);
const orientationTcgcProperty = {
kind: "property",
type: {
kind: "enum",
name: "Orientation",
isFixed: false,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
},
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
},
],
}
}
union LR {
left: "left",
right: "right",
string,
}
union UD {
up: "left",
down: "down",
string,
}
model Test {
orientation: LR | UD;
}
const enums = getAllModels(sdkContext).find(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["LR", "UD"])
const orientationTcgcOutput = {
kind: "property",
type: {
kind: "union",
name: undefined,
generatedName: "TestOrientation",
values: [
{
kind: "enum",
name: "LR",
isFixed: false,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
}
],
},
{
kind: "enum",
name: "UD",
isFixed: false,
values: [
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
}
],
},
]
}
}
union LR {
left: "left",
right: "right",
}
union UD {
up: "left",
down: "down",
}
model Test {
orientation: LR | UD;
}
const enums = getAllModels(sdkContext).find(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["LR", "UD"])
const orientationTcgcOutput = {
kind: "property",
type: {
kind: "union",
name: undefined,
generatedName: "TestOrientation",
values: [
{
kind: "enum",
name: "LR",
isFixed: true,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
}
],
},
{
kind: "enum",
name: "UD",
isFixed: true,
values: [
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
}
],
},
]
}
}
union Orientation {
lr: "left" | "right",
up: "up" | "down",
}
model Test {
orientation: Orientation;
}
const enums = getAllModels(sdkContext).find(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Orientation"])
const orientationTcgcOutput = {
kind: "property",
type: {
kind: "enum",
name: "Orientation",
isFixed: true,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
},
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
},
],
}
}
union Orientation {
lr: "left" | "right",
up: "up" | "down",
string,
}
model Test {
orientation: Orientation;
}
const enums = getAllModels(sdkContext).find(x => x.kind === "enum");
deepStrictEqual(enums.map(x => x.name), ["Orientation"])
const orientationTcgcOutput = {
kind: "property",
type: {
kind: "enum",
name: "Orientation",
isFixed: false,
values: [
{
kind: "enumvalue",
name: "left",
value: "left",
},
{
kind: "enumvalue",
name: "right",
value: "right",
},
{
kind: "enumvalue",
name: "up",
value: "up",
},
{
kind: "enumvalue",
name: "down",
value: "down",
},
],
}
}