@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 +77 -22
- package/_parser.d.ts +45 -0
- package/_parser.js +266 -0
- package/_types.d.ts +29 -0
- package/_types.js +2 -0
- package/bench/assets/medium.xml +1 -1
- package/bench/assets/small.xml +1 -1
- package/bench/bench.ts +6 -2
- package/deno.lock +17 -97
- package/mod.d.ts +3 -0
- package/mod.js +3 -0
- package/package.json +27 -23
- package/parse.d.ts +81 -0
- package/parse.js +227 -0
- package/stringify.d.ts +79 -0
- package/stringify.js +263 -0
- package/wasm/parse.d.ts +77 -0
- package/wasm/parse.js +123 -0
- package/wasm/wasm_xml_parser.js +3 -0
- package/_types.ts +0 -49
- package/_types_test.ts +0 -1
- package/deno.jsonc +0 -98
- package/mod.mjs +0 -1
- package/mod.ts +0 -3
- package/mod_test.ts +0 -1
- package/parse.mjs +0 -1
- package/parse.ts +0 -442
- package/parse_test.ts +0 -1303
- package/stringify.mjs +0 -1
- package/stringify.ts +0 -287
- package/stringify_test.ts +0 -303
- package/wasm_xml_parser/Cargo.lock +0 -159
- package/wasm_xml_parser/Cargo.toml +0 -16
- package/wasm_xml_parser/src/lib.rs +0 -234
- package/wasm_xml_parser/wasm_xml_parser.js +0 -2
package/deno.lock
CHANGED
|
@@ -1,112 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "5",
|
|
3
3
|
"specifiers": {
|
|
4
|
-
"jsr:@
|
|
5
|
-
"jsr:@
|
|
6
|
-
"jsr:@
|
|
7
|
-
"jsr:@libs/typing@2": "2.9.0",
|
|
8
|
-
"jsr:@libs/typing@3": "3.0.0",
|
|
9
|
-
"jsr:@std/assert@1": "1.0.6",
|
|
10
|
-
"jsr:@std/assert@^1.0.6": "1.0.6",
|
|
11
|
-
"jsr:@std/async@1": "1.0.5",
|
|
12
|
-
"jsr:@std/bytes@^1.0.2": "1.0.2",
|
|
13
|
-
"jsr:@std/expect@1": "1.0.4",
|
|
14
|
-
"jsr:@std/fmt@1": "1.0.2",
|
|
15
|
-
"jsr:@std/fs@1": "1.0.4",
|
|
16
|
-
"jsr:@std/html@1": "1.0.3",
|
|
17
|
-
"jsr:@std/http@1": "1.0.7",
|
|
18
|
-
"jsr:@std/internal@^1.0.4": "1.0.4",
|
|
19
|
-
"jsr:@std/path@1": "1.0.6",
|
|
20
|
-
"jsr:@std/streams@1": "1.0.6",
|
|
21
|
-
"npm:highlight.js@11": "11.10.0"
|
|
4
|
+
"jsr:@std/internal@^1.0.14": "1.0.14",
|
|
5
|
+
"jsr:@std/path@^1.1.4": "1.1.6",
|
|
6
|
+
"jsr:@std/xml@~0.1.3": "0.1.3"
|
|
22
7
|
},
|
|
23
8
|
"jsr": {
|
|
24
|
-
"@
|
|
25
|
-
"integrity": "
|
|
9
|
+
"@std/internal@1.0.14": {
|
|
10
|
+
"integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7"
|
|
26
11
|
},
|
|
27
|
-
"@
|
|
28
|
-
"integrity": "
|
|
12
|
+
"@std/path@1.1.6": {
|
|
13
|
+
"integrity": "c68485c2a4dfbb5ae3cc74fae4e8c4e5d874cf8a8ed12927917235c758b46cbe",
|
|
29
14
|
"dependencies": [
|
|
30
|
-
"jsr:@libs/logger",
|
|
31
|
-
"jsr:@libs/typing@2",
|
|
32
|
-
"jsr:@std/async",
|
|
33
|
-
"jsr:@std/streams"
|
|
34
|
-
]
|
|
35
|
-
},
|
|
36
|
-
"@libs/testing@3.0.0": {
|
|
37
|
-
"integrity": "514547988fadac36890692ccafc932546d9e27680df1b736dd7674ad2e7c9625",
|
|
38
|
-
"dependencies": [
|
|
39
|
-
"jsr:@libs/run",
|
|
40
|
-
"jsr:@libs/typing@2",
|
|
41
|
-
"jsr:@std/assert@1",
|
|
42
|
-
"jsr:@std/expect",
|
|
43
|
-
"jsr:@std/fmt",
|
|
44
|
-
"jsr:@std/html",
|
|
45
|
-
"jsr:@std/http",
|
|
46
|
-
"npm:highlight.js"
|
|
47
|
-
]
|
|
48
|
-
},
|
|
49
|
-
"@libs/typing@2.9.0": {
|
|
50
|
-
"integrity": "ddf35ea652b807cd9b19b4f3f163fb5d76d57299053753fbd01ba8b02d9306ad"
|
|
51
|
-
},
|
|
52
|
-
"@libs/typing@3.0.0": {
|
|
53
|
-
"integrity": "f84ffbbdcbb6a02e6a527911b1399dc79f6ad213aec4ad0a86c95df4b353738f"
|
|
54
|
-
},
|
|
55
|
-
"@std/assert@1.0.6": {
|
|
56
|
-
"integrity": "1904c05806a25d94fe791d6d883b685c9e2dcd60e4f9fc30f4fc5cf010c72207",
|
|
57
|
-
"dependencies": [
|
|
58
|
-
"jsr:@std/internal"
|
|
59
|
-
]
|
|
60
|
-
},
|
|
61
|
-
"@std/async@1.0.5": {
|
|
62
|
-
"integrity": "31d68214bfbb31bd4c6022401d484e3964147c76c9220098baa703a39b6c2da6"
|
|
63
|
-
},
|
|
64
|
-
"@std/bytes@1.0.2": {
|
|
65
|
-
"integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57"
|
|
66
|
-
},
|
|
67
|
-
"@std/expect@1.0.4": {
|
|
68
|
-
"integrity": "97f68a445a9de0d9670200d2b7a19a7505a01b2cb390a983ba8d97d90ce30c4f",
|
|
69
|
-
"dependencies": [
|
|
70
|
-
"jsr:@std/assert@^1.0.6",
|
|
71
15
|
"jsr:@std/internal"
|
|
72
16
|
]
|
|
73
17
|
},
|
|
74
|
-
"@std/
|
|
75
|
-
"integrity": "
|
|
76
|
-
},
|
|
77
|
-
"@std/fs@1.0.4": {
|
|
78
|
-
"integrity": "2907d32d8d1d9e540588fd5fe0ec21ee638134bd51df327ad4e443aaef07123c"
|
|
79
|
-
},
|
|
80
|
-
"@std/html@1.0.3": {
|
|
81
|
-
"integrity": "7a0ac35e050431fb49d44e61c8b8aac1ebd55937e0dc9ec6409aa4bab39a7988"
|
|
82
|
-
},
|
|
83
|
-
"@std/http@1.0.7": {
|
|
84
|
-
"integrity": "9b904fc256678a5c9759f1a53a24a3fdcc59d83dc62099bb472683b6f819194c"
|
|
85
|
-
},
|
|
86
|
-
"@std/internal@1.0.4": {
|
|
87
|
-
"integrity": "62e8e4911527e5e4f307741a795c0b0a9e6958d0b3790716ae71ce085f755422"
|
|
88
|
-
},
|
|
89
|
-
"@std/path@1.0.6": {
|
|
90
|
-
"integrity": "ab2c55f902b380cf28e0eec501b4906e4c1960d13f00e11cfbcd21de15f18fed"
|
|
91
|
-
},
|
|
92
|
-
"@std/streams@1.0.6": {
|
|
93
|
-
"integrity": "022ed94e380d06b4d91c49eb70241b7289ab78b8c2b4c4bbb7eb265e4997c25c",
|
|
94
|
-
"dependencies": [
|
|
95
|
-
"jsr:@std/bytes"
|
|
96
|
-
]
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
"npm": {
|
|
100
|
-
"highlight.js@11.10.0": {
|
|
101
|
-
"integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ=="
|
|
18
|
+
"@std/xml@0.1.3": {
|
|
19
|
+
"integrity": "afb7750d09f9f521046b27119d0e63f7aaad6eeb3d74e5f41fc04a9958014811"
|
|
102
20
|
}
|
|
103
21
|
},
|
|
104
22
|
"workspace": {
|
|
105
23
|
"dependencies": [
|
|
106
|
-
"jsr:@
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"
|
|
110
|
-
|
|
24
|
+
"jsr:@std/path@^1.1.4"
|
|
25
|
+
],
|
|
26
|
+
"packageJson": {
|
|
27
|
+
"dependencies": [
|
|
28
|
+
"npm:@jsr/std__path@^1.1.4"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
111
31
|
}
|
|
112
32
|
}
|
package/mod.d.ts
ADDED
package/mod.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from "./parse.js";
|
|
2
|
+
export * from "./stringify.js";
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMveG1sL21vZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tIFwiLi9wYXJzZS5qc1wiXG5leHBvcnQgKiBmcm9tIFwiLi9zdHJpbmdpZnkuanNcIlxuZXhwb3J0IHR5cGUgKiBmcm9tIFwiLi9fdHlwZXMuanNcIlxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsYUFBWTtBQUMxQixjQUFjLGlCQUFnQiJ9
|
package/package.json
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowlighter/xml",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"devDependencies": {},
|
|
8
|
-
"description": "XML parser/stringifier with no dependencies.",
|
|
9
|
-
"keywords": [
|
|
10
|
-
"xml",
|
|
11
|
-
"parser",
|
|
12
|
-
"stringifier",
|
|
13
|
-
"esm"
|
|
14
|
-
],
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"author": "lowlighter (Simon Lecoq)",
|
|
17
|
-
"homepage": "https://github.com/lowlighter/libs",
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/lowlighter/libs.git"
|
|
21
|
-
},
|
|
22
|
-
"funding": "https://github.com/sponsors/lowlighter",
|
|
5
|
+
"main": "./mod.js",
|
|
6
|
+
"types": "./mod.d.ts",
|
|
23
7
|
"exports": {
|
|
24
|
-
".":
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./mod.d.ts",
|
|
10
|
+
"import": "./mod.js",
|
|
11
|
+
"default": "./mod.js"
|
|
12
|
+
},
|
|
13
|
+
"./parse": {
|
|
14
|
+
"types": "./parse.d.ts",
|
|
15
|
+
"import": "./parse.js",
|
|
16
|
+
"default": "./parse.js"
|
|
17
|
+
},
|
|
18
|
+
"./stringify": {
|
|
19
|
+
"types": "./stringify.d.ts",
|
|
20
|
+
"import": "./stringify.js",
|
|
21
|
+
"default": "./stringify.js"
|
|
22
|
+
},
|
|
23
|
+
"./wasm/parse": {
|
|
24
|
+
"types": "./wasm/parse.d.ts",
|
|
25
|
+
"import": "./wasm/parse.js",
|
|
26
|
+
"default": "./wasm/parse.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@jsr/std__xml": "^0.1.3"
|
|
27
31
|
}
|
|
28
|
-
}
|
|
32
|
+
}
|
package/parse.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type CleanOptions, type FlattenOptions, type ReviveOptions } from "./_parser.js";
|
|
2
|
+
import type { 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
|
+
*
|
|
14
|
+
* > Note: `html` mode is currently not supported, use the WASM backend (`@libs/xml/wasm/parse`) instead.
|
|
15
|
+
* > Tracking issue: https://github.com/denoland/std/issues/7212
|
|
16
|
+
*/ mode?: "xml";
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Parse a XML string into an object.
|
|
20
|
+
*
|
|
21
|
+
* Output (cleaning, flattening, reviving, etc.) can be customized using the {@link ParseOptions} parameter.
|
|
22
|
+
*
|
|
23
|
+
* 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):
|
|
24
|
+
* - General properties
|
|
25
|
+
* - `readonly ["~name"]: string`: tag name
|
|
26
|
+
* - `readonly ["~parent"]: Nullable<XmlNode>`: parent node
|
|
27
|
+
* - `["#text"]?: string`: text content
|
|
28
|
+
* - Node properties
|
|
29
|
+
* - `readonly ["~children"]: Array<XmlNode|XmlText>`: node children
|
|
30
|
+
* - `readonly ["#comments"]?: Array<string>`: node comments
|
|
31
|
+
* - `readonly ["#text"]?: string`: concatenated children text content, this property becomes enumerable if at least one non-empty text node is present
|
|
32
|
+
* - XML document properties
|
|
33
|
+
* - `["#doctype"]?: XmlNode`: XML doctype
|
|
34
|
+
* - `["#instructions"]?: { [key:string]: Arrayable<XmlNode> }`: XML processing instructions
|
|
35
|
+
*
|
|
36
|
+
* Attributes are prefixed with an arobase (`@`).
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* console.log(parse(
|
|
40
|
+
* `
|
|
41
|
+
* <root>
|
|
42
|
+
* <!-- This is a comment -->
|
|
43
|
+
* <text>hello</text>
|
|
44
|
+
* <array>world</array>
|
|
45
|
+
* <array>monde</array>
|
|
46
|
+
* <array>世界</array>
|
|
47
|
+
* <array>🌏</array>
|
|
48
|
+
* <number>42</number>
|
|
49
|
+
* <boolean>true</boolean>
|
|
50
|
+
* <complex attribute="value">content</complex>
|
|
51
|
+
* </root>
|
|
52
|
+
* `))
|
|
53
|
+
* ```
|
|
54
|
+
*/ export declare function parse(content: string, options?: ParseOptions): XmlDocument;
|
|
55
|
+
/**
|
|
56
|
+
* Parse a XML string into an object.
|
|
57
|
+
*
|
|
58
|
+
* Output (cleaning, flattening, reviving, etc.) can be customized using the {@link ParseOptions} parameter.
|
|
59
|
+
*
|
|
60
|
+
* 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):
|
|
61
|
+
* - General properties
|
|
62
|
+
* - `readonly ["~name"]: string`: tag name
|
|
63
|
+
* - `readonly ["~parent"]: Nullable<XmlNode>`: parent node
|
|
64
|
+
* - `["#text"]?: string`: text content
|
|
65
|
+
* - Node properties
|
|
66
|
+
* - `readonly ["~children"]: Array<XmlNode|XmlText>`: node children
|
|
67
|
+
* - `readonly ["#comments"]?: Array<string>`: node comments
|
|
68
|
+
* - `readonly ["#text"]?: string`: concatenated children text content, this property becomes enumerable if at least one non-empty text node is present
|
|
69
|
+
* - XML document properties
|
|
70
|
+
* - `["#doctype"]?: XmlNode`: XML doctype
|
|
71
|
+
* - `["#instructions"]?: { [key:string]: Arrayable<XmlNode> }`: XML processing instructions
|
|
72
|
+
*
|
|
73
|
+
* Attributes are prefixed with an arobase (`@`).
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { fromFileUrl } from "@std/path"
|
|
77
|
+
*
|
|
78
|
+
* const file = await Deno.open(fromFileUrl(import.meta.resolve("./bench/assets/small.xml")))
|
|
79
|
+
* console.log(await parse(file.readable))
|
|
80
|
+
* ```
|
|
81
|
+
*/ export declare function parse(content: ReadableStream<Uint8Array>, options?: ParseOptions): Promise<XmlDocument>;
|
package/parse.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a XML string into an object.
|
|
3
|
+
* @module
|
|
4
|
+
*/ // Imports
|
|
5
|
+
import { parse as std_parse } from "@std/xml/parse";
|
|
6
|
+
import { parseXmlStreamFromBytes } from "@std/xml/parse-stream";
|
|
7
|
+
import { finalize, xml_doctype, xml_element, xml_instruction, xml_node, xml_text } from "./_parser.js";
|
|
8
|
+
export function parse(content, options) {
|
|
9
|
+
if (typeof content !== "string") return parse_stream(content, options);
|
|
10
|
+
const xml = xml_node("~xml");
|
|
11
|
+
content = content.replace(/^\s+/, "");
|
|
12
|
+
// @std sync parser only exposes a DOM tree of {declaration, root}
|
|
13
|
+
// and is missing DOCTYPE and processing instructions (they are discarded)
|
|
14
|
+
// Prescan the content to recover them first
|
|
15
|
+
content = prescan(content, xml);
|
|
16
|
+
const doc = std_parse(content, {
|
|
17
|
+
disallowDoctype: false
|
|
18
|
+
});
|
|
19
|
+
// XML declaration
|
|
20
|
+
if (doc.declaration) {
|
|
21
|
+
if (doc.declaration.version) xml["@version"] = doc.declaration.version;
|
|
22
|
+
if (doc.declaration.encoding) xml["@encoding"] = doc.declaration.encoding;
|
|
23
|
+
if (doc.declaration.standalone) xml["@standalone"] = doc.declaration.standalone;
|
|
24
|
+
}
|
|
25
|
+
build(doc.root, xml);
|
|
26
|
+
return finalize(xml, options);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse a XML stream into an object.
|
|
30
|
+
* @std streaming parser events are mapped to the same document structure as the string version,
|
|
31
|
+
* and unlike the sync DOM they natively expose the doctype and processing instructions.
|
|
32
|
+
*/ async function parse_stream(content, options) {
|
|
33
|
+
const xml = xml_node("~xml");
|
|
34
|
+
const stack = [
|
|
35
|
+
xml
|
|
36
|
+
];
|
|
37
|
+
await parseXmlStreamFromBytes(content, {
|
|
38
|
+
// XML declaration
|
|
39
|
+
onDeclaration (version, encoding, standalone) {
|
|
40
|
+
if (version) xml["@version"] = version;
|
|
41
|
+
if (encoding) xml["@encoding"] = encoding;
|
|
42
|
+
if (standalone) xml["@standalone"] = standalone;
|
|
43
|
+
},
|
|
44
|
+
// XML doctype (only the name and public/system identifiers are exposed by @std events)
|
|
45
|
+
onDoctype (name, publicId, systemId) {
|
|
46
|
+
const doctype = xml_node("~doctype", {
|
|
47
|
+
parent: xml
|
|
48
|
+
});
|
|
49
|
+
[
|
|
50
|
+
name,
|
|
51
|
+
publicId,
|
|
52
|
+
systemId
|
|
53
|
+
].filter((value)=>value !== undefined).forEach((value)=>doctype[`@${value}`] = "");
|
|
54
|
+
xml["#doctype"] = doctype;
|
|
55
|
+
},
|
|
56
|
+
// XML processing instruction
|
|
57
|
+
onProcessingInstruction (target, instruction) {
|
|
58
|
+
xml_instruction(xml, target, instruction.trim());
|
|
59
|
+
},
|
|
60
|
+
// XML tag opened
|
|
61
|
+
onStartElement (name, _colon, _uri, attributes, selfClosing) {
|
|
62
|
+
const node = xml_element(name, stack.at(-1));
|
|
63
|
+
for(let i = 0; i < attributes.count; i++)node[`@${attributes.getName(i)}`] = attributes.getValue(i);
|
|
64
|
+
if (!selfClosing) stack.push(node);
|
|
65
|
+
},
|
|
66
|
+
// XML tag closed
|
|
67
|
+
onEndElement () {
|
|
68
|
+
stack.pop();
|
|
69
|
+
},
|
|
70
|
+
// Text
|
|
71
|
+
onText (text) {
|
|
72
|
+
xml_text(text, {
|
|
73
|
+
type: "~text",
|
|
74
|
+
parent: stack.at(-1)
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
// CDATA
|
|
78
|
+
onCData (text) {
|
|
79
|
+
xml_text(text, {
|
|
80
|
+
type: "~cdata",
|
|
81
|
+
parent: stack.at(-1)
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
// Comment
|
|
85
|
+
onComment (text) {
|
|
86
|
+
xml_text(text, {
|
|
87
|
+
type: "~comment",
|
|
88
|
+
parent: stack.at(-1)
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}, {
|
|
92
|
+
disallowDoctype: false
|
|
93
|
+
});
|
|
94
|
+
return finalize(xml, options);
|
|
95
|
+
}
|
|
96
|
+
/** Recover `#doctype` and `#instructions`. */ function prescan(content, xml) {
|
|
97
|
+
// Prolog: skip whitespace/comments, collect instructions and doctype until the root element opens
|
|
98
|
+
let i = 0;
|
|
99
|
+
prolog: while(i < content.length){
|
|
100
|
+
switch(true){
|
|
101
|
+
case /\s/.test(content[i]):
|
|
102
|
+
{
|
|
103
|
+
i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
case content.startsWith("<!--", i):
|
|
107
|
+
{
|
|
108
|
+
const end = content.indexOf("-->", i + 4);
|
|
109
|
+
if (end < 0) break prolog;
|
|
110
|
+
i = end + 3;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
case content.startsWith("<?", i):
|
|
114
|
+
{
|
|
115
|
+
const end = content.indexOf("?>", i + 2);
|
|
116
|
+
if (end < 0) break prolog;
|
|
117
|
+
const raw = content.slice(i + 2, end);
|
|
118
|
+
i = end + 2;
|
|
119
|
+
const target = raw.match(/^\S+/)?.[0] ?? "";
|
|
120
|
+
// The <?xml?> declaration is already handled through std's DOM
|
|
121
|
+
if (target !== "xml") xml_instruction(xml, target, raw.slice(target.length).trim());
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
case content.startsWith("<!DOCTYPE", i):
|
|
125
|
+
{
|
|
126
|
+
// Find the closing ">", skipping quoted literals and the internal subset "[...]"
|
|
127
|
+
let j = i + 9;
|
|
128
|
+
doctype: while(j < content.length){
|
|
129
|
+
switch(content[j]){
|
|
130
|
+
case '"':
|
|
131
|
+
case "'":
|
|
132
|
+
{
|
|
133
|
+
const quote = content.indexOf(content[j], j + 1);
|
|
134
|
+
if (quote < 0) break doctype;
|
|
135
|
+
j = quote + 1;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case "[":
|
|
139
|
+
{
|
|
140
|
+
const bracket = content.indexOf("]", j + 1);
|
|
141
|
+
if (bracket < 0) break doctype;
|
|
142
|
+
j = bracket + 1;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case ">":
|
|
146
|
+
break doctype;
|
|
147
|
+
default:
|
|
148
|
+
j++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
xml["#doctype"] = Object.assign(xml_node("~doctype", {
|
|
152
|
+
parent: xml
|
|
153
|
+
}), xml_doctype(content.slice(i + 9, j).trim()));
|
|
154
|
+
const end = Math.min(j + 1, content.length);
|
|
155
|
+
content = `${content.slice(0, i)}${" ".repeat(end - i)}${content.slice(end)}`;
|
|
156
|
+
i = end;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
default:
|
|
160
|
+
break prolog;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Epilog: only comments and instructions may follow the root element, scan them backwards
|
|
164
|
+
const instructions = [];
|
|
165
|
+
let tail = content.trimEnd();
|
|
166
|
+
epilog: while(true){
|
|
167
|
+
switch(true){
|
|
168
|
+
case tail.endsWith("-->"):
|
|
169
|
+
{
|
|
170
|
+
const start = tail.lastIndexOf("<!--");
|
|
171
|
+
if (start < 0) break epilog;
|
|
172
|
+
tail = tail.slice(0, start).trimEnd();
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
case tail.endsWith("?>"):
|
|
176
|
+
{
|
|
177
|
+
const start = tail.lastIndexOf("<?");
|
|
178
|
+
if (start < 0) break epilog;
|
|
179
|
+
const raw = tail.slice(start + 2, -2);
|
|
180
|
+
const target = raw.match(/^\S+/)?.[0] ?? "";
|
|
181
|
+
instructions.unshift([
|
|
182
|
+
target,
|
|
183
|
+
raw.slice(target.length).trim()
|
|
184
|
+
]);
|
|
185
|
+
tail = tail.slice(0, start).trimEnd();
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
default:
|
|
189
|
+
break epilog;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
instructions.forEach(([target, raw])=>xml_instruction(xml, target, raw));
|
|
193
|
+
return content;
|
|
194
|
+
}
|
|
195
|
+
/** Walk a std DOM element into the ergonomic ~children/@attr/#text structure. */ function build(element, parent) {
|
|
196
|
+
// Attach under the enumerable key with array-grouping
|
|
197
|
+
const node = xml_element(element.name.raw, parent);
|
|
198
|
+
// Attributes
|
|
199
|
+
for (const [name, value] of Object.entries(element.attributes))node[`@${name}`] = value;
|
|
200
|
+
// Children
|
|
201
|
+
for (const child of element.children){
|
|
202
|
+
switch(child.type){
|
|
203
|
+
case "element":
|
|
204
|
+
build(child, node);
|
|
205
|
+
break;
|
|
206
|
+
case "text":
|
|
207
|
+
xml_text(child.text, {
|
|
208
|
+
type: "~text",
|
|
209
|
+
parent: node
|
|
210
|
+
});
|
|
211
|
+
break;
|
|
212
|
+
case "cdata":
|
|
213
|
+
xml_text(child.text, {
|
|
214
|
+
type: "~cdata",
|
|
215
|
+
parent: node
|
|
216
|
+
});
|
|
217
|
+
break;
|
|
218
|
+
case "comment":
|
|
219
|
+
xml_text(child.text, {
|
|
220
|
+
type: "~comment",
|
|
221
|
+
parent: node
|
|
222
|
+
});
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMveG1sL3BhcnNlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUGFyc2UgYSBYTUwgc3RyaW5nIGludG8gYW4gb2JqZWN0LlxuICogQG1vZHVsZVxuICovXG5cbi8vIEltcG9ydHNcbmltcG9ydCB7IHBhcnNlIGFzIHN0ZF9wYXJzZSB9IGZyb20gXCJAc3RkL3htbC9wYXJzZVwiXG5pbXBvcnQgeyBwYXJzZVhtbFN0cmVhbUZyb21CeXRlcyB9IGZyb20gXCJAc3RkL3htbC9wYXJzZS1zdHJlYW1cIlxuaW1wb3J0IHR5cGUgeyBYbWxEb2N1bWVudCBhcyBTdGREb2N1bWVudCwgWG1sRWxlbWVudCBhcyBTdGRFbGVtZW50LCBYbWxOb2RlIGFzIFN0ZE5vZGUgfSBmcm9tIFwiQHN0ZC94bWwvdHlwZXNcIlxuaW1wb3J0IHsgdHlwZSBDbGVhbk9wdGlvbnMsIGZpbmFsaXplLCB0eXBlIEZsYXR0ZW5PcHRpb25zLCB0eXBlIFJldml2ZU9wdGlvbnMsIHhtbF9kb2N0eXBlLCB4bWxfZWxlbWVudCwgeG1sX2luc3RydWN0aW9uLCB4bWxfbm9kZSwgeG1sX3RleHQgfSBmcm9tIFwiLi9fcGFyc2VyLmpzXCJcbmltcG9ydCB0eXBlIHsgWG1sRG9jdW1lbnQsIFhtbE5vZGUgfSBmcm9tIFwiLi9fdHlwZXMuanNcIlxuZXhwb3J0IHR5cGUgKiBmcm9tIFwiLi9fdHlwZXMuanNcIlxuZXhwb3J0IHR5cGUgeyBDbGVhbk9wdGlvbnMsIEZsYXR0ZW5PcHRpb25zLCBSZXZpdmVPcHRpb25zLCBSZXZpdmVyIH0gZnJvbSBcIi4vX3BhcnNlci5qc1wiXG5cbi8qKiBYTUwgcGFyc2VyIG9wdGlvbnMuICovXG5leHBvcnQgdHlwZSBQYXJzZU9wdGlvbnMgPSB7XG4gIC8qKiBSZW1vdmUgZWxlbWVudHMgZnJvbSByZXN1bHQuICovXG4gIGNsZWFuPzogQ2xlYW5PcHRpb25zXG4gIC8qKiBGbGF0dGVuIHJlc3VsdCBkZXBlbmRpbmcgb24gbm9kZSBjb250ZW50LiAqL1xuICBmbGF0dGVuPzogRmxhdHRlbk9wdGlvbnNcbiAgLyoqIFJldml2ZSByZXN1bHQuICovXG4gIHJldml2ZT86IFJldml2ZU9wdGlvbnNcbiAgLyoqXG4gICAqIFBhcnNpbmcgbW9kZS5cbiAgICogVXNpbmcgYGh0bWxgIGlzIG1vcmUgcGVybWlzc2l2ZSBhbmQgd2lsbCBub3QgdGhyb3cgb24gc29tZSBpbnZhbGlkIFhNTCBzeW50YXguXG4gICAqIE1haW5seSB1bnF1b3RlZCBhdHRyaWJ1dGVzIHdpbGwgYmUgc3VwcG9ydGVkIGFuZCBub3QgcHJvcGVybHkgY2xvc2VkIHRhZ3Mgd2lsbCBiZSBhY2NlcHRlZC5cbiAgICpcbiAgICogPiBOb3RlOiBgaHRtbGAgbW9kZSBpcyBjdXJyZW50bHkgbm90IHN1cHBvcnRlZCwgdXNlIHRoZSBXQVNNIGJhY2tlbmQgKGBAbGlicy94bWwvd2FzbS9wYXJzZWApIGluc3RlYWQuXG4gICAqID4gVHJhY2tpbmcgaXNzdWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9kZW5vbGFuZC9zdGQvaXNzdWVzLzcyMTJcbiAgICovXG4gIG1vZGU/OiBcInhtbFwiXG59XG5cbi8qKlxuICogUGFyc2UgYSBYTUwgc3RyaW5nIGludG8gYW4gb2JqZWN0LlxuICpcbiAqIE91dHB1dCAoY2xlYW5pbmcsIGZsYXR0ZW5pbmcsIHJldml2aW5nLCBldGMuKSBjYW4gYmUgY3VzdG9taXplZCB1c2luZyB0aGUge0BsaW5rIFBhcnNlT3B0aW9uc30gcGFyYW1ldGVyLlxuICpcbiAqIFVubGVzcyBmbGF0dGVuZWQsIG91dHB1dCBub2RlcyB3aWxsIGNvbnRhaW4gdGhlIGZvbGxvd2luZyBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzICh3aGljaCBtZWFuIHRoZXkncmUgbm90IFwidmlzaWJsZVwiIHdoZW4gaXRlcmF0aW5nIG92ZXIsIGJ1dCBhcmUgc3RpbGwgZXhwbGljaXRlbHkgYWNjZXNzaWJsZSk6XG4gKiAtIEdlbmVyYWwgcHJvcGVydGllc1xuICogICAtIGByZWFkb25seSBbXCJ+bmFtZVwiXTogc3RyaW5nYDogdGFnIG5hbWVcbiAqICAgLSBgcmVhZG9ubHkgW1wifnBhcmVudFwiXTogTnVsbGFibGU8WG1sTm9kZT5gOiBwYXJlbnQgbm9kZVxuICogICAtIGBbXCIjdGV4dFwiXT86IHN0cmluZ2A6IHRleHQgY29udGVudFxuICogLSBOb2RlIHByb3BlcnRpZXNcbiAqICAgLSBgcmVhZG9ubHkgW1wifmNoaWxkcmVuXCJdOiBBcnJheTxYbWxOb2RlfFhtbFRleHQ+YDogbm9kZSBjaGlsZHJlblxuICogICAtIGByZWFkb25seSBbXCIjY29tbWVudHNcIl0/OiBBcnJheTxzdHJpbmc+YDogbm9kZSBjb21tZW50c1xuICogICAtIGByZWFkb25seSBbXCIjdGV4dFwiXT86IHN0cmluZ2A6IGNvbmNhdGVuYXRlZCBjaGlsZHJlbiB0ZXh0IGNvbnRlbnQsIHRoaXMgcHJvcGVydHkgYmVjb21lcyBlbnVtZXJhYmxlIGlmIGF0IGxlYXN0IG9uZSBub24tZW1wdHkgdGV4dCBub2RlIGlzIHByZXNlbnRcbiAqIC0gWE1MIGRvY3VtZW50IHByb3BlcnRpZXNcbiAqICAtIGBbXCIjZG9jdHlwZVwiXT86IFhtbE5vZGVgOiBYTUwgZG9jdHlwZVxuICogIC0gYFtcIiNpbnN0cnVjdGlvbnNcIl0/OiB7IFtrZXk6c3RyaW5nXTogQXJyYXlhYmxlPFhtbE5vZGU+IH1gOiBYTUwgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbnNcbiAqXG4gKiBBdHRyaWJ1dGVzIGFyZSBwcmVmaXhlZCB3aXRoIGFuIGFyb2Jhc2UgKGBAYCkuXG4gKlxuICogYGBgdHNcbiAqIGNvbnNvbGUubG9nKHBhcnNlKFxuICogYFxuICogICA8cm9vdD5cbiAqICAgICA8IS0tIFRoaXMgaXMgYSBjb21tZW50IC0tPlxuICogICAgIDx0ZXh0PmhlbGxvPC90ZXh0PlxuICogICAgIDxhcnJheT53b3JsZDwvYXJyYXk+XG4gKiAgICAgPGFycmF5Pm1vbmRlPC9hcnJheT5cbiAqICAgICA8YXJyYXk+5LiW55WMPC9hcnJheT5cbiAqICAgICA8YXJyYXk+8J+MjzwvYXJyYXk+XG4gKiAgICAgPG51bWJlcj40MjwvbnVtYmVyPlxuICogICAgIDxib29sZWFuPnRydWU8L2Jvb2xlYW4+XG4gKiAgICAgPGNvbXBsZXggYXR0cmlidXRlPVwidmFsdWVcIj5jb250ZW50PC9jb21wbGV4PlxuICogICA8L3Jvb3Q+XG4gKiBgKSlcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2UoY29udGVudDogc3RyaW5nLCBvcHRpb25zPzogUGFyc2VPcHRpb25zKTogWG1sRG9jdW1lbnRcblxuLyoqXG4gKiBQYXJzZSBhIFhNTCBzdHJpbmcgaW50byBhbiBvYmplY3QuXG4gKlxuICogT3V0cHV0IChjbGVhbmluZywgZmxhdHRlbmluZywgcmV2aXZpbmcsIGV0Yy4pIGNhbiBiZSBjdXN0b21pemVkIHVzaW5nIHRoZSB7QGxpbmsgUGFyc2VPcHRpb25zfSBwYXJhbWV0ZXIuXG4gKlxuICogVW5sZXNzIGZsYXR0ZW5lZCwgb3V0cHV0IG5vZGVzIHdpbGwgY29udGFpbiB0aGUgZm9sbG93aW5nIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMgKHdoaWNoIG1lYW4gdGhleSdyZSBub3QgXCJ2aXNpYmxlXCIgd2hlbiBpdGVyYXRpbmcgb3ZlciwgYnV0IGFyZSBzdGlsbCBleHBsaWNpdGVseSBhY2Nlc3NpYmxlKTpcbiAqIC0gR2VuZXJhbCBwcm9wZXJ0aWVzXG4gKiAgIC0gYHJlYWRvbmx5IFtcIn5uYW1lXCJdOiBzdHJpbmdgOiB0YWcgbmFtZVxuICogICAtIGByZWFkb25seSBbXCJ+cGFyZW50XCJdOiBOdWxsYWJsZTxYbWxOb2RlPmA6IHBhcmVudCBub2RlXG4gKiAgIC0gYFtcIiN0ZXh0XCJdPzogc3RyaW5nYDogdGV4dCBjb250ZW50XG4gKiAtIE5vZGUgcHJvcGVydGllc1xuICogICAtIGByZWFkb25seSBbXCJ+Y2hpbGRyZW5cIl06IEFycmF5PFhtbE5vZGV8WG1sVGV4dD5gOiBub2RlIGNoaWxkcmVuXG4gKiAgIC0gYHJlYWRvbmx5IFtcIiNjb21tZW50c1wiXT86IEFycmF5PHN0cmluZz5gOiBub2RlIGNvbW1lbnRzXG4gKiAgIC0gYHJlYWRvbmx5IFtcIiN0ZXh0XCJdPzogc3RyaW5nYDogY29uY2F0ZW5hdGVkIGNoaWxkcmVuIHRleHQgY29udGVudCwgdGhpcyBwcm9wZXJ0eSBiZWNvbWVzIGVudW1lcmFibGUgaWYgYXQgbGVhc3Qgb25lIG5vbi1lbXB0eSB0ZXh0IG5vZGUgaXMgcHJlc2VudFxuICogLSBYTUwgZG9jdW1lbnQgcHJvcGVydGllc1xuICogIC0gYFtcIiNkb2N0eXBlXCJdPzogWG1sTm9kZWA6IFhNTCBkb2N0eXBlXG4gKiAgLSBgW1wiI2luc3RydWN0aW9uc1wiXT86IHsgW2tleTpzdHJpbmddOiBBcnJheWFibGU8WG1sTm9kZT4gfWA6IFhNTCBwcm9jZXNzaW5nIGluc3RydWN0aW9uc1xuICpcbiAqIEF0dHJpYnV0ZXMgYXJlIHByZWZpeGVkIHdpdGggYW4gYXJvYmFzZSAoYEBgKS5cbiAqXG4gKiBgYGB0c1xuICogaW1wb3J0IHsgZnJvbUZpbGVVcmwgfSBmcm9tIFwiQHN0ZC9wYXRoXCJcbiAqXG4gKiBjb25zdCBmaWxlID0gYXdhaXQgRGVuby5vcGVuKGZyb21GaWxlVXJsKGltcG9ydC5tZXRhLnJlc29sdmUoXCIuL2JlbmNoL2Fzc2V0cy9zbWFsbC54bWxcIikpKVxuICogY29uc29sZS5sb2coYXdhaXQgcGFyc2UoZmlsZS5yZWFkYWJsZSkpXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlKGNvbnRlbnQ6IFJlYWRhYmxlU3RyZWFtPFVpbnQ4QXJyYXk+LCBvcHRpb25zPzogUGFyc2VPcHRpb25zKTogUHJvbWlzZTxYbWxEb2N1bWVudD5cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZShjb250ZW50OiBzdHJpbmcgfCBSZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5Piwgb3B0aW9ucz86IFBhcnNlT3B0aW9ucyk6IFhtbERvY3VtZW50IHwgUHJvbWlzZTxYbWxEb2N1bWVudD4ge1xuICBpZiAodHlwZW9mIGNvbnRlbnQgIT09IFwic3RyaW5nXCIpXG4gICAgcmV0dXJuIHBhcnNlX3N0cmVhbShjb250ZW50LCBvcHRpb25zKVxuICBjb25zdCB4bWwgPSB4bWxfbm9kZShcIn54bWxcIikgYXMgWG1sRG9jdW1lbnRcbiAgY29udGVudCA9IGNvbnRlbnQucmVwbGFjZSgvXlxccysvLCBcIlwiKVxuICAvLyBAc3RkIHN5bmMgcGFyc2VyIG9ubHkgZXhwb3NlcyBhIERPTSB0cmVlIG9mIHtkZWNsYXJhdGlvbiwgcm9vdH1cbiAgLy8gYW5kIGlzIG1pc3NpbmcgRE9DVFlQRSBhbmQgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbnMgKHRoZXkgYXJlIGRpc2NhcmRlZClcbiAgLy8gUHJlc2NhbiB0aGUgY29udGVudCB0byByZWNvdmVyIHRoZW0gZmlyc3RcbiAgY29udGVudCA9IHByZXNjYW4oY29udGVudCwgeG1sKVxuICBjb25zdCBkb2M6IFN0ZERvY3VtZW50ID0gc3RkX3BhcnNlKGNvbnRlbnQsIHsgZGlzYWxsb3dEb2N0eXBlOiBmYWxzZSB9KVxuXG4gIC8vIFhNTCBkZWNsYXJhdGlvblxuICBpZiAoZG9jLmRlY2xhcmF0aW9uKSB7XG4gICAgaWYgKGRvYy5kZWNsYXJhdGlvbi52ZXJzaW9uKVxuICAgICAgeG1sW1wiQHZlcnNpb25cIl0gPSBkb2MuZGVjbGFyYXRpb24udmVyc2lvbiBhcyB0eXBlb2YgeG1sW1wiQHZlcnNpb25cIl1cbiAgICBpZiAoZG9jLmRlY2xhcmF0aW9uLmVuY29kaW5nKVxuICAgICAgeG1sW1wiQGVuY29kaW5nXCJdID0gZG9jLmRlY2xhcmF0aW9uLmVuY29kaW5nXG4gICAgaWYgKGRvYy5kZWNsYXJhdGlvbi5zdGFuZGFsb25lKVxuICAgICAgeG1sW1wiQHN0YW5kYWxvbmVcIl0gPSBkb2MuZGVjbGFyYXRpb24uc3RhbmRhbG9uZVxuICB9XG5cbiAgYnVpbGQoZG9jLnJvb3QsIHhtbClcblxuICByZXR1cm4gZmluYWxpemUoeG1sLCBvcHRpb25zKVxufVxuXG4vKipcbiAqIFBhcnNlIGEgWE1MIHN0cmVhbSBpbnRvIGFuIG9iamVjdC5cbiAqIEBzdGQgc3RyZWFtaW5nIHBhcnNlciBldmVudHMgYXJlIG1hcHBlZCB0byB0aGUgc2FtZSBkb2N1bWVudCBzdHJ1Y3R1cmUgYXMgdGhlIHN0cmluZyB2ZXJzaW9uLFxuICogYW5kIHVubGlrZSB0aGUgc3luYyBET00gdGhleSBuYXRpdmVseSBleHBvc2UgdGhlIGRvY3R5cGUgYW5kIHByb2Nlc3NpbmcgaW5zdHJ1Y3Rpb25zLlxuICovXG5hc3luYyBmdW5jdGlvbiBwYXJzZV9zdHJlYW0oY29udGVudDogUmVhZGFibGVTdHJlYW08VWludDhBcnJheT4sIG9wdGlvbnM/OiBQYXJzZU9wdGlvbnMpOiBQcm9taXNlPFhtbERvY3VtZW50PiB7XG4gIGNvbnN0IHhtbCA9IHhtbF9ub2RlKFwifnhtbFwiKSBhcyBYbWxEb2N1bWVudFxuICBjb25zdCBzdGFjayA9IFt4bWxdIGFzIEFycmF5PFhtbE5vZGU+XG4gIGF3YWl0IHBhcnNlWG1sU3RyZWFtRnJvbUJ5dGVzKGNvbnRlbnQsIHtcbiAgICAvLyBYTUwgZGVjbGFyYXRpb25cbiAgICBvbkRlY2xhcmF0aW9uKHZlcnNpb24sIGVuY29kaW5nLCBzdGFuZGFsb25lKSB7XG4gICAgICBpZiAodmVyc2lvbilcbiAgICAgICAgeG1sW1wiQHZlcnNpb25cIl0gPSB2ZXJzaW9uIGFzIFhtbERvY3VtZW50W1wiQHZlcnNpb25cIl1cbiAgICAgIGlmIChlbmNvZGluZylcbiAgICAgICAgeG1sW1wiQGVuY29kaW5nXCJdID0gZW5jb2RpbmdcbiAgICAgIGlmIChzdGFuZGFsb25lKVxuICAgICAgICB4bWxbXCJAc3RhbmRhbG9uZVwiXSA9IHN0YW5kYWxvbmVcbiAgICB9LFxuICAgIC8vIFhNTCBkb2N0eXBlIChvbmx5IHRoZSBuYW1lIGFuZCBwdWJsaWMvc3lzdGVtIGlkZW50aWZpZXJzIGFyZSBleHBvc2VkIGJ5IEBzdGQgZXZlbnRzKVxuICAgIG9uRG9jdHlwZShuYW1lLCBwdWJsaWNJZCwgc3lzdGVtSWQpIHtcbiAgICAgIGNvbnN0IGRvY3R5cGUgPSB4bWxfbm9kZShcIn5kb2N0eXBlXCIsIHsgcGFyZW50OiB4bWwgfSlcbiAgICAgIDtbbmFtZSwgcHVibGljSWQsIHN5c3RlbUlkXS5maWx0ZXIoKHZhbHVlKSA9PiB2YWx1ZSAhPT0gdW5kZWZpbmVkKS5mb3JFYWNoKCh2YWx1ZSkgPT4gZG9jdHlwZVtgQCR7dmFsdWV9YF0gPSBcIlwiKVxuICAgICAgeG1sW1wiI2RvY3R5cGVcIl0gPSBkb2N0eXBlXG4gICAgfSxcbiAgICAvLyBYTUwgcHJvY2Vzc2luZyBpbnN0cnVjdGlvblxuICAgIG9uUHJvY2Vzc2luZ0luc3RydWN0aW9uKHRhcmdldCwgaW5zdHJ1Y3Rpb24pIHtcbiAgICAgIHhtbF9pbnN0cnVjdGlvbih4bWwsIHRhcmdldCwgaW5zdHJ1Y3Rpb24udHJpbSgpKVxuICAgIH0sXG4gICAgLy8gWE1MIHRhZyBvcGVuZWRcbiAgICBvblN0YXJ0RWxlbWVudChuYW1lLCBfY29sb24sIF91cmksIGF0dHJpYnV0ZXMsIHNlbGZDbG9zaW5nKSB7XG4gICAgICBjb25zdCBub2RlID0geG1sX2VsZW1lbnQobmFtZSwgc3RhY2suYXQoLTEpISlcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXR0cmlidXRlcy5jb3VudDsgaSsrKVxuICAgICAgICBub2RlW2BAJHthdHRyaWJ1dGVzLmdldE5hbWUoaSl9YF0gPSBhdHRyaWJ1dGVzLmdldFZhbHVlKGkpXG4gICAgICBpZiAoIXNlbGZDbG9zaW5nKVxuICAgICAgICBzdGFjay5wdXNoKG5vZGUpXG4gICAgfSxcbiAgICAvLyBYTUwgdGFnIGNsb3NlZFxuICAgIG9uRW5kRWxlbWVudCgpIHtcbiAgICAgIHN0YWNrLnBvcCgpXG4gICAgfSxcbiAgICAvLyBUZXh0XG4gICAgb25UZXh0KHRleHQpIHtcbiAgICAgIHhtbF90ZXh0KHRleHQsIHsgdHlwZTogXCJ+dGV4dFwiLCBwYXJlbnQ6IHN0YWNrLmF0KC0xKSEgfSlcbiAgICB9LFxuICAgIC8vIENEQVRBXG4gICAgb25DRGF0YSh0ZXh0KSB7XG4gICAgICB4bWxfdGV4dCh0ZXh0LCB7IHR5cGU6IFwifmNkYXRhXCIsIHBhcmVudDogc3RhY2suYXQoLTEpISB9KVxuICAgIH0sXG4gICAgLy8gQ29tbWVudFxuICAgIG9uQ29tbWVudCh0ZXh0KSB7XG4gICAgICB4bWxfdGV4dCh0ZXh0LCB7IHR5cGU6IFwifmNvbW1lbnRcIiwgcGFyZW50OiBzdGFjay5hdCgtMSkhIH0pXG4gICAgfSxcbiAgfSwgeyBkaXNhbGxvd0RvY3R5cGU6IGZhbHNlIH0pXG4gIHJldHVybiBmaW5hbGl6ZSh4bWwsIG9wdGlvbnMpXG59XG5cbi8qKiBSZWNvdmVyIGAjZG9jdHlwZWAgYW5kIGAjaW5zdHJ1Y3Rpb25zYC4gKi9cbmZ1bmN0aW9uIHByZXNjYW4oY29udGVudDogc3RyaW5nLCB4bWw6IFhtbERvY3VtZW50KTogc3RyaW5nIHtcbiAgLy8gUHJvbG9nOiBza2lwIHdoaXRlc3BhY2UvY29tbWVudHMsIGNvbGxlY3QgaW5zdHJ1Y3Rpb25zIGFuZCBkb2N0eXBlIHVudGlsIHRoZSByb290IGVsZW1lbnQgb3BlbnNcbiAgbGV0IGkgPSAwXG4gIHByb2xvZzogd2hpbGUgKGkgPCBjb250ZW50Lmxlbmd0aCkge1xuICAgIHN3aXRjaCAodHJ1ZSkge1xuICAgICAgY2FzZSAvXFxzLy50ZXN0KGNvbnRlbnRbaV0pOiB7XG4gICAgICAgIGkrK1xuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuICAgICAgY2FzZSBjb250ZW50LnN0YXJ0c1dpdGgoXCI8IS0tXCIsIGkpOiB7XG4gICAgICAgIGNvbnN0IGVuZCA9IGNvbnRlbnQuaW5kZXhPZihcIi0tPlwiLCBpICsgNClcbiAgICAgICAgaWYgKGVuZCA8IDApXG4gICAgICAgICAgYnJlYWsgcHJvbG9nXG4gICAgICAgIGkgPSBlbmQgKyAzXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBjYXNlIGNvbnRlbnQuc3RhcnRzV2l0aChcIjw/XCIsIGkpOiB7XG4gICAgICAgIGNvbnN0IGVuZCA9IGNvbnRlbnQuaW5kZXhPZihcIj8+XCIsIGkgKyAyKVxuICAgICAgICBpZiAoZW5kIDwgMClcbiAgICAgICAgICBicmVhayBwcm9sb2dcbiAgICAgICAgY29uc3QgcmF3ID0gY29udGVudC5zbGljZShpICsgMiwgZW5kKVxuICAgICAgICBpID0gZW5kICsgMlxuICAgICAgICBjb25zdCB0YXJnZXQgPSByYXcubWF0Y2goL15cXFMrLyk/LlswXSA/PyBcIlwiXG4gICAgICAgIC8vIFRoZSA8P3htbD8+IGRlY2xhcmF0aW9uIGlzIGFscmVhZHkgaGFuZGxlZCB0aHJvdWdoIHN0ZCdzIERPTVxuICAgICAgICBpZiAodGFyZ2V0ICE9PSBcInhtbFwiKVxuICAgICAgICAgIHhtbF9pbnN0cnVjdGlvbih4bWwsIHRhcmdldCwgcmF3LnNsaWNlKHRhcmdldC5sZW5ndGgpLnRyaW0oKSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGNhc2UgY29udGVudC5zdGFydHNXaXRoKFwiPCFET0NUWVBFXCIsIGkpOiB7XG4gICAgICAgIC8vIEZpbmQgdGhlIGNsb3NpbmcgXCI+XCIsIHNraXBwaW5nIHF1b3RlZCBsaXRlcmFscyBhbmQgdGhlIGludGVybmFsIHN1YnNldCBcIlsuLi5dXCJcbiAgICAgICAgbGV0IGogPSBpICsgOVxuICAgICAgICBkb2N0eXBlOiB3aGlsZSAoaiA8IGNvbnRlbnQubGVuZ3RoKSB7XG4gICAgICAgICAgc3dpdGNoIChjb250ZW50W2pdKSB7XG4gICAgICAgICAgICBjYXNlICdcIic6XG4gICAgICAgICAgICBjYXNlIFwiJ1wiOiB7XG4gICAgICAgICAgICAgIGNvbnN0IHF1b3RlID0gY29udGVudC5pbmRleE9mKGNvbnRlbnRbal0sIGogKyAxKVxuICAgICAgICAgICAgICBpZiAocXVvdGUgPCAwKVxuICAgICAgICAgICAgICAgIGJyZWFrIGRvY3R5cGVcbiAgICAgICAgICAgICAgaiA9IHF1b3RlICsgMVxuICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBcIltcIjoge1xuICAgICAgICAgICAgICBjb25zdCBicmFja2V0ID0gY29udGVudC5pbmRleE9mKFwiXVwiLCBqICsgMSlcbiAgICAgICAgICAgICAgaWYgKGJyYWNrZXQgPCAwKVxuICAgICAgICAgICAgICAgIGJyZWFrIGRvY3R5cGVcbiAgICAgICAgICAgICAgaiA9IGJyYWNrZXQgKyAxXG4gICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFwiPlwiOlxuICAgICAgICAgICAgICBicmVhayBkb2N0eXBlXG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICBqKytcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgeG1sW1wiI2RvY3R5cGVcIl0gPSBPYmplY3QuYXNzaWduKHhtbF9ub2RlKFwifmRvY3R5cGVcIiwgeyBwYXJlbnQ6IHhtbCB9KSwgeG1sX2RvY3R5cGUoY29udGVudC5zbGljZShpICsgOSwgaikudHJpbSgpKSlcbiAgICAgICAgY29uc3QgZW5kID0gTWF0aC5taW4oaiArIDEsIGNvbnRlbnQubGVuZ3RoKVxuICAgICAgICBjb250ZW50ID0gYCR7Y29udGVudC5zbGljZSgwLCBpKX0ke1wiIFwiLnJlcGVhdChlbmQgLSBpKX0ke2NvbnRlbnQuc2xpY2UoZW5kKX1gXG4gICAgICAgIGkgPSBlbmRcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGJyZWFrIHByb2xvZ1xuICAgIH1cbiAgfVxuICAvLyBFcGlsb2c6IG9ubHkgY29tbWVudHMgYW5kIGluc3RydWN0aW9ucyBtYXkgZm9sbG93IHRoZSByb290IGVsZW1lbnQsIHNjYW4gdGhlbSBiYWNrd2FyZHNcbiAgY29uc3QgaW5zdHJ1Y3Rpb25zID0gW10gYXMgQXJyYXk8W3N0cmluZywgc3RyaW5nXT5cbiAgbGV0IHRhaWwgPSBjb250ZW50LnRyaW1FbmQoKVxuICBlcGlsb2c6IHdoaWxlICh0cnVlKSB7XG4gICAgc3dpdGNoICh0cnVlKSB7XG4gICAgICBjYXNlIHRhaWwuZW5kc1dpdGgoXCItLT5cIik6IHtcbiAgICAgICAgY29uc3Qgc3RhcnQgPSB0YWlsLmxhc3RJbmRleE9mKFwiPCEtLVwiKVxuICAgICAgICBpZiAoc3RhcnQgPCAwKVxuICAgICAgICAgIGJyZWFrIGVwaWxvZ1xuICAgICAgICB0YWlsID0gdGFpbC5zbGljZSgwLCBzdGFydCkudHJpbUVuZCgpXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBjYXNlIHRhaWwuZW5kc1dpdGgoXCI/PlwiKToge1xuICAgICAgICBjb25zdCBzdGFydCA9IHRhaWwubGFzdEluZGV4T2YoXCI8P1wiKVxuICAgICAgICBpZiAoc3RhcnQgPCAwKVxuICAgICAgICAgIGJyZWFrIGVwaWxvZ1xuICAgICAgICBjb25zdCByYXcgPSB0YWlsLnNsaWNlKHN0YXJ0ICsgMiwgLTIpXG4gICAgICAgIGNvbnN0IHRhcmdldCA9IHJhdy5tYXRjaCgvXlxcUysvKT8uWzBdID8/IFwiXCJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zLnVuc2hpZnQoW3RhcmdldCwgcmF3LnNsaWNlKHRhcmdldC5sZW5ndGgpLnRyaW0oKV0pXG4gICAgICAgIHRhaWwgPSB0YWlsLnNsaWNlKDAsIHN0YXJ0KS50cmltRW5kKClcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGJyZWFrIGVwaWxvZ1xuICAgIH1cbiAgfVxuICBpbnN0cnVjdGlvbnMuZm9yRWFjaCgoW3RhcmdldCwgcmF3XSkgPT4geG1sX2luc3RydWN0aW9uKHhtbCwgdGFyZ2V0LCByYXcpKVxuICByZXR1cm4gY29udGVudFxufVxuXG4vKiogV2FsayBhIHN0ZCBET00gZWxlbWVudCBpbnRvIHRoZSBlcmdvbm9taWMgfmNoaWxkcmVuL0BhdHRyLyN0ZXh0IHN0cnVjdHVyZS4gKi9cbmZ1bmN0aW9uIGJ1aWxkKGVsZW1lbnQ6IFN0ZEVsZW1lbnQsIHBhcmVudDogWG1sTm9kZSk6IHZvaWQge1xuICAvLyBBdHRhY2ggdW5kZXIgdGhlIGVudW1lcmFibGUga2V5IHdpdGggYXJyYXktZ3JvdXBpbmdcbiAgY29uc3Qgbm9kZSA9IHhtbF9lbGVtZW50KGVsZW1lbnQubmFtZS5yYXcsIHBhcmVudClcbiAgLy8gQXR0cmlidXRlc1xuICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoZWxlbWVudC5hdHRyaWJ1dGVzKSlcbiAgICBub2RlW2BAJHtuYW1lfWBdID0gdmFsdWVcbiAgLy8gQ2hpbGRyZW5cbiAgZm9yIChjb25zdCBjaGlsZCBvZiBlbGVtZW50LmNoaWxkcmVuIGFzIFJlYWRvbmx5QXJyYXk8U3RkTm9kZT4pIHtcbiAgICBzd2l0Y2ggKGNoaWxkLnR5cGUpIHtcbiAgICAgIGNhc2UgXCJlbGVtZW50XCI6XG4gICAgICAgIGJ1aWxkKGNoaWxkLCBub2RlKVxuICAgICAgICBicmVha1xuICAgICAgY2FzZSBcInRleHRcIjpcbiAgICAgICAgeG1sX3RleHQoY2hpbGQudGV4dCwgeyB0eXBlOiBcIn50ZXh0XCIsIHBhcmVudDogbm9kZSB9KVxuICAgICAgICBicmVha1xuICAgICAgY2FzZSBcImNkYXRhXCI6XG4gICAgICAgIHhtbF90ZXh0KGNoaWxkLnRleHQsIHsgdHlwZTogXCJ+Y2RhdGFcIiwgcGFyZW50OiBub2RlIH0pXG4gICAgICAgIGJyZWFrXG4gICAgICBjYXNlIFwiY29tbWVudFwiOlxuICAgICAgICB4bWxfdGV4dChjaGlsZC50ZXh0LCB7IHR5cGU6IFwifmNvbW1lbnRcIiwgcGFyZW50OiBub2RlIH0pXG4gICAgICAgIGJyZWFrXG4gICAgfVxuICB9XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztDQUdDLEdBRUQsVUFBVTtBQUNWLFNBQVMsU0FBUyxTQUFTLFFBQVEsaUJBQWdCO0FBQ25ELFNBQVMsdUJBQXVCLFFBQVEsd0JBQXVCO0FBRS9ELFNBQTRC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
|
package/stringify.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stringify an XML document object into a XML string.
|
|
3
|
+
* @module
|
|
4
|
+
*/ import type { Nullable, Stringifyable, XmlNode, XmlText } from "./_types.js";
|
|
5
|
+
export type * from "./_types.js";
|
|
6
|
+
/** XML stringifier options. */ export type StringifyOptions = {
|
|
7
|
+
/** Format options. */ format?: FormatOptions;
|
|
8
|
+
/** Replace options. */ replace?: ReplaceOptions;
|
|
9
|
+
};
|
|
10
|
+
/** XML stringifier {@linkcode StringifyOptions}`.format` */ export type FormatOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* Indent string (defaults to `" "`).
|
|
13
|
+
* Set to empty string to disable indentation and enable minification.
|
|
14
|
+
*/ indent?: string;
|
|
15
|
+
/** Break text node if its length is greater than this value (defaults to `128`). */ breakline?: number;
|
|
16
|
+
};
|
|
17
|
+
/** XML stringifier {@linkcode StringifyOptions}`.replace` */ export type ReplaceOptions = {
|
|
18
|
+
/**
|
|
19
|
+
* Force escape all XML entities.
|
|
20
|
+
* By default, only the ones that would break the XML structure are escaped.
|
|
21
|
+
*/ entities?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Custom replacer (this is applied after other revivals).
|
|
24
|
+
* When it is applied on an attribute, `key` and `value` will be given.
|
|
25
|
+
* When it is applied on a node, both `key` and `value` will be `null`.
|
|
26
|
+
* Return `undefined` to delete either the attribute or the tag.
|
|
27
|
+
*/ custom?: Replacer;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Custom XML stringifier replacer.
|
|
31
|
+
* It can be used to change the way some nodes are stringified.
|
|
32
|
+
*/ export type Replacer = (args: {
|
|
33
|
+
name: string;
|
|
34
|
+
key: Nullable<string>;
|
|
35
|
+
value: Nullable<string>;
|
|
36
|
+
node: Readonly<XmlNode>;
|
|
37
|
+
}) => unknown;
|
|
38
|
+
/**
|
|
39
|
+
* Stringify an {@link XmlDocument} object into a XML string.
|
|
40
|
+
*
|
|
41
|
+
* Output can be customized using the {@link options} parameter.
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { stringify } from "./stringify.ts"
|
|
45
|
+
*
|
|
46
|
+
* console.log(stringify({
|
|
47
|
+
* "@version": "1.0",
|
|
48
|
+
* "@standalone": "yes",
|
|
49
|
+
* root: {
|
|
50
|
+
* text: "hello",
|
|
51
|
+
* array: ["world", "monde", "世界", "🌏"],
|
|
52
|
+
* number: 42,
|
|
53
|
+
* boolean: true,
|
|
54
|
+
* complex: {
|
|
55
|
+
* "@attribute": "value",
|
|
56
|
+
* "#text": "content",
|
|
57
|
+
* },
|
|
58
|
+
* }
|
|
59
|
+
* }))
|
|
60
|
+
* ```
|
|
61
|
+
*/ export declare function stringify(document: Stringifyable, options?: StringifyOptions): string;
|
|
62
|
+
/**
|
|
63
|
+
* Helper to create a CDATA node.
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { stringify, cdata } from "./stringify.ts"
|
|
67
|
+
* stringify({ string: cdata(`hello <world>`) })
|
|
68
|
+
* // <string><![CDATA[hello <world>]]></string>
|
|
69
|
+
* ```
|
|
70
|
+
*/ export declare function cdata(text: string): Omit<XmlText, "~parent">;
|
|
71
|
+
/**
|
|
72
|
+
* Helper to create a comment node.
|
|
73
|
+
*
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { stringify, comment } from "./stringify.ts"
|
|
76
|
+
* stringify({ string: comment(`hello world`) })
|
|
77
|
+
* // <string><!--hello world--></string>
|
|
78
|
+
* ```
|
|
79
|
+
*/ export declare function comment(text: string): Omit<XmlText, "~parent">;
|