@lowlighter/xml 6.0.0 → 8.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/README.md CHANGED
@@ -28,7 +28,7 @@ console.log(parse(`
28
28
 
29
29
  // Parse a file
30
30
  using file = await Deno.open("bench/assets/small.xml")
31
- console.log(parse(file))
31
+ console.log(await parse(file.readable))
32
32
  ```
33
33
 
34
34
  ### Stringifying objects to XML
@@ -51,7 +51,7 @@ console.log(stringify({
51
51
 
52
52
  ## ✨ Features
53
53
 
54
- - Based on the [quick-xml](https://github.com/tafia/quick-xml) Rust package (compiled to WASM).
54
+ - Based on [`@std/xml`](https://jsr.io/@std/xml).
55
55
  - Support for `XML.parse` and `XML.stringify` in the style of the `JSON` global.
56
56
  - Support for `<!-- -->` comments.
57
57
  - Support for XML entities (`&amp;`, `&#38;`, `&#x26;`, …).
@@ -64,14 +64,75 @@ console.log(stringify({
64
64
  - Support for custom `reviver` and `replacer` functions
65
65
  - Support for metadata stored into non-enumerable properties (advanced usage).
66
66
 
67
+ ## 🕊️ Migrating from `7.x.x` to `8.x.x`
68
+
69
+ ### Using `@std/xml` instead of `quick-xml` as parser
70
+
71
+ The parser is now backed by [`@std/xml`](https://jsr.io/@std/xml) instead of a WASM-compiled binding of the [quick-xml](https://github.com/tafia/quick-xml) Rust package.
72
+
73
+ This change reduces the maintenance burden of the library while relying on a standardized parser.
74
+
75
+ The WASM parser from `7.x.x` is still available in the `@libs/xml/wasm/parse` export. While the TypeScript layer will continue being updated, the underlying WASM module that serves quick-xml tokenization won't.
76
+
77
+ ### Exported types are now PascalCase
78
+
79
+ ```diff ts
80
+ - import type { stringify_options, stringifyable, xml_document, xml_node, xml_text } from "jsr:@libs/xml@7/stringify"
81
+ + import type { StringifyOptions, Stringifyable, XmlDocument, XmlNode, XmlText } from "jsr:@libs/xml@8/stringify"
82
+ ```
83
+
84
+ ### Unsupported options in the default export
85
+
86
+ > Note: described options are still available in the legacy WASM backend from `@libs/xml/wasm/parse` export.
87
+
88
+ The `revive.entities` option of `parse` has been removed, XML entities are now always decoded. If you need values in their escaped form, re-escape them with `escape` from [`@std/html/entities`](https://jsr.io/@std/html):
89
+
90
+ ```diff ts
91
+ - const document = parse(text, { revive: { entities: false } })
92
+ + import { escape } from "jsr:@std/html/entities"
93
+ + const document = parse(text)
94
+ + // Apply `escape()` on values where the escaped form is needed
95
+ ```
96
+
97
+ The `mode: "html"` option of `parse` has been temporarily removed, as `@std/xml` only supports strict XML.
98
+
99
+ ```diff ts
100
+ - import { parse } from "jsr:@libs/xml@8/parse"
101
+ + import { parse } from "jsr:@libs/xml@8/wasm/parse"
102
+ const document = parse(text, { mode: "html" })
103
+ ```
104
+
105
+ Passing a `ReaderSync` to `parse` is no longer supported. You can still pass a `Reader` to `parse` but the result is now asynchronous.
106
+
107
+ ```diff
108
+ using file = await Deno.open("bench/assets/small.xml")
109
+ - console.log(parse(file))
110
+ + console.log(await parse(file.readable))
111
+ ```
112
+
113
+ ## 🕊️ Migrating from `6.x.x` to `7.x.x`
114
+
115
+ For both `stringify` and `parse`, the type `options` has been renamed and prefixed by their scope for more clarity.
116
+
117
+ ```diff ts
118
+ - import type { options } from "jsr:@libs/xml@6/stringify"
119
+ + import type { stringify_options } from "jsr:@libs/xml@7/stringify"
120
+ ```
121
+
122
+ ```diff ts
123
+ - import type { options } from "jsr:@libs/xml@6/parse"
124
+ + import type { parse_options } from "jsr:@libs/xml@7/parse"
125
+ ```
126
+
127
+ If you didn't use these typings, no further changes are required.
128
+
67
129
  ## 🕊️ Migrating from `5.x.x` to `6.x.x`
68
130
 
69
131
  Version `6.x.x` and onwards require Deno `2.x.x` or later.
70
132
 
71
133
  ## 🕊️ Migrating from `4.x.x` to `5.x.x`
72
134
 
73
- Prior to version version `5.0.0`, this library was fully written in TypeScript.
74
- It now uses a WASM-compiled binding of the [quick-xml](https://github.com/tafia/quick-xml) Rust package, which provides better performance while allowing us to support more features.
135
+ Prior to version version `5.0.0`, this library was fully written in TypeScript. It now uses a WASM-compiled binding of the [quick-xml](https://github.com/tafia/quick-xml) Rust package, which provides better performance while allowing us to support more features.
75
136
 
76
137
  ### Internal API changes
77
138
 
@@ -138,8 +199,7 @@ Processing instructions (like XML stylesheets) are now parsed the same way as re
138
199
 
139
200
  ### Mixed content support
140
201
 
141
- This breaks any existing code that was expecting mixed content to always be a string.
142
- Now, mixed content nodes will be parsed as usual, and the `#text` property will contain the "inner text" of the node.
202
+ This breaks any existing code that was expecting mixed content to always be a string. Now, mixed content nodes will be parsed as usual, and the `#text` property will contain the "inner text" of the node.
143
203
 
144
204
  Note that `#text` is actually a getter that recursively gets the `#text` of children nodes (ignoring comment nodes), so it'll also handle nested mixed content correctly.
145
205
 
@@ -159,11 +219,9 @@ Note that `#text` is actually a getter that recursively gets the `#text` of chil
159
219
 
160
220
  ### Comments
161
221
 
162
- Comments have been moved into `"#comments"` property.
163
- Note that this property is now always an array, even if there is only one comment.
222
+ Comments have been moved into `"#comments"` property. Note that this property is now always an array, even if there is only one comment.
164
223
 
165
- Additionally, you can find comments into the `~children` property by searching for nodes with `"~name": "~comment"`.
166
- If you call the `#text` getter on a parent node containing comments, it will return the inner text without comments.
224
+ Additionally, you can find comments into the `~children` property by searching for nodes with `"~name": "~comment"`. If you call the `#text` getter on a parent node containing comments, it will return the inner text without comments.
167
225
 
168
226
  ```xml
169
227
  <root><!--some comment--></root>
@@ -189,8 +247,7 @@ Parsing options are categorized into 4 groups:
189
247
  - `revive`, which can `trim` content (unless `xml:space="preserve"`), unescape xml `entities`, revive `booleans` and `numbers`
190
248
  - You can also provide a `custom` reviver function (applied after other revivals) that will be called on each attribute and node
191
249
  - _Note that signature of the reviver function has changed_
192
- - `mode`, which can be either `xml` or `html`.
193
- Choosing the latter will be more permissive than the former.
250
+ - `mode`, which can be either `xml` or `html`. Choosing the latter will be more permissive than the former.
194
251
 
195
252
  ```diff js
196
253
  const options = {
@@ -212,7 +269,7 @@ Please refer to the [documentation](https://jsr.io/@libs/xml/doc) for more infor
212
269
 
213
270
  The `parse()` function supports any `ReaderSync`, which means you can pass directly a file reader for example.
214
271
 
215
- ```ts
272
+ ```ts ignore
216
273
  import { parse } from "./parse.ts"
217
274
  parse(await Deno.readTextFile("example.xml"))
218
275
  ```
@@ -248,8 +305,7 @@ Please refer to the [documentation](https://jsr.io/@libs/xml/doc) for more infor
248
305
 
249
306
  ### Stringifying content
250
307
 
251
- Please refer to the above section about API changes.
252
- If you were handling XML document properties, using the `$XML` symbol or `#comment` property, or dealing with mixed nodes content, you'll most likely need to update your code.
308
+ Please refer to the above section about API changes. If you were handling XML document properties, using the `$XML` symbol or `#comment` property, or dealing with mixed nodes content, you'll most likely need to update your code.
253
309
 
254
310
  Additionally, the library now provides `comment()` and `cdata()` helpers to respectively create comment and CDATA nodes:
255
311
 
@@ -287,27 +343,26 @@ stringify({
287
343
  </root>
288
344
  ```
289
345
 
290
- Note that while you can _theoretically_ use internal API properties, currently, we strongly advise against doing so.
291
- Supporting `~children` might be added in the future ([#57](https://github.com/lowlighter/libs/issues/57)) for mixed content, but its behavior is not yet well defined.
292
- Setting `~name` manually might lead to unexpected behaviors, especially if it differs from the parent key.
346
+ Note that while you can _theoretically_ use internal API properties, currently, we strongly advise against doing so. Supporting `~children` might be added in the future ([#57](https://github.com/lowlighter/libs/issues/57)) for mixed content, but its behavior is not yet well
347
+ defined. Setting `~name` manually might lead to unexpected behaviors, especially if it differs from the parent key.
293
348
 
294
349
  > [!TIP]
295
- > For more type-safety, write `satisfies Partial<xml_document>` after whatever you pass into `stringify`, like so:
350
+ > For more type-safety, write `satisfies Partial<XmlDocument>` after whatever you pass into `stringify`, like so:
296
351
  >
297
352
  > <!-- TODO(lishaduck): Add ts highlighting once denoland/deno#24164 is resolved -->
298
353
  >
299
354
  > ```
300
- > import { stringify, type xml_document } from "./stringify.ts"
355
+ > import { stringify, type XmlDocument } from "./stringify.ts"
301
356
  >
302
357
  > const ast = {
303
358
  > "@version": "1.0",
304
359
  > "@encoding": "UTF-8",
305
360
  > "root": {},
306
- > } satisfies Partial<xml_document>
361
+ > } satisfies Partial<XmlDocument>
307
362
  > const result = stringify(ast)
308
363
  > ```
309
364
  >
310
- > We expose lax typing, but `Partial<xml_document>` uses the stricter typing we use internally.
365
+ > We expose lax typing, but `Partial<XmlDocument>` uses the stricter typing we use internally.
311
366
 
312
367
  ## 📜 License and credits
313
368
 
package/_parser.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared internals between the std-based ({@link ./parse.ts}) and WASM-based ({@link ./wasm/parse.ts}) XML parsers.
3
+ * @module
4
+ */ import type { Nullable, XmlNode } from "./_types.js";
5
+ /** XML parser `clean` options. */ export type CleanOptions = {
6
+ /** Remove attributes from result. */ attributes?: boolean;
7
+ /** Remove comments from result. */ comments?: boolean;
8
+ /** Remove XML doctype from result. */ doctype?: boolean;
9
+ /** Remove XML processing instructions from result. */ instructions?: boolean;
10
+ };
11
+ /** XML parser `flatten` options. */ export type FlattenOptions = {
12
+ /** If node only contains attributes values (i.e. with key starting with `@`), it'll be flattened as a regular object without `@` prefixes. */ attributes?: boolean;
13
+ /** If node only contains a `#text` value, it'll be flattened as a string (defaults to `true`). */ text?: boolean;
14
+ /** If node does not contains any attribute or text, it'll be flattened to `null` (defaults to `true`). */ empty?: boolean;
15
+ };
16
+ /** XML parser `revive` options. */ export type ReviveOptions = {
17
+ /**
18
+ * Trim texts (this is applied before other revivals, defaults to `true`).
19
+ * It honors `xml:space="preserve"` attribute.
20
+ */ trim?: boolean;
21
+ /**
22
+ * Revive XML entities (defaults to `true`).
23
+ * Automatically unescape XML entities and replace common entities with their respective characters.
24
+ */ entities?: boolean;
25
+ /** Revive booleans (matching `/^(?:[Tt]rue|[Ff]alse)$/`).*/ booleans?: boolean;
26
+ /**
27
+ * Revive finite numbers.
28
+ * Note that the version of the XML prolog is always treated as a string to avoid breaking documents.
29
+ */ numbers?: boolean;
30
+ /**
31
+ * Custom reviver (this is applied after other revivals).
32
+ * When it is applied on an attribute, `key` and `value` will be given.
33
+ * When it is applied on a node, both `key` and `value` will be `null`.
34
+ * Return `undefined` to delete either the attribute or the tag.
35
+ */ custom?: Reviver;
36
+ };
37
+ /**
38
+ * Custom XML parser reviver.
39
+ * It can be used to change the way some nodes are parsed.
40
+ */ export type Reviver = (args: {
41
+ name: string;
42
+ key: Nullable<string>;
43
+ value: Nullable<string>;
44
+ node: Readonly<XmlNode>;
45
+ }) => unknown;
package/_parser.js ADDED
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Shared internals between the std-based ({@link ./parse.ts}) and WASM-based ({@link ./wasm/parse.ts}) XML parsers.
3
+ * @module
4
+ */ // Imports
5
+ /** Apply parser option defaults and post-process the parsed document. */ export function finalize(xml, options) {
6
+ options ??= {};
7
+ options.revive ??= {};
8
+ options.revive.trim ??= true;
9
+ options.revive.entities ??= true;
10
+ options.flatten ??= {};
11
+ options.flatten.text ??= true;
12
+ options.flatten.empty ??= true;
13
+ if (!Object.keys(xml).length) throw new SyntaxError("Malformed XML document: empty document or no root node detected");
14
+ return postprocess(xml, options);
15
+ }
16
+ /** Attach a processing instruction under `#instructions` with array-grouping. */ export function xml_instruction(xml, name, raw) {
17
+ const instruction = Object.assign(xml_node(name, {
18
+ parent: xml
19
+ }), xml_attributes(raw));
20
+ xml["#instructions"] ??= {};
21
+ switch(true){
22
+ case Array.isArray(xml["#instructions"][name]):
23
+ ;
24
+ xml["#instructions"][name].push(instruction);
25
+ break;
26
+ case name in xml["#instructions"]:
27
+ xml["#instructions"][name] = [
28
+ xml["#instructions"][name],
29
+ instruction
30
+ ];
31
+ break;
32
+ default:
33
+ xml["#instructions"][name] = instruction;
34
+ }
35
+ }
36
+ /** Parse xml attributes. */ export function xml_attributes(raw) {
37
+ const attributes = {};
38
+ for (const [_, name, __, value] of raw.matchAll(/(?<name>[A-Za-z_][-\w.:]*)=(["'])(?<value>(?:(?!\2).)*)(\2)/g))attributes[`@${name}`] = value;
39
+ return attributes;
40
+ }
41
+ /** Parse xml doctype. */ export function xml_doctype(raw) {
42
+ const node = {};
43
+ const { attributes: _attributes, elements: _elements = "" } = raw.match(/^(?<attributes>[^\[]*)(?:\[(?<elements>[\s\S]*)\])?/)?.groups;
44
+ // Parse attributes
45
+ raw = raw.replace(`[${_elements}]`, "");
46
+ for (const [match, __, name] of _attributes.matchAll(/(["'])(?<name>(?:(?!\1).)*)(\1)/g)){
47
+ node[`@${name}`] = "";
48
+ raw = raw.replace(match, "");
49
+ }
50
+ raw.split(/\s+/).filter(Boolean).forEach((name)=>node[`@${name}`] = "");
51
+ // Parse elements
52
+ for (const [_, name, value] of _elements.matchAll(/<!ELEMENT\s+(?<name>\w+)\s+\((?<value>[^\)]+)\)/g))node[name] = value;
53
+ return node;
54
+ }
55
+ /** Create a new text node. */ export function xml_text(value, { type = "~text", parent = null } = {}) {
56
+ const text = Object.defineProperties({}, {
57
+ ["~parent"]: {
58
+ enumerable: false,
59
+ writable: false,
60
+ value: parent
61
+ },
62
+ ["~name"]: {
63
+ enumerable: false,
64
+ writable: false,
65
+ value: type
66
+ }
67
+ });
68
+ text["#text"] = value;
69
+ if (parent) parent["~children"].push(text);
70
+ return text;
71
+ }
72
+ /** Create a new element node and attach it under its parent's enumerable key with array-grouping. */ export function xml_element(name, parent) {
73
+ const node = xml_node(name, {
74
+ parent
75
+ });
76
+ switch(true){
77
+ case Array.isArray(parent[node["~name"]]):
78
+ ;
79
+ parent[node["~name"]].push(node);
80
+ break;
81
+ case node["~name"] in parent:
82
+ parent[node["~name"]] = [
83
+ parent[node["~name"]],
84
+ node
85
+ ];
86
+ break;
87
+ default:
88
+ parent[node["~name"]] = node;
89
+ }
90
+ return node;
91
+ }
92
+ /** Create a new node. */ export function xml_node(name, { parent = null } = {}) {
93
+ const node = Object.defineProperties({}, {
94
+ ["~parent"]: {
95
+ enumerable: false,
96
+ writable: false,
97
+ value: parent
98
+ },
99
+ ["~name"]: {
100
+ enumerable: false,
101
+ writable: false,
102
+ value: name
103
+ },
104
+ ["~children"]: {
105
+ enumerable: false,
106
+ writable: true,
107
+ value: []
108
+ },
109
+ ["#text"]: {
110
+ enumerable: false,
111
+ configurable: true,
112
+ get () {
113
+ const children = this["~children"].filter((node)=>node["~name"] !== "~comment");
114
+ // If xml:space is not set to "preserve", concatenate text nodes and trim them while removing empty ones
115
+ if (this["@xml:space"] !== "preserve") return children.map((child)=>child["#text"]).filter(Boolean).join(" ");
116
+ // If xml:space is set to "preserve", concatenate text nodes without trimming them
117
+ // In case of mixed content, add a space between mixed nodes if needed
118
+ let text = "";
119
+ for(let i = 0; i < children.length; i++){
120
+ const spaced = i && +children[i - 1]["~name"].startsWith("~") ^ +children[i]["~name"].startsWith("~") && !children[i - 1]["#text"].endsWith(" ") && !children[i]["#text"].startsWith(" ");
121
+ text += `${spaced ? " " : ""}${children[i]["#text"]}`;
122
+ }
123
+ return text;
124
+ }
125
+ },
126
+ ["#comments"]: {
127
+ enumerable: false,
128
+ configurable: true,
129
+ get () {
130
+ return this["~children"].filter((node)=>node["~name"] === "~comment").map((node)=>node["#text"]);
131
+ }
132
+ }
133
+ });
134
+ if (parent) parent["~children"].push(node);
135
+ return node;
136
+ }
137
+ /** Post-process xml node. */ function postprocess(node, options) {
138
+ // Clean XML document if required
139
+ if (node["~name"] === "~xml") {
140
+ if (options?.clean?.doctype) delete node["#doctype"];
141
+ if (options?.clean?.instructions) {
142
+ ;
143
+ node["~children"] = node["~children"].filter((child)=>!(child["~name"] in (node["#instructions"] ?? {})));
144
+ delete node["#instructions"];
145
+ }
146
+ }
147
+ // Clean node and enable enumerable properties if required
148
+ if (node["~children"]) {
149
+ if (options?.clean?.comments) {
150
+ ;
151
+ node["~children"] = node["~children"].filter((child)=>child["~name"] !== "~comment");
152
+ }
153
+ if (options?.revive?.trim) node["~children"].forEach((child)=>/^~(?:text|cdata|comment)$/.test(child["~name"]) ? child["#text"] = revive(child, "#text", {
154
+ revive: {
155
+ trim: node["@xml:space"] !== "preserve"
156
+ }
157
+ }) : null);
158
+ if (node["~children"].some((child)=>/^~(?:text|cdata)$/.test(child["~name"]) && child["#text"].trim().length + (node["@xml:space"] === "preserve" ? 1 : 0) * child["#text"].length)) Object.defineProperty(node, "#text", {
159
+ enumerable: true,
160
+ configurable: true
161
+ });
162
+ if (node["~children"].some((child)=>child["~name"] === "~comment")) Object.defineProperty(node, "#comments", {
163
+ enumerable: true,
164
+ configurable: true
165
+ });
166
+ }
167
+ // Process child nodes
168
+ for (const [key, value] of Object.entries(node)){
169
+ // Skip comments
170
+ if (key === "#comments") continue;
171
+ // Clean attributes if required
172
+ if (options?.clean?.attributes && key.startsWith("@")) {
173
+ delete node[key];
174
+ continue;
175
+ }
176
+ // Revive attribute value if required
177
+ if (key.startsWith("@")) {
178
+ node[key] = revive(node, key, options);
179
+ if (node[key] === undefined) delete node[key];
180
+ continue;
181
+ }
182
+ // Handle other nodes
183
+ if (Array.isArray(value)) {
184
+ node[key] = Object.defineProperties(value.map((child)=>postprocess(child, options)), {
185
+ ["~parent"]: {
186
+ enumerable: false,
187
+ writable: false,
188
+ value: node
189
+ },
190
+ ["~name"]: {
191
+ enumerable: false,
192
+ writable: false,
193
+ value: key
194
+ }
195
+ });
196
+ } else if (typeof value === "object" && value) {
197
+ node[key] = postprocess(value, options);
198
+ }
199
+ if (node[key] === undefined) delete node[key];
200
+ }
201
+ // Revive text if required
202
+ const keys = Object.keys(node);
203
+ if (keys.includes("#text")) {
204
+ const _options = {
205
+ ...options,
206
+ revive: {
207
+ ...options?.revive,
208
+ trim: options?.revive?.trim && node["@xml:space"] !== "preserve"
209
+ }
210
+ };
211
+ Object.defineProperty(node, "#text", {
212
+ enumerable: true,
213
+ configurable: true,
214
+ value: revive(node, "#text", _options)
215
+ });
216
+ }
217
+ // Custom revival if required
218
+ if (options?.revive?.custom) {
219
+ if (options.revive.custom({
220
+ name: node["~name"],
221
+ key: null,
222
+ value: null,
223
+ node: node
224
+ }) === undefined) return undefined;
225
+ }
226
+ // Flatten object if required
227
+ if (options?.flatten?.text && keys.length === 1 && keys.includes("#text")) return node["#text"];
228
+ if (options?.flatten?.attributes && keys.length && keys.every((key)=>key.startsWith("@"))) {
229
+ for (const key of keys){
230
+ node[key.slice(1)] = node[key];
231
+ delete node[key];
232
+ }
233
+ return node;
234
+ }
235
+ if (!keys.length) return options?.flatten?.empty ? null : options?.flatten?.text ? "" : Object.defineProperty(node, "#text", {
236
+ enumerable: true,
237
+ configurable: true,
238
+ value: ""
239
+ });
240
+ return node;
241
+ }
242
+ /** Entities */ const entities = {
243
+ "&lt;": "<",
244
+ "&gt;": ">",
245
+ "&apos;": "'",
246
+ "&quot;": '"',
247
+ "&amp;": "&"
248
+ };
249
+ /** Revive value. */ function revive(node, key, options) {
250
+ let value = node[key];
251
+ if (options?.revive?.trim) value = value.trim();
252
+ if (options?.revive?.entities) {
253
+ value = value.replaceAll(/&#(?<hex>x?)(?<code>[A-Fa-f\d]+);/g, (_, hex, code)=>String.fromCharCode(Number.parseInt(code, hex ? 16 : 10)));
254
+ for (const [entity, character] of Object.entries(entities))value = value.replaceAll(entity, character);
255
+ }
256
+ if (options?.revive?.numbers && value.length && Number.isFinite(Number(value)) && !(node["~name"] === "~xml" && key === "@version")) value = Number(value);
257
+ if (options?.revive?.booleans && /^(?:[Tt]rue|[Ff]alse)$/.test(value)) value = /^[Tt]rue$/.test(value);
258
+ if (options?.revive?.custom) return options.revive.custom({
259
+ name: node["~name"],
260
+ key,
261
+ value,
262
+ node: node
263
+ });
264
+ return value;
265
+ }
266
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMveG1sL19wYXJzZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTaGFyZWQgaW50ZXJuYWxzIGJldHdlZW4gdGhlIHN0ZC1iYXNlZCAoe0BsaW5rIC4vcGFyc2UudHN9KSBhbmQgV0FTTS1iYXNlZCAoe0BsaW5rIC4vd2FzbS9wYXJzZS50c30pIFhNTCBwYXJzZXJzLlxuICogQG1vZHVsZVxuICovXG5cbi8vIEltcG9ydHNcbmltcG9ydCB0eXBlIHsgTnVsbGFibGUsIFhtbERvY3VtZW50LCBYbWxOb2RlLCBYbWxUZXh0IH0gZnJvbSBcIi4vX3R5cGVzLmpzXCJcblxuLyoqIFhNTCBwYXJzZXIgYGNsZWFuYCBvcHRpb25zLiAqL1xuZXhwb3J0IHR5cGUgQ2xlYW5PcHRpb25zID0ge1xuICAvKiogUmVtb3ZlIGF0dHJpYnV0ZXMgZnJvbSByZXN1bHQuICovXG4gIGF0dHJpYnV0ZXM/OiBib29sZWFuXG4gIC8qKiBSZW1vdmUgY29tbWVudHMgZnJvbSByZXN1bHQuICovXG4gIGNvbW1lbnRzPzogYm9vbGVhblxuICAvKiogUmVtb3ZlIFhNTCBkb2N0eXBlIGZyb20gcmVzdWx0LiAqL1xuICBkb2N0eXBlPzogYm9vbGVhblxuICAvKiogUmVtb3ZlIFhNTCBwcm9jZXNzaW5nIGluc3RydWN0aW9ucyBmcm9tIHJlc3VsdC4gKi9cbiAgaW5zdHJ1Y3Rpb25zPzogYm9vbGVhblxufVxuXG4vKiogWE1MIHBhcnNlciBgZmxhdHRlbmAgb3B0aW9ucy4gKi9cbmV4cG9ydCB0eXBlIEZsYXR0ZW5PcHRpb25zID0ge1xuICAvKiogSWYgbm9kZSBvbmx5IGNvbnRhaW5zIGF0dHJpYnV0ZXMgdmFsdWVzIChpLmUuIHdpdGgga2V5IHN0YXJ0aW5nIHdpdGggYEBgKSwgaXQnbGwgYmUgZmxhdHRlbmVkIGFzIGEgcmVndWxhciBvYmplY3Qgd2l0aG91dCBgQGAgcHJlZml4ZXMuICovXG4gIGF0dHJpYnV0ZXM/OiBib29sZWFuXG4gIC8qKiBJZiBub2RlIG9ubHkgY29udGFpbnMgYSBgI3RleHRgIHZhbHVlLCBpdCdsbCBiZSBmbGF0dGVuZWQgYXMgYSBzdHJpbmcgKGRlZmF1bHRzIHRvIGB0cnVlYCkuICovXG4gIHRleHQ/OiBib29sZWFuXG4gIC8qKiBJZiBub2RlIGRvZXMgbm90IGNvbnRhaW5zIGFueSBhdHRyaWJ1dGUgb3IgdGV4dCwgaXQnbGwgYmUgZmxhdHRlbmVkIHRvIGBudWxsYCAoZGVmYXVsdHMgdG8gYHRydWVgKS4gKi9cbiAgZW1wdHk/OiBib29sZWFuXG59XG5cbi8qKiBYTUwgcGFyc2VyIGByZXZpdmVgIG9wdGlvbnMuICovXG5leHBvcnQgdHlwZSBSZXZpdmVPcHRpb25zID0ge1xuICAvKipcbiAgICogVHJpbSB0ZXh0cyAodGhpcyBpcyBhcHBsaWVkIGJlZm9yZSBvdGhlciByZXZpdmFscywgZGVmYXVsdHMgdG8gYHRydWVgKS5cbiAgICogSXQgaG9ub3JzIGB4bWw6c3BhY2U9XCJwcmVzZXJ2ZVwiYCBhdHRyaWJ1dGUuXG4gICAqL1xuICB0cmltPzogYm9vbGVhblxuICAvKipcbiAgICogUmV2aXZlIFhNTCBlbnRpdGllcyAoZGVmYXVsdHMgdG8gYHRydWVgKS5cbiAgICogQXV0b21hdGljYWxseSB1bmVzY2FwZSBYTUwgZW50aXRpZXMgYW5kIHJlcGxhY2UgY29tbW9uIGVudGl0aWVzIHdpdGggdGhlaXIgcmVzcGVjdGl2ZSBjaGFyYWN0ZXJzLlxuICAgKi9cbiAgZW50aXRpZXM/OiBib29sZWFuXG4gIC8qKiBSZXZpdmUgYm9vbGVhbnMgKG1hdGNoaW5nIGAvXig/OltUdF1ydWV8W0ZmXWFsc2UpJC9gKS4qL1xuICBib29sZWFucz86IGJvb2xlYW5cbiAgLyoqXG4gICAqIFJldml2ZSBmaW5pdGUgbnVtYmVycy5cbiAgICogTm90ZSB0aGF0IHRoZSB2ZXJzaW9uIG9mIHRoZSBYTUwgcHJvbG9nIGlzIGFsd2F5cyB0cmVhdGVkIGFzIGEgc3RyaW5nIHRvIGF2b2lkIGJyZWFraW5nIGRvY3VtZW50cy5cbiAgICovXG4gIG51bWJlcnM/OiBib29sZWFuXG4gIC8qKlxuICAgKiBDdXN0b20gcmV2aXZlciAodGhpcyBpcyBhcHBsaWVkIGFmdGVyIG90aGVyIHJldml2YWxzKS5cbiAgICogV2hlbiBpdCBpcyBhcHBsaWVkIG9uIGFuIGF0dHJpYnV0ZSwgYGtleWAgYW5kIGB2YWx1ZWAgd2lsbCBiZSBnaXZlbi5cbiAgICogV2hlbiBpdCBpcyBhcHBsaWVkIG9uIGEgbm9kZSwgYm90aCBga2V5YCBhbmQgYHZhbHVlYCB3aWxsIGJlIGBudWxsYC5cbiAgICogUmV0dXJuIGB1bmRlZmluZWRgIHRvIGRlbGV0ZSBlaXRoZXIgdGhlIGF0dHJpYnV0ZSBvciB0aGUgdGFnLlxuICAgKi9cbiAgY3VzdG9tPzogUmV2aXZlclxufVxuXG4vKipcbiAqIEN1c3RvbSBYTUwgcGFyc2VyIHJldml2ZXIuXG4gKiBJdCBjYW4gYmUgdXNlZCB0byBjaGFuZ2UgdGhlIHdheSBzb21lIG5vZGVzIGFyZSBwYXJzZWQuXG4gKi9cbmV4cG9ydCB0eXBlIFJldml2ZXIgPSAoYXJnczogeyBuYW1lOiBzdHJpbmc7IGtleTogTnVsbGFibGU8c3RyaW5nPjsgdmFsdWU6IE51bGxhYmxlPHN0cmluZz47IG5vZGU6IFJlYWRvbmx5PFhtbE5vZGU+IH0pID0+IHVua25vd25cblxuLyoqIEJhY2tlbmQtYWdub3N0aWMgcGFyc2VyIG9wdGlvbnMgKGVhY2ggYmFja2VuZCBleHRlbmRzIGl0IHdpdGggaXRzIG93biBzdXBwb3J0ZWQgYG1vZGVgKS4gKi9cbmV4cG9ydCB0eXBlIFBhcnNlck9wdGlvbnMgPSB7XG4gIC8qKiBSZW1vdmUgZWxlbWVudHMgZnJvbSByZXN1bHQuICovXG4gIGNsZWFuPzogQ2xlYW5PcHRpb25zXG4gIC8qKiBGbGF0dGVuIHJlc3VsdCBkZXBlbmRpbmcgb24gbm9kZSBjb250ZW50LiAqL1xuICBmbGF0dGVuPzogRmxhdHRlbk9wdGlvbnNcbiAgLyoqIFJldml2ZSByZXN1bHQuICovXG4gIHJldml2ZT86IFJldml2ZU9wdGlvbnNcbn1cblxuLyoqIEFwcGx5IHBhcnNlciBvcHRpb24gZGVmYXVsdHMgYW5kIHBvc3QtcHJvY2VzcyB0aGUgcGFyc2VkIGRvY3VtZW50LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmFsaXplKHhtbDogWG1sRG9jdW1lbnQsIG9wdGlvbnM/OiBQYXJzZXJPcHRpb25zKTogWG1sRG9jdW1lbnQge1xuICBvcHRpb25zID8/PSB7fVxuICBvcHRpb25zLnJldml2ZSA/Pz0ge31cbiAgb3B0aW9ucy5yZXZpdmUudHJpbSA/Pz0gdHJ1ZVxuICBvcHRpb25zLnJldml2ZS5lbnRpdGllcyA/Pz0gdHJ1ZVxuICBvcHRpb25zLmZsYXR0ZW4gPz89IHt9XG4gIG9wdGlvbnMuZmxhdHRlbi50ZXh0ID8/PSB0cnVlXG4gIG9wdGlvbnMuZmxhdHRlbi5lbXB0eSA/Pz0gdHJ1ZVxuICBpZiAoIU9iamVjdC5rZXlzKHhtbCkubGVuZ3RoKVxuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIk1hbGZvcm1lZCBYTUwgZG9jdW1lbnQ6IGVtcHR5IGRvY3VtZW50IG9yIG5vIHJvb3Qgbm9kZSBkZXRlY3RlZFwiKVxuICByZXR1cm4gcG9zdHByb2Nlc3MoeG1sLCBvcHRpb25zKSBhcyBYbWxEb2N1bWVudFxufVxuXG4vKiogQXR0YWNoIGEgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbiB1bmRlciBgI2luc3RydWN0aW9uc2Agd2l0aCBhcnJheS1ncm91cGluZy4gICovXG5leHBvcnQgZnVuY3Rpb24geG1sX2luc3RydWN0aW9uKHhtbDogWG1sRG9jdW1lbnQsIG5hbWU6IHN0cmluZywgcmF3OiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgaW5zdHJ1Y3Rpb24gPSBPYmplY3QuYXNzaWduKHhtbF9ub2RlKG5hbWUsIHsgcGFyZW50OiB4bWwgfSksIHhtbF9hdHRyaWJ1dGVzKHJhdykpXG4gIHhtbFtcIiNpbnN0cnVjdGlvbnNcIl0gPz89IHt9XG4gIHN3aXRjaCAodHJ1ZSkge1xuICAgIGNhc2UgQXJyYXkuaXNBcnJheSh4bWxbXCIjaW5zdHJ1Y3Rpb25zXCJdW25hbWVdKTpcbiAgICAgIDsoeG1sW1wiI2luc3RydWN0aW9uc1wiXVtuYW1lXSBhcyBBcnJheTxYbWxOb2RlPikucHVzaChpbnN0cnVjdGlvbilcbiAgICAgIGJyZWFrXG4gICAgY2FzZSBuYW1lIGluIHhtbFtcIiNpbnN0cnVjdGlvbnNcIl06XG4gICAgICB4bWxbXCIjaW5zdHJ1Y3Rpb25zXCJdW25hbWVdID0gW3htbFtcIiNpbnN0cnVjdGlvbnNcIl1bbmFtZV0gYXMgWG1sTm9kZSwgaW5zdHJ1Y3Rpb25dXG4gICAgICBicmVha1xuICAgIGRlZmF1bHQ6XG4gICAgICB4bWxbXCIjaW5zdHJ1Y3Rpb25zXCJdW25hbWVdID0gaW5zdHJ1Y3Rpb25cbiAgfVxufVxuXG4vKiogUGFyc2UgeG1sIGF0dHJpYnV0ZXMuICovXG5leHBvcnQgZnVuY3Rpb24geG1sX2F0dHJpYnV0ZXMocmF3OiBzdHJpbmcpOiBSZWNvcmQ8UHJvcGVydHlLZXksIHN0cmluZz4ge1xuICBjb25zdCBhdHRyaWJ1dGVzID0ge30gYXMgUmVjb3JkPFByb3BlcnR5S2V5LCBzdHJpbmc+XG4gIGZvciAoY29uc3QgW18sIG5hbWUsIF9fLCB2YWx1ZV0gb2YgcmF3Lm1hdGNoQWxsKC8oPzxuYW1lPltBLVphLXpfXVstXFx3LjpdKik9KFtcIiddKSg/PHZhbHVlPig/Oig/IVxcMikuKSopKFxcMikvZykpXG4gICAgYXR0cmlidXRlc1tgQCR7bmFtZX1gXSA9IHZhbHVlXG4gIHJldHVybiBhdHRyaWJ1dGVzXG59XG5cbi8qKiBQYXJzZSB4bWwgZG9jdHlwZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiB4bWxfZG9jdHlwZShyYXc6IHN0cmluZyk6IFhtbE5vZGUge1xuICBjb25zdCBub2RlID0ge30gYXMgWG1sTm9kZVxuICBjb25zdCB7IGF0dHJpYnV0ZXM6IF9hdHRyaWJ1dGVzLCBlbGVtZW50czogX2VsZW1lbnRzID0gXCJcIiB9ID0gcmF3Lm1hdGNoKC9eKD88YXR0cmlidXRlcz5bXlxcW10qKSg/OlxcWyg/PGVsZW1lbnRzPltcXHNcXFNdKilcXF0pPy8pPy5ncm91cHMhXG4gIC8vIFBhcnNlIGF0dHJpYnV0ZXNcbiAgcmF3ID0gcmF3LnJlcGxhY2UoYFske19lbGVtZW50c31dYCwgXCJcIilcbiAgZm9yIChjb25zdCBbbWF0Y2gsIF9fLCBuYW1lXSBvZiBfYXR0cmlidXRlcy5tYXRjaEFsbCgvKFtcIiddKSg/PG5hbWU+KD86KD8hXFwxKS4pKikoXFwxKS9nKSkge1xuICAgIG5vZGVbYEAke25hbWV9YF0gPSBcIlwiXG4gICAgcmF3ID0gcmF3LnJlcGxhY2UobWF0Y2gsIFwiXCIpXG4gIH1cbiAgcmF3LnNwbGl0KC9cXHMrLykuZmlsdGVyKEJvb2xlYW4pLmZvckVhY2goKG5hbWUpID0+IG5vZGVbYEAke25hbWV9YF0gPSBcIlwiKVxuICAvLyBQYXJzZSBlbGVtZW50c1xuICBmb3IgKGNvbnN0IFtfLCBuYW1lLCB2YWx1ZV0gb2YgX2VsZW1lbnRzLm1hdGNoQWxsKC88IUVMRU1FTlRcXHMrKD88bmFtZT5cXHcrKVxccytcXCgoPzx2YWx1ZT5bXlxcKV0rKVxcKS9nKSlcbiAgICBub2RlW25hbWVdID0gdmFsdWVcbiAgcmV0dXJuIG5vZGVcbn1cblxuLyoqIENyZWF0ZSBhIG5ldyB0ZXh0IG5vZGUuICovXG5leHBvcnQgZnVuY3Rpb24geG1sX3RleHQodmFsdWU6IHN0cmluZywgeyB0eXBlID0gXCJ+dGV4dFwiIGFzIFwifnRleHRcIiB8IFwifmNkYXRhXCIgfCBcIn5jb21tZW50XCIsIHBhcmVudCA9IG51bGwgYXMgTnVsbGFibGU8WG1sTm9kZT4gfSA9IHt9KTogWG1sVGV4dCB7XG4gIGNvbnN0IHRleHQgPSBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh7fSwge1xuICAgIFtcIn5wYXJlbnRcIl06IHsgZW51bWVyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiBmYWxzZSwgdmFsdWU6IHBhcmVudCB9LFxuICAgIFtcIn5uYW1lXCJdOiB7IGVudW1lcmFibGU6IGZhbHNlLCB3cml0YWJsZTogZmFsc2UsIHZhbHVlOiB0eXBlIH0sXG4gIH0pIGFzIFhtbFRleHRcbiAgdGV4dFtcIiN0ZXh0XCJdID0gdmFsdWVcbiAgaWYgKHBhcmVudClcbiAgICBwYXJlbnRbXCJ+Y2hpbGRyZW5cIl0ucHVzaCh0ZXh0KVxuICByZXR1cm4gdGV4dFxufVxuXG4vKiogQ3JlYXRlIGEgbmV3IGVsZW1lbnQgbm9kZSBhbmQgYXR0YWNoIGl0IHVuZGVyIGl0cyBwYXJlbnQncyBlbnVtZXJhYmxlIGtleSB3aXRoIGFycmF5LWdyb3VwaW5nLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHhtbF9lbGVtZW50KG5hbWU6IHN0cmluZywgcGFyZW50OiBYbWxOb2RlKTogWG1sTm9kZSB7XG4gIGNvbnN0IG5vZGUgPSB4bWxfbm9kZShuYW1lLCB7IHBhcmVudCB9KVxuICBzd2l0Y2ggKHRydWUpIHtcbiAgICBjYXNlIEFycmF5LmlzQXJyYXkocGFyZW50W25vZGVbXCJ+bmFtZVwiXV0pOlxuICAgICAgOyhwYXJlbnRbbm9kZVtcIn5uYW1lXCJdXSBhcyBBcnJheTxYbWxOb2RlPikucHVzaChub2RlKVxuICAgICAgYnJlYWtcbiAgICBjYXNlIG5vZGVbXCJ+bmFtZVwiXSBpbiBwYXJlbnQ6XG4gICAgICBwYXJlbnRbbm9kZVtcIn5uYW1lXCJdXSA9IFtwYXJlbnRbbm9kZVtcIn5uYW1lXCJdXSwgbm9kZV1cbiAgICAgIGJyZWFrXG4gICAgZGVmYXVsdDpcbiAgICAgIHBhcmVudFtub2RlW1wifm5hbWVcIl1dID0gbm9kZVxuICB9XG4gIHJldHVybiBub2RlXG59XG5cbi8qKiBDcmVhdGUgYSBuZXcgbm9kZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiB4bWxfbm9kZShuYW1lOiBzdHJpbmcsIHsgcGFyZW50ID0gbnVsbCBhcyBOdWxsYWJsZTxYbWxOb2RlPiB9ID0ge30pOiBYbWxOb2RlIHtcbiAgY29uc3Qgbm9kZSA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHt9LCB7XG4gICAgW1wifnBhcmVudFwiXTogeyBlbnVtZXJhYmxlOiBmYWxzZSwgd3JpdGFibGU6IGZhbHNlLCB2YWx1ZTogcGFyZW50IH0sXG4gICAgW1wifm5hbWVcIl06IHsgZW51bWVyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiBmYWxzZSwgdmFsdWU6IG5hbWUgfSxcbiAgICBbXCJ+Y2hpbGRyZW5cIl06IHsgZW51bWVyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiB0cnVlLCB2YWx1ZTogW10gfSxcbiAgICBbXCIjdGV4dFwiXToge1xuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICBnZXQodGhpczogWG1sTm9kZSkge1xuICAgICAgICBjb25zdCBjaGlsZHJlbiA9IHRoaXNbXCJ+Y2hpbGRyZW5cIl0uZmlsdGVyKChub2RlKSA9PiBub2RlW1wifm5hbWVcIl0gIT09IFwifmNvbW1lbnRcIilcbiAgICAgICAgLy8gSWYgeG1sOnNwYWNlIGlzIG5vdCBzZXQgdG8gXCJwcmVzZXJ2ZVwiLCBjb25jYXRlbmF0ZSB0ZXh0IG5vZGVzIGFuZCB0cmltIHRoZW0gd2hpbGUgcmVtb3ZpbmcgZW1wdHkgb25lc1xuICAgICAgICBpZiAodGhpc1tcIkB4bWw6c3BhY2VcIl0gIT09IFwicHJlc2VydmVcIilcbiAgICAgICAgICByZXR1cm4gY2hpbGRyZW4ubWFwKChjaGlsZCkgPT4gY2hpbGRbXCIjdGV4dFwiXSkuZmlsdGVyKEJvb2xlYW4pLmpvaW4oXCIgXCIpXG4gICAgICAgIC8vIElmIHhtbDpzcGFjZSBpcyBzZXQgdG8gXCJwcmVzZXJ2ZVwiLCBjb25jYXRlbmF0ZSB0ZXh0IG5vZGVzIHdpdGhvdXQgdHJpbW1pbmcgdGhlbVxuICAgICAgICAvLyBJbiBjYXNlIG9mIG1peGVkIGNvbnRlbnQsIGFkZCBhIHNwYWNlIGJldHdlZW4gbWl4ZWQgbm9kZXMgaWYgbmVlZGVkXG4gICAgICAgIGxldCB0ZXh0ID0gXCJcIlxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgY29uc3Qgc3BhY2VkID0gaSAmJiAoK2NoaWxkcmVuW2kgLSAxXVtcIn5uYW1lXCJdLnN0YXJ0c1dpdGgoXCJ+XCIpIF4gK2NoaWxkcmVuW2ldW1wifm5hbWVcIl0uc3RhcnRzV2l0aChcIn5cIikpICYmICghY2hpbGRyZW5baSAtIDFdW1wiI3RleHRcIl0uZW5kc1dpdGgoXCIgXCIpKSAmJiAoIWNoaWxkcmVuW2ldW1wiI3RleHRcIl0uc3RhcnRzV2l0aChcIiBcIikpXG4gICAgICAgICAgdGV4dCArPSBgJHtzcGFjZWQgPyBcIiBcIiA6IFwiXCJ9JHtjaGlsZHJlbltpXVtcIiN0ZXh0XCJdfWBcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGV4dFxuICAgICAgfSxcbiAgICB9LFxuICAgIFtcIiNjb21tZW50c1wiXToge1xuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICBnZXQodGhpczogWG1sTm9kZSkge1xuICAgICAgICByZXR1cm4gdGhpc1tcIn5jaGlsZHJlblwiXS5maWx0ZXIoKG5vZGUpID0+IG5vZGVbXCJ+bmFtZVwiXSA9PT0gXCJ+Y29tbWVudFwiKS5tYXAoKG5vZGUpID0+IG5vZGVbXCIjdGV4dFwiXSEpXG4gICAgICB9LFxuICAgIH0sXG4gIH0pIGFzIFhtbE5vZGVcbiAgaWYgKHBhcmVudClcbiAgICBwYXJlbnRbXCJ+Y2hpbGRyZW5cIl0ucHVzaChub2RlKVxuICByZXR1cm4gbm9kZVxufVxuXG4vKiogUG9zdC1wcm9jZXNzIHhtbCBub2RlLiAqL1xuZnVuY3Rpb24gcG9zdHByb2Nlc3Mobm9kZTogWG1sTm9kZSwgb3B0aW9uczogUGFyc2VyT3B0aW9ucykge1xuICAvLyBDbGVhbiBYTUwgZG9jdW1lbnQgaWYgcmVxdWlyZWRcbiAgaWYgKG5vZGVbXCJ+bmFtZVwiXSA9PT0gXCJ+eG1sXCIpIHtcbiAgICBpZiAob3B0aW9ucz8uY2xlYW4/LmRvY3R5cGUpXG4gICAgICBkZWxldGUgbm9kZVtcIiNkb2N0eXBlXCJdXG4gICAgaWYgKG9wdGlvbnM/LmNsZWFuPy5pbnN0cnVjdGlvbnMpIHtcbiAgICAgIDsobm9kZSBhcyBSZWNvcmQ8UHJvcGVydHlLZXksIHVua25vd24+KVtcIn5jaGlsZHJlblwiXSA9IG5vZGVbXCJ+Y2hpbGRyZW5cIl0uZmlsdGVyKChjaGlsZCkgPT4gIShjaGlsZFtcIn5uYW1lXCJdIGluICgobm9kZSBhcyBYbWxEb2N1bWVudClbXCIjaW5zdHJ1Y3Rpb25zXCJdID8/IHt9KSkpXG4gICAgICBkZWxldGUgbm9kZVtcIiNpbnN0cnVjdGlvbnNcIl1cbiAgICB9XG4gIH1cbiAgLy8gQ2xlYW4gbm9kZSBhbmQgZW5hYmxlIGVudW1lcmFibGUgcHJvcGVydGllcyBpZiByZXF1aXJlZFxuICBpZiAobm9kZVtcIn5jaGlsZHJlblwiXSkge1xuICAgIGlmIChvcHRpb25zPy5jbGVhbj8uY29tbWVudHMpIHtcbiAgICAgIDsobm9kZSBhcyBSZWNvcmQ8UHJvcGVydHlLZXksIHVua25vd24+KVtcIn5jaGlsZHJlblwiXSA9IG5vZGVbXCJ+Y2hpbGRyZW5cIl0uZmlsdGVyKChjaGlsZCkgPT4gY2hpbGRbXCJ+bmFtZVwiXSAhPT0gXCJ+Y29tbWVudFwiKVxuICAgIH1cbiAgICBpZiAob3B0aW9ucz8ucmV2aXZlPy50cmltKVxuICAgICAgbm9kZVtcIn5jaGlsZHJlblwiXS5mb3JFYWNoKChjaGlsZCkgPT4gL15+KD86dGV4dHxjZGF0YXxjb21tZW50KSQvLnRlc3QoY2hpbGRbXCJ+bmFtZVwiXSkgPyAoY2hpbGQgYXMgUmVjb3JkPFByb3BlcnR5S2V5LCB1bmtub3duPilbXCIjdGV4dFwiXSA9IHJldml2ZShjaGlsZCwgXCIjdGV4dFwiLCB7IHJldml2ZTogeyB0cmltOiBub2RlW1wiQHhtbDpzcGFjZVwiXSAhPT0gXCJwcmVzZXJ2ZVwiIH0gfSkgOiBudWxsKVxuICAgIGlmIChub2RlW1wifmNoaWxkcmVuXCJdLnNvbWUoKGNoaWxkKSA9PiAoL15+KD86dGV4dHxjZGF0YSkkLy50ZXN0KGNoaWxkW1wifm5hbWVcIl0pKSAmJiAoY2hpbGRbXCIjdGV4dFwiXS50cmltKCkubGVuZ3RoICsgKG5vZGVbXCJAeG1sOnNwYWNlXCJdID09PSBcInByZXNlcnZlXCIgPyAxIDogMCkgKiBjaGlsZFtcIiN0ZXh0XCJdLmxlbmd0aCkpKVxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG5vZGUsIFwiI3RleHRcIiwgeyBlbnVtZXJhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUgfSlcbiAgICBpZiAobm9kZVtcIn5jaGlsZHJlblwiXS5zb21lKChjaGlsZCkgPT4gY2hpbGRbXCJ+bmFtZVwiXSA9PT0gXCJ+Y29tbWVudFwiKSlcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShub2RlLCBcIiNjb21tZW50c1wiLCB7IGVudW1lcmFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9KVxuICB9XG4gIC8vIFByb2Nlc3MgY2hpbGQgbm9kZXNcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobm9kZSkpIHtcbiAgICAvLyBTa2lwIGNvbW1lbnRzXG4gICAgaWYgKGtleSA9PT0gXCIjY29tbWVudHNcIilcbiAgICAgIGNvbnRpbnVlXG4gICAgLy8gQ2xlYW4gYXR0cmlidXRlcyBpZiByZXF1aXJlZFxuICAgIGlmICgob3B0aW9ucz8uY2xlYW4/LmF0dHJpYnV0ZXMpICYmIChrZXkuc3RhcnRzV2l0aChcIkBcIikpKSB7XG4gICAgICBkZWxldGUgbm9kZVtrZXldXG4gICAgICBjb250aW51ZVxuICAgIH1cbiAgICAvLyBSZXZpdmUgYXR0cmlidXRlIHZhbHVlIGlmIHJlcXVpcmVkXG4gICAgaWYgKGtleS5zdGFydHNXaXRoKFwiQFwiKSkge1xuICAgICAgbm9kZVtrZXldID0gcmV2aXZlKG5vZGUsIGtleSwgb3B0aW9ucylcbiAgICAgIGlmIChub2RlW2tleV0gPT09IHVuZGVmaW5lZClcbiAgICAgICAgZGVsZXRlIG5vZGVba2V5XVxuICAgICAgY29udGludWVcbiAgICB9XG4gICAgLy8gSGFuZGxlIG90aGVyIG5vZGVzXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICBub2RlW2tleV0gPSBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh2YWx1ZS5tYXAoKGNoaWxkKSA9PiBwb3N0cHJvY2VzcyhjaGlsZCwgb3B0aW9ucykpLCB7XG4gICAgICAgIFtcIn5wYXJlbnRcIl06IHsgZW51bWVyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiBmYWxzZSwgdmFsdWU6IG5vZGUgfSxcbiAgICAgICAgW1wifm5hbWVcIl06IHsgZW51bWVyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiBmYWxzZSwgdmFsdWU6IGtleSB9LFxuICAgICAgfSlcbiAgICB9IGVsc2UgaWYgKCh0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIpICYmIHZhbHVlKSB7XG4gICAgICBub2RlW2tleV0gPSBwb3N0cHJvY2Vzcyh2YWx1ZSBhcyBYbWxOb2RlLCBvcHRpb25zKVxuICAgIH1cbiAgICBpZiAobm9kZVtrZXldID09PSB1bmRlZmluZWQpXG4gICAgICBkZWxldGUgbm9kZVtrZXldXG4gIH1cbiAgLy8gUmV2aXZlIHRleHQgaWYgcmVxdWlyZWRcbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKG5vZGUpXG4gIGlmIChrZXlzLmluY2x1ZGVzKFwiI3RleHRcIikpIHtcbiAgICBjb25zdCBfb3B0aW9ucyA9IHsgLi4ub3B0aW9ucywgcmV2aXZlOiB7IC4uLm9wdGlvbnM/LnJldml2ZSwgdHJpbTogKG9wdGlvbnM/LnJldml2ZT8udHJpbSkgJiYgKG5vZGVbXCJAeG1sOnNwYWNlXCJdICE9PSBcInByZXNlcnZlXCIpIH0gfVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShub2RlLCBcIiN0ZXh0XCIsIHsgZW51bWVyYWJsZTogdHJ1ZSwgY29uZmlndXJhYmxlOiB0cnVlLCB2YWx1ZTogcmV2aXZlKG5vZGUsIFwiI3RleHRcIiwgX29wdGlvbnMpIH0pXG4gIH1cbiAgLy8gQ3VzdG9tIHJldml2YWwgaWYgcmVxdWlyZWRcbiAgaWYgKG9wdGlvbnM/LnJldml2ZT8uY3VzdG9tKSB7XG4gICAgaWYgKG9wdGlvbnMucmV2aXZlLmN1c3RvbSh7IG5hbWU6IG5vZGVbXCJ+bmFtZVwiXSwga2V5OiBudWxsLCB2YWx1ZTogbnVsbCwgbm9kZTogbm9kZSBhcyBYbWxOb2RlIH0pID09PSB1bmRlZmluZWQpXG4gICAgICByZXR1cm4gdW5kZWZpbmVkXG4gIH1cbiAgLy8gRmxhdHRlbiBvYmplY3QgaWYgcmVxdWlyZWRcbiAgaWYgKChvcHRpb25zPy5mbGF0dGVuPy50ZXh0KSAmJiAoa2V5cy5sZW5ndGggPT09IDEpICYmIChrZXlzLmluY2x1ZGVzKFwiI3RleHRcIikpKVxuICAgIHJldHVybiBub2RlW1wiI3RleHRcIl1cbiAgaWYgKChvcHRpb25zPy5mbGF0dGVuPy5hdHRyaWJ1dGVzKSAmJiAoa2V5cy5sZW5ndGgpICYmIChrZXlzLmV2ZXJ5KChrZXkpID0+IGtleS5zdGFydHNXaXRoKFwiQFwiKSkpKSB7XG4gICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgbm9kZVtrZXkuc2xpY2UoMSldID0gbm9kZVtrZXldXG4gICAgICBkZWxldGUgbm9kZVtrZXldXG4gICAgfVxuICAgIHJldHVybiBub2RlXG4gIH1cbiAgaWYgKCFrZXlzLmxlbmd0aClcbiAgICByZXR1cm4gKG9wdGlvbnM/LmZsYXR0ZW4/LmVtcHR5KSA/IG51bGwgOiAob3B0aW9ucz8uZmxhdHRlbj8udGV4dCkgPyBcIlwiIDogT2JqZWN0LmRlZmluZVByb3BlcnR5KG5vZGUsIFwiI3RleHRcIiwgeyBlbnVtZXJhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUsIHZhbHVlOiBcIlwiIH0pXG4gIHJldHVybiBub2RlXG59XG5cbi8qKiBFbnRpdGllcyAqL1xuY29uc3QgZW50aXRpZXMgPSB7XG4gIFwiJmx0O1wiOiBcIjxcIixcbiAgXCImZ3Q7XCI6IFwiPlwiLFxuICBcIiZhcG9zO1wiOiBcIidcIixcbiAgXCImcXVvdDtcIjogJ1wiJyxcbiAgXCImYW1wO1wiOiBcIiZcIiwgLy9LZWVwIGxhc3Rcbn0gYXMgY29uc3RcblxuLyoqIFJldml2ZSB2YWx1ZS4gKi9cbmZ1bmN0aW9uIHJldml2ZShub2RlOiBYbWxOb2RlIHwgWG1sVGV4dCwga2V5OiBzdHJpbmcsIG9wdGlvbnM6IFBhcnNlck9wdGlvbnMpIHtcbiAgbGV0IHZhbHVlID0gKG5vZGUgYXMgWG1sTm9kZSlba2V5XSBhcyBzdHJpbmdcbiAgaWYgKG9wdGlvbnM/LnJldml2ZT8udHJpbSlcbiAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKVxuICBpZiAob3B0aW9ucz8ucmV2aXZlPy5lbnRpdGllcykge1xuICAgIHZhbHVlID0gdmFsdWUucmVwbGFjZUFsbCgvJiMoPzxoZXg+eD8pKD88Y29kZT5bQS1GYS1mXFxkXSspOy9nLCAoXywgaGV4LCBjb2RlKSA9PiBTdHJpbmcuZnJvbUNoYXJDb2RlKE51bWJlci5wYXJzZUludChjb2RlLCBoZXggPyAxNiA6IDEwKSkpXG4gICAgZm9yIChjb25zdCBbZW50aXR5LCBjaGFyYWN0ZXJdIG9mIE9iamVjdC5lbnRyaWVzKGVudGl0aWVzKSlcbiAgICAgIHZhbHVlID0gdmFsdWUucmVwbGFjZUFsbChlbnRpdHksIGNoYXJhY3RlcilcbiAgfVxuICBpZiAoKG9wdGlvbnM/LnJldml2ZT8ubnVtYmVycykgJiYgKHZhbHVlLmxlbmd0aCkgJiYgKE51bWJlci5pc0Zpbml0ZShOdW1iZXIodmFsdWUpKSkgJiYgKCEoKG5vZGVbXCJ+bmFtZVwiXSA9PT0gXCJ+eG1sXCIpICYmIChrZXkgPT09IFwiQHZlcnNpb25cIikpKSlcbiAgICB2YWx1ZSA9IE51bWJlcih2YWx1ZSkgYXMgdW5rbm93biBhcyBzdHJpbmdcbiAgaWYgKChvcHRpb25zPy5yZXZpdmU/LmJvb2xlYW5zKSAmJiAoL14oPzpbVHRdcnVlfFtGZl1hbHNlKSQvLnRlc3QodmFsdWUpKSlcbiAgICB2YWx1ZSA9IC9eW1R0XXJ1ZSQvLnRlc3QodmFsdWUpIGFzIHVua25vd24gYXMgc3RyaW5nXG4gIGlmIChvcHRpb25zPy5yZXZpdmU/LmN1c3RvbSlcbiAgICByZXR1cm4gb3B0aW9ucy5yZXZpdmUuY3VzdG9tKHsgbmFtZTogbm9kZVtcIn5uYW1lXCJdLCBrZXksIHZhbHVlLCBub2RlOiBub2RlIGFzIFhtbE5vZGUgfSlcbiAgcmV0dXJuIHZhbHVlXG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztDQUdDLEdBRUQsVUFBVTtBQXFFVix1RUFBdUUsR0FDdkUsT0FBTyxTQUFTLFNBQVMsR0FBZ0IsRUFBRSxPQUF1QjtFQUNoRSxZQUFZLENBQUM7RUFDYixRQUFRLE1BQU0sS0FBSyxDQUFDO0VBQ3BCLFFBQVEsTUFBTSxDQUFDLElBQUksS0FBSztFQUN4QixRQUFRLE1BQU0sQ0FBQyxRQUFRLEtBQUs7RUFDNUIsUUFBUSxPQUFPLEtBQUssQ0FBQztFQUNyQixRQUFRLE9BQU8sQ0FBQyxJQUFJLEtBQUs7RUFDekIsUUFBUSxPQUFPLENBQUMsS0FBSyxLQUFLO0VBQzFCLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxLQUFLLE1BQU0sRUFDMUIsTUFBTSxJQUFJLFlBQVk7RUFDeEIsT0FBTyxZQUFZLEtBQUs7QUFDMUI7QUFFQSxnRkFBZ0YsR0FDaEYsT0FBTyxTQUFTLGdCQUFnQixHQUFnQixFQUFFLElBQVksRUFBRSxHQUFXO0VBQ3pFLE1BQU0sY0FBYyxPQUFPLE1BQU0sQ0FBQyxTQUFTLE1BQU07SUFBRSxRQUFRO0VBQUksSUFBSSxlQUFlO0VBQ2xGLEdBQUcsQ0FBQyxnQkFBZ0IsS0FBSyxDQUFDO0VBQzFCLE9BQVE7SUFDTixLQUFLLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLOztNQUN6QyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFvQixJQUFJLENBQUM7TUFDckQ7SUFDRixLQUFLLFFBQVEsR0FBRyxDQUFDLGdCQUFnQjtNQUMvQixHQUFHLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxHQUFHO1FBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLEtB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
package/_types.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /** Nullable type. */ export type Nullable<T> = T | null;
2
+ /** XML text node. */ export type XmlText = {
3
+ /** Parent node. */ readonly ["~parent"]: XmlNode;
4
+ /** Tag name (`~text` for text nodes, `~cdata` for CDATA nodes and `~comment` for comment nodes). */ readonly ["~name"]: string;
5
+ /** Text content. */ ["#text"]: string;
6
+ };
7
+ /** XML node. */ export type XmlNode = {
8
+ /** Tag name (`~xml` for XML prolog, other nodes will be given their respective tag name). */ readonly ["~name"]: string;
9
+ /** Child nodes. */ readonly ["~children"]: Array<XmlNode | XmlText>;
10
+ /** Comments. */ readonly ["#comments"]?: Array<string>;
11
+ /** Text content. */ readonly ["#text"]: string;
12
+ [key: string]: unknown;
13
+ };
14
+ /** XML document. */ export type XmlDocument = XmlNode & {
15
+ /** XML version. */ ["@version"]?: `1.${number}`;
16
+ /** XML character encoding. */ ["@encoding"]?: string;
17
+ /** XML standalone. */ ["@standalone"]?: "yes" | "no";
18
+ /** XML doctype. */ ["#doctype"]?: XmlNode;
19
+ /** XML instructions. */ ["#instructions"]?: {
20
+ [key: string]: XmlNode | Array<XmlNode>;
21
+ };
22
+ };
23
+ /** Synchronous reader. */ export type ReaderSync = {
24
+ /** Read synchronously some data into a buffer and returns the number of bytes read. */ readSync(buffer: Uint8Array): Nullable<number>;
25
+ };
26
+ /** A laxer type for what can be stringified. We won’t ever create this, but we’ll accept it. */ export type Stringifyable = Partial<Omit<XmlDocument, "@version" | "@standalone"> & {
27
+ "@version": string;
28
+ "@standalone": string;
29
+ }>;
package/_types.js ADDED
@@ -0,0 +1,2 @@
1
+ /** Nullable type. */
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMveG1sL190eXBlcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiogTnVsbGFibGUgdHlwZS4gKi9cbmV4cG9ydCB0eXBlIE51bGxhYmxlPFQ+ID0gVCB8IG51bGxcblxuLyoqIFhNTCB0ZXh0IG5vZGUuICovXG5leHBvcnQgdHlwZSBYbWxUZXh0ID0ge1xuICAvKiogUGFyZW50IG5vZGUuICovXG4gIHJlYWRvbmx5IFtcIn5wYXJlbnRcIl06IFhtbE5vZGVcbiAgLyoqIFRhZyBuYW1lIChgfnRleHRgIGZvciB0ZXh0IG5vZGVzLCBgfmNkYXRhYCBmb3IgQ0RBVEEgbm9kZXMgYW5kIGB+Y29tbWVudGAgZm9yIGNvbW1lbnQgbm9kZXMpLiAqL1xuICByZWFkb25seSBbXCJ+bmFtZVwiXTogc3RyaW5nXG4gIC8qKiBUZXh0IGNvbnRlbnQuICovXG4gIFtcIiN0ZXh0XCJdOiBzdHJpbmdcbn1cblxuLyoqIFhNTCBub2RlLiAqL1xuZXhwb3J0IHR5cGUgWG1sTm9kZSA9IHtcbiAgLyoqIFRhZyBuYW1lIChgfnhtbGAgZm9yIFhNTCBwcm9sb2csIG90aGVyIG5vZGVzIHdpbGwgYmUgZ2l2ZW4gdGhlaXIgcmVzcGVjdGl2ZSB0YWcgbmFtZSkuICovXG4gIHJlYWRvbmx5IFtcIn5uYW1lXCJdOiBzdHJpbmdcbiAgLyoqIENoaWxkIG5vZGVzLiAqL1xuICByZWFkb25seSBbXCJ+Y2hpbGRyZW5cIl06IEFycmF5PFhtbE5vZGUgfCBYbWxUZXh0PlxuICAvKiogQ29tbWVudHMuICovXG4gIHJlYWRvbmx5IFtcIiNjb21tZW50c1wiXT86IEFycmF5PHN0cmluZz5cbiAgLyoqIFRleHQgY29udGVudC4gKi9cbiAgcmVhZG9ubHkgW1wiI3RleHRcIl06IHN0cmluZ1xuICAvLyBTaWduYXR1cmVcbiAgW2tleTogc3RyaW5nXTogdW5rbm93blxufVxuXG4vKiogWE1MIGRvY3VtZW50LiAqL1xuZXhwb3J0IHR5cGUgWG1sRG9jdW1lbnQgPSBYbWxOb2RlICYge1xuICAvKiogWE1MIHZlcnNpb24uICovXG4gIFtcIkB2ZXJzaW9uXCJdPzogYDEuJHtudW1iZXJ9YFxuICAvKiogWE1MIGNoYXJhY3RlciBlbmNvZGluZy4gKi9cbiAgW1wiQGVuY29kaW5nXCJdPzogc3RyaW5nXG4gIC8qKiBYTUwgc3RhbmRhbG9uZS4gKi9cbiAgW1wiQHN0YW5kYWxvbmVcIl0/OiBcInllc1wiIHwgXCJub1wiXG4gIC8qKiBYTUwgZG9jdHlwZS4gKi9cbiAgW1wiI2RvY3R5cGVcIl0/OiBYbWxOb2RlXG4gIC8qKiBYTUwgaW5zdHJ1Y3Rpb25zLiAqL1xuICBbXCIjaW5zdHJ1Y3Rpb25zXCJdPzogeyBba2V5OiBzdHJpbmddOiBYbWxOb2RlIHwgQXJyYXk8WG1sTm9kZT4gfVxufVxuXG4vKiogU3luY2hyb25vdXMgcmVhZGVyLiAqL1xuZXhwb3J0IHR5cGUgUmVhZGVyU3luYyA9IHtcbiAgLyoqIFJlYWQgc3luY2hyb25vdXNseSBzb21lIGRhdGEgaW50byBhIGJ1ZmZlciBhbmQgcmV0dXJucyB0aGUgbnVtYmVyIG9mIGJ5dGVzIHJlYWQuICovXG4gIHJlYWRTeW5jKGJ1ZmZlcjogVWludDhBcnJheSk6IE51bGxhYmxlPG51bWJlcj5cbn1cblxuLyoqIEEgbGF4ZXIgdHlwZSBmb3Igd2hhdCBjYW4gYmUgc3RyaW5naWZpZWQuIFdlIHdvbuKAmXQgZXZlciBjcmVhdGUgdGhpcywgYnV0IHdl4oCZbGwgYWNjZXB0IGl0LiAqL1xuZXhwb3J0IHR5cGUgU3RyaW5naWZ5YWJsZSA9IFBhcnRpYWw8T21pdDxYbWxEb2N1bWVudCwgXCJAdmVyc2lvblwiIHwgXCJAc3RhbmRhbG9uZVwiPiAmIHsgXCJAdmVyc2lvblwiOiBzdHJpbmc7IFwiQHN0YW5kYWxvbmVcIjogc3RyaW5nIH0+XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsbUJBQW1CLEdBQ25CIn0=
@@ -288,4 +288,4 @@
288
288
  <PRICE>$3.02</PRICE>
289
289
  <AVAILABILITY>022299</AVAILABILITY>
290
290
  </PLANT>
291
- </CATALOG>
291
+ </CATALOG>
@@ -4,4 +4,4 @@
4
4
  <from>Jani</from>
5
5
  <heading>Reminder</heading>
6
6
  <body>Don't forget me this weekend!</body>
7
- </note>
7
+ </note>
package/bench/bench.ts CHANGED
@@ -1,12 +1,16 @@
1
- import { expandGlob } from "@std/fs/expand-glob"
1
+ // deno-lint-ignore-file no-external-import no-import-prefix
2
+ import { expandGlob } from "jsr:@std/fs@1/expand-glob"
2
3
  import { parse } from "../mod.ts"
4
+ import { parse as parseWasm } from "../wasm/parse.ts"
5
+ import { parse as parse_v7 } from "jsr:@libs/xml@7.0.4/parse"
6
+ import { parse as parse_v6 } from "jsr:@libs/xml@6.0.8/parse"
3
7
  import { parse as parse_v5 } from "jsr:@libs/xml@5.0.2/parse"
4
8
  import { parse as parse_v4 } from "https://deno.land/x/xml@4.0.0/parse.ts"
5
9
  import { parse as parse_v3 } from "https://deno.land/x/xml@3.0.2/parse.ts"
6
10
 
7
11
  for await (const { name, path } of expandGlob("**/!(x-)*.xml", { globstar: true })) {
8
12
  const { size } = await (await Deno.open(path)).stat()
9
- for (const [func, f] of Object.entries({ parse, parse_v5, parse_v4, parse_v3 })) {
13
+ for (const [func, f] of Object.entries<(content: string) => unknown>({ parse, parseWasm, parse_v7, parse_v6, parse_v5, parse_v4, parse_v3 })) {
10
14
  Deno.bench(`${func}(): ${name}, ${size}b)`, async function (t) {
11
15
  const content = await Deno.readTextFile(path)
12
16
  t.start()