@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,174 @@
1
+ /**
2
+ * Accumulator values at run time (XSLT 3.0 sections 18.2.2 to 18.2.7):
3
+ * computed for a whole tree the first time a value of the tree is asked
4
+ * for, by a document-order traversal on an explicit stack, and cached
5
+ * per tree. Which accumulators apply to a tree is recorded per root (the
6
+ * source document: those of the initial mode; xsl:source-document: its
7
+ * use-accumulators; any other tree: all of them).
8
+ *
9
+ * @module @tradik/xslt3/xslt/runtime/accumulators
10
+ */
11
+
12
+ import { childrenOf, rootOf } from "../../xpath/eval/domNodes.js";
13
+ import { xsltError } from "../names.js";
14
+ import { patternMatches } from "../patterns/compile.js";
15
+ import { derive } from "./context.js";
16
+ import { originalNode } from "./copyOrigins.js";
17
+
18
+ /**
19
+ * The accumulator state of a transformation, created on first use.
20
+ * @param {object} tx
21
+ * @returns {{scopes: WeakMap, values: WeakMap, origins: WeakMap}}
22
+ */
23
+ function stateOf(tx) {
24
+ tx.accumulatorState ??= {
25
+ scopes: new WeakMap(),
26
+ values: new WeakMap(),
27
+ origins: new WeakMap(),
28
+ };
29
+ return tx.accumulatorState;
30
+ }
31
+
32
+ /**
33
+ * Records which accumulators apply to a tree.
34
+ * @param {object} tx
35
+ * @param {Node} root - Root of the tree
36
+ * @param {Set<string>|"all"} accumulators
37
+ */
38
+ export function setApplicable(tx, root, accumulators) {
39
+ stateOf(tx).scopes.set(root, accumulators);
40
+ }
41
+
42
+ /**
43
+ * Records that the nodes of a copy take their accumulator values from
44
+ * the nodes they were copied from.
45
+ * @param {object} tx
46
+ * @param {Node} copy
47
+ * @param {Node} original
48
+ */
49
+ export function setOrigin(tx, copy, original) {
50
+ stateOf(tx).origins.set(copy, original);
51
+ }
52
+
53
+ /**
54
+ * The new value of an accumulator at a traversal event.
55
+ * @param {object} accumulator
56
+ * @param {Node} node
57
+ * @param {boolean} end - Phase
58
+ * @param {Array} value - The old value
59
+ * @param {object} xc - Context of the transformation
60
+ * @returns {Array}
61
+ */
62
+ function step(accumulator, node, end, value, xc) {
63
+ const focus = derive(xc, { item: node, position: 1, size: 1 });
64
+ let rule = null;
65
+ for (const candidate of accumulator.rules) {
66
+ if (
67
+ candidate.end === end &&
68
+ patternMatches(candidate.pattern, node, focus)
69
+ ) {
70
+ rule = candidate;
71
+ }
72
+ }
73
+ if (!rule) return value;
74
+ const env = { value, next: xc.tx.globalEnv };
75
+ return rule.value(derive(focus, { env }), xc.tx.machine);
76
+ }
77
+
78
+ /**
79
+ * Computes the values of an accumulator for every node of a tree.
80
+ * @param {object} accumulator
81
+ * @param {Node} root
82
+ * @param {object} entry - Receives `before` and `after` (Maps by node)
83
+ * @param {object} xc - Context of the transformation
84
+ */
85
+ function traverse(accumulator, root, entry, xc) {
86
+ let value;
87
+ let failure = null;
88
+ const apply = (compute) => {
89
+ if (failure) return;
90
+ try {
91
+ value = compute();
92
+ } catch (error) {
93
+ failure = { error };
94
+ }
95
+ };
96
+ apply(() =>
97
+ accumulator.initial(derive(xc, { item: root, position: 1, size: 1 })),
98
+ );
99
+ const stack = [[root, false]];
100
+ while (stack.length > 0) {
101
+ const [node, closing] = stack.pop();
102
+ apply(() => step(accumulator, node, closing, value, xc));
103
+ (closing ? entry.after : entry.before).set(node, failure ?? { value });
104
+ if (closing) continue;
105
+ stack.push([node, true]);
106
+ const children = childrenOf(node);
107
+ for (let i = children.length - 1; i >= 0; i--) {
108
+ stack.push([children[i], false]);
109
+ }
110
+ }
111
+ }
112
+
113
+ /**
114
+ * The pre- or post-descent value of an accumulator at a node.
115
+ * @param {object} xc - XSLT context
116
+ * @param {string} key - Clark name of the accumulator
117
+ * @param {Node} node
118
+ * @param {boolean} after - Post-descent value
119
+ * @param {object} accumulator - The declaration (packages may each have
120
+ * one of that name)
121
+ * @returns {Array}
122
+ */
123
+ export function accumulatorValue(xc, key, node, after, accumulator) {
124
+ const tx = xc.tx;
125
+ const state = stateOf(tx);
126
+ let target = node;
127
+ for (let o; (o = originalNode(state.origins, target));) target = o;
128
+ const root = rootOf(target);
129
+ const scope = state.scopes.get(root) ?? "all";
130
+ if (scope !== "all" && !scope.has(key)) {
131
+ throw xsltError("XTDE3362", `The accumulator ${key} does not apply here`);
132
+ }
133
+ let byKey = state.values.get(root);
134
+ if (!byKey) state.values.set(root, (byKey = new Map()));
135
+ let entry = byKey.get(accumulator);
136
+ if (!entry) {
137
+ entry = { before: new Map(), after: new Map(), done: false };
138
+ byKey.set(accumulator, entry);
139
+ traverse(accumulator, root, entry, tx.globalContext);
140
+ entry.done = true;
141
+ }
142
+ const result = (after ? entry.after : entry.before).get(target);
143
+ if (!result) {
144
+ throw xsltError("XTDE3400", `The accumulator ${key} depends on itself`);
145
+ }
146
+ if (result.error) throw result.error;
147
+ return result.value;
148
+ }
149
+
150
+ /**
151
+ * Records the accumulators that apply to the trees of the global context
152
+ * item (xsl:global-context-item, all by default) and of the initial match
153
+ * selection (those of the initial mode, none by default).
154
+ * @param {object} tx
155
+ * @param {object} options - See CompiledStylesheet.transform
156
+ * @param {*} source - The (stripped) source node
157
+ */
158
+ export function setInitialAccumulators(tx, options, source) {
159
+ const { stylesheet } = tx;
160
+ const fromItems =
161
+ options.initialTemplate === undefined && !options.initialFunction;
162
+ const selection = fromItems
163
+ ? [options.initialMatchSelection ?? source].flat()
164
+ : [];
165
+ const fromMode = tx.defaultMode.accumulators ?? new Set();
166
+ for (const item of selection) {
167
+ if (typeof item?.nodeType === "number") {
168
+ setApplicable(tx, rootOf(item), fromMode);
169
+ }
170
+ }
171
+ if (typeof source?.nodeType === "number" && !selection.includes(source)) {
172
+ setApplicable(tx, rootOf(source), stylesheet.globalAccumulators);
173
+ }
174
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Template invocation at run time (XSLT 3.0 sections 6.7 to 6.9 and
3
+ * 10.1): applying templates to items in a mode, the built-in template
4
+ * rules, and binding the parameters of a template.
5
+ *
6
+ * @module @tradik/xslt3/xslt/runtime/apply
7
+ */
8
+
9
+ import { childrenOf, attributesOf } from "../../xpath/eval/domNodes.js";
10
+ import { isAtomic } from "../../xdm/atomic.js";
11
+ import { canonicalString } from "../../xdm/lexical.js";
12
+ import { stringValue } from "../../xdm/nodes.js";
13
+ import { xsltError } from "../names.js";
14
+ import { derive, withVariable } from "./context.js";
15
+ import { markCopied, markDocumentCopied } from "./baseUri.js";
16
+ import { copyNamespaceNodes } from "./copy.js";
17
+ import { BodyFrame, LoopFrame } from "./machine.js";
18
+ import { SequenceReceiver } from "./sequenceReceiver.js";
19
+
20
+ /**
21
+ * Parameters passed to a template: non-tunnel ones by Clark name, and
22
+ * the tunnel parameters this call adds.
23
+ * @typedef {{params: Map<string, Array>, tunnel: Map<string, Array>|null}} Args
24
+ */
25
+
26
+ /** No parameters. */
27
+ export const NO_ARGS = Object.freeze({ params: new Map(), tunnel: null });
28
+
29
+ /**
30
+ * Instantiates a template: binds its parameters and runs its body.
31
+ * @param {object} template - Compiled template
32
+ * @param {object} xc - Context of the invocation (focus, mode, rule set)
33
+ * @param {object} out - Receiver
34
+ * @param {import("./machine.js").Machine} machine
35
+ * @param {Args} args
36
+ */
37
+ export function invokeTemplate(template, xc, out, machine, args) {
38
+ let tunnel = xc.tunnel;
39
+ if (args.tunnel && args.tunnel.size > 0) {
40
+ tunnel = new Map(tunnel ?? []);
41
+ for (const [key, value] of args.tunnel) tunnel.set(key, value);
42
+ }
43
+ let ctx = derive(xc, { env: xc.tx.globalEnv, tunnel, merge: undefined });
44
+ for (const param of template.params) {
45
+ let value = param.tunnel
46
+ ? tunnel?.get(param.key)
47
+ : args.params.get(param.key);
48
+ if (value !== undefined) value = param.convert(value);
49
+ else if (param.required) {
50
+ throw xsltError("XTDE0700", `The parameter ${param.key} is required`);
51
+ } else value = param.value(ctx, machine);
52
+ ctx = withVariable(ctx, value);
53
+ }
54
+ if (template.convert) {
55
+ const result = new SequenceReceiver(xc.tx.scratch);
56
+ machine.runBody(template.body, ctx, result);
57
+ for (const item of template.convert(result.items)) out.item(item);
58
+ } else if (template.body.length > 0) {
59
+ machine.push(new BodyFrame(template.body, ctx, out));
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Applies templates to one item (the body of a LoopFrame visit).
65
+ * @param {*} item
66
+ * @param {object} xc - Context with the focus on the item
67
+ * @param {object} mode
68
+ * @param {object} out
69
+ * @param {import("./machine.js").Machine} machine
70
+ * @param {Args} args
71
+ */
72
+ export function applyToItem(item, xc, mode, out, machine, args) {
73
+ const rule = mode.find(item, xc);
74
+ if (rule) {
75
+ invokeTemplate(rule.template, derive(xc, { rule }), out, machine, args);
76
+ } else applyBuiltIn(item, xc, mode, out, machine, args);
77
+ }
78
+
79
+ /**
80
+ * Applies templates to a sequence of items in a mode.
81
+ * @param {Array} items
82
+ * @param {object} mode
83
+ * @param {object} xc - Context of the instruction
84
+ * @param {object} out
85
+ * @param {import("./machine.js").Machine} machine
86
+ * @param {Args} args
87
+ */
88
+ export function applyTemplates(items, mode, xc, out, machine, args) {
89
+ const size = items.length;
90
+ if (size === 0) return;
91
+ const base = derive(xc, {
92
+ mode,
93
+ group: undefined,
94
+ groupKey: undefined,
95
+ });
96
+ machine.push(
97
+ new LoopFrame(size, (i) => {
98
+ const item = items[i];
99
+ const ixc = derive(base, { item, position: i + 1, size });
100
+ applyToItem(item, ixc, mode, out, machine, args);
101
+ }),
102
+ );
103
+ }
104
+
105
+ /**
106
+ * The built-in template rule of a mode (its on-no-match behaviour).
107
+ * @param {*} item
108
+ * @param {object} xc - Context with the focus on the item
109
+ * @param {object} mode
110
+ * @param {object} out
111
+ * @param {import("./machine.js").Machine} machine
112
+ * @param {Args} args
113
+ */
114
+ export function applyBuiltIn(item, xc, mode, out, machine, args) {
115
+ const action = mode.onNoMatch;
116
+ const type = item?.nodeType;
117
+ const container = type === 1 || type === 9 || type === 11;
118
+ if (action === "fail") {
119
+ throw xsltError("XTDE0555", "No template rule matches the item");
120
+ }
121
+ // deep-skip processes the children of a document node (XSLT 3.0 6.7.1)
122
+ if (action === "deep-skip" && type !== 9 && type !== 11) return;
123
+ const copy = action === "shallow-copy";
124
+ if (action === "deep-copy" || (copy && !container)) {
125
+ if (type === undefined) out.item(item);
126
+ else out.copy(item, true);
127
+ return;
128
+ }
129
+ if (!container) {
130
+ if (action === "text-only-copy") {
131
+ if (isAtomic(item)) out.text(canonicalString(item));
132
+ else if (type === 2 || type === 3 || type === 4) {
133
+ out.text(stringValue(item));
134
+ }
135
+ }
136
+ return;
137
+ }
138
+ let target = out;
139
+ if (copy && type === 1) {
140
+ target = out.element(item.namespaceURI ?? "", item.nodeName);
141
+ markCopied(item, target.parent);
142
+ copyNamespaceNodes(item, target);
143
+ } else if (copy) {
144
+ target = out.document();
145
+ markDocumentCopied(item, target);
146
+ }
147
+ const children = childrenOf(item);
148
+ const selected =
149
+ type === 1 && action !== "text-only-copy"
150
+ ? [...attributesOf(item), ...children]
151
+ : children;
152
+ applyTemplates(selected, mode, xc, target, machine, args);
153
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Hash keys of atomic values for keys and grouping: two values get the
3
+ * same key when they are equal under `eq` (untyped values compared as
4
+ * strings, numbers compared as doubles after promotion, strings under a
5
+ * collation).
6
+ *
7
+ * @module @tradik/xslt3/xslt/runtime/atomicKeys
8
+ */
9
+
10
+ import { toDouble } from "../../functions/support.js";
11
+ import { mapKey } from "../../items/mapKey.js";
12
+ import { cast } from "../../xdm/cast.js";
13
+ import { types } from "../../xdm/types.js";
14
+
15
+ const NUMERIC = new Set(["decimal", "float", "double"]);
16
+
17
+ /**
18
+ * The key of an atomic value.
19
+ * @param {import("../../xdm/atomic.js").AtomicValue} value
20
+ * @param {{key: ((s: string) => string)|null}|null} [collation]
21
+ * @returns {string}
22
+ */
23
+ export function comparisonKey(value, collation = null) {
24
+ const atomic =
25
+ value.type === types.untypedAtomic ? cast(value, types.string) : value;
26
+ const primitive = atomic.type.primitive.localName;
27
+ if (NUMERIC.has(primitive)) return `n${toDouble(atomic)}`;
28
+ const key = mapKey(atomic);
29
+ if (collation?.key && key.startsWith("s")) {
30
+ return `s${collation.key(atomic.value)}`;
31
+ }
32
+ return key;
33
+ }
34
+
35
+ /** The key of NaN values. */
36
+ export const NAN_KEY = "nNaN";
@@ -0,0 +1,162 @@
1
+ /**
2
+ * The functions that tell what the processor provides (XSLT 3.0 section
3
+ * 20.4): system-property(), available-system-properties(),
4
+ * element-available(), function-available() and type-available().
5
+ *
6
+ * @module @tradik/xslt3/xslt/runtime/availability
7
+ */
8
+
9
+ import { isStandardFunction, NS } from "../../functions/signatures.js";
10
+ import { booleanItem, stringItem } from "../../xpath/eval/atomics.js";
11
+ import { AtomicValue } from "../../xdm/atomic.js";
12
+ import { QNameValue } from "../../xdm/qname.js";
13
+ import { getType, types, XS_NAMESPACE } from "../../xdm/types.js";
14
+ import { LIST_TYPES } from "../../xpath/eval/typeExprs.js";
15
+ import { resolveQName, XSL_NS } from "../names.js";
16
+ import {
17
+ availableInstructions,
18
+ systemProperty,
19
+ systemPropertyNames,
20
+ } from "./properties.js";
21
+
22
+ /**
23
+ * Resolves a QName argument with the namespaces of the calling expression.
24
+ * @param {string} text
25
+ * @param {object} context - Dynamic context (with `sc`)
26
+ * @param {string} code - Error code for an invalid name
27
+ * @param {string} [defaultUri] - Namespace of unprefixed names
28
+ * @returns {{uri: string, local: string}}
29
+ */
30
+ export function nameArgument(text, context, code, defaultUri = "") {
31
+ const namespaces = new Map(context.sc.namespaces);
32
+ namespaces.set("", defaultUri);
33
+ return resolveQName(text, namespaces, { code, useDefault: true });
34
+ }
35
+
36
+ /**
37
+ * Whether the transformation allows xsl:evaluate (the dynamicEvaluation
38
+ * option); always at compile time.
39
+ * @param {object} context - XPath dynamic context
40
+ * @returns {boolean}
41
+ */
42
+ const dynamicEvaluation = (context) =>
43
+ context.xc?.tx.dynamicEvaluation !== false;
44
+
45
+ /**
46
+ * Whether a function of a name exists with an arity.
47
+ * @param {object} library
48
+ * @param {string} uri
49
+ * @param {string} local
50
+ * @param {number} arity
51
+ * @returns {boolean}
52
+ */
53
+ const hasFunction = (library, uri, local, arity) =>
54
+ Boolean(library.lookup(uri, local, arity)) ||
55
+ isStandardFunction(uri, local, arity);
56
+
57
+ /**
58
+ * function-available().
59
+ * @param {Array} args
60
+ * @param {object} context
61
+ * @returns {Array}
62
+ */
63
+ function functionAvailable([[name], arity], context) {
64
+ const { uri, local } = nameArgument(name.value, context, "XTDE1400", NS.fn);
65
+ const library = context.sc.functions;
66
+ const n = arity?.length ? Number(arity[0].value) : null;
67
+ let found = false;
68
+ for (let i = n ?? 0; i <= (n ?? 20) && !found; i++) {
69
+ found = hasFunction(library, uri, local, i);
70
+ }
71
+ if (!found && uri === XS_NAMESPACE && (n === null || n === 1)) {
72
+ try {
73
+ // list types (xs:NMTOKENS...) have constructor functions too
74
+ found = Boolean(LIST_TYPES[local]) || !getType(local).abstract;
75
+ } catch {
76
+ found = false;
77
+ }
78
+ }
79
+ return [booleanItem(found)];
80
+ }
81
+
82
+ /**
83
+ * type-available().
84
+ * @param {Array} args
85
+ * @param {object} context
86
+ * @returns {Array}
87
+ */
88
+ function typeAvailable([[name]], context) {
89
+ const { uri, local } = nameArgument(name.value, context, "XTDE1428");
90
+ let found = false;
91
+ if (uri === XS_NAMESPACE) {
92
+ try {
93
+ found = Boolean(getType(local));
94
+ } catch {
95
+ found = ["anyType", "untyped", "anySimpleType"].includes(local);
96
+ }
97
+ }
98
+ return [booleanItem(found)];
99
+ }
100
+
101
+ /** Function definitions. */
102
+ export const availabilityFunctions = [
103
+ {
104
+ local: "system-property",
105
+ params: ["xs:string"],
106
+ returns: "xs:string",
107
+ impl: ([[name]], context) => {
108
+ const { uri, local } = nameArgument(name.value, context, "XTDE1390");
109
+ if (uri !== XSL_NS) return [stringItem("")];
110
+ const off =
111
+ local === "supports-dynamic-evaluation" && !dynamicEvaluation(context);
112
+ return [stringItem(off ? "no" : systemProperty(local))];
113
+ },
114
+ },
115
+ {
116
+ local: "available-system-properties",
117
+ params: [],
118
+ returns: "xs:QName*",
119
+ impl: () =>
120
+ systemPropertyNames().map(
121
+ (local) =>
122
+ new AtomicValue(types.QName, new QNameValue(XSL_NS, local, "xsl")),
123
+ ),
124
+ },
125
+ {
126
+ local: "element-available",
127
+ params: ["xs:string"],
128
+ returns: "xs:boolean",
129
+ impl: ([[name]], context) => {
130
+ // unprefixed: the default namespace (xmlns) in scope
131
+ const { uri, local } = nameArgument(
132
+ name.value,
133
+ context,
134
+ "XTDE1440",
135
+ context.sc.defaultNamespace,
136
+ );
137
+ const available =
138
+ uri === XSL_NS &&
139
+ availableInstructions.has(local) &&
140
+ (local !== "evaluate" || dynamicEvaluation(context));
141
+ return [booleanItem(available)];
142
+ },
143
+ },
144
+ {
145
+ local: "function-available",
146
+ params: ["xs:string"],
147
+ returns: "xs:boolean",
148
+ impl: functionAvailable,
149
+ },
150
+ {
151
+ local: "function-available",
152
+ params: ["xs:string", "xs:integer"],
153
+ returns: "xs:boolean",
154
+ impl: functionAvailable,
155
+ },
156
+ {
157
+ local: "type-available",
158
+ params: ["xs:string"],
159
+ returns: "xs:boolean",
160
+ impl: typeAvailable,
161
+ },
162
+ ];
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Base URIs of constructed nodes (XSLT 3.0 sections 11.1.? and 9.4): a
3
+ * temporary tree and the outermost element built by an instruction take
4
+ * the static base URI of the instruction; a copied element keeps the base
5
+ * URI of the original. Inner elements inherit theirs, adjusted by
6
+ * xml:base attributes, when fn:base-uri() asks (functions/nodePaths.js).
7
+ *
8
+ * @module @tradik/xslt3/xslt/runtime/baseUri
9
+ */
10
+
11
+ import { recordedBaseUri, setBaseUri } from "../../functions/baseUris.js";
12
+ import { nodeBaseUri } from "../../functions/nodePaths.js";
13
+
14
+ /**
15
+ * Records the base URI of an element just built, when it is the
16
+ * outermost element of its tree and that tree's document node has no
17
+ * base URI of its own (a copied document keeps the original's, which its
18
+ * new children inherit).
19
+ * @param {{parent: Node}} content - Receiver of the element's content
20
+ * @param {string|undefined} base - Static base URI of the instruction
21
+ */
22
+ export function markConstructed(content, base) {
23
+ const element = content.parent;
24
+ const parent = element?.parentNode;
25
+ if (parent?.nodeType === 1) return;
26
+ if (parent && copiedDocuments.has(parent)) return;
27
+ setBaseUri(element, base);
28
+ }
29
+
30
+ /** Document nodes made by copying a document. @type {WeakSet<Node>} */
31
+ const copiedDocuments = new WeakSet();
32
+
33
+ /**
34
+ * Records, on the copy of an element at the top of its new tree, the base
35
+ * URI its xml:base (copied too) applies to: the original's parent's. A
36
+ * shallow copy (xsl:copy), without the xml:base attribute, takes the
37
+ * original's own base URI. A copy attached to a new parent inherits.
38
+ * @param {Element} original
39
+ * @param {Element} copy
40
+ * @param {boolean} [withAttributes] - The attributes were copied too
41
+ */
42
+ export function markCopied(original, copy, withAttributes = true) {
43
+ if (copy.parentNode) return;
44
+ if (!withAttributes) {
45
+ setBaseUri(copy, nodeBaseUri(original));
46
+ return;
47
+ }
48
+ const parent = original.parentNode;
49
+ setBaseUri(copy, parent ? nodeBaseUri(parent) : recordedBaseUri(original));
50
+ }
51
+
52
+ /**
53
+ * Records, on the copy of a document node, the base URI of the original,
54
+ * when the copy is a new document (not content added to a tree).
55
+ * @param {Node} original - Document node
56
+ * @param {{parent?: Node}} content - Receiver of the copy's content
57
+ */
58
+ export function markDocumentCopied(original, content) {
59
+ const copy = content.parent;
60
+ if (copy && copy.nodeType !== 1 && !copy.parentNode) {
61
+ setBaseUri(copy, nodeBaseUri(original));
62
+ copiedDocuments.add(copy);
63
+ }
64
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The stylesheet compiler as seen from the run time (fn:transform): set
3
+ * by the API module when it loads, so that the run time does not import
4
+ * the compiler (which imports the run time).
5
+ *
6
+ * @module @tradik/xslt3/xslt/runtime/compilerHook
7
+ */
8
+
9
+ /** @type {(source: *, options: object) => object} */
10
+ let compiler;
11
+
12
+ /**
13
+ * Registers the compiler.
14
+ * @param {(source: *, options: object) => object} compile -
15
+ * compileStylesheet of api.js
16
+ */
17
+ export function setCompiler(compile) {
18
+ compiler = compile;
19
+ }
20
+
21
+ /**
22
+ * Compiles a stylesheet with the registered compiler.
23
+ * @param {*} source - Document, element or text of the stylesheet
24
+ * @param {object} options - Options of compileStylesheet
25
+ * @returns {object} the CompiledStylesheet
26
+ */
27
+ export const compileWith = (source, options) => compiler(source, options);