@blumintinc/eslint-plugin-blumint 1.5.2 → 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js
CHANGED
|
@@ -137,15 +137,16 @@ exports.enforceExportedFunctionTypes = (0, createRule_1.createRule)({
|
|
|
137
137
|
function isTypeExported(typeName) {
|
|
138
138
|
const sourceCode = context.getSourceCode();
|
|
139
139
|
const program = sourceCode.ast;
|
|
140
|
-
// Check for imported types
|
|
141
|
-
|
|
140
|
+
// Check for imported types first - if found, return true immediately
|
|
141
|
+
// since imported types are already available to consumers
|
|
142
|
+
const hasImportedType = program.body.some((node) => {
|
|
142
143
|
if (node.type === utils_1.AST_NODE_TYPES.ImportDeclaration) {
|
|
143
144
|
return node.specifiers.some((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
|
144
145
|
specifier.local.name === typeName);
|
|
145
146
|
}
|
|
146
147
|
return false;
|
|
147
148
|
});
|
|
148
|
-
if (
|
|
149
|
+
if (hasImportedType) {
|
|
149
150
|
return true;
|
|
150
151
|
}
|
|
151
152
|
// Check for exported type declarations
|
|
@@ -4581,22 +4581,83 @@ exports.enforceVerbNounNaming = (0, createRule_1.createRule)({
|
|
|
4581
4581
|
}
|
|
4582
4582
|
return isVerb;
|
|
4583
4583
|
}
|
|
4584
|
-
function
|
|
4584
|
+
function isPascalCase(name) {
|
|
4585
|
+
return /^[A-Z][a-zA-Z0-9]*$/.test(name);
|
|
4586
|
+
}
|
|
4587
|
+
function hasPropsParameter(node) {
|
|
4588
|
+
if (!node.params.length)
|
|
4589
|
+
return false;
|
|
4590
|
+
const firstParam = node.params[0];
|
|
4591
|
+
if (firstParam.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
4592
|
+
return true; // Destructured props
|
|
4593
|
+
}
|
|
4594
|
+
if (firstParam.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
4595
|
+
const paramName = firstParam.name.toLowerCase();
|
|
4596
|
+
return paramName === 'props';
|
|
4597
|
+
}
|
|
4598
|
+
return false;
|
|
4599
|
+
}
|
|
4600
|
+
function hasJsxReturn(node) {
|
|
4601
|
+
const sourceCode = context.getSourceCode();
|
|
4602
|
+
const text = sourceCode.getText(node);
|
|
4603
|
+
// Check for direct JSX returns
|
|
4604
|
+
if (text.includes('return <') || text.includes('=> <')) {
|
|
4605
|
+
return true;
|
|
4606
|
+
}
|
|
4607
|
+
// Check for JSX assigned to variables then returned
|
|
4608
|
+
if (text.includes('const ') && text.includes('<') && text.includes('return')) {
|
|
4609
|
+
return true;
|
|
4610
|
+
}
|
|
4611
|
+
return false;
|
|
4612
|
+
}
|
|
4613
|
+
function isReactComponent(node) {
|
|
4585
4614
|
if (node.type !== utils_1.AST_NODE_TYPES.FunctionDeclaration &&
|
|
4586
4615
|
node.type !== utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
4587
4616
|
node.type !== utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
4588
4617
|
return false;
|
|
4589
4618
|
}
|
|
4590
|
-
//
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4619
|
+
// Get the function name
|
|
4620
|
+
let functionName = '';
|
|
4621
|
+
if (node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration && node.id) {
|
|
4622
|
+
functionName = node.id.name;
|
|
4623
|
+
}
|
|
4624
|
+
else if (node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression || node.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
4625
|
+
const parent = node.parent;
|
|
4626
|
+
if (parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator && parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
4627
|
+
functionName = parent.id.name;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
// Check for React component indicators
|
|
4631
|
+
const indicators = [
|
|
4632
|
+
// 1. PascalCase naming
|
|
4633
|
+
functionName && isPascalCase(functionName),
|
|
4634
|
+
// 2. Props parameter
|
|
4635
|
+
hasPropsParameter(node),
|
|
4636
|
+
// 3. JSX return
|
|
4637
|
+
hasJsxReturn(node),
|
|
4638
|
+
// 4. React type annotations
|
|
4639
|
+
(() => {
|
|
4640
|
+
if (node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
4641
|
+
const parent = node.parent;
|
|
4642
|
+
if (parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
4643
|
+
const id = parent.id;
|
|
4644
|
+
if (id.type === utils_1.AST_NODE_TYPES.Identifier && id.typeAnnotation?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
|
|
4645
|
+
const typeText = context.getSourceCode().getText(id.typeAnnotation.typeAnnotation);
|
|
4646
|
+
return typeText.includes('React.') || typeText.includes('FC') || typeText.includes('FunctionComponent');
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
return false;
|
|
4651
|
+
})()
|
|
4652
|
+
];
|
|
4653
|
+
// Consider it a React component if it matches at least 2 indicators
|
|
4654
|
+
return indicators.filter(Boolean).length >= 2;
|
|
4594
4655
|
}
|
|
4595
4656
|
return {
|
|
4596
4657
|
FunctionDeclaration(node) {
|
|
4597
4658
|
if (!node.id)
|
|
4598
4659
|
return;
|
|
4599
|
-
if (
|
|
4660
|
+
if (isReactComponent(node)) {
|
|
4600
4661
|
return;
|
|
4601
4662
|
}
|
|
4602
4663
|
if (!isVerbPhrase(node.id.name)) {
|
|
@@ -4612,7 +4673,7 @@ exports.enforceVerbNounNaming = (0, createRule_1.createRule)({
|
|
|
4612
4673
|
// Only check if it's a function
|
|
4613
4674
|
if (node.init?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
4614
4675
|
node.init?.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
4615
|
-
if (
|
|
4676
|
+
if (isReactComponent(node.init)) {
|
|
4616
4677
|
return;
|
|
4617
4678
|
}
|
|
4618
4679
|
if (!isVerbPhrase(node.id.name)) {
|
|
@@ -89,6 +89,18 @@ function getObjectUsagesInHook(hookBody, objectName) {
|
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
+
else if (node.type === utils_1.AST_NODE_TYPES.JSXElement || node.type === utils_1.AST_NODE_TYPES.JSXFragment) {
|
|
93
|
+
// If we find a JSX element, check its attributes for spread operator
|
|
94
|
+
if (node.type === utils_1.AST_NODE_TYPES.JSXElement) {
|
|
95
|
+
node.openingElement.attributes.forEach((attr) => {
|
|
96
|
+
if (attr.type === utils_1.AST_NODE_TYPES.JSXSpreadAttribute &&
|
|
97
|
+
attr.argument.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
98
|
+
attr.argument.name === objectName) {
|
|
99
|
+
needsEntireObject = true;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
92
104
|
else if (node.type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
|
93
105
|
// If we find a spread operator with our target object, consider it as accessing all properties
|
|
94
106
|
if (node.argument.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
@@ -48,6 +48,9 @@ exports.preferSettingsObject = (0, createRule_1.createRule)({
|
|
|
48
48
|
create(context, [options]) {
|
|
49
49
|
const finalOptions = { ...defaultOptions, ...options };
|
|
50
50
|
function getParameterType(param) {
|
|
51
|
+
if (param.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
52
|
+
return getParameterType(param.left);
|
|
53
|
+
}
|
|
51
54
|
if (param.type === utils_1.AST_NODE_TYPES.Identifier && param.typeAnnotation) {
|
|
52
55
|
const typeNode = param.typeAnnotation.typeAnnotation;
|
|
53
56
|
if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
@@ -55,6 +58,12 @@ exports.preferSettingsObject = (0, createRule_1.createRule)({
|
|
|
55
58
|
? typeNode.typeName.name
|
|
56
59
|
: 'unknown';
|
|
57
60
|
}
|
|
61
|
+
if (typeNode.type === utils_1.AST_NODE_TYPES.TSStringKeyword)
|
|
62
|
+
return 'string';
|
|
63
|
+
if (typeNode.type === utils_1.AST_NODE_TYPES.TSNumberKeyword)
|
|
64
|
+
return 'number';
|
|
65
|
+
if (typeNode.type === utils_1.AST_NODE_TYPES.TSBooleanKeyword)
|
|
66
|
+
return 'boolean';
|
|
58
67
|
return typeNode.type;
|
|
59
68
|
}
|
|
60
69
|
return 'unknown';
|
|
@@ -95,7 +104,7 @@ exports.preferSettingsObject = (0, createRule_1.createRule)({
|
|
|
95
104
|
if (shouldIgnoreNode(node))
|
|
96
105
|
return;
|
|
97
106
|
const params = node.params;
|
|
98
|
-
// Check for too many parameters
|
|
107
|
+
// Check for too many parameters first
|
|
99
108
|
const minParams = finalOptions.minimumParameters !== undefined
|
|
100
109
|
? finalOptions.minimumParameters
|
|
101
110
|
: defaultOptions.minimumParameters;
|
|
@@ -107,7 +116,7 @@ exports.preferSettingsObject = (0, createRule_1.createRule)({
|
|
|
107
116
|
});
|
|
108
117
|
return;
|
|
109
118
|
}
|
|
110
|
-
//
|
|
119
|
+
// Then check for same type parameters if enabled
|
|
111
120
|
if (finalOptions.checkSameTypeParameters && params.length >= 2) {
|
|
112
121
|
if (hasSameTypeParameters(params)) {
|
|
113
122
|
context.report({
|