node-html-parser
Advanced tools
Comparing version 5.2.0 to 5.2.2
388
dist/main.js
@@ -0,1 +1,4 @@ | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __extends = (this && this.__extends) || (function () { | ||
@@ -16,5 +19,2 @@ var extendStatics = function (d, b) { | ||
})(); | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __assign = (this && this.__assign) || function () { | ||
@@ -59,82 +59,33 @@ __assign = Object.assign || function(t) { | ||
}); | ||
define("nodes/text", ["require", "exports", "he", "nodes/node", "nodes/type"], function (require, exports, he_1, node_1, type_1) { | ||
define("nodes/node", ["require", "exports", "he"], function (require, exports, he_1) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
node_1 = __importDefault(node_1); | ||
type_1 = __importDefault(type_1); | ||
/** | ||
* TextNode to contain a text element in DOM tree. | ||
* @param {string} value [description] | ||
* Node Class as base class for TextNode and HTMLElement. | ||
*/ | ||
var TextNode = /** @class */ (function (_super) { | ||
__extends(TextNode, _super); | ||
function TextNode(rawText, parentNode, range) { | ||
var _this = _super.call(this, parentNode, range) || this; | ||
/** | ||
* Node Type declaration. | ||
* @type {Number} | ||
*/ | ||
_this.nodeType = type_1.default.TEXT_NODE; | ||
_this._rawText = rawText; | ||
return _this; | ||
var Node = /** @class */ (function () { | ||
function Node(parentNode, range) { | ||
if (parentNode === void 0) { parentNode = null; } | ||
this.parentNode = parentNode; | ||
this.childNodes = []; | ||
Object.defineProperty(this, 'range', { | ||
enumerable: false, | ||
writable: true, | ||
configurable: true, | ||
value: range !== null && range !== void 0 ? range : [-1, -1] | ||
}); | ||
} | ||
Object.defineProperty(TextNode.prototype, "rawText", { | ||
Object.defineProperty(Node.prototype, "innerText", { | ||
get: function () { | ||
return this._rawText; | ||
return this.rawText; | ||
}, | ||
/** | ||
* Set rawText and invalidate trimmed caches | ||
*/ | ||
set: function (text) { | ||
this._rawText = text; | ||
this._trimmedRawText = void 0; | ||
this._trimmedText = void 0; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "trimmedRawText", { | ||
/** | ||
* Returns raw text with all whitespace trimmed except single leading/trailing non-breaking space | ||
*/ | ||
Object.defineProperty(Node.prototype, "textContent", { | ||
get: function () { | ||
if (this._trimmedRawText !== undefined) | ||
return this._trimmedRawText; | ||
this._trimmedRawText = trimText(this.rawText); | ||
return this._trimmedRawText; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "trimmedText", { | ||
/** | ||
* Returns text with all whitespace trimmed except single leading/trailing non-breaking space | ||
*/ | ||
get: function () { | ||
if (this._trimmedText !== undefined) | ||
return this._trimmedText; | ||
this._trimmedText = trimText(this.text); | ||
return this._trimmedText; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "text", { | ||
/** | ||
* Get unescaped text value of current node and its children. | ||
* @return {string} text content | ||
*/ | ||
get: function () { | ||
return (0, he_1.decode)(this.rawText); | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "isWhitespace", { | ||
/** | ||
* Detect if the node contains only white space. | ||
* @return {boolean} | ||
*/ | ||
get: function () { | ||
return /^(\s| )*$/.test(this.rawText); | ||
set: function (val) { | ||
this.rawText = (0, he_1.encode)(val); | ||
}, | ||
@@ -144,46 +95,12 @@ enumerable: false, | ||
}); | ||
TextNode.prototype.toString = function () { | ||
return this.rawText; | ||
}; | ||
return TextNode; | ||
}(node_1.default)); | ||
exports.default = TextNode; | ||
/** | ||
* Trim whitespace except single leading/trailing non-breaking space | ||
*/ | ||
function trimText(text) { | ||
var i = 0; | ||
var startPos; | ||
var endPos; | ||
while (i >= 0 && i < text.length) { | ||
if (/\S/.test(text[i])) { | ||
if (startPos === undefined) { | ||
startPos = i; | ||
i = text.length; | ||
} | ||
else { | ||
endPos = i; | ||
i = void 0; | ||
} | ||
} | ||
if (startPos === undefined) | ||
i++; | ||
else | ||
i--; | ||
} | ||
if (startPos === undefined) | ||
startPos = 0; | ||
if (endPos === undefined) | ||
endPos = text.length - 1; | ||
var hasLeadingSpace = startPos > 0 && /[^\S\r\n]/.test(text[startPos - 1]); | ||
var hasTrailingSpace = endPos < (text.length - 1) && /[^\S\r\n]/.test(text[endPos + 1]); | ||
return (hasLeadingSpace ? ' ' : '') + text.slice(startPos, endPos + 1) + (hasTrailingSpace ? ' ' : ''); | ||
} | ||
return Node; | ||
}()); | ||
exports.default = Node; | ||
}); | ||
define("matcher", ["require", "exports", "nodes/type"], function (require, exports, type_2) { | ||
define("matcher", ["require", "exports", "nodes/type"], function (require, exports, type_1) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
type_2 = __importDefault(type_2); | ||
type_1 = __importDefault(type_1); | ||
function isTag(node) { | ||
return node && node.nodeType === type_2.default.ELEMENT_NODE; | ||
return node && node.nodeType === type_1.default.ELEMENT_NODE; | ||
} | ||
@@ -288,17 +205,142 @@ function getAttributeValue(elem, name) { | ||
}); | ||
define("nodes/html", ["require", "exports", "he", "css-select", "nodes/node", "nodes/type", "nodes/text", "matcher", "back", "nodes/comment"], function (require, exports, he_2, css_select_1, node_2, type_3, text_1, matcher_1, back_1, comment_1) { | ||
define("nodes/text", ["require", "exports", "he", "nodes/node", "nodes/type"], function (require, exports, he_2, node_1, type_2) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
node_1 = __importDefault(node_1); | ||
type_2 = __importDefault(type_2); | ||
/** | ||
* TextNode to contain a text element in DOM tree. | ||
* @param {string} value [description] | ||
*/ | ||
var TextNode = /** @class */ (function (_super) { | ||
__extends(TextNode, _super); | ||
function TextNode(rawText, parentNode, range) { | ||
var _this = _super.call(this, parentNode, range) || this; | ||
/** | ||
* Node Type declaration. | ||
* @type {Number} | ||
*/ | ||
_this.nodeType = type_2.default.TEXT_NODE; | ||
_this._rawText = rawText; | ||
return _this; | ||
} | ||
TextNode.prototype.clone = function () { | ||
return new TextNode(this._rawText, null); | ||
}; | ||
Object.defineProperty(TextNode.prototype, "rawText", { | ||
get: function () { | ||
return this._rawText; | ||
}, | ||
/** | ||
* Set rawText and invalidate trimmed caches | ||
*/ | ||
set: function (text) { | ||
this._rawText = text; | ||
this._trimmedRawText = void 0; | ||
this._trimmedText = void 0; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "trimmedRawText", { | ||
/** | ||
* Returns raw text with all whitespace trimmed except single leading/trailing non-breaking space | ||
*/ | ||
get: function () { | ||
if (this._trimmedRawText !== undefined) | ||
return this._trimmedRawText; | ||
this._trimmedRawText = trimText(this.rawText); | ||
return this._trimmedRawText; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "trimmedText", { | ||
/** | ||
* Returns text with all whitespace trimmed except single leading/trailing non-breaking space | ||
*/ | ||
get: function () { | ||
if (this._trimmedText !== undefined) | ||
return this._trimmedText; | ||
this._trimmedText = trimText(this.text); | ||
return this._trimmedText; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "text", { | ||
/** | ||
* Get unescaped text value of current node and its children. | ||
* @return {string} text content | ||
*/ | ||
get: function () { | ||
return (0, he_2.decode)(this.rawText); | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TextNode.prototype, "isWhitespace", { | ||
/** | ||
* Detect if the node contains only white space. | ||
* @return {boolean} | ||
*/ | ||
get: function () { | ||
return /^(\s| )*$/.test(this.rawText); | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
TextNode.prototype.toString = function () { | ||
return this.rawText; | ||
}; | ||
return TextNode; | ||
}(node_1.default)); | ||
exports.default = TextNode; | ||
/** | ||
* Trim whitespace except single leading/trailing non-breaking space | ||
*/ | ||
function trimText(text) { | ||
var i = 0; | ||
var startPos; | ||
var endPos; | ||
while (i >= 0 && i < text.length) { | ||
if (/\S/.test(text[i])) { | ||
if (startPos === undefined) { | ||
startPos = i; | ||
i = text.length; | ||
} | ||
else { | ||
endPos = i; | ||
i = void 0; | ||
} | ||
} | ||
if (startPos === undefined) | ||
i++; | ||
else | ||
i--; | ||
} | ||
if (startPos === undefined) | ||
startPos = 0; | ||
if (endPos === undefined) | ||
endPos = text.length - 1; | ||
var hasLeadingSpace = startPos > 0 && /[^\S\r\n]/.test(text[startPos - 1]); | ||
var hasTrailingSpace = endPos < (text.length - 1) && /[^\S\r\n]/.test(text[endPos + 1]); | ||
return (hasLeadingSpace ? ' ' : '') + text.slice(startPos, endPos + 1) + (hasTrailingSpace ? ' ' : ''); | ||
} | ||
}); | ||
define("nodes/html", ["require", "exports", "css-select", "he", "back", "matcher", "nodes/comment", "nodes/node", "nodes/text", "nodes/type"], function (require, exports, css_select_1, he_3, back_1, matcher_1, comment_1, node_2, text_1, type_3) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parse = exports.base_parse = void 0; | ||
he_2 = __importDefault(he_2); | ||
he_3 = __importDefault(he_3); | ||
back_1 = __importDefault(back_1); | ||
matcher_1 = __importDefault(matcher_1); | ||
comment_1 = __importDefault(comment_1); | ||
node_2 = __importDefault(node_2); | ||
text_1 = __importDefault(text_1); | ||
type_3 = __importDefault(type_3); | ||
text_1 = __importDefault(text_1); | ||
matcher_1 = __importDefault(matcher_1); | ||
back_1 = __importDefault(back_1); | ||
comment_1 = __importDefault(comment_1); | ||
var voidTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']); | ||
function decode(val) { | ||
// clone string | ||
return JSON.parse(JSON.stringify(he_2.default.decode(val))); | ||
return JSON.parse(JSON.stringify(he_3.default.decode(val))); | ||
} | ||
@@ -1116,2 +1158,41 @@ // https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements | ||
}); | ||
Object.defineProperty(HTMLElement.prototype, "previousSibling", { | ||
get: function () { | ||
if (this.parentNode) { | ||
var children = this.parentNode.childNodes; | ||
var i = children.length; | ||
while (i > 0) { | ||
var child = children[--i]; | ||
if (this === child) | ||
return children[i - 1] || null; | ||
} | ||
return null; | ||
} | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLElement.prototype, "previousElementSibling", { | ||
get: function () { | ||
if (this.parentNode) { | ||
var children = this.parentNode.childNodes; | ||
var i = children.length; | ||
var find = false; | ||
while (i > 0) { | ||
var child = children[--i]; | ||
if (find) { | ||
if (child instanceof HTMLElement) { | ||
return child || null; | ||
} | ||
} | ||
else if (this === child) { | ||
find = true; | ||
} | ||
} | ||
return null; | ||
} | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLElement.prototype, "classNames", { | ||
@@ -1124,2 +1205,8 @@ get: function () { | ||
}); | ||
/** | ||
* Clone this Node | ||
*/ | ||
HTMLElement.prototype.clone = function () { | ||
return parse(this.toString()).firstChild; | ||
}; | ||
return HTMLElement; | ||
@@ -1368,14 +1455,21 @@ }(node_2.default)); | ||
// Pair error case <h3> <h3> handle : Fixes to <h3> </h3> | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.parentNode.appendChild(child); | ||
}); | ||
stack.pop(); | ||
// this is wrong, becouse this will put the H3 outside the current right position which should be inside the current Html Element, see issue 152 for more info | ||
if (options.parseNoneClosedTags !== true) { | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.parentNode.appendChild(child); | ||
}); | ||
stack.pop(); | ||
} | ||
} | ||
else { | ||
// Single error <div> <h3> </div> handle: Just removes <h3> | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.appendChild(child); | ||
}); | ||
// Why remove? this is already a HtmlElement and the missing <H3> is already added in this case. see issue 152 for more info | ||
// eslint-disable-next-line no-lonely-if | ||
if (options.parseNoneClosedTags !== true) { | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.appendChild(child); | ||
}); | ||
} | ||
} | ||
@@ -1399,41 +1493,2 @@ } | ||
}); | ||
define("nodes/node", ["require", "exports", "he"], function (require, exports, he_3) { | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* Node Class as base class for TextNode and HTMLElement. | ||
*/ | ||
var Node = /** @class */ (function () { | ||
function Node(parentNode, range) { | ||
if (parentNode === void 0) { parentNode = null; } | ||
this.parentNode = parentNode; | ||
this.childNodes = []; | ||
Object.defineProperty(this, 'range', { | ||
enumerable: false, | ||
writable: true, | ||
configurable: true, | ||
value: range !== null && range !== void 0 ? range : [-1, -1] | ||
}); | ||
} | ||
Object.defineProperty(Node.prototype, "innerText", { | ||
get: function () { | ||
return this.rawText; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Node.prototype, "textContent", { | ||
get: function () { | ||
return (0, he_3.decode)(this.rawText); | ||
}, | ||
set: function (val) { | ||
this.rawText = (0, he_3.encode)(val); | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return Node; | ||
}()); | ||
exports.default = Node; | ||
}); | ||
define("nodes/comment", ["require", "exports", "nodes/node", "nodes/type"], function (require, exports, node_3, type_4) { | ||
@@ -1456,2 +1511,5 @@ "use strict"; | ||
} | ||
CommentNode.prototype.clone = function () { | ||
return new CommentNode(this.rawText, null); | ||
}; | ||
Object.defineProperty(CommentNode.prototype, "text", { | ||
@@ -1458,0 +1516,0 @@ /** |
@@ -0,6 +1,7 @@ | ||
import HTMLElement from './html'; | ||
import Node from './node'; | ||
import NodeType from './type'; | ||
import HTMLElement from './html'; | ||
export default class CommentNode extends Node { | ||
rawText: string; | ||
clone(): CommentNode; | ||
constructor(rawText: string, parentNode: HTMLElement, range?: [number, number]); | ||
@@ -7,0 +8,0 @@ /** |
@@ -35,2 +35,5 @@ "use strict"; | ||
} | ||
CommentNode.prototype.clone = function () { | ||
return new CommentNode(this.rawText, null); | ||
}; | ||
Object.defineProperty(CommentNode.prototype, "text", { | ||
@@ -37,0 +40,0 @@ /** |
@@ -192,3 +192,9 @@ import Node from './node'; | ||
get nextElementSibling(): HTMLElement; | ||
get previousSibling(): Node; | ||
get previousElementSibling(): HTMLElement; | ||
get classNames(): string; | ||
/** | ||
* Clone this Node | ||
*/ | ||
clone(): Node; | ||
} | ||
@@ -198,2 +204,3 @@ export interface Options { | ||
comment: boolean; | ||
parseNoneClosedTags?: boolean; | ||
blockTextElements: { | ||
@@ -200,0 +207,0 @@ [tag: string]: boolean; |
@@ -42,10 +42,10 @@ "use strict"; | ||
exports.parse = exports.base_parse = void 0; | ||
var css_select_1 = require("css-select"); | ||
var he_1 = __importDefault(require("he")); | ||
var css_select_1 = require("css-select"); | ||
var back_1 = __importDefault(require("../back")); | ||
var matcher_1 = __importDefault(require("../matcher")); | ||
var comment_1 = __importDefault(require("./comment")); | ||
var node_1 = __importDefault(require("./node")); | ||
var text_1 = __importDefault(require("./text")); | ||
var type_1 = __importDefault(require("./type")); | ||
var text_1 = __importDefault(require("./text")); | ||
var matcher_1 = __importDefault(require("../matcher")); | ||
var back_1 = __importDefault(require("../back")); | ||
var comment_1 = __importDefault(require("./comment")); | ||
var voidTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']); | ||
@@ -867,2 +867,41 @@ function decode(val) { | ||
}); | ||
Object.defineProperty(HTMLElement.prototype, "previousSibling", { | ||
get: function () { | ||
if (this.parentNode) { | ||
var children = this.parentNode.childNodes; | ||
var i = children.length; | ||
while (i > 0) { | ||
var child = children[--i]; | ||
if (this === child) | ||
return children[i - 1] || null; | ||
} | ||
return null; | ||
} | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLElement.prototype, "previousElementSibling", { | ||
get: function () { | ||
if (this.parentNode) { | ||
var children = this.parentNode.childNodes; | ||
var i = children.length; | ||
var find = false; | ||
while (i > 0) { | ||
var child = children[--i]; | ||
if (find) { | ||
if (child instanceof HTMLElement) { | ||
return child || null; | ||
} | ||
} | ||
else if (this === child) { | ||
find = true; | ||
} | ||
} | ||
return null; | ||
} | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLElement.prototype, "classNames", { | ||
@@ -875,2 +914,8 @@ get: function () { | ||
}); | ||
/** | ||
* Clone this Node | ||
*/ | ||
HTMLElement.prototype.clone = function () { | ||
return parse(this.toString()).firstChild; | ||
}; | ||
return HTMLElement; | ||
@@ -1119,14 +1164,21 @@ }(node_1.default)); | ||
// Pair error case <h3> <h3> handle : Fixes to <h3> </h3> | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.parentNode.appendChild(child); | ||
}); | ||
stack.pop(); | ||
// this is wrong, becouse this will put the H3 outside the current right position which should be inside the current Html Element, see issue 152 for more info | ||
if (options.parseNoneClosedTags !== true) { | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.parentNode.appendChild(child); | ||
}); | ||
stack.pop(); | ||
} | ||
} | ||
else { | ||
// Single error <div> <h3> </div> handle: Just removes <h3> | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.appendChild(child); | ||
}); | ||
// Why remove? this is already a HtmlElement and the missing <H3> is already added in this case. see issue 152 for more info | ||
// eslint-disable-next-line no-lonely-if | ||
if (options.parseNoneClosedTags !== true) { | ||
oneBefore.removeChild(last); | ||
last.childNodes.forEach(function (child) { | ||
oneBefore.appendChild(child); | ||
}); | ||
} | ||
} | ||
@@ -1133,0 +1185,0 @@ } |
@@ -14,2 +14,3 @@ import NodeType from './type'; | ||
abstract toString(): string; | ||
abstract clone(): Node; | ||
constructor(parentNode?: HTMLElement, range?: [number, number]); | ||
@@ -16,0 +17,0 @@ get innerText(): string; |
@@ -9,2 +9,3 @@ import HTMLElement from './html'; | ||
export default class TextNode extends Node { | ||
clone(): TextNode; | ||
constructor(rawText: string, parentNode: HTMLElement, range?: [number, number]); | ||
@@ -11,0 +12,0 @@ /** |
@@ -40,2 +40,5 @@ "use strict"; | ||
} | ||
TextNode.prototype.clone = function () { | ||
return new TextNode(this._rawText, null); | ||
}; | ||
Object.defineProperty(TextNode.prototype, "rawText", { | ||
@@ -42,0 +45,0 @@ get: function () { |
{ | ||
"name": "node-html-parser", | ||
"version": "5.2.0", | ||
"version": "5.2.2", | ||
"description": "A very fast HTML parser, generating a simplified DOM, with basic element query support.", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
"require": "./dist/index.js", | ||
"import": "./esm/index.js", | ||
"types": "./dist/index.d.ts" | ||
}, | ||
"scripts": { | ||
@@ -51,3 +56,3 @@ "compile": "tsc", | ||
"dependencies": { | ||
"css-select": "^4.1.3", | ||
"css-select": "^4.2.1", | ||
"he": "1.2.0" | ||
@@ -113,7 +118,3 @@ }, | ||
"homepage": "https://github.com/taoqf/node-fast-html-parser", | ||
"sideEffects": false, | ||
"exports": { | ||
"require": "./dist/index.js", | ||
"import": "./esm/index.js" | ||
} | ||
"sideEffects": false | ||
} |
@@ -202,2 +202,6 @@ # Fast HTML Parser [![NPM version](https://badge.fury.io/js/node-html-parser.png)](http://badge.fury.io/js/node-html-parser) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Ftaoqf%2Fnode-html-parser%2Fbadge%3Fref%3Dmain&style=flat)](https://actions-badge.atrox.dev/taoqf/node-html-parser/goto?ref=main) | ||
#### Node#clone() | ||
Clone a node. | ||
## HTMLElement Properties | ||
@@ -251,2 +255,10 @@ | ||
### HTMLElement#previousSibling | ||
Returns a reference to the previous child node of the current element's parent. | ||
### HTMLElement#previousElementSibling | ||
Returns a reference to the previous child element of the current element's parent. | ||
### HTMLElement#textContent | ||
@@ -253,0 +265,0 @@ |
146722
3484
277
Updatedcss-select@^4.2.1