@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,205 @@
1
+ /**
2
+ * The stylesheet compiler: loads the modules, collects the declarations
3
+ * by kind and compiles them in dependency order (namespace aliases,
4
+ * decimal formats and function signatures before any expression; global
5
+ * names before any body), then runs the checks that need everything
6
+ * (called templates, attribute sets).
7
+ *
8
+ * @module @tradik/xslt3/xslt/compiler/stylesheet
9
+ */
10
+
11
+ import { defaultFunctionLibrary } from "../../xpath/index.js";
12
+ import { xsltFunctions } from "../runtime/functions.js";
13
+ import { declareAttributeSet } from "../instructions/attributeSets.js";
14
+ import { declareAccumulators } from "./accumulatorDecl.js";
15
+ import { declareGlobalContextItem } from "./globalContextItem.js";
16
+ import { infoOf } from "./elementInfo.js";
17
+ import { ExpressionCompiler } from "./expressions.js";
18
+ import {
19
+ collectGlobals,
20
+ compileFunction,
21
+ functionSignature,
22
+ winners,
23
+ } from "./globals.js";
24
+ import { collectDeclarations } from "./declarationKinds.js";
25
+ import { loadModuleTree } from "./modules.js";
26
+ import { collectDecimalFormats } from "./decimalFormats.js";
27
+ import {
28
+ checkCharacterMaps,
29
+ collectCharacterMaps,
30
+ collectOutputs,
31
+ } from "./outputDecl.js";
32
+ import { collectAliases, compileSpaceRules, declareKey } from "./miscDecl.js";
33
+ import { checkModeDeclarations, declareMode } from "./modeDecl.js";
34
+ import {
35
+ compileSlots,
36
+ importAccepted,
37
+ layoutGlobals,
38
+ markAbstract,
39
+ } from "./linker.js";
40
+ import { linkOverrides } from "./overrideLinks.js";
41
+ import { buildTable, packageHeader } from "./packageTable.js";
42
+ import { usePackage } from "./packages.js";
43
+ import { checkDeclaredModes, checkExecutable } from "./packageChecks.js";
44
+ import { PackageRegistry } from "./packageRegistry.js";
45
+ import { declareSimplified, declareTemplate } from "./templatesDecl.js";
46
+
47
+ /** Compiles a stylesheet; it is also the `cx` handed to every compiler. */
48
+ export class StylesheetCompiler extends PackageRegistry {
49
+ /**
50
+ * @param {Element} element
51
+ * @returns {number} the effective version of an element
52
+ */
53
+ versionOf(element) {
54
+ return infoOf(element).version;
55
+ }
56
+
57
+ /**
58
+ * @param {Element} element
59
+ * @returns {string|undefined} its base URI
60
+ */
61
+ baseUriOf(element) {
62
+ return infoOf(element).baseUri;
63
+ }
64
+
65
+ /**
66
+ * The declarations of a module tree by kind, checked.
67
+ * @param {object} tree - See modules.js
68
+ * @returns {(kind: string) => object[]} the declarations of a kind
69
+ */
70
+ collectDeclarations(tree) {
71
+ return collectDeclarations(tree, this);
72
+ }
73
+
74
+ /**
75
+ * Compiles the declarations that every expression depends on: function
76
+ * signatures, decimal formats, global variable names.
77
+ * @param {(kind: string) => object[]} all
78
+ * @returns {{signatures: Map, globals: Map, definitions: Map}}
79
+ */
80
+ compileContext(all) {
81
+ this.aliases = collectAliases(all("namespace-alias"));
82
+ const signatures = winners(
83
+ all("function").map((d) => ({
84
+ ...d,
85
+ signature: functionSignature(d, this),
86
+ })),
87
+ (d) => d.signature.key,
88
+ "XTSE0770",
89
+ );
90
+ const definitions = new Map(
91
+ [...signatures.values()].map((d) => [
92
+ d.signature.key,
93
+ this.functionDefinition(d.signature),
94
+ ]),
95
+ );
96
+ const accepted = this.uses.flatMap((use) =>
97
+ use.accepted
98
+ .filter(({ component }) => component.kind === "function")
99
+ .map(({ component }) => component.definition),
100
+ );
101
+ this.exprs = new ExpressionCompiler({
102
+ library: defaultFunctionLibrary.extend(xsltFunctions, accepted, [
103
+ ...definitions.values(),
104
+ ]),
105
+ decimalFormats: collectDecimalFormats(all("decimal-format"), this),
106
+ owner: this,
107
+ });
108
+ const globals = collectGlobals([...all("variable"), ...all("param")], this);
109
+ return { signatures, globals, definitions };
110
+ }
111
+
112
+ /**
113
+ * A compiler for a package used by this one.
114
+ * @param {string[]} chain - Names of the packages being compiled
115
+ * @returns {StylesheetCompiler}
116
+ */
117
+ usedPackage(chain) {
118
+ return new StylesheetCompiler({
119
+ ...this.options,
120
+ staticParams: new Map(),
121
+ packageChain: chain,
122
+ });
123
+ }
124
+
125
+ /**
126
+ * The first stage: modules loaded, used packages prepared, names and
127
+ * visibilities of the components known.
128
+ * @param {Document|Element} source
129
+ * @param {string|undefined} uri
130
+ */
131
+ prepare(source, uri) {
132
+ const tree = loadModuleTree(source, uri, this);
133
+ this.tree = tree;
134
+ this.header = packageHeader(tree.root);
135
+ this.packageName = this.header.name;
136
+ this.packageVersion = this.header.version;
137
+ const all = this.collectDeclarations(tree);
138
+ this.all = all;
139
+ this.exprs = new ExpressionCompiler({ library: defaultFunctionLibrary });
140
+ this.uses = all("use-package").map((d) =>
141
+ usePackage({ ...d, imported: d.precedence !== tree.precedence }, this),
142
+ );
143
+ this.level = Math.max(-1, ...this.uses.map((use) => use.child.level)) + 1;
144
+ this.context = this.compileContext(all);
145
+ buildTable(this, all, this.context);
146
+ }
147
+
148
+ /** The second stage: every declaration compiled and linked. */
149
+ finish() {
150
+ for (const use of this.uses) use.child.finish();
151
+ const { all, tree } = this;
152
+ const { signatures } = this.context;
153
+ importAccepted(this);
154
+ this.outputs = collectOutputs(all("output"), this);
155
+ this.characterMaps = collectCharacterMaps(all("character-map"), this);
156
+ checkCharacterMaps(this.outputs, this.characterMaps);
157
+ this.spaceRules = compileSpaceRules(
158
+ [...all("strip-space"), ...all("preserve-space")],
159
+ this,
160
+ );
161
+ for (const declaration of all("mode")) declareMode(declaration, this);
162
+ checkModeDeclarations(this.modes.values());
163
+ this.globals = compileSlots(this);
164
+ declareAccumulators(all, this);
165
+ declareGlobalContextItem(all("global-context-item"), this);
166
+ for (const { element } of all("attribute-set")) {
167
+ declareAttributeSet(element, this);
168
+ }
169
+ for (const declaration of all("key")) declareKey(declaration, this);
170
+ for (const declaration of all("template")) {
171
+ declareTemplate(declaration, this);
172
+ }
173
+ for (const declaration of all("simplified")) {
174
+ declareSimplified(declaration, this);
175
+ }
176
+ for (const { signature } of signatures.values()) {
177
+ Object.assign(
178
+ this.functionBodies.get(signature.key),
179
+ compileFunction(signature, this),
180
+ );
181
+ }
182
+ markAbstract(this);
183
+ linkOverrides(this, this.level);
184
+ for (const check of this.deferred) check();
185
+ checkDeclaredModes(this);
186
+ this.finishModes();
187
+ this.sc = this.exprs.staticContext(tree.root);
188
+ this.defaultModeName = infoOf(tree.root).defaultMode;
189
+ }
190
+
191
+ /**
192
+ * Compiles the stylesheet (the top-level package and the packages it
193
+ * uses).
194
+ * @param {Document|Element} source
195
+ * @param {string|undefined} uri
196
+ * @returns {StylesheetCompiler} this, with everything compiled
197
+ */
198
+ compile(source, uri) {
199
+ this.prepare(source, uri);
200
+ checkExecutable(this);
201
+ layoutGlobals(this);
202
+ this.finish();
203
+ return this;
204
+ }
205
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Tail positions (XSLT 3.0 section 7.2): xsl:break and
3
+ * xsl:next-iteration must be the last instruction of the body of the
4
+ * innermost xsl:iterate, or of an xsl:if, xsl:when, xsl:otherwise,
5
+ * xsl:try or xsl:catch that is itself in a tail position (XTSE3120).
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/tailPosition
8
+ */
9
+
10
+ import { isXsl, xsltError } from "../names.js";
11
+
12
+ /** Containers through which a tail position extends, to the element in tail position. */
13
+ const CONTAINERS = {
14
+ if: (parent) => parent,
15
+ when: (parent) => parent.parentNode,
16
+ otherwise: (parent) => parent.parentNode,
17
+ try: (parent) => parent,
18
+ catch: (parent) => parent.parentNode,
19
+ };
20
+
21
+ /**
22
+ * Whether a child is the last instruction of its parent, ignoring
23
+ * xsl:fallback (and the xsl:catch children of xsl:try).
24
+ * @param {object} child
25
+ * @param {Element} parent
26
+ * @param {object} cx - Stylesheet compiler (`children`)
27
+ * @returns {boolean}
28
+ */
29
+ function isLast(child, parent, cx) {
30
+ const children = cx.children(parent);
31
+ const index = children.indexOf(child);
32
+ return children
33
+ .slice(index + 1)
34
+ .every(
35
+ (next) =>
36
+ isXsl(next, "fallback") ||
37
+ (isXsl(parent, "try") && isXsl(next, "catch")),
38
+ );
39
+ }
40
+
41
+ /**
42
+ * Checks that an xsl:break or xsl:next-iteration is in a tail position
43
+ * of an xsl:iterate body.
44
+ * @param {Element} element
45
+ * @param {object} cx
46
+ * @throws {import("../../errors.js").XPathError} XTSE0010 outside
47
+ * xsl:iterate, XTSE3120 elsewhere than in a tail position
48
+ */
49
+ export function checkTailPosition(element, cx) {
50
+ let ancestor = element.parentNode;
51
+ while (ancestor?.nodeType === 1 && !isXsl(ancestor, "iterate")) {
52
+ ancestor = ancestor.parentNode;
53
+ }
54
+ if (ancestor?.nodeType !== 1) {
55
+ throw xsltError(
56
+ "XTSE0010",
57
+ `xsl:${element.localName} is only allowed within xsl:iterate`,
58
+ );
59
+ }
60
+ let node = element;
61
+ for (;;) {
62
+ const parent = node.parentNode;
63
+ const container = parent?.nodeType === 1 && isXsl(parent) && parent;
64
+ if (!container || !isLast(node, parent, cx)) break;
65
+ if (isXsl(parent, "iterate")) return;
66
+ const up = CONTAINERS[parent.localName];
67
+ if (!up) break;
68
+ node = up(parent);
69
+ }
70
+ throw xsltError(
71
+ "XTSE3120",
72
+ `xsl:${element.localName} must be in a tail position of xsl:iterate`,
73
+ );
74
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * xsl:template declarations (XSLT 3.0 section 6.1): named templates and
3
+ * template rules, registered in their modes.
4
+ *
5
+ * @module @tradik/xslt3/xslt/compiler/templatesDecl
6
+ */
7
+
8
+ import { compileParams } from "../instructions/params.js";
9
+ import { typeConverter } from "../instructions/variables.js";
10
+ import {
11
+ attr,
12
+ declaredName,
13
+ isXsl,
14
+ tokens,
15
+ XSL_NS,
16
+ xsltError,
17
+ } from "../names.js";
18
+ import { compilePattern } from "../patterns/compile.js";
19
+ import { splitContextItem } from "./contextItem.js";
20
+ import { compileBody } from "./body.js";
21
+ import { splitLeading } from "./children.js";
22
+ import { infoOf } from "./elementInfo.js";
23
+
24
+ /**
25
+ * Separates the leading xsl:param children of a template or function.
26
+ * @param {Array<object>} children
27
+ * @returns {{params: Element[], rest: Array<object>}}
28
+ */
29
+ export function splitParams(children) {
30
+ const { leading, rest } = splitLeading(children, "param");
31
+ if (rest.some((child) => isXsl(child, "param"))) {
32
+ throw xsltError("XTSE0010", "xsl:param must come first");
33
+ }
34
+ return { params: leading, rest };
35
+ }
36
+
37
+ /**
38
+ * The priority attribute of a template.
39
+ * @param {string|undefined} text
40
+ * @returns {number|null}
41
+ */
42
+ function parsePriority(text) {
43
+ if (text === undefined) return null;
44
+ const value = text.trim();
45
+ if (!/^[+-]?(\d+(\.\d*)?|\.\d+)$/.test(value)) {
46
+ throw xsltError("XTSE0530", `Invalid priority "${text}"`);
47
+ }
48
+ return Number(value);
49
+ }
50
+
51
+ /**
52
+ * The modes of a template rule.
53
+ * @param {Element} element
54
+ * @param {object} cx
55
+ * @returns {string[]} Clark names, "#all" for all modes
56
+ */
57
+ export function modesOf(element, cx) {
58
+ const text = attr(element, "mode");
59
+ if (text === undefined) return [infoOf(element).defaultMode];
60
+ const names = tokens(text).map((token) => {
61
+ if (token === "#all") return "#all";
62
+ if (token === "#default") return infoOf(element).defaultMode;
63
+ if (token === "#unnamed") return "";
64
+ const name = cx.exprs.qname(token, element, { syntaxCode: "XTSE0550" });
65
+ return `{${name.uri}}${name.local}`;
66
+ });
67
+ if (names.length === 0 || new Set(names).size !== names.length) {
68
+ throw xsltError("XTSE0550", "Invalid mode attribute");
69
+ }
70
+ if (names.includes("#all") && names.length > 1) {
71
+ throw xsltError("XTSE0550", "#all must be alone");
72
+ }
73
+ return names;
74
+ }
75
+
76
+ /**
77
+ * The alternatives of a union pattern as one.
78
+ * @param {object[]} alternatives
79
+ * @returns {object} an alternative matching when any of them does
80
+ */
81
+ function unionAlternative(alternatives) {
82
+ const keys = new Set(alternatives.map((alternative) => alternative.key));
83
+ return {
84
+ matches: (item, xc) => alternatives.some((a) => a.matches(item, xc)),
85
+ priority: 0.5,
86
+ key: keys.size === 1 ? alternatives[0].key : "*",
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Compiles an xsl:template and registers it.
92
+ * @param {object} declaration - `{element, precedence, importLow}`
93
+ * @param {object} cx - Stylesheet compiler
94
+ */
95
+ export function declareTemplate(declaration, cx) {
96
+ const { element, precedence, importLow } = declaration;
97
+ const match = attr(element, "match");
98
+ const nameText = attr(element, "name");
99
+ if (match === undefined) {
100
+ if (nameText === undefined) {
101
+ throw xsltError("XTSE0500", "xsl:template needs match or name");
102
+ }
103
+ if (
104
+ attr(element, "mode") !== undefined ||
105
+ attr(element, "priority") !== undefined
106
+ ) {
107
+ throw xsltError("XTSE0500", "mode and priority need a match pattern");
108
+ }
109
+ }
110
+ const contextItem = splitContextItem(cx.children(element), element, cx);
111
+ const { params: paramElements, rest } = splitParams(contextItem.rest);
112
+ const { params, scope } = compileParams(paramElements, cx, cx.globalScope());
113
+ const asText = attr(element, "as");
114
+ const template = {
115
+ params,
116
+ body: [...contextItem.steps, ...compileBody(element, cx, scope, rest)],
117
+ convert: asText
118
+ ? typeConverter(
119
+ cx.exprs.sequenceType(asText, element),
120
+ "XTTE0505",
121
+ "result of the template",
122
+ )
123
+ : null,
124
+ precedence,
125
+ importLow,
126
+ element,
127
+ };
128
+ if (nameText !== undefined) {
129
+ const name = declaredName(
130
+ cx.exprs.qname(nameText, element),
131
+ `{${XSL_NS}}initial-template`,
132
+ );
133
+ cx.addNamedTemplate(`{${name.uri}}${name.local}`, template);
134
+ }
135
+ if (match === undefined) return;
136
+ const pattern = compilePattern(match, element, cx);
137
+ const explicit = parsePriority(attr(element, "priority"));
138
+ // with a priority, a union pattern is one rule, not one per alternative
139
+ const alternatives =
140
+ explicit === null || pattern.alternatives.length === 1
141
+ ? pattern.alternatives
142
+ : [unionAlternative(pattern.alternatives)];
143
+ for (const mode of modesOf(element, cx)) {
144
+ for (const alternative of alternatives) {
145
+ cx.addRule(mode, {
146
+ template,
147
+ alternative,
148
+ priority: explicit ?? alternative.priority,
149
+ precedence,
150
+ position: cx.nextPosition(),
151
+ });
152
+ }
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Builds the template of a simplified stylesheet: a rule for "/" whose
158
+ * body is the literal result element.
159
+ * @param {object} declaration
160
+ * @param {object} cx
161
+ */
162
+ export function declareSimplified(declaration, cx) {
163
+ const { element, precedence, importLow } = declaration;
164
+ const template = {
165
+ params: [],
166
+ body: compileBody(element.parentNode, cx, cx.globalScope(), [element]),
167
+ convert: null,
168
+ precedence,
169
+ importLow,
170
+ element,
171
+ };
172
+ const pattern = compilePattern("/", element, cx);
173
+ cx.addRule("", {
174
+ template,
175
+ alternative: pattern.alternatives[0],
176
+ priority: -0.5,
177
+ precedence,
178
+ position: cx.nextPosition(),
179
+ });
180
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The use-accumulators attributes (XSLT 3.0 section 18.2.2) of xsl:mode,
3
+ * xsl:global-context-item, xsl:source-document and xsl:merge-source: the
4
+ * accumulators that apply to a tree.
5
+ *
6
+ * @module @tradik/xslt3/xslt/compiler/useAccumulators
7
+ */
8
+
9
+ import { compareCodepoints } from "../../xdm/strings.js";
10
+ import { attr, clarkOf, tokens, xsltError } from "../names.js";
11
+
12
+ /**
13
+ * The use-accumulators attributes of the xsl:mode declarations: the one
14
+ * of the highest import precedence wins.
15
+ * @param {object[]} declarations
16
+ * @param {object} cx
17
+ * @throws {import("../../errors.js").XPathError} XTSE0545 for different
18
+ * values at the same precedence
19
+ */
20
+ export function declareModeAccumulators(declarations, cx) {
21
+ const chosen = new Map();
22
+ for (const { element, precedence } of declarations) {
23
+ const text = attr(element, "use-accumulators");
24
+ if (text === undefined) continue;
25
+ const nameText = attr(element, "name");
26
+ const name =
27
+ nameText === undefined || nameText.trim() === "#unnamed"
28
+ ? ""
29
+ : clarkOf(cx.exprs.qname(nameText, element));
30
+ const accumulators = useAccumulators(text, element, cx);
31
+ const key =
32
+ accumulators === "all"
33
+ ? "#all"
34
+ : [...accumulators].sort(compareCodepoints).join();
35
+ const current = chosen.get(name);
36
+ if (current?.precedence === precedence && current.key !== key) {
37
+ current.conflict = true;
38
+ } else if (!current || current.precedence < precedence) {
39
+ chosen.set(name, { precedence, key, accumulators, conflict: false });
40
+ }
41
+ }
42
+ for (const [name, { accumulators, conflict }] of chosen) {
43
+ if (conflict) {
44
+ throw xsltError("XTSE0545", "Conflicting use-accumulators for a mode");
45
+ }
46
+ cx.mode(name).accumulators = accumulators;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Parses a use-accumulators attribute.
52
+ * @param {string} text
53
+ * @param {Element} element
54
+ * @param {object} cx
55
+ * @returns {Set<string>|"all"} Clark names of the accumulators, or all
56
+ * @throws {import("../../errors.js").XPathError} XTSE3300
57
+ */
58
+ export function useAccumulators(text, element, cx) {
59
+ const names = tokens(text);
60
+ if (names.includes("#all")) {
61
+ if (names.length > 1) {
62
+ throw xsltError("XTSE3300", "#all must be alone in use-accumulators");
63
+ }
64
+ return "all";
65
+ }
66
+ const keys = new Set();
67
+ for (const token of names) {
68
+ const name = cx.exprs.qname(token, element, { code: "XTSE3300" });
69
+ const key = clarkOf(name);
70
+ if (keys.has(key) || !cx.accumulators.has(key)) {
71
+ throw xsltError("XTSE3300", `Invalid accumulator ${token}`);
72
+ }
73
+ keys.add(key);
74
+ }
75
+ return keys;
76
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Static expressions (XSLT 3.0 section 9.7): use-when conditions, the
3
+ * values of static variables and parameters, and shadow attributes,
4
+ * evaluated at compile time in a restricted static context: the
5
+ * namespaces in scope, the static variables declared before, the
6
+ * standard functions and system-property(), function-available(),
7
+ * element-available() and type-available(); no context item.
8
+ *
9
+ * @module @tradik/xslt3/xslt/compiler/useWhen
10
+ */
11
+
12
+ import { defaultFunctionLibrary } from "../../xpath/index.js";
13
+ import { compileNode } from "../../xpath/eval/compiler.js";
14
+ import { createDynamicContext } from "../../xpath/eval/dynamicContext.js";
15
+ import { createStaticContext } from "../../xpath/eval/staticContext.js";
16
+ import { parseXPath } from "../../xpath/syntax/index.js";
17
+ import { effectiveBooleanValue } from "../../xdm/nodes.js";
18
+ import { standardAttr } from "../names.js";
19
+ import { availabilityFunctions } from "../runtime/availability.js";
20
+ import { simpleContent } from "../runtime/values.js";
21
+ import { parseAvt } from "./avt.js";
22
+ import { infoOf } from "./elementInfo.js";
23
+
24
+ const library = defaultFunctionLibrary.extend(availabilityFunctions);
25
+
26
+ /**
27
+ * Evaluates a static expression written on a stylesheet element.
28
+ * @param {string} text
29
+ * @param {Element} element
30
+ * @param {Map<string, Array>} statics - Static variables by Clark name
31
+ * @param {object} [resources] - Dynamic options: `xmlParser` and
32
+ * `createDocument`, for parse-xml(), json-to-xml() and the like
33
+ * @returns {Array} the value
34
+ */
35
+ export function evaluateStatic(text, element, statics, resources = {}) {
36
+ const info = infoOf(element);
37
+ const sc = createStaticContext(
38
+ {
39
+ namespaces: new Map(
40
+ [...info.namespaces].filter(([prefix]) => prefix !== ""),
41
+ ),
42
+ defaultElementNamespace: info.xpathDefaultNs,
43
+ baseUri: info.baseUri,
44
+ },
45
+ library,
46
+ );
47
+ sc.defaultNamespace = info.namespaces.get("") ?? "";
48
+ let vars = null;
49
+ let env = null;
50
+ for (const [key, value] of statics) {
51
+ vars = { key, next: vars };
52
+ env = { value, next: env };
53
+ }
54
+ const run = compileNode(parseXPath(text), { sc, vars });
55
+ const dyn = createDynamicContext(sc, resources, undefined);
56
+ dyn.sc = sc;
57
+ return run({ item: undefined, position: 0, size: 0, env, dyn });
58
+ }
59
+
60
+ /**
61
+ * Evaluates a static attribute value template (shadow attributes).
62
+ * @param {string} text
63
+ * @param {Element} element
64
+ * @param {Map<string, Array>} statics
65
+ * @param {object} [resources] - See {@link evaluateStatic}
66
+ * @returns {string}
67
+ */
68
+ export function evaluateStaticAvt(text, element, statics, resources) {
69
+ return parseAvt(text)
70
+ .map((part) =>
71
+ typeof part === "string"
72
+ ? part
73
+ : simpleContent(
74
+ evaluateStatic(part.expr, element, statics, resources),
75
+ " ",
76
+ ),
77
+ )
78
+ .join("");
79
+ }
80
+
81
+ /**
82
+ * Evaluates the use-when condition of an element.
83
+ * @param {Element} element
84
+ * @param {Map<string, Array>} [statics] - Static variables in scope
85
+ * @param {object} [resources] - See {@link evaluateStatic}
86
+ * @returns {boolean} true when the element is included
87
+ */
88
+ export function useWhen(element, statics = new Map(), resources = {}) {
89
+ const condition = standardAttr(element, "use-when");
90
+ if (condition === undefined) return true;
91
+ return effectiveBooleanValue(
92
+ evaluateStatic(condition, element, statics, resources),
93
+ );
94
+ }