@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,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compilation of sequence constructors (XSLT 3.0 section 5.7): each child
|
|
3
|
+
* of a template body, a literal result element or an instruction becomes
|
|
4
|
+
* a step of the body (see runtime/machine.js). Local variables extend the
|
|
5
|
+
* scope of their following siblings.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/compiler/body
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { avtEvaluator } from "../runtime/values.js";
|
|
11
|
+
import { isXsl, XSL_NS, xsltError } from "../names.js";
|
|
12
|
+
import { infoOf } from "./elementInfo.js";
|
|
13
|
+
import { instructionCompilers } from "../instructions/index.js";
|
|
14
|
+
import { compileLiteralElement } from "../instructions/literal.js";
|
|
15
|
+
import { compileLocalVariable } from "../instructions/variables.js";
|
|
16
|
+
import { checkAttributes } from "./attributes.js";
|
|
17
|
+
import { conditionalBody } from "../runtime/conditional.js";
|
|
18
|
+
import { locate, recordStep } from "../runtime/locations.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The scope of a compilation: the variables in scope (a linked list of
|
|
22
|
+
* Clark names, see xpath/eval/scope.js) and flags of the context.
|
|
23
|
+
* @typedef {object} Scope
|
|
24
|
+
* @property {{key: string, next: object}|null} vars
|
|
25
|
+
* @property {boolean} [inFunction] - In a stylesheet function
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Compiles a text child: literal text, or a text value template under
|
|
30
|
+
* expand-text="yes".
|
|
31
|
+
* @param {{nodeValue: string, parentNode: Element}} text
|
|
32
|
+
* @param {object} cx - Stylesheet compiler
|
|
33
|
+
* @param {Scope} scope
|
|
34
|
+
* @returns {Function} the step
|
|
35
|
+
*/
|
|
36
|
+
function compileText(text, cx, scope) {
|
|
37
|
+
const parent = text.parentNode;
|
|
38
|
+
const value = text.nodeValue;
|
|
39
|
+
if (infoOf(parent).expandText) {
|
|
40
|
+
const evaluator = avtEvaluator(cx.exprs.avt(value, parent, scope.vars));
|
|
41
|
+
return (xc, out) => out.text(evaluator(xc));
|
|
42
|
+
}
|
|
43
|
+
return (xc, out) => out.text(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Steps of an element whose instruction is not available: its
|
|
48
|
+
* xsl:fallback children, or a dynamic error when it has none.
|
|
49
|
+
* @param {Element} element
|
|
50
|
+
* @param {object} cx
|
|
51
|
+
* @param {Scope} scope
|
|
52
|
+
* @returns {Function|null}
|
|
53
|
+
*/
|
|
54
|
+
export function compileFallback(element, cx, scope) {
|
|
55
|
+
const fallbacks = cx
|
|
56
|
+
.children(element)
|
|
57
|
+
.filter((child) => child.nodeType === 1 && isXsl(child, "fallback"));
|
|
58
|
+
if (fallbacks.length === 0) {
|
|
59
|
+
const name = element.nodeName;
|
|
60
|
+
if (element.namespaceURI === XSL_NS) {
|
|
61
|
+
throw xsltError("XTSE0010", `Unknown XSLT element ${name}`);
|
|
62
|
+
}
|
|
63
|
+
return () => {
|
|
64
|
+
throw xsltError("XTDE1450", `The instruction ${name} is not available`);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const bodies = fallbacks.map((fallback) => compileBody(fallback, cx, scope));
|
|
68
|
+
return (xc, out, machine) => {
|
|
69
|
+
for (const body of bodies) machine.runBody(body, xc, out);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Compiles an XSLT instruction.
|
|
75
|
+
* @param {Element} element
|
|
76
|
+
* @param {object} cx
|
|
77
|
+
* @param {Scope} scope
|
|
78
|
+
* @returns {Function|null} the step, null for none
|
|
79
|
+
*/
|
|
80
|
+
function compileInstruction(element, cx, scope) {
|
|
81
|
+
const name = element.localName;
|
|
82
|
+
const compiler = instructionCompilers[name];
|
|
83
|
+
if (compiler) {
|
|
84
|
+
checkAttributes(element, cx);
|
|
85
|
+
return compiler(element, cx, scope);
|
|
86
|
+
}
|
|
87
|
+
if (name === "fallback") {
|
|
88
|
+
checkAttributes(element, cx);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (infoOf(element).version > 3) return compileFallback(element, cx, scope);
|
|
92
|
+
if (name === "include" || name === "import") {
|
|
93
|
+
throw xsltError(
|
|
94
|
+
name === "include" ? "XTSE0170" : "XTSE0190",
|
|
95
|
+
`xsl:${name} is only allowed at the top level`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
throw xsltError(
|
|
99
|
+
"XTSE0010",
|
|
100
|
+
`xsl:${name} is not allowed in a sequence constructor`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Compiles a child of a sequence constructor other than xsl:variable.
|
|
106
|
+
* @param {Node} child - Text or element
|
|
107
|
+
* @param {object} cx
|
|
108
|
+
* @param {Scope} scope
|
|
109
|
+
* @returns {Function|null} the step, null for none
|
|
110
|
+
*/
|
|
111
|
+
function compileChild(child, cx, scope) {
|
|
112
|
+
if (child.nodeType === 3) return compileText(child, cx, scope);
|
|
113
|
+
if (child.namespaceURI === XSL_NS) {
|
|
114
|
+
return compileInstruction(child, cx, scope);
|
|
115
|
+
}
|
|
116
|
+
if (infoOf(child).extension.has(child.namespaceURI)) {
|
|
117
|
+
return compileFallback(child, cx, scope);
|
|
118
|
+
}
|
|
119
|
+
return compileLiteralElement(child, cx, scope);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Compiles the children of a stylesheet element as a sequence
|
|
124
|
+
* constructor.
|
|
125
|
+
* @param {Element} parent
|
|
126
|
+
* @param {object} cx - Stylesheet compiler
|
|
127
|
+
* @param {Scope} scope
|
|
128
|
+
* @param {Node[]} [children] - The children to compile (default: all)
|
|
129
|
+
* @returns {import("../runtime/machine.js").Body}
|
|
130
|
+
*/
|
|
131
|
+
export function compileBody(parent, cx, scope, children) {
|
|
132
|
+
const body = [];
|
|
133
|
+
let current = scope;
|
|
134
|
+
for (const child of children ?? cx.children(parent)) {
|
|
135
|
+
try {
|
|
136
|
+
if (child.nodeType === 1 && isXsl(child, "variable")) {
|
|
137
|
+
checkAttributes(child, cx);
|
|
138
|
+
const compiled = compileLocalVariable(child, cx, current);
|
|
139
|
+
recordStep(compiled.step, child);
|
|
140
|
+
body.push(compiled.step);
|
|
141
|
+
current = compiled.scope;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const step = compileChild(child, cx, current);
|
|
145
|
+
recordStep(step, child);
|
|
146
|
+
if (step) body.push(step);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
throw locate(error, child);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// xsl:on-empty and xsl:on-non-empty make the whole body conditional
|
|
152
|
+
const conditional = body.some((step) => step.conditional !== undefined);
|
|
153
|
+
return conditional ? [conditionalBody(body)] : body;
|
|
154
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The children of a stylesheet element as the compiler sees them:
|
|
3
|
+
* comments and processing instructions dropped, adjacent text merged,
|
|
4
|
+
* whitespace-only text stripped (except in xsl:text and under
|
|
5
|
+
* xml:space="preserve"), and elements excluded by use-when left out
|
|
6
|
+
* (XSLT 3.0 sections 3.13.1 and 4.2).
|
|
7
|
+
*
|
|
8
|
+
* @module @tradik/xslt3/xslt/compiler/children
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { isXsl, XML_NS, XSL_NS } from "../names.js";
|
|
12
|
+
|
|
13
|
+
const WHITESPACE = /^[ \t\r\n]*$/;
|
|
14
|
+
|
|
15
|
+
/** XSLT elements whose content has no text: whitespace there is ignored. */
|
|
16
|
+
const ELEMENT_ONLY = new Set([
|
|
17
|
+
"stylesheet",
|
|
18
|
+
"transform",
|
|
19
|
+
"package",
|
|
20
|
+
"use-package",
|
|
21
|
+
"override",
|
|
22
|
+
"apply-templates",
|
|
23
|
+
"apply-imports",
|
|
24
|
+
"next-match",
|
|
25
|
+
"call-template",
|
|
26
|
+
"choose",
|
|
27
|
+
"attribute-set",
|
|
28
|
+
"character-map",
|
|
29
|
+
"analyze-string",
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {object} node
|
|
34
|
+
* @returns {boolean} whether a child is whitespace-only text
|
|
35
|
+
*/
|
|
36
|
+
export const isWhitespaceText = (node) =>
|
|
37
|
+
node.nodeType === 3 && WHITESPACE.test(node.nodeValue);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Splits leading children of one XSLT kind (xsl:param, xsl:sort) from the
|
|
41
|
+
* rest, ignoring whitespace text between them.
|
|
42
|
+
* @param {Array<object>} children
|
|
43
|
+
* @param {string} local - Local name of the leading elements
|
|
44
|
+
* @returns {{leading: Element[], rest: Array<object>}}
|
|
45
|
+
*/
|
|
46
|
+
export function splitLeading(children, local) {
|
|
47
|
+
const leading = [];
|
|
48
|
+
let end = 0;
|
|
49
|
+
for (let i = 0; i < children.length; i++) {
|
|
50
|
+
if (isXsl(children[i], local)) {
|
|
51
|
+
leading.push(children[i]);
|
|
52
|
+
end = i + 1;
|
|
53
|
+
} else if (!isWhitespaceText(children[i])) break;
|
|
54
|
+
}
|
|
55
|
+
return { leading, rest: children.slice(end) };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {Element} element
|
|
60
|
+
* @returns {boolean} whether xml:space="preserve" applies to the children
|
|
61
|
+
*/
|
|
62
|
+
function preservesSpace(element) {
|
|
63
|
+
for (let e = element; e && e.nodeType === 1; e = e.parentNode) {
|
|
64
|
+
const space = e.getAttributeNS(XML_NS, "space");
|
|
65
|
+
if (space) return space === "preserve";
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A text child of a stylesheet element: `{nodeType: 3, nodeValue}`.
|
|
72
|
+
* @typedef {{nodeType: 3, nodeValue: string, parentNode: Element}} TextChild
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The significant children of a stylesheet element.
|
|
77
|
+
* @param {Element} element
|
|
78
|
+
* @param {(element: Element) => boolean} included - Whether an element
|
|
79
|
+
* passes its use-when condition
|
|
80
|
+
* @returns {Array<Element|TextChild>} elements and texts
|
|
81
|
+
*/
|
|
82
|
+
export function significantChildren(element, included) {
|
|
83
|
+
const elementOnly =
|
|
84
|
+
element.namespaceURI === XSL_NS && ELEMENT_ONLY.has(element.localName);
|
|
85
|
+
const keepSpace =
|
|
86
|
+
isXsl(element, "text") || (!elementOnly && preservesSpace(element));
|
|
87
|
+
const result = [];
|
|
88
|
+
let text = null;
|
|
89
|
+
const flush = () => {
|
|
90
|
+
if (text !== null && (keepSpace || !WHITESPACE.test(text))) {
|
|
91
|
+
result.push({ nodeType: 3, nodeValue: text, parentNode: element });
|
|
92
|
+
}
|
|
93
|
+
text = null;
|
|
94
|
+
};
|
|
95
|
+
for (let child = element.firstChild; child; child = child.nextSibling) {
|
|
96
|
+
const type = child.nodeType;
|
|
97
|
+
if (type === 3 || type === 4) text = (text ?? "") + child.nodeValue;
|
|
98
|
+
else if (type === 1) {
|
|
99
|
+
flush();
|
|
100
|
+
if (included(child)) result.push(child);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
flush();
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatible signatures of an overriding and an overridden component
|
|
3
|
+
* (XSLT 3.0 section 3.5.3.3, XTSE3070): identical declared types of
|
|
4
|
+
* functions, variables and templates, and the template parameters an
|
|
5
|
+
* overriding template must keep.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/compiler/compatibility
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { attr, clarkOf, isXsl, xsltError } from "../names.js";
|
|
11
|
+
import { yesNo } from "./attributes.js";
|
|
12
|
+
import { infoOf } from "./elementInfo.js";
|
|
13
|
+
|
|
14
|
+
const QNAME = /([\p{L}_][\p{L}\p{N}_.-]*):([\p{L}_][\p{L}\p{N}_.-]*)/gu;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A declared type in a form that compares equal for identical types
|
|
18
|
+
* written with different prefixes or spacing.
|
|
19
|
+
* @param {Element} element - Declaration with the `as` attribute
|
|
20
|
+
* @returns {string}
|
|
21
|
+
*/
|
|
22
|
+
function typeOf(element) {
|
|
23
|
+
const namespaces = infoOf(element).namespaces;
|
|
24
|
+
return (attr(element, "as") ?? "item()*")
|
|
25
|
+
.replace(/\s+/g, "")
|
|
26
|
+
.replace(QNAME, (name, prefix, local) =>
|
|
27
|
+
namespaces.has(prefix) ? `Q{${namespaces.get(prefix)}}${local}` : name,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The xsl:param children of a template or function.
|
|
33
|
+
* @param {Element} element
|
|
34
|
+
* @param {object} cx
|
|
35
|
+
* @returns {Array<{key: string, type: string, required: boolean, tunnel:
|
|
36
|
+
* boolean}>}
|
|
37
|
+
*/
|
|
38
|
+
function paramsOf(element, cx) {
|
|
39
|
+
return cx
|
|
40
|
+
.children(element)
|
|
41
|
+
.filter((child) => isXsl(child, "param"))
|
|
42
|
+
.map((param) => ({
|
|
43
|
+
key: clarkOf(cx.exprs.qname(attr(param, "name"), param)),
|
|
44
|
+
type: typeOf(param),
|
|
45
|
+
required: yesNo(param, "required", false),
|
|
46
|
+
tunnel: yesNo(param, "tunnel", false),
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The xsl:context-item declaration of a template, as `use|type`.
|
|
52
|
+
* @param {Element} element
|
|
53
|
+
* @param {object} cx
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
function contextItemOf(element, cx) {
|
|
57
|
+
const item = cx.children(element).find((c) => isXsl(c, "context-item"));
|
|
58
|
+
if (!item) return "optional|item()";
|
|
59
|
+
const type = attr(item, "as") === undefined ? "item()" : typeOf(item);
|
|
60
|
+
return `${attr(item, "use")?.trim() ?? "optional"}|${type}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Whether an overriding template keeps the interface of the overridden
|
|
65
|
+
* one.
|
|
66
|
+
* @param {Element} overriding
|
|
67
|
+
* @param {Element} overridden
|
|
68
|
+
* @param {object} cx
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
function templatesCompatible(overriding, overridden, cx) {
|
|
72
|
+
const mine = new Map(paramsOf(overriding, cx).map((p) => [p.key, p]));
|
|
73
|
+
const theirs = paramsOf(overridden, cx);
|
|
74
|
+
for (const param of theirs) {
|
|
75
|
+
const other = mine.get(param.key);
|
|
76
|
+
if (param.tunnel) {
|
|
77
|
+
if (other && (!other.tunnel || other.type !== param.type)) return false;
|
|
78
|
+
} else if (
|
|
79
|
+
!other ||
|
|
80
|
+
other.tunnel ||
|
|
81
|
+
other.type !== param.type ||
|
|
82
|
+
other.required !== param.required
|
|
83
|
+
) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const known = new Set(theirs.map((p) => p.key));
|
|
88
|
+
return (
|
|
89
|
+
contextItemOf(overriding, cx) === contextItemOf(overridden, cx) &&
|
|
90
|
+
[...mine.values()].every((p) => known.has(p.key) || !p.required)
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {Element} element - xsl:function
|
|
96
|
+
* @returns {string} its new-each-time value
|
|
97
|
+
*/
|
|
98
|
+
const newEachTime = (element) =>
|
|
99
|
+
({ true: "yes", 1: "yes", false: "no", 0: "no" })[
|
|
100
|
+
attr(element, "new-each-time")?.trim()
|
|
101
|
+
] ??
|
|
102
|
+
attr(element, "new-each-time")?.trim() ??
|
|
103
|
+
"maybe";
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* XTSE3070: checks that an overriding declaration is compatible with the
|
|
107
|
+
* component it overrides.
|
|
108
|
+
* @param {Element} overriding
|
|
109
|
+
* @param {object} component - The overridden component (`kind`, `element`)
|
|
110
|
+
* @param {object} cx - The using package's compiler
|
|
111
|
+
*/
|
|
112
|
+
export function checkCompatible(overriding, component, cx) {
|
|
113
|
+
const overridden = component.element;
|
|
114
|
+
let compatible = typeOf(overriding) === typeOf(overridden);
|
|
115
|
+
if (component.kind === "function") {
|
|
116
|
+
const mine = paramsOf(overriding, cx).map((p) => p.type);
|
|
117
|
+
const theirs = paramsOf(overridden, cx).map((p) => p.type);
|
|
118
|
+
compatible &&=
|
|
119
|
+
mine.every((type, i) => type === theirs[i]) &&
|
|
120
|
+
newEachTime(overriding) === newEachTime(overridden);
|
|
121
|
+
} else if (component.kind === "template") {
|
|
122
|
+
compatible &&= templatesCompatible(overriding, overridden, cx);
|
|
123
|
+
}
|
|
124
|
+
if (!compatible) {
|
|
125
|
+
throw xsltError(
|
|
126
|
+
"XTSE3070",
|
|
127
|
+
`The override of ${component.local} is incompatible`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The named components a package declares (XSLT 3.0 section 3.5.3):
|
|
3
|
+
* named templates, functions, global variables and parameters,
|
|
4
|
+
* attribute sets and named modes, with their visibility from the
|
|
5
|
+
* visibility attribute and the xsl:expose declarations.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/compiler/components
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { attr, clarkOf, isXsl, xsltError } from "../names.js";
|
|
11
|
+
import { required } from "./attributes.js";
|
|
12
|
+
import { checkUnmatched, EXPLICIT, matchesOf } from "./visibility.js";
|
|
13
|
+
|
|
14
|
+
const DECLARED = new Set(["public", "private", "final", "abstract"]);
|
|
15
|
+
const MODE_DECLARED = new Set(["public", "private", "final"]);
|
|
16
|
+
|
|
17
|
+
/** Declared visibilities each explicitly exposed visibility allows. */
|
|
18
|
+
const EXPOSABLE = {
|
|
19
|
+
public: ["public"],
|
|
20
|
+
private: ["public", "private", "final"],
|
|
21
|
+
final: ["public", "final"],
|
|
22
|
+
abstract: ["abstract"],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The visibility attribute of a declaration.
|
|
27
|
+
* @param {Element} element
|
|
28
|
+
* @param {string} kind - Component kind
|
|
29
|
+
* @returns {string|null} null when absent
|
|
30
|
+
*/
|
|
31
|
+
export function declaredVisibility(element, kind) {
|
|
32
|
+
const text = attr(element, "visibility");
|
|
33
|
+
if (text === undefined) return null;
|
|
34
|
+
const value = text.trim();
|
|
35
|
+
if (!(kind === "mode" ? MODE_DECLARED : DECLARED).has(value)) {
|
|
36
|
+
throw xsltError("XTSE0020", `Invalid visibility ${text}`);
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The visibility of a component declared in a package.
|
|
43
|
+
* @param {object} component - `{kind, uri, local, arity, declared, isParam}`
|
|
44
|
+
* @param {object[]} rules - Parsed xsl:expose rules
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function exposedVisibility(component, rules) {
|
|
48
|
+
if (component.isParam) return "public";
|
|
49
|
+
const [best] = matchesOf(rules, component);
|
|
50
|
+
const { declared } = component;
|
|
51
|
+
let visibility = declared ?? best?.rule.visibility ?? "private";
|
|
52
|
+
if (best?.precision === EXPLICIT) {
|
|
53
|
+
visibility = best.rule.visibility;
|
|
54
|
+
if (declared && !EXPOSABLE[visibility].includes(declared)) {
|
|
55
|
+
throw xsltError(
|
|
56
|
+
"XTSE3010",
|
|
57
|
+
`xsl:expose makes the ${declared} ${component.kind} ${component.local} ${visibility}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (visibility === "abstract" && declared !== "abstract") {
|
|
62
|
+
throw xsltError(
|
|
63
|
+
"XTSE3025",
|
|
64
|
+
`xsl:expose cannot make ${component.local} abstract`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return visibility;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A component descriptor.
|
|
72
|
+
* @param {string} kind
|
|
73
|
+
* @param {{uri: string, local: string}} name
|
|
74
|
+
* @param {Element} element - Declaration
|
|
75
|
+
* @param {object} [extra] - `arity`, `isParam`
|
|
76
|
+
* @returns {object}
|
|
77
|
+
*/
|
|
78
|
+
function component(kind, name, element, extra = {}) {
|
|
79
|
+
const key = clarkOf(name);
|
|
80
|
+
return {
|
|
81
|
+
kind,
|
|
82
|
+
uri: name.uri,
|
|
83
|
+
local: name.local,
|
|
84
|
+
arity: extra.arity ?? null,
|
|
85
|
+
isParam: extra.isParam ?? false,
|
|
86
|
+
key: extra.arity === undefined ? key : `${key}#${extra.arity}`,
|
|
87
|
+
element,
|
|
88
|
+
declared: extra.isParam ? null : declaredVisibility(element, kind),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The named components declared in a package (the declarations of
|
|
94
|
+
* highest import precedence).
|
|
95
|
+
* @param {(kind: string) => object[]} all - Declarations by kind
|
|
96
|
+
* @param {object} cx - Stylesheet compiler (after compileContext)
|
|
97
|
+
* @param {{signatures: Map, globals: Map}} context - From compileContext
|
|
98
|
+
* @returns {object[]} components `{kind, uri, local, arity, key, element,
|
|
99
|
+
* declared, isParam}`
|
|
100
|
+
*/
|
|
101
|
+
export function declaredComponents(all, cx, { signatures, globals }) {
|
|
102
|
+
const qname = (element) => cx.exprs.qname(attr(element, "name"), element);
|
|
103
|
+
// the named templates of highest precedence (XTSE0660 is raised when
|
|
104
|
+
// they are compiled)
|
|
105
|
+
const named = (declarations) => {
|
|
106
|
+
const chosen = new Map();
|
|
107
|
+
for (const declaration of declarations) {
|
|
108
|
+
if (attr(declaration.element, "name") === undefined) continue;
|
|
109
|
+
const key = clarkOf(qname(declaration.element));
|
|
110
|
+
if (!(chosen.get(key)?.precedence > declaration.precedence)) {
|
|
111
|
+
chosen.set(key, declaration);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return chosen;
|
|
115
|
+
};
|
|
116
|
+
for (const { element } of all("template")) {
|
|
117
|
+
if (attr(element, "name") === undefined && attr(element, "visibility")) {
|
|
118
|
+
throw xsltError("XTSE0500", "A template rule has no visibility");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const list = [];
|
|
122
|
+
for (const { element } of named(all("template")).values()) {
|
|
123
|
+
list.push(component("template", qname(element), element));
|
|
124
|
+
}
|
|
125
|
+
for (const { signature } of signatures.values()) {
|
|
126
|
+
const { element } = signature.declaration;
|
|
127
|
+
list.push(
|
|
128
|
+
component("function", signature, element, { arity: signature.arity }),
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
for (const { element } of globals.values()) {
|
|
132
|
+
const isParam = isXsl(element, "param");
|
|
133
|
+
list.push(component("variable", qname(element), element, { isParam }));
|
|
134
|
+
}
|
|
135
|
+
// attribute sets and modes may be declared several times
|
|
136
|
+
const byName = new Map();
|
|
137
|
+
for (const { element } of all("attribute-set")) {
|
|
138
|
+
const name = cx.exprs.qname(required(element, "name"), element);
|
|
139
|
+
byName.set(`a${clarkOf(name)}`, component("attribute-set", name, element));
|
|
140
|
+
}
|
|
141
|
+
for (const { element } of all("mode")) {
|
|
142
|
+
if (attr(element, "name") === undefined) {
|
|
143
|
+
if (
|
|
144
|
+
!["private", undefined].includes(attr(element, "visibility")?.trim())
|
|
145
|
+
) {
|
|
146
|
+
throw xsltError("XTSE0020", "The unnamed mode is always private");
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const name = qname(element);
|
|
151
|
+
const mode = component("mode", name, element);
|
|
152
|
+
// several xsl:mode declarations: the one with a visibility counts
|
|
153
|
+
if (mode.declared || !byName.has(`m${clarkOf(name)}`)) {
|
|
154
|
+
byName.set(`m${clarkOf(name)}`, mode);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return [...list, ...byName.values()];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Gives the declared components their visibility.
|
|
162
|
+
* @param {object[]} components - From {@link declaredComponents}
|
|
163
|
+
* @param {object[]} rules - Parsed xsl:expose rules
|
|
164
|
+
* @param {boolean} implicit - An implicit package (xsl:stylesheet): its
|
|
165
|
+
* named templates and modes are public unless declared otherwise
|
|
166
|
+
*/
|
|
167
|
+
export function exposeComponents(components, rules, implicit) {
|
|
168
|
+
for (const item of components) {
|
|
169
|
+
item.visibility = exposedVisibility(item, rules);
|
|
170
|
+
if (
|
|
171
|
+
implicit &&
|
|
172
|
+
!item.declared &&
|
|
173
|
+
["template", "mode"].includes(item.kind)
|
|
174
|
+
) {
|
|
175
|
+
item.visibility = "public";
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
checkUnmatched(rules, "XTSE3020");
|
|
179
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:context-item (XSLT 3.0 section 10.1.1): the context item a
|
|
3
|
+
* template requires (use="required", XTTE3090 when absent), accepts
|
|
4
|
+
* (optional) or ignores (absent: the template runs with an absent
|
|
5
|
+
* focus), and its type (XTTE0590 when it does not match; no conversion).
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/compiler/contextItem
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { matchesSequenceType } from "../../xpath/eval/sequenceType.js";
|
|
11
|
+
import { derive } from "../runtime/context.js";
|
|
12
|
+
import { attr, isXsl, xsltError } from "../names.js";
|
|
13
|
+
import { checkAttributes } from "./attributes.js";
|
|
14
|
+
import { isWhitespaceText } from "./children.js";
|
|
15
|
+
|
|
16
|
+
/** Values of the use attribute. */
|
|
17
|
+
const USES = new Set(["required", "optional", "absent"]);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compiles the type of an `as` attribute that must be an item type.
|
|
21
|
+
* @param {Element} element
|
|
22
|
+
* @param {object} cx
|
|
23
|
+
* @returns {object|null} a sequence type of exactly one item
|
|
24
|
+
*/
|
|
25
|
+
function itemType(element, cx) {
|
|
26
|
+
const text = attr(element, "as");
|
|
27
|
+
if (text === undefined) return null;
|
|
28
|
+
const type = cx.exprs.sequenceType(text, element);
|
|
29
|
+
if (type.occurrence !== "" || type.itemType === null) {
|
|
30
|
+
throw xsltError("XTSE0020", `"${text}" is not an item type`);
|
|
31
|
+
}
|
|
32
|
+
return type;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The step that checks the context item of a template.
|
|
37
|
+
* @param {Element} element - xsl:context-item
|
|
38
|
+
* @param {boolean} named - The template has a name
|
|
39
|
+
* @param {object} cx
|
|
40
|
+
* @returns {{binding: Function}}
|
|
41
|
+
*/
|
|
42
|
+
function compileCheck(element, named, cx) {
|
|
43
|
+
checkAttributes(element);
|
|
44
|
+
const use = (attr(element, "use") ?? "optional").trim();
|
|
45
|
+
if (!USES.has(use)) throw xsltError("XTSE0020", `Invalid use "${use}"`);
|
|
46
|
+
if (use === "absent" && attr(element, "as") !== undefined) {
|
|
47
|
+
throw xsltError("XTSE3088", 'use="absent" cannot have a type');
|
|
48
|
+
}
|
|
49
|
+
if (!named && use !== "required") {
|
|
50
|
+
throw xsltError("XTSE0020", "A template rule requires its context item");
|
|
51
|
+
}
|
|
52
|
+
const type = itemType(element, cx);
|
|
53
|
+
return {
|
|
54
|
+
binding(xc) {
|
|
55
|
+
if (use === "absent") {
|
|
56
|
+
// no focus, hence no current template rule either (XTDE0560)
|
|
57
|
+
return derive(xc, {
|
|
58
|
+
item: undefined,
|
|
59
|
+
position: 0,
|
|
60
|
+
size: 0,
|
|
61
|
+
rule: null,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (xc.item === undefined) {
|
|
65
|
+
if (use === "required") {
|
|
66
|
+
throw xsltError("XTTE3090", "The template requires a context item");
|
|
67
|
+
}
|
|
68
|
+
} else if (type && !matchesSequenceType([xc.item], type)) {
|
|
69
|
+
throw xsltError("XTTE0590", "The context item has the wrong type");
|
|
70
|
+
}
|
|
71
|
+
return xc;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Separates the xsl:context-item of a template from its other children.
|
|
78
|
+
* @param {Array<object>} children - Significant children of the template
|
|
79
|
+
* @param {Element} template
|
|
80
|
+
* @param {object} cx
|
|
81
|
+
* @returns {{rest: Array<object>, steps: Array}} the other children, and
|
|
82
|
+
* the step that checks the context item (to run first)
|
|
83
|
+
*/
|
|
84
|
+
export function splitContextItem(children, template, cx) {
|
|
85
|
+
const index = children.findIndex((child) => !isWhitespaceText(child));
|
|
86
|
+
const first = children[index];
|
|
87
|
+
const declared = first !== undefined && isXsl(first, "context-item");
|
|
88
|
+
const rest = declared ? children.slice(index + 1) : children;
|
|
89
|
+
if (rest.some((child) => isXsl(child, "context-item"))) {
|
|
90
|
+
throw xsltError("XTSE0010", "xsl:context-item must be the first child");
|
|
91
|
+
}
|
|
92
|
+
if (!declared) return { rest, steps: [] };
|
|
93
|
+
const named = attr(template, "name") !== undefined;
|
|
94
|
+
return { rest, steps: [compileCheck(first, named, cx)] };
|
|
95
|
+
}
|