@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,92 @@
1
+ /**
2
+ * xsl:global-context-item (XSLT 3.0 section 3.5.6): whether the global
3
+ * context item is required, optional or absent, and its type, checked
4
+ * when a transformation starts.
5
+ *
6
+ * @module @tradik/xslt3/xslt/compiler/globalContextItem
7
+ */
8
+
9
+ import { coerce } from "../../xpath/eval/coercion.js";
10
+ import { attr, xsltError } from "../names.js";
11
+
12
+ /** Values of the use attribute. */
13
+ const USES = new Set(["required", "optional", "absent"]);
14
+
15
+ /**
16
+ * Compiles the xsl:global-context-item declarations into
17
+ * `cx.globalContextItem`: `{use, type}`.
18
+ * @param {object[]} declarations
19
+ * @param {object} cx
20
+ * @throws {import("../../errors.js").XPathError} XTSE3087 for two
21
+ * different declarations, XTSE0020 for an invalid use, XTSE3089 for a
22
+ * type with use="absent"
23
+ */
24
+ export function declareGlobalContextItem(declarations, cx) {
25
+ cx.globalContextItem = { use: "optional", type: null };
26
+ const seen = new Set();
27
+ const modules = new Set();
28
+ for (const { element } of declarations) {
29
+ if (modules.has(element.parentNode)) {
30
+ throw xsltError("XTSE3087", "Two xsl:global-context-item in a module");
31
+ }
32
+ modules.add(element.parentNode);
33
+ const use = (attr(element, "use") ?? "optional").trim();
34
+ if (!USES.has(use)) throw xsltError("XTSE0020", `Invalid use "${use}"`);
35
+ const asText = attr(element, "as");
36
+ if (use === "absent" && asText !== undefined) {
37
+ throw xsltError("XTSE3089", 'use="absent" cannot have a type');
38
+ }
39
+ // the types compared without whitespace, which is not significant
40
+ seen.add(`${use}|${asText?.replace(/\s+/g, "")}`);
41
+ if (seen.size > 1) {
42
+ throw xsltError("XTSE3087", "Conflicting xsl:global-context-item");
43
+ }
44
+ const type =
45
+ asText === undefined ? null : cx.exprs.sequenceType(asText, element);
46
+ cx.globalContextItem = { use, type };
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Checks the used packages: their global context item is absent, so one
52
+ * that declares it required cannot run (XSLT 3.0 xsl:global-context-item:
53
+ * XTTE0590).
54
+ * @param {object} cx - The top-level package's compiler
55
+ * @throws {import("../../errors.js").XPathError} XTTE0590
56
+ */
57
+ export function checkLibraryContextItems(cx) {
58
+ for (const { child } of cx.uses) {
59
+ if (child.globalContextItem.use === "required") {
60
+ throw xsltError(
61
+ "XTTE0590",
62
+ `The used package ${child.packageName} requires a global context item`,
63
+ );
64
+ }
65
+ checkLibraryContextItems(child);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * The global context item of a transformation, checked against the
71
+ * declaration.
72
+ * @param {object} declared - `{use, type}`
73
+ * @param {*} item - The item supplied, undefined for none
74
+ * @returns {*} the item, undefined when absent
75
+ * @throws {import("../../errors.js").XPathError} XTDE3086 when a
76
+ * required item is missing, XTTE0590 when it has the wrong type
77
+ */
78
+ export function globalContextItem(declared, item) {
79
+ if (declared.use === "absent") return undefined;
80
+ if (item === undefined) {
81
+ if (declared.use === "required") {
82
+ throw xsltError("XTDE3086", "A global context item is required");
83
+ }
84
+ return undefined;
85
+ }
86
+ if (!declared.type) return item;
87
+ try {
88
+ return coerce([item], declared.type, { what: "global context item" })[0];
89
+ } catch (error) {
90
+ throw xsltError("XTTE0590", error.message.replace(/^[A-Z]+\d+: /, ""));
91
+ }
92
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Global variables and parameters (XSLT 3.0 section 9.5) and stylesheet
3
+ * functions (section 10.3): names collected first (they are in scope
4
+ * everywhere), the declaration of highest import precedence chosen, then
5
+ * compiled.
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/globals
8
+ */
9
+
10
+ import { coerce } from "../../xpath/eval/coercion.js";
11
+ import { compileParams } from "../instructions/params.js";
12
+ import {
13
+ compileValue,
14
+ typeConverter,
15
+ variableName,
16
+ } from "../instructions/variables.js";
17
+ import {
18
+ attr,
19
+ displayName,
20
+ isXsl,
21
+ RESERVED_NAMESPACES,
22
+ xsltError,
23
+ } from "../names.js";
24
+ import { required, yesNo } from "./attributes.js";
25
+ import { compileBody } from "./body.js";
26
+ import { splitParams } from "./templatesDecl.js";
27
+
28
+ /**
29
+ * Chooses, among declarations with the same key, the one of highest
30
+ * import precedence.
31
+ * @param {object[]} declarations
32
+ * @param {(declaration: object) => string} keyOf
33
+ * @param {string} code - Error code for two at the same precedence
34
+ * @returns {Map<string, object>} the winners by key, in declaration order
35
+ */
36
+ export function winners(declarations, keyOf, code) {
37
+ const chosen = new Map();
38
+ for (const declaration of declarations) {
39
+ const key = keyOf(declaration);
40
+ const current = chosen.get(key);
41
+ if (current && current.precedence === declaration.precedence) {
42
+ throw xsltError(code, `Duplicate declaration of ${key}`);
43
+ }
44
+ if (!current || current.precedence < declaration.precedence) {
45
+ chosen.set(key, declaration);
46
+ }
47
+ }
48
+ return chosen;
49
+ }
50
+
51
+ /**
52
+ * Collects the global variables and parameters: their keys, in scope
53
+ * everywhere, and the winning declarations.
54
+ * @param {object[]} declarations - xsl:variable and xsl:param declarations
55
+ * @param {object} cx
56
+ * @returns {Map<string, object>}
57
+ */
58
+ export function collectGlobals(declarations, cx) {
59
+ return winners(
60
+ declarations,
61
+ (declaration) => {
62
+ declaration.key ??= variableName(declaration.element, cx);
63
+ return declaration.key;
64
+ },
65
+ "XTSE0630",
66
+ );
67
+ }
68
+
69
+ /**
70
+ * A scope without a variable: its binding keeps its place (references are
71
+ * resolved to depths) but cannot be found by name.
72
+ * @param {object} scope - `{vars}`
73
+ * @param {string} key - Clark name hidden
74
+ * @returns {object} the scope
75
+ */
76
+ function hideVariable(scope, key) {
77
+ const before = [];
78
+ let found = scope.vars;
79
+ while (found !== null && found.key !== key) {
80
+ before.push(found.key);
81
+ found = found.next;
82
+ }
83
+ if (found === null) return scope;
84
+ let vars = { key: "", next: found.next };
85
+ for (let i = before.length - 1; i >= 0; i--) {
86
+ vars = { key: before[i], next: vars };
87
+ }
88
+ return { ...scope, vars };
89
+ }
90
+
91
+ /**
92
+ * Compiles a global variable or parameter. Its own name is not in scope
93
+ * in its declaration (XSLT 3.0 section 9.9: XPST0008).
94
+ * @param {{element: Element, key: string}} declaration
95
+ * @param {object} cx
96
+ * @param {object} [global] - Default: the global scope of the package
97
+ * @returns {object} `{key, isParam, required, value, convert}`
98
+ */
99
+ export function compileGlobal({ element, key }, cx, global = cx.globalScope()) {
100
+ const scope = hideVariable(global, key);
101
+ const isParam = isXsl(element, "param");
102
+ if (isParam && yesNo(element, "tunnel", false)) {
103
+ throw xsltError(
104
+ "XTSE0020",
105
+ "A global parameter cannot be a tunnel parameter",
106
+ );
107
+ }
108
+ const compiled = compileValue(
109
+ element,
110
+ cx,
111
+ scope,
112
+ isParam ? "XTTE0590" : "XTTE0570",
113
+ );
114
+ return {
115
+ key,
116
+ isParam,
117
+ required: isParam && yesNo(element, "required", false),
118
+ // a static variable keeps the value of the static stage
119
+ value:
120
+ cx.staticDeclarations?.get(key)?.element === element
121
+ ? () =>
122
+ typeConverter(
123
+ compiled.type,
124
+ isParam ? "XTTE0590" : "XTTE0570",
125
+ `value of $${displayName(key)}`,
126
+ )(cx.statics.get(key))
127
+ : compiled.value,
128
+ convert: typeConverter(
129
+ compiled.type,
130
+ "XTTE0590",
131
+ `parameter $${displayName(key)}`,
132
+ ),
133
+ };
134
+ }
135
+
136
+ /**
137
+ * The function definition of an xsl:function for the function library;
138
+ * its body is compiled later by {@link compileFunction}.
139
+ * @param {object} declaration
140
+ * @param {object} cx
141
+ * @returns {object} `{key, uri, local, arity, declaration}`
142
+ */
143
+ export function functionSignature(declaration, cx) {
144
+ const { element } = declaration;
145
+ const name = cx.exprs.qname(required(element, "name"), element, {
146
+ syntaxCode: "XTSE0020",
147
+ });
148
+ yesNo(element, "override", true);
149
+ yesNo(element, "override-extension-function", true);
150
+ if (!name.uri) throw xsltError("XTSE0740", "A function name needs a prefix");
151
+ if (RESERVED_NAMESPACES.has(name.uri)) {
152
+ throw xsltError("XTSE0080", `The namespace ${name.uri} is reserved`);
153
+ }
154
+ const children = cx.children(element);
155
+ const arity = splitParams(children).params.length;
156
+ return {
157
+ key: `{${name.uri}}${name.local}#${arity}`,
158
+ ...name,
159
+ arity,
160
+ declaration,
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Compiles the body of a stylesheet function.
166
+ * @param {object} signature - From {@link functionSignature}
167
+ * @param {object} cx
168
+ * @returns {object} `{params, body, convert}`
169
+ */
170
+ export function compileFunction(signature, cx) {
171
+ const { element } = signature.declaration;
172
+ const { params: paramElements, rest } = splitParams(cx.children(element));
173
+ const { params, scope } = compileParams(
174
+ paramElements,
175
+ cx,
176
+ cx.globalScope(),
177
+ true,
178
+ );
179
+ const asText = attr(element, "as");
180
+ const type = asText ? cx.exprs.sequenceType(asText, element) : null;
181
+ return {
182
+ params: params.map((param) => ({
183
+ ...param,
184
+ convert: param.type
185
+ ? (value) =>
186
+ coerce(value, param.type, {
187
+ what: `argument $${displayName(param.key)}`,
188
+ })
189
+ : (value) => value,
190
+ })),
191
+ body: compileBody(element, cx, { ...scope, inFunction: true }, rest),
192
+ convert: typeConverter(type, "XTTE0780", "result of the function"),
193
+ memo: isMemoized(element),
194
+ };
195
+ }
196
+
197
+ /**
198
+ * Whether the results of a function are cached: cache="yes", or
199
+ * new-each-time="no" (the same arguments give the same nodes).
200
+ * @param {Element} element - xsl:function
201
+ * @returns {boolean}
202
+ */
203
+ function isMemoized(element) {
204
+ const flag = (name) => attr(element, name)?.trim();
205
+ return (
206
+ ["yes", "true", "1"].includes(flag("cache")) ||
207
+ ["no", "false", "0"].includes(flag("new-each-time"))
208
+ );
209
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Linking the packages of a stylesheet (XSLT 3.0 section 3.5.3.5): one
3
+ * environment for the global variables of every package, the components
4
+ * accepted from used packages entered in the registries of the using
5
+ * package, and abstract components made to fail when invoked (overriding
6
+ * declarations: see overrideLinks.js).
7
+ *
8
+ * @module @tradik/xslt3/xslt/compiler/linker
9
+ */
10
+
11
+ import { xsltError } from "../names.js";
12
+ import { compileGlobal } from "./globals.js";
13
+ import { usesOriginal } from "./overrideLinks.js";
14
+
15
+ /** A body that raises XTDE3052: an abstract component was invoked. */
16
+ const ABSTRACT_BODY = [
17
+ () => {
18
+ throw xsltError("XTDE3052", "An abstract component was invoked");
19
+ },
20
+ ];
21
+
22
+ /**
23
+ * Lays out the global variables of every package of the stylesheet in
24
+ * one environment, and gives each package the names it sees.
25
+ * @param {object} top - The top-level package's compiler
26
+ */
27
+ export function layoutGlobals(top) {
28
+ const slots = [];
29
+ const packages = [];
30
+ const visit = (cx) => {
31
+ for (const use of cx.uses) visit(use.child);
32
+ packages.push(cx);
33
+ slots.push(...cx.ownSlots);
34
+ };
35
+ visit(top);
36
+ for (const cx of packages) {
37
+ cx.layout = slots;
38
+ cx.setGlobals(
39
+ slots.map((slot, i) =>
40
+ cx.globalNames.get(slot.name) === slot ? slot.name : `\u0000${i}`,
41
+ ),
42
+ );
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Evaluates a global variable of a library package with an absent focus.
48
+ * @param {object} compiled - Compiled global
49
+ */
50
+ function withoutFocus(compiled) {
51
+ const { value } = compiled;
52
+ compiled.value = (xc, machine) =>
53
+ value({ ...xc, item: undefined, position: 0, size: 0 }, machine);
54
+ }
55
+
56
+ /**
57
+ * Compiles the global variables whose value this package gives.
58
+ * @param {object} cx
59
+ * @returns {object[]} compiled globals of the whole layout (meaningful
60
+ * for the top-level package, once every package is compiled)
61
+ */
62
+ export function compileSlots(cx) {
63
+ cx.layout.forEach((slot) => {
64
+ if (slot.owner !== cx) return;
65
+ const original = slot.original
66
+ ? cx.layout.indexOf(slot.original)
67
+ : undefined;
68
+ if (slot.original?.abstract && usesOriginal(slot.declaration.element)) {
69
+ throw xsltError("XTSE3075", "The overridden variable is abstract");
70
+ }
71
+ slot.compiled = compileGlobal(
72
+ slot.declaration,
73
+ cx,
74
+ cx.globalScope(original),
75
+ );
76
+ // the value an overriding variable replaced is only read through it
77
+ if (slot.name === "") slot.compiled.required = false;
78
+ // the global context item belongs to the top-level package
79
+ if (cx.packageChain.length > 0) withoutFocus(slot.compiled);
80
+ if (slot.abstract) {
81
+ slot.compiled.value = ABSTRACT_BODY[0];
82
+ slot.compiled.required = false;
83
+ }
84
+ });
85
+ return cx.layout.map((slot, i) => ({
86
+ ...slot.compiled,
87
+ key: cx.globalKeys[i],
88
+ }));
89
+ }
90
+
91
+ /**
92
+ * Enters the templates, attribute sets and modes accepted from used
93
+ * packages in the registries of this package.
94
+ * @param {object} cx
95
+ */
96
+ export function importAccepted(cx) {
97
+ for (const use of cx.uses) {
98
+ for (const { component } of use.accepted) {
99
+ const { owner, key } = component;
100
+ if (component.kind === "template") {
101
+ cx.namedTemplates.set(key, owner.namedTemplates.get(key));
102
+ } else if (component.kind === "attribute-set") {
103
+ cx.attributeSets.set(key, owner.attributeSets.get(key));
104
+ } else if (component.kind === "mode") {
105
+ cx.acceptedModes.set(key, owner.mode(key));
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Makes the abstract components of this package raise XTDE3052.
113
+ * @param {object} cx
114
+ */
115
+ export function markAbstract(cx) {
116
+ for (const entry of cx.table.values()) {
117
+ if (entry.owner !== cx || entry.visibility !== "abstract") continue;
118
+ if (entry.kind === "template") {
119
+ const template = cx.namedTemplates.get(entry.key);
120
+ template.body = ABSTRACT_BODY;
121
+ // its parameters are not evaluated: the call fails first
122
+ template.params = template.params.map((param) => ({
123
+ ...param,
124
+ required: false,
125
+ value: () => [],
126
+ }));
127
+ } else if (entry.kind === "function") {
128
+ entry.cell.body = ABSTRACT_BODY;
129
+ } else if (entry.kind === "attribute-set") {
130
+ const parts = cx.attributeSets.get(entry.key);
131
+ parts.splice(0, parts.length, { uses: [], body: ABSTRACT_BODY, cx });
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Other declarations: xsl:strip-space and xsl:preserve-space (XSLT 3.0
3
+ * section 4.3), xsl:namespace-alias (11.1.3) and xsl:key (20.2.1);
4
+ * xsl:mode is in modeDecl.js.
5
+ *
6
+ * @module @tradik/xslt3/xslt/compiler/miscDecl
7
+ */
8
+
9
+ import { compileBody } from "./body.js";
10
+ import { getCollation } from "../../functions/collations.js";
11
+ import { resolveUri } from "../../xpath/eval/uris.js";
12
+ import { required, yesNo } from "./attributes.js";
13
+ import { infoOf } from "./elementInfo.js";
14
+ import { attr, clarkOf, tokens, xsltError } from "../names.js";
15
+ import { compilePattern } from "../patterns/compile.js";
16
+
17
+ /**
18
+ * A name test of xsl:strip-space or xsl:preserve-space: `*`, `prefix:*`,
19
+ * `*:local` or a QName (in the xpath-default-namespace when unprefixed).
20
+ * @param {string} token
21
+ * @param {Element} element
22
+ * @param {object} cx
23
+ * @returns {{uri: string|null, local: string|null, priority: number}}
24
+ */
25
+ function nameTest(token, element, cx) {
26
+ if (token === "*") return { uri: null, local: null, priority: -0.5 };
27
+ if (token.startsWith("*:")) {
28
+ return { uri: null, local: token.slice(2), priority: -0.25 };
29
+ }
30
+ const eqWildcard = /^Q\{([^}]*)\}\*$/.exec(token);
31
+ if (eqWildcard) return { uri: eqWildcard[1], local: null, priority: -0.25 };
32
+ if (token.endsWith(":*")) {
33
+ const prefix = token.slice(0, -2);
34
+ const uri = infoOf(element).namespaces.get(prefix);
35
+ if (uri === undefined) {
36
+ throw xsltError("XTSE0280", `Undeclared prefix ${prefix}`);
37
+ }
38
+ return { uri, local: null, priority: -0.25 };
39
+ }
40
+ const name = cx.exprs.qname(token, element);
41
+ const uri = name.uri || infoOf(element).xpathDefaultNs;
42
+ return { uri, local: name.local, priority: 0 };
43
+ }
44
+
45
+ /**
46
+ * Compiles the whitespace stripping rules.
47
+ * @param {object[]} declarations - xsl:strip-space and xsl:preserve-space
48
+ * @param {object} cx
49
+ * @returns {object[]} rules `{strip, uri, local, priority, precedence,
50
+ * position}` (uri or local null for wildcards), best first
51
+ */
52
+ export function compileSpaceRules(declarations, cx) {
53
+ const rules = [];
54
+ declarations.forEach(({ element, precedence }, position) => {
55
+ const strip = element.localName === "strip-space";
56
+ for (const token of tokens(required(element, "elements"))) {
57
+ const test = nameTest(token, element, cx);
58
+ rules.push({ strip, ...test, precedence, position });
59
+ }
60
+ });
61
+ const seen = new Map();
62
+ for (const rule of rules) {
63
+ const key = `${rule.precedence}|${rule.uri}|${rule.local}`;
64
+ if (seen.has(key) && seen.get(key) !== rule.strip) {
65
+ throw xsltError(
66
+ "XTSE0270",
67
+ "The same name is in xsl:strip-space and xsl:preserve-space",
68
+ );
69
+ }
70
+ seen.set(key, rule.strip);
71
+ }
72
+ rules.sort(
73
+ (a, b) =>
74
+ b.precedence - a.precedence ||
75
+ b.priority - a.priority ||
76
+ b.position - a.position,
77
+ );
78
+ return rules;
79
+ }
80
+
81
+ /**
82
+ * Collects the namespace aliases.
83
+ * @param {object[]} declarations
84
+ * @returns {Map<string, {uri: string, prefix: string}>} result namespace
85
+ * and prefix by stylesheet namespace URI
86
+ */
87
+ export function collectAliases(declarations) {
88
+ const aliases = new Map();
89
+ const from = new Map();
90
+ for (const { element, precedence } of declarations) {
91
+ const namespaces = infoOf(element).namespaces;
92
+ const lookup = (name) => {
93
+ const prefix = required(element, name).trim();
94
+ const key = prefix === "#default" ? "" : prefix;
95
+ const uri = namespaces.get(key);
96
+ if (uri === undefined && key !== "") {
97
+ throw xsltError("XTSE0812", `Undeclared prefix ${prefix}`);
98
+ }
99
+ return { prefix: key, uri: uri ?? "" };
100
+ };
101
+ const source = lookup("stylesheet-prefix");
102
+ const result = lookup("result-prefix");
103
+ const previous = aliases.get(source.uri);
104
+ if (
105
+ previous &&
106
+ from.get(source.uri) === precedence &&
107
+ previous.uri !== result.uri
108
+ ) {
109
+ throw xsltError("XTSE0810", "Conflicting namespace aliases");
110
+ }
111
+ if (!previous || from.get(source.uri) <= precedence) {
112
+ aliases.set(source.uri, result);
113
+ from.set(source.uri, precedence);
114
+ }
115
+ }
116
+ return aliases;
117
+ }
118
+
119
+ /**
120
+ * XTSE1210: the collation of a key must be known.
121
+ * @param {string} uri - The collation attribute
122
+ * @param {Element} element
123
+ */
124
+ function knownCollation(uri, element) {
125
+ try {
126
+ getCollation(resolveUri(uri.trim(), infoOf(element).baseUri));
127
+ } catch {
128
+ throw xsltError("XTSE1210", `Unknown collation ${uri}`);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Compiles an xsl:key into the key registry.
134
+ * @param {object} declaration
135
+ * @param {object} cx
136
+ */
137
+ export function declareKey({ element }, cx) {
138
+ const name = clarkOf(cx.exprs.qname(required(element, "name"), element));
139
+ const use = attr(element, "use");
140
+ const children = cx.children(element);
141
+ if (use !== undefined && children.length > 0) {
142
+ // content that is no sequence constructor is the first error (XTSE0010)
143
+ compileBody(element, cx, cx.globalScope());
144
+ throw xsltError("XTSE1205", "xsl:key cannot have use and content");
145
+ }
146
+ if (use === undefined && children.length === 0) {
147
+ throw xsltError("XTSE1205", "xsl:key needs use or content");
148
+ }
149
+ const scope = cx.globalScope();
150
+ const collation = attr(element, "collation");
151
+ const definition = {
152
+ match: compilePattern(required(element, "match"), element, cx),
153
+ // namespace nodes are indexed only for keys that can match them
154
+ namespaces: required(element, "match").includes("namespace-node"),
155
+ use: use === undefined ? null : cx.exprs.xpath(use, element, scope.vars),
156
+ body: use === undefined ? compileBody(element, cx, scope) : null,
157
+ collation: collation ?? infoOf(element).defaultCollation,
158
+ compatible: infoOf(element).version < 2,
159
+ };
160
+ if (collation !== undefined) knownCollation(collation, element);
161
+ definition.composite = yesNo(element, "composite", false);
162
+ const list = cx.keys.get(name) ?? [];
163
+ if (list.length > 0 && list[0].collation !== definition.collation) {
164
+ throw xsltError("XTSE1220", `The key ${name} has different collations`);
165
+ }
166
+ if (list.length > 0 && list[0].composite !== definition.composite) {
167
+ throw xsltError("XTSE1222", `The key ${name} is composite and not`);
168
+ }
169
+ list.push(definition);
170
+ cx.keys.set(name, list);
171
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * xsl:mode declarations (XSLT 3.0 section 6.7.1): the behaviour of a
3
+ * mode for unmatched and ambiguously matched items, several declarations
4
+ * of a mode combined (XTSE0545 for a conflict at the same import
5
+ * precedence).
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/modeDecl
8
+ */
9
+
10
+ import { attr, clarkOf, xsltError } from "../names.js";
11
+
12
+ const ON_NO_MATCH = new Set([
13
+ "deep-copy",
14
+ "shallow-copy",
15
+ "deep-skip",
16
+ "shallow-skip",
17
+ "text-only-copy",
18
+ "fail",
19
+ ]);
20
+
21
+ /**
22
+ * Records the attributes of an xsl:mode declaration, noting two values
23
+ * of an attribute at the same import precedence (XTSE0545 unless a
24
+ * declaration of higher precedence settles it).
25
+ * @param {object} mode
26
+ * @param {Element} element
27
+ * @param {number} precedence
28
+ */
29
+ function recordModeAttributes(mode, element, precedence) {
30
+ mode.declared ??= new Map();
31
+ for (const attribute of element.attributes) {
32
+ const key = attribute.name;
33
+ // use-accumulators is compared as a set (useAccumulators.js)
34
+ if (
35
+ key === "name" ||
36
+ key === "use-accumulators" ||
37
+ key.includes(":") ||
38
+ key.startsWith("xmlns")
39
+ ) {
40
+ continue;
41
+ }
42
+ const value = attribute.value.trim();
43
+ const previous = mode.declared.get(key);
44
+ const conflict =
45
+ previous?.precedence === precedence &&
46
+ (previous.conflict || previous.value !== value);
47
+ mode.declared.set(key, { value, precedence, conflict });
48
+ }
49
+ }
50
+
51
+ /**
52
+ * XTSE0545: checks the xsl:mode declarations once all are recorded.
53
+ * @param {Iterable<object>} modes
54
+ */
55
+ export function checkModeDeclarations(modes) {
56
+ for (const mode of modes) {
57
+ for (const [key, { conflict }] of mode.declared ?? []) {
58
+ if (conflict) {
59
+ throw xsltError("XTSE0545", `Conflicting values of ${key} for a mode`);
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Applies an xsl:mode declaration.
67
+ * @param {object} declaration
68
+ * @param {object} cx
69
+ */
70
+ export function declareMode({ element, precedence }, cx) {
71
+ if (cx.children(element).length > 0) {
72
+ throw xsltError("XTSE0010", "xsl:mode must be empty");
73
+ }
74
+ const nameText = attr(element, "name");
75
+ const name =
76
+ nameText === undefined ? "" : clarkOf(cx.exprs.qname(nameText, element));
77
+ const mode = cx.mode(name);
78
+ recordModeAttributes(mode, element, precedence);
79
+ const onNoMatch = attr(element, "on-no-match");
80
+ if (onNoMatch !== undefined) {
81
+ if (!ON_NO_MATCH.has(onNoMatch.trim())) {
82
+ throw xsltError("XTSE0020", `Invalid on-no-match ${onNoMatch}`);
83
+ }
84
+ mode.onNoMatch = onNoMatch.trim();
85
+ }
86
+ const onMultiple = attr(element, "on-multiple-match");
87
+ if (onMultiple !== undefined) mode.onMultipleMatch = onMultiple.trim();
88
+ }