Skip to content

Commit dfe8cc4

Browse files
authored
feat: introduce excludeDeprecated option (#1111)
* feat: introduce excludeDeprecated option * remove only on test * add README
1 parent 0324ac3 commit dfe8cc4

22 files changed

+64
-18
lines changed

docs/src/content/docs/cli.md

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ _Thanks, [@psmyrdek](https://github.com/psmyrdek)!_
5454
| `--path-params-as-types` | | `false` | Allow dynamic string lookups on the `paths` object |
5555
| `--support-array-length` | | `false` | Generate tuples using array `minItems` / `maxItems` |
5656
| `--alphabetize` | | `false` | Sort types alphabetically |
57+
| `--exclude-deprecated` | | `false` | Exclude deprecated fields from types |
5758

5859
### `--path-params-as-types`
5960

packages/openapi-typescript/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ The following flags can be appended to the CLI command.
117117
| `--path-params-as-types` | | `false` | Allow dynamic string lookups on the `paths` object |
118118
| `--support-array-length` | | `false` | Generate tuples using array `minItems` / `maxItems` |
119119
| `--alphabetize` | | `false` | Sort types alphabetically |
120+
| `--exclude-deprecated` | | `false` | Exclude deprecated fields from types |
120121

121122
#### 🚩 `--path-params-as-types`
122123

packages/openapi-typescript/bin/cli.js

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Options
2727
--support-array-length (optional) Generate tuples using array minItems / maxItems
2828
--path-params-as-types (optional) Substitute path parameter names with their respective types
2929
--alphabetize (optional) Sort types alphabetically
30+
--exclude-deprecated (optional) Exclude deprecated fields from types
3031
`;
3132

3233
const OUTPUT_FILE = "FILE";
@@ -54,6 +55,7 @@ const flags = parser(args, {
5455
"supportArrayLength",
5556
"pathParamsAsTypes",
5657
"alphabetize",
58+
"excludeDeprecated",
5759
],
5860
string: ["auth", "header", "headersObject", "httpMethod"],
5961
alias: {
@@ -104,6 +106,7 @@ async function generateSchema(pathToSpec) {
104106
supportArrayLength: flags.supportArrayLength,
105107
pathParamsAsTypes: flags.pathParamsAsTypes,
106108
alphabetize: flags.alphabetize,
109+
excludeDeprecated: flags.excludeDeprecated,
107110
});
108111

109112
// output

packages/openapi-typescript/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ async function openapiTS(schema: string | URL | OpenAPI3 | Readable, options: Op
5151
parameters: {},
5252
silent: options.silent ?? false,
5353
supportArrayLength: options.supportArrayLength ?? false,
54+
excludeDeprecated: options.excludeDeprecated ?? false,
5455
};
5556

5657
// note: we may be loading many large schemas into memory at once; take care to reuse references without cloning
@@ -129,7 +130,7 @@ async function openapiTS(schema: string | URL | OpenAPI3 | Readable, options: Op
129130
if (!Object.keys(subschemaTypes).length) break;
130131
output.push(indent(`${key}: {`, indentLv));
131132
indentLv++;
132-
for (const [k, v] of getEntries(subschemaTypes, options.alphabetize)) {
133+
for (const [k, v] of getEntries(subschemaTypes, options.alphabetize, options.excludeDeprecated)) {
133134
if (EMPTY_OBJECT_RE.test(v)) output.push(indent(`${escObjKey(k)}: Record<string, never>;`, indentLv));
134135
else output.push(indent(`${escObjKey(k)}: ${v};`, indentLv));
135136
}

packages/openapi-typescript/src/transform/components-object.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function transformComponentsObject(components: ComponentsObject,
1616
if (components.schemas) {
1717
output.push(indent("schemas: {", indentLv));
1818
indentLv++;
19-
for (const [name, schemaObject] of getEntries(components.schemas, ctx.alphabetize)) {
19+
for (const [name, schemaObject] of getEntries(components.schemas, ctx.alphabetize, ctx.excludeDeprecated)) {
2020
const c = getSchemaObjectComment(schemaObject, indentLv);
2121
if (c) output.push(indent(c, indentLv));
2222
let key = escObjKey(name);
@@ -37,7 +37,7 @@ export default function transformComponentsObject(components: ComponentsObject,
3737
if (components.responses) {
3838
output.push(indent("responses: {", indentLv));
3939
indentLv++;
40-
for (const [name, responseObject] of getEntries(components.responses, ctx.alphabetize)) {
40+
for (const [name, responseObject] of getEntries(components.responses, ctx.alphabetize, ctx.excludeDeprecated)) {
4141
const c = getSchemaObjectComment(responseObject, indentLv);
4242
if (c) output.push(indent(c, indentLv));
4343
let key = escObjKey(name);
@@ -62,7 +62,7 @@ export default function transformComponentsObject(components: ComponentsObject,
6262
if (components.parameters) {
6363
output.push(indent("parameters: {", indentLv));
6464
indentLv++;
65-
for (const [name, parameterObject] of getEntries(components.parameters, ctx.alphabetize)) {
65+
for (const [name, parameterObject] of getEntries(components.parameters, ctx.alphabetize, ctx.excludeDeprecated)) {
6666
const c = getSchemaObjectComment(parameterObject, indentLv);
6767
if (c) output.push(indent(c, indentLv));
6868
let key = escObjKey(name);
@@ -90,7 +90,7 @@ export default function transformComponentsObject(components: ComponentsObject,
9090
if (components.requestBodies) {
9191
output.push(indent("requestBodies: {", indentLv));
9292
indentLv++;
93-
for (const [name, requestBodyObject] of getEntries(components.requestBodies, ctx.alphabetize)) {
93+
for (const [name, requestBodyObject] of getEntries(components.requestBodies, ctx.alphabetize, ctx.excludeDeprecated)) {
9494
const c = getSchemaObjectComment(requestBodyObject, indentLv);
9595
if (c) output.push(indent(c, indentLv));
9696
let key = escObjKey(name);
@@ -125,7 +125,7 @@ export default function transformComponentsObject(components: ComponentsObject,
125125
if (components.headers) {
126126
output.push(indent("headers: {", indentLv));
127127
indentLv++;
128-
for (const [name, headerObject] of getEntries(components.headers, ctx.alphabetize)) {
128+
for (const [name, headerObject] of getEntries(components.headers, ctx.alphabetize, ctx.excludeDeprecated)) {
129129
const c = getSchemaObjectComment(headerObject, indentLv);
130130
if (c) output.push(indent(c, indentLv));
131131
let key = escObjKey(name);
@@ -150,7 +150,7 @@ export default function transformComponentsObject(components: ComponentsObject,
150150
if (components.pathItems) {
151151
output.push(indent("pathItems: {", indentLv));
152152
indentLv++;
153-
for (const [name, pathItemObject] of getEntries(components.pathItems, ctx.alphabetize)) {
153+
for (const [name, pathItemObject] of getEntries(components.pathItems, ctx.alphabetize, ctx.excludeDeprecated)) {
154154
let key = escObjKey(name);
155155
if (ctx.immutableTypes) key = tsReadonly(key);
156156
if ("$ref" in pathItemObject) {

packages/openapi-typescript/src/transform/header-object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function transformHeaderObject(headerObject: HeaderObject, { path
1414
let { indentLv } = ctx;
1515
const output: string[] = ["{"];
1616
indentLv++;
17-
for (const [contentType, mediaTypeObject] of getEntries(headerObject.content, ctx.alphabetize)) {
17+
for (const [contentType, mediaTypeObject] of getEntries(headerObject.content, ctx.alphabetize, ctx.excludeDeprecated)) {
1818
const c = getSchemaObjectComment(mediaTypeObject, indentLv);
1919
if (c) output.push(indent(c, indentLv));
2020
let key = escStr(contentType);

packages/openapi-typescript/src/transform/operation-object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export default function transformOperationObject(operationObject: OperationObjec
8888
if (operationObject.responses) {
8989
output.push(indent(`responses: {`, indentLv));
9090
indentLv++;
91-
for (const [responseCode, responseObject] of getEntries(operationObject.responses, ctx.alphabetize)) {
91+
for (const [responseCode, responseObject] of getEntries(operationObject.responses, ctx.alphabetize, ctx.excludeDeprecated)) {
9292
const key = escObjKey(responseCode);
9393
const c = getSchemaObjectComment(responseObject, indentLv);
9494
if (c) output.push(indent(c, indentLv));

packages/openapi-typescript/src/transform/paths-object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default function transformPathsObject(pathsObject: PathsObject, ctx: Glob
77
let { indentLv } = ctx;
88
const output: string[] = ["{"];
99
indentLv++;
10-
for (const [url, pathItemObject] of getEntries(pathsObject, ctx.alphabetize)) {
10+
for (const [url, pathItemObject] of getEntries(pathsObject, ctx.alphabetize, ctx.excludeDeprecated)) {
1111
let path = url;
1212

1313
// build dynamic string template literal index

packages/openapi-typescript/src/transform/request-body-object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function transformRequestBodyObject(requestBodyObject: RequestBod
1515
output.push(indent(ctx.immutableTypes ? tsReadonly("content: {") : "content: {", indentLv));
1616
if (!Object.keys(requestBodyObject.content).length) return `${escStr("*/*")}: never`;
1717
indentLv++;
18-
for (const [contentType, mediaTypeObject] of getEntries(requestBodyObject.content, ctx.alphabetize)) {
18+
for (const [contentType, mediaTypeObject] of getEntries(requestBodyObject.content, ctx.alphabetize, ctx.excludeDeprecated)) {
1919
const c = getSchemaObjectComment(mediaTypeObject, indentLv);
2020
if (c) output.push(indent(c, indentLv));
2121
let key = escStr(contentType);

packages/openapi-typescript/src/transform/response-object.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default function transformResponseObject(responseObject: ResponseObject,
2222
indentLv++;
2323
output.push(indent(`headers: {`, indentLv));
2424
indentLv++;
25-
for (const [name, headerObject] of getEntries(responseObject.headers, ctx.alphabetize)) {
25+
for (const [name, headerObject] of getEntries(responseObject.headers, ctx.alphabetize, ctx.excludeDeprecated)) {
2626
const c = getSchemaObjectComment(headerObject, indentLv);
2727
if (c) output.push(indent(c, indentLv));
2828
let key = escObjKey(name);
@@ -52,7 +52,7 @@ export default function transformResponseObject(responseObject: ResponseObject,
5252
indentLv++;
5353
output.push(indent("content: {", indentLv));
5454
indentLv++;
55-
for (const [contentType, mediaTypeObject] of getEntries(responseObject.content, ctx.alphabetize)) {
55+
for (const [contentType, mediaTypeObject] of getEntries(responseObject.content, ctx.alphabetize, ctx.excludeDeprecated)) {
5656
let key = escStr(contentType);
5757
if (ctx.immutableTypes) key = tsReadonly(key);
5858
output.push(

packages/openapi-typescript/src/transform/schema-object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export function defaultSchemaObjectTransform(schemaObject: SchemaObject | Refere
145145
const coreType: string[] = [];
146146
if (("properties" in schemaObject && schemaObject.properties && Object.keys(schemaObject.properties).length) || ("additionalProperties" in schemaObject && schemaObject.additionalProperties)) {
147147
indentLv++;
148-
for (const [k, v] of getEntries(schemaObject.properties ?? {}, ctx.alphabetize)) {
148+
for (const [k, v] of getEntries(schemaObject.properties ?? {}, ctx.alphabetize, ctx.excludeDeprecated)) {
149149
const c = getSchemaObjectComment(v, indentLv);
150150
if (c) coreType.push(indent(c, indentLv));
151151
let key = escObjKey(k);

packages/openapi-typescript/src/transform/webhooks-object.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default function transformWebhooksObject(webhooksObject: WebhooksObject,
66
let { indentLv } = ctx;
77
const output: string[] = ["{"];
88
indentLv++;
9-
for (const [name, pathItemObject] of getEntries(webhooksObject, ctx.alphabetize)) {
9+
for (const [name, pathItemObject] of getEntries(webhooksObject, ctx.alphabetize, ctx.excludeDeprecated)) {
1010
output.push(
1111
indent(
1212
`${escStr(name)}: ${transformPathItemObject(pathItemObject, {

packages/openapi-typescript/src/types.ts

+3
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,8 @@ export interface OpenAPITSOptions {
621621
* function if available; else, it will use unidici's fetch function.
622622
*/
623623
fetch?: Fetch;
624+
/** Exclude deprecated fields from types? (default: false) */
625+
excludeDeprecated?: boolean;
624626
}
625627

626628
/** Subschema discriminator (note: only valid $ref types accepted here) */
@@ -661,6 +663,7 @@ export interface GlobalContext {
661663
pathParamsAsTypes: boolean;
662664
silent: boolean;
663665
supportArrayLength: boolean;
666+
excludeDeprecated: boolean;
664667
}
665668

666669
// Fetch is available in the global scope starting with Node v18.

packages/openapi-typescript/src/utils.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,10 @@ export function indent(input: string, level: number) {
260260
}
261261

262262
/** call Object.entries() and optionally sort */
263-
export function getEntries<T>(obj: ArrayLike<T> | Record<string, T>, alphabetize?: boolean) {
264-
const entries = Object.entries(obj);
263+
export function getEntries<T>(obj: ArrayLike<T> | Record<string, T>, alphabetize?: boolean, excludeDeprecated?: boolean) {
264+
let entries = Object.entries(obj);
265265
if (alphabetize) entries.sort(([a], [b]) => a.localeCompare(b, "en", { numeric: true }));
266+
if (excludeDeprecated) entries = entries.filter(([, v]) => !(v && typeof v === "object" && "deprecated" in v && v.deprecated));
266267
return entries;
267268
}
268269

packages/openapi-typescript/test/components-object.test.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const options: GlobalContext = {
1616
silent: true,
1717
supportArrayLength: false,
1818
transform: undefined,
19+
excludeDeprecated: false,
1920
};
2021

2122
const basicSchema: ComponentsObject = {
@@ -235,7 +236,35 @@ describe("Components Object", () => {
235236
}`);
236237
});
237238
});
238-
});
239+
describe("excludeDeprecated", () => {
240+
test("true", () => {
241+
const schema: ComponentsObject = {
242+
schemas: {
243+
Alpha: {
244+
type: "object",
245+
properties: {
246+
a: { type: "boolean", deprecated: true },
247+
z: { type: "boolean" },
248+
},
249+
},
250+
},
251+
};
252+
const generated = transformComponentsObject(schema, { ...options, excludeDeprecated: true });
253+
expect(generated).toBe(`{
254+
schemas: {
255+
Alpha: {
256+
z?: boolean;
257+
};
258+
};
259+
responses: never;
260+
parameters: never;
261+
requestBodies: never;
262+
headers: never;
263+
pathItems: never;
264+
}`);
265+
});
266+
});
267+
});
239268

240269
test("parameters with required: false", () => {
241270
const generated = transformComponentsObject(optionalParamSchema, options);

packages/openapi-typescript/test/header-object.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const options: TransformHeaderObjectOptions = {
1818
silent: true,
1919
supportArrayLength: false,
2020
transform: undefined,
21+
excludeDeprecated: false,
2122
},
2223
};
2324

packages/openapi-typescript/test/load.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ async function load(
118118
silent: true,
119119
supportArrayLength: false,
120120
transform: undefined,
121+
excludeDeprecated: false,
121122
...options,
122123
});
123124
}

packages/openapi-typescript/test/path-item-object.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const options: TransformPathItemObjectOptions = {
1818
silent: true,
1919
supportArrayLength: false,
2020
transform: undefined,
21+
excludeDeprecated: false,
2122
},
2223
};
2324

packages/openapi-typescript/test/paths-object.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const options: GlobalContext = {
1616
silent: true,
1717
supportArrayLength: false,
1818
transform: undefined,
19+
excludeDeprecated: false,
1920
};
2021

2122
describe("Paths Object", () => {

packages/openapi-typescript/test/request-body-object.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const options: TransformRequestBodyObjectOptions = {
1818
silent: true,
1919
supportArrayLength: false,
2020
transform: undefined,
21+
excludeDeprecated: false,
2122
},
2223
};
2324

packages/openapi-typescript/test/schema-object.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const options: TransformSchemaObjectOptions = {
1818
silent: true,
1919
supportArrayLength: false,
2020
transform: undefined,
21+
excludeDeprecated: false,
2122
},
2223
};
2324

packages/openapi-typescript/test/webhooks-object.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const options: GlobalContext = {
1616
silent: true,
1717
supportArrayLength: false,
1818
transform: undefined,
19+
excludeDeprecated: false,
1920
};
2021

2122
describe("Webhooks Object", () => {

0 commit comments

Comments
 (0)