@helios-lang/effect 0.1.1 → 0.1.3
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/dist/Ledger/Address.js +156 -0
- package/dist/Ledger/Address.js.map +1 -0
- package/dist/Ledger/AssetClass.js +74 -0
- package/dist/Ledger/AssetClass.js.map +1 -0
- package/dist/Ledger/Assets.js +122 -0
- package/dist/Ledger/Assets.js.map +1 -0
- package/dist/Ledger/Credential.js +17 -0
- package/dist/Ledger/Credential.js.map +1 -0
- package/dist/Ledger/DatumHash.js +21 -0
- package/dist/Ledger/DatumHash.js.map +1 -0
- package/dist/Ledger/MintingPolicy.js +45 -0
- package/dist/Ledger/MintingPolicy.js.map +1 -0
- package/dist/Ledger/PubKeyHash.js +21 -0
- package/dist/Ledger/PubKeyHash.js.map +1 -0
- package/dist/Ledger/TxId.js +15 -0
- package/dist/Ledger/TxId.js.map +1 -0
- package/dist/Ledger/TxInput.js +51 -0
- package/dist/Ledger/TxInput.js.map +1 -0
- package/dist/Ledger/TxOutput.js +118 -0
- package/dist/Ledger/TxOutput.js.map +1 -0
- package/dist/Ledger/TxOutputDatum.js +41 -0
- package/dist/Ledger/TxOutputDatum.js.map +1 -0
- package/dist/Ledger/TxOutputId.js +39 -0
- package/dist/Ledger/TxOutputId.js.map +1 -0
- package/dist/Ledger/ValidatorHash.js +21 -0
- package/dist/Ledger/ValidatorHash.js.map +1 -0
- package/dist/Ledger/index.js +14 -0
- package/dist/Ledger/index.js.map +1 -0
- package/dist/Uplc/Data.js +229 -21
- package/dist/Uplc/Data.js.map +1 -1
- package/dist/Uplc/index.js +0 -1
- package/dist/Uplc/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -10
- package/src/Ledger/Address.ts +252 -0
- package/src/Ledger/AssetClass.ts +96 -0
- package/src/Ledger/Assets.ts +164 -0
- package/src/Ledger/Credential.ts +29 -0
- package/src/Ledger/DatumHash.ts +36 -0
- package/src/Ledger/MintingPolicy.ts +57 -0
- package/src/Ledger/PubKeyHash.ts +36 -0
- package/src/Ledger/TxId.ts +31 -0
- package/src/Ledger/TxInput.test.ts +21 -0
- package/src/Ledger/TxInput.ts +66 -0
- package/src/Ledger/TxOutput.ts +165 -0
- package/src/Ledger/TxOutputDatum.ts +64 -0
- package/src/Ledger/TxOutputId.ts +63 -0
- package/src/Ledger/ValidatorHash.ts +36 -0
- package/src/Ledger/index.ts +13 -0
- package/src/Uplc/Data.test.ts +321 -0
- package/src/Uplc/Data.ts +445 -47
- package/src/Uplc/index.ts +0 -1
- package/src/index.ts +1 -1
- package/src/Address.ts +0 -20
- package/src/Uplc/DataSchema.test.ts +0 -207
- package/src/Uplc/DataSchema.ts +0 -181
package/src/Uplc/Data.ts
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect"
|
|
1
|
+
import { Effect, Encoding, ParseResult, Schema } from "effect"
|
|
2
2
|
import * as Bytes from "../internal/Bytes.js"
|
|
3
|
+
import { decode as decodeUtf8, encode as encodeUtf8 } from "../internal/Utf8.js"
|
|
3
4
|
import * as Cbor from "../Cbor.js"
|
|
4
5
|
|
|
5
6
|
const SuspendedData = Schema.suspend(
|
|
6
|
-
(): Schema.Schema<Data,
|
|
7
|
+
(): Schema.Schema<Data, DataJSON> => DataFromJSON
|
|
7
8
|
)
|
|
8
9
|
|
|
9
|
-
export const
|
|
10
|
-
bytes: Schema.
|
|
10
|
+
export const ByteArrayDataFromJSON = Schema.Struct({
|
|
11
|
+
bytes: Schema.Uint8ArrayFromHex
|
|
11
12
|
})
|
|
12
13
|
|
|
13
|
-
export type
|
|
14
|
+
export type ByteArrayData = Schema.Schema.Type<typeof ByteArrayDataFromJSON>
|
|
15
|
+
export type ByteArrayDataJSON = Schema.Schema.Encoded<
|
|
16
|
+
typeof ByteArrayDataFromJSON
|
|
17
|
+
>
|
|
14
18
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
export function makeByteArray(
|
|
19
|
+
export function makeByteArrayData(
|
|
18
20
|
bytes: string | number[] | Uint8Array
|
|
19
|
-
):
|
|
20
|
-
return { bytes: Bytes.
|
|
21
|
+
): ByteArrayData {
|
|
22
|
+
return { bytes: Bytes.toUint8Array(bytes) }
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -25,40 +27,39 @@ export function makeByteArray(
|
|
|
25
27
|
*
|
|
26
28
|
* Cannot used Branded types due Schema issues.
|
|
27
29
|
*/
|
|
28
|
-
export const
|
|
30
|
+
export const IntDataFromJSON = Schema.Struct({
|
|
29
31
|
int: Schema.BigIntFromNumber
|
|
30
32
|
})
|
|
31
33
|
|
|
32
|
-
export type
|
|
33
|
-
|
|
34
|
-
export type IntEncoded = Schema.Schema.Encoded<typeof Int>
|
|
34
|
+
export type IntData = Schema.Schema.Type<typeof IntDataFromJSON>
|
|
35
|
+
export type IntDataJSON = Schema.Schema.Encoded<typeof IntDataFromJSON>
|
|
35
36
|
|
|
36
|
-
export function
|
|
37
|
+
export function makeIntData(value: number | bigint): IntData {
|
|
37
38
|
return { int: BigInt(value) }
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
export const
|
|
41
|
+
export const ListDataFromJSON = Schema.Struct({
|
|
41
42
|
list: Schema.Array(SuspendedData)
|
|
42
43
|
})
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* Must be defined explicitly to avoid circular reference problems
|
|
46
47
|
*/
|
|
47
|
-
export type
|
|
48
|
+
export type ListData = {
|
|
48
49
|
readonly list: ReadonlyArray<Data>
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
export type
|
|
52
|
-
readonly list: ReadonlyArray<
|
|
52
|
+
export type ListDataJSON = {
|
|
53
|
+
readonly list: ReadonlyArray<DataJSON>
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
export function
|
|
56
|
+
export function makeListData(items: Data[]): ListData {
|
|
56
57
|
return {
|
|
57
58
|
list: items
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
export const
|
|
62
|
+
export const MapDataFromJSON = Schema.Struct({
|
|
62
63
|
map: Schema.Array(
|
|
63
64
|
Schema.Struct({
|
|
64
65
|
k: SuspendedData,
|
|
@@ -70,27 +71,27 @@ export const Map = Schema.Struct({
|
|
|
70
71
|
/**
|
|
71
72
|
* Must be defined explicitly to avoid circular reference problems
|
|
72
73
|
*/
|
|
73
|
-
export type
|
|
74
|
+
export type MapData = {
|
|
74
75
|
readonly map: ReadonlyArray<{
|
|
75
76
|
readonly k: Data
|
|
76
77
|
readonly v: Data
|
|
77
78
|
}>
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
export type
|
|
81
|
+
export type MapDataJSON = {
|
|
81
82
|
readonly map: ReadonlyArray<{
|
|
82
|
-
readonly k:
|
|
83
|
-
readonly v:
|
|
83
|
+
readonly k: DataJSON
|
|
84
|
+
readonly v: DataJSON
|
|
84
85
|
}>
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
export function
|
|
88
|
+
export function makeMapData(entries: [Data, Data][]): MapData {
|
|
88
89
|
return {
|
|
89
90
|
map: entries.map(([k, v]) => ({ k, v }))
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
export const
|
|
94
|
+
export const ConstrDataFromJSON = Schema.Struct({
|
|
94
95
|
constructor: Schema.Number,
|
|
95
96
|
fields: Schema.Array(SuspendedData)
|
|
96
97
|
})
|
|
@@ -98,40 +99,47 @@ export const Constr = Schema.Struct({
|
|
|
98
99
|
/**
|
|
99
100
|
* Must be defined explicitly to avoid circular reference problems
|
|
100
101
|
*/
|
|
101
|
-
export type
|
|
102
|
+
export type ConstrData = {
|
|
102
103
|
readonly constructor: number
|
|
103
104
|
readonly fields: ReadonlyArray<Data>
|
|
104
105
|
}
|
|
105
106
|
|
|
106
|
-
export type
|
|
107
|
+
export type ConstrDataJSON = {
|
|
107
108
|
readonly constructor: number
|
|
108
|
-
readonly fields: ReadonlyArray<
|
|
109
|
+
readonly fields: ReadonlyArray<DataJSON>
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
export function
|
|
112
|
+
export function makeConstrData(
|
|
113
|
+
tag: bigint | number,
|
|
114
|
+
fields: Data[]
|
|
115
|
+
): ConstrData {
|
|
112
116
|
return {
|
|
113
117
|
constructor: Number(tag),
|
|
114
118
|
fields
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
export const
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
export const DataFromJSON = Schema.Union(
|
|
123
|
+
ByteArrayDataFromJSON,
|
|
124
|
+
IntDataFromJSON,
|
|
125
|
+
ListDataFromJSON,
|
|
126
|
+
MapDataFromJSON,
|
|
127
|
+
ConstrDataFromJSON
|
|
128
|
+
)
|
|
121
129
|
|
|
122
|
-
export
|
|
130
|
+
export const Data = Schema.typeSchema(DataFromJSON)
|
|
123
131
|
|
|
124
132
|
/**
|
|
125
133
|
* Must be defined explicitly to avoid circular reference problems
|
|
126
134
|
*/
|
|
127
|
-
export type Data =
|
|
135
|
+
export type Data = ByteArrayData | ConstrData | IntData | ListData | MapData
|
|
128
136
|
|
|
129
|
-
export type
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
|
|
|
137
|
+
export type DataJSON =
|
|
138
|
+
| ByteArrayDataJSON
|
|
139
|
+
| ConstrDataJSON
|
|
140
|
+
| IntDataJSON
|
|
141
|
+
| ListDataJSON
|
|
142
|
+
| MapDataJSON
|
|
135
143
|
|
|
136
144
|
/**
|
|
137
145
|
* Simple recursive CBOR decoder
|
|
@@ -145,18 +153,18 @@ export const decode = (bytes: Bytes.BytesLike): Cbor.DecodeEffect<Data> =>
|
|
|
145
153
|
if (yield* Cbor.isList(stream)) {
|
|
146
154
|
const items = yield* Cbor.decodeList(decode)(stream)
|
|
147
155
|
|
|
148
|
-
return
|
|
156
|
+
return makeListData(items)
|
|
149
157
|
} else if (yield* Cbor.isBytes(stream)) {
|
|
150
|
-
return
|
|
158
|
+
return makeByteArrayData(yield* Cbor.decodeBytes(stream))
|
|
151
159
|
} else if (yield* Cbor.isMap(stream)) {
|
|
152
160
|
const entries = yield* Cbor.decodeMap(decode, decode)(stream)
|
|
153
161
|
|
|
154
|
-
return
|
|
162
|
+
return makeMapData(entries)
|
|
155
163
|
} else if (yield* Cbor.isConstr(stream)) {
|
|
156
164
|
const [tag, fields] = yield* Cbor.decodeConstr(decode)(stream)
|
|
157
|
-
return
|
|
165
|
+
return makeConstrData(tag, fields)
|
|
158
166
|
} else {
|
|
159
|
-
return
|
|
167
|
+
return makeIntData(yield* Cbor.decodeInt(stream))
|
|
160
168
|
}
|
|
161
169
|
})
|
|
162
170
|
|
|
@@ -257,3 +265,393 @@ export function log2i(x: bigint): number {
|
|
|
257
265
|
|
|
258
266
|
return p
|
|
259
267
|
}
|
|
268
|
+
|
|
269
|
+
const BigInt$ = Schema.transformOrFail(Data, Schema.BigIntFromSelf, {
|
|
270
|
+
strict: true,
|
|
271
|
+
decode: (data) => {
|
|
272
|
+
if ("int" in data) {
|
|
273
|
+
return ParseResult.succeed(data.int)
|
|
274
|
+
} else {
|
|
275
|
+
return ParseResult.fail(
|
|
276
|
+
new ParseResult.Unexpected(data, "expected IntData")
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
encode: (value) => ParseResult.succeed({ int: value })
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
export { BigInt$ as BigInt }
|
|
284
|
+
|
|
285
|
+
export const Int = Schema.transformOrFail(Data, Schema.Int, {
|
|
286
|
+
strict: true,
|
|
287
|
+
decode: (data) => {
|
|
288
|
+
if ("int" in data) {
|
|
289
|
+
return ParseResult.succeed(Number(data.int))
|
|
290
|
+
} else {
|
|
291
|
+
return ParseResult.fail(
|
|
292
|
+
new ParseResult.Unexpected(data, "expected IntData")
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
encode: (value) => {
|
|
297
|
+
if (value % 1.0 != 0) {
|
|
298
|
+
return ParseResult.fail(
|
|
299
|
+
new ParseResult.Unexpected(value, "not an integer")
|
|
300
|
+
)
|
|
301
|
+
} else {
|
|
302
|
+
return ParseResult.succeed({ int: BigInt(Math.round(value)) })
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
export const ByteArray = Schema.transformOrFail(
|
|
308
|
+
Data,
|
|
309
|
+
Schema.Uint8ArrayFromSelf,
|
|
310
|
+
{
|
|
311
|
+
strict: true,
|
|
312
|
+
decode: (data) => {
|
|
313
|
+
if ("bytes" in data) {
|
|
314
|
+
return ParseResult.succeed(data.bytes)
|
|
315
|
+
} else {
|
|
316
|
+
return ParseResult.fail(
|
|
317
|
+
new ParseResult.Unexpected(data, "expected ByteArrayData")
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
encode: (hex) => ParseResult.succeed({ bytes: hex })
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
export const Hex = Schema.transformOrFail(Data, Schema.String, {
|
|
326
|
+
strict: true,
|
|
327
|
+
decode: (data) => {
|
|
328
|
+
if ("bytes" in data) {
|
|
329
|
+
return ParseResult.succeed(Encoding.encodeHex(data.bytes))
|
|
330
|
+
} else {
|
|
331
|
+
return ParseResult.fail(
|
|
332
|
+
new ParseResult.Unexpected(data, "expected ByteArrayData")
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
encode: (hex) =>
|
|
337
|
+
Encoding.decodeHex(hex).pipe(
|
|
338
|
+
Effect.map((bs) => ({ bytes: bs })),
|
|
339
|
+
Effect.mapError(
|
|
340
|
+
(_e) => new ParseResult.Unexpected(hex, "invalid Hex string")
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
export const Option = <SomeType>(
|
|
346
|
+
someSchema: Schema.Schema<SomeType, Schema.Schema.Encoded<typeof Data>>
|
|
347
|
+
) =>
|
|
348
|
+
Schema.transformOrFail(Data, Schema.Option(someSchema), {
|
|
349
|
+
strict: true,
|
|
350
|
+
decode: (data) => {
|
|
351
|
+
if ("fields" in data) {
|
|
352
|
+
if (data.constructor == 0) {
|
|
353
|
+
if (data.fields.length < 1) {
|
|
354
|
+
return ParseResult.fail(
|
|
355
|
+
new ParseResult.Unexpected(
|
|
356
|
+
data,
|
|
357
|
+
"expected at least one field in ConstrData"
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return ParseResult.succeed({
|
|
363
|
+
_tag: "Some" as const,
|
|
364
|
+
value: data.fields[0]
|
|
365
|
+
})
|
|
366
|
+
} else if (data.constructor == 1) {
|
|
367
|
+
return ParseResult.succeed({ _tag: "None" as const })
|
|
368
|
+
} else {
|
|
369
|
+
return ParseResult.fail(
|
|
370
|
+
new ParseResult.Unexpected(
|
|
371
|
+
data,
|
|
372
|
+
"expected ConstrData with tag 0 or 1"
|
|
373
|
+
)
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
} else {
|
|
377
|
+
return ParseResult.fail(
|
|
378
|
+
new ParseResult.Unexpected(data, "expected ConstrData")
|
|
379
|
+
)
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
encode: (value) => {
|
|
383
|
+
if (value._tag == "None") {
|
|
384
|
+
return ParseResult.succeed({ constructor: 1, fields: [] })
|
|
385
|
+
} else {
|
|
386
|
+
return ParseResult.succeed({ constructor: 0, fields: [value.value] })
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
const String$ = Schema.transformOrFail(Data, Schema.String, {
|
|
392
|
+
strict: true,
|
|
393
|
+
decode: (data) => {
|
|
394
|
+
if ("bytes" in data) {
|
|
395
|
+
return decodeUtf8(data.bytes).pipe(
|
|
396
|
+
Effect.mapError((e) => {
|
|
397
|
+
return new ParseResult.Unexpected(data.bytes, e.message)
|
|
398
|
+
})
|
|
399
|
+
)
|
|
400
|
+
} else {
|
|
401
|
+
return ParseResult.fail(
|
|
402
|
+
new ParseResult.Unexpected(data, "expected ByteArrayData")
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
encode: (s) => ParseResult.succeed({ bytes: encodeUtf8(s) })
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
export { String$ as String }
|
|
410
|
+
|
|
411
|
+
const Array$ = <ItemType>(
|
|
412
|
+
itemSchema: Schema.Schema<ItemType, Schema.Schema.Encoded<typeof Data>>
|
|
413
|
+
) =>
|
|
414
|
+
Schema.transformOrFail(Data, Schema.Array(itemSchema), {
|
|
415
|
+
strict: true,
|
|
416
|
+
decode: (data) => {
|
|
417
|
+
if ("list" in data) {
|
|
418
|
+
return ParseResult.succeed(data.list)
|
|
419
|
+
} else {
|
|
420
|
+
return ParseResult.fail(
|
|
421
|
+
new ParseResult.Unexpected(data, "expected ListData")
|
|
422
|
+
)
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
encode: (items) => ParseResult.succeed({ list: items })
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
export { Array$ as Array }
|
|
429
|
+
|
|
430
|
+
export const PairArray = <KeyType, ValueType>(
|
|
431
|
+
keySchema: Schema.Schema<KeyType, Schema.Schema.Encoded<typeof Data>>,
|
|
432
|
+
valueSchema: Schema.Schema<ValueType, Schema.Schema.Encoded<typeof Data>>
|
|
433
|
+
) =>
|
|
434
|
+
Schema.transformOrFail(
|
|
435
|
+
Data,
|
|
436
|
+
Schema.Array(Schema.Tuple(keySchema, valueSchema)),
|
|
437
|
+
{
|
|
438
|
+
strict: true,
|
|
439
|
+
decode: (data) => {
|
|
440
|
+
if ("map" in data) {
|
|
441
|
+
return ParseResult.succeed(
|
|
442
|
+
data.map.map(({ k, v }) => [k, v] as const)
|
|
443
|
+
)
|
|
444
|
+
} else {
|
|
445
|
+
return ParseResult.fail(
|
|
446
|
+
new ParseResult.Unexpected(data, "expected MapData")
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
encode: (pairs) =>
|
|
451
|
+
ParseResult.succeed({ map: pairs.map(([k, v]) => ({ k, v })) })
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
export const Struct = <
|
|
456
|
+
FieldTypes extends { [fieldName: string]: Schema.Schema<any, Data> }
|
|
457
|
+
>(
|
|
458
|
+
fields: FieldTypes
|
|
459
|
+
) =>
|
|
460
|
+
Schema.transformOrFail(Data, Schema.Struct(fields), {
|
|
461
|
+
strict: true,
|
|
462
|
+
decode: (data) => {
|
|
463
|
+
if ("list" in data) {
|
|
464
|
+
return Effect.all(
|
|
465
|
+
Object.entries(fields).map(([fieldName], i) => {
|
|
466
|
+
if (i >= data.list.length) {
|
|
467
|
+
return Effect.fail(
|
|
468
|
+
new ParseResult.Unexpected(
|
|
469
|
+
data,
|
|
470
|
+
`expected at least ${i + 1} entries in ListData`
|
|
471
|
+
)
|
|
472
|
+
)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const itemData = data.list[i]
|
|
476
|
+
|
|
477
|
+
return Effect.succeed([fieldName, itemData] as [string, Data])
|
|
478
|
+
})
|
|
479
|
+
).pipe(Effect.map(Object.fromEntries))
|
|
480
|
+
} else {
|
|
481
|
+
return ParseResult.fail(
|
|
482
|
+
new ParseResult.Unexpected(data, "expected ListData")
|
|
483
|
+
)
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
encode: (fields) => ParseResult.succeed({ list: Object.values(fields) })
|
|
487
|
+
})
|
|
488
|
+
|
|
489
|
+
export const EnumVariant = <
|
|
490
|
+
FieldTypes extends { [fieldName: string]: Schema.Schema<any, Data> }
|
|
491
|
+
>(
|
|
492
|
+
tag: number | bigint,
|
|
493
|
+
fields: FieldTypes
|
|
494
|
+
) =>
|
|
495
|
+
Schema.transformOrFail(Data, Schema.Struct(fields), {
|
|
496
|
+
strict: true,
|
|
497
|
+
decode: (data) => {
|
|
498
|
+
if ("fields" in data) {
|
|
499
|
+
if (data.constructor != Number(tag)) {
|
|
500
|
+
return ParseResult.fail(
|
|
501
|
+
new ParseResult.Unexpected(
|
|
502
|
+
data,
|
|
503
|
+
`expected ConstrData with constructor tag ${tag}`
|
|
504
|
+
)
|
|
505
|
+
)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return Effect.all(
|
|
509
|
+
Object.entries(fields).map(([fieldName], i) => {
|
|
510
|
+
if (i >= data.fields.length) {
|
|
511
|
+
return Effect.fail(
|
|
512
|
+
new ParseResult.Unexpected(
|
|
513
|
+
data,
|
|
514
|
+
`expected at least ${i + 1} entries in ConstrData`
|
|
515
|
+
)
|
|
516
|
+
)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const itemData = data.fields[i]
|
|
520
|
+
|
|
521
|
+
return Effect.succeed([fieldName, itemData] as [string, Data])
|
|
522
|
+
})
|
|
523
|
+
).pipe(Effect.map(Object.fromEntries))
|
|
524
|
+
} else {
|
|
525
|
+
return ParseResult.fail(
|
|
526
|
+
new ParseResult.Unexpected(data, "expected ConstrData")
|
|
527
|
+
)
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
encode: (fields) =>
|
|
531
|
+
ParseResult.succeed({
|
|
532
|
+
constructor: Number(tag),
|
|
533
|
+
fields: Object.values(fields)
|
|
534
|
+
})
|
|
535
|
+
})
|
|
536
|
+
|
|
537
|
+
type EnumUnionTypeInternal<
|
|
538
|
+
VariantName,
|
|
539
|
+
VariantTypes extends {
|
|
540
|
+
[variantName: string]: { [fieldName: string]: Schema.Schema<any, Data> }
|
|
541
|
+
}
|
|
542
|
+
> = VariantName extends string
|
|
543
|
+
? { _tag: VariantName } & {
|
|
544
|
+
[FieldName in keyof VariantTypes[VariantName]]: Schema.Schema.Type<
|
|
545
|
+
VariantTypes[VariantName][FieldName]
|
|
546
|
+
>
|
|
547
|
+
}
|
|
548
|
+
: never
|
|
549
|
+
type EnumUnionType<
|
|
550
|
+
VariantTypes extends {
|
|
551
|
+
[variantName: string]: { [fieldName: string]: Schema.Schema<any, Data> }
|
|
552
|
+
}
|
|
553
|
+
> = EnumUnionTypeInternal<keyof VariantTypes, VariantTypes>
|
|
554
|
+
type EnumUnionDataInternal<
|
|
555
|
+
VariantName,
|
|
556
|
+
VariantTypes extends {
|
|
557
|
+
[variantName: string]: { [fieldName: string]: Schema.Schema<any, Data> }
|
|
558
|
+
}
|
|
559
|
+
> = VariantName extends string
|
|
560
|
+
? { _tag: VariantName } & {
|
|
561
|
+
[FieldName in keyof VariantTypes[VariantName]]: Data
|
|
562
|
+
}
|
|
563
|
+
: never
|
|
564
|
+
type EnumUnionData<
|
|
565
|
+
VariantTypes extends {
|
|
566
|
+
[variantName: string]: { [fieldName: string]: Schema.Schema<any, Data> }
|
|
567
|
+
}
|
|
568
|
+
> = EnumUnionDataInternal<keyof VariantTypes, VariantTypes>
|
|
569
|
+
|
|
570
|
+
export const Enum = <
|
|
571
|
+
VariantTypes extends {
|
|
572
|
+
[variantName: string]: { [fieldName: string]: Schema.Schema<any, Data> }
|
|
573
|
+
}
|
|
574
|
+
>(
|
|
575
|
+
variants: VariantTypes
|
|
576
|
+
): Schema.Schema<EnumUnionType<VariantTypes>, Data> =>
|
|
577
|
+
Schema.transformOrFail(
|
|
578
|
+
Data,
|
|
579
|
+
Schema.Union(
|
|
580
|
+
...Object.entries(variants).map(
|
|
581
|
+
([variantName, fieldSchemas]) =>
|
|
582
|
+
Schema.TaggedStruct(
|
|
583
|
+
variantName,
|
|
584
|
+
fieldSchemas
|
|
585
|
+
) as unknown as Schema.Schema<
|
|
586
|
+
EnumUnionType<VariantTypes>,
|
|
587
|
+
EnumUnionData<VariantTypes>
|
|
588
|
+
>
|
|
589
|
+
)
|
|
590
|
+
),
|
|
591
|
+
{
|
|
592
|
+
strict: true,
|
|
593
|
+
decode: (
|
|
594
|
+
data
|
|
595
|
+
): Effect.Effect<EnumUnionData<VariantTypes>, ParseResult.ParseIssue> => {
|
|
596
|
+
if ("fields" in data) {
|
|
597
|
+
const tag = data.constructor
|
|
598
|
+
|
|
599
|
+
const variantName: keyof VariantTypes = Object.keys(variants)[tag]
|
|
600
|
+
|
|
601
|
+
if ((variantName as string | undefined) == undefined) {
|
|
602
|
+
return ParseResult.fail(
|
|
603
|
+
new ParseResult.Unexpected(
|
|
604
|
+
data,
|
|
605
|
+
`no variant defined for tag ${tag}`
|
|
606
|
+
)
|
|
607
|
+
)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const fields = variants[variantName]
|
|
611
|
+
|
|
612
|
+
return Effect.all(
|
|
613
|
+
Object.entries(fields).map(([fieldName], i) => {
|
|
614
|
+
if (i >= data.fields.length) {
|
|
615
|
+
return Effect.fail(
|
|
616
|
+
new ParseResult.Unexpected(
|
|
617
|
+
data,
|
|
618
|
+
`expected at least ${i + 1} entries in ConstrData of ${variantName as unknown as string}`
|
|
619
|
+
)
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const itemData = data.fields[i]
|
|
624
|
+
|
|
625
|
+
return Effect.succeed([fieldName, itemData] as [string, Data])
|
|
626
|
+
})
|
|
627
|
+
).pipe(
|
|
628
|
+
Effect.map(
|
|
629
|
+
(entries) =>
|
|
630
|
+
({
|
|
631
|
+
_tag: variantName,
|
|
632
|
+
...Object.fromEntries(entries)
|
|
633
|
+
}) as unknown as EnumUnionData<VariantTypes>
|
|
634
|
+
)
|
|
635
|
+
)
|
|
636
|
+
} else {
|
|
637
|
+
return ParseResult.fail(
|
|
638
|
+
new ParseResult.Unexpected(data, "expected ConstrData")
|
|
639
|
+
)
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
encode: (value) => {
|
|
643
|
+
const variantName = value._tag
|
|
644
|
+
|
|
645
|
+
const tag = Object.keys(variants).indexOf(
|
|
646
|
+
variantName as unknown as string
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
return ParseResult.succeed({
|
|
650
|
+
constructor: tag,
|
|
651
|
+
fields: Object.entries(value)
|
|
652
|
+
.filter(([key]) => key != "_tag")
|
|
653
|
+
.map(([, field]) => field) as Data[]
|
|
654
|
+
})
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
)
|
package/src/Uplc/index.ts
CHANGED
package/src/index.ts
CHANGED
package/src/Address.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Schema } from "effect"
|
|
2
|
-
import * as Bech32 from "./Bech32.js"
|
|
3
|
-
|
|
4
|
-
export function isValid(addr: string): boolean {
|
|
5
|
-
if (addr.startsWith("addr1") || addr.startsWith("addr_test1")) {
|
|
6
|
-
return Bech32.isValid(addr)
|
|
7
|
-
}
|
|
8
|
-
// TODO: validate Byron format
|
|
9
|
-
|
|
10
|
-
return false
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const Address = Schema.String.pipe(
|
|
14
|
-
Schema.filter((addr: string) => {
|
|
15
|
-
return isValid(addr) || "Invalid Cardano Address"
|
|
16
|
-
}),
|
|
17
|
-
Schema.brand("Address")
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
export type Address = Schema.Schema.Type<typeof Address>
|