@xrplkit/xls26 2.3.1 → 2.5.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/package.json +1 -4
- package/readme.md +44 -54
- package/xls26.js +161 -101
package/package.json
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xrplkit/xls26",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"main": "xls26.js",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@xrplkit/toml": "1.0.0"
|
|
8
8
|
},
|
|
9
|
-
"publishConfig": {
|
|
10
|
-
"access": "public"
|
|
11
|
-
},
|
|
12
9
|
"keywords": [
|
|
13
10
|
"xrpl",
|
|
14
11
|
"xls-26",
|
package/readme.md
CHANGED
|
@@ -22,29 +22,27 @@ console.log(xls26Data)
|
|
|
22
22
|
|
|
23
23
|
```toml
|
|
24
24
|
[[ISSUERS]]
|
|
25
|
-
address = "
|
|
26
|
-
name = "
|
|
27
|
-
|
|
28
|
-
[[ISSUERS.WEBLINKS]]
|
|
29
|
-
url = "https://aesthetes.art"
|
|
30
|
-
type = "info"
|
|
31
|
-
title = "Official Website"
|
|
32
|
-
|
|
33
|
-
[[ISSUERS.WEBLINKS]]
|
|
34
|
-
url = "https://twitter.com/aesthetes_art"
|
|
35
|
-
type = "socialmedia"
|
|
25
|
+
address = "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De"
|
|
26
|
+
name = "Ripple"
|
|
27
|
+
desc = "We're building the Internet of Value."
|
|
36
28
|
|
|
37
29
|
[[TOKENS]]
|
|
38
|
-
issuer = "
|
|
39
|
-
currency = "
|
|
40
|
-
name = "
|
|
41
|
-
desc = "
|
|
42
|
-
icon = "https://
|
|
43
|
-
asset_class = "
|
|
30
|
+
issuer = "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De"
|
|
31
|
+
currency = "RLUSD"
|
|
32
|
+
name = "Ripple USD"
|
|
33
|
+
desc = "Ripple USD (RLUSD) is natively issued on the XRP Ledger and Ethereum blockchains and is enabled with a number of features to ensure strict adherence to compliance standards, flexibility for developers, and security for holders."
|
|
34
|
+
icon = "https://ripple.com/assets/rlusd-logo.png"
|
|
35
|
+
asset_class = "rwa"
|
|
36
|
+
asset_subclass = "stablecoin"
|
|
37
|
+
|
|
38
|
+
[[TOKENS.URLS]]
|
|
39
|
+
url = "https://ripple.com"
|
|
40
|
+
type = "website"
|
|
41
|
+
title = "Official Website"
|
|
44
42
|
|
|
45
|
-
[[TOKENS.
|
|
46
|
-
url = "https://
|
|
47
|
-
type = "
|
|
43
|
+
[[TOKENS.URLS]]
|
|
44
|
+
url = "https://x.com/ripple"
|
|
45
|
+
type = "social"
|
|
48
46
|
```
|
|
49
47
|
|
|
50
48
|
|
|
@@ -52,40 +50,32 @@ type = "community"
|
|
|
52
50
|
|
|
53
51
|
```javascript
|
|
54
52
|
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
tokens: [
|
|
53
|
+
issuers: [
|
|
54
|
+
{
|
|
55
|
+
address: 'rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De',
|
|
56
|
+
name: 'Ripple',
|
|
57
|
+
desc: "We're building the Internet of Value."
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
tokens: [
|
|
61
|
+
{
|
|
62
|
+
currency: 'RLUSD',
|
|
63
|
+
issuer: 'rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De',
|
|
64
|
+
name: 'Ripple USD',
|
|
65
|
+
desc: 'Ripple USD (RLUSD) is natively issued on the XRP Ledger and Ethereum blockchains and is enabled with a number of features to ensure strict adherence to compliance standards, flexibility for developers, and security for holders.',
|
|
66
|
+
icon: 'https://ripple.com/assets/rlusd-logo.png',
|
|
67
|
+
asset_class: 'rwa',
|
|
68
|
+
asset_subclass: 'stablecoin',
|
|
69
|
+
urls: [
|
|
73
70
|
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
type: 'community'
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
issues: []
|
|
71
|
+
url: 'https://ripple.com',
|
|
72
|
+
type: 'website',
|
|
73
|
+
title: 'Official Website'
|
|
74
|
+
},
|
|
75
|
+
{ url: 'https://x.com/ripple', type: 'social' }
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
issues: []
|
|
89
80
|
}
|
|
90
|
-
|
|
91
81
|
```
|
package/xls26.js
CHANGED
|
@@ -1,19 +1,50 @@
|
|
|
1
1
|
// The XLS-26 standard adds additional asset metadata fields to the existing xrp-ledger.toml standard,
|
|
2
2
|
// https://github.com/XRPLF/XRPL-Standards/discussions/71
|
|
3
3
|
// This package provides an implementation for a parser according to this standard.
|
|
4
|
+
// Version 5 from 2025-06-06.
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
import { parse as parseToml } from '@xrplkit/toml'
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
9
|
+
const validUrlRegex = /^(https?)|(ipfs):\/\/.*$/
|
|
10
|
+
const validUrlTypes = {
|
|
11
|
+
website: 'website',
|
|
12
|
+
social: 'social',
|
|
13
|
+
docs: 'docs',
|
|
14
|
+
other: 'other',
|
|
15
|
+
info: 'website',
|
|
16
|
+
socialmedia: 'social',
|
|
17
|
+
community: 'social',
|
|
18
|
+
support: 'website',
|
|
19
|
+
whitepaper: 'docs',
|
|
20
|
+
certificate: 'docs',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const validAssetClasses = [
|
|
24
|
+
'rwa',
|
|
25
|
+
'memes',
|
|
26
|
+
'wrapped',
|
|
27
|
+
'gaming',
|
|
28
|
+
'defi',
|
|
29
|
+
'other'
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const validAssetSubClasses = [
|
|
33
|
+
'stablecoin',
|
|
34
|
+
'commodity',
|
|
35
|
+
'real_estate',
|
|
36
|
+
'private_credit',
|
|
37
|
+
'equity',
|
|
38
|
+
'treasury',
|
|
39
|
+
'other'
|
|
15
40
|
]
|
|
16
41
|
|
|
42
|
+
const legacyAssetClasses = {
|
|
43
|
+
fiat: { asset_class: 'rwa', asset_subclass: 'stablecoin' },
|
|
44
|
+
commodity: { asset_class: 'rwa', asset_subclass: 'commodity' },
|
|
45
|
+
equity: { asset_class: 'rwa', asset_subclass: 'equity' }
|
|
46
|
+
}
|
|
47
|
+
|
|
17
48
|
const validAdvisoryTypes = [
|
|
18
49
|
'scam',
|
|
19
50
|
'spam',
|
|
@@ -22,17 +53,10 @@ const validAdvisoryTypes = [
|
|
|
22
53
|
'hijacked'
|
|
23
54
|
]
|
|
24
55
|
|
|
25
|
-
const validAssetClasses = [
|
|
26
|
-
'fiat',
|
|
27
|
-
'commodity',
|
|
28
|
-
'equity',
|
|
29
|
-
'cryptocurrency'
|
|
30
|
-
]
|
|
31
|
-
|
|
32
56
|
const issuerFields = [
|
|
33
57
|
{
|
|
34
58
|
key: 'address',
|
|
35
|
-
|
|
59
|
+
required: true,
|
|
36
60
|
validate: v => {
|
|
37
61
|
if(!/^[rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz]{25,35}$/.test(v))
|
|
38
62
|
throw 'is not a valid XRPL address'
|
|
@@ -42,40 +66,40 @@ const issuerFields = [
|
|
|
42
66
|
key: 'name',
|
|
43
67
|
validate: v => {
|
|
44
68
|
if(typeof v !== 'string' || v.length === 0)
|
|
45
|
-
throw '
|
|
69
|
+
throw 'must be a non empty string'
|
|
46
70
|
}
|
|
47
71
|
},
|
|
48
72
|
{
|
|
49
|
-
key: '
|
|
50
|
-
alternativeKeys: ['
|
|
73
|
+
key: 'desc',
|
|
74
|
+
alternativeKeys: ['description'],
|
|
51
75
|
validate: v => {
|
|
52
76
|
if(typeof v !== 'string' || v.length === 0)
|
|
53
|
-
throw '
|
|
77
|
+
throw 'must be a non empty string'
|
|
54
78
|
}
|
|
55
79
|
},
|
|
56
80
|
{
|
|
57
81
|
key: 'domain',
|
|
58
82
|
validate: v => {
|
|
59
83
|
if(typeof v !== 'string' || v.length === 0)
|
|
60
|
-
throw '
|
|
84
|
+
throw 'must be a non empty string'
|
|
61
85
|
}
|
|
62
86
|
},
|
|
63
87
|
{
|
|
64
88
|
key: 'icon',
|
|
65
89
|
alternativeKeys: ['avatar'],
|
|
66
90
|
validate: v => {
|
|
67
|
-
if(
|
|
68
|
-
throw '
|
|
91
|
+
if(!validUrlRegex.test(v))
|
|
92
|
+
throw 'must be a valid URL that starts with "http" or "ipfs"'
|
|
69
93
|
}
|
|
70
94
|
},
|
|
71
95
|
{
|
|
72
96
|
key: 'trust_level',
|
|
73
97
|
validate: v => {
|
|
74
98
|
if(v !== parseInt(v))
|
|
75
|
-
throw '
|
|
99
|
+
throw 'must be a integer'
|
|
76
100
|
|
|
77
101
|
if(v < 0 || v > 3)
|
|
78
|
-
throw '
|
|
102
|
+
throw 'must be between 0 and 3'
|
|
79
103
|
}
|
|
80
104
|
}
|
|
81
105
|
]
|
|
@@ -83,7 +107,8 @@ const issuerFields = [
|
|
|
83
107
|
const tokenFields = [
|
|
84
108
|
{
|
|
85
109
|
key: 'currency',
|
|
86
|
-
|
|
110
|
+
alternativeKeys: ['code'],
|
|
111
|
+
required: true,
|
|
87
112
|
validate: v => {
|
|
88
113
|
if(typeof v !== 'string' && v.length < 3)
|
|
89
114
|
throw 'is not a valid XRPL currency code'
|
|
@@ -91,7 +116,7 @@ const tokenFields = [
|
|
|
91
116
|
},
|
|
92
117
|
{
|
|
93
118
|
key: 'issuer',
|
|
94
|
-
|
|
119
|
+
required: true,
|
|
95
120
|
validate: v => {
|
|
96
121
|
if(!/^[rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz]{25,35}$/.test(v))
|
|
97
122
|
throw 'is not a valid XRPL address'
|
|
@@ -101,65 +126,75 @@ const tokenFields = [
|
|
|
101
126
|
key: 'name',
|
|
102
127
|
validate: v => {
|
|
103
128
|
if(typeof v !== 'string' || v.length === 0)
|
|
104
|
-
throw '
|
|
129
|
+
throw 'must be a non empty string'
|
|
105
130
|
}
|
|
106
131
|
},
|
|
107
132
|
{
|
|
108
|
-
key: '
|
|
109
|
-
alternativeKeys: ['
|
|
133
|
+
key: 'desc',
|
|
134
|
+
alternativeKeys: ['description'],
|
|
110
135
|
validate: v => {
|
|
111
136
|
if(typeof v !== 'string' || v.length === 0)
|
|
112
|
-
throw '
|
|
137
|
+
throw 'must be a non empty string'
|
|
113
138
|
}
|
|
114
139
|
},
|
|
115
140
|
{
|
|
116
141
|
key: 'icon',
|
|
117
142
|
alternativeKeys: ['avatar'],
|
|
118
143
|
validate: v => {
|
|
119
|
-
if(
|
|
120
|
-
throw '
|
|
144
|
+
if(!validUrlRegex.test(v))
|
|
145
|
+
throw 'must be a valid URL starting with "http" or "ipfs"'
|
|
121
146
|
}
|
|
122
147
|
},
|
|
123
148
|
{
|
|
124
149
|
key: 'trust_level',
|
|
125
150
|
validate: v => {
|
|
126
151
|
if(v !== parseInt(v))
|
|
127
|
-
throw '
|
|
152
|
+
throw 'must be a integer'
|
|
128
153
|
|
|
129
154
|
if(v < 0 || v > 3)
|
|
130
|
-
throw '
|
|
155
|
+
throw 'must be between 0 and 3'
|
|
131
156
|
}
|
|
132
157
|
},
|
|
133
158
|
{
|
|
134
159
|
key: 'asset_class',
|
|
135
160
|
validate: v => {
|
|
136
|
-
if(!validAssetClasses.includes(v))
|
|
137
|
-
throw `
|
|
161
|
+
if(!legacyAssetClasses[v] && !validAssetClasses.includes(v))
|
|
162
|
+
throw `must be one of: ${validAssetClasses.join(', ')}`
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
key: 'asset_subclass',
|
|
167
|
+
validate: v => {
|
|
168
|
+
if(!validAssetSubClasses.includes(v))
|
|
169
|
+
throw `must be one of: ${validAssetSubClasses.join(', ')}`
|
|
138
170
|
}
|
|
139
171
|
}
|
|
140
172
|
]
|
|
141
173
|
|
|
142
|
-
const
|
|
174
|
+
const urlFields = [
|
|
143
175
|
{
|
|
144
176
|
key: 'url',
|
|
145
|
-
|
|
177
|
+
required: true,
|
|
146
178
|
validate: v => {
|
|
147
|
-
if(
|
|
148
|
-
throw '
|
|
179
|
+
if(!validUrlRegex.test(v))
|
|
180
|
+
throw 'must be a valid URL starting with "http" or "ipfs"'
|
|
149
181
|
}
|
|
150
182
|
},
|
|
151
183
|
{
|
|
152
184
|
key: 'type',
|
|
153
185
|
validate: v => {
|
|
154
|
-
if(!
|
|
155
|
-
throw `
|
|
186
|
+
if(!validUrlTypes[v])
|
|
187
|
+
throw `must be one of: ${Array.from(new Set(Object.values(validUrlTypes))).join(', ')}`
|
|
188
|
+
},
|
|
189
|
+
transform: v => {
|
|
190
|
+
return validUrlTypes[v]
|
|
156
191
|
}
|
|
157
192
|
},
|
|
158
193
|
{
|
|
159
194
|
key: 'title',
|
|
160
195
|
validate: v => {
|
|
161
196
|
if(typeof v !== 'string' || v.length === 0)
|
|
162
|
-
throw '
|
|
197
|
+
throw 'must be a non empty string'
|
|
163
198
|
}
|
|
164
199
|
},
|
|
165
200
|
]
|
|
@@ -167,7 +202,7 @@ const weblinkFields = [
|
|
|
167
202
|
const advisoryFields = [
|
|
168
203
|
{
|
|
169
204
|
key: 'address',
|
|
170
|
-
|
|
205
|
+
required: true,
|
|
171
206
|
validate: v => {
|
|
172
207
|
if(!/^[rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz]{25,35}$/.test(v))
|
|
173
208
|
throw 'is not a valid XRPL address'
|
|
@@ -177,7 +212,7 @@ const advisoryFields = [
|
|
|
177
212
|
key: 'type',
|
|
178
213
|
validate: v => {
|
|
179
214
|
if(!validAdvisoryTypes.includes(v))
|
|
180
|
-
throw `
|
|
215
|
+
throw `must be one of: ${validAdvisoryTypes.join(', ')}`
|
|
181
216
|
}
|
|
182
217
|
},
|
|
183
218
|
{
|
|
@@ -185,7 +220,7 @@ const advisoryFields = [
|
|
|
185
220
|
alternativeKeys: ['desc'],
|
|
186
221
|
validate: v => {
|
|
187
222
|
if(typeof v !== 'string' || v.length === 0)
|
|
188
|
-
throw '
|
|
223
|
+
throw 'must be a non empty string'
|
|
189
224
|
}
|
|
190
225
|
}
|
|
191
226
|
]
|
|
@@ -203,71 +238,67 @@ export function parse(str){
|
|
|
203
238
|
let advisories = []
|
|
204
239
|
|
|
205
240
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
let { valid, parsed: issuer, issues: issuerIssues } = parseStanza(stanza, issuerFields)
|
|
241
|
+
for(let stanza of (toml.ISSUERS || toml.ACCOUNTS || [])){
|
|
242
|
+
let { valid, parsed: issuer, issues: issuerIssues } = parseStanza(stanza, issuerFields)
|
|
209
243
|
|
|
210
|
-
|
|
211
|
-
|
|
244
|
+
issues.push(
|
|
245
|
+
...issuerIssues.map(
|
|
246
|
+
issue => `[[ISSUERS]] ${issue}`
|
|
247
|
+
)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if(valid)
|
|
251
|
+
issuers.push(issuer)
|
|
252
|
+
else
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
for(let substanza of (stanza.URLS || stanza.WEBLINKS || [])){
|
|
256
|
+
let { valid, parsed: url, issues: urlIssues } = parseStanza(substanza, urlFields)
|
|
257
|
+
|
|
258
|
+
if(valid){
|
|
259
|
+
issuer.urls = [
|
|
260
|
+
...(issuer.urls || []),
|
|
261
|
+
url
|
|
262
|
+
]
|
|
263
|
+
}
|
|
212
264
|
|
|
213
265
|
issues.push(
|
|
214
|
-
...
|
|
215
|
-
issue => `[[ISSUERS]] ${issue}`
|
|
266
|
+
...urlIssues.map(
|
|
267
|
+
issue => `[[ISSUERS.URLS]] ${issue}`
|
|
216
268
|
)
|
|
217
269
|
)
|
|
218
|
-
|
|
219
|
-
if(valid && stanza.WEBLINKS){
|
|
220
|
-
for(let substanza of stanza.WEBLINKS){
|
|
221
|
-
let { valid, parsed: weblink, issues: weblinkIssues } = parseStanza(substanza, weblinkFields)
|
|
222
|
-
|
|
223
|
-
if(valid){
|
|
224
|
-
issuer.weblinks = [
|
|
225
|
-
...(issuer.weblinks || []),
|
|
226
|
-
weblink
|
|
227
|
-
]
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
issues.push(
|
|
231
|
-
...weblinkIssues.map(
|
|
232
|
-
issue => `[[WEBLINK]] ${issue}`
|
|
233
|
-
)
|
|
234
|
-
)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
270
|
}
|
|
238
271
|
}
|
|
239
272
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
let { valid, parsed: token, issues: tokenIssues } = parseStanza(stanza, tokenFields)
|
|
273
|
+
for(let stanza of (toml.TOKENS || toml.CURRENCIES || [])){
|
|
274
|
+
let { valid, parsed: token, issues: tokenIssues } = parseStanza(stanza, tokenFields)
|
|
243
275
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
issues.push(
|
|
248
|
-
...tokenIssues.map(
|
|
249
|
-
issue => `[[TOKENS]] ${issue}`
|
|
250
|
-
)
|
|
276
|
+
issues.push(
|
|
277
|
+
...tokenIssues.map(
|
|
278
|
+
issue => `[[TOKENS]] ${issue}`
|
|
251
279
|
)
|
|
280
|
+
)
|
|
252
281
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
issue => `[[WEBLINK]] ${issue}`
|
|
267
|
-
)
|
|
268
|
-
)
|
|
269
|
-
}
|
|
282
|
+
if(valid)
|
|
283
|
+
tokens.push(token)
|
|
284
|
+
else
|
|
285
|
+
continue
|
|
286
|
+
|
|
287
|
+
for(let substanza of (stanza.URLS || stanza.WEBLINKS || [])){
|
|
288
|
+
let { valid, parsed: url, issues: urlIssues } = parseStanza(substanza, urlFields)
|
|
289
|
+
|
|
290
|
+
if(valid){
|
|
291
|
+
token.urls = [
|
|
292
|
+
...(token.urls || []),
|
|
293
|
+
url
|
|
294
|
+
]
|
|
270
295
|
}
|
|
296
|
+
|
|
297
|
+
issues.push(
|
|
298
|
+
...urlIssues.map(
|
|
299
|
+
issue => `[[TOKENS.URLS]] ${issue}`
|
|
300
|
+
)
|
|
301
|
+
)
|
|
271
302
|
}
|
|
272
303
|
}
|
|
273
304
|
|
|
@@ -286,6 +317,32 @@ export function parse(str){
|
|
|
286
317
|
}
|
|
287
318
|
}
|
|
288
319
|
|
|
320
|
+
// Issuer URLs have been dropped since Version 5
|
|
321
|
+
// Issuer URLs now get mapped to respective tokens
|
|
322
|
+
|
|
323
|
+
for(let issuer of issuers){
|
|
324
|
+
if(!issuer.urls)
|
|
325
|
+
continue
|
|
326
|
+
|
|
327
|
+
for(let token of tokens){
|
|
328
|
+
if(token.issuer !== issuer.address)
|
|
329
|
+
continue
|
|
330
|
+
|
|
331
|
+
token.urls = [
|
|
332
|
+
...issuer.urls,
|
|
333
|
+
...(token.urls || [])
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
delete issuer.urls
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
for(let token of tokens){
|
|
341
|
+
if(!legacyAssetClasses[token.asset_class])
|
|
342
|
+
continue
|
|
343
|
+
|
|
344
|
+
Object.assign(token, legacyAssetClasses[token.asset_class])
|
|
345
|
+
}
|
|
289
346
|
|
|
290
347
|
return {
|
|
291
348
|
issuers,
|
|
@@ -300,7 +357,7 @@ function parseStanza(stanza, schemas){
|
|
|
300
357
|
let issues = []
|
|
301
358
|
let valid = true
|
|
302
359
|
|
|
303
|
-
for(let { key, alternativeKeys,
|
|
360
|
+
for(let { key, alternativeKeys, required, validate, transform } of schemas){
|
|
304
361
|
let keys = [key]
|
|
305
362
|
|
|
306
363
|
if(alternativeKeys)
|
|
@@ -321,11 +378,14 @@ function parseStanza(stanza, schemas){
|
|
|
321
378
|
}
|
|
322
379
|
}
|
|
323
380
|
|
|
381
|
+
if(transform)
|
|
382
|
+
value = transform(value)
|
|
383
|
+
|
|
324
384
|
parsed[key] = value
|
|
325
385
|
break
|
|
326
386
|
}
|
|
327
387
|
|
|
328
|
-
if(
|
|
388
|
+
if(required && parsed[key] === undefined){
|
|
329
389
|
issues.push(`${key} field missing: skipping stanza`)
|
|
330
390
|
valid = false
|
|
331
391
|
}
|