From faf128633b446091a596e46ae85399cb323c8608 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Jan 2024 07:38:06 -0800
Subject: [PATCH 1/4] Bump core from `9bf31a6` to `83a0c3f` (#180)
Bumps [core](https://github.com/microsoft/typespec) from `9bf31a6` to
`83a0c3f`.
Commits
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
core | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core b/core
index 9bf31a65c8..83a0c3f92e 160000
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit 9bf31a65c8cb0b05a6ffdb0693c3f07c1313485b
+Subproject commit 83a0c3f92e1ff4fea1d86afed36d7804795198b6
From 78246545faa50feb5d6ff21f5bd23b7c35c523c6 Mon Sep 17 00:00:00 2001
From: Allen Zhang
Date: Mon, 29 Jan 2024 11:12:14 -0800
Subject: [PATCH 2/4] Update example file values to avoid model validation
errors (#177)
---
.../examples/2021-10-01-preview/Employees_CreateOrUpdate.json | 4 ++--
eng/feeds/arm/examples/2021-10-01-preview/Employees_Get.json | 2 +-
.../2021-10-01-preview/Employees_ListByResourceGroup.json | 2 +-
.../2021-10-01-preview/Employees_ListBySubscription.json | 2 +-
.../arm/examples/2021-10-01-preview/Employees_Update.json | 2 +-
.../arm/examples/2021-10-01-preview/Operations_List.json | 2 +-
6 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/eng/feeds/arm/examples/2021-10-01-preview/Employees_CreateOrUpdate.json b/eng/feeds/arm/examples/2021-10-01-preview/Employees_CreateOrUpdate.json
index 0488455763..9b34209dcd 100644
--- a/eng/feeds/arm/examples/2021-10-01-preview/Employees_CreateOrUpdate.json
+++ b/eng/feeds/arm/examples/2021-10-01-preview/Employees_CreateOrUpdate.json
@@ -31,7 +31,7 @@
"key2913": "urperxmkkhhkp"
},
"location": "itajgxyqozseoygnl",
- "id": "dnkyotqlrefuwxribpzbl",
+ "id": "/subscriptions/11809CA1-E126-4017-945E-AA795CD5C5A9/resourceGroups/rgopenapi/providers/Microsoft.Contoso/employees/le-8MU--J3W6q8D386p3-iT3",
"name": "xepyxhpb",
"type": "svvamxrdnnv",
"systemData": {
@@ -59,7 +59,7 @@
"key2913": "urperxmkkhhkp"
},
"location": "itajgxyqozseoygnl",
- "id": "dnkyotqlrefuwxribpzbl",
+ "id": "/subscriptions/11809CA1-E126-4017-945E-AA795CD5C5A9/resourceGroups/rgopenapi/providers/Microsoft.Contoso/employees/9KF-f-8b",
"name": "xepyxhpb",
"type": "svvamxrdnnv",
"systemData": {
diff --git a/eng/feeds/arm/examples/2021-10-01-preview/Employees_Get.json b/eng/feeds/arm/examples/2021-10-01-preview/Employees_Get.json
index 9dddb10ec0..3ee7ff5b9c 100644
--- a/eng/feeds/arm/examples/2021-10-01-preview/Employees_Get.json
+++ b/eng/feeds/arm/examples/2021-10-01-preview/Employees_Get.json
@@ -20,7 +20,7 @@
"key2913": "urperxmkkhhkp"
},
"location": "itajgxyqozseoygnl",
- "id": "dnkyotqlrefuwxribpzbl",
+ "id": "/subscriptions/11809CA1-E126-4017-945E-AA795CD5C5A9/resourceGroups/rgopenapi/providers/Microsoft.Contoso/employees/le-8MU--J3W6q8D386p3-iT3",
"name": "xepyxhpb",
"type": "svvamxrdnnv",
"systemData": {
diff --git a/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListByResourceGroup.json b/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListByResourceGroup.json
index d69d5da321..f6512d2ba7 100644
--- a/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListByResourceGroup.json
+++ b/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListByResourceGroup.json
@@ -21,7 +21,7 @@
"key2913": "urperxmkkhhkp"
},
"location": "itajgxyqozseoygnl",
- "id": "dnkyotqlrefuwxribpzbl",
+ "id": "/subscriptions/11809CA1-E126-4017-945E-AA795CD5C5A9/resourceGroups/rgopenapi/providers/Microsoft.Contoso/employees/test",
"name": "xepyxhpb",
"type": "svvamxrdnnv",
"systemData": {
diff --git a/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListBySubscription.json b/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListBySubscription.json
index a56830812f..ffa095dd1d 100644
--- a/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListBySubscription.json
+++ b/eng/feeds/arm/examples/2021-10-01-preview/Employees_ListBySubscription.json
@@ -20,7 +20,7 @@
"key2913": "urperxmkkhhkp"
},
"location": "itajgxyqozseoygnl",
- "id": "dnkyotqlrefuwxribpzbl",
+ "id": "/subscriptions/11809CA1-E126-4017-945E-AA795CD5C5A9/resourceGroups/rgopenapi/providers/Microsoft.Contoso/employees/test",
"name": "xepyxhpb",
"type": "svvamxrdnnv",
"systemData": {
diff --git a/eng/feeds/arm/examples/2021-10-01-preview/Employees_Update.json b/eng/feeds/arm/examples/2021-10-01-preview/Employees_Update.json
index c4ada32ff0..f3f85a4656 100644
--- a/eng/feeds/arm/examples/2021-10-01-preview/Employees_Update.json
+++ b/eng/feeds/arm/examples/2021-10-01-preview/Employees_Update.json
@@ -30,7 +30,7 @@
"key2913": "urperxmkkhhkp"
},
"location": "itajgxyqozseoygnl",
- "id": "dnkyotqlrefuwxribpzbl",
+ "id": "/subscriptions/11809CA1-E126-4017-945E-AA795CD5C5A9/resourceGroups/contoso/providers/Microsoft.Contoso/employees/test",
"name": "xepyxhpb",
"type": "svvamxrdnnv",
"systemData": {
diff --git a/eng/feeds/arm/examples/2021-10-01-preview/Operations_List.json b/eng/feeds/arm/examples/2021-10-01-preview/Operations_List.json
index 29986520ea..6185e205aa 100644
--- a/eng/feeds/arm/examples/2021-10-01-preview/Operations_List.json
+++ b/eng/feeds/arm/examples/2021-10-01-preview/Operations_List.json
@@ -21,7 +21,7 @@
"actionType": "Internal"
}
],
- "nextLink": "bamebrbqkebjwevbq"
+ "nextLink": "https://sample.com/nextLink"
}
}
}
From 3f98132a317d967aa495f9d66072583b58a9c5f0 Mon Sep 17 00:00:00 2001
From: iscai-msft <43154838+iscai-msft@users.noreply.github.com>
Date: Mon, 29 Jan 2024 14:50:18 -0500
Subject: [PATCH 3/4] create multipart file sdktype for bytes in a multipart
formdata model (#166)
---
.changeset/chilly-foxes-type.md | 5 ++
.../src/interfaces.ts | 12 ++-
.../typespec-client-generator-core/src/lib.ts | 7 ++
.../src/types.ts | 34 ++++++++
.../test/types.test.ts | 78 +++++++++++++++++++
5 files changed, 134 insertions(+), 2 deletions(-)
create mode 100644 .changeset/chilly-foxes-type.md
diff --git a/.changeset/chilly-foxes-type.md b/.changeset/chilly-foxes-type.md
new file mode 100644
index 0000000000..fabe435e55
--- /dev/null
+++ b/.changeset/chilly-foxes-type.md
@@ -0,0 +1,5 @@
+---
+"@azure-tools/typespec-client-generator-core": patch
+---
+
+add MultipartFile type
diff --git a/packages/typespec-client-generator-core/src/interfaces.ts b/packages/typespec-client-generator-core/src/interfaces.ts
index 3d3500da04..cfef5d2c2e 100644
--- a/packages/typespec-client-generator-core/src/interfaces.ts
+++ b/packages/typespec-client-generator-core/src/interfaces.ts
@@ -83,7 +83,8 @@ export type SdkType =
| SdkEnumValueType
| SdkConstantType
| SdkUnionType
- | SdkModelType;
+ | SdkModelType
+ | SdkMultipartFileType;
export interface SdkBuiltInType extends SdkTypeBase {
kind: SdkBuiltInKinds;
@@ -110,7 +111,8 @@ export type SdkBuiltInKinds =
| "armId"
| "ipAddress"
| "azureLocation"
- | "etag";
+ | "etag"
+ | "multipartFile";
const SdkDatetimeEncodingsConst = ["rfc3339", "rfc7231", "unixTimestamp"] as const;
@@ -130,6 +132,11 @@ export interface SdkDurationType extends SdkTypeBase {
wireType: SdkBuiltInType;
}
+export interface SdkMultipartFileType extends SdkTypeBase {
+ kind: "multipartFile";
+ encode: "binary";
+}
+
export interface SdkArrayType extends SdkTypeBase {
kind: "array";
valueType: SdkType;
@@ -188,6 +195,7 @@ export interface SdkModelType extends SdkTypeBase {
kind: "model";
properties: SdkModelPropertyType[];
name: string;
+ isFormDataType: boolean;
generatedName?: string;
description?: string;
details?: string;
diff --git a/packages/typespec-client-generator-core/src/lib.ts b/packages/typespec-client-generator-core/src/lib.ts
index fb88c7d740..181c9c4d4a 100644
--- a/packages/typespec-client-generator-core/src/lib.ts
+++ b/packages/typespec-client-generator-core/src/lib.ts
@@ -67,6 +67,13 @@ export const $lib = createTypeSpecLibrary({
wrongType: paramMessage`Encoding '${"encoding"}' cannot be used on type '${"type"}'`,
},
},
+ "conflicting-multipart-model-usage": {
+ severity: "error",
+ messages: {
+ default: "Invalid encoding",
+ wrongType: paramMessage`Model '${"modelName"}' cannot be used as both multipart/form-data input and regular body input. You can create a separate model with name 'model ${"modelName"}FormData' extends ${"modelName"} {}`,
+ },
+ },
"discriminator-not-constant": {
severity: "error",
messages: {
diff --git a/packages/typespec-client-generator-core/src/types.ts b/packages/typespec-client-generator-core/src/types.ts
index dc245eca8e..8329b9fbcd 100644
--- a/packages/typespec-client-generator-core/src/types.ts
+++ b/packages/typespec-client-generator-core/src/types.ts
@@ -66,6 +66,7 @@ import {
SdkEnumValueType,
SdkModelPropertyTypeBase,
SdkModelType,
+ SdkMultipartFileType,
SdkTupleType,
SdkType,
} from "./interfaces.js";
@@ -266,6 +267,13 @@ export function getSdkDurationType(context: SdkContext, type: Scalar): SdkDurati
};
}
+function getSdkMultipartFileType(context: SdkContext, type: Scalar): SdkMultipartFileType {
+ return {
+ ...getSdkTypeBaseHelper(context, type, "multipartFile"),
+ encode: "binary",
+ };
+}
+
export function getSdkArrayOrDict(
context: SdkContext,
type: Model,
@@ -433,8 +441,24 @@ function addDiscriminatorToModelType(
export function getSdkModel(context: SdkContext, type: Model, operation?: Operation): SdkModelType {
type = getEffectivePayloadType(context, type);
let sdkType = context.modelsMap?.get(type) as SdkModelType | undefined;
+ const httpOperation = operation
+ ? ignoreDiagnostics(getHttpOperation(context.program, operation))
+ : undefined;
+ const isFormDataType = httpOperation
+ ? Boolean(httpOperation.parameters.body?.contentTypes.includes("multipart/form-data"))
+ : false;
if (sdkType) {
updateModelsMap(context, type, sdkType, operation);
+ if (isFormDataType !== sdkType.isFormDataType) {
+ // This means we have a model that is used both for formdata input and for regular body input
+ reportDiagnostic(context.program, {
+ code: "conflicting-multipart-model-usage",
+ target: type,
+ format: {
+ modelName: sdkType.name,
+ },
+ });
+ }
} else {
const docWrapper = getDocHelper(context, type);
sdkType = {
@@ -448,6 +472,7 @@ export function getSdkModel(context: SdkContext, type: Model, operation?: Operat
access: undefined, // dummy value since we need to update models map before we can set this
usage: UsageFlags.None, // dummy value since we need to update models map before we can set this
crossLanguageDefinitionId: getCrossLanguageDefinitionId(type),
+ isFormDataType,
};
updateModelsMap(context, type, sdkType, operation);
@@ -650,6 +675,15 @@ export function getClientType(context: SdkContext, type: Type, operation?: Opera
if (type.name === "duration") {
return getSdkDurationType(context, type);
}
+ const httpOperation = operation
+ ? ignoreDiagnostics(getHttpOperation(context.program, operation))
+ : undefined;
+ const hasMultipartInput =
+ httpOperation &&
+ httpOperation.parameters.body?.contentTypes.includes("multipart/form-data");
+ if (type.name === "bytes" && hasMultipartInput) {
+ return getSdkMultipartFileType(context, type);
+ }
const scalarType = getSdkBuiltInType(context, type);
// just add default encode, normally encode is on extended scalar and model property
addEncodeInfo(context, type, scalarType);
diff --git a/packages/typespec-client-generator-core/test/types.test.ts b/packages/typespec-client-generator-core/test/types.test.ts
index dbd330f320..e049185f51 100644
--- a/packages/typespec-client-generator-core/test/types.test.ts
+++ b/packages/typespec-client-generator-core/test/types.test.ts
@@ -1,5 +1,6 @@
import { AzureCoreTestLibrary } from "@azure-tools/typespec-azure-core/testing";
import { Enum, UsageFlags } from "@typespec/compiler";
+import { expectDiagnostics } from "@typespec/compiler/testing";
import { deepEqual, deepStrictEqual, strictEqual } from "assert";
import { beforeEach, describe, it } from "vitest";
import {
@@ -1983,6 +1984,83 @@ describe("typespec-client-generator-core: types", () => {
strictEqual(models.length, 2);
});
});
+ describe("SdkMultipartFormType", () => {
+ it("multipart form basic", async function () {
+ await runner.compileWithBuiltInService(`
+ model MultiPartRequest {
+ id: string;
+ profileImage: bytes;
+ }
+
+ op basic(@header contentType: "multipart/form-data", @body body: MultiPartRequest): NoContentResponse;
+ `);
+
+ const models = Array.from(getAllModels(runner.context));
+ strictEqual(models.length, 1);
+ const model = models[0] as SdkModelType;
+ strictEqual(model.kind, "model");
+ strictEqual(model.isFormDataType, true);
+ strictEqual(model.name, "MultiPartRequest");
+ strictEqual(model.properties.length, 2);
+ const id = model.properties.find((x) => x.nameInClient === "id")!;
+ strictEqual(id.kind, "property");
+ strictEqual(id.type.kind, "string");
+ const profileImage = model.properties.find((x) => x.nameInClient === "profileImage")!;
+ strictEqual(profileImage.kind, "property");
+ strictEqual(profileImage.type.kind, "multipartFile");
+ });
+ it("multipart conflicting model usage", async function () {
+ const diagnostics = await runner.diagnose(
+ `
+ @service({title: "Test Service"}) namespace TestService;
+ model MultiPartRequest {
+ id: string;
+ profileImage: bytes;
+ }
+
+ @post op multipartUse(@header contentType: "multipart/form-data", @body body: MultiPartRequest): NoContentResponse;
+ @put op jsonUse(@body body: MultiPartRequest): NoContentResponse;
+ `
+ );
+ getAllModels(runner.context);
+ expectDiagnostics(diagnostics, {
+ code: "@azure-tools/typespec-client-generator-core/conflicting-multipart-model-usage",
+ });
+
+ // expectDiagnostics(getAllModels(runner.context), {
+ // code: "@azure-tools/typespec-client-generator-core/conflicting-multipart-model-usage",
+ // });
+ });
+ it("multipart resolving conflicting model usage with spread", async function () {
+ await runner.compileWithBuiltInService(
+ `
+ model B {
+ doc: bytes
+ }
+
+ model A {
+ ...B
+ }
+
+ @put op multipartOperation(@header contentType: "multipart/form-data", ...A): void;
+ @post op normalOperation(...B): void;
+ `
+ );
+ const models = Array.from(getAllModels(runner.context));
+ strictEqual(models.length, 2);
+ const modelA = models.find((x) => x.name === "A")!;
+ strictEqual(modelA.kind, "model");
+ strictEqual(modelA.isFormDataType, true);
+ strictEqual(modelA.properties.length, 1);
+ strictEqual(modelA.properties[0].type.kind, "multipartFile");
+
+ const modelB = models.find((x) => x.name === "B")!;
+ strictEqual(modelB.kind, "model");
+ strictEqual(modelB.isFormDataType, false);
+ strictEqual(modelB.properties.length, 1);
+ strictEqual(modelB.properties[0].type.kind, "bytes");
+ });
+ });
describe("SdkTupleType", () => {
it("model with tupled properties", async function () {
await runner.compileAndDiagnose(`
From f699d8ef9d94f0202bbf1d3998460376dcbddfda Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Jan 2024 21:45:20 +0000
Subject: [PATCH 4/4] Bump @azure-tools/cadl-ranch-specs from 0.28.7 to 0.29.0
in /packages/e2e-tests/cadl-ranch-specs (#181)
Bumps
[@azure-tools/cadl-ranch-specs](https://github.com/Azure/cadl-ranch)
from 0.28.7 to 0.29.0.
Commits
[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@azure-tools/cadl-ranch-specs&package-manager=npm_and_yarn&previous-version=0.28.7&new-version=0.29.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
packages/e2e-tests/cadl-ranch-specs/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/e2e-tests/cadl-ranch-specs/package.json b/packages/e2e-tests/cadl-ranch-specs/package.json
index 26c9a30c81..7167aa5c18 100644
--- a/packages/e2e-tests/cadl-ranch-specs/package.json
+++ b/packages/e2e-tests/cadl-ranch-specs/package.json
@@ -1,7 +1,7 @@
{
"name": "@azure-tools/typespec-e2e-cadl-ranch-specs",
"dependencies": {
- "@azure-tools/cadl-ranch-specs": "0.28.7"
+ "@azure-tools/cadl-ranch-specs": "0.29.0"
},
"type": "module",
"private": true