Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/microsoft/typespec into cus…
Browse files Browse the repository at this point in the history
…tom-nullable-enum-fix
  • Loading branch information
jorgerangel-msft committed Oct 14, 2024
2 parents 3fb96c9 + ab6d951 commit a878210
Show file tree
Hide file tree
Showing 11 changed files with 464 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@typespec/openapi3"
---

Updates tsp-openapi3 to include path-level parameters in generated typespec operations.
4 changes: 2 additions & 2 deletions packages/http-specs/specs/encode/bytes/mockapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,11 @@ Scenarios.Encode_Bytes_RequestBody_base64 = createRequestBodyServerTests(
);
Scenarios.Encode_Bytes_RequestBody_base64url = createRequestBodyServerTests(
"/encode/bytes/body/request/base64url",
'"dGVzdA=="',
'"dGVzdA"',
{
"Content-Type": "application/json",
},
'"dGVzdA=="',
'"dGVzdA"',
);

Scenarios.Encode_Bytes_RequestBody_customContentType = createRequestBodyServerTests(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,12 @@ Scenarios.Parameters_BodyOptionality_OptionalExplicit = passOnSuccess([
{
uri: "/parameters/body-optionality/optional-explicit/omit",
method: "post",
request: {
body: {
name: "foo",
},
},
request: {},
response: {
status: 204,
},
handler: (req: MockRequest) => {
req.expect.bodyEquals({ name: "foo" });
req.expect.rawBodyEquals(undefined);
return { status: 204 };
},
kind: "MockApiDefinition",
Expand Down
35 changes: 15 additions & 20 deletions packages/http-specs/specs/routes/mockapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,29 @@ export const Scenarios: Record<string, ScenarioMockApi> = {};

function createTests(uri: string) {
const url = new URL("http://example.com" + uri);
const searchParams = url.searchParams;
const params: Record<string, any> = {};
for (const [key, value] of searchParams) {
params[key] = value;
const queryMap = new Map<string, string | string[]>();
for (const [key, value] of url.searchParams.entries()) {
if (queryMap.has(key)) {
const existing = queryMap.get(key)!;
if (Array.isArray(existing)) {
existing.push(value);
} else {
queryMap.set(key, [existing, value]);
}
} else {
queryMap.set(key, value);
}
}
return passOnSuccess({
uri: url.pathname,
method: "get",
request: {
params,
params: Object.fromEntries(queryMap),
},
response: {
status: 204,
},
handler: (req: MockRequest) => {
const queryMap = new Map<string, string | string[]>();
for (const [key, value] of url.searchParams.entries()) {
if (queryMap.has(key)) {
const existing = queryMap.get(key)!;
if (Array.isArray(existing)) {
existing.push(value);
} else {
queryMap.set(key, [existing, value]);
}
} else {
queryMap.set(key, value);
}
}
for (const [key, value] of queryMap.entries()) {
if (Array.isArray(value)) {
req.expect.containsQueryParam(key, value, "multi");
Expand Down Expand Up @@ -155,7 +150,7 @@ Scenarios.Routes_QueryParameters_QueryExpansion_Explode_primitive = createTests(
"/routes/query/query-expansion/explode/primitive?param=a",
);
Scenarios.Routes_QueryParameters_QueryExpansion_Explode_array = createTests(
"/routes/query/query-expansion/explode/array?param=a,b",
"/routes/query/query-expansion/explode/array?param=a&param=b",
);
Scenarios.Routes_QueryParameters_QueryExpansion_Explode_record = createTests(
"/routes/query/query-expansion/explode/record?a=1&b=2",
Expand All @@ -173,7 +168,7 @@ Scenarios.Routes_QueryParameters_QueryContinuation_Explode_primitive = createTes
"/routes/query/query-continuation/explode/primitive?fixed=true&param=a",
);
Scenarios.Routes_QueryParameters_QueryContinuation_Explode_array = createTests(
"/routes/query/query-continuation/explode/array?fixed=true&param=a,b",
"/routes/query/query-continuation/explode/array?fixed=true&param=a&param=b",
);
Scenarios.Routes_QueryParameters_QueryContinuation_Explode_record = createTests(
"/routes/query/query-continuation/explode/record?fixed=true&a=1&b=2",
Expand Down
1 change: 1 addition & 0 deletions packages/openapi3/src/cli/actions/convert/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export interface TypeSpecOperation extends TypeSpecDeclaration {

export interface TypeSpecOperationParameter {
name: string;
in: string;
doc?: string;
decorators: TypeSpecDecorator[];
isOptional: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export function transformPaths(
const operations: TypeSpecOperation[] = [];

for (const route of Object.keys(paths)) {
const routeParameters = paths[route].parameters?.map(transformOperationParameter) ?? [];
const path = paths[route];
for (const verb of supportedHttpMethods) {
const operation = path[verb];
Expand All @@ -48,7 +49,7 @@ export function transformPaths(
{ name: "route", args: [route] },
{ name: verb, args: [] },
],
parameters,
parameters: dedupeParameters([...routeParameters, ...parameters]),
doc: operation.description,
operationId: operation.operationId,
requestBodies: transformRequestBodies(operation.requestBody),
Expand All @@ -61,6 +62,30 @@ export function transformPaths(
return operations;
}

function dedupeParameters(
parameters: Refable<TypeSpecOperationParameter>[],
): Refable<TypeSpecOperationParameter>[] {
const seen = new Set<string>();
const dedupeList: Refable<TypeSpecOperationParameter>[] = [];

// iterate in reverse since more specific-scoped parameters are added last
for (let i = parameters.length - 1; i >= 0; i--) {
// ignore resolving the $ref for now, unlikely to be able to resolve
// issues without user intervention if a duplicate is present except in
// very simple cases.
const param = parameters[i];

const identifier = "$ref" in param ? param.$ref : `${param.in}.${param.name}`;

if (seen.has(identifier)) continue;
seen.add(identifier);

dedupeList.unshift(param);
}

return dedupeList;
}

function transformOperationParameter(
parameter: Refable<OpenAPI3Parameter>,
): Refable<TypeSpecOperationParameter> {
Expand All @@ -70,6 +95,7 @@ function transformOperationParameter(

return {
name: printIdentifier(parameter.name),
in: parameter.in,
doc: parameter.description,
decorators: getParameterDecorators(parameter),
isOptional: !parameter.required,
Expand Down
Loading

0 comments on commit a878210

Please sign in to comment.