@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,234 @@
1
+ /**
2
+ * What the compiled stylesheet holds, filled during compilation and read
3
+ * at run time: global variable names, named templates, modes and their
4
+ * rules, attribute sets, keys and stylesheet functions.
5
+ *
6
+ * @module @tradik/xslt3/xslt/compiler/registry
7
+ */
8
+
9
+ import { Mode } from "../patterns/modes.js";
10
+ import { useStaticContext } from "../runtime/context.js";
11
+ import { callFunction } from "../runtime/functionCall.js";
12
+ import { attr, displayName, tokens, xsltError } from "../names.js";
13
+ import { infoOf } from "./elementInfo.js";
14
+ import { expandCharacterMaps } from "./outputDecl.js";
15
+ import { StaticStage } from "./staticStage.js";
16
+
17
+ /** Registries of a stylesheet. */
18
+ export class CompilerRegistry extends StaticStage {
19
+ /** @param {object} options - See compileStylesheet */
20
+ constructor(options) {
21
+ super(options);
22
+ /** @type {Array<() => void>} checks run once everything is compiled */
23
+ this.deferred = [];
24
+ this.attributeSets = new Map();
25
+ /** @type {Map<string, object>} */
26
+ this.namedTemplates = new Map();
27
+ /** @type {Map<string, Mode>} */
28
+ this.modes = new Map();
29
+ this.allModeRules = [];
30
+ this.keys = new Map();
31
+ this.functionBodies = new Map();
32
+ this.declarationPrecedence = new WeakMap();
33
+ this.positions = 0;
34
+ this.globalKeys = [];
35
+ this.globalVars = null;
36
+ }
37
+
38
+ /** @param {string[]} keys - Clark names of the global variables */
39
+ setGlobals(keys) {
40
+ this.globalKeys = keys;
41
+ let vars = null;
42
+ for (const key of keys) vars = { key, next: vars };
43
+ this.globalVars = vars;
44
+ }
45
+
46
+ /** @returns {{vars: object|null}} the scope of top-level declarations */
47
+ globalScope() {
48
+ return { vars: this.globalVars };
49
+ }
50
+
51
+ /** @returns {number} the next declaration position */
52
+ nextPosition() {
53
+ return this.positions++;
54
+ }
55
+
56
+ /**
57
+ * @param {Element} element - A top-level declaration
58
+ * @returns {number} its import precedence
59
+ */
60
+ precedenceOf(element) {
61
+ return this.declarationPrecedence.get(element) ?? 0;
62
+ }
63
+
64
+ /**
65
+ * Registers a named template (the highest precedence wins).
66
+ * @param {string} key
67
+ * @param {object} template
68
+ */
69
+ addNamedTemplate(key, template) {
70
+ const current = this.namedTemplates.get(key);
71
+ if (current && current.precedence === template.precedence) {
72
+ throw xsltError("XTSE0660", `Two templates are named ${key}`);
73
+ }
74
+ if (!current || current.precedence < template.precedence) {
75
+ this.namedTemplates.set(key, template);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Gets or creates a mode.
81
+ * @param {string} name - Clark name, "" for the unnamed mode
82
+ * @returns {Mode}
83
+ */
84
+ mode(name) {
85
+ let mode = this.modes.get(name);
86
+ if (!mode) {
87
+ mode = new Mode(name);
88
+ for (const rule of this.allModeRules) mode.add({ ...rule });
89
+ this.modes.set(name, mode);
90
+ }
91
+ return mode;
92
+ }
93
+
94
+ /**
95
+ * Adds a template rule to a mode ("#all": every mode).
96
+ * @param {string} name
97
+ * @param {object} rule
98
+ */
99
+ addRule(name, rule) {
100
+ if (name === "#all") {
101
+ this.allModeRules.push(rule);
102
+ for (const mode of this.modes.values()) mode.add({ ...rule });
103
+ } else this.mode(name).add(rule);
104
+ }
105
+
106
+ /** Makes sure the unnamed mode exists. */
107
+ finishModes() {
108
+ this.mode("");
109
+ }
110
+
111
+ /**
112
+ * Resolves the mode attribute of xsl:apply-templates.
113
+ * @param {string|undefined} text
114
+ * @param {Element} element
115
+ * @returns {{current: boolean, name: string}}
116
+ */
117
+ modeRef(text, element) {
118
+ const token = text?.trim();
119
+ if (token === "#current") return { current: true, name: "" };
120
+ if (token === undefined || token === "#default") {
121
+ return { current: false, name: infoOf(element).defaultMode };
122
+ }
123
+ if (token === "#unnamed") return { current: false, name: "" };
124
+ if (tokens(token).length !== 1) {
125
+ throw xsltError("XTSE0550", `Invalid mode ${text}`);
126
+ }
127
+ const name = this.exprs.qname(token, element);
128
+ return { current: false, name: `{${name.uri}}${name.local}` };
129
+ }
130
+
131
+ /**
132
+ * Static checks of xsl:call-template once all templates are known.
133
+ * @param {string} key
134
+ * @param {{names: Set<string>}} params - Its xsl:with-param children
135
+ * @param {Element} element
136
+ */
137
+ checkCall(key, params, element) {
138
+ const template = this.namedTemplates.get(key);
139
+ if (!template) {
140
+ throw xsltError("XTSE0650", `No template named ${displayName(key)}`);
141
+ }
142
+ const declared = new Set(
143
+ template.params.filter((p) => !p.tunnel).map((p) => p.key),
144
+ );
145
+ for (const name of params.names) {
146
+ if (!declared.has(name) && infoOf(element).version >= 2) {
147
+ throw xsltError(
148
+ "XTSE0680",
149
+ `The template ${key} has no parameter ${name}`,
150
+ );
151
+ }
152
+ }
153
+ for (const param of template.params) {
154
+ if (param.required && !param.tunnel && !params.names.has(param.key)) {
155
+ throw xsltError("XTSE0690", `The parameter ${param.key} is required`);
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * The function library definition of a stylesheet function.
162
+ * @param {object} signature
163
+ * @returns {object}
164
+ */
165
+ functionDefinition(signature) {
166
+ // filled by compileFunction once every signature is known
167
+ const compiled = { params: [], body: [], convert: null };
168
+ this.functionBodies.set(signature.key, compiled);
169
+ return {
170
+ namespace: signature.uri,
171
+ local: signature.local,
172
+ params: Array(signature.arity).fill("item()*"),
173
+ returns: "item()*",
174
+ impl: (args, context) => callFunction(compiled, args, context),
175
+ // xsl:evaluate sees the public and final functions only
176
+ visibility:
177
+ attr(signature.declaration.element, "visibility")?.trim() ?? "private",
178
+ };
179
+ }
180
+
181
+ /**
182
+ * The XPath context in which a pattern's predicates are evaluated.
183
+ * @param {*} item - The node a step of the pattern tests
184
+ * @param {object} xc - XSLT context (its item is the item matched)
185
+ * @param {boolean} [local] - The pattern sees the local variables of xc
186
+ * @returns {object}
187
+ */
188
+ patternContext(item, xc, local = false) {
189
+ const dyn = Object.create(xc.tx.dyn);
190
+ dyn.xc = xc;
191
+ // no current output URI in patterns (XSLT 3.0 section 20.3.?)
192
+ dyn.dynamicCall = true;
193
+ useStaticContext(dyn, xc.tx.stylesheet.sc);
194
+ const env = local ? xc.env : xc.tx.globalEnv;
195
+ return { item, position: 1, size: 1, env, dyn };
196
+ }
197
+
198
+ /**
199
+ * The parameters of a named output definition.
200
+ * @param {string|null} name - Lexical QName, null for the unnamed one
201
+ * @param {Element} element - Element on which the name is written
202
+ * @param {object} [overrides] - Parameters that take precedence (those
203
+ * of an xsl:result-document)
204
+ * @returns {object}
205
+ */
206
+ outputFor(name, element, overrides = {}) {
207
+ let output = this.outputs.get("") ?? {};
208
+ if (name !== null) {
209
+ const qname = this.exprs.qname(name, element, { code: "XTDE1460" });
210
+ output = this.outputs.get(`{${qname.uri}}${qname.local}`);
211
+ if (!output) throw xsltError("XTDE1460", `No output definition ${name}`);
212
+ }
213
+ const params = { ...output, ...overrides };
214
+ if (params["item-separator"] === "#absent") delete params["item-separator"];
215
+ // The default html-version is implementation-defined (XSLT 3.0 section
216
+ // 26.1): HTML 4.01, as in XSLT 1.0 and 2.0, for an XSLT 1.0 or 2.0
217
+ // principal stylesheet module, else HTML5.
218
+ if (
219
+ (params.method === undefined || params.method === "html") &&
220
+ params["html-version"] === undefined &&
221
+ params.version === undefined &&
222
+ infoOf(this.tree.root).version < 3
223
+ ) {
224
+ params["html-version"] = "4.01";
225
+ }
226
+ if (params["use-character-maps"]) {
227
+ params["use-character-maps"] = expandCharacterMaps(
228
+ params["use-character-maps"],
229
+ this.characterMaps,
230
+ );
231
+ }
232
+ return params;
233
+ }
234
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * The static stage of compilation (XSLT 3.0 section 3.13): stylesheet
3
+ * modules loaded, elements kept or dropped by use-when, static variables
4
+ * and parameters evaluated in document order, shadow attributes
5
+ * replaced by their values.
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/staticStage
8
+ */
9
+
10
+ import { toSequence } from "../../xpath/eval/values.js";
11
+ import { stringItem } from "../../xpath/eval/atomics.js";
12
+ import {
13
+ attr,
14
+ clarkOf,
15
+ isXsl,
16
+ resolveQName,
17
+ setShadowAttributes,
18
+ XSL_NS,
19
+ xsltError,
20
+ } from "../names.js";
21
+ import { significantChildren } from "./children.js";
22
+ import { forgetInfo, infoOf } from "./elementInfo.js";
23
+ import {
24
+ isModuleReference,
25
+ loadModuleDocument,
26
+ preloadModule,
27
+ } from "./moduleLoading.js";
28
+ import { declareConsistently } from "./staticVariables.js";
29
+ import { evaluateStatic, evaluateStaticAvt, useWhen } from "./useWhen.js";
30
+
31
+ /**
32
+ * @param {Element} element
33
+ * @returns {boolean} whether an element declares a static variable or
34
+ * parameter
35
+ */
36
+ const isStaticDeclaration = (element) =>
37
+ (isXsl(element, "variable") || isXsl(element, "param")) &&
38
+ ["yes", "true", "1"].includes(attr(element, "static")?.trim()) &&
39
+ (isXsl(element.parentNode, "stylesheet") ||
40
+ isXsl(element.parentNode, "transform") ||
41
+ isXsl(element.parentNode, "package"));
42
+
43
+ /** Module loading and the static stage. */
44
+ export class StaticStage {
45
+ /**
46
+ * @param {object} options - See compileStylesheet: `loadStylesheet`,
47
+ * `parse`, `staticParams` (Map of Clark names to values)
48
+ */
49
+ constructor(options) {
50
+ this.options = options;
51
+ /** @type {Map<string, Array>} static variables by Clark name */
52
+ this.statics = new Map();
53
+ /** @type {Map<string, Document>} stylesheet modules by URI */
54
+ this.moduleDocuments = new Map();
55
+ this.childCache = new WeakMap();
56
+ this.includedCache = new WeakMap();
57
+ /** @type {Map<string, Document|Element>} loaded modules by URI */
58
+ this.loadedModules = new Map();
59
+ /** @type {Map<string, object>} static declarations by Clark name */
60
+ this.staticDeclarations = new Map();
61
+ /** @type {number[]} the xsl:import elements being loaded, outermost first */
62
+ this.importPath = [];
63
+ this.imports = 0;
64
+ /** @type {Set<string>} modules being loaded ahead (cycles) */
65
+ this.preloading = new Set();
66
+ // static expressions parse XML and build nodes with the XML parser
67
+ const parse = (text) => options.parse(text);
68
+ this.resources = {
69
+ xmlParser: parse,
70
+ createDocument: () => {
71
+ const document = parse("<x/>");
72
+ document.removeChild(document.documentElement);
73
+ return document;
74
+ },
75
+ };
76
+ }
77
+
78
+ /**
79
+ * @param {Element} element
80
+ * @returns {Array<Element|object>} the significant children
81
+ */
82
+ children(element) {
83
+ let children = this.childCache.get(element);
84
+ if (!children) {
85
+ children = significantChildren(element, (child) => this.included(child));
86
+ this.childCache.set(element, children);
87
+ }
88
+ return children;
89
+ }
90
+
91
+ /**
92
+ * Whether use-when keeps an element; a kept element has its shadow
93
+ * attributes evaluated, and a static declaration is evaluated.
94
+ * @param {Element} element
95
+ * @returns {boolean}
96
+ */
97
+ included(element) {
98
+ let included = this.includedCache.get(element);
99
+ if (included === undefined) {
100
+ // a shadow use-when (_use-when) is evaluated before the condition
101
+ const early = element.hasAttribute?.("_use-when");
102
+ if (early) this.applyShadows(element);
103
+ included = useWhen(element, this.statics, this.resources);
104
+ this.includedCache.set(element, included);
105
+ if (included) {
106
+ if (!early) this.applyShadows(element);
107
+ if (isStaticDeclaration(element)) this.declareStatic(element);
108
+ if (isModuleReference(element)) this.preload(element);
109
+ }
110
+ }
111
+ return included;
112
+ }
113
+
114
+ /**
115
+ * Evaluates the shadow attributes (`_name`) of an XSLT element.
116
+ * @param {Element} element
117
+ */
118
+ applyShadows(element) {
119
+ if (element.namespaceURI !== XSL_NS) return;
120
+ const values = new Map();
121
+ for (const attribute of element.attributes) {
122
+ const name = attribute.name;
123
+ if (!name.startsWith("_") || attribute.namespaceURI) continue;
124
+ const value = evaluateStaticAvt(
125
+ attribute.value,
126
+ element,
127
+ this.statics,
128
+ this.resources,
129
+ );
130
+ values.set(name.slice(1), value);
131
+ }
132
+ if (values.size > 0) {
133
+ setShadowAttributes(element, values);
134
+ forgetInfo(element);
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Evaluates a static variable or parameter.
140
+ * @param {Element} element
141
+ */
142
+ declareStatic(element) {
143
+ const name = attr(element, "name");
144
+ if (name === undefined) {
145
+ throw xsltError("XTSE0010", "A static variable needs a name");
146
+ }
147
+ if (this.children(element).length > 0) {
148
+ throw xsltError(
149
+ attr(element, "select") === undefined ? "XTSE0010" : "XTSE0620",
150
+ "A static variable has no content",
151
+ );
152
+ }
153
+ if (
154
+ isXsl(element, "param") &&
155
+ ["yes", "true", "1"].includes(attr(element, "required")?.trim()) &&
156
+ attr(element, "select") !== undefined
157
+ ) {
158
+ throw xsltError("XTSE0010", "A required static parameter has no select");
159
+ }
160
+ const key = clarkOf(resolveQName(name, infoOf(element).namespaces));
161
+ const supplied = this.options.staticParams?.get?.(key);
162
+ const select = attr(element, "select");
163
+ let value;
164
+ if (isXsl(element, "param") && supplied !== undefined) {
165
+ value = toSequence(supplied);
166
+ } else if (select !== undefined) {
167
+ value = evaluateStatic(select, element, this.statics, this.resources);
168
+ } else {
169
+ // no select, no content: "" without "as", else the empty sequence
170
+ value = attr(element, "as") === undefined ? [stringItem("")] : [];
171
+ }
172
+ declareConsistently(this, key, {
173
+ element,
174
+ value,
175
+ path: [...this.importPath],
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Loads the module of an xsl:import or xsl:include as soon as it is
181
+ * met (see moduleLoading.js).
182
+ * @param {Element} element
183
+ */
184
+ preload(element) {
185
+ preloadModule(this, element);
186
+ }
187
+
188
+ /**
189
+ * Loads an included or imported module (see moduleLoading.js).
190
+ * @param {string} uri - Absolute URI
191
+ * @param {string} [base] - Base URI it was resolved against
192
+ * @returns {Document|Element}
193
+ */
194
+ loadModule(uri, base) {
195
+ return loadModuleDocument(this, uri, base);
196
+ }
197
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Static variables declared more than once (XSLT 3.0 section 9.7): a
3
+ * declaration that comes later in stylesheet tree order than one of
4
+ * lower import precedence must be consistent with it (the same value),
5
+ * else XTSE3450; one of lower precedence than an earlier declaration is
6
+ * left out. The precedence of declarations met in tree order is told by
7
+ * their import paths: a declaration inside an import of the module of
8
+ * another has the lower precedence.
9
+ *
10
+ * @module @tradik/xslt3/xslt/compiler/staticVariables
11
+ */
12
+
13
+ import { isAtomic } from "../../xdm/atomic.js";
14
+ import { canonicalString } from "../../xdm/lexical.js";
15
+ import { xsltError } from "../names.js";
16
+
17
+ /**
18
+ * A static declaration.
19
+ * @typedef {object} StaticDeclaration
20
+ * @property {Element} element
21
+ * @property {Array} value
22
+ * @property {number[]} path - The xsl:import elements it is inside
23
+ */
24
+
25
+ /**
26
+ * @param {number[]} outer
27
+ * @param {number[]} inner
28
+ * @returns {boolean} whether `outer` is a prefix of `inner`
29
+ */
30
+ const isPrefix = (outer, inner) =>
31
+ outer.length <= inner.length && outer.every((step, i) => inner[i] === step);
32
+
33
+ /**
34
+ * Whether two declarations are consistent: the same kind (variable or
35
+ * param), type and value.
36
+ * @param {StaticDeclaration} a
37
+ * @param {StaticDeclaration} b
38
+ * @returns {boolean}
39
+ */
40
+ const consistent = (a, b) =>
41
+ a.element.localName === b.element.localName &&
42
+ a.element.getAttribute("as")?.trim() ===
43
+ b.element.getAttribute("as")?.trim() &&
44
+ sameValue(a.value, b.value);
45
+
46
+ /**
47
+ * @param {Array} a
48
+ * @param {Array} b
49
+ * @returns {boolean} whether two values are the same
50
+ */
51
+ function sameValue(a, b) {
52
+ return (
53
+ a.length === b.length &&
54
+ a.every((item, i) => {
55
+ const other = b[i];
56
+ if (!isAtomic(item) || !isAtomic(other)) return item === other;
57
+ return (
58
+ item.type === other.type &&
59
+ canonicalString(item) === canonicalString(other)
60
+ );
61
+ })
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Records a static variable, checked against an earlier declaration of
67
+ * the name.
68
+ * @param {{statics: Map, staticDeclarations: Map}} stage - The static
69
+ * stage (values and declarations by Clark name)
70
+ * @param {string} key - Clark name
71
+ * @param {StaticDeclaration} declaration
72
+ * @throws {import("../../errors.js").XPathError} XTSE3450
73
+ */
74
+ export function declareConsistently(stage, key, declaration) {
75
+ const earlier = stage.staticDeclarations.get(key);
76
+ if (earlier && earlier.element === declaration.element) return;
77
+ if (earlier && earlier.path.length !== declaration.path.length) {
78
+ // the earlier one is outside the import holding this one: it wins
79
+ if (isPrefix(earlier.path, declaration.path)) return;
80
+ }
81
+ if (
82
+ earlier &&
83
+ !isPrefix(earlier.path, declaration.path) &&
84
+ !consistent(earlier, declaration)
85
+ ) {
86
+ throw xsltError(
87
+ "XTSE3450",
88
+ `The static variable ${key} is declared with another value`,
89
+ );
90
+ }
91
+ stage.staticDeclarations.set(key, declaration);
92
+ stage.statics.set(key, declaration.value);
93
+ }