Skip to content

Commit

Permalink
chore: fix bugs and update docs (#6)
Browse files Browse the repository at this point in the history
* fix: example

* docs: add playground

* fix: additionalProperties bugs

* fix: add typeAlias description
  • Loading branch information
Himenon authored Jan 14, 2021
1 parent 20d8289 commit 13c233f
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 103 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ The hierarchical structure of the directory is converted to the hierarchical str

## Usage

- [Playground](https://himenon.github.io/openapi-typescript-code-generator-playground/index.html)

## Installation

```bash
Expand Down
2 changes: 2 additions & 0 deletions docs/ja/README-ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

## 使い方

- [Playground](https://himenon.github.io/openapi-typescript-code-generator-playground/index.html)

### インストール

```bash
Expand Down
20 changes: 2 additions & 18 deletions example/sample-axios.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
import * as Formatter from "@himenon/openapi-parameter-formatter";
import * as axios from "axios";

import { ApiClient, Client, HttpMethod, ObjectLike, QueryParameters } from "./client";
import { generateQueryString } from "./utils";

export interface RequestOption {
retries?: number;
timeout?: number;
deadline?: number;
}

const generateQueryString = (queryParameters: QueryParameters | undefined): string | undefined => {
if (!queryParameters) {
return undefined;
}
return Object.entries(queryParameters).reduce((queryString, [key, item]) => {
if (!item.style) {
return queryString + "&" + `${key}=${item}`;
}
const result = Formatter.QueryParameter.generate(key, item as Formatter.QueryParameter.Parameter);
if (result) {
return queryString + "&" + result;
}
return queryString;
}, "");
};

const convertHttpMethodToAxiosMethod = (httpMethod: HttpMethod): axios.Method => {
const patterns: { [key in HttpMethod]: axios.Method } = {
GET: "GET",
Expand All @@ -49,7 +33,7 @@ const apiClientImpl: ApiClient<RequestOption> = {
options?: RequestOption,
): Promise<any> => {
const query = generateQueryString(queryParameters);
const requestUrl = query ? url + "&" + query : url;
const requestUrl = query ? url + "?" + encodeURI(query) : url;
const response = await axios.default.request({
url: requestUrl,
method: convertHttpMethodToAxiosMethod(httpMethod),
Expand Down
21 changes: 2 additions & 19 deletions example/sample-debug.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,10 @@
import * as Formatter from "@himenon/openapi-parameter-formatter";

import { ApiClient, Client, HttpMethod, ObjectLike, QueryParameters } from "./client";
import { generateQueryString } from "./utils";

export interface RequestOption {
timeout?: number;
}

const generateQueryString = (queryParameters: QueryParameters | undefined): string | undefined => {
if (!queryParameters) {
return undefined;
}
return Object.entries(queryParameters).reduce((queryString, [key, item]) => {
if (!item.style) {
return queryString + "&" + `${key}=${item}`;
}
const result = Formatter.QueryParameter.generate(key, item as Formatter.QueryParameter.Parameter);
if (result) {
return queryString + "&" + result;
}
return queryString;
}, "");
};

const apiClientImpl: ApiClient<RequestOption> = {
request: async (
httpMethod: HttpMethod,
Expand All @@ -32,7 +15,7 @@ const apiClientImpl: ApiClient<RequestOption> = {
options?: RequestOption,
): Promise<any> => {
const query = generateQueryString(queryParameters);
const requestUrl = query ? url + "&" + query : url;
const requestUrl = query ? url + "?" + encodeURI(query) : url;
console.log({
httpMethod,
url,
Expand Down
22 changes: 3 additions & 19 deletions example/sample-fetch.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
import * as Formatter from "@himenon/openapi-parameter-formatter";
import fetch from "node-fetch";

import { ApiClient, Client, HttpMethod, ObjectLike, QueryParameters } from "./client";
import { generateQueryString } from "./utils";

export interface RequestOption {
timeout?: number;
}

const generateQueryString = (queryParameters: QueryParameters | undefined): string | undefined => {
if (!queryParameters) {
return undefined;
}
return Object.entries(queryParameters).reduce((queryString, [key, item]) => {
if (!item.style) {
return queryString + "&" + `${key}=${item}`;
}
const result = Formatter.QueryParameter.generate(key, item as Formatter.QueryParameter.Parameter);
if (result) {
return queryString + "&" + result;
}
return queryString;
}, "");
};

const apiClientImpl: ApiClient<RequestOption> = {
request: async (
httpMethod: HttpMethod,
Expand All @@ -33,9 +17,9 @@ const apiClientImpl: ApiClient<RequestOption> = {
options?: RequestOption,
): Promise<any> => {
const query = generateQueryString(queryParameters);
const requestUrl = query ? url + "&" + query : url;
const requestUrl = query ? url + "?" + encodeURI(query) : url;
const response = await fetch(requestUrl, {
body: requestBody,
body: JSON.stringify(requestBody),
headers,
method: httpMethod,
timeout: options?.timeout,
Expand Down
20 changes: 2 additions & 18 deletions example/sample-superagent.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
import * as Formatter from "@himenon/openapi-parameter-formatter";
import * as Superagent from "superagent";

import { ApiClient, Client, HttpMethod, ObjectLike, QueryParameters } from "./client";
import { generateQueryString } from "./utils";

export interface RequestOption {
retries?: number;
timeout?: number;
deadline?: number;
}

const generateQueryString = (queryParameters: QueryParameters | undefined): string | undefined => {
if (!queryParameters) {
return undefined;
}
return Object.entries(queryParameters).reduce((queryString, [key, item]) => {
if (!item.style) {
return queryString + "&" + `${key}=${item}`;
}
const result = Formatter.QueryParameter.generate(key, item as Formatter.QueryParameter.Parameter);
if (result) {
return queryString + "&" + result;
}
return queryString;
}, "");
};

const apiClientImpl: ApiClient<RequestOption> = {
request: (
httpMethod: HttpMethod,
Expand All @@ -35,7 +19,7 @@ const apiClientImpl: ApiClient<RequestOption> = {
options?: RequestOption,
): Promise<any> => {
const query = generateQueryString(queryParameters);
const requestUrl = query ? url + "&" + query : url;
const requestUrl = query ? url + "?" + encodeURI(query) : url;

return new Promise((resolve, reject) => {
const agent = Superagent;
Expand Down
24 changes: 24 additions & 0 deletions example/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as Formatter from "@himenon/openapi-parameter-formatter";

import { QueryParameters } from "./client";

export const generateQueryString = (queryParameters: QueryParameters | undefined): string | undefined => {
if (!queryParameters) {
return undefined;
}
const queries = Object.entries(queryParameters).reduce<string[]>((queryStringList, [key, item]) => {
if (!item.value) {
return queryStringList;
}
if (!item.style) {
return queryStringList.concat(`${key}=${item.value}`);
}
const result = Formatter.QueryParameter.generate(key, item as Formatter.QueryParameter.Parameter);
if (result) {
return queryStringList.concat(result);
}
return queryStringList;
}, []);

return queries.join("&");
};
1 change: 1 addition & 0 deletions src/Converter/v3/components/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const generateTypeAlias = (
export: true,
name,
type,
comment: schema.description,
});
};

Expand Down
1 change: 1 addition & 0 deletions src/Converter/v3/components/Schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const generateNamespace = (
value: factory.TypeAliasDeclaration.create({
export: true,
name: name,
comment: reference.data.description,
type: factory.TypeReferenceNode.create({
name: context.getReferenceName(currentPoint, reference.path),
}),
Expand Down
50 changes: 21 additions & 29 deletions src/Converter/v3/toTypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,44 +175,36 @@ export const convert: Convert = (
return nullable(factory, typeNode, !!schema.nullable);
}
case "object": {
if (!schema.properties) {
return factory.TypeNode.create({
type: "object",
value: [],
});
}
let typeNode: ts.TypeNode;
const required: string[] = schema.required || [];
// https://swagger.io/docs/specification/data-models/dictionaries/#free-form
// // https://swagger.io/docs/specification/data-models/dictionaries/#free-form
if (schema.additionalProperties === true) {
typeNode = factory.TypeNode.create({
return factory.TypeNode.create({
type: schema.type,
value: [],
});
} else {
const value: ts.PropertySignature[] = Object.entries(schema.properties).map(([name, jsonSchema]) => {
return factory.PropertySignature.create({
name,
type: convert(entryPoint, currentPoint, factory, jsonSchema, context, { parent: schema.properties }),
optional: !required.includes(name),
comment: typeof jsonSchema !== "boolean" ? jsonSchema.description : undefined,
});
}
const value: ts.PropertySignature[] = Object.entries(schema.properties || {}).map(([name, jsonSchema]) => {
return factory.PropertySignature.create({
name,
type: convert(entryPoint, currentPoint, factory, jsonSchema, context, { parent: schema.properties }),
optional: !required.includes(name),
comment: typeof jsonSchema !== "boolean" ? jsonSchema.description : undefined,
});
if (schema.additionalProperties) {
const additionalProperties = factory.IndexSignatureDeclaration.create({
name: "key",
type: convert(entryPoint, currentPoint, factory, schema.additionalProperties, context, { parent: schema.properties }),
});
return factory.TypeNode.create({
type: schema.type,
value: [...value, additionalProperties],
});
}
typeNode = factory.TypeNode.create({
});
if (schema.additionalProperties) {
const additionalProperties = factory.IndexSignatureDeclaration.create({
name: "key",
type: convert(entryPoint, currentPoint, factory, schema.additionalProperties, context, { parent: schema.properties }),
});
return factory.TypeNode.create({
type: schema.type,
value,
value: [...value, additionalProperties],
});
}
const typeNode = factory.TypeNode.create({
type: schema.type,
value,
});
return nullable(factory, typeNode, !!schema.nullable);
}
default:
Expand Down
19 changes: 19 additions & 0 deletions test/__tests__/__snapshots__/snapshot-test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ exports[`Generate Code Snapshot Test api.test.domain 1`] = `
/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#schemaObject */
export namespace Schemas {
/** String Literal */
export type StringType = string;
export type StringHasEnumType = \\"a\\" | \\"A\\" | \\"b\\" | \\"B\\" | \\"c\\" | \\"C\\";
export type StringDateType = string;
Expand All @@ -20,12 +21,14 @@ export namespace Schemas {
export type StringByteType = string;
export type StringBinaryType = string;
export type StringWithPatternType = string;
/** Number Literal */
export type NumberType = number;
export type NumberHasEnumType = 1 | 2 | 3 | 100 | 123 | 0.1 | -0.1 | 0;
export type NumberInt32Type = number;
export type NumberInt64Type = number;
export type NumberFloat = number;
export type NumberDouble = number;
/** Boolean Literal */
export type BooleanType = boolean;
export type ArrayStringType = string[];
export type ArrayNumberType = number[];
Expand Down Expand Up @@ -64,8 +67,10 @@ export namespace Schemas {
export type RemoteString = string;
export type RemoteRefString = Schemas.RemoteString;
export namespace Level1 {
/** Level 1 */
export type RemoteBoolean = boolean;
export namespace Level2 {
/** Level 2 */
export type RemoteNumber = number;
export namespace Level3 {
/** Level 3 */
Expand All @@ -80,9 +85,13 @@ export namespace Schemas {
}
}
}
/** Level 1 */
export type RemoteRefBoolean = Schemas.Level1.RemoteBoolean;
/** Level 2 */
export type RemoteRefNumber = Schemas.Level1.Level2.RemoteNumber;
/** Level 3 */
export type RemoteRefArray = Schemas.Level1.Level2.Level3.RemoteArray;
/** Level 4 */
export type RemoteRefObject = Schemas.Level1.Level2.Level3.Level4.RemoteObject;
export namespace DirectRef {
export type ForHeader = string;
Expand Down Expand Up @@ -218,6 +227,16 @@ export namespace Parameters {
export type RemoteReferenceB = Parameters.level1.B;
/** parameters -> schemas */
export type ReferenceOfParameterToSchema = Schemas.DirectRef.ForParameters;
/** deepObject */
export type DeepObjectParameter = {
[key: string]: {
gt?: string;
gte?: string;
lt?: string;
lte?: string;
any?: string | number | boolean;
};
};
}
/** @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#componentsObject */
export namespace RequestBodies {
Expand Down
23 changes: 23 additions & 0 deletions test/api.test.domain/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,29 @@ components:
name: ForReference
schema:
$ref: "./components/schemas/DirectRef/ForParameters.yml"
DeepObjectParameter:
description: deepObject
required: true
in: query
name: filter
schema:
type: object
additionalProperties:
type: object
properties:
gt:
type: string
gte:
type: string
lt:
type: string
lte:
type: string
any:
oneOf:
- type: string
- type: number
- type: boolean
responses:
Continue:
description: |
Expand Down

0 comments on commit 13c233f

Please sign in to comment.