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 @@ -204,6 +204,7 @@ function fromSdkClient(
methodParameterSegments: diagnostics.pipe(
getMethodParameterSegments(sdkContext, parameter),
),
isExactName: parameter.isExactName,
Comment thread
jorgerangel-msft marked this conversation as resolved.
});
}
return diagnostics.wrap(parameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ function fromQueryParameter(
crossLanguageDefinitionId: p.crossLanguageDefinitionId,
readOnly: isReadOnly(p),
methodParameterSegments: diagnostics.pipe(getMethodParameterSegments(sdkContext, p)),
isExactName: p.isExactName,
};

sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar);
Expand Down Expand Up @@ -539,6 +540,7 @@ function fromPathParameter(
readOnly: isReadOnly(p),
crossLanguageDefinitionId: p.crossLanguageDefinitionId,
methodParameterSegments: diagnostics.pipe(getMethodParameterSegments(sdkContext, p)),
isExactName: p.isExactName,
};

sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar);
Expand Down Expand Up @@ -574,6 +576,7 @@ function fromHeaderParameter(
crossLanguageDefinitionId: p.crossLanguageDefinitionId,
methodParameterSegments: diagnostics.pipe(getMethodParameterSegments(sdkContext, p)),
collectionHeaderPrefix: diagnostics.pipe(getCollectionHeaderPrefix(sdkContext, p)),
isExactName: p.isExactName,
};

sdkContext.__typeCache.updateSdkOperationParameterReferences(p, retVar);
Expand Down Expand Up @@ -604,6 +607,7 @@ function fromBodyParameter(
readOnly: isReadOnly(p),
crossLanguageDefinitionId: p.crossLanguageDefinitionId,
methodParameterSegments: diagnostics.pipe(getMethodParameterSegments(sdkContext, p)),
isExactName: p.isExactName,
serializationOptions: p.serializationOptions,
};

Expand Down Expand Up @@ -646,6 +650,7 @@ export function fromMethodParameter(
access: p.access,
decorators: p.decorators,
paramAlias,
isExactName: p.isExactName,
};

sdkContext.__typeCache.updateSdkMethodParameterReferences(p, retVar);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ function fromSdkModelType(
decorators: decorators,
external: fromSdkExternalTypeInfo(modelType),
serializationOptions: modelType.serializationOptions,
isExactName: modelType.isExactName,
} as InputModelType;

sdkContext.__typeCache.updateSdkTypeReferences(modelType, inputModelType);
Expand Down Expand Up @@ -291,6 +292,7 @@ function fromSdkModelProperty(
// A property is defined to be metadata if it is marked `@header`, `@cookie`, `@query`, `@path`.
isHttpMetadata: isHttpMetadata(sdkContext, sdkProperty),
encode: sdkProperty.encode,
isExactName: sdkProperty.isExactName,
} as InputModelProperty;

if (property) {
Expand Down Expand Up @@ -342,6 +344,7 @@ function createEnumType(
usage: sdkType.kind === "enum" ? sdkType.usage : UsageFlags.None,
decorators: sdkType.decorators,
external: fromSdkExternalTypeInfo(sdkType),
isExactName: sdkType.isExactName,
};

sdkContext.__typeCache.updateSdkTypeReferences(sdkType, inputEnumType);
Expand Down Expand Up @@ -431,6 +434,7 @@ function fromUnionType(
namespace: union.namespace,
decorators: union.decorators,
external: fromSdkExternalTypeInfo(union),
isExactName: union.isExactName,
});
}

Expand All @@ -448,6 +452,7 @@ function fromSdkConstantType(
valueType: diagnostics.pipe(fromSdkType(sdkContext, constantType.valueType)),
value: constantType.value,
decorators: constantType.decorators,
isExactName: constantType.isExactName,
};

sdkContext.__typeCache.updateConstantCache(constantType, literalType);
Expand Down
10 changes: 10 additions & 0 deletions packages/http-client-csharp/emitter/src/type/input-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export interface InputLiteralType extends InputTypeBase {
namespace: string;
valueType: InputPrimitiveType;
value: string | number | boolean | null;
/** Whether the name should be used exactly as-is, without casing transformations. */
isExactName?: boolean;
}

export function isInputLiteralType(type: InputType): type is InputLiteralType {
Expand Down Expand Up @@ -135,6 +137,8 @@ export interface InputUnionType extends InputTypeBase {
name: string;
variantTypes: InputType[];
namespace: string;
/** Whether the name should be used exactly as-is, without casing transformations. */
isExactName?: boolean;
}

export function isInputUnionType(type: InputType): type is InputUnionType {
Expand All @@ -159,6 +163,8 @@ export interface InputModelType extends InputTypeBase {
discriminatorProperty?: InputModelProperty;
baseModel?: InputModelType;
serializationOptions: SerializationOptions;
/** Whether the name should be used exactly as-is, without casing transformations. */
isExactName?: boolean;
}

export interface InputPropertyTypeBase extends DecoratedType {
Expand All @@ -172,6 +178,8 @@ export interface InputPropertyTypeBase extends DecoratedType {
crossLanguageDefinitionId: string;
readOnly: boolean;
access?: AccessFlags;
/** Whether the name should be used exactly as-is, without casing transformations. */
isExactName?: boolean;
}

export interface InputModelProperty extends InputPropertyTypeBase {
Expand Down Expand Up @@ -266,6 +274,8 @@ export interface InputEnumType extends InputTypeBase {
usage: UsageFlags;
access?: AccessFlags;
namespace: string;
/** Whether the name should be used exactly as-is, without casing transformations. */
isExactName?: boolean;
}

export interface InputEnumValueType extends InputTypeBase {
Expand Down
216 changes: 216 additions & 0 deletions packages/http-client-csharp/emitter/test/Unit/model-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1164,3 +1164,219 @@ describe("XML serialization options", () => {
ok(bodyParam.serializationOptions.json);
});
});

describe("Test isExactName propagation", () => {
let runner: TestHost;

beforeEach(async () => {
runner = await createEmitterTestHost();
});

it("propagates isExactName from @clientName decorator with exact() on property", async () => {
const program = await typeSpecCompile(
`
model Book {
@clientName(Azure.ClientGenerator.Core.exact("snake_case_name"), "csharp")
name: string;
}

op test(@body input: Book): Book;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const bookModel = root.models.find((m) => m.name === "Book");
ok(bookModel);
const nameProp = bookModel.properties.find((p) => p.name === "snake_case_name");
ok(nameProp);
strictEqual(nameProp.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on model", async () => {
const program = await typeSpecCompile(
`
@clientName(Azure.ClientGenerator.Core.exact("my_exact_model"), "csharp")
model Book {
name: string;
}

op test(@body input: Book): Book;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const bookModel = root.models.find((m) => m.name === "my_exact_model");
ok(bookModel);
strictEqual(bookModel.isExactName, true);
});

it("does not set isExactName when @clientName decorator does not use exact()", async () => {
const program = await typeSpecCompile(
`
model Book {
@clientName("regularName")
name: string;
}

op test(@body input: Book): Book;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const bookModel = root.models.find((m) => m.name === "Book");
ok(bookModel);
const nameProp = bookModel.properties.find((p) => p.name === "regularName");
ok(nameProp);
strictEqual(nameProp.isExactName, false);
});

it("propagates isExactName from @clientName decorator with exact() on enum", async () => {
const program = await typeSpecCompile(
`
@clientName(Azure.ClientGenerator.Core.exact("my_exact_enum"), "csharp")
enum Color {
Red,
Green,
Blue,
}

op test(@body input: Color): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const colorEnum = root.enums.find((e) => e.name === "my_exact_enum");
ok(colorEnum);
strictEqual(colorEnum.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on union", async () => {
const program = await typeSpecCompile(
`
@clientName(Azure.ClientGenerator.Core.exact("my_exact_union"), "csharp")
union Color {
string,
"red",
"green",
}

op test(@body input: Color): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const colorEnum = root.enums.find((e) => e.name === "my_exact_union");
ok(colorEnum);
strictEqual(colorEnum.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on a method parameter", async () => {
const program = await typeSpecCompile(
`
op test(@clientName(Azure.ClientGenerator.Core.exact("snake_case_param"), "csharp") regularName: string): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const methodParams = root.clients[0].methods[0].parameters;
const param = methodParams.find((p) => p.name === "snake_case_param");
ok(param);
strictEqual(param.kind, "method");
strictEqual(param.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on a query parameter", async () => {
const program = await typeSpecCompile(
`
op test(@query @clientName(Azure.ClientGenerator.Core.exact("snake_case_query"), "csharp") regularName: string): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const params = root.clients[0].methods[0].operation.parameters;
const param = params.find((p) => p.name === "snake_case_query");
ok(param);
strictEqual(param.kind, "query");
strictEqual(param.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on a header parameter", async () => {
const program = await typeSpecCompile(
`
op test(@header @clientName(Azure.ClientGenerator.Core.exact("snake_case_header"), "csharp") regularName: string): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const params = root.clients[0].methods[0].operation.parameters;
const param = params.find((p) => p.name === "snake_case_header");
ok(param);
strictEqual(param.kind, "header");
strictEqual(param.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on a path parameter", async () => {
const program = await typeSpecCompile(
`
@route("/{regularName}")
op test(@path @clientName(Azure.ClientGenerator.Core.exact("snake_case_path"), "csharp") regularName: string): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const params = root.clients[0].methods[0].operation.parameters;
const param = params.find((p) => p.name === "snake_case_path");
ok(param);
strictEqual(param.kind, "path");
strictEqual(param.isExactName, true);
});

it("propagates isExactName from @clientName decorator with exact() on a body parameter", async () => {
const program = await typeSpecCompile(
`
model Book {
name: string;
}
op test(@body @clientName(Azure.ClientGenerator.Core.exact("snake_case_body"), "csharp") regularName: Book): void;
`,
runner,
{ IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);
const bodyParam = root.clients[0].methods[0].operation.parameters.find(
(p) => p.name === "snake_case_body",
);
ok(bodyParam);
strictEqual(bodyParam.kind, "body");
strictEqual(bodyParam.isExactName, true);
});
});
Loading
Loading