Skip to content

Commit

Permalink
Merge pull request #501 from hey-api/fix/duplicate-parameter-type
Browse files Browse the repository at this point in the history
fix: prefix parameter type exports to avoid conflicts
  • Loading branch information
mrlubos authored Apr 27, 2024
2 parents 6c6a484 + 391aa23 commit ffd237d
Show file tree
Hide file tree
Showing 23 changed files with 235 additions and 187 deletions.
5 changes: 5 additions & 0 deletions .changeset/plenty-carpets-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": patch
---

fix: prefix parameter type exports to avoid conflicts
7 changes: 6 additions & 1 deletion packages/openapi-ts/src/openApi/common/parser/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,13 @@ export const getType = (
}

if (typeWithoutNamespace) {
const encodedType =
let encodedType =
ensureValidTypeScriptJavaScriptIdentifier(typeWithoutNamespace);
if (type.startsWith('#/components/parameters/')) {
// prefix parameter names to avoid conflicts, assuming people are mostly
// interested in importing schema types and don't care about this naming
encodedType = `Parameter${encodedType}`;
}
result.type = encodedType;
result.base = encodedType;
if (type.startsWith('#')) {
Expand Down
11 changes: 6 additions & 5 deletions packages/openapi-ts/src/openApi/v2/parser/getModelProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export const getModelProperties = (
getModel: GetModelFn,
): Model[] => {
const models: Model[] = [];
for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
const property = definition.properties[propertyName];

Object.entries(definition.properties ?? {}).forEach(
([propertyName, property]) => {
const propertyRequired = !!definition.required?.includes(propertyName);
if (property.$ref) {
const model = getType(property.$ref);
Expand Down Expand Up @@ -88,7 +88,8 @@ export const getModelProperties = (
uniqueItems: property.uniqueItems,
});
}
}
}
},
);

return models;
};
15 changes: 8 additions & 7 deletions packages/openapi-ts/src/openApi/v2/parser/getModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ import type { OpenApi } from '../interfaces/OpenApi';
import { getModel } from './getModel';

export const getModels = (openApi: OpenApi): Model[] => {
const models: Model[] = [];
for (const definitionName in openApi.definitions) {
if (openApi.definitions.hasOwnProperty(definitionName)) {
const definition = openApi.definitions[definitionName];
let models: Model[] = [];

Object.entries(openApi.definitions ?? {}).forEach(
([definitionName, definition]) => {
const definitionType = getType(definitionName);
const model = getModel(
openApi,
definition,
true,
definitionType.base.replace(reservedWords, '_$1'),
);
models.push(model);
}
}
models = [...models, model];
},
);

return models;
};
18 changes: 7 additions & 11 deletions packages/openapi-ts/src/openApi/v2/parser/getOperationResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,13 @@ export const getOperationResponse = (

// We support basic properties from response headers, since both
// fetch and XHR client just support string types.
if (response.headers) {
for (const name in response.headers) {
if (response.headers.hasOwnProperty(name)) {
operationResponse.in = 'header';
operationResponse.name = name;
operationResponse.type = 'string';
operationResponse.base = 'string';
return operationResponse;
}
}
}
Object.keys(response.headers ?? {}).forEach((name) => {
operationResponse.in = 'header';
operationResponse.name = name;
operationResponse.type = 'string';
operationResponse.base = 'string';
return operationResponse;
});

return operationResponse;
};
25 changes: 11 additions & 14 deletions packages/openapi-ts/src/openApi/v2/parser/getOperationResponses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,19 @@ export const getOperationResponses = (

// Iterate over each response code and get the
// status code and response message
for (const code in responses) {
if (responses.hasOwnProperty(code)) {
const responseOrReference = responses[code];
const response = getRef<OpenApiResponse>(openApi, responseOrReference);
const responseCode = getOperationResponseCode(code);
Object.entries(responses).forEach(([code, responseOrReference]) => {
const response = getRef<OpenApiResponse>(openApi, responseOrReference);
const responseCode = getOperationResponseCode(code);

if (responseCode) {
const operationResponse = getOperationResponse(
openApi,
response,
responseCode,
);
operationResponses.push(operationResponse);
}
if (responseCode) {
const operationResponse = getOperationResponse(
openApi,
response,
responseCode,
);
operationResponses.push(operationResponse);
}
}
});

// Sort the responses to 2xx success codes come before 4xx and 5xx error codes.
return operationResponses.sort((a, b): number =>
Expand Down
89 changes: 42 additions & 47 deletions packages/openapi-ts/src/openApi/v2/parser/getServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,53 @@ import { getOperationParameters } from './getOperationParameters';
*/
export const getServices = (openApi: OpenApi): Service[] => {
const services = new Map<string, Service>();
for (const url in openApi.paths) {
if (openApi.paths.hasOwnProperty(url)) {
// Grab path and parse any global path parameters
const path = openApi.paths[url];
const pathParams = getOperationParameters(openApi, path.parameters || []);

Object.entries(openApi.paths).forEach(([url, path]) => {
// Grab path and parse any global path parameters
const pathParams = getOperationParameters(openApi, path.parameters || []);

Object.keys(path).forEach((method) => {
// Parse all the methods for this path
for (const method in path) {
if (path.hasOwnProperty(method)) {
switch (method) {
case 'get':
case 'put':
case 'post':
case 'delete':
case 'options':
case 'head':
case 'patch': {
// Each method contains an OpenAPI operation, we parse the operation
const op = path[method]!;
const tags = op.tags?.length
? op.tags.filter(unique)
: ['Default'];
tags.forEach((tag) => {
const operation = getOperation(
openApi,
url,
method,
tag,
op,
pathParams,
);
switch (method) {
case 'get':
case 'put':
case 'post':
case 'delete':
case 'options':
case 'head':
case 'patch': {
// Each method contains an OpenAPI operation, we parse the operation
const op = path[method]!;
const tags = op.tags?.length ? op.tags.filter(unique) : ['Default'];
tags.forEach((tag) => {
const operation = getOperation(
openApi,
url,
method,
tag,
op,
pathParams,
);

// If we have already declared a service, then we should fetch that and
// append the new method to it. Otherwise we should create a new service object.
const service: Service = services.get(operation.service) || {
$refs: [],
imports: [],
name: operation.service,
operations: [],
};
// If we have already declared a service, then we should fetch that and
// append the new method to it. Otherwise we should create a new service object.
const service: Service = services.get(operation.service) || {
$refs: [],
imports: [],
name: operation.service,
operations: [],
};

// Push the operation in the service
service.operations.push(operation);
service.imports.push(...operation.imports);
services.set(operation.service, service);
});
break;
}
}
// Push the operation in the service
service.operations.push(operation);
service.imports.push(...operation.imports);
services.set(operation.service, service);
});
break;
}
}
}
}
});
});

return Array.from(services.values());
};
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,8 @@ export const getModelProperties = (
const models: Model[] = [];
const discriminator = findOneOfParentDiscriminator(openApi, parent);

for (const propertyName in definition.properties) {
if (definition.properties.hasOwnProperty(propertyName)) {
const property = definition.properties[propertyName];
Object.entries(definition.properties ?? {}).forEach(
([propertyName, property]) => {
const propertyRequired = !!definition.required?.includes(propertyName);
const propertyValues: Omit<
Model,
Expand Down Expand Up @@ -166,8 +165,8 @@ export const getModelProperties = (
type: model.type,
});
}
}
}
},
);

return models;
};
73 changes: 40 additions & 33 deletions packages/openapi-ts/src/openApi/v3/parser/getModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,46 @@ import type { OpenApi } from '../interfaces/OpenApi';
import { getModel } from './getModel';

export const getModels = (openApi: OpenApi): Model[] => {
const models: Model[] = [];
if (openApi.components) {
for (const definitionName in openApi.components.schemas) {
if (openApi.components.schemas.hasOwnProperty(definitionName)) {
const definition = openApi.components.schemas[definitionName];
const definitionType = getType(definitionName);
const model = getModel(
openApi,
definition,
true,
definitionType.base.replace(reservedWords, '_$1'),
);
models.push(model);
}
}
for (const definitionName in openApi.components.parameters) {
if (openApi.components.parameters.hasOwnProperty(definitionName)) {
const definition = openApi.components.parameters[definitionName];
const definitionType = getType(definitionName);
const schema = definition.schema;
if (schema) {
const model = getModel(
openApi,
schema,
true,
definitionType.base.replace(reservedWords, '_$1'),
);
model.description = definition.description || null;
model.deprecated = definition.deprecated;
models.push(model);
}
}
}
if (!openApi.components) {
return [];
}

let models: Model[] = [];

Object.entries(openApi.components.schemas ?? {}).forEach(
([definitionName, definition]) => {
const definitionType = getType(definitionName);
const model = getModel(
openApi,
definition,
true,
definitionType.base.replace(reservedWords, '_$1'),
);
models = [...models, model];
},
);

Object.entries(openApi.components.parameters ?? {}).forEach(
([definitionName, definition]) => {
const schema = definition.schema;
if (!schema) {
return;
}

const definitionType = getType(definitionName);
const model = getModel(
openApi,
schema,
true,
// prefix parameter names to avoid conflicts, assuming people are mostly
// interested in importing schema types and don't care about this naming
`Parameter${definitionType.base.replace(reservedWords, '_$1')}`,
);
model.deprecated = definition.deprecated;
model.description = definition.description || null;
models = [...models, model];
},
);

return models;
};
18 changes: 7 additions & 11 deletions packages/openapi-ts/src/openApi/v3/parser/getOperationResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,13 @@ export const getOperationResponse = (

// We support basic properties from response headers, since both
// fetch and XHR client just support string types.
if (response.headers) {
for (const name in response.headers) {
if (response.headers.hasOwnProperty(name)) {
operationResponse.in = 'header';
operationResponse.name = name;
operationResponse.type = 'string';
operationResponse.base = 'string';
return operationResponse;
}
}
}
Object.keys(response.headers ?? {}).forEach((name) => {
operationResponse.in = 'header';
operationResponse.name = name;
operationResponse.type = 'string';
operationResponse.base = 'string';
return operationResponse;
});

return operationResponse;
};
25 changes: 11 additions & 14 deletions packages/openapi-ts/src/openApi/v3/parser/getOperationResponses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,19 @@ export const getOperationResponses = (

// Iterate over each response code and get the
// status code and response message
for (const code in responses) {
if (responses.hasOwnProperty(code)) {
const responseOrReference = responses[code];
const response = getRef<OpenApiResponse>(openApi, responseOrReference);
const responseCode = getOperationResponseCode(code);
Object.entries(responses).forEach(([code, responseOrReference]) => {
const response = getRef<OpenApiResponse>(openApi, responseOrReference);
const responseCode = getOperationResponseCode(code);

if (responseCode) {
const operationResponse = getOperationResponse(
openApi,
response,
responseCode,
);
operationResponses.push(operationResponse);
}
if (responseCode) {
const operationResponse = getOperationResponse(
openApi,
response,
responseCode,
);
operationResponses.push(operationResponse);
}
}
});

// Sort the responses to 2xx success codes come before 4xx and 5xx error codes.
return operationResponses.sort((a, b): number =>
Expand Down
Loading

0 comments on commit ffd237d

Please sign in to comment.