@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,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:expose and xsl:accept (XSLT 3.0 sections 3.5.3.1 and 3.5.3.2): the
|
|
3
|
+
* rules that give components their visibility, chosen by how precisely
|
|
4
|
+
* a token of `names` matches a component (an explicit name beats a
|
|
5
|
+
* namespace or local-name wildcard, which beats `*`; the last such rule
|
|
6
|
+
* in document order wins).
|
|
7
|
+
*
|
|
8
|
+
* @module @tradik/xslt3/xslt/compiler/visibility
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { attr, resolveQName, tokens, xsltError } from "../names.js";
|
|
12
|
+
import { required } from "./attributes.js";
|
|
13
|
+
import { infoOf } from "./elementInfo.js";
|
|
14
|
+
|
|
15
|
+
/** Component kinds that xsl:expose and xsl:accept name. */
|
|
16
|
+
const KINDS = new Set([
|
|
17
|
+
"template",
|
|
18
|
+
"function",
|
|
19
|
+
"attribute-set",
|
|
20
|
+
"variable",
|
|
21
|
+
"mode",
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
/** How precisely a token matches: higher wins. */
|
|
25
|
+
export const EXPLICIT = 3;
|
|
26
|
+
const PARTIAL = 2;
|
|
27
|
+
const ANY = 1;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parses a token of a names attribute.
|
|
31
|
+
* @param {string} token
|
|
32
|
+
* @param {Element} element
|
|
33
|
+
* @returns {object} `{precision, uri, local, arity}` (null for wildcards)
|
|
34
|
+
*/
|
|
35
|
+
function parseToken(token, element) {
|
|
36
|
+
const namespaces = infoOf(element).namespaces;
|
|
37
|
+
if (token === "*") return { precision: ANY };
|
|
38
|
+
if (token.startsWith("*:")) {
|
|
39
|
+
return { precision: PARTIAL, uri: null, local: token.slice(2) };
|
|
40
|
+
}
|
|
41
|
+
const eqWildcard = /^Q\{([^{}]*)\}\*$/.exec(token);
|
|
42
|
+
if (eqWildcard) {
|
|
43
|
+
return { precision: PARTIAL, uri: eqWildcard[1], local: null };
|
|
44
|
+
}
|
|
45
|
+
if (token.endsWith(":*")) {
|
|
46
|
+
const { uri } = resolveQName(`${token.slice(0, -2)}:x`, namespaces, {
|
|
47
|
+
code: "XTSE0020",
|
|
48
|
+
});
|
|
49
|
+
return { precision: PARTIAL, uri, local: null };
|
|
50
|
+
}
|
|
51
|
+
const hash = token.lastIndexOf("#");
|
|
52
|
+
const arity = hash < 0 ? null : token.slice(hash + 1);
|
|
53
|
+
if (arity !== null && !/^\d+$/.test(arity)) {
|
|
54
|
+
throw xsltError("XTSE0020", `Invalid name ${token}`);
|
|
55
|
+
}
|
|
56
|
+
const name = resolveQName(
|
|
57
|
+
hash < 0 ? token : token.slice(0, hash),
|
|
58
|
+
namespaces,
|
|
59
|
+
{ code: "XTSE0020" },
|
|
60
|
+
);
|
|
61
|
+
return {
|
|
62
|
+
precision: EXPLICIT,
|
|
63
|
+
uri: name.uri,
|
|
64
|
+
local: name.local,
|
|
65
|
+
arity: arity === null ? null : Number(arity),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Parses xsl:expose or xsl:accept elements.
|
|
71
|
+
* @param {Element[]} elements - In document order
|
|
72
|
+
* @param {object} cx - Stylesheet compiler
|
|
73
|
+
* @param {object} options
|
|
74
|
+
* @param {Set<string>} options.allowed - Allowed visibility values
|
|
75
|
+
* @param {string} options.anyCode - Error of component="*" with a
|
|
76
|
+
* non-wildcard name (XTSE3022, XTSE3032)
|
|
77
|
+
* @returns {object[]} rules `{kind, visibility, tokens, element}`
|
|
78
|
+
*/
|
|
79
|
+
export function parseVisibilityRules(elements, cx, { allowed, anyCode }) {
|
|
80
|
+
return elements.map((element) => {
|
|
81
|
+
if (cx.children(element).length > 0) {
|
|
82
|
+
throw xsltError("XTSE0260", `xsl:${element.localName} must be empty`);
|
|
83
|
+
}
|
|
84
|
+
const kind = required(element, "component").trim();
|
|
85
|
+
if (kind !== "*" && !KINDS.has(kind)) {
|
|
86
|
+
throw xsltError("XTSE0020", `Invalid component ${kind}`);
|
|
87
|
+
}
|
|
88
|
+
const visibility = required(element, "visibility").trim();
|
|
89
|
+
if (!allowed.has(visibility)) {
|
|
90
|
+
throw xsltError("XTSE0020", `Invalid visibility ${visibility}`);
|
|
91
|
+
}
|
|
92
|
+
const parsed = tokens(required(element, "names")).map((token) =>
|
|
93
|
+
parseToken(token, element),
|
|
94
|
+
);
|
|
95
|
+
if (kind === "*" && parsed.some((t) => t.precision === EXPLICIT)) {
|
|
96
|
+
throw xsltError(anyCode, 'component="*" needs wildcard names');
|
|
97
|
+
}
|
|
98
|
+
return { kind, visibility, tokens: parsed, element };
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* How precisely a token matches a component.
|
|
104
|
+
* @param {object} token
|
|
105
|
+
* @param {object} component - `{kind, uri, local, arity}`
|
|
106
|
+
* @returns {number} 0 when it does not match
|
|
107
|
+
*/
|
|
108
|
+
function tokenMatch(token, component) {
|
|
109
|
+
if (token.precision === ANY) return ANY;
|
|
110
|
+
if (token.precision === PARTIAL) {
|
|
111
|
+
const matches =
|
|
112
|
+
token.uri === null
|
|
113
|
+
? token.local === component.local
|
|
114
|
+
: token.uri === component.uri;
|
|
115
|
+
return matches ? PARTIAL : 0;
|
|
116
|
+
}
|
|
117
|
+
if (token.uri !== component.uri || token.local !== component.local) return 0;
|
|
118
|
+
if (token.arity !== null && component.kind !== "function") return 0;
|
|
119
|
+
// a function is named with its arity
|
|
120
|
+
if (component.kind === "function") {
|
|
121
|
+
return token.arity === component.arity ? EXPLICIT : 0;
|
|
122
|
+
}
|
|
123
|
+
return EXPLICIT;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The matches of the rules for a component, best first.
|
|
128
|
+
* @param {object[]} rules
|
|
129
|
+
* @param {object} component
|
|
130
|
+
* @returns {Array<{rule: object, token: object, precision: number}>}
|
|
131
|
+
*/
|
|
132
|
+
export function matchesOf(rules, component) {
|
|
133
|
+
const found = [];
|
|
134
|
+
rules.forEach((rule, order) => {
|
|
135
|
+
if (rule.kind !== "*" && rule.kind !== component.kind) return;
|
|
136
|
+
for (const token of rule.tokens) {
|
|
137
|
+
const precision = tokenMatch(token, component);
|
|
138
|
+
if (precision > 0) {
|
|
139
|
+
token.used = true;
|
|
140
|
+
found.push({ rule, token, precision, order });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return found.sort((a, b) => b.precision - a.precision || b.order - a.order);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Checks that every explicit token matched a component.
|
|
149
|
+
* @param {object[]} rules
|
|
150
|
+
* @param {string} code - XTSE3020 (expose) or XTSE3030 (accept)
|
|
151
|
+
*/
|
|
152
|
+
export function checkUnmatched(rules, code) {
|
|
153
|
+
for (const rule of rules) {
|
|
154
|
+
for (const token of rule.tokens) {
|
|
155
|
+
if (token.precision === EXPLICIT && !token.used) {
|
|
156
|
+
throw xsltError(code, `${attr(rule.element, "names")} matches nothing`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XSLT 3.0 and 2.0 (and 1.0 in backwards-compatible mode): the public
|
|
3
|
+
* API of the transformation engine.
|
|
4
|
+
*
|
|
5
|
+
* @module @tradik/xslt3/xslt
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { CompiledStylesheet, compileStylesheet } from "./api.js";
|
|
9
|
+
export { XSLTProcessor } from "./processor.js";
|
|
10
|
+
export { versionMatches } from "./compiler/packageVersions.js";
|
|
11
|
+
export { untypedAtomic } from "./runtime/params.js";
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:analyze-string (XSLT 3.0 section 17.1): the matching and
|
|
3
|
+
* non-matching substrings of a string, each processed with the substring
|
|
4
|
+
* as context item; regex-group() gives the captured groups.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/xslt/instructions/analyzeString
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { allMatches, compileRegex } from "../../functions/regex/compile.js";
|
|
10
|
+
import { stringItem } from "../../xpath/eval/atomics.js";
|
|
11
|
+
import { atomize } from "../../xdm/nodes.js";
|
|
12
|
+
import { canonicalString } from "../../xdm/lexical.js";
|
|
13
|
+
import { compileBody } from "../compiler/body.js";
|
|
14
|
+
import { checkAttributes, required } from "../compiler/attributes.js";
|
|
15
|
+
import { derive, evaluate } from "../runtime/context.js";
|
|
16
|
+
import { BodyFrame, LoopFrame } from "../runtime/machine.js";
|
|
17
|
+
import { avtEvaluator } from "../runtime/values.js";
|
|
18
|
+
import { attr, isXsl, xsltError } from "../names.js";
|
|
19
|
+
|
|
20
|
+
/** Types accepted as the string of xsl:analyze-string. */
|
|
21
|
+
const STRING_LIKE = new Set(["string", "untypedAtomic", "anyURI"]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Compiles the regular expression, mapping its errors to XSLT codes.
|
|
25
|
+
* @param {string} regex
|
|
26
|
+
* @param {string} flags
|
|
27
|
+
* @returns {object}
|
|
28
|
+
*/
|
|
29
|
+
function regexOf(regex, flags) {
|
|
30
|
+
let compiled;
|
|
31
|
+
try {
|
|
32
|
+
compiled = compileRegex(regex, flags);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
const code = error.code === "FORX0001" ? "XTDE1145" : "XTDE1140";
|
|
35
|
+
throw xsltError(code, error.message);
|
|
36
|
+
}
|
|
37
|
+
compiled.regex.lastIndex = 0;
|
|
38
|
+
if (compiled.regex.test("")) {
|
|
39
|
+
throw xsltError("XTDE1150", 'The regular expression matches ""');
|
|
40
|
+
}
|
|
41
|
+
return compiled;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Splits a string into matching and non-matching substrings.
|
|
46
|
+
* @param {string} input
|
|
47
|
+
* @param {object} compiled
|
|
48
|
+
* @returns {Array<{text: string, groups: string[]|null}>}
|
|
49
|
+
*/
|
|
50
|
+
function segmentsOf(input, compiled) {
|
|
51
|
+
const segments = [];
|
|
52
|
+
let last = 0;
|
|
53
|
+
for (const match of allMatches(compiled, input)) {
|
|
54
|
+
if (match.index > last) {
|
|
55
|
+
segments.push({ text: input.slice(last, match.index), groups: null });
|
|
56
|
+
}
|
|
57
|
+
const groups = [];
|
|
58
|
+
for (let i = 0; i <= compiled.groups; i++) groups.push(match[i] ?? "");
|
|
59
|
+
segments.push({ text: match[0], groups });
|
|
60
|
+
last = match.index + match[0].length;
|
|
61
|
+
}
|
|
62
|
+
if (last < input.length) {
|
|
63
|
+
segments.push({ text: input.slice(last), groups: null });
|
|
64
|
+
}
|
|
65
|
+
return segments;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* xsl:analyze-string.
|
|
70
|
+
* @param {Element} element
|
|
71
|
+
* @param {object} cx
|
|
72
|
+
* @param {object} scope
|
|
73
|
+
* @returns {Function}
|
|
74
|
+
*/
|
|
75
|
+
export function compileAnalyzeString(element, cx, scope) {
|
|
76
|
+
const select = cx.exprs.xpath(
|
|
77
|
+
required(element, "select"),
|
|
78
|
+
element,
|
|
79
|
+
scope.vars,
|
|
80
|
+
);
|
|
81
|
+
const regex = avtEvaluator(
|
|
82
|
+
cx.exprs.avt(required(element, "regex"), element, scope.vars),
|
|
83
|
+
);
|
|
84
|
+
const flagsText = attr(element, "flags");
|
|
85
|
+
const flags = flagsText
|
|
86
|
+
? avtEvaluator(cx.exprs.avt(flagsText, element, scope.vars))
|
|
87
|
+
: () => "";
|
|
88
|
+
let matching = null;
|
|
89
|
+
let nonMatching = null;
|
|
90
|
+
let fallback = false;
|
|
91
|
+
for (const child of cx.children(element)) {
|
|
92
|
+
if (fallback && !isXsl(child, "fallback")) {
|
|
93
|
+
throw xsltError("XTSE0010", "xsl:fallback must come last");
|
|
94
|
+
}
|
|
95
|
+
if (isXsl(child, "matching-substring") && !matching && !nonMatching) {
|
|
96
|
+
checkAttributes(child);
|
|
97
|
+
matching = compileBody(child, cx, scope);
|
|
98
|
+
} else if (isXsl(child, "non-matching-substring") && !nonMatching) {
|
|
99
|
+
checkAttributes(child);
|
|
100
|
+
nonMatching = compileBody(child, cx, scope);
|
|
101
|
+
} else if (isXsl(child, "fallback")) fallback = true;
|
|
102
|
+
else throw xsltError("XTSE0010", "Invalid content of xsl:analyze-string");
|
|
103
|
+
}
|
|
104
|
+
if (!matching && !nonMatching) {
|
|
105
|
+
throw xsltError("XTSE1130", "xsl:analyze-string needs a substring child");
|
|
106
|
+
}
|
|
107
|
+
return (xc, out, machine) => {
|
|
108
|
+
const values = atomize(evaluate(select, xc));
|
|
109
|
+
if (values.length > 1) {
|
|
110
|
+
throw xsltError("XPTY0004", "xsl:analyze-string selects one string");
|
|
111
|
+
}
|
|
112
|
+
const primitive = values[0]?.type.primitive.localName;
|
|
113
|
+
if (values.length && !STRING_LIKE.has(primitive)) {
|
|
114
|
+
throw xsltError("XPTY0004", "xsl:analyze-string selects a string");
|
|
115
|
+
}
|
|
116
|
+
const input = values.length ? canonicalString(values[0]) : "";
|
|
117
|
+
const compiled = regexOf(regex(xc), flags(xc));
|
|
118
|
+
const segments = segmentsOf(input, compiled);
|
|
119
|
+
const size = segments.length;
|
|
120
|
+
if (size === 0) return;
|
|
121
|
+
const base = derive(xc, { rule: null });
|
|
122
|
+
machine.push(
|
|
123
|
+
new LoopFrame(size, (i) => {
|
|
124
|
+
const { text, groups } = segments[i];
|
|
125
|
+
const body = groups ? matching : nonMatching;
|
|
126
|
+
if (!body || body.length === 0) return;
|
|
127
|
+
const context = derive(base, {
|
|
128
|
+
item: stringItem(text),
|
|
129
|
+
position: i + 1,
|
|
130
|
+
size,
|
|
131
|
+
regex: groups ?? undefined,
|
|
132
|
+
});
|
|
133
|
+
machine.push(new BodyFrame(body, context, out));
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:assert (XSLT 3.0 section 23.2): when its test is false, or fails,
|
|
3
|
+
* the transformation fails as with xsl:message terminate="yes", with the
|
|
4
|
+
* error code of the error-code attribute (default XTMM9001). Assertions
|
|
5
|
+
* are checked unless the transform() option `assertions` is false.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/instructions/assert
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { effectiveBooleanValue } from "../../xdm/nodes.js";
|
|
11
|
+
import { required } from "../compiler/attributes.js";
|
|
12
|
+
import { compileBody } from "../compiler/body.js";
|
|
13
|
+
import { infoOf } from "../compiler/elementInfo.js";
|
|
14
|
+
import { evaluate } from "../runtime/context.js";
|
|
15
|
+
import { avtEvaluator, bodySequence } from "../runtime/values.js";
|
|
16
|
+
import { attr, isXsl, resolveQName, xsltError } from "../names.js";
|
|
17
|
+
|
|
18
|
+
/** Namespace of the standard error codes. */
|
|
19
|
+
const ERR = "http://www.w3.org/2005/xqt-errors";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether the test of an assertion holds; an error counts as false.
|
|
23
|
+
* @param {object} test
|
|
24
|
+
* @param {object} xc
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
function holds(test, xc) {
|
|
28
|
+
try {
|
|
29
|
+
return effectiveBooleanValue(evaluate(test, xc));
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (typeof error?.code !== "string") throw error;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* xsl:assert.
|
|
38
|
+
* @param {Element} element
|
|
39
|
+
* @param {object} cx
|
|
40
|
+
* @param {object} scope
|
|
41
|
+
* @returns {Function}
|
|
42
|
+
*/
|
|
43
|
+
export function compileAssert(element, cx, scope) {
|
|
44
|
+
const test = cx.exprs.xpath(required(element, "test"), element, scope.vars);
|
|
45
|
+
const selectText = attr(element, "select");
|
|
46
|
+
const select =
|
|
47
|
+
selectText === undefined
|
|
48
|
+
? null
|
|
49
|
+
: cx.exprs.xpath(selectText, element, scope.vars);
|
|
50
|
+
const children = cx.children(element).filter((c) => !isXsl(c, "fallback"));
|
|
51
|
+
if (select && children.length > 0) {
|
|
52
|
+
throw xsltError("XTSE3185", "xsl:assert cannot have select and content");
|
|
53
|
+
}
|
|
54
|
+
const body = compileBody(element, cx, scope, children);
|
|
55
|
+
const codeText = attr(element, "error-code");
|
|
56
|
+
const errorCode = codeText
|
|
57
|
+
? avtEvaluator(cx.exprs.avt(codeText, element, scope.vars))
|
|
58
|
+
: () => `Q{${ERR}}XTMM9001`;
|
|
59
|
+
const namespaces = infoOf(element).namespaces;
|
|
60
|
+
return (xc, out, machine) => {
|
|
61
|
+
if (!xc.tx.assertions || holds(test, xc)) return;
|
|
62
|
+
const value = select
|
|
63
|
+
? evaluate(select, xc)
|
|
64
|
+
: bodySequence(body, xc, machine);
|
|
65
|
+
xc.tx.messages.push(value);
|
|
66
|
+
const name = resolveQName(errorCode(xc), namespaces, { code: "XTDE0030" });
|
|
67
|
+
const code = name.uri === ERR ? name.local : `Q{${name.uri}}${name.local}`;
|
|
68
|
+
const error = xsltError(code, "Assertion failed");
|
|
69
|
+
error.value = value;
|
|
70
|
+
throw error;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribute sets (XSLT 3.0 section 10.2): named groups of xsl:attribute
|
|
3
|
+
* instructions, applied by use-attribute-sets on literal result elements,
|
|
4
|
+
* xsl:element, xsl:copy and other attribute sets.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/xslt/instructions/attributeSets
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { compileBody } from "../compiler/body.js";
|
|
10
|
+
import { required } from "../compiler/attributes.js";
|
|
11
|
+
import { derive } from "../runtime/context.js";
|
|
12
|
+
import { clarkOf, isXsl, tokens, xsltError } from "../names.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the names of a use-attribute-sets attribute; their existence
|
|
16
|
+
* is checked once the stylesheet is compiled (XTSE0710).
|
|
17
|
+
* @param {string|undefined} text
|
|
18
|
+
* @param {Element} element
|
|
19
|
+
* @param {object} cx - Stylesheet compiler
|
|
20
|
+
* @returns {string[]} Clark names
|
|
21
|
+
*/
|
|
22
|
+
export function attributeSetNames(text, element, cx) {
|
|
23
|
+
const names = tokens(text).map((token) => {
|
|
24
|
+
const name = clarkOf(cx.exprs.qname(token, element, { code: "XTSE0710" }));
|
|
25
|
+
return cx.originalName("attribute-set", name) ?? name;
|
|
26
|
+
});
|
|
27
|
+
for (const name of names) {
|
|
28
|
+
cx.deferred.push(() => {
|
|
29
|
+
if (!cx.attributeSets.has(name)) {
|
|
30
|
+
throw xsltError("XTSE0710", `No attribute set ${name}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return names;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Compiles an xsl:attribute-set declaration into the registry.
|
|
39
|
+
* @param {Element} element
|
|
40
|
+
* @param {object} cx
|
|
41
|
+
*/
|
|
42
|
+
export function declareAttributeSet(element, cx) {
|
|
43
|
+
const name = clarkOf(cx.exprs.qname(required(element, "name"), element));
|
|
44
|
+
const children = cx.children(element);
|
|
45
|
+
for (const child of children) {
|
|
46
|
+
if (child.nodeType !== 1 || !isXsl(child, "attribute")) {
|
|
47
|
+
throw xsltError(
|
|
48
|
+
"XTSE0010",
|
|
49
|
+
"An attribute set may only contain xsl:attribute",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const part = {
|
|
54
|
+
uses: attributeSetNames(
|
|
55
|
+
element.getAttribute("use-attribute-sets") || undefined,
|
|
56
|
+
element,
|
|
57
|
+
cx,
|
|
58
|
+
),
|
|
59
|
+
body: compileBody(element, cx, cx.globalScope()),
|
|
60
|
+
precedence: cx.precedenceOf(element),
|
|
61
|
+
cx,
|
|
62
|
+
};
|
|
63
|
+
const parts = cx.attributeSets.get(name) ?? [];
|
|
64
|
+
parts.push(part);
|
|
65
|
+
parts.sort((a, b) => a.precedence - b.precedence);
|
|
66
|
+
cx.attributeSets.set(name, parts);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Adds the attributes of attribute sets to an element under construction.
|
|
71
|
+
* @param {string[]} names - Clark names
|
|
72
|
+
* @param {object} xc - XSLT context
|
|
73
|
+
* @param {object} out - Receiver of the element's content
|
|
74
|
+
* @param {import("../runtime/machine.js").Machine} machine
|
|
75
|
+
* @param {object} cx - Stylesheet compiler
|
|
76
|
+
* @param {Set<string>} [active] - Sets being applied (cycle detection)
|
|
77
|
+
* @param {boolean} [crossed] - The chain went through another package
|
|
78
|
+
*/
|
|
79
|
+
export function applyAttributeSets(
|
|
80
|
+
names,
|
|
81
|
+
xc,
|
|
82
|
+
out,
|
|
83
|
+
machine,
|
|
84
|
+
cx,
|
|
85
|
+
active,
|
|
86
|
+
crossed = false,
|
|
87
|
+
) {
|
|
88
|
+
const applying = active ?? new Set();
|
|
89
|
+
const context = derive(xc, { env: xc.tx.globalEnv });
|
|
90
|
+
for (const name of names) {
|
|
91
|
+
if (applying.has(name)) {
|
|
92
|
+
// a cycle made by overriding in another package shows only when
|
|
93
|
+
// the components are bound: a dynamic error (XSLT 3.0 10.2)
|
|
94
|
+
throw xsltError(
|
|
95
|
+
crossed ? "XTDE0640" : "XTSE0720",
|
|
96
|
+
`The attribute set ${name} uses itself`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
applying.add(name);
|
|
100
|
+
for (const part of cx.attributeSets.get(name)) {
|
|
101
|
+
const across = crossed || part.cx !== cx;
|
|
102
|
+
applyAttributeSets(
|
|
103
|
+
part.uses,
|
|
104
|
+
xc,
|
|
105
|
+
out,
|
|
106
|
+
machine,
|
|
107
|
+
part.cx,
|
|
108
|
+
applying,
|
|
109
|
+
across,
|
|
110
|
+
);
|
|
111
|
+
machine.runBody(part.body, context, out);
|
|
112
|
+
}
|
|
113
|
+
applying.delete(name);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:on-empty, xsl:on-non-empty and xsl:where-populated (XSLT 3.0
|
|
3
|
+
* section 8.4). The first two mark their step (`conditional`); the
|
|
4
|
+
* sequence constructor that holds them is run by
|
|
5
|
+
* runtime/conditional.js (see compileBody).
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/instructions/conditional
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { compileBody } from "../compiler/body.js";
|
|
11
|
+
import { isWhitespaceText } from "../compiler/children.js";
|
|
12
|
+
import { evaluate } from "../runtime/context.js";
|
|
13
|
+
import { isDeemedEmpty, stepItems } from "../runtime/conditional.js";
|
|
14
|
+
import { attr, isXsl, xsltError } from "../names.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Compiles the content of xsl:on-empty or xsl:on-non-empty, which is
|
|
18
|
+
* that of xsl:sequence.
|
|
19
|
+
* @param {Element} element
|
|
20
|
+
* @param {object} cx
|
|
21
|
+
* @param {object} scope
|
|
22
|
+
* @returns {Function}
|
|
23
|
+
*/
|
|
24
|
+
function compileContent(element, cx, scope) {
|
|
25
|
+
const select = attr(element, "select");
|
|
26
|
+
const children = cx.children(element).filter((c) => !isXsl(c, "fallback"));
|
|
27
|
+
if (select === undefined) {
|
|
28
|
+
const body = compileBody(element, cx, scope, children);
|
|
29
|
+
return (xc, out, machine) => machine.runBody(body, xc, out);
|
|
30
|
+
}
|
|
31
|
+
if (children.length > 0) {
|
|
32
|
+
throw xsltError(
|
|
33
|
+
"XTSE3185",
|
|
34
|
+
`xsl:${element.localName} cannot have select and content`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const expr = cx.exprs.xpath(select, element, scope.vars);
|
|
38
|
+
return (xc, out) => {
|
|
39
|
+
for (const item of evaluate(expr, xc)) out.item(item);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* xsl:on-empty: the last instruction of its sequence constructor.
|
|
45
|
+
* @param {Element} element
|
|
46
|
+
* @param {object} cx
|
|
47
|
+
* @param {object} scope
|
|
48
|
+
* @returns {Function}
|
|
49
|
+
*/
|
|
50
|
+
export function compileOnEmpty(element, cx, scope) {
|
|
51
|
+
const siblings = cx.children(element.parentNode);
|
|
52
|
+
const after = siblings.slice(siblings.indexOf(element) + 1);
|
|
53
|
+
const misplaced = after.some(
|
|
54
|
+
(next) =>
|
|
55
|
+
!isWhitespaceText(next) &&
|
|
56
|
+
!isXsl(next, "fallback") &&
|
|
57
|
+
!isXsl(next, "catch"),
|
|
58
|
+
);
|
|
59
|
+
if (misplaced) {
|
|
60
|
+
throw xsltError(
|
|
61
|
+
"XTSE0010",
|
|
62
|
+
"xsl:on-empty must be the last instruction of a sequence constructor",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const step = compileContent(element, cx, scope);
|
|
66
|
+
step.conditional = "empty";
|
|
67
|
+
return step;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* xsl:on-non-empty.
|
|
72
|
+
* @param {Element} element
|
|
73
|
+
* @param {object} cx
|
|
74
|
+
* @param {object} scope
|
|
75
|
+
* @returns {Function}
|
|
76
|
+
*/
|
|
77
|
+
export function compileOnNonEmpty(element, cx, scope) {
|
|
78
|
+
const step = compileContent(element, cx, scope);
|
|
79
|
+
step.conditional = "non-empty";
|
|
80
|
+
return step;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* xsl:where-populated: the result of the content without the items
|
|
85
|
+
* deemed empty.
|
|
86
|
+
* @param {Element} element
|
|
87
|
+
* @param {object} cx
|
|
88
|
+
* @param {object} scope
|
|
89
|
+
* @returns {Function}
|
|
90
|
+
*/
|
|
91
|
+
export function compileWherePopulated(element, cx, scope) {
|
|
92
|
+
const body = compileBody(element, cx, scope);
|
|
93
|
+
const run = (xc, out, machine) => machine.runBody(body, xc, out);
|
|
94
|
+
return (xc, out, machine) => {
|
|
95
|
+
for (const item of stepItems(run, xc, machine)) {
|
|
96
|
+
if (!isDeemedEmpty(item)) out.item(item);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|