@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,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser of the XPath regular expression grammar (XSD 1.1 regExp with the
|
|
3
|
+
* F&O 3.1 additions: ^ $ anchors, reluctant quantifiers, back-references,
|
|
4
|
+
* non-capturing groups), producing JS RegExp source for the `u` flag.
|
|
5
|
+
* Character classes and escapes are handled by charClass.js.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/functions/regex/parser
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { parseCharClass } from "./charClass.js";
|
|
11
|
+
import { jsChar, parseEscape, regexError } from "./escapes.js";
|
|
12
|
+
import { RegexReader } from "./reader.js";
|
|
13
|
+
|
|
14
|
+
const isDigit = (c) => c !== undefined && c >= "0" && c <= "9";
|
|
15
|
+
|
|
16
|
+
/** Recursive-descent translator of one pattern to JS source. */
|
|
17
|
+
export class RegexParser {
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} pattern
|
|
20
|
+
* @param {{dotAll: boolean, multiLine: boolean, caseless: boolean}} options
|
|
21
|
+
* - The s and m flags; caseless: categories ignore the i flag
|
|
22
|
+
*/
|
|
23
|
+
constructor(pattern, options) {
|
|
24
|
+
this.reader = new RegexReader(pattern, options.caseless);
|
|
25
|
+
this.options = options;
|
|
26
|
+
this.groups = 0;
|
|
27
|
+
this.parents = [0];
|
|
28
|
+
this.open = [];
|
|
29
|
+
this.closed = new Set();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @returns {string} the translation of the whole pattern */
|
|
33
|
+
translate() {
|
|
34
|
+
const source = this.alternation();
|
|
35
|
+
if (!this.reader.atEnd()) regexError("unmatched )");
|
|
36
|
+
return source;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** @returns {string} branch ("|" branch)* */
|
|
40
|
+
alternation() {
|
|
41
|
+
const branches = [this.branch()];
|
|
42
|
+
while (this.reader.peek() === "|") {
|
|
43
|
+
this.reader.next();
|
|
44
|
+
branches.push(this.branch());
|
|
45
|
+
}
|
|
46
|
+
return branches.join("|");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @returns {string} a sequence of pieces */
|
|
50
|
+
branch() {
|
|
51
|
+
let source = "";
|
|
52
|
+
for (;;) {
|
|
53
|
+
const c = this.reader.peek();
|
|
54
|
+
if (c === undefined || c === "|" || c === ")") return source;
|
|
55
|
+
source += this.atom() + this.quantifier();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** @returns {string} one atom */
|
|
60
|
+
atom() {
|
|
61
|
+
const { reader, options } = this;
|
|
62
|
+
const c = reader.next();
|
|
63
|
+
switch (c) {
|
|
64
|
+
case "(":
|
|
65
|
+
return this.group();
|
|
66
|
+
case "[":
|
|
67
|
+
return parseCharClass(reader);
|
|
68
|
+
case ".":
|
|
69
|
+
return options.dotAll ? "[^]" : "[^\\n\\r]";
|
|
70
|
+
case "^":
|
|
71
|
+
// a line starts after any \n except one that ends the string
|
|
72
|
+
return options.multiLine ? "(?:^|(?<=\\n)(?!$))" : "(?:^)";
|
|
73
|
+
case "$":
|
|
74
|
+
return options.multiLine ? "(?:$|(?=\\n))" : "(?:$)";
|
|
75
|
+
case "\\":
|
|
76
|
+
return isDigit(reader.peek()) ? this.backReference() : escape(reader);
|
|
77
|
+
default:
|
|
78
|
+
if ("?*+{}]".includes(c)) regexError(`unexpected ${c}`);
|
|
79
|
+
return jsChar(c.codePointAt(0));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** @returns {string} a group, the reader being after "(" */
|
|
84
|
+
group() {
|
|
85
|
+
const { reader } = this;
|
|
86
|
+
let source;
|
|
87
|
+
if (reader.peek() === "?") {
|
|
88
|
+
reader.next();
|
|
89
|
+
if (reader.next() !== ":") regexError("unsupported group syntax (?");
|
|
90
|
+
source = `(?:${this.alternation()})`;
|
|
91
|
+
} else {
|
|
92
|
+
const number = ++this.groups;
|
|
93
|
+
this.parents[number] = this.open.at(-1) ?? 0;
|
|
94
|
+
this.open.push(number);
|
|
95
|
+
source = `(${this.alternation()})`;
|
|
96
|
+
this.open.pop();
|
|
97
|
+
this.closed.add(number);
|
|
98
|
+
}
|
|
99
|
+
if (reader.next() !== ")") regexError("missing )");
|
|
100
|
+
return source;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** @returns {string} a back-reference, the reader being on its digits */
|
|
104
|
+
backReference() {
|
|
105
|
+
const { reader } = this;
|
|
106
|
+
if (reader.peek() === "0") regexError("\\0 is not a back-reference");
|
|
107
|
+
let number = Number(reader.next());
|
|
108
|
+
while (
|
|
109
|
+
isDigit(reader.peek()) &&
|
|
110
|
+
number * 10 + Number(reader.peek()) <= this.groups
|
|
111
|
+
) {
|
|
112
|
+
number = number * 10 + Number(reader.next());
|
|
113
|
+
}
|
|
114
|
+
if (!this.closed.has(number)) {
|
|
115
|
+
regexError(`back-reference \\${number} to a group not closed before it`);
|
|
116
|
+
}
|
|
117
|
+
return `(?:\\${number})`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** @returns {string} an optional quantifier with its reluctant mark */
|
|
121
|
+
quantifier() {
|
|
122
|
+
const { reader } = this;
|
|
123
|
+
const c = reader.peek();
|
|
124
|
+
let source;
|
|
125
|
+
if (c === "?" || c === "*" || c === "+") {
|
|
126
|
+
source = reader.next();
|
|
127
|
+
} else if (c === "{") {
|
|
128
|
+
reader.next();
|
|
129
|
+
source = `{${this.bounds()}}`;
|
|
130
|
+
} else {
|
|
131
|
+
return "";
|
|
132
|
+
}
|
|
133
|
+
if (reader.peek() === "?") source += reader.next();
|
|
134
|
+
return source;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** @returns {string} "n", "n," or "n,m" of a {..} quantifier */
|
|
138
|
+
bounds() {
|
|
139
|
+
const { reader } = this;
|
|
140
|
+
const digits = () => {
|
|
141
|
+
let text = "";
|
|
142
|
+
while (isDigit(reader.peek())) text += reader.next();
|
|
143
|
+
return text;
|
|
144
|
+
};
|
|
145
|
+
const min = digits();
|
|
146
|
+
let text = min;
|
|
147
|
+
if (reader.peek() === ",") {
|
|
148
|
+
reader.next();
|
|
149
|
+
const max = digits();
|
|
150
|
+
if (max !== "" && BigInt(max) < BigInt(min || "0")) {
|
|
151
|
+
regexError("quantifier {n,m} with m < n");
|
|
152
|
+
}
|
|
153
|
+
text += `,${max}`;
|
|
154
|
+
}
|
|
155
|
+
if (min === "" || reader.next() !== "}") regexError("invalid quantifier");
|
|
156
|
+
return text;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* An escape outside a class as a JS atom.
|
|
162
|
+
* @param {RegexReader} reader
|
|
163
|
+
* @returns {string}
|
|
164
|
+
*/
|
|
165
|
+
function escape(reader) {
|
|
166
|
+
const item = parseEscape(reader);
|
|
167
|
+
if (item.char !== undefined) return item.set;
|
|
168
|
+
return item.atom ?? `[${item.set}]`;
|
|
169
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cursor over the codepoints of a regular expression.
|
|
3
|
+
*
|
|
4
|
+
* @module @tradik/xslt3/functions/regex/reader
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Reads a pattern codepoint by codepoint. */
|
|
8
|
+
export class RegexReader {
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} pattern
|
|
11
|
+
* @param {boolean} [caseless=false] - Whether the i flag is set and JS
|
|
12
|
+
* supports the (?-i:...) modifier, so categories can ignore it
|
|
13
|
+
*/
|
|
14
|
+
constructor(pattern, caseless = false) {
|
|
15
|
+
this.chars = Array.from(pattern);
|
|
16
|
+
this.pos = 0;
|
|
17
|
+
this.caseless = caseless;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {number} [offset=0]
|
|
22
|
+
* @returns {string|undefined} the character at the cursor plus offset
|
|
23
|
+
*/
|
|
24
|
+
peek(offset = 0) {
|
|
25
|
+
return this.chars[this.pos + offset];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** @returns {string|undefined} the character at the cursor, consumed */
|
|
29
|
+
next() {
|
|
30
|
+
return this.chars[this.pos++];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @returns {boolean} whether the whole pattern has been read */
|
|
34
|
+
atEnd() {
|
|
35
|
+
return this.pos >= this.chars.length;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fn:matches, fn:replace and fn:tokenize (F&O 3.1 sections 5.6.3 to
|
|
3
|
+
* 5.6.5).
|
|
4
|
+
*
|
|
5
|
+
* @module @tradik/xslt3/functions/regex/regexFunctions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { XPathError } from "../../errors.js";
|
|
9
|
+
import { normalizeWhitespace } from "../../xdm/strings.js";
|
|
10
|
+
import { booleanItem, define, stringArg, stringItem } from "../support.js";
|
|
11
|
+
import {
|
|
12
|
+
allMatches,
|
|
13
|
+
compileRegex,
|
|
14
|
+
rejectEmptyMatch,
|
|
15
|
+
testRegex,
|
|
16
|
+
} from "./compile.js";
|
|
17
|
+
|
|
18
|
+
/** @param {Array<*>|undefined} flags @returns {string} the flags argument */
|
|
19
|
+
const flagsArg = (flags) => (flags === undefined ? "" : flags[0].value);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parses a replacement string into literal text and group references.
|
|
23
|
+
* @param {string} replacement
|
|
24
|
+
* @param {number} groups - Number of capturing groups of the pattern
|
|
25
|
+
* @returns {Array<string|number>} literal strings and group numbers
|
|
26
|
+
* @throws {XPathError} FORX0004 for a "\" or "$" not used as an escape or
|
|
27
|
+
* a group reference
|
|
28
|
+
*/
|
|
29
|
+
export function parseReplacement(replacement, groups) {
|
|
30
|
+
const parts = [];
|
|
31
|
+
const isDigit = (c) => c >= "0" && c <= "9";
|
|
32
|
+
for (let i = 0; i < replacement.length; i++) {
|
|
33
|
+
const c = replacement[i];
|
|
34
|
+
const next = replacement[i + 1] ?? "";
|
|
35
|
+
if (c === "\\" && (next === "\\" || next === "$")) {
|
|
36
|
+
parts.push(next);
|
|
37
|
+
i++;
|
|
38
|
+
} else if (c === "$" && isDigit(next)) {
|
|
39
|
+
let number = Number(next);
|
|
40
|
+
i++;
|
|
41
|
+
while (
|
|
42
|
+
isDigit(replacement[i + 1] ?? "") &&
|
|
43
|
+
number * 10 + Number(replacement[i + 1]) <= groups
|
|
44
|
+
) {
|
|
45
|
+
number = number * 10 + Number(replacement[++i]);
|
|
46
|
+
}
|
|
47
|
+
parts.push(number);
|
|
48
|
+
} else if (c === "\\" || c === "$") {
|
|
49
|
+
throw new XPathError(
|
|
50
|
+
"FORX0004",
|
|
51
|
+
`Invalid replacement string: ${replacement}`,
|
|
52
|
+
);
|
|
53
|
+
} else {
|
|
54
|
+
parts.push(c);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return parts;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* fn:replace on strings.
|
|
62
|
+
* @param {string} input
|
|
63
|
+
* @param {string} pattern
|
|
64
|
+
* @param {string} replacement
|
|
65
|
+
* @param {string} [flags=""]
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
export function replace(input, pattern, replacement, flags = "") {
|
|
69
|
+
const compiled = compileRegex(pattern, flags);
|
|
70
|
+
const parts = compiled.literal
|
|
71
|
+
? [replacement]
|
|
72
|
+
: parseReplacement(replacement, compiled.groups);
|
|
73
|
+
rejectEmptyMatch(compiled);
|
|
74
|
+
let result = "";
|
|
75
|
+
let last = 0;
|
|
76
|
+
for (const match of allMatches(compiled, input)) {
|
|
77
|
+
result += input.slice(last, match.index);
|
|
78
|
+
for (const part of parts) {
|
|
79
|
+
result += typeof part === "number" ? (match[part] ?? "") : part;
|
|
80
|
+
}
|
|
81
|
+
last = match.index + match[0].length;
|
|
82
|
+
}
|
|
83
|
+
return result + input.slice(last);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* fn:tokenize on strings (the two- and three-argument forms).
|
|
88
|
+
* @param {string} input
|
|
89
|
+
* @param {string} pattern
|
|
90
|
+
* @param {string} [flags=""]
|
|
91
|
+
* @returns {string[]}
|
|
92
|
+
*/
|
|
93
|
+
export function tokenize(input, pattern, flags = "") {
|
|
94
|
+
const compiled = compileRegex(pattern, flags);
|
|
95
|
+
rejectEmptyMatch(compiled);
|
|
96
|
+
if (input === "") return [];
|
|
97
|
+
const tokens = [];
|
|
98
|
+
let last = 0;
|
|
99
|
+
for (const match of allMatches(compiled, input)) {
|
|
100
|
+
tokens.push(input.slice(last, match.index));
|
|
101
|
+
last = match.index + match[0].length;
|
|
102
|
+
}
|
|
103
|
+
tokens.push(input.slice(last));
|
|
104
|
+
return tokens;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const matchesImpl = ([input, [pattern], flags]) => [
|
|
108
|
+
booleanItem(
|
|
109
|
+
testRegex(compileRegex(pattern.value, flagsArg(flags)), stringArg(input)),
|
|
110
|
+
),
|
|
111
|
+
];
|
|
112
|
+
const replaceImpl = ([input, [pattern], [replacement], flags]) => [
|
|
113
|
+
stringItem(
|
|
114
|
+
replace(
|
|
115
|
+
stringArg(input),
|
|
116
|
+
pattern.value,
|
|
117
|
+
replacement.value,
|
|
118
|
+
flagsArg(flags),
|
|
119
|
+
),
|
|
120
|
+
),
|
|
121
|
+
];
|
|
122
|
+
const tokenizeImpl = ([input, [pattern], flags]) =>
|
|
123
|
+
tokenize(stringArg(input), pattern.value, flagsArg(flags)).map(stringItem);
|
|
124
|
+
|
|
125
|
+
const S = "xs:string";
|
|
126
|
+
const S_OPT = "xs:string?";
|
|
127
|
+
|
|
128
|
+
/** @type {import("../support.js").FunctionDefinition[]} */
|
|
129
|
+
export const regexFunctions = [
|
|
130
|
+
define("matches", [S_OPT, S], "xs:boolean", matchesImpl),
|
|
131
|
+
define("matches", [S_OPT, S, S], "xs:boolean", matchesImpl),
|
|
132
|
+
define("replace", [S_OPT, S, S], S, replaceImpl),
|
|
133
|
+
define("replace", [S_OPT, S, S, S], S, replaceImpl),
|
|
134
|
+
define("tokenize", [S_OPT], "xs:string*", ([input]) => {
|
|
135
|
+
const text = normalizeWhitespace(stringArg(input), "collapse");
|
|
136
|
+
return text === "" ? [] : text.split(" ").map(stringItem);
|
|
137
|
+
}),
|
|
138
|
+
define("tokenize", [S_OPT, S], "xs:string*", tokenizeImpl),
|
|
139
|
+
define("tokenize", [S_OPT, S, S], "xs:string*", tokenizeImpl),
|
|
140
|
+
];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translator of XPath 3.1 regular expressions (F&O 3.1 section 5.6.1:
|
|
3
|
+
* XSD 1.1 regular expressions plus ^ and $ anchors, reluctant quantifiers,
|
|
4
|
+
* back-references and non-capturing groups) and their flags (s, m, i, x,
|
|
5
|
+
* q) into JavaScript RegExp source for the `u` flag.
|
|
6
|
+
*
|
|
7
|
+
* Semantics kept from XPath rather than JS: "." excludes only \n and \r
|
|
8
|
+
* (everything with the s flag), multi-line ^ and $ only see \n as a line
|
|
9
|
+
* end, \d \w \s \i \c follow XSD, and lookaround, \b, \x and other JS-only
|
|
10
|
+
* syntax are rejected with FORX0002. JS's own `s` and `m` flags are never
|
|
11
|
+
* used; their effects are written into the expression.
|
|
12
|
+
*
|
|
13
|
+
* @module @tradik/xslt3/functions/regex/translate
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { XPathError } from "../../errors.js";
|
|
17
|
+
import { jsChar } from "./escapes.js";
|
|
18
|
+
import { RegexParser } from "./parser.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} TranslatedRegex
|
|
22
|
+
* @property {string} source - JS RegExp source
|
|
23
|
+
* @property {string} flags - JS flags: "u" or "iu"
|
|
24
|
+
* @property {number} groups - Number of capturing groups
|
|
25
|
+
* @property {number[]} parents - Enclosing group of each group (index =
|
|
26
|
+
* group number, 0 for the whole match)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Whether JS supports the (?-i:...) modifier (V8 12.5, Node 23). */
|
|
30
|
+
export const MODIFIERS = (() => {
|
|
31
|
+
try {
|
|
32
|
+
return new RegExp("(?-i:a)", "iu").test("a");
|
|
33
|
+
/* node:coverage ignore next 3 */
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
})();
|
|
38
|
+
|
|
39
|
+
const XML_SPACE = new Set([" ", "\t", "\n", "\r"]);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Removes whitespace outside character classes (the x flag).
|
|
43
|
+
* @param {string} pattern
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
export function stripWhitespace(pattern) {
|
|
47
|
+
let result = "";
|
|
48
|
+
let depth = 0;
|
|
49
|
+
const chars = Array.from(pattern);
|
|
50
|
+
for (let i = 0; i < chars.length; i++) {
|
|
51
|
+
const c = chars[i];
|
|
52
|
+
if (c === "\\") {
|
|
53
|
+
// the escaped character is the next one after removed whitespace
|
|
54
|
+
if (depth === 0) {
|
|
55
|
+
while (XML_SPACE.has(chars[i + 1])) i++;
|
|
56
|
+
}
|
|
57
|
+
result += c + (chars[++i] ?? "");
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (c === "[") depth++;
|
|
61
|
+
else if (c === "]" && depth > 0) depth--;
|
|
62
|
+
if (depth > 0 || !XML_SPACE.has(c)) result += c;
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Translates an XPath regular expression and its flags.
|
|
69
|
+
* @param {string} pattern
|
|
70
|
+
* @param {string} [flags=""]
|
|
71
|
+
* @returns {TranslatedRegex}
|
|
72
|
+
* @throws {XPathError} FORX0001 for invalid flags, FORX0002 for an invalid
|
|
73
|
+
* pattern
|
|
74
|
+
*/
|
|
75
|
+
export function translateRegex(pattern, flags = "") {
|
|
76
|
+
if (!/^[smixq]*$/.test(flags)) {
|
|
77
|
+
throw new XPathError(
|
|
78
|
+
"FORX0001",
|
|
79
|
+
`Invalid regular expression flags "${flags}"`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
const jsFlags = flags.includes("i") ? "iu" : "u";
|
|
83
|
+
if (flags.includes("q")) {
|
|
84
|
+
const source = Array.from(pattern, (c) => jsChar(c.codePointAt(0))).join(
|
|
85
|
+
"",
|
|
86
|
+
);
|
|
87
|
+
return { source, flags: jsFlags, groups: 0, parents: [0] };
|
|
88
|
+
}
|
|
89
|
+
const text = flags.includes("x") ? stripWhitespace(pattern) : pattern;
|
|
90
|
+
const translator = new RegexParser(text, {
|
|
91
|
+
dotAll: flags.includes("s"),
|
|
92
|
+
multiLine: flags.includes("m"),
|
|
93
|
+
caseless: flags.includes("i") && MODIFIERS,
|
|
94
|
+
});
|
|
95
|
+
const source = translator.translate();
|
|
96
|
+
return {
|
|
97
|
+
source,
|
|
98
|
+
flags: jsFlags,
|
|
99
|
+
groups: translator.groups,
|
|
100
|
+
parents: translator.parents,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unicode block ranges for the regular expression escapes \p{IsBlock}
|
|
3
|
+
* (XSD 1.1 Part 2 appendix G.4.2.3), generated from Blocks.txt of
|
|
4
|
+
* Unicode 15.0. Names have spaces and underscores removed; hyphens are
|
|
5
|
+
* kept ("IsLatin-1Supplement").
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/functions/regex/unicodeBlocks
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** "Name:start-end" entries (hex), separated by semicolons. */
|
|
11
|
+
const TABLE =
|
|
12
|
+
"BasicLatin:0-7f;Latin-1Supplement:80-ff;LatinExtended-A:100-17f;" +
|
|
13
|
+
"LatinExtended-B:180-24f;IPAExtensions:250-2af;" +
|
|
14
|
+
"SpacingModifierLetters:2b0-2ff;CombiningDiacriticalMarks:300-36f;" +
|
|
15
|
+
"GreekandCoptic:370-3ff;Cyrillic:400-4ff;CyrillicSupplement:500-52f;" +
|
|
16
|
+
"Armenian:530-58f;Hebrew:590-5ff;Arabic:600-6ff;Syriac:700-74f;" +
|
|
17
|
+
"ArabicSupplement:750-77f;Thaana:780-7bf;NKo:7c0-7ff;Samaritan:800-83f;" +
|
|
18
|
+
"Mandaic:840-85f;SyriacSupplement:860-86f;ArabicExtended-B:870-89f;" +
|
|
19
|
+
"ArabicExtended-A:8a0-8ff;Devanagari:900-97f;Bengali:980-9ff;" +
|
|
20
|
+
"Gurmukhi:a00-a7f;Gujarati:a80-aff;Oriya:b00-b7f;Tamil:b80-bff;" +
|
|
21
|
+
"Telugu:c00-c7f;Kannada:c80-cff;Malayalam:d00-d7f;Sinhala:d80-dff;" +
|
|
22
|
+
"Thai:e00-e7f;Lao:e80-eff;Tibetan:f00-fff;Myanmar:1000-109f;" +
|
|
23
|
+
"Georgian:10a0-10ff;HangulJamo:1100-11ff;Ethiopic:1200-137f;" +
|
|
24
|
+
"EthiopicSupplement:1380-139f;Cherokee:13a0-13ff;" +
|
|
25
|
+
"UnifiedCanadianAboriginalSyllabics:1400-167f;Ogham:1680-169f;" +
|
|
26
|
+
"Runic:16a0-16ff;Tagalog:1700-171f;Hanunoo:1720-173f;Buhid:1740-175f;" +
|
|
27
|
+
"Tagbanwa:1760-177f;Khmer:1780-17ff;Mongolian:1800-18af;" +
|
|
28
|
+
"UnifiedCanadianAboriginalSyllabicsExtended:18b0-18ff;Limbu:1900-194f;" +
|
|
29
|
+
"TaiLe:1950-197f;NewTaiLue:1980-19df;KhmerSymbols:19e0-19ff;" +
|
|
30
|
+
"Buginese:1a00-1a1f;TaiTham:1a20-1aaf;" +
|
|
31
|
+
"CombiningDiacriticalMarksExtended:1ab0-1aff;Balinese:1b00-1b7f;" +
|
|
32
|
+
"Sundanese:1b80-1bbf;Batak:1bc0-1bff;Lepcha:1c00-1c4f;OlChiki:1c50-1c7f;" +
|
|
33
|
+
"CyrillicExtended-C:1c80-1c8f;GeorgianExtended:1c90-1cbf;" +
|
|
34
|
+
"SundaneseSupplement:1cc0-1ccf;VedicExtensions:1cd0-1cff;" +
|
|
35
|
+
"PhoneticExtensions:1d00-1d7f;PhoneticExtensionsSupplement:1d80-1dbf;" +
|
|
36
|
+
"CombiningDiacriticalMarksSupplement:1dc0-1dff;" +
|
|
37
|
+
"LatinExtendedAdditional:1e00-1eff;GreekExtended:1f00-1fff;" +
|
|
38
|
+
"GeneralPunctuation:2000-206f;SuperscriptsandSubscripts:2070-209f;" +
|
|
39
|
+
"CurrencySymbols:20a0-20cf;CombiningDiacriticalMarksforSymbols:20d0-20ff;" +
|
|
40
|
+
"LetterlikeSymbols:2100-214f;NumberForms:2150-218f;Arrows:2190-21ff;" +
|
|
41
|
+
"MathematicalOperators:2200-22ff;MiscellaneousTechnical:2300-23ff;" +
|
|
42
|
+
"ControlPictures:2400-243f;OpticalCharacterRecognition:2440-245f;" +
|
|
43
|
+
"EnclosedAlphanumerics:2460-24ff;BoxDrawing:2500-257f;" +
|
|
44
|
+
"BlockElements:2580-259f;GeometricShapes:25a0-25ff;" +
|
|
45
|
+
"MiscellaneousSymbols:2600-26ff;Dingbats:2700-27bf;" +
|
|
46
|
+
"MiscellaneousMathematicalSymbols-A:27c0-27ef;" +
|
|
47
|
+
"SupplementalArrows-A:27f0-27ff;BraillePatterns:2800-28ff;" +
|
|
48
|
+
"SupplementalArrows-B:2900-297f;" +
|
|
49
|
+
"MiscellaneousMathematicalSymbols-B:2980-29ff;" +
|
|
50
|
+
"SupplementalMathematicalOperators:2a00-2aff;" +
|
|
51
|
+
"MiscellaneousSymbolsandArrows:2b00-2bff;Glagolitic:2c00-2c5f;" +
|
|
52
|
+
"LatinExtended-C:2c60-2c7f;Coptic:2c80-2cff;GeorgianSupplement:2d00-2d2f;" +
|
|
53
|
+
"Tifinagh:2d30-2d7f;EthiopicExtended:2d80-2ddf;CyrillicExtended-A:2de0-2dff;" +
|
|
54
|
+
"SupplementalPunctuation:2e00-2e7f;CJKRadicalsSupplement:2e80-2eff;" +
|
|
55
|
+
"KangxiRadicals:2f00-2fdf;IdeographicDescriptionCharacters:2ff0-2fff;" +
|
|
56
|
+
"CJKSymbolsandPunctuation:3000-303f;Hiragana:3040-309f;Katakana:30a0-30ff;" +
|
|
57
|
+
"Bopomofo:3100-312f;HangulCompatibilityJamo:3130-318f;Kanbun:3190-319f;" +
|
|
58
|
+
"BopomofoExtended:31a0-31bf;CJKStrokes:31c0-31ef;" +
|
|
59
|
+
"KatakanaPhoneticExtensions:31f0-31ff;EnclosedCJKLettersandMonths:3200-32ff;" +
|
|
60
|
+
"CJKCompatibility:3300-33ff;CJKUnifiedIdeographsExtensionA:3400-4dbf;" +
|
|
61
|
+
"YijingHexagramSymbols:4dc0-4dff;CJKUnifiedIdeographs:4e00-9fff;" +
|
|
62
|
+
"YiSyllables:a000-a48f;YiRadicals:a490-a4cf;Lisu:a4d0-a4ff;Vai:a500-a63f;" +
|
|
63
|
+
"CyrillicExtended-B:a640-a69f;Bamum:a6a0-a6ff;ModifierToneLetters:a700-a71f;" +
|
|
64
|
+
"LatinExtended-D:a720-a7ff;SylotiNagri:a800-a82f;" +
|
|
65
|
+
"CommonIndicNumberForms:a830-a83f;Phags-pa:a840-a87f;Saurashtra:a880-a8df;" +
|
|
66
|
+
"DevanagariExtended:a8e0-a8ff;KayahLi:a900-a92f;Rejang:a930-a95f;" +
|
|
67
|
+
"HangulJamoExtended-A:a960-a97f;Javanese:a980-a9df;" +
|
|
68
|
+
"MyanmarExtended-B:a9e0-a9ff;Cham:aa00-aa5f;MyanmarExtended-A:aa60-aa7f;" +
|
|
69
|
+
"TaiViet:aa80-aadf;MeeteiMayekExtensions:aae0-aaff;" +
|
|
70
|
+
"EthiopicExtended-A:ab00-ab2f;LatinExtended-E:ab30-ab6f;" +
|
|
71
|
+
"CherokeeSupplement:ab70-abbf;MeeteiMayek:abc0-abff;" +
|
|
72
|
+
"HangulSyllables:ac00-d7af;HangulJamoExtended-B:d7b0-d7ff;" +
|
|
73
|
+
"HighSurrogates:d800-db7f;HighPrivateUseSurrogates:db80-dbff;" +
|
|
74
|
+
"LowSurrogates:dc00-dfff;PrivateUseArea:e000-f8ff;" +
|
|
75
|
+
"CJKCompatibilityIdeographs:f900-faff;AlphabeticPresentationForms:fb00-fb4f;" +
|
|
76
|
+
"ArabicPresentationForms-A:fb50-fdff;VariationSelectors:fe00-fe0f;" +
|
|
77
|
+
"VerticalForms:fe10-fe1f;CombiningHalfMarks:fe20-fe2f;" +
|
|
78
|
+
"CJKCompatibilityForms:fe30-fe4f;SmallFormVariants:fe50-fe6f;" +
|
|
79
|
+
"ArabicPresentationForms-B:fe70-feff;HalfwidthandFullwidthForms:ff00-ffef;" +
|
|
80
|
+
"Specials:fff0-ffff;LinearBSyllabary:10000-1007f;" +
|
|
81
|
+
"LinearBIdeograms:10080-100ff;AegeanNumbers:10100-1013f;" +
|
|
82
|
+
"AncientGreekNumbers:10140-1018f;AncientSymbols:10190-101cf;" +
|
|
83
|
+
"PhaistosDisc:101d0-101ff;Lycian:10280-1029f;Carian:102a0-102df;" +
|
|
84
|
+
"CopticEpactNumbers:102e0-102ff;OldItalic:10300-1032f;Gothic:10330-1034f;" +
|
|
85
|
+
"OldPermic:10350-1037f;Ugaritic:10380-1039f;OldPersian:103a0-103df;" +
|
|
86
|
+
"Deseret:10400-1044f;Shavian:10450-1047f;Osmanya:10480-104af;" +
|
|
87
|
+
"Osage:104b0-104ff;Elbasan:10500-1052f;CaucasianAlbanian:10530-1056f;" +
|
|
88
|
+
"Vithkuqi:10570-105bf;LinearA:10600-1077f;LatinExtended-F:10780-107bf;" +
|
|
89
|
+
"CypriotSyllabary:10800-1083f;ImperialAramaic:10840-1085f;" +
|
|
90
|
+
"Palmyrene:10860-1087f;Nabataean:10880-108af;Hatran:108e0-108ff;" +
|
|
91
|
+
"Phoenician:10900-1091f;Lydian:10920-1093f;MeroiticHieroglyphs:10980-1099f;" +
|
|
92
|
+
"MeroiticCursive:109a0-109ff;Kharoshthi:10a00-10a5f;" +
|
|
93
|
+
"OldSouthArabian:10a60-10a7f;OldNorthArabian:10a80-10a9f;" +
|
|
94
|
+
"Manichaean:10ac0-10aff;Avestan:10b00-10b3f;" +
|
|
95
|
+
"InscriptionalParthian:10b40-10b5f;InscriptionalPahlavi:10b60-10b7f;" +
|
|
96
|
+
"PsalterPahlavi:10b80-10baf;OldTurkic:10c00-10c4f;OldHungarian:10c80-10cff;" +
|
|
97
|
+
"HanifiRohingya:10d00-10d3f;RumiNumeralSymbols:10e60-10e7f;" +
|
|
98
|
+
"Yezidi:10e80-10ebf;ArabicExtended-C:10ec0-10eff;OldSogdian:10f00-10f2f;" +
|
|
99
|
+
"Sogdian:10f30-10f6f;OldUyghur:10f70-10faf;Chorasmian:10fb0-10fdf;" +
|
|
100
|
+
"Elymaic:10fe0-10fff;Brahmi:11000-1107f;Kaithi:11080-110cf;" +
|
|
101
|
+
"SoraSompeng:110d0-110ff;Chakma:11100-1114f;Mahajani:11150-1117f;" +
|
|
102
|
+
"Sharada:11180-111df;SinhalaArchaicNumbers:111e0-111ff;Khojki:11200-1124f;" +
|
|
103
|
+
"Multani:11280-112af;Khudawadi:112b0-112ff;Grantha:11300-1137f;" +
|
|
104
|
+
"Newa:11400-1147f;Tirhuta:11480-114df;Siddham:11580-115ff;Modi:11600-1165f;" +
|
|
105
|
+
"MongolianSupplement:11660-1167f;Takri:11680-116cf;Ahom:11700-1174f;" +
|
|
106
|
+
"Dogra:11800-1184f;WarangCiti:118a0-118ff;DivesAkuru:11900-1195f;" +
|
|
107
|
+
"Nandinagari:119a0-119ff;ZanabazarSquare:11a00-11a4f;Soyombo:11a50-11aaf;" +
|
|
108
|
+
"UnifiedCanadianAboriginalSyllabicsExtended-A:11ab0-11abf;" +
|
|
109
|
+
"PauCinHau:11ac0-11aff;DevanagariExtended-A:11b00-11b5f;" +
|
|
110
|
+
"Bhaiksuki:11c00-11c6f;Marchen:11c70-11cbf;MasaramGondi:11d00-11d5f;" +
|
|
111
|
+
"GunjalaGondi:11d60-11daf;Makasar:11ee0-11eff;Kawi:11f00-11f5f;" +
|
|
112
|
+
"LisuSupplement:11fb0-11fbf;TamilSupplement:11fc0-11fff;" +
|
|
113
|
+
"Cuneiform:12000-123ff;CuneiformNumbersandPunctuation:12400-1247f;" +
|
|
114
|
+
"EarlyDynasticCuneiform:12480-1254f;Cypro-Minoan:12f90-12fff;" +
|
|
115
|
+
"EgyptianHieroglyphs:13000-1342f;" +
|
|
116
|
+
"EgyptianHieroglyphFormatControls:13430-1345f;" +
|
|
117
|
+
"AnatolianHieroglyphs:14400-1467f;BamumSupplement:16800-16a3f;" +
|
|
118
|
+
"Mro:16a40-16a6f;Tangsa:16a70-16acf;BassaVah:16ad0-16aff;" +
|
|
119
|
+
"PahawhHmong:16b00-16b8f;Medefaidrin:16e40-16e9f;Miao:16f00-16f9f;" +
|
|
120
|
+
"IdeographicSymbolsandPunctuation:16fe0-16fff;Tangut:17000-187ff;" +
|
|
121
|
+
"TangutComponents:18800-18aff;KhitanSmallScript:18b00-18cff;" +
|
|
122
|
+
"TangutSupplement:18d00-18d7f;KanaExtended-B:1aff0-1afff;" +
|
|
123
|
+
"KanaSupplement:1b000-1b0ff;KanaExtended-A:1b100-1b12f;" +
|
|
124
|
+
"SmallKanaExtension:1b130-1b16f;Nushu:1b170-1b2ff;Duployan:1bc00-1bc9f;" +
|
|
125
|
+
"ShorthandFormatControls:1bca0-1bcaf;ZnamennyMusicalNotation:1cf00-1cfcf;" +
|
|
126
|
+
"ByzantineMusicalSymbols:1d000-1d0ff;MusicalSymbols:1d100-1d1ff;" +
|
|
127
|
+
"AncientGreekMusicalNotation:1d200-1d24f;KaktovikNumerals:1d2c0-1d2df;" +
|
|
128
|
+
"MayanNumerals:1d2e0-1d2ff;TaiXuanJingSymbols:1d300-1d35f;" +
|
|
129
|
+
"CountingRodNumerals:1d360-1d37f;" +
|
|
130
|
+
"MathematicalAlphanumericSymbols:1d400-1d7ff;SuttonSignWriting:1d800-1daaf;" +
|
|
131
|
+
"LatinExtended-G:1df00-1dfff;GlagoliticSupplement:1e000-1e02f;" +
|
|
132
|
+
"CyrillicExtended-D:1e030-1e08f;NyiakengPuachueHmong:1e100-1e14f;" +
|
|
133
|
+
"Toto:1e290-1e2bf;Wancho:1e2c0-1e2ff;NagMundari:1e4d0-1e4ff;" +
|
|
134
|
+
"EthiopicExtended-B:1e7e0-1e7ff;MendeKikakui:1e800-1e8df;Adlam:1e900-1e95f;" +
|
|
135
|
+
"IndicSiyaqNumbers:1ec70-1ecbf;OttomanSiyaqNumbers:1ed00-1ed4f;" +
|
|
136
|
+
"ArabicMathematicalAlphabeticSymbols:1ee00-1eeff;MahjongTiles:1f000-1f02f;" +
|
|
137
|
+
"DominoTiles:1f030-1f09f;PlayingCards:1f0a0-1f0ff;" +
|
|
138
|
+
"EnclosedAlphanumericSupplement:1f100-1f1ff;" +
|
|
139
|
+
"EnclosedIdeographicSupplement:1f200-1f2ff;" +
|
|
140
|
+
"MiscellaneousSymbolsandPictographs:1f300-1f5ff;Emoticons:1f600-1f64f;" +
|
|
141
|
+
"OrnamentalDingbats:1f650-1f67f;TransportandMapSymbols:1f680-1f6ff;" +
|
|
142
|
+
"AlchemicalSymbols:1f700-1f77f;GeometricShapesExtended:1f780-1f7ff;" +
|
|
143
|
+
"SupplementalArrows-C:1f800-1f8ff;" +
|
|
144
|
+
"SupplementalSymbolsandPictographs:1f900-1f9ff;ChessSymbols:1fa00-1fa6f;" +
|
|
145
|
+
"SymbolsandPictographsExtended-A:1fa70-1faff;" +
|
|
146
|
+
"SymbolsforLegacyComputing:1fb00-1fbff;" +
|
|
147
|
+
"CJKUnifiedIdeographsExtensionB:20000-2a6df;" +
|
|
148
|
+
"CJKUnifiedIdeographsExtensionC:2a700-2b73f;" +
|
|
149
|
+
"CJKUnifiedIdeographsExtensionD:2b740-2b81f;" +
|
|
150
|
+
"CJKUnifiedIdeographsExtensionE:2b820-2ceaf;" +
|
|
151
|
+
"CJKUnifiedIdeographsExtensionF:2ceb0-2ebef;" +
|
|
152
|
+
"CJKCompatibilityIdeographsSupplement:2f800-2fa1f;" +
|
|
153
|
+
"CJKUnifiedIdeographsExtensionG:30000-3134f;" +
|
|
154
|
+
"CJKUnifiedIdeographsExtensionH:31350-323af;Tags:e0000-e007f;" +
|
|
155
|
+
"VariationSelectorsSupplement:e0100-e01ef;" +
|
|
156
|
+
"SupplementaryPrivateUseArea-A:f0000-fffff;" +
|
|
157
|
+
"SupplementaryPrivateUseArea-B:100000-10ffff";
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Former block names that XSD 1.0 regular expressions use, mapped to the
|
|
161
|
+
* current names.
|
|
162
|
+
*/
|
|
163
|
+
const ALIASES = {
|
|
164
|
+
Greek: "GreekandCoptic",
|
|
165
|
+
CombiningMarksforSymbols: "CombiningDiacriticalMarksforSymbols",
|
|
166
|
+
CyrillicSupplementary: "CyrillicSupplement",
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/** @type {Map<string, [number, number][]>} ranges by block name */
|
|
170
|
+
const blocks = new Map();
|
|
171
|
+
for (const entry of TABLE.split(";")) {
|
|
172
|
+
const [name, range] = entry.split(":");
|
|
173
|
+
const [start, end] = range.split("-").map((hex) => parseInt(hex, 16));
|
|
174
|
+
blocks.set(name, [[start, end]]);
|
|
175
|
+
}
|
|
176
|
+
for (const [alias, name] of Object.entries(ALIASES)) {
|
|
177
|
+
blocks.set(alias, blocks.get(name));
|
|
178
|
+
}
|
|
179
|
+
// XSD 1.0 "PrivateUse" also covers the supplementary private use planes
|
|
180
|
+
blocks.set("PrivateUse", [
|
|
181
|
+
...blocks.get("PrivateUseArea"),
|
|
182
|
+
...blocks.get("SupplementaryPrivateUseArea-A"),
|
|
183
|
+
...blocks.get("SupplementaryPrivateUseArea-B"),
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Ranges of a Unicode block (the name is case-sensitive; spaces and
|
|
188
|
+
* underscores are ignored).
|
|
189
|
+
* @param {string} name - Block name without the "Is" prefix
|
|
190
|
+
* @returns {[number, number][]|undefined} inclusive codepoint ranges
|
|
191
|
+
*/
|
|
192
|
+
export function blockRanges(name) {
|
|
193
|
+
return blocks.get(name.replace(/[\s_]/g, ""));
|
|
194
|
+
}
|