@ic-reactor/candid 3.0.14-beta.0 → 3.0.14-beta.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ic-reactor/candid",
3
- "version": "3.0.14-beta.0",
3
+ "version": "3.0.14-beta.1",
4
4
  "description": "IC Reactor Candid Adapter - Fetch and parse Candid definitions from Internet Computer canisters",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -44,7 +44,7 @@
44
44
  "dependencies": {
45
45
  "@noble/hashes": "^2.0.1",
46
46
  "zod": "^4.3.5",
47
- "@ic-reactor/core": "^3.0.14-beta.0"
47
+ "@ic-reactor/core": "^3.0.14-beta.1"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "zod": "^4.3.5",
@@ -1,5 +1,5 @@
1
1
  import {
2
- ArgumentFieldType,
2
+ VisitorDataType,
3
3
  CompoundField,
4
4
  FieldNode,
5
5
  FieldByType,
@@ -27,7 +27,7 @@ import {
27
27
  * }
28
28
  * ```
29
29
  */
30
- export function isFieldType<T extends ArgumentFieldType>(
30
+ export function isFieldType<T extends VisitorDataType>(
31
31
  field: FieldNode,
32
32
  type: T
33
33
  ): field is FieldByType<T> {
@@ -148,8 +148,8 @@ describe("ArgumentFieldVisitor", () => {
148
148
  expect(field.type).toBe("record")
149
149
  expect(field.label).toBe("person")
150
150
  expect(field.fields).toHaveLength(2)
151
- expect(field.fieldMap.has("name")).toBe(true)
152
- expect(field.fieldMap.has("age")).toBe(true)
151
+ expect(field.fields.some((f) => f.label === "name")).toBe(true)
152
+ expect(field.fields.some((f) => f.label === "age")).toBe(true)
153
153
 
154
154
  const nameField = field.fields.find((f) => f.label === "name")
155
155
  if (!nameField || nameField.type !== "text") {
@@ -289,14 +289,14 @@ describe("ArgumentFieldVisitor", () => {
289
289
 
290
290
  expect(field.type).toBe("variant")
291
291
  expect(field.label).toBe("status")
292
- expect(field.options).toEqual(["Inactive", "Active", "Pending"])
292
+ expect(field.fields.map((f) => f.label)).toEqual([
293
+ "Inactive",
294
+ "Active",
295
+ "Pending",
296
+ ])
293
297
  expect(field.defaultOption).toBe("Inactive")
294
298
  expect(field.fields).toHaveLength(3)
295
- expect(field.optionMap.has("Active")).toBe(true)
296
-
297
- field.fields.forEach((f) => {
298
- expect(f.type).toBe("null")
299
- })
299
+ expect(field.fields.some((f) => f.label === "Active")).toBe(true)
300
300
 
301
301
  // Test getOptionDefault helper
302
302
  expect(field.getOptionDefault("Active")).toEqual({ _type: "Active" })
@@ -338,7 +338,11 @@ describe("ArgumentFieldVisitor", () => {
338
338
  )
339
339
 
340
340
  expect(field.type).toBe("variant")
341
- expect(field.options).toEqual(["Approve", "Burn", "Transfer"]) // Sorted order
341
+ expect(field.fields.map((f) => f.label)).toEqual([
342
+ "Approve",
343
+ "Burn",
344
+ "Transfer",
345
+ ]) // Sorted order
342
346
 
343
347
  const transferField = field.fields.find(
344
348
  (f) => f.label === "Transfer"
@@ -371,8 +375,8 @@ describe("ArgumentFieldVisitor", () => {
371
375
  )
372
376
 
373
377
  expect(field.type).toBe("variant")
374
- expect(field.options).toContain("Ok")
375
- expect(field.options).toContain("Err")
378
+ expect(field.fields.some((f) => f.label === "Ok")).toBe(true)
379
+ expect(field.fields.some((f) => f.label === "Err")).toBe(true)
376
380
 
377
381
  const okField = field.fields.find((f) => f.label === "Ok")
378
382
  if (!okField || okField.type !== "text") {
@@ -567,8 +571,8 @@ describe("ArgumentFieldVisitor", () => {
567
571
  throw new Error("Extracted field is not variant")
568
572
  }
569
573
  expect(extracted.type).toBe("variant")
570
- expect(extracted.options).toContain("Leaf")
571
- expect(extracted.options).toContain("Node")
574
+ expect(extracted.fields.some((f) => f.label === "Leaf")).toBe(true)
575
+ expect(extracted.fields.some((f) => f.label === "Node")).toBe(true)
572
576
  })
573
577
 
574
578
  it("should handle recursive linked list", () => {
@@ -602,7 +606,7 @@ describe("ArgumentFieldVisitor", () => {
602
606
  throw new Error("Extracted field is not variant")
603
607
  }
604
608
  expect(extracted.type).toBe("variant")
605
- expect(extracted.options).toEqual(["Nil", "Cons"])
609
+ expect(extracted.fields.map((f) => f.label)).toEqual(["Nil", "Cons"])
606
610
 
607
611
  const consField = extracted.fields.find(
608
612
  (f) => f.label === "Cons"
@@ -919,9 +923,13 @@ describe("ArgumentFieldVisitor", () => {
919
923
  )
920
924
 
921
925
  expect(field.type).toBe("variant")
922
- expect(field.options).toContain("Motion")
923
- expect(field.options).toContain("TransferSnsTreasuryFunds")
924
- expect(field.options).toContain("UpgradeSnsControlledCanister")
926
+ expect(field.fields.some((f) => f.label === "Motion")).toBe(true)
927
+ expect(
928
+ field.fields.some((f) => f.label === "TransferSnsTreasuryFunds")
929
+ ).toBe(true)
930
+ expect(
931
+ field.fields.some((f) => f.label === "UpgradeSnsControlledCanister")
932
+ ).toBe(true)
925
933
 
926
934
  // Check Motion variant
927
935
  const motionField = field.fields.find(
@@ -1392,4 +1400,40 @@ describe("ArgumentFieldVisitor", () => {
1392
1400
  }
1393
1401
  })
1394
1402
  })
1403
+
1404
+ // ════════════════════════════════════════════════════════════════════════
1405
+ // Format Detection
1406
+ // ════════════════════════════════════════════════════════════════════════
1407
+
1408
+ describe("Format Detection", () => {
1409
+ it("should NOT detect eth format for method_name", () => {
1410
+ const field = visitor.visitText(IDL.Text, "method_name")
1411
+ expect(field.format).toBe("plain")
1412
+ })
1413
+
1414
+ it("should detect eth format for my_eth_address", () => {
1415
+ const field = visitor.visitText(IDL.Text, "my_eth_address")
1416
+ expect(field.format).toBe("eth")
1417
+ })
1418
+
1419
+ it("should detect eth format for myEthAddress", () => {
1420
+ const field = visitor.visitText(IDL.Text, "myEthAddress")
1421
+ expect(field.format).toBe("eth")
1422
+ })
1423
+
1424
+ it("should detect eth format for ethereum", () => {
1425
+ const field = visitor.visitText(IDL.Text, "ethereum")
1426
+ expect(field.format).toBe("eth")
1427
+ })
1428
+
1429
+ it("should detect btc format for bitcoin_address", () => {
1430
+ const field = visitor.visitText(IDL.Text, "bitcoin_address")
1431
+ expect(field.format).toBe("btc")
1432
+ })
1433
+
1434
+ it("should NOT detect btc format for debt", () => {
1435
+ const field = visitor.visitText(IDL.Text, "debt")
1436
+ expect(field.format).toBe("plain")
1437
+ })
1438
+ })
1395
1439
  })
@@ -278,7 +278,6 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
278
278
  ): RecordField {
279
279
  const name = this.currentName()
280
280
  const fields: FieldNode[] = []
281
- const fieldMap = new Map<string, FieldNode>()
282
281
  const defaultValue: Record<string, unknown> = {}
283
282
  const schemaShape: Record<string, z.ZodTypeAny> = {}
284
283
 
@@ -288,7 +287,6 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
288
287
  ) as FieldNode
289
288
 
290
289
  fields.push(field)
291
- fieldMap.set(key, field)
292
290
  defaultValue[key] = field.defaultValue
293
291
  schemaShape[key] = field.schema
294
292
  }
@@ -303,7 +301,6 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
303
301
  component: "record-container",
304
302
  renderHint: COMPOUND_RENDER_HINT,
305
303
  fields,
306
- fieldMap,
307
304
  defaultValue,
308
305
  schema,
309
306
  candidType: "record",
@@ -317,8 +314,6 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
317
314
  ): VariantField {
318
315
  const name = this.currentName()
319
316
  const fields: FieldNode[] = []
320
- const options: string[] = []
321
- const optionMap = new Map<string, FieldNode>()
322
317
  const variantSchemas: z.ZodTypeAny[] = []
323
318
 
324
319
  for (const [key, type] of fields_) {
@@ -327,8 +322,6 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
327
322
  ) as FieldNode
328
323
 
329
324
  fields.push(field)
330
- options.push(key)
331
- optionMap.set(key, field)
332
325
 
333
326
  if (field.type === "null") {
334
327
  variantSchemas.push(z.object({ _type: z.literal(key) }))
@@ -342,8 +335,8 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
342
335
  }
343
336
  }
344
337
 
345
- const defaultOption = options[0]
346
338
  const firstField = fields[0]
339
+ const defaultOption = firstField.label
347
340
 
348
341
  const defaultValue =
349
342
  firstField.type === "null"
@@ -353,11 +346,11 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
353
346
  [defaultOption]: firstField.defaultValue,
354
347
  }
355
348
 
356
- const schema = z.union(variantSchemas)
349
+ const schema = z.union(variantSchemas as [z.ZodTypeAny, ...z.ZodTypeAny[]])
357
350
 
358
351
  // Helper to get default value for any option
359
352
  const getOptionDefault = (option: string): Record<string, unknown> => {
360
- const optField = optionMap.get(option)
353
+ const optField = fields.find((f) => f.label === option)
361
354
  if (!optField) {
362
355
  throw new Error(`Unknown variant option: ${option}`)
363
356
  }
@@ -368,7 +361,7 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
368
361
 
369
362
  // Helper to get field for a specific option
370
363
  const getField = (option: string): FieldNode => {
371
- const optField = optionMap.get(option)
364
+ const optField = fields.find((f) => f.label === option)
372
365
  if (!optField) {
373
366
  throw new Error(`Unknown variant option: ${option}`)
374
367
  }
@@ -380,7 +373,9 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
380
373
  if (value._type && typeof value._type === "string") {
381
374
  return value._type
382
375
  }
383
- const validKeys = Object.keys(value).filter((k) => options.includes(k))
376
+ const validKeys = Object.keys(value).filter((k) =>
377
+ fields.some((f) => f.label === k)
378
+ )
384
379
  return validKeys[0] ?? defaultOption
385
380
  }
386
381
 
@@ -398,9 +393,7 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
398
393
  component: "variant-select",
399
394
  renderHint: COMPOUND_RENDER_HINT,
400
395
  fields,
401
- options,
402
396
  defaultOption,
403
- optionMap,
404
397
  defaultValue,
405
398
  schema,
406
399
  getOptionDefault,