Skip to content

Commit

Permalink
Fix parsing for return statements
Browse files Browse the repository at this point in the history
  • Loading branch information
therealparmesh committed Jul 26, 2022
1 parent 5623bae commit 7c82f6d
Showing 1 changed file with 138 additions and 61 deletions.
199 changes: 138 additions & 61 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const [DONE_WITH_TREE, DONE_WITH_SUBTREE] = [1, 2];

function traverseTree(node, visitorKeys, callback) {
const stack = [[node, null, null]];
const stack = [[node, [], null]];

while (stack.length > 0) {
try {
const current = stack.shift();
const [currentNode] = current;
const [currentNode, ancestors] = current;

callback(...current);

Expand All @@ -15,10 +15,10 @@ function traverseTree(node, visitorKeys, callback) {

if (Array.isArray(child)) {
for (const childItem of child) {
stack.push([childItem, currentNode, visitorKey]);
stack.push([childItem, [currentNode, ...ancestors], visitorKey]);
}
} else if (Boolean(child)) {
stack.push([child, currentNode, visitorKey]);
stack.push([child, [currentNode, ...ancestors], visitorKey]);
}
}
} catch (code) {
Expand All @@ -31,6 +31,57 @@ function traverseTree(node, visitorKeys, callback) {
}
}

function getReturnStatement(node) {
return node.type === 'VariableDeclaration'
? node.declarations?.[0]?.init?.body?.body?.find(
(statement) => statement.type === 'ReturnStatement',
) ??
(node.declarations?.[0]?.init?.body?.type === 'JSXElement'
? node.declarations?.[0]?.init?.body
: null)
: node.body?.body?.find(
(statement) => statement.type === 'ReturnStatement',
);
}

function isInNestedReturnStatement(ancestors, returnStatement) {
const nestedReturnStatementIndex = ancestors.findIndex(
(ancestor, index) =>
(ancestor.type === 'ReturnStatement' ||
(ancestor.type === 'JSXElement' &&
ancestors[index + 1]?.type === 'ArrowFunctionExpression')) &&
ancestor !== returnStatement,
);

const originalReturnStatementIndex = ancestors.findIndex(
(ancestor) => ancestor === returnStatement,
);

return (
nestedReturnStatementIndex !== -1 &&
originalReturnStatementIndex !== -1 &&
originalReturnStatementIndex > nestedReturnStatementIndex
);
}

function isInNestedFunction(ancestors, returnStatement) {
const nestedFunctionIndex = ancestors.findIndex(
(ancestor) =>
ancestor.type === 'ArrowFunctionExpression' ||
ancestor.type === 'FunctionDeclaration',
);

const originalReturnStatementIndex = ancestors.findIndex(
(ancestor) => ancestor === returnStatement,
);

return (
nestedFunctionIndex !== -1 &&
originalReturnStatementIndex !== -1 &&
originalReturnStatementIndex > nestedFunctionIndex
);
}

const rules = {
'data-component': {
meta: {
Expand Down Expand Up @@ -63,56 +114,69 @@ const rules = {
.filter((child) => {
let flag = false;

traverseTree(child, visitorKeys, (current) => {
if (current.type === 'JSXElement') {
flag = true;
traverseTree(
getReturnStatement(child),
visitorKeys,
(current) => {
if (current.type === 'JSXElement') {
flag = true;

throw DONE_WITH_TREE;
}
});
throw DONE_WITH_TREE;
}
},
);

return flag;
})
.filter((child) => {
let flag = false;

traverseTree(child, visitorKeys, (current) => {
if (
current.type === 'JSXElement' &&
current.openingElement.attributes.find(
(attributeNode) =>
attributeNode.name.name === 'data-component',
)
) {
throw DONE_WITH_SUBTREE;
} else if (
current.type === 'JSXElement' &&
excludeComponentNames.every(
(regex) =>
!regex.test(
current.openingElement.name.property
? current.openingElement.name.property.name
: current.openingElement.name.name,
),
) &&
!current.openingElement.attributes.find(
(attributeNode) =>
attributeNode.name.name === 'data-component',
)
) {
flag = true;

throw DONE_WITH_TREE;
}
});
traverseTree(
getReturnStatement(child),
visitorKeys,
(current, ancestors) => {
if (
current.type === 'JSXElement' &&
current.openingElement.attributes.find(
(attributeNode) =>
attributeNode.name.name === 'data-component',
)
) {
throw DONE_WITH_SUBTREE;
} else if (
current.type === 'JSXElement' &&
excludeComponentNames.every(
(regex) =>
!regex.test(
current.openingElement.name.property
? current.openingElement.name.property.name
: current.openingElement.name.name,
),
) &&
!current.openingElement.attributes.find(
(attributeNode) =>
attributeNode.name.name === 'data-component',
) &&
(isInNestedReturnStatement(
ancestors,
getReturnStatement(child),
) ||
!isInNestedFunction(ancestors, getReturnStatement(child)))
) {
flag = true;

throw DONE_WITH_TREE;
}
},
);

return flag;
});

const components = componentNodes
.map(
(child) =>
child?.id?.value ??
child?.id?.name ??
child?.declarations?.map(
(declaration) => declaration?.id?.name,
),
Expand All @@ -127,33 +191,46 @@ const rules = {
const [componentNode] = componentNodes;

const componentName =
componentNode?.id?.value ??
componentNode?.id?.name ??
componentNode?.declarations?.map(
(declaration) => declaration?.id?.name,
);

let fixNode = null;

traverseTree(componentNode, visitorKeys, (current) => {
if (
current.type === 'JSXElement' &&
excludeComponentNames.every(
(regex) =>
!regex.test(
current.openingElement.name.property
? current.openingElement.name.property.name
: current.openingElement.name.name,
),
) &&
!current.openingElement.attributes.find(
(attributeNode) => attributeNode.name.name === 'data-component',
)
) {
fixNode = current.openingElement;

throw DONE_WITH_TREE;
}
});
traverseTree(
getReturnStatement(componentNode),
visitorKeys,
(current, ancestors) => {
if (
current.type === 'JSXElement' &&
excludeComponentNames.every(
(regex) =>
!regex.test(
current.openingElement.name.property
? current.openingElement.name.property.name
: current.openingElement.name.name,
),
) &&
!current.openingElement.attributes.find(
(attributeNode) =>
attributeNode.name.name === 'data-component',
) &&
(isInNestedReturnStatement(
ancestors,
getReturnStatement(componentNode),
) ||
!isInNestedFunction(
ancestors,
getReturnStatement(componentNode),
))
) {
fixNode = current.openingElement;

throw DONE_WITH_TREE;
}
},
);

if (Boolean(components)) {
context.report({
Expand Down

0 comments on commit 7c82f6d

Please sign in to comment.