From 6988f9c8ac0277c915db2ea6c7fc984d3f7bcb89 Mon Sep 17 00:00:00 2001 From: saharmehrpour Date: Fri, 3 May 2024 21:20:18 -0400 Subject: [PATCH 1/2] get surrounding nodes based on 3 heuristics --- src/core/ruleExecutor.js | 146 +++++++++++++++++++++++++++++++-------- 1 file changed, 118 insertions(+), 28 deletions(-) diff --git a/src/core/ruleExecutor.js b/src/core/ruleExecutor.js index 6aaa46c..b7e1d36 100644 --- a/src/core/ruleExecutor.js +++ b/src/core/ruleExecutor.js @@ -584,27 +584,80 @@ const removeSiblings = (node) => { * @return {Node} - The root node. */ const getSurroundingNodes = (node) => { - while (node && node.parentNode) { - node = node.parentNode; - if (node.tagName && node.tagName.toLowerCase() === 'block') { - node = node.parentNode - break; + // case 1: static class + // Grab all code within static class + if (isStaticClass(node)) { + return node; + } + + // case 2: class, field + // Grab all fields and function/nested class signatures + if (isClassOrField(node)) { + // find the parent class + while (node && node.tagName && node.tagName.toLowerCase() !== "class" && node.parentNode) { + node = node.parentNode; } + removeFunctionBodies(node); + return node; } - removeSiblingsChildren(node); - let root = node; - while (root.parentNode) { - root = root.parentNode; + + // case 3: other, statements (starting node within method or at method signature) + // Grab all code within method and function signatures and private fields adjacent/same level as method + else { + // find the parent function + while (node && node.tagName && node.tagName.toLowerCase() !== "function" && node.parentNode) { + node = node.parentNode; + } + removeFunctionBodiesPublicFields(node); + // find the parent class + if (node.parentNode) { + node = node.parentNode; + } + while (node && node.tagName && node.tagName.toLowerCase() !== "class" && node.parentNode) { + node = node.parentNode; + } + return node; } - return root; }; +/** check if the node is a static class + * @param node {Node} + * @return {boolean} + */ +const isStaticClass = (node) => { + if (node.nodeType !== Node.ELEMENT_NODE || node.tagName.toLowerCase() !== "class") { + return false; + } + const children = node.childNodes; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + if (child.nodeType === Node.ELEMENT_NODE && + child.tagName.toLowerCase() === "specifier" && + child.textContent.trim() === "static") { + return true; + } + } + return false; +} + /** - * Remove child nodes of siblings, keeping the sibling nodes. + * check if the node is a class or a field. + * @param node {Node} + * @return {boolean} + */ +function isClassOrField(node) { + if (node.nodeType !== Node.ELEMENT_NODE) { + return false; + } + const tagName = node.tagName.toLowerCase(); + return tagName === "class" || tagName === "decl_stmt"; +} + +/** + * Remove child nodes of siblings, remove public fields * @param {Node} node - The node whose siblings' children should be removed. */ -const removeSiblingsChildren = (node) => { - const tagsToRemove = ["block"]; +const removeFunctionBodiesPublicFields = (node) => { if (!node || !node.parentNode) { return; } @@ -613,36 +666,73 @@ const removeSiblingsChildren = (node) => { // Loop over previous siblings while (currentNode.previousSibling) { currentNode = currentNode.previousSibling; - removeDescendantsByTagName(currentNode, tagsToRemove); + removeFunctionBodies(currentNode); + removePublicFields(currentNode); } // Reset currentNode to the original node currentNode = node; // Loop over next siblings while (currentNode.nextSibling) { currentNode = currentNode.nextSibling; - removeDescendantsByTagName(currentNode, tagsToRemove); + removeFunctionBodies(currentNode); + removePublicFields(currentNode); } - removeSiblingsChildren(node.parentNode); + removeFunctionBodiesPublicFields(node.parentNode); }; /** - * Remove descendants of a node by tag name. - * @param {Node} node - The node whose descendants should be removed. - * @param {string[]} tagsToRemove - The tag names of descendants to remove. + * remove function bodies + * @param node {Node} */ -const removeDescendantsByTagName = (node, tagsToRemove) => { - if (!node || !node.childNodes) { +const removeFunctionBodies = (node) => { + if (!node || node.nodeType !== Node.ELEMENT_NODE) { return; } - Array.from(node.childNodes).forEach((child) => { - if (child.tagName && tagsToRemove.includes(child.tagName.toLowerCase())) { - node.removeChild(child); - } else { - removeDescendantsByTagName(child, tagsToRemove); + + if (node.tagName.toLowerCase() === "function") { + for (let i = 0; i < node.childNodes.length; i++) { + const child = node.childNodes[i]; + if (child.tagName && child.tagName.toLowerCase() === "block") { + node.removeChild(child); + return; + } } - }); -}; + } else { + for (let i = 0; i < node.childNodes.length; i++) { + const child = node.childNodes[i]; + removeFunctionBodies(child); + } + } +} + +/** + * remove public fields + * @param node {Node} + */ +const removePublicFields = (node) => { + if (!node || node.nodeType !== Node.ELEMENT_NODE) { + return; + } + + try { + if (node.tagName.toLowerCase() === "decl_stmt") { + for (let i = 0; i < node.childNodes[0].childNodes.length; i++) { + const child = node.childNodes[0].childNodes[i]; // "decl" + + if (child.nodeType === Node.ELEMENT_NODE && + child.tagName.toLowerCase() === "specifier" && + child.textContent.trim() === "public") { + let parent = node.parentNode; + parent.removeChild(node); + return; + } + } + } + } catch (e) { + console.log("error in removing public fields", e); + } +} /** * validate the xpath queries in ruleI From f6b8f20c8a8f4b3c2ee6c6bafc09e7ec04356c95 Mon Sep 17 00:00:00 2001 From: saharmehrpour Date: Fri, 10 May 2024 14:24:13 -0400 Subject: [PATCH 2/2] update case 3 --- src/core/ruleExecutor.js | 69 ++++++++++++---------------------------- 1 file changed, 20 insertions(+), 49 deletions(-) diff --git a/src/core/ruleExecutor.js b/src/core/ruleExecutor.js index b7e1d36..336fbe6 100644 --- a/src/core/ruleExecutor.js +++ b/src/core/ruleExecutor.js @@ -601,14 +601,14 @@ const getSurroundingNodes = (node) => { return node; } - // case 3: other, statements (starting node within method or at method signature) - // Grab all code within method and function signatures and private fields adjacent/same level as method + // case 3: other, statements (starting node within method or at method signature) + // Grab all code within method and function signatures and fields adjacent/same level as method else { // find the parent function while (node && node.tagName && node.tagName.toLowerCase() !== "function" && node.parentNode) { node = node.parentNode; } - removeFunctionBodiesPublicFields(node); + removeSiblingFunctionBodies(node); // find the parent class if (node.parentNode) { node = node.parentNode; @@ -653,34 +653,6 @@ function isClassOrField(node) { return tagName === "class" || tagName === "decl_stmt"; } -/** - * Remove child nodes of siblings, remove public fields - * @param {Node} node - The node whose siblings' children should be removed. - */ -const removeFunctionBodiesPublicFields = (node) => { - if (!node || !node.parentNode) { - return; - } - - let currentNode = node; - // Loop over previous siblings - while (currentNode.previousSibling) { - currentNode = currentNode.previousSibling; - removeFunctionBodies(currentNode); - removePublicFields(currentNode); - } - // Reset currentNode to the original node - currentNode = node; - // Loop over next siblings - while (currentNode.nextSibling) { - currentNode = currentNode.nextSibling; - removeFunctionBodies(currentNode); - removePublicFields(currentNode); - } - - removeFunctionBodiesPublicFields(node.parentNode); -}; - /** * remove function bodies * @param node {Node} @@ -707,31 +679,30 @@ const removeFunctionBodies = (node) => { } /** - * remove public fields + * remove bodies of sibling functions * @param node {Node} */ -const removePublicFields = (node) => { +const removeSiblingFunctionBodies = (node) => { if (!node || node.nodeType !== Node.ELEMENT_NODE) { return; } - try { - if (node.tagName.toLowerCase() === "decl_stmt") { - for (let i = 0; i < node.childNodes[0].childNodes.length; i++) { - const child = node.childNodes[0].childNodes[i]; // "decl" - - if (child.nodeType === Node.ELEMENT_NODE && - child.tagName.toLowerCase() === "specifier" && - child.textContent.trim() === "public") { - let parent = node.parentNode; - parent.removeChild(node); - return; - } - } - } - } catch (e) { - console.log("error in removing public fields", e); + let currentNode = node; + // Loop over previous siblings + while (currentNode.previousSibling) { + currentNode = currentNode.previousSibling; + removeFunctionBodies(currentNode); } + // Reset currentNode to the original node + currentNode = node; + + // Loop over next siblings + while (currentNode.nextSibling) { + currentNode = currentNode.nextSibling; + removeFunctionBodies(currentNode) + } + + removeSiblingFunctionBodies(node.parentNode); } /**