Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,7 @@ function navigateModels(sdkContext: CSharpEmitterContext) {
for (const e of sdkContext.sdkPackage.enums) {
fromSdkType(sdkContext, e);
}
for (const u of sdkContext.sdkPackage.unions) {
fromSdkType(sdkContext, u);
}
}
46 changes: 45 additions & 1 deletion packages/http-client-csharp/emitter/src/lib/type-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,46 @@ function fromSdkBuiltInType(
};
}

function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType): InputUnionType {
function fromUnionType(
sdkContext: CSharpEmitterContext,
union: SdkUnionType,
): InputUnionType | InputModelType {
const variantTypes: InputType[] = [];
for (const value of union.variantTypes) {
const variantType = fromSdkType(sdkContext, value);
variantTypes.push(variantType);
}
if (isDiscriminatedUnion(union)) {
const baseType: InputModelType = {
kind: "model",
name: union.name,
namespace: union.namespace,
crossLanguageDefinitionId: union.crossLanguageDefinitionId,
access: union.access,
usage: union.usage,
properties: [],
serializationOptions: {},
summary: union.summary,
doc: union.doc,
deprecation: union.deprecation,
decorators: union.decorators,
external: fromSdkExternalTypeInfo(union),
} as InputModelType;
const discriminatedSubtypes: Record<string, InputModelType> = {};
variantTypes.forEach((variant) => {
if (variant.kind === "model") {
variant.baseModel = baseType;
if (variant.discriminatorValue !== undefined) {
discriminatedSubtypes[variant.discriminatorValue] = variant;
}
}
});
if (Object.keys(discriminatedSubtypes).length > 0) {
baseType.discriminatedSubtypes = discriminatedSubtypes;
}
//TODO we should hoist the discriminator property to the base type
return baseType;
}

return {
kind: "union",
Expand All @@ -401,6 +435,16 @@ function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType): I
};
}

function isDiscriminatedUnion(sdkType: SdkUnionType): boolean {
if (!sdkType.discriminatedOptions) {
return false;
}

return sdkType.variantTypes.every((variant) => {
return variant.kind === "model" && !variant.baseModel;
});
}

function fromSdkConstantType(
sdkContext: CSharpEmitterContext,
constantType: SdkConstantType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,52 @@ describe("External types", () => {
strictEqual((jsonElementProp.type as any).external.minVersion, "8.0.0");
});
});

describe("Union types to model hierarchies", () => {
let runner: TestHost;

beforeEach(async () => {
runner = await createEmitterTestHost();
});
it("should convert union with members to model hierarchy", async () => {
const program = await typeSpecCompile(
`
model Alpha {
alphaProp: string;
type: "alpha";
}
model Beta {
betaProp: int32;
type: "beta";
}
@discriminated(#{ discriminatorPropertyName: "type", envelope: "none" })
union MyUnion {
"alpha": Alpha,
"beta": Beta
}
op test(@body input: MyUnion): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const root = createModel(sdkContext);

const alphaModel = root.models.find((m) => m.name === "Alpha");
ok(alphaModel, "Alpha should exist");

const betaModel = root.models.find((m) => m.name === "Beta");
ok(betaModel, "Beta should exist");

const myUnion = root.models.find((m) => m.name === "MyUnion");
ok(myUnion, "MyUnion should exist");

// Validate that MyUnion is a model
strictEqual(myUnion.kind, "model", "MyUnion should be converted to a model");

// Validate that Alpha and Beta inherit from MyUnion
strictEqual(alphaModel.baseModel, myUnion, "Alpha should inherit from MyUnion");
strictEqual(betaModel.baseModel, myUnion, "Beta should inherit from MyUnion");
});
});
Loading