xml-toolkit 1.1.4 → 1.1.5
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/index.js +1 -0
- package/lib/XMLIterator.js +2 -2
- package/lib/XMLLexer.js +20 -18
- package/lib/XMLMessages.js +57 -0
- package/lib/XMLParser.js +3 -2
- package/lib/XMLPosition.js +49 -3
- package/lib/XMLReader.js +5 -20
- package/lib/XMLSchemata.js +7 -11
- package/lib/simple/DT7.js +13 -3
- package/lib/simple/XSSimpleType.js +37 -21
- package/lib/simple/XSSimpleTypeBoolean.js +2 -2
- package/lib/simple/XSSimpleTypeDT.js +15 -4
- package/lib/simple/XSSimpleTypeDecimal.js +14 -8
- package/lib/simple/XSSimpleTypeFloatingPoint.js +2 -2
- package/lib/validation/XMLValidationState.js +21 -42
- package/lib/validation/XMLValidatior.js +10 -2
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -31,6 +31,7 @@ module.exports = {
|
|
|
31
31
|
XMLSchema: require ('./lib/XMLSchema'),
|
|
32
32
|
XMLSchemaBuiltIn: require ('./lib/XMLSchemaBuiltIn'),
|
|
33
33
|
XMLSchemata: require ('./lib/XMLSchemata'),
|
|
34
|
+
XMLMessages: require ('./lib/XMLMessages'),
|
|
34
35
|
XSSimpleType,
|
|
35
36
|
XSSimpleTypeFloat,
|
|
36
37
|
XSSimpleTypeDouble,
|
package/lib/XMLIterator.js
CHANGED
package/lib/XMLLexer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const assert = require ('assert')
|
|
2
2
|
const {Transform} = require ('stream')
|
|
3
3
|
const {StringDecoder} = require('string_decoder')
|
|
4
|
+
const XMLPosition = require ('./XMLPosition.js')
|
|
4
5
|
|
|
5
6
|
const ST_TEXT = 0
|
|
6
7
|
const ST_LT = 1
|
|
@@ -23,6 +24,8 @@ const S_ENCODING = Symbol ('encoding')
|
|
|
23
24
|
|
|
24
25
|
const XMLLexer = class extends Transform {
|
|
25
26
|
|
|
27
|
+
#position = new XMLPosition ()
|
|
28
|
+
|
|
26
29
|
constructor (options = {}) {
|
|
27
30
|
|
|
28
31
|
options.readableObjectMode = true
|
|
@@ -51,6 +54,12 @@ const XMLLexer = class extends Transform {
|
|
|
51
54
|
|
|
52
55
|
}
|
|
53
56
|
|
|
57
|
+
get position () {
|
|
58
|
+
|
|
59
|
+
return this.#position
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
isClosing (pos) {
|
|
55
64
|
|
|
56
65
|
const {awaited, body} = this, {length} = awaited; if (length === 0) return true
|
|
@@ -74,7 +83,7 @@ const XMLLexer = class extends Transform {
|
|
|
74
83
|
|
|
75
84
|
default:
|
|
76
85
|
assert (awaited === null, 'not ST_TAG[_X]: awaited must be null')
|
|
77
|
-
this.
|
|
86
|
+
this.xPosition = 0
|
|
78
87
|
break
|
|
79
88
|
|
|
80
89
|
}
|
|
@@ -155,7 +164,7 @@ const XMLLexer = class extends Transform {
|
|
|
155
164
|
|
|
156
165
|
default:
|
|
157
166
|
this.setState (ST_TAG_X, CL_DEAFULT)
|
|
158
|
-
this.
|
|
167
|
+
this.xPosition = pos
|
|
159
168
|
break
|
|
160
169
|
|
|
161
170
|
}
|
|
@@ -182,7 +191,7 @@ const XMLLexer = class extends Transform {
|
|
|
182
191
|
|
|
183
192
|
case ST_TAG_X:
|
|
184
193
|
|
|
185
|
-
for (let pos = this.
|
|
194
|
+
for (let pos = this.xPosition + 1; pos < body.length; pos ++) {
|
|
186
195
|
|
|
187
196
|
switch (body.charCodeAt (pos)) {
|
|
188
197
|
|
|
@@ -196,7 +205,7 @@ const XMLLexer = class extends Transform {
|
|
|
196
205
|
|
|
197
206
|
}
|
|
198
207
|
|
|
199
|
-
this.
|
|
208
|
+
this.xPosition = pos
|
|
200
209
|
break
|
|
201
210
|
|
|
202
211
|
case CH_GT:
|
|
@@ -210,9 +219,6 @@ const XMLLexer = class extends Transform {
|
|
|
210
219
|
}
|
|
211
220
|
|
|
212
221
|
return
|
|
213
|
-
|
|
214
|
-
default:
|
|
215
|
-
throw new Error ('Invalid state: ' + this.state)
|
|
216
222
|
|
|
217
223
|
}
|
|
218
224
|
|
|
@@ -226,7 +232,11 @@ const XMLLexer = class extends Transform {
|
|
|
226
232
|
|
|
227
233
|
this.start = pos
|
|
228
234
|
|
|
229
|
-
if (lexeme.length
|
|
235
|
+
if (lexeme.length === 0) return
|
|
236
|
+
|
|
237
|
+
this.#position.scan (lexeme)
|
|
238
|
+
|
|
239
|
+
this.push (lexeme)
|
|
230
240
|
|
|
231
241
|
}
|
|
232
242
|
|
|
@@ -237,24 +247,16 @@ const XMLLexer = class extends Transform {
|
|
|
237
247
|
callback ()
|
|
238
248
|
|
|
239
249
|
}
|
|
240
|
-
|
|
241
|
-
getPosition () {
|
|
242
|
-
|
|
243
|
-
let {beforeBody, start} = this
|
|
244
250
|
|
|
245
|
-
return beforeBody + BigInt (start)
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
251
|
checkMaxLength () {
|
|
250
252
|
|
|
251
253
|
const {body, maxLength} = this, size = body.length - this.start;
|
|
252
254
|
|
|
253
255
|
if (size <= maxLength) return
|
|
254
256
|
|
|
255
|
-
|
|
257
|
+
this.#position.scan (body.slice (0, size - 1))
|
|
256
258
|
|
|
257
|
-
this.destroy (new Error (
|
|
259
|
+
this.destroy (new Error (this.position.format (['XML-00001', maxLength])))
|
|
258
260
|
|
|
259
261
|
}
|
|
260
262
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const util = require ('node:util')
|
|
2
|
+
|
|
3
|
+
const VOCABULARY = new Map ([
|
|
4
|
+
|
|
5
|
+
['XML-00001', 'maxLength=%i exceeded'],
|
|
6
|
+
['XML-00002', 'Unbalanced end element'],
|
|
7
|
+
['XML-00003', 'Unmatched end element, </${%s}> expected'],
|
|
8
|
+
|
|
9
|
+
['XVC-00001', 'No nested elements allowed inside %s'],
|
|
10
|
+
['XVC-00002', 'is unexpected here; should be %s'],
|
|
11
|
+
['XVC-00003', 'Unknown attribute: %s'],
|
|
12
|
+
['XVC-00004', 'The attribute "%s" must have the value "%s", not "%s"'],
|
|
13
|
+
['XVC-00005', 'Missing required attribute: "%s"'],
|
|
14
|
+
|
|
15
|
+
['XVS-00001', `The value "%s" doesn't match the pattern %s`],
|
|
16
|
+
['XVS-00002', `The value "%s" doesn't match any of the patterns: %s`],
|
|
17
|
+
['XVS-00003', `The value '%s' is not in list: %s`],
|
|
18
|
+
['XVS-00004', `The value '%s' has the length %i, which exceeds the allowed maximum of %i`],
|
|
19
|
+
['XVS-00005', `The value '%s' has the length %i, which is less than the allowed minimum of %i`],
|
|
20
|
+
['XVS-00006', `The value '%s' has the length %i, must be exaclty %i`],
|
|
21
|
+
['XVS-00007', `The value '%s' is less than the least allowed '%s'`],
|
|
22
|
+
['XVS-00008', `The value '%s' is greater than the greatest allowed '%s'`],
|
|
23
|
+
['XVS-00009', `The value '%s' is less or equal than the threshold '%s'`],
|
|
24
|
+
['XVS-00010', `The value '%s' is greater or equal than the threshold '%s'`],
|
|
25
|
+
['XVS-00011', `No boolean value can be empty`],
|
|
26
|
+
['XVS-00012', `'%s' is not a boolean value`],
|
|
27
|
+
['XVS-00013', `No decimal value can be empty`],
|
|
28
|
+
['XVS-00014', `'%s' is not a valid decimal: '%s' can occur only at the beginning`],
|
|
29
|
+
['XVS-00015', `'%s' is not a valid decimal: 2nd period occured at position %i`],
|
|
30
|
+
['XVS-00016', `'%s' is not a valid decimal: '%s' occured at position %i`],
|
|
31
|
+
['XVS-00017', `'%s' is not a valid decimal: is has no digits at all`],
|
|
32
|
+
['XVS-00018', `'%s' has %i digits, only %i allowed`],
|
|
33
|
+
['XVS-00019', `'%s' has %i digits after period, only %i allowed`],
|
|
34
|
+
['XVS-00020', `No floating point number can be empty`],
|
|
35
|
+
['XVS-00021', `'%s' is not a floating point number`],
|
|
36
|
+
['XVS-00022', `For a date value, the time part cannot be present, but '%s' contains it`],
|
|
37
|
+
['XVS-00023', `For a dateTime value, the time part is mandatory, missing from '%s'`],
|
|
38
|
+
['XVS-00024', `For a dateTimeStamp value, both time and timezone parts are mandatory, missing from '%s'`],
|
|
39
|
+
['XVS-00025', `The year separator is not found in '%s'`],
|
|
40
|
+
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
class XMLMessages {
|
|
44
|
+
|
|
45
|
+
static VOCABULARY = VOCABULARY
|
|
46
|
+
|
|
47
|
+
static format (args) {
|
|
48
|
+
|
|
49
|
+
args [0] = VOCABULARY.get (args [0])
|
|
50
|
+
|
|
51
|
+
return util.format.apply (util, args)
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = XMLMessages
|
package/lib/XMLParser.js
CHANGED
|
@@ -84,7 +84,7 @@ const XMLParser = class {
|
|
|
84
84
|
this.element = node
|
|
85
85
|
if (this.document === null) {
|
|
86
86
|
this.document = node
|
|
87
|
-
if (this.xs !== null) this.validator = new XMLValidatior (this.xs, node,
|
|
87
|
+
if (this.xs !== null) this.validator = new XMLValidatior (this.xs, node, nodes.position)
|
|
88
88
|
}
|
|
89
89
|
else {
|
|
90
90
|
if (this.xs !== null) this.validator.startElement (node)
|
|
@@ -93,7 +93,8 @@ const XMLParser = class {
|
|
|
93
93
|
|
|
94
94
|
case SAXEvent.TYPES.END_ELEMENT:
|
|
95
95
|
|
|
96
|
-
if (this.element === null)
|
|
96
|
+
if (this.element === null) throw new Error (nodes.position.format (['XML-00002']))
|
|
97
|
+
if (this.element.name != node.name) throw new Error (nodes.position.format (['XML-00003', this.element.name]))
|
|
97
98
|
node ['_ns_map'] = this.element ['_ns_map']
|
|
98
99
|
this.element.type = type
|
|
99
100
|
this.element = this.element.parent
|
package/lib/XMLPosition.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
const CH_LF = '\n'.charCodeAt (0)
|
|
2
|
+
const CH_SPACE = ' '.charCodeAt (0)
|
|
3
|
+
const MAX_LEN_TOTAL = 50
|
|
4
|
+
const STR_ELLIPSIS = '...'
|
|
5
|
+
const MAX_LEN = MAX_LEN_TOTAL - STR_ELLIPSIS.length
|
|
6
|
+
|
|
7
|
+
const XMLMessages = require ('./XMLMessages')
|
|
2
8
|
|
|
3
9
|
class XMLPosition {
|
|
4
10
|
|
|
@@ -6,11 +12,13 @@ class XMLPosition {
|
|
|
6
12
|
#localPosition = 0
|
|
7
13
|
#lastLine = 0
|
|
8
14
|
#lastLocalPosition = 0
|
|
15
|
+
#chunk
|
|
9
16
|
|
|
10
17
|
scan (chunk) {
|
|
11
18
|
|
|
12
19
|
this.#lastLine = this.#line
|
|
13
20
|
this.#lastLocalPosition = this.#localPosition
|
|
21
|
+
this.#chunk = chunk
|
|
14
22
|
|
|
15
23
|
for (let i = 0; i < chunk.length; i ++) switch (chunk.charCodeAt (i)) {
|
|
16
24
|
|
|
@@ -26,11 +34,49 @@ class XMLPosition {
|
|
|
26
34
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
get line () {
|
|
38
|
+
|
|
39
|
+
return this.#lastLine + 1
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get position () {
|
|
44
|
+
|
|
45
|
+
return this.#lastLocalPosition + 1
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get chunk () {
|
|
50
|
+
|
|
51
|
+
const {length} = this.#chunk; if (length <= MAX_LEN) return this.#chunk
|
|
52
|
+
|
|
53
|
+
return this.#chunk.substr (0, MAX_LEN) + STR_ELLIPSIS
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get src () {
|
|
58
|
+
|
|
59
|
+
const b = Buffer.from (this.chunk)
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < b.length; i ++) if (b [i] < CH_SPACE) b [i] = CH_SPACE
|
|
62
|
+
|
|
63
|
+
return ' `' + b + '`'
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
toString () {
|
|
30
68
|
|
|
31
|
-
|
|
69
|
+
const {line, position, src} = this
|
|
32
70
|
|
|
33
|
-
|
|
71
|
+
return `[${line}:${position}]${src} `
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
format (args) {
|
|
76
|
+
|
|
77
|
+
return this.toString () + XMLMessages.format (args)
|
|
78
|
+
|
|
79
|
+
}
|
|
34
80
|
|
|
35
81
|
}
|
|
36
82
|
|
package/lib/XMLReader.js
CHANGED
|
@@ -3,7 +3,6 @@ const {Transform} = require ('stream')
|
|
|
3
3
|
const SAXEvent = require ('./SAXEvent.js')
|
|
4
4
|
const XMLNode = require ('./XMLNode.js')
|
|
5
5
|
const XMLLexer = require ('./XMLLexer.js')
|
|
6
|
-
const XMLPosition = require ('./XMLPosition.js')
|
|
7
6
|
const XMLValidatior = require ('./validation/XMLValidatior.js')
|
|
8
7
|
|
|
9
8
|
const OPT_SRC = Symbol ('_src')
|
|
@@ -13,8 +12,6 @@ const NO_CHILDREN = []; NO_CHILDREN.push = () => {}
|
|
|
13
12
|
|
|
14
13
|
const XMLReader = class extends Transform {
|
|
15
14
|
|
|
16
|
-
#position = new XMLPosition ()
|
|
17
|
-
|
|
18
15
|
constructor (options = {}) {
|
|
19
16
|
|
|
20
17
|
options.decodeStrings = false
|
|
@@ -72,14 +69,10 @@ const XMLReader = class extends Transform {
|
|
|
72
69
|
this.filter = filter || null
|
|
73
70
|
this.map = map || null
|
|
74
71
|
|
|
75
|
-
this.line = 0
|
|
76
|
-
this.localPosition = 0
|
|
77
|
-
|
|
78
72
|
if (this.useEntities) this.entityResolver = new (require ('./EntityResolver.js')) ()
|
|
79
73
|
|
|
80
74
|
this.text = ''
|
|
81
75
|
this.element = null
|
|
82
|
-
this.position = 0
|
|
83
76
|
|
|
84
77
|
this [OPT_SRC] = null; this.on ('pipe', src => this [OPT_SRC] = src)
|
|
85
78
|
|
|
@@ -154,7 +147,7 @@ const XMLReader = class extends Transform {
|
|
|
154
147
|
if (!this.validator) switch (xmlNode.type) {
|
|
155
148
|
|
|
156
149
|
case SAXEvent.TYPES.START_ELEMENT:
|
|
157
|
-
this.validator = new XMLValidatior (this.xs, xmlNode,
|
|
150
|
+
this.validator = new XMLValidatior (this.xs, xmlNode, this.lex.position)
|
|
158
151
|
|
|
159
152
|
default:
|
|
160
153
|
return
|
|
@@ -250,18 +243,10 @@ const XMLReader = class extends Transform {
|
|
|
250
243
|
|
|
251
244
|
}
|
|
252
245
|
|
|
253
|
-
get linePos () {
|
|
254
|
-
|
|
255
|
-
return this.#position.toJSON ()
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
246
|
_transform (chunk, encoding, callback) {
|
|
260
247
|
|
|
261
248
|
const {length} = chunk; if (length !== 0) {
|
|
262
249
|
|
|
263
|
-
this.#position.scan (chunk)
|
|
264
|
-
|
|
265
250
|
let e = new XMLNode (chunk, this.entityResolver), {type} = e, {element} = this
|
|
266
251
|
|
|
267
252
|
switch (type) {
|
|
@@ -284,10 +269,12 @@ const XMLReader = class extends Transform {
|
|
|
284
269
|
}
|
|
285
270
|
|
|
286
271
|
switch (type) {
|
|
287
|
-
|
|
272
|
+
|
|
288
273
|
case SAXEvent.TYPES.END_ELEMENT:
|
|
289
274
|
|
|
290
|
-
if (element === null)
|
|
275
|
+
if (element === null) return callback (new Error (this.lex.position.format (['XML-00002'])))
|
|
276
|
+
|
|
277
|
+
if (e.name != element.name) return callback (new Error (this.lex.position.format (['XML-00003', this.element.name])))
|
|
291
278
|
|
|
292
279
|
e = element
|
|
293
280
|
|
|
@@ -324,8 +311,6 @@ const XMLReader = class extends Transform {
|
|
|
324
311
|
|
|
325
312
|
}
|
|
326
313
|
|
|
327
|
-
this.position += length
|
|
328
|
-
|
|
329
314
|
}
|
|
330
315
|
|
|
331
316
|
callback ()
|
package/lib/XMLSchemata.js
CHANGED
|
@@ -7,6 +7,7 @@ const XMLSchema = require ('./XMLSchema.js')
|
|
|
7
7
|
const XMLSchemaXml = require ('./XMLSchemaXml.js')
|
|
8
8
|
const XMLSchemaBuiltIn = require ('./XMLSchemaBuiltIn.js')
|
|
9
9
|
const XMLMarshaller = require ('./XMLMarshaller.js')
|
|
10
|
+
const XMLMessages = require ('./XMLMessages.js')
|
|
10
11
|
|
|
11
12
|
const XSAnyType = require ('./XSAnyType.js')
|
|
12
13
|
const {XSSimpleType} = require ('./simple/XSSimpleType.js')
|
|
@@ -117,24 +118,19 @@ const XMLSchemata = class extends Map {
|
|
|
117
118
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
test (v) {
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
let message = ''; for (const node of this.nodes) {
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
const result = this.xs.getSimpleType (node).test (v); if (!result) return null
|
|
125
126
|
|
|
126
|
-
|
|
127
|
+
if (message.length !== 0) message += '; '
|
|
127
128
|
|
|
128
|
-
|
|
129
|
-
catch (err) {
|
|
130
|
-
|
|
131
|
-
messages.push (err.message)
|
|
132
|
-
|
|
133
|
-
}
|
|
129
|
+
message += XMLMessages.format (result)
|
|
134
130
|
|
|
135
131
|
}
|
|
136
132
|
|
|
137
|
-
|
|
133
|
+
return message
|
|
138
134
|
|
|
139
135
|
}
|
|
140
136
|
|
package/lib/simple/DT7.js
CHANGED
|
@@ -9,13 +9,23 @@ const CH_9 = '9'.charCodeAt (0)
|
|
|
9
9
|
|
|
10
10
|
const tzCache = new Set (['Z', '+14:00', '-14:00'])
|
|
11
11
|
|
|
12
|
+
const die = payload => {
|
|
13
|
+
|
|
14
|
+
const err = Error ('DT7 error')
|
|
15
|
+
|
|
16
|
+
err.payload = payload
|
|
17
|
+
|
|
18
|
+
throw err
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
class DT7 {
|
|
13
23
|
|
|
14
24
|
constructor (src) {
|
|
15
25
|
|
|
16
26
|
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
27
|
|
|
18
|
-
const {length} = src; if (length < MIN_LENGTH)
|
|
28
|
+
const {length} = src; if (length < MIN_LENGTH) die (['XVS-00005', src, length, MIN_LENGTH])
|
|
19
29
|
|
|
20
30
|
this.src = src
|
|
21
31
|
|
|
@@ -28,8 +38,8 @@ class DT7 {
|
|
|
28
38
|
|
|
29
39
|
this.posMonth = this.src.indexOf ('-', 1)
|
|
30
40
|
|
|
31
|
-
if (this.posMonth === -1)
|
|
32
|
-
|
|
41
|
+
if (this.posMonth === -1) die (['XVS-00025', this.src])
|
|
42
|
+
|
|
33
43
|
if (this.posMonth < 3) throw Error (`'${this.year}' is not a valid year: cannot be shorter than 4 characters`)
|
|
34
44
|
|
|
35
45
|
if (this.src.charCodeAt (this.posDay) !== CH_MINUS) throw Error (`The character at ${this.posDay} must be '-', not '${this.src.charAt (this.posDay)}'`)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const XMLMessages = require ('../XMLMessages')
|
|
2
|
+
|
|
1
3
|
class XSSimpleType {
|
|
2
4
|
|
|
3
5
|
constructor (xs) {
|
|
@@ -51,7 +53,7 @@ class XSSimpleType {
|
|
|
51
53
|
|
|
52
54
|
const result = this.test (s); if (result === null) return s
|
|
53
55
|
|
|
54
|
-
reasons.push (result)
|
|
56
|
+
reasons.push (XMLMessages.format (result))
|
|
55
57
|
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -95,30 +97,54 @@ class XSSimpleType {
|
|
|
95
97
|
|
|
96
98
|
let ordered = undefined
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
{
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
const {minInclusive} = this; if (minInclusive != null && (ordered = this.toOrdered (value)) < minInclusive) return ['XVS-00007', value, minInclusive]
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
|
|
108
|
+
const {maxInclusive} = this; if (maxInclusive != null && (ordered ??= this.toOrdered (value)) > maxInclusive) return ['XVS-00008', value, maxInclusive]
|
|
109
|
+
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
{
|
|
103
113
|
|
|
104
|
-
|
|
114
|
+
const {minExclusive} = this; if (minExclusive != null && (ordered ??= this.toOrdered (value)) <= minExclusive) return ['XVS-00009', value, minExclusive]
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
{
|
|
119
|
+
|
|
120
|
+
const {maxExclusive} = this; if (maxExclusive != null && (ordered ??= this.toOrdered (value)) >= maxExclusive) return ['XVS-00010', value, maxExclusive]
|
|
121
|
+
|
|
122
|
+
}
|
|
105
123
|
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
testLength (value) {
|
|
109
127
|
|
|
110
|
-
const l = this.getLength (value), {length} = this
|
|
128
|
+
const l = this.getLength (value), {length, units} = this
|
|
111
129
|
|
|
112
130
|
if (length === null) {
|
|
113
131
|
|
|
114
|
-
|
|
132
|
+
{
|
|
115
133
|
|
|
116
|
-
|
|
134
|
+
const {maxLength} = this; if (l > maxLength) return ['XVS-00004', value, l, maxLength]
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
|
|
140
|
+
const {minLength} = this; if (l < minLength) return ['XVS-00005', value, l, minLength]
|
|
141
|
+
|
|
142
|
+
}
|
|
117
143
|
|
|
118
144
|
}
|
|
119
145
|
else {
|
|
120
146
|
|
|
121
|
-
if (l !== length) return
|
|
147
|
+
if (l !== length) return ['XVS-00006', value, l, length]
|
|
122
148
|
|
|
123
149
|
}
|
|
124
150
|
|
|
@@ -136,7 +162,7 @@ class XSSimpleType {
|
|
|
136
162
|
|
|
137
163
|
const {values} = this; if (values.includes (s)) return null
|
|
138
164
|
|
|
139
|
-
return
|
|
165
|
+
return ['XVS-00003', JSON.stringify (values)]
|
|
140
166
|
|
|
141
167
|
}
|
|
142
168
|
|
|
@@ -146,17 +172,7 @@ class XSSimpleType {
|
|
|
146
172
|
|
|
147
173
|
for (const pattern of patterns) if (pattern.test (s)) return null
|
|
148
174
|
|
|
149
|
-
|
|
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)
|
|
175
|
+
return [length === 1 ? 'XVS-00001' : 'XVS-00002', s, patterns.join (', ')]
|
|
160
176
|
|
|
161
177
|
}
|
|
162
178
|
|
|
@@ -57,13 +57,13 @@ class XSSimpleTypeBoolean extends XSSimpleType {
|
|
|
57
57
|
|
|
58
58
|
testLength (value) {
|
|
59
59
|
|
|
60
|
-
return value.length === 0 ? '
|
|
60
|
+
return value.length === 0 ? ['XVS-00011'] : null
|
|
61
61
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
testFormat (value) {
|
|
65
65
|
|
|
66
|
-
if (this.toOrdered (value) === undefined) return
|
|
66
|
+
if (this.toOrdered (value) === undefined) return ['XVS-00012', value]
|
|
67
67
|
|
|
68
68
|
return null
|
|
69
69
|
|
|
@@ -33,9 +33,20 @@ class XSSimpleTypeDate extends XSSimpleTypeDT {
|
|
|
33
33
|
|
|
34
34
|
testFormat (s) {
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
try {
|
|
37
|
+
|
|
38
|
+
const dt7 = new DT7 (s)
|
|
39
|
+
|
|
40
|
+
if (dt7.hour !== undefined) return ['XVS-00022', s]
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
if ('payload' in err) return err.payload
|
|
46
|
+
|
|
47
|
+
throw err
|
|
48
|
+
|
|
49
|
+
}
|
|
39
50
|
|
|
40
51
|
}
|
|
41
52
|
|
|
@@ -55,7 +66,7 @@ class XSSimpleTypeDateTime extends XSSimpleTypeDT {
|
|
|
55
66
|
|
|
56
67
|
const dt7 = new DT7 (s)
|
|
57
68
|
|
|
58
|
-
if (dt7.hour === undefined) return
|
|
69
|
+
if (dt7.hour === undefined) return ['XVS-00023', s]
|
|
59
70
|
|
|
60
71
|
}
|
|
61
72
|
|
|
@@ -77,7 +88,7 @@ class XSSimpleTypeDateTimeStamp extends XSSimpleTypeDateTime {
|
|
|
77
88
|
|
|
78
89
|
const dt7 = new DT7 (s)
|
|
79
90
|
|
|
80
|
-
if (dt7.hour === undefined || dt7.tz === undefined) return
|
|
91
|
+
if (dt7.hour === undefined || dt7.tz === undefined) return ['XVS-00024', s]
|
|
81
92
|
|
|
82
93
|
}
|
|
83
94
|
|
|
@@ -53,7 +53,7 @@ class XSSimpleTypeDecimal extends XSSimpleType {
|
|
|
53
53
|
|
|
54
54
|
testLength (value) {
|
|
55
55
|
|
|
56
|
-
return value.length === 0 ? '
|
|
56
|
+
return value.length === 0 ? ['XVS-00013'] : null
|
|
57
57
|
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -67,16 +67,16 @@ class XSSimpleTypeDecimal extends XSSimpleType {
|
|
|
67
67
|
|
|
68
68
|
case CH_PLUS:
|
|
69
69
|
case CH_MINUS:
|
|
70
|
-
if (i !== 0) return
|
|
70
|
+
if (i !== 0) return ['XVS-00014', value, value.charAt (i)]
|
|
71
71
|
continue
|
|
72
72
|
|
|
73
73
|
case CH_PERIOD:
|
|
74
|
-
if (period !== -1) return
|
|
74
|
+
if (period !== -1) return ['XVS-00015', value, i]
|
|
75
75
|
period = i
|
|
76
76
|
continue
|
|
77
77
|
|
|
78
78
|
default:
|
|
79
|
-
if (c < CH_0 || c > CH_9) return
|
|
79
|
+
if (c < CH_0 || c > CH_9) return ['XVS-00016', value, value.charAt (i), i]
|
|
80
80
|
total ++
|
|
81
81
|
if (period !== -1) fraction ++
|
|
82
82
|
|
|
@@ -84,13 +84,19 @@ class XSSimpleTypeDecimal extends XSSimpleType {
|
|
|
84
84
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
if (total === 0) return
|
|
87
|
+
if (total === 0) return ['XVS-00017', value]
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
{
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
const {totalDigits} = this; if (total > totalDigits) return ['XVS-00018', value, total, totalDigits]
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
{
|
|
96
|
+
|
|
97
|
+
const {fractionDigits} = this; if (fraction > fractionDigits) return ['XVS-00019', value, fraction, fractionDigits]
|
|
98
|
+
|
|
99
|
+
}
|
|
94
100
|
|
|
95
101
|
return null
|
|
96
102
|
|
|
@@ -32,13 +32,13 @@ class XSSimpleTypeFloatingPoint extends XSSimpleType {
|
|
|
32
32
|
|
|
33
33
|
testLength (value) {
|
|
34
34
|
|
|
35
|
-
return value.length === 0 ? '
|
|
35
|
+
return value.length === 0 ? ['XVS-00020'] : null
|
|
36
36
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
testFormat (value) {
|
|
40
40
|
|
|
41
|
-
if (Number.isNaN (this.toOrdered (value)) && value !== 'NaN') return
|
|
41
|
+
if (Number.isNaN (this.toOrdered (value)) && value !== 'NaN') return ['XVS-00021', value]
|
|
42
42
|
|
|
43
43
|
return null
|
|
44
44
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const {XSINamespace} = require ('../NamespacesMap')
|
|
2
|
+
const XMLMessages = require ('../XMLMessages')
|
|
2
3
|
|
|
3
4
|
class XMLValidationState {
|
|
4
5
|
|
|
@@ -17,16 +18,16 @@ class XMLValidationState {
|
|
|
17
18
|
}
|
|
18
19
|
catch (cause) {
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
this.warn (cause.message)
|
|
21
22
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
warn (message, cause) {
|
|
28
|
+
|
|
29
|
+
this.parent.warn (message, cause)
|
|
30
|
+
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
setTypeFrom (element) {
|
|
@@ -45,15 +46,7 @@ class XMLValidationState {
|
|
|
45
46
|
|
|
46
47
|
blameNothingExpected () {
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
formatPosition ({src}) {
|
|
53
|
-
|
|
54
|
-
const [line, char] = this.getPosition ()
|
|
55
|
-
|
|
56
|
-
return `${src} at line ${line}, position ${char}`
|
|
49
|
+
this.warn (['XVC-00001', this.parsedNode.src])
|
|
57
50
|
|
|
58
51
|
}
|
|
59
52
|
|
|
@@ -61,7 +54,7 @@ class XMLValidationState {
|
|
|
61
54
|
|
|
62
55
|
const expected = match.allExpected (parsedNode); if (expected == null) this.blameNothingExpected ()
|
|
63
56
|
|
|
64
|
-
|
|
57
|
+
this.warn (['XVC-00002', expected])
|
|
65
58
|
|
|
66
59
|
}
|
|
67
60
|
|
|
@@ -69,7 +62,7 @@ class XMLValidationState {
|
|
|
69
62
|
|
|
70
63
|
if (this.#child !== null) return this.#child.startElement (parsedNode)
|
|
71
64
|
|
|
72
|
-
const {match} = this; if (!match)
|
|
65
|
+
const {match} = this; if (!match) this.warn (['XVC-00001', this.anyType.debugQName])
|
|
73
66
|
|
|
74
67
|
const element = match.getElementDefinition (parsedNode); if (!element) this.blameUnexpectedTag (parsedNode, match)
|
|
75
68
|
|
|
@@ -103,16 +96,15 @@ class XMLValidationState {
|
|
|
103
96
|
|
|
104
97
|
this.#hadText = true
|
|
105
98
|
|
|
106
|
-
|
|
99
|
+
this.validateScalar (text, this.anyType.asSimpleType ())
|
|
107
100
|
|
|
108
|
-
|
|
101
|
+
}
|
|
109
102
|
|
|
110
|
-
|
|
111
|
-
catch (cause) {
|
|
103
|
+
validateScalar (value, type) {
|
|
112
104
|
|
|
113
|
-
|
|
105
|
+
const result = type.test (value ?? '')
|
|
114
106
|
|
|
115
|
-
|
|
107
|
+
if (result) this.warn (result)
|
|
116
108
|
|
|
117
109
|
}
|
|
118
110
|
|
|
@@ -154,7 +146,7 @@ class XMLValidationState {
|
|
|
154
146
|
|
|
155
147
|
if (attributesMap.getNamespaceURI (name) === XSINamespace) continue
|
|
156
148
|
|
|
157
|
-
|
|
149
|
+
this.warn (['XVC-00003', name])
|
|
158
150
|
|
|
159
151
|
}
|
|
160
152
|
|
|
@@ -162,31 +154,18 @@ class XMLValidationState {
|
|
|
162
154
|
|
|
163
155
|
const {attributes: {fixed, type}} = def
|
|
164
156
|
|
|
165
|
-
if (typeof fixed === 'string' && value !== fixed)
|
|
166
|
-
|
|
167
|
-
const validateBy = typeNode => {
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
|
|
171
|
-
this.xs.getSimpleType (typeNode).validateScalar (value)
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
catch (cause) {
|
|
175
|
-
|
|
176
|
-
throw Error (`attribute '${name}": ${cause.message}`, {cause})
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
}
|
|
157
|
+
if (typeof fixed === 'string' && value !== fixed) this.warn (['XVC-00004', name, fixed, value])
|
|
181
158
|
|
|
182
159
|
if (type) {
|
|
183
160
|
|
|
184
|
-
|
|
161
|
+
this.validateScalar (value, this.xs.getSimpleType (this.xs.getType (type)))
|
|
185
162
|
|
|
186
163
|
}
|
|
187
164
|
else {
|
|
188
165
|
|
|
189
|
-
for (const node of def.children)
|
|
166
|
+
for (const node of def.children)
|
|
167
|
+
|
|
168
|
+
this.validateScalar (value, this.xs.getSimpleType (node))
|
|
190
169
|
|
|
191
170
|
}
|
|
192
171
|
|
|
@@ -194,7 +173,7 @@ class XMLValidationState {
|
|
|
194
173
|
|
|
195
174
|
for (const [name, def] of attributes) if (!matched.has (def)) {
|
|
196
175
|
|
|
197
|
-
if (def.attributes.use === 'required')
|
|
176
|
+
if (def.attributes.use === 'required') this.warn (['XVC-00005', name])
|
|
198
177
|
|
|
199
178
|
if ('default' in def.attributes) attributesMap.set (name, def.attributes.default)
|
|
200
179
|
|
|
@@ -4,15 +4,23 @@ class XMLValidatior {
|
|
|
4
4
|
|
|
5
5
|
#state = null
|
|
6
6
|
|
|
7
|
-
constructor (xs, rootNode,
|
|
7
|
+
constructor (xs, rootNode, position) {
|
|
8
8
|
|
|
9
9
|
this.xs = xs
|
|
10
|
-
this.
|
|
10
|
+
this.position = position
|
|
11
11
|
|
|
12
12
|
this.startElement (rootNode)
|
|
13
13
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
warn (message) {
|
|
17
|
+
|
|
18
|
+
const {position} = this
|
|
19
|
+
|
|
20
|
+
throw Error (Array.isArray (message) ? position.format (message) : this.position + message)
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
startElement (parsedNode) {
|
|
17
25
|
|
|
18
26
|
if (this.#state === null) return this.#state = new XMLValidationState (this, parsedNode, this.xs.getSchema (parsedNode.namespaceURI).getElement (parsedNode.localName))
|