Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ferdikoomen/openapi-typescript-codegen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: parsable/openapi-typescript-codegen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 17 commits
  • 77 files changed
  • 4 contributors

Commits on Aug 5, 2021

  1. Copy the full SHA
    e23135a View commit details
  2. Copy the full SHA
    9c9fae2 View commit details
  3. Merge pull request #1 from parsable/feature/PE-2152

    Feature/pe 2152
    lub0v-parsable authored Aug 5, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    8275e01 View commit details
  4. Copy the full SHA
    163b358 View commit details
  5. Merge pull request #2 from parsable/feature/PE-2152-header

    [no-jira] - update header
    lub0v-parsable authored Aug 5, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    a5f6827 View commit details

Commits on Aug 9, 2021

  1. Copy the full SHA
    131d3f5 View commit details
  2. Merge pull request #3 from parsable/feature/PE-2152

    PE-2152 - export index files
    lub0v-parsable authored Aug 9, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    1af048c View commit details

Commits on Aug 25, 2021

  1. Copy the full SHA
    1ee6314 View commit details

Commits on Aug 26, 2021

  1. Copy the full SHA
    5e6a10a View commit details
  2. Copy the full SHA
    8dee078 View commit details
  3. Copy the full SHA
    93c0088 View commit details

Commits on Aug 27, 2021

  1. PE-2229 - cleanup

    lub0v-parsable committed Aug 27, 2021
    Copy the full SHA
    e38afc4 View commit details
  2. Merge pull request #4 from parsable/feature/PE-2229

    PE-2229 - rename OpenApi properties, remove config from http client, …
    lub0v-parsable authored Aug 27, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    537a23d View commit details

Commits on Sep 20, 2021

  1. Copy the full SHA
    ad6dac9 View commit details
  2. Merge pull request #5 from parsable/feature/PE-2380

    PE-2380 - properly generate client when no tags used
    lub0v-parsable authored Sep 20, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    4c5ac0d View commit details

Commits on Sep 17, 2024

  1. Copy the full SHA
    81922a7 View commit details
  2. Merge pull request #6 from parsable/GHA-publish

    add dependabot and Publish current version.
    pbrobles authored Sep 17, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    3b5807a View commit details
Showing with 13,160 additions and 1,047 deletions.
  1. +27 −0 .github/dependabot.yml
  2. +57 −0 .github/workflows/build-publish.yml
  3. +1 −0 .gitignore
  4. +25 −0 README.md
  5. +4 −0 bin/index.js
  6. +2 −10 jest.config.js
  7. +2 −2 package.json
  8. +10 −4 src/index.ts
  9. +2 −2 src/openApi/v2/parser/getOperationPath.spec.ts
  10. +3 −5 src/openApi/v2/parser/getOperationPath.ts
  11. +2 −2 src/openApi/v3/parser/getOperationPath.spec.ts
  12. +3 −5 src/openApi/v3/parser/getOperationPath.ts
  13. +2 −2 src/templates/core/ApiResult.hbs
  14. +13 −0 src/templates/core/BaseHttpRequest.hbs
  15. +18 −17 src/templates/core/OpenAPI.hbs
  16. +5 −5 src/templates/core/fetch/getHeaders.hbs
  17. +41 −2 src/templates/core/fetch/request.hbs
  18. +3 −3 src/templates/core/fetch/sendRequest.hbs
  19. +19 −0 src/templates/core/functions/deepAssign.hbs
  20. +2 −2 src/templates/core/functions/getUrl.hbs
  21. +13 −0 src/templates/core/index.hbs
  22. +5 −5 src/templates/core/node/getHeaders.hbs
  23. +41 −2 src/templates/core/node/request.hbs
  24. +2 −2 src/templates/core/node/sendRequest.hbs
  25. +5 −5 src/templates/core/xhr/getHeaders.hbs
  26. +42 −2 src/templates/core/xhr/request.hbs
  27. +3 −3 src/templates/core/xhr/sendRequest.hbs
  28. +39 −0 src/templates/exportAppClient.hbs
  29. +8 −28 src/templates/index.hbs
  30. 0 src/templates/{ → models}/exportModel.hbs
  31. +13 −0 src/templates/models/index.hbs
  32. +1 −0 src/templates/partials/header.hbs
  33. +3 −2 src/templates/partials/parameters.hbs
  34. +10 −0 src/templates/partials/passParameters.hbs
  35. 0 src/templates/{ → schemas}/exportSchema.hbs
  36. +5 −0 src/templates/schemas/index.hbs
  37. +61 −0 src/templates/services/exportService.hbs
  38. +28 −10 src/templates/{exportService.hbs → services/exportServiceFull.hbs}
  39. +6 −0 src/templates/services/index.hbs
  40. +14 −0 src/utils/getHttpClientName.spec.ts
  41. +3 −0 src/utils/getHttpRequestName.ts
  42. +3 −2 src/utils/postProcessClient.ts
  43. +2 −2 src/utils/postProcessService.ts
  44. +4 −1 src/utils/postProcessServiceOperations.ts
  45. +8 −3 src/utils/registerHandlebarTemplates.spec.ts
  46. +50 −7 src/utils/registerHandlebarTemplates.ts
  47. +44 −0 src/utils/writeAppClient.spec.ts
  48. +35 −0 src/utils/writeAppClient.ts
  49. +18 −3 src/utils/writeClient.spec.ts
  50. +13 −4 src/utils/writeClient.ts
  51. +50 −22 src/utils/writeClientCore.spec.ts
  52. +13 −2 src/utils/writeClientCore.ts
  53. +19 −3 src/utils/writeClientIndex.spec.ts
  54. +12 −1 src/utils/writeClientIndex.ts
  55. +18 −2 src/utils/writeClientModels.spec.ts
  56. +3 −1 src/utils/writeClientModels.ts
  57. +18 −2 src/utils/writeClientSchemas.spec.ts
  58. +3 −1 src/utils/writeClientSchemas.ts
  59. +21 −3 src/utils/writeClientServices.spec.ts
  60. +30 −3 src/utils/writeClientServices.ts
  61. +9,321 −0 test/__snapshots__/index.client.spec.js.snap
  62. +2,356 −802 test/__snapshots__/index.spec.js.snap
  63. +2 −1 test/e2e/scripts/generate.js
  64. +44 −5 test/e2e/v2.babel.spec.js
  65. +44 −5 test/e2e/v2.fetch.spec.js
  66. +38 −6 test/e2e/v2.node.spec.js
  67. +44 −5 test/e2e/v2.xhr.spec.js
  68. +58 −10 test/e2e/v3.babel.spec.js
  69. +58 −10 test/e2e/v3.fetch.spec.js
  70. +50 −11 test/e2e/v3.node.spec.js
  71. +58 −10 test/e2e/v3.xhr.spec.js
  72. +68 −0 test/index.client.spec.js
  73. +2 −0 test/index.spec.js
  74. +25 −0 test/spec/v2_no_tags.json
  75. +29 −0 test/spec/v2_tags_combined.json
  76. +25 −0 test/spec/v3_no_tags.json
  77. +31 −0 test/spec/v3_tags_combined.json
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "09:00"
timezone: "America/Los_Angeles"
ignore:
- dependency-name: "*"
update-types: [version-update:semver-major]
open-pull-requests-limit: 5
commit-message:
prefix: "bot: update npm dependencies: "

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 10
commit-message:
prefix: "[no-jira] bot: update github-actions image to "

57 changes: 57 additions & 0 deletions .github/workflows/build-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: build-publish
permissions:
contents: write
id-token: write
packages: write

on:
pull_request_target:
types:
- closed
branches:
- master

jobs:
build-publish:
name: build publish artifact
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: master
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 16.x
registry-url: https://npm.pkg.github.com/
scope: '@parsable'
cache: yarn
env:
NODE_AUTH_TOKEN: ${{secrets.GH_PAT_CLASSIC_MACHINE_PARSABLE}}
- name: Install Dependencies
run: yarn install
env:
NODE_AUTH_TOKEN: ${{secrets.GH_PAT_CLASSIC_MACHINE_PARSABLE}}
- name: Tag
id: tag
run: |
truncated_version=1.0.4
git config --global user.email "ops+machine-parsable@parsable.com"
git config --global user.name "machine-parsable"
npm version -m "Updating package.json for version ${truncated_version}" ${truncated_version}
git pull --ff-only
git push origin $(git branch --show-current) --tags
git status
echo "new_tag=${truncated_version}" >> $GITHUB_OUTPUT
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GH_PARSABLE_BOT_BYPASS }}
run: gh release create "${{steps.version.outputs.version}}"
- name: publishing artifact
run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -15,3 +15,4 @@ test/e2e/generated
samples/generated
samples/swagger-codegen-cli-v2.jar
samples/swagger-codegen-cli-v3.jar
example
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -47,6 +47,8 @@ $ openapi --help
--exportServices <value> Write services to disk (default: true)
--exportModels <value> Write models to disk (default: true)
--exportSchemas <value> Write schemas to disk (default: false)
--exportClient <value> Generate and write client class to disk (default: false)
--name <value> Custom client class name (default: "AppClient")
Examples
$ openapi --input ./spec.json
@@ -392,6 +394,29 @@ const getToken = async () => {
OpenAPI.TOKEN = getToken;
```

### Generate client instance with `--exportClient` option

The OpenAPI generator allows to create client instances to support the multiple backend services use case.
The generated client uses an instance of the server configuration and not the global `OpenAPI` constant.

To generate a client instance, use `--exportClient` option. To set a custom name to the client class, use `--name` option.

```
openapi --input ./spec.json --output ./dist --exportClient true --name DemoAppClient
```

The generated client will be exported from the `index` file and can be used as shown below:
```typescript
// create the client instance with server and authentication details
const appClient = new DemoAppClient({ BASE: 'http://server-host.com', TOKEN: '1234' });

// use the client instance to make the API call
const res: OrganizationResponse = await appClient.organizations.createOrganization({
name: 'OrgName',
description: 'OrgDescription',
});
```

### References

Local references to schema definitions (those beginning with `#/definitions/schemas/`)
4 changes: 4 additions & 0 deletions bin/index.js
Original file line number Diff line number Diff line change
@@ -19,7 +19,9 @@ const params = program
.option('--exportServices <value>', 'Write services to disk', true)
.option('--exportModels <value>', 'Write models to disk', true)
.option('--exportSchemas <value>', 'Write schemas to disk', false)
.option('--exportClient <value>', 'Generate and write client class to disk', false)
.option('--request <value>', 'Path to custom request file')
.option('--name <value>', 'Custom client class name', 'AppClient')
.parse(process.argv)
.opts();

@@ -36,6 +38,8 @@ if (OpenAPI) {
exportServices: JSON.parse(params.exportServices) === true,
exportModels: JSON.parse(params.exportModels) === true,
exportSchemas: JSON.parse(params.exportSchemas) === true,
exportClient: JSON.parse(params.exportClient) === true,
clientName: params.name,
request: params.request,
})
.then(() => {
12 changes: 2 additions & 10 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -5,10 +5,7 @@ module.exports = {
{
displayName: 'UNIT',
testEnvironment: 'node',
testMatch: [
'<rootDir>/src/**/*.spec.ts',
'<rootDir>/test/index.spec.js',
],
testMatch: ['<rootDir>/src/**/*.spec.ts', '<rootDir>/test/index.spec.js', '<rootDir>/test/index.client.spec.js'],
moduleFileExtensions: ['js', 'ts', 'd.ts'],
moduleNameMapper: {
'\\.hbs$': '<rootDir>/src/templates/__mocks__/index.js',
@@ -29,10 +26,5 @@ module.exports = {
],
},
],
collectCoverageFrom: [
'<rootDir>/src/**/*.ts',
'!<rootDir>/src/**/*.d.ts',
'!<rootDir>/bin',
'!<rootDir>/dist',
],
collectCoverageFrom: ['<rootDir>/src/**/*.ts', '!<rootDir>/src/**/*.d.ts', '!<rootDir>/bin', '!<rootDir>/dist'],
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openapi-typescript-codegen",
"version": "0.9.3",
"name": "@parsable/openapi-typescript-codegen",
"version": "0.0.4",
"description": "Library that generates Typescript clients based on the OpenAPI specification.",
"author": "Ferdi Koomen",
"homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen",
14 changes: 10 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -20,7 +20,9 @@ export type Options = {
exportServices?: boolean;
exportModels?: boolean;
exportSchemas?: boolean;
exportClient?: boolean;
request?: string;
clientName?: string;
write?: boolean;
};

@@ -37,6 +39,8 @@ export type Options = {
* @param exportServices: Generate services
* @param exportModels: Generate models
* @param exportSchemas: Generate schemas
* @param exportClient: Generate client class
* @param clientName: Custom client class name
* @param request: Path to custom request file
* @param write Write the files to disk (true or false)
*/
@@ -50,6 +54,8 @@ export async function generate({
exportServices = true,
exportModels = true,
exportSchemas = false,
exportClient = false,
clientName = 'AppClient',
request,
write = true,
}: Options): Promise<void> {
@@ -64,17 +70,17 @@ export async function generate({
switch (openApiVersion) {
case OpenApiVersion.V2: {
const client = parseV2(openApi);
const clientFinal = postProcessClient(client);
const clientFinal = postProcessClient(client, exportClient);
if (!write) break;
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas, request);
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas, exportClient, clientName, request);
break;
}

case OpenApiVersion.V3: {
const client = parseV3(openApi);
const clientFinal = postProcessClient(client);
const clientFinal = postProcessClient(client, exportClient);
if (!write) break;
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas, request);
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas, exportClient, clientName, request);
break;
}
}
4 changes: 2 additions & 2 deletions src/openApi/v2/parser/getOperationPath.spec.ts
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@ import { getOperationPath } from './getOperationPath';

describe('getOperationPath', () => {
it('should produce correct result', () => {
expect(getOperationPath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}/${type}');
expect(getOperationPath('/api/v{api-version}/list/{id}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}');
expect(getOperationPath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${apiVersion}/list/${id}/${type}');
expect(getOperationPath('/api/v{api-version}/list/{id}')).toEqual('/api/v${apiVersion}/list/${id}');
expect(getOperationPath('/api/v1/list/{id}')).toEqual('/api/v1/list/${id}');
expect(getOperationPath('/api/{foobar}')).toEqual('/api/${foobar}');
expect(getOperationPath('/api/{fooBar}')).toEqual('/api/${fooBar}');
8 changes: 3 additions & 5 deletions src/openApi/v2/parser/getOperationPath.ts
Original file line number Diff line number Diff line change
@@ -8,9 +8,7 @@ import { getOperationParameterName } from './getOperationParameterName';
* @param path
*/
export function getOperationPath(path: string): string {
return path
.replace(/\{(.*?)\}/g, (_, w: string) => {
return `\${${getOperationParameterName(w)}}`;
})
.replace('${apiVersion}', '${OpenAPI.VERSION}');
return path.replace(/\{(.*?)\}/g, (_, w: string) => {
return `\${${getOperationParameterName(w)}}`;
});
}
4 changes: 2 additions & 2 deletions src/openApi/v3/parser/getOperationPath.spec.ts
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@ import { getOperationPath } from './getOperationPath';

describe('getOperationPath', () => {
it('should produce correct result', () => {
expect(getOperationPath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}/${type}');
expect(getOperationPath('/api/v{api-version}/list/{id}')).toEqual('/api/v${OpenAPI.VERSION}/list/${id}');
expect(getOperationPath('/api/v{api-version}/list/{id}/{type}')).toEqual('/api/v${apiVersion}/list/${id}/${type}');
expect(getOperationPath('/api/v{api-version}/list/{id}')).toEqual('/api/v${apiVersion}/list/${id}');
expect(getOperationPath('/api/v1/list/{id}')).toEqual('/api/v1/list/${id}');
expect(getOperationPath('/api/{foobar}')).toEqual('/api/${foobar}');
expect(getOperationPath('/api/{fooBar}')).toEqual('/api/${fooBar}');
8 changes: 3 additions & 5 deletions src/openApi/v3/parser/getOperationPath.ts
Original file line number Diff line number Diff line change
@@ -8,9 +8,7 @@ import { getOperationParameterName } from './getOperationParameterName';
* @param path
*/
export function getOperationPath(path: string): string {
return path
.replace(/\{(.*?)\}/g, (_, w: string) => {
return `\${${getOperationParameterName(w)}}`;
})
.replace('${apiVersion}', '${OpenAPI.VERSION}');
return path.replace(/\{(.*?)\}/g, (_, w: string) => {
return `\${${getOperationParameterName(w)}}`;
});
}
4 changes: 2 additions & 2 deletions src/templates/core/ApiResult.hbs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{{>header}}

export type ApiResult = {
export type ApiResult<T = any> = {
readonly url: string;
readonly ok: boolean;
readonly status: number;
readonly statusText: string;
readonly body: any;
readonly body: T;
}
13 changes: 13 additions & 0 deletions src/templates/core/BaseHttpRequest.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{>header}}

import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import type { ClientConfig } from './OpenAPI';

export interface BaseHttpRequest<T = any> {
request<K = T>(
options: ApiRequestOptions,
config: ClientConfig,
mergeConfig?: ClientConfig
): Promise<ApiResult<K>>;
}
35 changes: 18 additions & 17 deletions src/templates/core/OpenAPI.hbs
Original file line number Diff line number Diff line change
@@ -5,22 +5,23 @@ import type { ApiRequestOptions } from './ApiRequestOptions';
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
type Headers = Record<string, string>;

type Config = {
BASE: string;
VERSION: string;
WITH_CREDENTIALS: boolean;
TOKEN?: string | Resolver<string>;
USERNAME?: string | Resolver<string>;
PASSWORD?: string | Resolver<string>;
HEADERS?: Headers | Resolver<Headers>;
export type ClientConfig = {
baseUrl?: string;
version?: string;
withCredentials?: boolean;
token?: string | Resolver<string>;
username?: string | Resolver<string>;
password?: string | Resolver<string>;
headers?: Headers | Resolver<Headers>;
}

export const OpenAPI: Config = {
BASE: '{{{server}}}',
VERSION: '{{{version}}}',
WITH_CREDENTIALS: false,
TOKEN: undefined,
USERNAME: undefined,
PASSWORD: undefined,
HEADERS: undefined,
{{#unless @root.exportClient}}
export const OpenAPI: ClientConfig = {
baseUrl: '{{{server}}}',
version: '{{{version}}}',
withCredentials: false,
token: undefined,
username: undefined,
password: undefined,
headers: undefined,
};
{{/unless}}
10 changes: 5 additions & 5 deletions src/templates/core/fetch/getHeaders.hbs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
const token = await resolve(options, OpenAPI.TOKEN);
const username = await resolve(options, OpenAPI.USERNAME);
const password = await resolve(options, OpenAPI.PASSWORD);
const defaultHeaders = await resolve(options, OpenAPI.HEADERS);
async function getHeaders(options: ApiRequestOptions, config: ClientConfig): Promise<Headers> {
const token = await resolve(options, config.token);
const username = await resolve(options, config.username);
const password = await resolve(options, config.password);
const defaultHeaders = await resolve(options, config.headers);

const headers = new Headers({
Accept: 'application/json',
Loading