@mtkruto/node 0.1.289 → 0.1.299
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 -1
- package/esm/client/4_client.js +1 -1
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/DomHandler.d.ts +83 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/DomHandler.js +203 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/DomSerializer.d.ts +50 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/DomSerializer.js +274 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/ElementType.d.ts +47 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/ElementType.js +51 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/FeedHandler.d.ts +66 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/FeedHandler.js +191 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/Node.d.ts +168 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/Node.js +385 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/Parser.d.ts +159 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/Parser.js +431 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/Tokenizer.d.ts +181 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/Tokenizer.js +1046 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/mod.d.ts +42 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/mod.js +52 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode.d.ts +11 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode.js +122 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode_codepoint.d.ts +1 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode_codepoint.js +24 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/encode.d.ts +46 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/encode.js +121 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/decode.d.ts +31 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/decode.js +30 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/entities.d.ts +2128 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/entities.js +2127 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/legacy.d.ts +109 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/legacy.js +108 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/xml.d.ts +8 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/xml.js +1 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/mod.d.ts +90 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/mod.js +95 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/helpers.d.ts +50 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/helpers.js +128 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/legacy.d.ts +46 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/legacy.js +110 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/manipulation.d.ts +42 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/manipulation.js +120 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/mod.d.ts +6 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/mod.js +6 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/querying.d.ts +54 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/querying.js +110 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/stringify.d.ts +40 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/stringify.js +75 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/traversal.d.ts +58 -0
- package/esm/deps/deno.land/x/html_parser@v0.1.3/src/utils/traversal.js +101 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/deflate.d.ts +2 -0
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/deflate.js +5 -1
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/inflate.d.ts +2 -2
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/inflate.js +5 -1
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/crc32.js +1 -1
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/deflate.js +8 -8
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/inffast.js +2 -2
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/inflate.js +19 -21
- package/esm/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/trees.js +3 -3
- package/package.json +1 -1
- package/script/client/4_client.js +1 -1
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/DomHandler.d.ts +83 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/DomHandler.js +207 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/DomSerializer.d.ts +50 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/DomSerializer.js +301 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/ElementType.d.ts +47 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/ElementType.js +55 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/FeedHandler.d.ts +66 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/FeedHandler.js +222 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/Node.d.ts +168 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/Node.js +404 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/Parser.d.ts +159 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/Parser.js +438 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/Tokenizer.d.ts +181 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/Tokenizer.js +1052 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/mod.d.ts +42 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/mod.js +88 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode.d.ts +11 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode.js +128 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode_codepoint.d.ts +1 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/decode_codepoint.js +30 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/encode.d.ts +46 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/encode.js +129 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/decode.d.ts +31 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/decode.js +32 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/entities.d.ts +2128 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/entities.js +2129 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/legacy.d.ts +109 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/legacy.js +110 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/xml.d.ts +8 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/maps/xml.js +3 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/mod.d.ts +90 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/entities/mod.js +114 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/helpers.d.ts +50 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/helpers.js +134 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/legacy.d.ts +46 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/legacy.js +118 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/manipulation.d.ts +42 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/manipulation.js +129 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/mod.d.ts +6 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/mod.js +22 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/querying.d.ts +54 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/querying.js +119 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/stringify.d.ts +40 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/stringify.js +86 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/traversal.d.ts +58 -0
- package/script/deps/deno.land/x/html_parser@v0.1.3/src/utils/traversal.js +112 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/deflate.d.ts +2 -0
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/deflate.js +7 -1
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/inflate.d.ts +2 -2
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/inflate.js +7 -1
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/crc32.js +1 -1
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/deflate.js +8 -8
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/inffast.js +2 -2
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/inflate.js +19 -21
- package/script/deps/raw.githubusercontent.com/MTKruto/compress/main/zlib/zlib/trees.js +3 -3
package/README.md
CHANGED
|
@@ -1 +1,77 @@
|
|
|
1
|
-
<
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# MTKruto
|
|
4
|
+
|
|
5
|
+
Cross-runtime JavaScript library for building Telegram clients
|
|
6
|
+
|
|
7
|
+
###### [Documentation](https://mtkruto.deno.dev) / [API Reference](https://deno.land/x/mtkruto/mod.ts) / [Discussion Chat](https://t.me/MTKrutoChat) / [License](#license)
|
|
8
|
+
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
### Key Features
|
|
12
|
+
|
|
13
|
+
- **Cross-runtime.** Runs inside browsers, Deno, Node.js, and Bun.
|
|
14
|
+
- **Type-safe.** DX is enhanced with TypeScript support.
|
|
15
|
+
- **Made for the Web.** Leverages Web APIs.
|
|
16
|
+
- **Unopinionated.** No hidden behaviors.
|
|
17
|
+
- **Extensible.** Highly customizable.
|
|
18
|
+
|
|
19
|
+
> Note: MTKruto has not reached version 1.0.0 yet. While it can run in production, we currently do not recommend depending on it for critical projects.
|
|
20
|
+
|
|
21
|
+
## Get Started
|
|
22
|
+
|
|
23
|
+
### Browsers
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<script type="module">
|
|
27
|
+
import { Client, getRandomId } from "https://esm.sh/@mtkruto/browser";
|
|
28
|
+
|
|
29
|
+
const client = new Client();
|
|
30
|
+
await client.connect();
|
|
31
|
+
|
|
32
|
+
const pong = await client.api.ping({ ping_id: getRandomId() });
|
|
33
|
+
console.debug(pong);
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> The [@mtkruto/browser](https://npm.im/@mtkruto/browser) package can also be used with front end frameworks and bundlers.
|
|
38
|
+
|
|
39
|
+
### Deno
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { Client, getRandomId } from "https://deno.land/x/mtkruto/mod.ts";
|
|
43
|
+
|
|
44
|
+
const client = new Client();
|
|
45
|
+
await client.connect();
|
|
46
|
+
|
|
47
|
+
const pong = await client.api.ping({ ping_id: getRandomId() });
|
|
48
|
+
console.debug(pong);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Node.js
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const { Client, getRandomId } = require("@mtkruto/node"); // npm install @mtkruto/node
|
|
55
|
+
|
|
56
|
+
const client = new Client();
|
|
57
|
+
await client.connect();
|
|
58
|
+
|
|
59
|
+
const pong = await client.api.ping({ ping_id: getRandomId() });
|
|
60
|
+
console.debug(pong);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Bun
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { Client, getRandomId } from "@mtkruto/mtkruto"; // bunx jsr i @mtkruto/mtkruto
|
|
67
|
+
|
|
68
|
+
const client = new Client();
|
|
69
|
+
await client.connect();
|
|
70
|
+
|
|
71
|
+
const pong = await client.api.ping({ ping_id: getRandomId() });
|
|
72
|
+
console.debug(pong);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MTKruto is made open-source under the GNU Lesser General Public License version 3, or at your option, any later version. Refer to [COPYING](./COPYING) and [COPYING.LESSER](./COPYING.LESSER) for more.
|
package/esm/client/4_client.js
CHANGED
|
@@ -1141,7 +1141,7 @@ export class Client extends Composer {
|
|
|
1141
1141
|
if (!this.connected) {
|
|
1142
1142
|
continue;
|
|
1143
1143
|
}
|
|
1144
|
-
__classPrivateFieldGet(this, _Client_pingLoopAbortController, "f")
|
|
1144
|
+
__classPrivateFieldGet(this, _Client_pingLoopAbortController, "f")?.signal.throwIfAborted();
|
|
1145
1145
|
await this.api.ping_delay_disconnect({ ping_id: getRandomId(), disconnect_delay: __classPrivateFieldGet(this, _Client_pingInterval, "f") / 1000 + 15 });
|
|
1146
1146
|
if (Date.now() - __classPrivateFieldGet(this, _Client_lastUpdates, "f").getTime() >= 15 * 60 * 1000) {
|
|
1147
1147
|
drop(__classPrivateFieldGet(this, _Client_updateManager, "f").recoverUpdateGap("lastUpdates"));
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Node, Element, Document, NodeWithChildren, DataNode } from './Node.js';
|
|
2
|
+
export interface DomHandlerOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Add a `startIndex` property to nodes.
|
|
5
|
+
* When the parser is used in a non-streaming fashion, `startIndex` is an integer
|
|
6
|
+
* indicating the position of the start of the node in the document.
|
|
7
|
+
*
|
|
8
|
+
* @default false
|
|
9
|
+
*/
|
|
10
|
+
withStartIndices?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Add an `endIndex` property to nodes.
|
|
13
|
+
* When the parser is used in a non-streaming fashion, `endIndex` is an integer
|
|
14
|
+
* indicating the position of the end of the node in the document.
|
|
15
|
+
*
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
withEndIndices?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Replace all whitespace with single spaces.
|
|
21
|
+
*
|
|
22
|
+
* **Note:** Enabling this might break your markup.
|
|
23
|
+
*
|
|
24
|
+
* @default false
|
|
25
|
+
* @deprecated
|
|
26
|
+
*/
|
|
27
|
+
normalizeWhitespace?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Treat the markup as XML.
|
|
30
|
+
*
|
|
31
|
+
* @default false
|
|
32
|
+
*/
|
|
33
|
+
xmlMode?: boolean;
|
|
34
|
+
}
|
|
35
|
+
interface ParserInterface {
|
|
36
|
+
startIndex: number | null;
|
|
37
|
+
endIndex: number | null;
|
|
38
|
+
}
|
|
39
|
+
type Callback = (error: Error | null, dom: Node[]) => void;
|
|
40
|
+
type ElementCallback = (element: Element) => void;
|
|
41
|
+
export declare class DomHandler {
|
|
42
|
+
/** The elements of the DOM */
|
|
43
|
+
dom: Node[];
|
|
44
|
+
/** The root element for the DOM */
|
|
45
|
+
root: Document;
|
|
46
|
+
/** Called once parsing has completed. */
|
|
47
|
+
private readonly callback;
|
|
48
|
+
/** Settings for the handler. */
|
|
49
|
+
private readonly options;
|
|
50
|
+
/** Callback whenever a tag is closed. */
|
|
51
|
+
private readonly elementCB;
|
|
52
|
+
/** Indicated whether parsing has been completed. */
|
|
53
|
+
private done;
|
|
54
|
+
/** Stack of open tags. */
|
|
55
|
+
protected tagStack: NodeWithChildren[];
|
|
56
|
+
/** A data node that is still being written to. */
|
|
57
|
+
protected lastNode: DataNode | null;
|
|
58
|
+
/** Reference to the parser instance. Used for location information. */
|
|
59
|
+
private parser;
|
|
60
|
+
/**
|
|
61
|
+
* @param callback Called once parsing has completed.
|
|
62
|
+
* @param options Settings for the handler.
|
|
63
|
+
* @param elementCB Callback whenever a tag is closed.
|
|
64
|
+
*/
|
|
65
|
+
constructor(callback?: Callback | null, options?: DomHandlerOptions | null, elementCB?: ElementCallback);
|
|
66
|
+
onparserinit(parser: ParserInterface): void;
|
|
67
|
+
onreset(): void;
|
|
68
|
+
onend(): void;
|
|
69
|
+
onerror(error: Error): void;
|
|
70
|
+
onclosetag(): void;
|
|
71
|
+
onopentag(name: string, attribs: {
|
|
72
|
+
[key: string]: string;
|
|
73
|
+
}): void;
|
|
74
|
+
ontext(data: string): void;
|
|
75
|
+
oncomment(data: string): void;
|
|
76
|
+
oncommentend(): void;
|
|
77
|
+
oncdatastart(): void;
|
|
78
|
+
oncdataend(): void;
|
|
79
|
+
onprocessinginstruction(name: string, data: string): void;
|
|
80
|
+
protected handleCallback(error: Error | null): void;
|
|
81
|
+
protected addNode(node: Node): void;
|
|
82
|
+
}
|
|
83
|
+
export default DomHandler;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { Element, Document, NodeWithChildren, Comment, Text, ProcessingInstruction, } from './Node.js';
|
|
2
|
+
import { ElementType } from './ElementType.js';
|
|
3
|
+
const reWhitespace = /\s+/g;
|
|
4
|
+
// Default options
|
|
5
|
+
const defaultOpts = {
|
|
6
|
+
normalizeWhitespace: false,
|
|
7
|
+
withStartIndices: false,
|
|
8
|
+
withEndIndices: false,
|
|
9
|
+
};
|
|
10
|
+
export class DomHandler {
|
|
11
|
+
/**
|
|
12
|
+
* @param callback Called once parsing has completed.
|
|
13
|
+
* @param options Settings for the handler.
|
|
14
|
+
* @param elementCB Callback whenever a tag is closed.
|
|
15
|
+
*/
|
|
16
|
+
constructor(callback, options, elementCB) {
|
|
17
|
+
/** The elements of the DOM */
|
|
18
|
+
Object.defineProperty(this, "dom", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: []
|
|
23
|
+
});
|
|
24
|
+
/** The root element for the DOM */
|
|
25
|
+
Object.defineProperty(this, "root", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: new Document(this.dom)
|
|
30
|
+
});
|
|
31
|
+
/** Called once parsing has completed. */
|
|
32
|
+
Object.defineProperty(this, "callback", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
/** Settings for the handler. */
|
|
39
|
+
Object.defineProperty(this, "options", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: void 0
|
|
44
|
+
});
|
|
45
|
+
/** Callback whenever a tag is closed. */
|
|
46
|
+
Object.defineProperty(this, "elementCB", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: void 0
|
|
51
|
+
});
|
|
52
|
+
/** Indicated whether parsing has been completed. */
|
|
53
|
+
Object.defineProperty(this, "done", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
writable: true,
|
|
57
|
+
value: false
|
|
58
|
+
});
|
|
59
|
+
/** Stack of open tags. */
|
|
60
|
+
Object.defineProperty(this, "tagStack", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
configurable: true,
|
|
63
|
+
writable: true,
|
|
64
|
+
value: [this.root]
|
|
65
|
+
});
|
|
66
|
+
/** A data node that is still being written to. */
|
|
67
|
+
Object.defineProperty(this, "lastNode", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: null
|
|
72
|
+
});
|
|
73
|
+
/** Reference to the parser instance. Used for location information. */
|
|
74
|
+
Object.defineProperty(this, "parser", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
value: null
|
|
79
|
+
});
|
|
80
|
+
// Make it possible to skip arguments, for backwards-compatibility
|
|
81
|
+
if (typeof options === 'function') {
|
|
82
|
+
elementCB = options;
|
|
83
|
+
options = defaultOpts;
|
|
84
|
+
}
|
|
85
|
+
if (typeof callback === 'object') {
|
|
86
|
+
options = callback;
|
|
87
|
+
callback = undefined;
|
|
88
|
+
}
|
|
89
|
+
this.callback = callback ?? null;
|
|
90
|
+
this.options = options ?? defaultOpts;
|
|
91
|
+
this.elementCB = elementCB ?? null;
|
|
92
|
+
}
|
|
93
|
+
onparserinit(parser) {
|
|
94
|
+
this.parser = parser;
|
|
95
|
+
}
|
|
96
|
+
// Resets the handler back to starting state
|
|
97
|
+
onreset() {
|
|
98
|
+
this.dom = [];
|
|
99
|
+
this.root = new Document(this.dom);
|
|
100
|
+
this.done = false;
|
|
101
|
+
this.tagStack = [this.root];
|
|
102
|
+
this.lastNode = null;
|
|
103
|
+
this.parser = this.parser ?? null;
|
|
104
|
+
}
|
|
105
|
+
// Signals the handler that parsing is done
|
|
106
|
+
onend() {
|
|
107
|
+
if (this.done)
|
|
108
|
+
return;
|
|
109
|
+
this.done = true;
|
|
110
|
+
this.parser = null;
|
|
111
|
+
this.handleCallback(null);
|
|
112
|
+
}
|
|
113
|
+
onerror(error) {
|
|
114
|
+
this.handleCallback(error);
|
|
115
|
+
}
|
|
116
|
+
onclosetag() {
|
|
117
|
+
this.lastNode = null;
|
|
118
|
+
const elem = this.tagStack.pop();
|
|
119
|
+
if (this.options.withEndIndices) {
|
|
120
|
+
elem.endIndex = this.parser.endIndex;
|
|
121
|
+
}
|
|
122
|
+
if (this.elementCB)
|
|
123
|
+
this.elementCB(elem);
|
|
124
|
+
}
|
|
125
|
+
onopentag(name, attribs) {
|
|
126
|
+
const type = this.options.xmlMode ? ElementType.Tag : undefined;
|
|
127
|
+
const element = new Element(name, attribs, undefined, type);
|
|
128
|
+
this.addNode(element);
|
|
129
|
+
this.tagStack.push(element);
|
|
130
|
+
}
|
|
131
|
+
ontext(data) {
|
|
132
|
+
const { normalizeWhitespace } = this.options;
|
|
133
|
+
const { lastNode } = this;
|
|
134
|
+
if (lastNode && lastNode.type === ElementType.Text) {
|
|
135
|
+
if (normalizeWhitespace) {
|
|
136
|
+
lastNode.data = (lastNode.data + data).replace(reWhitespace, ' ');
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
lastNode.data += data;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
if (normalizeWhitespace) {
|
|
144
|
+
data = data.replace(reWhitespace, ' ');
|
|
145
|
+
}
|
|
146
|
+
const node = new Text(data);
|
|
147
|
+
this.addNode(node);
|
|
148
|
+
this.lastNode = node;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
oncomment(data) {
|
|
152
|
+
if (this.lastNode && this.lastNode.type === ElementType.Comment) {
|
|
153
|
+
this.lastNode.data += data;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const node = new Comment(data);
|
|
157
|
+
this.addNode(node);
|
|
158
|
+
this.lastNode = node;
|
|
159
|
+
}
|
|
160
|
+
oncommentend() {
|
|
161
|
+
this.lastNode = null;
|
|
162
|
+
}
|
|
163
|
+
oncdatastart() {
|
|
164
|
+
const text = new Text('');
|
|
165
|
+
const node = new NodeWithChildren(ElementType.CDATA, [text]);
|
|
166
|
+
this.addNode(node);
|
|
167
|
+
text.parent = node;
|
|
168
|
+
this.lastNode = text;
|
|
169
|
+
}
|
|
170
|
+
oncdataend() {
|
|
171
|
+
this.lastNode = null;
|
|
172
|
+
}
|
|
173
|
+
onprocessinginstruction(name, data) {
|
|
174
|
+
const node = new ProcessingInstruction(name, data);
|
|
175
|
+
this.addNode(node);
|
|
176
|
+
}
|
|
177
|
+
handleCallback(error) {
|
|
178
|
+
if (typeof this.callback === 'function') {
|
|
179
|
+
this.callback(error, this.dom);
|
|
180
|
+
}
|
|
181
|
+
else if (error) {
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
addNode(node) {
|
|
186
|
+
const parent = this.tagStack[this.tagStack.length - 1];
|
|
187
|
+
const previousSibling = parent.children[parent.children.length - 1];
|
|
188
|
+
if (this.options.withStartIndices) {
|
|
189
|
+
node.startIndex = this.parser.startIndex;
|
|
190
|
+
}
|
|
191
|
+
if (this.options.withEndIndices) {
|
|
192
|
+
node.endIndex = this.parser.endIndex;
|
|
193
|
+
}
|
|
194
|
+
parent.children.push(node);
|
|
195
|
+
if (previousSibling) {
|
|
196
|
+
node.prev = previousSibling;
|
|
197
|
+
previousSibling.next = node;
|
|
198
|
+
}
|
|
199
|
+
node.parent = parent;
|
|
200
|
+
this.lastNode = null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export default DomHandler;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Node } from './Node.js';
|
|
2
|
+
/**
|
|
3
|
+
* Mixed-case SVG and MathML tags & attributes
|
|
4
|
+
* recognized by the HTML parser.
|
|
5
|
+
*
|
|
6
|
+
* @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
|
|
7
|
+
*/
|
|
8
|
+
export declare const elementNames: Map<string, string>;
|
|
9
|
+
export declare const attributeNames: Map<string, string>;
|
|
10
|
+
export interface DomSerializerOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Print an empty attribute's value.
|
|
13
|
+
*
|
|
14
|
+
* @default xmlMode
|
|
15
|
+
* @example With <code>emptyAttrs: false</code>: <code><input checked></code>
|
|
16
|
+
* @example With <code>emptyAttrs: true</code>: <code><input checked=""></code>
|
|
17
|
+
*/
|
|
18
|
+
emptyAttrs?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Print self-closing tags for tags without contents.
|
|
21
|
+
*
|
|
22
|
+
* @default xmlMode
|
|
23
|
+
* @example With <code>selfClosingTags: false</code>: <code><foo></foo></code>
|
|
24
|
+
* @example With <code>selfClosingTags: true</code>: <code><foo /></code>
|
|
25
|
+
*/
|
|
26
|
+
selfClosingTags?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Treat the input as an XML document; enables the `emptyAttrs` and `selfClosingTags` options.
|
|
29
|
+
*
|
|
30
|
+
* If the value is `"foreign"`, it will try to correct mixed-case attribute names.
|
|
31
|
+
*
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
xmlMode?: boolean | 'foreign';
|
|
35
|
+
/**
|
|
36
|
+
* Encode characters that are either reserved in HTML or XML, or are outside of the ASCII range.
|
|
37
|
+
*
|
|
38
|
+
* @default true
|
|
39
|
+
*/
|
|
40
|
+
decodeEntities?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Renders a DOM node or an array of DOM nodes to a string.
|
|
44
|
+
*
|
|
45
|
+
* Can be thought of as the equivalent of the `outerHTML` of the passed node(s).
|
|
46
|
+
*
|
|
47
|
+
* @param node Node to be rendered.
|
|
48
|
+
* @param options Changes serialization behavior
|
|
49
|
+
*/
|
|
50
|
+
export default function render(node: Node | ArrayLike<Node>, options?: DomSerializerOptions): string;
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Module dependencies
|
|
3
|
+
*/
|
|
4
|
+
import * as ElementType from './ElementType.js';
|
|
5
|
+
import { encodeXML } from './utils/entities/mod.js';
|
|
6
|
+
/**
|
|
7
|
+
* Mixed-case SVG and MathML tags & attributes
|
|
8
|
+
* recognized by the HTML parser.
|
|
9
|
+
*
|
|
10
|
+
* @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
|
|
11
|
+
*/
|
|
12
|
+
export const elementNames = new Map([
|
|
13
|
+
['altglyph', 'altGlyph'],
|
|
14
|
+
['altglyphdef', 'altGlyphDef'],
|
|
15
|
+
['altglyphitem', 'altGlyphItem'],
|
|
16
|
+
['animatecolor', 'animateColor'],
|
|
17
|
+
['animatemotion', 'animateMotion'],
|
|
18
|
+
['animatetransform', 'animateTransform'],
|
|
19
|
+
['clippath', 'clipPath'],
|
|
20
|
+
['feblend', 'feBlend'],
|
|
21
|
+
['fecolormatrix', 'feColorMatrix'],
|
|
22
|
+
['fecomponenttransfer', 'feComponentTransfer'],
|
|
23
|
+
['fecomposite', 'feComposite'],
|
|
24
|
+
['feconvolvematrix', 'feConvolveMatrix'],
|
|
25
|
+
['fediffuselighting', 'feDiffuseLighting'],
|
|
26
|
+
['fedisplacementmap', 'feDisplacementMap'],
|
|
27
|
+
['fedistantlight', 'feDistantLight'],
|
|
28
|
+
['fedropshadow', 'feDropShadow'],
|
|
29
|
+
['feflood', 'feFlood'],
|
|
30
|
+
['fefunca', 'feFuncA'],
|
|
31
|
+
['fefuncb', 'feFuncB'],
|
|
32
|
+
['fefuncg', 'feFuncG'],
|
|
33
|
+
['fefuncr', 'feFuncR'],
|
|
34
|
+
['fegaussianblur', 'feGaussianBlur'],
|
|
35
|
+
['feimage', 'feImage'],
|
|
36
|
+
['femerge', 'feMerge'],
|
|
37
|
+
['femergenode', 'feMergeNode'],
|
|
38
|
+
['femorphology', 'feMorphology'],
|
|
39
|
+
['feoffset', 'feOffset'],
|
|
40
|
+
['fepointlight', 'fePointLight'],
|
|
41
|
+
['fespecularlighting', 'feSpecularLighting'],
|
|
42
|
+
['fespotlight', 'feSpotLight'],
|
|
43
|
+
['fetile', 'feTile'],
|
|
44
|
+
['feturbulence', 'feTurbulence'],
|
|
45
|
+
['foreignobject', 'foreignObject'],
|
|
46
|
+
['glyphref', 'glyphRef'],
|
|
47
|
+
['lineargradient', 'linearGradient'],
|
|
48
|
+
['radialgradient', 'radialGradient'],
|
|
49
|
+
['textpath', 'textPath'],
|
|
50
|
+
]);
|
|
51
|
+
export const attributeNames = new Map([
|
|
52
|
+
['definitionurl', 'definitionURL'],
|
|
53
|
+
['attributename', 'attributeName'],
|
|
54
|
+
['attributetype', 'attributeType'],
|
|
55
|
+
['basefrequency', 'baseFrequency'],
|
|
56
|
+
['baseprofile', 'baseProfile'],
|
|
57
|
+
['calcmode', 'calcMode'],
|
|
58
|
+
['clippathunits', 'clipPathUnits'],
|
|
59
|
+
['diffuseconstant', 'diffuseConstant'],
|
|
60
|
+
['edgemode', 'edgeMode'],
|
|
61
|
+
['filterunits', 'filterUnits'],
|
|
62
|
+
['glyphref', 'glyphRef'],
|
|
63
|
+
['gradienttransform', 'gradientTransform'],
|
|
64
|
+
['gradientunits', 'gradientUnits'],
|
|
65
|
+
['kernelmatrix', 'kernelMatrix'],
|
|
66
|
+
['kernelunitlength', 'kernelUnitLength'],
|
|
67
|
+
['keypoints', 'keyPoints'],
|
|
68
|
+
['keysplines', 'keySplines'],
|
|
69
|
+
['keytimes', 'keyTimes'],
|
|
70
|
+
['lengthadjust', 'lengthAdjust'],
|
|
71
|
+
['limitingconeangle', 'limitingConeAngle'],
|
|
72
|
+
['markerheight', 'markerHeight'],
|
|
73
|
+
['markerunits', 'markerUnits'],
|
|
74
|
+
['markerwidth', 'markerWidth'],
|
|
75
|
+
['maskcontentunits', 'maskContentUnits'],
|
|
76
|
+
['maskunits', 'maskUnits'],
|
|
77
|
+
['numoctaves', 'numOctaves'],
|
|
78
|
+
['pathlength', 'pathLength'],
|
|
79
|
+
['patterncontentunits', 'patternContentUnits'],
|
|
80
|
+
['patterntransform', 'patternTransform'],
|
|
81
|
+
['patternunits', 'patternUnits'],
|
|
82
|
+
['pointsatx', 'pointsAtX'],
|
|
83
|
+
['pointsaty', 'pointsAtY'],
|
|
84
|
+
['pointsatz', 'pointsAtZ'],
|
|
85
|
+
['preservealpha', 'preserveAlpha'],
|
|
86
|
+
['preserveaspectratio', 'preserveAspectRatio'],
|
|
87
|
+
['primitiveunits', 'primitiveUnits'],
|
|
88
|
+
['refx', 'refX'],
|
|
89
|
+
['refy', 'refY'],
|
|
90
|
+
['repeatcount', 'repeatCount'],
|
|
91
|
+
['repeatdur', 'repeatDur'],
|
|
92
|
+
['requiredextensions', 'requiredExtensions'],
|
|
93
|
+
['requiredfeatures', 'requiredFeatures'],
|
|
94
|
+
['specularconstant', 'specularConstant'],
|
|
95
|
+
['specularexponent', 'specularExponent'],
|
|
96
|
+
['spreadmethod', 'spreadMethod'],
|
|
97
|
+
['startoffset', 'startOffset'],
|
|
98
|
+
['stddeviation', 'stdDeviation'],
|
|
99
|
+
['stitchtiles', 'stitchTiles'],
|
|
100
|
+
['surfacescale', 'surfaceScale'],
|
|
101
|
+
['systemlanguage', 'systemLanguage'],
|
|
102
|
+
['tablevalues', 'tableValues'],
|
|
103
|
+
['targetx', 'targetX'],
|
|
104
|
+
['targety', 'targetY'],
|
|
105
|
+
['textlength', 'textLength'],
|
|
106
|
+
['viewbox', 'viewBox'],
|
|
107
|
+
['viewtarget', 'viewTarget'],
|
|
108
|
+
['xchannelselector', 'xChannelSelector'],
|
|
109
|
+
['ychannelselector', 'yChannelSelector'],
|
|
110
|
+
['zoomandpan', 'zoomAndPan'],
|
|
111
|
+
]);
|
|
112
|
+
const unencodedElements = new Set([
|
|
113
|
+
'style',
|
|
114
|
+
'script',
|
|
115
|
+
'xmp',
|
|
116
|
+
'iframe',
|
|
117
|
+
'noembed',
|
|
118
|
+
'noframes',
|
|
119
|
+
'plaintext',
|
|
120
|
+
'noscript',
|
|
121
|
+
]);
|
|
122
|
+
/**
|
|
123
|
+
* Format attributes
|
|
124
|
+
*/
|
|
125
|
+
function formatAttributes(attributes, opts) {
|
|
126
|
+
if (!attributes)
|
|
127
|
+
return;
|
|
128
|
+
return Object.keys(attributes)
|
|
129
|
+
.map(key => {
|
|
130
|
+
const value = attributes[key] ?? '';
|
|
131
|
+
if (opts.xmlMode === 'foreign') {
|
|
132
|
+
/* Fix up mixed-case attribute names */
|
|
133
|
+
key = attributeNames.get(key) ?? key;
|
|
134
|
+
}
|
|
135
|
+
if (!opts.emptyAttrs && !opts.xmlMode && value === '') {
|
|
136
|
+
return key;
|
|
137
|
+
}
|
|
138
|
+
return `${key}="${opts.decodeEntities !== false
|
|
139
|
+
? encodeXML(value)
|
|
140
|
+
: value.replace(/"/g, '"')}"`;
|
|
141
|
+
})
|
|
142
|
+
.join(' ');
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Self-enclosing tags
|
|
146
|
+
*/
|
|
147
|
+
const singleTag = new Set([
|
|
148
|
+
'area',
|
|
149
|
+
'base',
|
|
150
|
+
'basefont',
|
|
151
|
+
'br',
|
|
152
|
+
'col',
|
|
153
|
+
'command',
|
|
154
|
+
'embed',
|
|
155
|
+
'frame',
|
|
156
|
+
'hr',
|
|
157
|
+
'img',
|
|
158
|
+
'input',
|
|
159
|
+
'isindex',
|
|
160
|
+
'keygen',
|
|
161
|
+
'link',
|
|
162
|
+
'meta',
|
|
163
|
+
'param',
|
|
164
|
+
'source',
|
|
165
|
+
'track',
|
|
166
|
+
'wbr',
|
|
167
|
+
]);
|
|
168
|
+
/**
|
|
169
|
+
* Renders a DOM node or an array of DOM nodes to a string.
|
|
170
|
+
*
|
|
171
|
+
* Can be thought of as the equivalent of the `outerHTML` of the passed node(s).
|
|
172
|
+
*
|
|
173
|
+
* @param node Node to be rendered.
|
|
174
|
+
* @param options Changes serialization behavior
|
|
175
|
+
*/
|
|
176
|
+
export default function render(node, options = {}) {
|
|
177
|
+
const nodes = 'length' in node ? node : [node];
|
|
178
|
+
let output = '';
|
|
179
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
180
|
+
output += renderNode(nodes[i], options);
|
|
181
|
+
}
|
|
182
|
+
return output;
|
|
183
|
+
}
|
|
184
|
+
function renderNode(node, options) {
|
|
185
|
+
switch (node.type) {
|
|
186
|
+
case ElementType.Root:
|
|
187
|
+
return render(node.children, options);
|
|
188
|
+
case ElementType.Directive:
|
|
189
|
+
case ElementType.Doctype:
|
|
190
|
+
return renderDirective(node);
|
|
191
|
+
case ElementType.Comment:
|
|
192
|
+
return renderComment(node);
|
|
193
|
+
case ElementType.CDATA:
|
|
194
|
+
return renderCdata(node);
|
|
195
|
+
case ElementType.Script:
|
|
196
|
+
case ElementType.Style:
|
|
197
|
+
case ElementType.Tag:
|
|
198
|
+
return renderTag(node, options);
|
|
199
|
+
case ElementType.Text:
|
|
200
|
+
return renderText(node, options);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const foreignModeIntegrationPoints = new Set([
|
|
204
|
+
'mi',
|
|
205
|
+
'mo',
|
|
206
|
+
'mn',
|
|
207
|
+
'ms',
|
|
208
|
+
'mtext',
|
|
209
|
+
'annotation-xml',
|
|
210
|
+
'foreignObject',
|
|
211
|
+
'desc',
|
|
212
|
+
'title',
|
|
213
|
+
]);
|
|
214
|
+
const foreignElements = new Set(['svg', 'math']);
|
|
215
|
+
function renderTag(elem, opts) {
|
|
216
|
+
// Handle SVG / MathML in HTML
|
|
217
|
+
if (opts.xmlMode === 'foreign') {
|
|
218
|
+
/* Fix up mixed-case element names */
|
|
219
|
+
elem.name = elementNames.get(elem.name) ?? elem.name;
|
|
220
|
+
/* Exit foreign mode at integration points */
|
|
221
|
+
if (elem.parent &&
|
|
222
|
+
foreignModeIntegrationPoints.has(elem.parent.name)) {
|
|
223
|
+
opts = { ...opts, xmlMode: false };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (!opts.xmlMode && foreignElements.has(elem.name)) {
|
|
227
|
+
opts = { ...opts, xmlMode: 'foreign' };
|
|
228
|
+
}
|
|
229
|
+
let tag = `<${elem.name}`;
|
|
230
|
+
const attribs = formatAttributes(elem.attribs, opts);
|
|
231
|
+
if (attribs) {
|
|
232
|
+
tag += ` ${attribs}`;
|
|
233
|
+
}
|
|
234
|
+
if (elem.children.length === 0 &&
|
|
235
|
+
(opts.xmlMode
|
|
236
|
+
? // In XML mode or foreign mode, and user hasn't explicitly turned off self-closing tags
|
|
237
|
+
opts.selfClosingTags !== false
|
|
238
|
+
: // User explicitly asked for self-closing tags, even in HTML mode
|
|
239
|
+
opts.selfClosingTags && singleTag.has(elem.name))) {
|
|
240
|
+
if (!opts.xmlMode)
|
|
241
|
+
tag += ' ';
|
|
242
|
+
tag += '/>';
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
tag += '>';
|
|
246
|
+
if (elem.children.length > 0) {
|
|
247
|
+
tag += render(elem.children, opts);
|
|
248
|
+
}
|
|
249
|
+
if (opts.xmlMode || !singleTag.has(elem.name)) {
|
|
250
|
+
tag += `</${elem.name}>`;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return tag;
|
|
254
|
+
}
|
|
255
|
+
function renderDirective(elem) {
|
|
256
|
+
return `<${elem.data}>`;
|
|
257
|
+
}
|
|
258
|
+
function renderText(elem, opts) {
|
|
259
|
+
let data = elem.data || '';
|
|
260
|
+
// If entities weren't decoded, no need to encode them back
|
|
261
|
+
if (opts.decodeEntities !== false &&
|
|
262
|
+
!(!opts.xmlMode &&
|
|
263
|
+
elem.parent &&
|
|
264
|
+
unencodedElements.has(elem.parent.name))) {
|
|
265
|
+
data = encodeXML(data);
|
|
266
|
+
}
|
|
267
|
+
return data;
|
|
268
|
+
}
|
|
269
|
+
function renderCdata(elem) {
|
|
270
|
+
return `<![CDATA[${elem.children[0].data}]]>`;
|
|
271
|
+
}
|
|
272
|
+
function renderComment(elem) {
|
|
273
|
+
return `<!--${elem.data}-->`;
|
|
274
|
+
}
|