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

Merge pull request #1265 from hey-api/fix/parameters-explode-false

fix: handle non-exploded array query parameters

authored by

Lubos and committed by
GitHub
f31d4e27 37970e0d

+498 -234
+5
.changeset/eight-poets-arrive.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix: handle non-exploded array query parameters
+6 -3
packages/openapi-ts/src/compiler/utils.ts
··· 10 10 name: string; 11 11 } 12 12 13 - const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); 13 + const printer = ts.createPrinter({ 14 + newLine: ts.NewLineKind.LineFeed, 15 + removeComments: false, 16 + }); 14 17 15 18 export const createSourceFile = (sourceText: string) => 16 19 ts.createSourceFile( 17 20 '', 18 21 sourceText, 19 - ts.ScriptTarget.ES2015, 20 - undefined, 22 + ts.ScriptTarget.ESNext, 23 + false, 21 24 ts.ScriptKind.TS, 22 25 ); 23 26
+13 -8
packages/openapi-ts/src/index.ts
··· 223 223 '@hey-api/schemas', 224 224 '@hey-api/services', 225 225 ] 226 - ).map((plugin) => { 227 - if (typeof plugin === 'string') { 228 - return plugin; 229 - } 226 + ) 227 + .map((plugin) => { 228 + if (typeof plugin === 'string') { 229 + return plugin; 230 + } 231 + 232 + if (plugin.name) { 233 + // @ts-expect-error 234 + userPluginsConfig[plugin.name] = plugin; 235 + } 230 236 231 - // @ts-expect-error 232 - userPluginsConfig[plugin.name] = plugin; 233 - return plugin.name; 234 - }); 237 + return plugin.name; 238 + }) 239 + .filter(Boolean); 235 240 236 241 const pluginOrder = getPluginOrder({ 237 242 pluginConfigs: {
+19
packages/openapi-ts/src/ir/ir.d.ts
··· 61 61 62 62 export interface IRParameterObject { 63 63 /** 64 + * Determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986 `:/?#[]@!$&'()*+,;=` to be included without percent-encoding. The default value is `false`. This property SHALL be ignored if the request body media type is not `application/x-www-form-urlencoded` or `multipart/form-data`. If a value is explicitly defined, then the value of `contentType` (implicit or explicit) SHALL be ignored. 65 + */ 66 + allowReserved?: boolean; 67 + /** 68 + * When this is true, property values of type `array` or `object` generate separate parameters for each value of the array, or key-value-pair of the map. For other types of properties this property has no effect. When `style` is `form`, the default value is `true`. For all other styles, the default value is `false`. This property SHALL be ignored if the request body media type is not `application/x-www-form-urlencoded` or `multipart/form-data`. If a value is explicitly defined, then the value of `contentType` (implicit or explicit) SHALL be ignored. 69 + */ 70 + explode: boolean; 71 + /** 64 72 * Endpoint parameters must specify their location. 65 73 */ 66 74 location: 'cookie' | 'header' | 'path' | 'query'; ··· 72 80 pagination?: boolean | string; 73 81 required?: boolean; 74 82 schema: IRSchemaObject; 83 + /** 84 + * Describes how the parameter value will be serialized depending on the type of the parameter value. Default values (based on value of `in`): for `query` - `form`; for `path` - `simple`; for `header` - `simple`; for `cookie` - `form`. 85 + */ 86 + style: 87 + | 'deepObject' 88 + | 'form' 89 + | 'label' 90 + | 'matrix' 91 + | 'pipeDelimited' 92 + | 'simple' 93 + | 'spaceDelimited'; 75 94 } 76 95 77 96 export interface IRResponsesObject {
+57
packages/openapi-ts/src/openApi/3.0.x/parser/parameter.ts
··· 9 9 import { paginationField } from './pagination'; 10 10 import { schemaToIrSchema } from './schema'; 11 11 12 + /** 13 + * Returns default parameter `allowReserved` based on value of `in`. 14 + */ 15 + const defaultAllowReserved = ( 16 + _in: ParameterObject['in'], 17 + ): boolean | undefined => { 18 + switch (_in) { 19 + // this keyword only applies to parameters with an `in` value of `query` 20 + case 'query': 21 + return false; 22 + default: 23 + return; 24 + } 25 + }; 26 + 27 + /** 28 + * Returns default parameter `explode` based on value of `style`. 29 + */ 30 + const defaultExplode = (style: Required<ParameterObject>['style']): boolean => { 31 + switch (style) { 32 + // default value for `deepObject` is `false`, but that behavior is undefined 33 + // so we use `true` to make this work with the `client-fetch` package 34 + case 'deepObject': 35 + case 'form': 36 + return true; 37 + default: 38 + return false; 39 + } 40 + }; 41 + 42 + /** 43 + * Returns default parameter `style` based on value of `in`. 44 + */ 45 + const defaultStyle = ( 46 + _in: ParameterObject['in'], 47 + ): Required<ParameterObject>['style'] => { 48 + switch (_in) { 49 + case 'header': 50 + case 'path': 51 + return 'simple'; 52 + case 'cookie': 53 + case 'query': 54 + return 'form'; 55 + } 56 + }; 57 + 12 58 export const parametersArrayToObject = ({ 13 59 context, 14 60 parameters, ··· 141 187 schema: finalSchema, 142 188 }); 143 189 190 + const style = parameter.style || defaultStyle(parameter.in); 191 + const explode = 192 + parameter.explode !== undefined ? parameter.explode : defaultExplode(style); 193 + const allowReserved = 194 + parameter.allowReserved !== undefined 195 + ? parameter.allowReserved 196 + : defaultAllowReserved(parameter.in); 197 + 144 198 const irParameter: IRParameterObject = { 199 + allowReserved, 200 + explode, 145 201 location: parameter.in, 146 202 name: parameter.name, 147 203 schema: schemaToIrSchema({ 148 204 context, 149 205 schema: finalSchema, 150 206 }), 207 + style, 151 208 }; 152 209 153 210 if (pagination) {
+57
packages/openapi-ts/src/openApi/3.1.x/parser/parameter.ts
··· 9 9 import { paginationField } from './pagination'; 10 10 import { schemaToIrSchema } from './schema'; 11 11 12 + /** 13 + * Returns default parameter `allowReserved` based on value of `in`. 14 + */ 15 + const defaultAllowReserved = ( 16 + _in: ParameterObject['in'], 17 + ): boolean | undefined => { 18 + switch (_in) { 19 + // this keyword only applies to parameters with an `in` value of `query` 20 + case 'query': 21 + return false; 22 + default: 23 + return; 24 + } 25 + }; 26 + 27 + /** 28 + * Returns default parameter `explode` based on value of `style`. 29 + */ 30 + const defaultExplode = (style: Required<ParameterObject>['style']): boolean => { 31 + switch (style) { 32 + // default value for `deepObject` is `false`, but that behavior is undefined 33 + // so we use `true` to make this work with the `client-fetch` package 34 + case 'deepObject': 35 + case 'form': 36 + return true; 37 + default: 38 + return false; 39 + } 40 + }; 41 + 42 + /** 43 + * Returns default parameter `style` based on value of `in`. 44 + */ 45 + const defaultStyle = ( 46 + _in: ParameterObject['in'], 47 + ): Required<ParameterObject>['style'] => { 48 + switch (_in) { 49 + case 'header': 50 + case 'path': 51 + return 'simple'; 52 + case 'cookie': 53 + case 'query': 54 + return 'form'; 55 + } 56 + }; 57 + 12 58 export const parametersArrayToObject = ({ 13 59 context, 14 60 parameters, ··· 134 180 schema: finalSchema, 135 181 }); 136 182 183 + const style = parameter.style || defaultStyle(parameter.in); 184 + const explode = 185 + parameter.explode !== undefined ? parameter.explode : defaultExplode(style); 186 + const allowReserved = 187 + parameter.allowReserved !== undefined 188 + ? parameter.allowReserved 189 + : defaultAllowReserved(parameter.in); 190 + 137 191 const irParameter: IRParameterObject = { 192 + allowReserved, 193 + explode, 138 194 location: parameter.in, 139 195 name: parameter.name, 140 196 schema: schemaToIrSchema({ 141 197 context, 142 198 schema: finalSchema, 143 199 }), 200 + style, 144 201 }; 145 202 146 203 if (pagination) {
+32
packages/openapi-ts/src/plugins/@hey-api/services/plugin.ts
··· 153 153 } 154 154 } 155 155 156 + for (const name in operation.parameters?.query) { 157 + const parameter = operation.parameters.query[name]; 158 + if ( 159 + (parameter.schema.type === 'array' || 160 + parameter.schema.type === 'tuple') && 161 + (parameter.style !== 'form' || !parameter.explode) 162 + ) { 163 + // override the default settings for `querySerializer` 164 + if (context.config.client.name === '@hey-api/client-fetch') { 165 + obj.push({ 166 + key: 'querySerializer', 167 + value: [ 168 + { 169 + key: 'array', 170 + value: [ 171 + { 172 + key: 'explode', 173 + value: false, 174 + }, 175 + { 176 + key: 'style', 177 + value: 'form', 178 + }, 179 + ], 180 + }, 181 + ], 182 + }); 183 + } 184 + break; 185 + } 186 + } 187 + 156 188 return compiler.objectExpression({ 157 189 identifiers: ['responseTransformer'], 158 190 obj,
+8
packages/openapi-ts/test/3.0.x.spec.ts
··· 75 75 }), 76 76 description: 'handles empty response status codes', 77 77 }, 78 + { 79 + config: createConfig({ 80 + input: 'parameter-explode-false.json', 81 + output: 'parameter-explode-false', 82 + plugins: ['@hey-api/services'], 83 + }), 84 + description: 'handles non-exploded array query parameters', 85 + }, 78 86 ]; 79 87 80 88 it.each(scenarios)('$description', async ({ config }) => {
+8
packages/openapi-ts/test/3.1.x.spec.ts
··· 108 108 }, 109 109 { 110 110 config: createConfig({ 111 + input: 'parameter-explode-false.json', 112 + output: 'parameter-explode-false', 113 + plugins: ['@hey-api/services'], 114 + }), 115 + description: 'handles non-exploded array query parameters', 116 + }, 117 + { 118 + config: createConfig({ 111 119 input: 'required-all-of-ref.json', 112 120 output: 'required-all-of-ref', 113 121 plugins: [
+3
packages/openapi-ts/test/__snapshots__/3.0.x/parameter-explode-false/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + export * from './types.gen'; 3 + export * from './services.gen';
+19
packages/openapi-ts/test/__snapshots__/3.0.x/parameter-explode-false/services.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { createClient, createConfig, type Options } from '@hey-api/client-fetch'; 4 + import type { PostFooData } from './types.gen'; 5 + 6 + export const client = createClient(createConfig()); 7 + 8 + export const postFoo = <ThrowOnError extends boolean = false>(options?: Options<PostFooData, ThrowOnError>) => { 9 + return (options?.client ?? client).post<unknown, unknown, ThrowOnError>({ 10 + ...options, 11 + url: '/foo', 12 + querySerializer: { 13 + array: { 14 + explode: false, 15 + style: 'form' 16 + } 17 + } 18 + }); 19 + };
+9
packages/openapi-ts/test/__snapshots__/3.0.x/parameter-explode-false/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type PostFooData = { 4 + body?: never; 5 + path?: never; 6 + query?: { 7 + foo?: Array<string>; 8 + }; 9 + };
+83 -77
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/schemas/default/schemas.gen.ts
··· 79 79 80 80 export const SimpleReferenceSchema = { 81 81 description: 'This is a simple reference', 82 - '$ref': '#/components/schemas/ModelWithString' 82 + allOf: [ 83 + { 84 + '$ref': '#/components/schemas/ModelWithString' 85 + } 86 + ] 83 87 } as const; 84 88 85 89 export const SimpleStringWithPatternSchema = { 86 90 description: 'This is a simple string', 91 + type: 'string', 92 + nullable: true, 87 93 maxLength: 64, 88 - pattern: '^[a-zA-Z0-9_]*$', 89 - type: ['string', 'null'] 94 + pattern: '^[a-zA-Z0-9_]*$' 90 95 } as const; 91 96 92 97 export const EnumWithStringsSchema = { ··· 215 220 anyOf: [ 216 221 {}, 217 222 { 218 - type: 'null' 223 + nullable: true 219 224 } 220 225 ] 221 226 } ··· 377 382 properties: { 378 383 nullableProp1: { 379 384 description: 'This is a simple string property', 380 - type: ['string', 'null'] 385 + type: 'string', 386 + nullable: true 381 387 }, 382 388 nullableRequiredProp1: { 383 389 description: 'This is a simple string property', 384 - type: ['string', 'null'] 390 + type: 'string', 391 + nullable: true 385 392 }, 386 393 nullableProp2: { 387 394 description: 'This is a simple string property', 388 - type: ['string', 'null'] 395 + nullable: true, 396 + type: 'string' 389 397 }, 390 398 nullableRequiredProp2: { 391 399 description: 'This is a simple string property', 392 - type: ['string', 'null'] 400 + nullable: true, 401 + type: 'string' 393 402 }, 394 403 'foo_bar-enum': { 395 404 description: 'This is a simple enum with strings', ··· 740 749 anyOf: [ 741 750 { 742 751 items: { 743 - anyOf: [ 752 + nullable: true, 753 + allOf: [ 744 754 { 745 755 '$ref': '#/components/schemas/ModelWithDictionary' 746 - }, 747 - { 748 - type: 'null' 749 756 } 750 757 ] 751 758 }, ··· 753 760 }, 754 761 { 755 762 items: { 756 - anyOf: [ 763 + nullable: true, 764 + allOf: [ 757 765 { 758 766 '$ref': '#/components/schemas/ModelWithArray' 759 - }, 760 - { 761 - type: 'null' 762 767 } 763 768 ] 764 769 }, ··· 775 780 } as const; 776 781 777 782 export const ConstValueSchema = { 778 - type: 'string', 779 - const: 'ConstValue' 783 + enum: ['ConstValue'], 784 + type: 'string' 780 785 } as const; 781 786 782 787 export const CompositionWithNestedAnyOfAndNullSchema = { ··· 784 789 type: 'object', 785 790 properties: { 786 791 propA: { 787 - anyOf: [ 792 + nullable: true, 793 + allOf: [ 788 794 { 789 795 items: { 790 796 anyOf: [ ··· 797 803 ] 798 804 }, 799 805 type: 'array' 800 - }, 801 - { 802 - type: 'null' 803 806 } 804 807 ], 805 808 title: 'Scopes' ··· 812 815 type: 'object', 813 816 properties: { 814 817 propA: { 815 - type: ['object', 'null'], 818 + nullable: true, 819 + type: 'object', 816 820 oneOf: [ 817 821 { 818 822 type: 'object', ··· 914 918 type: 'object', 915 919 properties: { 916 920 propA: { 917 - type: ['object', 'null'], 921 + nullable: true, 922 + type: 'object', 918 923 allOf: [ 919 924 { 920 925 type: 'object', ··· 943 948 type: 'object', 944 949 properties: { 945 950 propA: { 946 - type: ['object', 'null'], 951 + nullable: true, 952 + type: 'object', 947 953 anyOf: [ 948 954 { 949 955 type: 'object', ··· 1009 1015 readOnly: true 1010 1016 }, 1011 1017 requiredAndNullable: { 1012 - type: ['string', 'null'] 1018 + type: 'string', 1019 + nullable: true 1013 1020 }, 1014 1021 string: { 1015 1022 type: 'string' ··· 1049 1056 required: ['first'], 1050 1057 properties: { 1051 1058 first: { 1052 - type: ['object', 'null'], 1059 + type: 'object', 1053 1060 required: ['second'], 1054 1061 readOnly: true, 1062 + nullable: true, 1055 1063 properties: { 1056 1064 second: { 1057 - type: ['object', 'null'], 1065 + type: 'object', 1058 1066 required: ['third'], 1059 1067 readOnly: true, 1068 + nullable: true, 1060 1069 properties: { 1061 1070 third: { 1062 - type: ['string', 'null'], 1071 + type: 'string', 1063 1072 required: true, 1064 - readOnly: true 1073 + readOnly: true, 1074 + nullable: true 1065 1075 } 1066 1076 } 1067 1077 } ··· 1294 1304 type: 'object', 1295 1305 properties: { 1296 1306 String: { 1297 - const: 'String' 1307 + enum: ['String'], 1308 + type: 'string' 1298 1309 }, 1299 1310 number: { 1300 - const: 0 1311 + enum: [0], 1312 + type: 'number' 1301 1313 }, 1302 1314 null: { 1303 - const: null 1315 + nullable: true 1304 1316 }, 1305 1317 withType: { 1306 - type: 'string', 1307 - const: 'Some string' 1318 + enum: ['Some string'], 1319 + type: 'string' 1308 1320 } 1309 1321 } 1310 1322 } as const; ··· 1324 1336 export const NestedAnyOfArraysNullableSchema = { 1325 1337 properties: { 1326 1338 nullableArray: { 1327 - anyOf: [ 1339 + nullable: true, 1340 + allOf: [ 1328 1341 { 1329 1342 items: { 1330 1343 anyOf: [ ··· 1337 1350 ] 1338 1351 }, 1339 1352 type: 'array' 1340 - }, 1341 - { 1342 - type: 'null' 1343 1353 } 1344 1354 ] 1345 1355 } ··· 1374 1384 required: ['baz', 'qux'], 1375 1385 properties: { 1376 1386 baz: { 1377 - type: ['integer', 'null'], 1387 + type: 'integer', 1378 1388 format: 'uint16', 1379 - minimum: 0 1389 + minimum: 0, 1390 + nullable: true 1380 1391 }, 1381 1392 qux: { 1382 1393 type: 'integer', ··· 1387 1398 } as const; 1388 1399 1389 1400 export const NullableObjectSchema = { 1390 - type: ['object', 'null'], 1391 1401 description: 'An object that can be null', 1402 + nullable: true, 1403 + type: 'object', 1392 1404 properties: { 1393 1405 foo: { 1394 1406 type: 'string' ··· 1463 1475 properties: { 1464 1476 content: { 1465 1477 type: 'array', 1466 - prefixItems: [ 1467 - { 1468 - type: 'string', 1469 - format: 'date-time' 1470 - }, 1471 - { 1472 - type: 'string' 1473 - } 1474 - ], 1478 + items: { 1479 + type: 'string', 1480 + format: 'date-time' 1481 + }, 1475 1482 maxItems: 2, 1476 1483 minItems: 2 1477 1484 }, ··· 1589 1596 1590 1597 export const ModelWithPrefixItemsConstantSizeArraySchema = { 1591 1598 type: 'array', 1592 - prefixItems: [ 1593 - { 1594 - '$ref': '#/components/schemas/ModelWithInteger' 1595 - }, 1596 - { 1597 - oneOf: [ 1598 - { 1599 - type: 'number' 1600 - }, 1601 - { 1602 - type: 'string' 1603 - } 1604 - ] 1605 - }, 1606 - { 1607 - type: 'string' 1608 - } 1609 - ] 1599 + items: { 1600 + oneOf: [ 1601 + { 1602 + '$ref': '#/components/schemas/ModelWithInteger' 1603 + }, 1604 + { 1605 + type: 'number' 1606 + }, 1607 + { 1608 + type: 'string' 1609 + } 1610 + ] 1611 + } 1610 1612 } as const; 1611 1613 1612 1614 export const ModelWithAnyOfConstantSizeArrayNullableSchema = { 1613 - type: ['array'], 1615 + type: 'array', 1614 1616 items: { 1615 1617 oneOf: [ 1616 1618 { 1617 - type: ['number', 'null'] 1619 + type: 'number', 1620 + nullable: true 1618 1621 }, 1619 1622 { 1620 1623 type: 'string' ··· 1718 1721 required: ['baz', 'qux'], 1719 1722 properties: { 1720 1723 baz: { 1721 - type: ['integer', 'null'], 1724 + type: 'integer', 1722 1725 format: 'uint16', 1723 - minimum: 0 1726 + minimum: 0, 1727 + nullable: true 1724 1728 }, 1725 1729 qux: { 1726 1730 type: 'integer', ··· 1761 1765 } as const; 1762 1766 1763 1767 export const SchemaWithFormRestrictedKeysSchema = { 1764 - type: 'object', 1765 1768 properties: { 1766 1769 description: { 1767 1770 type: 'string' ··· 1949 1952 type: 'boolean' 1950 1953 }, 1951 1954 error: { 1952 - type: ['string', 'null'] 1955 + type: 'string', 1956 + nullable: true 1953 1957 }, 1954 1958 hasError: { 1955 1959 type: 'boolean', ··· 1968 1972 type: 'object', 1969 1973 properties: { 1970 1974 item: { 1971 - type: ['string', 'null'] 1975 + type: 'string', 1976 + nullable: true 1972 1977 }, 1973 1978 error: { 1974 - type: ['string', 'null'] 1979 + type: 'string', 1980 + nullable: true 1975 1981 }, 1976 1982 hasError: { 1977 1983 type: 'boolean',
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/services/default/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/angular-query-experimental/asClass/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/angular-query-experimental/axios/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/angular-query-experimental/fetch/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/react-query/asClass/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/react-query/axios/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/react-query/fetch/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/solid-query/asClass/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/solid-query/axios/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/solid-query/fetch/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/svelte-query/asClass/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/svelte-query/axios/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/svelte-query/fetch/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/vue-query/asClass/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/vue-query/axios/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+4 -8
packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@tanstack/vue-query/fetch/types.gen.ts
··· 153 153 }>; 154 154 155 155 export type AnyOfAnyAndNull = { 156 - data?: unknown | null; 156 + data?: unknown; 157 157 }; 158 158 159 159 /** ··· 655 655 export type ModelWithConst = { 656 656 String?: 'String'; 657 657 number?: 0; 658 - null?: null; 658 + null?: unknown; 659 659 withType?: 'Some string'; 660 660 }; 661 661 ··· 751 751 number | string 752 752 ]; 753 753 754 - export type ModelWithPrefixItemsConstantSizeArray = [ 755 - ModelWithInteger, 756 - number | string, 757 - string 758 - ]; 754 + export type ModelWithPrefixItemsConstantSizeArray = Array<ModelWithInteger | number | string>; 759 755 760 756 export type ModelWithAnyOfConstantSizeArrayNullable = [ 761 757 number | null | string, ··· 1344 1340 /** 1345 1341 * This is an enum parameter 1346 1342 */ 1347 - parameterEnum: 'Success' | 'Warning' | 'Error' | null; 1343 + parameterEnum: 'Success' | 'Warning' | 'Error'; 1348 1344 }; 1349 1345 }; 1350 1346
+3
packages/openapi-ts/test/__snapshots__/3.1.x/parameter-explode-false/index.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + export * from './types.gen'; 3 + export * from './services.gen';
+19
packages/openapi-ts/test/__snapshots__/3.1.x/parameter-explode-false/services.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + import { createClient, createConfig, type Options } from '@hey-api/client-fetch'; 4 + import type { PostFooData } from './types.gen'; 5 + 6 + export const client = createClient(createConfig()); 7 + 8 + export const postFoo = <ThrowOnError extends boolean = false>(options?: Options<PostFooData, ThrowOnError>) => { 9 + return (options?.client ?? client).post<unknown, unknown, ThrowOnError>({ 10 + ...options, 11 + url: '/foo', 12 + querySerializer: { 13 + array: { 14 + explode: false, 15 + style: 'form' 16 + } 17 + } 18 + }); 19 + };
+9
packages/openapi-ts/test/__snapshots__/3.1.x/parameter-explode-false/types.gen.ts
··· 1 + // This file is auto-generated by @hey-api/openapi-ts 2 + 3 + export type PostFooData = { 4 + body?: never; 5 + path?: never; 6 + query?: { 7 + foo?: Array<string>; 8 + }; 9 + };
+1 -1
packages/openapi-ts/test/plugins.spec.ts
··· 27 27 client: '@hey-api/client-fetch', 28 28 experimentalParser: true, 29 29 ...userConfig, 30 - input: path.join(__dirname, 'spec', '3.1.x', 'full.json'), 30 + input: path.join(__dirname, 'spec', version, 'full.json'), 31 31 output: path.join( 32 32 outputDir, 33 33 typeof userConfig.plugins[0] === 'string'
+21 -17
packages/openapi-ts/test/sample.cjs
··· 13 13 input: { 14 14 // include: 15 15 // '^(#/components/schemas/import|#/paths/api/v{api-version}/simple/options)$', 16 - path: './test/spec/3.0.x/full.json', 16 + path: './test/spec/3.0.x/parameter-explode-false.json', 17 17 // path: 'https://mongodb-mms-prod-build-server.s3.amazonaws.com/openapi/2caffd88277a4e27c95dcefc7e3b6a63a3b03297-v2-2023-11-15.json', 18 18 }, 19 19 // name: 'foo', ··· 23 23 path: './test/generated/sample/', 24 24 }, 25 25 plugins: [ 26 - // { 27 - // name: '@hey-api/schemas', 28 - // type: 'json', 29 - // }, 30 - // { 31 - // // asClass: true, 32 - // // include... 33 - // name: '@hey-api/services', 34 - // // serviceNameBuilder: '^Parameters', 35 - // }, 36 - // { 37 - // dates: true, 38 - // name: '@hey-api/transformers', 39 - // }, 26 + { 27 + // name: '@hey-api/schemas', 28 + // type: 'json', 29 + }, 30 + { 31 + // asClass: true, 32 + // include... 33 + name: '@hey-api/services', 34 + // serviceNameBuilder: '^Parameters', 35 + }, 36 + { 37 + // dates: true, 38 + // name: '@hey-api/transformers', 39 + }, 40 40 { 41 41 // enums: 'typescript', 42 42 // enums: 'typescript+namespace', ··· 45 45 // style: 'PascalCase', 46 46 tree: true, 47 47 }, 48 - // '@tanstack/react-query', 49 - // 'zod', 48 + { 49 + // name: '@tanstack/react-query', 50 + }, 51 + { 52 + // name: 'zod', 53 + }, 50 54 ], 51 55 // useOptions: false, 52 56 };
+31
packages/openapi-ts/test/spec/3.0.x/parameter-explode-false.json
··· 1 + { 2 + "openapi": "3.0.0", 3 + "info": { 4 + "title": "OpenAPI 3.0.0 parameter explode false example", 5 + "version": "1" 6 + }, 7 + "paths": { 8 + "/foo": { 9 + "post": { 10 + "parameters": [ 11 + { 12 + "name": "foo", 13 + "in": "query", 14 + "explode": false, 15 + "schema": { 16 + "type": "array", 17 + "items": { 18 + "type": "string" 19 + } 20 + } 21 + } 22 + ], 23 + "responses": { 24 + "default": { 25 + "description": "OK" 26 + } 27 + } 28 + } 29 + } 30 + } 31 + }
+31
packages/openapi-ts/test/spec/3.1.x/parameter-explode-false.json
··· 1 + { 2 + "openapi": "3.1.0", 3 + "info": { 4 + "title": "OpenAPI 3.1.0 parameter explode false example", 5 + "version": "1" 6 + }, 7 + "paths": { 8 + "/foo": { 9 + "post": { 10 + "parameters": [ 11 + { 12 + "name": "foo", 13 + "in": "query", 14 + "explode": false, 15 + "schema": { 16 + "type": "array", 17 + "items": { 18 + "type": "string" 19 + } 20 + } 21 + } 22 + ], 23 + "responses": { 24 + "default": { 25 + "description": "OK" 26 + } 27 + } 28 + } 29 + } 30 + } 31 + }