@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,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functions on URIs (F&O 3.1 sections 5.4.10 to 5.4.12 and 8.1):
|
|
3
|
+
* encode-for-uri, iri-to-uri, escape-html-uri and resolve-uri, which
|
|
4
|
+
* implements the reference resolution of RFC 3986 section 5.2.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/functions/uri
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { XPathError } from "../errors.js";
|
|
10
|
+
import { AtomicValue } from "../xdm/atomic.js";
|
|
11
|
+
import { types } from "../xdm/types.js";
|
|
12
|
+
import { define, stringArg, stringItem } from "./support.js";
|
|
13
|
+
|
|
14
|
+
const encoder = new globalThis.TextEncoder();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Percent-encodes (UTF-8, upper-case hex) the codepoints that `keep`
|
|
18
|
+
* rejects.
|
|
19
|
+
* @param {string} text
|
|
20
|
+
* @param {(cp: number) => boolean} keep
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
export function percentEncode(text, keep) {
|
|
24
|
+
let result = "";
|
|
25
|
+
for (const char of text) {
|
|
26
|
+
if (keep(char.codePointAt(0))) {
|
|
27
|
+
result += char;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
for (const byte of encoder.encode(char)) {
|
|
31
|
+
result += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const unreserved = /^[A-Za-z0-9\-_.~]$/;
|
|
38
|
+
const notInUri = new Set([...'<>"{}|\\^`'].map((c) => c.codePointAt(0)));
|
|
39
|
+
|
|
40
|
+
/** @type {Record<string, (cp: number) => boolean>} kept codepoints */
|
|
41
|
+
const escapers = {
|
|
42
|
+
"encode-for-uri": (cp) => unreserved.test(String.fromCodePoint(cp)),
|
|
43
|
+
"iri-to-uri": (cp) => cp > 0x20 && cp < 0x7f && !notInUri.has(cp),
|
|
44
|
+
"escape-html-uri": (cp) => cp >= 0x20 && cp <= 0x7e,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const referencePattern =
|
|
48
|
+
/^(?:([^:/?#]*):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/s;
|
|
49
|
+
const schemePattern = /^[A-Za-z][A-Za-z0-9+.-]*$/;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Splits a URI reference into its RFC 3986 components.
|
|
53
|
+
* @param {string} uri
|
|
54
|
+
* @returns {{scheme?: string, authority?: string, path: string,
|
|
55
|
+
* query?: string, fragment?: string}}
|
|
56
|
+
* @throws {XPathError} FORG0002 for an invalid scheme or percent-encoding,
|
|
57
|
+
* or a "#" in the fragment
|
|
58
|
+
*/
|
|
59
|
+
function parseReference(uri) {
|
|
60
|
+
const [, scheme, authority, path, query, fragment] =
|
|
61
|
+
referencePattern.exec(uri);
|
|
62
|
+
if (
|
|
63
|
+
(scheme !== undefined && !schemePattern.test(scheme)) ||
|
|
64
|
+
/%(?![0-9A-Fa-f]{2})/.test(uri) ||
|
|
65
|
+
fragment?.includes("#")
|
|
66
|
+
) {
|
|
67
|
+
throw new XPathError("FORG0002", `Invalid URI ${uri}`);
|
|
68
|
+
}
|
|
69
|
+
return { scheme, authority, path, query, fragment };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* remove_dot_segments of RFC 3986 section 5.2.4.
|
|
74
|
+
* @param {string} path
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
export function removeDotSegments(path) {
|
|
78
|
+
const output = [];
|
|
79
|
+
const segments = path.split("/");
|
|
80
|
+
segments.forEach((segment, i) => {
|
|
81
|
+
const last = i === segments.length - 1;
|
|
82
|
+
if (segment === ".") {
|
|
83
|
+
if (last) output.push("");
|
|
84
|
+
} else if (segment === "..") {
|
|
85
|
+
if (output.length > 1 || (output.length === 1 && output[0] !== "")) {
|
|
86
|
+
output.pop();
|
|
87
|
+
}
|
|
88
|
+
if (last) output.push("");
|
|
89
|
+
} else {
|
|
90
|
+
output.push(segment);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return output.join("/");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolves a URI reference against an absolute base (RFC 3986 5.2.2).
|
|
98
|
+
* @param {string} relative
|
|
99
|
+
* @param {string} base
|
|
100
|
+
* @returns {string}
|
|
101
|
+
* @throws {XPathError} FORG0002 for invalid URIs, a relative base or a base
|
|
102
|
+
* with a fragment
|
|
103
|
+
*/
|
|
104
|
+
export function resolveUri(relative, base) {
|
|
105
|
+
const r = parseReference(relative);
|
|
106
|
+
if (r.scheme !== undefined) return relative;
|
|
107
|
+
const b = parseReference(base);
|
|
108
|
+
if (b.scheme === undefined || b.fragment !== undefined) {
|
|
109
|
+
throw new XPathError("FORG0002", `Invalid base URI ${base}`);
|
|
110
|
+
}
|
|
111
|
+
let { authority, path, query } = r;
|
|
112
|
+
if (authority === undefined) {
|
|
113
|
+
authority = b.authority;
|
|
114
|
+
if (path === "") {
|
|
115
|
+
path = b.path;
|
|
116
|
+
query ??= b.query;
|
|
117
|
+
} else if (!path.startsWith("/")) {
|
|
118
|
+
path =
|
|
119
|
+
b.authority !== undefined && b.path === ""
|
|
120
|
+
? `/${path}`
|
|
121
|
+
: b.path.slice(0, b.path.lastIndexOf("/") + 1) + path;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return (
|
|
125
|
+
`${b.scheme}:` +
|
|
126
|
+
(authority === undefined ? "" : `//${authority}`) +
|
|
127
|
+
removeDotSegments(path) +
|
|
128
|
+
(query === undefined ? "" : `?${query}`) +
|
|
129
|
+
(r.fragment === undefined ? "" : `#${r.fragment}`)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* fn:resolve-uri.
|
|
135
|
+
* @param {Array<*>[]} args - [$relative, $base?]
|
|
136
|
+
* @param {{staticBaseUri?: string}} context
|
|
137
|
+
* @returns {Array<*>}
|
|
138
|
+
*/
|
|
139
|
+
function resolveUriFunction([relative, base], context) {
|
|
140
|
+
if (relative.length === 0) return [];
|
|
141
|
+
const baseUri = base ? base[0].value : context.staticBaseUri;
|
|
142
|
+
// an absolute URI is returned as is, without a base
|
|
143
|
+
const absolute = parseReference(relative[0].value).scheme !== undefined;
|
|
144
|
+
if (!absolute && (baseUri === undefined || baseUri === null)) {
|
|
145
|
+
throw new XPathError("FONS0005", "The static base URI is absent");
|
|
146
|
+
}
|
|
147
|
+
return [
|
|
148
|
+
new AtomicValue(types.anyURI, resolveUri(relative[0].value, baseUri)),
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** @type {import("./support.js").FunctionDefinition[]} */
|
|
153
|
+
export const uriFunctions = [
|
|
154
|
+
...Object.entries(escapers).map(([local, keep]) =>
|
|
155
|
+
define(local, ["xs:string?"], "xs:string", ([s]) => [
|
|
156
|
+
stringItem(percentEncode(stringArg(s), keep)),
|
|
157
|
+
]),
|
|
158
|
+
),
|
|
159
|
+
define("resolve-uri", ["xs:string?"], "xs:anyURI?", resolveUriFunction),
|
|
160
|
+
define(
|
|
161
|
+
"resolve-uri",
|
|
162
|
+
["xs:string?", "xs:string"],
|
|
163
|
+
"xs:anyURI?",
|
|
164
|
+
resolveUriFunction,
|
|
165
|
+
),
|
|
166
|
+
];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fn:load-xquery-module (F&O 3.1, "Dynamic loading"): there is no XQuery
|
|
3
|
+
* processor, so every call raises FOQM0006 once its arguments are checked
|
|
4
|
+
* against the signature.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/functions/xqueryModule
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { XPathError } from "../errors.js";
|
|
10
|
+
import { define } from "./support.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @returns {never}
|
|
14
|
+
* @throws {XPathError} FOQM0006
|
|
15
|
+
*/
|
|
16
|
+
function noXQuery() {
|
|
17
|
+
throw new XPathError("FOQM0006", "No XQuery processor is available");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Function definitions. */
|
|
21
|
+
export const xqueryModuleFunctions = [
|
|
22
|
+
define("load-xquery-module", ["xs:string"], "map(*)", noXQuery),
|
|
23
|
+
define("load-xquery-module", ["xs:string", "map(*)"], "map(*)", noXQuery),
|
|
24
|
+
];
|
package/src/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tradik/xslt3: XSLT 3.0 and XPath 3.1 in JavaScript (in development).
|
|
3
|
+
*
|
|
4
|
+
* One engine for XSLT 3.0 and 2.0 stylesheets, and 1.0 ones in
|
|
5
|
+
* backwards-compatible mode; see docs/XSLT3.md for the design and the
|
|
6
|
+
* milestones. Public so far: XPath 3.1 (compileXPath, evaluateXPath) and
|
|
7
|
+
* Serialization 3.1 (serialize, serializeChunks, serializeToBytes) and
|
|
8
|
+
* XSLT (compileStylesheet, XSLTProcessor).
|
|
9
|
+
*
|
|
10
|
+
* @module @tradik/xslt3
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Version of this package, kept equal to package.json. */
|
|
14
|
+
export const VERSION = "1.0.0";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
compileXPath,
|
|
18
|
+
createFunctionLibrary,
|
|
19
|
+
defaultFunctionLibrary,
|
|
20
|
+
evaluateXPath,
|
|
21
|
+
FunctionLibrary,
|
|
22
|
+
readFileUri,
|
|
23
|
+
XPathError,
|
|
24
|
+
} from "./xpath/index.js";
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
serialize,
|
|
28
|
+
serializeChunks,
|
|
29
|
+
serializeToBytes,
|
|
30
|
+
} from "./serialize/index.js";
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
CompiledStylesheet,
|
|
34
|
+
compileStylesheet,
|
|
35
|
+
untypedAtomic,
|
|
36
|
+
versionMatches,
|
|
37
|
+
XSLTProcessor,
|
|
38
|
+
} from "./xslt/index.js";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arrays of XDM 3.1: immutable lists of members, each member a sequence.
|
|
3
|
+
* An array is also a function of arity 1 from a position (xs:integer,
|
|
4
|
+
* starting at 1) to the member there.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/items/array
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { XPathError } from "../errors.js";
|
|
10
|
+
import { ITEM_KIND } from "../xdm/atomic.js";
|
|
11
|
+
import { cast } from "../xdm/cast.js";
|
|
12
|
+
import { atomize } from "../xdm/nodes.js";
|
|
13
|
+
import { derivesFrom, types } from "../xdm/types.js";
|
|
14
|
+
|
|
15
|
+
/** An immutable XDM array. */
|
|
16
|
+
export class XdmArray {
|
|
17
|
+
/**
|
|
18
|
+
* @param {Array<Array>} [members] - Members (sequences); owned by the array
|
|
19
|
+
*/
|
|
20
|
+
constructor(members = []) {
|
|
21
|
+
this.members = members;
|
|
22
|
+
Object.freeze(this);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** @returns {"array"} the item kind */
|
|
26
|
+
get [ITEM_KIND]() {
|
|
27
|
+
return "array";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @returns {number} 1: an array is a function of one position */
|
|
31
|
+
get arity() {
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @returns {null} arrays are anonymous functions */
|
|
36
|
+
get name() {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** @returns {number} number of members */
|
|
41
|
+
get size() {
|
|
42
|
+
return this.members.length;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Member at a position.
|
|
47
|
+
* @param {bigint|number} position - 1-based
|
|
48
|
+
* @returns {Array} the member
|
|
49
|
+
* @throws {XPathError} FOAY0001 when the position is out of bounds
|
|
50
|
+
*/
|
|
51
|
+
get(position) {
|
|
52
|
+
const index = Number(position) - 1;
|
|
53
|
+
if (!(index >= 0 && index < this.members.length)) {
|
|
54
|
+
throw new XPathError(
|
|
55
|
+
"FOAY0001",
|
|
56
|
+
`Array index ${position} is out of bounds (size ${this.members.length})`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return this.members[index];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Calls the array as a function: `$array($position)`.
|
|
64
|
+
* @param {Array<Array>} args - One argument: a single xs:integer
|
|
65
|
+
* (xs:untypedAtomic is cast)
|
|
66
|
+
* @returns {Array} the member
|
|
67
|
+
* @throws {XPathError} XPTY0004 for another argument, FOAY0001 when out
|
|
68
|
+
* of bounds
|
|
69
|
+
*/
|
|
70
|
+
invoke(args) {
|
|
71
|
+
const values = atomize(args[0]);
|
|
72
|
+
let position = values[0];
|
|
73
|
+
if (values.length === 1 && position.type === types.untypedAtomic) {
|
|
74
|
+
position = cast(position, types.integer);
|
|
75
|
+
}
|
|
76
|
+
if (values.length !== 1 || !derivesFrom(position.type, types.integer)) {
|
|
77
|
+
throw new XPathError(
|
|
78
|
+
"XPTY0004",
|
|
79
|
+
"An array lookup needs exactly one xs:integer",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return this.get(position.value);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function items of XDM 3.1 other than maps and arrays: named function
|
|
3
|
+
* references, inline functions, partial applications and coerced functions.
|
|
4
|
+
*
|
|
5
|
+
* A function item is self-contained: `invoke(args)` applies the function
|
|
6
|
+
* conversion rules to its arguments and checks its result, using the
|
|
7
|
+
* static and dynamic context captured when the item was created.
|
|
8
|
+
*
|
|
9
|
+
* @module @tradik/xslt3/items/function
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { ITEM_KIND } from "../xdm/atomic.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Signature of a function item.
|
|
16
|
+
* @typedef {object} Signature
|
|
17
|
+
* @property {object[]} params - Compiled sequence types of the parameters
|
|
18
|
+
* (see xpath/eval/sequenceType.js)
|
|
19
|
+
* @property {object} returns - Compiled sequence type of the result
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** A function item. */
|
|
23
|
+
export class FunctionItem {
|
|
24
|
+
/**
|
|
25
|
+
* @param {object} init
|
|
26
|
+
* @param {import("../xdm/qname.js").QNameValue|null} [init.name] - Name,
|
|
27
|
+
* null for anonymous functions
|
|
28
|
+
* @param {number} init.arity - Number of parameters
|
|
29
|
+
* @param {Signature} init.signature - Parameter and result types
|
|
30
|
+
* @param {(args: Array<Array>) => Array} init.invoke - Implementation,
|
|
31
|
+
* called with one sequence per parameter
|
|
32
|
+
*/
|
|
33
|
+
constructor({ name = null, arity, signature, invoke }) {
|
|
34
|
+
this.name = name;
|
|
35
|
+
this.arity = arity;
|
|
36
|
+
this.signature = signature;
|
|
37
|
+
this.invoke = invoke;
|
|
38
|
+
Object.freeze(this);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** @returns {"function"} the item kind */
|
|
42
|
+
get [ITEM_KIND]() {
|
|
43
|
+
return "function";
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/items/map.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps of XDM 3.1: immutable sets of entries from atomic keys (compared
|
|
3
|
+
* with op:same-key, see mapKey.js) to sequences. A map is also a function
|
|
4
|
+
* of arity 1 that returns the value of a key, or the empty sequence.
|
|
5
|
+
*
|
|
6
|
+
* Entries keep their insertion order, which XDM leaves
|
|
7
|
+
* implementation-dependent.
|
|
8
|
+
*
|
|
9
|
+
* @module @tradik/xslt3/items/map
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { XPathError } from "../errors.js";
|
|
13
|
+
import { ITEM_KIND } from "../xdm/atomic.js";
|
|
14
|
+
import { atomize } from "../xdm/nodes.js";
|
|
15
|
+
import { mapKey } from "./mapKey.js";
|
|
16
|
+
|
|
17
|
+
/** An immutable XDM map. */
|
|
18
|
+
export class XdmMap {
|
|
19
|
+
/**
|
|
20
|
+
* @param {Map<string, {key: import("../xdm/atomic.js").AtomicValue, value: Array}>} [entries]
|
|
21
|
+
* - Entries by key string; owned by the new map
|
|
22
|
+
*/
|
|
23
|
+
constructor(entries = new Map()) {
|
|
24
|
+
this.entries = entries;
|
|
25
|
+
Object.freeze(this);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** @returns {"map"} the item kind */
|
|
29
|
+
get [ITEM_KIND]() {
|
|
30
|
+
return "map";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @returns {number} 1: a map is a function of one key */
|
|
34
|
+
get arity() {
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** @returns {null} maps are anonymous functions */
|
|
39
|
+
get name() {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** @returns {number} number of entries */
|
|
44
|
+
get size() {
|
|
45
|
+
return this.entries.size;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Builds a map from key/value pairs; a later duplicate key replaces the
|
|
50
|
+
* earlier one unless `onDuplicate` throws.
|
|
51
|
+
* @param {Iterable<[import("../xdm/atomic.js").AtomicValue, Array]>} pairs
|
|
52
|
+
* @param {(key: import("../xdm/atomic.js").AtomicValue) => void} [onDuplicate]
|
|
53
|
+
* @returns {XdmMap}
|
|
54
|
+
*/
|
|
55
|
+
static from(pairs, onDuplicate) {
|
|
56
|
+
const entries = new Map();
|
|
57
|
+
for (const [key, value] of pairs) {
|
|
58
|
+
const k = mapKey(key);
|
|
59
|
+
if (onDuplicate && entries.has(k)) onDuplicate(key);
|
|
60
|
+
entries.set(k, { key, value });
|
|
61
|
+
}
|
|
62
|
+
return new XdmMap(entries);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {import("../xdm/atomic.js").AtomicValue} key
|
|
67
|
+
* @returns {Array|undefined} the value of the key, undefined when absent
|
|
68
|
+
*/
|
|
69
|
+
get(key) {
|
|
70
|
+
return this.entries.get(mapKey(key))?.value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** @param {import("../xdm/atomic.js").AtomicValue} key @returns {boolean} */
|
|
74
|
+
has(key) {
|
|
75
|
+
return this.entries.has(mapKey(key));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @returns {import("../xdm/atomic.js").AtomicValue[]} the keys */
|
|
79
|
+
keys() {
|
|
80
|
+
return [...this.entries.values()].map((entry) => entry.key);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {import("../xdm/atomic.js").AtomicValue} key
|
|
85
|
+
* @param {Array} value
|
|
86
|
+
* @returns {XdmMap} a copy with the entry added or replaced
|
|
87
|
+
*/
|
|
88
|
+
put(key, value) {
|
|
89
|
+
const entries = new Map(this.entries);
|
|
90
|
+
entries.set(mapKey(key), { key, value });
|
|
91
|
+
return new XdmMap(entries);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {import("../xdm/atomic.js").AtomicValue[]} keys
|
|
96
|
+
* @returns {XdmMap} a copy without the keys
|
|
97
|
+
*/
|
|
98
|
+
remove(keys) {
|
|
99
|
+
const entries = new Map(this.entries);
|
|
100
|
+
for (const key of keys) entries.delete(mapKey(key));
|
|
101
|
+
return new XdmMap(entries);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Calls the map as a function: `$map($key)`.
|
|
106
|
+
* @param {Array<Array>} args - One argument: a single atomic value
|
|
107
|
+
* @returns {Array} the value, or the empty sequence
|
|
108
|
+
* @throws {XPathError} XPTY0004 when the argument is not one atomic value
|
|
109
|
+
*/
|
|
110
|
+
invoke(args) {
|
|
111
|
+
const key = atomize(args[0]);
|
|
112
|
+
if (key.length !== 1) {
|
|
113
|
+
throw new XPathError(
|
|
114
|
+
"XPTY0004",
|
|
115
|
+
"A map lookup needs exactly one atomic key",
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return this.get(key[0]) ?? [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map keys: the string under which a map stores an atomic key, equal for
|
|
3
|
+
* two keys exactly when they are the same key under op:same-key (F&O 3.1
|
|
4
|
+
* section 17.1.1):
|
|
5
|
+
*
|
|
6
|
+
* - strings, xs:anyURI and xs:untypedAtomic compare as codepoint strings;
|
|
7
|
+
* - numbers compare by exact mathematical value, whatever their type
|
|
8
|
+
* (the double 0.1 is not the decimal 0.1), NaN is the same key as NaN;
|
|
9
|
+
* - dates and times are equal when they are the same instant, but a value
|
|
10
|
+
* with a timezone is never the same key as one without;
|
|
11
|
+
* - durations compare by months and seconds, whatever their subtype;
|
|
12
|
+
* - other values are only the same key as values of the same primitive.
|
|
13
|
+
*
|
|
14
|
+
* @module @tradik/xslt3/items/mapKey
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Decimal } from "../xdm/decimal.js";
|
|
18
|
+
import { formatHexBinary } from "../xdm/binary.js";
|
|
19
|
+
import { localSeconds, timelineSeconds } from "../xdm/timeline.js";
|
|
20
|
+
|
|
21
|
+
const stringLike = new Set(["string", "anyURI", "untypedAtomic"]);
|
|
22
|
+
const numeric = new Set(["decimal", "float", "double"]);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Exact decimal value of a finite double.
|
|
26
|
+
* @param {number} n
|
|
27
|
+
* @returns {Decimal}
|
|
28
|
+
*/
|
|
29
|
+
export function exactDecimal(n) {
|
|
30
|
+
const view = new DataView(new ArrayBuffer(8));
|
|
31
|
+
view.setFloat64(0, n);
|
|
32
|
+
const high = view.getUint32(0);
|
|
33
|
+
const biased = (high >>> 20) & 0x7ff;
|
|
34
|
+
const fraction = (BigInt(high & 0xfffff) << 32n) | BigInt(view.getUint32(4));
|
|
35
|
+
const mantissa = biased === 0 ? fraction : fraction | (1n << 52n);
|
|
36
|
+
const exponent = (biased === 0 ? 1 : biased) - 1075;
|
|
37
|
+
const signed = n < 0 ? -mantissa : mantissa;
|
|
38
|
+
if (exponent >= 0) return Decimal.of(signed << BigInt(exponent));
|
|
39
|
+
return Decimal.of(signed * 5n ** BigInt(-exponent), -exponent);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Key string of a numeric value.
|
|
44
|
+
* @param {bigint|Decimal|number} value
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function numericKey(value) {
|
|
48
|
+
if (typeof value === "bigint") return `n${value}`;
|
|
49
|
+
if (typeof value === "object") return `n${value}`;
|
|
50
|
+
if (Number.isNaN(value)) return "nNaN";
|
|
51
|
+
if (!Number.isFinite(value)) return value > 0 ? "nINF" : "n-INF";
|
|
52
|
+
return `n${exactDecimal(value)}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Key string of an atomic map key.
|
|
57
|
+
* @param {import("../xdm/atomic.js").AtomicValue} key
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
export function mapKey(key) {
|
|
61
|
+
const primitive = key.type.primitive.localName;
|
|
62
|
+
const { value } = key;
|
|
63
|
+
if (stringLike.has(primitive)) return `s${value}`;
|
|
64
|
+
if (numeric.has(primitive)) return numericKey(value);
|
|
65
|
+
switch (primitive) {
|
|
66
|
+
case "boolean":
|
|
67
|
+
return `b${value}`;
|
|
68
|
+
case "duration":
|
|
69
|
+
return `d${value.months}:${value.seconds}`;
|
|
70
|
+
case "hexBinary":
|
|
71
|
+
case "base64Binary":
|
|
72
|
+
return `${primitive}${formatHexBinary(value)}`;
|
|
73
|
+
case "QName":
|
|
74
|
+
case "NOTATION":
|
|
75
|
+
return `${primitive}{${value.namespaceURI}}${value.localName}`;
|
|
76
|
+
default: {
|
|
77
|
+
const zoned = value.timezone !== null;
|
|
78
|
+
const seconds = zoned ? timelineSeconds(value, 0) : localSeconds(value);
|
|
79
|
+
return `${primitive}${zoned ? "Z" : "L"}${seconds}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XSLT and XQuery Serialization 3.1: turns an XDM sequence into text with
|
|
3
|
+
* the xml, xhtml, html, text, json or adaptive output method.
|
|
4
|
+
*
|
|
5
|
+
* ```js
|
|
6
|
+
* serialize(items, { method: "xml", indent: true }); // a string
|
|
7
|
+
* for (const chunk of serializeChunks(items, { method: "html" })) write(chunk);
|
|
8
|
+
* serializeToBytes(items, { encoding: "UTF-16" }); // a Uint8Array
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Parameters are given by their camelCase names (`omitXmlDeclaration`) or
|
|
12
|
+
* the hyphenated names of the specification (`"omit-xml-declaration"`);
|
|
13
|
+
* see params/settings.js for the values and the defaults. Errors are
|
|
14
|
+
* XPathErrors with the codes of Serialization 3.1 (SENR0001, SERE00xx,
|
|
15
|
+
* SEPM00xx, SESU00xx).
|
|
16
|
+
*
|
|
17
|
+
* @module @tradik/xslt3/serialize
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { DEFAULT_CHUNK_SIZE, OutputBuffer } from "./output/buffer.js";
|
|
21
|
+
import { encodeText } from "./output/encoding.js";
|
|
22
|
+
import { Expander } from "./output/expander.js";
|
|
23
|
+
import { MarkupWriter } from "./markup/writer.js";
|
|
24
|
+
import { AdaptiveWriter } from "./methods/adaptive.js";
|
|
25
|
+
import { JsonWriter } from "./methods/json.js";
|
|
26
|
+
import { writeText } from "./methods/text.js";
|
|
27
|
+
import { normalizeSettings } from "./params/settings.js";
|
|
28
|
+
import { normalizeSequence } from "./sequence.js";
|
|
29
|
+
|
|
30
|
+
export { DEFAULT_CHUNK_SIZE } from "./output/buffer.js";
|
|
31
|
+
export { normalizeSettings } from "./params/settings.js";
|
|
32
|
+
export { OUTPUT_NAMESPACE } from "./params/names.js";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {*} value - A sequence (JS array) or a single item
|
|
36
|
+
* @returns {Array}
|
|
37
|
+
*/
|
|
38
|
+
const toSequence = (value) => (Array.isArray(value) ? value : [value]);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Serializes nodes inside JSON or adaptive output: a whole serialization
|
|
42
|
+
* with another method, without an XML declaration.
|
|
43
|
+
* @param {import("./params/settings.js").Settings} settings
|
|
44
|
+
* @param {string} method
|
|
45
|
+
* @returns {(node: Node) => string}
|
|
46
|
+
*/
|
|
47
|
+
const nodeSerializer = (settings, method) => (node) => {
|
|
48
|
+
const nested = { ...settings, method, omitXmlDeclaration: true };
|
|
49
|
+
return [...chunksOf([node], nested, new OutputBuffer(Infinity))].join("");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {Array} sequence
|
|
54
|
+
* @param {import("./params/settings.js").Settings} settings
|
|
55
|
+
* @param {OutputBuffer} buffer
|
|
56
|
+
* @yields {string} the output in chunks
|
|
57
|
+
* @returns {Generator<string, void, void>}
|
|
58
|
+
*/
|
|
59
|
+
function* chunksOf(sequence, settings, buffer) {
|
|
60
|
+
const { method } = settings;
|
|
61
|
+
if (method === "json") {
|
|
62
|
+
const node = nodeSerializer(settings, settings.jsonNodeOutputMethod);
|
|
63
|
+
const writer = new JsonWriter(settings, new Expander(settings), node);
|
|
64
|
+
buffer.write(writer.sequence(sequence, 0));
|
|
65
|
+
} else if (method === "adaptive") {
|
|
66
|
+
const writer = new AdaptiveWriter(
|
|
67
|
+
new Expander(settings),
|
|
68
|
+
nodeSerializer(settings, "xml"),
|
|
69
|
+
);
|
|
70
|
+
const separator = settings.itemSeparator ?? "\n";
|
|
71
|
+
sequence.forEach((item, index) => {
|
|
72
|
+
buffer.write((index ? separator : "") + writer.item(item));
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
const entries = normalizeSequence(sequence, settings.itemSeparator);
|
|
76
|
+
yield* method === "text"
|
|
77
|
+
? writeText(entries, settings, buffer)
|
|
78
|
+
: new MarkupWriter(settings, buffer).run(entries);
|
|
79
|
+
}
|
|
80
|
+
const rest = buffer.take();
|
|
81
|
+
if (rest) yield rest;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Serializes a sequence in chunks, as the output is produced, so a large
|
|
86
|
+
* result can be streamed.
|
|
87
|
+
* @param {*} sequence - XDM items (array) or one item
|
|
88
|
+
* @param {Record<string, *>} [params] - Serialization parameters
|
|
89
|
+
* @param {{chunkSize?: number}} [options] - Chunk size in UTF-16 code
|
|
90
|
+
* units (default {@link DEFAULT_CHUNK_SIZE}); a chunk can be longer
|
|
91
|
+
* when one text node or attribute is
|
|
92
|
+
* @returns {Generator<string, void, void>} the chunks
|
|
93
|
+
* @throws {import("../errors.js").XPathError} serialization errors (on
|
|
94
|
+
* creation for parameter errors, while iterating for the others)
|
|
95
|
+
*/
|
|
96
|
+
export function serializeChunks(sequence, params = {}, options = {}) {
|
|
97
|
+
const settings = normalizeSettings(params);
|
|
98
|
+
const buffer = new OutputBuffer(options.chunkSize ?? DEFAULT_CHUNK_SIZE);
|
|
99
|
+
return chunksOf(toSequence(sequence), settings, buffer);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Serializes a sequence to a string.
|
|
104
|
+
* @param {*} sequence - XDM items (array) or one item
|
|
105
|
+
* @param {Record<string, *>} [params] - Serialization parameters
|
|
106
|
+
* @returns {string}
|
|
107
|
+
* @throws {import("../errors.js").XPathError} serialization errors
|
|
108
|
+
* @example serialize([doc], { method: "xml", omitXmlDeclaration: true })
|
|
109
|
+
*/
|
|
110
|
+
export function serialize(sequence, params = {}) {
|
|
111
|
+
const settings = normalizeSettings(params);
|
|
112
|
+
const buffer = new OutputBuffer(Infinity);
|
|
113
|
+
return [...chunksOf(toSequence(sequence), settings, buffer)].join("");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Serializes a sequence to bytes in the requested encoding, with a byte
|
|
118
|
+
* order mark when byte-order-mark is set (by default for "UTF-16").
|
|
119
|
+
* @param {*} sequence - XDM items (array) or one item
|
|
120
|
+
* @param {Record<string, *>} [params] - Serialization parameters
|
|
121
|
+
* @returns {Uint8Array}
|
|
122
|
+
* @throws {import("../errors.js").XPathError} serialization errors
|
|
123
|
+
*/
|
|
124
|
+
export function serializeToBytes(sequence, params = {}) {
|
|
125
|
+
const settings = normalizeSettings(params);
|
|
126
|
+
const buffer = new OutputBuffer(Infinity);
|
|
127
|
+
const text = [...chunksOf(toSequence(sequence), settings, buffer)].join("");
|
|
128
|
+
return encodeText(text, settings.encoding, settings.byteOrderMark);
|
|
129
|
+
}
|