Skip to content

Commit 4328e52

Browse files
authored
Bump domhandler, dom-serializer (#995)
1 parent 866ac40 commit 4328e52

File tree

13 files changed

+761
-664
lines changed

13 files changed

+761
-664
lines changed

package-lock.json

Lines changed: 649 additions & 578 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@
3636
"htmlparser2"
3737
],
3838
"dependencies": {
39-
"dom-serializer": "^1.0.1",
39+
"dom-serializer": "^2.0.0",
4040
"domelementtype": "^2.3.0",
41-
"domhandler": "^4.3.1"
41+
"domhandler": "^5.0.1"
4242
},
4343
"devDependencies": {
4444
"@types/jest": "^27.4.1",

src/__fixtures__/fixture.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1-
import { parseDOM } from "htmlparser2";
1+
import { Parser, ParserOptions } from "htmlparser2";
2+
import DomHandler, { Document } from "domhandler";
3+
4+
/**
5+
* Re-implementation of htmlparser2's `parseDocument` function.
6+
*
7+
* @param str String to parse.
8+
* @param options Optional parser options to use.
9+
* @returns The parsed document.
10+
*/
11+
export function parseDocument(str: string, options?: ParserOptions): Document {
12+
const handler = new DomHandler();
13+
new Parser(handler, options).end(str);
14+
return handler.root;
15+
}
16+
217
const markup = Array(21).join(
318
"<?xml><tag1 id='asdf'> <script>text</script> <!-- comment --> <tag2> text </tag1>"
419
);
520

6-
export default parseDOM(markup);
21+
export default parseDocument(markup).children;

src/feeds.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { getFeed } from "./feeds";
44
import fs from "fs";
55
import path from "path";
6-
import { parseDocument } from "htmlparser2";
6+
import { parseDocument } from "./__fixtures__/fixture";
77

88
const documents = path.join(__dirname, "__fixtures__", "Documents");
99

src/feeds.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Node, Element } from "domhandler";
1+
import type { AnyNode, Element } from "domhandler";
22
import { textContent } from "./stringify";
33
import { getElementsByTagName } from "./legacy";
44

@@ -80,7 +80,7 @@ export interface Feed {
8080
* @param doc - The DOM to to extract the feed from.
8181
* @returns The feed.
8282
*/
83-
export function getFeed(doc: Node[]): Feed | null {
83+
export function getFeed(doc: AnyNode[]): Feed | null {
8484
const feedRoot = getOneElement(isValidFeed, doc);
8585

8686
return !feedRoot
@@ -206,7 +206,7 @@ const MEDIA_KEYS_INT = [
206206
* @param where Nodes to search in.
207207
* @returns Media elements.
208208
*/
209-
function getMediaElements(where: Node | Node[]): FeedItemMedia[] {
209+
function getMediaElements(where: AnyNode[]): FeedItemMedia[] {
210210
return getElementsByTagName("media:content", where).map((elem) => {
211211
const { attribs } = elem;
212212

@@ -247,7 +247,7 @@ function getMediaElements(where: Node | Node[]): FeedItemMedia[] {
247247
*/
248248
function getOneElement(
249249
tagName: string | ((name: string) => boolean),
250-
node: Node | Node[]
250+
node: AnyNode[]
251251
): Element | null {
252252
return getElementsByTagName(tagName, node, true, 1)[0];
253253
}
@@ -260,7 +260,11 @@ function getOneElement(
260260
* @param recurse Whether to recurse into child nodes.
261261
* @returns The text content of the element.
262262
*/
263-
function fetch(tagName: string, where: Node | Node[], recurse = false): string {
263+
function fetch(
264+
tagName: string,
265+
where: AnyNode | AnyNode[],
266+
recurse = false
267+
): string {
264268
return textContent(getElementsByTagName(tagName, where, recurse, 1)).trim();
265269
}
266270

@@ -277,7 +281,7 @@ function addConditionally<T>(
277281
obj: T,
278282
prop: keyof T,
279283
tagName: string,
280-
where: Node | Node[],
284+
where: AnyNode[],
281285
recurse = false
282286
) {
283287
const val = fetch(tagName, where, recurse);

src/helpers.spec.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { parseDOM, parseDocument } from "htmlparser2";
1+
import { parseDocument } from "./__fixtures__/fixture";
22
import { removeSubsets, compareDocumentPosition, uniqueSort } from "./helpers";
33
import type { Element, Document } from "domhandler";
44

55
describe("helpers", () => {
66
describe("removeSubsets", () => {
7-
const dom = parseDOM(
8-
"<div><p><span></span></p><p></p></div>"
9-
)[0] as Element;
7+
const dom = parseDocument("<div><p><span></span></p><p></p></div>")
8+
.children[0] as Element;
109

1110
it("removes identical trees", () =>
1211
expect(removeSubsets([dom, dom])).toHaveLength(1));
@@ -28,7 +27,7 @@ describe("helpers", () => {
2827

2928
describe("compareDocumentPosition", () => {
3029
const markup = "<div><p><span></span></p><a></a></div>";
31-
const dom = parseDOM(markup)[0] as Element;
30+
const dom = parseDocument(markup).children[0] as Element;
3231
const p = dom.children[0] as Element;
3332
const span = p.children[0];
3433
const a = dom.children[1];
@@ -46,7 +45,7 @@ describe("helpers", () => {
4645
expect(compareDocumentPosition(span, p)).toBe(20));
4746

4847
it("reports when the nodes belong to separate documents", () => {
49-
const otherDom = parseDOM(markup)[0] as Element;
48+
const otherDom = parseDocument(markup).children[0] as Element;
5049
const other = (otherDom.children[0] as Element).children[0];
5150

5251
expect(compareDocumentPosition(span, other)).toBe(1);
@@ -56,9 +55,8 @@ describe("helpers", () => {
5655
expect(compareDocumentPosition(span, span)).toBe(0));
5756

5857
it("does not end up in infinite loop (#109)", () => {
59-
const dom = parseDOM(
60-
"<div><span>1</span><span>2</span></div>"
61-
)[0] as Element;
58+
const dom = parseDocument("<div><span>1</span><span>2</span></div>")
59+
.children[0] as Element;
6260

6361
expect(
6462
compareDocumentPosition(

src/helpers.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { hasChildren, Node } from "domhandler";
1+
import { hasChildren, AnyNode, ParentNode } from "domhandler";
22

33
/**
44
* Given an array of nodes, remove any member that is contained by another.
@@ -7,7 +7,7 @@ import { hasChildren, Node } from "domhandler";
77
* @param nodes Nodes to filter.
88
* @returns Remaining nodes that aren't subtrees of each other.
99
*/
10-
export function removeSubsets(nodes: Node[]): Node[] {
10+
export function removeSubsets(nodes: AnyNode[]): AnyNode[] {
1111
let idx = nodes.length;
1212

1313
/*
@@ -75,9 +75,12 @@ export const enum DocumentPosition {
7575
* See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for
7676
* a description of these values.
7777
*/
78-
export function compareDocumentPosition(nodeA: Node, nodeB: Node): number {
79-
const aParents = [];
80-
const bParents = [];
78+
export function compareDocumentPosition(
79+
nodeA: AnyNode,
80+
nodeB: AnyNode
81+
): number {
82+
const aParents: ParentNode[] = [];
83+
const bParents: ParentNode[] = [];
8184

8285
if (nodeA === nodeB) {
8386
return 0;
@@ -105,7 +108,7 @@ export function compareDocumentPosition(nodeA: Node, nodeB: Node): number {
105108
}
106109

107110
const sharedParent = aParents[idx - 1];
108-
const siblings = sharedParent.children;
111+
const siblings: AnyNode[] = sharedParent.children;
109112
const aSibling = aParents[idx];
110113
const bSibling = bParents[idx];
111114

@@ -130,7 +133,7 @@ export function compareDocumentPosition(nodeA: Node, nodeB: Node): number {
130133
* @param nodes Array of DOM nodes.
131134
* @returns Collection of unique nodes, sorted in document order.
132135
*/
133-
export function uniqueSort<T extends Node>(nodes: T[]): T[] {
136+
export function uniqueSort<T extends AnyNode>(nodes: T[]): T[] {
134137
nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
135138

136139
nodes.sort((a, b) => {

src/legacy.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import {
66
getElementsByTagName,
77
getElementsByTagType,
88
} from "./legacy";
9-
import type { Node, Element } from "domhandler";
9+
import type { AnyNode, Element } from "domhandler";
1010

1111
describe("legacy", () => {
1212
// Set up expected structures
1313
const expected = {
1414
idAsdf: fixture[1] as Element,
15-
tag2: [] as Node[],
16-
typeScript: [] as Node[],
15+
tag2: [] as AnyNode[],
16+
typeScript: [] as AnyNode[],
1717
};
1818

1919
beforeAll(() => {

src/legacy.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { isTag, isText, Node, Element } from "domhandler";
1+
import { isTag, isText, AnyNode, Element } from "domhandler";
22
import { ElementType } from "domelementtype";
33
import { filter, findOne } from "./querying";
44

5-
type TestType = (elem: Node) => boolean;
5+
type TestType = (elem: AnyNode) => boolean;
66

77
/**
88
* An object with keys to check elements against. If a key is `tag_name`,
@@ -27,23 +27,23 @@ const Checks: Record<
2727
> = {
2828
tag_name(name) {
2929
if (typeof name === "function") {
30-
return (elem: Node) => isTag(elem) && name(elem.name);
30+
return (elem: AnyNode) => isTag(elem) && name(elem.name);
3131
} else if (name === "*") {
3232
return isTag;
3333
}
34-
return (elem: Node) => isTag(elem) && elem.name === name;
34+
return (elem: AnyNode) => isTag(elem) && elem.name === name;
3535
},
3636
tag_type(type) {
3737
if (typeof type === "function") {
38-
return (elem: Node) => type(elem.type);
38+
return (elem: AnyNode) => type(elem.type);
3939
}
40-
return (elem: Node) => elem.type === type;
40+
return (elem: AnyNode) => elem.type === type;
4141
},
4242
tag_contains(data) {
4343
if (typeof data === "function") {
44-
return (elem: Node) => isText(elem) && data(elem.data);
44+
return (elem: AnyNode) => isText(elem) && data(elem.data);
4545
}
46-
return (elem: Node) => isText(elem) && elem.data === data;
46+
return (elem: AnyNode) => isText(elem) && elem.data === data;
4747
},
4848
};
4949

@@ -58,9 +58,9 @@ function getAttribCheck(
5858
value: undefined | string | ((value: string) => boolean)
5959
): TestType {
6060
if (typeof value === "function") {
61-
return (elem: Node) => isTag(elem) && value(elem.attribs[attrib]);
61+
return (elem: AnyNode) => isTag(elem) && value(elem.attribs[attrib]);
6262
}
63-
return (elem: Node) => isTag(elem) && elem.attribs[attrib] === value;
63+
return (elem: AnyNode) => isTag(elem) && elem.attribs[attrib] === value;
6464
}
6565

6666
/**
@@ -70,7 +70,7 @@ function getAttribCheck(
7070
* functions returns `true` for the node.
7171
*/
7272
function combineFuncs(a: TestType, b: TestType): TestType {
73-
return (elem: Node) => a(elem) || b(elem);
73+
return (elem: AnyNode) => a(elem) || b(elem);
7474
}
7575

7676
/**
@@ -95,7 +95,7 @@ function compileTest(options: TestElementOpts): TestType | null {
9595
* @param node The element to test.
9696
* @returns Whether the element matches the description in `options`.
9797
*/
98-
export function testElement(options: TestElementOpts, node: Node): boolean {
98+
export function testElement(options: TestElementOpts, node: AnyNode): boolean {
9999
const test = compileTest(options);
100100
return test ? test(node) : true;
101101
}
@@ -110,10 +110,10 @@ export function testElement(options: TestElementOpts, node: Node): boolean {
110110
*/
111111
export function getElements(
112112
options: TestElementOpts,
113-
nodes: Node | Node[],
113+
nodes: AnyNode | AnyNode[],
114114
recurse: boolean,
115115
limit = Infinity
116-
): Node[] {
116+
): AnyNode[] {
117117
const test = compileTest(options);
118118
return test ? filter(test, nodes, recurse, limit) : [];
119119
}
@@ -127,7 +127,7 @@ export function getElements(
127127
*/
128128
export function getElementById(
129129
id: string | ((id: string) => boolean),
130-
nodes: Node | Node[],
130+
nodes: AnyNode | AnyNode[],
131131
recurse = true
132132
): Element | null {
133133
if (!Array.isArray(nodes)) nodes = [nodes];
@@ -144,7 +144,7 @@ export function getElementById(
144144
*/
145145
export function getElementsByTagName(
146146
tagName: string | ((name: string) => boolean),
147-
nodes: Node | Node[],
147+
nodes: AnyNode | AnyNode[],
148148
recurse = true,
149149
limit = Infinity
150150
): Element[] {
@@ -161,9 +161,9 @@ export function getElementsByTagName(
161161
*/
162162
export function getElementsByTagType(
163163
type: ElementType | ((type: ElementType) => boolean),
164-
nodes: Node | Node[],
164+
nodes: AnyNode | AnyNode[],
165165
recurse = true,
166166
limit = Infinity
167-
): Node[] {
167+
): AnyNode[] {
168168
return filter(Checks.tag_type(type as string), nodes, recurse, limit);
169169
}

src/manipulation.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { Node, Element } from "domhandler";
1+
import type { ChildNode, Element } from "domhandler";
22

33
/**
44
* Remove an element from the dom
55
*
66
* @category Manipulation
77
* @param elem The element to be removed
88
*/
9-
export function removeElement(elem: Node): void {
9+
export function removeElement(elem: ChildNode): void {
1010
if (elem.prev) elem.prev.next = elem.next;
1111
if (elem.next) elem.next.prev = elem.prev;
1212

@@ -23,7 +23,7 @@ export function removeElement(elem: Node): void {
2323
* @param elem The element to be replaced
2424
* @param replacement The element to be added
2525
*/
26-
export function replaceElement(elem: Node, replacement: Node): void {
26+
export function replaceElement(elem: ChildNode, replacement: ChildNode): void {
2727
const prev = (replacement.prev = elem.prev);
2828
if (prev) {
2929
prev.next = replacement;
@@ -48,7 +48,7 @@ export function replaceElement(elem: Node, replacement: Node): void {
4848
* @param elem The element to append to.
4949
* @param child The element to be added as a child.
5050
*/
51-
export function appendChild(elem: Element, child: Node): void {
51+
export function appendChild(elem: Element, child: ChildNode): void {
5252
removeElement(child);
5353

5454
child.next = null;
@@ -70,7 +70,7 @@ export function appendChild(elem: Element, child: Node): void {
7070
* @param elem The element to append after.
7171
* @param next The element be added.
7272
*/
73-
export function append(elem: Node, next: Node): void {
73+
export function append(elem: ChildNode, next: ChildNode): void {
7474
removeElement(next);
7575

7676
const { parent } = elem;
@@ -99,7 +99,7 @@ export function append(elem: Node, next: Node): void {
9999
* @param elem The element to prepend before.
100100
* @param child The element to be added as a child.
101101
*/
102-
export function prependChild(elem: Element, child: Node): void {
102+
export function prependChild(elem: Element, child: ChildNode): void {
103103
removeElement(child);
104104

105105
child.parent = elem;
@@ -121,7 +121,7 @@ export function prependChild(elem: Element, child: Node): void {
121121
* @param elem The element to prepend before.
122122
* @param prev The element be added.
123123
*/
124-
export function prepend(elem: Node, prev: Node): void {
124+
export function prepend(elem: ChildNode, prev: ChildNode): void {
125125
removeElement(prev);
126126

127127
const { parent } = elem;

0 commit comments

Comments
 (0)