Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spec/common/queryKeys.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { makeQueryKeys } from "../../src/common/queryKeys";
import { compile } from "../test.utils";

Expand Down
28 changes: 17 additions & 11 deletions spec/common/requests.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript";
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import SwaggerParser from "@apidevtools/swagger-parser";
import {
chunker,
Expand Down Expand Up @@ -249,25 +249,31 @@ describe("makeRequests", () => {
content: {
"application/xml": {
schema: {
$ref: '#/components/schemas/Pet'
}
}
}
}
$ref: "#/components/schemas/Pet",
},
},
},
},
},
schemas: {
Pets: {},
Pet: {},
Photos: {},
"Pet.Dog": {},
"Pet.Cat": {}
}
}
"Pet.Cat": {},
},
},
};

const parser = new SwaggerParser();
const api = await parser.bundle(doc)
const str = compile(makeRequests(parser.$refs, api.paths as OpenAPIV3.PathsObject<{}, {}>, {} as any));
const api = await parser.bundle(doc);
const str = compile(
makeRequests(
parser.$refs,
api.paths as OpenAPIV3.PathsObject<{}, {}>,
{} as any
)
);
expect(str).toBe(expected);
});
});
Expand Down
2 changes: 1 addition & 1 deletion spec/common/types.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { makeTypes } from "../../src/common/types";
import { compile } from "../test.utils";

Expand Down
2 changes: 1 addition & 1 deletion spec/react-query/mutations.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { makeMutations } from "../../src/react-query/mutations";
import { compile } from "../test.utils";

Expand Down
56 changes: 55 additions & 1 deletion spec/react-query/queries.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { makeQueries } from "../../src/react-query/queries";
import { compile } from "../test.utils";

Expand All @@ -11,6 +11,13 @@ const expected = `function makeQueries(requests: Requests) {
}
`;

const expected = `function makeQueries(requests: Requests) {
return {
useGetPets: (status_in?: string[], options?: Omit<UseQueryOptions<Response<"getPets">, unknown, Response<"getPets">, ReturnType<QueryKeys["getPets"]>>, "queryKey" | "queryFn">): UseQueryResult<Response<"getPets">, unknown> => useQuery({ queryKey: queryKeys.getPets(status_in), queryFn: () => requests.getPets(status_in), ...options })
} as const;
}
`;

describe("makeQueries", () => {
it("generates queries for every GET path", () => {
const doc: OpenAPIV3.Document = {
Expand Down Expand Up @@ -147,4 +154,51 @@ describe("makeQueries", () => {
const str = compile([makeQueries({} as any, doc.paths)]);
expect(str).toBe(expected);
});

it("generates queries for every GET path with query parameters", () => {
const doc: OpenAPIV3.Document = {
openapi: "3.0.0",
info: {
title: "Test",
version: "1.0.0",
},
paths: {
"/pets": {
get: {
operationId: "getPets",
parameters: [
{
in: "query",
name: "status.in",
required: false,
schema: {
description: "Return the page of entries after this one.",
items: {
type: "string",
},
type: "array",
},
},
],
responses: {
default: {
description: "anything",
content: {
"application/json": {
schema: {
$ref: "",
},
},
},
},
},
},
},
},
};

const str = compile([makeQueries({} as any, doc.paths)]);
console.log(str);
expect(str).toBe(expected2);
});
});
2 changes: 1 addition & 1 deletion spec/swr/queries.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { makeQueries } from "../../src/swr/queries";
import { compile } from "../test.utils";

Expand Down
6 changes: 3 additions & 3 deletions src/common/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import ts from "typescript";
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { normalizeOperationId, createParams } from "./util";
import SwaggerParser from "@apidevtools/swagger-parser";

const NULL_IF_UNDEFINED_FN_NAME = "nullIfUndefined";

export function makeQueryKeys(
$refs: SwaggerParser.$Refs,
paths: OpenAPIV3.PathsObject
paths: OpenAPIV3.PathsObject | undefined
) {
const queryKeys = Object.entries(paths)
const queryKeys = Object.entries(paths ?? {})
.filter(([_, item]) => !!item?.get)
.map(([pattern, item]) =>
makeQueryKey($refs, pattern, item!.get, item!.parameters)
Expand Down
19 changes: 12 additions & 7 deletions src/common/requests.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import ts, { PropertyAssignment } from "typescript";
import type SwaggerParser from "@apidevtools/swagger-parser";
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import {
schemaObjectOrRefType,
normalizeOperationId,
isReferenceObject,
combineUniqueParams,
sanitizeParamName,
} from "./util";

import type { CLIOptions } from "../cli";
Expand All @@ -22,10 +23,10 @@ const methods = [

export function makeRequests(
$refs: SwaggerParser.$Refs,
paths: OpenAPIV3.PathsObject,
paths: OpenAPIV3.PathsObject | undefined,
options: CLIOptions
) {
const requests = Object.entries(paths).flatMap(([pattern, item]) =>
const requests = Object.entries(paths ?? {}).flatMap(([pattern, item]) =>
makeRequestsPropertyAssignment($refs, pattern, item!, options)
);

Expand Down Expand Up @@ -182,7 +183,7 @@ function createRequestParams(
arrowFuncParam: ts.factory.createParameterDeclaration(
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
/*name*/ ts.factory.createIdentifier(param.name),
/*name*/ ts.factory.createIdentifier(sanitizeParamName(param.name)),
/*questionToken*/ param.required
? undefined
: ts.factory.createToken(ts.SyntaxKind.QuestionToken),
Expand Down Expand Up @@ -275,7 +276,7 @@ export function getAxiosRequestGenericTypeResponse(
item: OpenAPIV3.OperationObject,
$refs: SwaggerParser.$Refs
) {
const genericType = Object.entries(item.responses).flatMap(
const genericType = Object.entries(item.responses ?? {}).flatMap(
([statusCode, resOrRef]) =>
makeAxiosRequestGenericType($refs, statusCode, resOrRef)
);
Expand Down Expand Up @@ -378,10 +379,14 @@ function makeRequest(
const queryParamProperties = queryParamObjects.map((paramObject) =>
paramObject.required
? ts.factory.createShorthandPropertyAssignment(
/*name*/ ts.factory.createIdentifier(paramObject.name),
/*name*/ ts.factory.createIdentifier(
sanitizeParamName(paramObject.name)
),
/*objectAssignmentInitializer*/ undefined
)
: shorthandOptionalObjectLiteralSpread(paramObject.name)
: shorthandOptionalObjectLiteralSpread(
sanitizeParamName(paramObject.name)
)
);

if (queryParamProperties.length) {
Expand Down
12 changes: 4 additions & 8 deletions src/common/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OpenAPIV3 } from "openapi-types";
import { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import ts from "typescript";
import {
appendNullToUnion,
Expand All @@ -13,12 +13,9 @@ import SwaggerParser from "@apidevtools/swagger-parser";

function schemaObjectTypeToArrayType(
$refs: SwaggerParser.$Refs,
item: OpenAPIV3.NonArraySchemaObject
item: OpenAPIV3.SchemaObject
): ts.TypeNode {
return appendNullToUnion(
nonArraySchemaObjectTypeToTs($refs, item),
item.nullable
);
return appendNullToUnion(nonArraySchemaObjectTypeToTs($refs, item));
}

function resolveArray(
Expand All @@ -29,8 +26,7 @@ function resolveArray(
return appendNullToUnion(
ts.factory.createArrayTypeNode(
createTypeRefOrSchemaObjectIfPathRef($refs, item.items)
),
item.nullable
)
);
}

Expand Down
33 changes: 17 additions & 16 deletions src/common/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript";
import type { OpenAPI, OpenAPIV3 } from "openapi-types";
import type { OpenAPI, OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import { createLiteralNodeFromProperties } from "./types";
import type SwaggerParser from "@apidevtools/swagger-parser";

Expand Down Expand Up @@ -224,43 +224,40 @@ export function createDictionaryType(

export function nonArraySchemaObjectTypeToTs(
$refs: SwaggerParser.$Refs,
item: OpenAPIV3.NonArraySchemaObject
item: OpenAPIV3.SchemaObject
): ts.TypeNode {
if (!item.type) {
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
}

switch (item.type) {
case "string": {
if (item.enum) {
return schemaObjectTypeToEnumType(item.enum, item.nullable);
return schemaObjectTypeToEnumType(item.enum);
}
return appendNullToUnion(
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
item.nullable
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
);
}
case "integer":
case "number":
return appendNullToUnion(
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
item.nullable
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
);
case "boolean":
return appendNullToUnion(
ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword),
item.nullable
ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)
);
case "object": {
if (item.additionalProperties) {
return createDictionaryType($refs, item);
}

return appendNullToUnion(
createLiteralNodeFromProperties($refs, item),
item.nullable
);
return appendNullToUnion(createLiteralNodeFromProperties($refs, item));
}
case "null":
return ts.factory.createLiteralTypeNode(ts.factory.createNull());

default:
return unknownTypeNode;
}
Expand Down Expand Up @@ -342,6 +339,10 @@ export function sanitizeTypeName(name: string) {
.join("");
}

export function sanitizeParamName(name: string) {
return name.replace(/[.]/, "_");
}

/**
* Removes the path in the ref and just returns the last part, which is used as the Type name
* @param ref The ref in the OpenAPI file
Expand All @@ -367,11 +368,11 @@ export function createParams(
.sort((x, y) => (x.required === y.required ? 0 : x.required ? -1 : 1)) // put all optional values at the end
.map((param) => ({
required: param.required ?? false,
name: ts.factory.createIdentifier(param.name),
name: ts.factory.createIdentifier(sanitizeParamName(param.name)),
arrowFuncParam: ts.factory.createParameterDeclaration(
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
/*name*/ ts.factory.createIdentifier(param.name),
/*name*/ ts.factory.createIdentifier(sanitizeParamName(param.name)),
/*questionToken*/ param.required
? undefined
: ts.factory.createToken(ts.SyntaxKind.QuestionToken),
Expand Down
4 changes: 2 additions & 2 deletions src/react-query/generator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript";
import type { OpenAPI, OpenAPIV3 } from "openapi-types";
import type { OpenAPI, OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import SwaggerParser from "@apidevtools/swagger-parser";
import { print } from "./print";
import { makeImports } from "./imports";
Expand Down Expand Up @@ -36,7 +36,7 @@ function parseOpenApiV3Doc(
queryKeys: makeQueryKeys($refs, doc.paths),
requests: makeRequests($refs, doc.paths, options),
queries: makeQueries($refs, doc.paths),
mutations: makeMutations($refs, doc.paths),
mutations: makeMutations($refs, doc.paths ?? {}),
types: makeTypes($refs, doc),
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/react-query/mutations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript";
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import SwaggerParser from "@apidevtools/swagger-parser";
import {
capitalizeFirstLetter,
Expand Down
6 changes: 3 additions & 3 deletions src/react-query/queries.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript";
import type { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import SwaggerParser from "@apidevtools/swagger-parser";
import {
capitalizeFirstLetter,
Expand All @@ -9,9 +9,9 @@ import {

export function makeQueries(
$refs: SwaggerParser.$Refs,
paths: OpenAPIV3.PathsObject
paths: OpenAPIV3.PathsObject | undefined
) {
const properties = Object.entries(paths)
const properties = Object.entries(paths ?? {})
.filter(([_, item]) => !!item?.get)
.map(([pattern, item]) =>
makeProperty($refs, pattern, item!.get, item!.parameters)
Expand Down
2 changes: 1 addition & 1 deletion src/swr/generator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript";
import type { OpenAPI, OpenAPIV3 } from "openapi-types";
import type { OpenAPI, OpenAPIV3_1 as OpenAPIV3 } from "openapi-types";
import SwaggerParser from "@apidevtools/swagger-parser";
import { isOpenApiV3Document } from "../common/util";
import { makeQueryKeys } from "../common/queryKeys";
Expand Down
Loading