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.
@@ -0,0 +1,130 @@
1
+ const {XSSimpleType} = require ('./XSSimpleType.js')
2
+
3
+ const CH_PLUS = '+'.charCodeAt (0)
4
+ const CH_MINUS = '-'.charCodeAt (0)
5
+ const CH_PERIOD = '.'.charCodeAt (0)
6
+ const CH_0 = '0'.charCodeAt (0)
7
+ const CH_9 = '9'.charCodeAt (0)
8
+
9
+ class XSSimpleTypeDecimal extends XSSimpleType {
10
+
11
+ #fractionDigits = undefined
12
+ #totalDigits = undefined
13
+
14
+ get name () {
15
+ return 'decimal'
16
+ }
17
+
18
+ isValidNumber (num) {
19
+
20
+ return !Number.isNaN (num)
21
+
22
+ }
23
+
24
+ toOrdered (value) {
25
+
26
+ return parseFloat (value)
27
+
28
+ }
29
+
30
+ set totalDigits (v) {
31
+
32
+ this.#totalDigits = parseInt (v)
33
+
34
+ }
35
+
36
+ get totalDigits () {
37
+
38
+ return this.#totalDigits ?? super.totalDigits ?? Infinity
39
+
40
+ }
41
+
42
+ set fractionDigits (v) {
43
+
44
+ this.#fractionDigits = parseInt (v)
45
+
46
+ }
47
+
48
+ get fractionDigits () {
49
+
50
+ return this.#fractionDigits ?? super.fractionDigits ?? Infinity
51
+
52
+ }
53
+
54
+ testLength (value) {
55
+
56
+ return value.length === 0 ? 'No decimal value can be empty' : null
57
+
58
+ }
59
+
60
+ testFormat (value) {
61
+
62
+ let period = -1, total = 0, fraction = 0
63
+
64
+ for (let i = 0; i < value.length; i ++) {
65
+
66
+ const c = value.charCodeAt (i); switch (c) {
67
+
68
+ case CH_PLUS:
69
+ case CH_MINUS:
70
+ if (i !== 0) return `'${value}' is not a valid decimal: '${value.charAt (i)}' can occur only at the beginning`
71
+ continue
72
+
73
+ case CH_PERIOD:
74
+ if (period !== -1) return `'${value}' is not a valid decimal: 2nd period occured at position ${i}`
75
+ period = i
76
+ continue
77
+
78
+ default:
79
+ if (c < CH_0 || c > CH_9) return `'${value}' is not a valid decimal: '${value.charAt (i)}' occured at position ${i}`
80
+ total ++
81
+ if (period !== -1) fraction ++
82
+
83
+ }
84
+
85
+ }
86
+
87
+ if (total === 0) return `'${value}' is not a valid decimal: is has no digits at all`
88
+
89
+ const {totalDigits, fractionDigits} = this
90
+
91
+ if (total > totalDigits) return `'${value}' has ${total} digits, only ${totalDigits} allowed`
92
+
93
+ if (fraction > fractionDigits) return `'${value}' has ${fraction} digits after period, only ${fractionDigits} allowed`
94
+
95
+ return null
96
+
97
+ }
98
+
99
+ stringify (value) {
100
+
101
+ let num = value
102
+
103
+ const {fractionDigits} = this
104
+
105
+ const t = typeof value; switch (t) {
106
+
107
+ case 'bigint':
108
+ return fractionDigits === 0 || fractionDigits === Infinity ?
109
+ String (value) :
110
+ `${value}.${'0'.repeat (fractionDigits)}`
111
+
112
+ case 'string':
113
+ num = parseFloat (value)
114
+
115
+ case 'number':
116
+ if (!this.isValidNumber (num)) this.blame (value, 'cannot be read as number')
117
+ return fractionDigits === Infinity ?
118
+ num.toString () :
119
+ num.toFixed (this.fractionDigits)
120
+
121
+ default:
122
+ this.blame (value, `no idea how to treat ${t} as decimal`)
123
+
124
+ }
125
+
126
+ }
127
+
128
+ }
129
+
130
+ module.exports = XSSimpleTypeDecimal
@@ -0,0 +1,80 @@
1
+ const {XSSimpleType} = require ('./XSSimpleType.js')
2
+
3
+ class XSSimpleTypeFloatingPoint extends XSSimpleType {
4
+
5
+ stringify (value) {
6
+
7
+ const verbatim = value
8
+
9
+ if (Number.isNaN (value)) return 'NaN'
10
+
11
+ if (typeof value !== 'number') value = this.toOrdered (value)
12
+
13
+ if (Number.isNaN (value)) this.blame (verbatim, 'Not a number, yet not NaN')
14
+
15
+ switch (value) {
16
+ case Number.POSITIVE_INFINITY: return 'INF'
17
+ case Number.NEGATIVE_INFINITY: return '-INF'
18
+ default: return String (value)
19
+ }
20
+
21
+ }
22
+
23
+ get name () {
24
+ return 'float'
25
+ }
26
+
27
+ toOrdered (value) {
28
+
29
+ return parseFloat (value)
30
+
31
+ }
32
+
33
+ testLength (value) {
34
+
35
+ return value.length === 0 ? 'No floating point number can be empty' : null
36
+
37
+ }
38
+
39
+ testFormat (value) {
40
+
41
+ if (Number.isNaN (this.toOrdered (value)) && value !== 'NaN') return `'${value}' is not a floating point number`
42
+
43
+ return null
44
+
45
+ }
46
+
47
+ }
48
+
49
+ class XSSimpleTypeFloat extends XSSimpleTypeFloatingPoint {
50
+
51
+ constructor (xs) {
52
+
53
+ super (xs)
54
+ this.maxInclusive = 3.4028235E+38
55
+ this.minInclusive = -this.maxInclusive
56
+
57
+ }
58
+
59
+ }
60
+
61
+ class XSSimpleTypeDouble extends XSSimpleTypeFloatingPoint {
62
+
63
+ constructor (xs) {
64
+
65
+ super (xs)
66
+ this.maxInclusive = 1.7976931348623157E+308
67
+ this.minInclusive = -this.maxInclusive
68
+
69
+ }
70
+
71
+ }
72
+
73
+ module.exports = {
74
+ XSSimpleTypeFloat,
75
+ XSSimpleTypeDouble,
76
+ byName: {
77
+ 'float' : XSSimpleTypeFloat,
78
+ 'double': XSSimpleTypeDouble,
79
+ }
80
+ }
@@ -0,0 +1,72 @@
1
+ const XSSimpleTypeDecimal = require ('./XSSimpleTypeDecimal')
2
+
3
+ const fromTo = (minInclusive, maxInclusive) => class extends XSSimpleTypeInteger {
4
+
5
+ constructor (xs) {
6
+
7
+ super (xs)
8
+ this.minInclusive = minInclusive
9
+ this.maxInclusive = maxInclusive
10
+
11
+ }
12
+
13
+ }
14
+
15
+ class XSSimpleTypeInteger extends XSSimpleTypeDecimal {
16
+
17
+ get name () {
18
+ return 'integer'
19
+ }
20
+
21
+ toOrdered (value) {
22
+
23
+ return BigInt (value)
24
+
25
+ }
26
+
27
+ set fractionDigits (v) {
28
+
29
+ if (v != '0') throw Error (`For an integer type, fractionDigits must be 0, not ${v}`)
30
+
31
+ }
32
+
33
+ get fractionDigits () {
34
+
35
+ return 0
36
+
37
+ }
38
+
39
+ isValidNumber (num) {
40
+
41
+ return Number.isInteger (num)
42
+
43
+ }
44
+
45
+ }
46
+
47
+ module.exports = {
48
+
49
+ XSSimpleTypeInteger,
50
+
51
+ byName: {
52
+
53
+ integer : XSSimpleTypeInteger,
54
+
55
+ negativeInteger : fromTo (undefined, 1n),
56
+ nonPositiveInteger : fromTo (undefined, 0n),
57
+ nonNegativeInteger : fromTo (0n, undefined),
58
+ positiveInteger : fromTo (1n, undefined),
59
+
60
+ unsignedLong : fromTo ( 0n, 18446744073709551615n),
61
+ unsignedInt : fromTo ( 0n, 4294967295n),
62
+ unsignedShort : fromTo ( 0n, 65535n),
63
+ unsignedByte : fromTo ( 0n, 255n),
64
+
65
+ long : fromTo (-9223372036854775808n, 9223372036854775807n),
66
+ int : fromTo (-2147483648n, 2147483647n),
67
+ short : fromTo (-32768n, 32767n),
68
+ byte : fromTo (-128n, 127n),
69
+
70
+ }
71
+
72
+ }
@@ -0,0 +1,24 @@
1
+ const {XSSimpleType} = require ('./XSSimpleType.js')
2
+ const NamespacePrefixesMap = require ('../NamespacePrefixesMap.js')
3
+
4
+ class XSSimpleTypeQName extends XSSimpleType {
5
+
6
+ get name () {
7
+ return 'QName'
8
+ }
9
+
10
+ stringify (value) {
11
+
12
+ if (typeof value !== 'object' || !('localName' in value)) this.blame (value, 'not a {localName} object')
13
+
14
+ const {xs} = this
15
+
16
+ if (!xs.ns) xs.ns = new NamespacePrefixesMap (xs)
17
+
18
+ return xs.ns.QName (value.localName, value.namespaceURI)
19
+
20
+ }
21
+
22
+ }
23
+
24
+ module.exports = XSSimpleTypeQName
@@ -0,0 +1,54 @@
1
+ class Match {
2
+
3
+ constructor (occurable) {
4
+
5
+ this.occurable = occurable
6
+ this.occured = 0
7
+
8
+ }
9
+
10
+ get isSatisfied () {
11
+
12
+ return this.occured >= this.occurable.minOccurs
13
+
14
+ }
15
+
16
+ get isMaxedOut () {
17
+
18
+ return this.occured >= this.occurable.maxOccurs
19
+
20
+ }
21
+
22
+ allExpected (node) {
23
+
24
+ const all = new Set ([...this.expected (node ['_ns_map'])])
25
+
26
+ switch (all.size) {
27
+
28
+ case 0: return null
29
+
30
+ case 1: for (const first of all) return first
31
+
32
+ default: return `(${[...all].sort ().join (' | ')})`
33
+
34
+ }
35
+
36
+ }
37
+
38
+ // toString () {
39
+
40
+ // const {occurable: {minOccurs, maxOccurs}, occured} = this
41
+
42
+ // return `[${minOccurs} .. ${maxOccurs}]: ${occured}`
43
+
44
+ // }
45
+
46
+ getElementDefinition (node) {
47
+
48
+ return this.isMaxedOut ? null : this.getNextElementDefinition (node)
49
+
50
+ }
51
+
52
+ }
53
+
54
+ module.exports = Match
@@ -0,0 +1,33 @@
1
+ const Match = require ('./Match')
2
+
3
+ class All extends Match {
4
+
5
+ getNextElementDefinition (node) {
6
+
7
+ for (const child of this.children) if (child.occured === 0) {
8
+
9
+ const el = child.getElementDefinition (node); if (el === null) continue
10
+
11
+ this.occured = 1; for (const child of this.children) if (child.occured === 0) this.occured = 0
12
+
13
+ return el
14
+
15
+ }
16
+
17
+ return null
18
+
19
+ }
20
+
21
+ * expected (nsMap) {
22
+
23
+ for (const child of this.children)
24
+
25
+ if (!child.isSatisfied)
26
+
27
+ for (const n of child.expected (nsMap)) yield n
28
+
29
+ }
30
+
31
+ }
32
+
33
+ module.exports = All
@@ -0,0 +1,15 @@
1
+ const Match = require ('./Match')
2
+
3
+ class Any extends Match {
4
+
5
+ getNextElementDefinition () {
6
+
7
+ this.occured ++
8
+
9
+ return this.occurable.node
10
+
11
+ }
12
+
13
+ }
14
+
15
+ module.exports = Any
@@ -0,0 +1,74 @@
1
+ const Match = require ('./Match')
2
+
3
+ class MatchChoice extends Match {
4
+
5
+ #filteredChildren = null
6
+
7
+ constructor (occurable) {
8
+
9
+ super (occurable)
10
+
11
+ }
12
+
13
+ get filteredChildren () {
14
+
15
+ if (this.#filteredChildren === null) this.#filteredChildren = this.children
16
+
17
+ return this.#filteredChildren
18
+
19
+ }
20
+
21
+ getNextElementDefinition (node) {
22
+
23
+ for (const child of this.filteredChildren) {
24
+
25
+ const el = child.getElementDefinition (node); if (el === null) continue
26
+
27
+ if (child.isSatisfied) {
28
+
29
+ this.occured ++
30
+
31
+ for (const child of (this.#filteredChildren = this.children)) child.occured = 0
32
+
33
+ }
34
+ else {
35
+
36
+ this.#filteredChildren = [child]
37
+
38
+ }
39
+
40
+ return el
41
+
42
+ }
43
+
44
+ return null
45
+
46
+ }
47
+
48
+ get isSatisfied () {
49
+
50
+ const {occured, occurable: {minOccurs}} = this
51
+
52
+ if (occured >= minOccurs) return true
53
+
54
+ if (occured < minOccurs - 1) return false
55
+
56
+ for (const child of (this.filteredChildren)) if (child.isSatisfied) return true
57
+
58
+ return false
59
+
60
+ }
61
+
62
+ * expected (nsMap) {
63
+
64
+ for (const child of this.filteredChildren)
65
+
66
+ // if (!child.isSatisfied)
67
+
68
+ for (const n of child.expected ()) yield n
69
+
70
+ }
71
+
72
+ }
73
+
74
+ module.exports = MatchChoice
@@ -0,0 +1,45 @@
1
+ const Match = require ('./Match')
2
+
3
+ class MatchElement extends Match {
4
+
5
+ getNextElementDefinition ({namespaceURI, localName}) {
6
+
7
+ const {node: {attributes: {name}, targetNamespace}} = this.occurable
8
+
9
+ if (localName !== name || namespaceURI != targetNamespace) return null
10
+
11
+ this.occured ++
12
+
13
+ return this.occurable.node
14
+
15
+ }
16
+
17
+ get clarkNotation () {
18
+
19
+ const {occurable: {node: {attributes: {name}, targetNamespace}}} = this
20
+
21
+ return `{${targetNamespace}}${name}`
22
+
23
+ }
24
+
25
+ * expected (nsMap) {
26
+
27
+ if (this.isMaxedOut) return
28
+
29
+ const {occurable: {node: {attributes: {name}, targetNamespace}}} = this
30
+
31
+ if (!nsMap) return yield this.clarkNotation
32
+
33
+ for (const qName of nsMap.getQNames (name, targetNamespace)) return yield `<${qName}>`
34
+
35
+ }
36
+
37
+ // toString () {
38
+
39
+ // return this.clarkNotation + ' ' + super.toString ()
40
+
41
+ // }
42
+
43
+ }
44
+
45
+ module.exports = MatchElement
@@ -0,0 +1,84 @@
1
+ const Match = require ('./Match')
2
+
3
+ class MatchSequence extends Match {
4
+
5
+ constructor (occurable) {
6
+
7
+ super (occurable)
8
+
9
+ this.index = 0
10
+
11
+ }
12
+
13
+ getElementDefinition (node) {
14
+
15
+ const {children} = this, {length} = children; if (length === 0) return null
16
+
17
+ while (!this.isMaxedOut) {
18
+
19
+ const child = children [this.index], el = child.getElementDefinition (node)
20
+
21
+ if (el !== null) return el
22
+
23
+ if (!child.isSatisfied) return null
24
+
25
+ if ((++ this.index) < length) continue
26
+
27
+ this.index = 0
28
+
29
+ this.occured ++
30
+
31
+ }
32
+
33
+ return null
34
+
35
+ }
36
+
37
+ get isSatisfied () {
38
+
39
+ const {children} = this, {length} = children; if (length === 0) return true
40
+
41
+ for (let i = this.index + 1; i < length; i ++) {
42
+
43
+ if (children [i].isSatisfied) continue
44
+
45
+ // console.log (children [i])
46
+
47
+ return false
48
+
49
+ }
50
+
51
+ return (this.occured + 1) >= this.occurable.minOccurs
52
+
53
+ }
54
+
55
+ * expected (nsMap) {
56
+
57
+ const {children} = this, {length} = children; if (length === 0) return
58
+
59
+ for (const n of children [this.index].expected (nsMap)) yield n
60
+
61
+ if (!children [this.index].isSatisfied) return
62
+
63
+ for (let i = this.index + 1; i < length; i ++) {
64
+
65
+ const child = children [i]
66
+
67
+ for (const n of child.expected (nsMap)) yield n
68
+
69
+ // if (child.minOccurs > 0) break
70
+
71
+ }
72
+
73
+ }
74
+
75
+ // toString () {
76
+
77
+ // return `<${this.children.join ('; ')}>@${this.index} ${super.toString ()}`
78
+
79
+ // }
80
+
81
+
82
+ }
83
+
84
+ module.exports = MatchSequence
@@ -0,0 +1,88 @@
1
+ const CLASS_MAP = {
2
+ 'all': require ('./MatchAll'),
3
+ 'any': require ('./MatchAny'),
4
+ 'choice': require ('./MatchChoice'),
5
+ 'element': require ('./MatchElement'),
6
+ 'sequence': require ('./MatchSequence'),
7
+ }
8
+
9
+ const parseOccurs = v => v == null ? 1 : v === 'unbounded' ? Infinity : parseInt (v)
10
+
11
+ class Occurable {
12
+
13
+ node
14
+
15
+ constructor (arg, xs, minOccurs, maxOccurs) {
16
+
17
+ if (xs) this.xs = xs
18
+
19
+ this.children = []
20
+
21
+ if (Array.isArray (arg)) {
22
+
23
+ this.type = 'sequence'
24
+ this.minOccurs = 1
25
+ this.maxOccurs = 1
26
+
27
+ for (const o of arg) {
28
+
29
+ if (o.type === 'sequence' && o.minOccurs === 1 && o.maxOccurs === 1) {
30
+
31
+ this.children = this.children.concat (o.children)
32
+
33
+ }
34
+ else {
35
+
36
+ this.children.push (o)
37
+
38
+ }
39
+
40
+ }
41
+
42
+ }
43
+ else {
44
+
45
+ const node = arg
46
+
47
+ this.node = node
48
+
49
+ this.type = node.localName
50
+
51
+ this.minOccurs = parseOccurs (minOccurs ?? node.attributes ['minOccurs'])
52
+ this.maxOccurs = parseOccurs (maxOccurs ?? node.attributes ['maxOccurs'])
53
+
54
+ this.scan ()
55
+
56
+ }
57
+
58
+ }
59
+
60
+ scan () {
61
+
62
+ for (let node of this.node.children) switch (node.localName) {
63
+ case 'any':
64
+ case 'all':
65
+ case 'choice':
66
+ case 'sequence':
67
+ case 'element':
68
+ const {minOccurs, maxOccurs} = node.attributes
69
+ while ('ref' in node.attributes) node = this.xs.getByReference (node.attributes.ref)
70
+ this.children.push (new Occurable (node, this.xs, minOccurs, maxOccurs))
71
+ break
72
+ }
73
+
74
+ }
75
+
76
+ createMatch () {
77
+
78
+ const {type} = this, m = new CLASS_MAP [type] (this)
79
+
80
+ if (type !== 'element') m.children = this.children.map (o => o.createMatch ())
81
+
82
+ return m
83
+
84
+ }
85
+
86
+ }
87
+
88
+ module.exports = Occurable