-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathparse.ts
105 lines (91 loc) · 2.41 KB
/
parse.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { removeElement } from 'domutils';
import {
type AnyNode,
Document,
type ParentNode,
isDocument as checkIsDocument,
} from 'domhandler';
import type { InternalOptions } from './options.js';
/**
* Get the parse function with options.
*
* @param parser - The parser function.
* @returns The parse function with options.
*/
export function getParse(
parser: (
content: string,
options: InternalOptions,
isDocument: boolean,
context: ParentNode | null,
) => Document,
) {
/**
* Parse a HTML string or a node.
*
* @param content - The HTML string or node.
* @param options - The parser options.
* @param isDocument - If `content` is a document.
* @param context - The context node in the DOM tree.
* @returns The parsed document node.
*/
return function parse(
content: string | Document | AnyNode | AnyNode[] | Buffer,
options: InternalOptions,
isDocument: boolean,
context: ParentNode | null,
): Document {
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(content)) {
content = content.toString();
}
if (typeof content === 'string') {
return parser(content, options, isDocument, context);
}
const doc = content as AnyNode | AnyNode[] | Document;
if (!Array.isArray(doc) && checkIsDocument(doc)) {
// If `doc` is already a root, just return it
return doc;
}
// Add conent to new root element
const root = new Document([]);
// Update the DOM using the root
update(doc, root);
return root;
};
}
/**
* Update the dom structure, for one changed layer.
*
* @param newChilds - The new children.
* @param parent - The new parent.
* @returns The parent node.
*/
export function update(
newChilds: AnyNode[] | AnyNode,
parent: ParentNode | null,
): ParentNode | null {
// Normalize
const arr = Array.isArray(newChilds) ? newChilds : [newChilds];
// Update parent
if (parent) {
parent.children = arr;
} else {
parent = null;
}
// Update neighbors
for (let i = 0; i < arr.length; i++) {
const node = arr[i];
// Cleanly remove existing nodes from their previous structures.
if (node.parent && node.parent.children !== arr) {
removeElement(node);
}
if (parent) {
node.prev = arr[i - 1] || null;
node.next = arr[i + 1] || null;
} else {
node.prev = node.next = null;
}
node.parent = parent;
}
return parent;
}