Skip to content

Commit f9f3e60

Browse files
authored
Update readme (#374)
* Update README, docs * Update Prettier config, format * chore: update lint rules * chore: update generated example
1 parent ffe4ee5 commit f9f3e60

19 files changed

+23735
-23506
lines changed

.eslintrc.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
module.exports = {
22
parser: "@typescript-eslint/parser",
3-
extends: [
4-
"plugin:@typescript-eslint/recommended",
5-
"prettier",
6-
"prettier/@typescript-eslint",
7-
],
3+
extends: ["plugin:@typescript-eslint/recommended", "prettier", "prettier/@typescript-eslint"],
84
plugins: ["@typescript-eslint", "prettier"],
95
rules: {
106
"@typescript-eslint/camelcase": "off",
7+
"@typescript-eslint/explicit-module-boundary-types": "off",
8+
"@typescript-eslint/no-explicit-any": "off", // in a foreign schema, sometimes we need “any”
119
"@typescript-eslint/no-use-before-define": "off",
1210
"prettier/prettier": "error",
1311
"prefer-const": "off",

.prettierrc

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"proseWrap": "always",
3+
"printWidth": 120
4+
}

CONTRIBUTING.md

+25-25
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,46 @@
22

33
Thanks for being willing to contribute!
44

5-
**Working on your first Pull Request?** You can learn how from this _free_
6-
series [How to Contribute to an Open Source Project on GitHub][egghead]
5+
**Working on your first Pull Request?** You can learn how from this _free_ series [How to Contribute to an Open Source
6+
Project on GitHub][egghead]
77

88
## Project setup
99

1010
1. Fork and clone the repo
1111
2. Run `npm install` to install dependencies
1212
3. Create a branch for your PR with `git checkout -b pr/your-branch-name`
1313

14-
> Tip: Keep your `master` branch pointing at the original repository and make
15-
> pull requests from branches on your fork. To do this, run:
14+
It’s also recommended you have [ESLint][eslint] installed and set up correctly. You may also run the command
15+
`npm run lint` to see lint errors.
16+
17+
> Tip: Keep your `main` branch pointing at the original repository and make pull requests from branches on your fork. To
18+
> do this, run:
1619
>
1720
> ```
1821
> git remote add upstream https://github.com/drwpow/openapi-typescript.git
1922
> git fetch upstream
2023
> git branch --set-upstream-to=upstream/master master
2124
> ```
2225
>
23-
> This will add the original repository as a "remote" called "upstream," Then
24-
> fetch the git information from that remote, then set your local `master`
25-
> branch to use the upstream master branch whenever you run `git pull`. Then you
26-
> can make all of your pull request branches based on this `master` branch.
27-
> Whenever you want to update your version of `master`, do a regular `git pull`.
26+
> This will add the original repository as a "remote" called "upstream," Then fetch the git information from that
27+
> remote, then set your local `main` branch to use the upstream main branch whenever you run `git pull`. Then you can
28+
> make all of your pull request branches based on this `main` branch. Whenever you want to update your version of
29+
> `main`, do a regular `git pull`.
2830
29-
## Committing and Pushing changes
31+
## Committing and pushing changes
3032
3133
Please make sure to run the tests (`npm test`) before you commit your changes.
3234
3335
### Local schemas
3436
35-
This repo supports OpenAPI 2.0 and 3.0. There are some real-world examples
36-
located in `tests/v2/specs/*.yaml` and `tests/v3/specs/*.yaml`, respectively.
37-
Testing large, real schemas was a major goal of this project. Many libraries
38-
only test the “Petstore” example from Swagger, which is contrived and is
39-
missing much complexity from companies’ production schemas.
37+
This repo supports OpenAPI 2.0 and 3.0. There are some real-world examples located in `tests/v2/specs/*.yaml` and
38+
`tests/v3/specs/*.yaml`, respectively. Testing large, real schemas was a major goal of this project. Many libraries only
39+
test the “Petstore” example from Swagger, which is contrived and is missing much complexity from companies’ production
40+
schemas.
4041
41-
_Note: don’t update the `yaml` schemas with your own custom additions (but if
42-
the official versions have updated, then it’s fine to upadte them here). If
43-
you’d like to add your schema for testing, then please add them as a new
44-
schema, and add them to `./expected/*.ts`._
42+
_Note: don’t update the `yaml` schemas with your own custom additions (but if the official versions have updated, then
43+
it’s fine to upadte them here). If you’d like to add your schema for testing, then please add them as a new schema, and
44+
add them to `./expected/*.ts`._
4545
4646
#### Regenerating schemas
4747
@@ -60,12 +60,10 @@ _Also if this appears in `examples/` feel free to update that, too!_
6060
6161
## Help needed
6262
63-
Please check out the [the open issues][issues]. Issues labelled [**Help
64-
Wanted**][help-wanted] and [**Good First Issue**][good-first-issue] are
65-
especially good to help with.
63+
Please check out the [the open issues][issues]. Issues labelled [**Help Wanted**][help-wanted] and [**Good First
64+
Issue**][good-first-issue] are especially good to help with.
6665
67-
Also, please watch the repo and respond to questions/bug reports/feature
68-
requests! Thanks!
66+
Also, please watch the repo and respond to questions/bug reports/feature requests! Thanks!
6967
7068
## Deploying (access only)
7169
@@ -79,6 +77,8 @@ Follow the prompts to release.
7977

8078
[all-contributors]: https://github.com/all-contributors/all-contributors
8179
[egghead]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
82-
[good-first-issue]: https://github.com/drwpow/openapi-typescript/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
80+
[eslint]: https://eslint.org/
81+
[good-first-issue]:
82+
https://github.com/drwpow/openapi-typescript/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
8383
[help-wanted]: https://github.com/drwpow/openapi-typescript/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
8484
[issues]: https://github.com/drwpow/openapi-typescript/issues

README.md

+38-127
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
[![codecov](https://codecov.io/gh/drwpow/openapi-typescript/branch/master/graph/badge.svg)](https://codecov.io/gh/drwpow/openapi-typescript)
33

44
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
5+
56
[![All Contributors](https://img.shields.io/badge/all_contributors-23-orange.svg?style=flat-square)](#contributors-)
7+
68
<!-- ALL-CONTRIBUTORS-BADGE:END -->
79

810
# 📘️ openapi-typescript
911

10-
🚀 Convert [OpenAPI 3.0][openapi3] and [OpenAPI 2.0 (Swagger)][openapi2] schemas to TypeScript interfaces using Node.js.
12+
🚀 Convert [OpenAPI 3.0][openapi3] and [2.0 (Swagger)][openapi2] schemas to TypeScript interfaces using Node.js.
1113

1214
💅 The output is prettified with [Prettier][prettier] (and can be customized!).
1315

@@ -44,7 +46,8 @@ _Thanks to @psmyrdek for this feature!_
4446

4547
#### Generating multiple schemas
4648

47-
In your `package.json`, for each schema you’d like to transform add one `generate:specs:[name]` npm-script. Then combine them all into one `generate:specs` script, like so:
49+
In your `package.json`, for each schema you’d like to transform add one `generate:specs:[name]` npm-script. Then combine
50+
them all into one `generate:specs` script, like so:
4851

4952
```json
5053
"scripts": {
@@ -55,6 +58,13 @@ In your `package.json`, for each schema you’d like to transform add one `gener
5558
}
5659
```
5760

61+
If you use [npm-run-all][npm-run-all], you can shorten this:
62+
63+
```json
64+
"scripts": {
65+
"generate:specs": "run-p generate:specs:*",
66+
```
67+
5868
You can even specify unique options per-spec, if needed. To generate them all together, run:
5969

6070
```bash
@@ -86,21 +96,20 @@ const input = JSON.parse(readFileSync("spec.json", "utf8")); // Input can be any
8696
const output = swaggerToTS(input); // Outputs TypeScript defs as a string (to be parsed, or written to a file)
8797
```
8898

89-
The Node API is a bit more flexible: it will only take a JS object as input (OpenAPI format), and
90-
return a string of TS definitions. This lets you pull from any source (a Swagger server, local
91-
files, etc.), and similarly lets you parse, post-process, and save the output anywhere.
99+
The Node API is a bit more flexible: it will only take a JS object as input (OpenAPI format), and return a string of TS
100+
definitions. This lets you pull from any source (a Swagger server, local files, etc.), and similarly lets you parse,
101+
post-process, and save the output anywhere.
92102

93-
If your specs are in YAML, you’ll have to convert them to JS objects using a library such as
94-
[js-yaml][js-yaml]. If you’re batching large folders of specs, [glob][glob] may also come in handy.
103+
If your specs are in YAML, you’ll have to convert them to JS objects using a library such as [js-yaml][js-yaml]. If
104+
you’re batching large folders of specs, [glob][glob] may also come in handy.
95105

96106
#### PropertyMapper
97107

98-
In order to allow more control over how properties are parsed, and to specifically handle
99-
`x-something`-properties, the `propertyMapper` option may be specified as the optional 2nd
100-
parameter.
108+
In order to allow more control over how properties are parsed, and to specifically handle `x-something`-properties, the
109+
`propertyMapper` option may be specified as the optional 2nd parameter.
101110

102-
This is a function that, if specified, is called for each property and allows you to change how
103-
openapi-typescript handles parsing of Swagger files.
111+
This is a function that, if specified, is called for each property and allows you to change how openapi-typescript
112+
handles parsing of Swagger files.
104113

105114
An example on how to use the `x-nullable` property to control if a property is optional:
106115

@@ -123,132 +132,32 @@ const output = swaggerToTS(swagger, {
123132

124133
_Thanks to @atlefren for this feature!_
125134

126-
## Upgrading from v1 to v2
127-
128-
Some options were removed in openapi-typescript v2 that will break apps using v1, but it does so in exchange for more control, more stability, and more resilient types.
129-
130-
TL;DR:
131-
132-
```diff
133-
-import { OpenAPI2 } from './generated';
134-
+import { definitions } from './generated';
135+
## Migrating from v1 to v2
135136

136-
-type MyType = OpenAPI2.MyType;
137-
+type MyType = definitions['MyType'];
138-
```
137+
[Migrating from v1 to v2](./docs/migrating-from-v1.md)
139138

140-
#### In-depth explanation
141-
142-
In order to explain the change, let’s go through an example with the following Swagger definition (partial):
143-
144-
```yaml
145-
swagger: 2.0
146-
definitions:
147-
user:
148-
type: object
149-
properties:
150-
role:
151-
type: object
152-
properties:
153-
access:
154-
enum:
155-
- admin
156-
- user
157-
user_role:
158-
type: object
159-
role:
160-
type: string
161-
team:
162-
type: object
163-
properties:
164-
users:
165-
type: array
166-
items:
167-
$ref: user
168-
```
139+
## Project Goals
169140

170-
This is how **v1** would have generated those types:
141+
1. Support converting any OpenAPI 3.0 or 2.0 (Swagger) schema to TypeScript types, no matter how complicated
142+
1. The generated TypeScript types **must** match your schema as closely as possible (i.e. don’t convert names to
143+
`PascalCase` or follow any TypeScript-isms; faithfully reproduce your schema as closely as possible, capitalization
144+
and all)
145+
1. This library is a TypeScript generator, not a schema validator.
171146

172-
```ts
173-
declare namespace OpenAPI2 {
174-
export interface User {
175-
role?: UserRole;
176-
}
177-
export interface UserRole {
178-
access?: "admin" | "user";
179-
}
180-
export interface UserRole {
181-
role?: string;
182-
}
183-
export interface Team {
184-
users?: User[];
185-
}
186-
}
187-
```
147+
## Contributing
188148

189-
Uh oh. It tried to be intelligent, and keep interfaces shallow by transforming `user.role` into `UserRole.` However, we also have another `user_role` entry that has a conflicting `UserRole` interface. This is not what we want.
190-
191-
v1 of this project made certain assumptions about your schema that don’t always hold true. This is how **v2** generates types from that same schema:
192-
193-
```ts
194-
export interface definitions {
195-
user: {
196-
role?: {
197-
access?: "admin" | "user";
198-
};
199-
};
200-
user_role: {
201-
role?: string;
202-
};
203-
team: {
204-
users?: definitions["user"][];
205-
};
206-
}
207-
```
208-
209-
This matches your schema more accurately, and doesn’t try to be clever by keeping things shallow. It’s also more predictable, with the generated types matching your schema naming. In your code here’s what would change:
210-
211-
```diff
212-
-UserRole
213-
+definitions['user']['role'];
214-
```
215-
216-
While this is a change, it’s more predictable. Now you don’t have to guess what `user_role` was renamed to; you simply chain your type from the Swagger definition you‘re used to.
217-
218-
#### Better \$ref generation
219-
220-
openapi-typescript v1 would attempt to resolve and flatten `$ref`s. This was bad because it would break on circular references (which both Swagger and TypeScript allow), and resolution also slowed it down.
221-
222-
In v2, your `$ref`s are preserved as-declared, and TypeScript does all the work. Now the responsibility is on your schema to handle collisions rather than openapi-typescript, which is a better approach in general.
223-
224-
#### No Wrappers
225-
226-
The `--wrapper` CLI flag was removed because it was awkward having to manage part of your TypeScript definition in a CLI flag. In v2, simply compose the wrapper yourself however you’d like in TypeScript:
227-
228-
```ts
229-
import { components as Schema1 } from './generated/schema-1.ts';
230-
import { components as Schema2 } from './generated/schema-2.ts';
231-
232-
declare namespace OpenAPI3 {
233-
export Schema1;
234-
export Schema2;
235-
}
236-
```
237-
238-
#### No CamelCasing
239-
240-
The `--camelcase` flag was removed because it would mangle object names incorrectly or break trying to sanitize them (for example, you couldn’t run camelcase on a schema with `my.obj` and `my-obj`—they both would transfom to the same thing causing unexpected results).
241-
242-
OpenAPI allows for far more flexibility in naming schema objects than JavaScript, so that should be carried over from your schema. In v2, the naming of generated types maps 1:1 with your schema name.
149+
PRs are welcome! Please see our [CONTRIBUTING.md](./CONTRIBUTING.md) guide. Opening an issue beforehand to discuss is
150+
encouraged but not required.
243151

244152
[glob]: https://www.npmjs.com/package/glob
245153
[js-yaml]: https://www.npmjs.com/package/js-yaml
246154
[openapi2]: https://swagger.io/specification/v2/
247-
[openapi3]: https://swagger.io/specification
248155
[namespace]: https://www.typescriptlang.org/docs/handbook/namespaces.html
156+
[npm-run-all]: https://www.npmjs.com/package/npm-run-all
157+
[openapi3]: https://swagger.io/specification
249158
[prettier]: https://npmjs.com/prettier
250159

251-
## Contributors ✨
160+
### Contributors ✨
252161

253162
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
254163

@@ -291,6 +200,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
291200

292201
<!-- markdownlint-enable -->
293202
<!-- prettier-ignore-end -->
203+
294204
<!-- ALL-CONTRIBUTORS-LIST:END -->
295205

296-
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
206+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification.
207+
Contributions of any kind welcome!

bin/cli.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ Options
3737
}
3838
);
3939

40-
console.info(
41-
chalk.bold(`✨ openapi-typescript ${require("../package.json").version}`)
42-
);
40+
console.info(chalk.bold(`✨ openapi-typescript ${require("../package.json").version}`));
4341

4442
const pathToSpec = cli.input[0];
4543
const timeStart = process.hrtime();
@@ -76,11 +74,7 @@ const timeStart = process.hrtime();
7674

7775
const timeEnd = process.hrtime(timeStart);
7876
const time = timeEnd[0] + Math.round(timeEnd[1] / 1e6);
79-
console.log(
80-
chalk.green(
81-
`🚀 ${cli.input[0]} -> ${chalk.bold(cli.flags.output)} [${time}ms]`
82-
)
83-
);
77+
console.log(chalk.green(`🚀 ${cli.input[0]} -> ${chalk.bold(cli.flags.output)} [${time}ms]`));
8478
return;
8579
}
8680

bin/loaders/index.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ async function load(pathToSpec) {
1010
try {
1111
rawSpec = await loadFromHttp(pathToSpec);
1212
} catch (e) {
13-
if (e.code === 'ENOTFOUND') {
14-
throw new Error(`The URL ${pathToSpec} could not be reached. Ensure the URL is correct, that you're connected to the internet and that the URL is reachable via a browser.`)
13+
if (e.code === "ENOTFOUND") {
14+
throw new Error(
15+
`The URL ${pathToSpec} could not be reached. Ensure the URL is correct, that you're connected to the internet and that the URL is reachable via a browser.`
16+
);
1517
}
1618
throw e;
1719
}
@@ -46,8 +48,6 @@ module.exports.loadSpec = async (pathToSpec) => {
4648
try {
4749
return JSON.parse(rawSpec);
4850
} catch {
49-
throw new Error(
50-
`The spec under ${pathToSpec} couldn’t be parsed neither as YAML nor JSON.`
51-
);
51+
throw new Error(`The spec under ${pathToSpec} couldn’t be parsed neither as YAML nor JSON.`);
5252
}
5353
};

0 commit comments

Comments
 (0)