fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #1468 from hey-api/fix/no-unchecked-indexed-access

fix: handle indexed access checks

authored by

Lubos and committed by
GitHub
ac442f05 6dfbd49d

+138 -107
+7
.changeset/brown-parents-explain.md
··· 1 + --- 2 + '@hey-api/client-axios': patch 3 + '@hey-api/client-fetch': patch 4 + '@hey-api/openapi-ts': patch 5 + --- 6 + 7 + fix: handle indexed access checks
+1
packages/client-axios/tsconfig.base.json
··· 5 5 "module": "ESNext", 6 6 "moduleResolution": "Bundler", 7 7 "noImplicitOverride": true, 8 + "noUncheckedIndexedAccess": true, 8 9 "noUnusedLocals": true, 9 10 "strict": true, 10 11 "target": "ES2022",
+5 -1
packages/client-fetch/src/utils.ts
··· 332 332 return; 333 333 } 334 334 335 - const cleanContent = contentType.split(';')[0].trim(); 335 + const cleanContent = contentType.split(';')[0]?.trim(); 336 + 337 + if (!cleanContent) { 338 + return; 339 + } 336 340 337 341 if ( 338 342 cleanContent.startsWith('application/json') ||
+1
packages/client-fetch/tsconfig.base.json
··· 5 5 "module": "ESNext", 6 6 "moduleResolution": "Bundler", 7 7 "noImplicitOverride": true, 8 + "noUncheckedIndexedAccess": true, 8 9 "noUnusedLocals": true, 9 10 "strict": true, 10 11 "target": "ES2022",
+2 -2
packages/openapi-ts/src/compiler/transform.ts
··· 29 29 createIdentifier({ text: element }), 30 30 ); 31 31 }, 32 - createIdentifier({ text: path[0] }), 32 + createIdentifier({ text: path[0]! }), 33 33 ); 34 34 35 35 export const createAccessExpression = (path: string[]) => ··· 39 39 expression, 40 40 name: element, 41 41 }), 42 - createIdentifier({ text: path[0] }), 42 + createIdentifier({ text: path[0]! }), 43 43 ); 44 44 45 45 /**
+2 -2
packages/openapi-ts/src/compiler/types.ts
··· 160 160 // TODO; handle more than single nested level, i.e. foo.bar.baz 161 161 const parts = value.split('.'); 162 162 return createPropertyAccessExpression({ 163 - expression: parts[0], 164 - name: parts[1], 163 + expression: parts[0]!, 164 + name: parts[1]!, 165 165 }); 166 166 } 167 167 return ots.string(value, unescape);
+1 -1
packages/openapi-ts/src/compiler/utils.ts
··· 75 75 */ 76 76 export function stringToTsNodes(value: string): ts.Node { 77 77 const file = createSourceFile(value); 78 - return file.statements[0]; 78 + return file.statements[0]!; 79 79 } 80 80 81 81 export const createIdentifier = ({ text }: { text: string }) => {
+1 -1
packages/openapi-ts/src/generate/__tests__/index.test.ts
··· 68 68 69 69 generateIndexFile({ files }); 70 70 71 - files.index.write(); 71 + files.index!.write(); 72 72 73 73 expect(fs.writeFileSync).toHaveBeenCalledWith( 74 74 expect.stringContaining(path.resolve('index.ts')),
+2 -2
packages/openapi-ts/src/generate/indexFile.ts
··· 62 62 Object.keys(files) 63 63 .sort() 64 64 .forEach((name) => { 65 - const file = files[name]; 65 + const file = files[name]!; 66 66 67 67 if (name === 'index' || file.isEmpty()) { 68 68 return; 69 69 } 70 70 71 71 if (['sdk', 'types'].includes(name)) { 72 - files.index.add( 72 + files.index!.add( 73 73 compiler.exportAllDeclaration({ 74 74 module: `./${file.nameWithoutExtension()}`, 75 75 }),
+1 -1
packages/openapi-ts/src/index.ts
··· 495 495 496 496 Performance.end('createClient'); 497 497 498 - if (configs[0].logs.level === 'debug') { 498 + if (configs[0]!.logs.level === 'debug') { 499 499 const perfReport = new PerformanceReport({ 500 500 totalMark: 'createClient', 501 501 });
+1 -1
packages/openapi-ts/src/ir/operation.ts
··· 46 46 return { 47 47 in: 'body', 48 48 name: operation.body.pagination, 49 - schema: finalSchema.properties![operation.body.pagination], 49 + schema: finalSchema.properties![operation.body.pagination]!, 50 50 }; 51 51 } 52 52
+9 -9
packages/openapi-ts/src/ir/parameter.ts
··· 5 5 parameterGroup?: Record<string, IR.ParameterObject>, 6 6 ): boolean => { 7 7 for (const name in parameterGroup) { 8 - if (parameterGroup[name].required) { 8 + if (parameterGroup[name]!.required) { 9 9 return true; 10 10 } 11 11 } ··· 47 47 } 48 48 49 49 for (const name in parameters.cookie) { 50 - const parameter = parameters.cookie[name]; 50 + const parameter = parameters.cookie[name]!; 51 51 if (parameter.pagination) { 52 52 return { 53 53 in: parameter.location, ··· 58 58 schema: 59 59 parameter.pagination === true 60 60 ? parameter.schema 61 - : parameter.schema.properties![parameter.pagination], 61 + : parameter.schema.properties![parameter.pagination]!, 62 62 }; 63 63 } 64 64 } 65 65 66 66 for (const name in parameters.header) { 67 - const parameter = parameters.header[name]; 67 + const parameter = parameters.header[name]!; 68 68 if (parameter.pagination) { 69 69 return { 70 70 in: parameter.location, ··· 75 75 schema: 76 76 parameter.pagination === true 77 77 ? parameter.schema 78 - : parameter.schema.properties![parameter.pagination], 78 + : parameter.schema.properties![parameter.pagination]!, 79 79 }; 80 80 } 81 81 } 82 82 83 83 for (const name in parameters.path) { 84 - const parameter = parameters.path[name]; 84 + const parameter = parameters.path[name]!; 85 85 if (parameter.pagination) { 86 86 return { 87 87 in: parameter.location, ··· 92 92 schema: 93 93 parameter.pagination === true 94 94 ? parameter.schema 95 - : parameter.schema.properties![parameter.pagination], 95 + : parameter.schema.properties![parameter.pagination]!, 96 96 }; 97 97 } 98 98 } 99 99 100 100 for (const name in parameters.query) { 101 - const parameter = parameters.query[name]; 101 + const parameter = parameters.query[name]!; 102 102 if (parameter.pagination) { 103 103 return { 104 104 in: parameter.location, ··· 109 109 schema: 110 110 parameter.pagination === true 111 111 ? parameter.schema 112 - : parameter.schema.properties![parameter.pagination], 112 + : parameter.schema.properties![parameter.pagination]!, 113 113 }; 114 114 } 115 115 }
+3 -3
packages/openapi-ts/src/ir/parser.ts
··· 9 9 10 10 if (context.ir.components) { 11 11 for (const name in context.ir.components.schemas) { 12 - const schema = context.ir.components.schemas[name]; 12 + const schema = context.ir.components.schemas[name]!; 13 13 const $ref = `#/components/schemas/${name}`; 14 14 await context.broadcast('schema', { $ref, name, schema }); 15 15 } 16 16 17 17 for (const name in context.ir.components.parameters) { 18 - const parameter = context.ir.components.parameters[name]; 18 + const parameter = context.ir.components.parameters[name]!; 19 19 const $ref = `#/components/parameters/${name}`; 20 20 await context.broadcast('parameter', { $ref, name, parameter }); 21 21 } 22 22 23 23 for (const name in context.ir.components.requestBodies) { 24 - const requestBody = context.ir.components.requestBodies[name]; 24 + const requestBody = context.ir.components.requestBodies[name]!; 25 25 const $ref = `#/components/requestBodies/${name}`; 26 26 await context.broadcast('requestBody', { $ref, name, requestBody }); 27 27 }
+6 -5
packages/openapi-ts/src/openApi/3.0.x/parser/index.ts
··· 38 38 // TODO: parser - handle more component types, old parser handles only parameters and schemas 39 39 if (context.spec.components) { 40 40 for (const name in context.spec.components.securitySchemes) { 41 - const securityOrReference = context.spec.components.securitySchemes[name]; 41 + const securityOrReference = 42 + context.spec.components.securitySchemes[name]!; 42 43 const securitySchemeObject = 43 44 '$ref' in securityOrReference 44 45 ? context.resolveRef<SecuritySchemeObject>(securityOrReference.$ref) ··· 52 53 continue; 53 54 } 54 55 55 - const parameterOrReference = context.spec.components.parameters[name]; 56 + const parameterOrReference = context.spec.components.parameters[name]!; 56 57 const parameter = 57 58 '$ref' in parameterOrReference 58 59 ? context.resolveRef<ParameterObject>(parameterOrReference.$ref) ··· 72 73 } 73 74 74 75 const requestBodyOrReference = 75 - context.spec.components.requestBodies[name]; 76 + context.spec.components.requestBodies[name]!; 76 77 const requestBody = 77 78 '$ref' in requestBodyOrReference 78 79 ? context.resolveRef<RequestBodyObject>(requestBodyOrReference.$ref) ··· 91 92 continue; 92 93 } 93 94 94 - const schema = context.spec.components.schemas[name]; 95 + const schema = context.spec.components.schemas[name]!; 95 96 96 97 parseSchema({ 97 98 $ref, ··· 102 103 } 103 104 104 105 for (const path in context.spec.paths) { 105 - const pathItem = context.spec.paths[path as keyof PathsObject]; 106 + const pathItem = context.spec.paths[path as keyof PathsObject]!; 106 107 107 108 const finalPathItem = pathItem.$ref 108 109 ? {
+1 -1
packages/openapi-ts/src/openApi/3.0.x/parser/mediaType.ts
··· 61 61 for (const mediaType in content) { 62 62 return { 63 63 mediaType, 64 - schema: content[mediaType].schema, 64 + schema: content[mediaType]!.schema, 65 65 type: mediaTypeToIrMediaType({ mediaType }), 66 66 }; 67 67 }
+1 -1
packages/openapi-ts/src/openApi/3.0.x/parser/pagination.ts
··· 66 66 paginationKeywordsRegExp.lastIndex = 0; 67 67 68 68 if (paginationKeywordsRegExp.test(name)) { 69 - const property = schema.properties[name]; 69 + const property = schema.properties[name]!; 70 70 71 71 if (typeof property !== 'boolean' && !('$ref' in property)) { 72 72 const schemaType = getSchemaType({ schema: property });
+5 -5
packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts
··· 200 200 const schemaProperties: Record<string, IR.SchemaObject> = {}; 201 201 202 202 for (const name in schema.properties) { 203 - const property = schema.properties[name]; 203 + const property = schema.properties[name]!; 204 204 if (typeof property === 'boolean') { 205 205 // TODO: parser - handle boolean properties 206 206 } else { ··· 395 395 396 396 // TODO: parser - this is a hack to bring back up meta fields 397 397 // without it, some schemas were missing original deprecated 398 - if (nestedItems[0].deprecated) { 399 - irSchema.deprecated = nestedItems[0].deprecated; 398 + if (nestedItems[0]!.deprecated) { 399 + irSchema.deprecated = nestedItems[0]!.deprecated; 400 400 } 401 401 402 402 // TODO: parser - this is a hack to bring back up meta fields 403 403 // without it, some schemas were missing original description 404 - if (nestedItems[0].description) { 405 - irSchema.description = nestedItems[0].description; 404 + if (nestedItems[0]!.description) { 405 + irSchema.description = nestedItems[0]!.description; 406 406 } 407 407 } 408 408
+6 -5
packages/openapi-ts/src/openApi/3.1.x/parser/index.ts
··· 38 38 // TODO: parser - handle more component types, old parser handles only parameters and schemas 39 39 if (context.spec.components) { 40 40 for (const name in context.spec.components.securitySchemes) { 41 - const securityOrReference = context.spec.components.securitySchemes[name]; 41 + const securityOrReference = 42 + context.spec.components.securitySchemes[name]!; 42 43 const securitySchemeObject = 43 44 '$ref' in securityOrReference 44 45 ? context.resolveRef<SecuritySchemeObject>(securityOrReference.$ref) ··· 52 53 continue; 53 54 } 54 55 55 - const parameterOrReference = context.spec.components.parameters[name]; 56 + const parameterOrReference = context.spec.components.parameters[name]!; 56 57 const parameter = 57 58 '$ref' in parameterOrReference 58 59 ? context.resolveRef<ParameterObject>(parameterOrReference.$ref) ··· 72 73 } 73 74 74 75 const requestBodyOrReference = 75 - context.spec.components.requestBodies[name]; 76 + context.spec.components.requestBodies[name]!; 76 77 const requestBody = 77 78 '$ref' in requestBodyOrReference 78 79 ? context.resolveRef<RequestBodyObject>(requestBodyOrReference.$ref) ··· 91 92 continue; 92 93 } 93 94 94 - const schema = context.spec.components.schemas[name]; 95 + const schema = context.spec.components.schemas[name]!; 95 96 96 97 parseSchema({ 97 98 $ref, ··· 102 103 } 103 104 104 105 for (const path in context.spec.paths) { 105 - const pathItem = context.spec.paths[path as keyof PathsObject]; 106 + const pathItem = context.spec.paths[path as keyof PathsObject]!; 106 107 107 108 const finalPathItem = pathItem.$ref 108 109 ? {
+1 -1
packages/openapi-ts/src/openApi/3.1.x/parser/mediaType.ts
··· 51 51 for (const mediaType in content) { 52 52 return { 53 53 mediaType, 54 - schema: content[mediaType].schema, 54 + schema: content[mediaType]!.schema, 55 55 type: mediaTypeToIrMediaType({ mediaType }), 56 56 }; 57 57 }
+1 -1
packages/openapi-ts/src/openApi/3.1.x/parser/pagination.ts
··· 62 62 paginationKeywordsRegExp.lastIndex = 0; 63 63 64 64 if (paginationKeywordsRegExp.test(name)) { 65 - const property = schema.properties[name]; 65 + const property = schema.properties[name]!; 66 66 67 67 if (typeof property !== 'boolean') { 68 68 const schemaTypes = getSchemaTypes({ schema: property });
+2 -2
packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts
··· 253 253 const schemaProperties: Record<string, IR.SchemaObject> = {}; 254 254 255 255 for (const name in schema.properties) { 256 - const property = schema.properties[name]; 256 + const property = schema.properties[name]!; 257 257 if (typeof property === 'boolean') { 258 258 // TODO: parser - handle boolean properties 259 259 } else { ··· 820 820 irSchema, 821 821 schema: { 822 822 ...schema, 823 - type: schemaTypes[0], 823 + type: schemaTypes[0]!, 824 824 }, 825 825 }); 826 826 }
+1 -1
packages/openapi-ts/src/openApi/common/parser/getDefault.ts
··· 26 26 model?.export === 'enum' && 27 27 model.enum?.[definition.default as number] 28 28 ) { 29 - const { value } = model.enum[definition.default as number]; 29 + const { value } = model.enum[definition.default as number]!; 30 30 return value; 31 31 } 32 32 return definition.default;
+2 -2
packages/openapi-ts/src/openApi/common/parser/type.ts
··· 114 114 if (matches?.length) { 115 115 const match1 = getType({ 116 116 debug, 117 - type: ensureValidTypeScriptJavaScriptIdentifier(matches[1]), 117 + type: ensureValidTypeScriptJavaScriptIdentifier(matches[1]!), 118 118 }); 119 119 const match2 = getType({ 120 120 debug, 121 - type: ensureValidTypeScriptJavaScriptIdentifier(matches[2]), 121 + type: ensureValidTypeScriptJavaScriptIdentifier(matches[2]!), 122 122 }); 123 123 124 124 if (match1.type === 'unknown[]') {
+1 -1
packages/openapi-ts/src/openApi/v2/parser/getOperations.ts
··· 20 20 const operations: Operation[] = []; 21 21 22 22 for (const path in openApi.paths) { 23 - const pathItem = openApi.paths[path]; 23 + const pathItem = openApi.paths[path]!; 24 24 const pathParameters = getOperationParameters({ 25 25 openApi, 26 26 parameters: pathItem.parameters ?? [],
+2 -2
packages/openapi-ts/src/openApi/v3/parser/__tests__/getModel.test.ts
··· 110 110 openApi, 111 111 types: {}, 112 112 }); 113 - expect(model.properties[0].properties.length).toBe(2); 113 + expect(model.properties[0]!.properties.length).toBe(2); 114 114 }); 115 115 116 116 it('Parses any of 2', () => { ··· 129 129 openApi, 130 130 types: {}, 131 131 }); 132 - expect(model.properties[0].properties.length).toBe(3); 132 + expect(model.properties[0]!.properties.length).toBe(3); 133 133 }); 134 134 });
+2 -2
packages/openapi-ts/src/openApi/v3/parser/discriminator.ts
··· 7 7 const inverseDictionary = (map: Dictionary<string>): Dictionary<string> => { 8 8 const m2: Dictionary<string> = {}; 9 9 for (const name in map) { 10 - m2[map[name]] = name; 10 + m2[map[name]!] = name; 11 11 } 12 12 return m2; 13 13 }; ··· 19 19 if (openApi.components && parent) { 20 20 for (const definitionName in openApi.components.schemas) { 21 21 if (openApi.components.schemas.hasOwnProperty(definitionName)) { 22 - const schema = openApi.components.schemas[definitionName]; 22 + const schema = openApi.components.schemas[definitionName]!; 23 23 if ( 24 24 schema.discriminator && 25 25 schema.oneOf?.length &&
+3 -3
packages/openapi-ts/src/openApi/v3/parser/getContent.ts
··· 27 27 ): Content | undefined => { 28 28 const basicMediaTypeWithSchema = Object.keys(content) 29 29 .filter((mediaType) => { 30 - const cleanMediaType = mediaType.split(';')[0].trim(); 30 + const cleanMediaType = mediaType.split(';')[0]!.trim(); 31 31 return BASIC_MEDIA_TYPES.includes(cleanMediaType); 32 32 }) 33 33 .find((mediaType) => Boolean(content[mediaType]?.schema)); ··· 35 35 if (basicMediaTypeWithSchema) { 36 36 return { 37 37 mediaType: basicMediaTypeWithSchema, 38 - schema: content[basicMediaTypeWithSchema].schema as OpenApiSchema, 38 + schema: content[basicMediaTypeWithSchema]!.schema as OpenApiSchema, 39 39 }; 40 40 } 41 41 ··· 46 46 if (firstMediaTypeWithSchema) { 47 47 return { 48 48 mediaType: firstMediaTypeWithSchema, 49 - schema: content[firstMediaTypeWithSchema].schema as OpenApiSchema, 49 + schema: content[firstMediaTypeWithSchema]!.schema as OpenApiSchema, 50 50 }; 51 51 } 52 52 };
+1 -1
packages/openapi-ts/src/openApi/v3/parser/getOperations.ts
··· 20 20 const operations: Operation[] = []; 21 21 22 22 for (const path in openApi.paths) { 23 - const pathItem = openApi.paths[path]; 23 + const pathItem = openApi.paths[path]!; 24 24 const pathParameters = getOperationParameters({ 25 25 openApi, 26 26 parameters: pathItem.parameters ?? [],
+1 -1
packages/openapi-ts/src/openApi/v3/parser/operation.ts
··· 26 26 let mergedParameters = [...opParams]; 27 27 let pendingParameters = [...globalParams]; 28 28 while (pendingParameters.length > 0) { 29 - const pendingParam = pendingParameters[0]; 29 + const pendingParam = pendingParameters[0]!; 30 30 pendingParameters = pendingParameters.slice(1); 31 31 const canMerge = mergedParameters.every( 32 32 (param) =>
+2 -2
packages/openapi-ts/src/plugins/@hey-api/schemas/__tests__/schemas.test.ts
··· 76 76 }, 77 77 }); 78 78 79 - files.schemas.write(); 79 + files.schemas!.write(); 80 80 81 81 expect(fs.writeFileSync).toHaveBeenCalledWith( 82 82 expect.stringContaining('schemas.gen.ts'), ··· 154 154 }, 155 155 }); 156 156 157 - files.schemas.write(); 157 + files.schemas!.write(); 158 158 159 159 expect(fs.writeFileSync).toHaveBeenCalledWith( 160 160 expect.stringContaining('schemas.gen.ts'),
+1 -1
packages/openapi-ts/src/plugins/@hey-api/schemas/plugin-legacy.ts
··· 92 92 expression, 93 93 name: toSchemaName(name, schema), 94 94 }); 95 - files.schemas.add(statement); 95 + files.schemas!.add(statement); 96 96 }; 97 97 98 98 // OpenAPI 2.0
+4 -4
packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts
··· 123 123 124 124 if (schema.properties) { 125 125 for (const name in schema.properties) { 126 - const property = schema.properties[name]; 126 + const property = schema.properties[name]!; 127 127 128 128 if (typeof property !== 'boolean') { 129 129 schema.properties[name] = schemaToJsonSchemaDraft_05({ ··· 228 228 229 229 if (schema.properties) { 230 230 for (const name in schema.properties) { 231 - const property = schema.properties[name]; 231 + const property = schema.properties[name]!; 232 232 233 233 if (typeof property !== 'boolean') { 234 234 schema.properties[name] = schemaToJsonSchema2020_12({ ··· 271 271 } 272 272 273 273 for (const name in context.spec.components.schemas) { 274 - const schema = context.spec.components.schemas[name]; 274 + const schema = context.spec.components.schemas[name]!; 275 275 const obj = schemaToJsonSchemaDraft_05({ 276 276 context, 277 277 plugin, ··· 299 299 } 300 300 301 301 for (const name in context.spec.components.schemas) { 302 - const schema = context.spec.components.schemas[name]; 302 + const schema = context.spec.components.schemas[name]!; 303 303 const obj = schemaToJsonSchema2020_12({ 304 304 context, 305 305 plugin,
+4 -4
packages/openapi-ts/src/plugins/@hey-api/sdk/__tests__/plugin.test.ts
··· 108 108 }, 109 109 }); 110 110 111 - files.sdk.write(); 111 + files.sdk!.write(); 112 112 113 113 expect(fs.writeFileSync).toHaveBeenCalledWith( 114 114 expect.stringContaining(path.resolve('sdk.gen.ts')), ··· 215 215 }, 216 216 }); 217 217 218 - files.sdk.write(); 218 + files.sdk!.write(); 219 219 220 220 expect(fs.writeFileSync).toHaveBeenCalledWith( 221 221 expect.stringContaining(path.resolve('sdk.gen.ts')), ··· 284 284 }, 285 285 }); 286 286 287 - files.sdk.write(); 287 + files.sdk!.write(); 288 288 289 289 expect(fs.writeFileSync).toHaveBeenCalledWith( 290 290 expect.stringContaining(path.resolve('sdk.gen.ts')), ··· 355 355 }, 356 356 }); 357 357 358 - files.sdk.write(); 358 + files.sdk!.write(); 359 359 360 360 expect(fs.writeFileSync).toHaveBeenCalledWith( 361 361 expect.stringContaining(path.resolve('sdk.gen.ts')),
+4 -4
packages/openapi-ts/src/plugins/@hey-api/sdk/plugin-legacy.ts
··· 875 875 processService({ 876 876 client, 877 877 onClientImport: (imported) => { 878 - files.sdk.import({ 878 + files.sdk!.import({ 879 879 module: clientModulePath({ config, sourceOutput: sdkOutput }), 880 880 name: imported, 881 881 }); 882 882 }, 883 883 onImport: (imported) => { 884 - files.sdk.import({ 884 + files.sdk!.import({ 885 885 // this detection could be done safer, but it shouldn't cause any issues 886 886 asType: !imported.endsWith('Transformer'), 887 - module: `./${files.types.nameWithoutExtension()}`, 887 + module: `./${files.types!.nameWithoutExtension()}`, 888 888 name: imported, 889 889 }); 890 890 }, 891 891 onNode: (node) => { 892 - files.sdk.add(node); 892 + files.sdk!.add(node); 893 893 }, 894 894 service, 895 895 });
+6 -2
packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts
··· 61 61 return; 62 62 } 63 63 64 - const cleanContent = contentType.split(';')[0].trim(); 64 + const cleanContent = contentType.split(';')[0]?.trim(); 65 + 66 + if (!cleanContent) { 67 + return; 68 + } 65 69 66 70 if ( 67 71 cleanContent.startsWith('application/json') || ··· 254 258 } 255 259 256 260 for (const name in operation.parameters?.query) { 257 - const parameter = operation.parameters.query[name]; 261 + const parameter = operation.parameters.query[name]!; 258 262 if ( 259 263 (parameter.schema.type === 'array' || 260 264 parameter.schema.type === 'tuple') &&
+6 -3
packages/openapi-ts/src/plugins/@hey-api/transformers/plugin-legacy.ts
··· 86 86 87 87 if (refModels.length === 1) { 88 88 const { created, name: nameModelResponseTransformer } = 89 - ensureModelResponseTransformerExists({ ...props, model: refModels[0] }); 89 + ensureModelResponseTransformerExists({ ...props, model: refModels[0]! }); 90 90 91 91 if (!created) { 92 92 return []; ··· 162 162 const refModels = getRefModels(props); 163 163 164 164 const { created, name: nameModelResponseTransformer } = 165 - ensureModelResponseTransformerExists({ ...props, model: refModels[0] }); 165 + ensureModelResponseTransformerExists({ 166 + ...props, 167 + model: refModels[0]!, 168 + }); 166 169 167 170 if (!created) { 168 171 return []; ··· 328 331 $ref: `transformers/${name}`, 329 332 name, 330 333 }, 331 - model: successResponses[0], 334 + model: successResponses[0]!, 332 335 onNode, 333 336 onRemoveNode, 334 337 path: [dataVariableName],
+6 -6
packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts
··· 57 57 const parts = $ref.split('/'); 58 58 return `${parts.slice(0, parts.length - 1).join('/')}/${stringCase({ 59 59 case: 'camelCase', 60 - value: parts[parts.length - 1], 60 + value: parts[parts.length - 1]!, 61 61 })}${affix}`; 62 62 }; 63 63 ··· 104 104 // append return statement if one does not already exist 105 105 if ( 106 106 nodes.length && 107 - !isNodeReturnStatement({ node: nodes[nodes.length - 1] }) 107 + !isNodeReturnStatement({ node: nodes[nodes.length - 1]! }) 108 108 ) { 109 109 nodes.push(compiler.returnStatement({ expression: identifierData })); 110 110 } ··· 227 227 ], 228 228 statements: 229 229 nodes.length === 1 230 - ? ts.isStatement(nodes[0]) 230 + ? ts.isStatement(nodes[0]!) 231 231 ? [] 232 232 : [ 233 233 compiler.returnStatement({ ··· 247 247 const required = schema.required ?? []; 248 248 249 249 for (const name in schema.properties) { 250 - const property = schema.properties[name]; 250 + const property = schema.properties[name]!; 251 251 const propertyAccessExpression = compiler.propertyAccessExpression({ 252 252 expression: dataExpression || dataVariableName, 253 253 name, ··· 325 325 context, 326 326 dataExpression: 'item', 327 327 plugin, 328 - schema: schema.items[0], 328 + schema: schema.items[0]!, 329 329 }); 330 330 } 331 331 ··· 357 357 thenStatement: compiler.block({ 358 358 statements: 359 359 nodes.length === 1 360 - ? ts.isStatement(nodes[0]) 360 + ? ts.isStatement(nodes[0]!) 361 361 ? [] 362 362 : [ 363 363 compiler.returnStatement({
+2 -2
packages/openapi-ts/src/plugins/@hey-api/typescript/plugin-legacy.ts
··· 360 360 if (bodyParameter.length === 1) { 361 361 bodyParameters = { 362 362 ...emptyModel, 363 - ...bodyParameter[0], 363 + ...bodyParameter[0]!, 364 364 in: 'body', 365 - isRequired: bodyParameter[0].isRequired, 365 + isRequired: bodyParameter[0]!.isRequired, 366 366 name: 'body', 367 367 prop: 'body', 368 368 };
+4 -4
packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts
··· 273 273 ); 274 274 275 275 if (itemTypes.length === 1) { 276 - return compiler.typeArrayNode(itemTypes[0]); 276 + return compiler.typeArrayNode(itemTypes[0]!); 277 277 } 278 278 279 279 if (schema.logicalOperator === 'and') { ··· 434 434 let hasOptionalProperties = false; 435 435 436 436 for (const name in schema.properties) { 437 - const property = schema.properties[name]; 437 + const property = schema.properties[name]!; 438 438 const isRequired = required.includes(name); 439 439 schemaProperties.push({ 440 440 comment: parseSchemaJsDoc({ schema: property }), ··· 481 481 plugin, 482 482 schema: 483 483 indexPropertyItems.length === 1 484 - ? indexPropertyItems[0] 484 + ? indexPropertyItems[0]! 485 485 : { 486 486 items: indexPropertyItems, 487 487 logicalOperator: 'or', ··· 665 665 const required: Array<string> = []; 666 666 667 667 for (const name in parameters) { 668 - const parameter = parameters[name]; 668 + const parameter = parameters[name]!; 669 669 670 670 properties[name] = deduplicateSchema({ 671 671 schema: parameter.schema,
+4 -4
packages/openapi-ts/src/plugins/@tanstack/query-core/plugin-legacy.ts
··· 681 681 throw new Error('🚫 TanStack Query plugin does not support legacy clients'); 682 682 } 683 683 684 - const file = files[plugin.name]; 684 + const file = files[plugin.name]!; 685 685 686 686 file.import({ 687 687 ...clientApi.OptionsLegacyParser, ··· 689 689 }); 690 690 691 691 const typesModulePath = relativeModulePath({ 692 - moduleOutput: files.types.nameWithoutExtension(), 692 + moduleOutput: files.types!.nameWithoutExtension(), 693 693 sourceOutput: plugin.output, 694 694 }); 695 695 ··· 1295 1295 } 1296 1296 1297 1297 const sdkModulePath = relativeModulePath({ 1298 - moduleOutput: files.sdk.nameWithoutExtension(), 1298 + moduleOutput: files.sdk!.nameWithoutExtension(), 1299 1299 sourceOutput: plugin.output, 1300 1300 }); 1301 1301 ··· 1309 1309 if (hasUsedQueryFn) { 1310 1310 file.import({ 1311 1311 module: sdkModulePath, 1312 - name: queryFn.split('.')[0], 1312 + name: queryFn.split('.')[0]!, 1313 1313 }); 1314 1314 } 1315 1315 }
+1 -1
packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts
··· 1271 1271 module: context 1272 1272 .file({ id: plugin.name })! 1273 1273 .relativePathToFile({ context, id: 'sdk' }), 1274 - name: queryFn.split('.')[0], 1274 + name: queryFn.split('.')[0]!, 1275 1275 }); 1276 1276 } 1277 1277 });
+2 -2
packages/openapi-ts/src/plugins/zod/plugin.ts
··· 314 314 // let hasOptionalProperties = false; 315 315 316 316 for (const name in schema.properties) { 317 - const property = schema.properties[name]; 317 + const property = schema.properties[name]!; 318 318 const isRequired = required.includes(name); 319 319 320 320 let propertyExpression = schemaToZodSchema({ ··· 779 779 ); 780 780 781 781 if (schema.logicalOperator === 'and') { 782 - const firstSchema = schema.items[0]; 782 + const firstSchema = schema.items[0]!; 783 783 // we want to add an intersection, but not every schema can use the same API. 784 784 // if the first item contains another array or not an object, we cannot use 785 785 // `.merge()` as that does not exist on `.union()` and non-object schemas.
+2 -2
packages/openapi-ts/src/utils/__tests__/postprocess.test.ts
··· 61 61 const { services } = postProcessClient(parserClient); 62 62 63 63 expect(services).toHaveLength(1); 64 - expect(services[0].name).toEqual('Default'); 64 + expect(services[0]!.name).toEqual('Default'); 65 65 }); 66 66 }); 67 67 ··· 94 94 const { services } = postProcessClient(parserClient); 95 95 96 96 expect(services).toHaveLength(1); 97 - expect(services[0].name).toEqual('Default'); 97 + expect(services[0]!.name).toEqual('Default'); 98 98 }); 99 99 });
+1 -1
packages/openapi-ts/src/utils/ref.ts
··· 11 11 */ 12 12 export const refToName = ($ref: string): string => { 13 13 const parts = refToParts($ref); 14 - const name = parts[parts.length - 1]; 14 + const name = parts[parts.length - 1]!; 15 15 // refs using unicode characters become encoded, didn't investigate why 16 16 // but the suspicion is this comes from `@apidevtools/json-schema-ref-parser` 17 17 return decodeURI(name);
+1 -1
packages/openapi-ts/src/utils/stringCase.ts
··· 31 31 _case === 'snake_case' || _case === 'SCREAMING_SNAKE_CASE' ? '_' : '-'; 32 32 33 33 for (let index = 0; index < string.length; index++) { 34 - const character = string[index]; 34 + const character = string[index]!; 35 35 isLastLastCharPreserved = 36 36 index > 2 ? string[index - 3] === separator : true; 37 37
+1 -1
packages/openapi-ts/src/utils/type.ts
··· 41 41 * {@link https://github.com/hey-api/openapi-ts/issues/768} 42 42 */ 43 43 if (model.export === 'reference' && model.$refs.length === 1) { 44 - if (model.$refs[0].startsWith(refSchemasPartial)) { 44 + if (model.$refs[0]!.startsWith(refSchemasPartial)) { 45 45 const meta = getSchemasMeta(model.base); 46 46 typeNode = compiler.typeNode(meta.name); 47 47 }
+5 -1
packages/openapi-ts/test/__snapshots__/test/generated/v3-hey-api-client-fetch-bundle/client/utils.ts.snap
··· 332 332 return; 333 333 } 334 334 335 - const cleanContent = contentType.split(';')[0].trim(); 335 + const cleanContent = contentType.split(';')[0]?.trim(); 336 + 337 + if (!cleanContent) { 338 + return; 339 + } 336 340 337 341 if ( 338 342 cleanContent.startsWith('application/json') ||
+5 -1
packages/openapi-ts/test/__snapshots__/test/generated/v3-hey-api-client-fetch-bundle_transform/client/utils.ts.snap
··· 332 332 return; 333 333 } 334 334 335 - const cleanContent = contentType.split(';')[0].trim(); 335 + const cleanContent = contentType.split(';')[0]?.trim(); 336 + 337 + if (!cleanContent) { 338 + return; 339 + } 336 340 337 341 if ( 338 342 cleanContent.startsWith('application/json') ||
+3 -3
packages/openapi-ts/test/performance.test.ts
··· 23 23 Performance.measure('createClient'); 24 24 const measures = Performance.getEntriesByName('createClient'); 25 25 26 - expect(measures[0].duration).toBeLessThanOrEqual(1000); 26 + expect(measures[0]!.duration).toBeLessThanOrEqual(1000); 27 27 }); 28 28 29 29 it('parses spec under 500ms', async () => { ··· 38 38 Performance.measure('parser'); 39 39 const measures = Performance.getEntriesByName('parser'); 40 40 41 - expect(measures[0].duration).toBeLessThanOrEqual(500); 41 + expect(measures[0]!.duration).toBeLessThanOrEqual(500); 42 42 }); 43 43 44 44 it('parses spec under 500ms (experimental)', async () => { ··· 54 54 Performance.measure('parser'); 55 55 const measures = Performance.getEntriesByName('parser'); 56 56 57 - expect(measures[0].duration).toBeLessThanOrEqual(500); 57 + expect(measures[0]!.duration).toBeLessThanOrEqual(500); 58 58 }); 59 59 });
+1 -1
packages/openapi-ts/test/plugins.test.ts
··· 33 33 outputDir, 34 34 typeof userConfig.plugins[0] === 'string' 35 35 ? userConfig.plugins[0] 36 - : userConfig.plugins[0].name, 36 + : userConfig.plugins[0]!.name, 37 37 typeof userConfig.output === 'string' ? userConfig.output : '', 38 38 ), 39 39 });
+1
packages/openapi-ts/tsconfig.base.json
··· 5 5 "module": "ESNext", 6 6 "moduleResolution": "Bundler", 7 7 "noImplicitOverride": true, 8 + "noUncheckedIndexedAccess": true, 8 9 "noUnusedLocals": true, 9 10 "strict": true, 10 11 "target": "ES2022",