Skip to content

Commit bfb5ae5

Browse files
committed
Change additionalProperties default
1 parent 31527ed commit bfb5ae5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+72586
-9332
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ For anything more complicated, or for generating specs dynamically, you can also
111111
| `--output [location]` | `-o` | (stdout) | Where should the output file be saved? |
112112
| `--auth [token]` | | | (optional) Provide an auth token to be passed along in the request (only if accessing a private schema). |
113113
| `--immutable-types` | | `false` | (optional) Generates immutable types (readonly properties and readonly array). |
114+
| `--additional-properties` | `-ap` | `false` | (optional) Allow arbitrary properties for all schema objects without `additionalProperties: false` |
114115
| `--prettier-config [location]` | | | (optional) Path to your custom Prettier configuration for output |
115116
| `--raw-schema` | | `false` | Generate TS types from partial schema (e.g. having `components.schema` at the top level) |
116117

bin/cli.js

+19-7
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ const cli = meow(
1212
$ openapi-typescript [input] [options]
1313
1414
Options
15-
--help display this
16-
--output, -o Specify output file (default: stdout)
17-
--auth (optional) Provide an authentication token for private URL
18-
--immutable-types (optional) Generates immutable types (readonly properties and readonly array)
19-
--prettier-config (optional) specify path to Prettier config file
20-
--raw-schema (optional) Read from raw schema instead of document
21-
--version (optional) Schema version (must be present for raw schemas)
15+
--help display this
16+
--output, -o Specify output file (default: stdout)
17+
--auth (optional) Provide an authentication token for private URL
18+
--immutable-types, -it (optional) Generates immutable types (readonly properties and readonly array)
19+
--additional-properties, -ap (optional) Allow arbitrary properties for all schema objects without "additionalProperties: false"
20+
--prettier-config, -c (optional) specify path to Prettier config file
21+
--raw-schema (optional) Parse as partial schema (raw components)
22+
--version (optional) Force schema parsing version
2223
`,
2324
{
2425
flags: {
@@ -31,9 +32,15 @@ Options
3132
},
3233
immutableTypes: {
3334
type: "boolean",
35+
alias: "it",
36+
},
37+
additionalProperties: {
38+
type: "boolean",
39+
alias: "ap",
3440
},
3541
prettierConfig: {
3642
type: "string",
43+
alias: "c",
3744
},
3845
rawSchema: {
3946
type: "boolean",
@@ -58,6 +65,9 @@ async function main() {
5865
if (output === "FILE") {
5966
console.info(bold(`✨ openapi-typescript ${require("../package.json").version}`)); // only log if we’re NOT writing to stdout
6067
}
68+
if (cli.flags.rawSchema && !cli.flags.version) {
69+
throw new Error(`--raw-schema requires --version flag`);
70+
}
6171

6272
// 1. input
6373
let spec = undefined;
@@ -73,6 +83,8 @@ async function main() {
7383

7484
// 2. generate schema (the main part!)
7585
const result = openapiTS(spec, {
86+
auth: cli.flags.auth,
87+
additionalProperties: cli.flags.additionalProperties,
7688
immutableTypes: cli.flags.immutableTypes,
7789
prettierConfig: cli.flags.prettierConfig,
7890
rawSchema: cli.flags.rawSchema,

src/index.ts

+18-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import prettier from "prettier";
33
import parserTypescript from "prettier/parser-typescript";
44
import { swaggerVersion } from "./utils";
55
import { transformAll } from "./transform/index";
6-
import { OpenAPI2, OpenAPI3, SchemaObject, SwaggerToTSOptions } from "./types";
6+
import { GlobalContext, OpenAPI2, OpenAPI3, SchemaObject, SwaggerToTSOptions } from "./types";
77
export * from "./types"; // expose all types to consumers
88

99
export const WARNING_MESSAGE = `/**
@@ -16,22 +16,27 @@ export const WARNING_MESSAGE = `/**
1616

1717
export default function openapiTS(
1818
schema: OpenAPI2 | OpenAPI3 | Record<string, SchemaObject>,
19-
options?: SwaggerToTSOptions
19+
options: SwaggerToTSOptions = {}
2020
): string {
21-
// 1. determine version
22-
const version = (options && options.version) || swaggerVersion(schema as OpenAPI2 | OpenAPI3);
21+
// 1. set up context
22+
const ctx: GlobalContext = {
23+
auth: options.auth,
24+
additionalProperties: options.additionalProperties || false,
25+
formatter: typeof options.formatter === "function" ? options.formatter : undefined,
26+
immutableTypes: options.immutableTypes || false,
27+
rawSchema: options.rawSchema || false,
28+
version: options.version || swaggerVersion(schema as OpenAPI2 | OpenAPI3),
29+
} as any;
2330

2431
// 2. generate output
25-
let output = `${WARNING_MESSAGE}
26-
${transformAll(schema, {
27-
formatter: options && typeof options.formatter === "function" ? options.formatter : undefined,
28-
immutableTypes: (options && options.immutableTypes) || false,
29-
rawSchema: options && options.rawSchema,
30-
version,
31-
})}
32-
`;
32+
let output = WARNING_MESSAGE;
33+
const rootTypes = transformAll(schema, { ...ctx });
34+
for (const k of Object.keys(rootTypes)) {
35+
if (typeof rootTypes[k] !== "string") continue;
36+
output += `export interface ${k} {\n ${rootTypes[k]}\n}\n\n`;
37+
}
3338

34-
// 3. Prettify output
39+
// 3. Prettify
3540
let prettierOptions: prettier.Options = {
3641
parser: "typescript",
3742
plugins: [parserTypescript],

src/transform/headers.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
1-
import { HeaderObject, SchemaFormatter } from "../types";
1+
import { GlobalContext, HeaderObject } from "../types";
22
import { comment, tsReadonly } from "../utils";
33
import { transformSchemaObj } from "./schema";
44

5+
interface TransformHeadersOptions extends GlobalContext {
6+
required: Set<string>;
7+
}
8+
59
export function transformHeaderObjMap(
610
headerMap: Record<string, HeaderObject>,
7-
options: { formatter?: SchemaFormatter; immutableTypes: boolean; version: number }
11+
options: TransformHeadersOptions
812
): string {
913
let output = "";
1014

11-
Object.entries(headerMap).forEach(([k, v]) => {
12-
if (!v.schema) return;
15+
for (const k of Object.keys(headerMap)) {
16+
const v = headerMap[k];
17+
if (!v.schema) continue;
1318

1419
if (v.description) output += comment(v.description);
1520

1621
const readonly = tsReadonly(options.immutableTypes);
1722
const required = v.required ? "" : "?";
1823

1924
output += ` ${readonly}"${k}"${required}: ${transformSchemaObj(v.schema, options)}\n`;
20-
});
25+
}
2126

2227
return output;
2328
}

src/transform/index.ts

+61-89
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,137 @@
1-
import { OperationObject, PathItemObject, SchemaFormatter } from "../types";
1+
import { GlobalContext, OperationObject, PathItemObject } from "../types";
22
import { comment, tsReadonly } from "../utils";
33
import { transformHeaderObjMap } from "./headers";
44
import { transformOperationObj } from "./operation";
55
import { transformPathsObj } from "./paths";
6-
import { transformResponsesObj, transformRequestBodies } from "./responses";
6+
import { transformRequestBodies } from "./request";
7+
import { transformResponsesObj } from "./responses";
78
import { transformSchemaObjMap } from "./schema";
89

9-
interface TransformOptions {
10-
formatter?: SchemaFormatter;
11-
immutableTypes: boolean;
12-
rawSchema?: boolean;
13-
version: number;
14-
}
15-
16-
export function transformAll(schema: any, { formatter, immutableTypes, rawSchema, version }: TransformOptions): string {
17-
const readonly = tsReadonly(immutableTypes);
10+
export function transformAll(schema: any, ctx: GlobalContext): Record<string, string> {
11+
const readonly = tsReadonly(ctx.immutableTypes);
1812

19-
let output = "";
13+
let output: Record<string, string> = {};
2014

2115
let operations: Record<string, { operation: OperationObject; pathItem: PathItemObject }> = {};
2216

2317
// --raw-schema mode
24-
if (rawSchema) {
25-
switch (version) {
18+
if (ctx.rawSchema) {
19+
const required = new Set(Object.keys(schema));
20+
switch (ctx.version) {
2621
case 2: {
27-
return `export interface definitions {\n ${transformSchemaObjMap(schema, {
28-
formatter,
29-
immutableTypes,
30-
required: Object.keys(schema),
31-
version,
32-
})}\n}`;
22+
output.definitions = transformSchemaObjMap(schema, { ...ctx, required });
23+
return output;
3324
}
3425
case 3: {
35-
return `export interface schemas {\n ${transformSchemaObjMap(schema, {
36-
formatter,
37-
immutableTypes,
38-
required: Object.keys(schema),
39-
version,
40-
})}\n }\n\n`;
26+
output.schemas = transformSchemaObjMap(schema, { ...ctx, required });
27+
return output;
4128
}
4229
}
4330
}
4431

4532
// #/paths (V2 & V3)
46-
output += `export interface paths {\n`; // open paths
33+
output.paths = ""; // open paths
4734
if (schema.paths) {
48-
output += transformPathsObj(schema.paths, {
35+
output.paths += transformPathsObj(schema.paths, {
36+
...ctx,
4937
globalParameters: (schema.components && schema.components.parameters) || schema.parameters,
50-
immutableTypes,
5138
operations,
52-
version,
5339
});
5440
}
55-
output += `}\n\n`; // close paths
5641

57-
switch (version) {
42+
switch (ctx.version) {
5843
case 2: {
5944
// #/definitions
6045
if (schema.definitions) {
61-
output += `export interface definitions {\n ${transformSchemaObjMap(schema.definitions, {
62-
formatter,
63-
immutableTypes,
64-
required: Object.keys(schema.definitions),
65-
version,
66-
})}\n}\n\n`;
46+
output.definitions = transformSchemaObjMap(schema.definitions, {
47+
...ctx,
48+
required: new Set(Object.keys(schema.definitions)),
49+
});
6750
}
6851

6952
// #/parameters
7053
if (schema.parameters) {
71-
const required = Object.keys(schema.parameters);
72-
output += `export interface parameters {\n ${transformSchemaObjMap(schema.parameters, {
73-
formatter,
74-
immutableTypes,
75-
required,
76-
version,
77-
})}\n }\n\n`;
54+
output.parameters = transformSchemaObjMap(schema.parameters, {
55+
...ctx,
56+
required: new Set(Object.keys(schema.parameters)),
57+
});
7858
}
7959

8060
// #/parameters
8161
if (schema.responses) {
82-
output += `export interface responses {\n ${transformResponsesObj(schema.responses, {
83-
formatter,
84-
immutableTypes,
85-
version,
86-
})}\n }\n\n`;
62+
output.responses = transformResponsesObj(schema.responses, ctx);
8763
}
8864
break;
8965
}
9066
case 3: {
9167
// #/components
92-
output += `export interface components {\n`; // open components
68+
output.components = "";
9369

9470
if (schema.components) {
9571
// #/components/schemas
9672
if (schema.components.schemas) {
97-
const required = Object.keys(schema.components.schemas);
98-
output += ` ${readonly}schemas: {\n ${transformSchemaObjMap(schema.components.schemas, {
99-
formatter,
100-
immutableTypes,
101-
required,
102-
version,
73+
output.components += ` ${readonly}schemas: {\n ${transformSchemaObjMap(schema.components.schemas, {
74+
...ctx,
75+
required: new Set(Object.keys(schema.components.schemas)),
10376
})}\n }\n`;
10477
}
10578

10679
// #/components/responses
10780
if (schema.components.responses) {
108-
output += ` ${readonly}responses: {\n ${transformResponsesObj(schema.components.responses, {
109-
formatter,
110-
immutableTypes,
111-
version,
112-
})}\n }\n`;
81+
output.components += ` ${readonly}responses: {\n ${transformResponsesObj(
82+
schema.components.responses,
83+
ctx
84+
)}\n }\n`;
11385
}
11486

11587
// #/components/parameters
11688
if (schema.components.parameters) {
117-
const required = Object.keys(schema.components.parameters);
118-
output += ` ${readonly}parameters: {\n ${transformSchemaObjMap(schema.components.parameters, {
119-
formatter,
120-
immutableTypes,
121-
required,
122-
version,
89+
output.components += ` ${readonly}parameters: {\n ${transformSchemaObjMap(schema.components.parameters, {
90+
...ctx,
91+
required: new Set(Object.keys(schema.components.parameters)),
12392
})}\n }\n`;
12493
}
12594

12695
// #/components/requestBodies
12796
if (schema.components.requestBodies) {
128-
output += ` ${readonly}requestBodies: {\n ${transformRequestBodies(schema.components.requestBodies, {
129-
formatter,
130-
immutableTypes,
131-
version,
132-
})}\n }\n`;
97+
output.components += ` ${readonly}requestBodies: {\n ${transformRequestBodies(
98+
schema.components.requestBodies,
99+
ctx
100+
)}\n }\n`;
133101
}
134102

135103
// #/components/headers
136104
if (schema.components.headers) {
137-
output += ` ${readonly}headers: {\n ${transformHeaderObjMap(schema.components.headers, {
138-
formatter,
139-
immutableTypes,
140-
version,
141-
})} }\n`;
105+
output.components += ` ${readonly}headers: {\n ${transformHeaderObjMap(schema.components.headers, {
106+
...ctx,
107+
required: new Set<string>(),
108+
})}\n }\n`;
142109
}
143110
}
144-
145-
output += `}\n\n`; // close components
146111
break;
147112
}
148113
}
149114

150-
output += `export interface operations {\n`; // open operations
115+
// #/operations
116+
output.operations = "";
151117
if (Object.keys(operations).length) {
152-
Object.entries(operations).forEach(([operationId, { operation, pathItem }]) => {
153-
if (operation.description) output += comment(operation.description); // handle comment
154-
output += ` ${readonly}"${operationId}": {\n ${transformOperationObj(operation, {
118+
for (const id of Object.keys(operations)) {
119+
const { operation, pathItem } = operations[id];
120+
if (operation.description) output.operations += comment(operation.description); // handle comment
121+
output.operations += ` ${readonly}"${id}": {\n ${transformOperationObj(operation, {
122+
...ctx,
155123
pathItem,
156124
globalParameters: (schema.components && schema.components.parameters) || schema.parameters,
157-
immutableTypes,
158-
version,
159125
})}\n }\n`;
160-
});
126+
}
127+
}
128+
129+
// cleanup: trim whitespace
130+
for (const k of Object.keys(output)) {
131+
if (typeof output[k] === "string") {
132+
output[k] = output[k].trim();
133+
}
161134
}
162-
output += `}\n`; // close operations
163135

164-
return output.trim();
136+
return output;
165137
}

0 commit comments

Comments
 (0)