xml-twig 1.2.80 → 1.2.81

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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/twig.js +121 -121
package/README.md CHANGED
@@ -32,7 +32,7 @@ npm install xml-twig
32
32
  npm install node-expat
33
33
 
34
34
  ```
35
- In my tests I parsed a 750 MB big XML file, the `node-expat` is around two times faster than `sax` (node-expat: 2:20 Minutes, sax: 4:20 Minutes). However, you may run into problems when you try to install the `node-expat` parser. That's the reason why `node-expat` parsers is not installed automatically.
35
+ In my tests I parsed a 750 MB big XML file, the `node-expat` is around two times faster than `sax` (node-expat: 2:20 Minutes, sax: 4:20 Minutes). However, you may run into problems when you try to install the `node-expat` parser. That's the reason why `node-expat` parser is not installed automatically.
36
36
 
37
37
 
38
38
  ## How to use it
@@ -232,7 +232,7 @@ With option `{ namespaces : true }` you will get access to the `.namespace` prop
232
232
  Specify attribute name or regular expression or custom condition. For details see [AttributeCondition](./doc/twig.md#AttributeCondition).<br>
233
233
  Let's assume an XML element like this:
234
234
  ```js
235
- <person firstName="Jean-Luc", lastName="Picard", age="59" />
235
+ <person firstName="Jean-Luc", lastName="Picard", age="59" />
236
236
  ```
237
237
  Here are some examples the get attribute and values:
238
238
  ```js
@@ -329,7 +329,7 @@ For methods which return a single **Twig** element (e.g. `elt.next("book")`) the
329
329
 
330
330
  #### Twig Properties
331
331
 
332
- `.isEmpty` - **boolean**: `true` if empty. An empty element ha no text nor any child elements, however empty elements can have attributes.
332
+ `.isEmpty` - **boolean**: `true` if empty. An empty element has no text nor any child elements, however empty elements can have attributes.
333
333
 
334
334
  `.level` - **integer**: The level of the element. Root element has 0, children have 1, grand-children 2 and so on
335
335
 
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  },
6
6
  "name": "xml-twig",
7
7
  "description": "Node module for processing huge XML documents in tree mode",
8
- "version": "1.2.80",
8
+ "version": "1.2.81",
9
9
  "main": "twig.js",
10
10
  "directories": {
11
11
  "doc": "doc"
package/twig.js CHANGED
@@ -26,12 +26,12 @@ const Any = new AnyHandler();
26
26
  /**
27
27
  * Optional settings for the Twig parser
28
28
  * @typedef ParserOptions
29
- * @param {string} method - The underlying parser. Either `'sax'` or `'expat'`.
30
- * @param {string} encoding - Encoding of the XML File. Applies only to `expat` parser.
31
- * @param {boolean} xmlns - If `true`, then namespaces are accessible by `namespace` property.
32
- * @param {boolean} trim - If `true`, then turn any whitespace into a single space. Text and comments are trimmed.
33
- * @param {boolean} resumeAfterError - If `true` then parser continues reading after an error. Otherwise it throws exception.
34
- * @param {boolean} partial - It `true` then unhandled elements are purged.
29
+ * @property {string} [method] - The underlying parser. Either `'sax'` or `'expat'`.
30
+ * @property {string} [encoding] - Encoding of the XML File. Applies only to `expat` parser.
31
+ * @property {boolean} [xmlns] - If `true`, then namespaces are accessible by `namespace` property.
32
+ * @property {boolean} [trim] - If `true`, then turn any whitespace into a single space. Text and comments are trimmed.
33
+ * @property {boolean} [resumeAfterError] - If `true` then parser continues reading after an error. Otherwise it throws exception.
34
+ * @property {boolean} [partial] - It `true` then unhandled elements are purged.
35
35
  * @example { encoding: 'UTF-8', xmlns: true }
36
36
  * @default { method: 'sax', encoding: 'UTF-8', xmlns: false, trim: true, resumeAfterError: false, partial: false }
37
37
  */
@@ -41,9 +41,9 @@ const Any = new AnyHandler();
41
41
  * Element can be specified as string, Regular Expression, custom function, `Twig.Root` or `Twig.Any`<br>
42
42
  * You can specify a `function` or a `event` name
43
43
  * @typedef TwigHandler
44
- * @param {HandlerCondition} tag - Element specification
45
- * @param {?HandlerFunction} function - Definition of handler function, either anonymous or explicit function
46
- * @param {?string} event - Type of the event to be emitted
44
+ * @property {HandlerCondition} tag - Element specification
45
+ * @property {?HandlerFunction} function - Definition of handler function, either anonymous or explicit function
46
+ * @property {?string} event - Type of the event to be emitted
47
47
  */
48
48
 
49
49
  /**
@@ -54,24 +54,22 @@ const Any = new AnyHandler();
54
54
  * - If [HandlerConditionFilter](#HandlerConditionFilter) then function must return `true`
55
55
  * - Use `Twig.Root` to call the handler on root element, i.e. when the end of document is reached
56
56
  * - Use `Twig.Any` to call the handler on every element
57
- * @typedef {string|RegExp|HandlerConditionFilter|RootHandler|AnyHandler} HandlerCondition
57
+ * @typedef {string|RegExp|HandlerConditionFilter|RootHandler|AnyHandler|undefined} HandlerCondition
58
58
  */
59
59
 
60
60
  /**
61
61
  * Handler function for Twig objects, i.e. the way you like to use the XML element.
62
62
  * @typedef HandlerFunction
63
- * @param {Twig} elt - The current Twig element on which the function was called.
63
+ * @property {Twig} elt - The current Twig element on which the function was called.
64
64
  */
65
65
 
66
66
  /**
67
67
  * Custom filter function to specify when handler shall be called
68
68
  * @typedef {function} HandlerConditionFilter
69
69
  * @param {string} name - Name of the element
70
+ * @returns {boolean} If the function returns `true`, then it is included in the filter
70
71
  */
71
72
 
72
-
73
-
74
-
75
73
  /**
76
74
  * Optional condition to get elements<br>
77
75
  * - If `undefined`, then all elements are returned.<br>
@@ -79,7 +77,7 @@ const Any = new AnyHandler();
79
77
  * - If `RegExp` then the element name must match the Regular Expression
80
78
  * - If [ElementConditionFilter](#ElementConditionFilter) then function must return `true`
81
79
  * - Use [Twig](#Twig) object to find a specific element
82
- * @typedef {string|RegExp|ElementConditionFilter|Twig} ElementCondition
80
+ * @typedef {string|RegExp|ElementConditionFilter|Twig|undefined} ElementCondition
83
81
  */
84
82
 
85
83
  /**
@@ -87,6 +85,7 @@ const Any = new AnyHandler();
87
85
  * @typedef {function} ElementConditionFilter
88
86
  * @param {string} name - Name of the element
89
87
  * @param {Twig} elt - The Twig object
88
+ * @returns {boolean} If the function returns `true`, then it is included in the filter
90
89
  */
91
90
 
92
91
 
@@ -94,11 +93,11 @@ const Any = new AnyHandler();
94
93
  /**
95
94
  * Create a new Twig parser
96
95
  * @param {TwigHandler|TwigHandler[]} handler - Object or array of element specification and function to handle elements
97
- * @param {?ParserOptions} options - Object of optional options
96
+ * @param {ParserOptions} [options] - Object of optional options
98
97
  * @throws {UnsupportedParser} - For an unsupported parser. Currently `expat` and `sax` (default) are supported.
99
98
  */
100
99
  function createParser(handler, options) {
101
- options = Object.assign({ method: SAX, encoding: 'UTF-8', xmlns: false, trim: true, resumeAfterError: false, partial: false }, options)
100
+ options = Object.assign({ method: SAX, encoding: 'UTF-8', xmlns: false, trim: true, resumeAfterError: false, partial: false }, options);
102
101
  let parser;
103
102
  let namespaces = {};
104
103
  let closeEvent;
@@ -117,11 +116,11 @@ function createParser(handler, options) {
117
116
 
118
117
  Object.defineProperty(parser, 'currentLine', {
119
118
  enumerable: true,
120
- get() { return parser._parser.line + 1 }
119
+ get() { return parser._parser.line + 1; }
121
120
  });
122
121
  Object.defineProperty(parser, 'currentColumn', {
123
122
  enumerable: true,
124
- get() { return parser._parser.column + 1 }
123
+ get() { return parser._parser.column + 1; }
125
124
  });
126
125
 
127
126
  closeEvent = "closetag";
@@ -161,7 +160,7 @@ function createParser(handler, options) {
161
160
  }
162
161
  }
163
162
  }
164
- })
163
+ });
165
164
 
166
165
  parser.on("processinginstruction", function (pi) {
167
166
  if (pi.name === 'xml') {
@@ -184,7 +183,7 @@ function createParser(handler, options) {
184
183
  enumerable: true
185
184
  });
186
185
  }
187
- })
186
+ });
188
187
 
189
188
  parser.on("attribute", function (attr) {
190
189
  current.attribute(attr.name, attr.value);
@@ -196,17 +195,17 @@ function createParser(handler, options) {
196
195
  enumerable: true
197
196
  });
198
197
  }
199
- })
198
+ });
200
199
  parser.on("cdata", function (str) {
201
200
  current.text = current.text ?? '' + str;
202
- })
201
+ });
203
202
 
204
203
  let hndl = Array.isArray(handler) ? handler : [handler];
205
204
  let rootHandler = hndl.find(x => x.tag instanceof RootHandler);
206
205
  parser.on("end", function () {
207
206
  if (typeof rootHandler?.function === 'function') rootHandler.function(tree);
208
207
  if (typeof rootHandler?.event === 'string') parser.emit(rootHandler.event, tree);
209
- })
208
+ });
210
209
 
211
210
  } else if (options.method === EXPAT) {
212
211
  parser = require("node-expat").createParser();
@@ -214,11 +213,11 @@ function createParser(handler, options) {
214
213
 
215
214
  Object.defineProperty(parser, 'currentLine', {
216
215
  enumerable: true,
217
- get() { return parser.parser.getCurrentLineNumber() }
216
+ get() { return parser.parser.getCurrentLineNumber(); }
218
217
  });
219
218
  Object.defineProperty(parser, 'currentColumn', {
220
219
  enumerable: true,
221
- get() { return parser.parser.getCurrentColumnNumber() }
220
+ get() { return parser.parser.getCurrentColumnNumber(); }
222
221
  });
223
222
  closeEvent = "endElement";
224
223
 
@@ -260,7 +259,7 @@ function createParser(handler, options) {
260
259
  }
261
260
  }
262
261
  }
263
- })
262
+ });
264
263
 
265
264
  parser.on('xmlDecl', function (version, encoding, standalone) {
266
265
  tree = new Twig(null);
@@ -273,11 +272,11 @@ function createParser(handler, options) {
273
272
  writable: false,
274
273
  enumerable: true
275
274
  });
276
- })
275
+ });
277
276
 
278
277
  parser.on('processingInstruction', function (target, data) {
279
278
  tree.PI = { target: target, data: data };
280
- })
279
+ });
281
280
  } else {
282
281
  throw new UnsupportedParser(options.method);
283
282
  }
@@ -314,17 +313,17 @@ function createParser(handler, options) {
314
313
  current.purge();
315
314
  current = current.parent();
316
315
 
317
- })
316
+ });
318
317
 
319
318
  // Common events
320
319
  parser.on('text', function (str) {
321
320
  current.text = current.text ?? '' + options.trim ? str.trim() : str;
322
- })
321
+ });
323
322
 
324
323
  parser.on("comment", function (str) {
325
324
  if (current.hasOwnProperty('comment')) {
326
325
  if (typeof current.comment === 'string') {
327
- current.comment = [current.comment, str.trim()]
326
+ current.comment = [current.comment, str.trim()];
328
327
  } else {
329
328
  current.comment.push(str.trim());
330
329
  }
@@ -337,7 +336,7 @@ function createParser(handler, options) {
337
336
  });
338
337
  }
339
338
 
340
- })
339
+ });
341
340
 
342
341
  parser.on('error', function (err) {
343
342
  console.error(`error at line [${parser.currentLine}], column [${parser.currentColumn}]`, err);
@@ -429,10 +428,10 @@ class Twig {
429
428
 
430
429
  /**
431
430
  * Create a new Twig object
432
- * @param {string} name - The name of the XML element
433
- * @param {Twig} parent - The parent object
434
- * @param {?object} attributes - Attribute object
435
- * @param {string|number} index - Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last'
431
+ * @param {?string} name - The name of the XML element
432
+ * @param {Twig} [parent] - The parent object
433
+ * @param {object} [attributes] - Attribute object
434
+ * @param {string|number} [index] - Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last'
436
435
  */
437
436
  constructor(name, parent, attributes, index) {
438
437
  if (index === undefined)
@@ -472,11 +471,11 @@ class Twig {
472
471
  purge = function () {
473
472
  if (!this.isRoot)
474
473
  this.#parent.#children = this.#parent.#children.filter(x => !Object.is(this, x));
475
- }
474
+ };
476
475
 
477
476
  /**
478
477
  * Purges up to the elt element. This allows you to keep part of the tree in memory when you purge.
479
- * @param {Twig} elt - Up to this element the tree will be purged. The `elt` object itself is not purged.<br>
478
+ * @param {Twig} [elt] - Up to this element the tree will be purged. The `elt` object itself is not purged.<br>
480
479
  * If `undefined` then the current element is purged (i.e. `purge()`)
481
480
  */
482
481
  purgeUpTo = function (elt) {
@@ -493,7 +492,7 @@ class Twig {
493
492
  purgeThis = prev;
494
493
  }
495
494
  }
496
- }
495
+ };
497
496
 
498
497
  /**
499
498
  * Escapes special XML characters. According W3C specification these are only `&, <, >, ", '` - this is a XML parser, not HTML!
@@ -506,7 +505,7 @@ class Twig {
506
505
  .replaceAll(">", "&gt;")
507
506
  .replaceAll('"', "&quot;")
508
507
  .replaceAll("'", "&apos;");
509
- }
508
+ };
510
509
 
511
510
  /**
512
511
  * Sets the name of root element. In some cases the root is created before the XML-Root element is available<br>
@@ -596,9 +595,9 @@ class Twig {
596
595
  */
597
596
  set text(value) {
598
597
  if (typeof value === 'string')
599
- this.#text = value
598
+ this.#text = value;
600
599
  else if (['number', 'bigint', 'boolean'].includes(typeof value))
601
- this.#text = value.toString()
600
+ this.#text = value.toString();
602
601
  else
603
602
  throw new UnsupportedType(value);
604
603
  }
@@ -608,7 +607,7 @@ class Twig {
608
607
  */
609
608
  pin = function () {
610
609
  this.#pinned = true;
611
- }
610
+ };
612
611
 
613
612
  /**
614
613
  * Checks if element is pinned
@@ -623,12 +622,12 @@ class Twig {
623
622
  */
624
623
  close = function () {
625
624
  Object.seal(this);
626
- }
625
+ };
627
626
 
628
627
  /**
629
628
  * Internal recursive function used by `writer()`
630
629
  * @param {XMLWriter} xw - The writer object
631
- * @param {Twig[]} children - Array of child elements
630
+ * @param {Twig[]} childArray - Array of child elements
632
631
  */
633
632
  #addChild = function (xw, childArray) {
634
633
  for (let elt of childArray) {
@@ -640,7 +639,7 @@ class Twig {
640
639
  this.#addChild(xw, elt.children());
641
640
  }
642
641
  xw.endElement();
643
- }
642
+ };
644
643
 
645
644
 
646
645
  /**
@@ -660,13 +659,13 @@ class Twig {
660
659
  this.#addChild(xw, this.#children);
661
660
  xw.endElement();
662
661
  return xw;
663
- }
662
+ };
664
663
 
665
664
  /**
666
665
  * Returns attribute value or `null` if not found.<br>
667
666
  * If more than one matches the condition, then it returns object as [attribute()](#attribute)
668
- * @param {?AttributeCondition} condition - Optional condition to select attribute
669
- * @returns {string|number|object} - The value of the attribute or `null` if the does not exist
667
+ * @param {AttributeCondition} [condition] - Optional condition to select attribute
668
+ * @returns {?string|number|object} - The value of the attribute or `null` if the does not exist
670
669
  */
671
670
  attr = function (condition) {
672
671
  let attr = this.attribute(condition);
@@ -674,7 +673,7 @@ class Twig {
674
673
  return null;
675
674
 
676
675
  return Object.keys(attr).length === 1 ? attr[Object.keys(attr)[0]] : attr;
677
- }
676
+ };
678
677
 
679
678
  /**
680
679
  * Returns all attributes of the element
@@ -691,12 +690,12 @@ class Twig {
691
690
  */
692
691
  hasAttribute = function (name) {
693
692
  return this.#attributes[name] !== undefined;
694
- }
693
+ };
695
694
 
696
695
  /**
697
696
  * Retrieve or update XML attribute. For update, the condition must be a string, i.e. must match to one attribute only.
698
- * @param {?AttributeCondition} condition - Optional condition to select attributes
699
- * @param {?string|number|bigint|boolean} value - New value of the attribute.<br>If `undefined` then existing attributes is returned.
697
+ * @param {AttributeCondition} [condition] - Optional condition to select attributes
698
+ * @param {string|number|bigint|boolean} [value] - New value of the attribute.<br>If `undefined` then existing attributes is returned.
700
699
  * @returns {object} Attributes or `null` if no matching attribute found
701
700
  * @example attribute((name, val) => { return name === 'age' && val > 50})
702
701
  * attribute((name) => { return ['firstName', 'lastName'].includes(name) })
@@ -711,9 +710,9 @@ class Twig {
711
710
  } else if (typeof condition === 'function') {
712
711
  attr = Object.fromEntries(Object.entries(this.#attributes).filter(([key, val]) => condition(key, val)));
713
712
  } else if (typeof condition === 'string') {
714
- attr = this.attribute(key => { return key === condition });
713
+ attr = this.attribute(key => key === condition);
715
714
  } else if (condition instanceof RegExp) {
716
- attr = this.attribute(key => { return condition.test(key) });
715
+ attr = this.attribute(key => condition.test(key));
717
716
  } else if (condition instanceof Twig) {
718
717
  throw new UnsupportedCondition(condition, ['string', 'RegEx', 'function']);
719
718
  } else {
@@ -722,15 +721,15 @@ class Twig {
722
721
  return attr === null || Object.keys(attr).length == 0 ? null : attr;
723
722
  } else if (typeof condition === 'string') {
724
723
  if (typeof value === 'string')
725
- this.#attributes[condition] = value
724
+ this.#attributes[condition] = value;
726
725
  else if (['number', 'bigint', 'boolean'].includes(typeof value))
727
- this.#attributes[condition] = value.toString()
726
+ this.#attributes[condition] = value.toString();
728
727
  else
729
728
  throw new UnsupportedType(value);
730
729
  } else {
731
730
  console.warn('Condition must be a `string` if you like to update an attribute');
732
731
  }
733
- }
732
+ };
734
733
 
735
734
  /**
736
735
  * Delete the attribute
@@ -738,7 +737,7 @@ class Twig {
738
737
  */
739
738
  deleteAttribute = function (name) {
740
739
  delete this.#attributes[name];
741
- }
740
+ };
742
741
 
743
742
  /**
744
743
  * Returns the root object
@@ -754,7 +753,7 @@ class Twig {
754
753
  }
755
754
  return ret;
756
755
  }
757
- }
756
+ };
758
757
 
759
758
  /**
760
759
  * Returns the parent element or null if root element
@@ -762,42 +761,44 @@ class Twig {
762
761
  */
763
762
  parent = function () {
764
763
  return this.isRoot ? null : this.#parent;
765
- }
764
+ };
766
765
 
767
766
  /**
768
767
  * @returns {Twig} - The current element
769
768
  */
770
769
  self = function () {
771
770
  return this;
772
- }
771
+ };
773
772
 
774
773
  /**
775
774
  * Common function to filter Twig elements from array
776
775
  * @param {Twig|Twig[]} elements - Array of elements you like to filter or a single element
777
- * @param {?ElementCondition} condition - The filter condition
776
+ * @param {ElementCondition} [condition] - The filter condition
778
777
  * @returns {Twig[]} List of matching elements or empty array
779
778
  */
780
779
  filterElements(elements, condition) {
781
780
  if (!Array.isArray(elements))
782
- return filterElements([elements], condition);
781
+ return this.filterElements([elements], condition);
783
782
 
784
- if (condition === undefined) {
785
- return elements;
786
- } else if (typeof condition === 'string') {
787
- return elements.filter(x => x.name === condition);
788
- } else if (condition instanceof RegExp) {
789
- return elements.filter(x => x.condition.test(x.name));
790
- } else if (condition instanceof Twig) {
791
- return elements.filter(x => Object.is(x, condition));
792
- } else if (typeof condition === 'function') {
793
- return elements.filter(x => condition(x.name, x));
783
+ if (condition !== undefined) {
784
+ if (typeof condition === 'string') {
785
+ return elements.filter(x => x.name === condition);
786
+ } else if (condition instanceof RegExp) {
787
+ return elements.filter(x => x.condition.test(x.name));
788
+ } else if (condition instanceof Twig) {
789
+ return elements.filter(x => Object.is(x, condition));
790
+ } else if (typeof condition === 'function') {
791
+ return elements.filter(x => condition(x.name, x));
792
+ }
794
793
  }
794
+
795
+ return elements;
795
796
  }
796
797
 
797
798
  /**
798
799
  * Common function to filter Twig element
799
800
  * @param {Twig} element - Element you like to filter
800
- * @param {?ElementCondition} condition - The filter condition
801
+ * @param {ElementCondition} [condition] - The filter condition
801
802
  * @returns {boolean} `true` if the condition matches
802
803
  */
803
804
  testElement(element, condition) {
@@ -817,17 +818,17 @@ class Twig {
817
818
 
818
819
  /**
819
820
  * All children, optionally matching `condition` of the current element or empty array
820
- * @param {?ElementCondition} condition - Optional condition
821
+ * @param {ElementCondition} [condition] - Optional condition
821
822
  * @returns {Twig[]}
822
823
  */
823
824
  children = function (condition) {
824
825
  return this.filterElements(this.#children, condition);
825
- }
826
+ };
826
827
 
827
828
  /**
828
829
  * Returns the next matching element.
829
- * @param {?ElementCondition} condition - Optional condition
830
- * @returns {Twig} - The next element
830
+ * @param {ElementCondition} [condition] - Optional condition
831
+ * @returns {?Twig} - The next element
831
832
  * @see https://www.w3.org/TR/xpath-datamodel-31/#document-order
832
833
  */
833
834
  next = function (condition) {
@@ -848,12 +849,12 @@ class Twig {
848
849
  return null;
849
850
 
850
851
  return this.testElement(elt, condition) ? elt : elt.next(condition);
851
- }
852
+ };
852
853
 
853
854
  /**
854
855
  * Returns the previous matching element.
855
- * @param {?ElementCondition} condition - Optional condition
856
- * @returns {Twig} - The previous element
856
+ * @param {ElementCondition} [condition] - Optional condition
857
+ * @returns {?Twig} - The previous element
857
858
  * @see https://www.w3.org/TR/xpath-datamodel-31/#document-order
858
859
  */
859
860
  previous = function (condition) {
@@ -869,23 +870,23 @@ class Twig {
869
870
  }
870
871
 
871
872
  return this.testElement(elt, condition) ? elt : elt.previous(condition);
872
- }
873
+ };
873
874
 
874
875
  /**
875
876
  * Returns the first matching element. This is usually the root element
876
- * @param {?ElementCondition} condition - Optional condition
877
- * @returns {Twig} - The first element
877
+ * @param {ElementCondition} [condition] - Optional condition
878
+ * @returns {?Twig} - The first element
878
879
  */
879
880
  first = function (condition) {
880
881
  if (this === null)
881
882
  return null;
882
883
  return this.testElement(this.root(), condition) ? this.root() : this.root().next(condition);
883
- }
884
+ };
884
885
 
885
886
  /**
886
887
  * Returns the last matching element.
887
- * @param {?ElementCondition} condition - Optional condition
888
- * @returns {Twig} - The last element
888
+ * @param {ElementCondition} [condition] - Optional condition
889
+ * @returns {?Twig} - The last element
889
890
  */
890
891
  last = function (condition) {
891
892
  if (this === null)
@@ -899,7 +900,7 @@ class Twig {
899
900
  }
900
901
 
901
902
  return this.testElement(elt, condition) ? elt : elt.previous(condition);
902
- }
903
+ };
903
904
 
904
905
  /**
905
906
  * Check if the element is the first child of the parent
@@ -909,7 +910,7 @@ class Twig {
909
910
  if (this.isRoot) {
910
911
  return false;
911
912
  } else {
912
- return this.index === 0
913
+ return this.index === 0;
913
914
  }
914
915
  }
915
916
 
@@ -927,7 +928,7 @@ class Twig {
927
928
 
928
929
  /**
929
930
  * Returns descendants (children, grandchildren, etc.) of the current element
930
- * @param {?ElementCondition} condition - Optional condition
931
+ * @param {ElementCondition} [condition] - Optional condition
931
932
  * @returns {Twig[]} - Array of descendants or empty array
932
933
  */
933
934
  descendant = function (condition) {
@@ -937,11 +938,11 @@ class Twig {
937
938
  elts = elts.concat(c.descendant());
938
939
  }
939
940
  return this.filterElements(elts, condition);
940
- }
941
+ };
941
942
 
942
943
  /**
943
944
  * Returns descendants (children, grandchildren, etc.) of the current element and the current element itself
944
- * @param {?ElementCondition} condition - Optional condition
945
+ * @param {ElementCondition} [condition] - Optional condition
945
946
  * @returns {Twig[]} - Array of descendants or empty array
946
947
  */
947
948
  descendantOrSelf = function (condition) {
@@ -951,11 +952,11 @@ class Twig {
951
952
  elts = elts.concat(c.descendant());
952
953
  }
953
954
  return this.filterElements(elts, condition);
954
- }
955
+ };
955
956
 
956
957
  /**
957
958
  * Returns ancestors (parent, grandparent, etc.) of the current element
958
- * @param {?ElementCondition} condition - Optional condition
959
+ * @param {ElementCondition} [condition] - Optional condition
959
960
  * @returns {Twig[]} - Array of ancestors or empty array
960
961
  */
961
962
  ancestor = function (condition) {
@@ -969,11 +970,11 @@ class Twig {
969
970
  }
970
971
  }
971
972
  return this.filterElements(elts, condition);
972
- }
973
+ };
973
974
 
974
975
  /**
975
976
  * Returns ancestors (parent, grandparent, etc.) of the current element and the current element itself
976
- * @param {?ElementCondition} condition - Optional condition
977
+ * @param {ElementCondition} [condition] - Optional condition
977
978
  * @returns {Twig[]} - Array of ancestors or empty array
978
979
  */
979
980
  ancestorOrSelf = function (condition) {
@@ -987,11 +988,11 @@ class Twig {
987
988
  }
988
989
  }
989
990
  return this.filterElements(elts, condition);
990
- }
991
+ };
991
992
 
992
993
  /**
993
994
  * Returns all sibling element of the current element
994
- * @param {?ElementCondition} condition - Optional condition
995
+ * @param {ElementCondition} [condition] - Optional condition
995
996
  * @returns {Twig[]} - Array of sibling or empty array
996
997
  */
997
998
  sibling = function (condition) {
@@ -1000,11 +1001,11 @@ class Twig {
1000
1001
  elts = this.#parent.#children.filter(x => !Object.is(x, this));
1001
1002
  }
1002
1003
  return this.filterElements(elts, condition);
1003
- }
1004
+ };
1004
1005
 
1005
1006
  /**
1006
1007
  * Returns all sibling element of the current element and the current element itself
1007
- * @param {?ElementCondition} condition - Optional condition
1008
+ * @param {ElementCondition} [condition] - Optional condition
1008
1009
  * @returns {Twig[]} - Array of sibling or empty array
1009
1010
  */
1010
1011
  siblingOrSelf = function (condition) {
@@ -1013,11 +1014,11 @@ class Twig {
1013
1014
  elts = this.#parent.#children;
1014
1015
  }
1015
1016
  return this.filterElements(elts, condition);
1016
- }
1017
+ };
1017
1018
 
1018
1019
  /**
1019
1020
  * Returns all following sibling element of the current element
1020
- * @param {?ElementCondition} condition - Optional condition
1021
+ * @param {ElementCondition} [condition] - Optional condition
1021
1022
  * @returns {Twig[]} - Array of sibling or empty array
1022
1023
  */
1023
1024
  followingSibling = function (condition) {
@@ -1026,11 +1027,11 @@ class Twig {
1026
1027
  elts = this.#parent.#children.slice(this.index + 1);
1027
1028
  }
1028
1029
  return this.filterElements(elts, condition);
1029
- }
1030
+ };
1030
1031
 
1031
1032
  /**
1032
1033
  * Returns all preceding sibling element of the current element
1033
- * @param {?ElementCondition} condition - Optional condition
1034
+ * @param {ElementCondition} [condition] - Optional condition
1034
1035
  * @returns {Twig[]} - Array of sibling or empty array
1035
1036
  */
1036
1037
  precedingSibling = function (condition) {
@@ -1039,12 +1040,12 @@ class Twig {
1039
1040
  elts = this.#parent.#children.slice(0, this.index);
1040
1041
  }
1041
1042
  return this.filterElements(elts, condition);
1042
- }
1043
+ };
1043
1044
 
1044
1045
  /**
1045
1046
  * Returns next sibling element of the current element
1046
- * @param {?ElementCondition} condition - Optional condition
1047
- * @returns {Twig} - The next sibling or `null`
1047
+ * @param {ElementCondition} [condition] - Optional condition
1048
+ * @returns {?Twig} - The next sibling or `null`
1048
1049
  */
1049
1050
  nextSibling = function (condition) {
1050
1051
  let elt;
@@ -1054,12 +1055,12 @@ class Twig {
1054
1055
  return null;
1055
1056
 
1056
1057
  return this.testElement(elt, condition) ? elt : elt.nextSibling(condition);
1057
- }
1058
+ };
1058
1059
 
1059
1060
  /**
1060
1061
  * Returns previous sibling element of the current element
1061
- * @param {?ElementCondition} condition - Optional condition
1062
- * @returns {Twig} - The previous sibling or `null`
1062
+ * @param {ElementCondition} [condition] - Optional condition
1063
+ * @returns {?Twig} - The previous sibling or `null`
1063
1064
  */
1064
1065
  prevSibling = function (condition) {
1065
1066
  if (!this.isRoot && this.index > 0) {
@@ -1068,12 +1069,12 @@ class Twig {
1068
1069
  } else {
1069
1070
  return null;
1070
1071
  }
1071
- }
1072
+ };
1072
1073
 
1073
1074
  /**
1074
1075
  * Find a specific element within current element. Same as `.descendant(condition)[0]`
1075
1076
  * @param {ElementCondition} condition - Find condition
1076
- * @returns {Twig} - First matching element or `null`
1077
+ * @returns {?Twig} - First matching element or `null`
1077
1078
  */
1078
1079
  find = function (condition) {
1079
1080
  let children = this.filterElements(this.#children, condition);
@@ -1086,14 +1087,14 @@ class Twig {
1086
1087
  return ret;
1087
1088
  }
1088
1089
  return null;
1089
- }
1090
+ };
1090
1091
 
1091
1092
  /**
1092
1093
  * Add a new element in the current element
1093
1094
  * @param {string} name - The tag name
1094
- * @param {?string} text - Text of the element
1095
- * @param {?object} attributes - Element attributes
1096
- * @param {name|number} position - Position name 'first', 'last' or the position in the `children`
1095
+ * @param {?string} [text] - Text of the element
1096
+ * @param {?object} [attributes] - Element attributes
1097
+ * @param {name|number} [position] - Position name 'first', 'last' or the position in the `children`
1097
1098
  * @returns {Twig} - The appended element
1098
1099
  */
1099
1100
  addElement = function (name, text, attributes, position) {
@@ -1101,14 +1102,14 @@ class Twig {
1101
1102
  twig.#text = text ?? null;
1102
1103
  twig.close();
1103
1104
  return twig;
1104
- }
1105
+ };
1105
1106
 
1106
1107
  /**
1107
1108
  * Deletes the current element from tree, same as `purge()`. The root object cannot be deleted.
1108
1109
  */
1109
1110
  delete = function () {
1110
1111
  this.purge();
1111
- }
1112
+ };
1112
1113
 
1113
1114
 
1114
1115
  }
@@ -1167,4 +1168,3 @@ class UnsupportedCondition extends TypeError {
1167
1168
 
1168
1169
 
1169
1170
  module.exports = { createParser, Twig, Any, Root };
1170
-