@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.
- package/LICENSE.md +28 -0
- package/README.md +98 -2
- package/package.json +43 -4
- package/src/errors.js +20 -0
- package/src/functions/aggregates.js +144 -0
- package/src/functions/arraySort.js +33 -0
- package/src/functions/arrays.js +181 -0
- package/src/functions/attributeTypes.js +58 -0
- package/src/functions/baseUris.js +82 -0
- package/src/functions/collations.js +127 -0
- package/src/functions/collections.js +84 -0
- package/src/functions/context.js +83 -0
- package/src/functions/core.js +167 -0
- package/src/functions/datetime.js +203 -0
- package/src/functions/deepEqual.js +132 -0
- package/src/functions/diagnostics.js +88 -0
- package/src/functions/focus.js +34 -0
- package/src/functions/format/dateComponents.js +176 -0
- package/src/functions/format/datePicture.js +115 -0
- package/src/functions/format/decimalFormat.js +65 -0
- package/src/functions/format/digitPattern.js +145 -0
- package/src/functions/format/formatDateTime.js +204 -0
- package/src/functions/format/formatInteger.js +109 -0
- package/src/functions/format/formatNumber.js +165 -0
- package/src/functions/format/fractionFormat.js +80 -0
- package/src/functions/format/germanWords.js +89 -0
- package/src/functions/format/numberLanguages.js +41 -0
- package/src/functions/format/numberPicture.js +202 -0
- package/src/functions/format/numberWords.js +155 -0
- package/src/functions/format/place.js +74 -0
- package/src/functions/format/timezoneFormat.js +89 -0
- package/src/functions/higherOrder.js +106 -0
- package/src/functions/ids.js +127 -0
- package/src/functions/json/index.js +17 -0
- package/src/functions/json/jsonChars.js +110 -0
- package/src/functions/json/jsonParser.js +203 -0
- package/src/functions/json/jsonStrings.js +116 -0
- package/src/functions/json/jsonToXml.js +116 -0
- package/src/functions/json/parseJson.js +119 -0
- package/src/functions/json/xmlRepresentation.js +103 -0
- package/src/functions/json/xmlToJson.js +147 -0
- package/src/functions/library.js +47 -0
- package/src/functions/mapArrayEqual.js +41 -0
- package/src/functions/maps.js +152 -0
- package/src/functions/math.js +73 -0
- package/src/functions/nodePaths.js +181 -0
- package/src/functions/nodes.js +199 -0
- package/src/functions/numeric.js +148 -0
- package/src/functions/options.js +58 -0
- package/src/functions/parseIetfDate.js +104 -0
- package/src/functions/parseXml.js +77 -0
- package/src/functions/qnames.js +68 -0
- package/src/functions/random.js +128 -0
- package/src/functions/regex/analyzeString.js +144 -0
- package/src/functions/regex/charClass.js +112 -0
- package/src/functions/regex/compile.js +81 -0
- package/src/functions/regex/escapes.js +109 -0
- package/src/functions/regex/parser.js +169 -0
- package/src/functions/regex/reader.js +37 -0
- package/src/functions/regex/regexFunctions.js +140 -0
- package/src/functions/regex/translate.js +102 -0
- package/src/functions/regex/unicodeBlocks.js +194 -0
- package/src/functions/registry.js +140 -0
- package/src/functions/sequences.js +173 -0
- package/src/functions/serializeFunction.js +53 -0
- package/src/functions/signatures.js +105 -0
- package/src/functions/sort.js +102 -0
- package/src/functions/stringMatch.js +45 -0
- package/src/functions/strings.js +194 -0
- package/src/functions/stringsCore.js +66 -0
- package/src/functions/support.js +106 -0
- package/src/functions/textDecoding.js +117 -0
- package/src/functions/ucaCollation.js +127 -0
- package/src/functions/unparsedText.js +71 -0
- package/src/functions/uri.js +166 -0
- package/src/functions/xqueryModule.js +24 -0
- package/src/index.js +38 -0
- package/src/items/array.js +84 -0
- package/src/items/function.js +45 -0
- package/src/items/map.js +120 -0
- package/src/items/mapKey.js +82 -0
- package/src/serialize/index.js +129 -0
- package/src/serialize/markup/content.js +74 -0
- package/src/serialize/markup/dialect.js +178 -0
- package/src/serialize/markup/htmlData.js +70 -0
- package/src/serialize/markup/namespaces.js +145 -0
- package/src/serialize/markup/prolog.js +91 -0
- package/src/serialize/markup/writer.js +183 -0
- package/src/serialize/methods/adaptive.js +131 -0
- package/src/serialize/methods/json.js +158 -0
- package/src/serialize/methods/text.js +43 -0
- package/src/serialize/output/buffer.js +48 -0
- package/src/serialize/output/encoding.js +146 -0
- package/src/serialize/output/expander.js +204 -0
- package/src/serialize/params/fromElement.js +141 -0
- package/src/serialize/params/fromMap.js +128 -0
- package/src/serialize/params/names.js +69 -0
- package/src/serialize/params/settings.js +153 -0
- package/src/serialize/params/values.js +163 -0
- package/src/serialize/sequence.js +111 -0
- package/src/xdm/arithmetic.js +155 -0
- package/src/xdm/atomic.js +142 -0
- package/src/xdm/binary.js +92 -0
- package/src/xdm/calendar.js +71 -0
- package/src/xdm/cast.js +176 -0
- package/src/xdm/compare.js +192 -0
- package/src/xdm/datetime.js +206 -0
- package/src/xdm/decimal.js +200 -0
- package/src/xdm/duration.js +128 -0
- package/src/xdm/generalCompare.js +152 -0
- package/src/xdm/index.js +47 -0
- package/src/xdm/lexical.js +126 -0
- package/src/xdm/nodes.js +170 -0
- package/src/xdm/numeric.js +122 -0
- package/src/xdm/qname.js +65 -0
- package/src/xdm/strings.js +52 -0
- package/src/xdm/temporalArithmetic.js +180 -0
- package/src/xdm/timeline.js +68 -0
- package/src/xdm/types.js +178 -0
- package/src/xpath/eval/atomics.js +45 -0
- package/src/xpath/eval/axes.js +212 -0
- package/src/xpath/eval/calls.js +168 -0
- package/src/xpath/eval/coercion.js +146 -0
- package/src/xpath/eval/compiler.js +71 -0
- package/src/xpath/eval/constructors.js +129 -0
- package/src/xpath/eval/decimalFormats.js +93 -0
- package/src/xpath/eval/descendantMemo.js +77 -0
- package/src/xpath/eval/documentOrder.js +142 -0
- package/src/xpath/eval/domNodes.js +174 -0
- package/src/xpath/eval/dynamicCall.js +27 -0
- package/src/xpath/eval/dynamicContext.js +161 -0
- package/src/xpath/eval/flow.js +115 -0
- package/src/xpath/eval/functionItems.js +194 -0
- package/src/xpath/eval/groupedChildren.js +88 -0
- package/src/xpath/eval/inline.js +71 -0
- package/src/xpath/eval/namespaceNodes.js +90 -0
- package/src/xpath/eval/nodeTests.js +164 -0
- package/src/xpath/eval/operators.js +190 -0
- package/src/xpath/eval/paths.js +163 -0
- package/src/xpath/eval/positional.js +81 -0
- package/src/xpath/eval/predicates.js +56 -0
- package/src/xpath/eval/primary.js +99 -0
- package/src/xpath/eval/resources.js +149 -0
- package/src/xpath/eval/scope.js +108 -0
- package/src/xpath/eval/sequenceType.js +193 -0
- package/src/xpath/eval/staticContext.js +142 -0
- package/src/xpath/eval/steps.js +98 -0
- package/src/xpath/eval/subtype.js +154 -0
- package/src/xpath/eval/typeExprs.js +147 -0
- package/src/xpath/eval/typeNames.js +101 -0
- package/src/xpath/eval/uris.js +21 -0
- package/src/xpath/eval/values.js +64 -0
- package/src/xpath/index.js +217 -0
- package/src/xpath/syntax/ast.js +130 -0
- package/src/xpath/syntax/chars.js +58 -0
- package/src/xpath/syntax/constructors.js +144 -0
- package/src/xpath/syntax/expressions.js +107 -0
- package/src/xpath/syntax/index.js +44 -0
- package/src/xpath/syntax/kindTests.js +134 -0
- package/src/xpath/syntax/lexer.js +220 -0
- package/src/xpath/syntax/operators.js +111 -0
- package/src/xpath/syntax/paths.js +102 -0
- package/src/xpath/syntax/postfix.js +91 -0
- package/src/xpath/syntax/primaries.js +149 -0
- package/src/xpath/syntax/steps.js +146 -0
- package/src/xpath/syntax/syntaxError.js +31 -0
- package/src/xpath/syntax/tokenStream.js +163 -0
- package/src/xpath/syntax/typeAst.js +76 -0
- package/src/xpath/syntax/typeOperators.js +127 -0
- package/src/xpath/syntax/types.js +158 -0
- package/src/xslt/api.js +153 -0
- package/src/xslt/compiler/acceptance.js +178 -0
- package/src/xslt/compiler/accumulatorDecl.js +146 -0
- package/src/xslt/compiler/attributeValues.js +174 -0
- package/src/xslt/compiler/attributes.js +211 -0
- package/src/xslt/compiler/avt.js +103 -0
- package/src/xslt/compiler/body.js +154 -0
- package/src/xslt/compiler/children.js +105 -0
- package/src/xslt/compiler/compatibility.js +130 -0
- package/src/xslt/compiler/components.js +179 -0
- package/src/xslt/compiler/contextItem.js +95 -0
- package/src/xslt/compiler/decimalFormats.js +132 -0
- package/src/xslt/compiler/declarationKinds.js +82 -0
- package/src/xslt/compiler/elementInfo.js +246 -0
- package/src/xslt/compiler/expressions.js +175 -0
- package/src/xslt/compiler/globalContextItem.js +92 -0
- package/src/xslt/compiler/globals.js +209 -0
- package/src/xslt/compiler/linker.js +134 -0
- package/src/xslt/compiler/miscDecl.js +171 -0
- package/src/xslt/compiler/modeDecl.js +88 -0
- package/src/xslt/compiler/moduleLoading.js +111 -0
- package/src/xslt/compiler/modules.js +158 -0
- package/src/xslt/compiler/outputDecl.js +209 -0
- package/src/xslt/compiler/overrideLinks.js +141 -0
- package/src/xslt/compiler/packageChecks.js +84 -0
- package/src/xslt/compiler/packageRegistry.js +95 -0
- package/src/xslt/compiler/packageTable.js +181 -0
- package/src/xslt/compiler/packageVersions.js +143 -0
- package/src/xslt/compiler/packages.js +138 -0
- package/src/xslt/compiler/registry.js +234 -0
- package/src/xslt/compiler/staticStage.js +197 -0
- package/src/xslt/compiler/staticVariables.js +93 -0
- package/src/xslt/compiler/stylesheet.js +205 -0
- package/src/xslt/compiler/tailPosition.js +74 -0
- package/src/xslt/compiler/templatesDecl.js +180 -0
- package/src/xslt/compiler/useAccumulators.js +76 -0
- package/src/xslt/compiler/useWhen.js +94 -0
- package/src/xslt/compiler/visibility.js +160 -0
- package/src/xslt/index.js +11 -0
- package/src/xslt/instructions/analyzeString.js +137 -0
- package/src/xslt/instructions/assert.js +72 -0
- package/src/xslt/instructions/attributeSets.js +115 -0
- package/src/xslt/instructions/conditional.js +99 -0
- package/src/xslt/instructions/control.js +123 -0
- package/src/xslt/instructions/copy.js +151 -0
- package/src/xslt/instructions/elements.js +161 -0
- package/src/xslt/instructions/evaluate.js +189 -0
- package/src/xslt/instructions/fork.js +35 -0
- package/src/xslt/instructions/grouping.js +106 -0
- package/src/xslt/instructions/index.js +94 -0
- package/src/xslt/instructions/iterate.js +182 -0
- package/src/xslt/instructions/literal.js +142 -0
- package/src/xslt/instructions/maps.js +72 -0
- package/src/xslt/instructions/merge.js +190 -0
- package/src/xslt/instructions/number.js +205 -0
- package/src/xslt/instructions/output.js +102 -0
- package/src/xslt/instructions/params.js +110 -0
- package/src/xslt/instructions/resultDocument.js +143 -0
- package/src/xslt/instructions/sort.js +114 -0
- package/src/xslt/instructions/sourceDocument.js +73 -0
- package/src/xslt/instructions/templates.js +153 -0
- package/src/xslt/instructions/text.js +151 -0
- package/src/xslt/instructions/try.js +186 -0
- package/src/xslt/instructions/variables.js +119 -0
- package/src/xslt/names.js +204 -0
- package/src/xslt/patterns/axisOrigins.js +121 -0
- package/src/xslt/patterns/compile.js +151 -0
- package/src/xslt/patterns/general.js +132 -0
- package/src/xslt/patterns/grammar.js +190 -0
- package/src/xslt/patterns/modes.js +153 -0
- package/src/xslt/patterns/paths.js +130 -0
- package/src/xslt/patterns/patternChecks.js +29 -0
- package/src/xslt/patterns/steps.js +162 -0
- package/src/xslt/processor.js +178 -0
- package/src/xslt/runtime/accumulatorFunctions.js +48 -0
- package/src/xslt/runtime/accumulators.js +174 -0
- package/src/xslt/runtime/apply.js +153 -0
- package/src/xslt/runtime/atomicKeys.js +36 -0
- package/src/xslt/runtime/availability.js +162 -0
- package/src/xslt/runtime/baseUri.js +64 -0
- package/src/xslt/runtime/compilerHook.js +27 -0
- package/src/xslt/runtime/conditional.js +110 -0
- package/src/xslt/runtime/context.js +106 -0
- package/src/xslt/runtime/copy.js +123 -0
- package/src/xslt/runtime/copyFunctions.js +71 -0
- package/src/xslt/runtime/copyOrigins.js +60 -0
- package/src/xslt/runtime/defaultMethod.js +42 -0
- package/src/xslt/runtime/documentContent.js +93 -0
- package/src/xslt/runtime/dynamicXPath.js +90 -0
- package/src/xslt/runtime/functionCache.js +65 -0
- package/src/xslt/runtime/functionCall.js +57 -0
- package/src/xslt/runtime/functions.js +191 -0
- package/src/xslt/runtime/groups.js +108 -0
- package/src/xslt/runtime/invocation.js +156 -0
- package/src/xslt/runtime/iteration.js +107 -0
- package/src/xslt/runtime/keys.js +141 -0
- package/src/xslt/runtime/lazy.js +97 -0
- package/src/xslt/runtime/locations.js +86 -0
- package/src/xslt/runtime/machine.js +137 -0
- package/src/xslt/runtime/merging.js +167 -0
- package/src/xslt/runtime/namespaceScope.js +141 -0
- package/src/xslt/runtime/numberFormat.js +89 -0
- package/src/xslt/runtime/numbering.js +168 -0
- package/src/xslt/runtime/params.js +59 -0
- package/src/xslt/runtime/properties.js +103 -0
- package/src/xslt/runtime/rawResults.js +82 -0
- package/src/xslt/runtime/sequenceReceiver.js +102 -0
- package/src/xslt/runtime/snapshot.js +66 -0
- package/src/xslt/runtime/sortKeys.js +119 -0
- package/src/xslt/runtime/streamAvailable.js +60 -0
- package/src/xslt/runtime/strip.js +102 -0
- package/src/xslt/runtime/transformFunction.js +169 -0
- package/src/xslt/runtime/transformation.js +168 -0
- package/src/xslt/runtime/transformationContext.js +85 -0
- package/src/xslt/runtime/treeReceiver.js +194 -0
- 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
|
+
}
|