@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,166 @@
1
+ /**
2
+ * Functions on URIs (F&O 3.1 sections 5.4.10 to 5.4.12 and 8.1):
3
+ * encode-for-uri, iri-to-uri, escape-html-uri and resolve-uri, which
4
+ * implements the reference resolution of RFC 3986 section 5.2.
5
+ *
6
+ * @module @tradik/xslt3/functions/uri
7
+ */
8
+
9
+ import { XPathError } from "../errors.js";
10
+ import { AtomicValue } from "../xdm/atomic.js";
11
+ import { types } from "../xdm/types.js";
12
+ import { define, stringArg, stringItem } from "./support.js";
13
+
14
+ const encoder = new globalThis.TextEncoder();
15
+
16
+ /**
17
+ * Percent-encodes (UTF-8, upper-case hex) the codepoints that `keep`
18
+ * rejects.
19
+ * @param {string} text
20
+ * @param {(cp: number) => boolean} keep
21
+ * @returns {string}
22
+ */
23
+ export function percentEncode(text, keep) {
24
+ let result = "";
25
+ for (const char of text) {
26
+ if (keep(char.codePointAt(0))) {
27
+ result += char;
28
+ continue;
29
+ }
30
+ for (const byte of encoder.encode(char)) {
31
+ result += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
32
+ }
33
+ }
34
+ return result;
35
+ }
36
+
37
+ const unreserved = /^[A-Za-z0-9\-_.~]$/;
38
+ const notInUri = new Set([...'<>"{}|\\^`'].map((c) => c.codePointAt(0)));
39
+
40
+ /** @type {Record<string, (cp: number) => boolean>} kept codepoints */
41
+ const escapers = {
42
+ "encode-for-uri": (cp) => unreserved.test(String.fromCodePoint(cp)),
43
+ "iri-to-uri": (cp) => cp > 0x20 && cp < 0x7f && !notInUri.has(cp),
44
+ "escape-html-uri": (cp) => cp >= 0x20 && cp <= 0x7e,
45
+ };
46
+
47
+ const referencePattern =
48
+ /^(?:([^:/?#]*):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/s;
49
+ const schemePattern = /^[A-Za-z][A-Za-z0-9+.-]*$/;
50
+
51
+ /**
52
+ * Splits a URI reference into its RFC 3986 components.
53
+ * @param {string} uri
54
+ * @returns {{scheme?: string, authority?: string, path: string,
55
+ * query?: string, fragment?: string}}
56
+ * @throws {XPathError} FORG0002 for an invalid scheme or percent-encoding,
57
+ * or a "#" in the fragment
58
+ */
59
+ function parseReference(uri) {
60
+ const [, scheme, authority, path, query, fragment] =
61
+ referencePattern.exec(uri);
62
+ if (
63
+ (scheme !== undefined && !schemePattern.test(scheme)) ||
64
+ /%(?![0-9A-Fa-f]{2})/.test(uri) ||
65
+ fragment?.includes("#")
66
+ ) {
67
+ throw new XPathError("FORG0002", `Invalid URI ${uri}`);
68
+ }
69
+ return { scheme, authority, path, query, fragment };
70
+ }
71
+
72
+ /**
73
+ * remove_dot_segments of RFC 3986 section 5.2.4.
74
+ * @param {string} path
75
+ * @returns {string}
76
+ */
77
+ export function removeDotSegments(path) {
78
+ const output = [];
79
+ const segments = path.split("/");
80
+ segments.forEach((segment, i) => {
81
+ const last = i === segments.length - 1;
82
+ if (segment === ".") {
83
+ if (last) output.push("");
84
+ } else if (segment === "..") {
85
+ if (output.length > 1 || (output.length === 1 && output[0] !== "")) {
86
+ output.pop();
87
+ }
88
+ if (last) output.push("");
89
+ } else {
90
+ output.push(segment);
91
+ }
92
+ });
93
+ return output.join("/");
94
+ }
95
+
96
+ /**
97
+ * Resolves a URI reference against an absolute base (RFC 3986 5.2.2).
98
+ * @param {string} relative
99
+ * @param {string} base
100
+ * @returns {string}
101
+ * @throws {XPathError} FORG0002 for invalid URIs, a relative base or a base
102
+ * with a fragment
103
+ */
104
+ export function resolveUri(relative, base) {
105
+ const r = parseReference(relative);
106
+ if (r.scheme !== undefined) return relative;
107
+ const b = parseReference(base);
108
+ if (b.scheme === undefined || b.fragment !== undefined) {
109
+ throw new XPathError("FORG0002", `Invalid base URI ${base}`);
110
+ }
111
+ let { authority, path, query } = r;
112
+ if (authority === undefined) {
113
+ authority = b.authority;
114
+ if (path === "") {
115
+ path = b.path;
116
+ query ??= b.query;
117
+ } else if (!path.startsWith("/")) {
118
+ path =
119
+ b.authority !== undefined && b.path === ""
120
+ ? `/${path}`
121
+ : b.path.slice(0, b.path.lastIndexOf("/") + 1) + path;
122
+ }
123
+ }
124
+ return (
125
+ `${b.scheme}:` +
126
+ (authority === undefined ? "" : `//${authority}`) +
127
+ removeDotSegments(path) +
128
+ (query === undefined ? "" : `?${query}`) +
129
+ (r.fragment === undefined ? "" : `#${r.fragment}`)
130
+ );
131
+ }
132
+
133
+ /**
134
+ * fn:resolve-uri.
135
+ * @param {Array<*>[]} args - [$relative, $base?]
136
+ * @param {{staticBaseUri?: string}} context
137
+ * @returns {Array<*>}
138
+ */
139
+ function resolveUriFunction([relative, base], context) {
140
+ if (relative.length === 0) return [];
141
+ const baseUri = base ? base[0].value : context.staticBaseUri;
142
+ // an absolute URI is returned as is, without a base
143
+ const absolute = parseReference(relative[0].value).scheme !== undefined;
144
+ if (!absolute && (baseUri === undefined || baseUri === null)) {
145
+ throw new XPathError("FONS0005", "The static base URI is absent");
146
+ }
147
+ return [
148
+ new AtomicValue(types.anyURI, resolveUri(relative[0].value, baseUri)),
149
+ ];
150
+ }
151
+
152
+ /** @type {import("./support.js").FunctionDefinition[]} */
153
+ export const uriFunctions = [
154
+ ...Object.entries(escapers).map(([local, keep]) =>
155
+ define(local, ["xs:string?"], "xs:string", ([s]) => [
156
+ stringItem(percentEncode(stringArg(s), keep)),
157
+ ]),
158
+ ),
159
+ define("resolve-uri", ["xs:string?"], "xs:anyURI?", resolveUriFunction),
160
+ define(
161
+ "resolve-uri",
162
+ ["xs:string?", "xs:string"],
163
+ "xs:anyURI?",
164
+ resolveUriFunction,
165
+ ),
166
+ ];
@@ -0,0 +1,24 @@
1
+ /**
2
+ * fn:load-xquery-module (F&O 3.1, "Dynamic loading"): there is no XQuery
3
+ * processor, so every call raises FOQM0006 once its arguments are checked
4
+ * against the signature.
5
+ *
6
+ * @module @tradik/xslt3/functions/xqueryModule
7
+ */
8
+
9
+ import { XPathError } from "../errors.js";
10
+ import { define } from "./support.js";
11
+
12
+ /**
13
+ * @returns {never}
14
+ * @throws {XPathError} FOQM0006
15
+ */
16
+ function noXQuery() {
17
+ throw new XPathError("FOQM0006", "No XQuery processor is available");
18
+ }
19
+
20
+ /** Function definitions. */
21
+ export const xqueryModuleFunctions = [
22
+ define("load-xquery-module", ["xs:string"], "map(*)", noXQuery),
23
+ define("load-xquery-module", ["xs:string", "map(*)"], "map(*)", noXQuery),
24
+ ];
package/src/index.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @tradik/xslt3: XSLT 3.0 and XPath 3.1 in JavaScript (in development).
3
+ *
4
+ * One engine for XSLT 3.0 and 2.0 stylesheets, and 1.0 ones in
5
+ * backwards-compatible mode; see docs/XSLT3.md for the design and the
6
+ * milestones. Public so far: XPath 3.1 (compileXPath, evaluateXPath) and
7
+ * Serialization 3.1 (serialize, serializeChunks, serializeToBytes) and
8
+ * XSLT (compileStylesheet, XSLTProcessor).
9
+ *
10
+ * @module @tradik/xslt3
11
+ */
12
+
13
+ /** Version of this package, kept equal to package.json. */
14
+ export const VERSION = "1.0.0";
15
+
16
+ export {
17
+ compileXPath,
18
+ createFunctionLibrary,
19
+ defaultFunctionLibrary,
20
+ evaluateXPath,
21
+ FunctionLibrary,
22
+ readFileUri,
23
+ XPathError,
24
+ } from "./xpath/index.js";
25
+
26
+ export {
27
+ serialize,
28
+ serializeChunks,
29
+ serializeToBytes,
30
+ } from "./serialize/index.js";
31
+
32
+ export {
33
+ CompiledStylesheet,
34
+ compileStylesheet,
35
+ untypedAtomic,
36
+ versionMatches,
37
+ XSLTProcessor,
38
+ } from "./xslt/index.js";
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Arrays of XDM 3.1: immutable lists of members, each member a sequence.
3
+ * An array is also a function of arity 1 from a position (xs:integer,
4
+ * starting at 1) to the member there.
5
+ *
6
+ * @module @tradik/xslt3/items/array
7
+ */
8
+
9
+ import { XPathError } from "../errors.js";
10
+ import { ITEM_KIND } from "../xdm/atomic.js";
11
+ import { cast } from "../xdm/cast.js";
12
+ import { atomize } from "../xdm/nodes.js";
13
+ import { derivesFrom, types } from "../xdm/types.js";
14
+
15
+ /** An immutable XDM array. */
16
+ export class XdmArray {
17
+ /**
18
+ * @param {Array<Array>} [members] - Members (sequences); owned by the array
19
+ */
20
+ constructor(members = []) {
21
+ this.members = members;
22
+ Object.freeze(this);
23
+ }
24
+
25
+ /** @returns {"array"} the item kind */
26
+ get [ITEM_KIND]() {
27
+ return "array";
28
+ }
29
+
30
+ /** @returns {number} 1: an array is a function of one position */
31
+ get arity() {
32
+ return 1;
33
+ }
34
+
35
+ /** @returns {null} arrays are anonymous functions */
36
+ get name() {
37
+ return null;
38
+ }
39
+
40
+ /** @returns {number} number of members */
41
+ get size() {
42
+ return this.members.length;
43
+ }
44
+
45
+ /**
46
+ * Member at a position.
47
+ * @param {bigint|number} position - 1-based
48
+ * @returns {Array} the member
49
+ * @throws {XPathError} FOAY0001 when the position is out of bounds
50
+ */
51
+ get(position) {
52
+ const index = Number(position) - 1;
53
+ if (!(index >= 0 && index < this.members.length)) {
54
+ throw new XPathError(
55
+ "FOAY0001",
56
+ `Array index ${position} is out of bounds (size ${this.members.length})`,
57
+ );
58
+ }
59
+ return this.members[index];
60
+ }
61
+
62
+ /**
63
+ * Calls the array as a function: `$array($position)`.
64
+ * @param {Array<Array>} args - One argument: a single xs:integer
65
+ * (xs:untypedAtomic is cast)
66
+ * @returns {Array} the member
67
+ * @throws {XPathError} XPTY0004 for another argument, FOAY0001 when out
68
+ * of bounds
69
+ */
70
+ invoke(args) {
71
+ const values = atomize(args[0]);
72
+ let position = values[0];
73
+ if (values.length === 1 && position.type === types.untypedAtomic) {
74
+ position = cast(position, types.integer);
75
+ }
76
+ if (values.length !== 1 || !derivesFrom(position.type, types.integer)) {
77
+ throw new XPathError(
78
+ "XPTY0004",
79
+ "An array lookup needs exactly one xs:integer",
80
+ );
81
+ }
82
+ return this.get(position.value);
83
+ }
84
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Function items of XDM 3.1 other than maps and arrays: named function
3
+ * references, inline functions, partial applications and coerced functions.
4
+ *
5
+ * A function item is self-contained: `invoke(args)` applies the function
6
+ * conversion rules to its arguments and checks its result, using the
7
+ * static and dynamic context captured when the item was created.
8
+ *
9
+ * @module @tradik/xslt3/items/function
10
+ */
11
+
12
+ import { ITEM_KIND } from "../xdm/atomic.js";
13
+
14
+ /**
15
+ * Signature of a function item.
16
+ * @typedef {object} Signature
17
+ * @property {object[]} params - Compiled sequence types of the parameters
18
+ * (see xpath/eval/sequenceType.js)
19
+ * @property {object} returns - Compiled sequence type of the result
20
+ */
21
+
22
+ /** A function item. */
23
+ export class FunctionItem {
24
+ /**
25
+ * @param {object} init
26
+ * @param {import("../xdm/qname.js").QNameValue|null} [init.name] - Name,
27
+ * null for anonymous functions
28
+ * @param {number} init.arity - Number of parameters
29
+ * @param {Signature} init.signature - Parameter and result types
30
+ * @param {(args: Array<Array>) => Array} init.invoke - Implementation,
31
+ * called with one sequence per parameter
32
+ */
33
+ constructor({ name = null, arity, signature, invoke }) {
34
+ this.name = name;
35
+ this.arity = arity;
36
+ this.signature = signature;
37
+ this.invoke = invoke;
38
+ Object.freeze(this);
39
+ }
40
+
41
+ /** @returns {"function"} the item kind */
42
+ get [ITEM_KIND]() {
43
+ return "function";
44
+ }
45
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Maps of XDM 3.1: immutable sets of entries from atomic keys (compared
3
+ * with op:same-key, see mapKey.js) to sequences. A map is also a function
4
+ * of arity 1 that returns the value of a key, or the empty sequence.
5
+ *
6
+ * Entries keep their insertion order, which XDM leaves
7
+ * implementation-dependent.
8
+ *
9
+ * @module @tradik/xslt3/items/map
10
+ */
11
+
12
+ import { XPathError } from "../errors.js";
13
+ import { ITEM_KIND } from "../xdm/atomic.js";
14
+ import { atomize } from "../xdm/nodes.js";
15
+ import { mapKey } from "./mapKey.js";
16
+
17
+ /** An immutable XDM map. */
18
+ export class XdmMap {
19
+ /**
20
+ * @param {Map<string, {key: import("../xdm/atomic.js").AtomicValue, value: Array}>} [entries]
21
+ * - Entries by key string; owned by the new map
22
+ */
23
+ constructor(entries = new Map()) {
24
+ this.entries = entries;
25
+ Object.freeze(this);
26
+ }
27
+
28
+ /** @returns {"map"} the item kind */
29
+ get [ITEM_KIND]() {
30
+ return "map";
31
+ }
32
+
33
+ /** @returns {number} 1: a map is a function of one key */
34
+ get arity() {
35
+ return 1;
36
+ }
37
+
38
+ /** @returns {null} maps are anonymous functions */
39
+ get name() {
40
+ return null;
41
+ }
42
+
43
+ /** @returns {number} number of entries */
44
+ get size() {
45
+ return this.entries.size;
46
+ }
47
+
48
+ /**
49
+ * Builds a map from key/value pairs; a later duplicate key replaces the
50
+ * earlier one unless `onDuplicate` throws.
51
+ * @param {Iterable<[import("../xdm/atomic.js").AtomicValue, Array]>} pairs
52
+ * @param {(key: import("../xdm/atomic.js").AtomicValue) => void} [onDuplicate]
53
+ * @returns {XdmMap}
54
+ */
55
+ static from(pairs, onDuplicate) {
56
+ const entries = new Map();
57
+ for (const [key, value] of pairs) {
58
+ const k = mapKey(key);
59
+ if (onDuplicate && entries.has(k)) onDuplicate(key);
60
+ entries.set(k, { key, value });
61
+ }
62
+ return new XdmMap(entries);
63
+ }
64
+
65
+ /**
66
+ * @param {import("../xdm/atomic.js").AtomicValue} key
67
+ * @returns {Array|undefined} the value of the key, undefined when absent
68
+ */
69
+ get(key) {
70
+ return this.entries.get(mapKey(key))?.value;
71
+ }
72
+
73
+ /** @param {import("../xdm/atomic.js").AtomicValue} key @returns {boolean} */
74
+ has(key) {
75
+ return this.entries.has(mapKey(key));
76
+ }
77
+
78
+ /** @returns {import("../xdm/atomic.js").AtomicValue[]} the keys */
79
+ keys() {
80
+ return [...this.entries.values()].map((entry) => entry.key);
81
+ }
82
+
83
+ /**
84
+ * @param {import("../xdm/atomic.js").AtomicValue} key
85
+ * @param {Array} value
86
+ * @returns {XdmMap} a copy with the entry added or replaced
87
+ */
88
+ put(key, value) {
89
+ const entries = new Map(this.entries);
90
+ entries.set(mapKey(key), { key, value });
91
+ return new XdmMap(entries);
92
+ }
93
+
94
+ /**
95
+ * @param {import("../xdm/atomic.js").AtomicValue[]} keys
96
+ * @returns {XdmMap} a copy without the keys
97
+ */
98
+ remove(keys) {
99
+ const entries = new Map(this.entries);
100
+ for (const key of keys) entries.delete(mapKey(key));
101
+ return new XdmMap(entries);
102
+ }
103
+
104
+ /**
105
+ * Calls the map as a function: `$map($key)`.
106
+ * @param {Array<Array>} args - One argument: a single atomic value
107
+ * @returns {Array} the value, or the empty sequence
108
+ * @throws {XPathError} XPTY0004 when the argument is not one atomic value
109
+ */
110
+ invoke(args) {
111
+ const key = atomize(args[0]);
112
+ if (key.length !== 1) {
113
+ throw new XPathError(
114
+ "XPTY0004",
115
+ "A map lookup needs exactly one atomic key",
116
+ );
117
+ }
118
+ return this.get(key[0]) ?? [];
119
+ }
120
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Map keys: the string under which a map stores an atomic key, equal for
3
+ * two keys exactly when they are the same key under op:same-key (F&O 3.1
4
+ * section 17.1.1):
5
+ *
6
+ * - strings, xs:anyURI and xs:untypedAtomic compare as codepoint strings;
7
+ * - numbers compare by exact mathematical value, whatever their type
8
+ * (the double 0.1 is not the decimal 0.1), NaN is the same key as NaN;
9
+ * - dates and times are equal when they are the same instant, but a value
10
+ * with a timezone is never the same key as one without;
11
+ * - durations compare by months and seconds, whatever their subtype;
12
+ * - other values are only the same key as values of the same primitive.
13
+ *
14
+ * @module @tradik/xslt3/items/mapKey
15
+ */
16
+
17
+ import { Decimal } from "../xdm/decimal.js";
18
+ import { formatHexBinary } from "../xdm/binary.js";
19
+ import { localSeconds, timelineSeconds } from "../xdm/timeline.js";
20
+
21
+ const stringLike = new Set(["string", "anyURI", "untypedAtomic"]);
22
+ const numeric = new Set(["decimal", "float", "double"]);
23
+
24
+ /**
25
+ * Exact decimal value of a finite double.
26
+ * @param {number} n
27
+ * @returns {Decimal}
28
+ */
29
+ export function exactDecimal(n) {
30
+ const view = new DataView(new ArrayBuffer(8));
31
+ view.setFloat64(0, n);
32
+ const high = view.getUint32(0);
33
+ const biased = (high >>> 20) & 0x7ff;
34
+ const fraction = (BigInt(high & 0xfffff) << 32n) | BigInt(view.getUint32(4));
35
+ const mantissa = biased === 0 ? fraction : fraction | (1n << 52n);
36
+ const exponent = (biased === 0 ? 1 : biased) - 1075;
37
+ const signed = n < 0 ? -mantissa : mantissa;
38
+ if (exponent >= 0) return Decimal.of(signed << BigInt(exponent));
39
+ return Decimal.of(signed * 5n ** BigInt(-exponent), -exponent);
40
+ }
41
+
42
+ /**
43
+ * Key string of a numeric value.
44
+ * @param {bigint|Decimal|number} value
45
+ * @returns {string}
46
+ */
47
+ function numericKey(value) {
48
+ if (typeof value === "bigint") return `n${value}`;
49
+ if (typeof value === "object") return `n${value}`;
50
+ if (Number.isNaN(value)) return "nNaN";
51
+ if (!Number.isFinite(value)) return value > 0 ? "nINF" : "n-INF";
52
+ return `n${exactDecimal(value)}`;
53
+ }
54
+
55
+ /**
56
+ * Key string of an atomic map key.
57
+ * @param {import("../xdm/atomic.js").AtomicValue} key
58
+ * @returns {string}
59
+ */
60
+ export function mapKey(key) {
61
+ const primitive = key.type.primitive.localName;
62
+ const { value } = key;
63
+ if (stringLike.has(primitive)) return `s${value}`;
64
+ if (numeric.has(primitive)) return numericKey(value);
65
+ switch (primitive) {
66
+ case "boolean":
67
+ return `b${value}`;
68
+ case "duration":
69
+ return `d${value.months}:${value.seconds}`;
70
+ case "hexBinary":
71
+ case "base64Binary":
72
+ return `${primitive}${formatHexBinary(value)}`;
73
+ case "QName":
74
+ case "NOTATION":
75
+ return `${primitive}{${value.namespaceURI}}${value.localName}`;
76
+ default: {
77
+ const zoned = value.timezone !== null;
78
+ const seconds = zoned ? timelineSeconds(value, 0) : localSeconds(value);
79
+ return `${primitive}${zoned ? "Z" : "L"}${seconds}`;
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * XSLT and XQuery Serialization 3.1: turns an XDM sequence into text with
3
+ * the xml, xhtml, html, text, json or adaptive output method.
4
+ *
5
+ * ```js
6
+ * serialize(items, { method: "xml", indent: true }); // a string
7
+ * for (const chunk of serializeChunks(items, { method: "html" })) write(chunk);
8
+ * serializeToBytes(items, { encoding: "UTF-16" }); // a Uint8Array
9
+ * ```
10
+ *
11
+ * Parameters are given by their camelCase names (`omitXmlDeclaration`) or
12
+ * the hyphenated names of the specification (`"omit-xml-declaration"`);
13
+ * see params/settings.js for the values and the defaults. Errors are
14
+ * XPathErrors with the codes of Serialization 3.1 (SENR0001, SERE00xx,
15
+ * SEPM00xx, SESU00xx).
16
+ *
17
+ * @module @tradik/xslt3/serialize
18
+ */
19
+
20
+ import { DEFAULT_CHUNK_SIZE, OutputBuffer } from "./output/buffer.js";
21
+ import { encodeText } from "./output/encoding.js";
22
+ import { Expander } from "./output/expander.js";
23
+ import { MarkupWriter } from "./markup/writer.js";
24
+ import { AdaptiveWriter } from "./methods/adaptive.js";
25
+ import { JsonWriter } from "./methods/json.js";
26
+ import { writeText } from "./methods/text.js";
27
+ import { normalizeSettings } from "./params/settings.js";
28
+ import { normalizeSequence } from "./sequence.js";
29
+
30
+ export { DEFAULT_CHUNK_SIZE } from "./output/buffer.js";
31
+ export { normalizeSettings } from "./params/settings.js";
32
+ export { OUTPUT_NAMESPACE } from "./params/names.js";
33
+
34
+ /**
35
+ * @param {*} value - A sequence (JS array) or a single item
36
+ * @returns {Array}
37
+ */
38
+ const toSequence = (value) => (Array.isArray(value) ? value : [value]);
39
+
40
+ /**
41
+ * Serializes nodes inside JSON or adaptive output: a whole serialization
42
+ * with another method, without an XML declaration.
43
+ * @param {import("./params/settings.js").Settings} settings
44
+ * @param {string} method
45
+ * @returns {(node: Node) => string}
46
+ */
47
+ const nodeSerializer = (settings, method) => (node) => {
48
+ const nested = { ...settings, method, omitXmlDeclaration: true };
49
+ return [...chunksOf([node], nested, new OutputBuffer(Infinity))].join("");
50
+ };
51
+
52
+ /**
53
+ * @param {Array} sequence
54
+ * @param {import("./params/settings.js").Settings} settings
55
+ * @param {OutputBuffer} buffer
56
+ * @yields {string} the output in chunks
57
+ * @returns {Generator<string, void, void>}
58
+ */
59
+ function* chunksOf(sequence, settings, buffer) {
60
+ const { method } = settings;
61
+ if (method === "json") {
62
+ const node = nodeSerializer(settings, settings.jsonNodeOutputMethod);
63
+ const writer = new JsonWriter(settings, new Expander(settings), node);
64
+ buffer.write(writer.sequence(sequence, 0));
65
+ } else if (method === "adaptive") {
66
+ const writer = new AdaptiveWriter(
67
+ new Expander(settings),
68
+ nodeSerializer(settings, "xml"),
69
+ );
70
+ const separator = settings.itemSeparator ?? "\n";
71
+ sequence.forEach((item, index) => {
72
+ buffer.write((index ? separator : "") + writer.item(item));
73
+ });
74
+ } else {
75
+ const entries = normalizeSequence(sequence, settings.itemSeparator);
76
+ yield* method === "text"
77
+ ? writeText(entries, settings, buffer)
78
+ : new MarkupWriter(settings, buffer).run(entries);
79
+ }
80
+ const rest = buffer.take();
81
+ if (rest) yield rest;
82
+ }
83
+
84
+ /**
85
+ * Serializes a sequence in chunks, as the output is produced, so a large
86
+ * result can be streamed.
87
+ * @param {*} sequence - XDM items (array) or one item
88
+ * @param {Record<string, *>} [params] - Serialization parameters
89
+ * @param {{chunkSize?: number}} [options] - Chunk size in UTF-16 code
90
+ * units (default {@link DEFAULT_CHUNK_SIZE}); a chunk can be longer
91
+ * when one text node or attribute is
92
+ * @returns {Generator<string, void, void>} the chunks
93
+ * @throws {import("../errors.js").XPathError} serialization errors (on
94
+ * creation for parameter errors, while iterating for the others)
95
+ */
96
+ export function serializeChunks(sequence, params = {}, options = {}) {
97
+ const settings = normalizeSettings(params);
98
+ const buffer = new OutputBuffer(options.chunkSize ?? DEFAULT_CHUNK_SIZE);
99
+ return chunksOf(toSequence(sequence), settings, buffer);
100
+ }
101
+
102
+ /**
103
+ * Serializes a sequence to a string.
104
+ * @param {*} sequence - XDM items (array) or one item
105
+ * @param {Record<string, *>} [params] - Serialization parameters
106
+ * @returns {string}
107
+ * @throws {import("../errors.js").XPathError} serialization errors
108
+ * @example serialize([doc], { method: "xml", omitXmlDeclaration: true })
109
+ */
110
+ export function serialize(sequence, params = {}) {
111
+ const settings = normalizeSettings(params);
112
+ const buffer = new OutputBuffer(Infinity);
113
+ return [...chunksOf(toSequence(sequence), settings, buffer)].join("");
114
+ }
115
+
116
+ /**
117
+ * Serializes a sequence to bytes in the requested encoding, with a byte
118
+ * order mark when byte-order-mark is set (by default for "UTF-16").
119
+ * @param {*} sequence - XDM items (array) or one item
120
+ * @param {Record<string, *>} [params] - Serialization parameters
121
+ * @returns {Uint8Array}
122
+ * @throws {import("../errors.js").XPathError} serialization errors
123
+ */
124
+ export function serializeToBytes(sequence, params = {}) {
125
+ const settings = normalizeSettings(params);
126
+ const buffer = new OutputBuffer(Infinity);
127
+ const text = [...chunksOf(toSequence(sequence), settings, buffer)].join("");
128
+ return encodeText(text, settings.encoding, settings.byteOrderMark);
129
+ }