feat(docs): improve CBOR decoder tool UI and add data decoder option#65
Conversation
There was a problem hiding this comment.
Pull request overview
This PR enhances the CBOR decoder tool UI and extends its functionality to support decoding multiple types of Cardano data structures.
- Improved CBOR decoder UI with modern card-based layout and better error display
- Added support for decoding Transaction Witness Sets and Plutus Data in addition to Transactions
- Updated API documentation to reflect schema changes and new codec options
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
packages/evolution/src/core/index.ts |
Exports TransactionWitnessSet module to enable witness set decoding functionality |
packages/evolution/docs/modules/core/TSchema.ts.md |
Updates function signatures for Variant and Struct with improved type definitions |
docs/next-env.d.ts |
Adjusts Next.js type reference path from .next/types to out/dev/types |
docs/content/docs/modules/core/TSchema.mdx |
Adds constructor documentation (TaggedStruct, Variant) and expands StructOptions interface with new fields |
docs/content/docs/modules/core/Data.mdx |
Updates method signatures and adds DataSchema interface documentation |
docs/content/docs/modules/core/CBOR.mdx |
Introduces AIKEN_DEFAULT_OPTIONS constant and extends CodecOptions with encodeMapAsPairs field |
docs/app/tools/tx-decoder/transaction-decoder.tsx |
Implements multi-type decoder (transaction/witnessSet/data) with redesigned card-based UI |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| </svg> | ||
| <div className="flex-1 min-w-0 space-y-2"> | ||
| <p className="text-sm font-medium text-destructive">Error decoding {decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'witness set' : 'data'}</p> | ||
| <pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words overflow-wrap-anywhere font-mono">{error}</pre> |
There was a problem hiding this comment.
[nitpick] The CSS class overflow-wrap-anywhere may not be a valid Tailwind CSS utility class. The standard Tailwind utilities for overflow-wrap are break-normal, break-words, and break-all. The property overflow-wrap: anywhere is valid CSS, but you need to verify this is configured in your Tailwind setup or use break-words which is the standard Tailwind utility with similar behavior.
| <pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words overflow-wrap-anywhere font-mono">{error}</pre> | |
| <pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words font-mono">{error}</pre> |
| const [error, setError] = useState<string | null>(null) | ||
| const [decodeType, setDecodeType] = useState<DecodeType>('transaction') | ||
|
|
||
| const decodeTx = async () => { |
There was a problem hiding this comment.
The decodeTx function is declared as async but doesn't use await anywhere in its body. The function performs only synchronous operations (decoding CBOR, encoding to JSON, and setting state). Remove the async keyword to accurately reflect the function's behavior.
| const decodeTx = async () => { | |
| const decodeTx = () => { |
| toData: (a: A, overrideOptions?: ParseOptions) => I | ||
| fromData: (i: I, overrideOptions?: ParseOptions) => A | ||
| toCBORHex: (a: A, overrideOptions?: ParseOptions) => string | ||
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => any |
There was a problem hiding this comment.
The return type of toCBORBytes has been changed from Uint8Array to any, which removes type safety. This is a regression that allows any type to be returned without compile-time checks. Unless there's a specific reason for this change, the return type should remain Uint8Array to maintain type safety.
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => any | |
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => Uint8Array |
| @@ -289,7 +334,31 @@ export interface StructOptions { | |||
| * | |||
| * Default: true when index is specified, false otherwise | |||
| */ | |||
There was a problem hiding this comment.
Inconsistency in property naming: flat was renamed to flatInUnion, but the documentation doesn't indicate this is a breaking change. If this is part of the StructOptions interface, existing code using flat will break. Consider documenting this as a breaking change or supporting both property names with deprecation warnings.
| */ | |
| */ | |
| /** | |
| * @deprecated Use `flatInUnion` instead. The `flat` property has been renamed to `flatInUnion` for clarity. | |
| * Both `flat` and `flatInUnion` are currently supported, but `flat` will be removed in a future release. | |
| */ |
| fields: Fields, | ||
| options?: StructOptions | ||
| ) => Struct<Fields> | ||
| options: StructOptions = {} |
There was a problem hiding this comment.
The documentation shows a default parameter value in a declare signature (options: StructOptions = {}). TypeScript declaration files (.d.ts) and declare statements should not include default parameter values - these are implementation details. The signature should use options?: StructOptions instead, with the default value documented separately or shown only in implementation files.
| options: StructOptions = {} | |
| options?: StructOptions |
| setError(`Please enter a ${decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'transaction witness set' : 'plutus data'} CBOR hex string`) | ||
| return | ||
| } | ||
|
|
||
| const tx = Core.Transaction.fromCBORHex(cleanHex) | ||
| const json = JSON.stringify(tx.toJSON(), (key, value) => | ||
| typeof value === 'bigint' ? value.toString() : value | ||
| , 2) | ||
| setDecodedJson(json) | ||
| if (decodeType === 'transaction') { | ||
| const tx = Core.Transaction.fromCBORHex(cleanHex) | ||
| const json = Schema.encodeSync(Schema.parseJson(Core.Transaction.Transaction, {space: 2}))(tx) | ||
| setDecodedJson(json) | ||
| } else if (decodeType === 'witnessSet') { | ||
| const witnessSet = Core.TransactionWitnessSet.fromCBORHex(cleanHex) | ||
| const json = Schema.encodeSync(Schema.parseJson(Core.TransactionWitnessSet.TransactionWitnessSet, {space: 2}))(witnessSet) | ||
| setDecodedJson(json) | ||
| } else { | ||
| const data = Core.Data.fromCBORHex(cleanHex) | ||
| const json = Schema.encodeSync(Schema.parseJson(Core.Data.DataSchema, {space: 2}))(data) | ||
| setDecodedJson(json) | ||
| } | ||
| } catch (err) { | ||
| console.error('Decode error:', err) | ||
| setError(err instanceof Error ? err.message : "Failed to decode transaction") | ||
| setError(err instanceof Error ? err.message : `Failed to decode ${decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'witness set' : 'data'}`) |
There was a problem hiding this comment.
Repeated ternary expressions for message formatting create code duplication and reduce maintainability. Consider extracting this logic into a helper function or using a lookup object:
const getDecodeTypeLabel = (type: DecodeType, variant: 'short' | 'full' = 'short'): string => {
const labels = {
transaction: { short: 'transaction', full: 'transaction' },
witnessSet: { short: 'witness set', full: 'transaction witness set' },
data: { short: 'data', full: 'plutus data' }
}
return labels[type][variant]
}This pattern is repeated on lines 22, 41, 83, 92, and 106.
| <select | ||
| id="decode-type" | ||
| value={decodeType} | ||
| onChange={(e) => setDecodeType(e.target.value as DecodeType)} | ||
| className="flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring" | ||
| > | ||
| <option value="transaction">Transaction</option> | ||
| <option value="witnessSet">Transaction Witness Set</option> | ||
| <option value="data">Plutus Data</option> | ||
| </select> |
There was a problem hiding this comment.
[nitpick] The <select> element lacks proper accessibility attributes. Add an aria-label or ensure the associated <label> is properly connected for screen reader users. While the htmlFor attribute on the label connects to the select via id, consider adding aria-describedby if there's additional help text needed.
| toCBORHex: (a: A, overrideOptions?: ParseOptions) => string | ||
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => any | ||
| fromCBORHex: (i: string, overrideOptions?: ParseOptions) => A | ||
| fromCBORBytes: (i: any, overrideOptions?: ParseOptions) => A |
There was a problem hiding this comment.
The parameter type for fromCBORBytes has been changed from Uint8Array to any, which removes input type safety. This allows any type to be passed without compile-time validation, potentially leading to runtime errors. The parameter should be typed as Uint8Array to maintain API safety and catch errors at compile time.
| fromCBORBytes: (i: any, overrideOptions?: ParseOptions) => A | |
| fromCBORBytes: (i: Uint8Array, overrideOptions?: ParseOptions) => A |
|
|
||
| ```ts | ||
| export declare const toCBORBytes: (input: Data, options?: CBOR.CodecOptions) => Uint8Array | ||
| export declare const toCBORBytes: (data: Data, options?: CBOR.CodecOptions) => any |
There was a problem hiding this comment.
The return type of toCBORBytes has been changed from Uint8Array to any, which removes type safety. This is inconsistent with the function's purpose of encoding data to CBOR bytes. The return type should be Uint8Array to provide proper type guarantees to API consumers.
| export declare const toCBORBytes: (data: Data, options?: CBOR.CodecOptions) => any | |
| export declare const toCBORBytes: (data: Data, options?: CBOR.CodecOptions) => Uint8Array |
| **Signature** | ||
|
|
||
| ```ts | ||
| export declare const Variant: <Variants extends Record<string, Schema.Struct.Fields>>( |
There was a problem hiding this comment.
The Variant signature in the documentation shows Record<string, Schema.Struct.Fields> as the constraint, but the actual implementation in TSchema.ts.md uses Record<PropertyKey, Schema.Struct.Fields>. These should be consistent. Using PropertyKey (which includes string | number | symbol) is more flexible, but if the implementation only supports string keys, the documentation should match.
| export declare const Variant: <Variants extends Record<string, Schema.Struct.Fields>>( | |
| export declare const Variant: <Variants extends Record<PropertyKey, Schema.Struct.Fields>>( |
No description provided.