diff --git a/index.js b/index.js
index 96b62a6..35239f4 100644
--- a/index.js
+++ b/index.js
@@ -11,33 +11,37 @@ function getJSXElementName(jsx) {
}
}
-function handleJSX(context, name, jsx) {
+function handleJSX(context, name, exported, jsx) {
if (
!providerRegex.test(getJSXElementName(jsx)) &&
!jsx.openingElement.attributes.find(
(a) => a.name?.name === 'data-component',
)
) {
- context.report({
- node: jsx,
- message: `${name} is missing the data-component attribute for the top-level element.`,
- fix(fixer) {
- return fixer.insertTextAfterRange(
- jsx.openingElement.typeParameters
- ? jsx.openingElement.typeParameters.range
- : jsx.openingElement.name.range,
- ` data-component="${name}"`,
- );
+ context.possibleReports.push({
+ name,
+ exported,
+ report: {
+ node: jsx.openingElement,
+ message: `${name} is missing the data-component attribute for the top-level element.`,
+ fix(fixer) {
+ return fixer.insertTextAfterRange(
+ jsx.openingElement.typeParameters
+ ? jsx.openingElement.typeParameters.range
+ : jsx.openingElement.name.range,
+ ` data-component="${name}"`,
+ );
+ },
},
});
}
}
-function handleBlockStatement(context, name, block) {
+function handleBlockStatement(context, name, exported, block) {
// Find the root return statement. Are there any other types of returns we need to handle?
const ret = block.body.find((c) => c.type === 'ReturnStatement');
if (ret && ret.argument.type === 'JSXElement') {
- handleJSX(context, name, ret.argument);
+ handleJSX(context, name, exported, ret.argument);
}
}
@@ -49,31 +53,31 @@ function isForwardRef(expression) {
return calleeName === 'forwardRef' && expression.arguments.length == 1;
}
-function handleExpression(context, name, expression) {
+function handleExpression(context, name, exported, expression) {
switch (expression.type) {
case 'FunctionExpression':
- handleBlockStatement(context, name, expression.body);
+ handleBlockStatement(context, name, exported, expression.body);
break;
case 'ArrowFunctionExpression':
switch (expression.body.type) {
case 'JSXElement':
- handleJSX(context, name, expression.body);
+ handleJSX(context, name, exported, expression.body);
break;
case 'BlockStatement':
- handleBlockStatement(context, name, expression.body);
+ handleBlockStatement(context, name, exported, expression.body);
break;
}
break;
case 'ClassExpression':
expression.body.body.forEach((x) => {
if (x.type === 'MethodDefinition' && x.key.name === 'render') {
- handleBlockStatement(context, name, x.value.body);
+ handleBlockStatement(context, name, exported, x.value.body);
}
});
break;
case 'CallExpression':
if (isForwardRef(expression)) {
- handleExpression(context, name, expression.arguments[0]);
+ handleExpression(context, name, exported, expression.arguments[0]);
}
break;
}
@@ -94,6 +98,7 @@ const rules = {
create(context) {
return {
Program(root) {
+ context = { ...context, possibleReports: [] };
root.body.forEach((node) => {
// We will need to save any non-exported declarations and handle them only if they get exported at the end
let exported = false;
@@ -109,11 +114,21 @@ const rules = {
switch (node.type) {
case 'VariableDeclaration':
node.declarations.forEach((variable) => {
- handleExpression(context, variable.id.name, variable.init);
+ handleExpression(
+ context,
+ variable.id.name,
+ exported,
+ variable.init,
+ );
});
break;
case 'FunctionDeclaration':
- handleBlockStatement(context, node.id.name, node.body);
+ handleBlockStatement(
+ context,
+ node.id.name,
+ exported,
+ node.body,
+ );
break;
case 'ClassDeclaration':
node.body.body.forEach((x) => {
@@ -121,7 +136,12 @@ const rules = {
x.type === 'MethodDefinition' &&
x.key.name === 'render'
) {
- handleBlockStatement(context, node.id.name, x.value.body);
+ handleBlockStatement(
+ context,
+ node.id.name,
+ exported,
+ x.value.body,
+ );
return;
}
});
@@ -135,10 +155,31 @@ const rules = {
handleExpression(
context,
node.arguments[0].id.name,
+ exported,
node.arguments[0],
);
}
break;
+ case 'AssignmentExpression':
+ handleExpression(context, node.left.name, exported, node.right);
+ break;
+ case 'ExportNamedDeclaration':
+ node.specifiers.forEach((s) => {
+ const report = context.possibleReports.find(
+ (r) => r.name === s.local.name,
+ );
+ if (report) {
+ report.exported = true;
+ }
+ });
+ break;
+ }
+ });
+
+ // Report all issues for exported components
+ context.possibleReports.forEach((r) => {
+ if (r.exported) {
+ context.report(r.report);
}
});
},
diff --git a/test.js b/test.js
index 0a2ca96..bcd01b4 100644
--- a/test.js
+++ b/test.js
@@ -6,11 +6,11 @@ const { join } = require('path');
// Test File Definitions
//------------------------------------------------------------------------------
-const singleComponent = `const temp = () => {
+const singleComponent = `export const temp = () => {
return