Skip to content

Commit 8ac7465

Browse files
authored
fix: schemas key double quote replace (#915) (#916)
1 parent f9229a2 commit 8ac7465

File tree

8 files changed

+390
-1
lines changed

8 files changed

+390
-1
lines changed

src/load.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import path from "path";
77
import { Readable } from "stream";
88
import { request } from "undici";
99
import { URL } from "url";
10-
import { parseRef } from "./utils.js";
10+
import { parseRef, replaceKeys } from "./utils.js";
1111

1212
type PartialSchema = Record<string, any>; // not a very accurate type, but this is easier to deal with before we know we’re dealing with a valid spec
1313
type SchemaMap = { [url: string]: PartialSchema };
@@ -184,6 +184,9 @@ export default async function load(
184184
}
185185
}
186186

187+
// schemas key double quote replace
188+
schemas[schemaID] = replaceKeys(schemas[schemaID]);
189+
187190
// scan $refs, but don’t transform (load everything in parallel)
188191
const refPromises: Promise<any>[] = [];
189192
schemas[schemaID] = JSON.parse(JSON.stringify(schemas[schemaID]), (k, v) => {

src/utils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,24 @@ export function tsUnionOf(types: Array<string | number | boolean>): string {
266266
if (types.length === 1) return `${types[0]}`; // don’t add parentheses around one thing
267267
return `(${types.join(") | (")})`;
268268
}
269+
270+
export function replaceKeys(obj: Record<string, any>): Record<string, any> {
271+
if (typeof obj === "object" && obj !== undefined && obj !== null) {
272+
if (Array.isArray(obj)) {
273+
return obj.map((item) => replaceKeys(item));
274+
} else {
275+
const keyValues = Object.keys(obj).map((key) => {
276+
const newKey = key.replace(DOUBLE_QUOTE_RE, '\\"');
277+
const newValue = obj[key];
278+
if (typeof newValue === "object") {
279+
return { [newKey]: replaceKeys(newValue) };
280+
} else {
281+
return { [newKey]: newValue };
282+
}
283+
});
284+
return Object.assign({}, ...keyValues);
285+
}
286+
} else {
287+
return obj;
288+
}
289+
}

test/v3/expected/jsdoc2.additional.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
'/v1/getUser2': {
8+
/** UserController.getUser2 */
9+
get: operations['UserController.getUser2.DjHhjSamaD']
10+
}
11+
}
12+
13+
export interface components {
14+
schemas: {
15+
IUserWithId: (components['schemas']['Partial<Pick<IUser,"id">>'] | string) & { [key: string]: unknown }
16+
'Partial<Pick<IUser,"id">>': {
17+
id?: number
18+
} & { [key: string]: unknown }
19+
IUserWithName: {
20+
name: string
21+
} & { [key: string]: unknown }
22+
IUser: {
23+
id: number
24+
name?: string
25+
} & { [key: string]: unknown }
26+
}
27+
}
28+
29+
export interface operations {
30+
/** UserController.getUser2 */
31+
'UserController.getUser2.DjHhjSamaD': {
32+
parameters: {
33+
query: {
34+
param1?: number
35+
param2?: (string | components['schemas']['IUserWithId']) & { [key: string]: unknown }
36+
param3?: (string | components['schemas']['IUserWithName']) & { [key: string]: unknown }
37+
}
38+
}
39+
responses: {
40+
/** Successful response */
41+
200: {
42+
content: {
43+
'application/json': unknown
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
export interface external {}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export type paths = {
7+
'/v1/getUser2': {
8+
/** UserController.getUser2 */
9+
get: operations['UserController.getUser2.DjHhjSamaD']
10+
}
11+
}
12+
13+
export type components = {
14+
schemas: {
15+
IUserWithId: components['schemas']['Partial<Pick<IUser,"id">>'] | string
16+
'Partial<Pick<IUser,"id">>': {
17+
id?: number
18+
}
19+
IUserWithName: {
20+
name: string
21+
}
22+
IUser: {
23+
id: number
24+
name?: string
25+
}
26+
}
27+
}
28+
29+
export type operations = {
30+
/** UserController.getUser2 */
31+
'UserController.getUser2.DjHhjSamaD': {
32+
parameters: {
33+
query: {
34+
param1?: number
35+
param2?: string | components['schemas']['IUserWithId']
36+
param3?: string | components['schemas']['IUserWithName']
37+
}
38+
}
39+
responses: {
40+
/** Successful response */
41+
200: {
42+
content: {
43+
'application/json': unknown
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
export type external = {}

test/v3/expected/jsdoc2.immutable.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
readonly '/v1/getUser2': {
8+
/** UserController.getUser2 */
9+
readonly get: operations['UserController.getUser2.DjHhjSamaD']
10+
}
11+
}
12+
13+
export interface components {
14+
readonly schemas: {
15+
readonly IUserWithId: components['schemas']['Partial<Pick<IUser,"id">>'] | string
16+
readonly 'Partial<Pick<IUser,"id">>': {
17+
readonly id?: number
18+
}
19+
readonly IUserWithName: {
20+
readonly name: string
21+
}
22+
readonly IUser: {
23+
readonly id: number
24+
readonly name?: string
25+
}
26+
}
27+
}
28+
29+
export interface operations {
30+
/** UserController.getUser2 */
31+
readonly 'UserController.getUser2.DjHhjSamaD': {
32+
readonly parameters: {
33+
readonly query: {
34+
readonly param1?: number
35+
readonly param2?: string | components['schemas']['IUserWithId']
36+
readonly param3?: string | components['schemas']['IUserWithName']
37+
}
38+
}
39+
readonly responses: {
40+
/** Successful response */
41+
readonly 200: {
42+
readonly content: {
43+
readonly 'application/json': unknown
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
export interface external {}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
'/v1/getUser2': {
8+
/** UserController.getUser2 */
9+
get: operations['UserController.getUser2.DjHhjSamaD']
10+
}
11+
}
12+
13+
export interface components {
14+
schemas: {
15+
IUserWithId: components['schemas']['Partial<Pick<IUser,"id">>'] | string
16+
'Partial<Pick<IUser,"id">>': {
17+
id?: number
18+
}
19+
IUserWithName: {
20+
name: string
21+
}
22+
IUser: {
23+
id: number
24+
name?: string
25+
}
26+
}
27+
}
28+
29+
export interface operations {
30+
/** UserController.getUser2 */
31+
'UserController.getUser2.DjHhjSamaD': {
32+
parameters: {
33+
query: {
34+
param1?: number
35+
param2?: string | components['schemas']['IUserWithId']
36+
param3?: string | components['schemas']['IUserWithName']
37+
}
38+
}
39+
responses: {
40+
/** Successful response */
41+
200: {
42+
content: {
43+
'application/json': unknown
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
export interface external {}

test/v3/expected/jsdoc2.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
'/v1/getUser2': {
8+
/** UserController.getUser2 */
9+
get: operations['UserController.getUser2.DjHhjSamaD']
10+
}
11+
}
12+
13+
export interface components {
14+
schemas: {
15+
IUserWithId: components['schemas']['Partial<Pick<IUser,"id">>'] | string
16+
'Partial<Pick<IUser,"id">>': {
17+
id?: number
18+
}
19+
IUserWithName: {
20+
name: string
21+
}
22+
IUser: {
23+
id: number
24+
name?: string
25+
}
26+
}
27+
}
28+
29+
export interface operations {
30+
/** UserController.getUser2 */
31+
'UserController.getUser2.DjHhjSamaD': {
32+
parameters: {
33+
query: {
34+
param1?: number
35+
param2?: string | components['schemas']['IUserWithId']
36+
param3?: string | components['schemas']['IUserWithName']
37+
}
38+
}
39+
responses: {
40+
/** Successful response */
41+
200: {
42+
content: {
43+
'application/json': unknown
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
export interface external {}

0 commit comments

Comments
 (0)