diff --git a/.chronus/changes/move_nullable_to_type-2024-4-21-18-6-54.md b/.chronus/changes/move_nullable_to_type-2024-4-21-18-6-54.md new file mode 100644 index 0000000000..449735721e --- /dev/null +++ b/.chronus/changes/move_nullable_to_type-2024-4-21-18-6-54.md @@ -0,0 +1,7 @@ +--- +changeKind: breaking +packages: + - "@azure-tools/typespec-client-generator-core" +--- + +return nullable types as a new type called `SdkNullableType` diff --git a/docs/howtos/DataPlane Generation - DPG/06types.mdx b/docs/howtos/DataPlane Generation - DPG/06types.mdx index f5e9e6bcda..9fdced5ecd 100644 --- a/docs/howtos/DataPlane Generation - DPG/06types.mdx +++ b/docs/howtos/DataPlane Generation - DPG/06types.mdx @@ -39,7 +39,6 @@ model Foo { "serializedName": "prop", "flatten": true, "optional": false, - "nullable": false, "type": { "kind": "model", "name": "Properties", @@ -50,7 +49,6 @@ model Foo { "serializedName": "name", "flatten": false, "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -224,7 +222,6 @@ model Animal is Record { "name": "name", "serializedName": "name", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -235,7 +232,6 @@ model Animal is Record { "name": "kind", "serializedName": "kind", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -244,8 +240,7 @@ model Animal is Record { ], "additionalProperties": { "kind": "any" - }, - "additionalPropertiesNullable": false + } } ``` @@ -353,7 +348,6 @@ model Animal { "name": "name", "serializedName": "name", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -364,7 +358,6 @@ model Animal { "name": "kind", "serializedName": "kind", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -380,7 +373,6 @@ model Animal { "name": "category", "serializedName": "category", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -391,16 +383,13 @@ model Animal { "name": "value", "serializedName": "value", "optional": false, - "nullable": false, "type": { "kind": "any" } } ], - "additionalProperties": undefined, - "additionalPropertiesNullable": undefined - }, - "additionalPropertiesNullable": false + "additionalProperties": undefined + } } ``` @@ -581,7 +570,6 @@ model Animal { "name": "name", "serializedName": "name", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -592,7 +580,6 @@ model Animal { "name": "kind", "serializedName": "kind", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -612,8 +599,7 @@ model Animal { "kind": "int32" } ] - }, - "additionalPropertiesNullable": false + } } ``` @@ -711,7 +697,6 @@ model Animal { "name": "name", "serializedName": "name", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -722,7 +707,6 @@ model Animal { "name": "kind", "serializedName": "kind", "optional": false, - "nullable": false, "type": { "kind": "string", "encode": "string" @@ -730,9 +714,12 @@ model Animal { } ], "additionalProperties": { - "kind": "string" - }, - "additionalPropertiesNullable": true + "kind": "nullable", + "valueType": { + "kind": "string", + "encode": "string" + } + } } ``` @@ -806,6 +793,210 @@ public final class Animal implements JsonSerializable { +### Nullable + +TypeSpec uses `| null` to represent nullable types. Nullability is handled differently in languages, but emitter authors will find information +about nullability by inspecting the type of a property. + + + + +```typespec +model Foo { + basicNullableProperty: string | null; + modelNullableProperty: Bar | null; + unionNullableProperty: Bar | Baz | null; + enumNullableProperty: LR | null; +} + +model Bar { + prop: string; +} + +model Baz { + prop: int32; +} + +enum LR { + left, + right, +} +``` + + + + +A nullable type has kind `nullable` and property `valueType`. The kind of the type tells you the property is nullable, while the `valueType` tells you the underlying type you want to generate. + +```json +{ + "kind": "model", + "name": "Foo", + "properties": [ + { + "kind": "property", + "name": "basicNullableProperty", + "serializedName": "basicNullableProperty", + "optional": false, + "type": { + "kind": "nullable", + "valueType": { + "kind": "string", + "encode": "string" + } + } + }, + { + "kind": "property", + "name": "modelNullableProperty", + "serializedName": "modelNullableProperty", + "optional": false, + "type": { + "kind": "nullable", + "valueType": { + "kind": "model", + "name": "Bar", + "properties": [ + { + "kind": "property", + "name": "prop", + "serializedName": "prop", + "optional": false, + "type": { + "kind": "string", + "encode": "string" + } + } + ] + } + } + }, + { + "kind": "property", + "name": "unionNullableProperty", + "serializedName": "unionNullableProperty", + "optional": false, + "type": { + "kind": "nullable", + "valueType": { + "kind": "union", + "values": [ + { + "kind": "model", + "name": "Bar", + "properties": [ + { + "kind": "property", + "name": "prop", + "serializedName": "prop", + "optional": false, + "type": { + "kind": "string", + "encode": "string" + } + } + ] + }, + { + "kind": "model", + "name": "Baz", + "properties": [ + { + "kind": "property", + "name": "prop", + "serializedName": "prop", + "optional": false, + "type": { + "kind": "int32", + "encode": "int32" + } + } + ] + } + ] + } + } + }, + { + "kind": "property", + "name": "enumNullableProperty", + "serializedName": "enumNullableProperty", + "optional": false, + "type": { + "kind": "nullable", + "valueType": { + "kind": "enum", + "name": "LR", + "generatedName": false, + "valueType": { + "kind": "string" + }, + "values": [ + { + "kind": "enumvalue", + "name": "left", + "value": "left" + }, + { + "kind": "enumvalue", + "name": "right", + "value": "right" + } + ], + "isFixed": true, + "isUnionAsEnum": false + } + } + } + ] +} +``` + + + + +Python treat nullable as optional. If you actually want to send the value `null` to the service without the property being ignored, you can send in `corehttp.serialization.NULL`. Python does not restrict you from setting any property to this value. + +```python +from enum import Enum +from corehttp.utils import CaseInsensitiveEnumMeta + +class Bar(_model_base.Model): + prop: Optional[str] = rest_field() + +class Baz(_model_base.Model): + prop: Optional[str] = rest_field() + +class LR(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LEFT = "left" + RIGHT = "right" + +class Foo(_model_base.Model): + basicNullableProperty: Optional[str] = rest_field() + modelNullableProperty: Optional["_models.Bar"] = rest_field() + unionNullableProperty: Optional[Union["_models.Bar", "_models.Baz"]] = rest_field() + enumNullableProperty: Optional["LR"] = rest_field() + +``` + + + + +TODO + + + + +TODO + + + + +TODO + + + + ## Unions ### Union of literals with same type diff --git a/packages/typespec-client-generator-core/doc/types.tsp b/packages/typespec-client-generator-core/doc/types.tsp index 46da305b4b..8a4b18b7a7 100644 --- a/packages/typespec-client-generator-core/doc/types.tsp +++ b/packages/typespec-client-generator-core/doc/types.tsp @@ -9,13 +9,11 @@ namespace TypeSpec.ClientGenerator.Core; * * @property __raw: the original TypeSpec type * @property kind: the kind of type - * @property nullable: Whether the type is nullable on the wire * @property deprecation: deprecated message if the type is deprecated */ @discriminator("kind") model SdkType { __raw?: unknown; - nullable: boolean; deprecation?: string; } diff --git a/packages/typespec-client-generator-core/src/http.ts b/packages/typespec-client-generator-core/src/http.ts index 157895e26d..5a8d2a90a7 100644 --- a/packages/typespec-client-generator-core/src/http.ts +++ b/packages/typespec-client-generator-core/src/http.ts @@ -45,7 +45,6 @@ import { isAcceptHeader, isContentTypeHeader, isNeverOrVoidType, - isNullable, isSubscriptionId, } from "./internal-utils.js"; import { createDiagnostic } from "./lib.js"; @@ -165,7 +164,6 @@ function getSdkHttpParameters( apiVersions: getAvailableApiVersions(context, tspBody.type, httpOperation.operation), type, optional: false, - nullable: isNullable(tspBody.type), correspondingMethodParams, }; } @@ -234,7 +232,6 @@ function createContentTypeOrAcceptHeader( let type: SdkType = { kind: "string", encode: "string", - nullable: false, }; // for contentType, we treat it as a constant IFF there's one value and it's application/json. // this is to prevent a breaking change when a service adds more content types in the future. @@ -250,7 +247,6 @@ function createContentTypeOrAcceptHeader( ) { // in this case, we just want a content type of application/json type = { - nullable: false, kind: "constant", value: bodyObject.contentTypes[0], valueType: type, @@ -268,7 +264,6 @@ function createContentTypeOrAcceptHeader( isApiVersionParam: false, onClient: false, optional: false, - nullable: false, }; } @@ -397,7 +392,6 @@ function getSdkHttpResponseAndExceptions( details: getDocHelper(context, header).details, serializedName: getHeaderFieldName(context.program, header), type: clientType, - nullable: isNullable(header.type), }); } if (innerResponse.body && !isNeverOrVoidType(innerResponse.body.type)) { @@ -437,7 +431,6 @@ function getSdkHttpResponseAndExceptions( httpOperation.operation, httpOperation.operation ), - nullable: body ? isNullable(body) : true, }; if (response.statusCodes === "*" || (body && isErrorModel(context.program, body))) { exceptions.set(response.statusCodes, sdkResponse); diff --git a/packages/typespec-client-generator-core/src/interfaces.ts b/packages/typespec-client-generator-core/src/interfaces.ts index 8e211f1809..d2d4cf9ec0 100644 --- a/packages/typespec-client-generator-core/src/interfaces.ts +++ b/packages/typespec-client-generator-core/src/interfaces.ts @@ -80,11 +80,6 @@ export interface SdkOperationGroup { interface SdkTypeBase { __raw?: Type; kind: string; - /** - * @deprecated Moving `.nullable` onto the parameter itself for fidelity. - * https://github.com/Azure/typespec-azure/issues/448 - */ - nullable: boolean; deprecation?: string; description?: string; details?: string; @@ -97,6 +92,7 @@ export type SdkType = | SdkArrayType | SdkTupleType | SdkDictionaryType + | SdkNullableType | SdkEnumType | SdkEnumValueType | SdkConstantType @@ -230,7 +226,6 @@ export interface SdkDurationType extends SdkTypeBase { export interface SdkArrayType extends SdkTypeBase { kind: "array"; valueType: SdkType; - nullableValues: boolean; } export interface SdkTupleType extends SdkTypeBase { @@ -242,7 +237,11 @@ export interface SdkDictionaryType extends SdkTypeBase { kind: "dict"; keyType: SdkType; valueType: SdkType; - nullableValues: boolean; +} + +export interface SdkNullableType extends SdkTypeBase { + kind: "nullable"; + type: SdkType; } export interface SdkEnumType extends SdkTypeBase { @@ -289,7 +288,7 @@ export interface SdkModelType extends SdkTypeBase { properties: SdkModelPropertyType[]; name: string; /** - * @deprecated This property is deprecated. Check the bitwise and value of UsageFlags.MultipartFormData nad the `.usage` property on this model + * @deprecated This property is deprecated. Check the bitwise and value of UsageFlags.MultipartFormData and the `.usage` property on this model. */ isFormDataType: boolean; /** @@ -300,7 +299,6 @@ export interface SdkModelType extends SdkTypeBase { access: AccessFlags; usage: UsageFlags; additionalProperties?: SdkType; - additionalPropertiesNullable?: boolean; discriminatorValue?: string; discriminatedSubtypes?: Record; discriminatorProperty?: SdkModelPropertyType; @@ -325,7 +323,6 @@ export interface SdkModelPropertyTypeBase { type: SdkType; /** * @deprecated This property is deprecated. Use `.name` instead. - * https://github.com/Azure/typespec-azure/issues/446 */ nameInClient: string; name: string; @@ -337,7 +334,6 @@ export interface SdkModelPropertyTypeBase { clientDefaultValue?: any; isApiVersionParam: boolean; optional: boolean; - nullable: boolean; } export interface SdkEndpointParameter extends SdkModelPropertyTypeBase { @@ -421,21 +417,18 @@ export interface SdkServiceResponseHeader { type: SdkType; description?: string; details?: string; - nullable: boolean; } export interface SdkMethodResponse { kind: "method"; type?: SdkType; - nullable: boolean; - resultPath?: string; // if exists, tells you how to get from the service response to the method response + resultPath?: string; // if exists, tells you how to get from the service response to the method response. } export interface SdkServiceResponse { type?: SdkType; headers: SdkServiceResponseHeader[]; apiVersions: string[]; - nullable: boolean; } export interface SdkHttpResponse extends SdkServiceResponse { @@ -481,16 +474,16 @@ interface SdkMethodBase { interface SdkServiceMethodBase extends SdkMethodBase { /** - * @deprecated This property is deprecated. Access .correspondingMethodParams on the service parameters instead + * @deprecated This property is deprecated. Access .correspondingMethodParams on the service parameters instead. * @param serviceParam */ getParameterMapping(serviceParam: SdkServiceParameter): SdkModelPropertyType[]; operation: TServiceOperation; parameters: SdkMethodParameter[]; /** - * @deprecated This property is deprecated. Access .resultPath on the method response instead + * @deprecated This property is deprecated. Access .resultPath on the method response instead. */ - getResponseMapping(): string | undefined; // how to map service response -> method response (e.g. paging). If undefined, it's a 1:1 mapping + getResponseMapping(): string | undefined; response: SdkMethodResponse; exception?: SdkMethodResponse; } @@ -555,7 +548,7 @@ export interface SdkPackage { models: SdkModelType[]; enums: SdkEnumType[]; /** - * @deprecated This property is deprecated. Look at `.diagnostics` on SdkContext instead + * @deprecated This property is deprecated. Look at `.diagnostics` on SdkContext instead. */ diagnostics: readonly Diagnostic[]; crossLanguagePackageId: string; @@ -573,8 +566,8 @@ export enum UsageFlags { Input = 1 << 1, Output = 1 << 2, ApiVersionEnum = 1 << 3, - // Input will also be set when JsonMergePatch is set + // Input will also be set when JsonMergePatch is set. JsonMergePatch = 1 << 4, - // Input will also be set when MultipartFormData is set + // Input will also be set when MultipartFormData is set. MultipartFormData = 1 << 5, } diff --git a/packages/typespec-client-generator-core/src/internal-utils.ts b/packages/typespec-client-generator-core/src/internal-utils.ts index 2dcad81323..af56cc92f7 100644 --- a/packages/typespec-client-generator-core/src/internal-utils.ts +++ b/packages/typespec-client-generator-core/src/internal-utils.ts @@ -1,4 +1,3 @@ -import { getUnionAsEnum } from "@azure-tools/typespec-azure-core"; import { BooleanLiteral, Diagnostic, @@ -17,7 +16,6 @@ import { getDoc, getNamespaceFullName, getSummary, - ignoreDiagnostics, isNeverType, isNullType, isVoidType, @@ -26,13 +24,13 @@ import { HttpOperation, HttpStatusCodeRange } from "@typespec/http"; import { getAddedOnVersions, getRemovedOnVersions, getVersions } from "@typespec/versioning"; import { SdkBuiltInKinds, + SdkBuiltInType, SdkClient, SdkEnumType, SdkHttpResponse, SdkModelPropertyType, SdkModelType, SdkParameter, - SdkServiceOperation, SdkType, SdkUnionType, } from "./interfaces.js"; @@ -242,13 +240,12 @@ export function getHashForType(type: SdkType): string { interface DefaultSdkTypeBase { __raw: Type; - nullable: boolean; deprecation?: string; kind: TKind; } /** - * Helper function to return default values for nullable, encode etc + * Helper function to return default values for encode etc * @param type */ export function getSdkTypeBaseHelper( @@ -258,7 +255,6 @@ export function getSdkTypeBaseHelper( ): DefaultSdkTypeBase { return { __raw: type, - nullable: false, deprecation: getDeprecationDetails(context.program, type)?.message, kind, }; @@ -347,7 +343,11 @@ export function getNonNullOptions(type: Union): Type[] { return [...type.variants.values()].map((x) => x.type).filter((t) => !isNullType(t)); } -function getAllResponseBodiesAndNonBodyExists( +export function getNullOption(type: Union): Type | undefined { + return [...type.variants.values()].map((x) => x.type).filter((t) => isNullType(t))[0]; +} + +export function getAllResponseBodiesAndNonBodyExists( responses: Map ): { allResponseBodies: SdkType[]; @@ -357,7 +357,7 @@ function getAllResponseBodiesAndNonBodyExists( let nonBodyExists = false; for (const response of responses.values()) { if (response.type) { - if (response.nullable) { + if (response.type.kind === "nullable") { nonBodyExists = true; } allResponseBodies.push(response.type); @@ -374,21 +374,6 @@ export function getAllResponseBodies( return getAllResponseBodiesAndNonBodyExists(responses).allResponseBodies; } -/** - * Determines if a type is nullable. - * @param type - * @returns - */ -export function isNullable(type: Type | SdkServiceOperation): boolean { - if (type.kind === "Union") { - if (getNonNullOptions(type).length < type.variants.size) return true; - return Boolean(ignoreDiagnostics(getUnionAsEnum(type))?.nullable); - } - if (type.kind === "http") { - return getAllResponseBodiesAndNonBodyExists(type.responses).nonBodyExists; - } - return false; -} /** * Use this if you are trying to create a generated name for something without an original TypeSpec type. * @@ -436,3 +421,10 @@ export function getLocationOfOperation(operation: Operation): Namespace | Interf export function isNeverOrVoidType(type: Type): boolean { return isNeverType(type) || isVoidType(type); } + +export function getAnyType(): SdkBuiltInType { + return { + kind: "any", + encode: "string", + }; +} diff --git a/packages/typespec-client-generator-core/src/package.ts b/packages/typespec-client-generator-core/src/package.ts index 514e40a5cd..41f57cb7fa 100644 --- a/packages/typespec-client-generator-core/src/package.ts +++ b/packages/typespec-client-generator-core/src/package.ts @@ -41,7 +41,6 @@ import { SdkServiceMethod, SdkServiceOperation, SdkServiceParameter, - SdkServiceResponseHeader, SdkType, UsageFlags, } from "./interfaces.js"; @@ -49,7 +48,7 @@ import { TCGCContext, createGeneratedName, filterApiVersionsWithDecorators, - getAllResponseBodies, + getAllResponseBodiesAndNonBodyExists, getAvailableApiVersions, getClientNamespaceStringHelper, getDocHelper, @@ -57,7 +56,6 @@ import { getLocationOfOperation, getSdkTypeBaseHelper, isNeverOrVoidType, - isNullable, updateWithApiVersionInformation, } from "./internal-utils.js"; import { createDiagnostic } from "./lib.js"; @@ -201,11 +199,7 @@ function getSdkMethodResponse( ): SdkMethodResponse { const responses = sdkOperation.responses; // TODO: put head as bool here - const headers: SdkServiceResponseHeader[] = []; - for (const response of Object.values(responses)) { - headers.push(...response.headers); - } - const allResponseBodies = getAllResponseBodies(responses); + const { allResponseBodies, nonBodyExists } = getAllResponseBodiesAndNonBodyExists(responses); const responseTypes = new Set(allResponseBodies.map((x) => getHashForType(x))); let type: SdkType | undefined = undefined; if (responseTypes.size > 1) { @@ -214,17 +208,21 @@ function getSdkMethodResponse( __raw: operation, kind: "union", values: allResponseBodies, - nullable: isNullable(sdkOperation), name: createGeneratedName(operation, "UnionResponse"), isGeneratedName: true, }; } else if (responseTypes) { type = allResponseBodies[0]; } + if (nonBodyExists && type) { + type = { + kind: "nullable", + type: type, + }; + } return { kind: "method", type, - nullable: isNullable(sdkOperation), }; } @@ -382,7 +380,6 @@ function getSdkInitializationType< isGeneratedName: true, access: client.kind === "SdkClient" ? "public" : "internal", usage: UsageFlags.Input, - nullable: false, crossLanguageDefinitionId: `${getNamespaceFullName(client.service.namespace!)}.${name}`, apiVersions: context.__tspTypeToApiVersions.get(client.type)!, isFormDataType: false, @@ -412,7 +409,6 @@ function getSdkMethodParameter( name, isGeneratedName: Boolean(libraryName), optional: false, - nullable: false, discriminator: false, serializedName: name, isApiVersionParam: false, @@ -469,7 +465,6 @@ function getSdkEndpointParameter( const name = "endpoint"; type = { kind: "endpoint", - nullable: false, serverUrl: "{endpoint}", templateArguments: [ { @@ -479,7 +474,6 @@ function getSdkEndpointParameter( description: "Service host", kind: "path", onClient: true, - nullable: false, urlEncode: false, optional: false, serializedName: "endpoint", @@ -498,7 +492,6 @@ function getSdkEndpointParameter( const templateArguments: SdkPathParameter[] = []; type = { kind: "endpoint", - nullable: false, serverUrl: servers[0].url, templateArguments, }; @@ -539,7 +532,6 @@ function getSdkEndpointParameter( apiVersions: context.__tspTypeToApiVersions.get(client.type)!, optional, isApiVersionParam: false, - nullable: false, }); } diff --git a/packages/typespec-client-generator-core/src/types.ts b/packages/typespec-client-generator-core/src/types.ts index abf4e48160..9ef1b97655 100644 --- a/packages/typespec-client-generator-core/src/types.ts +++ b/packages/typespec-client-generator-core/src/types.ts @@ -76,17 +76,18 @@ import { } from "./interfaces.js"; import { createGeneratedName, + getAnyType, getAvailableApiVersions, getDocHelper, getLocationOfOperation, getNonNullOptions, + getNullOption, getSdkTypeBaseHelper, intOrFloat, isAzureCoreModel, isMultipartFormData, isMultipartOperation, isNeverOrVoidType, - isNullable, updateWithApiVersionInformation, } from "./internal-utils.js"; import { createDiagnostic } from "./lib.js"; @@ -104,13 +105,6 @@ import { UnionEnumVariant } from "../../typespec-azure-core/dist/src/helpers/uni import { getSdkHttpParameter, isSdkHttpParameter } from "./http.js"; import { TCGCContext } from "./internal-utils.js"; -function getAnyType(context: TCGCContext, type: Type): SdkBuiltInType { - return { - ...getSdkTypeBaseHelper(context, type, "any"), - encode: getEncodeHelper(context, type, "any"), - }; -} - function getEncodeHelper(context: TCGCContext, type: Type, kind: string): string { if (type.kind === "ModelProperty" || type.kind === "Scalar") { return getEncode(context.program, type)?.encoding || kind; @@ -131,8 +125,9 @@ export function addFormatInfo( type: ModelProperty | Scalar, propertyType: SdkType ): void { + const innerType = propertyType.kind === "nullable" ? propertyType.type : propertyType; const format = getFormat(context.program, type) ?? ""; - if (isSdkBuiltInKind(format)) propertyType.kind = format; + if (isSdkBuiltInKind(format)) innerType.kind = format; } /** @@ -150,39 +145,32 @@ export function addEncodeInfo( defaultContentType?: string ): [void, readonly Diagnostic[]] { const diagnostics = createDiagnosticCollector(); + const innerType = propertyType.kind === "nullable" ? propertyType.type : propertyType; const encodeData = getEncode(context.program, type); - if (propertyType.kind === "duration") { + if (innerType.kind === "duration") { if (!encodeData) return diagnostics.wrap(undefined); - propertyType.encode = encodeData.encoding as DurationKnownEncoding; - propertyType.wireType = diagnostics.pipe( + innerType.encode = encodeData.encoding as DurationKnownEncoding; + innerType.wireType = diagnostics.pipe( getClientTypeWithDiagnostics(context, encodeData.type) ) as SdkBuiltInType; - if (type.kind === "ModelProperty" && isNullable(type.type)) { - // eslint-disable-next-line deprecation/deprecation - propertyType.wireType.nullable = true; - } } - if (propertyType.kind === "utcDateTime" || propertyType.kind === "offsetDateTime") { + if (innerType.kind === "utcDateTime" || innerType.kind === "offsetDateTime") { if (encodeData) { - propertyType.encode = encodeData.encoding as DateTimeKnownEncoding; - propertyType.wireType = diagnostics.pipe( + innerType.encode = encodeData.encoding as DateTimeKnownEncoding; + innerType.wireType = diagnostics.pipe( getClientTypeWithDiagnostics(context, encodeData.type) ) as SdkBuiltInType; } else if (type.kind === "ModelProperty" && isHeader(context.program, type)) { - propertyType.encode = "rfc7231"; - } - if (type.kind === "ModelProperty" && isNullable(type.type)) { - // eslint-disable-next-line deprecation/deprecation - propertyType.wireType.nullable = true; + innerType.encode = "rfc7231"; } } - if (propertyType.kind === "bytes") { + if (innerType.kind === "bytes") { if (encodeData) { - propertyType.encode = encodeData.encoding as BytesKnownEncoding; + innerType.encode = encodeData.encoding as BytesKnownEncoding; } else if (!defaultContentType || defaultContentType === "application/json") { - propertyType.encode = "base64"; + innerType.encode = "base64"; } else { - propertyType.encode = "bytes"; + innerType.encode = "bytes"; } } return diagnostics.wrap(undefined); @@ -243,7 +231,7 @@ function getSdkBuiltInTypeWithDiagnostics( diagnostics.add( createDiagnostic({ code: "unsupported-kind", target: type, format: { kind: type.kind } }) ); - return diagnostics.wrap(getAnyType(context, type)); + return diagnostics.wrap(getAnyType()); } export function getSdkBuiltInType( @@ -297,14 +285,12 @@ export function getSdkArrayOrDictWithDiagnostics( getClientTypeWithDiagnostics(context, type.indexer.key, operation) ), valueType, - nullableValues: isNullable(type.indexer.value!), }); } else if (name === "integer") { // only array's index key name is integer return diagnostics.wrap({ ...getSdkTypeBaseHelper(context, type, "array"), valueType, - nullableValues: isNullable(type.indexer.value!), }); } } @@ -345,26 +331,20 @@ export function getSdkUnionWithDiagnostics( ): [SdkType, readonly Diagnostic[]] { const diagnostics = createDiagnosticCollector(); const nonNullOptions = getNonNullOptions(type); + const nullOption = getNullOption(type); + let retval: SdkType | undefined = undefined; + if (nonNullOptions.length === 0) { diagnostics.add(createDiagnostic({ code: "union-null", target: type })); - return diagnostics.wrap(getAnyType(context, type)); + return diagnostics.wrap(getAnyType()); } - // convert to normal type if the union is type | null if (nonNullOptions.length === 1) { - const clientType = diagnostics.pipe( - getClientTypeWithDiagnostics(context, nonNullOptions[0], operation) - ); - // eslint-disable-next-line deprecation/deprecation - clientType.nullable = isNullable(type); - clientType.__raw = type; - return diagnostics.wrap(clientType); - } - - // judge if the union can be converted to enum - // if language does not need flatten union as enum - // need to filter the case that union is composed of union or enum - if ( + retval = diagnostics.pipe(getClientTypeWithDiagnostics(context, nonNullOptions[0], operation)); + } else if ( + // judge if the union can be converted to enum + // if language does not need flatten union as enum + // filter the case that union is composed of union or enum context.flattenUnionAsEnum || ![...type.variants.values()].some((variant) => { return variant.type.kind === "Union" || variant.type.kind === "Enum"; @@ -372,19 +352,30 @@ export function getSdkUnionWithDiagnostics( ) { const unionAsEnum = diagnostics.pipe(getUnionAsEnum(type)); if (unionAsEnum) { - return diagnostics.wrap(getSdkUnionEnum(context, unionAsEnum, operation)); + retval = getSdkUnionEnum(context, unionAsEnum, operation); } } - return diagnostics.wrap({ - ...getSdkTypeBaseHelper(context, type, "union"), - name: getLibraryName(context, type) || getGeneratedName(context, type), - isGeneratedName: !type.name, - values: nonNullOptions.map((x) => - diagnostics.pipe(getClientTypeWithDiagnostics(context, x, operation)) - ), - nullable: isNullable(type), - }); + // other cases + if (retval === undefined) { + retval = { + ...getSdkTypeBaseHelper(context, type, "union"), + name: getLibraryName(context, type) || getGeneratedName(context, type), + isGeneratedName: !type.name, + values: nonNullOptions.map((x) => + diagnostics.pipe(getClientTypeWithDiagnostics(context, x, operation)) + ), + }; + } + + if (nullOption !== undefined) { + retval = { + ...getSdkTypeBaseHelper(context, type, "nullable"), + type: retval, + }; + } + + return diagnostics.wrap(retval); } function getSdkConstantWithDiagnostics( @@ -495,7 +486,6 @@ function addDiscriminatorToModelType( } } else { discriminatorType = { - nullable: false, kind: "string", encode: "string", }; @@ -520,7 +510,6 @@ function addDiscriminatorToModelType( isApiVersionParam: false, isMultipartFileInput: false, // discriminator property cannot be a file flatten: false, // discriminator properties can not be flattened - nullable: false, }); model.discriminatorProperty = model.properties[0]; } @@ -571,14 +560,12 @@ export function getSdkModelWithDiagnostics( sdkType.additionalProperties = diagnostics.pipe( getClientTypeWithDiagnostics(context, type.sourceModel!.indexer!.value!, operation) ); - sdkType.additionalPropertiesNullable = isNullable(type.sourceModel!.indexer!.value!); } // model MyModel { ...Record<>} should be model with additional properties if (type.indexer) { sdkType.additionalProperties = diagnostics.pipe( getClientTypeWithDiagnostics(context, type.indexer.value, operation) ); - sdkType.additionalPropertiesNullable = isNullable(type.indexer.value); } // propreties should be generated first since base model'sdiscriminator handling is depend on derived model's properties diagnostics.pipe(addPropertiesToModelType(context, type, sdkType, operation)); @@ -591,7 +578,6 @@ export function getSdkModelWithDiagnostics( if (baseModel.kind === "dict") { // model MyModel extends Record<> {} should be model with additional properties sdkType.additionalProperties = baseModel.valueType; - sdkType.additionalPropertiesNullable = isNullable(baseModel.valueType.__raw!); } else { sdkType.baseModel = baseModel; } @@ -713,16 +699,15 @@ function getSdkUnionEnumValues( value: member.value, valueType: enumType.valueType, enumType, - nullable: false, }); } return values; } -function getSdkUnionEnum(context: TCGCContext, type: UnionEnum, operation?: Operation) { - let sdkType = context.modelsMap?.get(type.union) as SdkEnumType | undefined; +export function getSdkUnionEnum(context: TCGCContext, type: UnionEnum, operation?: Operation) { + const union = type.union; + let sdkType = context.modelsMap?.get(union) as SdkEnumType | undefined; if (!sdkType) { - const union = type.union; const docWrapper = getDocHelper(context, union); const name = getLibraryName(context, type.union) || getGeneratedName(context, type.union); sdkType = { @@ -735,7 +720,6 @@ function getSdkUnionEnum(context: TCGCContext, type: UnionEnum, operation?: Oper getUnionAsEnumValueType(context, type.union) ?? getSdkEnumValueType(context, type.flattenedMembers.values()), values: [], - nullable: type.nullable, isFixed: !type.open, isFlags: false, usage: UsageFlags.None, // We will add usage as we loop through the operations @@ -880,7 +864,7 @@ export function getClientTypeWithDiagnostics( retval = getSdkEnumValue(context, enumType, type); break; default: - retval = getAnyType(context, type); + retval = getAnyType(); diagnostics.add( createDiagnostic({ code: "unsupported-kind", target: type, format: { kind: type.kind } }) ); @@ -938,7 +922,6 @@ function getSdkCredentialType( __raw: client.service, kind: "credential", scheme: scheme, - nullable: false, }); } } @@ -947,7 +930,6 @@ function getSdkCredentialType( __raw: client.service, kind: "union", values: credentialTypes, - nullable: false, name: createGeneratedName(client.service, "CredentialUnion"), isGeneratedName: true, }; @@ -973,7 +955,6 @@ export function getSdkCredentialParameter( onClient: true, optional: false, isApiVersionParam: false, - nullable: false, }; } @@ -1004,7 +985,6 @@ export function getSdkModelPropertyTypeBase( name, isGeneratedName: false, optional: type.optional, - nullable: isNullable(type.type), ...updateWithApiVersionInformation( context, type, @@ -1194,8 +1174,9 @@ function updateUsageOfModel( options = options ?? {}; options.propagation = options?.propagation ?? true; options.ignoreSubTypeStack = options.ignoreSubTypeStack ?? []; - if (!type || !["model", "enum", "array", "dict", "union", "enumvalue"].includes(type.kind)) - return; + // if (!type || !["model", "enum", "array", "dict", "union", "enumvalue"].includes(type.kind)) + // return; + if (!type) return; if (options?.seenModelNames === undefined) { options.seenModelNames = new Set(); } @@ -1213,6 +1194,10 @@ function updateUsageOfModel( updateUsageOfModel(context, usage, type.enumType, options); return; } + if (type.kind === "nullable") { + updateUsageOfModel(context, usage, type.type, options); + return; + } if (type.kind !== "model" && type.kind !== "enum") return; options.seenModelNames.add(type); diff --git a/packages/typespec-client-generator-core/test/package.test.ts b/packages/typespec-client-generator-core/test/package.test.ts index c94e29ad40..4a048e0ee6 100644 --- a/packages/typespec-client-generator-core/test/package.test.ts +++ b/packages/typespec-client-generator-core/test/package.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable deprecation/deprecation */ import { AzureCoreTestLibrary } from "@azure-tools/typespec-azure-core/testing"; import { ApiKeyAuth, OAuth2Flow, Oauth2Auth } from "@typespec/http"; import { deepStrictEqual, ok, strictEqual } from "assert"; @@ -126,7 +127,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(client.initialization.properties.length, 1); const endpointParam = client.initialization.properties[0]; strictEqual(endpointParam.kind, "endpoint"); - //eslint-disable-next-line deprecation/deprecation strictEqual(endpointParam.nameInClient, "endpoint"); strictEqual(endpointParam.name, "endpoint"); strictEqual(endpointParam.onClient, true); @@ -160,7 +160,6 @@ describe("typespec-client-generator-core: package", () => { const credentialParam = client.initialization.properties.filter( (p): p is SdkCredentialParameter => p.kind === "credential" )[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(credentialParam.nameInClient, "credential"); strictEqual(credentialParam.name, "credential"); strictEqual(credentialParam.onClient, true); @@ -201,7 +200,6 @@ describe("typespec-client-generator-core: package", () => { const credentialParam = client.initialization.properties.filter( (p): p is SdkCredentialParameter => p.kind === "credential" )[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(credentialParam.nameInClient, "credential"); strictEqual(credentialParam.name, "credential"); strictEqual(credentialParam.onClient, true); @@ -247,7 +245,6 @@ describe("typespec-client-generator-core: package", () => { const credentialParam = client.initialization.properties.filter( (p): p is SdkCredentialParameter => p.kind === "credential" )[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(credentialParam.nameInClient, "credential"); strictEqual(credentialParam.name, "credential"); strictEqual(credentialParam.onClient, true); @@ -304,7 +301,6 @@ describe("typespec-client-generator-core: package", () => { )[0]; strictEqual(endpointParam.clientDefaultValue, undefined); strictEqual(endpointParam.urlEncode, false); - //eslint-disable-next-line deprecation/deprecation strictEqual(endpointParam.nameInClient, "endpoint"); strictEqual(endpointParam.name, "endpoint"); strictEqual(endpointParam.type.kind, "endpoint"); @@ -324,7 +320,6 @@ describe("typespec-client-generator-core: package", () => { const credentialParam = client.initialization.properties.filter( (p): p is SdkCredentialParameter => p.kind === "credential" )[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(credentialParam.nameInClient, "credential"); strictEqual(credentialParam.name, "credential"); strictEqual(credentialParam.onClient, true); @@ -374,7 +369,6 @@ describe("typespec-client-generator-core: package", () => { const endpointParam = endpointParams[0]; strictEqual(endpointParam.clientDefaultValue, undefined); strictEqual(endpointParam.urlEncode, false); - //eslint-disable-next-line deprecation/deprecation strictEqual(endpointParam.nameInClient, "endpoint"); strictEqual(endpointParam.name, "endpoint"); strictEqual(endpointParam.onClient, true); @@ -395,7 +389,6 @@ describe("typespec-client-generator-core: package", () => { const apiVersionParam = endpointParamType.templateArguments[1]; strictEqual(apiVersionParam.clientDefaultValue, "v1.0"); strictEqual(apiVersionParam.urlEncode, true); - //eslint-disable-next-line deprecation/deprecation strictEqual(apiVersionParam.nameInClient, "apiVersion"); strictEqual(apiVersionParam.name, "apiVersion"); strictEqual(apiVersionParam.onClient, true); @@ -407,7 +400,6 @@ describe("typespec-client-generator-core: package", () => { (p): p is SdkCredentialParameter => p.kind === "credential" ); ok(credentialParam); - //eslint-disable-next-line deprecation/deprecation strictEqual(credentialParam.nameInClient, "credential"); strictEqual(credentialParam.name, "credential"); strictEqual(credentialParam.onClient, true); @@ -477,7 +469,6 @@ describe("typespec-client-generator-core: package", () => { const apiVersionParam = client.initialization.properties.filter( (p) => p.isApiVersionParam )[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(apiVersionParam.nameInClient, "apiVersion"); strictEqual(apiVersionParam.name, "apiVersion"); strictEqual(apiVersionParam.onClient, true); @@ -544,7 +535,6 @@ describe("typespec-client-generator-core: package", () => { const apiVersionParam = client.initialization.properties.filter( (p) => p.isApiVersionParam )[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(apiVersionParam.nameInClient, "apiVersion"); strictEqual(apiVersionParam.name, "apiVersion"); strictEqual(apiVersionParam.onClient, true); @@ -595,7 +585,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(mainClient.methods.length, 1); strictEqual(mainClient.initialization.properties.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(mainClient.initialization.properties[0].nameInClient, "endpoint"); strictEqual(mainClient.initialization.properties[0].name, "endpoint"); @@ -642,7 +631,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(mainClient.methods.length, 2); ok(mainClient.initialization); strictEqual(mainClient.initialization.properties.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(mainClient.initialization.properties[0].nameInClient, "endpoint"); strictEqual(mainClient.initialization.properties[0].name, "endpoint"); @@ -726,7 +714,6 @@ describe("typespec-client-generator-core: package", () => { const client = sdkPackage.clients[0]; strictEqual(client.initialization.properties.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(client.initialization.properties[0].nameInClient, "endpoint"); strictEqual(client.initialization.properties[0].name, "endpoint"); @@ -757,11 +744,9 @@ describe("typespec-client-generator-core: package", () => { const client = sdkPackage.clients[0]; strictEqual(client.initialization.properties.length, 2); - //eslint-disable-next-line deprecation/deprecation strictEqual(client.initialization.properties[0].nameInClient, "endpoint"); strictEqual(client.initialization.properties[0].name, "endpoint"); const clientApiVersionParam = client.initialization.properties[1]; - //eslint-disable-next-line deprecation/deprecation strictEqual(clientApiVersionParam.nameInClient, "apiVersion"); strictEqual(clientApiVersionParam.name, "apiVersion"); strictEqual(clientApiVersionParam.onClient, true); @@ -806,7 +791,6 @@ describe("typespec-client-generator-core: package", () => { const client = sdkPackage.clients[0]; strictEqual(client.initialization.properties.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(client.initialization.properties[0].nameInClient, "endpoint"); strictEqual(client.initialization.properties[0].name, "endpoint"); @@ -838,12 +822,10 @@ describe("typespec-client-generator-core: package", () => { const client = sdkPackage.clients[0]; strictEqual(client.initialization.properties.length, 2); - //eslint-disable-next-line deprecation/deprecation strictEqual(client.initialization.properties[0].nameInClient, "endpoint"); strictEqual(client.initialization.properties[0].name, "endpoint"); const clientApiVersionParam = client.initialization.properties[1]; - //eslint-disable-next-line deprecation/deprecation strictEqual(clientApiVersionParam.nameInClient, "apiVersion"); strictEqual(clientApiVersionParam.name, "apiVersion"); strictEqual(clientApiVersionParam.onClient, true); @@ -893,12 +875,10 @@ describe("typespec-client-generator-core: package", () => { const client = sdkPackage.clients[0]; strictEqual(client.initialization.properties.length, 2); - //eslint-disable-next-line deprecation/deprecation strictEqual(client.initialization.properties[0].nameInClient, "endpoint"); strictEqual(client.initialization.properties[0].name, "endpoint"); const clientApiVersionParam = client.initialization.properties[1]; - //eslint-disable-next-line deprecation/deprecation strictEqual(clientApiVersionParam.nameInClient, "apiVersion"); strictEqual(clientApiVersionParam.name, "apiVersion"); strictEqual(clientApiVersionParam.onClient, true); @@ -924,7 +904,6 @@ describe("typespec-client-generator-core: package", () => { const apiVersionParam = withApiVersion.operation.parameters[0]; strictEqual(apiVersionParam.kind, "path"); strictEqual(apiVersionParam.serializedName, "apiVersion"); - //eslint-disable-next-line deprecation/deprecation strictEqual(apiVersionParam.nameInClient, "apiVersion"); strictEqual(apiVersionParam.name, "apiVersion"); strictEqual(apiVersionParam.isApiVersionParam, true); @@ -951,14 +930,12 @@ describe("typespec-client-generator-core: package", () => { const methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "path"); strictEqual(methodParam.name, "path"); strictEqual(methodParam.optional, false); strictEqual(methodParam.onClient, false); strictEqual(methodParam.isApiVersionParam, false); strictEqual(methodParam.type.kind, "string"); - strictEqual(methodParam.nullable, false); const serviceOperation = method.operation; strictEqual(serviceOperation.bodyParam, undefined); @@ -969,7 +946,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(pathParam.kind, "path"); strictEqual(pathParam.serializedName, "path"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, "path"); strictEqual(pathParam.name, "path"); strictEqual(pathParam.optional, false); @@ -977,13 +953,11 @@ describe("typespec-client-generator-core: package", () => { strictEqual(pathParam.isApiVersionParam, false); strictEqual(pathParam.type.kind, "string"); strictEqual(pathParam.urlEncode, true); - strictEqual(pathParam.nullable, false); strictEqual(method.response.kind, "method"); strictEqual(method.response.type, undefined); const correspondingMethodParams = pathParam.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(pathParam.name, correspondingMethodParams[0].name); }); @@ -998,11 +972,11 @@ describe("typespec-client-generator-core: package", () => { const sdkPackage = runner.context.experimental_sdkPackage; const method = getServiceMethodOfClient(sdkPackage); const methodParam = method.parameters[0]; - strictEqual(methodParam.nullable, true); + strictEqual(methodParam.type.kind, "nullable"); const serviceOperation = method.operation; const pathParam = serviceOperation.parameters[0]; - strictEqual(pathParam.nullable, true); + strictEqual(pathParam.type.kind, "nullable"); }); it("path defined in model", async () => { @@ -1031,7 +1005,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(pathMethod.onClient, false); strictEqual(pathMethod.isApiVersionParam, false); strictEqual(pathMethod.type.kind, "string"); - strictEqual(pathMethod.nullable, false); const serviceOperation = method.operation; strictEqual(serviceOperation.bodyParam, undefined); @@ -1045,7 +1018,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(pathParam.isApiVersionParam, false); strictEqual(pathParam.type.kind, "string"); strictEqual(pathParam.urlEncode, true); - strictEqual(pathParam.nullable, false); strictEqual(pathParam.correspondingMethodParams.length, 1); deepStrictEqual(pathParam.correspondingMethodParams[0], pathMethod); }); @@ -1066,14 +1038,12 @@ describe("typespec-client-generator-core: package", () => { const methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "header"); strictEqual(methodParam.name, "header"); strictEqual(methodParam.optional, false); strictEqual(methodParam.onClient, false); strictEqual(methodParam.isApiVersionParam, false); strictEqual(methodParam.type.kind, "string"); - strictEqual(methodParam.nullable, false); const serviceOperation = method.operation; strictEqual(serviceOperation.bodyParam, undefined); @@ -1084,7 +1054,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(headerParam.kind, "header"); strictEqual(headerParam.serializedName, "header"); - //eslint-disable-next-line deprecation/deprecation strictEqual(headerParam.nameInClient, "header"); strictEqual(headerParam.name, "header"); strictEqual(headerParam.optional, false); @@ -1092,11 +1061,9 @@ describe("typespec-client-generator-core: package", () => { strictEqual(headerParam.isApiVersionParam, false); strictEqual(headerParam.type.kind, "string"); strictEqual(headerParam.collectionFormat, undefined); - strictEqual(headerParam.nullable, false); const correspondingMethodParams = headerParam.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(headerParam.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(headerParam.name, correspondingMethodParams[0].name); }); @@ -1111,11 +1078,11 @@ describe("typespec-client-generator-core: package", () => { const sdkPackage = runner.context.experimental_sdkPackage; const method = getServiceMethodOfClient(sdkPackage); const methodParam = method.parameters[0]; - strictEqual(methodParam.nullable, true); + strictEqual(methodParam.type.kind, "nullable"); const serviceOperation = method.operation; const headerParam = serviceOperation.parameters[0]; - strictEqual(headerParam.nullable, true); + strictEqual(headerParam.type.kind, "nullable"); }); it("header collection format", async () => { @@ -1150,14 +1117,12 @@ describe("typespec-client-generator-core: package", () => { const methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "query"); strictEqual(methodParam.name, "query"); strictEqual(methodParam.optional, false); strictEqual(methodParam.onClient, false); strictEqual(methodParam.isApiVersionParam, false); strictEqual(methodParam.type.kind, "string"); - strictEqual(methodParam.nullable, false); const serviceOperation = method.operation; strictEqual(serviceOperation.bodyParam, undefined); @@ -1167,7 +1132,6 @@ describe("typespec-client-generator-core: package", () => { const queryParam = serviceOperation.parameters[0]; strictEqual(queryParam.kind, "query"); strictEqual(queryParam.serializedName, "query"); - //eslint-disable-next-line deprecation/deprecation strictEqual(queryParam.nameInClient, "query"); strictEqual(queryParam.name, "query"); strictEqual(queryParam.optional, false); @@ -1175,11 +1139,9 @@ describe("typespec-client-generator-core: package", () => { strictEqual(queryParam.isApiVersionParam, false); strictEqual(queryParam.type.kind, "string"); strictEqual(queryParam.collectionFormat, undefined); - strictEqual(queryParam.nullable, false); const correspondingMethodParams = queryParam.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(queryParam.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(queryParam.name, correspondingMethodParams[0].name); }); @@ -1194,11 +1156,11 @@ describe("typespec-client-generator-core: package", () => { const sdkPackage = runner.context.experimental_sdkPackage; const method = getServiceMethodOfClient(sdkPackage); const methodParam = method.parameters[0]; - strictEqual(methodParam.nullable, true); + strictEqual(methodParam.type.kind, "nullable"); const serviceOperation = method.operation; const queryParam = serviceOperation.parameters[0]; - strictEqual(queryParam.nullable, true); + strictEqual(queryParam.type.kind, "nullable"); }); it("query collection format", async () => { @@ -1244,7 +1206,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(methodBodyParam.onClient, false); strictEqual(methodBodyParam.isApiVersionParam, false); strictEqual(methodBodyParam.type, sdkPackage.models[0]); - strictEqual(methodBodyParam.nullable, false); const methodContentTypeParam = method.parameters.find((x) => x.name === "contentType"); ok(methodContentTypeParam); @@ -1262,17 +1223,14 @@ describe("typespec-client-generator-core: package", () => { strictEqual(bodyParameter.onClient, false); strictEqual(bodyParameter.optional, false); strictEqual(bodyParameter.type, sdkPackage.models[0]); - strictEqual(bodyParameter.nullable, false); const correspondingMethodParams = bodyParameter.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(bodyParameter.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(bodyParameter.name, correspondingMethodParams[0].name); strictEqual(serviceOperation.parameters.length, 1); const contentTypeParam = serviceOperation.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(contentTypeParam.nameInClient, "contentType"); strictEqual(contentTypeParam.name, "contentType"); strictEqual(contentTypeParam.serializedName, "Content-Type"); @@ -1300,11 +1258,11 @@ describe("typespec-client-generator-core: package", () => { const method = getServiceMethodOfClient(sdkPackage); const methodBodyParam = method.parameters.find((x) => x.name === "body"); ok(methodBodyParam); - strictEqual(methodBodyParam.nullable, true); + strictEqual(methodBodyParam.type.kind, "nullable"); const serviceOperation = method.operation; ok(serviceOperation.bodyParam); - strictEqual(serviceOperation.bodyParam.nullable, true); + strictEqual(serviceOperation.bodyParam.type.kind, "nullable"); }); it("body optional", async () => { @@ -1353,13 +1311,11 @@ describe("typespec-client-generator-core: package", () => { const correspondingMethodParams = bodyParameter.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(bodyParameter.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(bodyParameter.name, correspondingMethodParams[0].name); strictEqual(serviceOperation.parameters.length, 1); const contentTypeParam = serviceOperation.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(contentTypeParam.nameInClient, "contentType"); strictEqual(contentTypeParam.name, "contentType"); strictEqual(contentTypeParam.serializedName, "Content-Type"); @@ -1396,7 +1352,6 @@ describe("typespec-client-generator-core: package", () => { let methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "header"); strictEqual(methodParam.name, "header"); strictEqual(methodParam.optional, false); @@ -1406,7 +1361,6 @@ describe("typespec-client-generator-core: package", () => { methodParam = method.parameters[1]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "query"); strictEqual(methodParam.name, "query"); strictEqual(methodParam.optional, false); @@ -1416,7 +1370,6 @@ describe("typespec-client-generator-core: package", () => { methodParam = method.parameters[2]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "body"); strictEqual(methodParam.name, "body"); strictEqual(methodParam.optional, false); @@ -1426,7 +1379,6 @@ describe("typespec-client-generator-core: package", () => { methodParam = method.parameters[3]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "contentType"); strictEqual(methodParam.name, "contentType"); strictEqual(methodParam.optional, false); @@ -1440,7 +1392,6 @@ describe("typespec-client-generator-core: package", () => { ok(serviceOperation.bodyParam); const correspondingBodyParams = serviceOperation.bodyParam.correspondingMethodParams; strictEqual(correspondingBodyParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(correspondingBodyParams[0].nameInClient, "body"); strictEqual(correspondingBodyParams[0].name, "body"); @@ -1451,13 +1402,11 @@ describe("typespec-client-generator-core: package", () => { strictEqual(headerParams.length, 2); let correspondingHeaderParams = headerParams[0].correspondingMethodParams; strictEqual(correspondingHeaderParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(correspondingHeaderParams[0].nameInClient, "header"); strictEqual(correspondingHeaderParams[0].name, "header"); correspondingHeaderParams = headerParams[1].correspondingMethodParams; strictEqual(correspondingHeaderParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(correspondingHeaderParams[0].nameInClient, "contentType"); strictEqual(correspondingHeaderParams[0].name, "contentType"); @@ -1465,7 +1414,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(queryParams.length, 1); const correspondingQueryParams = queryParams[0].correspondingMethodParams; strictEqual(correspondingQueryParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(correspondingQueryParams[0].nameInClient, "query"); strictEqual(correspondingQueryParams[0].name, "query"); }); @@ -1483,7 +1431,6 @@ describe("typespec-client-generator-core: package", () => { let methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "body"); strictEqual(methodParam.name, "body"); strictEqual(methodParam.optional, false); @@ -1493,7 +1440,6 @@ describe("typespec-client-generator-core: package", () => { methodParam = method.parameters[1]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "contentType"); strictEqual(methodParam.name, "contentType"); strictEqual(methodParam.optional, false); @@ -1508,14 +1454,12 @@ describe("typespec-client-generator-core: package", () => { ok(serviceOperation.bodyParam); const correspondingBodyParams = serviceOperation.bodyParam.correspondingMethodParams; strictEqual(correspondingBodyParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(correspondingBodyParams[0].nameInClient, "body"); strictEqual(correspondingBodyParams[0].name, "body"); strictEqual(serviceOperation.parameters.length, 1); const correspondingHeaderParams = serviceOperation.parameters[0].correspondingMethodParams; strictEqual(correspondingHeaderParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(correspondingHeaderParams[0].nameInClient, "contentType"); strictEqual(correspondingHeaderParams[0].name, "contentType"); }); @@ -1531,13 +1475,11 @@ describe("typespec-client-generator-core: package", () => { strictEqual(method.parameters.length, 2); const methodBodyParam = method.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(methodBodyParam.nameInClient, "body"); strictEqual(methodBodyParam.name, "body"); strictEqual(methodBodyParam.type, sdkPackage.models[0]); const methodContentTypeParam = method.parameters[1]; - //eslint-disable-next-line deprecation/deprecation strictEqual(methodContentTypeParam.nameInClient, "contentType"); strictEqual(methodContentTypeParam.name, "contentType"); @@ -1552,7 +1494,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(serviceOperation.parameters.length, 1); const serviceContentTypeParam = serviceOperation.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(serviceContentTypeParam.nameInClient, "contentType"); strictEqual(serviceContentTypeParam.name, "contentType"); strictEqual(serviceContentTypeParam.serializedName, "Content-Type"); @@ -1575,14 +1516,12 @@ describe("typespec-client-generator-core: package", () => { strictEqual(method.parameters.length, 1); const methodAcceptParam = method.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(methodAcceptParam.nameInClient, "accept"); strictEqual(methodAcceptParam.name, "accept"); const serviceOperation = method.operation; strictEqual(serviceOperation.parameters.length, 1); const serviceContentTypeParam = serviceOperation.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(serviceContentTypeParam.nameInClient, "accept"); strictEqual(serviceContentTypeParam.name, "accept"); strictEqual(serviceContentTypeParam.serializedName, "Accept"); @@ -1619,14 +1558,12 @@ describe("typespec-client-generator-core: package", () => { strictEqual(method.parameters.length, 1); const methodAcceptParam = method.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(methodAcceptParam.nameInClient, "accept"); strictEqual(methodAcceptParam.name, "accept"); const serviceOperation = method.operation; strictEqual(serviceOperation.parameters.length, 1); const serviceContentTypeParam = serviceOperation.parameters[0]; - //eslint-disable-next-line deprecation/deprecation strictEqual(serviceContentTypeParam.nameInClient, "accept"); strictEqual(serviceContentTypeParam.name, "accept"); strictEqual(serviceContentTypeParam.serializedName, "Accept"); @@ -1855,8 +1792,6 @@ describe("typespec-client-generator-core: package", () => { ); strictEqual(createResponse.headers.length, 1); strictEqual(createResponse.headers[0].serializedName, "id"); - strictEqual(createResponse.headers[0].nullable, false); - strictEqual(createResponse.nullable, false); strictEqual( createResponse.type, sdkPackage.models.find((x) => x.name === "Widget") @@ -1864,7 +1799,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(method.response.resultPath, undefined); strictEqual(method.response.kind, "method"); - strictEqual(method.response.nullable, false); const methodResponseType = method.response.type; ok(methodResponseType); strictEqual( @@ -1891,10 +1825,9 @@ describe("typespec-client-generator-core: package", () => { const createResponse = serviceResponses.get(200); ok(createResponse); - strictEqual(createResponse.headers[0].nullable, true); - strictEqual(createResponse.nullable, true); - - strictEqual(method.response.nullable, true); + strictEqual(createResponse.headers[0].type.kind, "nullable"); + strictEqual(createResponse.type?.kind, "nullable"); + strictEqual(method.response.type?.kind, "nullable"); }); it("OkResponse with NoContentResponse", async () => { @@ -1913,13 +1846,15 @@ describe("typespec-client-generator-core: package", () => { const okResponse = serviceResponses.get(200); ok(okResponse); - strictEqual(okResponse.nullable, false); const noContentResponse = serviceResponses.get(204); ok(noContentResponse); - strictEqual(noContentResponse.nullable, true); - - strictEqual(method.response.nullable, true); + strictEqual(noContentResponse.type, undefined); + strictEqual(method.response.type?.kind, "nullable"); + strictEqual( + method.response.type?.type, + sdkPackage.models.find((x) => x.name === "Widget") + ); }); it("NoContentResponse", async () => { @@ -1932,7 +1867,7 @@ describe("typespec-client-generator-core: package", () => { const method = getServiceMethodOfClient(sdkPackage); strictEqual(sdkPackage.models.length, 0); strictEqual(method.name, "delete"); - strictEqual(method.response.nullable, true); + strictEqual(method.response.type, undefined); const serviceResponses = method.operation.responses; strictEqual(serviceResponses.size, 1); @@ -1941,7 +1876,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(voidResponse.kind, "http"); strictEqual(voidResponse.type, undefined); strictEqual(voidResponse.headers.length, 0); - strictEqual(voidResponse.nullable, true); strictEqual(method.response.type, undefined); strictEqual(method.response.resultPath, undefined); @@ -1999,7 +1933,6 @@ describe("typespec-client-generator-core: package", () => { const bodyParameter = method.operation.bodyParam; ok(bodyParameter); strictEqual(bodyParameter.kind, "body"); - //eslint-disable-next-line deprecation/deprecation strictEqual(bodyParameter.nameInClient, "widget"); strictEqual(bodyParameter.name, "widget"); strictEqual(bodyParameter.onClient, false); @@ -2072,7 +2005,6 @@ describe("typespec-client-generator-core: package", () => { ok(pathParam); strictEqual(pathParam.kind, "path"); strictEqual(pathParam.serializedName, "id"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, "id"); strictEqual(pathParam.name, "id"); strictEqual(pathParam.optional, false); @@ -2090,7 +2022,6 @@ describe("typespec-client-generator-core: package", () => { const correspondingMethodParams = pathParam.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(pathParam.name, correspondingMethodParams[0].name); }); @@ -2105,7 +2036,6 @@ describe("typespec-client-generator-core: package", () => { let methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "id"); strictEqual(methodParam.name, "id"); strictEqual(methodParam.optional, false); @@ -2115,7 +2045,6 @@ describe("typespec-client-generator-core: package", () => { methodParam = method.parameters[1]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "widget"); strictEqual(methodParam.name, "widget"); strictEqual(methodParam.optional, false); @@ -2139,7 +2068,6 @@ describe("typespec-client-generator-core: package", () => { ok(pathParam); strictEqual(pathParam.kind, "path"); strictEqual(pathParam.serializedName, "id"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, "id"); strictEqual(pathParam.name, "id"); strictEqual(pathParam.optional, false); @@ -2195,7 +2123,6 @@ describe("typespec-client-generator-core: package", () => { const methodParam = method.parameters[0]; strictEqual(methodParam.kind, "method"); - //eslint-disable-next-line deprecation/deprecation strictEqual(methodParam.nameInClient, "id"); strictEqual(methodParam.name, "id"); strictEqual(methodParam.optional, false); @@ -2209,7 +2136,6 @@ describe("typespec-client-generator-core: package", () => { ok(pathParam); strictEqual(pathParam.kind, "path"); strictEqual(pathParam.serializedName, "id"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, "id"); strictEqual(pathParam.name, "id"); strictEqual(pathParam.optional, false); @@ -2219,7 +2145,6 @@ describe("typespec-client-generator-core: package", () => { const correspondingMethodParams = pathParam.correspondingMethodParams; strictEqual(correspondingMethodParams.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, correspondingMethodParams[0].nameInClient); strictEqual(pathParam.name, correspondingMethodParams[0].name); }); @@ -2458,7 +2383,6 @@ describe("typespec-client-generator-core: package", () => { const pathParam = method.operation.parameters.find((x) => x.kind === "path"); ok(pathParam); strictEqual(pathParam.kind, "path"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam.nameInClient, "widgetName"); strictEqual(pathParam.name, "widgetName"); strictEqual(pathParam.serializedName, "widgetName"); @@ -2469,7 +2393,6 @@ describe("typespec-client-generator-core: package", () => { const queryParam = method.operation.parameters.find((x) => x.kind === "query"); ok(queryParam); strictEqual(queryParam.isApiVersionParam, true); - //eslint-disable-next-line deprecation/deprecation strictEqual(queryParam.nameInClient, "apiVersion"); strictEqual(queryParam.name, "apiVersion"); strictEqual(queryParam.serializedName, "api-version"); @@ -2574,7 +2497,6 @@ describe("typespec-client-generator-core: package", () => { const pathParam1 = pathParams[0]; strictEqual(pathParam1.kind, "path"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam1.nameInClient, "widgetName"); strictEqual(pathParam1.name, "widgetName"); strictEqual(pathParam1.serializedName, "widgetName"); @@ -2584,7 +2506,6 @@ describe("typespec-client-generator-core: package", () => { const pathParam2 = pathParams[1]; strictEqual(pathParam2.kind, "path"); - //eslint-disable-next-line deprecation/deprecation strictEqual(pathParam2.nameInClient, "operationId"); strictEqual(pathParam2.name, "operationId"); strictEqual(pathParam2.serializedName, "operationId"); @@ -2595,7 +2516,6 @@ describe("typespec-client-generator-core: package", () => { const apiVersionParam = getStatus.operation.parameters.find((x) => x.kind === "query"); ok(apiVersionParam); strictEqual(apiVersionParam.isApiVersionParam, true); - //eslint-disable-next-line deprecation/deprecation strictEqual(apiVersionParam.nameInClient, "apiVersion"); strictEqual(apiVersionParam.name, "apiVersion"); strictEqual(apiVersionParam.serializedName, "api-version"); @@ -2609,7 +2529,6 @@ describe("typespec-client-generator-core: package", () => { const operationAcceptParam = getStatus.operation.parameters.find((x) => x.kind === "header"); ok(operationAcceptParam); - // eslint-disable-next-line deprecation/deprecation strictEqual(operationAcceptParam.nameInClient, "accept"); strictEqual(operationAcceptParam.name, "accept"); strictEqual(operationAcceptParam.clientDefaultValue, undefined); @@ -2673,7 +2592,6 @@ describe("typespec-client-generator-core: package", () => { ok(queryParam); strictEqual(queryParam.serializedName, "api-version"); ok(serviceOperation.bodyParam); - //eslint-disable-next-line deprecation/deprecation strictEqual(serviceOperation.bodyParam.nameInClient, "resource"); strictEqual(serviceOperation.bodyParam.name, "resource"); strictEqual(serviceOperation.bodyParam.type, widgetModel); @@ -2787,7 +2705,6 @@ describe("typespec-client-generator-core: package", () => { const apiVersion = operation.parameters.find((x) => x.isApiVersionParam); ok(apiVersion); strictEqual(apiVersion.kind, "query"); - //eslint-disable-next-line deprecation/deprecation strictEqual(apiVersion.nameInClient, "apiVersion"); strictEqual(apiVersion.name, "apiVersion"); strictEqual(apiVersion.serializedName, "api-version"); @@ -2925,7 +2842,6 @@ describe("typespec-client-generator-core: package", () => { strictEqual(bodyParameter.optional, false); strictEqual(bodyParameter.type.kind, "model"); strictEqual(bodyParameter.type.properties.length, 1); - //eslint-disable-next-line deprecation/deprecation strictEqual(bodyParameter.type.properties[0].nameInClient, "name"); strictEqual(bodyParameter.type.properties[0].name, "name"); @@ -2933,8 +2849,8 @@ describe("typespec-client-generator-core: package", () => { strictEqual(correspondingMethodParams.length, 1); strictEqual( - bodyParameter.type.properties[0].nameInClient, //eslint-disable-line deprecation/deprecation - correspondingMethodParams[0].nameInClient //eslint-disable-line deprecation/deprecation + bodyParameter.type.properties[0].nameInClient, + correspondingMethodParams[0].nameInClient ); strictEqual(bodyParameter.type.properties[0].name, correspondingMethodParams[0].name); }); @@ -2989,10 +2905,8 @@ describe("typespec-client-generator-core: package", () => { strictEqual(bodyParameter.optional, false); strictEqual(bodyParameter.type.kind, "model"); strictEqual(bodyParameter.type.properties.length, 2); - //eslint-disable-next-line deprecation/deprecation strictEqual(bodyParameter.type.properties[0].nameInClient, "kind"); strictEqual(bodyParameter.type.properties[0].name, "kind"); - //eslint-disable-next-line deprecation/deprecation strictEqual(bodyParameter.type.properties[1].nameInClient, "name"); strictEqual(bodyParameter.type.properties[1].name, "name"); diff --git a/packages/typespec-client-generator-core/test/public-utils.test.ts b/packages/typespec-client-generator-core/test/public-utils.test.ts index 0c65ff1afa..39a5d4a929 100644 --- a/packages/typespec-client-generator-core/test/public-utils.test.ts +++ b/packages/typespec-client-generator-core/test/public-utils.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable deprecation/deprecation */ import { AzureCoreTestLibrary } from "@azure-tools/typespec-azure-core/testing"; import { Model, @@ -1426,7 +1427,6 @@ describe("typespec-client-generator-core: public-utils", () => { const models = runner.context.experimental_sdkPackage.models; const diagnostics = runner.context.diagnostics; ok(diagnostics); - // eslint-disable-next-line deprecation/deprecation deepStrictEqual(diagnostics, runner.context.experimental_sdkPackage.diagnostics); strictEqual(models.length, 4); const union = models[0].properties[0].type; diff --git a/packages/typespec-client-generator-core/test/types.test.ts b/packages/typespec-client-generator-core/test/types.test.ts index f6ebe9fe5a..4ca2eb576d 100644 --- a/packages/typespec-client-generator-core/test/types.test.ts +++ b/packages/typespec-client-generator-core/test/types.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable deprecation/deprecation */ import { AzureCoreTestLibrary } from "@azure-tools/typespec-azure-core/testing"; import { Enum, Model, Union } from "@typespec/compiler"; import { expectDiagnostics } from "@typespec/compiler/testing"; @@ -245,7 +246,6 @@ describe("typespec-client-generator-core: types", () => { ): void; ` ); - // eslint-disable-next-line deprecation/deprecation expectDiagnostics(runner.context.experimental_sdkPackage.diagnostics, []); expectDiagnostics(runner.context.diagnostics, []); const m = runner.context.experimental_sdkPackage.models.find((x) => x.name === "TestModel"); @@ -363,16 +363,13 @@ describe("typespec-client-generator-core: types", () => { } ` ); - const sdkType = getSdkTypeHelper(runner); + const nullableType = getSdkTypeHelper(runner); + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; strictEqual(sdkType.kind, "duration"); strictEqual(sdkType.wireType.kind, "float"); strictEqual(sdkType.encode, "seconds"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.nullable, true); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.wireType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, true); }); it("float seconds decorated scalar", async function () { @@ -477,16 +474,13 @@ describe("typespec-client-generator-core: types", () => { } ` ); - const sdkType = getSdkTypeHelper(runner); + const nullableType = getSdkTypeHelper(runner); + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; strictEqual(sdkType.kind, "utcDateTime"); strictEqual(sdkType.wireType.kind, "int64"); strictEqual(sdkType.encode, "unixTimestamp"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.nullable, true); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.wireType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, true); }); it("unixTimestamp array", async function () { @@ -542,12 +536,11 @@ describe("typespec-client-generator-core: types", () => { } `); - const sdkType = getSdkTypeHelper(runner); + const nullableType = getSdkTypeHelper(runner); + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; strictEqual(sdkType.kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, true); }); it("nullable with more types", async function () { @@ -559,15 +552,14 @@ describe("typespec-client-generator-core: types", () => { } `); - const sdkType = getSdkTypeHelper(runner); + const nullableType = getSdkTypeHelper(runner); + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; strictEqual(sdkType.kind, "union"); strictEqual(sdkType.values.length, 2); strictEqual(sdkType.values[0].kind, "string"); strictEqual(sdkType.values[1].kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, true); }); it("record with nullable", async function () { @@ -582,12 +574,8 @@ describe("typespec-client-generator-core: types", () => { const sdkType = getSdkTypeHelper(runner); strictEqual(sdkType.kind, "dict"); const elementType = sdkType.valueType; - strictEqual(elementType.kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(elementType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, false); - strictEqual(sdkType.nullableValues, true); + strictEqual(elementType.kind, "nullable"); + strictEqual(elementType.type.kind, "float32"); }); it("record with nullable with more types", async function () { @@ -602,15 +590,13 @@ describe("typespec-client-generator-core: types", () => { const sdkType = getSdkTypeHelper(runner); strictEqual(sdkType.kind, "dict"); const elementType = sdkType.valueType; - strictEqual(elementType.kind, "union"); - strictEqual(elementType.values.length, 2); - strictEqual(elementType.values[0].kind, "string"); - strictEqual(elementType.values[1].kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(elementType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, false); - strictEqual(sdkType.nullableValues, true); + strictEqual(elementType.kind, "nullable"); + + const elementTypeValueType = elementType.type; + strictEqual(elementTypeValueType.kind, "union"); + strictEqual(elementTypeValueType.values.length, 2); + strictEqual(elementTypeValueType.values[0].kind, "string"); + strictEqual(elementTypeValueType.values[1].kind, "float32"); }); it("array with nullable", async function () { @@ -625,12 +611,8 @@ describe("typespec-client-generator-core: types", () => { const sdkType = getSdkTypeHelper(runner); strictEqual(sdkType.kind, "array"); const elementType = sdkType.valueType; - strictEqual(elementType.kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(elementType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, false); - strictEqual(sdkType.nullableValues, true); + strictEqual(elementType.kind, "nullable"); + strictEqual(elementType.type.kind, "float32"); }); it("array with nullable with more types", async function () { @@ -645,15 +627,12 @@ describe("typespec-client-generator-core: types", () => { const sdkType = getSdkTypeHelper(runner); strictEqual(sdkType.kind, "array"); const elementType = sdkType.valueType; - strictEqual(elementType.kind, "union"); - strictEqual(elementType.values.length, 2); - strictEqual(elementType.values[0].kind, "string"); - strictEqual(elementType.values[1].kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(elementType.nullable, true); - const nameProp = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(nameProp.nullable, false); - strictEqual(sdkType.nullableValues, true); + strictEqual(elementType.kind, "nullable"); + const elementTypeValueType = elementType.type; + strictEqual(elementTypeValueType.kind, "union"); + strictEqual(elementTypeValueType.values.length, 2); + strictEqual(elementTypeValueType.values[0].kind, "string"); + strictEqual(elementTypeValueType.values[1].kind, "float32"); }); it("additional property is nullable", async function () { @@ -684,26 +663,26 @@ describe("typespec-client-generator-core: types", () => { const extendsType = models.find((x) => x.name === "TestExtends"); ok(extendsType); strictEqual(extendsType.kind, "model"); - strictEqual(extendsType.additionalProperties?.kind, "string"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(extendsType.additionalProperties?.nullable, true); - strictEqual(extendsType.additionalPropertiesNullable, true); + const additionalProperties = extendsType.additionalProperties; + ok(additionalProperties); + strictEqual(additionalProperties.kind, "nullable"); + strictEqual(additionalProperties.type.kind, "string"); const isType = models.find((x) => x.name === "TestIs"); ok(isType); strictEqual(isType.kind, "model"); - strictEqual(isType.additionalProperties?.kind, "string"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(isType.additionalProperties?.nullable, true); - strictEqual(isType.additionalPropertiesNullable, true); + const isTypeAdditionalProperties = isType.additionalProperties; + ok(isTypeAdditionalProperties); + strictEqual(isTypeAdditionalProperties.kind, "nullable"); + strictEqual(isTypeAdditionalProperties.type.kind, "string"); const spreadType = models.find((x) => x.name === "TestSpread"); ok(spreadType); strictEqual(spreadType.kind, "model"); - strictEqual(spreadType.additionalProperties?.kind, "string"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(spreadType.additionalProperties?.nullable, true); - strictEqual(spreadType.additionalPropertiesNullable, true); + const spreadTypeAdditionalProperties = spreadType.additionalProperties; + ok(spreadTypeAdditionalProperties); + strictEqual(spreadTypeAdditionalProperties.kind, "nullable"); + strictEqual(spreadTypeAdditionalProperties.type.kind, "string"); }); it("additional property nullable with more types", async function () { @@ -734,41 +713,51 @@ describe("typespec-client-generator-core: types", () => { const extendsType = models.find((x) => x.name === "TestExtends"); ok(extendsType); strictEqual(extendsType.kind, "model"); - strictEqual(extendsType.additionalProperties?.kind, "union"); - strictEqual(extendsType.additionalProperties?.name, "TestExtendsAdditionalProperty"); - strictEqual(extendsType.additionalProperties?.isGeneratedName, true); - strictEqual(extendsType.additionalProperties?.values.length, 2); - strictEqual(extendsType.additionalProperties?.values[0].kind, "string"); - strictEqual(extendsType.additionalProperties?.values[1].kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(extendsType.additionalProperties?.nullable, true); - strictEqual(extendsType.additionalPropertiesNullable, true); + + const extendsTypeAdditionalProperties = extendsType.additionalProperties; + ok(extendsTypeAdditionalProperties); + strictEqual(extendsTypeAdditionalProperties.kind, "nullable"); + const extendsAdPropUnderlyingType = extendsTypeAdditionalProperties.type; + strictEqual(extendsAdPropUnderlyingType.kind, "union"); + strictEqual(extendsAdPropUnderlyingType.name, "TestExtendsAdditionalProperty"); + strictEqual(extendsAdPropUnderlyingType.isGeneratedName, true); + strictEqual(extendsAdPropUnderlyingType.values.length, 2); + strictEqual(extendsAdPropUnderlyingType.values[0].kind, "string"); + strictEqual(extendsAdPropUnderlyingType.values[1].kind, "float32"); const isType = models.find((x) => x.name === "TestIs"); ok(isType); strictEqual(isType.kind, "model"); - strictEqual(isType.additionalProperties?.kind, "union"); - strictEqual(isType.additionalProperties?.name, "TestIsAdditionalProperty"); - strictEqual(isType.additionalProperties?.isGeneratedName, true); - strictEqual(isType.additionalProperties?.values.length, 2); - strictEqual(isType.additionalProperties?.values[0].kind, "string"); - strictEqual(isType.additionalProperties?.values[1].kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(isType.additionalProperties?.nullable, true); - strictEqual(isType.additionalPropertiesNullable, true); + const isTypeAdditionalProperties = isType.additionalProperties; + ok(isTypeAdditionalProperties); + strictEqual(isTypeAdditionalProperties.kind, "nullable"); + + const isTypeAdditionalPropertiesUnderlyingType = isTypeAdditionalProperties.type; + strictEqual(isTypeAdditionalPropertiesUnderlyingType.kind, "union"); + strictEqual(isTypeAdditionalPropertiesUnderlyingType.name, "TestIsAdditionalProperty"); + strictEqual(isTypeAdditionalPropertiesUnderlyingType.isGeneratedName, true); + strictEqual(isTypeAdditionalPropertiesUnderlyingType.values.length, 2); + strictEqual(isTypeAdditionalPropertiesUnderlyingType.values[0].kind, "string"); + strictEqual(isTypeAdditionalPropertiesUnderlyingType.values[1].kind, "float32"); const spreadType = models.find((x) => x.name === "TestSpread"); ok(spreadType); strictEqual(spreadType.kind, "model"); - strictEqual(spreadType.additionalProperties?.kind, "union"); - strictEqual(spreadType.additionalProperties?.name, "TestSpreadAdditionalProperty"); - strictEqual(spreadType.additionalProperties?.isGeneratedName, true); - strictEqual(spreadType.additionalProperties?.values.length, 2); - strictEqual(spreadType.additionalProperties?.values[0].kind, "string"); - strictEqual(spreadType.additionalProperties?.values[1].kind, "float32"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(spreadType.additionalProperties?.nullable, true); - strictEqual(spreadType.additionalPropertiesNullable, true); + + const spreadTypeAdditionalProperties = spreadType.additionalProperties; + ok(spreadTypeAdditionalProperties); + strictEqual(spreadTypeAdditionalProperties.kind, "nullable"); + + const spreadTypeAdditionalPropertiesUnderlyingType = spreadTypeAdditionalProperties.type; + strictEqual(spreadTypeAdditionalPropertiesUnderlyingType.kind, "union"); + strictEqual( + spreadTypeAdditionalPropertiesUnderlyingType.name, + "TestSpreadAdditionalProperty" + ); + strictEqual(spreadTypeAdditionalPropertiesUnderlyingType.isGeneratedName, true); + strictEqual(spreadTypeAdditionalPropertiesUnderlyingType.values.length, 2); + strictEqual(spreadTypeAdditionalPropertiesUnderlyingType.values[0].kind, "string"); + strictEqual(spreadTypeAdditionalPropertiesUnderlyingType.values[1].kind, "float32"); }); it("model with simple union property", async function () { @@ -861,14 +850,35 @@ describe("typespec-client-generator-core: types", () => { } `); - const sdkType = getSdkTypeHelper(runner); + const nullableType = getSdkTypeHelper(runner); + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; strictEqual(sdkType.kind, "enum"); strictEqual(sdkType.isUnionAsEnum, false); strictEqual(sdkType.name, "PetKind"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.nullable, true); - const pet = runner.context.experimental_sdkPackage.models[0].properties[0]; - strictEqual(pet.nullable, true); + + const values = sdkType.values; + strictEqual(values.length, 3); + }); + + it("model with nullable union as enum", async function () { + await runner.compileWithBuiltInService(` + @usage(Usage.input | Usage.output) + @access(Access.public) + model Home { + pet: "dog" | "cat" | "bird" | string | null; + } + `); + + const nullableType = getSdkTypeHelper(runner); + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; + strictEqual(sdkType.kind, "enum"); + strictEqual(sdkType.isUnionAsEnum, true); + strictEqual(sdkType.name, "HomePet"); + const values = sdkType.values; strictEqual(values.length, 3); }); @@ -892,12 +902,12 @@ describe("typespec-client-generator-core: types", () => { strictEqual(models.length, 2); const model = models.find((x) => x.kind === "model" && x.name === "Test"); ok(model); - const sdkType = model.properties[0].type; + const nullableType = model.properties[0].type; + strictEqual(nullableType.kind, "nullable"); + + const sdkType = nullableType.type; strictEqual(sdkType.kind, "model"); strictEqual(sdkType.name, "PropertyModel"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(sdkType.nullable, true); - strictEqual(model.properties[0].nullable, true); }); it("mix types", async function () { @@ -928,9 +938,6 @@ describe("typespec-client-generator-core: types", () => { const nullableModel = models.find((x) => x.kind === "model" && x.name === "TestNullable"); ok(nullableModel); strictEqual(model.properties[0].type.kind, "union"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(model.properties[0].type.nullable, false); - strictEqual(model.properties[0].nullable, false); const unionType = model.properties[0].type; strictEqual(unionType.kind, "union"); for (const v of unionType.values) { @@ -940,11 +947,16 @@ describe("typespec-client-generator-core: types", () => { strictEqual(v.kind, "constant"); } } - strictEqual(nullableModel.properties[0].type.kind, "union"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(nullableModel.properties[0].type.nullable, true); - strictEqual(nullableModel.properties[0].nullable, true); - for (const v of nullableModel.properties[0].type.values) { + const nullableProp = nullableModel.properties[0]; + strictEqual(nullableProp.type.kind, "nullable"); + strictEqual(nullableProp.type.type.kind, "union"); + strictEqual(nullableProp.type.type.values.length, 3); + + // now check without null with help of helper function + strictEqual(nullableModel.properties[0].type.kind, "nullable"); + const sdkType = nullableProp.type.type; + strictEqual(sdkType.kind, "union"); + for (const v of sdkType.values) { if (v.kind === "model") { strictEqual(v.name, "ModelType"); } else { @@ -1005,12 +1017,12 @@ describe("typespec-client-generator-core: types", () => { string, } + @usage(Usage.input | Usage.output) + @access(Access.public) model Foo { prop: string; } - @usage(Usage.input | Usage.output) - @access(Access.public) union NullableUnion { Foo, null @@ -1521,11 +1533,12 @@ describe("typespec-client-generator-core: types", () => { ` )) as { Test: Union }; - const enumType = getClientType(runner.context, Test); + const nullableType = getClientType(runner.context, Test); + strictEqual(nullableType.kind, "nullable"); + + const enumType = nullableType.type; strictEqual(enumType.kind, "enum"); strictEqual(enumType.name, "Test"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(enumType.nullable, true); strictEqual(enumType.isUnionAsEnum, true); const values = enumType.values; strictEqual(values.length, 4); @@ -1572,11 +1585,13 @@ describe("typespec-client-generator-core: types", () => { ` )) as { Test: Union }; - const unionType = getClientType(runner.context, Test); + const nullableType = getClientType(runner.context, Test); + strictEqual(nullableType.kind, "nullable"); + const unionType = nullableType.type; + strictEqual(unionType.kind, "union"); strictEqual(unionType.name, "Test"); - // eslint-disable-next-line deprecation/deprecation - strictEqual(unionType.nullable, true); + const values = unionType.values; strictEqual(values.length, 3); const a = values[0] as SdkEnumType; @@ -1927,7 +1942,6 @@ describe("typespec-client-generator-core: types", () => { (x) => x.kind === "property" && x.serializedName === "encodedWireName" ); ok(jsonEncodedProp); - // eslint-disable-next-line deprecation/deprecation strictEqual(jsonEncodedProp.nameInClient, "jsonEncodedAndProjectedName"); strictEqual(jsonEncodedProp.name, "jsonEncodedAndProjectedName"); @@ -1936,7 +1950,6 @@ describe("typespec-client-generator-core: types", () => { (x) => x.kind === "property" && x.serializedName === "realWireName" ); ok(jsonProjectedProp); - //eslint-disable-next-line deprecation/deprecation strictEqual(jsonProjectedProp.nameInClient, "jsonProjectedName"); strictEqual(jsonProjectedProp.name, "jsonProjectedName"); @@ -1945,7 +1958,6 @@ describe("typespec-client-generator-core: types", () => { (x) => x.kind === "property" && x.serializedName === "regular" ); ok(regularProp); - // eslint-disable-next-line deprecation/deprecation strictEqual(regularProp.nameInClient, "regular"); strictEqual(regularProp.name, "regular"); }); @@ -2197,7 +2209,6 @@ describe("typespec-client-generator-core: types", () => { strictEqual(recursiveModel.properties.length, 1); const prop = recursiveModel.properties[0]; strictEqual(prop.kind, "property"); - //eslint-disable-next-line deprecation/deprecation strictEqual(prop.nameInClient, "prop"); strictEqual(prop.name, "prop"); strictEqual(prop.type.kind, "model"); @@ -3432,12 +3443,10 @@ describe("typespec-client-generator-core: types", () => { const models = getAllModels(runner.context); strictEqual(models.length, 1); strictEqual(models[0].kind, "model"); - // eslint-disable-next-line deprecation/deprecation strictEqual(models[0].isError, true); const rawModel = models[0].__raw; ok(rawModel); strictEqual(rawModel.kind, "Model"); - // eslint-disable-next-line deprecation/deprecation strictEqual(isErrorOrChildOfError(runner.context, rawModel), true); }); @@ -3473,7 +3482,6 @@ describe("typespec-client-generator-core: types", () => { `); const models = getAllModels(runner.context); strictEqual(models.length, 5); - // eslint-disable-next-line deprecation/deprecation const errorModels = models.filter((x) => x.kind === "model" && x.isError); deepStrictEqual(errorModels.map((x) => x.name).sort(), [ "ApiError", @@ -3481,7 +3489,6 @@ describe("typespec-client-generator-core: types", () => { "FourHundredError", "FourZeroFourError", ]); - // eslint-disable-next-line deprecation/deprecation const validModel = models.filter((x) => x.kind === "model" && !x.isError); deepStrictEqual( validModel.map((x) => x.name), @@ -3554,7 +3561,6 @@ describe("typespec-client-generator-core: types", () => { strictEqual(models.length, 1); const model = models[0]; strictEqual(model.kind, "model"); - // eslint-disable-next-line deprecation/deprecation strictEqual(model.isFormDataType, true); ok((model.usage & UsageFlags.MultipartFormData) > 0); strictEqual(model.name, "MultiPartRequest"); @@ -3606,7 +3612,6 @@ describe("typespec-client-generator-core: types", () => { const modelA = models.find((x) => x.name === "A"); ok(modelA); strictEqual(modelA.kind, "model"); - // eslint-disable-next-line deprecation/deprecation strictEqual(modelA.isFormDataType, true); ok((modelA.usage & UsageFlags.MultipartFormData) > 0); strictEqual(modelA.properties.length, 1); @@ -3617,7 +3622,6 @@ describe("typespec-client-generator-core: types", () => { const modelB = models.find((x) => x.name === "B"); ok(modelB); strictEqual(modelB.kind, "model"); - // eslint-disable-next-line deprecation/deprecation strictEqual(modelB.isFormDataType, false); ok((modelB.usage & UsageFlags.MultipartFormData) === 0); strictEqual(modelB.properties.length, 1); @@ -3705,14 +3709,12 @@ describe("typespec-client-generator-core: types", () => { const pictureWrapper = models.find((x) => x.name === "PictureWrapper"); ok(pictureWrapper); - // eslint-disable-next-line deprecation/deprecation strictEqual(pictureWrapper.isFormDataType, true); ok((pictureWrapper.usage & UsageFlags.MultipartFormData) > 0); const errorResponse = models.find((x) => x.name === "ErrorResponse"); ok(errorResponse); strictEqual(errorResponse.kind, "model"); - // eslint-disable-next-line deprecation/deprecation strictEqual(errorResponse.isFormDataType, false); ok((errorResponse.usage & UsageFlags.MultipartFormData) === 0); });