@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,111 @@
1
+ /**
2
+ * Loading of stylesheet modules for the static stage: the documents of
3
+ * xsl:import and xsl:include (cached by URI, so that a module is one tree
4
+ * however often it is referenced), loaded as soon as the reference is met
5
+ * so that the static variables of the module are in scope for what
6
+ * follows (XSLT 3.0 section 9.7).
7
+ *
8
+ * @module @tradik/xslt3/xslt/compiler/moduleLoading
9
+ */
10
+
11
+ import { resolveUri } from "../../xpath/eval/uris.js";
12
+ import { attr, isXsl, xsltError } from "../names.js";
13
+ import { infoOf, setModuleUri } from "./elementInfo.js";
14
+
15
+ /**
16
+ * An embedded stylesheet module: the element of a document whose id is
17
+ * the fragment identifier of its URI.
18
+ * @param {Document} document
19
+ * @param {string} id
20
+ * @param {string} uri - For the error message
21
+ * @returns {Element}
22
+ */
23
+ function embeddedStylesheet(document, id, uri) {
24
+ const stack = [document.documentElement];
25
+ while (stack.length > 0) {
26
+ const element = stack.pop();
27
+ if (element.getAttribute("id") === id) return element;
28
+ for (let child = element.lastChild; child; child = child.previousSibling) {
29
+ if (child.nodeType === 1) stack.push(child);
30
+ }
31
+ }
32
+ throw xsltError("XTSE0165", `No element with id ${id} in ${uri}`);
33
+ }
34
+
35
+ /**
36
+ * @param {Element} element
37
+ * @returns {boolean} whether an element is a top-level xsl:import or
38
+ * xsl:include
39
+ */
40
+ export const isModuleReference = (element) =>
41
+ (isXsl(element, "import") || isXsl(element, "include")) &&
42
+ isModuleRoot(element.parentNode);
43
+
44
+ /**
45
+ * @param {Node} node
46
+ * @returns {boolean} whether a node is the root of a stylesheet module
47
+ */
48
+ const isModuleRoot = (node) =>
49
+ isXsl(node, "stylesheet") ||
50
+ isXsl(node, "transform") ||
51
+ isXsl(node, "package");
52
+
53
+ /**
54
+ * Loads the module of an xsl:import or xsl:include as soon as it is
55
+ * met, so that its static variables are in scope for what follows
56
+ * (XSLT 3.0 section 9.7); the module tree is built later from the same
57
+ * documents (modules.js).
58
+ * @param {object} stage - The static stage
59
+ * @param {Element} element - xsl:import or xsl:include
60
+ */
61
+ export function preloadModule(stage, element) {
62
+ const href = attr(element, "href");
63
+ if (href === undefined) return;
64
+ const uri = resolveUri(href.trim(), infoOf(element).baseUri);
65
+ if (stage.preloading.has(uri)) return;
66
+ let loaded;
67
+ try {
68
+ loaded = stage.loadModule(uri, infoOf(element).baseUri);
69
+ } catch {
70
+ // reported when the module tree is built, after the checks of the
71
+ // element (modules.js)
72
+ return;
73
+ }
74
+ const root = loaded.nodeType === 9 ? loaded.documentElement : loaded;
75
+ if (!isModuleRoot(root)) return;
76
+ setModuleUri(root, uri);
77
+ stage.preloading.add(uri);
78
+ const imported = isXsl(element, "import");
79
+ if (imported) stage.importPath.push(stage.imports++);
80
+ if (stage.included(root)) stage.children(root);
81
+ if (imported) stage.importPath.pop();
82
+ stage.preloading.delete(uri);
83
+ }
84
+
85
+ /**
86
+ * Loads an included or imported module (`uri#id` for an embedded one).
87
+ * @param {object} stage - The static stage (`options`, `loadedModules`)
88
+ * @param {string} uri - Absolute URI
89
+ * @param {string} [base] - Base URI it was resolved against, passed on
90
+ * to the `loadStylesheet` option
91
+ * @returns {Document|Element}
92
+ */
93
+ export function loadModuleDocument(stage, uri, base) {
94
+ if (stage.loadedModules.has(uri)) return stage.loadedModules.get(uri);
95
+ const [location, fragment] = uri.split("#");
96
+ let document;
97
+ try {
98
+ document = stage.options.loadStylesheet?.(location, base);
99
+ } catch (error) {
100
+ throw xsltError("XTSE0165", `Cannot load ${uri}: ${error.message}`);
101
+ }
102
+ if (!document) throw xsltError("XTSE0165", `Cannot load ${uri}`);
103
+ if (typeof document === "string") {
104
+ document = stage.options.parse(document, location);
105
+ }
106
+ const module = fragment
107
+ ? embeddedStylesheet(document, fragment, uri)
108
+ : document;
109
+ stage.loadedModules.set(uri, module);
110
+ return module;
111
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Stylesheet modules (XSLT 3.0 sections 3.11 to 3.12): the principal
3
+ * module and the modules it includes and imports, loaded into a tree whose
4
+ * post-order numbering gives the import precedence of each declaration.
5
+ *
6
+ * @module @tradik/xslt3/xslt/compiler/modules
7
+ */
8
+
9
+ import { resolveUri } from "../../xpath/eval/uris.js";
10
+ import { attr, isXsl, XSL_NS, xslAttr, xsltError } from "../names.js";
11
+ import { setModuleUri } from "./elementInfo.js";
12
+ import { checkAttributes, checkEmpty, required } from "./attributes.js";
13
+
14
+ /**
15
+ * @typedef {object} ModuleNode
16
+ * @property {Element} root - xsl:stylesheet, xsl:transform or the literal
17
+ * result element of a simplified stylesheet
18
+ * @property {string|undefined} uri
19
+ * @property {boolean} simplified
20
+ * @property {ModuleNode[]} imports
21
+ * @property {Element[]} declarations - Top-level elements, includes resolved
22
+ * @property {number} [precedence]
23
+ * @property {number} [importLow] - Lowest precedence of its import tree
24
+ */
25
+
26
+ /** Roots of simplified stylesheet modules. */
27
+ const simplifiedRoots = new WeakSet();
28
+
29
+ /**
30
+ * The root element of a stylesheet module.
31
+ * @param {Document|Element} source
32
+ * @returns {{root: Element, simplified: boolean}}
33
+ */
34
+ export function moduleRoot(source, principal = false) {
35
+ const root = source.nodeType === 9 ? source.documentElement : source;
36
+ if (!root) throw xsltError("XTSE0150", "The stylesheet is empty");
37
+ if (isXsl(root, "package") && !principal) {
38
+ throw xsltError("XTSE0165", "A package cannot be included or imported");
39
+ }
40
+ if (
41
+ isXsl(root, "stylesheet") ||
42
+ isXsl(root, "transform") ||
43
+ isXsl(root, "package")
44
+ ) {
45
+ if (attr(root, "version") === undefined && !root.hasAttribute("_version")) {
46
+ throw xsltError("XTSE0010", `xsl:${root.localName} requires a version`);
47
+ }
48
+ return { root, simplified: false };
49
+ }
50
+ if (root.namespaceURI === XSL_NS) {
51
+ throw xsltError("XTSE0150", `xsl:${root.localName} is not a stylesheet`);
52
+ }
53
+ if (xslAttr(root, "version") === undefined) {
54
+ throw xsltError(
55
+ "XTSE0150",
56
+ "A simplified stylesheet needs an xsl:version attribute",
57
+ );
58
+ }
59
+ return { root, simplified: true };
60
+ }
61
+
62
+ /**
63
+ * Loads the module tree.
64
+ * @param {Document|Element} source - Principal module
65
+ * @param {string|undefined} uri - Its URI
66
+ * @param {object} cx - Stylesheet compiler: `children(element)`,
67
+ * `loadModule(uri)` (returns a Document), `moduleDocuments`
68
+ * @returns {ModuleNode}
69
+ */
70
+ export function loadModuleTree(source, uri, cx) {
71
+ const active = [];
72
+ const load = (document, moduleUri, imported = false) => {
73
+ const { root, simplified } = moduleRoot(document, active.length === 0);
74
+ if (moduleUri !== undefined) {
75
+ if (active.includes(moduleUri)) {
76
+ throw imported
77
+ ? xsltError("XTSE0210", `${moduleUri} imports itself`)
78
+ : xsltError("XTSE0180", `${moduleUri} includes itself`);
79
+ }
80
+ cx.moduleDocuments.set(moduleUri, document.ownerDocument ?? document);
81
+ }
82
+ setModuleUri(root, moduleUri);
83
+ if (!simplified) checkAttributes(root);
84
+ const node = {
85
+ root,
86
+ uri: moduleUri,
87
+ simplified,
88
+ imports: [],
89
+ declarations: [],
90
+ };
91
+ if (simplified) {
92
+ simplifiedRoots.add(root);
93
+ node.declarations.push(root);
94
+ return node;
95
+ }
96
+ if (!cx.included(root)) return node;
97
+ active.push(moduleUri);
98
+ for (const child of cx.children(root)) {
99
+ if (child.nodeType === 3) {
100
+ throw xsltError("XTSE0120", "Text is not allowed at the top level");
101
+ }
102
+ const href = () => {
103
+ checkAttributes(child);
104
+ checkEmpty(child, cx);
105
+ return resolveUri(required(child, "href"), cx.baseUriOf(child));
106
+ };
107
+ const base = cx.baseUriOf(child);
108
+ // XSLT 3.0 allows xsl:import anywhere among the declarations
109
+ if (isXsl(child, "import")) {
110
+ const target = href();
111
+ node.imports.push(load(cx.loadModule(target, base), target, true));
112
+ } else if (isXsl(child, "include")) {
113
+ const target = href();
114
+ const included = load(cx.loadModule(target, base), target);
115
+ node.imports.push(...included.imports);
116
+ node.declarations.push(...included.declarations);
117
+ } else {
118
+ node.declarations.push(child);
119
+ }
120
+ }
121
+ active.pop();
122
+ return node;
123
+ };
124
+ const tree = load(source, uri);
125
+ let counter = 0;
126
+ const number = (node) => {
127
+ const low = counter;
128
+ for (const imported of node.imports) number(imported);
129
+ node.precedence = counter++;
130
+ node.importLow = low;
131
+ };
132
+ number(tree);
133
+ return tree;
134
+ }
135
+
136
+ /**
137
+ * The declarations of a module tree with their precedence, in
138
+ * declaration order (lowest precedence first).
139
+ * @param {ModuleNode} tree
140
+ * @returns {Array<{element: Element, precedence: number, importLow: number,
141
+ * simplified: boolean}>}
142
+ */
143
+ export function declarationsOf(tree) {
144
+ const result = [];
145
+ const visit = (node) => {
146
+ for (const imported of node.imports) visit(imported);
147
+ for (const element of node.declarations) {
148
+ result.push({
149
+ element,
150
+ precedence: node.precedence,
151
+ importLow: node.importLow,
152
+ simplified: simplifiedRoots.has(element),
153
+ });
154
+ }
155
+ };
156
+ visit(tree);
157
+ return result;
158
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Declarations collected for serialization:
3
+ * xsl:output (XSLT 3.0 section 26) and xsl:character-map (26.1).
4
+ *
5
+ * @module @tradik/xslt3/xslt/compiler/outputDecl
6
+ */
7
+
8
+ import { parametersFromElement } from "../../serialize/params/fromElement.js";
9
+ import { resolveUri } from "../../xpath/eval/uris.js";
10
+ import { clarkOf, isXsl, tokens, xsltError } from "../names.js";
11
+ import { required } from "./attributes.js";
12
+
13
+ /** xsl:output attributes whose value is a list of QNames. */
14
+ const QNAME_LISTS = new Set(["cdata-section-elements", "suppress-indentation"]);
15
+
16
+ /** The serialization methods of Serialization 3.1. */
17
+ const METHODS = new Set(["xml", "html", "xhtml", "text", "json", "adaptive"]);
18
+
19
+ /**
20
+ * The method parameter: a standard method, or a QName in Clark notation.
21
+ * @param {string} value
22
+ * @param {Element} element
23
+ * @param {object} cx
24
+ * @returns {string}
25
+ * @throws {import("../../errors.js").XPathError} XTSE1570 for an unknown
26
+ * unprefixed method
27
+ */
28
+ function outputMethod(value, element, cx) {
29
+ const method = value.trim();
30
+ if (METHODS.has(method)) return method;
31
+ if (!method.includes(":")) {
32
+ throw xsltError("XTSE1570", `Unknown output method ${method}`);
33
+ }
34
+ return clarkOf(cx.exprs.qname(method, element, { code: "XTSE1570" }));
35
+ }
36
+
37
+ /**
38
+ * The parameters of the parameter-document of an xsl:output, overridden
39
+ * by its attributes (Serialization 3.1 section 3.1).
40
+ * @param {Element} element
41
+ * @param {object} cx - Stylesheet compiler (`loadModule`, `baseUriOf`)
42
+ * @returns {Record<string, *>} parameters by name, none without the
43
+ * attribute
44
+ */
45
+ function parameterDocument(element, cx) {
46
+ const href = element.getAttribute("parameter-document");
47
+ if (!href) return {};
48
+ return readParameterDocument(href, element, cx);
49
+ }
50
+
51
+ /**
52
+ * The parameters of a serialization parameter document (xsl:output and
53
+ * xsl:result-document parameter-document).
54
+ * @param {string} href - URI reference, relative to the element's base
55
+ * @param {Element} element - The element that names the document
56
+ * @param {object} cx - Stylesheet compiler (`loadModule`, `baseUriOf`)
57
+ * @returns {Record<string, *>} parameters by name
58
+ */
59
+ export function readParameterDocument(href, element, cx) {
60
+ const base = cx.baseUriOf(element);
61
+ const source = cx.loadModule(resolveUri(href.trim(), base), base);
62
+ const root = source.nodeType === 9 ? source.documentElement : source;
63
+ return parametersFromElement(root);
64
+ }
65
+
66
+ /**
67
+ * Collects the xsl:output declarations by name: the parameters of each
68
+ * name merged, higher precedence winning (XTSE1560 for a conflict at the
69
+ * same precedence).
70
+ * @param {object[]} declarations
71
+ * @param {object} cx
72
+ * @returns {Map<string, object>} parameters (spec names) by Clark name,
73
+ * "" for the unnamed output definition
74
+ */
75
+ export function collectOutputs(declarations, cx) {
76
+ const outputs = new Map();
77
+ const sources = new Map();
78
+ for (const { element, precedence } of declarations) {
79
+ const nameText = element.getAttribute("name");
80
+ const name = nameText ? clarkOf(cx.exprs.qname(nameText, element)) : "";
81
+ const params = outputs.get(name) ?? {};
82
+ const from = sources.get(name) ?? {};
83
+ const document = parameterDocument(element, cx);
84
+ for (const [key, value] of Object.entries(document)) {
85
+ if (!element.hasAttribute(key) && from[key] !== precedence) {
86
+ params[key] = value;
87
+ from[key] = precedence;
88
+ }
89
+ }
90
+ for (const attribute of element.attributes) {
91
+ const key = attribute.name;
92
+ if (
93
+ key === "name" ||
94
+ key === "parameter-document" ||
95
+ attribute.namespaceURI ||
96
+ key.startsWith("xmlns")
97
+ ) {
98
+ continue;
99
+ }
100
+ let value = attribute.value;
101
+ if (QNAME_LISTS.has(key)) {
102
+ const previous = params[key] ?? [];
103
+ const names = tokens(value).map((token) =>
104
+ clarkOf(cx.exprs.qname(token, element, { useDefault: true })),
105
+ );
106
+ params[key] = [...previous, ...names];
107
+ continue;
108
+ }
109
+ if (key === "use-character-maps") {
110
+ value = tokens(value).map((token) =>
111
+ clarkOf(cx.exprs.qname(token, element)),
112
+ );
113
+ params[key] = [...(params[key] ?? []), ...value];
114
+ continue;
115
+ }
116
+ if (key === "method") value = outputMethod(value, element, cx);
117
+ if (from[key] === precedence && params[key] !== value) {
118
+ throw xsltError(
119
+ "XTSE1560",
120
+ `Conflicting values of ${key} in xsl:output`,
121
+ );
122
+ }
123
+ if (from[key] === undefined || from[key] <= precedence) {
124
+ params[key] = value;
125
+ from[key] = precedence;
126
+ }
127
+ }
128
+ outputs.set(name, params);
129
+ sources.set(name, from);
130
+ }
131
+ return outputs;
132
+ }
133
+
134
+ /**
135
+ * Collects the character maps.
136
+ * @param {object[]} declarations
137
+ * @param {object} cx
138
+ * @returns {Map<string, {uses: string[], map: Map<string, string>}>}
139
+ */
140
+ export function collectCharacterMaps(declarations, cx) {
141
+ const maps = new Map();
142
+ for (const { element, precedence } of declarations) {
143
+ const name = clarkOf(cx.exprs.qname(required(element, "name"), element));
144
+ const current = maps.get(name);
145
+ if (current?.precedence === precedence) {
146
+ throw xsltError("XTSE1580", `Two character maps are named ${name}`);
147
+ }
148
+ const map = new Map();
149
+ for (const child of cx.children(element)) {
150
+ if (child.nodeType !== 1 || !isXsl(child, "output-character")) {
151
+ throw xsltError(
152
+ "XTSE0010",
153
+ "xsl:character-map contains xsl:output-character",
154
+ );
155
+ }
156
+ const character = child.getAttribute("character");
157
+ if ([...character].length !== 1) {
158
+ throw xsltError("XTSE0020", "character must be a single character");
159
+ }
160
+ map.set(character, child.getAttribute("string"));
161
+ }
162
+ const uses = tokens(element.getAttribute("use-character-maps") || "").map(
163
+ (token) => clarkOf(cx.exprs.qname(token, element)),
164
+ );
165
+ // declarations come lowest precedence first: a later one wins
166
+ maps.set(name, { uses, map, precedence });
167
+ }
168
+ return maps;
169
+ }
170
+
171
+ /**
172
+ * Checks the character maps that maps and output definitions use: they
173
+ * exist (XTSE1590) and do not use themselves (XTSE1600).
174
+ * @param {Map<string, object>} outputs
175
+ * @param {Map<string, object>} maps
176
+ */
177
+ export function checkCharacterMaps(outputs, maps) {
178
+ for (const name of maps.keys()) expandCharacterMaps([name], maps);
179
+ for (const output of outputs.values()) {
180
+ expandCharacterMaps(output["use-character-maps"] ?? [], maps);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Expands a list of character maps (with the maps they use) into one map.
186
+ * @param {string[]|Map<string, string>} names - Names, or a map already
187
+ * @param {Map<string, object>} maps
188
+ * @param {Set<string>} [active]
189
+ * @returns {Map<string, string>}
190
+ */
191
+ export function expandCharacterMaps(names, maps, active = new Set()) {
192
+ // a parameter document gives the character map itself
193
+ if (names instanceof Map) return names;
194
+ const result = new Map();
195
+ for (const name of names) {
196
+ const entry = maps.get(name);
197
+ if (!entry) throw xsltError("XTSE1590", `No character map ${name}`);
198
+ if (active.has(name)) {
199
+ throw xsltError("XTSE1600", `The character map ${name} uses itself`);
200
+ }
201
+ active.add(name);
202
+ for (const [c, s] of expandCharacterMaps(entry.uses, maps, active)) {
203
+ result.set(c, s);
204
+ }
205
+ active.delete(name);
206
+ for (const [c, s] of entry.map) result.set(c, s);
207
+ }
208
+ return result;
209
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Overriding declarations (XSLT 3.0 sections 3.5.3.3 and 3.5.3.4)
3
+ * compiled into the component they override, so that the references of
4
+ * the used package reach them; the overridden body is kept for the name
5
+ * xsl:original, and template rules join the used package's mode.
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/overrideLinks
8
+ */
9
+
10
+ import { callFunction } from "../runtime/functionCall.js";
11
+ import { ORIGINAL, XSL_NS, xsltError } from "../names.js";
12
+ import { declareAttributeSet } from "../instructions/attributeSets.js";
13
+ import { ExpressionCompiler } from "./expressions.js";
14
+ import { compileFunction, functionSignature } from "./globals.js";
15
+ import { LEVEL_PRECEDENCE } from "./packageTable.js";
16
+ import { declareTemplate } from "./templatesDecl.js";
17
+
18
+ /**
19
+ * Whether an overriding declaration refers to xsl:original.
20
+ * @param {Element} element
21
+ * @returns {boolean}
22
+ */
23
+ export function usesOriginal(element) {
24
+ const stack = [element];
25
+ while (stack.length > 0) {
26
+ const node = stack.pop();
27
+ for (const attribute of node.attributes) {
28
+ if (attribute.value.includes("xsl:original")) return true;
29
+ }
30
+ for (let c = node.firstChild; c; c = c.nextSibling) {
31
+ if (c.nodeType === 1) stack.push(c);
32
+ }
33
+ }
34
+ return false;
35
+ }
36
+
37
+ /**
38
+ * Compiles an overriding declaration while xsl:original names the
39
+ * overridden component.
40
+ * @param {object} cx
41
+ * @param {object} entry - `{kind, key}` of the overridden component
42
+ * @param {() => *} compile
43
+ * @returns {*} what compile returns
44
+ */
45
+ function overriding(cx, entry, compile) {
46
+ cx.overriding = entry;
47
+ try {
48
+ return compile();
49
+ } finally {
50
+ cx.overriding = null;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Compiles an overriding function into the overridden one; its
56
+ * xsl:original() calls the overridden body.
57
+ * @param {object} cx
58
+ * @param {Element} element
59
+ * @param {object} component - The overridden function
60
+ */
61
+ function overrideFunction(cx, element, component) {
62
+ const signature = functionSignature({ element }, cx);
63
+ const original = { ...component.cell };
64
+ const saved = cx.exprs;
65
+ cx.exprs = new ExpressionCompiler({
66
+ library: saved.library.extend([
67
+ {
68
+ namespace: XSL_NS,
69
+ local: "original",
70
+ params: Array(signature.arity).fill("item()*"),
71
+ returns: "item()*",
72
+ impl: (args, context) => callFunction(original, args, context),
73
+ },
74
+ ]),
75
+ decimalFormats: saved.decimalFormats,
76
+ owner: cx,
77
+ });
78
+ try {
79
+ Object.assign(component.cell, compileFunction(signature, cx));
80
+ } finally {
81
+ cx.exprs = saved;
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Compiles an overriding attribute set into the parts of the overridden
87
+ * one.
88
+ * @param {object} cx
89
+ * @param {Element} element
90
+ * @param {object} component - The overridden attribute set
91
+ */
92
+ function overrideAttributeSet(cx, element, component) {
93
+ const parts = cx.attributeSets.get(component.key);
94
+ cx.attributeSets.delete(component.key);
95
+ overriding(cx, component, () => declareAttributeSet(element, cx));
96
+ const original = [...parts];
97
+ parts.splice(0, parts.length, ...cx.attributeSets.get(component.key));
98
+ cx.attributeSets.set(component.key, parts);
99
+ cx.attributeSets.set(`${ORIGINAL}#${component.key}`, original);
100
+ }
101
+
102
+ /**
103
+ * Compiles an overriding named template into the overridden one.
104
+ * @param {object} cx
105
+ * @param {object} declaration - `{element, precedence, importLow}`
106
+ * @param {object} component - The overridden template
107
+ */
108
+ function overrideTemplate(cx, declaration, component) {
109
+ const cell = cx.namedTemplates.get(component.key);
110
+ overriding(cx, component, () => declareTemplate(declaration, cx));
111
+ const original = { ...cell };
112
+ Object.assign(cell, cx.namedTemplates.get(component.key));
113
+ cx.namedTemplates.set(component.key, cell);
114
+ cx.namedTemplates.set(`${ORIGINAL}#${component.key}`, original);
115
+ }
116
+
117
+ /**
118
+ * Compiles the overriding declarations of this package's
119
+ * xsl:use-package elements and links them (overriding variables are
120
+ * linked by their slots, see packageTable.js).
121
+ * @param {object} cx
122
+ * @param {number} level - Import precedences start at level * 1e6
123
+ */
124
+ export function linkOverrides(cx, level) {
125
+ for (const use of cx.uses) {
126
+ for (const { element, component } of use.overrides) {
127
+ if (component?.visibility === "abstract" && usesOriginal(element)) {
128
+ throw xsltError("XTSE3075", "The overridden component is abstract");
129
+ }
130
+ const precedence = level * LEVEL_PRECEDENCE + use.precedence;
131
+ const declaration = { element, precedence, importLow: precedence };
132
+ const kind = component?.kind;
133
+ if (kind === "function") overrideFunction(cx, element, component);
134
+ else if (kind === "attribute-set") {
135
+ overrideAttributeSet(cx, element, component);
136
+ } else if (kind === "template") {
137
+ overrideTemplate(cx, declaration, component);
138
+ } else if (kind === undefined) declareTemplate(declaration, cx);
139
+ }
140
+ }
141
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Checks on a whole package: modes declared when declared-modes="yes"
3
+ * (XSLT 3.0 section 3.5.4.1, XTSE3085), no abstract component left in the
4
+ * top-level package (XTSE3080), and which components can start a
5
+ * transformation (sections 2.3.3 to 2.3.5).
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/packageChecks
8
+ */
9
+
10
+ import { standardAttr, xsltError } from "../names.js";
11
+ import { matchesOf } from "./visibility.js";
12
+
13
+ const ENTRY_VISIBILITIES = new Set(["public", "final"]);
14
+
15
+ /**
16
+ * XTSE3085: with declared-modes="yes", every mode a package uses must be
17
+ * declared by xsl:mode or accepted from a used package.
18
+ * @param {object} cx - Package compiler, its templates compiled
19
+ */
20
+ export function checkDeclaredModes(cx) {
21
+ if (!cx.header.declaredModes) return;
22
+ const declared = new Set(
23
+ cx.all("mode").map(({ element }) => cx.declaredModeName(element)),
24
+ );
25
+ for (const [key, entry] of cx.table) {
26
+ if (key.startsWith("mode ")) {
27
+ declared.add(entry.key);
28
+ }
29
+ }
30
+ const used = new Set([...cx.modes.keys(), ...cx.modeRefs]);
31
+ if (standardAttr(cx.tree.root, "default-mode") !== undefined) {
32
+ used.add(cx.defaultModeOf(cx.tree.root));
33
+ }
34
+ for (const name of used) {
35
+ if (!declared.has(name)) {
36
+ throw xsltError(
37
+ "XTSE3085",
38
+ `The mode ${name || "#unnamed"} is not declared`,
39
+ );
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * XTSE3080: the top-level package has no abstract component.
46
+ * @param {object} cx - Its compiler, prepared
47
+ */
48
+ export function checkExecutable(cx) {
49
+ for (const entry of cx.table.values()) {
50
+ if (entry.visibility === "abstract") {
51
+ throw xsltError("XTSE3080", `The component ${entry.local} is abstract`);
52
+ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Whether a component of the top-level package can be the initial named
58
+ * template or function (public or final).
59
+ * @param {object} cx
60
+ * @param {string} kind - "template" or "function"
61
+ * @param {string} key - Clark name (with `#arity` for a function)
62
+ * @returns {boolean}
63
+ */
64
+ export function isEntryPoint(cx, kind, key) {
65
+ return ENTRY_VISIBILITIES.has(cx.table.get(`${kind} ${key}`)?.visibility);
66
+ }
67
+
68
+ /**
69
+ * Whether a mode can be the initial mode (section 2.3.3).
70
+ * @param {object} cx - The top-level package's compiler
71
+ * @param {string} name - Clark name, "" for the unnamed mode
72
+ * @returns {boolean}
73
+ */
74
+ export function isEligibleMode(cx, name) {
75
+ if (name === "" || name === cx.defaultModeName) return true;
76
+ if (isEntryPoint(cx, "mode", name)) return true;
77
+ if (cx.header.declaredModes || !cx.modes.has(name)) return false;
78
+ if (cx.table.has(`mode ${name}`)) return false;
79
+ // a mode used without declaration is eligible, unless xsl:expose makes
80
+ // it private (XSLT 3.0 section 3.5.3.1)
81
+ const [uri, local] = name.slice(1).split("}");
82
+ const [best] = matchesOf(cx.exposeRules ?? [], { kind: "mode", uri, local });
83
+ return !best || ENTRY_VISIBILITIES.has(best.rule.visibility);
84
+ }