diff --git a/src/js/matcher.js b/src/js/matcher.js index 9f713a51..f1ea6f0a 100644 --- a/src/js/matcher.js +++ b/src/js/matcher.js @@ -267,81 +267,87 @@ export class Matcher { } } if (parentNode) { - const arr = [].slice.call(parentNode.childNodes) - .filter(n => n.nodeType === ELEMENT_NODE); + const arr = [].slice.call(parentNode.children); const l = arr.length; - const selectorNodes = new Set(); - if (selectorBranches) { - for (const refNode of arr) { - let bool; - for (const leaves of selectorBranches) { - bool = this._matchLeaves(leaves, refNode); - if (!bool) { - break; - } - } - if (bool) { - selectorNodes.add(refNode); - } - } - } - if (reverse) { - arr.reverse(); - } - // :first-child, :last-child, :nth-child(0 of S) - if (a === 0) { - if (b > 0 && b <= l) { - if (selectorNodes.size) { - for (const current of arr) { - if (selectorNodes.has(current)) { - matched.add(current); + if (l) { + const selectorNodes = new Set(); + if (selectorBranches) { + const branchesLen = selectorBranches.length; + for (const refNode of arr) { + let bool; + for (let i = 0; i < branchesLen; i++) { + const leaves = selectorBranches[i]; + bool = this._matchLeaves(leaves, refNode); + if (!bool) { break; } } - } else if (!selector) { - const current = arr[b - 1]; - matched.add(current); + if (bool) { + selectorNodes.add(refNode); + } } } - // :nth-child() - } else { - let nth = b - 1; - if (a > 0) { - while (nth < 0) { - nth += a; - } + if (reverse) { + arr.reverse(); } - if (nth >= 0 && nth < l) { - let j = a > 0 ? 0 : b - 1; - for (let i = 0; i < l && nth >= 0 && nth < l; i++) { - const current = arr[i]; + // :first-child, :last-child, :nth-child(0 of S) + if (a === 0) { + if (b > 0 && b <= l) { if (selectorNodes.size) { - if (selectorNodes.has(current)) { - if (j === nth) { + for (let i = 0; i < l; i++) { + const current = arr[i]; + if (selectorNodes.has(current)) { matched.add(current); - nth += a; - } - if (a > 0) { - j++; - } else { - j--; + break; } } - } else if (i === nth) { - if (!selector) { - matched.add(current); - } + } else if (!selector) { + const current = arr[b - 1]; + matched.add(current); + } + } + // :nth-child() + } else { + let nth = b - 1; + if (a > 0) { + while (nth < 0) { nth += a; } } + if (nth >= 0 && nth < l) { + let j = a > 0 ? 0 : b - 1; + for (let i = 0; i < l && nth >= 0 && nth < l; i++) { + const current = arr[i]; + if (selectorNodes.size) { + if (selectorNodes.has(current)) { + if (j === nth) { + matched.add(current); + nth += a; + } + if (a > 0) { + j++; + } else { + j--; + } + } + } else if (i === nth) { + if (!selector) { + matched.add(current); + } + nth += a; + } + } + } } } } else { const { root } = this.#root; if (node === root && root.nodeType === ELEMENT_NODE && (a + b) === 1) { if (selectorBranches) { + const branchesLen = selectorBranches.length; let bool; - for (const leaves of selectorBranches) { + for (let i = 0; i < branchesLen; i++) { + const leaves = selectorBranches[i]; bool = this._matchLeaves(leaves, node); if (bool) { break; @@ -372,50 +378,53 @@ export class Matcher { const { localName, parentNode, prefix } = node; const matched = new Set(); if (parentNode) { - const arr = [].slice.call(parentNode.childNodes) - .filter(n => n.nodeType === ELEMENT_NODE); + const arr = [].slice.call(parentNode.children); const l = arr.length; - if (reverse) { - arr.reverse(); - } - // :first-of-type, :last-of-type - if (a === 0) { - if (b > 0 && b <= l) { - let i = 0; - for (const current of arr) { - const { localName: itemLocalName, prefix: itemPrefix } = current; - if (itemLocalName === localName && itemPrefix === prefix) { - if (i === b - 1) { - matched.add(current); - break; + if (l) { + if (reverse) { + arr.reverse(); + } + // :first-of-type, :last-of-type + if (a === 0) { + if (b > 0 && b <= l) { + let j = 0; + for (let i = 0; i < l; i++) { + const current = arr[i]; + const { localName: itemLocalName, prefix: itemPrefix } = current; + if (itemLocalName === localName && itemPrefix === prefix) { + if (j === b - 1) { + matched.add(current); + break; + } + j++; } - i++; } } - } - // :nth-of-type() - } else { - let nth = b - 1; - if (a > 0) { - while (nth < 0) { - nth += a; - } - } - if (nth >= 0 && nth < l) { - let i = a > 0 ? 0 : b - 1; - for (const current of arr) { - const { localName: itemLocalName, prefix: itemPrefix } = current; - if (itemLocalName === localName && itemPrefix === prefix) { - if (i === nth) { - matched.add(current); - nth += a; - } - if (nth < 0 || nth >= l) { - break; - } else if (a > 0) { - i++; - } else { - i--; + // :nth-of-type() + } else { + let nth = b - 1; + if (a > 0) { + while (nth < 0) { + nth += a; + } + } + if (nth >= 0 && nth < l) { + let j = a > 0 ? 0 : b - 1; + for (let i = 0; i < l; i++) { + const current = arr[i]; + const { localName: itemLocalName, prefix: itemPrefix } = current; + if (itemLocalName === localName && itemPrefix === prefix) { + if (j === nth) { + matched.add(current); + nth += a; + } + if (nth < 0 || nth >= l) { + break; + } else if (a > 0) { + j++; + } else { + j--; + } } } } @@ -1345,9 +1354,9 @@ export class Matcher { } case 'empty': { if (node.hasChildNodes()) { - const childNodes = node.childNodes[Symbol.iterator](); + const nodes = node.childNodes.values(); let bool; - for (const refNode of childNodes) { + for (const refNode of nodes) { bool = refNode.nodeType !== ELEMENT_NODE && refNode.nodeType !== TEXT_NODE; if (!bool) { @@ -2057,7 +2066,7 @@ export class Matcher { break; } case '>': { - const childNodes = node.children[Symbol.iterator](); + const childNodes = [].slice.call(node.children); for (const refNode of childNodes) { const bool = this._matchLeaves(leaves, refNode, { forgive }); if (bool) { @@ -2069,7 +2078,9 @@ export class Matcher { case ' ': default: { const { nodes, pending } = this._findDescendantNodes(leaves, node); - if (pending) { + if (nodes.size) { + matched = nodes; + } else if (pending) { const { document } = this.#root; const iterator = document.createNodeIterator(node, SHOW_ELEMENT); let refNode = iterator.nextNode(); @@ -2083,8 +2094,6 @@ export class Matcher { } refNode = iterator.nextNode(); } - } else if (nodes.size) { - matched = nodes; } } } @@ -2149,10 +2158,9 @@ export class Matcher { * find nodes * @param {object} twig - twig * @param {string} targetType - target type - * @param {boolean} complex - is complex selector * @returns {object} - collection of nodes etc. */ - _findNodes(twig, targetType, complex) { + _findNodes(twig, targetType) { const { leaves: [leaf, ...items] } = twig; const { type: leafType } = leaf; const leafName = unescapeSelector(leaf.name); @@ -2206,7 +2214,7 @@ export class Matcher { } } } else if (root.nodeType === DOCUMENT_FRAGMENT_NODE) { - const childNodes = root.children[Symbol.iterator](); + const childNodes = [].slice.call(root.children); const arr = []; for (const node of childNodes) { if (node.classList.contains(leafName)) { @@ -2219,20 +2227,15 @@ export class Matcher { nodes = new Set(arr); } } else { - const collection = root.getElementsByClassName(leafName); - const iterator = collection[Symbol.iterator](); + const arr = [].slice.call(root.getElementsByClassName(leafName)); if (this.#node.nodeType === ELEMENT_NODE) { - for (const node of iterator) { + for (const node of arr) { if (node === this.#node || isInclusive(node, this.#node)) { nodes.add(node); } } - } else if (collection.length) { - if (targetType === TARGET_ALL && !complex) { - nodes = new Set([].slice.call(collection)); - } else { - nodes = iterator; - } + } else if (arr.length) { + nodes = new Set(arr); } } break; @@ -2263,35 +2266,28 @@ export class Matcher { pending = true; } else if (root.nodeType === DOCUMENT_FRAGMENT_NODE) { const tagName = leafName.toLowerCase(); - const childNodes = root.children[Symbol.iterator](); + const childNodes = [].slice.call(root.children); const arr = []; for (const node of childNodes) { - if (node.nodeType === ELEMENT_NODE) { - if (node.localName === tagName) { - arr.push(node); - } - const a = [].slice.call(node.getElementsByTagName(leafName)); - arr.push(...a); + if (node.localName === tagName) { + arr.push(node); } + const a = [].slice.call(node.getElementsByTagName(leafName)); + arr.push(...a); } if (arr.length) { nodes = new Set(arr); } } else { - const collection = root.getElementsByTagName(leafName); - const iterator = collection[Symbol.iterator](); + const arr = [].slice.call(root.getElementsByTagName(leafName)); if (this.#node.nodeType === ELEMENT_NODE) { - for (const node of iterator) { + for (const node of arr) { if (node === this.#node || isInclusive(node, this.#node)) { nodes.add(node); } } - } else if (collection.length) { - if (targetType === TARGET_ALL && !complex) { - nodes = new Set([].slice.call(collection)); - } else { - nodes = iterator; - } + } else if (arr.length) { + nodes = new Set(arr); } } break; @@ -2330,7 +2326,7 @@ export class Matcher { } const itemsLen = items.length; // check last leaf if node not found, not pending and leaves left - if (nodes instanceof Set && !nodes.size && !pending && itemsLen) { + if (!nodes.size && !pending && itemsLen) { const lastLeaf = items[itemsLen - 1]; const { type: lastLeafType } = lastLeaf; if (lastLeafType === SELECTOR_PSEUDO_CLASS) { @@ -2360,10 +2356,9 @@ export class Matcher { _getEntryTwig(branch, targetType) { const branchLen = branch.length; const firstTwig = branch[0]; - const complex = branchLen > 1; let find; let twig; - if (complex) { + if (branchLen > 1) { const { leaves: [{ type: firstType }] } = firstTwig; const lastTwig = branch[branchLen - 1]; const { leaves: [{ type: lastType }] } = lastTwig; @@ -2386,7 +2381,6 @@ export class Matcher { twig = firstTwig; } return { - complex, find, twig }; @@ -2403,25 +2397,17 @@ export class Matcher { const pendingItems = new Set(); let i = 0; for (const { branch } of ast) { - const { complex, find, twig } = this._getEntryTwig(branch, targetType); - const { - compound, nodes, pending - } = this._findNodes(twig, targetType, complex); - if (pending) { + const { find, twig } = this._getEntryTwig(branch, targetType); + const { compound, nodes, pending } = this._findNodes(twig, targetType); + if (nodes.size) { + this.#nodes[i] = nodes; + } else if (pending) { pendingItems.add(new Map([ ['index', i], ['twig', twig] ])); - // nodes can be instance of Set - } else if (nodes instanceof Set) { - if (nodes.size) { - this.#nodes[i] = nodes; - } else { - this.#ast[i].skip = true; - } - // or Array Iterator object - } else if (nodes) { - this.#nodes[i] = nodes; + } else { + this.#ast[i].skip = true; } this.#ast[i].filtered = !compound; this.#ast[i].find = find; @@ -2535,13 +2521,7 @@ export class Matcher { const n = [...nodes]; nodes = new Set([...n, ...collectedNodes]); } else { - let iterator; - if (collectedNodes instanceof Set) { - iterator = collectedNodes[Symbol.iterator](); - } else { - iterator = collectedNodes; - } - const node = iterator.next().value; + const [node] = [...collectedNodes]; nodes.add(node); } } else { @@ -2596,11 +2576,11 @@ export class Matcher { break; } } + } else { + matched = false; } if (matched && targetType !== TARGET_ALL) { break; - } else if (matched) { - matched = false; } } } else { @@ -2616,28 +2596,28 @@ export class Matcher { for (const nextNode of nextNodes) { const m = this._matchCombinator(twig, nextNode, { find }); if (m.size) { - if (j === 0) { - matched = true; - break; - } else { - arr.push(...m); - } + arr.push(...m); } } - if (matched) { - nodes.add(node); - break; - } else if (arr.length) { - nextNodes = new Set(arr); + if (arr.length) { + if (j === 0) { + nodes.add(node); + matched = true; + break; + } else { + matched = false; + nextNodes = new Set(arr); + } } else { + matched = false; break; } } + } else { + matched = false; } if (matched && targetType !== TARGET_ALL) { break; - } else if (matched) { - matched = false; } } } diff --git a/test/matcher.test.js b/test/matcher.test.js index a77bd5af..1a8ec85e 100644 --- a/test/matcher.test.js +++ b/test/matcher.test.js @@ -10226,7 +10226,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('li', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: false, find: 'prev', twig: { leaves: [ @@ -10269,7 +10268,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('ul > li', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: true, find: 'next', twig: { leaves: [ @@ -10312,7 +10310,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('ul > li', document); const res = matcher._getEntryTwig(branch, 'first'); assert.deepEqual(res, { - complex: true, find: 'prev', twig: { leaves: [ @@ -10371,7 +10368,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('ul > li + li', document); const res = matcher._getEntryTwig(branch, 'first'); assert.deepEqual(res, { - complex: true, find: 'next', twig: { leaves: [ @@ -10414,7 +10410,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('#ul1 > #li1', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: true, find: 'prev', twig: { leaves: [ @@ -10457,7 +10452,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('#ul1 > li', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: true, find: 'next', twig: { leaves: [ @@ -10500,7 +10494,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('ul > #li1', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: true, find: 'prev', twig: { leaves: [ @@ -10547,7 +10540,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('ul > .li::after', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: true, find: 'prev', twig: { leaves: [ @@ -10598,7 +10590,6 @@ describe('match AST leaf and DOM node', () => { const matcher = new Matcher('ul::after > .li', document); const res = matcher._getEntryTwig(branch); assert.deepEqual(res, { - complex: true, find: 'next', twig: { leaves: [ @@ -10835,16 +10826,16 @@ describe('match AST leaf and DOM node', () => { } ], [ - [ + new Set([ document.getElementById('li1'), document.getElementById('li2'), document.getElementById('li3') - ][Symbol.iterator](), - [ + ]), + new Set([ document.getElementById('li1'), document.getElementById('li2'), document.getElementById('li3') - ][Symbol.iterator]() + ]) ] ], 'result'); }); @@ -10922,11 +10913,11 @@ describe('match AST leaf and DOM node', () => { document.getElementById('li2'), document.getElementById('li3') ]), - [ + new Set([ document.getElementById('li1'), document.getElementById('li2'), document.getElementById('li3') - ][Symbol.iterator]() + ]) ] ], 'result'); }); @@ -11327,7 +11318,7 @@ describe('match AST leaf and DOM node', () => { it('should get matched node(s)', () => { const matcher = new Matcher('li:last-child, li:first-child + li', document); - const res = matcher._find('all'); + const res = matcher._find(); assert.deepEqual([...res], [ document.getElementById('li3'), document.getElementById('li2')