@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,130 @@
1
+ /**
2
+ * Path patterns: the steps checked against the pattern grammar, then
3
+ * matched from the last step upwards: the last step is tested on the
4
+ * node, each `/` moves to the parent and each `//` to some ancestor,
5
+ * until the first step; an absolute pattern requires a document node
6
+ * above it.
7
+ *
8
+ * @module @tradik/xslt3/xslt/patterns/paths
9
+ */
10
+
11
+ import { parentOf } from "../../xpath/eval/domNodes.js";
12
+ import { compileGeneralPath } from "./general.js";
13
+ import { compileStep, stepPriority, stepKey } from "./steps.js";
14
+
15
+ /** Functions allowed as the first step of a path pattern. */
16
+ const ROOT_FUNCTIONS = new Set(["id", "key", "doc", "element-with-id", "root"]);
17
+
18
+ /** @param {*} node @returns {boolean} whether a node is a document node */
19
+ const isDocument = (node) => node?.nodeType === 9 || node?.nodeType === 11;
20
+
21
+ /**
22
+ * Whether a step stands for `//` (descendant-or-self::node()).
23
+ * @param {object} step
24
+ * @returns {boolean}
25
+ */
26
+ const isSlashSlash = (step) =>
27
+ step.type === "AxisStep" &&
28
+ step.axis === "descendant-or-self" &&
29
+ step.nodeTest.type === "AnyKindTest" &&
30
+ step.predicates.length === 0;
31
+
32
+ /** Axes the fast matcher follows upwards (self:: only alone). */
33
+ const FAST_AXES = new Set(["child", "attribute", "namespace"]);
34
+
35
+ /**
36
+ * Whether the fast matcher handles a step: an axis step on a fast axis,
37
+ * `//`, or an unfiltered rooted first step (key(), id(), doc(), $var...).
38
+ * @param {object} step
39
+ * @param {boolean} first
40
+ * @param {boolean} alone - The step is the whole pattern
41
+ * @returns {boolean}
42
+ */
43
+ function isFastStep(step, first, alone) {
44
+ if (step.type === "AxisStep") {
45
+ return (
46
+ FAST_AXES.has(step.axis) ||
47
+ isSlashSlash(step) ||
48
+ (alone && step.axis === "self")
49
+ );
50
+ }
51
+ return (
52
+ first &&
53
+ ((step.type === "FunctionCall" && ROOT_FUNCTIONS.has(step.name.local)) ||
54
+ step.type === "VarRef")
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Builds the matcher of the parts of a path pattern.
60
+ * @param {Array<{separator: string|null, test: {test: Function}}>} parts -
61
+ * Steps in order; `separator` is what precedes the step ("/", "//", or
62
+ * null for the first step of a relative pattern)
63
+ * @returns {(item: *, xc: object) => boolean}
64
+ */
65
+ export function matchParts(parts) {
66
+ const last = parts.length - 1;
67
+ const matchFrom = (node, k, xc) => {
68
+ if (!parts[k].test.test(node, xc)) return false;
69
+ const { separator } = parts[k];
70
+ if (k === 0) {
71
+ if (separator === null) return true;
72
+ if (separator === "/") return isDocument(parentOf(node));
73
+ for (let a = parentOf(node); a; a = parentOf(a)) {
74
+ if (isDocument(a)) return true;
75
+ }
76
+ return false;
77
+ }
78
+ if (separator === "/") {
79
+ const parent = parentOf(node);
80
+ return parent !== null && matchFrom(parent, k - 1, xc);
81
+ }
82
+ for (let a = parentOf(node); a; a = parentOf(a)) {
83
+ if (matchFrom(a, k - 1, xc)) return true;
84
+ }
85
+ return false;
86
+ };
87
+ return (item, xc) =>
88
+ typeof item?.nodeType === "number" && matchFrom(item, last, xc);
89
+ }
90
+
91
+ /**
92
+ * Compiles a path pattern (a PathExpr, or a single step).
93
+ * @param {object} ast
94
+ * @param {object} env - See compile.js
95
+ * @returns {import("./compile.js").PatternAlternative}
96
+ */
97
+ export function compilePathPattern(ast, env) {
98
+ const absolute = ast.type === "PathExpr" && ast.absolute;
99
+ const steps = ast.type === "PathExpr" ? ast.steps : [ast];
100
+ if (absolute && steps.length === 0) {
101
+ return { matches: (item) => isDocument(item), priority: -0.5, key: "k9" };
102
+ }
103
+ const last = steps.at(-1);
104
+ const single = steps.length === 1 && !absolute;
105
+ const fast = steps.every((step, i) =>
106
+ isFastStep(step, i === 0 && !absolute, single),
107
+ );
108
+ if (!fast) {
109
+ return {
110
+ matches: compileGeneralPath(ast, env),
111
+ priority: single ? stepPriority(last) : 0.5,
112
+ key: last.type === "AxisStep" ? stepKey(last, env.sc) : "*",
113
+ };
114
+ }
115
+ const parts = [];
116
+ let separator = absolute ? "/" : null;
117
+ for (const step of steps) {
118
+ if (isSlashSlash(step)) {
119
+ separator = "//";
120
+ continue;
121
+ }
122
+ parts.push({ separator, test: compileStep(step, env) });
123
+ separator = "/";
124
+ }
125
+ return {
126
+ matches: matchParts(parts),
127
+ priority: single ? stepPriority(last) : 0.5,
128
+ key: last.type === "AxisStep" ? parts.at(-1).test.key : "*",
129
+ };
130
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The grouping functions patterns cannot call (XTSE1060, XTSE1070).
3
+ *
4
+ * @module @tradik/xslt3/xslt/patterns/patternChecks
5
+ */
6
+
7
+ import { xsltError } from "../names.js";
8
+
9
+ /** Functions a pattern cannot call (XTSE1060, XTSE1070). */
10
+ const GROUPING_CALLS = {
11
+ "current-group": "XTSE1060",
12
+ "current-grouping-key": "XTSE1070",
13
+ };
14
+
15
+ /**
16
+ * Checks that a pattern does not call current-group() or
17
+ * current-grouping-key().
18
+ * @param {object} ast
19
+ */
20
+ export function checkGroupingCalls(ast) {
21
+ if (ast === null || typeof ast !== "object") return;
22
+ if (ast.type === "FunctionCall" && !ast.name.prefix && !ast.name.uri) {
23
+ const code = GROUPING_CALLS[ast.name.local];
24
+ if (code) {
25
+ throw xsltError(code, `A pattern cannot call ${ast.name.local}()`);
26
+ }
27
+ }
28
+ for (const value of Object.values(ast)) checkGroupingCalls(value);
29
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * The steps of path patterns: axis steps tested on a node (with their
3
+ * predicates evaluated among the node's siblings when they depend on the
4
+ * position), and the rooted steps key(), id(), doc(), $var, tested by
5
+ * membership. Also the default priorities of single-step patterns.
6
+ *
7
+ * @module @tradik/xslt3/xslt/patterns/steps
8
+ */
9
+
10
+ import { compileNode } from "../../xpath/eval/compiler.js";
11
+ import {
12
+ attributesOf,
13
+ childrenOf,
14
+ parentOf,
15
+ } from "../../xpath/eval/domNodes.js";
16
+ import { compileNodeTest } from "../../xpath/eval/nodeTests.js";
17
+ import { isPositionIndependent } from "../../xpath/eval/positional.js";
18
+ import { compilePredicate } from "../../xpath/eval/predicates.js";
19
+ import { namespaceOf } from "../../xpath/eval/staticContext.js";
20
+
21
+ /** Node kinds an axis step can match, by axis. */
22
+ const AXIS_KINDS = {
23
+ child: (node) => [1, 3, 4, 7, 8].includes(node?.nodeType),
24
+ attribute: (node) => node?.nodeType === 2,
25
+ namespace: (node) => node?.nodeType === 13,
26
+ self: (node) => typeof node?.nodeType === "number",
27
+ };
28
+
29
+ /** Index keys of kind tests. */
30
+ const KIND_KEYS = {
31
+ TextTest: "k3",
32
+ CommentTest: "k8",
33
+ PITest: "k7",
34
+ DocumentTest: "k9",
35
+ NamespaceNodeTest: "k13",
36
+ };
37
+
38
+ /**
39
+ * The index key of an axis step.
40
+ * @param {object} step
41
+ * @param {object} sc
42
+ * @returns {string}
43
+ */
44
+ export function stepKey(step, sc) {
45
+ const { nodeTest, axis } = step;
46
+ const attribute = axis === "attribute";
47
+ if (axis === "self") return "*";
48
+ if (axis === "namespace") return "k13";
49
+ if (nodeTest.type === "NameTest") {
50
+ const defaultNs = attribute ? "" : sc.defaultElementNamespace;
51
+ const uri = namespaceOf(nodeTest.name, sc, defaultNs);
52
+ return `${attribute ? "a" : "e"}{${uri}}${nodeTest.name.local}`;
53
+ }
54
+ if (nodeTest.type === "Wildcard") return attribute ? "k2" : "k1";
55
+ if (nodeTest.type === "ElementTest") return "k1";
56
+ if (nodeTest.type === "AttributeTest") return "k2";
57
+ return KIND_KEYS[nodeTest.type] ?? "*";
58
+ }
59
+
60
+ /**
61
+ * Compiles an axis step of a pattern.
62
+ * @param {object} step
63
+ * @param {object} env - `{cx, sc, vars}`
64
+ * @returns {{key: string, test: (node: *, xc: object) => boolean}}
65
+ */
66
+ function compileAxisStep(step, env) {
67
+ // document-node() as a step without axis matches document nodes
68
+ const documentStep =
69
+ step.axis === "child" &&
70
+ step.nodeTest.type === "DocumentTest" &&
71
+ !env.text.startsWith("child::", step.start);
72
+
73
+ // the axis is child, attribute, namespace or (alone) self: see paths.js
74
+ const kindOk = documentStep ? AXIS_KINDS.self : AXIS_KINDS[step.axis];
75
+ const nodeTest = compileNodeTest(step.nodeTest, step.axis, env.sc);
76
+ const accepts = (node) => kindOk(node) && nodeTest(node);
77
+ const scope = { sc: env.sc, vars: env.vars };
78
+ const predicates = step.predicates.map((p) =>
79
+ compilePredicate(p, scope, compileNode),
80
+ );
81
+ const key = stepKey(step, env.sc);
82
+ if (predicates.length === 0) return { key, test: accepts };
83
+ const independent = step.predicates.every((p) =>
84
+ isPositionIndependent(p, env.sc),
85
+ );
86
+ const attribute = step.axis === "attribute";
87
+ return {
88
+ key,
89
+ test(node, xc) {
90
+ if (!accepts(node)) return false;
91
+ const ctx = env.cx.patternContext(node, xc, env.local);
92
+ if (independent) {
93
+ return predicates.every((predicate) => predicate([node], ctx).length);
94
+ }
95
+ const parent = parentOf(node);
96
+ let candidates = parent
97
+ ? (attribute ? attributesOf(parent) : childrenOf(parent)).filter(
98
+ accepts,
99
+ )
100
+ : [node];
101
+ for (const predicate of predicates) {
102
+ candidates = predicate(candidates, ctx);
103
+ }
104
+ return candidates.includes(node);
105
+ },
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Compiles a step of a pattern.
111
+ * @param {object} step - AxisStep, or a FunctionCall/VarRef first step
112
+ * @param {object} env - `{cx, sc, vars}`
113
+ * @returns {{key: string, test: (node: *, xc: object) => boolean}}
114
+ */
115
+ export function compileStep(step, env) {
116
+ if (step.type === "AxisStep") return compileAxisStep(step, env);
117
+ const run = env.cx.exprs.compileAst(step, env.sc, env.vars);
118
+ return {
119
+ key: "*",
120
+ test: (node, xc) =>
121
+ typeof node?.nodeType === "number" &&
122
+ run(env.cx.patternContext(node, xc, env.local)).includes(node),
123
+ };
124
+ }
125
+
126
+ /** Default priorities of kind tests without a name. */
127
+ const KIND_PRIORITY = {
128
+ AnyKindTest: -0.5,
129
+ TextTest: -0.5,
130
+ CommentTest: -0.5,
131
+ NamespaceNodeTest: -0.5,
132
+ };
133
+
134
+ /**
135
+ * The default priority of a pattern made of one step.
136
+ * @param {object} step
137
+ * @returns {number}
138
+ */
139
+ export function stepPriority(step) {
140
+ if (step.type !== "AxisStep" || step.predicates.length > 0) return 0.5;
141
+ const test = step.nodeTest;
142
+ switch (test.type) {
143
+ case "NameTest":
144
+ return 0;
145
+ case "Wildcard":
146
+ return test.prefix !== null || test.local !== null || test.uri !== null
147
+ ? -0.25
148
+ : -0.5;
149
+ case "PITest":
150
+ return test.target === null ? -0.5 : 0;
151
+ case "ElementTest":
152
+ case "AttributeTest":
153
+ if (test.name === null && test.typeName === null) return -0.5;
154
+ return test.name !== null && test.typeName !== null ? 0.25 : 0;
155
+ case "DocumentTest":
156
+ return test.elementTest === null
157
+ ? -0.5
158
+ : stepPriority({ ...step, nodeTest: test.elementTest });
159
+ default:
160
+ return KIND_PRIORITY[test.type] ?? 0;
161
+ }
162
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * XSLTProcessor: the W3C/browser-style API over compileStylesheet, with
3
+ * the method names of the @tradik/xslt-processor (XSLT 1.0) package.
4
+ *
5
+ * @module @tradik/xslt3/xslt/processor
6
+ */
7
+
8
+ import { serialize } from "../serialize/index.js";
9
+ import { compileStylesheet } from "./api.js";
10
+
11
+ /**
12
+ * @param {string|null} namespaceURI
13
+ * @param {string} localName
14
+ * @returns {string} Clark name
15
+ */
16
+ const keyOf = (namespaceURI, localName) =>
17
+ `{${namespaceURI ?? ""}}${localName}`;
18
+
19
+ /**
20
+ * A loader of the 1.0 package's API, which may return XML text, as a
21
+ * loader of documents.
22
+ * @param {Function} loader - `(uri, base) => Document|string|null`
23
+ * @param {(text: string, uri?: string) => Document} [parseXml]
24
+ * @returns {(uri: string, base?: string) => Document|null}
25
+ */
26
+ function documentsFrom(loader, parseXml) {
27
+ return (uri, base) => {
28
+ const result = loader(uri, base);
29
+ if (typeof result !== "string") return result;
30
+ if (parseXml) return parseXml(result, uri);
31
+ return new globalThis.DOMParser().parseFromString(
32
+ result,
33
+ "application/xml",
34
+ );
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Checks a loader given to a setter.
40
+ * @param {*} loader
41
+ * @param {string} method - Name of the setter, for the message
42
+ * @throws {TypeError} when it is neither a function nor null
43
+ */
44
+ function checkLoader(loader, method) {
45
+ if (loader != null && typeof loader !== "function") {
46
+ throw new TypeError(`${method}: the loader must be a function or null`);
47
+ }
48
+ }
49
+
50
+ /** Applies an XSLT 3.0/2.0 stylesheet to documents. */
51
+ export class XSLTProcessor {
52
+ /**
53
+ * @param {object} [options] - Options of compileStylesheet and
54
+ * CompiledStylesheet.transform used for every transformation
55
+ */
56
+ constructor(options = {}) {
57
+ this.options = options;
58
+ this.stylesheet = null;
59
+ /** @type {Map<string, *>} */
60
+ this.parameters = new Map();
61
+ }
62
+
63
+ /**
64
+ * Compiles a stylesheet.
65
+ * @param {Document|Element|string} style
66
+ */
67
+ importStylesheet(style) {
68
+ this.stylesheet = compileStylesheet(style, this.options);
69
+ }
70
+
71
+ /**
72
+ * Runs the imported stylesheet.
73
+ * @param {Node} source
74
+ * @returns {object} the transformation result
75
+ */
76
+ run(source) {
77
+ if (!this.stylesheet) throw new Error("No stylesheet imported");
78
+ return this.stylesheet.transform({
79
+ ...this.options,
80
+ source,
81
+ params: this.parameters,
82
+ });
83
+ }
84
+
85
+ /**
86
+ * @param {Node} source
87
+ * @returns {Document|DocumentFragment} the principal result
88
+ */
89
+ transformToDocument(source) {
90
+ return this.run(source).principal;
91
+ }
92
+
93
+ /**
94
+ * @param {Node} source
95
+ * @returns {string} the principal result serialized with its output
96
+ * parameters (xsl:output, or the xsl:result-document that wrote it)
97
+ */
98
+ transformToString(source) {
99
+ const { principal, output } = this.run(source);
100
+ return serialize([principal].flat(), output);
101
+ }
102
+
103
+ /**
104
+ * Sets the loader of included and imported modules, used by the next
105
+ * importStylesheet().
106
+ * @param {((uri: string, base?: string) => Document|string)|null} loader
107
+ * @returns {XSLTProcessor} this
108
+ */
109
+ setStylesheetLoader(loader) {
110
+ checkLoader(loader, "setStylesheetLoader");
111
+ this.options = { ...this.options, loadStylesheet: loader ?? undefined };
112
+ return this;
113
+ }
114
+
115
+ /**
116
+ * Sets the loader of doc() and document(); it may return XML text.
117
+ * @param {((uri: string, base?: string) => Document|string|null)|null} loader
118
+ * @returns {XSLTProcessor} this
119
+ */
120
+ setDocumentLoader(loader) {
121
+ checkLoader(loader, "setDocumentLoader");
122
+ const documentLoader =
123
+ loader == null ? undefined : documentsFrom(loader, this.options.parseXml);
124
+ this.options = { ...this.options, documentLoader };
125
+ return this;
126
+ }
127
+
128
+ /**
129
+ * @param {Node} source
130
+ * @param {Document} output - Document that owns the fragment
131
+ * @returns {DocumentFragment} the principal result as a fragment
132
+ */
133
+ transformToFragment(source, output) {
134
+ const { principal } = this.run(source);
135
+ const fragment = output.createDocumentFragment();
136
+ for (const child of principal.childNodes) {
137
+ fragment.appendChild(output.importNode(child, true));
138
+ }
139
+ return fragment;
140
+ }
141
+
142
+ /**
143
+ * @param {string|null} namespaceURI
144
+ * @param {string} localName
145
+ * @param {*} value
146
+ */
147
+ setParameter(namespaceURI, localName, value) {
148
+ this.parameters.set(keyOf(namespaceURI, localName), value);
149
+ }
150
+
151
+ /**
152
+ * @param {string|null} namespaceURI
153
+ * @param {string} localName
154
+ * @returns {*} the value, "" when not set (as in browsers)
155
+ */
156
+ getParameter(namespaceURI, localName) {
157
+ return this.parameters.get(keyOf(namespaceURI, localName)) ?? "";
158
+ }
159
+
160
+ /**
161
+ * @param {string|null} namespaceURI
162
+ * @param {string} localName
163
+ */
164
+ removeParameter(namespaceURI, localName) {
165
+ this.parameters.delete(keyOf(namespaceURI, localName));
166
+ }
167
+
168
+ /** Removes every parameter. */
169
+ clearParameters() {
170
+ this.parameters.clear();
171
+ }
172
+
173
+ /** Removes the stylesheet and the parameters. */
174
+ reset() {
175
+ this.stylesheet = null;
176
+ this.parameters.clear();
177
+ }
178
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * accumulator-before() and accumulator-after() (XSLT 3.0 sections
3
+ * 18.2.6 and 18.2.7).
4
+ *
5
+ * @module @tradik/xslt3/xslt/runtime/accumulatorFunctions
6
+ */
7
+
8
+ import { isNode } from "../../xdm/atomic.js";
9
+ import { xsltError } from "../names.js";
10
+ import { accumulatorValue } from "./accumulators.js";
11
+ import { nameArgument } from "./availability.js";
12
+
13
+ /**
14
+ * Implementation of both functions.
15
+ * @param {boolean} after
16
+ * @returns {(args: Array, context: object) => Array}
17
+ */
18
+ const accumulatorFunction = (after) => (args, context) => {
19
+ const [[name]] = args;
20
+ const { uri, local } = nameArgument(name.value, context, "XTDE3340");
21
+ const key = `{${uri}}${local}`;
22
+ // accumulators are local to the package of the call (XSLT 3.0 3.5.5)
23
+ const owner = context.sc?.owner ?? context.xc.tx.stylesheet;
24
+ const accumulator = owner.accumulators.get(key);
25
+ if (!accumulator) {
26
+ throw xsltError("XTDE3340", `No accumulator ${name.value}`);
27
+ }
28
+ const item = context.contextItem;
29
+ if (item === undefined) {
30
+ throw xsltError("XTDE3350", "An accumulator function needs a context item");
31
+ }
32
+ if (!isNode(item) || item.nodeType === 2 || item.nodeType === 13) {
33
+ throw xsltError(
34
+ "XTTE3360",
35
+ "An accumulator function needs a context node other than an attribute",
36
+ );
37
+ }
38
+ return accumulatorValue(context.xc, key, item, after, accumulator);
39
+ };
40
+
41
+ /** Function definitions. */
42
+ export const accumulatorFunctions = ["before", "after"].map((phase) => ({
43
+ local: `accumulator-${phase}`,
44
+ params: ["xs:string"],
45
+ returns: "item()*",
46
+ focus: true,
47
+ impl: accumulatorFunction(phase === "after"),
48
+ }));