@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,106 @@
1
+ /**
2
+ * xsl:for-each-group (XSLT 3.0 section 14): group-by, group-adjacent,
3
+ * group-starting-with and group-ending-with, then the groups processed
4
+ * in order (or sorted), each with its current group and grouping key.
5
+ *
6
+ * @module @tradik/xslt3/xslt/instructions/grouping
7
+ */
8
+
9
+ import { getCollation } from "../../functions/collations.js";
10
+ import { compileBody } from "../compiler/body.js";
11
+ import { required, yesNo } from "../compiler/attributes.js";
12
+ import { derive, evaluate } from "../runtime/context.js";
13
+ import { groupByKeys, groupByPattern } from "../runtime/groups.js";
14
+ import { avtEvaluator } from "../runtime/values.js";
15
+ import { attr, xsltError } from "../names.js";
16
+ import { compilePattern } from "../patterns/compile.js";
17
+ import { BodyFrame, LoopFrame } from "../runtime/machine.js";
18
+ import { compileSorts, splitSorts } from "./sort.js";
19
+
20
+ const METHODS = [
21
+ "group-by",
22
+ "group-adjacent",
23
+ "group-starting-with",
24
+ "group-ending-with",
25
+ ];
26
+
27
+ /**
28
+ * xsl:for-each-group.
29
+ * @param {Element} element
30
+ * @param {object} cx
31
+ * @param {object} scope
32
+ * @returns {Function}
33
+ */
34
+ export function compileForEachGroup(element, cx, scope) {
35
+ const select = cx.exprs.xpath(
36
+ required(element, "select"),
37
+ element,
38
+ scope.vars,
39
+ );
40
+ const present = METHODS.filter((name) => attr(element, name) !== undefined);
41
+ if (present.length !== 1) {
42
+ throw xsltError("XTSE1080", "xsl:for-each-group needs one grouping method");
43
+ }
44
+ const method = present[0];
45
+ const text = attr(element, method);
46
+ const byPattern = method.endsWith("with");
47
+ const keys = byPattern ? null : cx.exprs.xpath(text, element, scope.vars);
48
+ const pattern = byPattern
49
+ ? compilePattern(text, element, cx, scope.vars)
50
+ : null;
51
+ const collationText = attr(element, "collation");
52
+ if (collationText !== undefined && byPattern) {
53
+ throw xsltError("XTSE1090", "collation needs group-by or group-adjacent");
54
+ }
55
+ const collation =
56
+ collationText === undefined
57
+ ? null
58
+ : avtEvaluator(cx.exprs.avt(collationText, element, scope.vars));
59
+ const { sorts, rest } = splitSorts(cx.children(element));
60
+ const sort = compileSorts(sorts, cx, scope);
61
+ const body = compileBody(element, cx, scope, rest);
62
+ const composite = yesNo(element, "composite", false);
63
+ return (xc, out, machine) => {
64
+ const items = evaluate(select, xc);
65
+ let collationObject = getCollation(undefined, xc.tx.dyn);
66
+ if (collation) {
67
+ const uri = collation(xc);
68
+ try {
69
+ collationObject = getCollation(uri, xc.tx.dyn);
70
+ } catch {
71
+ throw xsltError("XTDE1110", `Unknown collation ${uri}`);
72
+ }
73
+ }
74
+ const groups = byPattern
75
+ ? groupByPattern(items, pattern, xc, method === "group-starting-with")
76
+ : groupByKeys(items, (focus) => evaluate(keys, focus), xc, {
77
+ adjacent: method === "group-adjacent",
78
+ collation: collationObject,
79
+ composite,
80
+ });
81
+ const order = sort.order(
82
+ groups.map((group) => group.items[0]),
83
+ xc,
84
+ machine,
85
+ (focus, i) =>
86
+ derive(focus, { group: groups[i].items, groupKey: groups[i].key }),
87
+ );
88
+ const ordered = order.map((i) => groups[i]);
89
+ const size = ordered.length;
90
+ if (size === 0 || body.length === 0) return;
91
+ const base = derive(xc, { rule: null });
92
+ machine.push(
93
+ new LoopFrame(size, (i) => {
94
+ const group = ordered[i];
95
+ const context = derive(base, {
96
+ item: group.items[0],
97
+ position: i + 1,
98
+ size,
99
+ group: group.items,
100
+ groupKey: group.key,
101
+ });
102
+ machine.push(new BodyFrame(body, context, out));
103
+ }),
104
+ );
105
+ };
106
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The compilers of the XSLT instructions, by local name. Each takes the
3
+ * instruction element, the stylesheet compiler and the scope, and returns
4
+ * a step of the sequence constructor (see runtime/machine.js) or null.
5
+ *
6
+ * @module @tradik/xslt3/xslt/instructions
7
+ */
8
+
9
+ import { compileAnalyzeString } from "./analyzeString.js";
10
+ import { compileAssert } from "./assert.js";
11
+ import { compileChoose, compileForEach, compileIf } from "./control.js";
12
+ import {
13
+ compileCopy,
14
+ compileCopyOf,
15
+ compileDocument,
16
+ compilePerformSort,
17
+ } from "./copy.js";
18
+ import { compileAttribute, compileElement } from "./elements.js";
19
+ import {
20
+ compileOnEmpty,
21
+ compileOnNonEmpty,
22
+ compileWherePopulated,
23
+ } from "./conditional.js";
24
+ import { compileEvaluate } from "./evaluate.js";
25
+ import { compileFork } from "./fork.js";
26
+ import { compileForEachGroup } from "./grouping.js";
27
+ import {
28
+ compileBreak,
29
+ compileIterate,
30
+ compileNextIteration,
31
+ } from "./iterate.js";
32
+ import { compileMerge } from "./merge.js";
33
+ import { compileNumber } from "./number.js";
34
+ import { compileMap, compileMapEntry } from "./maps.js";
35
+ import { compileMessage } from "./output.js";
36
+ import { compileResultDocument } from "./resultDocument.js";
37
+ import { compileSourceDocument } from "./sourceDocument.js";
38
+ import {
39
+ compileApplyImports,
40
+ compileApplyTemplates,
41
+ compileCallTemplate,
42
+ } from "./templates.js";
43
+ import { compileTry } from "./try.js";
44
+ import {
45
+ compileComment,
46
+ compileNamespace,
47
+ compileProcessingInstruction,
48
+ compileSequence,
49
+ compileText,
50
+ compileValueOf,
51
+ } from "./text.js";
52
+
53
+ /** @type {Record<string, Function>} */
54
+ export const instructionCompilers = {
55
+ "analyze-string": compileAnalyzeString,
56
+ "apply-imports": compileApplyImports,
57
+ "apply-templates": compileApplyTemplates,
58
+ attribute: compileAttribute,
59
+ "call-template": compileCallTemplate,
60
+ choose: compileChoose,
61
+ comment: compileComment,
62
+ copy: compileCopy,
63
+ "copy-of": compileCopyOf,
64
+ document: compileDocument,
65
+ element: compileElement,
66
+ "for-each": compileForEach,
67
+ "for-each-group": compileForEachGroup,
68
+ if: compileIf,
69
+ message: compileMessage,
70
+ namespace: compileNamespace,
71
+ "next-match": compileApplyImports,
72
+ number: compileNumber,
73
+ "perform-sort": compilePerformSort,
74
+ "processing-instruction": compileProcessingInstruction,
75
+ "result-document": compileResultDocument,
76
+ map: compileMap,
77
+ "map-entry": compileMapEntry,
78
+ try: compileTry,
79
+ sequence: compileSequence,
80
+ text: compileText,
81
+ "value-of": compileValueOf,
82
+ // XSLT 3.0 instructions of task 0031
83
+ break: compileBreak,
84
+ iterate: compileIterate,
85
+ "next-iteration": compileNextIteration,
86
+ "on-empty": compileOnEmpty,
87
+ "on-non-empty": compileOnNonEmpty,
88
+ "where-populated": compileWherePopulated,
89
+ fork: compileFork,
90
+ "source-document": compileSourceDocument,
91
+ merge: compileMerge,
92
+ evaluate: compileEvaluate,
93
+ assert: compileAssert,
94
+ };
@@ -0,0 +1,182 @@
1
+ /**
2
+ * xsl:iterate, xsl:next-iteration, xsl:break and xsl:on-completion
3
+ * (XSLT 3.0 section 7.2). The iterations run on the work stack (see
4
+ * runtime/iteration.js); xsl:next-iteration and xsl:break record their
5
+ * effect in the iteration state of the context, read before the next
6
+ * item is processed.
7
+ *
8
+ * @module @tradik/xslt3/xslt/instructions/iterate
9
+ */
10
+
11
+ import { compileBody } from "../compiler/body.js";
12
+ import { checkAttributes, required } from "../compiler/attributes.js";
13
+ import { isWhitespaceText, splitLeading } from "../compiler/children.js";
14
+ import { checkTailPosition } from "../compiler/tailPosition.js";
15
+ import { evaluate } from "../runtime/context.js";
16
+ import { IterateFrame } from "../runtime/iteration.js";
17
+ import { BodyFrame } from "../runtime/machine.js";
18
+ import { attr, isXsl, XSL_NS, xsltError } from "../names.js";
19
+ import { compileParams, compileWithParams } from "./params.js";
20
+
21
+ /** @type {WeakMap<Element, object[]>} the parameters of each xsl:iterate */
22
+ const iterateParams = new WeakMap();
23
+
24
+ /**
25
+ * Compiles the select attribute or the content of xsl:break or
26
+ * xsl:on-completion.
27
+ * @param {Element} element
28
+ * @param {object} cx
29
+ * @param {object} scope
30
+ * @returns {import("../runtime/machine.js").Body}
31
+ */
32
+ function compileContent(element, cx, scope) {
33
+ const select = attr(element, "select");
34
+ const children = cx.children(element).filter((c) => !isXsl(c, "fallback"));
35
+ if (select === undefined) return compileBody(element, cx, scope, children);
36
+ if (children.length > 0) {
37
+ throw xsltError(
38
+ "XTSE3125",
39
+ `xsl:${element.localName} has select and content`,
40
+ );
41
+ }
42
+ const expr = cx.exprs.xpath(select, element, scope.vars);
43
+ return [
44
+ (xc, out) => {
45
+ for (const item of evaluate(expr, xc)) out.item(item);
46
+ },
47
+ ];
48
+ }
49
+
50
+ /**
51
+ * Checks that a parameter of xsl:iterate without initial value accepts
52
+ * the empty sequence.
53
+ * @param {object} param
54
+ * @throws {import("../../errors.js").XPathError} XTSE3520
55
+ */
56
+ function checkOptional(param) {
57
+ try {
58
+ param.convert([]);
59
+ } catch {
60
+ throw xsltError(
61
+ "XTSE3520",
62
+ `The parameter ${param.key} of xsl:iterate needs an initial value`,
63
+ );
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Checks that the xsl:on-completion elements near an xsl:iterate (its
69
+ * siblings and descendants) are children of an xsl:iterate.
70
+ * @param {Element} element - xsl:iterate
71
+ * @throws {import("../../errors.js").XPathError} XTSE0010
72
+ */
73
+ function checkCompletions(element) {
74
+ const nodes = [
75
+ ...element.parentNode.childNodes,
76
+ ...element.getElementsByTagNameNS(XSL_NS, "on-completion"),
77
+ ];
78
+ for (const node of nodes) {
79
+ if (isXsl(node, "on-completion") && !isXsl(node.parentNode, "iterate")) {
80
+ throw xsltError("XTSE0010", "xsl:on-completion must be in xsl:iterate");
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * xsl:iterate.
87
+ * @param {Element} element
88
+ * @param {object} cx
89
+ * @param {object} scope
90
+ * @returns {Function}
91
+ */
92
+ export function compileIterate(element, cx, scope) {
93
+ const select = cx.exprs.xpath(
94
+ required(element, "select"),
95
+ element,
96
+ scope.vars,
97
+ );
98
+ checkCompletions(element);
99
+ const { leading, rest } = splitLeading(cx.children(element), "param");
100
+ const { params, scope: inner } = compileParams(leading, cx, scope);
101
+ leading.forEach((param, i) => {
102
+ const implicit =
103
+ attr(param, "select") === undefined && cx.children(param).length === 0;
104
+ if (implicit && params[i].type) checkOptional(params[i]);
105
+ });
106
+ iterateParams.set(element, params);
107
+ let body = rest;
108
+ let completion = [];
109
+ const first = rest.find((child) => !isWhitespaceText(child));
110
+ if (first && isXsl(first, "on-completion")) {
111
+ checkAttributes(first);
112
+ completion = compileContent(first, cx, inner);
113
+ body = rest.filter((child) => child !== first);
114
+ }
115
+ if (body.some((c) => isXsl(c, "param") || isXsl(c, "on-completion"))) {
116
+ throw xsltError(
117
+ "XTSE0010",
118
+ "xsl:param, then xsl:on-completion, must come first in xsl:iterate",
119
+ );
120
+ }
121
+ const steps = compileBody(element, cx, inner, body);
122
+ return (xc, out, machine) => {
123
+ const items = evaluate(select, xc);
124
+ machine.push(
125
+ new IterateFrame({ items, params, steps, completion, xc, out }),
126
+ );
127
+ };
128
+ }
129
+
130
+ /**
131
+ * The innermost xsl:iterate ancestor of an element.
132
+ * @param {Element} element
133
+ * @returns {Element}
134
+ */
135
+ function enclosingIterate(element) {
136
+ let node = element.parentNode;
137
+ while (!isXsl(node, "iterate")) node = node.parentNode;
138
+ return node;
139
+ }
140
+
141
+ /**
142
+ * xsl:next-iteration.
143
+ * @param {Element} element
144
+ * @param {object} cx
145
+ * @param {object} scope
146
+ * @returns {Function}
147
+ */
148
+ export function compileNextIteration(element, cx, scope) {
149
+ checkTailPosition(element, cx);
150
+ const children = cx.children(element);
151
+ if (!children.every((c) => isXsl(c, "with-param") || isXsl(c, "fallback"))) {
152
+ throw xsltError("XTSE0010", "xsl:next-iteration contains xsl:with-param");
153
+ }
154
+ const withParams = compileWithParams(children, cx, scope);
155
+ const declared = iterateParams.get(enclosingIterate(element));
156
+ const keys = new Set(declared.map((param) => param.key));
157
+ for (const name of withParams.names) {
158
+ if (!keys.has(name)) {
159
+ throw xsltError("XTSE3130", `xsl:iterate has no parameter ${name}`);
160
+ }
161
+ }
162
+ return (xc, out, machine) => {
163
+ const { params } = withParams.evaluate(xc, machine);
164
+ xc.iteration.next = params;
165
+ };
166
+ }
167
+
168
+ /**
169
+ * xsl:break.
170
+ * @param {Element} element
171
+ * @param {object} cx
172
+ * @param {object} scope
173
+ * @returns {Function}
174
+ */
175
+ export function compileBreak(element, cx, scope) {
176
+ checkTailPosition(element, cx);
177
+ const body = compileContent(element, cx, scope);
178
+ return (xc, out, machine) => {
179
+ xc.iteration.broken = true;
180
+ if (body.length > 0) machine.push(new BodyFrame(body, xc, out));
181
+ };
182
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Literal result elements (XSLT 3.0 section 11.1): the element is copied
3
+ * with its namespace nodes (less the XSLT namespace and the excluded
4
+ * ones, with namespace aliases applied) and its attributes, whose values
5
+ * are attribute value templates; its content is a sequence constructor.
6
+ *
7
+ * @module @tradik/xslt3/xslt/instructions/literal
8
+ */
9
+
10
+ import { compileBody } from "../compiler/body.js";
11
+ import { infoOf } from "../compiler/elementInfo.js";
12
+ import { isNamespaceDeclaration } from "../../xpath/eval/domNodes.js";
13
+ import { markConstructed } from "../runtime/baseUri.js";
14
+ import { BodyFrame } from "../runtime/machine.js";
15
+ import { avtEvaluator } from "../runtime/values.js";
16
+ import { XSL_NS, xslAttr, xsltError } from "../names.js";
17
+ import { attributeSetNames, applyAttributeSets } from "./attributeSets.js";
18
+
19
+ /** Attributes in the XSLT namespace allowed on literal result elements. */
20
+ const LRE_ATTRIBUTES = new Set([
21
+ "version",
22
+ "exclude-result-prefixes",
23
+ "extension-element-prefixes",
24
+ "xpath-default-namespace",
25
+ "default-collation",
26
+ "default-mode",
27
+ "default-validation",
28
+ "expand-text",
29
+ "use-attribute-sets",
30
+ "use-when",
31
+ "type",
32
+ "validation",
33
+ "inherit-namespaces",
34
+ ]);
35
+
36
+ /**
37
+ * The result name of a stylesheet name after namespace aliasing.
38
+ * @param {string} uri
39
+ * @param {string} prefix
40
+ * @param {string} local
41
+ * @param {Map<string, {uri: string, prefix: string}>} aliases
42
+ * @returns {{uri: string, qname: string}}
43
+ */
44
+ export function aliasedName(uri, prefix, local, aliases) {
45
+ const alias = aliases.get(uri);
46
+ if (!alias) return { uri, qname: prefix ? `${prefix}:${local}` : local };
47
+ const resultPrefix = alias.uri === "" ? "" : alias.prefix;
48
+ return {
49
+ uri: alias.uri,
50
+ qname: resultPrefix ? `${resultPrefix}:${local}` : local,
51
+ };
52
+ }
53
+
54
+ /**
55
+ * The namespace nodes a literal result element copies.
56
+ * @param {Element} element
57
+ * @param {Map<string, object>} aliases
58
+ * @returns {Array<[string, string]>} prefix, URI pairs
59
+ */
60
+ function copiedNamespaces(element, aliases) {
61
+ const info = infoOf(element);
62
+ const result = [];
63
+ for (const [prefix, uri] of info.namespaces) {
64
+ if (prefix === "xml" || uri === XSL_NS) continue;
65
+ if (aliases.has(uri) || info.excluded.has(uri)) continue;
66
+ if (uri === "" && prefix !== "") continue;
67
+ result.push([prefix, uri]);
68
+ }
69
+ return result;
70
+ }
71
+
72
+ /**
73
+ * Compiles a literal result element.
74
+ * @param {Element} element
75
+ * @param {object} cx - Stylesheet compiler
76
+ * @param {import("../compiler/body.js").Scope} scope
77
+ * @returns {Function} the step
78
+ */
79
+ export function compileLiteralElement(element, cx, scope) {
80
+ const { uri, qname } = aliasedName(
81
+ element.namespaceURI ?? "",
82
+ element.prefix ?? "",
83
+ element.localName,
84
+ cx.aliases,
85
+ );
86
+ const namespaces = copiedNamespaces(element, cx.aliases);
87
+ const compatible = infoOf(element).version < 2;
88
+ const attributes = [];
89
+ const forwards = infoOf(element).version > 3;
90
+ for (const attribute of element.attributes) {
91
+ if (isNamespaceDeclaration(attribute)) continue;
92
+ if (attribute.namespaceURI === XSL_NS) {
93
+ if (!forwards && !LRE_ATTRIBUTES.has(attribute.localName)) {
94
+ throw xsltError(
95
+ "XTSE0805",
96
+ `Unknown attribute ${attribute.name} on a literal result element`,
97
+ );
98
+ }
99
+ // a non-schema-aware processor (XTSE1660)
100
+ const local = attribute.localName;
101
+ if (
102
+ local === "type" ||
103
+ (local === "validation" && attribute.value.trim() === "strict")
104
+ ) {
105
+ throw xsltError(
106
+ "XTSE1660",
107
+ `xsl:${local} needs a schema-aware processor`,
108
+ );
109
+ }
110
+ continue;
111
+ }
112
+ const name = aliasedName(
113
+ attribute.namespaceURI ?? "",
114
+ attribute.prefix ?? "",
115
+ attribute.localName,
116
+ cx.aliases,
117
+ );
118
+ const parts = cx.exprs.avt(attribute.value, element, scope.vars);
119
+ attributes.push({ ...name, value: avtEvaluator(parts, compatible) });
120
+ }
121
+ const sets = attributeSetNames(
122
+ xslAttr(element, "use-attribute-sets"),
123
+ element,
124
+ cx,
125
+ );
126
+ const body = compileBody(element, cx, scope);
127
+ // its own xml:base is copied: the base URI it applies to is the parent's
128
+ const parent = element.parentNode;
129
+ const base = infoOf(parent?.nodeType === 1 ? parent : element).baseUri;
130
+ return (xc, out, machine) => {
131
+ const content = out.element(uri, qname);
132
+ markConstructed(content, base);
133
+ for (const [prefix, namespace] of namespaces) {
134
+ content.declareExplicit(prefix, namespace);
135
+ }
136
+ if (sets.length > 0) applyAttributeSets(sets, xc, content, machine, cx);
137
+ for (const attribute of attributes) {
138
+ content.attribute(attribute.uri, attribute.qname, attribute.value(xc));
139
+ }
140
+ if (body.length > 0) machine.push(new BodyFrame(body, xc, content));
141
+ };
142
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * xsl:map and xsl:map-entry (XSLT 3.0 section 21.4): maps built from
3
+ * instructions.
4
+ *
5
+ * @module @tradik/xslt3/xslt/instructions/maps
6
+ */
7
+
8
+ import { XdmMap } from "../../items/map.js";
9
+ import { isMap } from "../../xdm/atomic.js";
10
+ import { atomize } from "../../xdm/nodes.js";
11
+ import { compileBody } from "../compiler/body.js";
12
+ import { required } from "../compiler/attributes.js";
13
+ import { evaluate } from "../runtime/context.js";
14
+ import { bodySequence } from "../runtime/values.js";
15
+ import { attr, xsltError } from "../names.js";
16
+
17
+ /**
18
+ * xsl:map.
19
+ * @param {Element} element
20
+ * @param {object} cx
21
+ * @param {object} scope
22
+ * @returns {Function}
23
+ */
24
+ export function compileMap(element, cx, scope) {
25
+ const body = compileBody(element, cx, scope);
26
+ return (xc, out, machine) => {
27
+ const pairs = [];
28
+ for (const item of bodySequence(body, xc, machine)) {
29
+ if (!isMap(item)) {
30
+ throw xsltError("XTTE3375", "xsl:map content must be maps");
31
+ }
32
+ for (const { key, value } of item.entries.values()) {
33
+ pairs.push([key, value]);
34
+ }
35
+ }
36
+ out.item(
37
+ XdmMap.from(pairs, () => {
38
+ throw xsltError("XTDE3365", "Duplicate key in xsl:map");
39
+ }),
40
+ );
41
+ };
42
+ }
43
+
44
+ /**
45
+ * xsl:map-entry.
46
+ * @param {Element} element
47
+ * @param {object} cx
48
+ * @param {object} scope
49
+ * @returns {Function}
50
+ */
51
+ export function compileMapEntry(element, cx, scope) {
52
+ const key = cx.exprs.xpath(required(element, "key"), element, scope.vars);
53
+ const select = attr(element, "select");
54
+ const body = compileBody(element, cx, scope);
55
+ if (select !== undefined && body.length > 0) {
56
+ throw xsltError("XTSE3280", "xsl:map-entry has select and content");
57
+ }
58
+ const value =
59
+ select === undefined
60
+ ? (xc, machine) => bodySequence(body, xc, machine)
61
+ : (
62
+ (expr) => (xc) =>
63
+ evaluate(expr, xc)
64
+ )(cx.exprs.xpath(select, element, scope.vars));
65
+ return (xc, out, machine) => {
66
+ const keys = atomize(evaluate(key, xc));
67
+ if (keys.length !== 1) {
68
+ throw xsltError("XPTY0004", "A map key must be a single atomic value");
69
+ }
70
+ out.item(XdmMap.from([[keys[0], value(xc, machine)]]));
71
+ };
72
+ }