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

Merge pull request #2166 from hey-api/fix/zod-tuple

fix(zod): support tuple types

authored by

Lubos and committed by
GitHub
67125d3b 3d0aeb82

+170 -49
+5
.changeset/hot-wolves-wait.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix(parser): filter orphans only when there are some operations
+5
.changeset/spicy-wombats-allow.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix(zod): support tuple types
+58 -11
packages/openapi-ts-tests/test/__snapshots__/3.0.x/plugins/zod/default/zod.gen.ts
··· 818 818 ]) 819 819 }), 820 820 z.object({ 821 - content: z.unknown(), 821 + content: z.tuple([ 822 + z.string().datetime(), 823 + z.string().datetime() 824 + ]), 822 825 foo: z.enum([ 823 826 'Corge' 824 827 ]) ··· 849 852 foo: zModelWithNestedArrayEnumsDataFoo.optional() 850 853 }); 851 854 852 - export const zModelWithConstantSizeArray = z.unknown(); 855 + export const zModelWithConstantSizeArray = z.tuple([ 856 + z.number(), 857 + z.number() 858 + ]); 853 859 854 - export const zModelWithAnyOfConstantSizeArray = z.unknown(); 860 + export const zModelWithAnyOfConstantSizeArray = z.tuple([ 861 + z.union([ 862 + z.number(), 863 + z.string() 864 + ]), 865 + z.union([ 866 + z.number(), 867 + z.string() 868 + ]), 869 + z.union([ 870 + z.number(), 871 + z.string() 872 + ]) 873 + ]); 855 874 856 875 export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ 857 876 zModelWithInteger, ··· 859 878 z.string() 860 879 ])); 861 880 862 - export const zModelWithAnyOfConstantSizeArrayNullable = z.unknown(); 881 + export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ 882 + z.union([ 883 + z.number(), 884 + z.null(), 885 + z.string() 886 + ]), 887 + z.union([ 888 + z.number(), 889 + z.null(), 890 + z.string() 891 + ]), 892 + z.union([ 893 + z.number(), 894 + z.null(), 895 + z.string() 896 + ]) 897 + ]); 898 + 899 + /** 900 + * Model with restricted keyword name 901 + */ 902 + export const zImport = z.string(); 863 903 864 - export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.unknown(); 904 + export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.tuple([ 905 + z.union([ 906 + z.number(), 907 + zImport 908 + ]), 909 + z.union([ 910 + z.number(), 911 + zImport 912 + ]) 913 + ]); 865 914 866 - export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.unknown(); 915 + export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([ 916 + z.intersection(z.number(), z.string()), 917 + z.intersection(z.number(), z.string()) 918 + ]); 867 919 868 920 export const zModelWithNumericEnumUnion = z.object({ 869 921 value: z.unknown().optional() ··· 911 963 * Model used to test deduplication strategy 912 964 */ 913 965 export const zDeleteFooData2 = z.string(); 914 - 915 - /** 916 - * Model with restricted keyword name 917 - */ 918 - export const zImport = z.string(); 919 966 920 967 export const zSchemaWithFormRestrictedKeys = z.object({ 921 968 description: z.string().optional(),
+66 -12
packages/openapi-ts-tests/test/__snapshots__/3.1.x/plugins/zod/default/zod.gen.ts
··· 815 815 ]) 816 816 }), 817 817 z.object({ 818 - content: z.unknown(), 818 + content: z.tuple([ 819 + z.string().datetime(), 820 + z.string() 821 + ]), 819 822 foo: z.enum([ 820 823 'Corge' 821 824 ]) ··· 846 849 foo: zModelWithNestedArrayEnumsDataFoo.optional() 847 850 }); 848 851 849 - export const zModelWithConstantSizeArray = z.unknown(); 852 + export const zModelWithConstantSizeArray = z.tuple([ 853 + z.number(), 854 + z.number() 855 + ]); 850 856 851 - export const zModelWithAnyOfConstantSizeArray = z.unknown(); 857 + export const zModelWithAnyOfConstantSizeArray = z.tuple([ 858 + z.union([ 859 + z.number(), 860 + z.string() 861 + ]), 862 + z.union([ 863 + z.number(), 864 + z.string() 865 + ]), 866 + z.union([ 867 + z.number(), 868 + z.string() 869 + ]) 870 + ]); 852 871 853 - export const zModelWithPrefixItemsConstantSizeArray = z.unknown(); 872 + export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ 873 + zModelWithInteger, 874 + z.union([ 875 + z.number(), 876 + z.string() 877 + ]), 878 + z.string() 879 + ]); 854 880 855 - export const zModelWithAnyOfConstantSizeArrayNullable = z.unknown(); 881 + export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ 882 + z.union([ 883 + z.number(), 884 + z.null(), 885 + z.string() 886 + ]), 887 + z.union([ 888 + z.number(), 889 + z.null(), 890 + z.string() 891 + ]), 892 + z.union([ 893 + z.number(), 894 + z.null(), 895 + z.string() 896 + ]) 897 + ]); 856 898 857 - export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.unknown(); 899 + /** 900 + * Model with restricted keyword name 901 + */ 902 + export const zImport = z.string(); 858 903 859 - export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.unknown(); 904 + export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.tuple([ 905 + z.union([ 906 + z.number(), 907 + zImport 908 + ]), 909 + z.union([ 910 + z.number(), 911 + zImport 912 + ]) 913 + ]); 914 + 915 + export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([ 916 + z.intersection(z.number(), z.string()), 917 + z.intersection(z.number(), z.string()) 918 + ]); 860 919 861 920 export const zModelWithNumericEnumUnion = z.object({ 862 921 value: z.unknown().optional() ··· 904 963 * Model used to test deduplication strategy 905 964 */ 906 965 export const zDeleteFooData2 = z.string(); 907 - 908 - /** 909 - * Model with restricted keyword name 910 - */ 911 - export const zImport = z.string(); 912 966 913 967 export const zSchemaWithFormRestrictedKeys = z.object({ 914 968 description: z.string().optional(),
+5 -2
packages/openapi-ts-tests/test/openapi-ts.config.ts
··· 31 31 }, 32 32 // orphans: false, 33 33 // preserveOrder: true, 34 + // schemas: { 35 + // include: ['Foo'], 36 + // }, 34 37 // tags: { 35 38 // exclude: ['bar'], 36 39 // }, ··· 51 54 // 'invalid', 52 55 // 'servers-entry.yaml', 53 56 // ), 54 - path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.yaml'), 57 + path: path.resolve(__dirname, 'spec', '3.1.x', 'full.yaml'), 55 58 // path: 'http://localhost:4000/', 56 59 // path: 'https://get.heyapi.dev/', 57 60 // path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0', ··· 150 153 { 151 154 // comments: false, 152 155 // exportFromIndex: true, 153 - metadata: true, 156 + // metadata: true, 154 157 name: 'zod', 155 158 }, 156 159 ],
+1 -1
packages/openapi-ts/src/openApi/shared/utils/filter.ts
··· 938 938 schemas, 939 939 }); 940 940 941 - if (!filters.orphans) { 941 + if (!filters.orphans && operations.size) { 942 942 const { operationDependencies } = collectOperationDependencies({ 943 943 graph, 944 944 operations,
+28 -21
packages/openapi-ts/src/plugins/zod/plugin.ts
··· 609 609 610 610 const tupleTypeToZodSchema = ({ 611 611 context, 612 + plugin, 613 + result, 612 614 schema, 613 615 }: { 614 616 context: IR.Context; 617 + plugin: Plugin.Instance<Config>; 618 + result: Result; 615 619 schema: SchemaWithType<'tuple'>; 616 620 }) => { 617 621 if (schema.const && Array.isArray(schema.const)) { ··· 638 642 return expression; 639 643 } 640 644 641 - // TODO: parser - handle tuple items 642 - // const itemTypes: Array<ts.TypeNode> = []; 645 + const tupleElements: Array<ts.Expression> = []; 643 646 644 - // for (const item of schema.items ?? []) { 645 - // itemTypes.push( 646 - // schemaToType({ 647 - // context, 648 - // namespace, 649 - // plugin, 650 - // schema: item, 651 - // }), 652 - // ); 653 - // } 647 + for (const item of schema.items ?? []) { 648 + tupleElements.push( 649 + schemaToZodSchema({ 650 + context, 651 + plugin, 652 + result, 653 + schema: item, 654 + }), 655 + ); 656 + } 654 657 655 - // return compiler.typeTupleNode({ 656 - // types: itemTypes, 657 - // }); 658 - 659 - return unknownTypeToZodSchema({ 660 - context, 661 - schema: { 662 - type: 'unknown', 663 - }, 658 + const expression = compiler.callExpression({ 659 + functionName: compiler.propertyAccessExpression({ 660 + expression: zIdentifier, 661 + name: compiler.identifier({ text: 'tuple' }), 662 + }), 663 + parameters: [ 664 + compiler.arrayLiteralExpression({ 665 + elements: tupleElements, 666 + }), 667 + ], 664 668 }); 669 + return expression; 665 670 }; 666 671 667 672 const undefinedTypeToZodSchema = ({ ··· 790 795 return { 791 796 expression: tupleTypeToZodSchema({ 792 797 context, 798 + plugin, 799 + result, 793 800 schema: schema as SchemaWithType<'tuple'>, 794 801 }), 795 802 };
+2 -2
packages/openapi-ts/src/types/input.d.ts
··· 140 140 include?: ReadonlyArray<string>; 141 141 }; 142 142 /** 143 - * Keep reusable components without any references in the output? By 144 - * default, we exclude orphaned resources. 143 + * Keep reusable components without any references from operations in the 144 + * output? By default, we exclude orphaned resources. 145 145 * 146 146 * @default false 147 147 */