@devflow-tools/plugin-react 0.12.6 → 0.13.0

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.
Files changed (57) hide show
  1. package/dist/analyzers/__tests__/diagnose-bug.test.d.ts +2 -0
  2. package/dist/analyzers/__tests__/diagnose-bug.test.d.ts.map +1 -0
  3. package/dist/analyzers/__tests__/diagnose-bug.test.js +45 -0
  4. package/dist/analyzers/__tests__/diagnose-bug.test.js.map +1 -0
  5. package/dist/analyzers/__tests__/file-scanner.test.d.ts +2 -0
  6. package/dist/analyzers/__tests__/file-scanner.test.d.ts.map +1 -0
  7. package/dist/analyzers/__tests__/file-scanner.test.js +32 -0
  8. package/dist/analyzers/__tests__/file-scanner.test.js.map +1 -0
  9. package/dist/analyzers/__tests__/hooks-review.test.d.ts +2 -0
  10. package/dist/analyzers/__tests__/hooks-review.test.d.ts.map +1 -0
  11. package/dist/analyzers/__tests__/hooks-review.test.js +185 -0
  12. package/dist/analyzers/__tests__/hooks-review.test.js.map +1 -0
  13. package/dist/analyzers/__tests__/new-component.test.d.ts +2 -0
  14. package/dist/analyzers/__tests__/new-component.test.d.ts.map +1 -0
  15. package/dist/analyzers/__tests__/new-component.test.js +40 -0
  16. package/dist/analyzers/__tests__/new-component.test.js.map +1 -0
  17. package/dist/analyzers/__tests__/performance-audit.test.d.ts +2 -0
  18. package/dist/analyzers/__tests__/performance-audit.test.d.ts.map +1 -0
  19. package/dist/analyzers/__tests__/performance-audit.test.js +109 -0
  20. package/dist/analyzers/__tests__/performance-audit.test.js.map +1 -0
  21. package/dist/analyzers/__tests__/refactor-component.test.d.ts +2 -0
  22. package/dist/analyzers/__tests__/refactor-component.test.d.ts.map +1 -0
  23. package/dist/analyzers/__tests__/refactor-component.test.js +65 -0
  24. package/dist/analyzers/__tests__/refactor-component.test.js.map +1 -0
  25. package/dist/analyzers/diagnose-bug.d.ts +9 -0
  26. package/dist/analyzers/diagnose-bug.d.ts.map +1 -0
  27. package/dist/analyzers/diagnose-bug.js +108 -0
  28. package/dist/analyzers/diagnose-bug.js.map +1 -0
  29. package/dist/analyzers/file-scanner.d.ts +16 -0
  30. package/dist/analyzers/file-scanner.d.ts.map +1 -0
  31. package/dist/analyzers/file-scanner.js +143 -0
  32. package/dist/analyzers/file-scanner.js.map +1 -0
  33. package/dist/analyzers/hooks-review.d.ts +10 -0
  34. package/dist/analyzers/hooks-review.d.ts.map +1 -0
  35. package/dist/analyzers/hooks-review.js +307 -0
  36. package/dist/analyzers/hooks-review.js.map +1 -0
  37. package/dist/analyzers/new-component.d.ts +12 -0
  38. package/dist/analyzers/new-component.d.ts.map +1 -0
  39. package/dist/analyzers/new-component.js +59 -0
  40. package/dist/analyzers/new-component.js.map +1 -0
  41. package/dist/analyzers/performance-audit.d.ts +10 -0
  42. package/dist/analyzers/performance-audit.d.ts.map +1 -0
  43. package/dist/analyzers/performance-audit.js +239 -0
  44. package/dist/analyzers/performance-audit.js.map +1 -0
  45. package/dist/analyzers/refactor-component.d.ts +3 -0
  46. package/dist/analyzers/refactor-component.d.ts.map +1 -0
  47. package/dist/analyzers/refactor-component.js +90 -0
  48. package/dist/analyzers/refactor-component.js.map +1 -0
  49. package/dist/analyzers/types.d.ts +27 -0
  50. package/dist/analyzers/types.d.ts.map +1 -0
  51. package/dist/analyzers/types.js +2 -0
  52. package/dist/analyzers/types.js.map +1 -0
  53. package/dist/index.d.ts +3 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +1861 -0
  56. package/dist/index.js.map +1 -0
  57. package/package.json +3 -3
@@ -0,0 +1,108 @@
1
+ import { readFileContent, getRelativePath } from './file-scanner.js';
2
+ import { readdirSync, statSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { execSync } from 'child_process';
5
+ export function diagnoseBug(input) {
6
+ const { projectRoot, errorMessage, stackTrace } = input;
7
+ const rootCauses = [];
8
+ // Parse error type
9
+ const isNullAccess = /Cannot read propert.*null|Cannot read propert.*undefined/.test(errorMessage);
10
+ const isRenderError = /render|jsx|component/i.test(errorMessage);
11
+ // Scan files for common patterns
12
+ const files = scanProjectFiles(projectRoot);
13
+ for (const file of files) {
14
+ const content = readFileContent(file);
15
+ const relPath = getRelativePath(projectRoot, file);
16
+ const lines = content.split('\n');
17
+ // Check for null/undefined access patterns
18
+ if (isNullAccess) {
19
+ for (let i = 0; i < lines.length; i++) {
20
+ const line = lines[i];
21
+ if (/\w+\.\w+\.\w+/.test(line) && !/\?\.|&&|\|\||\?/.test(line)) {
22
+ if (!/import|from|type|interface/.test(line)) {
23
+ rootCauses.push({
24
+ probability: 'medium',
25
+ description: '链式属性访问缺少空值检查',
26
+ file: relPath,
27
+ line: i + 1,
28
+ evidence: line.trim(),
29
+ fix: '使用可选链操作符 ?. 或添加空值检查',
30
+ });
31
+ }
32
+ }
33
+ }
34
+ }
35
+ // Check for missing keys in lists
36
+ if (isRenderError) {
37
+ for (let i = 0; i < lines.length; i++) {
38
+ if (/\.map\s*\(.*=>\s*<\w+/.test(lines[i]) && !/key=/.test(lines[i])) {
39
+ rootCauses.push({
40
+ probability: 'medium',
41
+ description: '列表渲染缺少 key 属性',
42
+ file: relPath,
43
+ line: i + 1,
44
+ evidence: lines[i].trim(),
45
+ fix: '为列表项添加唯一的 key 属性',
46
+ });
47
+ }
48
+ }
49
+ }
50
+ }
51
+ // Get recent git changes
52
+ let recentChanges = [];
53
+ try {
54
+ const gitLog = execSync('git log --oneline -5', { cwd: projectRoot, encoding: 'utf-8' });
55
+ recentChanges = gitLog.trim().split('\n');
56
+ }
57
+ catch { }
58
+ // Extract file from stack trace
59
+ let relevantFile;
60
+ let relevantLine;
61
+ if (stackTrace) {
62
+ const fileMatch = stackTrace.match(/(?:at\s+\w+\s+\()?([^(]+:\d+):?\d*\)?/);
63
+ if (fileMatch) {
64
+ const [file, line] = fileMatch[1].split(':');
65
+ relevantFile = file;
66
+ relevantLine = parseInt(line);
67
+ }
68
+ }
69
+ return {
70
+ success: true,
71
+ summary: `分析错误 "${errorMessage.substring(0, 50)}...",发现 ${rootCauses.length} 个可能原因`,
72
+ data: { rootCauses, recentChanges, relevantFile, relevantLine },
73
+ findings: rootCauses.map(rc => ({
74
+ severity: rc.probability === 'high' ? 'critical' : 'warning',
75
+ category: 'bug-root-cause',
76
+ title: rc.description,
77
+ description: rc.evidence ?? rc.description,
78
+ file: rc.file,
79
+ line: rc.line,
80
+ suggestion: rc.fix,
81
+ })),
82
+ };
83
+ }
84
+ function scanProjectFiles(root) {
85
+ const files = [];
86
+ function walk(dir) {
87
+ try {
88
+ const entries = readdirSync(dir);
89
+ for (const entry of entries) {
90
+ if (['node_modules', 'dist', 'build', '.git'].includes(entry))
91
+ continue;
92
+ const fullPath = join(dir, entry);
93
+ try {
94
+ const stat = statSync(fullPath);
95
+ if (stat.isDirectory())
96
+ walk(fullPath);
97
+ else if (/\.(tsx?|jsx?)$/.test(entry))
98
+ files.push(fullPath);
99
+ }
100
+ catch { }
101
+ }
102
+ }
103
+ catch { }
104
+ }
105
+ walk(root);
106
+ return files;
107
+ }
108
+ //# sourceMappingURL=diagnose-bug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose-bug.js","sourceRoot":"","sources":["../../src/analyzers/diagnose-bug.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { AnalyzerContext } from './types.js';
2
+ export declare function scanFiles(root: string, options?: {
3
+ extensions?: string[];
4
+ ignore?: string[];
5
+ pattern?: RegExp;
6
+ }): AnalyzerContext;
7
+ export declare function readFileContent(filePath: string): string;
8
+ export declare function getRelativePath(root: string, filePath: string): string;
9
+ export declare function normalizeAnalyzerPath(filePath: string, projectRoot: string): string;
10
+ export declare function selectAnalyzerFiles(ctx: AnalyzerContext, options: {
11
+ filePath?: string;
12
+ componentName?: string;
13
+ scope: 'target' | 'related' | 'project';
14
+ matchComponent?: (file: string, componentName: string) => boolean;
15
+ }): string[];
16
+ //# sourceMappingURL=file-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-scanner.d.ts","sourceRoot":"","sources":["../../src/analyzers/file-scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,eAAe,CAuBjB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC;CACnE,GACA,MAAM,EAAE,CAuCV"}
@@ -0,0 +1,143 @@
1
+ import { readdirSync, statSync, readFileSync } from 'fs';
2
+ import { join, extname, relative, basename } from 'path';
3
+ const DEFAULT_IGNORE = ['node_modules', 'dist', 'build', '.git', '.next', 'coverage'];
4
+ const REACT_EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js'];
5
+ export function scanFiles(root, options) {
6
+ const extensions = options?.extensions ?? REACT_EXTENSIONS;
7
+ const ignore = options?.ignore ?? DEFAULT_IGNORE;
8
+ const files = [];
9
+ function walk(dir) {
10
+ const entries = readdirSync(dir);
11
+ for (const entry of entries) {
12
+ if (ignore.includes(entry))
13
+ continue;
14
+ const fullPath = join(dir, entry);
15
+ const stat = statSync(fullPath);
16
+ if (stat.isDirectory()) {
17
+ walk(fullPath);
18
+ }
19
+ else if (extensions.includes(extname(entry))) {
20
+ if (!options?.pattern || options.pattern.test(fullPath)) {
21
+ files.push(fullPath);
22
+ }
23
+ }
24
+ }
25
+ }
26
+ walk(root);
27
+ return { projectRoot: root, files };
28
+ }
29
+ export function readFileContent(filePath) {
30
+ return readFileSync(filePath, 'utf-8');
31
+ }
32
+ export function getRelativePath(root, filePath) {
33
+ return relative(root, filePath);
34
+ }
35
+ export function normalizeAnalyzerPath(filePath, projectRoot) {
36
+ return filePath.replace(projectRoot, '').replace(/\\/g, '/').replace(/^\/+/, '');
37
+ }
38
+ export function selectAnalyzerFiles(ctx, options) {
39
+ const { filePath, componentName, scope, matchComponent } = options;
40
+ if (scope === 'project')
41
+ return ctx.files;
42
+ const normalizedFilePath = filePath
43
+ ? normalizeAnalyzerPath(filePath, ctx.projectRoot)
44
+ : undefined;
45
+ const componentCandidates = buildComponentCandidates(componentName, normalizedFilePath);
46
+ if (normalizedFilePath) {
47
+ const exactFiles = ctx.files.filter((file) => {
48
+ const relPath = normalizeAnalyzerPath(getRelativePath(ctx.projectRoot, file), ctx.projectRoot);
49
+ return relPath === normalizedFilePath;
50
+ });
51
+ const fallbackFiles = exactFiles.length > 0
52
+ ? exactFiles
53
+ : findFallbackPathMatches(ctx, normalizedFilePath, componentCandidates);
54
+ if (scope === 'target') {
55
+ return fallbackFiles.length > 0 ? fallbackFiles : ctx.files;
56
+ }
57
+ const related = new Set(fallbackFiles);
58
+ const directory = parentDir(normalizedFilePath);
59
+ for (const file of ctx.files) {
60
+ if (related.size >= 5)
61
+ break;
62
+ const relPath = normalizeAnalyzerPath(getRelativePath(ctx.projectRoot, file), ctx.projectRoot);
63
+ if (directory && relPath.startsWith(directory)) {
64
+ related.add(file);
65
+ }
66
+ }
67
+ return related.size > 0 ? Array.from(related) : ctx.files;
68
+ }
69
+ if (componentName && matchComponent) {
70
+ const matched = ctx.files.filter((file) => componentCandidates.some((candidate) => matchComponent(file, candidate)));
71
+ if (matched.length > 0)
72
+ return matched;
73
+ }
74
+ return ctx.files;
75
+ }
76
+ function parentDir(filePath) {
77
+ const index = filePath.lastIndexOf('/');
78
+ return index >= 0 ? filePath.slice(0, index + 1) : '';
79
+ }
80
+ function findFallbackPathMatches(ctx, normalizedFilePath, componentCandidates) {
81
+ const targetPath = normalizedFilePath.replace(/\/+$/, '');
82
+ const targetDirectory = `${targetPath}/`;
83
+ const targetBaseName = basename(targetPath).toLowerCase();
84
+ const directoryMatches = [];
85
+ for (const file of ctx.files) {
86
+ const relPath = normalizeAnalyzerPath(getRelativePath(ctx.projectRoot, file), ctx.projectRoot);
87
+ const relPathLower = relPath.toLowerCase();
88
+ const relPathWithoutExt = relPathLower.replace(/\.[^.]+$/, '');
89
+ const fileBaseName = basename(relPathLower).replace(/\.[^.]+$/, '');
90
+ let score = 0;
91
+ if (relPathLower === targetPath.toLowerCase())
92
+ score += 5;
93
+ if (relPathWithoutExt === targetPath.toLowerCase())
94
+ score += 4;
95
+ if (relPathLower.startsWith(targetDirectory.toLowerCase()))
96
+ score += 3;
97
+ if (fileBaseName === targetBaseName)
98
+ score += 2;
99
+ if (componentCandidates.some((candidate) => candidate.toLowerCase() === fileBaseName))
100
+ score += 4;
101
+ if (score > 0) {
102
+ directoryMatches.push({ file, score });
103
+ }
104
+ }
105
+ return directoryMatches
106
+ .sort((a, b) => b.score - a.score || a.file.localeCompare(b.file))
107
+ .map((item) => item.file);
108
+ }
109
+ function buildComponentCandidates(componentName, normalizedFilePath) {
110
+ const values = new Set();
111
+ const addCandidate = (value) => {
112
+ if (!value)
113
+ return;
114
+ const trimmed = value.trim();
115
+ if (!trimmed)
116
+ return;
117
+ values.add(trimmed);
118
+ values.add(toPascalCase(trimmed));
119
+ values.add(toCamelCase(trimmed));
120
+ };
121
+ addCandidate(componentName);
122
+ if (normalizedFilePath) {
123
+ const fileBaseName = basename(normalizedFilePath).replace(/\.[^.]+$/, '');
124
+ addCandidate(fileBaseName);
125
+ const directoryBaseName = basename(normalizedFilePath.replace(/\/+$/, ''));
126
+ if (directoryBaseName && directoryBaseName !== fileBaseName) {
127
+ addCandidate(directoryBaseName);
128
+ }
129
+ }
130
+ return Array.from(values);
131
+ }
132
+ function toPascalCase(value) {
133
+ return value
134
+ .split(/[^a-zA-Z0-9]+/)
135
+ .filter(Boolean)
136
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
137
+ .join('');
138
+ }
139
+ function toCamelCase(value) {
140
+ const pascal = toPascalCase(value);
141
+ return pascal ? pascal.charAt(0).toLowerCase() + pascal.slice(1) : '';
142
+ }
143
+ //# sourceMappingURL=file-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-scanner.js","sourceRoot":"","sources":["../../src/analyzers/file-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { AnalysisResult, AnalyzerContext } from './types.js';
2
+ export interface HooksReviewOptions {
3
+ filePath?: string;
4
+ componentName?: string;
5
+ scope?: 'target' | 'related' | 'project';
6
+ maxFindings?: number;
7
+ outputMode?: 'summary' | 'focused' | 'full';
8
+ }
9
+ export declare function reviewHooks(ctx: AnalyzerContext, options?: HooksReviewOptions): AnalysisResult;
10
+ //# sourceMappingURL=hooks-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-review.d.ts","sourceRoot":"","sources":["../../src/analyzers/hooks-review.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAW,eAAe,EAAE,MAAM,YAAY,CAAC;AAS3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CAC7C;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,kBAAuB,GAC/B,cAAc,CAuGhB"}
@@ -0,0 +1,307 @@
1
+ import ts from 'typescript';
2
+ import { readFileContent, getRelativePath, selectAnalyzerFiles } from './file-scanner.js';
3
+ const BUILTIN_HOOKS = new Set([
4
+ 'useState', 'useEffect', 'useContext', 'useReducer', 'useCallback',
5
+ 'useMemo', 'useRef', 'useImperativeHandle', 'useLayoutEffect',
6
+ 'useDebugValue', 'useDeferredValue', 'useTransition', 'useId',
7
+ 'useSyncExternalStore', 'useInsertionEffect',
8
+ ]);
9
+ export function reviewHooks(ctx, options = {}) {
10
+ const scope = options.scope ?? (options.filePath || options.componentName ? 'target' : 'project');
11
+ const outputMode = options.outputMode ?? (scope === 'project' ? 'focused' : 'summary');
12
+ const maxFindings = normalizeMaxFindings(options.maxFindings, outputMode);
13
+ const selectedFiles = selectFiles(ctx, options, scope);
14
+ const findings = [];
15
+ const metrics = {
16
+ totalHookCalls: 0,
17
+ useState: 0,
18
+ useEffect: 0,
19
+ useMemo: 0,
20
+ useCallback: 0,
21
+ customHooks: 0,
22
+ violations: 0,
23
+ };
24
+ for (const file of selectedFiles) {
25
+ const content = readFileContent(file);
26
+ const relPath = getRelativePath(ctx.projectRoot, file);
27
+ const lines = content.split('\n');
28
+ const sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true, inferScriptKind(file));
29
+ collectHookMetrics(lines, sourceFile, metrics);
30
+ const hookViolations = findHookViolations(lines, sourceFile, relPath);
31
+ findings.push(...hookViolations);
32
+ metrics.violations += hookViolations.length;
33
+ // Check for missing cleanup in useEffect
34
+ const useEffectPattern = /useEffect\s*\(\s*\(\s*\)\s*=>\s*\{/g;
35
+ let match;
36
+ while ((match = useEffectPattern.exec(content)) !== null) {
37
+ const startIdx = match.index;
38
+ const lineNum = content.substring(0, startIdx).split('\n').length;
39
+ const blockEnd = findBlockEnd(content, startIdx);
40
+ const blockContent = content.substring(startIdx, blockEnd);
41
+ if (!/return\s*[\(\s]*\(\)\s*=>/.test(blockContent) && !/return\s*\{/.test(blockContent)) {
42
+ if (/(setInterval|setTimeout|addEventListener|subscribe|\.on\()/.test(blockContent)) {
43
+ findings.push({
44
+ severity: 'warning',
45
+ category: 'missing-cleanup',
46
+ title: 'useEffect 缺少清理函数',
47
+ description: 'useEffect 设置了定时器/监听器但未提供清理函数',
48
+ file: relPath,
49
+ line: lineNum,
50
+ suggestion: '添加 return () => { /* cleanup */ }',
51
+ });
52
+ metrics.violations++;
53
+ }
54
+ }
55
+ }
56
+ }
57
+ const criticalCount = findings.filter(f => f.severity === 'critical').length;
58
+ const warningCount = findings.filter(f => f.severity === 'warning').length;
59
+ const sortedFindings = sortFindings(findings, options);
60
+ const limitedFindings = outputMode === 'full'
61
+ ? sortedFindings
62
+ : sortedFindings.slice(0, maxFindings);
63
+ const truncated = limitedFindings.length < sortedFindings.length;
64
+ const targetLabel = describeTarget(options, scope);
65
+ const reportId = truncated ? buildReportId(targetLabel, selectedFiles) : undefined;
66
+ return {
67
+ success: true,
68
+ summary: buildSummary({
69
+ targetLabel,
70
+ scannedFiles: selectedFiles.length,
71
+ criticalCount,
72
+ warningCount,
73
+ totalFindings: sortedFindings.length,
74
+ shownFindings: limitedFindings.length,
75
+ truncated,
76
+ }),
77
+ findings: limitedFindings,
78
+ metrics: {
79
+ ...metrics,
80
+ scannedFiles: selectedFiles.length,
81
+ },
82
+ totalFindings: sortedFindings.length,
83
+ truncated,
84
+ reportId,
85
+ data: {
86
+ target: targetLabel,
87
+ scope,
88
+ outputMode,
89
+ scannedFiles: selectedFiles.map((file) => getRelativePath(ctx.projectRoot, file)),
90
+ totalFindings: sortedFindings.length,
91
+ shownFindings: limitedFindings.length,
92
+ truncated,
93
+ reportId,
94
+ },
95
+ _report: reportId ? {
96
+ target: targetLabel,
97
+ scope,
98
+ outputMode,
99
+ scannedFiles: selectedFiles.map((file) => getRelativePath(ctx.projectRoot, file)),
100
+ metrics: {
101
+ ...metrics,
102
+ scannedFiles: selectedFiles.length,
103
+ },
104
+ findings: sortedFindings,
105
+ } : undefined,
106
+ };
107
+ }
108
+ function findBlockEnd(content, startIdx) {
109
+ let depth = 0;
110
+ let inString = false;
111
+ let stringChar = '';
112
+ for (let i = startIdx; i < content.length; i++) {
113
+ const ch = content[i];
114
+ if (inString) {
115
+ if (ch === stringChar && content[i - 1] !== '\\')
116
+ inString = false;
117
+ continue;
118
+ }
119
+ if (ch === '"' || ch === "'" || ch === '`') {
120
+ inString = true;
121
+ stringChar = ch;
122
+ continue;
123
+ }
124
+ if (ch === '{')
125
+ depth++;
126
+ if (ch === '}') {
127
+ depth--;
128
+ if (depth === 0)
129
+ return i;
130
+ }
131
+ }
132
+ return content.length;
133
+ }
134
+ function normalizeMaxFindings(maxFindings, outputMode) {
135
+ if (outputMode === 'full')
136
+ return Number.MAX_SAFE_INTEGER;
137
+ if (!maxFindings || Number.isNaN(maxFindings)) {
138
+ return outputMode === 'summary' ? 5 : 10;
139
+ }
140
+ return Math.max(1, Math.min(maxFindings, 50));
141
+ }
142
+ function selectFiles(ctx, options, scope) {
143
+ return selectAnalyzerFiles(ctx, {
144
+ filePath: options.filePath,
145
+ componentName: options.componentName,
146
+ scope,
147
+ matchComponent: (file, componentName) => {
148
+ const pattern = new RegExp(`(?:^|[^a-zA-Z0-9_])${escapeRegExp(componentName)}(?:[^a-zA-Z0-9_]|$)`);
149
+ return pattern.test(readFileContent(file));
150
+ },
151
+ });
152
+ }
153
+ function sortFindings(findings, options) {
154
+ const severityRank = {
155
+ critical: 0,
156
+ warning: 1,
157
+ suggestion: 2,
158
+ info: 3,
159
+ };
160
+ const targetPath = options.filePath?.replace(/\\/g, '/').toLowerCase();
161
+ const targetName = options.componentName?.toLowerCase();
162
+ return [...findings].sort((a, b) => {
163
+ const aTarget = getTargetScore(a, targetPath, targetName);
164
+ const bTarget = getTargetScore(b, targetPath, targetName);
165
+ if (aTarget !== bTarget)
166
+ return bTarget - aTarget;
167
+ const severityDiff = severityRank[a.severity] - severityRank[b.severity];
168
+ if (severityDiff !== 0)
169
+ return severityDiff;
170
+ return (a.file ?? '').localeCompare(b.file ?? '');
171
+ });
172
+ }
173
+ function getTargetScore(finding, targetPath, targetName) {
174
+ const file = finding.file?.replace(/\\/g, '/').toLowerCase() ?? '';
175
+ const title = `${finding.title} ${finding.description}`.toLowerCase();
176
+ let score = 0;
177
+ if (targetPath && file.includes(targetPath))
178
+ score += 2;
179
+ if (targetName && title.includes(targetName))
180
+ score += 1;
181
+ return score;
182
+ }
183
+ function describeTarget(options, scope) {
184
+ if (options.filePath)
185
+ return `文件 ${options.filePath}`;
186
+ if (options.componentName)
187
+ return `组件 ${options.componentName}`;
188
+ return scope === 'project' ? '当前项目' : '目标范围';
189
+ }
190
+ function buildSummary(params) {
191
+ const { targetLabel, scannedFiles, criticalCount, warningCount, totalFindings, shownFindings, truncated } = params;
192
+ const base = `已审查${targetLabel},扫描 ${scannedFiles} 个文件,发现 ${criticalCount} 个 critical、${warningCount} 个 warning,共 ${totalFindings} 个问题`;
193
+ if (!truncated)
194
+ return base;
195
+ return `${base};当前仅返回前 ${shownFindings} 条高优先级发现`;
196
+ }
197
+ function buildReportId(targetLabel, files) {
198
+ const source = `${targetLabel}:${files.join('|')}`;
199
+ let hash = 0;
200
+ for (let i = 0; i < source.length; i++) {
201
+ hash = (hash * 31 + source.charCodeAt(i)) >>> 0;
202
+ }
203
+ return `react-hooks-${hash.toString(16)}`;
204
+ }
205
+ function escapeRegExp(value) {
206
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
207
+ }
208
+ function collectHookMetrics(lines, sourceFile, metrics) {
209
+ const counted = new Set();
210
+ const visit = (node) => {
211
+ if (ts.isCallExpression(node)) {
212
+ const hookName = getHookName(node.expression);
213
+ if (hookName && !counted.has(node.getStart(sourceFile))) {
214
+ counted.add(node.getStart(sourceFile));
215
+ if (BUILTIN_HOOKS.has(hookName)) {
216
+ metrics[hookName] = (metrics[hookName] ?? 0) + 1;
217
+ }
218
+ else {
219
+ metrics.customHooks = (metrics.customHooks ?? 0) + 1;
220
+ }
221
+ metrics.totalHookCalls++;
222
+ }
223
+ }
224
+ ts.forEachChild(node, visit);
225
+ };
226
+ visit(sourceFile);
227
+ for (let i = 0; i < lines.length; i++) {
228
+ const line = lines[i].trim();
229
+ if (/^\s*(import|export\s+.*from)\s/.test(line))
230
+ continue;
231
+ }
232
+ }
233
+ function findHookViolations(lines, sourceFile, relPath) {
234
+ const findings = [];
235
+ const seen = new Set();
236
+ const visit = (node) => {
237
+ if (ts.isCallExpression(node)) {
238
+ const hookName = getHookName(node.expression);
239
+ if (hookName) {
240
+ const violation = findViolationAncestor(node, sourceFile);
241
+ if (violation) {
242
+ const line = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
243
+ const key = `${violation.category}:${line}:${hookName}`;
244
+ if (!seen.has(key)) {
245
+ seen.add(key);
246
+ findings.push({
247
+ severity: 'critical',
248
+ category: violation.category,
249
+ title: violation.category === 'loop-hook' ? '循环中调用 Hook' : '条件调用 Hook',
250
+ description: `${hookName} ${violation.description},违反 Hooks 规则`,
251
+ file: relPath,
252
+ line,
253
+ codeSnippet: lines[line - 1]?.trim(),
254
+ suggestion: violation.category === 'loop-hook'
255
+ ? `将 ${hookName} 移到循环外部`
256
+ : `将 ${hookName} 移到组件顶层`,
257
+ });
258
+ }
259
+ }
260
+ }
261
+ }
262
+ ts.forEachChild(node, visit);
263
+ };
264
+ visit(sourceFile);
265
+ return findings;
266
+ }
267
+ function findViolationAncestor(node, sourceFile) {
268
+ let current = node.parent;
269
+ while (current && current !== sourceFile) {
270
+ if (ts.isForStatement(current) ||
271
+ ts.isForInStatement(current) ||
272
+ ts.isForOfStatement(current) ||
273
+ ts.isWhileStatement(current) ||
274
+ ts.isDoStatement(current)) {
275
+ return { category: 'loop-hook', description: '在循环中调用' };
276
+ }
277
+ if (ts.isIfStatement(current) ||
278
+ ts.isConditionalExpression(current) ||
279
+ ts.isCaseClause(current) ||
280
+ ts.isDefaultClause(current)) {
281
+ return { category: 'conditional-hook', description: '在条件分支中调用' };
282
+ }
283
+ current = current.parent;
284
+ }
285
+ return null;
286
+ }
287
+ function getHookName(expression) {
288
+ if (ts.isIdentifier(expression) && /^use[A-Z]/.test(expression.text)) {
289
+ return expression.text;
290
+ }
291
+ if (ts.isPropertyAccessExpression(expression) &&
292
+ ts.isIdentifier(expression.name) &&
293
+ /^use[A-Z]/.test(expression.name.text)) {
294
+ return expression.name.text;
295
+ }
296
+ return null;
297
+ }
298
+ function inferScriptKind(filePath) {
299
+ if (filePath.endsWith('.tsx'))
300
+ return ts.ScriptKind.TSX;
301
+ if (filePath.endsWith('.ts'))
302
+ return ts.ScriptKind.TS;
303
+ if (filePath.endsWith('.jsx'))
304
+ return ts.ScriptKind.JSX;
305
+ return ts.ScriptKind.JS;
306
+ }
307
+ //# sourceMappingURL=hooks-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-review.js","sourceRoot":"","sources":["../../src/analyzers/hooks-review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { AnalysisResult } from './types.js';
2
+ interface GenerateComponentInput {
3
+ projectRoot: string;
4
+ componentName: string;
5
+ props: Array<{
6
+ name: string;
7
+ type: string;
8
+ }>;
9
+ }
10
+ export declare function generateComponent(input: GenerateComponentInput): AnalysisResult;
11
+ export {};
12
+ //# sourceMappingURL=new-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-component.d.ts","sourceRoot":"","sources":["../../src/analyzers/new-component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,UAAU,sBAAsB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,cAAc,CA6D/E"}