Skip to content

Commit

Permalink
typespec-autorest - remove usage of deprecated isContentTypeHeader (#…
Browse files Browse the repository at this point in the history
…2335)

Similar to OpenAPI3 changes in
microsoft/typespec#6311

---------

Co-authored-by: Christopher Radek <[email protected]>
  • Loading branch information
chrisradek and Christopher Radek authored Mar 7, 2025
1 parent 01e6d76 commit c049424
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: internal
packages:
- "@azure-tools/typespec-autorest"
---

Removes usage of isContentTypeHeader
118 changes: 70 additions & 48 deletions packages/typespec-autorest/src/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,9 @@ import {
HttpOperation,
HttpOperationBody,
HttpOperationMultipartBody,
HttpOperationParameter,
HttpOperationParameters,
HttpOperationPathParameter,
HttpOperationQueryParameter,
HttpOperationResponse,
HttpProperty,
HttpStatusCodeRange,
HttpStatusCodesEntry,
MetadataInfo,
Expand All @@ -126,7 +124,6 @@ import {
getServers,
getStatusCodeDescription,
getVisibilitySuffix,
isContentTypeHeader,
isSharedRoute,
reportIfNoRoutes,
resolveRequestVisibility,
Expand Down Expand Up @@ -280,6 +277,11 @@ interface ProcessedSchema extends PendingSchema {
schema: OpenAPI2Schema | undefined;
}

type HttpParameterProperties = Extract<
HttpProperty,
{ kind: "header" | "query" | "path" | "cookie" }
>;

export async function getOpenAPIForService(
context: AutorestEmitterContext,
options: AutorestDocumentEmitterOptions,
Expand Down Expand Up @@ -444,12 +446,16 @@ export async function getOpenAPIForService(
for (const prop of server.parameters.values()) {
const param = getOpenAPI2Parameter(
{
param: prop,
type: "path",
name: prop.name,
explode: false,
style: "simple",
allowReserved: false,
kind: "path",
path: [],
property: prop,
options: {
allowReserved: false,
explode: false,
style: "simple",
name: prop.name,
type: "path",
},
},
{
visibility: Visibility.Read,
Expand Down Expand Up @@ -1108,23 +1114,22 @@ export async function getOpenAPIForService(
function emitEndpointParameters(methodParams: HttpOperationParameters, visibility: Visibility) {
const consumes: string[] = methodParams.body?.contentTypes ?? [];

for (const httpOpParam of methodParams.parameters) {
const shared = params.get(httpOpParam.param);
for (const httpProperty of methodParams.properties) {
const shared = params.get(httpProperty.property);
if (shared) {
currentEndpoint.parameters.push(shared);
continue;
}

// eslint-disable-next-line @typescript-eslint/no-deprecated
if (httpOpParam.type === "header" && isContentTypeHeader(program, httpOpParam.param)) {
if (!isHttpParameterProperty(httpProperty)) {
continue;
}
if (httpOpParam.type === "cookie") {
reportDiagnostic(program, { code: "cookies-unsupported", target: httpOpParam.param });
if (httpProperty.kind === "cookie") {
reportDiagnostic(program, { code: "cookies-unsupported", target: httpProperty.property });
continue;
}
emitParameter(httpOpParam.param, () =>
getOpenAPI2Parameter(httpOpParam, { visibility, ignoreMetadataAnnotations: false }),
emitParameter(httpProperty.property, () =>
getOpenAPI2Parameter(httpProperty, { visibility, ignoreMetadataAnnotations: false }),
);
}

Expand Down Expand Up @@ -1401,118 +1406,129 @@ export async function getOpenAPIForService(
}
}

function getQueryCollectionFormat(param: HttpOperationQueryParameter): string | undefined {
if (param.explode) {
function getQueryCollectionFormat(
httpProp: HttpProperty & { kind: "query" },
): string | undefined {
if (httpProp.options.explode) {
return "multi";
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
let collectionFormat = param.format;
let collectionFormat = httpProp.options.format;
if (collectionFormat && !["csv", "ssv", "tsv", "pipes", "multi"].includes(collectionFormat)) {
collectionFormat = undefined;
reportDiagnostic(program, { code: "invalid-multi-collection-format", target: param.param });
reportDiagnostic(program, {
code: "invalid-multi-collection-format",
target: httpProp.property,
});
}

return collectionFormat;
}
function getOpenAPI2QueryParameter(
param: HttpOperationQueryParameter,
httpProp: HttpProperty & { kind: "query" },
schemaContext: SchemaContext,
): OpenAPI2QueryParameter {
const base = getOpenAPI2ParameterBase(param.param, param.name);
const collectionFormat = getQueryCollectionFormat(param);
const schema = getSimpleParameterSchema(param.param, schemaContext, base.name);
const property = httpProp.property;
const base = getOpenAPI2ParameterBase(property, httpProp.options.name);
const collectionFormat = getQueryCollectionFormat(httpProp);
const schema = getSimpleParameterSchema(property, schemaContext, base.name);
return {
in: "query",
collectionFormat:
collectionFormat === "csv" && schema.items === undefined // If csv
? undefined
: (collectionFormat as any),
default: param.param.defaultValue && getDefaultValue(param.param.defaultValue, param.param),
default: property.defaultValue && getDefaultValue(property.defaultValue, property),
...base,
...schema,
};
}

function getOpenAPI2PathParameter(
param: HttpOperationPathParameter,
httpProp: HttpProperty & { kind: "path" },
schemaContext: SchemaContext,
): OpenAPI2PathParameter {
const base = getOpenAPI2ParameterBase(param.param, param.name);
const property = httpProp.property;
const base = getOpenAPI2ParameterBase(property, httpProp.options.name);

const result: OpenAPI2PathParameter = {
in: "path",
default: param.param.defaultValue && getDefaultValue(param.param.defaultValue, param.param),
default: property.defaultValue && getDefaultValue(property.defaultValue, property),
...base,
...getSimpleParameterSchema(param.param, schemaContext, base.name),
...getSimpleParameterSchema(property, schemaContext, base.name),
};

if (param.allowReserved) {
if (httpProp.options.allowReserved) {
result["x-ms-skip-url-encoding"] = true;
}

return result;
}

function getOpenAPI2HeaderParameter(
param: ModelProperty,
prop: ModelProperty,
schemaContext: SchemaContext,
name?: string,
): OpenAPI2HeaderParameter {
const base = getOpenAPI2ParameterBase(param, name);
const headerOptions = getHeaderFieldOptions(program, param);
const base = getOpenAPI2ParameterBase(prop, name);
const headerOptions = getHeaderFieldOptions(program, prop);
// eslint-disable-next-line @typescript-eslint/no-deprecated
let collectionFormat = headerOptions.format;
if (
!collectionFormat &&
(typeof headerOptions.explode === "boolean" || $.array.is(param.type))
(typeof headerOptions.explode === "boolean" || $.array.is(prop.type))
) {
collectionFormat = headerOptions.explode ? "multi" : "csv";
}
if (collectionFormat && !["csv", "ssv", "tsv", "pipes"].includes(collectionFormat)) {
collectionFormat = undefined;
reportDiagnostic(program, { code: "invalid-multi-collection-format", target: param });
reportDiagnostic(program, { code: "invalid-multi-collection-format", target: prop });
}
return {
in: "header",
default: param.defaultValue && getDefaultValue(param.defaultValue, param),
default: prop.defaultValue && getDefaultValue(prop.defaultValue, prop),
...base,
collectionFormat: collectionFormat as any,
...getSimpleParameterSchema(param, schemaContext, base.name),
...getSimpleParameterSchema(prop, schemaContext, base.name),
};
}

function getOpenAPI2ParameterInternal(
param: HttpOperationParameter,
httpProperty: HttpParameterProperties,
schemaContext: SchemaContext,
): OpenAPI2Parameter & { in: "query" | "path" | "header" } {
switch (param.type) {
switch (httpProperty.kind) {
case "query":
return getOpenAPI2QueryParameter(param, schemaContext);
return getOpenAPI2QueryParameter(httpProperty, schemaContext);
case "path":
return getOpenAPI2PathParameter(param, schemaContext);
return getOpenAPI2PathParameter(httpProperty, schemaContext);
case "header":
return getOpenAPI2HeaderParameter(param.param, schemaContext, param.name);
return getOpenAPI2HeaderParameter(
httpProperty.property,
schemaContext,
httpProperty.options.name,
);
case "cookie":
compilerAssert(false, "Should verify cookies before");
break;
default:
const _assertNever: never = param;
const _assertNever: never = httpProperty;
compilerAssert(false, "Unreachable");
}
}

function getOpenAPI2Parameter<T extends OpenAPI2Parameter["in"]>(
param: HttpOperationParameter & { type: T },
httpProp: HttpParameterProperties & { kind: T },
schemaContext: SchemaContext,
): OpenAPI2Parameter & { in: T } {
const value = getOpenAPI2ParameterInternal(param, schemaContext);
const value = getOpenAPI2ParameterInternal(httpProp, schemaContext);
// Apply decorators to a copy of the parameter definition. We use
// Object.assign here because applyIntrinsicDecorators returns a new object
// based on the target object and we need to apply its changes back to the
// original parameter.
Object.assign(
value,
applyIntrinsicDecorators(param.param, {
applyIntrinsicDecorators(httpProp.property, {
type: (value as any).type,
format: (value as any).format,
}),
Expand Down Expand Up @@ -2760,3 +2776,9 @@ async function loadExamples(
}
return diagnostics.wrap(map);
}

function isHttpParameterProperty(
httpProperty: HttpProperty,
): httpProperty is HttpParameterProperties {
return ["header", "query", "path", "cookie"].includes(httpProperty.kind);
}

0 comments on commit c049424

Please sign in to comment.