xml-toolkit 1.0.59 → 1.0.61

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 CHANGED
@@ -20,7 +20,8 @@ module.exports = {
20
20
  XMLNode: require ('./lib/XMLNode'),
21
21
  XMLLexer: require ('./lib/XMLLexer'),
22
22
  XMLParser: require ('./lib/XMLParser'),
23
- XMLPrinter: require ('./lib/XMLPrinter'),
23
+ XMLPrinter: require ('./lib/printer/XMLPrinter'),
24
+ XMLStreamPrinter: require ('./lib/printer/XMLStreamPrinter'),
24
25
  XMLReader: require ('./lib/XMLReader'),
25
26
  XMLSchema: require ('./lib/XMLSchema'),
26
27
  XMLSchemaBuiltIn: require ('./lib/XMLSchemaBuiltIn'),
@@ -1,6 +1,8 @@
1
1
  const assert = require ('assert')
2
2
  const NamespacePrefixesMap = require ('./NamespacePrefixesMap.js')
3
- const XMLPrinter = require ('./XMLPrinter.js')
3
+ const XMLPrinter = require ('./printer/XMLPrinter.js')
4
+ const XMLStreamPrinter = require ('./printer/XMLStreamPrinter.js')
5
+ const {Readable} = require ('node:stream')
4
6
 
5
7
  const XSI_TYPE = Symbol.for ('type')
6
8
 
@@ -15,10 +17,10 @@ const XMLMarshaller = class {
15
17
  this.schemaElement = this.schema.get (localName); assert (this.schemaElement, 'No schema element found for namespaceURI = ' + namespaceURI + ', localName = ' + localName)
16
18
 
17
19
  this.ns = new NamespacePrefixesMap (xs)
18
-
20
+
19
21
  this.isNsDumped = false
20
-
21
- this.printer = new XMLPrinter (printerOptions)
22
+
23
+ this.printer = new ('out' in printerOptions ? XMLStreamPrinter : XMLPrinter) (printerOptions)
22
24
 
23
25
  }
24
26
 
@@ -40,7 +42,18 @@ const XMLMarshaller = class {
40
42
 
41
43
  try {
42
44
 
43
- this.appendElement (schemaElement, data, this.ns.QName (o.localName || attributes.name, targetNamespace))
45
+ const result = this.appendElement (schemaElement, data, this.ns.QName (o.localName || attributes.name, targetNamespace))
46
+
47
+ if (result instanceof Promise) {
48
+
49
+ result.then (printer.end, printer.destroy)
50
+
51
+ }
52
+ else {
53
+
54
+ return printer.text
55
+
56
+ }
44
57
 
45
58
  }
46
59
  catch (cause) {
@@ -51,17 +64,17 @@ const XMLMarshaller = class {
51
64
 
52
65
  }
53
66
 
54
- return printer.text
55
-
56
67
  }
57
68
 
58
69
  appendElement (node, data, qName) {
59
70
 
60
71
  this.appendStartTag (node, data, qName)
61
-
62
- this.appendElementBody (node, data)
63
-
64
- this.printer.closeElement ()
72
+
73
+ const result = this.appendElementBody (node, data), finish = () => this.printer.closeElement ()
74
+
75
+ if (!(result instanceof Promise)) return finish ()
76
+
77
+ return result.then (finish, this.printer.destroy)
65
78
 
66
79
  }
67
80
 
@@ -71,7 +84,7 @@ const XMLMarshaller = class {
71
84
 
72
85
  if (!this.isNsDumped) {
73
86
 
74
- this.printer.text += this.ns
87
+ this.printer.write (this.ns.toString ())
75
88
 
76
89
  this.isNsDumped = true
77
90
 
@@ -110,13 +123,19 @@ const XMLMarshaller = class {
110
123
  const {attributes: {type}, children} = node
111
124
 
112
125
  if (data && data [XSI_TYPE]) {
113
- let d = {}; for (let k in data) d [k] = data [k]
114
- this.appendContent (this.schema.getType (data [XSI_TYPE]), d)
126
+
127
+ const d = {}; for (let k in data) d [k] = data [k]
128
+
129
+ return this.appendContent (this.schema.getType (data [XSI_TYPE]), d)
130
+
115
131
  }
132
+ else if (type) {
116
133
 
117
- if (type) return this.appendContent (this.xs.getType (type), data)
134
+ return this.appendContent (this.xs.getType (type), data)
118
135
 
119
- for (const i of children) this.appendContent (i, data)
136
+ }
137
+
138
+ return this.appendAllContent (children, data)
120
139
 
121
140
  }
122
141
 
@@ -142,7 +161,7 @@ const XMLMarshaller = class {
142
161
 
143
162
  return this.printer.writeAttribute (
144
163
  this.ns.QName (name, targetNamespace),
145
- this.xs.getAttributeSimpleType (node).stringify (v)
164
+ this.xs.getAttributeSimpleType (node).stringify (v) // throws
146
165
  )
147
166
 
148
167
  case 'extension':
@@ -178,7 +197,7 @@ const XMLMarshaller = class {
178
197
 
179
198
  const type = this.xs.getSimpleType (node)
180
199
 
181
- const xml = type.stringify (data)
200
+ const xml = type.stringify (data) // throws
182
201
 
183
202
  this.printer.writeCharacters (xml)
184
203
 
@@ -192,6 +211,8 @@ const XMLMarshaller = class {
192
211
 
193
212
  const qName = this.ns.QName (name, targetNamespace)
194
213
 
214
+ if (v instanceof Readable) return this.printer.forEach (v, d => this.appendElement (node, d, qName))
215
+
195
216
  if (!Array.isArray (v)) return this.appendElement (node, v, qName)
196
217
 
197
218
  for (const d of v) this.appendElement (node, d, qName)
@@ -199,17 +220,29 @@ const XMLMarshaller = class {
199
220
  return
200
221
 
201
222
  case 'extension':
202
-
203
- this.appendContent (this.xs.getType (attributes.base), data)
204
-
223
+
224
+ return this.appendAllContent ([this.xs.getType (attributes.base), ...children], data)
225
+
205
226
  default:
206
227
 
207
- for (const i of children) this.appendContent (i, data)
228
+ return this.appendAllContent (children, data)
208
229
 
209
230
  }
210
231
 
211
232
  }
212
-
233
+
234
+ appendAllContent (list, data) {
235
+
236
+ for (let i = 0; i < list.length; i ++) {
237
+
238
+ const result = this.appendContent (list [i], data); if (!(result instanceof Promise)) continue
239
+
240
+ return result.then (this.appendAllContent (list.slice (i + 1), data), this.printer.destroy)
241
+
242
+ }
243
+
244
+ }
245
+
213
246
  }
214
247
 
215
248
  module.exports = XMLMarshaller
package/lib/XMLNode.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const SAXEvent = require ('./SAXEvent.js')
2
- const XMLPrinter = require ('./XMLPrinter.js')
2
+ const XMLPrinter = require ('./printer/XMLPrinter.js')
3
3
  const NamespacesMap = require ('./NamespacesMap')
4
4
  const MoxyLikeJsonEncoder = require ('./MoxyLikeJsonEncoder')
5
5
 
package/lib/XMLSchema.js CHANGED
@@ -110,18 +110,18 @@ const XMLSchema = class extends Map {
110
110
  const {localName} = node
111
111
 
112
112
  for (const e of node.children) this.copyTargetNamespace (e, localName === 'schema')
113
-
113
+
114
114
  const {formDefault} = this; if (!(localName in formDefault)) return
115
-
115
+
116
116
  if (!force) {
117
-
118
- const {form} = node.attributes
119
-
120
- if (form !== FORM_Q && formDefault [localName] !== FORM_Q) return
117
+
118
+ const form = node.attributes?.form || formDefault [localName]
119
+
120
+ if (form !== FORM_Q) return
121
121
 
122
122
  }
123
123
 
124
- node.targetNamespace = this.targetNamespace
124
+ node.targetNamespace = this.targetNamespace
125
125
 
126
126
  }
127
127
 
@@ -1,6 +1,6 @@
1
1
  const os = require ('os')
2
2
  const stringEscape = require ('string-escape-map')
3
- const SAXEvent = require ('./SAXEvent.js')
3
+ const SAXEvent = require ('../SAXEvent.js')
4
4
 
5
5
  const CH_QQ = '"'.charCodeAt (0)
6
6
  const CH_GT = '>'.charCodeAt (0)
@@ -19,7 +19,7 @@ const ESC = [
19
19
 
20
20
  const isSafeNonNegative = value => Number.isSafeInteger (value) && value >= 0
21
21
 
22
- const XMLPrinter = class {
22
+ module.exports = class {
23
23
 
24
24
  constructor (o = {}) {
25
25
 
@@ -85,7 +85,6 @@ const XMLPrinter = class {
85
85
 
86
86
  reset () {
87
87
 
88
- this.text = ''
89
88
  this.stack = []
90
89
  this.isOpening = false
91
90
 
@@ -97,15 +96,7 @@ const XMLPrinter = class {
97
96
 
98
97
  newLine (delta = 0) {
99
98
 
100
- this.text += `${this.EOL}${this.space.repeat (this.level + this.stack.length + delta)}`
101
-
102
- }
103
-
104
- get lastCharCode () {
105
-
106
- const {text} = this
107
-
108
- return text.charCodeAt (text.length - 1)
99
+ this.write (`${this.EOL}${this.space.repeat (this.level + this.stack.length + delta)}`)
109
100
 
110
101
  }
111
102
 
@@ -113,12 +104,12 @@ const XMLPrinter = class {
113
104
 
114
105
  if (this.stack.length !== 0) {
115
106
  if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine (-1)
116
- if (this.isOpening) this.text += `>`
107
+ if (this.isOpening) this.write (`>`)
117
108
  }
118
109
 
119
- if (this.space && this.text) this.newLine ()
110
+ if (this.space && !this.isVirgin) this.newLine ()
120
111
 
121
- this.text += `<${name}`
112
+ this.write (`<${name}`)
122
113
  this.stack.push (name)
123
114
 
124
115
  this.isOpening = true
@@ -139,16 +130,16 @@ const XMLPrinter = class {
139
130
 
140
131
  this.newLine (-1)
141
132
 
142
- this.text += this.attrSpace
133
+ this.write (this.attrSpace)
143
134
 
144
135
  }
145
136
  else {
146
137
 
147
- this.text += ' '
138
+ this.write (' ')
148
139
 
149
140
  }
150
141
 
151
- this.text += `${name}="${this.ESC_ATTR.escape (value)}"`
142
+ this.write (`${name}="${this.ESC_ATTR.escape (value)}"`)
152
143
 
153
144
  return this
154
145
 
@@ -170,11 +161,11 @@ const XMLPrinter = class {
170
161
 
171
162
  if (this.isOpening) {
172
163
  if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine (-1)
173
- this.text += `>`
164
+ this.write (`>`)
174
165
  this.isOpening = false
175
166
  }
176
167
 
177
- this.text += value
168
+ this.write (value)
178
169
 
179
170
  return this
180
171
 
@@ -186,12 +177,12 @@ const XMLPrinter = class {
186
177
 
187
178
  if (this.isOpening) {
188
179
  if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine ()
189
- this.text += ` />`
180
+ this.write (` />`)
190
181
  this.isOpening = false
191
182
  }
192
183
  else {
193
184
  if (this.space && this.lastCharCode === CH_GT) this.newLine ()
194
- this.text += `</${name}>`
185
+ this.write (`</${name}>`)
195
186
  }
196
187
 
197
188
  return this
@@ -271,18 +262,16 @@ const XMLPrinter = class {
271
262
 
272
263
  if (this.stack.length !== 0) throw Error ('The document is already started')
273
264
 
274
- this.text += '<?xml version="1.0"'
265
+ this.write ('<?xml version="1.0"')
275
266
 
276
- if (encoding != null) this.text += ` encoding="${encoding}"`
267
+ if (encoding != null) this.write (` encoding="${encoding}"`)
277
268
 
278
- if (standalone != null) this.text += ` standalone="${standalone ? 'yes' : 'no'}"`
269
+ if (standalone != null) this.write (` standalone="${standalone ? 'yes' : 'no'}"`)
279
270
 
280
- this.text += '?>'
271
+ this.write ('?>')
281
272
 
282
273
  return this
283
274
 
284
- }
285
-
286
- }
275
+ }
287
276
 
288
- module.exports = XMLPrinter
277
+ }
@@ -0,0 +1,39 @@
1
+ const XMLPrinter = class extends (require ('./Base.js')) {
2
+
3
+ get destroy () {
4
+
5
+ return err => {throw err}
6
+
7
+ }
8
+
9
+ reset () {
10
+
11
+ this.text = ''
12
+
13
+ return super.reset ()
14
+
15
+ }
16
+
17
+ get lastCharCode () {
18
+
19
+ const {text} = this
20
+
21
+ return text.charCodeAt (text.length - 1)
22
+
23
+ }
24
+
25
+ get isVirgin () {
26
+
27
+ return this.text.length === 0
28
+
29
+ }
30
+
31
+ write (s) {
32
+
33
+ this.text += s
34
+
35
+ }
36
+
37
+ }
38
+
39
+ module.exports = XMLPrinter
@@ -0,0 +1,122 @@
1
+ const {Writable} = require ('node:stream')
2
+
3
+ const XMLStreamPrinter = class extends (require ('./Base.js')) {
4
+
5
+ #inStreams = []
6
+ #isVirgin = true
7
+ #lastCharCode = 0
8
+ #open = true
9
+
10
+ constructor (o) {
11
+
12
+ if (!o || typeof o !== 'object' || !('out' in o)) throw Error (`XMLStreamPrinter requires an .out option`)
13
+ if (!(o.out instanceof Writable)) throw Error (`.out must be Writable, ${typeof o.out} ${o.out} found`)
14
+
15
+ super (o)
16
+
17
+ this.out = o.out
18
+ this.out.on ('drain', () => this.open = true)
19
+
20
+ }
21
+
22
+ get end () {
23
+
24
+ return () => this.out.end ()
25
+
26
+ }
27
+
28
+ get destroy () {
29
+
30
+ return err => this.out.destroy (err)
31
+
32
+ }
33
+
34
+ get inStream () {
35
+
36
+ return this.#inStreams.at (-1)
37
+
38
+ }
39
+
40
+ forEach (stream, onData) {
41
+
42
+ if (this.#inStreams.length !== 0) return this.destroy (Error ('Nested streams not yet supported'))
43
+
44
+ if (!this.#open) stream.pause ()
45
+
46
+ this.#inStreams.push (stream)
47
+
48
+ return new Promise ((ok, fail) => {
49
+
50
+ stream.on ('error', err => {
51
+
52
+ this.destroy (err)
53
+
54
+ fail (err)
55
+
56
+ })
57
+
58
+ stream.on ('end', () => {
59
+
60
+ this.#inStreams.pop ()
61
+
62
+ ok ()
63
+
64
+ })
65
+
66
+ stream.on ('data', data => {
67
+
68
+ try {
69
+
70
+ onData (data)
71
+
72
+ }
73
+ catch (err) {
74
+
75
+ stream.destroy (err)
76
+
77
+ }
78
+
79
+ })
80
+
81
+ })
82
+
83
+ }
84
+
85
+ set open (nowOpen) {
86
+
87
+ const wasOpen = this.#open; if (wasOpen === nowOpen) return
88
+
89
+ this.#open = nowOpen
90
+
91
+ if (!this.inStream) return
92
+
93
+ nowOpen ? this.inStream.resume () : this.inStream.pause ()
94
+
95
+ }
96
+
97
+ get lastCharCode () {
98
+
99
+ return this.#lastCharCode
100
+
101
+ }
102
+
103
+ get isVirgin () {
104
+
105
+ return this.#isVirgin
106
+
107
+ }
108
+
109
+ write (s) {
110
+
111
+ const {length} = s; if (length === 0) return
112
+
113
+ this.#lastCharCode = s.charCodeAt (length - 1)
114
+ this.#isVirgin = false
115
+
116
+ this.open = this.out.write (s)
117
+
118
+ }
119
+
120
+ }
121
+
122
+ module.exports = XMLStreamPrinter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xml-toolkit",
3
- "version": "1.0.59",
3
+ "version": "1.0.61",
4
4
  "description": "XML parser, marshaller, SOAP adapter",
5
5
  "main": "index.js",
6
6
  "files": [