xml-toolkit 1.0.61 → 1.1.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/README.md +35 -45
- package/index.js +12 -6
- package/lib/XMLMarshaller.js +1 -1
- package/lib/XMLParser.js +42 -13
- package/lib/XMLReader.js +44 -0
- package/lib/XMLSchema.js +11 -0
- package/lib/XMLSchemaBuiltIn.js +20 -5
- package/lib/XMLSchemaXml.js +0 -1
- package/lib/XMLSchemata.js +94 -11
- package/lib/XSAnyType.js +98 -0
- package/lib/simple/DT7.js +248 -0
- package/lib/simple/XSSimpleType.js +259 -0
- package/lib/simple/XSSimpleTypeBoolean.js +91 -0
- package/lib/simple/XSSimpleTypeDT.js +96 -0
- package/lib/simple/XSSimpleTypeDecimal.js +130 -0
- package/lib/simple/XSSimpleTypeFloatingPoint.js +80 -0
- package/lib/simple/XSSimpleTypeInteger.js +72 -0
- package/lib/simple/XSSimpleTypeQName.js +24 -0
- package/lib/validation/Match.js +54 -0
- package/lib/validation/MatchAll.js +33 -0
- package/lib/validation/MatchAny.js +15 -0
- package/lib/validation/MatchChoice.js +74 -0
- package/lib/validation/MatchElement.js +45 -0
- package/lib/validation/MatchSequence.js +84 -0
- package/lib/validation/Occurable.js +88 -0
- package/lib/validation/XMLValidationState.js +169 -0
- package/lib/validation/XMLValidatior.js +38 -0
- package/lib/xml.xsd +1 -1
- package/package.json +1 -1
- package/lib/XSSimpleType.js +0 -329
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
const MIN_LENGTH = 10
|
|
2
|
+
const CH_PERIOD = '.'.charCodeAt (0)
|
|
3
|
+
const CH_COLON = ':'.charCodeAt (0)
|
|
4
|
+
const CH_MINUS = '-'.charCodeAt (0)
|
|
5
|
+
const CH_PLUS = '+'.charCodeAt (0)
|
|
6
|
+
const CH_T = 'T'.charCodeAt (0)
|
|
7
|
+
const CH_0 = '0'.charCodeAt (0)
|
|
8
|
+
const CH_9 = '9'.charCodeAt (0)
|
|
9
|
+
|
|
10
|
+
const tzCache = new Set (['Z', '+14:00', '-14:00'])
|
|
11
|
+
|
|
12
|
+
class DT7 {
|
|
13
|
+
|
|
14
|
+
constructor (src) {
|
|
15
|
+
|
|
16
|
+
const t = typeof src; if (t !== 'string') throw Error (`The Seven-property Date Time Model can only be constructed from a string, not a(n) ${t}`)
|
|
17
|
+
|
|
18
|
+
const {length} = src; if (length < MIN_LENGTH) throw Error (`${length} chars found, at least ${MIN_LENGTH} required`)
|
|
19
|
+
|
|
20
|
+
this.src = src
|
|
21
|
+
|
|
22
|
+
this.parse ()
|
|
23
|
+
this.validate ()
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
parse () {
|
|
28
|
+
|
|
29
|
+
this.posMonth = this.src.indexOf ('-', 1)
|
|
30
|
+
|
|
31
|
+
if (this.posMonth === -1) throw Error (`The year separator is not found`)
|
|
32
|
+
|
|
33
|
+
if (this.posMonth < 3) throw Error (`'${this.year}' is not a valid year: cannot be shorter than 4 characters`)
|
|
34
|
+
|
|
35
|
+
if (this.src.charCodeAt (this.posDay) !== CH_MINUS) throw Error (`The character at ${this.posDay} must be '-', not '${this.src.charAt (this.posDay)}'`)
|
|
36
|
+
|
|
37
|
+
const {length} = this.src
|
|
38
|
+
|
|
39
|
+
if (length < this.endOfDate) throw Error (`The day part must be 2 chars long, found '${this.day}'`)
|
|
40
|
+
|
|
41
|
+
if (length !== (this.endOfDateTime = this.endOfDate)) this.parseAfterDate ()
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
parseAfterDate () {
|
|
46
|
+
|
|
47
|
+
if (this.src.charCodeAt (this.endOfDate) !== CH_T) return
|
|
48
|
+
|
|
49
|
+
for (const pos of [this.endOfHour, this.endOfMinute])
|
|
50
|
+
|
|
51
|
+
if (this.src.charCodeAt (pos) !== CH_COLON)
|
|
52
|
+
|
|
53
|
+
throw Error (`Invalid time part: the character at position ${pos} must be ':', not '${this.src.charAt (pos)}'`)
|
|
54
|
+
|
|
55
|
+
this.hasTime = true
|
|
56
|
+
|
|
57
|
+
this.parseAfterMinute ()
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
parseAfterMinute () {
|
|
62
|
+
|
|
63
|
+
this.endOfDateTime = this.endOfMinute + 3; if (this.src.charCodeAt (this.endOfDateTime) !== CH_PERIOD) return
|
|
64
|
+
|
|
65
|
+
const {length} = this.src; while (true) {
|
|
66
|
+
|
|
67
|
+
this.endOfDateTime ++; if (this.endOfDateTime === length) break
|
|
68
|
+
|
|
69
|
+
const c = this.src.charCodeAt (this.endOfDateTime); if (c >= CH_0 && c <= CH_9) continue
|
|
70
|
+
|
|
71
|
+
break
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get posDay () {
|
|
78
|
+
|
|
79
|
+
return this.posMonth + 3
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get endOfDate () {
|
|
84
|
+
|
|
85
|
+
return this.posMonth + 6
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get endOfHour () {
|
|
90
|
+
|
|
91
|
+
return this.posMonth + 9
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get endOfMinute () {
|
|
96
|
+
|
|
97
|
+
return this.posMonth + 12
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get year () {
|
|
102
|
+
|
|
103
|
+
return this.src.substring (0, this.posMonth)
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get month () {
|
|
108
|
+
|
|
109
|
+
return this.src.substring (this.posMonth + 1, this.posDay)
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get day () {
|
|
114
|
+
|
|
115
|
+
return this.src.substring (this.posDay + 1, this.posDay + 3)
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get hour () {
|
|
120
|
+
|
|
121
|
+
if (this.hasTime) return this.src.substring (this.endOfDate + 1, this.endOfHour)
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get minute () {
|
|
126
|
+
|
|
127
|
+
if (this.hasTime) return this.src.substring (this.endOfHour + 1, this.endOfMinute)
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get second () {
|
|
132
|
+
|
|
133
|
+
if (this.hasTime) return this.src.substring (this.endOfMinute + 1, this.endOfDateTime)
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get tz () {
|
|
138
|
+
|
|
139
|
+
const s = this.src.substring (this.endOfDateTime)
|
|
140
|
+
|
|
141
|
+
return s.length === 0 ? undefined : s
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
validate () {
|
|
146
|
+
|
|
147
|
+
this.validateDate ()
|
|
148
|
+
|
|
149
|
+
if (this.hasTime) this.validateTime ()
|
|
150
|
+
|
|
151
|
+
this.validateTZ ()
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
validateDate () {
|
|
156
|
+
|
|
157
|
+
this.validateMonth ()
|
|
158
|
+
this.validateYear ()
|
|
159
|
+
this.validateDay ()
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
validateYear () {
|
|
164
|
+
|
|
165
|
+
const {year} = this, {length} = year, base = year.charCodeAt (0) === CH_MINUS ? 1 : 0
|
|
166
|
+
|
|
167
|
+
if (year.charCodeAt (base) === CH_0 && length - base !== 4) throw Error (`Starting with 0, the year must have exactly 4 digits`)
|
|
168
|
+
|
|
169
|
+
for (let i = base; i < length; i ++) {
|
|
170
|
+
|
|
171
|
+
const c = year.charCodeAt (i)
|
|
172
|
+
|
|
173
|
+
if (c > CH_9 || c < CH_0) throw Error (`Invalid year: '${year.charAt (i)} at position ${i}'`)
|
|
174
|
+
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
validateMonth () {
|
|
180
|
+
|
|
181
|
+
const {month} = this
|
|
182
|
+
|
|
183
|
+
if (month < '01' || month > '12') throw Error (`Invalid month`)
|
|
184
|
+
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
validateDay () {
|
|
188
|
+
|
|
189
|
+
const {day} = this
|
|
190
|
+
|
|
191
|
+
if (day < '01' || day > '31') throw Error (`Invalid day`)
|
|
192
|
+
|
|
193
|
+
if (day === '31' || (this.month === '02' && day > '28')) {
|
|
194
|
+
|
|
195
|
+
if (new Date (this.src.substring (0, this.endOfDate)).getDate () != day) throw Error (`Non existing day`)
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
validateTime () {
|
|
202
|
+
|
|
203
|
+
const {hour, minute, second} = this
|
|
204
|
+
|
|
205
|
+
if (hour < '00' || hour > '23') throw Error (`Invalid hour`)
|
|
206
|
+
if (minute < '00' || minute > '59') throw Error (`Invalid minute`)
|
|
207
|
+
|
|
208
|
+
const intSecond = second.length === 2 ? second : second.substring (0, 2)
|
|
209
|
+
|
|
210
|
+
if (intSecond < '00' || intSecond > '59') throw Error (`Invalid second`)
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
validateTZ () {
|
|
215
|
+
|
|
216
|
+
const {tz} = this; if (tz === undefined || tzCache.has (tz)) return
|
|
217
|
+
|
|
218
|
+
switch (tz.charCodeAt (0)) {
|
|
219
|
+
case CH_PLUS:
|
|
220
|
+
case CH_MINUS:
|
|
221
|
+
break
|
|
222
|
+
default:
|
|
223
|
+
throw Error (`Unless 'Z', the timezone must start with either '+' or '-', not ${tz.charAt (0)}`)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (tz.length !== 6) throw Error (`Invalid timezone length: ${tz.length}`)
|
|
227
|
+
|
|
228
|
+
if (tz.charCodeAt (3) !== CH_COLON) throw Error (`Invalid timezone: ':' not found at position 3`)
|
|
229
|
+
|
|
230
|
+
{
|
|
231
|
+
|
|
232
|
+
const hh = tz.substring (1, 3); if (hh < '00' || hh > '13') throw Error (`Invalid TZ hour: ${hh}`)
|
|
233
|
+
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
{
|
|
237
|
+
|
|
238
|
+
const mm = tz.substring (4, 6); if (mm < '00' || mm > '59') throw Error (`Invalid TZ minute: ${mm}`)
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
tzCache.add (tz)
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
module.exports = DT7
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
class XSSimpleType {
|
|
2
|
+
|
|
3
|
+
constructor (xs) {
|
|
4
|
+
|
|
5
|
+
this.xs = xs
|
|
6
|
+
this.length = null
|
|
7
|
+
this.maxLength = Infinity
|
|
8
|
+
this.minLength = 0
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get totalDigits () { return undefined }
|
|
13
|
+
set totalDigits (v) { throw Error ('totalDigits are not supported for this type') }
|
|
14
|
+
|
|
15
|
+
get fractionDigits () { return undefined }
|
|
16
|
+
set fractionDigits (_) { throw Error ('fractionDigits are not supported for this type') }
|
|
17
|
+
|
|
18
|
+
toOrdered (_) { throw Error ('the ordering is not supported for this type') }
|
|
19
|
+
|
|
20
|
+
get patterns () { return [] }
|
|
21
|
+
get values () { return [] }
|
|
22
|
+
|
|
23
|
+
get name () {
|
|
24
|
+
return 'anyType'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
blame (value, reasons) {
|
|
28
|
+
|
|
29
|
+
if (!Array.isArray (reasons)) reasons = [reasons]
|
|
30
|
+
|
|
31
|
+
let s; try {
|
|
32
|
+
|
|
33
|
+
s = JSON.stringify (value)
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
catch (x) {
|
|
37
|
+
|
|
38
|
+
s = String (value)
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
throw Error (`Cannot stringify ${typeof value} ${s} as ${this.name}: ${reasons.join ('; ')}`)
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
stringify (value) {
|
|
47
|
+
|
|
48
|
+
if (value == null) this.blame (value, 'nullish values are unacceptable')
|
|
49
|
+
|
|
50
|
+
const reasons = []; for (const s of this.strings (value)) {
|
|
51
|
+
|
|
52
|
+
const result = this.test (s); if (result === null) return s
|
|
53
|
+
|
|
54
|
+
reasons.push (result)
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.blame (value, reasons)
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
* strings (value) {
|
|
63
|
+
|
|
64
|
+
yield String (value)
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
test (s) {
|
|
69
|
+
|
|
70
|
+
if (this.isEnumeration) return this.testEnumeration (s)
|
|
71
|
+
|
|
72
|
+
return this.testLength (s) ?? this.testFormat (s) ?? this.testBounds (s) ?? this.testPatterns (s) ?? (/*super.test ? super.test (s) :*/ null)
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
testFormat (s) {
|
|
77
|
+
|
|
78
|
+
return null
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get units () {
|
|
83
|
+
|
|
84
|
+
return 'chars'
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getLength (value) {
|
|
89
|
+
|
|
90
|
+
return value.length
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
testBounds (value) {
|
|
95
|
+
|
|
96
|
+
let ordered = undefined
|
|
97
|
+
|
|
98
|
+
if (this.minInclusive != null && (ordered = this.toOrdered (value)) < this.minInclusive) throw Error (`The value '${value}' is less than allowed '${this.minInclusive}'`)
|
|
99
|
+
|
|
100
|
+
if (this.maxInclusive != null && (ordered ??= this.toOrdered (value)) > this.maxInclusive) throw Error (`The value '${value}' is greater than allowed '${this.maxInclusive}'`)
|
|
101
|
+
|
|
102
|
+
if (this.minExclusive != null && (ordered ??= this.toOrdered (value)) <= this.minExclusive) throw Error (`The value '${value}' is less or equal than the threshold '${this.minExclusive}'`)
|
|
103
|
+
|
|
104
|
+
if (this.maxExclusive != null && (ordered ??= this.toOrdered (value)) >= this.maxExclusive) throw Error (`The value '${value}' is greater or equal than the threshold '${this.maxExclusive}'`)
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
testLength (value) {
|
|
109
|
+
|
|
110
|
+
const l = this.getLength (value), {length} = this
|
|
111
|
+
|
|
112
|
+
if (length === null) {
|
|
113
|
+
|
|
114
|
+
if (l > this.maxLength) return `The value '${value}' is ${l} ${this.units} long, which exceeds the allowed maximum of ${this.maxLength}`
|
|
115
|
+
|
|
116
|
+
if (l < this.minLength) return `The value '${value}' is ${l} ${this.units} long, which is less than the allowed minimum of ${this.minLength}`
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
|
|
121
|
+
if (l !== length) return `The value '${value}' is ${l} ${this.units} long, must be exaclty ${length}`
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return null
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get isEnumeration () {
|
|
130
|
+
|
|
131
|
+
return this.values.length !== 0
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
testEnumeration (s) {
|
|
136
|
+
|
|
137
|
+
const {values} = this; if (values.includes (s)) return null
|
|
138
|
+
|
|
139
|
+
return `The value '${s}' is not in list: ${JSON.stringify (values)}`
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
testPatterns (s) {
|
|
144
|
+
|
|
145
|
+
const {patterns} = this, {length} = patterns; if (length === 0) return null
|
|
146
|
+
|
|
147
|
+
for (const pattern of patterns) if (pattern.test (s)) return null
|
|
148
|
+
|
|
149
|
+
if (length === 1) return `The value '${s}' doesn't match the pattern '${patterns [0]}'`
|
|
150
|
+
|
|
151
|
+
return `The value '${s}' doesn't match any of the patterns: ${patterns.map (_ => '' + _).join (', ')}`
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
validateScalar (s) {
|
|
156
|
+
|
|
157
|
+
const result = this.test (s ?? '')
|
|
158
|
+
|
|
159
|
+
if (result) throw Error (result)
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
restrict (entries) {
|
|
164
|
+
|
|
165
|
+
return class extends this.constructor {
|
|
166
|
+
|
|
167
|
+
#patterns = []
|
|
168
|
+
#values = []
|
|
169
|
+
|
|
170
|
+
get patterns () {
|
|
171
|
+
return this.#patterns
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
get values () {
|
|
175
|
+
return this.#values
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
get name () {
|
|
179
|
+
return super.name
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
constructor (xs) {
|
|
183
|
+
|
|
184
|
+
super (xs)
|
|
185
|
+
|
|
186
|
+
for (const entry of entries) {
|
|
187
|
+
|
|
188
|
+
const {localName, attributes} = entry
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
|
|
192
|
+
const {value} = attributes; switch (localName) {
|
|
193
|
+
|
|
194
|
+
case 'enumeration':
|
|
195
|
+
this.#values.push (value)
|
|
196
|
+
break
|
|
197
|
+
|
|
198
|
+
case 'pattern':
|
|
199
|
+
this.#patterns.push (new RegExp (value))
|
|
200
|
+
break
|
|
201
|
+
|
|
202
|
+
case 'totalDigits':
|
|
203
|
+
this.totalDigits = value
|
|
204
|
+
break
|
|
205
|
+
|
|
206
|
+
case 'fractionDigits':
|
|
207
|
+
this.fractionDigits = value
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
case 'length':
|
|
211
|
+
this.length = parseInt (value)
|
|
212
|
+
break
|
|
213
|
+
|
|
214
|
+
case 'maxLength':
|
|
215
|
+
this.maxLength = parseInt (value)
|
|
216
|
+
break
|
|
217
|
+
|
|
218
|
+
case 'minLength':
|
|
219
|
+
this.minLength = parseInt (value)
|
|
220
|
+
break
|
|
221
|
+
|
|
222
|
+
case 'maxInclusive':
|
|
223
|
+
this.maxInclusive = this.toOrdered (value)
|
|
224
|
+
break
|
|
225
|
+
|
|
226
|
+
case 'maxExclusive':
|
|
227
|
+
this.maxExclusive = this.toOrdered (value)
|
|
228
|
+
break
|
|
229
|
+
|
|
230
|
+
case 'minInclusive':
|
|
231
|
+
this.minInclusive = this.toOrdered (value)
|
|
232
|
+
break
|
|
233
|
+
|
|
234
|
+
case 'minExclusive':
|
|
235
|
+
this.minExclusive = this.toOrdered (value)
|
|
236
|
+
break
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
catch (cause) {
|
|
242
|
+
|
|
243
|
+
throw cause
|
|
244
|
+
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
module.exports = {
|
|
258
|
+
XSSimpleType,
|
|
259
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const {XSSimpleType} = require ('./XSSimpleType.js')
|
|
2
|
+
|
|
3
|
+
class XSSimpleTypeBoolean extends XSSimpleType {
|
|
4
|
+
|
|
5
|
+
static toCanonical (value) {
|
|
6
|
+
|
|
7
|
+
switch (typeof value) {
|
|
8
|
+
|
|
9
|
+
case 'boolean': return value
|
|
10
|
+
|
|
11
|
+
case 'number':
|
|
12
|
+
switch (value) {
|
|
13
|
+
case 0: return false
|
|
14
|
+
case 1: return true
|
|
15
|
+
default: return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
case 'string':
|
|
19
|
+
|
|
20
|
+
switch (value) {
|
|
21
|
+
|
|
22
|
+
case '0':
|
|
23
|
+
case 'false':
|
|
24
|
+
return false
|
|
25
|
+
|
|
26
|
+
case '1':
|
|
27
|
+
case 'true':
|
|
28
|
+
return true
|
|
29
|
+
|
|
30
|
+
default:
|
|
31
|
+
return null
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get name () {
|
|
40
|
+
return 'boolean'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toOrdered (value) {
|
|
44
|
+
|
|
45
|
+
switch (value) {
|
|
46
|
+
case '0':
|
|
47
|
+
case 'false':
|
|
48
|
+
return 0
|
|
49
|
+
case '1':
|
|
50
|
+
case 'true':
|
|
51
|
+
return 1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return undefined
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
testLength (value) {
|
|
59
|
+
|
|
60
|
+
return value.length === 0 ? 'No boolean value can be empty' : null
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
testFormat (value) {
|
|
65
|
+
|
|
66
|
+
if (this.toOrdered (value) === undefined) return `'${value}' is not a boolean value`
|
|
67
|
+
|
|
68
|
+
return null
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
* strings (value) {
|
|
73
|
+
|
|
74
|
+
const c = XSSimpleTypeBoolean.toCanonical (value); if (c !== null) {
|
|
75
|
+
|
|
76
|
+
if (c) {
|
|
77
|
+
yield 'true'
|
|
78
|
+
yield '1'
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
yield 'false'
|
|
82
|
+
yield '0'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = XSSimpleTypeBoolean
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const {XSSimpleType} = require ('./XSSimpleType.js')
|
|
2
|
+
const DT7 = require ('./DT7.js')
|
|
3
|
+
|
|
4
|
+
class XSSimpleTypeDT extends XSSimpleType {
|
|
5
|
+
|
|
6
|
+
adjust (value) {
|
|
7
|
+
|
|
8
|
+
return typeof value === 'string' ? value : new Date (value).toJSON ()
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class XSSimpleTypeDate extends XSSimpleTypeDT {
|
|
15
|
+
|
|
16
|
+
* strings (value) {
|
|
17
|
+
|
|
18
|
+
value = this.adjust (value)
|
|
19
|
+
|
|
20
|
+
const ymd = value.substring (0, 10)
|
|
21
|
+
|
|
22
|
+
const {length} = value; if (length > 10) {
|
|
23
|
+
|
|
24
|
+
const pos = value.indexOf ('Z')
|
|
25
|
+
|
|
26
|
+
if (pos !== -1 && pos !== length - 1) yield ymd + value.substring (pos)
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
yield ymd
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
testFormat (s) {
|
|
35
|
+
|
|
36
|
+
const dt7 = new DT7 (s)
|
|
37
|
+
|
|
38
|
+
if (dt7.hour !== undefined) return `For a date value, the time part cannot be present`
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class XSSimpleTypeDateTime extends XSSimpleTypeDT {
|
|
45
|
+
|
|
46
|
+
adjust (value) {
|
|
47
|
+
|
|
48
|
+
value = super.adjust (value)
|
|
49
|
+
|
|
50
|
+
return value.length === 10 ? value + 'T00:00:00' : value
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
testFormat (s) {
|
|
55
|
+
|
|
56
|
+
const dt7 = new DT7 (s)
|
|
57
|
+
|
|
58
|
+
if (dt7.hour === undefined) return `For a dateTime value, the time part is mandatory`
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
* strings (value) {
|
|
63
|
+
|
|
64
|
+
value = this.adjust (value)
|
|
65
|
+
|
|
66
|
+
yield value
|
|
67
|
+
|
|
68
|
+
if (value.length > 19) yield value.substring (0, 19)
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class XSSimpleTypeDateTimeStamp extends XSSimpleTypeDateTime {
|
|
75
|
+
|
|
76
|
+
testFormat (s) {
|
|
77
|
+
|
|
78
|
+
const dt7 = new DT7 (s)
|
|
79
|
+
|
|
80
|
+
if (dt7.hour === undefined || dt7.tz === undefined) return `For a dateTimeStamp value, both time and timezone parts are mandatory`
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
XSSimpleTypeDate,
|
|
88
|
+
XSSimpleTypeDateTime,
|
|
89
|
+
XSSimpleTypeDateTimeStamp,
|
|
90
|
+
byName: {
|
|
91
|
+
date : XSSimpleTypeDate,
|
|
92
|
+
dateTime : XSSimpleTypeDateTime,
|
|
93
|
+
dateTimeStamp : XSSimpleTypeDateTimeStamp,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|