From ce7d842b107bcafd01aeeca6ec8a1eb1cf67e21a Mon Sep 17 00:00:00 2001 From: David Blass Date: Sun, 5 Nov 2023 19:29:40 -0500 Subject: [PATCH 1/7] experiment with simplifying some abi.ts types --- packages/abitype/package.json | 16 +++----- packages/abitype/src/types.ts | 12 ++++++ packages/abitype/src/utils.ts | 75 +++++++++++++++++------------------ 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/packages/abitype/package.json b/packages/abitype/package.json index 348c7e6b..75ecf236 100644 --- a/packages/abitype/package.json +++ b/packages/abitype/package.json @@ -10,7 +10,8 @@ "build:esm+types": "tsc --project tsconfig.build.json --module es2020 --outDir ./dist/esm --declaration --declarationMap --declarationDir ./dist/types && echo > ./dist/esm/package.json '{\"type\":\"module\",\"sideEffects\":false}'", "clean": "rm -rf dist tsconfig.tsbuildinfo abis zod", "test:build": "publint --strict", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "typeperf": "tsc --noEmit --extendedDiagnostics --composite false --incremental false" }, "files": [ "dist", @@ -48,12 +49,8 @@ }, "typesVersions": { "*": { - "abis": [ - "./dist/types/exports/abis.d.ts" - ], - "zod": [ - "./dist/types/exports/zod.d.ts" - ] + "abis": ["./dist/types/exports/abis.d.ts"], + "zod": ["./dist/types/exports/zod.d.ts"] } }, "peerDependencies": { @@ -73,10 +70,7 @@ "ethers": "^6.5.1", "zod": "^3.22.4" }, - "contributors": [ - "awkweb.eth ", - "jxom.eth " - ], + "contributors": ["awkweb.eth ", "jxom.eth "], "funding": "https://github.com/sponsors/wagmi-dev", "keywords": [ "abi", diff --git a/packages/abitype/src/types.ts b/packages/abitype/src/types.ts index 33dde0b2..0c2aa799 100644 --- a/packages/abitype/src/types.ts +++ b/packages/abitype/src/types.ts @@ -141,6 +141,18 @@ type KeyofUnion = T extends T ? keyof T : never */ export type Pretty = { [K in keyof T]: T[K] } & unknown +/** + * Check that a type is a subtype of another. + * + * Useful for ensuring more complex types conform to a base pattern, e.g. by + * defining a set of keys. + * + * @param Base - The type that T must extend. + * @param T - The type to check. + * @returns T + */ +export type Satisfy = T + /** * Creates range between two positive numbers using [tail recursion](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#tail-recursion-elimination-on-conditional-types). * diff --git a/packages/abitype/src/utils.ts b/packages/abitype/src/utils.ts index 4ad1816d..9d230a71 100644 --- a/packages/abitype/src/utils.ts +++ b/packages/abitype/src/utils.ts @@ -5,15 +5,11 @@ import type { AbiStateMutability, AbiType, MBits, - SolidityAddress, SolidityArray, - SolidityBool, SolidityBytes, SolidityFixedArrayRange, SolidityFixedArraySizeLookup, - SolidityFunction, SolidityInt, - SolidityString, SolidityTuple, TypedData, TypedDataParameter, @@ -34,44 +30,45 @@ import type { Error, Merge, Pretty, Tuple } from './types.js' export type AbiTypeToPrimitiveType< TAbiType extends AbiType, TAbiParameterKind extends AbiParameterKind = AbiParameterKind, -> = PrimitiveTypeLookup[TAbiType] +> = TAbiType extends SolidityBytes + ? // If PrimitiveTypeLookup is missing key values from AbiType, + // there will be an error on this property access + PrimitiveTypeLookup[TAbiType][TAbiParameterKind] + : PrimitiveTypeLookup[TAbiType] -// Using a map to look up types is faster, than nested conditional types -// s/o https://twitter.com/SeaRyanC/status/1538971176357113858 -type PrimitiveTypeLookup< - TAbiType extends AbiType, - TAbiParameterKind extends AbiParameterKind = AbiParameterKind, -> = { - [_ in SolidityAddress]: ResolvedRegister['AddressType'] -} & { - [_ in SolidityBool]: boolean -} & { - [_ in SolidityBytes]: ResolvedRegister['BytesType'][TAbiParameterKind] -} & { - [_ in SolidityFunction]: `${ResolvedRegister['AddressType']}${string}` -} & { - [_ in SolidityInt]: TAbiType extends `${'u' | ''}int${infer TBits}` - ? TBits extends keyof BitsTypeLookup - ? BitsTypeLookup[TBits] - : Error<'Unknown bits value.'> - : Error<`Unknown 'SolidityInt' format.`> -} & { - [_ in SolidityString]: string -} & { - [_ in SolidityTuple]: Record -} & { - [_ in SolidityArray]: readonly unknown[] +interface PrimitiveTypeLookup + extends SolidityIntMap, + SolidityByteMap, + SolidityArrayMap { + address: ResolvedRegister['AddressType'] + bool: boolean + function: `${ResolvedRegister['AddressType']}${string}` + string: string + tuple: Record +} + +type SolidityIntMap = { + [_ in SolidityInt]: _ extends `${ + | 'u' + | ''}int${infer TBits extends keyof BitsTypeLookup}` + ? BitsTypeLookup[TBits] + : never +} + +type SolidityByteMap = { + [_ in SolidityBytes]: ResolvedRegister['BytesType'] } -type GreaterThan48Bits = Exclude -type LessThanOrEqualTo48Bits = Exclude -type NoBits = Exclude -type BitsTypeLookup = { - [_ in `${LessThanOrEqualTo48Bits}`]: ResolvedRegister['IntType'] -} & { - [_ in `${GreaterThan48Bits}`]: ResolvedRegister['BigIntType'] -} & { - [_ in NoBits]: ResolvedRegister['BigIntType'] +type SolidityArrayMap = { [_ in SolidityArray]: readonly unknown[] } + +type GreaterThan48Bits = Exclude +type LessThanOrEqualTo48Bits = Exclude +type NoBits = '' + +export type BitsTypeLookup = { + [K in MBits]: ResolvedRegister[K extends LessThanOrEqualTo48Bits + ? 'IntType' + : 'BigIntType'] } /** From c6422e16462c95757497406b3178b213bb496bc7 Mon Sep 17 00:00:00 2001 From: David Blass Date: Sun, 5 Nov 2023 22:47:21 -0500 Subject: [PATCH 2/7] finish initial improvements to utils.ts --- packages/abitype/src/utils.ts | 152 +++++++++++++++++----------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/packages/abitype/src/utils.ts b/packages/abitype/src/utils.ts index 9d230a71..306eb9d6 100644 --- a/packages/abitype/src/utils.ts +++ b/packages/abitype/src/utils.ts @@ -81,100 +81,100 @@ export type BitsTypeLookup = { export type AbiParameterToPrimitiveType< TAbiParameter extends AbiParameter | { name: string; type: unknown }, TAbiParameterKind extends AbiParameterKind = AbiParameterKind, -> = TAbiParameter['type'] extends Exclude< // 1. Check to see if type is basic (not tuple or array) and can be looked up immediately. - AbiType, - SolidityTuple | SolidityArray -> +> = TAbiParameter['type'] extends AbiBasicType ? AbiTypeToPrimitiveType : // 2. Check if type is tuple and covert each component TAbiParameter extends { type: SolidityTuple components: infer TComponents extends readonly AbiParameter[] } - ? TComponents extends readonly [] - ? [] - : _HasUnnamedAbiParameter extends true - ? // Has unnamed tuple parameters so return as array - readonly [ - ...{ - [K in keyof TComponents]: AbiParameterToPrimitiveType< - TComponents[K], - TAbiParameterKind - > - }, - ] - : // All tuple parameters are named so return as object - { - [Component in - TComponents[number] as Component extends { - name: string - } - ? Component['name'] - : never]: AbiParameterToPrimitiveType - } + ? AbiComponentsToPrimitiveType : // 3. Check if type is array. - /** - * First, infer `Head` against a known size type (either fixed-length array value or `""`). - * - * | Input | Head | - * | --------------- | ------------ | - * | `string[]` | `string` | - * | `string[][][3]` | `string[][]` | - */ - TAbiParameter['type'] extends `${infer Head}[${ - | '' - | `${SolidityFixedArrayRange}`}]` - ? /** - * Then, infer in the opposite direction, using the known `Head` to infer the exact `Size` value. - * - * | Input | Size | - * | ------------ | ---- | - * | `${Head}[]` | `""` | - * | `${Head}[3]` | `3` | - */ - TAbiParameter['type'] extends `${Head}[${infer Size}]` - ? // Check if size is within range for fixed-length arrays, if so create a tuple. - // Otherwise, create an array. Tuples and arrays are created with `[${Size}]` popped off the end - // and passed back into the function to continue reduing down to the basic types found in Step 1. - Size extends keyof SolidityFixedArraySizeLookup - ? Tuple< - AbiParameterToPrimitiveType< - Merge, - TAbiParameterKind - >, - SolidityFixedArraySizeLookup[Size] - > - : readonly AbiParameterToPrimitiveType< - Merge, - TAbiParameterKind - >[] - : never + MaybeExtractArrayParameterType extends [ + infer Head extends string, + infer Size, + ] + ? AbiArrayToPrimitiveType : // 4. If type is not basic, tuple, or array, we don't know what the type is. // This can happen when a fixed-length array is out of range (`Size` doesn't exist in `SolidityFixedArraySizeLookup`), // the array has depth greater than `Config['ArrayMaxDepth']`, etc. ResolvedRegister['StrictAbiType'] extends true - ? TAbiParameter['type'] extends infer TAbiType extends string - ? Error<`Unknown type '${TAbiType}'.`> - : never + ? Error<`Unknown type '${TAbiParameter['type'] & string}'.`> : // 5. If we've gotten this far, let's check for errors in tuple components. // (Happens for recursive tuple typed data types.) TAbiParameter extends { components: Error } ? TAbiParameter['components'] : unknown -// TODO: Speed up by returning immediately as soon as named parameter is found. -type _HasUnnamedAbiParameter = - TAbiParameters extends readonly [ - infer Head extends AbiParameter, - ...infer Tail extends readonly AbiParameter[], - ] - ? Head extends { name: string } - ? Head['name'] extends '' - ? true - : _HasUnnamedAbiParameter - : true - : false +type AbiBasicType = Exclude + +type AbiComponentsToPrimitiveType< + Components extends readonly AbiParameter[], + TAbiParameterKind extends AbiParameterKind, +> = Components extends readonly [] + ? [] + : undefined | '' extends Components[number]['name'] + ? // Has unnamed tuple parameters so return as array + readonly [ + ...{ + [K in keyof Components]: AbiParameterToPrimitiveType< + Components[K], + TAbiParameterKind + > + }, + ] + : // All tuple parameters are named so return as object + { + [Component in + Components[number] as Component['name'] & {}]: AbiParameterToPrimitiveType< + Component, + TAbiParameterKind + > + } + +type MaybeExtractArrayParameterType = + /** + * First, infer `Head` against a known size type (either fixed-length array value or `""`). + * + * | Input | Head | + * | --------------- | ------------ | + * | `string[]` | `string` | + * | `string[][][3]` | `string[][]` | + */ + T extends `${infer Head}[${'' | `${SolidityFixedArrayRange}`}]` + ? // * Then, infer in the opposite direction, using the known `Head` to infer the exact `Size` value. + // * + // * | Input | Size | + // * | ------------ | ---- | + // * | `${Head}[]` | `""` | + // * | `${Head}[3]` | `3` | + // */ + T extends `${Head}[${infer Size}]` + ? [Head, Size] + : undefined + : undefined + +type AbiArrayToPrimitiveType< + TAbiParameter extends AbiParameter | { name: string; type: unknown }, + TAbiParameterKind extends AbiParameterKind, + Head extends string, + Size, +> = Size extends keyof SolidityFixedArraySizeLookup + ? // Check if size is within range for fixed-length arrays, if so create a tuple. + Tuple< + AbiParameterToPrimitiveType< + Merge, + TAbiParameterKind + >, + SolidityFixedArraySizeLookup[Size] + > + : // Otherwise, create an array. Tuples and arrays are created with `[${Size}]` popped off the end + // and passed back into the function to continue reduing down to the basic types found in Step 1. + readonly AbiParameterToPrimitiveType< + Merge, + TAbiParameterKind + >[] /** * Converts array of {@link AbiParameter} to corresponding TypeScript primitive types. From 3530fe2b2178154f21c8ee6d852160e287772e64 Mon Sep 17 00:00:00 2001 From: David Blass Date: Wed, 8 Nov 2023 09:52:52 -0500 Subject: [PATCH 3/7] integrate some attest bench+test examples --- package.json | 1 + packages/abitype/src/utils.bench.ts | 34 +++++++++++++++++++++ packages/abitype/src/utils.test.ts | 24 +++++++++++++++ packages/abitype/src/utils.ts | 3 +- packages/abitype/test/globalSetup.ts | 6 ++++ packages/abitype/test/vitest.workspace.ts | 1 + pnpm-lock.yaml | 37 +++++++++++++++++++++++ 7 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 packages/abitype/src/utils.bench.ts create mode 100644 packages/abitype/src/utils.test.ts create mode 100644 packages/abitype/test/globalSetup.ts diff --git a/package.json b/package.json index 55cde6cc..0d080c94 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "version:update": "bun .scripts/updateVersion.ts" }, "devDependencies": { + "@arktype/attest": "0.0.4", "@biomejs/biome": "1.2.2", "@changesets/changelog-github": "^0.4.8", "@changesets/cli": "^2.26.0", diff --git a/packages/abitype/src/utils.bench.ts b/packages/abitype/src/utils.bench.ts new file mode 100644 index 00000000..cd66be46 --- /dev/null +++ b/packages/abitype/src/utils.bench.ts @@ -0,0 +1,34 @@ +import { bench } from '@arktype/attest' +import type { TypedDataToPrimitiveTypes } from './utils.js' + +bench('recursive', () => { + const types3 = { + Foo: [{ name: 'bar', type: 'Bar[]' }], + Bar: [{ name: 'foo', type: 'Foo[]' }], + } as const + return {} as TypedDataToPrimitiveTypes +}).types([12, 'instantiations']) + +bench('deep', () => { + const types = { + Contributor: [ + { name: 'name', type: 'string' }, + { name: 'address', type: 'address' }, + ], + Website: [ + { name: 'domain', type: 'string' }, + { name: 'webmaster', type: 'Contributor' }, + ], + Project: [ + { name: 'name', type: 'string' }, + { name: 'contributors', type: 'Contributor[2]' }, + { name: 'website', type: 'Website' }, + ], + Organization: [ + { name: 'name', type: 'string' }, + { name: 'projects', type: 'Project[]' }, + { name: 'website', type: 'Website' }, + ], + } as const + return {} as TypedDataToPrimitiveTypes +}).types([44, 'instantiations']) diff --git a/packages/abitype/src/utils.test.ts b/packages/abitype/src/utils.test.ts new file mode 100644 index 00000000..a4b2c9f9 --- /dev/null +++ b/packages/abitype/src/utils.test.ts @@ -0,0 +1,24 @@ +import { attest } from '@arktype/attest' +import { test } from 'vitest' +import type { TypedDataToPrimitiveTypes } from './utils.js' + +test('self-referencing', () => { + const types = { + Name: [ + { name: 'first', type: 'Name' }, + { name: 'last', type: 'string' }, + ], + } as const + type Result = TypedDataToPrimitiveTypes + attest< + Result, + { + Name: { + first: [ + "Error: Cannot convert self-referencing struct 'Name' to primitive type.", + ] + last: 'Meagher' + } + } + >() +}) diff --git a/packages/abitype/src/utils.ts b/packages/abitype/src/utils.ts index 306eb9d6..dd31c06f 100644 --- a/packages/abitype/src/utils.ts +++ b/packages/abitype/src/utils.ts @@ -394,7 +394,8 @@ export type TypedDataToPrimitiveTypes< ? AbiParameterToPrimitiveType : Error<`Cannot convert unknown type '${K2['type']}' to primitive type.`> } -} + // Ensure the result is "Prettied" +} & unknown type _TypedDataParametersToAbiParameters< TTypedDataParameters extends readonly TypedDataParameter[], diff --git a/packages/abitype/test/globalSetup.ts b/packages/abitype/test/globalSetup.ts new file mode 100644 index 00000000..bd2ac4a4 --- /dev/null +++ b/packages/abitype/test/globalSetup.ts @@ -0,0 +1,6 @@ +import { cleanup, setup } from '@arktype/attest' + +export default () => { + setup() + return cleanup +} diff --git a/packages/abitype/test/vitest.workspace.ts b/packages/abitype/test/vitest.workspace.ts index 6009e332..1adff125 100644 --- a/packages/abitype/test/vitest.workspace.ts +++ b/packages/abitype/test/vitest.workspace.ts @@ -13,6 +13,7 @@ export default defineWorkspace([ name: 'abitype', environment: 'node', setupFiles: ['./packages/abitype/test/setup.ts'], + globalSetup: ['./packages/abitype/test/globalSetup.ts'], include: ['./packages/abitype/**/*.test.ts'], }, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8154c8dd..f7265521 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,9 @@ importers: .: devDependencies: + '@arktype/attest': + specifier: 0.0.4 + version: 0.0.4(typescript@5.0.4) '@biomejs/biome': specifier: 1.2.2 version: 1.2.2 @@ -272,6 +275,28 @@ packages: '@jridgewell/trace-mapping': 0.3.18 dev: true + /@arktype/attest@0.0.4(typescript@5.0.4): + resolution: {integrity: sha512-9abICJ9UBeMLkqvXBzPMkR5wFqnXiutiBmiT3wZX+P5S0iQc1R/DPpH4fgcGe12oTSCN0k7OlsT+0uzpUzLEow==} + peerDependencies: + typescript: '*' + dependencies: + '@arktype/fs': 0.0.3 + '@arktype/util': 0.0.2 + '@typescript/vfs': 1.5.0 + arktype: 1.0.27-alpha + typescript: 5.0.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@arktype/fs@0.0.3: + resolution: {integrity: sha512-7jOCMs3Q95/Cn1QEFfrG99/QEcRNeLYZqEkLQ1grHuM/uefhw+7KZpswazjHlQe+6AZ9RVijy2Zdh69Xjyqmyg==} + dev: true + + /@arktype/util@0.0.2: + resolution: {integrity: sha512-pEq0vTCl1jytMDbNb0anfUL8pZ0UeR6/xLQ7KGUfapYKifEMUaoegZ/Hp4UKXguzSvZOMcwb/5f0ilYdDbBtLQ==} + dev: true + /@babel/code-frame@7.21.4: resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} engines: {node: '>=6.9.0'} @@ -1323,6 +1348,14 @@ packages: - supports-color dev: true + /@typescript/vfs@1.5.0: + resolution: {integrity: sha512-AJS307bPgbsZZ9ggCT3wwpg3VbTKMFNHfaY/uF0ahSkYYrPF2dSSKDNIDIQAHm9qJqbLvCsSJH7yN4Vs/CsMMg==} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /@vitest/coverage-v8@0.34.5(vitest@0.34.5): resolution: {integrity: sha512-97xjhRTSdmeeHCm2nNHhT3hLsMYkAhHXm/rwj6SZ3voka8xiCJrwgtfIjoZIFEL4OO0KezGmVuHWQXcMunULIA==} peerDependencies: @@ -1643,6 +1676,10 @@ packages: resolution: {integrity: sha512-fExL2kFDC1Q2DUOx3whE/9KoN66IzkY4b4zUHUBFM1ojEYjZZYDcUW3bek/ufGionX9giIKDC5redH2IlGqcQQ==} dev: true + /arktype@1.0.27-alpha: + resolution: {integrity: sha512-IGoOTif9W6y2folO1+JoPEffZwO56NSuxb7n4C/iYymKluGek1Z1W6Rsi2P3L27SuQpke3DdsjUxW2ABBhH4hQ==} + dev: true + /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: From f82f73787f6e16ceb92a800772597e66435fc094 Mon Sep 17 00:00:00 2001 From: David Blass Date: Tue, 14 Nov 2023 06:05:20 -0500 Subject: [PATCH 4/7] cleanup tests, format --- .attest/assertions.json | 34 ++++++++++++++++++++++++++++++ .gitignore | 2 ++ packages/abitype/src/utils.test.ts | 16 ++++++-------- 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 .attest/assertions.json diff --git a/.attest/assertions.json b/.attest/assertions.json new file mode 100644 index 00000000..0ec1b1bf --- /dev/null +++ b/.attest/assertions.json @@ -0,0 +1,34 @@ +{ + "packages/abitype/src/utils.test.ts": [ + { + "location": { + "start": { + "line": 12, + "char": 3 + }, + "end": { + "line": 22, + "char": 6 + } + }, + "args": [], + "typeArgs": [ + { + "type": "{ Name: { first: [\"Error: Cannot convert self-referencing struct 'Name' to primitive type.\"]; last: string; }; }", + "relationships": { + "args": [], + "typeArgs": ["equality", "equality"] + } + }, + { + "type": "{ Name: { first: [\"Error: Cannot convert self-referencing struct 'Name' to primitive type.\"]; last: string; }; }", + "relationships": { + "args": [], + "typeArgs": ["equality", "equality"] + } + } + ], + "errors": [] + } + ] +} diff --git a/.gitignore b/.gitignore index 56651542..23e926c3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ node_modules tsconfig*.tsbuildinfo bench playgrounds/performance/out +# temporary type-testing cache +.attest # local env files .env diff --git a/packages/abitype/src/utils.test.ts b/packages/abitype/src/utils.test.ts index a4b2c9f9..7a3d621d 100644 --- a/packages/abitype/src/utils.test.ts +++ b/packages/abitype/src/utils.test.ts @@ -3,22 +3,18 @@ import { test } from 'vitest' import type { TypedDataToPrimitiveTypes } from './utils.js' test('self-referencing', () => { - const types = { - Name: [ - { name: 'first', type: 'Name' }, - { name: 'last', type: 'string' }, - ], - } as const - type Result = TypedDataToPrimitiveTypes + type Result = TypedDataToPrimitiveTypes<{ + Name: [{ name: 'first'; type: 'Name' }, { name: 'last'; type: 'string' }] + }> attest< - Result, { Name: { first: [ "Error: Cannot convert self-referencing struct 'Name' to primitive type.", ] - last: 'Meagher' + last: string } - } + }, + Result >() }) From a4d7e27cd5a5ba8154e3153de5ce57d0f8e6065b Mon Sep 17 00:00:00 2001 From: David Blass Date: Tue, 14 Nov 2023 06:35:03 -0500 Subject: [PATCH 5/7] remove .attest cache dir --- .attest/assertions.json | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 .attest/assertions.json diff --git a/.attest/assertions.json b/.attest/assertions.json deleted file mode 100644 index 0ec1b1bf..00000000 --- a/.attest/assertions.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "packages/abitype/src/utils.test.ts": [ - { - "location": { - "start": { - "line": 12, - "char": 3 - }, - "end": { - "line": 22, - "char": 6 - } - }, - "args": [], - "typeArgs": [ - { - "type": "{ Name: { first: [\"Error: Cannot convert self-referencing struct 'Name' to primitive type.\"]; last: string; }; }", - "relationships": { - "args": [], - "typeArgs": ["equality", "equality"] - } - }, - { - "type": "{ Name: { first: [\"Error: Cannot convert self-referencing struct 'Name' to primitive type.\"]; last: string; }; }", - "relationships": { - "args": [], - "typeArgs": ["equality", "equality"] - } - } - ], - "errors": [] - } - ] -} From e0419be6a105199fe7c3c315130002c13043c742 Mon Sep 17 00:00:00 2001 From: David Blass Date: Tue, 14 Nov 2023 06:43:08 -0500 Subject: [PATCH 6/7] fix utils comment typo --- packages/abitype/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/abitype/src/utils.ts b/packages/abitype/src/utils.ts index dd31c06f..07d7cad2 100644 --- a/packages/abitype/src/utils.ts +++ b/packages/abitype/src/utils.ts @@ -170,7 +170,7 @@ type AbiArrayToPrimitiveType< SolidityFixedArraySizeLookup[Size] > : // Otherwise, create an array. Tuples and arrays are created with `[${Size}]` popped off the end - // and passed back into the function to continue reduing down to the basic types found in Step 1. + // and passed back into the function to continue reducing down to the basic types found in Step 1. readonly AbiParameterToPrimitiveType< Merge, TAbiParameterKind From 4f6fbcddebf96d0a385d8f965644ffe9c8c9e825 Mon Sep 17 00:00:00 2001 From: David Blass Date: Tue, 14 Nov 2023 07:34:09 -0500 Subject: [PATCH 7/7] improve unnamed check --- packages/abitype/src/utils.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/abitype/src/utils.ts b/packages/abitype/src/utils.ts index 07d7cad2..90d78091 100644 --- a/packages/abitype/src/utils.ts +++ b/packages/abitype/src/utils.ts @@ -114,17 +114,13 @@ type AbiComponentsToPrimitiveType< TAbiParameterKind extends AbiParameterKind, > = Components extends readonly [] ? [] - : undefined | '' extends Components[number]['name'] - ? // Has unnamed tuple parameters so return as array - readonly [ - ...{ - [K in keyof Components]: AbiParameterToPrimitiveType< - Components[K], - TAbiParameterKind - > - }, - ] - : // All tuple parameters are named so return as object + : // Compare the original set of names to a "validated" + // set where each name is coerced to a string and undefined|"" are excluded + Components[number]['name'] extends Exclude< + Components[number]['name'] & string, + undefined | '' + > + ? // If all the original names are present, all tuple parameters are named so return as object { [Component in Components[number] as Component['name'] & {}]: AbiParameterToPrimitiveType< @@ -132,6 +128,13 @@ type AbiComponentsToPrimitiveType< TAbiParameterKind > } + : // Otherwise, has unnamed tuple parameters so return as array + { + [I in keyof Components]: AbiParameterToPrimitiveType< + Components[I], + TAbiParameterKind + > + } type MaybeExtractArrayParameterType = /**