@helios-lang/contract-utils 0.3.4 → 0.3.6

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.
Files changed (56) hide show
  1. package/package.json +1 -1
  2. package/src/artifacts/Artifact.js +14 -0
  3. package/src/artifacts/ArtifactWriter.js +199 -0
  4. package/src/artifacts/ChildArtifactWriter.js +118 -0
  5. package/src/artifacts/FunctionArtifact.js +90 -0
  6. package/src/artifacts/ModuleArtifact.js +83 -0
  7. package/src/artifacts/RootArtifact.js +105 -0
  8. package/src/artifacts/TypeArtifact.js +104 -0
  9. package/src/artifacts/ValidatorArtifact.js +158 -0
  10. package/src/artifacts/index.js +1 -0
  11. package/src/artifacts/symbols.js +16 -0
  12. package/src/cast/Cast.js +315 -160
  13. package/src/cast/UserFunc.js +182 -131
  14. package/src/cast/index.js +12 -3
  15. package/src/codegen/LoadedScriptsWriter.js +35 -11
  16. package/src/codegen/TypeSchema.js +123 -0
  17. package/src/context/index.js +1 -0
  18. package/src/hl2ts.js +0 -4
  19. package/src/index.js +38 -21
  20. package/src/internal.js +12 -0
  21. package/types/artifacts/Artifact.d.ts +11 -0
  22. package/types/artifacts/Artifact.d.ts.map +1 -0
  23. package/types/artifacts/ArtifactWriter.d.ts +64 -0
  24. package/types/artifacts/ArtifactWriter.d.ts.map +1 -0
  25. package/types/artifacts/ChildArtifactWriter.d.ts +35 -0
  26. package/types/artifacts/ChildArtifactWriter.d.ts.map +1 -0
  27. package/types/artifacts/FunctionArtifact.d.ts +14 -0
  28. package/types/artifacts/FunctionArtifact.d.ts.map +1 -0
  29. package/types/artifacts/ModuleArtifact.d.ts +29 -0
  30. package/types/artifacts/ModuleArtifact.d.ts.map +1 -0
  31. package/types/artifacts/RootArtifact.d.ts +11 -0
  32. package/types/artifacts/RootArtifact.d.ts.map +1 -0
  33. package/types/artifacts/TypeArtifact.d.ts +17 -0
  34. package/types/artifacts/TypeArtifact.d.ts.map +1 -0
  35. package/types/artifacts/ValidatorArtifact.d.ts +17 -0
  36. package/types/artifacts/ValidatorArtifact.d.ts.map +1 -0
  37. package/types/artifacts/index.d.ts +2 -0
  38. package/types/artifacts/index.d.ts.map +1 -0
  39. package/types/artifacts/symbols.d.ts +8 -0
  40. package/types/artifacts/symbols.d.ts.map +1 -0
  41. package/types/cast/Cast.d.ts +77 -3
  42. package/types/cast/Cast.d.ts.map +1 -1
  43. package/types/cast/UserFunc.d.ts +39 -0
  44. package/types/cast/UserFunc.d.ts.map +1 -1
  45. package/types/cast/index.d.ts +2 -2
  46. package/types/codegen/LoadedScriptsWriter.d.ts +18 -0
  47. package/types/codegen/LoadedScriptsWriter.d.ts.map +1 -1
  48. package/types/codegen/TypeSchema.d.ts +5 -0
  49. package/types/codegen/TypeSchema.d.ts.map +1 -1
  50. package/types/context/writeContractContextArtifacts.d.ts +30 -0
  51. package/types/context/writeContractContextArtifacts.d.ts.map +1 -0
  52. package/types/hl2ts.d.ts.map +1 -1
  53. package/types/index.d.ts +34 -28
  54. package/types/index.d.ts.map +1 -1
  55. package/types/internal.d.ts +5 -0
  56. package/types/internal.d.ts.map +1 -0
package/src/cast/Cast.js CHANGED
@@ -54,9 +54,24 @@ import {
54
54
 
55
55
  /**
56
56
  * @import { TxInput, TxOutput } from "@helios-lang/ledger"
57
- * @import { TypeSchema } from "@helios-lang/type-utils"
58
- * @import { UplcData } from "@helios-lang/uplc"
59
- * @import { Cast, CastConfig, CastLike, SchemaToUplcContext, UplcToSchemaContext } from "../index.js"
57
+ * @import { EnumTypeSchema, TypeSchema } from "@helios-lang/type-utils"
58
+ * @import { ConstrData, UplcData } from "@helios-lang/uplc"
59
+ * @import { Cast, CastConfig, CastLike } from "../index.js"
60
+ */
61
+
62
+ /**
63
+ * @typedef {Object} SchemaToUplcContext
64
+ * @prop {Record<string, TypeSchema>} defs - symbol table permitting recursive schema references
65
+ * @prop {string} dataPath - provides developer-facing cues for any parsing errors, showing the deep field path of any error
66
+ * @prop {boolean} unwrapSingleFieldEnumVariants - defaults to false. If true, assumes the following input objects for enum variants: `{VariantName: SingleFieldData}`, instead of the more verbose `{VariantName: {SingleFieldName: SingleFieldData}}`
67
+ */
68
+
69
+ /**
70
+ * @typedef {Object} UplcToSchemaContext
71
+ * @prop {Record<string, TypeSchema>} defs - symbol table permitting recursive schema references
72
+ * @prop {string} dataPath - provides developer-facing cues for any parsing errors, showing the deep field path of any error
73
+ * @prop {boolean} unwrapSingleFieldEnumVariants - defaults to false. If true, the following enum variant outputs are created: `{VariantName: SingleFieldData}`, instead of the more verbose `{VariantName: {SingleFieldName: SingleFieldData}}`
74
+ * @prop {boolean} isMainnet
60
75
  */
61
76
 
62
77
  /**
@@ -110,10 +125,11 @@ class CastImpl {
110
125
  * @returns {TStrict}
111
126
  */
112
127
  fromUplcData(data, dataPath = "") {
113
- return uplcToSchemaWithDataPath(this.schema, data, {
114
- config: this.config,
115
- dataPath,
116
- defs: {}
128
+ return convertFromUplcData(this.schema, data, {
129
+ isMainnet: this.config.isMainnet,
130
+ unwrapSingleFieldEnumVariants:
131
+ !!this.config.unwrapSingleFieldEnumVariants,
132
+ dataPath
117
133
  })
118
134
  }
119
135
 
@@ -129,24 +145,63 @@ class CastImpl {
129
145
  * @returns {UplcData}
130
146
  */
131
147
  toUplcData(x, dataPath = "") {
132
- const t = schemaToUplcWithDataPath(this.schema, x, {
133
- defs: {},
134
- dataPath
148
+ return convertToUplcData(this.schema, x, {
149
+ dataPath,
150
+ unwrapSingleFieldEnumVariants:
151
+ !!this.config.unwrapSingleFieldEnumVariants
135
152
  })
136
- t.rawData = x
137
- return t
138
153
  }
139
154
  }
140
155
 
141
156
  /**
157
+ * @template T
142
158
  * @param {TypeSchema} schema
143
- * @param {any} x
159
+ * @param {UplcData} data
160
+ * @param {{
161
+ * isMainnet: boolean,
162
+ * dataPath?: string,
163
+ * unwrapSingleFieldEnumVariants?: boolean
164
+ * }} options
165
+ * @returns {T}
166
+ */
167
+ export function convertFromUplcData(schema, data, options) {
168
+ return convertUplcDataToSchemaDataWithDataPath(schema, data, {
169
+ isMainnet: options.isMainnet,
170
+ unwrapSingleFieldEnumVariants: !!options.unwrapSingleFieldEnumVariants,
171
+ dataPath: options.dataPath ?? "",
172
+ defs: {}
173
+ })
174
+ }
175
+
176
+ /**
177
+ * @template T
178
+ * @param {TypeSchema} schema
179
+ * @param {T} x
180
+ * @param {{
181
+ * dataPath?: string,
182
+ * unwrapSingleFieldEnumVariants?: boolean
183
+ * }} [options]
184
+ * @returns {UplcData}
185
+ */
186
+ export function convertToUplcData(schema, x, options = {}) {
187
+ const t = convertSchemaDataToUplcDataWithDataPath(schema, x, {
188
+ defs: {},
189
+ unwrapSingleFieldEnumVariants: !!options.unwrapSingleFieldEnumVariants,
190
+ dataPath: options.dataPath ?? ""
191
+ })
192
+ t.rawData = x
193
+ return t
194
+ }
195
+
196
+ /**
197
+ * @param {TypeSchema} schema
198
+ * @param {any} x - data
144
199
  * @param {SchemaToUplcContext} context
145
200
  * @returns {UplcData}
146
201
  */
147
- function schemaToUplcWithDataPath(schema, x, context) {
202
+ function convertSchemaDataToUplcDataWithDataPath(schema, x, context) {
148
203
  try {
149
- const t = schemaToUplc(schema, x, context)
204
+ const t = convertSchemaDataToUplcData(schema, x, context)
150
205
  t.dataPath = context.dataPath
151
206
  return t
152
207
  } catch (e) {
@@ -159,28 +214,37 @@ function schemaToUplcWithDataPath(schema, x, context) {
159
214
  }
160
215
  }
161
216
 
217
+ /**
218
+ * @template T [{dataPath: string}]
219
+ * @param {T} context
220
+ * @param {string} dataPath
221
+ * @returns {T}
222
+ */
223
+ function passContext(context, dataPath) {
224
+ return {
225
+ ...context,
226
+ dataPath
227
+ }
228
+ }
229
+
162
230
  /**
163
231
  * @param {TypeSchema} schema
164
- * @param {any} x
165
- * @param {SchemaToUplcContext} inputContextOnly
232
+ * @param {any} x - JS data
233
+ * @param {SchemaToUplcContext} context
166
234
  * @returns {UplcData}
167
235
  */
168
- function schemaToUplc(schema, x, inputContextOnly) {
169
- // const { defs = {}, dataPath = "" } = inputContext
170
- // important: DON'T extend the inputContext for use in nested calls.
171
- const { dataPath, defs } = inputContextOnly
172
-
173
- // Only the defs can be passed down, and it's simpler syntactically
174
- // ... just use the defs directly in the nested calls.
236
+ function convertSchemaDataToUplcData(schema, x, context) {
237
+ const { dataPath, defs } = context
175
238
 
176
239
  const kind = schema.kind
177
240
  switch (kind) {
178
241
  case "reference": {
179
242
  const def = expectDefined(defs[schema.id])
180
- return schemaToUplcWithDataPath(def, x, {
181
- defs,
182
- dataPath: `${dataPath}::ref{${schema.id}}`
183
- })
243
+ return convertSchemaDataToUplcDataWithDataPath(
244
+ def,
245
+ x,
246
+ passContext(context, `${dataPath}::ref{${schema.id}}`)
247
+ )
184
248
  }
185
249
  case "internal": {
186
250
  const name = schema.name
@@ -258,10 +322,11 @@ function schemaToUplc(schema, x, inputContextOnly) {
258
322
  case "list":
259
323
  return makeListData(
260
324
  x.map((x, i) =>
261
- schemaToUplcWithDataPath(schema.itemType, x, {
262
- defs,
263
- dataPath: `${dataPath}.list[${i}]`
264
- })
325
+ convertSchemaDataToUplcDataWithDataPath(
326
+ schema.itemType,
327
+ x,
328
+ passContext(context, `${dataPath}.list[${i}]`)
329
+ )
265
330
  )
266
331
  )
267
332
  case "map": {
@@ -275,14 +340,22 @@ function schemaToUplc(schema, x, inputContextOnly) {
275
340
  entries.map(([k, v], i) => {
276
341
  const displayKey = "string" == typeof k ? `'${k}'` : `@{i}`
277
342
  return [
278
- schemaToUplcWithDataPath(schema.keyType, k, {
279
- defs,
280
- dataPath: `${dataPath}[mapKey ${displayKey}]`
281
- }),
282
- schemaToUplcWithDataPath(schema.valueType, v, {
283
- defs,
284
- dataPath: `${dataPath}[mapVal ${displayKey}]`
285
- })
343
+ convertSchemaDataToUplcDataWithDataPath(
344
+ schema.keyType,
345
+ k,
346
+ passContext(
347
+ context,
348
+ `${dataPath}[mapKey ${displayKey}]`
349
+ )
350
+ ),
351
+ convertSchemaDataToUplcDataWithDataPath(
352
+ schema.valueType,
353
+ v,
354
+ passContext(
355
+ context,
356
+ `${dataPath}[mapVal ${displayKey}]`
357
+ )
358
+ )
286
359
  ]
287
360
  })
288
361
  )
@@ -290,19 +363,21 @@ function schemaToUplc(schema, x, inputContextOnly) {
290
363
  case "tuple":
291
364
  return makeListData(
292
365
  x.map((x, i) =>
293
- schemaToUplcWithDataPath(schema.itemTypes[i], x, {
294
- defs,
295
- dataPath: `${dataPath}[tuple@${i}]`
296
- })
366
+ convertSchemaDataToUplcDataWithDataPath(
367
+ schema.itemTypes[i],
368
+ x,
369
+ passContext(context, `${dataPath}[tuple@${i}]`)
370
+ )
297
371
  )
298
372
  )
299
373
  case "option":
300
374
  return wrapUplcDataOption(
301
375
  x
302
- ? schemaToUplcWithDataPath(schema.someType, x, {
303
- defs,
304
- dataPath: `${dataPath}::Some`
305
- })
376
+ ? convertSchemaDataToUplcDataWithDataPath(
377
+ schema.someType,
378
+ x,
379
+ passContext(context, `${dataPath}::Some`)
380
+ )
306
381
  : undefined
307
382
  )
308
383
  case "struct": {
@@ -310,21 +385,25 @@ function schemaToUplc(schema, x, inputContextOnly) {
310
385
  switch (schema.format) {
311
386
  case "singleton":
312
387
  const singleFieldName = schema.fieldTypes[0].name
313
- return schemaToUplcWithDataPath(
388
+ return convertSchemaDataToUplcDataWithDataPath(
314
389
  schema.fieldTypes[0].type,
315
390
  x[singleFieldName],
316
- {
317
- defs,
318
- dataPath: `${dataPath}[sfStruct.${singleFieldName}]`
319
- }
391
+ passContext(
392
+ context,
393
+ `${dataPath}[sfStruct.${singleFieldName}]`
394
+ )
320
395
  )
321
396
  case "list":
322
397
  return makeListData(
323
398
  schema.fieldTypes.map(({ name, type }) =>
324
- schemaToUplcWithDataPath(type, x[name], {
325
- defs,
326
- dataPath: `${dataPath}[fStruct].${name}`
327
- })
399
+ convertSchemaDataToUplcDataWithDataPath(
400
+ type,
401
+ x[name],
402
+ passContext(
403
+ context,
404
+ `${dataPath}[fStruct].${name}`
405
+ )
406
+ )
328
407
  )
329
408
  )
330
409
  case "map": {
@@ -365,14 +444,15 @@ function schemaToUplc(schema, x, inputContextOnly) {
365
444
  encodeUtf8(encodingKey)
366
445
  )
367
446
 
368
- const valueData = schemaToUplcWithDataPath(
369
- ft.type,
370
- value,
371
- {
372
- defs,
373
- dataPath: `${dataPath}[mStruct].${fieldName}${encodingInfo}`
374
- }
375
- )
447
+ const valueData =
448
+ convertSchemaDataToUplcDataWithDataPath(
449
+ ft.type,
450
+ value,
451
+ passContext(
452
+ context,
453
+ `${dataPath}[mStruct].${fieldName}${encodingInfo}`
454
+ )
455
+ )
376
456
 
377
457
  pairs.push([keyData, valueData])
378
458
  }
@@ -405,16 +485,11 @@ function schemaToUplc(schema, x, inputContextOnly) {
405
485
  )
406
486
  }
407
487
 
408
- // Gives the encoding of nested data a context to prevent a second ConstrData wrapper on the MapData
409
- // ... only for the first field.
410
- return makeConstrData(
488
+ return convertEnumVariantDataToConstrData(
489
+ schema,
411
490
  tag,
412
- schema.variantTypes[tag].fieldTypes.map((f, i) =>
413
- schemaToUplcWithDataPath(f.type, variantFields[f.name], {
414
- defs,
415
- dataPath: `${dataPath}[${schema.name}::${variantName}].${f.name}`
416
- })
417
- )
491
+ variantFields,
492
+ passContext(context, dataPath)
418
493
  )
419
494
  }
420
495
  case "variant":
@@ -423,10 +498,14 @@ function schemaToUplc(schema, x, inputContextOnly) {
423
498
  return makeConstrData(
424
499
  schema.tag,
425
500
  schema.fieldTypes.map(({ name, type }) =>
426
- schemaToUplcWithDataPath(type, x[name], {
427
- defs,
428
- dataPath: `${dataPath}[enumVariant ${schema.id}.${name}`
429
- })
501
+ convertSchemaDataToUplcDataWithDataPath(
502
+ type,
503
+ x[name],
504
+ passContext(
505
+ context,
506
+ `${dataPath}[enumVariant ${schema.id}.${name}`
507
+ )
508
+ )
430
509
  )
431
510
  )
432
511
  default:
@@ -434,13 +513,54 @@ function schemaToUplc(schema, x, inputContextOnly) {
434
513
  }
435
514
  }
436
515
 
516
+ /**
517
+ * Gives the encoding of nested data a context to prevent a second ConstrData wrapper on the MapData
518
+ * ... only for the first field.
519
+ * @param {EnumTypeSchema} schema
520
+ * @param {number} tag
521
+ * @param {any} data - can be any in order to represent a single unwrapped field
522
+ * @param {SchemaToUplcContext} context
523
+ * @returns {ConstrData}
524
+ */
525
+ function convertEnumVariantDataToConstrData(schema, tag, data, context) {
526
+ const variantSchema = schema.variantTypes[tag]
527
+ const variantName = variantSchema.name
528
+
529
+ if (
530
+ context.unwrapSingleFieldEnumVariants &&
531
+ variantSchema.fieldTypes.length == 1
532
+ ) {
533
+ const singleFieldName = variantSchema.fieldTypes[0].name
534
+
535
+ // rewrap as preparation for converting to UplcData
536
+ data = {
537
+ [singleFieldName]: data
538
+ }
539
+ }
540
+
541
+ // at this point `data` should be of type `Record<string, any>`
542
+ return makeConstrData(
543
+ tag,
544
+ variantSchema.fieldTypes.map((f) =>
545
+ convertSchemaDataToUplcDataWithDataPath(
546
+ f.type,
547
+ data[f.name],
548
+ passContext(
549
+ context,
550
+ `[${schema.name}::${variantName}].${f.name}`
551
+ )
552
+ )
553
+ )
554
+ )
555
+ }
556
+
437
557
  /**
438
558
  * @param {TypeSchema} schema
439
559
  * @param {UplcData} data
440
560
  * @param {UplcToSchemaContext} context
441
561
  * @returns {any}
442
562
  */
443
- function uplcToSchemaWithDataPath(schema, data, context) {
563
+ function convertUplcDataToSchemaDataWithDataPath(schema, data, context) {
444
564
  try {
445
565
  const t = uplcToSchema(schema, data, context)
446
566
  return t
@@ -460,15 +580,12 @@ function uplcToSchemaWithDataPath(schema, data, context) {
460
580
  * This should fail when deviating
461
581
  * @param {TypeSchema} schema
462
582
  * @param {UplcData} data
463
- * @param {UplcToSchemaContext} inputContextOnly
583
+ * @param {UplcToSchemaContext} context
464
584
  * @returns {any}
465
585
  */
466
- function uplcToSchema(schema, data, inputContextOnly) {
586
+ function uplcToSchema(schema, data, context) {
467
587
  const kind = schema.kind
468
- const { config, defs } = inputContextOnly
469
- // Note: don't use the inputContext directly in nested calls.
470
- const { dataPath, ...context } = inputContextOnly
471
- // use { ... context } augmented with a de-novo `dataPath` attr
588
+ const { dataPath, defs, isMainnet } = context
472
589
 
473
590
  switch (kind) {
474
591
  case "internal": {
@@ -476,10 +593,7 @@ function uplcToSchema(schema, data, inputContextOnly) {
476
593
 
477
594
  switch (name) {
478
595
  case "Address":
479
- return convertUplcDataToShelleyAddress(
480
- config.isMainnet,
481
- data
482
- )
596
+ return convertUplcDataToShelleyAddress(isMainnet, data)
483
597
  case "Any":
484
598
  // TODO: should this throw an error?
485
599
  return null
@@ -533,9 +647,9 @@ function uplcToSchema(schema, data, inputContextOnly) {
533
647
  case "TxId":
534
648
  return convertUplcDataToTxId(data)
535
649
  case "TxInput":
536
- return convertUplcDataToTxInput(config.isMainnet, data)
650
+ return convertUplcDataToTxInput(isMainnet, data)
537
651
  case "TxOutput":
538
- return convertUplcDataToTxOutput(config.isMainnet, data)
652
+ return convertUplcDataToTxOutput(isMainnet, data)
539
653
  case "TxOutputDatum":
540
654
  return convertUplcDataToTxOutputDatum(data)
541
655
  case "TxOutputId":
@@ -550,43 +664,51 @@ function uplcToSchema(schema, data, inputContextOnly) {
550
664
  }
551
665
  case "list":
552
666
  return expectListData(data).items.map((x, i) =>
553
- uplcToSchemaWithDataPath(schema.itemType, x, {
554
- ...context,
555
- dataPath: `${dataPath}[${i}]`
556
- })
667
+ convertUplcDataToSchemaDataWithDataPath(
668
+ schema.itemType,
669
+ x,
670
+ passContext(context, `${dataPath}[${i}]`)
671
+ )
557
672
  )
558
673
  case "map":
559
674
  return new Map(
560
675
  expectMapData(data).items.map(([k, v], i) => {
561
- const key = uplcToSchemaWithDataPath(schema.keyType, k, {
562
- ...context,
563
- dataPath: `${dataPath}[mapKey @${i}]`
564
- })
676
+ const key = convertUplcDataToSchemaDataWithDataPath(
677
+ schema.keyType,
678
+ k,
679
+ passContext(context, `${dataPath}[mapKey @${i}]`)
680
+ )
565
681
  const displayKey =
566
682
  "string" == typeof key ? `'${key}'` : `@{i}`
567
683
  return [
568
684
  key,
569
- uplcToSchemaWithDataPath(schema.valueType, v, {
570
- ...context,
571
- dataPath: `${dataPath}[mapVal ${displayKey}]`
572
- })
685
+ convertUplcDataToSchemaDataWithDataPath(
686
+ schema.valueType,
687
+ v,
688
+ passContext(
689
+ context,
690
+ `${dataPath}[mapVal ${displayKey}]`
691
+ )
692
+ )
573
693
  ]
574
694
  })
575
695
  )
576
696
  case "tuple":
577
697
  return expectListData(data).items.map((x, i) =>
578
- uplcToSchemaWithDataPath(schema.itemTypes[i], x, {
579
- ...context,
580
- dataPath: `${dataPath}[tuple@${i}]`
581
- })
698
+ convertUplcDataToSchemaDataWithDataPath(
699
+ schema.itemTypes[i],
700
+ x,
701
+ passContext(context, `${dataPath}[tuple@${i}]`)
702
+ )
582
703
  )
583
704
  case "option": {
584
705
  const optionData = unwrapUplcDataOption(data)
585
706
  return optionData
586
- ? uplcToSchemaWithDataPath(schema.someType, optionData, {
587
- ...context,
588
- dataPath: `${dataPath}::Some`
589
- })
707
+ ? convertUplcDataToSchemaDataWithDataPath(
708
+ schema.someType,
709
+ optionData,
710
+ passContext(context, `${dataPath}::Some`)
711
+ )
590
712
  : undefined
591
713
  }
592
714
  case "struct": {
@@ -594,11 +716,12 @@ function uplcToSchema(schema, data, inputContextOnly) {
594
716
  switch (schema.format) {
595
717
  case "singleton":
596
718
  return {
597
- [schema.fieldTypes[0].name]: uplcToSchemaWithDataPath(
598
- schema.fieldTypes[0].type,
599
- data,
600
- { ...context, dataPath: `${dataPath}[sfStruct]` }
601
- )
719
+ [schema.fieldTypes[0].name]:
720
+ convertUplcDataToSchemaDataWithDataPath(
721
+ schema.fieldTypes[0].type,
722
+ data,
723
+ passContext(context, `${dataPath}[sfStruct]`)
724
+ )
602
725
  }
603
726
  case "list": {
604
727
  const fields = expectListData(data).items
@@ -615,10 +738,14 @@ function uplcToSchema(schema, data, inputContextOnly) {
615
738
  const { name, type } = schema.fieldTypes[i]
616
739
  return [
617
740
  name,
618
- uplcToSchemaWithDataPath(type, field, {
619
- ...context,
620
- dataPath: `${dataPath}[fStruct].${name}`
621
- })
741
+ convertUplcDataToSchemaDataWithDataPath(
742
+ type,
743
+ field,
744
+ passContext(
745
+ context,
746
+ `${dataPath}[fStruct].${name}`
747
+ )
748
+ )
622
749
  ]
623
750
  })
624
751
  )
@@ -679,13 +806,13 @@ function uplcToSchema(schema, data, inputContextOnly) {
679
806
  return /** @type {const} */ ([
680
807
  i,
681
808
  name,
682
- uplcToSchemaWithDataPath(
809
+ convertUplcDataToSchemaDataWithDataPath(
683
810
  type,
684
811
  encodedDataPair[1],
685
- {
686
- ...context,
687
- dataPath: `${dataPath}[mStruct].${name}`
688
- }
812
+ passContext(
813
+ context,
814
+ `${dataPath}[mStruct].${name}`
815
+ )
689
816
  )
690
817
  ])
691
818
  })
@@ -701,38 +828,12 @@ function uplcToSchema(schema, data, inputContextOnly) {
701
828
  }
702
829
  case "enum": {
703
830
  defs[schema.id] = schema
704
- const { tag, fields } = expectConstrData(data)
705
831
 
706
- const variantSchema = schema.variantTypes[tag]
707
-
708
- if (!variantSchema) {
709
- throw new Error(`tag ${tag} out of range`)
710
- }
711
-
712
- const nExpected = variantSchema.fieldTypes.length
713
-
714
- if (fields.length != nExpected) {
715
- throw new Error(
716
- `expected ${nExpected} fields for variant ${variantSchema.name} (tag ${tag}), got ${fields.length} fields`
717
- )
718
- }
719
-
720
- const fieldCount = variantSchema.fieldTypes.length
721
- return {
722
- [variantSchema.name]: Object.fromEntries(
723
- fields.map((f, i) => [
724
- variantSchema.fieldTypes[i].name,
725
- uplcToSchemaWithDataPath(
726
- variantSchema.fieldTypes[i].type,
727
- f,
728
- {
729
- ...context,
730
- dataPath: `${dataPath}[${schema.name}::${variantSchema.name}]`
731
- }
732
- )
733
- ])
734
- )
735
- }
832
+ return convertConstrDataFieldsToEnumVariantFields(
833
+ schema,
834
+ expectConstrData(data),
835
+ passContext(context, dataPath)
836
+ )
736
837
  }
737
838
  case "variant": {
738
839
  defs[schema.id] = schema
@@ -741,10 +842,14 @@ function uplcToSchema(schema, data, inputContextOnly) {
741
842
  return Object.fromEntries(
742
843
  fields.map((field, i) => [
743
844
  schema.fieldTypes[i].name,
744
- uplcToSchemaWithDataPath(schema.fieldTypes[i].type, field, {
745
- ...context,
746
- dataPath: `${dataPath}[enumVariant ${schema.id}].${schema.fieldTypes[i].name}`
747
- })
845
+ convertUplcDataToSchemaDataWithDataPath(
846
+ schema.fieldTypes[i].type,
847
+ field,
848
+ passContext(
849
+ context,
850
+ `${dataPath}[enumVariant ${schema.id}].${schema.fieldTypes[i].name}`
851
+ )
852
+ )
748
853
  ])
749
854
  )
750
855
  }
@@ -753,6 +858,56 @@ function uplcToSchema(schema, data, inputContextOnly) {
753
858
  }
754
859
  }
755
860
 
861
+ /**
862
+ * @param {EnumTypeSchema} schema
863
+ * @param {ConstrData} data
864
+ * @param {UplcToSchemaContext} context
865
+ * @returns {Record<string, any>}
866
+ */
867
+ function convertConstrDataFieldsToEnumVariantFields(schema, data, context) {
868
+ const { tag, fields } = data
869
+
870
+ const variantSchema = schema.variantTypes[tag]
871
+
872
+ if (!variantSchema) {
873
+ throw new Error(`tag ${tag} out of range`)
874
+ }
875
+
876
+ const nExpected = variantSchema.fieldTypes.length
877
+
878
+ if (fields.length != nExpected) {
879
+ throw new Error(
880
+ `expected ${nExpected} fields for variant ${variantSchema.name} (tag ${tag}), got ${fields.length} fields`
881
+ )
882
+ }
883
+ const result = {
884
+ [variantSchema.name]: Object.fromEntries(
885
+ fields.map((f, i) => [
886
+ variantSchema.fieldTypes[i].name,
887
+ convertUplcDataToSchemaDataWithDataPath(
888
+ variantSchema.fieldTypes[i].type,
889
+ f,
890
+ passContext(
891
+ context,
892
+ `${context.dataPath}[${schema.name}::${variantSchema.name}]`
893
+ )
894
+ )
895
+ ])
896
+ )
897
+ }
898
+
899
+ if (
900
+ context.unwrapSingleFieldEnumVariants &&
901
+ variantSchema.fieldTypes.length == 1
902
+ ) {
903
+ const singleFieldName = variantSchema.fieldTypes[0].name
904
+ const variantName = variantSchema.name
905
+ result[variantName] = result[variantName][singleFieldName]
906
+ }
907
+
908
+ return result
909
+ }
910
+
756
911
  /**
757
912
  * @template TStrict
758
913
  * @template TPermissive