Skip to content

Commit

Permalink
Merge pull request #784 from hey-api/fix/suffix-service-name
Browse files Browse the repository at this point in the history
fix: handle illegal service names
  • Loading branch information
mrlubos authored Jul 16, 2024
2 parents 20bc5e7 + f12dccf commit 274851b
Show file tree
Hide file tree
Showing 34 changed files with 104 additions and 97 deletions.
5 changes: 5 additions & 0 deletions .changeset/hip-hats-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix: suffix illegal service names
17 changes: 11 additions & 6 deletions packages/openapi-ts/src/generate/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { Model, Operation, OperationParameter, Service } from '../openApi';
import type { Client } from '../types/client';
import { getConfig, isStandaloneClient } from '../utils/config';
import { escapeComment, escapeName } from '../utils/escape';
import { reservedWordsRegExp } from '../utils/reservedWords';
import { transformServiceName } from '../utils/transform';
import { setUniqueTypeName } from '../utils/type';
import { unique } from '../utils/unique';
Expand Down Expand Up @@ -381,14 +382,18 @@ const toRequestOptions = (
});
};

const toOperationName = (operation: Operation) => {
const toOperationName = (operation: Operation, handleIllegal: boolean) => {
const config = getConfig();

if (!config.services.methodNameBuilder) {
return operation.name;
if (config.services.methodNameBuilder) {
return config.services.methodNameBuilder(operation);
}

return config.services.methodNameBuilder(operation);
if (handleIllegal && operation.name.match(reservedWordsRegExp)) {
return `${operation.name}_`;
}

return operation.name;
};

const toOperationStatements = (
Expand Down Expand Up @@ -544,7 +549,7 @@ const processService = (
const statement = compiler.export.const({
comment: toOperationComment(operation),
expression,
name: toOperationName(operation),
name: toOperationName(operation, true),
});
onNode(statement);
});
Expand All @@ -556,7 +561,7 @@ const processService = (
accessLevel: 'public',
comment: toOperationComment(operation),
isStatic: config.name === undefined && config.client !== 'angular',
name: toOperationName(operation),
name: toOperationName(operation, false),
parameters: toOperationParamType(client, operation),
returnType: isStandalone
? undefined
Expand Down
3 changes: 0 additions & 3 deletions packages/openapi-ts/src/openApi/common/interfaces/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ export interface Operation extends OperationParameters {
*/
id: string | null;
method: Method;
/**
* Method name. Methods contain the request logic.
*/
name: string;
path: string;
responseHeader: string | null;
Expand Down
4 changes: 2 additions & 2 deletions packages/openapi-ts/src/openApi/common/parser/type.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import camelcase from 'camelcase';

import { getConfig, isStandaloneClient } from '../../../utils/config';
import { reservedWordsRegExp } from '../../../utils/reservedWords';
import { transformTypeName } from '../../../utils/transform';
import { isDefinitionTypeNullable } from '../../v3/parser/inferType';
import type { Type } from '../interfaces/Type';
import { reservedWords } from './reservedWords';
import {
ensureValidTypeScriptJavaScriptIdentifier,
sanitizeOperationParameterName,
Expand Down Expand Up @@ -166,5 +166,5 @@ export const transformTypeKeyName = (value: string): string => {
}

const clean = sanitizeOperationParameterName(value).trim();
return camelcase(clean).replace(reservedWords, '_$1');
return camelcase(clean).replace(reservedWordsRegExp, '_$1');
};
4 changes: 2 additions & 2 deletions packages/openapi-ts/src/openApi/v2/parser/getModels.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Client } from '../../../types/client';
import { reservedWords } from '../../common/parser/reservedWords';
import { reservedWordsRegExp } from '../../../utils/reservedWords';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
import { getModel } from './getModel';
Expand All @@ -13,7 +13,7 @@ export const getModels = (
Object.entries(openApi.definitions ?? {}).forEach(
([definitionName, definition]) => {
const definitionType = getType({ type: definitionName });
const name = definitionType.base.replace(reservedWords, '_$1');
const name = definitionType.base.replace(reservedWordsRegExp, '_$1');
const meta = {
$ref: `#/definitions/${definitionName}`,
name,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest';

import type { Config } from '../../../../types/config';
import { reservedWords } from '../../../common/parser/reservedWords';
import { reservedWordsRegExp } from '../../../../utils/reservedWords';
import { getType } from '../../../common/parser/type';
import { getModel } from '../getModel';

Expand Down Expand Up @@ -96,7 +96,7 @@ describe('getModel', () => {
isDefinition: true,
meta: {
$ref: '',
name: definitionType.base.replace(reservedWords, '_$1'),
name: definitionType.base.replace(reservedWordsRegExp, '_$1'),
},
openApi,
types: {},
Expand All @@ -112,7 +112,7 @@ describe('getModel', () => {
isDefinition: true,
meta: {
$ref: '',
name: definitionType.base.replace(reservedWords, '_$1'),
name: definitionType.base.replace(reservedWordsRegExp, '_$1'),
},
openApi,
types: {},
Expand Down
6 changes: 3 additions & 3 deletions packages/openapi-ts/src/openApi/v3/parser/getModels.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Client } from '../../../types/client';
import { getConfig } from '../../../utils/config';
import { reservedWords } from '../../common/parser/reservedWords';
import { reservedWordsRegExp } from '../../../utils/reservedWords';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
import { getModel } from './getModel';
Expand All @@ -24,7 +24,7 @@ export const getModels = (
Object.entries(openApi.components.schemas ?? {}).forEach(
([definitionName, definition]) => {
const definitionType = getType({ type: definitionName });
const name = definitionType.base.replace(reservedWords, '_$1');
const name = definitionType.base.replace(reservedWordsRegExp, '_$1');
const meta = {
$ref: `#/components/schemas/${definitionName}`,
name,
Expand Down Expand Up @@ -66,7 +66,7 @@ export const getModels = (
* Note: there's a related code to this workaround in `getType()`
* method that needs to be cleaned up when this is addressed.
*/
const name = `Parameter${definitionType.base.replace(reservedWords, '_$1')}`;
const name = `Parameter${definitionType.base.replace(reservedWordsRegExp, '_$1')}`;
const meta = {
$ref: `#/components/parameters/${definitionName}`,
name,
Expand Down
4 changes: 2 additions & 2 deletions packages/openapi-ts/src/utils/escape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { EOL } from 'os';
* Javascript identifier regexp pattern retrieved from
* {@link} https://developer.mozilla.org/docs/Web/JavaScript/Reference/Lexical_grammar#identifiers
*/
const validTypescriptIdentifierRegex =
const validTypescriptIdentifierRegExp =
/^[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*$/u;

export const escapeName = (value: string): string => {
if (value || value === '') {
const validName = validTypescriptIdentifierRegex.test(value);
const validName = validTypescriptIdentifierRegExp.test(value);
if (!validName) {
return `'${value}'`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const reservedWords =
export const reservedWordsRegExp =
/^(arguments|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|eval|export|extends|false|finally|for|function|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)$/g;
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import type { CancelablePromise } from './core/CancelablePromise';
import { OpenAPI } from './core/OpenAPI';
import { request as __request } from './core/request';
import type { PostServiceWithEmptyTagData, PostServiceWithEmptyTagResponse3, ApiVversionOdataControllerCountResponse, DeleteFooData3, CallWithParametersData, CallWithWeirdParameterNamesData, GetCallWithOptionalParamData, PostCallWithOptionalParamData, CallWithDescriptionsData, DeprecatedCallData, PostApiRequestBodyData, PostApiFormDataData, CallWithDefaultParametersData, CallWithDefaultOptionalParametersData, CallToTestOrderOfParamsData, CallWithNoContentResponseResponse, CallWithResponseAndNoContentResponseResponse, CallWithResponseResponse, CallWithDuplicateResponsesResponse, CallWithResponsesResponse, DummyAResponse, DummyBResponse, CollectionFormatData, TypesData, TypesResponse, UploadFileData, UploadFileResponse, FileResponseData, FileResponseResponse, ComplexTypesData, ComplexTypesResponse, ComplexParamsData, ComplexParamsResponse, MultipartRequestData, MultipartResponseResponse, CallWithResultFromHeaderResponse, TestErrorCodeData, TestErrorCodeResponse, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response } from './types.gen';
import type { ImportData, ImportResponse, ApiVversionOdataControllerCountResponse, DeleteFooData3, CallWithParametersData, CallWithWeirdParameterNamesData, GetCallWithOptionalParamData, PostCallWithOptionalParamData, CallWithDescriptionsData, DeprecatedCallData, PostApiRequestBodyData, PostApiFormDataData, CallWithDefaultParametersData, CallWithDefaultOptionalParametersData, CallToTestOrderOfParamsData, CallWithNoContentResponseResponse, CallWithResponseAndNoContentResponseResponse, CallWithResponseResponse, CallWithDuplicateResponsesResponse, CallWithResponsesResponse, DummyAResponse, DummyBResponse, CollectionFormatData, TypesData, TypesResponse, UploadFileData, UploadFileResponse, FileResponseData, FileResponseResponse, ComplexTypesData, ComplexTypesResponse, ComplexParamsData, ComplexParamsResponse, MultipartRequestData, MultipartResponseResponse, CallWithResultFromHeaderResponse, TestErrorCodeData, TestErrorCodeResponse, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response } from './types.gen';

export class DefaultService {
/**
* @throws ApiError
*/
public static serviceWithEmptyTag(): CancelablePromise<void> {
public static export(): CancelablePromise<void> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v{api-version}/no-tag'
Expand All @@ -23,7 +23,7 @@ export class DefaultService {
* @returns ModelWithReadOnlyAndWriteOnly Default success response
* @throws ApiError
*/
public static postServiceWithEmptyTag(data: PostServiceWithEmptyTagData): CancelablePromise<PostServiceWithEmptyTagResponse3> {
public static import(data: ImportData): CancelablePromise<ImportResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v{api-version}/no-tag',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -997,11 +997,11 @@ export type ParameterSimpleParameter = string;
*/
export type Parameterx_Foo_Bar = ModelWithString;

export type PostServiceWithEmptyTagData = {
export type ImportData = {
requestBody: ModelWithReadOnlyAndWriteOnly | ModelWithArrayReadOnlyAndWriteOnly;
};

export type PostServiceWithEmptyTagResponse3 = Model_From_Zendesk | ModelWithReadOnlyAndWriteOnly;
export type ImportResponse = Model_From_Zendesk | ModelWithReadOnlyAndWriteOnly;

export type ApiVversionOdataControllerCountResponse = Model_From_Zendesk;

Expand Down Expand Up @@ -1426,7 +1426,7 @@ export type NonAsciiæøåÆøÅöôêÊ字符串Response = Array<NonAsciiString
export type $OpenApiTs = {
'/api/v{api-version}/no-tag': {
post: {
req: PostServiceWithEmptyTagData;
req: ImportData;
res: {
/**
* Success
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { HttpClient } from '@angular/common/http';
import type { Observable } from 'rxjs';
import { OpenAPI } from './core/OpenAPI';
import { request as __request } from './core/request';
import type { PostServiceWithEmptyTagData, PostServiceWithEmptyTagResponse3, ApiVversionOdataControllerCountResponse, DeleteFooData3, CallWithParametersData, CallWithWeirdParameterNamesData, GetCallWithOptionalParamData, PostCallWithOptionalParamData, CallWithDescriptionsData, DeprecatedCallData, PostApiRequestBodyData, PostApiFormDataData, CallWithDefaultParametersData, CallWithDefaultOptionalParametersData, CallToTestOrderOfParamsData, CallWithNoContentResponseResponse, CallWithResponseAndNoContentResponseResponse, CallWithResponseResponse, CallWithDuplicateResponsesResponse, CallWithResponsesResponse, DummyAResponse, DummyBResponse, CollectionFormatData, TypesData, TypesResponse, UploadFileData, UploadFileResponse, FileResponseData, FileResponseResponse, ComplexTypesData, ComplexTypesResponse, ComplexParamsData, ComplexParamsResponse, MultipartRequestData, MultipartResponseResponse, CallWithResultFromHeaderResponse, TestErrorCodeData, TestErrorCodeResponse, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response } from './types.gen';
import type { ImportData, ImportResponse, ApiVversionOdataControllerCountResponse, DeleteFooData3, CallWithParametersData, CallWithWeirdParameterNamesData, GetCallWithOptionalParamData, PostCallWithOptionalParamData, CallWithDescriptionsData, DeprecatedCallData, PostApiRequestBodyData, PostApiFormDataData, CallWithDefaultParametersData, CallWithDefaultOptionalParametersData, CallToTestOrderOfParamsData, CallWithNoContentResponseResponse, CallWithResponseAndNoContentResponseResponse, CallWithResponseResponse, CallWithDuplicateResponsesResponse, CallWithResponsesResponse, DummyAResponse, DummyBResponse, CollectionFormatData, TypesData, TypesResponse, UploadFileData, UploadFileResponse, FileResponseData, FileResponseResponse, ComplexTypesData, ComplexTypesResponse, ComplexParamsData, ComplexParamsResponse, MultipartRequestData, MultipartResponseResponse, CallWithResultFromHeaderResponse, TestErrorCodeData, TestErrorCodeResponse, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response } from './types.gen';

@Injectable({
providedIn: 'root'
Expand All @@ -16,7 +16,7 @@ export class DefaultService {
/**
* @throws ApiError
*/
public serviceWithEmptyTag(): Observable<void> {
public export(): Observable<void> {
return __request(OpenAPI, this.http, {
method: 'GET',
url: '/api/v{api-version}/no-tag'
Expand All @@ -30,7 +30,7 @@ export class DefaultService {
* @returns ModelWithReadOnlyAndWriteOnly Default success response
* @throws ApiError
*/
public postServiceWithEmptyTag(data: PostServiceWithEmptyTagData): Observable<PostServiceWithEmptyTagResponse3> {
public import(data: ImportData): Observable<ImportResponse> {
return __request(OpenAPI, this.http, {
method: 'POST',
url: '/api/v{api-version}/no-tag',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -874,11 +874,11 @@ export type ParameterSimpleParameter = string;
*/
export type Parameterx_Foo_Bar = ModelWithString;

export type PostServiceWithEmptyTagData = {
export type ImportData = {
requestBody: ModelWithReadOnlyAndWriteOnly | ModelWithArrayReadOnlyAndWriteOnly;
};

export type PostServiceWithEmptyTagResponse3 = Model_From_Zendesk | ModelWithReadOnlyAndWriteOnly;
export type ImportResponse = Model_From_Zendesk | ModelWithReadOnlyAndWriteOnly;

export type ApiVversionOdataControllerCountResponse = Model_From_Zendesk;

Expand Down Expand Up @@ -1303,7 +1303,7 @@ export type NonAsciiæøåÆøÅöôêÊ字符串Response = Array<NonAsciiString
export type $OpenApiTs = {
'/api/v{api-version}/no-tag': {
post: {
req: PostServiceWithEmptyTagData;
req: ImportData;
res: {
/**
* Success
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import type { CancelablePromise } from './core/CancelablePromise';
import { OpenAPI } from './core/OpenAPI';
import { request as __request } from './core/request';
import type { PostServiceWithEmptyTagData, PostServiceWithEmptyTagResponse3, ApiVversionOdataControllerCountResponse, DeleteFooData3, CallWithParametersData, CallWithWeirdParameterNamesData, GetCallWithOptionalParamData, PostCallWithOptionalParamData, CallWithDescriptionsData, DeprecatedCallData, PostApiRequestBodyData, PostApiFormDataData, CallWithDefaultParametersData, CallWithDefaultOptionalParametersData, CallToTestOrderOfParamsData, CallWithNoContentResponseResponse, CallWithResponseAndNoContentResponseResponse, CallWithResponseResponse, CallWithDuplicateResponsesResponse, CallWithResponsesResponse, DummyAResponse, DummyBResponse, CollectionFormatData, TypesData, TypesResponse, UploadFileData, UploadFileResponse, FileResponseData, FileResponseResponse, ComplexTypesData, ComplexTypesResponse, ComplexParamsData, ComplexParamsResponse, MultipartRequestData, MultipartResponseResponse, CallWithResultFromHeaderResponse, TestErrorCodeData, TestErrorCodeResponse, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response } from './types.gen';
import type { ImportData, ImportResponse, ApiVversionOdataControllerCountResponse, DeleteFooData3, CallWithParametersData, CallWithWeirdParameterNamesData, GetCallWithOptionalParamData, PostCallWithOptionalParamData, CallWithDescriptionsData, DeprecatedCallData, PostApiRequestBodyData, PostApiFormDataData, CallWithDefaultParametersData, CallWithDefaultOptionalParametersData, CallToTestOrderOfParamsData, CallWithNoContentResponseResponse, CallWithResponseAndNoContentResponseResponse, CallWithResponseResponse, CallWithDuplicateResponsesResponse, CallWithResponsesResponse, DummyAResponse, DummyBResponse, CollectionFormatData, TypesData, TypesResponse, UploadFileData, UploadFileResponse, FileResponseData, FileResponseResponse, ComplexTypesData, ComplexTypesResponse, ComplexParamsData, ComplexParamsResponse, MultipartRequestData, MultipartResponseResponse, CallWithResultFromHeaderResponse, TestErrorCodeData, TestErrorCodeResponse, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response } from './types.gen';

export class DefaultService {
/**
* @throws ApiError
*/
public static serviceWithEmptyTag(): CancelablePromise<void> {
public static export(): CancelablePromise<void> {
return __request(OpenAPI, {
method: 'GET',
url: '/api/v{api-version}/no-tag'
Expand All @@ -23,7 +23,7 @@ export class DefaultService {
* @returns ModelWithReadOnlyAndWriteOnly Default success response
* @throws ApiError
*/
public static postServiceWithEmptyTag(data: PostServiceWithEmptyTagData): CancelablePromise<PostServiceWithEmptyTagResponse3> {
public static import(data: ImportData): CancelablePromise<ImportResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v{api-version}/no-tag',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -997,11 +997,11 @@ export type ParameterSimpleParameter = string;
*/
export type Parameterx_Foo_Bar = ModelWithString;

export type PostServiceWithEmptyTagData = {
export type ImportData = {
requestBody: ModelWithReadOnlyAndWriteOnly | ModelWithArrayReadOnlyAndWriteOnly;
};

export type PostServiceWithEmptyTagResponse3 = Model_From_Zendesk | ModelWithReadOnlyAndWriteOnly;
export type ImportResponse = Model_From_Zendesk | ModelWithReadOnlyAndWriteOnly;

export type ApiVversionOdataControllerCountResponse = Model_From_Zendesk;

Expand Down Expand Up @@ -1426,7 +1426,7 @@ export type NonAsciiæøåÆøÅöôêÊ字符串Response = Array<NonAsciiString
export type $OpenApiTs = {
'/api/v{api-version}/no-tag': {
post: {
req: PostServiceWithEmptyTagData;
req: ImportData;
res: {
/**
* Success
Expand Down
Loading

0 comments on commit 274851b

Please sign in to comment.