Skip to content

Commit

Permalink
Merge pull request #15 from josstn/non-ascii-services
Browse files Browse the repository at this point in the history
Support non-ascii characters in service name, operation name and parameter name.
  • Loading branch information
mrlubos authored Feb 16, 2024
2 parents 09ff143 + 7588831 commit 95380ff
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 29 deletions.
9 changes: 3 additions & 6 deletions src/openApi/v2/parser/getOperationName.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import camelCase from 'camelcase';

import sanitizeOperationName from '../../../utils/sanitizeOperationName';

/**
* Convert the input value to a correct operation (method) classname.
* This will use the operation ID - if available - and otherwise fallback
* on a generated name from the URL
*/
export const getOperationName = (url: string, method: string, operationId?: string): string => {
if (operationId) {
return camelCase(
operationId
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.trim()
);
return camelCase(sanitizeOperationName(operationId).trim());
}

const urlWithoutPlaceholders = url
Expand Down
6 changes: 2 additions & 4 deletions src/openApi/v2/parser/getOperationParameterName.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import camelCase from 'camelcase';

import { reservedWords } from '../../../utils/reservedWords';
import sanitizeOperationParameterName from '../../../utils/sanitizeOperationParameterName';

/**
* Replaces any invalid characters from a parameter name.
* For example: 'filter.someProperty' becomes 'filterSomeProperty'.
*/
export const getOperationParameterName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.trim();
const clean = sanitizeOperationParameterName(value).trim();
return camelCase(clean).replace(reservedWords, '_$1');
};
7 changes: 3 additions & 4 deletions src/openApi/v2/parser/getServiceName.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import camelCase from 'camelcase';

import sanitizeServiceName from '../../../utils/sanitizeServiceName';

/**
* Convert the input value to a correct service name. This converts
* the input string to PascalCase.
*/
export const getServiceName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.trim();
const clean = sanitizeServiceName(value).trim();
return camelCase(clean, { pascalCase: true });
};
9 changes: 3 additions & 6 deletions src/openApi/v3/parser/getOperationName.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import camelCase from 'camelcase';

import sanitizeOperationName from '../../../utils/sanitizeOperationName';

/**
* Convert the input value to a correct operation (method) classname.
* This will use the operation ID - if available - and otherwise fallback
* on a generated name from the URL
*/
export const getOperationName = (url: string, method: string, operationId?: string): string => {
if (operationId) {
return camelCase(
operationId
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.trim()
);
return camelCase(sanitizeOperationName(operationId).trim());
}

const urlWithoutPlaceholders = url
Expand Down
7 changes: 2 additions & 5 deletions src/openApi/v3/parser/getOperationParameterName.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import camelCase from 'camelcase';

import { reservedWords } from '../../../utils/reservedWords';
import sanitizeOperationParameterName from '../../../utils/sanitizeOperationParameterName';

/**
* Replaces any invalid characters from a parameter name.
* For example: 'filter.someProperty' becomes 'filterSomeProperty'.
*/
export const getOperationParameterName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace('[]', 'Array')
.replace(/[^\w\-]+/g, '-')
.trim();
const clean = sanitizeOperationParameterName(value).trim();
return camelCase(clean).replace(reservedWords, '_$1');
};
1 change: 1 addition & 0 deletions src/openApi/v3/parser/getServiceName.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ describe('getServiceName', () => {
expect(getServiceName('@fooBar')).toEqual('FooBar');
expect(getServiceName('$fooBar')).toEqual('FooBar');
expect(getServiceName('123fooBar')).toEqual('FooBar');
expect(getServiceName('non-ascii-æøåÆØÅöôêÊ字符串')).toEqual('NonAsciiÆøåÆøÅöôêÊ字符串');
});
});
7 changes: 3 additions & 4 deletions src/openApi/v3/parser/getServiceName.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import camelCase from 'camelcase';

import sanitizeServiceName from '../../../utils/sanitizeServiceName';

/**
* Convert the input value to a correct service name. This converts
* the input string to PascalCase.
*/
export const getServiceName = (value: string): string => {
const clean = value
.replace(/^[^a-zA-Z]+/g, '')
.replace(/[^\w\-]+/g, '-')
.trim();
const clean = sanitizeServiceName(value).trim();
return camelCase(clean, { pascalCase: true });
};
7 changes: 7 additions & 0 deletions src/utils/sanitizeOperationName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sanitizeServiceName from './sanitizeServiceName';

/**
* sanitizeOperationName does the same as sanitizeServiceName.
*/
const sanitizeOperationName = sanitizeServiceName;
export default sanitizeOperationName;
7 changes: 7 additions & 0 deletions src/utils/sanitizeOperationParameterName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sanitizeOperationName from './sanitizeOperationName';

const sanitizeOperationParameterName = (name: string): string => {
const withoutBrackets = name.replace('[]', 'Array');
return sanitizeOperationName(withoutBrackets);
};
export default sanitizeOperationParameterName;
18 changes: 18 additions & 0 deletions src/utils/sanitizeServiceName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Sanitizes service names, so they are valid typescript identifiers of a certain form.
*
* 1: Remove any leading characters that are illegal as starting character of a typescript identifier.
* 2: Replace illegal characters in remaining part of type name with underscore (-).
*
* Step 1 should perhaps instead also replace illegal characters with underscore, or prefix with it, like sanitizeEnumName
* does. The way this is now one could perhaps end up removing all characters, if all are illegal start characters. It
* would be sort of a breaking change to do so, though, previously generated code might change then.
*
* Javascript identifier regexp pattern retrieved from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#identifiers
*
* The output of this is expected to be converted to PascalCase
*/
const sanitizeServiceName = (name: string) =>
name.replace(/^[^\p{ID_Start}]+/u, '').replace(/[^$\u200c\u200d\p{ID_Continue}]/gu, '-');

export default sanitizeServiceName;
62 changes: 62 additions & 0 deletions test/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ export { MultipleTags1Service } from './services/MultipleTags1Service';
export { MultipleTags2Service } from './services/MultipleTags2Service';
export { MultipleTags3Service } from './services/MultipleTags3Service';
export { NoContentService } from './services/NoContentService';
export { NonAsciiÆøåÆøÅöôêÊService } from './services/NonAsciiÆøåÆøÅöôêÊService';
export { ParametersService } from './services/ParametersService';
export { ResponseService } from './services/ResponseService';
export { SimpleService } from './services/SimpleService';
Expand Down Expand Up @@ -2852,6 +2853,36 @@ export class NoContentService {
"
`;

exports[`v2 should generate: test/generated/v2/services/NonAsciiÆøåÆøÅöôêÊService.ts 1`] = `
"/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { NonAsciiStringæøåÆØÅöôêÊ字符串 } from '../models/NonAsciiStringæøåÆØÅöôêÊ字符串';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class NonAsciiÆøåÆøÅöôêÊService {
/**
* @param nonAsciiParamæøåÆøÅöôêÊ Dummy input param
* @returns NonAsciiStringæøåÆØÅöôêÊ字符串 Successful response
* @throws ApiError
*/
public static nonAsciiæøåÆøÅöôêÊ字符串(
nonAsciiParamæøåÆøÅöôêÊ: number,
): CancelablePromise<NonAsciiStringæøåÆØÅöôêÊ字符串> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串',
query: {
'nonAsciiParamæøåÆØÅöôêÊ': nonAsciiParamæøåÆøÅöôêÊ,
},
});
}
}
"
`;

exports[`v2 should generate: test/generated/v2/services/ParametersService.ts 1`] = `
"/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
Expand Down Expand Up @@ -3894,6 +3925,7 @@ export { MultipleTags1Service } from './services/MultipleTags1Service';
export { MultipleTags2Service } from './services/MultipleTags2Service';
export { MultipleTags3Service } from './services/MultipleTags3Service';
export { NoContentService } from './services/NoContentService';
export { NonAsciiÆøåÆøÅöôêÊService } from './services/NonAsciiÆøåÆøÅöôêÊService';
export { ParametersService } from './services/ParametersService';
export { RequestBodyService } from './services/RequestBodyService';
export { ResponseService } from './services/ResponseService';
Expand Down Expand Up @@ -7487,6 +7519,36 @@ export class NoContentService {
"
`;

exports[`v3 should generate: test/generated/v3/services/NonAsciiÆøåÆøÅöôêÊService.ts 1`] = `
"/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { NonAsciiStringæøåÆØÅöôêÊ字符串 } from '../models/NonAsciiStringæøåÆØÅöôêÊ字符串';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class NonAsciiÆøåÆøÅöôêÊService {
/**
* @param nonAsciiParamæøåÆøÅöôêÊ Dummy input param
* @returns NonAsciiStringæøåÆØÅöôêÊ字符串 Successful response
* @throws ApiError
*/
public static nonAsciiæøåÆøÅöôêÊ字符串(
nonAsciiParamæøåÆøÅöôêÊ: number,
): CancelablePromise<Array<NonAsciiStringæøåÆØÅöôêÊ字符串>> {
return __request(OpenAPI, {
method: 'POST',
url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串',
query: {
'nonAsciiParamæøåÆØÅöôêÊ': nonAsciiParamæøåÆøÅöôêÊ,
},
});
}
}
"
`;

exports[`v3 should generate: test/generated/v3/services/ParametersService.ts 1`] = `
"/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
Expand Down
27 changes: 27 additions & 0 deletions test/spec/v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,33 @@
}
}
}
},
"/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串": {
"post": {
"tags": [
"Non-Ascii-æøåÆØÅöôêÊ"
],
"operationId": "nonAsciiæøåÆØÅöôêÊ字符串",
"parameters": [
{
"description": "Dummy input param",
"name": "nonAsciiParamæøåÆØÅöôêÊ",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"schema": {
"$ref": "#/definitions/NonAsciiStringæøåÆØÅöôêÊ字符串"
}
}
}
}
}
},
"definitions": {
Expand Down
34 changes: 34 additions & 0 deletions test/spec/v3.json
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,40 @@
}
}
}
},
"/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串": {
"post": {
"tags": [
"Non-Ascii-æøåÆØÅöôêÊ"
],
"operationId": "nonAsciiæøåÆØÅöôêÊ字符串",
"parameters": [
{
"description": "Dummy input param",
"name": "nonAsciiParamæøåÆØÅöôêÊ",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/NonAsciiStringæøåÆØÅöôêÊ字符串"
}
}
}
}
}
}
}
}
},
"components": {
Expand Down

0 comments on commit 95380ff

Please sign in to comment.