@tradik/xslt-processor 1.0.3 → 1.3.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.
Files changed (131) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +110 -520
  3. package/bin/lib/decode.js +15 -0
  4. package/bin/lib/dom.js +177 -0
  5. package/bin/lib/loaders.js +127 -0
  6. package/bin/lib/options.js +131 -0
  7. package/bin/lib/output.js +114 -0
  8. package/bin/lib/paths.js +186 -0
  9. package/bin/lib/transform.js +206 -0
  10. package/bin/xslt.js +73 -168
  11. package/dist/xslt-processor.browser.js +9564 -1585
  12. package/dist/xslt-processor.browser.js.map +4 -4
  13. package/dist/xslt-processor.browser.min.js +13 -2
  14. package/dist/xslt-processor.browser.min.js.map +4 -4
  15. package/dist/xslt-processor.cjs +9572 -1586
  16. package/dist/xslt-processor.cjs.map +4 -4
  17. package/dist/xslt-processor.d.cts +658 -0
  18. package/dist/xslt-processor.d.ts +459 -12
  19. package/dist/xslt-processor.js +9546 -1582
  20. package/dist/xslt-processor.js.map +4 -4
  21. package/package.json +71 -20
  22. package/src/XSLTProcessor.js +494 -48
  23. package/src/async/abort.js +63 -0
  24. package/src/async/documentUris.js +128 -0
  25. package/src/async/loaders.js +134 -0
  26. package/src/async/preload.js +159 -0
  27. package/src/async/processor.js +206 -0
  28. package/src/async/stream.js +125 -0
  29. package/src/bridge/engine.js +221 -0
  30. package/src/bridge/loader.js +78 -0
  31. package/src/bridge/results.js +75 -0
  32. package/src/bridge/version.js +63 -0
  33. package/src/index.js +26 -8
  34. package/src/io/decode.js +140 -0
  35. package/src/io/readSource.js +167 -0
  36. package/src/xpath/axes.js +562 -0
  37. package/src/xpath/documentOrder.js +270 -0
  38. package/src/xpath/evaluator.js +518 -357
  39. package/src/xpath/index.js +8 -2
  40. package/src/xpath/namespaceNodes.js +172 -0
  41. package/src/xpath/nodeSetFunctions.js +169 -0
  42. package/src/xpath/parser.js +30 -5
  43. package/src/xpath/strings.js +183 -0
  44. package/src/xpath/tokenizer.js +37 -23
  45. package/src/xslt/attributeSets.js +95 -0
  46. package/src/xslt/avt.js +103 -0
  47. package/src/xslt/computedNames.js +91 -0
  48. package/src/xslt/copying.js +212 -0
  49. package/src/xslt/declarationNames.js +80 -0
  50. package/src/xslt/domParsing.js +95 -0
  51. package/src/xslt/elements.js +57 -0
  52. package/src/xslt/engine/bindings.js +195 -0
  53. package/src/xslt/engine/context.js +105 -0
  54. package/src/xslt/engine/controlFlow.js +145 -0
  55. package/src/xslt/engine/copyInstructions.js +133 -0
  56. package/src/xslt/engine/declarations.js +233 -0
  57. package/src/xslt/engine/functionSupport.js +103 -0
  58. package/src/xslt/engine/methods.js +33 -0
  59. package/src/xslt/engine/nodeConstruction.js +187 -0
  60. package/src/xslt/engine/numbering.js +104 -0
  61. package/src/xslt/engine/outputDeclaration.js +77 -0
  62. package/src/xslt/engine/sequenceConstructor.js +228 -0
  63. package/src/xslt/engine/stylesheetLoading.js +208 -0
  64. package/src/xslt/engine/templateInvocation.js +253 -0
  65. package/src/xslt/engine/templateRules.js +243 -0
  66. package/src/xslt/engine/textInstructions.js +171 -0
  67. package/src/xslt/engine/topLevel.js +130 -0
  68. package/src/xslt/engine/transformation.js +263 -0
  69. package/src/xslt/engine/workStack.js +245 -0
  70. package/src/xslt/engine.js +184 -1736
  71. package/src/xslt/exslt/arguments.js +99 -0
  72. package/src/xslt/exslt/calendar.js +120 -0
  73. package/src/xslt/exslt/common.js +44 -0
  74. package/src/xslt/exslt/dateCalc.js +261 -0
  75. package/src/xslt/exslt/dateFormat.js +150 -0
  76. package/src/xslt/exslt/dateParse.js +265 -0
  77. package/src/xslt/exslt/dates.js +259 -0
  78. package/src/xslt/exslt/duration.js +207 -0
  79. package/src/xslt/exslt/dynamic.js +59 -0
  80. package/src/xslt/exslt/index.js +59 -0
  81. package/src/xslt/exslt/math.js +177 -0
  82. package/src/xslt/exslt/sets.js +96 -0
  83. package/src/xslt/exslt/stringOps.js +163 -0
  84. package/src/xslt/exslt/strings.js +147 -0
  85. package/src/xslt/exslt/uri.js +92 -0
  86. package/src/xslt/formatNumber.js +233 -0
  87. package/src/xslt/forwardsCompatible.js +75 -0
  88. package/src/xslt/functions.js +270 -0
  89. package/src/xslt/index.js +38 -1
  90. package/src/xslt/keys.js +164 -0
  91. package/src/xslt/literalResult.js +223 -0
  92. package/src/xslt/matchScope.js +116 -0
  93. package/src/xslt/number.js +271 -0
  94. package/src/xslt/numberFormat.js +253 -0
  95. package/src/xslt/outputNames.js +58 -0
  96. package/src/xslt/patternCompiler.js +175 -0
  97. package/src/xslt/patterns.js +324 -0
  98. package/src/xslt/qname.js +90 -0
  99. package/src/xslt/resultDocument.js +98 -0
  100. package/src/xslt/resultNamespaces.js +219 -0
  101. package/src/xslt/resultTree.js +211 -0
  102. package/src/xslt/serializer/baseWriter.js +390 -0
  103. package/src/xslt/serializer/chunks.js +120 -0
  104. package/src/xslt/serializer/constants.js +92 -0
  105. package/src/xslt/serializer/encoding.js +327 -0
  106. package/src/xslt/serializer/escape.js +135 -0
  107. package/src/xslt/serializer/frames.js +168 -0
  108. package/src/xslt/serializer/htmlDoctype.js +102 -0
  109. package/src/xslt/serializer/htmlEntities.js +77 -0
  110. package/src/xslt/serializer/htmlSerializer.js +239 -0
  111. package/src/xslt/serializer/indent.js +51 -0
  112. package/src/xslt/serializer/namespaces.js +68 -0
  113. package/src/xslt/serializer/rawText.js +41 -0
  114. package/src/xslt/serializer/settings.js +179 -0
  115. package/src/xslt/serializer/textSerializer.js +77 -0
  116. package/src/xslt/serializer/xhtmlDocument.js +103 -0
  117. package/src/xslt/serializer/xmlSerializer.js +227 -0
  118. package/src/xslt/serializer.js +90 -0
  119. package/src/xslt/sort.js +151 -0
  120. package/src/xslt/spaceNameTests.js +115 -0
  121. package/src/xslt/stylesheetChecks.js +206 -0
  122. package/src/xslt/stylesheetNamespaces.js +266 -0
  123. package/src/xslt/templatePriority.js +45 -0
  124. package/src/xslt/uri.js +68 -0
  125. package/src/xslt/variables.js +152 -0
  126. package/src/xslt/whitespace.js +200 -0
  127. package/LICENSE +0 -29
  128. package/src/XSLTProcessor.test.js +0 -930
  129. package/src/xpath/evaluator.test.js +0 -1852
  130. package/src/xpath/tokenizer.test.js +0 -224
  131. package/src/xslt/engine.test.js +0 -3130
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Document order of nodes that are not children of their parent: attributes
3
+ * and synthesized namespace nodes (XPath 1.0 section 5).
4
+ *
5
+ * An element comes first, then its namespace nodes, then its attributes, then
6
+ * its children. `Node.compareDocumentPosition` cannot order namespace nodes,
7
+ * which are not DOM nodes, and jsdom reports an element and one of its own
8
+ * attributes as equal, so both kinds are ordered through their element here.
9
+ *
10
+ * Browsers implement `compareDocumentPosition` natively. The JavaScript DOMs
11
+ * of Node.js walk the ancestors of both nodes on every call, and xmldom also
12
+ * looks each ancestor up in its parent's child list, which makes sorting a
13
+ * large node-set take minutes; some DOMs have no such method at all. A
14
+ * {@link DocumentOrderIndex} numbers the nodes of a tree once instead, in one
15
+ * walk, and sorts node-sets by those numbers: the XSLT engine uses one per
16
+ * transformation (the source tree does not change while it runs) unless the
17
+ * DOM compares positions natively.
18
+ *
19
+ * @module xpath/documentOrder
20
+ */
21
+
22
+ "use strict";
23
+
24
+ import { NAMESPACE_NODE } from "./namespaceNodes.js";
25
+
26
+ /**
27
+ * Rank of a node among the nodes anchored at the same element: the element,
28
+ * its namespace nodes, its attributes.
29
+ *
30
+ * @param {Node} node - Any node
31
+ * @returns {number} 0 for the element (or any other node), 1 for a namespace
32
+ * node, 2 for an attribute
33
+ */
34
+ function rankOf(node) {
35
+ const type = node.nodeType;
36
+ if (type === NAMESPACE_NODE) return 1;
37
+ return type === 2 ? 2 : 0;
38
+ }
39
+
40
+ /**
41
+ * The node whose position in the tree stands for a node: the element of an
42
+ * attached attribute or namespace node, else the node itself.
43
+ *
44
+ * @param {Node} node - Any node
45
+ * @param {number} rank - The node's rank (see rankOf)
46
+ * @returns {Node} The anchor
47
+ */
48
+ function anchorOf(node, rank) {
49
+ return rank === 0 ? node : (node.ownerElement ?? node);
50
+ }
51
+
52
+ /**
53
+ * Compare two distinct nodes in document order.
54
+ *
55
+ * @param {Node} a - First node
56
+ * @param {Node} b - Second node
57
+ * @param {(a: Node, b: Node) => number} compareDom - Order of two DOM nodes
58
+ * in different positions of the tree (compareDocumentPosition based)
59
+ * @returns {number} Negative when a comes first, positive when b does
60
+ *
61
+ * @example
62
+ * compareNodeOrder(attribute, ownerElement, compareDom); // 1
63
+ */
64
+ export function compareNodeOrder(a, b, compareDom) {
65
+ const rankA = rankOf(a);
66
+ const rankB = rankOf(b);
67
+ if (rankA === 0 && rankB === 0) return compareDom(a, b);
68
+ const anchorA = anchorOf(a, rankA);
69
+ const anchorB = anchorOf(b, rankB);
70
+ if (anchorA !== anchorB) return compareDom(anchorA, anchorB);
71
+ if (rankA !== rankB) return rankA - rankB;
72
+ // Two namespace nodes, or two attributes, of the same element
73
+ return rankA === 1 ? a.index - b.index : compareDom(a, b);
74
+ }
75
+
76
+ /**
77
+ * Order of two DOM nodes in different positions of a tree, from
78
+ * `compareDocumentPosition`.
79
+ *
80
+ * @param {Node} a - First node
81
+ * @param {Node} b - Second node
82
+ * @returns {number} -1 when a comes first, 1 when b does, 0 when the DOM
83
+ * gives no order
84
+ */
85
+ export function compareDomPositions(a, b) {
86
+ const position = a.compareDocumentPosition(b);
87
+ if (position & 4) return -1; // b follows a
88
+ if (position & 2) return 1; // b precedes a
89
+ return 0;
90
+ }
91
+
92
+ /**
93
+ * Whether a node's DOM compares positions in native code (browsers), as
94
+ * opposed to a JavaScript implementation (jsdom, xmldom) or none.
95
+ *
96
+ * @param {Node} node - A DOM node
97
+ * @returns {boolean} True for a built-in `compareDocumentPosition`
98
+ *
99
+ * @example
100
+ * hasNativePositionComparison(document.body); // true in a browser
101
+ */
102
+ export function hasNativePositionComparison(node) {
103
+ const compare = node.compareDocumentPosition;
104
+ return (
105
+ typeof compare === "function" &&
106
+ Function.prototype.toString.call(compare).includes("[native code]")
107
+ );
108
+ }
109
+
110
+ /**
111
+ * The topmost ancestor of a node.
112
+ *
113
+ * @param {Node} node - A DOM node
114
+ * @returns {Node} The document, or the root of a detached tree
115
+ */
116
+ function rootOf(node) {
117
+ let root = node;
118
+ while (root.parentNode) root = root.parentNode;
119
+ return root;
120
+ }
121
+
122
+ /**
123
+ * Sort key offset of attributes among the nodes anchored at an element:
124
+ * after the element (0) and its namespace nodes (1 + index).
125
+ */
126
+ const ATTRIBUTE_KEY = 2 ** 30;
127
+
128
+ /**
129
+ * Document order positions of DOM nodes, computed tree by tree.
130
+ *
131
+ * The first time a node of a tree is looked up, the whole tree is numbered
132
+ * in document order (attributes are not: they are ordered through their
133
+ * element, and among themselves by their index in the element's attribute
134
+ * list, looked up only when two attributes of one element are sorted). Trees are numbered in
135
+ * the order they are first seen, so nodes of different documents have a
136
+ * stable, implementation-defined order (XPath 1.0 section 5). A node added
137
+ * to a tree after it was numbered makes the tree numbered again; nodes
138
+ * moved within a numbered tree are not noticed, so an index must not
139
+ * outlive changes to its trees.
140
+ *
141
+ * @example
142
+ * const order = new DocumentOrderIndex();
143
+ * order.sort([lastChild, firstChild]); // [firstChild, lastChild]
144
+ */
145
+ export class DocumentOrderIndex {
146
+ constructor() {
147
+ /** @type {WeakMap<Node, number>} */
148
+ this.positions = new WeakMap();
149
+ /** @type {WeakMap<Attr, number>} */
150
+ this.attributeIndexes = new WeakMap();
151
+ this.nextPosition = 0;
152
+ }
153
+
154
+ /**
155
+ * The position of a tree node in document order.
156
+ *
157
+ * @param {Node} node - A DOM node, not an attribute of an element nor a
158
+ * namespace node (see {@link DocumentOrderIndex#sort})
159
+ * @returns {number} Its position; larger for later nodes
160
+ */
161
+ positionOf(node) {
162
+ let position = this.positions.get(node);
163
+ if (position === undefined) {
164
+ this.numberTree(rootOf(node));
165
+ position = this.positions.get(node);
166
+ }
167
+ return position ?? this.assign(node);
168
+ }
169
+
170
+ /**
171
+ * Give a node the next position.
172
+ *
173
+ * @param {Node} node - A DOM node
174
+ * @returns {number} The assigned position
175
+ */
176
+ assign(node) {
177
+ const position = this.nextPosition++;
178
+ this.positions.set(node, position);
179
+ return position;
180
+ }
181
+
182
+ /**
183
+ * Number a tree in document order, without recursion (deep trees).
184
+ *
185
+ * @param {Node} root - The root of the tree
186
+ * @returns {void}
187
+ */
188
+ numberTree(root) {
189
+ let node = root;
190
+ for (;;) {
191
+ this.assign(node);
192
+ if (node.firstChild) {
193
+ node = node.firstChild;
194
+ continue;
195
+ }
196
+ while (node !== root && !node.nextSibling) node = node.parentNode;
197
+ if (node === root) return;
198
+ node = node.nextSibling;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * The index of an attribute in the attribute list of its element.
204
+ *
205
+ * @param {Attr} attribute - An attribute with an ownerElement
206
+ * @returns {number} Its index (0 when the element does not list it)
207
+ */
208
+ attributeIndexOf(attribute) {
209
+ let index = this.attributeIndexes.get(attribute);
210
+ if (index === undefined) {
211
+ const attributes = attribute.ownerElement.attributes;
212
+ for (let i = 0; i < attributes.length; i++) {
213
+ this.attributeIndexes.set(attributes[i], i);
214
+ }
215
+ index = this.attributeIndexes.get(attribute) ?? 0;
216
+ }
217
+ return index;
218
+ }
219
+
220
+ /**
221
+ * The sort key of a node: the position of the node, or of the element it
222
+ * hangs off, then its rank among the nodes anchored at that element. All
223
+ * attributes of an element share one key (see
224
+ * {@link DocumentOrderIndex#compareKeys}): walking the attribute list of
225
+ * every element up front would dominate sorting `$items/@v`, where no two
226
+ * attributes share an element.
227
+ *
228
+ * @param {Node} node - A DOM node or namespace node
229
+ * @returns {{node: Node, major: number, minor: number}} The key
230
+ */
231
+ keyOf(node) {
232
+ if (node.nodeType === NAMESPACE_NODE) {
233
+ const major = this.positionOf(node.ownerElement);
234
+ return { node, major, minor: 1 + node.index };
235
+ }
236
+ if (node.nodeType === 2 && node.ownerElement) {
237
+ const major = this.positionOf(node.ownerElement);
238
+ return { node, major, minor: ATTRIBUTE_KEY };
239
+ }
240
+ return { node, major: this.positionOf(node), minor: 0 };
241
+ }
242
+
243
+ /**
244
+ * Order of two sort keys; attributes of the same element are ordered by
245
+ * their index in its attribute list, looked up only for such a tie.
246
+ *
247
+ * @param {{node: Node, major: number, minor: number}} a - First key
248
+ * @param {{node: Node, major: number, minor: number}} b - Second key
249
+ * @returns {number} Negative when a comes first, positive when b does
250
+ */
251
+ compareKeys(a, b) {
252
+ const order = a.major - b.major || a.minor - b.minor;
253
+ if (order !== 0 || a.minor !== ATTRIBUTE_KEY) return order;
254
+ return this.attributeIndexOf(a.node) - this.attributeIndexOf(b.node);
255
+ }
256
+
257
+ /**
258
+ * Sort nodes in document order: an element, then its namespace nodes (by
259
+ * index), then its attributes, then its children.
260
+ *
261
+ * @param {Node[]} nodes - DOM nodes and namespace nodes, sorted in place
262
+ * @returns {Node[]} The same array
263
+ */
264
+ sort(nodes) {
265
+ const keyed = nodes.map((node) => this.keyOf(node));
266
+ keyed.sort((a, b) => this.compareKeys(a, b));
267
+ for (let i = 0; i < keyed.length; i++) nodes[i] = keyed[i].node;
268
+ return nodes;
269
+ }
270
+ }