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

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.
@@ -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.fields.map((f) => f.label)).toEqual([
292
+ expect(field.options.map((f) => f.label)).toEqual([
293
293
  "Inactive",
294
294
  "Active",
295
295
  "Pending",
296
296
  ])
297
297
  expect(field.defaultOption).toBe("Inactive")
298
- expect(field.fields).toHaveLength(3)
299
- expect(field.fields.some((f) => f.label === "Active")).toBe(true)
298
+ expect(field.options).toHaveLength(3)
299
+ expect(field.options.some((f) => f.label === "Active")).toBe(true)
300
300
 
301
301
  // Test getOptionDefault helper
302
302
  expect(field.getOptionDefault("Active")).toEqual({ _type: "Active" })
@@ -338,13 +338,13 @@ describe("ArgumentFieldVisitor", () => {
338
338
  )
339
339
 
340
340
  expect(field.type).toBe("variant")
341
- expect(field.fields.map((f) => f.label)).toEqual([
341
+ expect(field.options.map((f) => f.label)).toEqual([
342
342
  "Approve",
343
343
  "Burn",
344
344
  "Transfer",
345
345
  ]) // Sorted order
346
346
 
347
- const transferField = field.fields.find(
347
+ const transferField = field.options.find(
348
348
  (f) => f.label === "Transfer"
349
349
  ) as RecordField
350
350
  if (!transferField || transferField.type !== "record") {
@@ -353,7 +353,7 @@ describe("ArgumentFieldVisitor", () => {
353
353
  expect(transferField.type).toBe("record")
354
354
  expect(transferField.fields).toHaveLength(2)
355
355
 
356
- const burnField = field.fields.find((f) => f.label === "Burn")
356
+ const burnField = field.options.find((f) => f.label === "Burn")
357
357
  if (!burnField || burnField.type !== "text") {
358
358
  throw new Error("Burn field not found or not text")
359
359
  }
@@ -375,16 +375,16 @@ describe("ArgumentFieldVisitor", () => {
375
375
  )
376
376
 
377
377
  expect(field.type).toBe("variant")
378
- expect(field.fields.some((f) => f.label === "Ok")).toBe(true)
379
- expect(field.fields.some((f) => f.label === "Err")).toBe(true)
378
+ expect(field.options.some((f) => f.label === "Ok")).toBe(true)
379
+ expect(field.options.some((f) => f.label === "Err")).toBe(true)
380
380
 
381
- const okField = field.fields.find((f) => f.label === "Ok")
381
+ const okField = field.options.find((f) => f.label === "Ok")
382
382
  if (!okField || okField.type !== "text") {
383
383
  throw new Error("Ok field not found or not text")
384
384
  }
385
385
  expect(okField.type).toBe("text")
386
386
 
387
- const errField = field.fields.find((f) => f.label === "Err")
387
+ const errField = field.options.find((f) => f.label === "Err")
388
388
  if (!errField || errField.type !== "text") {
389
389
  throw new Error("Err field not found or not text")
390
390
  }
@@ -571,8 +571,8 @@ describe("ArgumentFieldVisitor", () => {
571
571
  throw new Error("Extracted field is not variant")
572
572
  }
573
573
  expect(extracted.type).toBe("variant")
574
- expect(extracted.fields.some((f) => f.label === "Leaf")).toBe(true)
575
- expect(extracted.fields.some((f) => f.label === "Node")).toBe(true)
574
+ expect(extracted.options.some((f) => f.label === "Leaf")).toBe(true)
575
+ expect(extracted.options.some((f) => f.label === "Node")).toBe(true)
576
576
  })
577
577
 
578
578
  it("should handle recursive linked list", () => {
@@ -606,9 +606,9 @@ describe("ArgumentFieldVisitor", () => {
606
606
  throw new Error("Extracted field is not variant")
607
607
  }
608
608
  expect(extracted.type).toBe("variant")
609
- expect(extracted.fields.map((f) => f.label)).toEqual(["Nil", "Cons"])
609
+ expect(extracted.options.map((f) => f.label)).toEqual(["Nil", "Cons"])
610
610
 
611
- const consField = extracted.fields.find(
611
+ const consField = extracted.options.find(
612
612
  (f) => f.label === "Cons"
613
613
  ) as RecordField
614
614
  if (!consField || consField.type !== "record") {
@@ -630,11 +630,11 @@ describe("ArgumentFieldVisitor", () => {
630
630
 
631
631
  expect(meta.functionType).toBe("query")
632
632
  expect(meta.functionName).toBe("lookup")
633
- expect(meta.fields).toHaveLength(1)
634
- expect(meta.fields[0].type).toBe("text")
635
- expect(meta.defaultValues).toEqual([""])
633
+ expect(meta.args).toHaveLength(1)
634
+ expect(meta.args[0].type).toBe("text")
635
+ expect(meta.defaults).toEqual([""])
636
636
  expect(meta.argCount).toBe(1)
637
- expect(meta.isNoArgs).toBe(false)
637
+ expect(meta.isEmpty).toBe(false)
638
638
  })
639
639
 
640
640
  it("should handle update function", () => {
@@ -657,10 +657,10 @@ describe("ArgumentFieldVisitor", () => {
657
657
 
658
658
  expect(meta.functionType).toBe("update")
659
659
  expect(meta.functionName).toBe("transfer")
660
- expect(meta.fields).toHaveLength(1)
661
- expect(meta.fields[0].type).toBe("record")
660
+ expect(meta.args).toHaveLength(1)
661
+ expect(meta.args[0].type).toBe("record")
662
662
 
663
- const recordField = meta.fields[0] as RecordField
663
+ const recordField = meta.args[0] as RecordField
664
664
  if (recordField.type !== "record") {
665
665
  throw new Error("Expected record field")
666
666
  }
@@ -675,10 +675,10 @@ describe("ArgumentFieldVisitor", () => {
675
675
  )
676
676
  const meta = visitor.visitFunc(funcType, "authorize")
677
677
 
678
- expect(meta.fields).toHaveLength(3)
679
- expect(meta.fields[0].type).toBe("principal")
680
- expect(meta.fields[1].type).toBe("text")
681
- expect(meta.fields[2].type).toBe("optional")
678
+ expect(meta.args).toHaveLength(3)
679
+ expect(meta.args[0].type).toBe("principal")
680
+ expect(meta.args[1].type).toBe("text")
681
+ expect(meta.args[2].type).toBe("optional")
682
682
  expect(meta.argCount).toBe(3)
683
683
  })
684
684
 
@@ -687,10 +687,10 @@ describe("ArgumentFieldVisitor", () => {
687
687
  const meta = visitor.visitFunc(funcType, "getBalance")
688
688
 
689
689
  expect(meta.functionType).toBe("query")
690
- expect(meta.fields).toHaveLength(0)
691
- expect(meta.defaultValues).toEqual([])
690
+ expect(meta.args).toHaveLength(0)
691
+ expect(meta.defaults).toEqual([])
692
692
  expect(meta.argCount).toBe(0)
693
- expect(meta.isNoArgs).toBe(true)
693
+ expect(meta.isEmpty).toBe(true)
694
694
  })
695
695
  })
696
696
 
@@ -734,20 +734,20 @@ describe("ArgumentFieldVisitor", () => {
734
734
  // Check get_balance
735
735
  const getBalanceMeta = serviceMeta["get_balance"]
736
736
  expect(getBalanceMeta.functionType).toBe("query")
737
- expect(getBalanceMeta.fields).toHaveLength(1)
738
- expect(getBalanceMeta.fields[0].type).toBe("principal")
737
+ expect(getBalanceMeta.args).toHaveLength(1)
738
+ expect(getBalanceMeta.args[0].type).toBe("principal")
739
739
 
740
740
  // Check transfer
741
741
  const transferMeta = serviceMeta["transfer"]
742
742
  expect(transferMeta.functionType).toBe("update")
743
- expect(transferMeta.fields).toHaveLength(1)
744
- expect(transferMeta.fields[0].type).toBe("record")
743
+ expect(transferMeta.args).toHaveLength(1)
744
+ expect(transferMeta.args[0].type).toBe("record")
745
745
 
746
746
  // Check get_metadata
747
747
  const getMetadataMeta = serviceMeta["get_metadata"]
748
748
  expect(getMetadataMeta.functionType).toBe("query")
749
- expect(getMetadataMeta.fields).toHaveLength(0)
750
- expect(getMetadataMeta.isNoArgs).toBe(true)
749
+ expect(getMetadataMeta.args).toHaveLength(0)
750
+ expect(getMetadataMeta.isEmpty).toBe(true)
751
751
  })
752
752
  })
753
753
 
@@ -772,7 +772,7 @@ describe("ArgumentFieldVisitor", () => {
772
772
  )
773
773
  const meta = visitor.visitFunc(funcType, "updateUser")
774
774
 
775
- const argRecord = meta.fields[0] as RecordField
775
+ const argRecord = meta.args[0] as RecordField
776
776
  if (argRecord.type !== "record") {
777
777
  throw new Error("Expected record field")
778
778
  }
@@ -803,7 +803,7 @@ describe("ArgumentFieldVisitor", () => {
803
803
  const funcType = IDL.Func([IDL.Vec(IDL.Text)], [], [])
804
804
  const meta = visitor.visitFunc(funcType, "addTags")
805
805
 
806
- const vecField = meta.fields[0] as VectorField
806
+ const vecField = meta.args[0] as VectorField
807
807
  if (vecField.type !== "vector") {
808
808
  throw new Error("Expected vector field")
809
809
  }
@@ -923,16 +923,16 @@ describe("ArgumentFieldVisitor", () => {
923
923
  )
924
924
 
925
925
  expect(field.type).toBe("variant")
926
- expect(field.fields.some((f) => f.label === "Motion")).toBe(true)
926
+ expect(field.options.some((f) => f.label === "Motion")).toBe(true)
927
927
  expect(
928
- field.fields.some((f) => f.label === "TransferSnsTreasuryFunds")
928
+ field.options.some((f) => f.label === "TransferSnsTreasuryFunds")
929
929
  ).toBe(true)
930
930
  expect(
931
- field.fields.some((f) => f.label === "UpgradeSnsControlledCanister")
931
+ field.options.some((f) => f.label === "UpgradeSnsControlledCanister")
932
932
  ).toBe(true)
933
933
 
934
934
  // Check Motion variant
935
- const motionField = field.fields.find(
935
+ const motionField = field.options.find(
936
936
  (f) => f.label === "Motion"
937
937
  ) as RecordField
938
938
  if (!motionField || motionField.type !== "record") {
@@ -942,7 +942,7 @@ describe("ArgumentFieldVisitor", () => {
942
942
  expect(motionField.fields).toHaveLength(1)
943
943
 
944
944
  // Check TransferSnsTreasuryFunds variant
945
- const transferField = field.fields.find(
945
+ const transferField = field.options.find(
946
946
  (f) => f.label === "TransferSnsTreasuryFunds"
947
947
  ) as RecordField
948
948
  if (!transferField || transferField.type !== "record") {
@@ -1011,8 +1011,8 @@ describe("ArgumentFieldVisitor", () => {
1011
1011
  const funcType = IDL.Func([IDL.Text, IDL.Nat], [], [])
1012
1012
  const meta = visitor.visitFunc(funcType, "test")
1013
1013
 
1014
- expect(meta.fields[0].displayLabel).toBe("Arg 0")
1015
- expect(meta.fields[1].displayLabel).toBe("Arg 1")
1014
+ expect(meta.args[0].displayLabel).toBe("Arg 0")
1015
+ expect(meta.args[1].displayLabel).toBe("Arg 1")
1016
1016
  })
1017
1017
 
1018
1018
  it("should format tuple index labels correctly", () => {
@@ -1231,14 +1231,14 @@ describe("ArgumentFieldVisitor", () => {
1231
1231
  "action"
1232
1232
  )
1233
1233
 
1234
- const transferField = field.getField("Transfer")
1234
+ const transferField = field.getOption("Transfer")
1235
1235
  expect(transferField.type).toBe("record")
1236
1236
 
1237
- const burnField = field.getField("Burn")
1237
+ const burnField = field.getOption("Burn")
1238
1238
  expect(burnField.type).toBe("text") // nat is rendered as text for large numbers
1239
1239
  })
1240
1240
 
1241
- it("getSelectedOption should return the selected option from a value", () => {
1241
+ it("getSelectedKey should return the selected key from a value", () => {
1242
1242
  const variantType = IDL.Variant({ A: IDL.Null, B: IDL.Text, C: IDL.Nat })
1243
1243
  const field = visitor.visitVariant(
1244
1244
  variantType,
@@ -1250,11 +1250,11 @@ describe("ArgumentFieldVisitor", () => {
1250
1250
  "choice"
1251
1251
  )
1252
1252
 
1253
- expect(field.getSelectedOption({ A: null })).toBe("A")
1254
- expect(field.getSelectedOption({ B: "hello" })).toBe("B")
1255
- expect(field.getSelectedOption({ C: "100" })).toBe("C")
1253
+ expect(field.getSelectedKey({ A: null })).toBe("A")
1254
+ expect(field.getSelectedKey({ B: "hello" })).toBe("B")
1255
+ expect(field.getSelectedKey({ C: "100" })).toBe("C")
1256
1256
  // Falls back to default option for unknown values
1257
- expect(field.getSelectedOption({})).toBe("A")
1257
+ expect(field.getSelectedKey({})).toBe("A")
1258
1258
  })
1259
1259
 
1260
1260
  it("getSelectedField should return the field for the selected option", () => {
@@ -1271,10 +1271,10 @@ describe("ArgumentFieldVisitor", () => {
1271
1271
  "result"
1272
1272
  )
1273
1273
 
1274
- const okField = field.getSelectedField({ Ok: "100" })
1274
+ const okField = field.getSelectedOption({ Ok: "100" })
1275
1275
  expect(okField.label).toBe("Ok")
1276
1276
 
1277
- const errField = field.getSelectedField({ Err: "error" })
1277
+ const errField = field.getSelectedOption({ Err: "error" })
1278
1278
  expect(errField.label).toBe("Err")
1279
1279
  })
1280
1280
  })
@@ -1312,7 +1312,7 @@ describe("ArgumentFieldVisitor", () => {
1312
1312
  it("should create item field with correct index in name path", () => {
1313
1313
  const funcType = IDL.Func([IDL.Vec(IDL.Text)], [], [])
1314
1314
  const meta = visitor.visitFunc(funcType, "addItems")
1315
- const vecField = meta.fields[0] as VectorField
1315
+ const vecField = meta.args[0] as VectorField
1316
1316
 
1317
1317
  const item0 = vecField.createItemField(0)
1318
1318
  expect(item0.name).toBe("[0][0]")
@@ -1328,7 +1328,7 @@ describe("ArgumentFieldVisitor", () => {
1328
1328
  []
1329
1329
  )
1330
1330
  const meta = visitor.visitFunc(funcType, "addItems")
1331
- const vecField = meta.fields[0] as VectorField
1331
+ const vecField = meta.args[0] as VectorField
1332
1332
 
1333
1333
  const item = vecField.createItemField(3, { label: "Person 3" })
1334
1334
  expect(item.label).toBe("Person 3")
@@ -1338,7 +1338,7 @@ describe("ArgumentFieldVisitor", () => {
1338
1338
  it("should use default label when not provided", () => {
1339
1339
  const funcType = IDL.Func([IDL.Vec(IDL.Text)], [], [])
1340
1340
  const meta = visitor.visitFunc(funcType, "addTags")
1341
- const vecField = meta.fields[0] as VectorField
1341
+ const vecField = meta.args[0] as VectorField
1342
1342
 
1343
1343
  const item = vecField.createItemField(2)
1344
1344
  expect(item.label).toBe("Item 2")
@@ -1,5 +1,6 @@
1
1
  import { isQuery } from "../helpers"
2
2
  import { checkTextFormat, checkNumberFormat } from "../constants"
3
+ import { MetadataError } from "./types"
3
4
  import type {
4
5
  FieldNode,
5
6
  RecordField,
@@ -233,13 +234,13 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
233
234
  const functionType = isQuery(t) ? "query" : "update"
234
235
  const argCount = t.argTypes.length
235
236
 
236
- const fields = t.argTypes.map((arg, index) => {
237
+ const args = t.argTypes.map((arg, index) => {
237
238
  return this.withName(`[${index}]`, () =>
238
239
  arg.accept(this, `__arg${index}`)
239
240
  ) as FieldNode
240
241
  })
241
242
 
242
- const defaultValues = fields.map((field) => field.defaultValue)
243
+ const defaults = args.map((field) => field.defaultValue)
243
244
 
244
245
  // Handle empty args case for schema
245
246
  // For no-arg functions, use an empty array schema
@@ -250,7 +251,7 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
250
251
  [z.ZodTypeAny, ...z.ZodTypeAny[]]
251
252
  >)
252
253
  : z.tuple(
253
- fields.map((field) => field.schema) as [
254
+ args.map((field) => field.schema) as [
254
255
  z.ZodTypeAny,
255
256
  ...z.ZodTypeAny[],
256
257
  ]
@@ -259,11 +260,11 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
259
260
  return {
260
261
  functionType,
261
262
  functionName,
262
- fields,
263
- defaultValues: defaultValues,
263
+ args,
264
+ defaults,
264
265
  schema,
265
266
  argCount,
266
- isNoArgs: argCount === 0,
267
+ isEmpty: argCount === 0,
267
268
  }
268
269
  }
269
270
 
@@ -313,7 +314,7 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
313
314
  label: string
314
315
  ): VariantField {
315
316
  const name = this.currentName()
316
- const fields: FieldNode[] = []
317
+ const options: FieldNode[] = []
317
318
  const variantSchemas: z.ZodTypeAny[] = []
318
319
 
319
320
  for (const [key, type] of fields_) {
@@ -321,7 +322,7 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
321
322
  type.accept(this, key)
322
323
  ) as FieldNode
323
324
 
324
- fields.push(field)
325
+ options.push(field)
325
326
 
326
327
  if (field.type === "null") {
327
328
  variantSchemas.push(z.object({ _type: z.literal(key) }))
@@ -335,24 +336,28 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
335
336
  }
336
337
  }
337
338
 
338
- const firstField = fields[0]
339
- const defaultOption = firstField.label
339
+ const firstOption = options[0]
340
+ const defaultOption = firstOption.label
340
341
 
341
342
  const defaultValue =
342
- firstField.type === "null"
343
+ firstOption.type === "null"
343
344
  ? { _type: defaultOption }
344
345
  : {
345
346
  _type: defaultOption,
346
- [defaultOption]: firstField.defaultValue,
347
+ [defaultOption]: firstOption.defaultValue,
347
348
  }
348
349
 
349
350
  const schema = z.union(variantSchemas as [z.ZodTypeAny, ...z.ZodTypeAny[]])
350
351
 
351
352
  // Helper to get default value for any option
352
353
  const getOptionDefault = (option: string): Record<string, unknown> => {
353
- const optField = fields.find((f) => f.label === option)
354
+ const optField = options.find((f) => f.label === option)
354
355
  if (!optField) {
355
- throw new Error(`Unknown variant option: ${option}`)
356
+ throw new MetadataError(
357
+ `Unknown variant option: "${option}". Available: ${options.map((o) => o.label).join(", ")}`,
358
+ name,
359
+ "variant"
360
+ )
356
361
  }
357
362
  return optField.type === "null"
358
363
  ? { _type: option }
@@ -360,29 +365,33 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
360
365
  }
361
366
 
362
367
  // Helper to get field for a specific option
363
- const getField = (option: string): FieldNode => {
364
- const optField = fields.find((f) => f.label === option)
368
+ const getOption = (option: string): FieldNode => {
369
+ const optField = options.find((f) => f.label === option)
365
370
  if (!optField) {
366
- throw new Error(`Unknown variant option: ${option}`)
371
+ throw new MetadataError(
372
+ `Unknown variant option: "${option}". Available: ${options.map((o) => o.label).join(", ")}`,
373
+ name,
374
+ "variant"
375
+ )
367
376
  }
368
377
  return optField
369
378
  }
370
379
 
371
- // Helper to get currently selected option from a value
372
- const getSelectedOption = (value: Record<string, unknown>): string => {
380
+ // Helper to get currently selected option key from a value
381
+ const getSelectedKey = (value: Record<string, unknown>): string => {
373
382
  if (value._type && typeof value._type === "string") {
374
383
  return value._type
375
384
  }
376
385
  const validKeys = Object.keys(value).filter((k) =>
377
- fields.some((f) => f.label === k)
386
+ options.some((f) => f.label === k)
378
387
  )
379
388
  return validKeys[0] ?? defaultOption
380
389
  }
381
390
 
382
- // Helper to get selected field from a value
383
- const getSelectedField = (value: Record<string, unknown>): FieldNode => {
384
- const selectedOption = getSelectedOption(value)
385
- return getField(selectedOption)
391
+ // Helper to get the field for the currently selected option
392
+ const getSelectedOption = (value: Record<string, unknown>): FieldNode => {
393
+ const selectedKey = getSelectedKey(value)
394
+ return getOption(selectedKey)
386
395
  }
387
396
 
388
397
  return {
@@ -392,14 +401,14 @@ export class FieldVisitor<A = BaseActor> extends IDL.Visitor<
392
401
  name,
393
402
  component: "variant-select",
394
403
  renderHint: COMPOUND_RENDER_HINT,
395
- fields,
404
+ options,
396
405
  defaultOption,
397
406
  defaultValue,
398
407
  schema,
399
408
  getOptionDefault,
400
- getField,
409
+ getOption,
410
+ getSelectedKey,
401
411
  getSelectedOption,
402
- getSelectedField,
403
412
  candidType: "variant",
404
413
  }
405
414
  }