diff --git a/README.md b/README.md index 59b2118fd..a179993ed 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ npx openapi-typescript schema.yaml | `--support-array-length` | | `false` | (optional) Generate tuples using array minItems / maxItems | | `--make-paths-enum` | `-pe` | `false` | (optional) Generate an enum of endpoint paths | | `--path-params-as-types` | | `false` | (optional) Substitute path parameter names with their respective types | +| `--alphabetize` | | `false` | (optional) Sort types alphabetically | | `--raw-schema` | | `false` | Generate TS types from partial schema (e.g. having `components.schema` at the top level) | ### 🐢 Node diff --git a/bin/cli.js b/bin/cli.js index 0dc3d6e82..4975150e6 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -30,6 +30,7 @@ Options --export-type (optional) Export type instead of interface --support-array-length (optional) Generate tuples using array minItems / maxItems --path-params-as-types (optional) Substitute path parameter names with their respective types + --alphabetize (optional) Sort types alphabetically --version (optional) Force schema parsing version `; @@ -57,6 +58,7 @@ const flags = parser(args, { "supportArrayLength", "makePathsEnum", "pathParamsAsTypes", + "alphabetize", ], number: ["version"], string: ["auth", "header", "headersObject", "httpMethod", "prettierConfig"], @@ -112,6 +114,7 @@ async function generateSchema(pathToSpec) { exportType: flags.exportType, supportArrayLength: flags.supportArrayLength, pathParamsAsTypes: flags.pathParamsAsTypes, + alphabetize: flags.alphabetize, }); // output diff --git a/src/index.ts b/src/index.ts index ba0a314a3..363683372 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,6 +46,7 @@ async function openapiTS( contentNever: options.contentNever || false, makePathsEnum: options.makePathsEnum || false, pathParamsAsTypes: options.pathParamsAsTypes, + alphabetize: options.alphabetize || false, rawSchema: options.rawSchema || false, supportArrayLength: options.supportArrayLength, version: options.version || 3, diff --git a/src/transform/headers.ts b/src/transform/headers.ts index a746d4758..3e428ada7 100644 --- a/src/transform/headers.ts +++ b/src/transform/headers.ts @@ -1,5 +1,5 @@ import type { GlobalContext, HeaderObject } from "../types.js"; -import { comment, tsReadonly } from "../utils.js"; +import { comment, getEntries, tsReadonly } from "../utils.js"; import { transformSchemaObj } from "./schema.js"; interface TransformHeadersOptions extends GlobalContext { @@ -12,8 +12,7 @@ export function transformHeaderObjMap( ): string { let output = ""; - for (const k of Object.keys(headerMap)) { - const v = headerMap[k]; + for (const [k, v] of getEntries(headerMap, options)) { if (!v.schema) continue; if (v.description) output += comment(v.description); diff --git a/src/transform/parameters.ts b/src/transform/parameters.ts index 7f408d20b..db22b6449 100644 --- a/src/transform/parameters.ts +++ b/src/transform/parameters.ts @@ -1,5 +1,5 @@ import type { GlobalContext, ParameterObject, ReferenceObject } from "../types.js"; -import { comment, tsReadonly } from "../utils.js"; +import { comment, getEntries, tsReadonly } from "../utils.js"; import { transformSchemaObj } from "./schema.js"; interface TransformParametersOptions extends GlobalContext { @@ -19,11 +19,16 @@ export function transformParametersArray( // sort into map const mappedParams: Record> = {}; - for (const paramObj of parameters as any[]) { - if (paramObj.$ref && globalParameters) { - const paramName = paramObj.$ref.split('["').pop().replace(PARAM_END_RE, ""); // take last segment + for (const paramObj of parameters) { + if ("$ref" in paramObj && paramObj.$ref && globalParameters) { + // take last segment + let paramName = paramObj.$ref.split('["').pop(); + paramName = String(paramName).replace(PARAM_END_RE, ""); + if (globalParameters[paramName]) { - const reference = globalParameters[paramName] as any; + const reference = globalParameters[paramName]; + if (!reference.in) continue; + if (!mappedParams[reference.in]) mappedParams[reference.in] = {}; switch (ctx.version) { case 3: { @@ -36,7 +41,7 @@ export function transformParametersArray( case 2: { mappedParams[reference.in][reference.name || paramName] = { ...reference, - $ref: paramObj.$ref, + ...("$ref" in paramObj ? { $ref: paramObj.$ref } : null), }; break; } @@ -45,15 +50,16 @@ export function transformParametersArray( continue; } + if (!("in" in paramObj)) continue; if (!paramObj.in || !paramObj.name) continue; if (!mappedParams[paramObj.in]) mappedParams[paramObj.in] = {}; mappedParams[paramObj.in][paramObj.name] = paramObj; } // transform output - for (const [paramIn, paramGroup] of Object.entries(mappedParams)) { + for (const [paramIn, paramGroup] of getEntries(mappedParams, ctx)) { output += ` ${readonly}${paramIn}: {\n`; // open in - for (const [paramName, paramObj] of Object.entries(paramGroup)) { + for (const [paramName, paramObj] of getEntries(paramGroup, ctx)) { let paramComment = ""; if (paramObj.deprecated) paramComment += `@deprecated `; if (paramObj.description) paramComment += paramObj.description; diff --git a/src/transform/paths.ts b/src/transform/paths.ts index 3c7316b24..6e7923198 100644 --- a/src/transform/paths.ts +++ b/src/transform/paths.ts @@ -1,5 +1,5 @@ import type { GlobalContext, OperationObject, ParameterObject, PathItemObject } from "../types.js"; -import { comment, tsReadonly, nodeType } from "../utils.js"; +import { comment, tsReadonly, nodeType, getEntries } from "../utils.js"; import { transformOperationObj } from "./operation.js"; import { transformParametersArray } from "./parameters.js"; @@ -33,7 +33,7 @@ export function transformPathsObj(paths: Record, options let output = ""; - for (const [url, pathItem] of Object.entries(paths)) { + for (const [url, pathItem] of getEntries(paths, options)) { if (pathItem.description) output += comment(pathItem.description); // add comment if (pathItem.$ref) { diff --git a/src/transform/request.ts b/src/transform/request.ts index 59f6485bb..77ed8757f 100644 --- a/src/transform/request.ts +++ b/src/transform/request.ts @@ -1,11 +1,11 @@ import type { GlobalContext, RequestBody } from "../types.js"; -import { comment, tsReadonly } from "../utils.js"; +import { comment, getEntries, tsReadonly } from "../utils.js"; import { transformSchemaObj } from "./schema.js"; export function transformRequestBodies(requestBodies: Record, ctx: GlobalContext) { let output = ""; - for (const [name, requestBody] of Object.entries(requestBodies)) { + for (const [name, requestBody] of getEntries(requestBodies, ctx)) { if (requestBody && requestBody.description) output += ` ${comment(requestBody.description)}`; output += ` "${name}": {\n ${transformRequestBodyObj(requestBody, ctx)}\n }\n`; } @@ -20,7 +20,7 @@ export function transformRequestBodyObj(requestBody: RequestBody, ctx: GlobalCon if (requestBody.content && Object.keys(requestBody.content).length) { output += ` ${readonly}content: {\n`; // open content - for (const [k, v] of Object.entries(requestBody.content)) { + for (const [k, v] of getEntries(requestBody.content, ctx)) { output += ` ${readonly}"${k}": ${transformSchemaObj(v.schema, { ...ctx, required: new Set() })};\n`; } output += ` }\n`; // close content diff --git a/src/transform/responses.ts b/src/transform/responses.ts index aabae07cf..9b27b5f4c 100644 --- a/src/transform/responses.ts +++ b/src/transform/responses.ts @@ -1,5 +1,5 @@ import type { GlobalContext } from "../types.js"; -import { comment, tsReadonly } from "../utils.js"; +import { comment, getEntries, tsReadonly } from "../utils.js"; import { transformHeaderObjMap } from "./headers.js"; import { transformSchemaObj } from "./schema.js"; @@ -15,9 +15,8 @@ export function transformResponsesObj(responsesObj: Record, ctx: Gl let output = ""; - for (const httpStatusCode of Object.keys(responsesObj)) { + for (const [httpStatusCode, response] of getEntries(responsesObj, ctx)) { const statusCode = Number(httpStatusCode) || `"${httpStatusCode}"`; // don’t surround w/ quotes if numeric status code - const response = responsesObj[httpStatusCode]; if (response.description) output += comment(response.description); if (response.$ref) { @@ -48,10 +47,10 @@ export function transformResponsesObj(responsesObj: Record, ctx: Gl switch (ctx.version) { case 3: { output += ` ${readonly}content: {\n`; // open content - for (const contentType of Object.keys(response.content)) { - const contentResponse = response.content[contentType] as any; + // TODO: proper type definitions for this + for (const [contentType, contentResponse] of getEntries(response.content, ctx)) { const responseType = - contentResponse && contentResponse?.schema + "schema" in contentResponse ? transformSchemaObj(contentResponse.schema, { ...ctx, required: new Set() }) : "unknown"; output += ` ${readonly}"${contentType}": ${responseType};\n`; diff --git a/src/transform/schema.ts b/src/transform/schema.ts index 88bb3acfe..cafcc6a68 100644 --- a/src/transform/schema.ts +++ b/src/transform/schema.ts @@ -9,6 +9,7 @@ import { tsUnionOf, parseSingleSimpleValue, ParsedSimpleValue, + getEntries, } from "../utils.js"; interface TransformSchemaObjOptions extends GlobalContext { @@ -27,9 +28,7 @@ function hasDefaultValue(node: any): boolean { export function transformSchemaObjMap(obj: Record, options: TransformSchemaObjOptions): string { let output = ""; - for (const k of Object.keys(obj)) { - const v = obj[k]; - + for (const [k, v] of getEntries(obj, options)) { // 1. Add comment in jsdoc notation const comment = prepareComment(v); if (comment) output += comment; diff --git a/src/types.ts b/src/types.ts index 9a6bc1e0e..b54e212c0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -136,6 +136,8 @@ export interface SwaggerToTSOptions { rawSchema?: boolean; /** (optional) Generate an enum containing all API paths. **/ makePathsEnum?: boolean; + /** (optional) Sort types alphabetically. */ + alphabetize?: boolean; /** (optional) Should logging be suppressed? (necessary for STDOUT) */ silent?: boolean; /** (optional) OpenAPI version. Must be present if parsing raw schema */ @@ -186,6 +188,7 @@ export interface GlobalContext { makePathsEnum: boolean; namespace?: string; pathParamsAsTypes?: boolean; + alphabetize?: boolean; rawSchema: boolean; silent?: boolean; supportArrayLength?: boolean; diff --git a/src/utils.ts b/src/utils.ts index 5f3b6c81d..f1a77a51c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import type { OpenAPI2, OpenAPI3, ReferenceObject } from "./types.js"; +import type { GlobalContext, OpenAPI2, OpenAPI3, ReferenceObject } from "./types.js"; type CommentObject = { const?: boolean; // jsdoc without value @@ -292,3 +292,9 @@ export function replaceKeys(obj: Record): Record { return obj; } } + +export function getEntries(obj: ArrayLike | Record, options: GlobalContext) { + const entries = Object.entries(obj); + if (options.alphabetize) entries.sort(([a], [b]) => a.localeCompare(b, "en", { numeric: true })); + return entries; +} diff --git a/test/core/operation.test.js b/test/core/operation.test.js index e8da55db2..2ab105f9c 100644 --- a/test/core/operation.test.js +++ b/test/core/operation.test.js @@ -187,4 +187,108 @@ describe("parameters", () => { }`); }); + + describe("alphabetize", () => { + function assertSchema(actual, expected) { + const result = transformOperationObj(actual, { + ...defaults, + alphabetize: true, + version: 3, + pathItem: { + parameters: [ + { + in: "path", + name: "p2", + schema: { + type: "string", + }, + }, + { + in: "path", + name: "p3", + schema: { + type: "string", + }, + }, + ], + }, + }); + expect(result.trim()).to.equal(expected.trim()); + } + + it("content types", () => { + const actual = { + requestBody: { + content: { + "font/woff2": { + schema: { type: "string" }, + }, + "font/otf": { + schema: { type: "string" }, + }, + "font/sfnt": { + schema: { type: "string" }, + }, + "font/ttf": { + schema: { type: "string" }, + }, + "font/woff": { + schema: { type: "string" }, + }, + }, + }, + }; + + const expected = `parameters: { + path: { + "p2"?: string; + "p3"?: string; + } + + } + requestBody: { + content: { + "font/otf": string; + "font/sfnt": string; + "font/ttf": string; + "font/woff": string; + "font/woff2": string; + } + }`; + + assertSchema(actual, expected); + }); + + it("operation parameters", () => { + const actual = { + parameters: [ + { + in: "path", + name: "p2", + schema: { + type: "number", + }, + }, + { + in: "path", + name: "p1", + schema: { + type: "string", + }, + }, + ], + }; + + const expected = `parameters: { + path: { + "p1"?: string; + "p2"?: number; + "p3"?: string; + } + + }`; + + assertSchema(actual, expected); + }); + }); }); diff --git a/test/core/parameters.test.js b/test/core/parameters.test.js index 996809102..b82837b05 100644 --- a/test/core/parameters.test.js +++ b/test/core/parameters.test.js @@ -67,6 +67,58 @@ describe("transformParametersArray()", () => { ); }); + it("basic (alphabetize)", () => { + const schema = [ + { in: "query", name: "delta", required: true, type: "string" }, + { in: "query", name: "charlie", required: true, type: "string" }, + { in: "query", name: "alpha", required: true, type: "string" }, + { in: "query", name: "bravo", required: true, type: "string" }, + ]; + + const actual = transformParametersArray(schema, { + ...defaults, + version: 2, + alphabetize: true, + globalParameters: { + per_page: { in: "query", name: "per_page", required: true, type: "number" }, + page: { in: "query", name: "page", type: "number" }, + since: { in: "query", name: "since", type: "string" }, + }, + }).trim(); + expect(actual).to.equal(`query: { + "alpha": string; + "bravo": string; + "charlie": string; + "delta": string; + }`); + }); + + it("numeric (alphabetize)", () => { + const schema = [ + { in: "query", name: "1000", required: true, type: "string" }, + { in: "query", name: "123", required: true, type: "string" }, + { in: "query", name: "1001", required: true, type: "string" }, + { in: "query", name: "111", required: true, type: "string" }, + ]; + + const actual = transformParametersArray(schema, { + ...defaults, + version: 2, + alphabetize: true, + globalParameters: { + per_page: { in: "query", name: "per_page", required: true, type: "number" }, + page: { in: "query", name: "page", type: "number" }, + since: { in: "query", name: "since", type: "string" }, + }, + }).trim(); + expect(actual).to.equal(`query: { + "111": string; + "123": string; + "1000": string; + "1001": string; + }`); + }); + const refSchema = [ { $ref: 'parameters["per_page"]' }, { $ref: 'parameters["page"]' }, @@ -107,6 +159,24 @@ describe("transformParametersArray()", () => { readonly "per_page": parameters["per_page"]; readonly "page"?: parameters["page"]; readonly "since"?: parameters["since"]; + }`); + }); + + it("$ref (alphabetize)", () => { + const actual = transformParametersArray(refSchema, { + ...defaults, + version: 2, + alphabetize: true, + globalParameters: { + per_page: { in: "query", name: "per_page", required: true, type: "number" }, + page: { in: "query", name: "page", type: "number" }, + since: { in: "query", name: "since", type: "string" }, + }, + }).trim(); + expect(actual).to.equal(`query: { + "page"?: parameters["page"]; + "per_page": parameters["per_page"]; + "since"?: parameters["since"]; }`); }); }); @@ -171,6 +241,58 @@ describe("transformParametersArray()", () => { ); }); + it("basic (alphabetize)", () => { + const schema = [ + { in: "query", name: "delta", required: true, schema: { type: "string" } }, + { in: "query", name: "charlie", required: true, schema: { type: "string" } }, + { in: "query", name: "alpha", required: true, schema: { type: "string" } }, + { in: "query", name: "bravo", required: true, schema: { type: "string" } }, + ]; + + const actual = transformParametersArray(schema, { + ...defaults, + version: 3, + alphabetize: true, + globalParameters: { + per_page: { in: "query", name: "per_page", required: true, type: "number" }, + page: { in: "query", name: "page", type: "number" }, + since: { in: "query", name: "since", type: "string" }, + }, + }).trim(); + expect(actual).to.equal(`query: { + "alpha": string; + "bravo": string; + "charlie": string; + "delta": string; + }`); + }); + + it("numeric (alphabetize)", () => { + const schema = [ + { in: "query", name: "1000", required: true, schema: { type: "string" } }, + { in: "query", name: "123", required: true, schema: { type: "string" } }, + { in: "query", name: "1001", required: true, schema: { type: "string" } }, + { in: "query", name: "111", required: true, schema: { type: "string" } }, + ]; + + const actual = transformParametersArray(schema, { + ...defaults, + version: 3, + alphabetize: true, + globalParameters: { + per_page: { in: "query", name: "per_page", required: true, type: "number" }, + page: { in: "query", name: "page", type: "number" }, + since: { in: "query", name: "since", type: "string" }, + }, + }).trim(); + expect(actual).to.equal(`query: { + "111": string; + "123": string; + "1000": string; + "1001": string; + }`); + }); + const refSchema = [ { $ref: 'components["parameters"]["per_page"]' }, { $ref: 'components["parameters"]["page"]' }, @@ -214,6 +336,24 @@ describe("transformParametersArray()", () => { }`); }); + it("$ref (alphabetize)", () => { + const actual = transformParametersArray(refSchema, { + ...defaults, + version: 3, + alphabetize: true, + globalParameters: { + per_page: { in: "query", name: "per_page", required: true, type: "number" }, + page: { in: "query", name: "page", type: "number" }, + since: { in: "query", name: "since", type: "string" }, + }, + }).trim(); + expect(actual).to.equal(`query: { + "page"?: components["parameters"]["page"]; + "per_page": components["parameters"]["per_page"]; + "since"?: components["parameters"]["since"]; + }`); + }); + it("nullable", () => { const schema = [ { in: "query", name: "nullableString", schema: { type: "string", nullable: true } }, diff --git a/test/core/paths.test.js b/test/core/paths.test.js index 46378433e..4787eb854 100644 --- a/test/core/paths.test.js +++ b/test/core/paths.test.js @@ -14,6 +14,9 @@ const defaults = { operations: {}, rawSchema: false, version: 3, // both 2 and 3 should generate the same + commentHeader: "", + contentNever: false, + makePathsEnum: false, }; describe("transformPathsObj", () => { @@ -525,4 +528,141 @@ describe("transformPathsObj", () => { };`) ); }); + + describe("alphabetize", () => { + function assertSchema(actual, expected) { + const result = format(transform(actual, { ...defaults, alphabetize: true })); + expect(result).to.equal(format(expected)); + } + + it("operations", () => { + const actual = { + "/pies": { get: {} }, + "/cakes": { get: {} }, + "/donuts": { get: {} }, + "/cookies": { get: {} }, + }; + + const expected = ` + "/cakes": { + get: {}; + }; + "/cookies": { + get: {}; + }; + "/donuts": { + get: {}; + }; + "/pies": { + get: {}; + }; +`; + + assertSchema(actual, expected); + }); + + it("parameters", () => { + const actual = { + "/contact": { + post: { + parameters: [ + { name: "q", in: "query", required: true, schema: { type: "string" } }, + { name: "p", in: "query", schema: { type: "integer" } }, + ], + }, + }, + }; + + const expected = ` + "/contact": { + post: { + parameters: { + query: { + p?: number; + q: string; + }; + }; + }; + }; + `; + + assertSchema(actual, expected); + }); + + it("response codes", () => { + const actual = { + "/contact": { + post: { + responses: { + 500: {}, + 200: {}, + 400: {}, + 40: {}, + }, + }, + }, + }; + + const expected = ` + "/contact": { + post: { + responses: { + 40: unknown; + 200: unknown; + 400: unknown; + 500: unknown; + }; + }; + }; + `; + + assertSchema(actual, expected); + }); + + it("response properties", () => { + const actual = { + "/contact": { + post: { + responses: { + 200: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + lastName: { type: "string" }, + firstName: { type: "string" }, + age: { type: "integer" }, + }, + additionalProperties: false, + }, + }, + }, + }, + }, + }, + }, + }; + + const expected = ` + "/contact": { + post: { + responses: { + 200: { + content: { + "application/json": { + age?: number; + firstName?: string; + lastName?: string; + }; + }; + }; + } + } + } + `; + + assertSchema(actual, expected); + }); + }); }); diff --git a/test/core/request.test.js b/test/core/request.test.js index a275d17fd..dc5475ce6 100644 --- a/test/core/request.test.js +++ b/test/core/request.test.js @@ -56,6 +56,63 @@ describe("requestBodies", () => { ); }); + it("basic (alphabetize)", () => { + const schema = { + SupportAnimal: { + description: "Support Animal request body", + content: { + "application/json": { + schema: { + type: "string", + }, + }, + }, + }, + Pet: { + description: "Pet request body", + content: { + "application/json": { + schema: { + type: "string", + }, + }, + }, + }, + Mount: { + description: "Mount request body", + content: { + "application/json": { + schema: { + type: "string", + }, + }, + }, + }, + }; + + const actual = format(transformRequestBodies(schema, { ...defaults, alphabetize: true, version: 2 })); + expect(actual).to.equal( + format(`/** Mount request body */ + Mount: { + content: { + "application/json": string; + }; + }; + /** Pet request body */ + Pet: { + content: { + "application/json": string; + }; + }; + /** Support Animal request body */ + SupportAnimal: { + content: { + "application/json": string; + }; + };`) + ); + }); + const schemaHyphen = { "Pet-example": { description: "Pet-example request body", diff --git a/test/core/schema.test.js b/test/core/schema.test.js index 301b43fa8..eb7300fc8 100644 --- a/test/core/schema.test.js +++ b/test/core/schema.test.js @@ -179,6 +179,57 @@ describe("SchemaObject", () => { ); }); + describe("alphabetize", () => { + it("object", () => { + const opts = { ...defaults, alphabetize: true }; + expect(transform(objStd, opts)).to.equal( + `{\n"object"?: {\n"number"?: components["schemas"]["object_ref"];\n"string"?: string;\n\n};\n\n}` + ); + expect(transform(objUnknown, opts)).to.equal(`{ [key: string]: unknown }`); + expect(transform({}, opts)).to.equal(`unknown`); + expect(transform(objNullable, opts)).to.equal(`({\n"string"?: string;\n\n}) | null`); + expect(transform(objRequired, opts)).to.equal(`{\n"optional"?: boolean;\n"required": string;\n\n}`); + }); + + it("array", () => { + const opts = { ...defaults, alphabetize: true }; + expect(transform({ type: "array", items: { type: "string" } }, opts)).to.equal(`(string)[]`); + expect(transform({ type: "array", items: { type: "number" } }, opts)).to.equal(`(number)[]`); + expect(transform({ type: "array", items: { type: "boolean" } }, opts)).to.equal(`(boolean)[]`); + expect( + transform( + { type: "array", items: { type: "array", items: { type: "array", items: { type: "number" } } } }, + opts + ) + ).to.equal(`(((number)[])[])[]`); + expect(transform({ type: "array", items: { $ref: 'components["schemas"]["ArrayItem"]' } }, opts)).to.equal( + `(components["schemas"]["ArrayItem"])[]` + ); + expect(transform({ items: { $ref: 'components["schemas"]["ArrayItem"]' } }, opts)).to.equal( + `(components["schemas"]["ArrayItem"])[]` + ); + expect(transform({ type: "array", items: { type: "string" }, nullable: true }, opts)).to.equal( + `((string)[]) | null` + ); + // enums should not be alphabetized, because the implicit order of the + // values can be significant. + expect(transform({ type: "array", items: { enum: ["vanilla", "chocolate"] } }, opts)).to.equal( + `(('vanilla') | ('chocolate'))[]` + ); + // non-enum arrays probably should be alphabetized but are not. It + // would take a more significant rewrite of schema.ts to make that + // possible, and I'm not sure that it makes much difference. Primary + // use-case for alphabetize is to ensure types are stable when checked + // into git. I doubt array declarations will shuffle positions, even + // when the docs are generated dynamically. + /* + expect(transform({ type: "array", items: [{ type: "string" }, { type: "number" }] }, opts)).to.equal( + `[number, string]` + ); + */ + }); + }); + it("enum", () => { const enumBasic = ["Totoro", "Sats'uki", "Mei"]; // note: also tests quotes in enum expect( diff --git a/tsconfig.json b/tsconfig.json index 4e1cd0510..9aec762c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,6 @@ "target": "ESNext", "useDefineForClassFields": true }, - "exclude": ["examples", "node_modules"], + "exclude": ["examples", "node_modules", "**/generated/*", "**/expected/*"], "include": ["scripts", "src", "test"] }