@lowlighter/xml 6.0.1 → 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/stringify.js ADDED
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Stringify an XML document object into a XML string.
3
+ * @module
4
+ */ // Imports
5
+ /** Internal symbol to store properties without erasing user-provided ones. */ const internal = Symbol("internal");
6
+ /**
7
+ * Stringify an {@link XmlDocument} object into a XML string.
8
+ *
9
+ * Output can be customized using the {@link options} parameter.
10
+ *
11
+ * ```ts
12
+ * import { stringify } from "./stringify.ts"
13
+ *
14
+ * console.log(stringify({
15
+ * "@version": "1.0",
16
+ * "@standalone": "yes",
17
+ * root: {
18
+ * text: "hello",
19
+ * array: ["world", "monde", "世界", "🌏"],
20
+ * number: 42,
21
+ * boolean: true,
22
+ * complex: {
23
+ * "@attribute": "value",
24
+ * "#text": "content",
25
+ * },
26
+ * }
27
+ * }))
28
+ * ```
29
+ */ export function stringify(document, options) {
30
+ options ??= {};
31
+ options.format ??= {};
32
+ options.format.indent ??= " ";
33
+ options.format.breakline ??= 128;
34
+ const _options = options;
35
+ let text = "";
36
+ document = clone(document);
37
+ // Add prolog
38
+ text += xml_prolog(document, _options);
39
+ // Add processing instructions
40
+ if (document["#instructions"]) {
41
+ for (const [name, nodes] of Object.entries(document["#instructions"])){
42
+ for (const node of [
43
+ nodes
44
+ ].flat()){
45
+ if (!("~name" in node)) Object.defineProperties(node, {
46
+ ["~name"]: {
47
+ enumerable: false,
48
+ writable: false,
49
+ value: name
50
+ }
51
+ });
52
+ text += xml_instruction(node, _options);
53
+ }
54
+ }
55
+ }
56
+ // Add doctype
57
+ if (document["#doctype"]) text += xml_doctype(document["#doctype"], _options);
58
+ // Add root node
59
+ const [root, ...garbage] = xml_children(document, _options);
60
+ if (!root) throw new SyntaxError("No root node detected");
61
+ if (garbage.length) throw new SyntaxError("Multiple root node detected");
62
+ text += xml_node(root, {
63
+ ..._options,
64
+ depth: 0
65
+ });
66
+ return text.trim();
67
+ }
68
+ /**
69
+ * Clone the provided user document so it {@linkcode stringify} can edit it in-place without affecting user.
70
+ *
71
+ * It copies all enumerable properties along non-enumerable one supported by `parse`
72
+ */ function clone(document) {
73
+ const cloned = Array.isArray(document) ? [] : {};
74
+ for(const property in document)cloned[property] = document[property] !== null && [
75
+ "object",
76
+ "function"
77
+ ].includes(typeof document[property]) ? clone(document[property]) : document[property];
78
+ [
79
+ "~name",
80
+ "~parent",
81
+ "#text",
82
+ "~children",
83
+ "#comments",
84
+ "#text",
85
+ "#doctype",
86
+ "#instructions",
87
+ internal
88
+ ].forEach((property)=>{
89
+ if (property in document) Object.defineProperty(cloned, property, Object.getOwnPropertyDescriptor(document, property));
90
+ });
91
+ return cloned;
92
+ }
93
+ /**
94
+ * Helper to create a CDATA node.
95
+ *
96
+ * ```ts
97
+ * import { stringify, cdata } from "./stringify.ts"
98
+ * stringify({ string: cdata(`hello <world>`) })
99
+ * // <string><![CDATA[hello <world>]]></string>
100
+ * ```
101
+ */ export function cdata(text) {
102
+ return {
103
+ "~name": "~cdata",
104
+ "#text": text
105
+ };
106
+ }
107
+ /**
108
+ * Helper to create a comment node.
109
+ *
110
+ * ```ts
111
+ * import { stringify, comment } from "./stringify.ts"
112
+ * stringify({ string: comment(`hello world`) })
113
+ * // <string><!--hello world--></string>
114
+ * ```
115
+ */ export function comment(text) {
116
+ return {
117
+ "~name": "~comment",
118
+ "#text": text
119
+ };
120
+ }
121
+ /** Create XML prolog. */ function xml_prolog(document, options) {
122
+ ;
123
+ document["~name"] ??= "xml";
124
+ return xml_instruction(document, options);
125
+ }
126
+ /** Create XML instruction. */ function xml_instruction(node, { format: { indent } }) {
127
+ let text = "";
128
+ const attributes = xml_attributes(node, arguments[1]);
129
+ if (attributes.length) {
130
+ text += `<?${node["~name"].replace(/^~/, "")}`;
131
+ for (const [name, value] of attributes)text += ` ${name}="${value}"`;
132
+ text += `?>${indent ? "\n" : ""}`;
133
+ }
134
+ return text;
135
+ }
136
+ /** Create XML doctype. */ function xml_doctype(node, { format: { indent } }) {
137
+ let text = "";
138
+ const attributes = xml_attributes(node, arguments[1]);
139
+ const elements = xml_children(node, arguments[1]);
140
+ if (attributes.length + elements.length) {
141
+ text += `<!DOCTYPE`;
142
+ for (const [name] of attributes)text += ` ${!/^[A-Za-z0-9_]+$/.test(name) ? `"${name}"` : name}`;
143
+ if (elements.length) {
144
+ text += `${indent ? `\n${indent}` : " "}[${indent ? "\n" : ""}`;
145
+ for (const element of elements)text += `${indent}<!ELEMENT ${element["~name"]} (${element["#text"]})>${indent ? "\n" : ""}`;
146
+ text += `${indent ? indent : ""}]${indent ? "\n" : ""}`;
147
+ }
148
+ text += `>${indent ? "\n" : ""}`;
149
+ }
150
+ return text;
151
+ }
152
+ /** Create XML node. */ function xml_node(node, { format: { breakline = 0, indent = "" }, replace, depth = 0 }) {
153
+ if (replace?.custom) {
154
+ if (replace.custom({
155
+ name: node["~name"],
156
+ key: null,
157
+ value: null,
158
+ node
159
+ }) === undefined) return "";
160
+ }
161
+ let text = `${indent.repeat(depth)}<${node["~name"]}`;
162
+ const attributes = xml_attributes(node, arguments[1]);
163
+ const children = xml_children(node, arguments[1]);
164
+ const preserve = node["@xml:space"] === "preserve";
165
+ for (const [name, value] of attributes)text += ` ${name}="${value}"`;
166
+ if (children.length || "#text" in node && node["#text"].length) {
167
+ const inline = indent && !preserve && (children.length || node["#text"].length > breakline - indent.length * depth);
168
+ text += `>${indent && !preserve && children.length ? "\n" : ""}`;
169
+ if ("#text" in node) {
170
+ if (inline) text += `\n${indent.repeat(depth + 1)}`;
171
+ text += node["#text"];
172
+ if (inline) text += "\n";
173
+ }
174
+ for (const child of children)text += xml_node(child, {
175
+ ...arguments[1],
176
+ depth: depth + 1
177
+ });
178
+ if (inline) text += indent.repeat(depth);
179
+ text += `</${node["~name"]}>${indent ? "\n" : ""}`;
180
+ } else {
181
+ text += `/>${indent ? "\n" : ""}`;
182
+ }
183
+ return text;
184
+ }
185
+ /** Extract children from node. */ function xml_children(node, options) {
186
+ const children = Object.keys(node).filter((key)=>/^[A-Za-z_]/.test(key)).flatMap((key)=>[
187
+ node[key]
188
+ ].flat().map((value)=>{
189
+ switch(true){
190
+ case value === null:
191
+ return {
192
+ ["~name"]: key,
193
+ ["#text"]: ""
194
+ };
195
+ case typeof value === "object":
196
+ {
197
+ const child = {
198
+ ...value,
199
+ ["~name"]: key
200
+ };
201
+ if (value["~name"]?.startsWith("~")) child[internal] = value["~name"];
202
+ return child;
203
+ }
204
+ default:
205
+ return {
206
+ ["~name"]: key,
207
+ ["#text"]: `${value}`
208
+ };
209
+ }
210
+ })).map((node)=>{
211
+ if ("#text" in node) {
212
+ const cdata = node[internal] === "~cdata";
213
+ const comment = node[internal] === "~comment";
214
+ node["#text"] = replace(node, "#text", {
215
+ ...options,
216
+ escape: cdata ? [] : [
217
+ "&",
218
+ "<",
219
+ ">"
220
+ ]
221
+ });
222
+ if (node["#text"] === undefined) delete node["#text"];
223
+ else node["#text"] = cdata ? `<![CDATA[${node["#text"]}]]>` : comment ? `<!--${node["#text"]}-->` : `${node["#text"]}`;
224
+ }
225
+ return node;
226
+ });
227
+ return children;
228
+ }
229
+ /** Extract attributes from node. */ function xml_attributes(node, options) {
230
+ return Object.entries(node).filter(([key])=>key.startsWith("@")).map(([key])=>[
231
+ key.slice(1),
232
+ replace(node, key, {
233
+ ...options,
234
+ escape: [
235
+ "&",
236
+ '"',
237
+ "'"
238
+ ]
239
+ })
240
+ ]).filter(([_, value])=>value !== undefined);
241
+ }
242
+ /** Entities */ const entities = {
243
+ "&": "&amp;",
244
+ '"': "&quot;",
245
+ "<": "&lt;",
246
+ ">": "&gt;",
247
+ "'": "&apos;"
248
+ };
249
+ /** Replace value. */ function replace(node, key, options) {
250
+ let value = `${node[key]}`;
251
+ if (options?.escape) {
252
+ if (options?.replace?.entities) options.escape = Object.keys(entities);
253
+ for (const char of options?.escape)value = `${value}`.replaceAll(char, entities[char]);
254
+ }
255
+ if (options?.replace?.custom) return options.replace.custom({
256
+ name: node["~name"],
257
+ key,
258
+ value,
259
+ node: node
260
+ });
261
+ return value;
262
+ }
263
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMveG1sL3N0cmluZ2lmeS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFN0cmluZ2lmeSBhbiBYTUwgZG9jdW1lbnQgb2JqZWN0IGludG8gYSBYTUwgc3RyaW5nLlxuICogQG1vZHVsZVxuICovXG5cbi8vIEltcG9ydHNcbmltcG9ydCB0eXBlIHsgTnVsbGFibGUsIFN0cmluZ2lmeWFibGUsIFhtbERvY3VtZW50LCBYbWxOb2RlLCBYbWxUZXh0IH0gZnJvbSBcIi4vX3R5cGVzLmpzXCJcbmV4cG9ydCB0eXBlICogZnJvbSBcIi4vX3R5cGVzLmpzXCJcblxuLyoqIFhNTCBzdHJpbmdpZmllciBvcHRpb25zLiAqL1xuZXhwb3J0IHR5cGUgU3RyaW5naWZ5T3B0aW9ucyA9IHtcbiAgLyoqIEZvcm1hdCBvcHRpb25zLiAqL1xuICBmb3JtYXQ/OiBGb3JtYXRPcHRpb25zXG4gIC8qKiBSZXBsYWNlIG9wdGlvbnMuICovXG4gIHJlcGxhY2U/OiBSZXBsYWNlT3B0aW9uc1xufVxuXG4vKiogWE1MIHN0cmluZ2lmaWVyIHtAbGlua2NvZGUgU3RyaW5naWZ5T3B0aW9uc31gLmZvcm1hdGAgKi9cbmV4cG9ydCB0eXBlIEZvcm1hdE9wdGlvbnMgPSB7XG4gIC8qKlxuICAgKiBJbmRlbnQgc3RyaW5nIChkZWZhdWx0cyB0byBgXCIgIFwiYCkuXG4gICAqIFNldCB0byBlbXB0eSBzdHJpbmcgdG8gZGlzYWJsZSBpbmRlbnRhdGlvbiBhbmQgZW5hYmxlIG1pbmlmaWNhdGlvbi5cbiAgICovXG4gIGluZGVudD86IHN0cmluZ1xuICAvKiogQnJlYWsgdGV4dCBub2RlIGlmIGl0cyBsZW5ndGggaXMgZ3JlYXRlciB0aGFuIHRoaXMgdmFsdWUgKGRlZmF1bHRzIHRvIGAxMjhgKS4gKi9cbiAgYnJlYWtsaW5lPzogbnVtYmVyXG59XG5cbi8qKiBYTUwgc3RyaW5naWZpZXIge0BsaW5rY29kZSBTdHJpbmdpZnlPcHRpb25zfWAucmVwbGFjZWAgKi9cbmV4cG9ydCB0eXBlIFJlcGxhY2VPcHRpb25zID0ge1xuICAvKipcbiAgICogRm9yY2UgZXNjYXBlIGFsbCBYTUwgZW50aXRpZXMuXG4gICAqIEJ5IGRlZmF1bHQsIG9ubHkgdGhlIG9uZXMgdGhhdCB3b3VsZCBicmVhayB0aGUgWE1MIHN0cnVjdHVyZSBhcmUgZXNjYXBlZC5cbiAgICovXG4gIGVudGl0aWVzPzogYm9vbGVhblxuICAvKipcbiAgICogQ3VzdG9tIHJlcGxhY2VyICh0aGlzIGlzIGFwcGxpZWQgYWZ0ZXIgb3RoZXIgcmV2aXZhbHMpLlxuICAgKiBXaGVuIGl0IGlzIGFwcGxpZWQgb24gYW4gYXR0cmlidXRlLCBga2V5YCBhbmQgYHZhbHVlYCB3aWxsIGJlIGdpdmVuLlxuICAgKiBXaGVuIGl0IGlzIGFwcGxpZWQgb24gYSBub2RlLCBib3RoIGBrZXlgIGFuZCBgdmFsdWVgIHdpbGwgYmUgYG51bGxgLlxuICAgKiBSZXR1cm4gYHVuZGVmaW5lZGAgdG8gZGVsZXRlIGVpdGhlciB0aGUgYXR0cmlidXRlIG9yIHRoZSB0YWcuXG4gICAqL1xuICBjdXN0b20/OiBSZXBsYWNlclxufVxuXG4vKipcbiAqIEN1c3RvbSBYTUwgc3RyaW5naWZpZXIgcmVwbGFjZXIuXG4gKiBJdCBjYW4gYmUgdXNlZCB0byBjaGFuZ2UgdGhlIHdheSBzb21lIG5vZGVzIGFyZSBzdHJpbmdpZmllZC5cbiAqL1xuZXhwb3J0IHR5cGUgUmVwbGFjZXIgPSAoYXJnczogeyBuYW1lOiBzdHJpbmc7IGtleTogTnVsbGFibGU8c3RyaW5nPjsgdmFsdWU6IE51bGxhYmxlPHN0cmluZz47IG5vZGU6IFJlYWRvbmx5PFhtbE5vZGU+IH0pID0+IHVua25vd25cblxuLyoqIFhNTCBzdHJpbmdpZmllciBvcHRpb25zICh3aXRoIG5vbi1udWxsYWJsZSBmb3JtYXQgb3B0aW9ucykuICovXG50eXBlIF9PcHRpb25zID0gU3RyaW5naWZ5T3B0aW9ucyAmIHsgZm9ybWF0OiBOb25OdWxsYWJsZTxTdHJpbmdpZnlPcHRpb25zW1wiZm9ybWF0XCJdPiB9XG5cbi8qKiBJbnRlcm5hbCBzeW1ib2wgdG8gc3RvcmUgcHJvcGVydGllcyB3aXRob3V0IGVyYXNpbmcgdXNlci1wcm92aWRlZCBvbmVzLiAqL1xuY29uc3QgaW50ZXJuYWwgPSBTeW1ib2woXCJpbnRlcm5hbFwiKVxuXG4vKipcbiAqIFN0cmluZ2lmeSBhbiB7QGxpbmsgWG1sRG9jdW1lbnR9IG9iamVjdCBpbnRvIGEgWE1MIHN0cmluZy5cbiAqXG4gKiBPdXRwdXQgY2FuIGJlIGN1c3RvbWl6ZWQgdXNpbmcgdGhlIHtAbGluayBvcHRpb25zfSBwYXJhbWV0ZXIuXG4gKlxuICogYGBgdHNcbiAqIGltcG9ydCB7IHN0cmluZ2lmeSB9IGZyb20gXCIuL3N0cmluZ2lmeS50c1wiXG4gKlxuICogY29uc29sZS5sb2coc3RyaW5naWZ5KHtcbiAqICAgXCJAdmVyc2lvblwiOiBcIjEuMFwiLFxuICogICBcIkBzdGFuZGFsb25lXCI6IFwieWVzXCIsXG4gKiAgIHJvb3Q6IHtcbiAqICAgICB0ZXh0OiBcImhlbGxvXCIsXG4gKiAgICAgYXJyYXk6IFtcIndvcmxkXCIsIFwibW9uZGVcIiwgXCLkuJbnlYxcIiwgXCLwn4yPXCJdLFxuICogICAgIG51bWJlcjogNDIsXG4gKiAgICAgYm9vbGVhbjogdHJ1ZSxcbiAqICAgICBjb21wbGV4OiB7XG4gKiAgICAgICBcIkBhdHRyaWJ1dGVcIjogXCJ2YWx1ZVwiLFxuICogICAgICAgXCIjdGV4dFwiOiBcImNvbnRlbnRcIixcbiAqICAgICB9LFxuICogICB9XG4gKiB9KSlcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gc3RyaW5naWZ5KGRvY3VtZW50OiBTdHJpbmdpZnlhYmxlLCBvcHRpb25zPzogU3RyaW5naWZ5T3B0aW9ucyk6IHN0cmluZyB7XG4gIG9wdGlvbnMgPz89IHt9XG4gIG9wdGlvbnMuZm9ybWF0ID8/PSB7fVxuICBvcHRpb25zLmZvcm1hdC5pbmRlbnQgPz89IFwiICBcIlxuICBvcHRpb25zLmZvcm1hdC5icmVha2xpbmUgPz89IDEyOFxuICBjb25zdCBfb3B0aW9ucyA9IG9wdGlvbnMgYXMgX09wdGlvbnNcbiAgbGV0IHRleHQgPSBcIlwiXG4gIGRvY3VtZW50ID0gY2xvbmUoZG9jdW1lbnQpXG4gIC8vIEFkZCBwcm9sb2dcbiAgdGV4dCArPSB4bWxfcHJvbG9nKGRvY3VtZW50IGFzIFhtbERvY3VtZW50LCBfb3B0aW9ucylcbiAgLy8gQWRkIHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb25zXG4gIGlmIChkb2N1bWVudFtcIiNpbnN0cnVjdGlvbnNcIl0pIHtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBub2Rlc10gb2YgT2JqZWN0LmVudHJpZXMoZG9jdW1lbnRbXCIjaW5zdHJ1Y3Rpb25zXCJdKSkge1xuICAgICAgZm9yIChjb25zdCBub2RlIG9mIFtub2Rlc10uZmxhdCgpKSB7XG4gICAgICAgIGlmICghKFwifm5hbWVcIiBpbiBub2RlKSlcbiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhub2RlLCB7IFtcIn5uYW1lXCJdOiB7IGVudW1lcmFibGU6IGZhbHNlLCB3cml0YWJsZTogZmFsc2UsIHZhbHVlOiBuYW1lIH0gfSlcbiAgICAgICAgdGV4dCArPSB4bWxfaW5zdHJ1Y3Rpb24obm9kZSwgX29wdGlvbnMpXG4gICAgICB9XG4gICAgfVxuICB9XG4gIC8vIEFkZCBkb2N0eXBlXG4gIGlmIChkb2N1bWVudFtcIiNkb2N0eXBlXCJdKVxuICAgIHRleHQgKz0geG1sX2RvY3R5cGUoZG9jdW1lbnRbXCIjZG9jdHlwZVwiXSBhcyBYbWxOb2RlLCBfb3B0aW9ucylcblxuICAvLyBBZGQgcm9vdCBub2RlXG4gIGNvbnN0IFtyb290LCAuLi5nYXJiYWdlXSA9IHhtbF9jaGlsZHJlbihkb2N1bWVudCBhcyBYbWxEb2N1bWVudCwgX29wdGlvbnMpXG4gIGlmICghcm9vdClcbiAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJObyByb290IG5vZGUgZGV0ZWN0ZWRcIilcbiAgaWYgKGdhcmJhZ2UubGVuZ3RoKVxuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIk11bHRpcGxlIHJvb3Qgbm9kZSBkZXRlY3RlZFwiKVxuICB0ZXh0ICs9IHhtbF9ub2RlKHJvb3QsIHsgLi4uX29wdGlvbnMsIGRlcHRoOiAwIH0pXG5cbiAgcmV0dXJuIHRleHQudHJpbSgpXG59XG5cbi8qKlxuICogQ2xvbmUgdGhlIHByb3ZpZGVkIHVzZXIgZG9jdW1lbnQgc28gaXQge0BsaW5rY29kZSBzdHJpbmdpZnl9IGNhbiBlZGl0IGl0IGluLXBsYWNlIHdpdGhvdXQgYWZmZWN0aW5nIHVzZXIuXG4gKlxuICogSXQgY29waWVzIGFsbCBlbnVtZXJhYmxlIHByb3BlcnRpZXMgYWxvbmcgbm9uLWVudW1lcmFibGUgb25lIHN1cHBvcnRlZCBieSBgcGFyc2VgXG4gKi9cbmZ1bmN0aW9uIGNsb25lKGRvY3VtZW50OiBSZWNvcmQ8UHJvcGVydHlLZXksIHVua25vd24+KSB7XG4gIGNvbnN0IGNsb25lZCA9IChBcnJheS5pc0FycmF5KGRvY3VtZW50KSA/IFtdIDoge30pIGFzIHR5cGVvZiBkb2N1bWVudFxuICBmb3IgKGNvbnN0IHByb3BlcnR5IGluIGRvY3VtZW50KVxuICAgIGNsb25lZFtwcm9wZXJ0eV0gPSAoKGRvY3VtZW50W3Byb3BlcnR5XSAhPT0gbnVsbCkgJiYgKFtcIm9iamVjdFwiLCBcImZ1bmN0aW9uXCJdLmluY2x1ZGVzKHR5cGVvZiBkb2N1bWVudFtwcm9wZXJ0eV0pKSkgPyBjbG9uZShkb2N1bWVudFtwcm9wZXJ0eV0gYXMgUmVjb3JkPFByb3BlcnR5S2V5LCB1bmtub3duPikgOiBkb2N1bWVudFtwcm9wZXJ0eV1cbiAgO1tcIn5uYW1lXCIsIFwifnBhcmVudFwiLCBcIiN0ZXh0XCIsIFwifmNoaWxkcmVuXCIsIFwiI2NvbW1lbnRzXCIsIFwiI3RleHRcIiwgXCIjZG9jdHlwZVwiLCBcIiNpbnN0cnVjdGlvbnNcIiwgaW50ZXJuYWxdLmZvckVhY2goKHByb3BlcnR5KSA9PiB7XG4gICAgaWYgKHByb3BlcnR5IGluIGRvY3VtZW50KVxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGNsb25lZCwgcHJvcGVydHksIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoZG9jdW1lbnQsIHByb3BlcnR5KSEpXG4gIH0pXG4gIHJldHVybiBjbG9uZWRcbn1cblxuLyoqXG4gKiBIZWxwZXIgdG8gY3JlYXRlIGEgQ0RBVEEgbm9kZS5cbiAqXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgc3RyaW5naWZ5LCBjZGF0YSB9IGZyb20gXCIuL3N0cmluZ2lmeS50c1wiXG4gKiBzdHJpbmdpZnkoeyBzdHJpbmc6IGNkYXRhKGBoZWxsbyA8d29ybGQ+YCkgfSlcbiAqIC8vIDxzdHJpbmc+PCFbQ0RBVEFbaGVsbG8gPHdvcmxkPl1dPjwvc3RyaW5nPlxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjZGF0YSh0ZXh0OiBzdHJpbmcpOiBPbWl0PFhtbFRleHQsIFwifnBhcmVudFwiPiB7XG4gIHJldHVybiB7XG4gICAgXCJ+bmFtZVwiOiBcIn5jZGF0YVwiLFxuICAgIFwiI3RleHRcIjogdGV4dCxcbiAgfVxufVxuXG4vKipcbiAqIEhlbHBlciB0byBjcmVhdGUgYSBjb21tZW50IG5vZGUuXG4gKlxuICogYGBgdHNcbiAqIGltcG9ydCB7IHN0cmluZ2lmeSwgY29tbWVudCB9IGZyb20gXCIuL3N0cmluZ2lmeS50c1wiXG4gKiBzdHJpbmdpZnkoeyBzdHJpbmc6IGNvbW1lbnQoYGhlbGxvIHdvcmxkYCkgfSlcbiAqIC8vIDxzdHJpbmc+PCEtLWhlbGxvIHdvcmxkLS0+PC9zdHJpbmc+XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbW1lbnQodGV4dDogc3RyaW5nKTogT21pdDxYbWxUZXh0LCBcIn5wYXJlbnRcIj4ge1xuICByZXR1cm4ge1xuICAgIFwifm5hbWVcIjogXCJ+Y29tbWVudFwiLFxuICAgIFwiI3RleHRcIjogdGV4dCxcbiAgfVxufVxuXG4vKiogQ3JlYXRlIFhNTCBwcm9sb2cuICovXG5mdW5jdGlvbiB4bWxfcHJvbG9nKGRvY3VtZW50OiBYbWxEb2N1bWVudCwgb3B0aW9uczogX09wdGlvbnMpOiBzdHJpbmcge1xuICA7KGRvY3VtZW50IGFzIFJlY29yZDxQcm9wZXJ0eUtleSwgdW5rbm93bj4pW1wifm5hbWVcIl0gPz89IFwieG1sXCJcbiAgcmV0dXJuIHhtbF9pbnN0cnVjdGlvbihkb2N1bWVudCwgb3B0aW9ucylcbn1cblxuLyoqIENyZWF0ZSBYTUwgaW5zdHJ1Y3Rpb24uICovXG5mdW5jdGlvbiB4bWxfaW5zdHJ1Y3Rpb24obm9kZTogWG1sTm9kZSwgeyBmb3JtYXQ6IHsgaW5kZW50IH0gfTogX09wdGlvbnMpOiBzdHJpbmcge1xuICBsZXQgdGV4dCA9IFwiXCJcbiAgY29uc3QgYXR0cmlidXRlcyA9IHhtbF9hdHRyaWJ1dGVzKG5vZGUgYXMgWG1sTm9kZSwgYXJndW1lbnRzWzFdKVxuICBpZiAoYXR0cmlidXRlcy5sZW5ndGgpIHtcbiAgICB0ZXh0ICs9IGA8PyR7bm9kZVtcIn5uYW1lXCJdLnJlcGxhY2UoL15+LywgXCJcIil9YFxuICAgIGZvciAoY29uc3QgW25hbWUsIHZhbHVlXSBvZiBhdHRyaWJ1dGVzKVxuICAgICAgdGV4dCArPSBgICR7bmFtZX09XCIke3ZhbHVlfVwiYFxuICAgIHRleHQgKz0gYD8+JHtpbmRlbnQgPyBcIlxcblwiIDogXCJcIn1gXG4gIH1cbiAgcmV0dXJuIHRleHRcbn1cblxuLyoqIENyZWF0ZSBYTUwgZG9jdHlwZS4gKi9cbmZ1bmN0aW9uIHhtbF9kb2N0eXBlKG5vZGU6IFhtbE5vZGUsIHsgZm9ybWF0OiB7IGluZGVudCB9IH06IF9PcHRpb25zKTogc3RyaW5nIHtcbiAgbGV0IHRleHQgPSBcIlwiXG4gIGNvbnN0IGF0dHJpYnV0ZXMgPSB4bWxfYXR0cmlidXRlcyhub2RlLCBhcmd1bWVudHNbMV0pXG4gIGNvbnN0IGVsZW1lbnRzID0geG1sX2NoaWxkcmVuKG5vZGUsIGFyZ3VtZW50c1sxXSlcbiAgaWYgKGF0dHJpYnV0ZXMubGVuZ3RoICsgZWxlbWVudHMubGVuZ3RoKSB7XG4gICAgdGV4dCArPSBgPCFET0NUWVBFYFxuICAgIGZvciAoY29uc3QgW25hbWVdIG9mIGF0dHJpYnV0ZXMpXG4gICAgICB0ZXh0ICs9IGAgJHshL15bQS1aYS16MC05X10rJC8udGVzdChuYW1lKSA/IGBcIiR7bmFtZX1cImAgOiBuYW1lfWBcbiAgICBpZiAoZWxlbWVudHMubGVuZ3RoKSB7XG4gICAgICB0ZXh0ICs9IGAke2luZGVudCA/IGBcXG4ke2luZGVudH1gIDogXCIgXCJ9WyR7aW5kZW50ID8gXCJcXG5cIiA6IFwiXCJ9YFxuICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKVxuICAgICAgICB0ZXh0ICs9IGAke2luZGVudH08IUVMRU1FTlQgJHtlbGVtZW50W1wifm5hbWVcIl19ICgke2VsZW1lbnRbXCIjdGV4dFwiXX0pPiR7aW5kZW50ID8gXCJcXG5cIiA6IFwiXCJ9YFxuICAgICAgdGV4dCArPSBgJHtpbmRlbnQgPyBpbmRlbnQgOiBcIlwifV0ke2luZGVudCA/IFwiXFxuXCIgOiBcIlwifWBcbiAgICB9XG4gICAgdGV4dCArPSBgPiR7aW5kZW50ID8gXCJcXG5cIiA6IFwiXCJ9YFxuICB9XG4gIHJldHVybiB0ZXh0XG59XG5cbi8qKiBDcmVhdGUgWE1MIG5vZGUuICovXG5mdW5jdGlvbiB4bWxfbm9kZShub2RlOiBYbWxOb2RlLCB7IGZvcm1hdDogeyBicmVha2xpbmUgPSAwLCBpbmRlbnQgPSBcIlwiIH0sIHJlcGxhY2UsIGRlcHRoID0gMCB9OiBfT3B0aW9ucyAmIHsgZGVwdGg/OiBudW1iZXIgfSk6IHN0cmluZyB7XG4gIGlmIChyZXBsYWNlPy5jdXN0b20pIHtcbiAgICBpZiAocmVwbGFjZS5jdXN0b20oeyBuYW1lOiBub2RlW1wifm5hbWVcIl0sIGtleTogbnVsbCwgdmFsdWU6IG51bGwsIG5vZGUgfSkgPT09IHVuZGVmaW5lZClcbiAgICAgIHJldHVybiBcIlwiXG4gIH1cbiAgbGV0IHRleHQgPSBgJHtpbmRlbnQucmVwZWF0KGRlcHRoKX08JHtub2RlW1wifm5hbWVcIl19YFxuICBjb25zdCBhdHRyaWJ1dGVzID0geG1sX2F0dHJpYnV0ZXMobm9kZSwgYXJndW1lbnRzWzFdKVxuICBjb25zdCBjaGlsZHJlbiA9IHhtbF9jaGlsZHJlbihub2RlLCBhcmd1bWVudHNbMV0pXG4gIGNvbnN0IHByZXNlcnZlID0gbm9kZVtcIkB4bWw6c3BhY2VcIl0gPT09IFwicHJlc2VydmVcIlxuICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgYXR0cmlidXRlcylcbiAgICB0ZXh0ICs9IGAgJHtuYW1lfT1cIiR7dmFsdWV9XCJgXG4gIGlmICgoY2hpbGRyZW4ubGVuZ3RoKSB8fCAoKFwiI3RleHRcIiBpbiBub2RlKSAmJiAobm9kZVtcIiN0ZXh0XCJdLmxlbmd0aCkpKSB7XG4gICAgY29uc3QgaW5saW5lID0gaW5kZW50ICYmICghcHJlc2VydmUpICYmICgoY2hpbGRyZW4ubGVuZ3RoKSB8fCAobm9kZVtcIiN0ZXh0XCJdLmxlbmd0aCA+IGJyZWFrbGluZSAtIGluZGVudC5sZW5ndGggKiBkZXB0aCkpXG4gICAgdGV4dCArPSBgPiR7aW5kZW50ICYmICghcHJlc2VydmUpICYmIChjaGlsZHJlbi5sZW5ndGgpID8gXCJcXG5cIiA6IFwiXCJ9YFxuICAgIGlmIChcIiN0ZXh0XCIgaW4gbm9kZSkge1xuICAgICAgaWYgKGlubGluZSlcbiAgICAgICAgdGV4dCArPSBgXFxuJHtpbmRlbnQucmVwZWF0KGRlcHRoICsgMSl9YFxuICAgICAgdGV4dCArPSBub2RlW1wiI3RleHRcIl1cbiAgICAgIGlmIChpbmxpbmUpXG4gICAgICAgIHRleHQgKz0gXCJcXG5cIlxuICAgIH1cbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIGNoaWxkcmVuKVxuICAgICAgdGV4dCArPSB4bWxfbm9kZShjaGlsZCwgeyAuLi5hcmd1bWVudHNbMV0sIGRlcHRoOiBkZXB0aCArIDEgfSlcbiAgICBpZiAoaW5saW5lKVxuICAgICAgdGV4dCArPSBpbmRlbnQucmVwZWF0KGRlcHRoKVxuICAgIHRleHQgKz0gYDwvJHtub2RlW1wifm5hbWVcIl19PiR7aW5kZW50ID8gXCJcXG5cIiA6IFwiXCJ9YFxuICB9IGVsc2Uge1xuICAgIHRleHQgKz0gYC8+JHtpbmRlbnQgPyBcIlxcblwiIDogXCJcIn1gXG4gIH1cbiAgcmV0dXJuIHRleHRcbn1cblxuLyoqIEV4dHJhY3QgY2hpbGRyZW4gZnJvbSBub2RlLiAqL1xuZnVuY3Rpb24geG1sX2NoaWxkcmVuKG5vZGU6IFhtbE5vZGUsIG9wdGlvbnM6IFN0cmluZ2lmeU9wdGlvbnMpOiBBcnJheTxYbWxOb2RlPiB7XG4gIGNvbnN0IGNoaWxkcmVuID0gT2JqZWN0LmtleXMobm9kZSlcbiAgICAuZmlsdGVyKChrZXkpID0+IC9eW0EtWmEtel9dLy50ZXN0KGtleSkpXG4gICAgLmZsYXRNYXAoKGtleSkgPT5cbiAgICAgIFtub2RlIVtrZXldXS5mbGF0KCkubWFwKCh2YWx1ZSkgPT4ge1xuICAgICAgICBzd2l0Y2ggKHRydWUpIHtcbiAgICAgICAgICBjYXNlIHZhbHVlID09PSBudWxsOlxuICAgICAgICAgICAgcmV0dXJuICh7IFtcIn5uYW1lXCJdOiBrZXksIFtcIiN0ZXh0XCJdOiBcIlwiIH0pXG4gICAgICAgICAgY2FzZSB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCI6IHtcbiAgICAgICAgICAgIGNvbnN0IGNoaWxkID0geyAuLi52YWx1ZSBhcyBSZWNvcmQ8UHJvcGVydHlLZXksIHVua25vd24+LCBbXCJ+bmFtZVwiXToga2V5IH0gYXMgUmVjb3JkPFByb3BlcnR5S2V5LCB1bmtub3duPlxuICAgICAgICAgICAgaWYgKCgodmFsdWUgYXMgUmVjb3JkPFByb3BlcnR5S2V5LCB1bmtub3duPilbXCJ+bmFtZVwiXSBhcyBzdHJpbmcpPy5zdGFydHNXaXRoKFwiflwiKSlcbiAgICAgICAgICAgICAgY2hpbGRbaW50ZXJuYWxdID0gKHZhbHVlIGFzIFJlY29yZDxQcm9wZXJ0eUtleSwgdW5rbm93bj4pW1wifm5hbWVcIl1cbiAgICAgICAgICAgIHJldHVybiBjaGlsZFxuICAgICAgICAgIH1cbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgcmV0dXJuICh7IFtcIn5uYW1lXCJdOiBrZXksIFtcIiN0ZXh0XCJdOiBgJHt2YWx1ZX1gIH0pXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgKVxuICAgIC5tYXAoKG5vZGUpID0+IHtcbiAgICAgIGlmIChcIiN0ZXh0XCIgaW4gbm9kZSkge1xuICAgICAgICBjb25zdCBjZGF0YSA9IG5vZGVbaW50ZXJuYWxdID09PSBcIn5jZGF0YVwiXG4gICAgICAgIGNvbnN0IGNvbW1lbnQgPSBub2RlW2ludGVybmFsXSA9PT0gXCJ+Y29tbWVudFwiXG4gICAgICAgIG5vZGVbXCIjdGV4dFwiXSA9IHJlcGxhY2Uobm9kZSBhcyBYbWxOb2RlLCBcIiN0ZXh0XCIsIHsgLi4ub3B0aW9ucywgZXNjYXBlOiBjZGF0YSA/IFtdIDogW1wiJlwiLCBcIjxcIiwgXCI+XCJdIH0pIGFzIHN0cmluZ1xuICAgICAgICBpZiAobm9kZVtcIiN0ZXh0XCJdID09PSB1bmRlZmluZWQpXG4gICAgICAgICAgZGVsZXRlIG5vZGVbXCIjdGV4dFwiXVxuICAgICAgICBlbHNlXG4gICAgICAgICAgbm9kZVtcIiN0ZXh0XCJdID0gY2RhdGEgPyBgPCFbQ0RBVEFbJHtub2RlW1wiI3RleHRcIl19XV0+YCA6IGNvbW1lbnQgPyBgPCEtLSR7bm9kZVtcIiN0ZXh0XCJdfS0tPmAgOiBgJHtub2RlW1wiI3RleHRcIl19YFxuICAgICAgfVxuICAgICAgcmV0dXJuIG5vZGVcbiAgICB9KSBhcyBSZXR1cm5UeXBlPHR5cGVvZiB4bWxfY2hpbGRyZW4+XG4gIHJldHVybiBjaGlsZHJlblxufVxuXG4vKiogRXh0cmFjdCBhdHRyaWJ1dGVzIGZyb20gbm9kZS4gKi9cbmZ1bmN0aW9uIHhtbF9hdHRyaWJ1dGVzKG5vZGU6IFhtbE5vZGUsIG9wdGlvbnM6IFN0cmluZ2lmeU9wdGlvbnMpOiBBcnJheTxbc3RyaW5nLCBzdHJpbmddPiB7XG4gIHJldHVybiBPYmplY3QuZW50cmllcyhub2RlISlcbiAgICAuZmlsdGVyKChba2V5XSkgPT4ga2V5LnN0YXJ0c1dpdGgoXCJAXCIpKVxuICAgIC5tYXAoKFtrZXldKSA9PiBba2V5LnNsaWNlKDEpLCByZXBsYWNlKG5vZGUhLCBrZXksIHsgLi4ub3B0aW9ucywgZXNjYXBlOiBbXCImXCIsICdcIicsIFwiJ1wiXSB9KV0pXG4gICAgLmZpbHRlcigoW18sIHZhbHVlXSkgPT4gdmFsdWUgIT09IHVuZGVmaW5lZCkgYXMgUmV0dXJuVHlwZTx0eXBlb2YgeG1sX2F0dHJpYnV0ZXM+XG59XG5cbi8qKiBFbnRpdGllcyAqL1xuY29uc3QgZW50aXRpZXMgPSB7XG4gIFwiJlwiOiBcIiZhbXA7XCIsIC8vS2VlcCBmaXJzdFxuICAnXCInOiBcIiZxdW90O1wiLFxuICBcIjxcIjogXCImbHQ7XCIsXG4gIFwiPlwiOiBcIiZndDtcIixcbiAgXCInXCI6IFwiJmFwb3M7XCIsXG59IGFzIGNvbnN0XG5cbi8qKiBSZXBsYWNlIHZhbHVlLiAqL1xuZnVuY3Rpb24gcmVwbGFjZShub2RlOiBYbWxOb2RlIHwgWG1sVGV4dCwga2V5OiBzdHJpbmcsIG9wdGlvbnM6IFN0cmluZ2lmeU9wdGlvbnMgJiB7IGVzY2FwZT86IEFycmF5PGtleW9mIHR5cGVvZiBlbnRpdGllcz4gfSkge1xuICBsZXQgdmFsdWUgPSBgJHsobm9kZSBhcyBYbWxOb2RlKVtrZXldfWAgYXMgc3RyaW5nXG4gIGlmIChvcHRpb25zPy5lc2NhcGUpIHtcbiAgICBpZiAob3B0aW9ucz8ucmVwbGFjZT8uZW50aXRpZXMpXG4gICAgICBvcHRpb25zLmVzY2FwZSA9IE9iamVjdC5rZXlzKGVudGl0aWVzKSBhcyBBcnJheTxrZXlvZiB0eXBlb2YgZW50aXRpZXM+XG4gICAgZm9yIChjb25zdCBjaGFyIG9mIG9wdGlvbnM/LmVzY2FwZSlcbiAgICAgIHZhbHVlID0gYCR7dmFsdWV9YC5yZXBsYWNlQWxsKGNoYXIsIGVudGl0aWVzW2NoYXJdKVxuICB9XG4gIGlmIChvcHRpb25zPy5yZXBsYWNlPy5jdXN0b20pXG4gICAgcmV0dXJuIG9wdGlvbnMucmVwbGFjZS5jdXN0b20oeyBuYW1lOiBub2RlW1wifm5hbWVcIl0sIGtleSwgdmFsdWUsIG5vZGU6IG5vZGUgYXMgWG1sTm9kZSB9KVxuICByZXR1cm4gdmFsdWVcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0NBR0MsR0FFRCxVQUFVO0FBZ0RWLDRFQUE0RSxHQUM1RSxNQUFNLFdBQVcsT0FBTztBQUV4Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0F1QkMsR0FDRCxPQUFPLFNBQVMsVUFBVSxRQUF1QixFQUFFLE9BQTBCO0VBQzNFLFlBQVksQ0FBQztFQUNiLFFBQVEsTUFBTSxLQUFLLENBQUM7RUFDcEIsUUFBUSxNQUFNLENBQUMsTUFBTSxLQUFLO0VBQzFCLFFBQVEsTUFBTSxDQUFDLFNBQVMsS0FBSztFQUM3QixNQUFNLFdBQVc7RUFDakIsSUFBSSxPQUFPO0VBQ1gsV0FBVyxNQUFNO0VBQ2pCLGFBQWE7RUFDYixRQUFRLFdBQVcsVUFBeUI7RUFDNUMsOEJBQThCO0VBQzlCLElBQUksUUFBUSxDQUFDLGdCQUFnQixFQUFFO0lBQzdCLEtBQUssTUFBTSxDQUFDLE1BQU0sTUFBTSxJQUFJLE9BQU8sT0FBTyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRztNQUNyRSxLQUFLLE1BQU0sUUFBUTtRQUFDO09BQU0sQ0FBQyxJQUFJLEdBQUk7UUFDakMsSUFBSSxDQUFDLENBQUMsV0FBVyxJQUFJLEdBQ25CLE9BQU8sZ0JBQWdCLENBQUMsTUFBTTtVQUFFLENBQUMsUUFBUSxFQUFFO1lBQUUsWUFBWTtZQUFPLFVBQVU7WUFBTyxPQUFPO1VBQUs7UUFBRTtRQUNqRyxRQUFRLGdCQUFnQixNQUFNO01BQ2hDO0lBQ0Y7RUFDRjtFQUNBLGNBQWM7RUFDZCxJQUFJLFFBQVEsQ0FBQyxXQUFXLEVBQ3RCLFFBQVEsWUFBWSxRQUFRLENBQUMsV0FBVyxFQUFhO0VBRXZELGdCQUFnQjtFQUNoQixNQUFNLENBQUMsTUFB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
@@ -0,0 +1,77 @@
1
+ import { type CleanOptions, type FlattenOptions, type ReviveOptions } from "../_parser.js";
2
+ import type { ReaderSync, XmlDocument } from "../_types.js";
3
+ export type * from "../_types.js";
4
+ export type { CleanOptions, FlattenOptions, ReviveOptions, Reviver } from "../_parser.js";
5
+ /** XML parser options. */ export type ParseOptions = {
6
+ /** Remove elements from result. */ clean?: CleanOptions;
7
+ /** Flatten result depending on node content. */ flatten?: FlattenOptions;
8
+ /** Revive result. */ revive?: ReviveOptions;
9
+ /**
10
+ * Parsing mode.
11
+ * Using `html` is more permissive and will not throw on some invalid XML syntax.
12
+ * Mainly unquoted attributes will be supported and not properly closed tags will be accepted.
13
+ */ mode?: "xml" | "html";
14
+ };
15
+ /**
16
+ * Parse a XML string into an object.
17
+ *
18
+ * Output (cleaning, flattening, reviving, etc.) can be customized using the {@link ParseOptions} parameter.
19
+ *
20
+ * Unless flattened, output nodes will contain the following non-enumerable properties (which mean they're not "visible" when iterating over, but are still explicitely accessible):
21
+ * - General properties
22
+ * - `readonly ["~name"]: string`: tag name
23
+ * - `readonly ["~parent"]: Nullable<XmlNode>`: parent node
24
+ * - `["#text"]?: string`: text content
25
+ * - Node properties
26
+ * - `readonly ["~children"]: Array<XmlNode|XmlText>`: node children
27
+ * - `readonly ["#comments"]?: Array<string>`: node comments
28
+ * - `readonly ["#text"]?: string`: concatenated children text content, this property becomes enumerable if at least one non-empty text node is present
29
+ * - XML document properties
30
+ * - `["#doctype"]?: XmlNode`: XML doctype
31
+ * - `["#instructions"]?: { [key:string]: Arrayable<XmlNode> }`: XML processing instructions
32
+ *
33
+ * Attributes are prefixed with an arobase (`@`).
34
+ *
35
+ * You can also pass an object that implements {@link ReaderSync} instead of a string.
36
+ *
37
+ * ```ts
38
+ * console.log(parse(
39
+ * `
40
+ * <root>
41
+ * <!-- This is a comment -->
42
+ * <text>hello</text>
43
+ * <array>world</array>
44
+ * <array>monde</array>
45
+ * <array>世界</array>
46
+ * <array>🌏</array>
47
+ * <number>42</number>
48
+ * <boolean>true</boolean>
49
+ * <complex attribute="value">content</complex>
50
+ * </root>
51
+ * `))
52
+ * ```
53
+ */ export declare function parse(content: string, options?: ParseOptions): XmlDocument;
54
+ /**
55
+ * Parse a XML file into an object.
56
+ *
57
+ * Output (cleaning, flattening, reviving, etc.) can be customized using the {@link ParseOptions} parameter.
58
+ *
59
+ * ```ts
60
+ * import { fromFileUrl } from "@std/path"
61
+ *
62
+ * const file = await Deno.open(fromFileUrl(import.meta.resolve("../bench/assets/small.xml")))
63
+ * console.log(parse(file))
64
+ * ```
65
+ */ export declare function parse(content: ReaderSync, options?: ParseOptions): XmlDocument;
66
+ /**
67
+ * Parse a XML stream into an object.
68
+ *
69
+ * Output (cleaning, flattening, reviving, etc.) can be customized using the {@link ParseOptions} parameter.
70
+ *
71
+ * ```ts
72
+ * import { fromFileUrl } from "@std/path"
73
+ *
74
+ * const file = await Deno.open(fromFileUrl(import.meta.resolve("../bench/assets/small.xml")))
75
+ * console.log(await parse(file.readable))
76
+ * ```
77
+ */ export declare function parse(content: ReadableStream<Uint8Array>, options?: ParseOptions): Promise<XmlDocument>;
package/wasm/parse.js ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Parse a XML string into an object (legacy WASM backend).
3
+ *
4
+ * This backend predates the {@link ../parse.ts} implementation based on `@std/xml` and is kept as an alternative,
5
+ * mainly because it additionally supports the more permissive `html` parsing mode.
6
+ * Both share the same options, output structure and types.
7
+ *
8
+ * @module
9
+ */ // Imports
10
+ import { initSync, JsReader, source, Token, tokenize } from "./wasm_xml_parser.js";
11
+ import { finalize, xml_doctype, xml_element, xml_instruction, xml_node, xml_text } from "../_parser.js";
12
+ initSync(source());
13
+ export function parse(content, options) {
14
+ if (content instanceof ReadableStream) return new Response(content).bytes().then((bytes)=>parse_bytes(bytes, options));
15
+ return parse_bytes(content, options);
16
+ }
17
+ /** Tokenize a XML document with the WASM tokenizer and map the tokens to the same document structure as the std backend. */ function parse_bytes(content, options) {
18
+ const xml = xml_node("~xml");
19
+ const stack = [
20
+ xml
21
+ ];
22
+ const tokens = [];
23
+ const states = [];
24
+ const flags = {
25
+ root: false
26
+ };
27
+ try {
28
+ const reader = content instanceof Uint8Array ? new JsReader(content) : new JsReader(new TextEncoder().encode(content), typeof content === "object" ? content : undefined);
29
+ tokenize(reader, tokens, states, options?.mode === "html");
30
+ } catch (error) {
31
+ if (states.at(-1)?.[0] === Token.StateParseAttribute) tokens.push([
32
+ Token.Error,
33
+ `Failed to parse attribute around position ${states.at(-1)[1]}`
34
+ ]);
35
+ if (!states.length) throw new EvalError(`WASM XML parser crashed: ${error}`);
36
+ }
37
+ const errors = tokens.find(([token])=>token === Token.Error);
38
+ if (errors) throw new SyntaxError(`Malformed XML document: ${errors[1]}`);
39
+ for (const [token, name, value = name] of tokens){
40
+ switch(token){
41
+ // XML declaration
42
+ case Token.XMLDeclaration:
43
+ {
44
+ // https://www.w3.org/TR/REC-xml/#NT-VersionNum
45
+ const version = value.match(/version=(["'])(?<version>1\.\d+)(\1)/)?.groups?.version;
46
+ if (version) xml["@version"] = version;
47
+ // https://www.w3.org/TR/REC-xml/#NT-EncodingDecl
48
+ const encoding = value.match(/encoding=(["'])(?<encoding>[A-Za-z][-\w.]*)(\1)/)?.groups?.encoding;
49
+ if (encoding) xml["@encoding"] = encoding;
50
+ // https://www.w3.org/TR/REC-xml/#NT-SDDecl
51
+ const standalone = value.match(/standalone=(["'])(?<standalone>yes|no)(\1)/)?.groups?.standalone;
52
+ if (standalone) xml["@standalone"] = standalone;
53
+ break;
54
+ }
55
+ // XML Doctype definition
56
+ case Token.XMLDoctype:
57
+ {
58
+ xml["#doctype"] = Object.assign(xml_node("~doctype", {
59
+ parent: xml
60
+ }), xml_doctype(value));
61
+ break;
62
+ }
63
+ // XML processing instruction
64
+ case Token.XMLInstruction:
65
+ {
66
+ const target = value.match(/^\S+/)?.[0] ?? "";
67
+ xml_instruction(xml, target, value.slice(target.length).trim());
68
+ break;
69
+ }
70
+ // XML tag opened
71
+ case Token.TagOpen:
72
+ {
73
+ if (stack.length === 1) {
74
+ if (flags.root) throw new SyntaxError("Multiple root node detected");
75
+ flags.root = true;
76
+ }
77
+ stack.push(xml_element(name, stack.at(-1)));
78
+ break;
79
+ }
80
+ // XML tag closed
81
+ case Token.TagClose:
82
+ {
83
+ stack.pop();
84
+ break;
85
+ }
86
+ // XML attribute
87
+ case Token.TagAttribute:
88
+ {
89
+ stack.at(-1)[`@${name}`] = value;
90
+ break;
91
+ }
92
+ // Text
93
+ case Token.Text:
94
+ {
95
+ xml_text(value, {
96
+ type: "~text",
97
+ parent: stack.at(-1)
98
+ });
99
+ break;
100
+ }
101
+ // CDATA
102
+ case Token.CData:
103
+ {
104
+ xml_text(value, {
105
+ type: "~cdata",
106
+ parent: stack.at(-1)
107
+ });
108
+ break;
109
+ }
110
+ // Comment
111
+ case Token.Comment:
112
+ {
113
+ xml_text(value, {
114
+ type: "~comment",
115
+ parent: stack.at(-1)
116
+ });
117
+ break;
118
+ }
119
+ }
120
+ }
121
+ return finalize(xml, options);
122
+ }
123
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMveG1sL3dhc20vcGFyc2UudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQYXJzZSBhIFhNTCBzdHJpbmcgaW50byBhbiBvYmplY3QgKGxlZ2FjeSBXQVNNIGJhY2tlbmQpLlxuICpcbiAqIFRoaXMgYmFja2VuZCBwcmVkYXRlcyB0aGUge0BsaW5rIC4uL3BhcnNlLnRzfSBpbXBsZW1lbnRhdGlvbiBiYXNlZCBvbiBgQHN0ZC94bWxgIGFuZCBpcyBrZXB0IGFzIGFuIGFsdGVybmF0aXZlLFxuICogbWFpbmx5IGJlY2F1c2UgaXQgYWRkaXRpb25hbGx5IHN1cHBvcnRzIHRoZSBtb3JlIHBlcm1pc3NpdmUgYGh0bWxgIHBhcnNpbmcgbW9kZS5cbiAqIEJvdGggc2hhcmUgdGhlIHNhbWUgb3B0aW9ucywgb3V0cHV0IHN0cnVjdHVyZSBhbmQgdHlwZXMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbi8vIEltcG9ydHNcbmltcG9ydCB7IGluaXRTeW5jLCBKc1JlYWRlciwgc291cmNlLCBUb2tlbiwgdG9rZW5pemUgfSBmcm9tIFwiLi93YXNtX3htbF9wYXJzZXIuanNcIlxuaW1wb3J0IHsgdHlwZSBDbGVhbk9wdGlvbnMsIGZpbmFsaXplLCB0eXBlIEZsYXR0ZW5PcHRpb25zLCB0eXBlIFJldml2ZU9wdGlvbnMsIHhtbF9kb2N0eXBlLCB4bWxfZWxlbWVudCwgeG1sX2luc3RydWN0aW9uLCB4bWxfbm9kZSwgeG1sX3RleHQgfSBmcm9tIFwiLi4vX3BhcnNlci5qc1wiXG5pbXBvcnQgdHlwZSB7IFJlYWRlclN5bmMsIFhtbERvY3VtZW50LCBYbWxOb2RlIH0gZnJvbSBcIi4uL190eXBlcy5qc1wiXG5leHBvcnQgdHlwZSAqIGZyb20gXCIuLi9fdHlwZXMuanNcIlxuZXhwb3J0IHR5cGUgeyBDbGVhbk9wdGlvbnMsIEZsYXR0ZW5PcHRpb25zLCBSZXZpdmVPcHRpb25zLCBSZXZpdmVyIH0gZnJvbSBcIi4uL19wYXJzZXIuanNcIlxuaW5pdFN5bmMoc291cmNlKCkpXG5cbi8qKiBYTUwgcGFyc2VyIG9wdGlvbnMuICovXG5leHBvcnQgdHlwZSBQYXJzZU9wdGlvbnMgPSB7XG4gIC8qKiBSZW1vdmUgZWxlbWVudHMgZnJvbSByZXN1bHQuICovXG4gIGNsZWFuPzogQ2xlYW5PcHRpb25zXG4gIC8qKiBGbGF0dGVuIHJlc3VsdCBkZXBlbmRpbmcgb24gbm9kZSBjb250ZW50LiAqL1xuICBmbGF0dGVuPzogRmxhdHRlbk9wdGlvbnNcbiAgLyoqIFJldml2ZSByZXN1bHQuICovXG4gIHJldml2ZT86IFJldml2ZU9wdGlvbnNcbiAgLyoqXG4gICAqIFBhcnNpbmcgbW9kZS5cbiAgICogVXNpbmcgYGh0bWxgIGlzIG1vcmUgcGVybWlzc2l2ZSBhbmQgd2lsbCBub3QgdGhyb3cgb24gc29tZSBpbnZhbGlkIFhNTCBzeW50YXguXG4gICAqIE1haW5seSB1bnF1b3RlZCBhdHRyaWJ1dGVzIHdpbGwgYmUgc3VwcG9ydGVkIGFuZCBub3QgcHJvcGVybHkgY2xvc2VkIHRhZ3Mgd2lsbCBiZSBhY2NlcHRlZC5cbiAgICovXG4gIG1vZGU/OiBcInhtbFwiIHwgXCJodG1sXCJcbn1cblxuLyoqXG4gKiBQYXJzZSBhIFhNTCBzdHJpbmcgaW50byBhbiBvYmplY3QuXG4gKlxuICogT3V0cHV0IChjbGVhbmluZywgZmxhdHRlbmluZywgcmV2aXZpbmcsIGV0Yy4pIGNhbiBiZSBjdXN0b21pemVkIHVzaW5nIHRoZSB7QGxpbmsgUGFyc2VPcHRpb25zfSBwYXJhbWV0ZXIuXG4gKlxuICogVW5sZXNzIGZsYXR0ZW5lZCwgb3V0cHV0IG5vZGVzIHdpbGwgY29udGFpbiB0aGUgZm9sbG93aW5nIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMgKHdoaWNoIG1lYW4gdGhleSdyZSBub3QgXCJ2aXNpYmxlXCIgd2hlbiBpdGVyYXRpbmcgb3ZlciwgYnV0IGFyZSBzdGlsbCBleHBsaWNpdGVseSBhY2Nlc3NpYmxlKTpcbiAqIC0gR2VuZXJhbCBwcm9wZXJ0aWVzXG4gKiAgIC0gYHJlYWRvbmx5IFtcIn5uYW1lXCJdOiBzdHJpbmdgOiB0YWcgbmFtZVxuICogICAtIGByZWFkb25seSBbXCJ+cGFyZW50XCJdOiBOdWxsYWJsZTxYbWxOb2RlPmA6IHBhcmVudCBub2RlXG4gKiAgIC0gYFtcIiN0ZXh0XCJdPzogc3RyaW5nYDogdGV4dCBjb250ZW50XG4gKiAtIE5vZGUgcHJvcGVydGllc1xuICogICAtIGByZWFkb25seSBbXCJ+Y2hpbGRyZW5cIl06IEFycmF5PFhtbE5vZGV8WG1sVGV4dD5gOiBub2RlIGNoaWxkcmVuXG4gKiAgIC0gYHJlYWRvbmx5IFtcIiNjb21tZW50c1wiXT86IEFycmF5PHN0cmluZz5gOiBub2RlIGNvbW1lbnRzXG4gKiAgIC0gYHJlYWRvbmx5IFtcIiN0ZXh0XCJdPzogc3RyaW5nYDogY29uY2F0ZW5hdGVkIGNoaWxkcmVuIHRleHQgY29udGVudCwgdGhpcyBwcm9wZXJ0eSBiZWNvbWVzIGVudW1lcmFibGUgaWYgYXQgbGVhc3Qgb25lIG5vbi1lbXB0eSB0ZXh0IG5vZGUgaXMgcHJlc2VudFxuICogLSBYTUwgZG9jdW1lbnQgcHJvcGVydGllc1xuICogIC0gYFtcIiNkb2N0eXBlXCJdPzogWG1sTm9kZWA6IFhNTCBkb2N0eXBlXG4gKiAgLSBgW1wiI2luc3RydWN0aW9uc1wiXT86IHsgW2tleTpzdHJpbmddOiBBcnJheWFibGU8WG1sTm9kZT4gfWA6IFhNTCBwcm9jZXNzaW5nIGluc3RydWN0aW9uc1xuICpcbiAqIEF0dHJpYnV0ZXMgYXJlIHByZWZpeGVkIHdpdGggYW4gYXJvYmFzZSAoYEBgKS5cbiAqXG4gKiBZb3UgY2FuIGFsc28gcGFzcyBhbiBvYmplY3QgdGhhdCBpbXBsZW1lbnRzIHtAbGluayBSZWFkZXJTeW5jfSBpbnN0ZWFkIG9mIGEgc3RyaW5nLlxuICpcbiAqIGBgYHRzXG4gKiBjb25zb2xlLmxvZyhwYXJzZShcbiAqIGBcbiAqICAgPHJvb3Q+XG4gKiAgICAgPCEtLSBUaGlzIGlzIGEgY29tbWVudCAtLT5cbiAqICAgICA8dGV4dD5oZWxsbzwvdGV4dD5cbiAqICAgICA8YXJyYXk+d29ybGQ8L2FycmF5PlxuICogICAgIDxhcnJheT5tb25kZTwvYXJyYXk+XG4gKiAgICAgPGFycmF5PuS4lueVjDwvYXJyYXk+XG4gKiAgICAgPGFycmF5PvCfjI88L2FycmF5PlxuICogICAgIDxudW1iZXI+NDI8L251bWJlcj5cbiAqICAgICA8Ym9vbGVhbj50cnVlPC9ib29sZWFuPlxuICogICAgIDxjb21wbGV4IGF0dHJpYnV0ZT1cInZhbHVlXCI+Y29udGVudDwvY29tcGxleD5cbiAqICAgPC9yb290PlxuICogYCkpXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlKGNvbnRlbnQ6IHN0cmluZywgb3B0aW9ucz86IFBhcnNlT3B0aW9ucyk6IFhtbERvY3VtZW50XG4vKipcbiAqIFBhcnNlIGEgWE1MIGZpbGUgaW50byBhbiBvYmplY3QuXG4gKlxuICogT3V0cHV0IChjbGVhbmluZywgZmxhdHRlbmluZywgcmV2aXZpbmcsIGV0Yy4pIGNhbiBiZSBjdXN0b21pemVkIHVzaW5nIHRoZSB7QGxpbmsgUGFyc2VPcHRpb25zfSBwYXJhbWV0ZXIuXG4gKlxuICogYGBgdHNcbiAqIGltcG9ydCB7IGZyb21GaWxlVXJsIH0gZnJvbSBcIkBzdGQvcGF0aFwiXG4gKlxuICogY29uc3QgZmlsZSA9IGF3YWl0IERlbm8ub3Blbihmcm9tRmlsZVVybChpbXBvcnQubWV0YS5yZXNvbHZlKFwiLi4vYmVuY2gvYXNzZXRzL3NtYWxsLnhtbFwiKSkpXG4gKiBjb25zb2xlLmxvZyhwYXJzZShmaWxlKSlcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2UoY29udGVudDogUmVhZGVyU3luYywgb3B0aW9ucz86IFBhcnNlT3B0aW9ucyk6IFhtbERvY3VtZW50XG4vKipcbiAqIFBhcnNlIGEgWE1MIHN0cmVhbSBpbnRvIGFuIG9iamVjdC5cbiAqXG4gKiBPdXRwdXQgKGNsZWFuaW5nLCBmbGF0dGVuaW5nLCByZXZpdmluZywgZXRjLikgY2FuIGJlIGN1c3RvbWl6ZWQgdXNpbmcgdGhlIHtAbGluayBQYXJzZU9wdGlvbnN9IHBhcmFtZXRlci5cbiAqXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgZnJvbUZpbGVVcmwgfSBmcm9tIFwiQHN0ZC9wYXRoXCJcbiAqXG4gKiBjb25zdCBmaWxlID0gYXdhaXQgRGVuby5vcGVuKGZyb21GaWxlVXJsKGltcG9ydC5tZXRhLnJlc29sdmUoXCIuLi9iZW5jaC9hc3NldHMvc21hbGwueG1sXCIpKSlcbiAqIGNvbnNvbGUubG9nKGF3YWl0IHBhcnNlKGZpbGUucmVhZGFibGUpKVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZShjb250ZW50OiBSZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5Piwgb3B0aW9ucz86IFBhcnNlT3B0aW9ucyk6IFByb21pc2U8WG1sRG9jdW1lbnQ+XG5leHBvcnQgZnVuY3Rpb24gcGFyc2UoY29udGVudDogc3RyaW5nIHwgUmVhZGVyU3luYyB8IFJlYWRhYmxlU3RyZWFtPFVpbnQ4QXJyYXk+LCBvcHRpb25zPzogUGFyc2VPcHRpb25zKSB7XG4gIGlmIChjb250ZW50IGluc3RhbmNlb2YgUmVhZGFibGVTdHJlYW0pXG4gICAgcmV0dXJuIG5ldyBSZXNwb25zZShjb250ZW50KS5ieXRlcygpLnRoZW4oKGJ5dGVzKSA9PiBwYXJzZV9ieXRlcyhieXRlcywgb3B0aW9ucykpXG4gIHJldHVybiBwYXJzZV9ieXRlcyhjb250ZW50LCBvcHRpb25zKVxufVxuXG4vKiogVG9rZW5pemUgYSBYTUwgZG9jdW1lbnQgd2l0aCB0aGUgV0FTTSB0b2tlbml6ZXIgYW5kIG1hcCB0aGUgdG9rZW5zIHRvIHRoZSBzYW1lIGRvY3VtZW50IHN0cnVjdHVyZSBhcyB0aGUgc3RkIGJhY2tlbmQuICovXG5mdW5jdGlvbiBwYXJzZV9ieXRlcyhjb250ZW50OiBzdHJpbmcgfCBSZWFkZXJTeW5jIHwgVWludDhBcnJheSwgb3B0aW9ucz86IFBhcnNlT3B0aW9ucyk6IFhtbERvY3VtZW50IHtcbiAgY29uc3QgeG1sID0geG1sX25vZGUoXCJ+eG1sXCIpIGFzIFhtbERvY3VtZW50XG4gIGNvbnN0IHN0YWNrID0gW3htbF0gYXMgQXJyYXk8WG1sTm9kZT5cbiAgY29uc3QgdG9rZW5zID0gW10gYXMgQXJyYXk8W251bWJlciwgc3RyaW5nLCBzdHJpbmc/XT5cbiAgY29uc3Qgc3RhdGVzID0gW10gYXMgQXJyYXk8W251bWJlciwgbnVtYmVyXT5cbiAgY29uc3QgZmxhZ3MgPSB7IHJvb3Q6IGZhbHNlIH1cbiAgdHJ5IHtcbiAgICBjb25zdCByZWFkZXIgPSBjb250ZW50IGluc3RhbmNlb2YgVWludDhBcnJheSA/IG5ldyBKc1JlYWRlcihjb250ZW50KSA6IG5ldyBKc1JlYWRlcihuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoY29udGVudCBhcyBzdHJpbmcpLCB0eXBlb2YgY29udGVudCA9PT0gXCJvYmplY3RcIiA/IGNvbnRlbnQgOiB1bmRlZmluZWQpXG4gICAgdG9rZW5pemUocmVhZGVyLCB0b2tlbnMsIHN0YXRlcywgb3B0aW9ucz8ubW9kZSA9PT0gXCJodG1sXCIpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKHN0YXRlcy5hdCgtMSk/LlswXSA9PT0gVG9rZW4uU3RhdGVQYXJzZUF0dHJpYnV0ZSlcbiAgICAgIHRva2Vucy5wdXNoKFtUb2tlbi5FcnJvciwgYEZhaWxlZCB0byBwYXJzZSBhdHRyaWJ1dGUgYXJvdW5kIHBvc2l0aW9uICR7c3RhdGVzLmF0KC0xKSFbMV19YF0pXG4gICAgaWYgKCFzdGF0ZXMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEV2YWxFcnJvcihgV0FTTSBYTUwgcGFyc2VyIGNyYXNoZWQ6ICR7ZXJyb3J9YClcbiAgfVxuICBjb25zdCBlcnJvcnMgPSB0b2tlbnMuZmluZCgoW3Rva2VuXSkgPT4gdG9rZW4gPT09IFRva2VuLkVycm9yKVxuICBpZiAoZXJyb3JzKVxuICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihgTWFsZm9ybWVkIFhNTCBkb2N1bWVudDogJHtlcnJvcnNbMV19YClcbiAgZm9yIChjb25zdCBbdG9rZW4sIG5hbWUsIHZhbHVlID0gbmFtZV0gb2YgdG9rZW5zKSB7XG4gICAgc3dpdGNoICh0b2tlbikge1xuICAgICAgLy8gWE1MIGRlY2xhcmF0aW9uXG4gICAgICBjYXNlIFRva2VuLlhNTERlY2xhcmF0aW9uOiB7XG4gICAgICAgIC8vIGh0dHBzOi8vd3d3LnczLm9yZy9UUi9SRUMteG1sLyNOVC1WZXJzaW9uTnVtXG4gICAgICAgIGNvbnN0IHZlcnNpb24gPSB2YWx1ZS5tYXRjaCgvdmVyc2lvbj0oW1wiJ10pKD88dmVyc2lvbj4xXFwuXFxkKykoXFwxKS8pPy5ncm91cHM/LnZlcnNpb25cbiAgICAgICAgaWYgKHZlcnNpb24pXG4gICAgICAgICAgeG1sW1wiQHZlcnNpb25cIl0gPSB2ZXJzaW9uIGFzIHR5cGVvZiB4bWxbXCJAdmVyc2lvblwiXVxuICAgICAgICAvLyBodHRwczovL3d3dy53My5vcmcvVFIvUkVDLXhtbC8jTlQtRW5jb2RpbmdEZWNsXG4gICAgICAgIGNvbnN0IGVuY29kaW5nID0gdmFsdWUubWF0Y2goL2VuY29kaW5nPShbXCInXSkoPzxlbmNvZGluZz5bQS1aYS16XVstXFx3Ll0qKShcXDEpLyk/Lmdyb3Vwcz8uZW5jb2RpbmdcbiAgICAgICAgaWYgKGVuY29kaW5nKVxuICAgICAgICAgIHhtbFtcIkBlbmNvZGluZ1wiXSA9IGVuY29kaW5nIGFzIHR5cGVvZiB4bWxbXCJAZW5jb2RpbmdcIl1cbiAgICAgICAgLy8gaHR0cHM6Ly93d3cudzMub3JnL1RSL1JFQy14bWwvI05ULVNERGVjbFxuICAgICAgICBjb25zdCBzdGFuZGFsb25lID0gdmFsdWUubWF0Y2goL3N0YW5kYWxvbmU9KFtcIiddKSg/PHN0YW5kYWxvbmU+eWVzfG5vKShcXDEpLyk/Lmdyb3Vwcz8uc3RhbmRhbG9uZVxuICAgICAgICBpZiAoc3RhbmRhbG9uZSlcbiAgICAgICAgICB4bWxbXCJAc3RhbmRhbG9uZVwiXSA9IHN0YW5kYWxvbmUgYXMgdHlwZW9mIHhtbFtcIkBzdGFuZGFsb25lXCJdXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgICAvLyBYTUwgRG9jdHlwZSBkZWZpbml0aW9uXG4gICAgICBjYXNlIFRva2VuLlhNTERvY3R5cGU6IHtcbiAgICAgICAgeG1sW1wiI2RvY3R5cGVcIl0gPSBPYmplY3QuYXNzaWduKHhtbF9ub2RlKFwifmRvY3R5cGVcIiwgeyBwYXJlbnQ6IHhtbCB9KSwgeG1sX2RvY3R5cGUodmFsdWUpKVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgLy8gWE1MIHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb25cbiAgICAgIGNhc2UgVG9rZW4uWE1MSW5zdHJ1Y3Rpb246IHtcbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gdmFsdWUubWF0Y2goL15cXFMrLyk/LlswXSA/PyBcIlwiXG4gICAgICAgIHhtbF9pbnN0cnVjdGlvbih4bWwsIHRhcmdldCwgdmFsdWUuc2xpY2UodGFyZ2V0Lmxlbmd0aCkudHJpbSgpKVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgLy8gWE1MIHRhZyBvcGVuZWRcbiAgICAgIGNhc2UgVG9rZW4uVGFnT3Blbjoge1xuICAgICAgICBpZiAoc3RhY2subGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgaWYgKGZsYWdzLnJvb3QpXG4gICAgICAgICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJNdWx0aXBsZSByb290IG5vZGUgZGV0ZWN0ZWRcIilcbiAgICAgICAgICBmbGFncy5yb290ID0gdHJ1ZVxuICAgICAgICB9XG4gICAgICAgIHN0YWNrLnB1c2goeG1sX2VsZW1lbnQobmFtZSwgc3RhY2suYXQoLTEpISkpXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgICAvLyBYTUwgdGFnIGNsb3NlZFxuICAgICAgY2FzZSBUb2tlbi5UYWdDbG9zZToge1xuICAgICAgICBzdGFjay5wb3AoKVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgLy8gWE1MIGF0dHJpYnV0ZVxuICAgICAgY2FzZSBUb2tlbi5UYWdBdHRyaWJ1dGU6IHtcbiAgICAgICAgc3RhY2suYXQoLTEpIVtgQCR7bmFtZX1gXSA9IHZhbHVlXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgICAvLyBUZXh0XG4gICAgICBjYXNlIFRva2VuLlRleHQ6IHtcbiAgICAgICAgeG1sX3RleHQodmFsdWUsIHsgdHlwZTogXCJ+dGV4dFwiLCBwYXJlbnQ6IHN0YWNrLmF0KC0xKSEgfSlcbiAgICAgICAgYnJlYWtcbiAgICAgIH1cbiAgICAgIC8vIENEQVRBXG4gICAgICBjYXNlIFRva2VuLkNEYXRhOiB7XG4gICAgICAgIHhtbF90ZXh0KHZhbHVlLCB7IHR5cGU6IFwifmNkYXRhXCIsIHBhcmVudDogc3RhY2suYXQoLTEpISB9KVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgLy8gQ29tbWVudFxuICAgICAgY2FzZSBUb2tlbi5Db21tZW50OiB7XG4gICAgICAgIHhtbF90ZXh0KHZhbHVlLCB7IHR5cGU6IFwifmNvbW1lbnRcIiwgcGFyZW50OiBzdGFjay5hdCgtMSkhIH0pXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBmaW5hbGl6ZSh4bWwsIG9wdGlvbnMpXG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0NBUUMsR0FFRCxVQUFVO0FBQ1YsU0FBUyxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsUUFBUSxRQUFRLHVCQUFzQjtBQUNsRixTQUE0QixRQUFRLEVBQTJDLFdBQVcsRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSxRQUFRLFFBQVEsZ0JBQWU7QUFJbkssU0FBUztBQW9GVCxPQUFPLFNBQVMsTUFBTSxPQUF5RCxFQUFFLE9BQXNCO0VBQ3JHLElBQUksbUJBQW1CLGdCQUNyQixPQUFPLElBQUksU0FBUyxTQUFTLEtBQUssR0FBRyxJQUFJLENBQUMsQ0FBQyxRQUFVLFlBQVks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