code-auditor-mcp 2.6.2 → 3.0.1
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/README.md +23 -196
- package/dist/analyzers/analyzerUtils.d.ts +13 -11
- package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
- package/dist/analyzers/analyzerUtils.js +22 -56
- package/dist/analyzers/analyzerUtils.js.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/dataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/dataAccessAnalyzer.js +50 -24
- package/dist/analyzers/dataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/documentationAnalyzer.d.ts +4 -1
- package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/documentationAnalyzer.js +210 -111
- package/dist/analyzers/documentationAnalyzer.js.map +1 -1
- package/dist/analyzers/dryAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/dryAnalyzer.js +190 -58
- package/dist/analyzers/dryAnalyzer.js.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.d.ts +20 -0
- package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/invariantsAnalyzer.js +148 -0
- package/dist/analyzers/invariantsAnalyzer.js.map +1 -0
- package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/reactAnalyzer.js +2 -2
- package/dist/analyzers/reactAnalyzer.js.map +1 -1
- package/dist/analyzers/schemaAnalyzer.d.ts +2 -0
- package/dist/analyzers/schemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/schemaAnalyzer.js +306 -147
- package/dist/analyzers/schemaAnalyzer.js.map +1 -1
- package/dist/analyzers/solidAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/solidAnalyzer.js +145 -119
- package/dist/analyzers/solidAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +3 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js +41 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +8 -8
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +6 -6
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +367 -24
- package/dist/auditRunner.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +740 -18
- package/dist/cli.js.map +1 -1
- package/dist/codeIndexDB-enhanced.d.ts +35 -13
- package/dist/codeIndexDB-enhanced.d.ts.map +1 -1
- package/dist/codeIndexDB-enhanced.js +311 -214
- package/dist/codeIndexDB-enhanced.js.map +1 -1
- package/dist/{codeIndexDb.d.ts → codeIndexDB.d.ts} +51 -224
- package/dist/codeIndexDB.d.ts.map +1 -0
- package/dist/codeIndexDB.js +2042 -0
- package/dist/codeIndexDB.js.map +1 -0
- package/dist/codeIndexService.d.ts.map +1 -1
- package/dist/codeIndexService.js.map +1 -1
- package/dist/componentScanner.d.ts +14 -8
- package/dist/componentScanner.d.ts.map +1 -1
- package/dist/componentScanner.js +136 -113
- package/dist/componentScanner.js.map +1 -1
- package/dist/config/configLoader.d.ts.map +1 -1
- package/dist/config/configLoader.js +10 -7
- package/dist/config/configLoader.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/fingerprint.d.ts +15 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +32 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/functionScanner.d.ts +5 -0
- package/dist/functionScanner.d.ts.map +1 -1
- package/dist/functionScanner.js +417 -341
- package/dist/functionScanner.js.map +1 -1
- package/dist/generators/AWSQConfigGenerator.d.ts.map +1 -1
- package/dist/generators/AiderConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.js.map +1 -1
- package/dist/generators/ClaudeConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ClineConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CodeiumConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ConfigGeneratorFactory.d.ts.map +1 -1
- package/dist/generators/ConfigGeneratorFactory.js.map +1 -1
- package/dist/generators/ContinueConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CopilotConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CursorConfigGenerator.d.ts.map +1 -1
- package/dist/generators/JetBrainsConfigGenerator.d.ts.map +1 -1
- package/dist/generators/VSCodeConfigGenerator.d.ts.map +1 -1
- package/dist/grammars/tree-sitter-go.wasm +0 -0
- package/dist/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/invariants/index.d.ts +9 -0
- package/dist/invariants/index.d.ts.map +1 -0
- package/dist/invariants/index.js +4 -0
- package/dist/invariants/index.js.map +1 -0
- package/dist/invariants/invariant-rules.schema.json +137 -0
- package/dist/invariants/ruleEngine.d.ts +32 -0
- package/dist/invariants/ruleEngine.d.ts.map +1 -0
- package/dist/invariants/ruleEngine.js +536 -0
- package/dist/invariants/ruleEngine.js.map +1 -0
- package/dist/invariants/ruleValidator.d.ts +17 -0
- package/dist/invariants/ruleValidator.d.ts.map +1 -0
- package/dist/invariants/ruleValidator.js +264 -0
- package/dist/invariants/ruleValidator.js.map +1 -0
- package/dist/invariants/types.d.ts +78 -0
- package/dist/invariants/types.d.ts.map +1 -0
- package/dist/invariants/types.js +5 -0
- package/dist/invariants/types.js.map +1 -0
- package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.js.map +1 -1
- package/dist/languages/LanguageRegistry.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.js +1 -1
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
- package/dist/languages/UniversalAnalyzer.js.map +1 -1
- package/dist/languages/adapterBridge.d.ts +102 -0
- package/dist/languages/adapterBridge.d.ts.map +1 -0
- package/dist/languages/adapterBridge.js +382 -0
- package/dist/languages/adapterBridge.js.map +1 -0
- package/dist/languages/go/GoAdapter.d.ts +37 -26
- package/dist/languages/go/GoAdapter.d.ts.map +1 -1
- package/dist/languages/go/GoAdapter.js +560 -281
- package/dist/languages/go/GoAdapter.js.map +1 -1
- package/dist/languages/index.d.ts +5 -2
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +11 -9
- package/dist/languages/index.js.map +1 -1
- package/dist/languages/tree-sitter/converter.d.ts +43 -0
- package/dist/languages/tree-sitter/converter.d.ts.map +1 -0
- package/dist/languages/tree-sitter/converter.js +150 -0
- package/dist/languages/tree-sitter/converter.js.map +1 -0
- package/dist/languages/tree-sitter/parser.d.ts +36 -0
- package/dist/languages/tree-sitter/parser.d.ts.map +1 -0
- package/dist/languages/tree-sitter/parser.js +114 -0
- package/dist/languages/tree-sitter/parser.js.map +1 -0
- package/dist/languages/types.d.ts +11 -0
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +92 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +951 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -0
- package/dist/mcp-tools/projectTasks.d.ts +58 -22
- package/dist/mcp-tools/projectTasks.d.ts.map +1 -1
- package/dist/mcp-tools/projectTasks.js +172 -10
- package/dist/mcp-tools/projectTasks.js.map +1 -1
- package/dist/mcp-tools/whitelistTools.d.ts +21 -21
- package/dist/mcp-tools/whitelistTools.d.ts.map +1 -1
- package/dist/mcp-tools/workflowGuide.d.ts.map +1 -1
- package/dist/mcp-tools/workflowGuide.js +130 -126
- package/dist/mcp-tools/workflowGuide.js.map +1 -1
- package/dist/mcp-tools-shared.d.ts.map +1 -1
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/mcp-ui-simple.js +1 -1
- package/dist/mcp-ui-simple.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +1376 -1181
- package/dist/mcp.js.map +1 -1
- package/dist/mcpAuditJobs.d.ts +4 -0
- package/dist/mcpAuditJobs.d.ts.map +1 -1
- package/dist/mcpAuditJobs.js +49 -2
- package/dist/mcpAuditJobs.js.map +1 -1
- package/dist/mcpToolErrors.d.ts.map +1 -1
- package/dist/mcpToolErrors.js.map +1 -1
- package/dist/native/ast-grep-napi.darwin-arm64.node +0 -0
- package/dist/native/ast-grep-napi.darwin-x64.node +0 -0
- package/dist/native/ast-grep-napi.linux-arm64-gnu.node +0 -0
- package/dist/native/ast-grep-napi.linux-arm64-musl.node +0 -0
- package/dist/native/ast-grep-napi.linux-x64-gnu.node +0 -0
- package/dist/native/ast-grep-napi.linux-x64-musl.node +0 -0
- package/dist/native/ast-grep-napi.win32-x64-msvc.node +0 -0
- package/dist/native-bootstrap.d.ts +15 -0
- package/dist/native-bootstrap.d.ts.map +1 -0
- package/dist/native-bootstrap.js +75 -0
- package/dist/native-bootstrap.js.map +1 -0
- package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
- package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
- package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
- package/dist/reporting/reportGenerator.d.ts.map +1 -1
- package/dist/reporting/reportGenerator.js +4 -0
- package/dist/reporting/reportGenerator.js.map +1 -1
- package/dist/reporting/sarifReportGenerator.d.ts +39 -0
- package/dist/reporting/sarifReportGenerator.d.ts.map +1 -0
- package/dist/reporting/sarifReportGenerator.js +229 -0
- package/dist/reporting/sarifReportGenerator.js.map +1 -0
- package/dist/search/QueryParser.d.ts +41 -0
- package/dist/search/QueryParser.d.ts.map +1 -1
- package/dist/search/QueryParser.js +200 -19
- package/dist/search/QueryParser.js.map +1 -1
- package/dist/services/CodeMapGenerator.d.ts.map +1 -1
- package/dist/services/CodeMapGenerator.js +4 -4
- package/dist/services/CodeMapGenerator.js.map +1 -1
- package/dist/services/ProjectTaskRepository.d.ts +15 -2
- package/dist/services/ProjectTaskRepository.d.ts.map +1 -1
- package/dist/services/ProjectTaskRepository.js +16 -1
- package/dist/services/ProjectTaskRepository.js.map +1 -1
- package/dist/services/SchemaParser.d.ts.map +1 -1
- package/dist/services/SchemaParser.js +5 -8
- package/dist/services/SchemaParser.js.map +1 -1
- package/dist/services/auditJobService.d.ts +1 -1
- package/dist/services/projectTaskHelpers.js.map +1 -1
- package/dist/services/whitelistService.d.ts.map +1 -1
- package/dist/services/whitelistService.js +1 -1
- package/dist/services/whitelistService.js.map +1 -1
- package/dist/tool-registry.d.ts +79 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +139 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/types/projectTask.d.ts +4 -0
- package/dist/types/projectTask.d.ts.map +1 -1
- package/dist/types.d.ts +26 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/InteractivePrompts.d.ts.map +1 -1
- package/dist/ui/InteractivePrompts.js.map +1 -1
- package/dist/utils/astParser.d.ts +31 -38
- package/dist/utils/astParser.d.ts.map +1 -1
- package/dist/utils/astParser.js +138 -196
- package/dist/utils/astParser.js.map +1 -1
- package/dist/utils/astUtils.d.ts +87 -58
- package/dist/utils/astUtils.d.ts.map +1 -1
- package/dist/utils/astUtils.js +852 -581
- package/dist/utils/astUtils.js.map +1 -1
- package/dist/utils/componentPatterns.js.map +1 -1
- package/dist/utils/componentResponsibility.d.ts +13 -9
- package/dist/utils/componentResponsibility.d.ts.map +1 -1
- package/dist/utils/componentResponsibility.js +236 -206
- package/dist/utils/componentResponsibility.js.map +1 -1
- package/dist/utils/dependencyExtractor.d.ts +11 -6
- package/dist/utils/dependencyExtractor.d.ts.map +1 -1
- package/dist/utils/dependencyExtractor.js +200 -119
- package/dist/utils/dependencyExtractor.js.map +1 -1
- package/dist/utils/fileDiscovery.d.ts +1 -1
- package/dist/utils/fileDiscovery.d.ts.map +1 -1
- package/dist/utils/fileDiscovery.js +15 -6
- package/dist/utils/fileDiscovery.js.map +1 -1
- package/dist/utils/jsDocParser.d.ts +27 -30
- package/dist/utils/jsDocParser.d.ts.map +1 -1
- package/dist/utils/jsDocParser.js +271 -207
- package/dist/utils/jsDocParser.js.map +1 -1
- package/dist/utils/reactDetection.d.ts +27 -12
- package/dist/utils/reactDetection.d.ts.map +1 -1
- package/dist/utils/reactDetection.js +331 -219
- package/dist/utils/reactDetection.js.map +1 -1
- package/dist/workers/auditWorker.js +17 -3
- package/dist/workers/auditWorker.js.map +1 -1
- package/package.json +54 -51
- package/dist/adapters/GoAdapter.d.ts +0 -53
- package/dist/adapters/GoAdapter.d.ts.map +0 -1
- package/dist/adapters/GoAdapter.js +0 -611
- package/dist/adapters/GoAdapter.js.map +0 -1
- package/dist/adapters/GoConfig.d.ts +0 -35
- package/dist/adapters/GoConfig.d.ts.map +0 -1
- package/dist/adapters/GoConfig.js +0 -155
- package/dist/adapters/GoConfig.js.map +0 -1
- package/dist/adapters/LanguageAdapter.d.ts +0 -135
- package/dist/adapters/LanguageAdapter.d.ts.map +0 -1
- package/dist/adapters/LanguageAdapter.js +0 -47
- package/dist/adapters/LanguageAdapter.js.map +0 -1
- package/dist/adapters/TypeScriptAdapter.d.ts +0 -43
- package/dist/adapters/TypeScriptAdapter.d.ts.map +0 -1
- package/dist/adapters/TypeScriptAdapter.js +0 -386
- package/dist/adapters/TypeScriptAdapter.js.map +0 -1
- package/dist/adapters/UniversalAnalyzer.d.ts +0 -42
- package/dist/adapters/UniversalAnalyzer.d.ts.map +0 -1
- package/dist/adapters/UniversalAnalyzer.js +0 -103
- package/dist/adapters/UniversalAnalyzer.js.map +0 -1
- package/dist/adapters/UniversalSOLIDAnalyzer.d.ts +0 -48
- package/dist/adapters/UniversalSOLIDAnalyzer.d.ts.map +0 -1
- package/dist/adapters/UniversalSOLIDAnalyzer.js +0 -178
- package/dist/adapters/UniversalSOLIDAnalyzer.js.map +0 -1
- package/dist/adapters/solidAnalyzerCompat.d.ts +0 -21
- package/dist/adapters/solidAnalyzerCompat.d.ts.map +0 -1
- package/dist/adapters/solidAnalyzerCompat.js +0 -78
- package/dist/adapters/solidAnalyzerCompat.js.map +0 -1
- package/dist/analyzers/dataAccessAnalyzerCompat.d.ts +0 -20
- package/dist/analyzers/dataAccessAnalyzerCompat.d.ts.map +0 -1
- package/dist/analyzers/dataAccessAnalyzerCompat.js +0 -59
- package/dist/analyzers/dataAccessAnalyzerCompat.js.map +0 -1
- package/dist/analyzers/documentationAnalyzerCompat.d.ts +0 -20
- package/dist/analyzers/documentationAnalyzerCompat.d.ts.map +0 -1
- package/dist/analyzers/documentationAnalyzerCompat.js +0 -52
- package/dist/analyzers/documentationAnalyzerCompat.js.map +0 -1
- package/dist/analyzers/dryAnalyzerCompat.d.ts +0 -20
- package/dist/analyzers/dryAnalyzerCompat.d.ts.map +0 -1
- package/dist/analyzers/dryAnalyzerCompat.js +0 -44
- package/dist/analyzers/dryAnalyzerCompat.js.map +0 -1
- package/dist/analyzers/schemaAnalyzerCompat.d.ts +0 -20
- package/dist/analyzers/schemaAnalyzerCompat.d.ts.map +0 -1
- package/dist/analyzers/schemaAnalyzerCompat.js +0 -69
- package/dist/analyzers/schemaAnalyzerCompat.js.map +0 -1
- package/dist/analyzers/solidAnalyzerCompat.d.ts +0 -20
- package/dist/analyzers/solidAnalyzerCompat.d.ts.map +0 -1
- package/dist/analyzers/solidAnalyzerCompat.js +0 -78
- package/dist/analyzers/solidAnalyzerCompat.js.map +0 -1
- package/dist/codeIndexDb.d.ts.map +0 -1
- package/dist/codeIndexDb.js +0 -2102
- package/dist/codeIndexDb.js.map +0 -1
- package/dist/languages/typescript/TypeScriptAdapter.d.ts +0 -108
- package/dist/languages/typescript/TypeScriptAdapter.d.ts.map +0 -1
- package/dist/languages/typescript/TypeScriptAdapter.js +0 -567
- package/dist/languages/typescript/TypeScriptAdapter.js.map +0 -1
- package/dist/languages/typescript/test-extraction.d.ts +0 -2
- package/dist/languages/typescript/test-extraction.d.ts.map +0 -1
- package/dist/languages/typescript/test-extraction.js +0 -36
- package/dist/languages/typescript/test-extraction.js.map +0 -1
- package/dist/mcp-hybrid.d.ts +0 -10
- package/dist/mcp-hybrid.d.ts.map +0 -1
- package/dist/mcp-hybrid.js +0 -41
- package/dist/mcp-hybrid.js.map +0 -1
- package/dist/mcp-index.d.ts +0 -13
- package/dist/mcp-index.d.ts.map +0 -1
- package/dist/mcp-index.js +0 -136
- package/dist/mcp-index.js.map +0 -1
- package/dist/mcp-standalone.d.ts +0 -3
- package/dist/mcp-standalone.d.ts.map +0 -1
- package/dist/mcp-standalone.js +0 -1324
- package/dist/mcp-standalone.js.map +0 -1
- package/dist/mcp-ui-server.d.ts +0 -27
- package/dist/mcp-ui-server.d.ts.map +0 -1
- package/dist/mcp-ui-server.js +0 -484
- package/dist/mcp-ui-server.js.map +0 -1
- package/dist/test-multi-strategy-search.d.ts +0 -3
- package/dist/test-multi-strategy-search.d.ts.map +0 -1
- package/dist/test-multi-strategy-search.js +0 -170
- package/dist/test-multi-strategy-search.js.map +0 -1
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Component Responsibility Detection Utilities
|
|
3
|
+
* Detects and categorizes responsibilities within React components
|
|
4
|
+
*/
|
|
5
|
+
import { walkAST, getLineAndColumn } from '../languages/adapterBridge.js';
|
|
2
6
|
import { ResponsibilityType } from '../types.js';
|
|
3
7
|
import { extractHooks } from './reactDetection.js';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/** Get raw text from a tree-sitter node (stored on ASTNode.raw). */
|
|
12
|
+
function rawText(node) {
|
|
13
|
+
return node.raw?.text ?? '';
|
|
14
|
+
}
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Main detection entry point
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
4
18
|
/**
|
|
5
19
|
* Detects and categorizes responsibilities within a React component
|
|
6
20
|
*/
|
|
7
|
-
export function detectComponentResponsibilities(
|
|
21
|
+
export function detectComponentResponsibilities(component, metadata) {
|
|
8
22
|
const responsibilities = [];
|
|
9
23
|
const seenTypes = new Set();
|
|
10
24
|
// Analyze different aspects of the component
|
|
11
|
-
const hookResponsibilities = analyzeHookUsage(
|
|
12
|
-
const eventResponsibilities = analyzeEventHandlers(
|
|
13
|
-
const effectResponsibilities = analyzeEffects(
|
|
14
|
-
const renderingResponsibilities = analyzeRenderingLogic(
|
|
25
|
+
const hookResponsibilities = analyzeHookUsage(component, metadata);
|
|
26
|
+
const eventResponsibilities = analyzeEventHandlers(component);
|
|
27
|
+
const effectResponsibilities = analyzeEffects(component);
|
|
28
|
+
const renderingResponsibilities = analyzeRenderingLogic(component);
|
|
15
29
|
// Combine and deduplicate responsibilities
|
|
16
30
|
[...hookResponsibilities, ...eventResponsibilities, ...effectResponsibilities, ...renderingResponsibilities]
|
|
17
31
|
.forEach(resp => {
|
|
@@ -34,58 +48,63 @@ export function detectComponentResponsibilities(sourceFile, component, metadata)
|
|
|
34
48
|
});
|
|
35
49
|
return responsibilities;
|
|
36
50
|
}
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Pattern detection helpers
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
37
54
|
/**
|
|
38
55
|
* Identifies data fetching patterns in code
|
|
39
56
|
*/
|
|
40
57
|
export function containsDataFetching(node) {
|
|
41
58
|
let hasDataFetching = false;
|
|
42
|
-
|
|
59
|
+
walkAST(node, (n) => {
|
|
43
60
|
// Check for fetch, axios, API calls
|
|
44
|
-
if (
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
47
|
-
callText
|
|
48
|
-
callText.includes('
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
if (n.type === 'call_expression') {
|
|
62
|
+
const exprNode = n.children?.[0]; // identifier or member_expression
|
|
63
|
+
if (exprNode) {
|
|
64
|
+
const callText = rawText(exprNode);
|
|
65
|
+
if (callText.includes('fetch') ||
|
|
66
|
+
callText.includes('axios') ||
|
|
67
|
+
callText.includes('api') ||
|
|
68
|
+
callText.includes('http') ||
|
|
69
|
+
callText.includes('request')) {
|
|
70
|
+
hasDataFetching = true;
|
|
71
|
+
}
|
|
52
72
|
}
|
|
53
73
|
}
|
|
54
74
|
// Check for async/await patterns
|
|
55
|
-
if (
|
|
75
|
+
if (n.type === 'await_expression') {
|
|
56
76
|
hasDataFetching = true;
|
|
57
77
|
}
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
checkNode(node);
|
|
78
|
+
});
|
|
61
79
|
return hasDataFetching;
|
|
62
80
|
}
|
|
63
81
|
/**
|
|
64
82
|
* Identifies form handling patterns
|
|
65
83
|
*/
|
|
66
|
-
export function containsFormHandling(node
|
|
84
|
+
export function containsFormHandling(node) {
|
|
67
85
|
let hasFormHandling = false;
|
|
68
|
-
|
|
86
|
+
walkAST(node, (n) => {
|
|
69
87
|
// Check for form-related method calls
|
|
70
|
-
if (
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
callText
|
|
74
|
-
callText.includes('
|
|
75
|
-
|
|
76
|
-
|
|
88
|
+
if (n.type === 'call_expression') {
|
|
89
|
+
const exprNode = n.children?.[0];
|
|
90
|
+
if (exprNode) {
|
|
91
|
+
const callText = rawText(exprNode);
|
|
92
|
+
if (callText.includes('preventDefault') ||
|
|
93
|
+
callText.includes('handleSubmit') ||
|
|
94
|
+
callText.includes('validate') ||
|
|
95
|
+
callText.includes('setFieldValue')) {
|
|
96
|
+
hasFormHandling = true;
|
|
97
|
+
}
|
|
77
98
|
}
|
|
78
99
|
}
|
|
79
|
-
// Check for form state patterns
|
|
80
|
-
if (
|
|
81
|
-
const text = n
|
|
100
|
+
// Check for form state patterns in identifiers
|
|
101
|
+
if (n.type === 'identifier') {
|
|
102
|
+
const text = rawText(n);
|
|
82
103
|
if (text.includes('form') || text.includes('Field') || text.includes('input')) {
|
|
83
104
|
hasFormHandling = true;
|
|
84
105
|
}
|
|
85
106
|
}
|
|
86
|
-
|
|
87
|
-
};
|
|
88
|
-
checkNode(node);
|
|
107
|
+
});
|
|
89
108
|
return hasFormHandling;
|
|
90
109
|
}
|
|
91
110
|
/**
|
|
@@ -95,38 +114,42 @@ export function containsBusinessLogic(node) {
|
|
|
95
114
|
let hasBusinessLogic = false;
|
|
96
115
|
let statementCount = 0;
|
|
97
116
|
let hasComplexConditions = false;
|
|
98
|
-
|
|
99
|
-
// Count statements in
|
|
100
|
-
if (
|
|
101
|
-
statementCount += n.
|
|
117
|
+
walkAST(node, (n) => {
|
|
118
|
+
// Count statements in blocks
|
|
119
|
+
if (n.type === 'statement_block') {
|
|
120
|
+
statementCount += (n.children ?? []).length;
|
|
102
121
|
}
|
|
103
122
|
// Check for complex conditions
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
const conditionText = n.getFullText();
|
|
123
|
+
if (n.type === 'if_statement' || n.type === 'ternary_expression') {
|
|
124
|
+
const conditionText = rawText(n);
|
|
107
125
|
if (conditionText.includes('&&') && conditionText.includes('||')) {
|
|
108
126
|
hasComplexConditions = true;
|
|
109
127
|
}
|
|
110
128
|
}
|
|
111
|
-
// Check for calculations or transformations
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
// Check for calculations or transformations (binary expressions)
|
|
130
|
+
if (n.type === 'binary_expression') {
|
|
131
|
+
// Check operator token in raw tree-sitter children
|
|
132
|
+
const raw = n.raw;
|
|
133
|
+
const opChild = raw?.children?.find(c => !c.isNamed);
|
|
134
|
+
if (opChild && (opChild.type === '*' || opChild.type === '/' || opChild.type === '%')) {
|
|
117
135
|
hasBusinessLogic = true;
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
// Check for array operations suggesting data transformation
|
|
121
|
-
if (
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
|
|
139
|
+
if (n.type === 'call_expression') {
|
|
140
|
+
const exprNode = n.children?.[0];
|
|
141
|
+
if (exprNode && exprNode.type === 'member_expression') {
|
|
142
|
+
// Property of member expression is the last child
|
|
143
|
+
const propNode = exprNode.children?.[exprNode.children.length - 1];
|
|
144
|
+
if (propNode) {
|
|
145
|
+
const methodName = rawText(propNode);
|
|
146
|
+
if (['map', 'filter', 'reduce', 'sort', 'groupBy'].includes(methodName)) {
|
|
147
|
+
hasBusinessLogic = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
125
150
|
}
|
|
126
151
|
}
|
|
127
|
-
|
|
128
|
-
};
|
|
129
|
-
checkNode(node);
|
|
152
|
+
});
|
|
130
153
|
// Consider it business logic if there are complex conditions or many statements
|
|
131
154
|
return hasBusinessLogic || (statementCount > 10 && hasComplexConditions);
|
|
132
155
|
}
|
|
@@ -153,12 +176,15 @@ export function areResponsibilitiesRelated(resp1, resp2) {
|
|
|
153
176
|
];
|
|
154
177
|
return relatedGroups.some(group => group.includes(resp1) && group.includes(resp2));
|
|
155
178
|
}
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// Sub-analyzers
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
156
182
|
/**
|
|
157
183
|
* Analyzes hook usage to identify responsibilities
|
|
158
184
|
*/
|
|
159
|
-
export function analyzeHookUsage(
|
|
185
|
+
export function analyzeHookUsage(component, metadata) {
|
|
160
186
|
const responsibilities = [];
|
|
161
|
-
const hooks = metadata?.hooks || extractHooks(component
|
|
187
|
+
const hooks = metadata?.hooks || extractHooks(component);
|
|
162
188
|
// Define hook groups that represent cohesive responsibilities
|
|
163
189
|
const hookGroups = {
|
|
164
190
|
state: {
|
|
@@ -208,21 +234,7 @@ export function analyzeHookUsage(sourceFile, component, metadata) {
|
|
|
208
234
|
});
|
|
209
235
|
}
|
|
210
236
|
}
|
|
211
|
-
// Group hooks by type for backward compatibility
|
|
212
|
-
const stateHooks = hooks.filter(h => h.name === 'useState' || h.name === 'useReducer');
|
|
213
|
-
const effectHooks = hooks.filter(h => h.name === 'useEffect' || h.name === 'useLayoutEffect');
|
|
214
|
-
const contextHooks = hooks.filter(h => h.name === 'useContext');
|
|
215
|
-
const routerHooks = hooks.filter(h => h.name === 'useRouter' || h.name === 'useNavigate' || h.name === 'useParams' || h.name === 'useSearchParams');
|
|
216
237
|
const customHooks = hooks.filter(h => h.customHook);
|
|
217
|
-
// Additional analysis for custom hooks only (standard hooks already handled by groups)
|
|
218
|
-
const uncategorizedHooks = hooks.filter(hook => {
|
|
219
|
-
// Skip if already in a group
|
|
220
|
-
for (const [_, hookNames] of usedGroups.entries()) {
|
|
221
|
-
if (hookNames.includes(hook.name))
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
return true;
|
|
225
|
-
});
|
|
226
238
|
// Analyze custom hooks for mixed responsibilities
|
|
227
239
|
if (customHooks.length > 0) {
|
|
228
240
|
customHooks.forEach(hook => {
|
|
@@ -250,116 +262,110 @@ export function analyzeHookUsage(sourceFile, component, metadata) {
|
|
|
250
262
|
/**
|
|
251
263
|
* Analyzes useEffect hooks for side effects and data fetching
|
|
252
264
|
*/
|
|
253
|
-
export function analyzeEffects(
|
|
265
|
+
export function analyzeEffects(component) {
|
|
254
266
|
const responsibilities = [];
|
|
255
|
-
ts.forEachChild
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
(node.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
267
|
+
// Walk children only, not the component node itself (matches old ts.forEachChild behavior)
|
|
268
|
+
for (const child of component.children ?? []) {
|
|
269
|
+
walkAST(child, (node) => {
|
|
270
|
+
if (node.type === 'call_expression') {
|
|
271
|
+
const callee = node.children?.[0];
|
|
272
|
+
if (callee && callee.type === 'identifier') {
|
|
273
|
+
const calleeText = rawText(callee);
|
|
274
|
+
if (calleeText === 'useEffect' || calleeText === 'useLayoutEffect') {
|
|
275
|
+
const argsNode = node.children?.find(c => c.type === 'arguments');
|
|
276
|
+
const argList = argsNode?.children ?? [];
|
|
277
|
+
// First argument is the effect callback
|
|
278
|
+
const effectBody = argList.find(c => c.type !== '(' && c.type !== ')');
|
|
279
|
+
if (effectBody) {
|
|
280
|
+
const effectText = rawText(effectBody);
|
|
281
|
+
const { line } = getLineAndColumn(node);
|
|
282
|
+
// Check for data fetching
|
|
283
|
+
if (containsDataFetching(effectBody)) {
|
|
284
|
+
responsibilities.push({
|
|
285
|
+
type: ResponsibilityType.DataFetching,
|
|
286
|
+
indicators: ['fetch in useEffect', 'async data loading'],
|
|
287
|
+
severity: 'mixed',
|
|
288
|
+
line,
|
|
289
|
+
details: 'Data fetching in effect hook'
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
// Check for subscriptions
|
|
293
|
+
if (effectText.match(/addEventListener|subscribe|on\(/)) {
|
|
294
|
+
responsibilities.push({
|
|
295
|
+
type: ResponsibilityType.Subscriptions,
|
|
296
|
+
indicators: ['event subscription', 'listener setup'],
|
|
297
|
+
severity: 'mixed',
|
|
298
|
+
line
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
// Check for side effects (analytics, logging)
|
|
302
|
+
if (effectText.match(/track|analytics|log|console|gtag|ga\(/i)) {
|
|
303
|
+
responsibilities.push({
|
|
304
|
+
type: ResponsibilityType.SideEffects,
|
|
305
|
+
indicators: ['analytics', 'tracking', 'logging'],
|
|
306
|
+
severity: 'unrelated',
|
|
307
|
+
line,
|
|
308
|
+
details: 'Analytics/logging side effects'
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
292
313
|
}
|
|
293
314
|
}
|
|
294
|
-
}
|
|
295
|
-
ts.forEachChild(node, visit);
|
|
296
|
-
});
|
|
297
|
-
return responsibilities;
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Helper to find a node at a specific line number
|
|
301
|
-
*/
|
|
302
|
-
function findNodeAtLine(root, targetLine) {
|
|
303
|
-
let result = null;
|
|
304
|
-
function visit(node) {
|
|
305
|
-
if (result)
|
|
306
|
-
return;
|
|
307
|
-
const sourceFile = node.getSourceFile();
|
|
308
|
-
if (sourceFile) {
|
|
309
|
-
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
310
|
-
if (line + 1 === targetLine) {
|
|
311
|
-
result = node;
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
ts.forEachChild(node, visit);
|
|
315
|
+
});
|
|
316
316
|
}
|
|
317
|
-
|
|
318
|
-
return result;
|
|
317
|
+
return responsibilities;
|
|
319
318
|
}
|
|
320
319
|
/**
|
|
321
320
|
* Analyzes event handlers in a component
|
|
322
321
|
*/
|
|
323
|
-
export function analyzeEventHandlers(
|
|
322
|
+
export function analyzeEventHandlers(component) {
|
|
324
323
|
const responsibilities = [];
|
|
325
324
|
const eventHandlers = [];
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
325
|
+
// Walk children only, not the component node itself
|
|
326
|
+
for (const child of component.children ?? []) {
|
|
327
|
+
walkAST(child, (node) => {
|
|
328
|
+
// Check JSX attributes for event handlers
|
|
329
|
+
if (node.type === 'jsx_attribute') {
|
|
330
|
+
const nameNode = node.children?.find(c => c.type === 'property_identifier');
|
|
331
|
+
if (nameNode) {
|
|
332
|
+
const attrName = rawText(nameNode);
|
|
333
|
+
if (attrName.startsWith('on')) {
|
|
334
|
+
const { line } = getLineAndColumn(node);
|
|
335
|
+
// Calculate complexity of the handler
|
|
336
|
+
let complexity = 0;
|
|
337
|
+
const initializer = node.children?.find(c => c.type === 'jsx_expression');
|
|
338
|
+
if (initializer) {
|
|
339
|
+
// The expression inside jsx_expression (skip `{` and `}`)
|
|
340
|
+
const expr = initializer.children?.find(c => c.type !== '{' && c.type !== '}');
|
|
341
|
+
if (expr && (expr.type === 'arrow_function' || expr.type === 'function_expression')) {
|
|
342
|
+
complexity = calculateHandlerComplexity(expr);
|
|
343
|
+
}
|
|
340
344
|
}
|
|
345
|
+
eventHandlers.push({
|
|
346
|
+
name: attrName,
|
|
347
|
+
complexity,
|
|
348
|
+
line
|
|
349
|
+
});
|
|
341
350
|
}
|
|
342
351
|
}
|
|
343
|
-
eventHandlers.push({
|
|
344
|
-
name: attrName,
|
|
345
|
-
complexity,
|
|
346
|
-
line: line + 1
|
|
347
|
-
});
|
|
348
352
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
353
|
+
// Check for method definitions that look like event handlers
|
|
354
|
+
if (node.type === 'method_definition' || node.type === 'public_field_definition') {
|
|
355
|
+
const nameNode = node.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
|
|
356
|
+
if (nameNode) {
|
|
357
|
+
const name = rawText(nameNode);
|
|
358
|
+
if (name.match(/^(handle|on)[A-Z]/)) {
|
|
359
|
+
const { line } = getLineAndColumn(node);
|
|
360
|
+
const complexity = node.type === 'method_definition'
|
|
361
|
+
? calculateHandlerComplexity(node)
|
|
362
|
+
: 0;
|
|
363
|
+
eventHandlers.push({ name, complexity, line });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
359
366
|
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
});
|
|
367
|
+
});
|
|
368
|
+
}
|
|
363
369
|
// Analyze the collected event handlers
|
|
364
370
|
if (eventHandlers.length > 0) {
|
|
365
371
|
// Check for complex business logic in handlers
|
|
@@ -401,64 +407,88 @@ export function analyzeEventHandlers(sourceFile, component) {
|
|
|
401
407
|
*/
|
|
402
408
|
function calculateHandlerComplexity(node) {
|
|
403
409
|
let lineCount = 0;
|
|
404
|
-
|
|
405
|
-
if (
|
|
406
|
-
|
|
407
|
-
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
408
|
-
lineCount = end.line - start.line + 1;
|
|
410
|
+
// Use location for line span calculation
|
|
411
|
+
if (node.location?.start && node.location?.end) {
|
|
412
|
+
lineCount = node.location.end.line - node.location.start.line + 1;
|
|
409
413
|
}
|
|
410
414
|
// Also check for complexity indicators
|
|
411
|
-
|
|
415
|
+
const hasBusinessLogic = containsBusinessLogic(node);
|
|
412
416
|
return hasBusinessLogic ? lineCount * 1.5 : lineCount;
|
|
413
417
|
}
|
|
414
418
|
/**
|
|
415
419
|
* Analyzes rendering logic and JSX complexity
|
|
416
420
|
*/
|
|
417
|
-
export function analyzeRenderingLogic(
|
|
421
|
+
export function analyzeRenderingLogic(component) {
|
|
418
422
|
const responsibilities = [];
|
|
419
423
|
let jsxElementCount = 0;
|
|
420
424
|
let conditionalRenderCount = 0;
|
|
421
425
|
let hasComplexStyling = false;
|
|
422
426
|
let hasLayoutLogic = false;
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
427
|
+
// Walk children only, not the component node itself
|
|
428
|
+
for (const child of component.children ?? []) {
|
|
429
|
+
walkAST(child, (node) => {
|
|
430
|
+
// Count JSX elements
|
|
431
|
+
if (node.type === 'jsx_element') {
|
|
432
|
+
jsxElementCount++;
|
|
433
|
+
// Check for layout components — find tag name from open_tag child
|
|
434
|
+
const openTag = node.children?.find(c => c.type === 'open_tag');
|
|
435
|
+
if (openTag) {
|
|
436
|
+
const tagNode = openTag.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
|
|
437
|
+
if (tagNode) {
|
|
438
|
+
const tagName = rawText(tagNode);
|
|
439
|
+
if (tagName.match(/Grid|Flex|Layout|Container|Row|Col/i)) {
|
|
440
|
+
hasLayoutLogic = true;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
433
444
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
const styleExpr = node.initializer.expression;
|
|
444
|
-
if (styleExpr && !ts.isObjectLiteralExpression(styleExpr)) {
|
|
445
|
-
// Dynamic style calculation
|
|
446
|
-
hasComplexStyling = true;
|
|
445
|
+
if (node.type === 'jsx_self_closing_element') {
|
|
446
|
+
jsxElementCount++;
|
|
447
|
+
// Check tag name (first named child that's not `<`)
|
|
448
|
+
const tagNode = node.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
|
|
449
|
+
if (tagNode) {
|
|
450
|
+
const tagName = rawText(tagNode);
|
|
451
|
+
if (tagName.match(/Grid|Flex|Layout|Container|Row|Col/i)) {
|
|
452
|
+
hasLayoutLogic = true;
|
|
453
|
+
}
|
|
447
454
|
}
|
|
448
455
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if (classExpr && !ts.isStringLiteral(classExpr)) {
|
|
455
|
-
// Dynamic className
|
|
456
|
-
hasComplexStyling = true;
|
|
456
|
+
// Check for conditional rendering (ternary in JSX expression or return statement)
|
|
457
|
+
if (node.type === 'ternary_expression' && node.parent) {
|
|
458
|
+
const parentType = node.parent.type;
|
|
459
|
+
if (parentType === 'jsx_expression' || parentType === 'return_statement') {
|
|
460
|
+
conditionalRenderCount++;
|
|
457
461
|
}
|
|
458
462
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
463
|
+
// Check for complex styling logic
|
|
464
|
+
if (node.type === 'jsx_attribute') {
|
|
465
|
+
const nameNode = node.children?.find(c => c.type === 'property_identifier');
|
|
466
|
+
if (nameNode) {
|
|
467
|
+
const attrName = rawText(nameNode);
|
|
468
|
+
if (attrName === 'style') {
|
|
469
|
+
const jsxExpr = node.children?.find(c => c.type === 'jsx_expression');
|
|
470
|
+
if (jsxExpr) {
|
|
471
|
+
const styleExpr = jsxExpr.children?.find(c => c.type !== '{' && c.type !== '}');
|
|
472
|
+
if (styleExpr && styleExpr.type !== 'object') {
|
|
473
|
+
// Dynamic style calculation
|
|
474
|
+
hasComplexStyling = true;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (attrName === 'className') {
|
|
479
|
+
const jsxExpr = node.children?.find(c => c.type === 'jsx_expression');
|
|
480
|
+
if (jsxExpr) {
|
|
481
|
+
const classExpr = jsxExpr.children?.find(c => c.type !== '{' && c.type !== '}');
|
|
482
|
+
if (classExpr && classExpr.type !== 'string') {
|
|
483
|
+
// Dynamic className
|
|
484
|
+
hasComplexStyling = true;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
}
|
|
462
492
|
// Add layout responsibility only if it's significant
|
|
463
493
|
// Don't flag basic styling in forms or simple components
|
|
464
494
|
if ((hasLayoutLogic && jsxElementCount > 20) || (hasComplexStyling && !hasLayoutLogic)) {
|