@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,95 @@
1
+ /**
2
+ * What a package adds to the registries of a stylesheet (XSLT 3.0
3
+ * section 3.5): the modes accepted from used packages, the modes the
4
+ * package refers to (declared-modes), and the name xsl:original while an
5
+ * overriding declaration is compiled.
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/packageRegistry
8
+ */
9
+
10
+ import { attr, clarkOf, ORIGINAL } from "../names.js";
11
+ import { infoOf } from "./elementInfo.js";
12
+ import { CompilerRegistry } from "./registry.js";
13
+
14
+ /** Registries of a package. */
15
+ export class PackageRegistry extends CompilerRegistry {
16
+ /** @param {object} options - See compileStylesheet (and packageChain) */
17
+ constructor(options) {
18
+ super(options);
19
+ /** @type {Map<string, import("../patterns/modes.js").Mode>} */
20
+ this.acceptedModes = new Map();
21
+ /** @type {Set<string>} modes named by xsl:apply-templates */
22
+ this.modeRefs = new Set();
23
+ /** @type {object|null} the component an overriding one is compiled for */
24
+ this.overriding = null;
25
+ /** @type {string[]} names of the packages being compiled */
26
+ this.packageChain = options.packageChain ?? [];
27
+ this.uses = [];
28
+ this.table = new Map();
29
+ }
30
+
31
+ /**
32
+ * The scope of top-level declarations.
33
+ * @param {number} [original] - Index of the global that the name
34
+ * xsl:original refers to (in an overriding variable)
35
+ * @returns {{vars: object|null}}
36
+ */
37
+ globalScope(original) {
38
+ if (original === undefined) return super.globalScope();
39
+ let vars = null;
40
+ this.globalKeys.forEach((key, i) => {
41
+ vars = { key: i === original ? ORIGINAL : key, next: vars };
42
+ });
43
+ return { vars };
44
+ }
45
+
46
+ /**
47
+ * The registry key of a template or attribute set reference: the
48
+ * overridden component for xsl:original in an overriding declaration.
49
+ * @param {string} kind - "template" or "attribute-set"
50
+ * @param {string} name - Clark name
51
+ * @returns {string|null} null when the name is not xsl:original there
52
+ */
53
+ originalName(kind, name) {
54
+ if (name !== ORIGINAL || this.overriding?.kind !== kind) return null;
55
+ return `${ORIGINAL}#${this.overriding.key}`;
56
+ }
57
+
58
+ /**
59
+ * @param {Element} element - xsl:mode
60
+ * @returns {string} the Clark name of the mode it declares
61
+ */
62
+ declaredModeName(element) {
63
+ const text = attr(element, "name");
64
+ return text === undefined ? "" : clarkOf(this.exprs.qname(text, element));
65
+ }
66
+
67
+ /**
68
+ * @param {Element} element
69
+ * @returns {string} the default mode of an element
70
+ */
71
+ defaultModeOf(element) {
72
+ return infoOf(element).defaultMode;
73
+ }
74
+
75
+ /**
76
+ * A mode accepted from a used package, else one of this package.
77
+ * @param {string} name - Clark name, "" for the unnamed mode
78
+ * @returns {import("../patterns/modes.js").Mode}
79
+ */
80
+ mode(name) {
81
+ return this.acceptedModes.get(name) ?? super.mode(name);
82
+ }
83
+
84
+ /**
85
+ * Resolves the mode attribute of xsl:apply-templates, noting the mode.
86
+ * @param {string|undefined} text
87
+ * @param {Element} element
88
+ * @returns {{current: boolean, name: string}}
89
+ */
90
+ modeRef(text, element) {
91
+ const ref = super.modeRef(text, element);
92
+ if (!ref.current) this.modeRefs.add(ref.name);
93
+ return ref;
94
+ }
95
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * The components of a package (XSLT 3.0 section 3.5.3): its own
3
+ * declarations, the components accepted from used packages and the
4
+ * overriding declarations, checked for conflicts (XTSE3050, XTSE3055);
5
+ * the non-hidden ones are what a using package sees (`exports`). Global
6
+ * variables are slots of one environment shared by every package of the
7
+ * stylesheet; each package names the slots it can see.
8
+ *
9
+ * @module @tradik/xslt3/xslt/compiler/packageTable
10
+ */
11
+
12
+ import { attr, isXsl, xsltError } from "../names.js";
13
+ import { yesNo } from "./attributes.js";
14
+ import { declaredComponents, exposeComponents } from "./components.js";
15
+ import { parseVersion } from "./packageVersions.js";
16
+ import { modesOf } from "./templatesDecl.js";
17
+ import { parseVisibilityRules } from "./visibility.js";
18
+
19
+ /** Import precedences of the packages that use another one start here. */
20
+ export const LEVEL_PRECEDENCE = 1e6;
21
+
22
+ /**
23
+ * The attributes of the package: name, version, declared-modes.
24
+ * @param {Element} root - Root of the principal module
25
+ * @returns {{name: string|undefined, version: string, declaredModes:
26
+ * boolean, implicit: boolean}}
27
+ */
28
+ export function packageHeader(root) {
29
+ if (!isXsl(root, "package")) {
30
+ return {
31
+ name: undefined,
32
+ version: "1",
33
+ declaredModes: false,
34
+ implicit: true,
35
+ };
36
+ }
37
+ const version = attr(root, "package-version")?.trim() ?? "1";
38
+ if (parseVersion(version) === null) {
39
+ throw xsltError("XTSE0020", `Invalid package-version ${version}`);
40
+ }
41
+ return {
42
+ name: attr(root, "name")?.trim(),
43
+ version,
44
+ declaredModes: yesNo(root, "declared-modes", true),
45
+ implicit: false,
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Adds a component to the table of a package.
51
+ * @param {Map<string, object>} table
52
+ * @param {object} entry
53
+ * @param {string} code - Error code of a conflict
54
+ */
55
+ function enter(table, entry, code) {
56
+ const id = `${entry.kind} ${entry.key}`;
57
+ if (table.has(id)) {
58
+ throw xsltError(code, `Two components ${entry.kind} ${entry.local}`);
59
+ }
60
+ table.set(id, entry);
61
+ }
62
+
63
+ /**
64
+ * A variable slot (see the module comment).
65
+ * @param {string} name - Clark name
66
+ * @param {object} owner - Compiler of the declaration that gives its value
67
+ * @param {object} declaration - `{element, key}`
68
+ * @returns {object}
69
+ */
70
+ const slot = (name, owner, declaration) => ({
71
+ name,
72
+ owner,
73
+ declaration,
74
+ original: null,
75
+ abstract: false,
76
+ });
77
+
78
+ /**
79
+ * Builds the component table, the exports and the variable slots.
80
+ * @param {object} cx - The package's compiler after compileContext
81
+ * @param {(kind: string) => object[]} all - Declarations by kind
82
+ * @param {{signatures: Map, globals: Map, definitions: Map}} context
83
+ */
84
+ export function buildTable(cx, all, context) {
85
+ const rules = parseVisibilityRules(
86
+ all("expose").map(({ element }) => element),
87
+ cx,
88
+ {
89
+ allowed: new Set(["public", "private", "final", "abstract"]),
90
+ anyCode: "XTSE3022",
91
+ },
92
+ );
93
+ const own = declaredComponents(all, cx, context);
94
+ exposeComponents(own, rules, cx.header.implicit);
95
+ // kept for the modes used without declaration (see packageChecks.js)
96
+ cx.exposeRules = rules;
97
+ const table = new Map();
98
+ cx.ownSlots = [];
99
+ cx.globalNames = new Map();
100
+ for (const component of own) {
101
+ const entry = { ...component, owner: cx };
102
+ if (component.kind === "function") {
103
+ entry.definition = context.definitions.get(component.key);
104
+ entry.cell = cx.functionBodies.get(component.key);
105
+ } else if (component.kind === "variable") {
106
+ const declaration = context.globals.get(component.key);
107
+ entry.slot = slot(component.key, cx, declaration);
108
+ entry.slot.abstract = component.visibility === "abstract";
109
+ cx.ownSlots.push(entry.slot);
110
+ cx.globalNames.set(component.key, entry.slot);
111
+ }
112
+ enter(table, entry, "XTSE3050");
113
+ }
114
+ const overridden = new Set();
115
+ for (const use of cx.uses) {
116
+ for (const { component, visibility, override } of use.accepted) {
117
+ const entry = { ...component, visibility, override };
118
+ if (override) {
119
+ const id = `${component.kind} ${component.key}`;
120
+ if (table.has(id) && !overridden.has(id)) {
121
+ throw xsltError(
122
+ component.kind === "function" ? "XTSE0770" : "XTSE3055",
123
+ `${component.local} is declared and overridden`,
124
+ );
125
+ }
126
+ overridden.add(id);
127
+ if (component.kind === "variable") overrideSlot(cx, entry, override);
128
+ entry.owner = cx;
129
+ }
130
+ if (component.kind === "variable") {
131
+ cx.globalNames.set(entry.key, entry.slot);
132
+ }
133
+ enter(table, entry, "XTSE3050");
134
+ }
135
+ }
136
+ checkRulesInAcceptedModes(cx, all, table);
137
+ cx.table = table;
138
+ cx.exports = [...table.values()];
139
+ }
140
+
141
+ /**
142
+ * Gives a variable slot the value of its overriding declaration; the
143
+ * value it had moves to a new hidden slot, its `xsl:original`.
144
+ * @param {object} cx
145
+ * @param {object} entry - Table entry of the accepted variable
146
+ * @param {Element} element - The overriding xsl:variable or xsl:param
147
+ */
148
+ function overrideSlot(cx, entry, element) {
149
+ const target = entry.slot;
150
+ const original = slot("", target.owner, target.declaration);
151
+ original.original = target.original;
152
+ original.abstract = target.abstract;
153
+ cx.ownSlots.push(original);
154
+ target.owner = cx;
155
+ target.declaration = { element, key: entry.key };
156
+ target.original = original;
157
+ target.abstract = false;
158
+ entry.isParam = isXsl(element, "param");
159
+ }
160
+
161
+ /**
162
+ * XTSE3050: template rules outside xsl:override cannot be added to a mode
163
+ * of a used package.
164
+ * @param {object} cx
165
+ * @param {(kind: string) => object[]} all
166
+ * @param {Map<string, object>} table
167
+ */
168
+ function checkRulesInAcceptedModes(cx, all, table) {
169
+ for (const { element } of all("template")) {
170
+ if (attr(element, "match") === undefined) continue;
171
+ for (const mode of modesOf(element, cx)) {
172
+ const entry = table.get(`mode ${mode}`);
173
+ if (entry && entry.owner !== cx) {
174
+ throw xsltError(
175
+ "XTSE3050",
176
+ `The mode ${mode} belongs to a used package`,
177
+ );
178
+ }
179
+ }
180
+ }
181
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Package versions and version ranges (XSLT 3.0 section 3.5.1): parsing,
3
+ * ordering, and matching a version against the range of an
4
+ * xsl:use-package declaration.
5
+ *
6
+ * @module @tradik/xslt3/xslt/compiler/packageVersions
7
+ */
8
+
9
+ import { xsltError } from "../names.js";
10
+
11
+ /**
12
+ * Parses a package version into its portions: integers (BigInt) and an
13
+ * optional final NCName.
14
+ * @param {string} text - `NumericPart ("-" NamePart)?`
15
+ * @param {boolean} [keepZeros] - Keep trailing zero portions (prefixes)
16
+ * @returns {Array<bigint|string>|null} null when the syntax is wrong
17
+ */
18
+ export function parseVersion(text, keepZeros = false) {
19
+ const match = /^(\d+(?:\.\d+)*)(?:-(.+))?$/.exec(text.trim());
20
+ // the name part is an NCName; any name without ":" is accepted
21
+ if (!match || match[2]?.includes(":")) return null;
22
+ const portions = match[1].split(".").map(BigInt);
23
+ if (!keepZeros) {
24
+ while (portions.length > 1 && portions.at(-1) === 0n) portions.pop();
25
+ }
26
+ if (match[2] !== undefined) portions.push(match[2]);
27
+ return portions;
28
+ }
29
+
30
+ /**
31
+ * Compares two portions: integers numerically, names by code point, a
32
+ * name before an integer.
33
+ * @param {bigint|string} a
34
+ * @param {bigint|string} b
35
+ * @returns {number}
36
+ */
37
+ function comparePortion(a, b) {
38
+ const aName = typeof a === "string";
39
+ if (aName !== (typeof b === "string")) return aName ? -1 : 1;
40
+ return a < b ? -1 : a > b ? 1 : 0;
41
+ }
42
+
43
+ /**
44
+ * Compares two parsed versions.
45
+ * @param {Array<bigint|string>} a
46
+ * @param {Array<bigint|string>} b
47
+ * @returns {number} negative, zero or positive
48
+ */
49
+ export function compareVersions(a, b) {
50
+ const length = Math.min(a.length, b.length);
51
+ for (let i = 0; i < length; i++) {
52
+ const order = comparePortion(a[i], b[i]);
53
+ if (order !== 0) return order;
54
+ }
55
+ if (a.length === b.length) return 0;
56
+ // the longer one is greater when its next portion is an integer
57
+ const longer = a.length > b.length ? a : b;
58
+ const sign = typeof longer[length] === "string" ? -1 : 1;
59
+ return a.length > b.length ? sign : -sign;
60
+ }
61
+
62
+ /**
63
+ * A version or a version prefix (`1.3.*`) of a range.
64
+ * @param {string} text
65
+ * @returns {{portions: Array<bigint|string>, prefix: boolean}}
66
+ */
67
+ function parseBound(text) {
68
+ const prefix = text.endsWith(".*");
69
+ const portions = parseVersion(prefix ? text.slice(0, -2) : text, prefix);
70
+ if (!portions) throw xsltError("XTSE0020", `Invalid version ${text}`);
71
+ return { portions, prefix };
72
+ }
73
+
74
+ /**
75
+ * Whether a version is at most some version matching a bound.
76
+ * @param {Array<bigint|string>} version
77
+ * @param {{portions: Array, prefix: boolean}} bound
78
+ * @returns {boolean}
79
+ */
80
+ function atMost(version, bound) {
81
+ if (!bound.prefix) return compareVersions(version, bound.portions) <= 0;
82
+ return (
83
+ matchesPrefix(version, bound.portions) ||
84
+ compareVersions(version, bound.portions) < 0
85
+ );
86
+ }
87
+
88
+ /**
89
+ * @param {Array<bigint|string>} version
90
+ * @param {Array<bigint|string>} prefix
91
+ * @returns {boolean} whether the leading portions of the version are the
92
+ * prefix
93
+ */
94
+ function matchesPrefix(version, prefix) {
95
+ const name = typeof version.at(-1) === "string" ? [version.at(-1)] : [];
96
+ const numbers = version.slice(0, version.length - name.length);
97
+ // trailing zeros were dropped: 1.0.* matches 1
98
+ while (numbers.length < prefix.length) numbers.push(0n);
99
+ const padded = [...numbers, ...name];
100
+ return prefix.every((portion, i) => portion === padded[i]);
101
+ }
102
+
103
+ /**
104
+ * Parses a version range into a predicate.
105
+ * @param {string|undefined} text - The package-version attribute of
106
+ * xsl:use-package (absent: any version)
107
+ * @returns {(version: Array<bigint|string>) => boolean}
108
+ * @throws {import("../../errors.js").XPathError} XTSE0020 for a bad range
109
+ */
110
+ export function parseVersionRange(text) {
111
+ const range = (text ?? "*").trim();
112
+ if (range === "*") return () => true;
113
+ const tests = range.split(/\s*,\s*/).map((part) => {
114
+ const to = /^(.*?)\s*\bto\s+(\S+)$/.exec(part);
115
+ if (to) {
116
+ const upper = parseBound(to[2]);
117
+ if (to[1] === "") return (v) => atMost(v, upper);
118
+ const lower = parseBound(to[1]);
119
+ if (lower.prefix) throw xsltError("XTSE0020", `Invalid range ${part}`);
120
+ return (v) => compareVersions(v, lower.portions) >= 0 && atMost(v, upper);
121
+ }
122
+ if (part.endsWith("+")) {
123
+ const lower = parseBound(part.slice(0, -1));
124
+ return (v) => compareVersions(v, lower.portions) >= 0;
125
+ }
126
+ const bound = parseBound(part);
127
+ return bound.prefix
128
+ ? (v) => matchesPrefix(v, bound.portions)
129
+ : (v) => compareVersions(v, bound.portions) === 0;
130
+ });
131
+ return (version) => tests.some((test) => test(version));
132
+ }
133
+
134
+ /**
135
+ * Whether a package version matches a version range.
136
+ * @param {string} version - Package version (absent: "1")
137
+ * @param {string} [range] - Version range (absent: "*")
138
+ * @returns {boolean}
139
+ */
140
+ export function versionMatches(version, range) {
141
+ const parsed = parseVersion(version ?? "1");
142
+ return parsed !== null && parseVersionRange(range)(parsed);
143
+ }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * xsl:use-package (XSLT 3.0 section 3.5.2): the used package located
3
+ * through the `resolvePackage` option and compiled for this use, and the
4
+ * components it offers accepted (xsl:accept) or overridden
5
+ * (xsl:override) by the using package (section 3.5.3.2).
6
+ *
7
+ * @module @tradik/xslt3/xslt/compiler/packages
8
+ */
9
+
10
+ import { attr, isXsl, xsltError } from "../names.js";
11
+ import { acceptComponents, matchOverrides } from "./acceptance.js";
12
+ import { checkAttributes, required } from "./attributes.js";
13
+ import { parseVersionRange, versionMatches } from "./packageVersions.js";
14
+ import { checkUnmatched, parseVisibilityRules } from "./visibility.js";
15
+
16
+ const ACCEPT_VALUES = new Set([
17
+ "public",
18
+ "private",
19
+ "final",
20
+ "abstract",
21
+ "hidden",
22
+ ]);
23
+ const OVERRIDABLE = new Set([
24
+ "template",
25
+ "function",
26
+ "variable",
27
+ "param",
28
+ "attribute-set",
29
+ ]);
30
+
31
+ /**
32
+ * Locates and prepares the package of an xsl:use-package declaration.
33
+ * @param {Element} element
34
+ * @param {object} cx - The using package's compiler
35
+ * @returns {object} the prepared compiler of the used package
36
+ */
37
+ function locatePackage(element, cx) {
38
+ const name = required(element, "name").trim();
39
+ const range = attr(element, "package-version");
40
+ parseVersionRange(range);
41
+ if (cx.packageChain.includes(name)) {
42
+ throw xsltError("XTSE3005", `The package ${name} depends on itself`);
43
+ }
44
+ const found = cx.options.resolvePackage?.(name, range?.trim() ?? "*");
45
+ if (!found) throw xsltError("XTSE3000", `No package ${name} ${range ?? ""}`);
46
+ const { source, baseUri } =
47
+ typeof found === "object" && "source" in found ? found : { source: found };
48
+ const child = cx.usedPackage([...cx.packageChain, name]);
49
+ const document =
50
+ typeof source === "string" ? cx.options.parse(source, baseUri) : source;
51
+ child.prepare(document, baseUri ?? (document.documentURI || undefined));
52
+ // a package without a name takes the one it was found by
53
+ const named = child.packageName ?? name;
54
+ if (named !== name || !versionMatches(child.packageVersion, range)) {
55
+ throw xsltError("XTSE3000", `No package ${name} ${range ?? ""}`);
56
+ }
57
+ return child;
58
+ }
59
+
60
+ /**
61
+ * The xsl:accept rules and overriding declarations of an xsl:use-package.
62
+ * @param {Element} element
63
+ * @param {object} cx
64
+ * @returns {{rules: object[], overrides: Element[]}}
65
+ */
66
+ function useContent(element, cx) {
67
+ const accepts = [];
68
+ const overrides = [];
69
+ for (const child of cx.children(element)) {
70
+ if (isXsl(child, "accept")) {
71
+ checkAttributes(child);
72
+ accepts.push(child);
73
+ } else if (isXsl(child, "override")) {
74
+ checkAttributes(child);
75
+ for (const declaration of cx.children(child)) {
76
+ if (
77
+ declaration.nodeType !== 1 ||
78
+ !OVERRIDABLE.has(declaration.localName) ||
79
+ !isXsl(declaration)
80
+ ) {
81
+ throw xsltError(
82
+ "XTSE0010",
83
+ "xsl:override holds only overridable declarations",
84
+ );
85
+ }
86
+ overrides.push(declaration);
87
+ }
88
+ } else {
89
+ throw xsltError(
90
+ "XTSE0010",
91
+ "xsl:use-package holds xsl:accept and xsl:override",
92
+ );
93
+ }
94
+ }
95
+ const rules = parseVisibilityRules(accepts, cx, {
96
+ allowed: ACCEPT_VALUES,
97
+ anyCode: "XTSE3032",
98
+ });
99
+ return { rules, overrides };
100
+ }
101
+
102
+ /**
103
+ * Resolves an xsl:use-package declaration: prepares the used package and
104
+ * decides the visibility of each of its components in this package.
105
+ * @param {object} declaration - `{element, imported}`
106
+ * @param {object} cx - The using package's compiler
107
+ * @returns {object} `{element, child, accepted, overrides}`: accepted
108
+ * components `{component, visibility, override}` (hidden ones left
109
+ * out), overriding declarations `{element, symbol, component}`
110
+ */
111
+ export function usePackage(declaration, cx) {
112
+ const { element } = declaration;
113
+ if (declaration.imported) {
114
+ throw xsltError(
115
+ "XTSE3008",
116
+ "xsl:use-package cannot be in an imported module",
117
+ );
118
+ }
119
+ checkAttributes(element);
120
+ const child = locatePackage(element, cx);
121
+ const { rules, overrides } = useContent(element, cx);
122
+ const byKey = new Map(child.exports.map((c) => [`${c.kind} ${c.key}`, c]));
123
+ const { list, overridden } = matchOverrides(overrides, rules, byKey, cx);
124
+ const accepted = acceptComponents(
125
+ child.exports,
126
+ overridden,
127
+ rules,
128
+ cx.header.implicit,
129
+ );
130
+ checkUnmatched(rules, "XTSE3030");
131
+ return {
132
+ element,
133
+ child,
134
+ accepted,
135
+ overrides: list,
136
+ precedence: declaration.precedence,
137
+ };
138
+ }