@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,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
|
+
}
|