@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,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path patterns: the steps checked against the pattern grammar, then
|
|
3
|
+
* matched from the last step upwards: the last step is tested on the
|
|
4
|
+
* node, each `/` moves to the parent and each `//` to some ancestor,
|
|
5
|
+
* until the first step; an absolute pattern requires a document node
|
|
6
|
+
* above it.
|
|
7
|
+
*
|
|
8
|
+
* @module @tradik/xslt3/xslt/patterns/paths
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { parentOf } from "../../xpath/eval/domNodes.js";
|
|
12
|
+
import { compileGeneralPath } from "./general.js";
|
|
13
|
+
import { compileStep, stepPriority, stepKey } from "./steps.js";
|
|
14
|
+
|
|
15
|
+
/** Functions allowed as the first step of a path pattern. */
|
|
16
|
+
const ROOT_FUNCTIONS = new Set(["id", "key", "doc", "element-with-id", "root"]);
|
|
17
|
+
|
|
18
|
+
/** @param {*} node @returns {boolean} whether a node is a document node */
|
|
19
|
+
const isDocument = (node) => node?.nodeType === 9 || node?.nodeType === 11;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether a step stands for `//` (descendant-or-self::node()).
|
|
23
|
+
* @param {object} step
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
const isSlashSlash = (step) =>
|
|
27
|
+
step.type === "AxisStep" &&
|
|
28
|
+
step.axis === "descendant-or-self" &&
|
|
29
|
+
step.nodeTest.type === "AnyKindTest" &&
|
|
30
|
+
step.predicates.length === 0;
|
|
31
|
+
|
|
32
|
+
/** Axes the fast matcher follows upwards (self:: only alone). */
|
|
33
|
+
const FAST_AXES = new Set(["child", "attribute", "namespace"]);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Whether the fast matcher handles a step: an axis step on a fast axis,
|
|
37
|
+
* `//`, or an unfiltered rooted first step (key(), id(), doc(), $var...).
|
|
38
|
+
* @param {object} step
|
|
39
|
+
* @param {boolean} first
|
|
40
|
+
* @param {boolean} alone - The step is the whole pattern
|
|
41
|
+
* @returns {boolean}
|
|
42
|
+
*/
|
|
43
|
+
function isFastStep(step, first, alone) {
|
|
44
|
+
if (step.type === "AxisStep") {
|
|
45
|
+
return (
|
|
46
|
+
FAST_AXES.has(step.axis) ||
|
|
47
|
+
isSlashSlash(step) ||
|
|
48
|
+
(alone && step.axis === "self")
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return (
|
|
52
|
+
first &&
|
|
53
|
+
((step.type === "FunctionCall" && ROOT_FUNCTIONS.has(step.name.local)) ||
|
|
54
|
+
step.type === "VarRef")
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Builds the matcher of the parts of a path pattern.
|
|
60
|
+
* @param {Array<{separator: string|null, test: {test: Function}}>} parts -
|
|
61
|
+
* Steps in order; `separator` is what precedes the step ("/", "//", or
|
|
62
|
+
* null for the first step of a relative pattern)
|
|
63
|
+
* @returns {(item: *, xc: object) => boolean}
|
|
64
|
+
*/
|
|
65
|
+
export function matchParts(parts) {
|
|
66
|
+
const last = parts.length - 1;
|
|
67
|
+
const matchFrom = (node, k, xc) => {
|
|
68
|
+
if (!parts[k].test.test(node, xc)) return false;
|
|
69
|
+
const { separator } = parts[k];
|
|
70
|
+
if (k === 0) {
|
|
71
|
+
if (separator === null) return true;
|
|
72
|
+
if (separator === "/") return isDocument(parentOf(node));
|
|
73
|
+
for (let a = parentOf(node); a; a = parentOf(a)) {
|
|
74
|
+
if (isDocument(a)) return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (separator === "/") {
|
|
79
|
+
const parent = parentOf(node);
|
|
80
|
+
return parent !== null && matchFrom(parent, k - 1, xc);
|
|
81
|
+
}
|
|
82
|
+
for (let a = parentOf(node); a; a = parentOf(a)) {
|
|
83
|
+
if (matchFrom(a, k - 1, xc)) return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
};
|
|
87
|
+
return (item, xc) =>
|
|
88
|
+
typeof item?.nodeType === "number" && matchFrom(item, last, xc);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Compiles a path pattern (a PathExpr, or a single step).
|
|
93
|
+
* @param {object} ast
|
|
94
|
+
* @param {object} env - See compile.js
|
|
95
|
+
* @returns {import("./compile.js").PatternAlternative}
|
|
96
|
+
*/
|
|
97
|
+
export function compilePathPattern(ast, env) {
|
|
98
|
+
const absolute = ast.type === "PathExpr" && ast.absolute;
|
|
99
|
+
const steps = ast.type === "PathExpr" ? ast.steps : [ast];
|
|
100
|
+
if (absolute && steps.length === 0) {
|
|
101
|
+
return { matches: (item) => isDocument(item), priority: -0.5, key: "k9" };
|
|
102
|
+
}
|
|
103
|
+
const last = steps.at(-1);
|
|
104
|
+
const single = steps.length === 1 && !absolute;
|
|
105
|
+
const fast = steps.every((step, i) =>
|
|
106
|
+
isFastStep(step, i === 0 && !absolute, single),
|
|
107
|
+
);
|
|
108
|
+
if (!fast) {
|
|
109
|
+
return {
|
|
110
|
+
matches: compileGeneralPath(ast, env),
|
|
111
|
+
priority: single ? stepPriority(last) : 0.5,
|
|
112
|
+
key: last.type === "AxisStep" ? stepKey(last, env.sc) : "*",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const parts = [];
|
|
116
|
+
let separator = absolute ? "/" : null;
|
|
117
|
+
for (const step of steps) {
|
|
118
|
+
if (isSlashSlash(step)) {
|
|
119
|
+
separator = "//";
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
parts.push({ separator, test: compileStep(step, env) });
|
|
123
|
+
separator = "/";
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
matches: matchParts(parts),
|
|
127
|
+
priority: single ? stepPriority(last) : 0.5,
|
|
128
|
+
key: last.type === "AxisStep" ? parts.at(-1).test.key : "*",
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The grouping functions patterns cannot call (XTSE1060, XTSE1070).
|
|
3
|
+
*
|
|
4
|
+
* @module @tradik/xslt3/xslt/patterns/patternChecks
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { xsltError } from "../names.js";
|
|
8
|
+
|
|
9
|
+
/** Functions a pattern cannot call (XTSE1060, XTSE1070). */
|
|
10
|
+
const GROUPING_CALLS = {
|
|
11
|
+
"current-group": "XTSE1060",
|
|
12
|
+
"current-grouping-key": "XTSE1070",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks that a pattern does not call current-group() or
|
|
17
|
+
* current-grouping-key().
|
|
18
|
+
* @param {object} ast
|
|
19
|
+
*/
|
|
20
|
+
export function checkGroupingCalls(ast) {
|
|
21
|
+
if (ast === null || typeof ast !== "object") return;
|
|
22
|
+
if (ast.type === "FunctionCall" && !ast.name.prefix && !ast.name.uri) {
|
|
23
|
+
const code = GROUPING_CALLS[ast.name.local];
|
|
24
|
+
if (code) {
|
|
25
|
+
throw xsltError(code, `A pattern cannot call ${ast.name.local}()`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (const value of Object.values(ast)) checkGroupingCalls(value);
|
|
29
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The steps of path patterns: axis steps tested on a node (with their
|
|
3
|
+
* predicates evaluated among the node's siblings when they depend on the
|
|
4
|
+
* position), and the rooted steps key(), id(), doc(), $var, tested by
|
|
5
|
+
* membership. Also the default priorities of single-step patterns.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/patterns/steps
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { compileNode } from "../../xpath/eval/compiler.js";
|
|
11
|
+
import {
|
|
12
|
+
attributesOf,
|
|
13
|
+
childrenOf,
|
|
14
|
+
parentOf,
|
|
15
|
+
} from "../../xpath/eval/domNodes.js";
|
|
16
|
+
import { compileNodeTest } from "../../xpath/eval/nodeTests.js";
|
|
17
|
+
import { isPositionIndependent } from "../../xpath/eval/positional.js";
|
|
18
|
+
import { compilePredicate } from "../../xpath/eval/predicates.js";
|
|
19
|
+
import { namespaceOf } from "../../xpath/eval/staticContext.js";
|
|
20
|
+
|
|
21
|
+
/** Node kinds an axis step can match, by axis. */
|
|
22
|
+
const AXIS_KINDS = {
|
|
23
|
+
child: (node) => [1, 3, 4, 7, 8].includes(node?.nodeType),
|
|
24
|
+
attribute: (node) => node?.nodeType === 2,
|
|
25
|
+
namespace: (node) => node?.nodeType === 13,
|
|
26
|
+
self: (node) => typeof node?.nodeType === "number",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** Index keys of kind tests. */
|
|
30
|
+
const KIND_KEYS = {
|
|
31
|
+
TextTest: "k3",
|
|
32
|
+
CommentTest: "k8",
|
|
33
|
+
PITest: "k7",
|
|
34
|
+
DocumentTest: "k9",
|
|
35
|
+
NamespaceNodeTest: "k13",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The index key of an axis step.
|
|
40
|
+
* @param {object} step
|
|
41
|
+
* @param {object} sc
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
export function stepKey(step, sc) {
|
|
45
|
+
const { nodeTest, axis } = step;
|
|
46
|
+
const attribute = axis === "attribute";
|
|
47
|
+
if (axis === "self") return "*";
|
|
48
|
+
if (axis === "namespace") return "k13";
|
|
49
|
+
if (nodeTest.type === "NameTest") {
|
|
50
|
+
const defaultNs = attribute ? "" : sc.defaultElementNamespace;
|
|
51
|
+
const uri = namespaceOf(nodeTest.name, sc, defaultNs);
|
|
52
|
+
return `${attribute ? "a" : "e"}{${uri}}${nodeTest.name.local}`;
|
|
53
|
+
}
|
|
54
|
+
if (nodeTest.type === "Wildcard") return attribute ? "k2" : "k1";
|
|
55
|
+
if (nodeTest.type === "ElementTest") return "k1";
|
|
56
|
+
if (nodeTest.type === "AttributeTest") return "k2";
|
|
57
|
+
return KIND_KEYS[nodeTest.type] ?? "*";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Compiles an axis step of a pattern.
|
|
62
|
+
* @param {object} step
|
|
63
|
+
* @param {object} env - `{cx, sc, vars}`
|
|
64
|
+
* @returns {{key: string, test: (node: *, xc: object) => boolean}}
|
|
65
|
+
*/
|
|
66
|
+
function compileAxisStep(step, env) {
|
|
67
|
+
// document-node() as a step without axis matches document nodes
|
|
68
|
+
const documentStep =
|
|
69
|
+
step.axis === "child" &&
|
|
70
|
+
step.nodeTest.type === "DocumentTest" &&
|
|
71
|
+
!env.text.startsWith("child::", step.start);
|
|
72
|
+
|
|
73
|
+
// the axis is child, attribute, namespace or (alone) self: see paths.js
|
|
74
|
+
const kindOk = documentStep ? AXIS_KINDS.self : AXIS_KINDS[step.axis];
|
|
75
|
+
const nodeTest = compileNodeTest(step.nodeTest, step.axis, env.sc);
|
|
76
|
+
const accepts = (node) => kindOk(node) && nodeTest(node);
|
|
77
|
+
const scope = { sc: env.sc, vars: env.vars };
|
|
78
|
+
const predicates = step.predicates.map((p) =>
|
|
79
|
+
compilePredicate(p, scope, compileNode),
|
|
80
|
+
);
|
|
81
|
+
const key = stepKey(step, env.sc);
|
|
82
|
+
if (predicates.length === 0) return { key, test: accepts };
|
|
83
|
+
const independent = step.predicates.every((p) =>
|
|
84
|
+
isPositionIndependent(p, env.sc),
|
|
85
|
+
);
|
|
86
|
+
const attribute = step.axis === "attribute";
|
|
87
|
+
return {
|
|
88
|
+
key,
|
|
89
|
+
test(node, xc) {
|
|
90
|
+
if (!accepts(node)) return false;
|
|
91
|
+
const ctx = env.cx.patternContext(node, xc, env.local);
|
|
92
|
+
if (independent) {
|
|
93
|
+
return predicates.every((predicate) => predicate([node], ctx).length);
|
|
94
|
+
}
|
|
95
|
+
const parent = parentOf(node);
|
|
96
|
+
let candidates = parent
|
|
97
|
+
? (attribute ? attributesOf(parent) : childrenOf(parent)).filter(
|
|
98
|
+
accepts,
|
|
99
|
+
)
|
|
100
|
+
: [node];
|
|
101
|
+
for (const predicate of predicates) {
|
|
102
|
+
candidates = predicate(candidates, ctx);
|
|
103
|
+
}
|
|
104
|
+
return candidates.includes(node);
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Compiles a step of a pattern.
|
|
111
|
+
* @param {object} step - AxisStep, or a FunctionCall/VarRef first step
|
|
112
|
+
* @param {object} env - `{cx, sc, vars}`
|
|
113
|
+
* @returns {{key: string, test: (node: *, xc: object) => boolean}}
|
|
114
|
+
*/
|
|
115
|
+
export function compileStep(step, env) {
|
|
116
|
+
if (step.type === "AxisStep") return compileAxisStep(step, env);
|
|
117
|
+
const run = env.cx.exprs.compileAst(step, env.sc, env.vars);
|
|
118
|
+
return {
|
|
119
|
+
key: "*",
|
|
120
|
+
test: (node, xc) =>
|
|
121
|
+
typeof node?.nodeType === "number" &&
|
|
122
|
+
run(env.cx.patternContext(node, xc, env.local)).includes(node),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Default priorities of kind tests without a name. */
|
|
127
|
+
const KIND_PRIORITY = {
|
|
128
|
+
AnyKindTest: -0.5,
|
|
129
|
+
TextTest: -0.5,
|
|
130
|
+
CommentTest: -0.5,
|
|
131
|
+
NamespaceNodeTest: -0.5,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The default priority of a pattern made of one step.
|
|
136
|
+
* @param {object} step
|
|
137
|
+
* @returns {number}
|
|
138
|
+
*/
|
|
139
|
+
export function stepPriority(step) {
|
|
140
|
+
if (step.type !== "AxisStep" || step.predicates.length > 0) return 0.5;
|
|
141
|
+
const test = step.nodeTest;
|
|
142
|
+
switch (test.type) {
|
|
143
|
+
case "NameTest":
|
|
144
|
+
return 0;
|
|
145
|
+
case "Wildcard":
|
|
146
|
+
return test.prefix !== null || test.local !== null || test.uri !== null
|
|
147
|
+
? -0.25
|
|
148
|
+
: -0.5;
|
|
149
|
+
case "PITest":
|
|
150
|
+
return test.target === null ? -0.5 : 0;
|
|
151
|
+
case "ElementTest":
|
|
152
|
+
case "AttributeTest":
|
|
153
|
+
if (test.name === null && test.typeName === null) return -0.5;
|
|
154
|
+
return test.name !== null && test.typeName !== null ? 0.25 : 0;
|
|
155
|
+
case "DocumentTest":
|
|
156
|
+
return test.elementTest === null
|
|
157
|
+
? -0.5
|
|
158
|
+
: stepPriority({ ...step, nodeTest: test.elementTest });
|
|
159
|
+
default:
|
|
160
|
+
return KIND_PRIORITY[test.type] ?? 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XSLTProcessor: the W3C/browser-style API over compileStylesheet, with
|
|
3
|
+
* the method names of the @tradik/xslt-processor (XSLT 1.0) package.
|
|
4
|
+
*
|
|
5
|
+
* @module @tradik/xslt3/xslt/processor
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { serialize } from "../serialize/index.js";
|
|
9
|
+
import { compileStylesheet } from "./api.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string|null} namespaceURI
|
|
13
|
+
* @param {string} localName
|
|
14
|
+
* @returns {string} Clark name
|
|
15
|
+
*/
|
|
16
|
+
const keyOf = (namespaceURI, localName) =>
|
|
17
|
+
`{${namespaceURI ?? ""}}${localName}`;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A loader of the 1.0 package's API, which may return XML text, as a
|
|
21
|
+
* loader of documents.
|
|
22
|
+
* @param {Function} loader - `(uri, base) => Document|string|null`
|
|
23
|
+
* @param {(text: string, uri?: string) => Document} [parseXml]
|
|
24
|
+
* @returns {(uri: string, base?: string) => Document|null}
|
|
25
|
+
*/
|
|
26
|
+
function documentsFrom(loader, parseXml) {
|
|
27
|
+
return (uri, base) => {
|
|
28
|
+
const result = loader(uri, base);
|
|
29
|
+
if (typeof result !== "string") return result;
|
|
30
|
+
if (parseXml) return parseXml(result, uri);
|
|
31
|
+
return new globalThis.DOMParser().parseFromString(
|
|
32
|
+
result,
|
|
33
|
+
"application/xml",
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks a loader given to a setter.
|
|
40
|
+
* @param {*} loader
|
|
41
|
+
* @param {string} method - Name of the setter, for the message
|
|
42
|
+
* @throws {TypeError} when it is neither a function nor null
|
|
43
|
+
*/
|
|
44
|
+
function checkLoader(loader, method) {
|
|
45
|
+
if (loader != null && typeof loader !== "function") {
|
|
46
|
+
throw new TypeError(`${method}: the loader must be a function or null`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Applies an XSLT 3.0/2.0 stylesheet to documents. */
|
|
51
|
+
export class XSLTProcessor {
|
|
52
|
+
/**
|
|
53
|
+
* @param {object} [options] - Options of compileStylesheet and
|
|
54
|
+
* CompiledStylesheet.transform used for every transformation
|
|
55
|
+
*/
|
|
56
|
+
constructor(options = {}) {
|
|
57
|
+
this.options = options;
|
|
58
|
+
this.stylesheet = null;
|
|
59
|
+
/** @type {Map<string, *>} */
|
|
60
|
+
this.parameters = new Map();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Compiles a stylesheet.
|
|
65
|
+
* @param {Document|Element|string} style
|
|
66
|
+
*/
|
|
67
|
+
importStylesheet(style) {
|
|
68
|
+
this.stylesheet = compileStylesheet(style, this.options);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Runs the imported stylesheet.
|
|
73
|
+
* @param {Node} source
|
|
74
|
+
* @returns {object} the transformation result
|
|
75
|
+
*/
|
|
76
|
+
run(source) {
|
|
77
|
+
if (!this.stylesheet) throw new Error("No stylesheet imported");
|
|
78
|
+
return this.stylesheet.transform({
|
|
79
|
+
...this.options,
|
|
80
|
+
source,
|
|
81
|
+
params: this.parameters,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {Node} source
|
|
87
|
+
* @returns {Document|DocumentFragment} the principal result
|
|
88
|
+
*/
|
|
89
|
+
transformToDocument(source) {
|
|
90
|
+
return this.run(source).principal;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Node} source
|
|
95
|
+
* @returns {string} the principal result serialized with its output
|
|
96
|
+
* parameters (xsl:output, or the xsl:result-document that wrote it)
|
|
97
|
+
*/
|
|
98
|
+
transformToString(source) {
|
|
99
|
+
const { principal, output } = this.run(source);
|
|
100
|
+
return serialize([principal].flat(), output);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Sets the loader of included and imported modules, used by the next
|
|
105
|
+
* importStylesheet().
|
|
106
|
+
* @param {((uri: string, base?: string) => Document|string)|null} loader
|
|
107
|
+
* @returns {XSLTProcessor} this
|
|
108
|
+
*/
|
|
109
|
+
setStylesheetLoader(loader) {
|
|
110
|
+
checkLoader(loader, "setStylesheetLoader");
|
|
111
|
+
this.options = { ...this.options, loadStylesheet: loader ?? undefined };
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Sets the loader of doc() and document(); it may return XML text.
|
|
117
|
+
* @param {((uri: string, base?: string) => Document|string|null)|null} loader
|
|
118
|
+
* @returns {XSLTProcessor} this
|
|
119
|
+
*/
|
|
120
|
+
setDocumentLoader(loader) {
|
|
121
|
+
checkLoader(loader, "setDocumentLoader");
|
|
122
|
+
const documentLoader =
|
|
123
|
+
loader == null ? undefined : documentsFrom(loader, this.options.parseXml);
|
|
124
|
+
this.options = { ...this.options, documentLoader };
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {Node} source
|
|
130
|
+
* @param {Document} output - Document that owns the fragment
|
|
131
|
+
* @returns {DocumentFragment} the principal result as a fragment
|
|
132
|
+
*/
|
|
133
|
+
transformToFragment(source, output) {
|
|
134
|
+
const { principal } = this.run(source);
|
|
135
|
+
const fragment = output.createDocumentFragment();
|
|
136
|
+
for (const child of principal.childNodes) {
|
|
137
|
+
fragment.appendChild(output.importNode(child, true));
|
|
138
|
+
}
|
|
139
|
+
return fragment;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @param {string|null} namespaceURI
|
|
144
|
+
* @param {string} localName
|
|
145
|
+
* @param {*} value
|
|
146
|
+
*/
|
|
147
|
+
setParameter(namespaceURI, localName, value) {
|
|
148
|
+
this.parameters.set(keyOf(namespaceURI, localName), value);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {string|null} namespaceURI
|
|
153
|
+
* @param {string} localName
|
|
154
|
+
* @returns {*} the value, "" when not set (as in browsers)
|
|
155
|
+
*/
|
|
156
|
+
getParameter(namespaceURI, localName) {
|
|
157
|
+
return this.parameters.get(keyOf(namespaceURI, localName)) ?? "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @param {string|null} namespaceURI
|
|
162
|
+
* @param {string} localName
|
|
163
|
+
*/
|
|
164
|
+
removeParameter(namespaceURI, localName) {
|
|
165
|
+
this.parameters.delete(keyOf(namespaceURI, localName));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Removes every parameter. */
|
|
169
|
+
clearParameters() {
|
|
170
|
+
this.parameters.clear();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Removes the stylesheet and the parameters. */
|
|
174
|
+
reset() {
|
|
175
|
+
this.stylesheet = null;
|
|
176
|
+
this.parameters.clear();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* accumulator-before() and accumulator-after() (XSLT 3.0 sections
|
|
3
|
+
* 18.2.6 and 18.2.7).
|
|
4
|
+
*
|
|
5
|
+
* @module @tradik/xslt3/xslt/runtime/accumulatorFunctions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { isNode } from "../../xdm/atomic.js";
|
|
9
|
+
import { xsltError } from "../names.js";
|
|
10
|
+
import { accumulatorValue } from "./accumulators.js";
|
|
11
|
+
import { nameArgument } from "./availability.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Implementation of both functions.
|
|
15
|
+
* @param {boolean} after
|
|
16
|
+
* @returns {(args: Array, context: object) => Array}
|
|
17
|
+
*/
|
|
18
|
+
const accumulatorFunction = (after) => (args, context) => {
|
|
19
|
+
const [[name]] = args;
|
|
20
|
+
const { uri, local } = nameArgument(name.value, context, "XTDE3340");
|
|
21
|
+
const key = `{${uri}}${local}`;
|
|
22
|
+
// accumulators are local to the package of the call (XSLT 3.0 3.5.5)
|
|
23
|
+
const owner = context.sc?.owner ?? context.xc.tx.stylesheet;
|
|
24
|
+
const accumulator = owner.accumulators.get(key);
|
|
25
|
+
if (!accumulator) {
|
|
26
|
+
throw xsltError("XTDE3340", `No accumulator ${name.value}`);
|
|
27
|
+
}
|
|
28
|
+
const item = context.contextItem;
|
|
29
|
+
if (item === undefined) {
|
|
30
|
+
throw xsltError("XTDE3350", "An accumulator function needs a context item");
|
|
31
|
+
}
|
|
32
|
+
if (!isNode(item) || item.nodeType === 2 || item.nodeType === 13) {
|
|
33
|
+
throw xsltError(
|
|
34
|
+
"XTTE3360",
|
|
35
|
+
"An accumulator function needs a context node other than an attribute",
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return accumulatorValue(context.xc, key, item, after, accumulator);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** Function definitions. */
|
|
42
|
+
export const accumulatorFunctions = ["before", "after"].map((phase) => ({
|
|
43
|
+
local: `accumulator-${phase}`,
|
|
44
|
+
params: ["xs:string"],
|
|
45
|
+
returns: "item()*",
|
|
46
|
+
focus: true,
|
|
47
|
+
impl: accumulatorFunction(phase === "after"),
|
|
48
|
+
}));
|