@ic-reactor/candid 3.0.12-beta.0 → 3.0.14-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/metadata-display-reactor.d.ts.map +1 -1
- package/dist/metadata-display-reactor.js +2 -2
- package/dist/metadata-display-reactor.js.map +1 -1
- package/dist/visitor/arguments/helpers.d.ts +40 -0
- package/dist/visitor/arguments/helpers.d.ts.map +1 -0
- package/dist/visitor/arguments/helpers.js +81 -0
- package/dist/visitor/arguments/helpers.js.map +1 -0
- package/dist/visitor/arguments/index.d.ts +19 -6
- package/dist/visitor/arguments/index.d.ts.map +1 -1
- package/dist/visitor/arguments/index.js +343 -24
- package/dist/visitor/arguments/index.js.map +1 -1
- package/dist/visitor/arguments/types.d.ts +183 -178
- package/dist/visitor/arguments/types.d.ts.map +1 -1
- package/dist/visitor/arguments/types.js +1 -40
- package/dist/visitor/arguments/types.js.map +1 -1
- package/dist/visitor/returns/types.d.ts +3 -4
- package/dist/visitor/returns/types.d.ts.map +1 -1
- package/dist/visitor/types.d.ts +14 -0
- package/dist/visitor/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/metadata-display-reactor.ts +2 -2
- package/src/visitor/arguments/helpers.ts +104 -0
- package/src/visitor/arguments/index.test.ts +443 -23
- package/src/visitor/arguments/index.ts +410 -41
- package/src/visitor/arguments/schema.test.ts +117 -7
- package/src/visitor/arguments/types.ts +284 -284
- package/src/visitor/returns/types.ts +4 -27
- package/src/visitor/types.ts +45 -0
- package/src/visitor/arguments/README.md +0 -230
package/src/visitor/types.ts
CHANGED
|
@@ -26,3 +26,48 @@ export type AllNumberTypes =
|
|
|
26
26
|
| IDL.FixedNatClass
|
|
27
27
|
| IDL.FixedIntClass
|
|
28
28
|
| IDL.FloatClass
|
|
29
|
+
|
|
30
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
31
|
+
// Shared Types for Visitors (Arguments & Returns)
|
|
32
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The core Candid type category used across visitors.
|
|
36
|
+
*/
|
|
37
|
+
export type VisitorDataType =
|
|
38
|
+
| "record"
|
|
39
|
+
| "variant"
|
|
40
|
+
| "tuple"
|
|
41
|
+
| "optional"
|
|
42
|
+
| "vector"
|
|
43
|
+
| "blob"
|
|
44
|
+
| "recursive"
|
|
45
|
+
| "principal"
|
|
46
|
+
| "number"
|
|
47
|
+
| "text"
|
|
48
|
+
| "boolean"
|
|
49
|
+
| "null"
|
|
50
|
+
| "unknown"
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Detected format for text fields based on label heuristics.
|
|
54
|
+
* Used to provide format-specific validation and display.
|
|
55
|
+
*/
|
|
56
|
+
export type TextFormat =
|
|
57
|
+
| "plain"
|
|
58
|
+
| "timestamp"
|
|
59
|
+
| "uuid"
|
|
60
|
+
| "url"
|
|
61
|
+
| "email"
|
|
62
|
+
| "phone"
|
|
63
|
+
| "btc"
|
|
64
|
+
| "eth"
|
|
65
|
+
| "account-id"
|
|
66
|
+
| "principal"
|
|
67
|
+
| "cycle"
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Detected format for number fields based on label heuristics.
|
|
71
|
+
* Used to provide format-specific validation and display.
|
|
72
|
+
*/
|
|
73
|
+
export type NumberFormat = "timestamp" | "cycle" | "value" | "token" | "normal"
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
# Argument Field Visitor
|
|
2
|
-
|
|
3
|
-
The `ArgumentFieldVisitor` traverses Candid IDL types to generate two things:
|
|
4
|
-
|
|
5
|
-
1. **Field Metadata**: Structure, labels, names (for form binding), and default values for rendering form fields.
|
|
6
|
-
2. **Validation Schema**: A Zod schema for validating form inputs.
|
|
7
|
-
|
|
8
|
-
## Usage
|
|
9
|
-
|
|
10
|
-
### 1. Initialize the Visitor
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
import { ArgumentFieldVisitor } from "@ic-reactor/candid"
|
|
14
|
-
import { IDL } from "@icp-sdk/core/candid"
|
|
15
|
-
|
|
16
|
-
const visitor = new ArgumentFieldVisitor()
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### 2. Generate Metadata & Schema
|
|
20
|
-
|
|
21
|
-
You can visit a single function or an entire service.
|
|
22
|
-
|
|
23
|
-
#### For a Service
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
const serviceMeta = visitor.visitService(idlFactory({ IDL }))
|
|
27
|
-
const transferMeta = serviceMeta["icrc1_transfer"]
|
|
28
|
-
|
|
29
|
-
console.log(transferMeta)
|
|
30
|
-
// Output:
|
|
31
|
-
// {
|
|
32
|
-
// functionName: "icrc1_transfer",
|
|
33
|
-
// functionType: "update",
|
|
34
|
-
// fields: [...], // Field definitions for rendering
|
|
35
|
-
// defaultValues: [...], // Default values for the form (array of argument defaults)
|
|
36
|
-
// schema: ZodSchema, // Zod schema for validation
|
|
37
|
-
// argCount: 1, // Number of arguments
|
|
38
|
-
// isNoArgs: false // Whether the function takes no arguments
|
|
39
|
-
// }
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
#### For a Single Function
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
const funcType = IDL.Func([IDL.Text, IDL.Nat], [], [])
|
|
46
|
-
const meta = visitor.visitFunc(funcType, "myMethod")
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### 3. Field Properties
|
|
50
|
-
|
|
51
|
-
Each field in `meta.fields` has the following properties:
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
{
|
|
55
|
-
type: "text" | "number" | "boolean" | "principal" | "record" | "variant" | ...,
|
|
56
|
-
label: "fieldName", // Human-readable label
|
|
57
|
-
name: "[0].field.nested", // TanStack Form compatible path
|
|
58
|
-
defaultValue: ..., // Default value for this field
|
|
59
|
-
schema: ZodSchema, // Zod schema for this field
|
|
60
|
-
candidType: "text", // Original Candid type
|
|
61
|
-
ui: { // Optional UI hints
|
|
62
|
-
placeholder: "e.g. 100",
|
|
63
|
-
},
|
|
64
|
-
// Type-specific properties:
|
|
65
|
-
// - For "number" fields (Nat8, Int32, Float): min, max, unsigned, isFloat, bits
|
|
66
|
-
// - For "text" fields (Nat, Int, Nat64): (handled as text for BigInt support)
|
|
67
|
-
// - For variants: options, optionMap, getOptionDefault()
|
|
68
|
-
// - For vectors: itemField, getItemDefault()
|
|
69
|
-
// - For optionals: innerField, getInnerDefault()
|
|
70
|
-
// - For records: fields, fieldMap
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### 4. Special Handling & Validation
|
|
75
|
-
|
|
76
|
-
#### BigInts as Text
|
|
77
|
-
|
|
78
|
-
Large integer types (`Nat`, `Int`, `Nat64`, `Int64`, `Nat32` > 32-bit representations) are generated with `type: "text"`.
|
|
79
|
-
|
|
80
|
-
- **Reason**: Standard JavaScript numbers lose precision for values > `2^53 - 1`. HTML number inputs can be unreliable for large integers.
|
|
81
|
-
- **Validation**: The Zod schema strictly validates these as **strings containing only digits** (or sign for signed types).
|
|
82
|
-
- **Label**: They retain their `candidType` (e.g. `nat`) for reference.
|
|
83
|
-
|
|
84
|
-
#### Strict Validation
|
|
85
|
-
|
|
86
|
-
- **Required Fields**: Text and Number fields include `.min(1, "Required")`. Empty strings are rejected.
|
|
87
|
-
- **Integers**: Regex validation ensures only digits (no decimals).
|
|
88
|
-
- **Floats**: Float32/Float64 allow decimal points (e.g., `123.1`) and are validated using standard `!isNaN(Number(val))`.
|
|
89
|
-
- **Principals**: Validated using `Principal.fromText()`. Empty strings are rejected.
|
|
90
|
-
|
|
91
|
-
#### Optional Fields
|
|
92
|
-
|
|
93
|
-
- **Behavior**: Optional fields (`Opt`) wrap the inner schema.
|
|
94
|
-
- **Empty Handling**: An empty string input (`""`) is automatically transformed to `null` (Candid `null` / `None`), ensuring optional fields can be cleared.
|
|
95
|
-
|
|
96
|
-
### 5. Integration with TanStack Form
|
|
97
|
-
|
|
98
|
-
The visitor is optimized for standard form libraries like TanStack Form.
|
|
99
|
-
|
|
100
|
-
```tsx
|
|
101
|
-
import { useForm } from "@tanstack/react-form"
|
|
102
|
-
|
|
103
|
-
function MethodForm({ meta }) {
|
|
104
|
-
const form = useForm({
|
|
105
|
-
defaultValues: meta.defaultValues,
|
|
106
|
-
validators: {
|
|
107
|
-
onChange: meta.schema, // Use generated Zod schema for validation
|
|
108
|
-
},
|
|
109
|
-
onSubmit: async ({ value }) => {
|
|
110
|
-
console.log("Structured Data:", value)
|
|
111
|
-
// value is ready to be passed to strict Candid adapters
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
return (
|
|
116
|
-
<form
|
|
117
|
-
onSubmit={(e) => {
|
|
118
|
-
e.preventDefault()
|
|
119
|
-
e.stopPropagation()
|
|
120
|
-
form.handleSubmit()
|
|
121
|
-
}}
|
|
122
|
-
>
|
|
123
|
-
{meta.fields.map((field) => (
|
|
124
|
-
<form.Field key={field.name} name={field.name}>
|
|
125
|
-
{(fieldApi) => (
|
|
126
|
-
<div>
|
|
127
|
-
<label>{field.label}</label>
|
|
128
|
-
<input
|
|
129
|
-
type={
|
|
130
|
-
field.type === "text" || field.type === "principal"
|
|
131
|
-
? "text"
|
|
132
|
-
: field.type
|
|
133
|
-
}
|
|
134
|
-
value={fieldApi.state.value}
|
|
135
|
-
onChange={(e) => fieldApi.handleChange(e.target.value)}
|
|
136
|
-
placeholder={field.ui?.placeholder}
|
|
137
|
-
/>
|
|
138
|
-
{fieldApi.state.meta.errors.map((err) => (
|
|
139
|
-
<span key={err} className="error">
|
|
140
|
-
{err}
|
|
141
|
-
</span>
|
|
142
|
-
))}
|
|
143
|
-
</div>
|
|
144
|
-
)}
|
|
145
|
-
</form.Field>
|
|
146
|
-
))}
|
|
147
|
-
<button type="submit">Submit</button>
|
|
148
|
-
</form>
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### 6. Dynamic Fields
|
|
154
|
-
|
|
155
|
-
For **Vectors** and **Variants**, you can access helper paths dynamically:
|
|
156
|
-
|
|
157
|
-
- **Vector**: Field name `items` -> Item name `items[0]`, `items[1]`.
|
|
158
|
-
- **Record**: Field name `user` -> Nested `user.name`.
|
|
159
|
-
|
|
160
|
-
The `name` property in the metadata is pre-calculated to match this structure (e.g., `[0].args.user.name` if it's the first argument).
|
|
161
|
-
|
|
162
|
-
### 7. Working with Vectors (Arrays)
|
|
163
|
-
|
|
164
|
-
Use helper methods like `getItemDefault()` to manage array items.
|
|
165
|
-
|
|
166
|
-
```tsx
|
|
167
|
-
function VectorField({ field, form }) {
|
|
168
|
-
return (
|
|
169
|
-
<form.Field name={field.name} mode="array">
|
|
170
|
-
{(arrayFieldApi) => (
|
|
171
|
-
<div>
|
|
172
|
-
{arrayFieldApi.state.value.map((_, index) => (
|
|
173
|
-
/* Render items using field.name + [index] */
|
|
174
|
-
))}
|
|
175
|
-
<button
|
|
176
|
-
onClick={() => arrayFieldApi.pushValue(field.getItemDefault())}
|
|
177
|
-
>
|
|
178
|
-
Add Item
|
|
179
|
-
</button>
|
|
180
|
-
</div>
|
|
181
|
-
)}
|
|
182
|
-
</form.Field>
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### 8. Working with Variants
|
|
188
|
-
|
|
189
|
-
Use `optionMap` for lookup and `getOptionDefault()` for switching types.
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
<select
|
|
193
|
-
onChange={(e) => {
|
|
194
|
-
// Switch variant type and default value
|
|
195
|
-
const newValue = field.getOptionDefault(e.target.value)
|
|
196
|
-
form.setFieldValue(field.name, newValue)
|
|
197
|
-
}}
|
|
198
|
-
>
|
|
199
|
-
{field.options.map((opt) => (
|
|
200
|
-
<option key={opt}>{opt}</option>
|
|
201
|
-
))}
|
|
202
|
-
</select>
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### 9. Type Guards
|
|
206
|
-
|
|
207
|
-
The library exports type guard utilities for safer type narrowing:
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
import {
|
|
211
|
-
isFieldType,
|
|
212
|
-
isCompoundField,
|
|
213
|
-
isPrimitiveField,
|
|
214
|
-
} from "@ic-reactor/candid"
|
|
215
|
-
|
|
216
|
-
if (isFieldType(field, "record")) {
|
|
217
|
-
// field is RecordArgumentField
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### 10. Recursive Types
|
|
222
|
-
|
|
223
|
-
Recursive types (like linked lists) use `z.lazy()` schemas. Use `field.extract()` to get the inner definition when rendering.
|
|
224
|
-
|
|
225
|
-
```tsx
|
|
226
|
-
function RecursiveField({ field }) {
|
|
227
|
-
const innerField = useMemo(() => field.extract(), [field])
|
|
228
|
-
return <DynamicField field={innerField} ... />
|
|
229
|
-
}
|
|
230
|
-
```
|