@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,147 @@
1
+ /**
2
+ * fn:xml-to-json (F&O 3.1 section 17.5.4): the XML representation of JSON
3
+ * (elements map, array, string, number, boolean and null in the fn
4
+ * namespace) to a JSON text. The input is checked against the rules of
5
+ * the schema for that representation (FOJS0006); comments, processing
6
+ * instructions and whitespace between elements are ignored.
7
+ *
8
+ * @module @tradik/xslt3/functions/json/xmlToJson
9
+ */
10
+
11
+ import { formatDouble, parseDouble } from "../../xdm/numeric.js";
12
+ import { normalizeWhitespace, parseBoolean } from "../../xdm/strings.js";
13
+ import { readOptions } from "../options.js";
14
+ import { define, FN_NAMESPACE, stringItem } from "../support.js";
15
+ import { unescapeJsonChars } from "./jsonChars.js";
16
+ import { escapeChar, escapeJsonString, needsEscape } from "./jsonStrings.js";
17
+ import {
18
+ checkAttributes,
19
+ flag,
20
+ invalid,
21
+ members,
22
+ textOf,
23
+ } from "./xmlRepresentation.js";
24
+
25
+ /**
26
+ * A JSON string literal of a string or key.
27
+ * @param {string} text
28
+ * @param {boolean} escaped - The text holds JSON escape sequences, kept
29
+ * @returns {string}
30
+ */
31
+ function quote(text, escaped) {
32
+ if (!escaped) return `"${escapeJsonString(text)}"`;
33
+ let result = "";
34
+ for (const { cp, escape } of unescapeJsonChars(text)) {
35
+ result +=
36
+ escape ?? (needsEscape(cp) ? escapeChar(cp) : String.fromCodePoint(cp));
37
+ }
38
+ return `"${result}"`;
39
+ }
40
+
41
+ /**
42
+ * Writes one element of the representation.
43
+ * @param {Element} element
44
+ * @param {boolean} inMap - The element is an entry of a map (needs a key)
45
+ * @param {string} indent - Line break and indentation, "" when not indenting
46
+ * @returns {string}
47
+ */
48
+ function write(element, inMap, indent) {
49
+ if (element.namespaceURI !== FN_NAMESPACE) {
50
+ invalid(`element {${element.namespaceURI ?? ""}}${element.localName}`);
51
+ }
52
+ const name = element.localName;
53
+ checkAttributes(element);
54
+ if (inMap && !element.hasAttribute("key")) invalid("an entry without key");
55
+ flag(element, "escaped-key");
56
+ const inner = indent && `${indent} `;
57
+ const list = (open, close, items) =>
58
+ items.length
59
+ ? `${open}${items.map((item) => inner + item).join(",")}${indent}${close}`
60
+ : `${open}${close}`;
61
+ switch (name) {
62
+ case "map": {
63
+ const keys = new Set();
64
+ const entries = members(element).map((child) => {
65
+ const escaped = flag(child, "escaped-key");
66
+ const raw = child.getAttribute("key") ?? "";
67
+ const key = escaped ? unescapeKey(raw) : raw;
68
+ if (keys.has(key)) invalid(`duplicate key "${key}"`);
69
+ keys.add(key);
70
+ const separator = indent ? ": " : ":";
71
+ return `${quote(raw, escaped)}${separator}${write(child, true, inner)}`;
72
+ });
73
+ return list("{", "}", entries);
74
+ }
75
+ case "array":
76
+ return list(
77
+ "[",
78
+ "]",
79
+ members(element).map((child) => write(child, false, inner)),
80
+ );
81
+ case "string":
82
+ return quote(textOf(element), flag(element, "escaped"));
83
+ case "number": {
84
+ const value = parseDouble(
85
+ normalizeWhitespace(textOf(element), "collapse"),
86
+ );
87
+ if (value === null || !Number.isFinite(value)) invalid("number");
88
+ return formatDouble(value);
89
+ }
90
+ case "boolean": {
91
+ const value = parseBoolean(
92
+ normalizeWhitespace(textOf(element), "collapse"),
93
+ );
94
+ if (value === null) invalid("boolean");
95
+ return String(value);
96
+ }
97
+ case "null":
98
+ if (/\S/.test(textOf(element))) invalid("content in <null>");
99
+ return "null";
100
+ default:
101
+ return invalid(`element <${name}>`);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * The unescaped form of an escaped key, for duplicate detection.
107
+ * @param {string} key
108
+ * @returns {string}
109
+ */
110
+ const unescapeKey = (key) =>
111
+ unescapeJsonChars(key)
112
+ .map(({ cp }) => String.fromCodePoint(cp))
113
+ .join("");
114
+
115
+ /**
116
+ * fn:xml-to-json of a node.
117
+ * @param {Node} node - Document or element node
118
+ * @param {Array} [optionsArg]
119
+ * @returns {Array} an xs:string
120
+ */
121
+ function xmlToJson(node, optionsArg) {
122
+ const { indent } = readOptions(
123
+ optionsArg?.[0],
124
+ { indent: { type: "xs:boolean", default: false } },
125
+ "FOJS0005",
126
+ );
127
+ let element = node;
128
+ // 11: a temporary tree (xsl:variable without "as") is a document node
129
+ if (node.nodeType === 9 || node.nodeType === 11) {
130
+ const children = members(node);
131
+ if (children.length !== 1) invalid("a document needs one element");
132
+ element = children[0];
133
+ } else if (node.nodeType !== 1) {
134
+ invalid("not an element or document node");
135
+ }
136
+ return [stringItem(write(element, false, indent ? "\n" : ""))];
137
+ }
138
+
139
+ /** Function definitions. */
140
+ export const xmlToJsonFunctions = [
141
+ define("xml-to-json", ["node()?"], "xs:string?", ([input]) =>
142
+ input.length ? xmlToJson(input[0]) : [],
143
+ ),
144
+ define("xml-to-json", ["node()?", "map(*)"], "xs:string?", ([input, o]) =>
145
+ input.length ? xmlToJson(input[0], o) : [],
146
+ ),
147
+ ];
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The function modules of F&O 3.1 that need no evaluator, collected for
3
+ * the function registry. fn:concat, fn:string-join and fn:string-length
4
+ * are exported separately (`coreStringFunctions`) because the core library
5
+ * may define them.
6
+ *
7
+ * @module @tradik/xslt3/functions/library
8
+ */
9
+
10
+ import { aggregateFunctions } from "./aggregates.js";
11
+ import { dateTimeFunctions } from "./datetime.js";
12
+ import { formatDateTimeFunctions } from "./format/formatDateTime.js";
13
+ import { formatIntegerFunctions } from "./format/formatInteger.js";
14
+ import { formatNumberFunctions } from "./format/formatNumber.js";
15
+ import { mathFunctions } from "./math.js";
16
+ import { numericFunctions } from "./numeric.js";
17
+ import { parseIetfDateFunctions } from "./parseIetfDate.js";
18
+ import { qnameFunctions } from "./qnames.js";
19
+ import { analyzeStringFunctions } from "./regex/analyzeString.js";
20
+ import { regexFunctions } from "./regex/regexFunctions.js";
21
+ import { sequenceFunctions } from "./sequences.js";
22
+ import { serializeFunctions } from "./serializeFunction.js";
23
+ import { stringFunctions } from "./strings.js";
24
+ import { stringMatchFunctions } from "./stringMatch.js";
25
+ import { uriFunctions } from "./uri.js";
26
+
27
+ export { coreStringFunctions } from "./stringsCore.js";
28
+
29
+ /** @type {import("./support.js").FunctionDefinition[]} */
30
+ export const libraryFunctions = [
31
+ ...stringFunctions,
32
+ ...stringMatchFunctions,
33
+ ...uriFunctions,
34
+ ...regexFunctions,
35
+ ...analyzeStringFunctions,
36
+ ...numericFunctions,
37
+ ...formatIntegerFunctions,
38
+ ...formatNumberFunctions,
39
+ ...mathFunctions,
40
+ ...dateTimeFunctions,
41
+ ...formatDateTimeFunctions,
42
+ ...parseIetfDateFunctions,
43
+ ...qnameFunctions,
44
+ ...sequenceFunctions,
45
+ ...aggregateFunctions,
46
+ ...serializeFunctions,
47
+ ];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * fn:deep-equal for maps and arrays (F&O 3.1 section 14.2.1), the
3
+ * `deepEqualItem` hook that deepEqual.js calls for items that are neither
4
+ * atomic values nor nodes: maps are equal when they have the same keys
5
+ * (op:same-key) with deep-equal values, arrays when their members are
6
+ * deep-equal one by one. Other function items raise FOTY0015.
7
+ *
8
+ * @module @tradik/xslt3/functions/mapArrayEqual
9
+ */
10
+
11
+ import { XPathError } from "../errors.js";
12
+ import { itemKind } from "../xdm/atomic.js";
13
+ import { deepEqualSequences } from "./deepEqual.js";
14
+
15
+ /**
16
+ * Whether two items that are not both atomic values or nodes are
17
+ * deep-equal.
18
+ * @param {*} a
19
+ * @param {*} b
20
+ * @param {import("./deepEqual.js").DeepEqualOptions} options - Options of
21
+ * deepEqualSequences, with this function as `deepEqualItem`
22
+ * @returns {boolean}
23
+ * @throws {XPathError} FOTY0015 for function items other than maps and
24
+ * arrays
25
+ */
26
+ export function deepEqualItem(a, b, options) {
27
+ const kind = itemKind(a);
28
+ if (kind === "function" || itemKind(b) === "function") {
29
+ throw new XPathError("FOTY0015", "deep-equal cannot compare functions");
30
+ }
31
+ if (kind !== itemKind(b) || a.size !== b.size) return false;
32
+ if (kind === "array") {
33
+ return a.members.every((member, i) =>
34
+ deepEqualSequences(member, b.members[i], options),
35
+ );
36
+ }
37
+ return [...a.entries.values()].every(({ key, value }) => {
38
+ const other = b.get(key);
39
+ return other !== undefined && deepEqualSequences(value, other, options);
40
+ });
41
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Functions on maps (F&O 3.1 section 17.1), in the namespace
3
+ * http://www.w3.org/2005/xpath-functions/map.
4
+ *
5
+ * @module @tradik/xslt3/functions/maps
6
+ */
7
+
8
+ import { XPathError } from "../errors.js";
9
+ import { XdmArray } from "../items/array.js";
10
+ import { XdmMap } from "../items/map.js";
11
+ import { isArray, isMap } from "../xdm/atomic.js";
12
+ import { booleanItem, integerItem, stringItem } from "../xpath/eval/atomics.js";
13
+ import { NS } from "./signatures.js";
14
+
15
+ const DUPLICATES = new Set([
16
+ "use-first",
17
+ "use-last",
18
+ "use-any",
19
+ "combine",
20
+ "reject",
21
+ ]);
22
+
23
+ /**
24
+ * map:merge.
25
+ * @param {XdmMap[]} maps
26
+ * @param {XdmMap} [options]
27
+ * @returns {XdmMap}
28
+ */
29
+ function merge(maps, options) {
30
+ const duplicates = options?.get(stringItem("duplicates"));
31
+ let policy = "use-first";
32
+ if (duplicates !== undefined) {
33
+ const value = duplicates[0]?.value;
34
+ if (duplicates.length !== 1 || typeof value !== "string") {
35
+ throw new XPathError("XPTY0004", "duplicates must be an xs:string");
36
+ }
37
+ if (!DUPLICATES.has(value)) {
38
+ throw new XPathError("FOJS0005", `Invalid duplicates option ${value}`);
39
+ }
40
+ policy = value;
41
+ }
42
+ const entries = new Map();
43
+ for (const map of maps) {
44
+ for (const [k, entry] of map.entries) {
45
+ const existing = entries.get(k);
46
+ if (!existing || policy === "use-last") entries.set(k, entry);
47
+ else if (policy === "reject") {
48
+ throw new XPathError("FOJS0003", "Duplicate key in map:merge");
49
+ } else if (policy === "combine") {
50
+ entries.set(k, {
51
+ key: existing.key,
52
+ value: [...existing.value, ...entry.value],
53
+ });
54
+ }
55
+ }
56
+ }
57
+ return new XdmMap(entries);
58
+ }
59
+
60
+ /**
61
+ * map:find: values of a key in maps nested in a sequence.
62
+ * @param {Array} sequence
63
+ * @param {*} key
64
+ * @param {Array[]} found - Values are appended
65
+ */
66
+ function find(sequence, key, found) {
67
+ for (const item of sequence) {
68
+ if (isMap(item)) {
69
+ const value = item.get(key);
70
+ if (value !== undefined) found.push(value);
71
+ for (const entry of item.entries.values()) find(entry.value, key, found);
72
+ } else if (isArray(item)) {
73
+ for (const member of item.members) find(member, key, found);
74
+ }
75
+ }
76
+ }
77
+
78
+ /**
79
+ * @param {string} local
80
+ * @param {string[]} params
81
+ * @param {string} returns
82
+ * @param {Function} impl
83
+ * @returns {object} a definition in the map namespace
84
+ */
85
+ const mapFunction = (local, params, returns, impl) => ({
86
+ namespace: NS.map,
87
+ local,
88
+ params,
89
+ returns,
90
+ impl,
91
+ });
92
+
93
+ /** Function definitions. */
94
+ export const mapFunctions = [
95
+ mapFunction("size", ["map(*)"], "xs:integer", ([[map]]) => [
96
+ integerItem(map.size),
97
+ ]),
98
+ mapFunction("keys", ["map(*)"], "xs:anyAtomicType*", ([[map]]) => map.keys()),
99
+ mapFunction(
100
+ "contains",
101
+ ["map(*)", "xs:anyAtomicType"],
102
+ "xs:boolean",
103
+ ([[map], [key]]) => [booleanItem(map.has(key))],
104
+ ),
105
+ mapFunction(
106
+ "get",
107
+ ["map(*)", "xs:anyAtomicType"],
108
+ "item()*",
109
+ ([[map], [key]]) => map.get(key) ?? [],
110
+ ),
111
+ mapFunction(
112
+ "put",
113
+ ["map(*)", "xs:anyAtomicType", "item()*"],
114
+ "map(*)",
115
+ ([[map], [key], value]) => [map.put(key, value)],
116
+ ),
117
+ mapFunction(
118
+ "remove",
119
+ ["map(*)", "xs:anyAtomicType*"],
120
+ "map(*)",
121
+ ([[map], keys]) => [map.remove(keys)],
122
+ ),
123
+ mapFunction(
124
+ "entry",
125
+ ["xs:anyAtomicType", "item()*"],
126
+ "map(*)",
127
+ ([[key], value]) => [XdmMap.from([[key, value]])],
128
+ ),
129
+ mapFunction("merge", ["map(*)*"], "map(*)", ([maps]) => [merge(maps)]),
130
+ mapFunction("merge", ["map(*)*", "map(*)"], "map(*)", ([maps, [options]]) => [
131
+ merge(maps, options),
132
+ ]),
133
+ mapFunction(
134
+ "for-each",
135
+ ["map(*)", "function(xs:anyAtomicType, item()*) as item()*"],
136
+ "item()*",
137
+ ([[map], [f]]) =>
138
+ [...map.entries.values()].flatMap(({ key, value }) =>
139
+ f.invoke([[key], value]),
140
+ ),
141
+ ),
142
+ mapFunction(
143
+ "find",
144
+ ["item()*", "xs:anyAtomicType"],
145
+ "array(*)",
146
+ ([sequence, [key]]) => {
147
+ const found = [];
148
+ find(sequence, key, found);
149
+ return [new XdmArray(found)];
150
+ },
151
+ ),
152
+ ];
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Trigonometric and exponential functions (F&O 3.1 section 4.8), in the
3
+ * namespace http://www.w3.org/2005/xpath-functions/math. They follow IEEE
4
+ * 754 (JS Math) except where F&O differs: math:pow(1, y) and
5
+ * math:pow(-1, ±INF) are 1.
6
+ *
7
+ * @module @tradik/xslt3/functions/math
8
+ */
9
+
10
+ import { define, doubleItem, MATH_NAMESPACE, toDouble } from "./support.js";
11
+
12
+ const D = "xs:double?";
13
+
14
+ /**
15
+ * math:pow on JS numbers.
16
+ * @param {number} x
17
+ * @param {number} y
18
+ * @returns {number}
19
+ */
20
+ export function pow(x, y) {
21
+ if (x === 1 || (x === -1 && !Number.isFinite(y) && !Number.isNaN(y))) {
22
+ return 1;
23
+ }
24
+ return x ** y;
25
+ }
26
+
27
+ /**
28
+ * Declares a math function of one optional xs:double.
29
+ * @param {string} local
30
+ * @param {(x: number) => number} apply
31
+ * @returns {import("./support.js").FunctionDefinition}
32
+ */
33
+ const unary = (local, apply) =>
34
+ define(
35
+ local,
36
+ [D],
37
+ D,
38
+ ([arg]) => (arg.length === 0 ? [] : [doubleItem(apply(arg[0].value))]),
39
+ { namespace: MATH_NAMESPACE },
40
+ );
41
+
42
+ /** @type {import("./support.js").FunctionDefinition[]} */
43
+ export const mathFunctions = [
44
+ define("pi", [], "xs:double", () => [doubleItem(Math.PI)], {
45
+ namespace: MATH_NAMESPACE,
46
+ }),
47
+ unary("exp", Math.exp),
48
+ unary("exp10", (x) => 10 ** x),
49
+ unary("log", Math.log),
50
+ unary("log10", Math.log10),
51
+ unary("sqrt", Math.sqrt),
52
+ unary("sin", Math.sin),
53
+ unary("cos", Math.cos),
54
+ unary("tan", Math.tan),
55
+ unary("asin", Math.asin),
56
+ unary("acos", Math.acos),
57
+ unary("atan", Math.atan),
58
+ define(
59
+ "pow",
60
+ [D, "xs:numeric"],
61
+ D,
62
+ ([x, [y]]) =>
63
+ x.length === 0 ? [] : [doubleItem(pow(x[0].value, toDouble(y)))],
64
+ { namespace: MATH_NAMESPACE },
65
+ ),
66
+ define(
67
+ "atan2",
68
+ ["xs:double", "xs:double"],
69
+ "xs:double",
70
+ ([[y], [x]]) => [doubleItem(Math.atan2(y.value, x.value))],
71
+ { namespace: MATH_NAMESPACE },
72
+ ),
73
+ ];
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Functions locating nodes and their namespaces (F&O 3.1 sections 13 and
3
+ * 10.2): fn:path, fn:base-uri, fn:document-uri, fn:resolve-QName,
4
+ * fn:in-scope-prefixes and fn:namespace-uri-for-prefix.
5
+ *
6
+ * @module @tradik/xslt3/functions/nodePaths
7
+ */
8
+
9
+ import { XPathError } from "../errors.js";
10
+ import { AtomicValue } from "../xdm/atomic.js";
11
+ import { parseQName } from "../xdm/qname.js";
12
+ import { types } from "../xdm/types.js";
13
+ import { stringItem } from "../xpath/eval/atomics.js";
14
+ import {
15
+ childrenOf,
16
+ nodeLocalName,
17
+ nodeNamespace,
18
+ parentOf,
19
+ } from "../xpath/eval/domNodes.js";
20
+ import { inScopeNamespaces } from "../xpath/eval/namespaceNodes.js";
21
+ import { documentUriOf, nodeBaseUri } from "./baseUris.js";
22
+ import { focusNode } from "./focus.js";
23
+
24
+ export { nodeBaseUri };
25
+
26
+ /** @param {Node} node @returns {boolean} */
27
+ const isDocument = (node) => node.nodeType === 9 || node.nodeType === 11;
28
+
29
+ /**
30
+ * @param {Node} node
31
+ * @param {(n: Node) => boolean} same - Siblings counted for the position
32
+ * @returns {number} 1-based position among the matching siblings
33
+ */
34
+ function positionAmong(node, same) {
35
+ const parent = parentOf(node);
36
+ if (!parent) return 1;
37
+ return childrenOf(parent).filter(same).indexOf(node) + 1;
38
+ }
39
+
40
+ /**
41
+ * One step of fn:path.
42
+ * @param {Node} node
43
+ * @returns {string}
44
+ */
45
+ function pathStep(node) {
46
+ const name = `Q{${nodeNamespace(node)}}${nodeLocalName(node)}`;
47
+ switch (node.nodeType) {
48
+ case 1:
49
+ return `${name}[${positionAmong(
50
+ node,
51
+ (n) =>
52
+ n.nodeType === 1 &&
53
+ `Q{${nodeNamespace(n)}}${nodeLocalName(n)}` === name,
54
+ )}]`;
55
+ case 2:
56
+ return node.namespaceURI ? `@${name}` : `@${nodeLocalName(node)}`;
57
+ case 7:
58
+ return `processing-instruction(${nodeLocalName(node)})[${positionAmong(
59
+ node,
60
+ (n) => n.nodeType === 7 && nodeLocalName(n) === nodeLocalName(node),
61
+ )}]`;
62
+ case 8:
63
+ return `comment()[${positionAmong(node, (n) => n.nodeType === 8)}]`;
64
+ case 13:
65
+ return node.localName
66
+ ? `namespace::${node.localName}`
67
+ : 'namespace::*[Q{http://www.w3.org/2005/xpath-functions}local-name()=""]';
68
+ default:
69
+ return `text()[${positionAmong(node, (n) => n.nodeType === 3 || n.nodeType === 4)}]`;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * fn:path of a node.
75
+ * @param {Node} node
76
+ * @returns {string}
77
+ */
78
+ function pathOf(node) {
79
+ const steps = [];
80
+ let current = node;
81
+ for (; parentOf(current); current = parentOf(current)) {
82
+ steps.unshift(pathStep(current));
83
+ }
84
+ if (isDocument(current)) return `/${steps.join("/")}`;
85
+ const root = "Q{http://www.w3.org/2005/xpath-functions}root()";
86
+ return steps.length ? `${root}/${steps.join("/")}` : root;
87
+ }
88
+
89
+ /** @param {string|undefined} uri @returns {Array} an optional xs:anyURI */
90
+ const anyUri = (uri) =>
91
+ uri === undefined ? [] : [new AtomicValue(types.anyURI, uri)];
92
+
93
+ /**
94
+ * fn:resolve-QName: a lexical QName resolved with the in-scope namespaces
95
+ * of an element.
96
+ * @param {Array<Array>} args
97
+ * @returns {Array} an optional xs:QName
98
+ * @throws {XPathError} FOCA0002 for an invalid lexical QName, FONS0004
99
+ * for an undeclared prefix
100
+ */
101
+ function resolveQName([name, [element]]) {
102
+ if (!name.length) return [];
103
+ const namespaces = inScopeNamespaces(element);
104
+ const resolve = (prefix) => namespaces.get(prefix) ?? (prefix ? null : "");
105
+ const qname = parseQName(name[0].value, resolve);
106
+ if (qname === null) {
107
+ throw new XPathError("FOCA0002", `"${name[0].value}" is not a QName`);
108
+ }
109
+ return [new AtomicValue(types.QName, qname)];
110
+ }
111
+
112
+ /** Function definitions. */
113
+ export const nodePathFunctions = [
114
+ {
115
+ local: "path",
116
+ params: [],
117
+ returns: "xs:string?",
118
+ focus: true,
119
+ impl: (_, context) => [stringItem(pathOf(focusNode(context)))],
120
+ },
121
+ {
122
+ local: "path",
123
+ params: ["node()?"],
124
+ returns: "xs:string?",
125
+ impl: ([arg]) => (arg.length ? [stringItem(pathOf(arg[0]))] : []),
126
+ },
127
+ {
128
+ local: "base-uri",
129
+ params: [],
130
+ returns: "xs:anyURI?",
131
+ focus: true,
132
+ impl: (_, context) => anyUri(nodeBaseUri(focusNode(context))),
133
+ },
134
+ {
135
+ local: "base-uri",
136
+ params: ["node()?"],
137
+ returns: "xs:anyURI?",
138
+ impl: ([arg]) => (arg.length ? anyUri(nodeBaseUri(arg[0])) : []),
139
+ },
140
+ {
141
+ local: "document-uri",
142
+ params: [],
143
+ returns: "xs:anyURI?",
144
+ focus: true,
145
+ impl: (_, context) => {
146
+ const node = focusNode(context);
147
+ return isDocument(node) ? anyUri(documentUriOf(node)) : [];
148
+ },
149
+ },
150
+ {
151
+ local: "document-uri",
152
+ params: ["node()?"],
153
+ returns: "xs:anyURI?",
154
+ impl: ([arg]) =>
155
+ arg.length && isDocument(arg[0]) ? anyUri(documentUriOf(arg[0])) : [],
156
+ },
157
+ {
158
+ local: "resolve-QName",
159
+ params: ["xs:string?", "element()"],
160
+ returns: "xs:QName?",
161
+ impl: resolveQName,
162
+ },
163
+ {
164
+ local: "in-scope-prefixes",
165
+ params: ["element()"],
166
+ returns: "xs:string*",
167
+ impl: ([[element]]) =>
168
+ [...inScopeNamespaces(element)]
169
+ .filter(([, uri]) => uri !== "")
170
+ .map(([prefix]) => stringItem(prefix)),
171
+ },
172
+ {
173
+ local: "namespace-uri-for-prefix",
174
+ params: ["xs:string?", "element()"],
175
+ returns: "xs:anyURI?",
176
+ impl: ([prefix, [element]]) => {
177
+ const uri = inScopeNamespaces(element).get(prefix[0]?.value ?? "");
178
+ return uri ? anyUri(uri) : [];
179
+ },
180
+ },
181
+ ];