@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,194 @@
1
+ /**
2
+ * Static function resolution and the function items of known functions:
3
+ * library functions (see functions/registry.js), constructor functions of
4
+ * the atomic types, and F&O functions without an implementation yet.
5
+ *
6
+ * @module @tradik/xslt3/xpath/eval/functionItems
7
+ */
8
+
9
+ import { XPathError } from "../../errors.js";
10
+ import { isStandardFunction, NS } from "../../functions/signatures.js";
11
+ import { FunctionItem } from "../../items/function.js";
12
+ import { QNameValue } from "../../xdm/qname.js";
13
+ import { XS_NAMESPACE } from "../../xdm/types.js";
14
+ import { parseSequenceType } from "../syntax/types.js";
15
+ import { TokenStream } from "../syntax/tokenStream.js";
16
+ import { coerce } from "./coercion.js";
17
+ import { dynamicCallContext } from "./dynamicCall.js";
18
+ import { compileSequenceType } from "./sequenceType.js";
19
+ import { createStaticContext } from "./staticContext.js";
20
+ import { compileCastTarget, LIST_TYPES } from "./typeExprs.js";
21
+
22
+ /** Largest arity of a function reference to a variadic function. */
23
+ const MAX_ARITY = 1000000;
24
+
25
+ /** Static context in which definition types are read. */
26
+ const BUILT_IN_CONTEXT = createStaticContext({}, null);
27
+
28
+ /** @type {Map<string, object>} compiled sequence types by text */
29
+ const typeCache = new Map();
30
+
31
+ /**
32
+ * @param {string} text - A sequence type in XPath syntax
33
+ * @returns {import("./sequenceType.js").SequenceType}
34
+ */
35
+ export function sequenceTypeOf(text) {
36
+ let type = typeCache.get(text);
37
+ if (!type) {
38
+ const tokens = new TokenStream(text);
39
+ type = compileSequenceType(parseSequenceType(tokens), BUILT_IN_CONTEXT);
40
+ if (tokens.peek().type !== "eof") tokens.fail("Unexpected token");
41
+ typeCache.set(text, type);
42
+ }
43
+ return type;
44
+ }
45
+
46
+ /**
47
+ * Signature of a definition at an arity (variadic definitions repeat their
48
+ * last parameter).
49
+ * @param {import("../../functions/registry.js").FunctionDefinition} definition
50
+ * @param {number} arity
51
+ * @returns {{params: object[], returns: object}}
52
+ */
53
+ export function definitionSignature(definition, arity) {
54
+ const texts = definition.params;
55
+ const params = [];
56
+ for (let i = 0; i < arity; i++) {
57
+ params.push(sequenceTypeOf(texts[Math.min(i, texts.length - 1)]));
58
+ }
59
+ return { params, returns: sequenceTypeOf(definition.returns) };
60
+ }
61
+
62
+ /**
63
+ * A resolved static function: `call(args, ctx)` takes evaluated arguments
64
+ * and returns the result; `signature` gives the parameter types.
65
+ * @typedef {object} ResolvedFunction
66
+ * @property {QNameValue} name
67
+ * @property {number} arity
68
+ * @property {{params: object[], returns: object}} signature
69
+ * @property {boolean} focus - Depends on the focus
70
+ * @property {(args: Array<Array>, ctx: object) => Array} call
71
+ */
72
+
73
+ /**
74
+ * Builds the call of a library function.
75
+ * @returns {ResolvedFunction}
76
+ */
77
+ function libraryFunction(definition, name, arity, sc) {
78
+ const signature = definitionSignature(definition, arity);
79
+ const options = signature.params.map((_, i) => ({
80
+ what: `argument ${i + 1} of ${name}()`,
81
+ compatible: sc.backwardsCompatible,
82
+ }));
83
+ const call = definition.focus
84
+ ? (args, ctx) => {
85
+ const context = Object.create(ctx.dyn);
86
+ context.contextItem = ctx.item;
87
+ context.position = ctx.position;
88
+ context.size = ctx.size;
89
+ return definition.impl(
90
+ args.map((arg, i) => coerce(arg, signature.params[i], options[i])),
91
+ context,
92
+ );
93
+ }
94
+ : (args, ctx) =>
95
+ definition.impl(
96
+ args.map((arg, i) => coerce(arg, signature.params[i], options[i])),
97
+ ctx.dyn,
98
+ );
99
+ return { name, arity, signature, focus: Boolean(definition.focus), call };
100
+ }
101
+
102
+ /**
103
+ * Builds the call of a constructor function `xs:T($arg)`.
104
+ * @returns {ResolvedFunction|null} null when T has no constructor
105
+ */
106
+ function constructorFunction(name, sc) {
107
+ let caster;
108
+ try {
109
+ caster = compileCastTarget(
110
+ { prefix: null, uri: XS_NAMESPACE, local: name.localName },
111
+ sc,
112
+ );
113
+ } catch {
114
+ return null;
115
+ }
116
+ const signature = {
117
+ params: [sequenceTypeOf("xs:anyAtomicType?")],
118
+ returns: sequenceTypeOf(
119
+ name.localName === "error"
120
+ ? "empty-sequence()"
121
+ : LIST_TYPES[name.localName]
122
+ ? `xs:${LIST_TYPES[name.localName]}*`
123
+ : `xs:${name.localName}?`,
124
+ ),
125
+ };
126
+ const what = { what: `argument of ${name}()` };
127
+ const call = ([arg]) => {
128
+ const values = coerce(arg, signature.params[0], what);
129
+ return values.length === 0 ? [] : caster(values[0]);
130
+ };
131
+ return { name, arity: 1, signature, focus: false, call };
132
+ }
133
+
134
+ /**
135
+ * Resolves a function by expanded name and arity.
136
+ * @param {string} uri
137
+ * @param {string} local
138
+ * @param {number} arity
139
+ * @param {import("./staticContext.js").StaticContext} sc
140
+ * @returns {ResolvedFunction}
141
+ * @throws {XPathError} XPST0017 when there is no such function
142
+ */
143
+ export function resolveFunction(uri, local, arity, sc) {
144
+ if (arity > MAX_ARITY) {
145
+ throw new XPathError("FOAR0002", `Arity ${arity} is too large`);
146
+ }
147
+ const prefix = Object.keys(NS).find((key) => NS[key] === uri);
148
+ const name = new QNameValue(
149
+ uri,
150
+ local,
151
+ prefix ?? (uri === XS_NAMESPACE ? "xs" : ""),
152
+ );
153
+ const definition = sc.functions.lookup(uri, local, arity);
154
+ if (definition) return libraryFunction(definition, name, arity, sc);
155
+ const constructor =
156
+ uri === XS_NAMESPACE && arity === 1 ? constructorFunction(name, sc) : null;
157
+ if (constructor) return constructor;
158
+ if (isStandardFunction(uri, local, arity)) {
159
+ return {
160
+ name,
161
+ arity,
162
+ signature: null,
163
+ focus: false,
164
+ call: () => {
165
+ throw new XPathError(
166
+ "XPST0017",
167
+ `${local}#${arity} is not implemented`,
168
+ );
169
+ },
170
+ };
171
+ }
172
+ throw new XPathError(
173
+ "XPST0017",
174
+ `Unknown function Q{${uri}}${local}#${arity}`,
175
+ );
176
+ }
177
+
178
+ /**
179
+ * The function item of a resolved function; a focus-dependent function
180
+ * keeps the focus of `ctx`.
181
+ * @param {ResolvedFunction} resolved
182
+ * @param {import("./scope.js").Context} ctx
183
+ * @returns {FunctionItem}
184
+ */
185
+ export function functionItemOf(resolved, ctx) {
186
+ if (resolved.signature === null) return resolved.call();
187
+ return new FunctionItem({
188
+ name: resolved.name,
189
+ arity: resolved.arity,
190
+ signature: resolved.signature,
191
+ invoke: (args) =>
192
+ resolved.call(args, { ...ctx, dyn: dynamicCallContext(ctx.dyn) }),
193
+ });
194
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * `//T[P]` with a positional predicate (`//item[last()]`, `//x[1]`):
3
+ * `descendant-or-self::node()/child::T[P]`, which cannot become
4
+ * `descendant::T[P]` (see positional.js) because P sees the position of a
5
+ * node among the T children of its parent.
6
+ *
7
+ * Instead of applying `child::T[P]` to every node of the tree (one context
8
+ * and one child walk per node, text nodes included), one descendant walk
9
+ * collects the T nodes, grouped by parent in document order; P filters
10
+ * each group as it would filter the children of that parent. A parent
11
+ * without T children gives nothing in both evaluations.
12
+ *
13
+ * @module @tradik/xslt3/xpath/eval/groupedChildren
14
+ */
15
+
16
+ import { XPathError } from "../../errors.js";
17
+ import { isNode } from "../../xdm/atomic.js";
18
+ import { axisNodes } from "./descendantMemo.js";
19
+ import { parentOf } from "./domNodes.js";
20
+ import { compileNodeTest } from "./nodeTests.js";
21
+ import { compilePredicate } from "./predicates.js";
22
+
23
+ /**
24
+ * Whether a step is `descendant-or-self::node()` and the next one a child
25
+ * step: the pair `groupedChildren` evaluates (when the descendant shortcut
26
+ * of paths.js does not apply).
27
+ * @param {object} step
28
+ * @param {object|undefined} next
29
+ * @returns {boolean}
30
+ */
31
+ export const isGroupedChildren = (step, next) =>
32
+ step.type === "AxisStep" &&
33
+ step.axis === "descendant-or-self" &&
34
+ step.nodeTest.type === "AnyKindTest" &&
35
+ step.predicates.length === 0 &&
36
+ next?.type === "AxisStep" &&
37
+ next.axis === "child";
38
+
39
+ /**
40
+ * Compiles the child step of a `descendant-or-self::node()/child::T[P]`
41
+ * pair.
42
+ * @param {object} step - The child AxisStep
43
+ * @param {import("./scope.js").Scope} scope
44
+ * @param {Function} compile
45
+ * @returns {(input: Array, ctx: object) => Node[]} the nodes selected from
46
+ * the input nodes, in document order without duplicates
47
+ */
48
+ export function compileGroupedChildren(step, scope, compile) {
49
+ const test = compileNodeTest(step.nodeTest, "child", scope.sc);
50
+ const predicates = step.predicates.map((p) =>
51
+ compilePredicate(p, scope, compile),
52
+ );
53
+ return (input, ctx) => {
54
+ // Candidates in document order when there is one input node
55
+ const found = [];
56
+ for (const node of input) {
57
+ if (!isNode(node)) {
58
+ throw new XPathError(
59
+ "XPTY0019",
60
+ "The left operand of / must contain only nodes",
61
+ );
62
+ }
63
+ const nodes = axisNodes("descendant", node, test, Infinity, ctx.dyn);
64
+ for (const n of nodes) found.push(n);
65
+ }
66
+ const groups = new Map();
67
+ // Walks from nested input nodes overlap
68
+ const seen = input.length > 1 ? new Set() : null;
69
+ for (const node of found) {
70
+ if (seen) {
71
+ if (seen.has(node)) continue;
72
+ seen.add(node);
73
+ }
74
+ const parent = parentOf(node);
75
+ const group = groups.get(parent);
76
+ if (group) group.push(node);
77
+ else groups.set(parent, [node]);
78
+ }
79
+ const kept = new Set();
80
+ for (const group of groups.values()) {
81
+ let nodes = group;
82
+ for (const predicate of predicates) nodes = predicate(nodes, ctx);
83
+ for (const node of nodes) kept.add(node);
84
+ }
85
+ if (input.length > 1) return ctx.dyn.order.sort([...kept]);
86
+ return found.filter((node) => kept.has(node));
87
+ };
88
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Compiler of inline function expressions (XPath 3.1 section 3.1.7): a
3
+ * closure over the variables in scope, with an absent focus in its body;
4
+ * arguments and result are converted to the declared types.
5
+ *
6
+ * @module @tradik/xslt3/xpath/eval/inline
7
+ */
8
+
9
+ import { dynamicCallContext } from "./dynamicCall.js";
10
+ import { XPathError } from "../../errors.js";
11
+ import { FunctionItem } from "../../items/function.js";
12
+ import { coerce } from "./coercion.js";
13
+ import { bindVariable } from "./scope.js";
14
+ import { ANY_SEQUENCE, compileSequenceType } from "./sequenceType.js";
15
+ import { clark, namespaceOf } from "./staticContext.js";
16
+
17
+ /** Compilers by node type. */
18
+ export const inlineCompilers = {
19
+ InlineFunctionExpr(node, scope, compile) {
20
+ const { sc } = scope;
21
+ const keys = node.params.map((param) =>
22
+ clark(namespaceOf(param.name, sc, ""), param.name.local),
23
+ );
24
+ if (new Set(keys).size !== keys.length) {
25
+ throw new XPathError(
26
+ "XQST0039",
27
+ "Two parameters of an inline function have the same name",
28
+ );
29
+ }
30
+ const params = node.params.map((param) =>
31
+ param.sequenceType
32
+ ? compileSequenceType(param.sequenceType, sc)
33
+ : ANY_SEQUENCE,
34
+ );
35
+ const returns = node.returnType
36
+ ? compileSequenceType(node.returnType, sc)
37
+ : ANY_SEQUENCE;
38
+ let bodyScope = scope;
39
+ for (const key of keys) bodyScope = bindVariable(bodyScope, key);
40
+ const body = compile(node.body, bodyScope);
41
+ const arity = keys.length;
42
+ const argOptions = keys.map((_, i) => ({
43
+ what: `argument ${i + 1} of an inline function`,
44
+ }));
45
+ const resultOptions = { what: "result of an inline function" };
46
+ const signature = { params, returns };
47
+ return (ctx) => [
48
+ new FunctionItem({
49
+ arity,
50
+ signature,
51
+ invoke: (args) => {
52
+ let env = ctx.env;
53
+ for (let i = 0; i < arity; i++) {
54
+ env = {
55
+ value: coerce(args[i], params[i], argOptions[i]),
56
+ next: env,
57
+ };
58
+ }
59
+ const value = body({
60
+ item: undefined,
61
+ position: 0,
62
+ size: 0,
63
+ env,
64
+ dyn: dynamicCallContext(ctx.dyn),
65
+ });
66
+ return coerce(value, returns, resultOptions);
67
+ },
68
+ }),
69
+ ];
70
+ },
71
+ };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Namespace nodes (XDM 3.1 section 6.4), which DOMs do not have: objects
3
+ * with nodeType 13 made for the in-scope namespaces of an element, once
4
+ * per element so that they keep their identity.
5
+ *
6
+ * The in-scope namespaces come from the `xmlns` attributes of the element
7
+ * and its ancestors, the names of the element and its attributes (DOMs
8
+ * built with createElementNS may lack the declarations), and the xml
9
+ * prefix, which is always in scope.
10
+ *
11
+ * @module @tradik/xslt3/xpath/eval/namespaceNodes
12
+ */
13
+
14
+ import { isNamespaceDeclaration, NODE_TYPES, parentOf } from "./domNodes.js";
15
+
16
+ /** The namespace bound to the xml prefix. */
17
+ export const XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace";
18
+
19
+ /** A namespace node: prefix ("" for the default namespace) and URI. */
20
+ export class NamespaceNode {
21
+ /**
22
+ * @param {Element} element - Parent element
23
+ * @param {string} prefix
24
+ * @param {string} uri
25
+ */
26
+ constructor(element, prefix, uri) {
27
+ this.ownerElement = element;
28
+ this.localName = prefix;
29
+ this.nodeName = prefix;
30
+ this.nodeValue = uri;
31
+ this.namespaceURI = null;
32
+ this.prefix = null;
33
+ this.childNodes = [];
34
+ Object.freeze(this);
35
+ }
36
+
37
+ /** @returns {number} 13, the nodeType of namespace nodes */
38
+ get nodeType() {
39
+ return NODE_TYPES.namespace;
40
+ }
41
+ }
42
+
43
+ /** @type {WeakMap<Element, NamespaceNode[]>} */
44
+ const cache = new WeakMap();
45
+
46
+ /**
47
+ * In-scope namespaces of an element as prefix → URI ("" URI: undeclared).
48
+ * @param {Element} element
49
+ * @returns {Map<string, string>}
50
+ */
51
+ export function inScopeNamespaces(element) {
52
+ const chain = [];
53
+ for (let e = element; e && e.nodeType === 1; e = parentOf(e)) chain.push(e);
54
+ const bindings = new Map();
55
+ for (const e of chain.reverse()) {
56
+ for (const attribute of e.attributes) {
57
+ if (!isNamespaceDeclaration(attribute)) continue;
58
+ const name = attribute.name ?? attribute.nodeName;
59
+ const prefix = name === "xmlns" ? "" : name.slice(6);
60
+ bindings.set(prefix, attribute.value ?? attribute.nodeValue);
61
+ }
62
+ }
63
+ const declare = (node) => {
64
+ if (node.namespaceURI) bindings.set(node.prefix ?? "", node.namespaceURI);
65
+ };
66
+ declare(element);
67
+ for (const attribute of element.attributes) {
68
+ if (!isNamespaceDeclaration(attribute) && attribute.prefix) {
69
+ declare(attribute);
70
+ }
71
+ }
72
+ bindings.set("xml", XML_NAMESPACE);
73
+ return bindings;
74
+ }
75
+
76
+ /**
77
+ * @param {Element} element
78
+ * @returns {NamespaceNode[]} the namespace nodes of an element
79
+ */
80
+ export function namespaceNodesOf(element) {
81
+ let nodes = cache.get(element);
82
+ if (!nodes) {
83
+ nodes = [];
84
+ for (const [prefix, uri] of inScopeNamespaces(element)) {
85
+ if (uri !== "") nodes.push(new NamespaceNode(element, prefix, uri));
86
+ }
87
+ cache.set(element, nodes);
88
+ }
89
+ return nodes;
90
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Node tests (XPath 3.1 section 3.3.2.2) and kind tests (section 2.5.5.3)
3
+ * compiled to predicates on DOM nodes.
4
+ *
5
+ * @module @tradik/xslt3/xpath/eval/nodeTests
6
+ */
7
+
8
+ import { XPathError } from "../../errors.js";
9
+ import {
10
+ childrenOf,
11
+ isXdmNode,
12
+ nodeLocalName,
13
+ nodeNamespace,
14
+ } from "./domNodes.js";
15
+ import { clark, namespaceOf } from "./staticContext.js";
16
+ import { untypedMatches } from "./typeNames.js";
17
+
18
+ /**
19
+ * A compiled kind test.
20
+ * @typedef {object} KindTest
21
+ * @property {string|null} kind - XDM node kind, null for node()
22
+ * @property {string|null} name - Clark name required, null for any
23
+ * @property {(node: Node) => boolean} matches - Applies to nodes only
24
+ */
25
+
26
+ /** nodeType of the principal node kind of an axis. */
27
+ const principal = (axis) =>
28
+ axis === "attribute" ? 2 : axis === "namespace" ? 13 : 1;
29
+
30
+ /**
31
+ * @param {Node} node
32
+ * @returns {string} Clark name of a node
33
+ */
34
+ const nodeName = (node) => clark(nodeNamespace(node), nodeLocalName(node));
35
+
36
+ /**
37
+ * Element or attribute test with an optional name and type.
38
+ * @param {object} test - ElementTest or AttributeTest
39
+ * @param {"element"|"attribute"} kind
40
+ * @param {import("./staticContext.js").StaticContext} sc
41
+ * @returns {KindTest}
42
+ */
43
+ function namedKindTest(test, kind, sc) {
44
+ const nodeType = kind === "element" ? 1 : 2;
45
+ const defaultNs = kind === "element" ? sc.defaultElementNamespace : "";
46
+ const name = test.name
47
+ ? clark(namespaceOf(test.name, sc, defaultNs), test.name.local)
48
+ : null;
49
+ const typed = test.typeName ? untypedMatches(test.typeName, kind, sc) : true;
50
+ return {
51
+ kind,
52
+ name,
53
+ matches: (node) =>
54
+ typed &&
55
+ node.nodeType === nodeType &&
56
+ (name === null || nodeName(node) === name),
57
+ };
58
+ }
59
+
60
+ /** Kind test compilers by node type. */
61
+ const kindTests = {
62
+ AnyKindTest: () => ({ kind: null, name: null, matches: () => true }),
63
+ TextTest: () => ({
64
+ kind: "text",
65
+ name: null,
66
+ matches: (node) => node.nodeType === 3 || node.nodeType === 4,
67
+ }),
68
+ CommentTest: () => ({
69
+ kind: "comment",
70
+ name: null,
71
+ matches: (node) => node.nodeType === 8,
72
+ }),
73
+ NamespaceNodeTest: () => ({
74
+ kind: "namespace",
75
+ name: null,
76
+ matches: (node) => node.nodeType === 13,
77
+ }),
78
+ PITest: (test) => ({
79
+ kind: "processing-instruction",
80
+ name: test.target === null ? null : clark("", test.target),
81
+ matches: (node) =>
82
+ node.nodeType === 7 &&
83
+ (test.target === null || nodeLocalName(node) === test.target),
84
+ }),
85
+ ElementTest: (test, sc) => namedKindTest(test, "element", sc),
86
+ AttributeTest: (test, sc) => namedKindTest(test, "attribute", sc),
87
+ SchemaElementTest: (test, sc) => {
88
+ namespaceOf(test.name, sc, sc.defaultElementNamespace);
89
+ throw new XPathError(
90
+ "XPST0008",
91
+ `No element declaration for schema-element(${test.name.local})`,
92
+ );
93
+ },
94
+ SchemaAttributeTest: (test, sc) => {
95
+ namespaceOf(test.name, sc, "");
96
+ throw new XPathError(
97
+ "XPST0008",
98
+ `No attribute declaration for schema-attribute(${test.name.local})`,
99
+ );
100
+ },
101
+ DocumentTest: (test, sc) => {
102
+ const element = test.elementTest && compileKindTest(test.elementTest, sc);
103
+ const matches = (node) => {
104
+ if (node.nodeType !== 9 && node.nodeType !== 11) return false;
105
+ if (!element) return true;
106
+ const children = childrenOf(node);
107
+ const elements = children.filter((child) => child.nodeType === 1);
108
+ const others = children.every(
109
+ (child) =>
110
+ child.nodeType === 1 || child.nodeType === 7 || child.nodeType === 8,
111
+ );
112
+ return elements.length === 1 && others && element.matches(elements[0]);
113
+ };
114
+ return { kind: "document", name: null, element, matches };
115
+ },
116
+ };
117
+
118
+ /**
119
+ * @param {import("../syntax/typeAst.js").KindTest} test
120
+ * @param {import("./staticContext.js").StaticContext} sc
121
+ * @returns {KindTest}
122
+ * @throws {XPathError} XPST0008 for schema-element(), schema-attribute()
123
+ * and unknown type names, XPST0081 for undeclared prefixes
124
+ */
125
+ export function compileKindTest(test, sc) {
126
+ return kindTests[test.type](test, sc);
127
+ }
128
+
129
+ /**
130
+ * Compiles the node test of an axis step.
131
+ * @param {import("../syntax/typeAst.js").NodeTest} test
132
+ * @param {string} axis
133
+ * @param {import("./staticContext.js").StaticContext} sc
134
+ * @returns {(node: Node) => boolean} the test, false for the nodes that
135
+ * are not XDM nodes
136
+ */
137
+ export function compileNodeTest(test, axis, sc) {
138
+ const nodeType = principal(axis);
139
+ if (test.type === "NameTest") {
140
+ const defaultNs = nodeType === 1 ? sc.defaultElementNamespace : "";
141
+ const uri = namespaceOf(test.name, sc, defaultNs);
142
+ const local = test.name.local;
143
+ // nodeLocalName() of the principal node kinds, without a second read
144
+ // of nodeType
145
+ const matches = (node) =>
146
+ node.nodeType === nodeType &&
147
+ (node.localName ?? node.nodeName) === local &&
148
+ nodeNamespace(node) === uri;
149
+ // The name, for axes that can look a node up by name (attribute)
150
+ matches.qname = { uri, local };
151
+ return matches;
152
+ }
153
+ if (test.type === "Wildcard") {
154
+ const uri = test.prefix !== null ? namespaceOf(test, sc, "") : test.uri;
155
+ const { local } = test;
156
+ return (node) =>
157
+ node.nodeType === nodeType &&
158
+ (local === null || nodeLocalName(node) === local) &&
159
+ (uri === null || nodeNamespace(node) === uri);
160
+ }
161
+ // node() on an axis: any XDM node, not a document type node
162
+ if (test.type === "AnyKindTest") return isXdmNode;
163
+ return compileKindTest(test, sc).matches;
164
+ }