@tradik/xslt3 0.0.0-stage → 1.0.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 (286) hide show
  1. package/LICENSE.md +28 -0
  2. package/README.md +98 -2
  3. package/package.json +43 -4
  4. package/src/errors.js +20 -0
  5. package/src/functions/aggregates.js +144 -0
  6. package/src/functions/arraySort.js +33 -0
  7. package/src/functions/arrays.js +181 -0
  8. package/src/functions/attributeTypes.js +58 -0
  9. package/src/functions/baseUris.js +82 -0
  10. package/src/functions/collations.js +127 -0
  11. package/src/functions/collections.js +84 -0
  12. package/src/functions/context.js +83 -0
  13. package/src/functions/core.js +167 -0
  14. package/src/functions/datetime.js +203 -0
  15. package/src/functions/deepEqual.js +132 -0
  16. package/src/functions/diagnostics.js +88 -0
  17. package/src/functions/focus.js +34 -0
  18. package/src/functions/format/dateComponents.js +176 -0
  19. package/src/functions/format/datePicture.js +115 -0
  20. package/src/functions/format/decimalFormat.js +65 -0
  21. package/src/functions/format/digitPattern.js +145 -0
  22. package/src/functions/format/formatDateTime.js +204 -0
  23. package/src/functions/format/formatInteger.js +109 -0
  24. package/src/functions/format/formatNumber.js +165 -0
  25. package/src/functions/format/fractionFormat.js +80 -0
  26. package/src/functions/format/germanWords.js +89 -0
  27. package/src/functions/format/numberLanguages.js +41 -0
  28. package/src/functions/format/numberPicture.js +202 -0
  29. package/src/functions/format/numberWords.js +155 -0
  30. package/src/functions/format/place.js +74 -0
  31. package/src/functions/format/timezoneFormat.js +89 -0
  32. package/src/functions/higherOrder.js +106 -0
  33. package/src/functions/ids.js +127 -0
  34. package/src/functions/json/index.js +17 -0
  35. package/src/functions/json/jsonChars.js +110 -0
  36. package/src/functions/json/jsonParser.js +203 -0
  37. package/src/functions/json/jsonStrings.js +116 -0
  38. package/src/functions/json/jsonToXml.js +116 -0
  39. package/src/functions/json/parseJson.js +119 -0
  40. package/src/functions/json/xmlRepresentation.js +103 -0
  41. package/src/functions/json/xmlToJson.js +147 -0
  42. package/src/functions/library.js +47 -0
  43. package/src/functions/mapArrayEqual.js +41 -0
  44. package/src/functions/maps.js +152 -0
  45. package/src/functions/math.js +73 -0
  46. package/src/functions/nodePaths.js +181 -0
  47. package/src/functions/nodes.js +199 -0
  48. package/src/functions/numeric.js +148 -0
  49. package/src/functions/options.js +58 -0
  50. package/src/functions/parseIetfDate.js +104 -0
  51. package/src/functions/parseXml.js +77 -0
  52. package/src/functions/qnames.js +68 -0
  53. package/src/functions/random.js +128 -0
  54. package/src/functions/regex/analyzeString.js +144 -0
  55. package/src/functions/regex/charClass.js +112 -0
  56. package/src/functions/regex/compile.js +81 -0
  57. package/src/functions/regex/escapes.js +109 -0
  58. package/src/functions/regex/parser.js +169 -0
  59. package/src/functions/regex/reader.js +37 -0
  60. package/src/functions/regex/regexFunctions.js +140 -0
  61. package/src/functions/regex/translate.js +102 -0
  62. package/src/functions/regex/unicodeBlocks.js +194 -0
  63. package/src/functions/registry.js +140 -0
  64. package/src/functions/sequences.js +173 -0
  65. package/src/functions/serializeFunction.js +53 -0
  66. package/src/functions/signatures.js +105 -0
  67. package/src/functions/sort.js +102 -0
  68. package/src/functions/stringMatch.js +45 -0
  69. package/src/functions/strings.js +194 -0
  70. package/src/functions/stringsCore.js +66 -0
  71. package/src/functions/support.js +106 -0
  72. package/src/functions/textDecoding.js +117 -0
  73. package/src/functions/ucaCollation.js +127 -0
  74. package/src/functions/unparsedText.js +71 -0
  75. package/src/functions/uri.js +166 -0
  76. package/src/functions/xqueryModule.js +24 -0
  77. package/src/index.js +38 -0
  78. package/src/items/array.js +84 -0
  79. package/src/items/function.js +45 -0
  80. package/src/items/map.js +120 -0
  81. package/src/items/mapKey.js +82 -0
  82. package/src/serialize/index.js +129 -0
  83. package/src/serialize/markup/content.js +74 -0
  84. package/src/serialize/markup/dialect.js +178 -0
  85. package/src/serialize/markup/htmlData.js +70 -0
  86. package/src/serialize/markup/namespaces.js +145 -0
  87. package/src/serialize/markup/prolog.js +91 -0
  88. package/src/serialize/markup/writer.js +183 -0
  89. package/src/serialize/methods/adaptive.js +131 -0
  90. package/src/serialize/methods/json.js +158 -0
  91. package/src/serialize/methods/text.js +43 -0
  92. package/src/serialize/output/buffer.js +48 -0
  93. package/src/serialize/output/encoding.js +146 -0
  94. package/src/serialize/output/expander.js +204 -0
  95. package/src/serialize/params/fromElement.js +141 -0
  96. package/src/serialize/params/fromMap.js +128 -0
  97. package/src/serialize/params/names.js +69 -0
  98. package/src/serialize/params/settings.js +153 -0
  99. package/src/serialize/params/values.js +163 -0
  100. package/src/serialize/sequence.js +111 -0
  101. package/src/xdm/arithmetic.js +155 -0
  102. package/src/xdm/atomic.js +142 -0
  103. package/src/xdm/binary.js +92 -0
  104. package/src/xdm/calendar.js +71 -0
  105. package/src/xdm/cast.js +176 -0
  106. package/src/xdm/compare.js +192 -0
  107. package/src/xdm/datetime.js +206 -0
  108. package/src/xdm/decimal.js +200 -0
  109. package/src/xdm/duration.js +128 -0
  110. package/src/xdm/generalCompare.js +152 -0
  111. package/src/xdm/index.js +47 -0
  112. package/src/xdm/lexical.js +126 -0
  113. package/src/xdm/nodes.js +170 -0
  114. package/src/xdm/numeric.js +122 -0
  115. package/src/xdm/qname.js +65 -0
  116. package/src/xdm/strings.js +52 -0
  117. package/src/xdm/temporalArithmetic.js +180 -0
  118. package/src/xdm/timeline.js +68 -0
  119. package/src/xdm/types.js +178 -0
  120. package/src/xpath/eval/atomics.js +45 -0
  121. package/src/xpath/eval/axes.js +212 -0
  122. package/src/xpath/eval/calls.js +168 -0
  123. package/src/xpath/eval/coercion.js +146 -0
  124. package/src/xpath/eval/compiler.js +71 -0
  125. package/src/xpath/eval/constructors.js +129 -0
  126. package/src/xpath/eval/decimalFormats.js +93 -0
  127. package/src/xpath/eval/descendantMemo.js +77 -0
  128. package/src/xpath/eval/documentOrder.js +142 -0
  129. package/src/xpath/eval/domNodes.js +174 -0
  130. package/src/xpath/eval/dynamicCall.js +27 -0
  131. package/src/xpath/eval/dynamicContext.js +161 -0
  132. package/src/xpath/eval/flow.js +115 -0
  133. package/src/xpath/eval/functionItems.js +194 -0
  134. package/src/xpath/eval/groupedChildren.js +88 -0
  135. package/src/xpath/eval/inline.js +71 -0
  136. package/src/xpath/eval/namespaceNodes.js +90 -0
  137. package/src/xpath/eval/nodeTests.js +164 -0
  138. package/src/xpath/eval/operators.js +190 -0
  139. package/src/xpath/eval/paths.js +163 -0
  140. package/src/xpath/eval/positional.js +81 -0
  141. package/src/xpath/eval/predicates.js +56 -0
  142. package/src/xpath/eval/primary.js +99 -0
  143. package/src/xpath/eval/resources.js +149 -0
  144. package/src/xpath/eval/scope.js +108 -0
  145. package/src/xpath/eval/sequenceType.js +193 -0
  146. package/src/xpath/eval/staticContext.js +142 -0
  147. package/src/xpath/eval/steps.js +98 -0
  148. package/src/xpath/eval/subtype.js +154 -0
  149. package/src/xpath/eval/typeExprs.js +147 -0
  150. package/src/xpath/eval/typeNames.js +101 -0
  151. package/src/xpath/eval/uris.js +21 -0
  152. package/src/xpath/eval/values.js +64 -0
  153. package/src/xpath/index.js +217 -0
  154. package/src/xpath/syntax/ast.js +130 -0
  155. package/src/xpath/syntax/chars.js +58 -0
  156. package/src/xpath/syntax/constructors.js +144 -0
  157. package/src/xpath/syntax/expressions.js +107 -0
  158. package/src/xpath/syntax/index.js +44 -0
  159. package/src/xpath/syntax/kindTests.js +134 -0
  160. package/src/xpath/syntax/lexer.js +220 -0
  161. package/src/xpath/syntax/operators.js +111 -0
  162. package/src/xpath/syntax/paths.js +102 -0
  163. package/src/xpath/syntax/postfix.js +91 -0
  164. package/src/xpath/syntax/primaries.js +149 -0
  165. package/src/xpath/syntax/steps.js +146 -0
  166. package/src/xpath/syntax/syntaxError.js +31 -0
  167. package/src/xpath/syntax/tokenStream.js +163 -0
  168. package/src/xpath/syntax/typeAst.js +76 -0
  169. package/src/xpath/syntax/typeOperators.js +127 -0
  170. package/src/xpath/syntax/types.js +158 -0
  171. package/src/xslt/api.js +153 -0
  172. package/src/xslt/compiler/acceptance.js +178 -0
  173. package/src/xslt/compiler/accumulatorDecl.js +146 -0
  174. package/src/xslt/compiler/attributeValues.js +174 -0
  175. package/src/xslt/compiler/attributes.js +211 -0
  176. package/src/xslt/compiler/avt.js +103 -0
  177. package/src/xslt/compiler/body.js +154 -0
  178. package/src/xslt/compiler/children.js +105 -0
  179. package/src/xslt/compiler/compatibility.js +130 -0
  180. package/src/xslt/compiler/components.js +179 -0
  181. package/src/xslt/compiler/contextItem.js +95 -0
  182. package/src/xslt/compiler/decimalFormats.js +132 -0
  183. package/src/xslt/compiler/declarationKinds.js +82 -0
  184. package/src/xslt/compiler/elementInfo.js +246 -0
  185. package/src/xslt/compiler/expressions.js +175 -0
  186. package/src/xslt/compiler/globalContextItem.js +92 -0
  187. package/src/xslt/compiler/globals.js +209 -0
  188. package/src/xslt/compiler/linker.js +134 -0
  189. package/src/xslt/compiler/miscDecl.js +171 -0
  190. package/src/xslt/compiler/modeDecl.js +88 -0
  191. package/src/xslt/compiler/moduleLoading.js +111 -0
  192. package/src/xslt/compiler/modules.js +158 -0
  193. package/src/xslt/compiler/outputDecl.js +209 -0
  194. package/src/xslt/compiler/overrideLinks.js +141 -0
  195. package/src/xslt/compiler/packageChecks.js +84 -0
  196. package/src/xslt/compiler/packageRegistry.js +95 -0
  197. package/src/xslt/compiler/packageTable.js +181 -0
  198. package/src/xslt/compiler/packageVersions.js +143 -0
  199. package/src/xslt/compiler/packages.js +138 -0
  200. package/src/xslt/compiler/registry.js +234 -0
  201. package/src/xslt/compiler/staticStage.js +197 -0
  202. package/src/xslt/compiler/staticVariables.js +93 -0
  203. package/src/xslt/compiler/stylesheet.js +205 -0
  204. package/src/xslt/compiler/tailPosition.js +74 -0
  205. package/src/xslt/compiler/templatesDecl.js +180 -0
  206. package/src/xslt/compiler/useAccumulators.js +76 -0
  207. package/src/xslt/compiler/useWhen.js +94 -0
  208. package/src/xslt/compiler/visibility.js +160 -0
  209. package/src/xslt/index.js +11 -0
  210. package/src/xslt/instructions/analyzeString.js +137 -0
  211. package/src/xslt/instructions/assert.js +72 -0
  212. package/src/xslt/instructions/attributeSets.js +115 -0
  213. package/src/xslt/instructions/conditional.js +99 -0
  214. package/src/xslt/instructions/control.js +123 -0
  215. package/src/xslt/instructions/copy.js +151 -0
  216. package/src/xslt/instructions/elements.js +161 -0
  217. package/src/xslt/instructions/evaluate.js +189 -0
  218. package/src/xslt/instructions/fork.js +35 -0
  219. package/src/xslt/instructions/grouping.js +106 -0
  220. package/src/xslt/instructions/index.js +94 -0
  221. package/src/xslt/instructions/iterate.js +182 -0
  222. package/src/xslt/instructions/literal.js +142 -0
  223. package/src/xslt/instructions/maps.js +72 -0
  224. package/src/xslt/instructions/merge.js +190 -0
  225. package/src/xslt/instructions/number.js +205 -0
  226. package/src/xslt/instructions/output.js +102 -0
  227. package/src/xslt/instructions/params.js +110 -0
  228. package/src/xslt/instructions/resultDocument.js +143 -0
  229. package/src/xslt/instructions/sort.js +114 -0
  230. package/src/xslt/instructions/sourceDocument.js +73 -0
  231. package/src/xslt/instructions/templates.js +153 -0
  232. package/src/xslt/instructions/text.js +151 -0
  233. package/src/xslt/instructions/try.js +186 -0
  234. package/src/xslt/instructions/variables.js +119 -0
  235. package/src/xslt/names.js +204 -0
  236. package/src/xslt/patterns/axisOrigins.js +121 -0
  237. package/src/xslt/patterns/compile.js +151 -0
  238. package/src/xslt/patterns/general.js +132 -0
  239. package/src/xslt/patterns/grammar.js +190 -0
  240. package/src/xslt/patterns/modes.js +153 -0
  241. package/src/xslt/patterns/paths.js +130 -0
  242. package/src/xslt/patterns/patternChecks.js +29 -0
  243. package/src/xslt/patterns/steps.js +162 -0
  244. package/src/xslt/processor.js +178 -0
  245. package/src/xslt/runtime/accumulatorFunctions.js +48 -0
  246. package/src/xslt/runtime/accumulators.js +174 -0
  247. package/src/xslt/runtime/apply.js +153 -0
  248. package/src/xslt/runtime/atomicKeys.js +36 -0
  249. package/src/xslt/runtime/availability.js +162 -0
  250. package/src/xslt/runtime/baseUri.js +64 -0
  251. package/src/xslt/runtime/compilerHook.js +27 -0
  252. package/src/xslt/runtime/conditional.js +110 -0
  253. package/src/xslt/runtime/context.js +106 -0
  254. package/src/xslt/runtime/copy.js +123 -0
  255. package/src/xslt/runtime/copyFunctions.js +71 -0
  256. package/src/xslt/runtime/copyOrigins.js +60 -0
  257. package/src/xslt/runtime/defaultMethod.js +42 -0
  258. package/src/xslt/runtime/documentContent.js +93 -0
  259. package/src/xslt/runtime/dynamicXPath.js +90 -0
  260. package/src/xslt/runtime/functionCache.js +65 -0
  261. package/src/xslt/runtime/functionCall.js +57 -0
  262. package/src/xslt/runtime/functions.js +191 -0
  263. package/src/xslt/runtime/groups.js +108 -0
  264. package/src/xslt/runtime/invocation.js +156 -0
  265. package/src/xslt/runtime/iteration.js +107 -0
  266. package/src/xslt/runtime/keys.js +141 -0
  267. package/src/xslt/runtime/lazy.js +97 -0
  268. package/src/xslt/runtime/locations.js +86 -0
  269. package/src/xslt/runtime/machine.js +137 -0
  270. package/src/xslt/runtime/merging.js +167 -0
  271. package/src/xslt/runtime/namespaceScope.js +141 -0
  272. package/src/xslt/runtime/numberFormat.js +89 -0
  273. package/src/xslt/runtime/numbering.js +168 -0
  274. package/src/xslt/runtime/params.js +59 -0
  275. package/src/xslt/runtime/properties.js +103 -0
  276. package/src/xslt/runtime/rawResults.js +82 -0
  277. package/src/xslt/runtime/sequenceReceiver.js +102 -0
  278. package/src/xslt/runtime/snapshot.js +66 -0
  279. package/src/xslt/runtime/sortKeys.js +119 -0
  280. package/src/xslt/runtime/streamAvailable.js +60 -0
  281. package/src/xslt/runtime/strip.js +102 -0
  282. package/src/xslt/runtime/transformFunction.js +169 -0
  283. package/src/xslt/runtime/transformation.js +168 -0
  284. package/src/xslt/runtime/transformationContext.js +85 -0
  285. package/src/xslt/runtime/treeReceiver.js +194 -0
  286. package/src/xslt/runtime/values.js +92 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The receiver that collects the result of a sequence constructor as a
3
+ * sequence (variables and parameters with `as`, function bodies,
4
+ * xsl:sequence content...): constructed nodes are parentless, existing
5
+ * nodes are kept as they are.
6
+ *
7
+ * @module @tradik/xslt3/xslt/runtime/sequenceReceiver
8
+ */
9
+
10
+ import { NamespaceNode } from "../../xpath/eval/namespaceNodes.js";
11
+ import { copyNode } from "./copy.js";
12
+ import { prefixOf, TreeReceiver } from "./treeReceiver.js";
13
+
14
+ /** Collects items. */
15
+ export class SequenceReceiver {
16
+ /**
17
+ * @param {() => Document} scratch - Gives the document that owns new
18
+ * nodes
19
+ */
20
+ constructor(scratch) {
21
+ this.scratch = scratch;
22
+ /** @type {Array} the items received */
23
+ this.items = [];
24
+ }
25
+
26
+ /**
27
+ * @param {string} uri
28
+ * @param {string} qname
29
+ * @returns {TreeReceiver} the receiver of the new element's content
30
+ */
31
+ element(uri, qname) {
32
+ const element = this.scratch().createElementNS(uri || null, qname);
33
+ this.items.push(element);
34
+ const content = new TreeReceiver(element, new Map());
35
+ content.declare(prefixOf(qname), uri);
36
+ content.onReplace = (old, renamed) => {
37
+ this.items[this.items.indexOf(old)] = renamed;
38
+ };
39
+ return content;
40
+ }
41
+
42
+ /**
43
+ * @param {string} uri
44
+ * @param {string} qname
45
+ * @param {string} value
46
+ */
47
+ attribute(uri, qname, value) {
48
+ let name = qname;
49
+ if (uri && !prefixOf(qname)) name = `ns0:${qname}`;
50
+ const attribute = this.scratch().createAttributeNS(uri || null, name);
51
+ attribute.value = value;
52
+ attribute.nodeValue = value;
53
+ this.items.push(attribute);
54
+ }
55
+
56
+ /**
57
+ * @param {string} prefix
58
+ * @param {string} uri
59
+ */
60
+ namespace(prefix, uri) {
61
+ this.items.push(new NamespaceNode(null, prefix, uri));
62
+ }
63
+
64
+ /** @param {string} text */
65
+ text(text) {
66
+ this.items.push(this.scratch().createTextNode(text));
67
+ }
68
+
69
+ /** @param {string} text */
70
+ comment(text) {
71
+ this.items.push(this.scratch().createComment(text));
72
+ }
73
+
74
+ /**
75
+ * @param {string} target
76
+ * @param {string} data
77
+ */
78
+ pi(target, data) {
79
+ this.items.push(this.scratch().createProcessingInstruction(target, data));
80
+ }
81
+
82
+ /** @param {*} item - Any item, kept as it is */
83
+ item(item) {
84
+ this.items.push(item);
85
+ }
86
+
87
+ /**
88
+ * Adds a copy of a node.
89
+ * @param {Node} node
90
+ * @param {boolean} copyNamespaces
91
+ */
92
+ copy(node, copyNamespaces) {
93
+ copyNode(node, this, copyNamespaces);
94
+ }
95
+
96
+ /** @returns {TreeReceiver} the receiver of a new document node */
97
+ document() {
98
+ const fragment = this.scratch().createDocumentFragment();
99
+ this.items.push(fragment);
100
+ return new TreeReceiver(fragment, new Map());
101
+ }
102
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * fn:snapshot of one node (XSLT 3.0 section 20.7): a deep copy of the
3
+ * node inside copies of its ancestors. Each ancestor is copied with its
4
+ * attributes and namespaces but without its other children, so the copy
5
+ * keeps the node's root, parent, attributes and namespaces.
6
+ *
7
+ * @module @tradik/xslt3/xslt/runtime/snapshot
8
+ */
9
+
10
+ import { namedAttributeOf, parentOf } from "../../xpath/eval/domNodes.js";
11
+ import { namespaceNodesOf } from "../../xpath/eval/namespaceNodes.js";
12
+ import { copyNode, startElementCopy } from "./copy.js";
13
+
14
+ /**
15
+ * Copies the ancestors of a node, outermost first.
16
+ * @param {Node[]} ancestors - Root first
17
+ * @param {object} receiver - Sequence receiver that gets the root copy
18
+ * @param {(copy: Node, original: Node) => void} record - Told of each copy
19
+ * @returns {object} the tree receiver of the innermost copy's content
20
+ */
21
+ function copyAncestors(ancestors, receiver, record) {
22
+ const [root, ...rest] = ancestors;
23
+ let content =
24
+ root.nodeType === 1
25
+ ? startElementCopy(root, receiver, true)
26
+ : receiver.document();
27
+ record(content.parent, root);
28
+ for (const element of rest) {
29
+ content = startElementCopy(element, content, true);
30
+ record(content.parent, element);
31
+ }
32
+ return content;
33
+ }
34
+
35
+ /**
36
+ * The snapshot of a node.
37
+ * @param {Node} node
38
+ * @param {object} receiver - Sequence receiver (items get the root copy)
39
+ * @param {(copy: Node, original: Node) => void} record - Told of the
40
+ * copy of each ancestor (accumulator values are those of the originals)
41
+ * @returns {Node} the copy of the node inside the copied tree
42
+ */
43
+ export function snapshotNode(node, receiver, record) {
44
+ const ancestors = [];
45
+ for (let p = parentOf(node); p; p = parentOf(p)) ancestors.unshift(p);
46
+ if (ancestors.length === 0) {
47
+ copyNode(node, receiver, true);
48
+ return receiver.items.at(-1);
49
+ }
50
+ const content = copyAncestors(ancestors, receiver, record);
51
+ const parent = content.parent;
52
+ if (node.nodeType === 2) {
53
+ return namedAttributeOf(
54
+ parent,
55
+ node.namespaceURI ?? "",
56
+ node.localName ?? node.nodeName,
57
+ );
58
+ }
59
+ if (node.nodeType === 13) {
60
+ return namespaceNodesOf(parent).find(
61
+ (ns) => ns.localName === node.localName,
62
+ );
63
+ }
64
+ copyNode(node, content, true);
65
+ return parent.lastChild;
66
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Sort keys at run time (XSLT 3.0 sections 13.1.2 and 13.1.3): the
3
+ * settings of a key from its attribute value templates, the key value of
4
+ * an item, and the comparison of key values (empty first, then NaN).
5
+ *
6
+ * @module @tradik/xslt3/xslt/runtime/sortKeys
7
+ */
8
+
9
+ import { getCollation } from "../../functions/collations.js";
10
+ import { stringItem } from "../../xpath/eval/atomics.js";
11
+ import { compareAtomic } from "../../xdm/compare.js";
12
+ import { toNumber } from "../../xdm/generalCompare.js";
13
+ import { atomize, stringValue } from "../../xdm/nodes.js";
14
+ import { types } from "../../xdm/types.js";
15
+ import { cast } from "../../xdm/cast.js";
16
+ import { xsltError } from "../names.js";
17
+ import { evaluate } from "./context.js";
18
+ import { bodySequence } from "./values.js";
19
+
20
+ /**
21
+ * The comparison function of a lang or case-order setting.
22
+ * @param {string|undefined} lang
23
+ * @param {string|undefined} caseOrder
24
+ * @returns {(a: string, b: string) => number}
25
+ */
26
+ function languageCollation(lang, caseOrder) {
27
+ let collator;
28
+ try {
29
+ collator = new Intl.Collator(lang || "en", {
30
+ caseFirst: caseOrder === "lower-first" ? "lower" : "upper",
31
+ });
32
+ } catch {
33
+ throw xsltError("XTDE0030", `Invalid lang ${lang}`);
34
+ }
35
+ return (a, b) => collator.compare(a, b);
36
+ }
37
+
38
+ /**
39
+ * The comparison settings of a key, from its attribute value templates.
40
+ * @param {object} key - Compiled xsl:sort
41
+ * @param {object} xc
42
+ * @returns {{descending: boolean, dataType: string, compare: Function}}
43
+ */
44
+ export function settingsOf(key, xc) {
45
+ const order = key.order?.(xc).trim() ?? "ascending";
46
+ if (order !== "ascending" && order !== "descending") {
47
+ throw xsltError("XTDE0030", `Invalid sort order ${order}`);
48
+ }
49
+ const dataType = key.dataType?.(xc).trim() ?? "";
50
+ if (!["", "text", "number"].includes(dataType) && !dataType.includes(":")) {
51
+ throw xsltError("XTDE0030", `Invalid data-type ${dataType}`);
52
+ }
53
+ const caseOrder = key.caseOrder?.(xc).trim();
54
+ if (caseOrder && caseOrder !== "upper-first" && caseOrder !== "lower-first") {
55
+ throw xsltError("XTDE0030", `Invalid case-order ${caseOrder}`);
56
+ }
57
+ const lang = key.lang?.(xc).trim();
58
+ let compare;
59
+ if (key.collation) {
60
+ const uri = key.collation(xc).trim();
61
+ try {
62
+ compare = getCollation(uri, xc.tx.dyn).compare;
63
+ } catch {
64
+ throw xsltError("XTDE1035", `Unknown collation ${uri}`);
65
+ }
66
+ } else if (lang || caseOrder) compare = languageCollation(lang, caseOrder);
67
+ return { descending: order === "descending", dataType, compare };
68
+ }
69
+
70
+ /**
71
+ * The sort key value of one item.
72
+ * @param {object} key - Compiled xsl:sort
73
+ * @param {object} settings
74
+ * @param {object} xc - Context with the item as focus
75
+ * @param {object} machine
76
+ * @returns {*} an atomic value, or null for the empty sequence
77
+ */
78
+ export function keyValue(key, settings, xc, machine) {
79
+ let values = key.expr
80
+ ? evaluate(key.expr, xc)
81
+ : bodySequence(key.body, xc, machine);
82
+ if (key.compatible) values = values.slice(0, 1);
83
+ if (settings.dataType === "text") {
84
+ return values.length ? stringItem(values.map(stringValue).join(" ")) : null;
85
+ }
86
+ const atoms = atomize(values);
87
+ if (atoms.length > 1) {
88
+ throw xsltError("XTTE1020", "A sort key must be a single value");
89
+ }
90
+ if (atoms.length === 0) return null;
91
+ if (settings.dataType === "number") return toNumber(atoms[0]);
92
+ const [value] = atoms;
93
+ return value.type === types.untypedAtomic ? cast(value, types.string) : value;
94
+ }
95
+
96
+ const isNaNValue = (v) => typeof v.value === "number" && Number.isNaN(v.value);
97
+
98
+ /**
99
+ * Compares two key values: the empty sequence first, then NaN.
100
+ * @param {*} a
101
+ * @param {*} b
102
+ * @param {object} settings
103
+ * @param {object} xc
104
+ * @returns {number}
105
+ */
106
+ export function compareValues(a, b, settings, xc) {
107
+ if (a === null || b === null) {
108
+ return (a === null ? 0 : 1) - (b === null ? 0 : 1);
109
+ }
110
+ if (isNaNValue(a) || isNaNValue(b)) {
111
+ return Number(!isNaNValue(a)) - Number(!isNaNValue(b));
112
+ }
113
+ const options = { ...xc.tx.dyn.compareOptions, collation: settings.compare };
114
+ try {
115
+ return compareAtomic(a, b, options).order || 0;
116
+ } catch {
117
+ throw xsltError("XTDE1030", "Sort key values are not comparable");
118
+ }
119
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * fn:stream-available (XSLT 3.0 section 18.1): whether a call of
3
+ * xsl:source-document with streamable="yes" on the URI would start
4
+ * successfully. The processor does not stream, so this holds when the
5
+ * resource is a well-formed document or, as a streaming parser would see
6
+ * it, a resource that starts with a well-formed prolog and an element
7
+ * (a later well-formedness error is only met while streaming).
8
+ *
9
+ * @module @tradik/xslt3/xslt/runtime/streamAvailable
10
+ */
11
+
12
+ import { booleanItem } from "../../functions/support.js";
13
+
14
+ /** XML declaration, comments, processing instructions and whitespace. */
15
+ const MISC = String.raw`(?:\s+|<!--[\s\S]*?-->|<\?[\s\S]*?\?>)*`;
16
+
17
+ /** A prolog (with an optional document type declaration), then a tag. */
18
+ const STARTS_WITH_ELEMENT = new RegExp(
19
+ `^\\uFEFF?${MISC}(?:<!DOCTYPE[^\\[>]*(?:\\[[\\s\\S]*?\\]\\s*)?>${MISC})?<[\\p{L}_:]`,
20
+ "u",
21
+ );
22
+
23
+ /**
24
+ * Whether a text starts as an XML document with an element.
25
+ * @param {string} text
26
+ * @returns {boolean}
27
+ */
28
+ export const startsWithElement = (text) => STARTS_WITH_ELEMENT.test(text);
29
+
30
+ /**
31
+ * Whether a document is available for streaming.
32
+ * @param {string} uri
33
+ * @param {object} context - XPath dynamic context
34
+ * @returns {boolean}
35
+ */
36
+ function available(uri, context) {
37
+ try {
38
+ const document = context.loadDocument(uri);
39
+ if (document.documentElement) return true;
40
+ } catch {
41
+ // not a well-formed document: perhaps one that starts well
42
+ }
43
+ try {
44
+ return startsWithElement(context.loadText(uri));
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ /** Function definitions. */
51
+ export const streamAvailableFunctions = [
52
+ {
53
+ local: "stream-available",
54
+ params: ["xs:string?"],
55
+ returns: "xs:boolean",
56
+ impl: ([uri], context) => [
57
+ booleanItem(uri.length > 0 && available(uri[0].value, context)),
58
+ ],
59
+ },
60
+ ];
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Whitespace stripping of source documents (XSLT 3.0 section 4.3): the
3
+ * whitespace-only text nodes whose parent element matches xsl:strip-space
4
+ * (and no better xsl:preserve-space rule), outside xml:space="preserve",
5
+ * are removed from a copy of the document.
6
+ *
7
+ * @module @tradik/xslt3/xslt/runtime/strip
8
+ */
9
+
10
+ import { XML_NS } from "../names.js";
11
+
12
+ const WHITESPACE = /^[ \t\r\n]*$/;
13
+
14
+ /**
15
+ * Builds the decision of the rules for an element name.
16
+ * @param {object[]} rules - Best first (see compileSpaceRules)
17
+ * @returns {(element: Element) => boolean} whether to strip its children
18
+ */
19
+ export function stripDecider(rules) {
20
+ const cache = new Map();
21
+ return (element) => {
22
+ const uri = element.namespaceURI ?? "";
23
+ const local = element.localName;
24
+ const key = `{${uri}}${local}`;
25
+ let strip = cache.get(key);
26
+ if (strip === undefined) {
27
+ const rule = rules.find(
28
+ (r) =>
29
+ (r.uri === null || r.uri === uri) &&
30
+ (r.local === null || r.local === local),
31
+ );
32
+ strip = rule ? rule.strip : false;
33
+ cache.set(key, strip);
34
+ }
35
+ return strip;
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Whether a text node is one that stripping removes: whitespace only,
41
+ * its parent element matched by xsl:strip-space and not under
42
+ * xml:space="preserve".
43
+ * @param {Node} node
44
+ * @param {object[]} rules
45
+ * @returns {boolean}
46
+ */
47
+ export function isStrippedText(node, rules) {
48
+ const parent = node.parentNode;
49
+ if (node.nodeType !== 3 || parent?.nodeType !== 1) return false;
50
+ if (!WHITESPACE.test(node.nodeValue) || !stripDecider(rules)(parent)) {
51
+ return false;
52
+ }
53
+ for (let e = parent; e?.nodeType === 1; e = e.parentNode) {
54
+ const space = e.getAttributeNS(XML_NS, "space");
55
+ if (space) return space !== "preserve";
56
+ }
57
+ return true;
58
+ }
59
+
60
+ /**
61
+ * A stripped copy of a document (the document itself when no rule
62
+ * strips anything).
63
+ * @param {Document} document
64
+ * @param {object[]} rules
65
+ * @returns {Document}
66
+ */
67
+ export function stripDocument(document, rules) {
68
+ if (!rules.some((rule) => rule.strip)) return document;
69
+ const decide = stripDecider(rules);
70
+ const copy = document.implementation.createDocument(null, null, null);
71
+ for (const child of document.childNodes) {
72
+ if (child.nodeType !== 10) copy.appendChild(copy.importNode(child, true));
73
+ }
74
+ if (document.documentURI) {
75
+ try {
76
+ copy.documentURI = document.documentURI;
77
+ } catch {
78
+ // read-only in some DOMs
79
+ }
80
+ }
81
+ const stack = [[copy.documentElement, false]];
82
+ while (stack.length > 0) {
83
+ const [element, preserved] = stack.pop();
84
+ if (!element) continue;
85
+ const space = element.getAttributeNS(XML_NS, "space");
86
+ const keep = space === "preserve" || (space !== "default" && preserved);
87
+ const strip = !keep && decide(element);
88
+ for (let child = element.firstChild; child;) {
89
+ const next = child.nextSibling;
90
+ if (child.nodeType === 1) stack.push([child, keep]);
91
+ else if (
92
+ strip &&
93
+ child.nodeType === 3 &&
94
+ WHITESPACE.test(child.nodeValue)
95
+ ) {
96
+ element.removeChild(child);
97
+ }
98
+ child = next;
99
+ }
100
+ }
101
+ return copy;
102
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * fn:transform (F&O 3.1, "Dynamic loading"): runs another stylesheet from an
3
+ * XPath expression and returns its results as a map: "output" for the
4
+ * principal result and the absolute URI of each secondary result, each
5
+ * delivered as a document (default), serialized as a string, or raw.
6
+ * The stylesheet is compiled with the options of the calling one (module
7
+ * and package loaders) and runs with the resource loaders of the calling
8
+ * transformation.
9
+ *
10
+ * @module @tradik/xslt3/xslt/runtime/transformFunction
11
+ */
12
+
13
+ import { XdmMap } from "../../items/map.js";
14
+ import { serialize } from "../../serialize/index.js";
15
+ import { atomize } from "../../xdm/nodes.js";
16
+ import { parametersFromMap } from "../../serialize/params/fromMap.js";
17
+ import { stringItem } from "../../xpath/eval/atomics.js";
18
+ import { resolveUri } from "../../xpath/eval/uris.js";
19
+ import { xsltError } from "../names.js";
20
+ import { compileWith } from "./compilerHook.js";
21
+
22
+ /**
23
+ * @param {*} item - An xs:QName value
24
+ * @returns {string} its Clark name
25
+ */
26
+ const clark = (item) => `{${item.value.namespaceURI}}${item.value.localName}`;
27
+
28
+ /**
29
+ * A map with QName keys as a Map by Clark name.
30
+ * @param {XdmMap|undefined} map
31
+ * @returns {Map<string, Array>}
32
+ */
33
+ function byClarkName(map) {
34
+ const result = new Map();
35
+ for (const { key, value } of map?.entries.values() ?? []) {
36
+ result.set(clark(key), value);
37
+ }
38
+ return result;
39
+ }
40
+
41
+ /**
42
+ * The string value of an option, atomized (a value built by
43
+ * xsl:map-entry content is a text node).
44
+ * @param {Array|undefined} value
45
+ * @returns {string|undefined}
46
+ */
47
+ const text = (value) =>
48
+ value?.length ? String(atomize(value.slice(0, 1))[0]?.value) : undefined;
49
+
50
+ /**
51
+ * Reads the options map.
52
+ * @param {XdmMap} map
53
+ * @returns {(name: string) => Array|undefined} the value of an option
54
+ */
55
+ const reader = (map) => (name) => map.get(stringItem(name));
56
+
57
+ /**
58
+ * The stylesheet to run, compiled.
59
+ * @param {(name: string) => Array|undefined} option
60
+ * @param {object} context - XPath dynamic context
61
+ * @param {object} compileOptions - Options of the calling stylesheet
62
+ * @returns {object} the CompiledStylesheet
63
+ * @throws {import("../../errors.js").XPathError} FOXT0002 when no
64
+ * stylesheet is given or it cannot be loaded
65
+ */
66
+ function compiled(option, context, compileOptions) {
67
+ const value = (name) => option(name)?.[0];
68
+ const staticParams = byClarkName(value("static-params"));
69
+ const base = text(option("stylesheet-base-uri"));
70
+ const compile = (source, baseUri) =>
71
+ compileWith(source, { ...compileOptions, baseUri, staticParams });
72
+ const location = text(option("stylesheet-location"));
73
+ if (location !== undefined) {
74
+ const uri = resolveUri(location, context.staticBaseUri);
75
+ let source;
76
+ try {
77
+ source = compileOptions.loadStylesheet?.(uri, context.staticBaseUri);
78
+ } catch (error) {
79
+ throw xsltError("FOXT0002", `Cannot load ${uri}: ${error.message}`);
80
+ }
81
+ if (!source) throw xsltError("FOXT0002", `No stylesheet at ${uri}`);
82
+ return compile(source, uri);
83
+ }
84
+ const node = value("stylesheet-node") ?? text(option("stylesheet-text"));
85
+ if (node !== undefined) return compile(node, base);
86
+ const name = text(option("package-name"));
87
+ const found =
88
+ name === undefined
89
+ ? undefined
90
+ : compileOptions.resolvePackage?.(
91
+ name,
92
+ text(option("package-version")) ?? "*",
93
+ );
94
+ if (!found) throw xsltError("FOXT0002", "fn:transform: no stylesheet");
95
+ return compile(found.source ?? found, found.baseUri ?? base);
96
+ }
97
+
98
+ /**
99
+ * A result in the requested delivery format.
100
+ * @param {*} value - Document, fragment or raw sequence
101
+ * @param {string} format - "document", "serialized" or "raw"
102
+ * @param {object} output - Its serialization parameters
103
+ * @returns {Array}
104
+ */
105
+ function delivered(value, format, output) {
106
+ const sequence = [value].flat();
107
+ if (format === "serialized") return [stringItem(serialize(sequence, output))];
108
+ return sequence;
109
+ }
110
+
111
+ /**
112
+ * fn:transform.
113
+ * @param {Array} args - The options map
114
+ * @param {object} context - XPath dynamic context
115
+ * @returns {Array} the result map
116
+ */
117
+ function transform([[map]], context) {
118
+ const option = reader(map);
119
+ const value = (name) => option(name)?.[0];
120
+ const tx = context.xc?.tx;
121
+ const compileOptions =
122
+ tx?.stylesheet.options ?? context.sc?.owner?.options ?? {};
123
+ const format = text(option("delivery-format")) ?? "document";
124
+ const stylesheet = compiled(option, context, compileOptions);
125
+ const initial = (name) => (value(name) ? clark(value(name)) : undefined);
126
+ const functionParams = value("function-params");
127
+ const result = stylesheet.transform({
128
+ ...tx?.options,
129
+ source: value("source-node"),
130
+ initialTemplate: initial("initial-template"),
131
+ initialMode: initial("initial-mode"),
132
+ initialMatchSelection: option("initial-match-selection"),
133
+ initialFunction: value("initial-function") && {
134
+ name: initial("initial-function"),
135
+ args: functionParams?.members ?? [],
136
+ },
137
+ globalContextItem: value("global-context-item"),
138
+ params: byClarkName(value("stylesheet-params")),
139
+ templateParams: byClarkName(value("template-params")),
140
+ tunnelParams: byClarkName(value("tunnel-params")),
141
+ baseOutputUri: text(option("base-output-uri")),
142
+ buildTree: format === "raw" ? false : undefined,
143
+ onMessage: undefined,
144
+ });
145
+ const extra = value("serialization-params");
146
+ const params = extra ? parametersFromMap(extra) : {};
147
+ const entries = [];
148
+ const principal = [result.principal].flat();
149
+ if (principal.length > 0 || format !== "raw") {
150
+ entries.push([
151
+ stringItem("output"),
152
+ delivered(result.principal, format, { ...result.output, ...params }),
153
+ ]);
154
+ }
155
+ for (const [uri, { document, output }] of result.secondary) {
156
+ entries.push([stringItem(uri), delivered(document, format, output)]);
157
+ }
158
+ return [XdmMap.from(entries)];
159
+ }
160
+
161
+ /** Function definitions. */
162
+ export const transformFunctions = [
163
+ {
164
+ local: "transform",
165
+ params: ["map(*)"],
166
+ returns: "map(*)",
167
+ impl: transform,
168
+ },
169
+ ];