baseguard 1.0.3 → 1.0.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/.baseguardrc.example.json +63 -63
- package/.eslintrc.json +24 -24
- package/.prettierrc +7 -7
- package/CHANGELOG.md +195 -195
- package/DEPLOYMENT.md +624 -624
- package/DEPLOYMENT_CHECKLIST.md +239 -239
- package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -202
- package/QUICK_START.md +134 -134
- package/README.md +488 -488
- package/RELEASE_NOTES_v1.0.2.md +434 -434
- package/bin/base.js +627 -627
- package/dist/ai/fix-manager.d.ts.map +1 -1
- package/dist/ai/fix-manager.js +1 -1
- package/dist/ai/fix-manager.js.map +1 -1
- package/dist/ai/gemini-analyzer.d.ts.map +1 -1
- package/dist/ai/gemini-analyzer.js +29 -35
- package/dist/ai/gemini-analyzer.js.map +1 -1
- package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
- package/dist/ai/gemini-code-fixer.js +58 -58
- package/dist/ai/gemini-code-fixer.js.map +1 -1
- package/dist/ai/jules-implementer.d.ts +3 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -1
- package/dist/ai/jules-implementer.js +63 -32
- package/dist/ai/jules-implementer.js.map +1 -1
- package/dist/ai/unified-code-fixer.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/config.js +2 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +44 -15
- package/dist/commands/fix.js.map +1 -1
- package/dist/core/api-key-manager.js +2 -2
- package/dist/core/api-key-manager.js.map +1 -1
- package/dist/core/baseguard.d.ts +1 -0
- package/dist/core/baseguard.d.ts.map +1 -1
- package/dist/core/baseguard.js +13 -10
- package/dist/core/baseguard.js.map +1 -1
- package/dist/core/baseline-checker.d.ts.map +1 -1
- package/dist/core/baseline-checker.js +2 -1
- package/dist/core/baseline-checker.js.map +1 -1
- package/dist/core/configuration-recovery.d.ts.map +1 -1
- package/dist/core/configuration-recovery.js +1 -1
- package/dist/core/configuration-recovery.js.map +1 -1
- package/dist/core/debug-logger.d.ts.map +1 -1
- package/dist/core/debug-logger.js +1 -1
- package/dist/core/debug-logger.js.map +1 -1
- package/dist/core/error-handler.d.ts.map +1 -1
- package/dist/core/error-handler.js +2 -1
- package/dist/core/error-handler.js.map +1 -1
- package/dist/core/gitignore-manager.js +5 -5
- package/dist/core/graceful-degradation-manager.d.ts.map +1 -1
- package/dist/core/graceful-degradation-manager.js +16 -16
- package/dist/core/graceful-degradation-manager.js.map +1 -1
- package/dist/core/lazy-loader.d.ts.map +1 -1
- package/dist/core/lazy-loader.js +9 -2
- package/dist/core/lazy-loader.js.map +1 -1
- package/dist/core/memory-manager.d.ts +0 -3
- package/dist/core/memory-manager.d.ts.map +1 -1
- package/dist/core/memory-manager.js.map +1 -1
- package/dist/core/parser-worker.d.ts +2 -0
- package/dist/core/parser-worker.d.ts.map +1 -0
- package/dist/core/parser-worker.js +19 -0
- package/dist/core/parser-worker.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -1
- package/dist/core/startup-optimizer.js +4 -8
- package/dist/core/startup-optimizer.js.map +1 -1
- package/dist/core/system-error-handler.d.ts.map +1 -1
- package/dist/core/system-error-handler.js.map +1 -1
- package/dist/git/automation-engine.d.ts.map +1 -1
- package/dist/git/automation-engine.js +5 -4
- package/dist/git/automation-engine.js.map +1 -1
- package/dist/git/github-manager.d.ts.map +1 -1
- package/dist/git/github-manager.js.map +1 -1
- package/dist/git/hook-manager.js +5 -5
- package/dist/git/hook-manager.js.map +1 -1
- package/dist/parsers/parser-manager.d.ts.map +1 -1
- package/dist/parsers/parser-manager.js +1 -1
- package/dist/parsers/parser-manager.js.map +1 -1
- package/dist/parsers/svelte-parser.js +1 -1
- package/dist/parsers/svelte-parser.js.map +1 -1
- package/dist/parsers/vanilla-parser.d.ts.map +1 -1
- package/dist/parsers/vanilla-parser.js.map +1 -1
- package/dist/parsers/vue-parser.d.ts.map +1 -1
- package/dist/parsers/vue-parser.js.map +1 -1
- package/dist/ui/components.d.ts +1 -1
- package/dist/ui/components.d.ts.map +1 -1
- package/dist/ui/components.js +11 -11
- package/dist/ui/components.js.map +1 -1
- package/dist/ui/terminal-header.js +14 -14
- package/package.json +105 -105
- package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
- package/src/ai/agentkit-orchestrator.ts +533 -533
- package/src/ai/fix-manager.ts +362 -362
- package/src/ai/gemini-analyzer.ts +665 -671
- package/src/ai/gemini-code-fixer.ts +539 -540
- package/src/ai/index.ts +3 -3
- package/src/ai/jules-implementer.ts +504 -460
- package/src/ai/unified-code-fixer.ts +347 -347
- package/src/commands/automation.ts +343 -343
- package/src/commands/check.ts +298 -299
- package/src/commands/config.ts +584 -583
- package/src/commands/fix.ts +264 -238
- package/src/commands/index.ts +6 -6
- package/src/commands/init.ts +155 -155
- package/src/commands/status.ts +306 -306
- package/src/core/api-key-manager.ts +298 -298
- package/src/core/baseguard.ts +757 -756
- package/src/core/baseline-checker.ts +564 -563
- package/src/core/cache-manager.ts +271 -271
- package/src/core/configuration-recovery.ts +672 -673
- package/src/core/configuration.ts +595 -595
- package/src/core/debug-logger.ts +590 -590
- package/src/core/directory-filter.ts +420 -420
- package/src/core/error-handler.ts +518 -517
- package/src/core/file-processor.ts +337 -337
- package/src/core/gitignore-manager.ts +168 -168
- package/src/core/graceful-degradation-manager.ts +596 -596
- package/src/core/index.ts +16 -16
- package/src/core/lazy-loader.ts +317 -307
- package/src/core/memory-manager.ts +290 -295
- package/src/core/parser-worker.ts +33 -0
- package/src/core/startup-optimizer.ts +246 -255
- package/src/core/system-error-handler.ts +755 -756
- package/src/git/automation-engine.ts +361 -361
- package/src/git/github-manager.ts +190 -192
- package/src/git/hook-manager.ts +210 -210
- package/src/git/index.ts +3 -3
- package/src/index.ts +7 -7
- package/src/parsers/feature-validator.ts +558 -558
- package/src/parsers/index.ts +7 -7
- package/src/parsers/parser-manager.ts +418 -419
- package/src/parsers/parser.ts +25 -25
- package/src/parsers/react-parser-optimized.ts +160 -160
- package/src/parsers/react-parser.ts +358 -358
- package/src/parsers/svelte-parser.ts +510 -510
- package/src/parsers/vanilla-parser.ts +685 -686
- package/src/parsers/vue-parser.ts +476 -478
- package/src/types/index.ts +95 -95
- package/src/ui/components.ts +567 -567
- package/src/ui/help.ts +192 -192
- package/src/ui/index.ts +3 -3
- package/src/ui/prompts.ts +680 -680
- package/src/ui/terminal-header.ts +58 -58
- package/test-build.js +40 -40
- package/test-config-commands.js +55 -55
- package/test-header-simple.js +32 -32
- package/test-terminal-header.js +11 -11
- package/test-ui.js +28 -28
- package/tests/e2e/baseguard.e2e.test.ts +515 -515
- package/tests/e2e/cross-platform.e2e.test.ts +419 -419
- package/tests/e2e/git-integration.e2e.test.ts +486 -486
- package/tests/fixtures/react-project/package.json +13 -13
- package/tests/fixtures/react-project/src/App.css +75 -75
- package/tests/fixtures/react-project/src/App.tsx +76 -76
- package/tests/fixtures/svelte-project/package.json +10 -10
- package/tests/fixtures/svelte-project/src/App.svelte +368 -368
- package/tests/fixtures/vanilla-project/index.html +75 -75
- package/tests/fixtures/vanilla-project/script.js +330 -330
- package/tests/fixtures/vanilla-project/styles.css +358 -358
- package/tests/fixtures/vue-project/package.json +11 -11
- package/tests/fixtures/vue-project/src/App.vue +215 -215
- package/tsconfig.json +34 -34
- package/vitest.config.ts +11 -11
- package/dist/terminal-header.d.ts +0 -12
- package/dist/terminal-header.js +0 -45
package/src/parsers/parser.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import type { DetectedFeature } from '../types/index.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Abstract base class for all code parsers
|
|
5
|
-
*/
|
|
6
|
-
export abstract class Parser {
|
|
7
|
-
/**
|
|
8
|
-
* Check if this parser can handle the given file
|
|
9
|
-
*/
|
|
10
|
-
abstract canParse(filePath: string): boolean;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Parse features from file content
|
|
14
|
-
*/
|
|
15
|
-
abstract parseFeatures(content: string, filePath: string): Promise<DetectedFeature[]>;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Get supported file extensions for this parser
|
|
19
|
-
*/
|
|
20
|
-
abstract getSupportedExtensions(): string[];
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get parser name for identification
|
|
24
|
-
*/
|
|
25
|
-
abstract getName(): string;
|
|
1
|
+
import type { DetectedFeature } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for all code parsers
|
|
5
|
+
*/
|
|
6
|
+
export abstract class Parser {
|
|
7
|
+
/**
|
|
8
|
+
* Check if this parser can handle the given file
|
|
9
|
+
*/
|
|
10
|
+
abstract canParse(filePath: string): boolean;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parse features from file content
|
|
14
|
+
*/
|
|
15
|
+
abstract parseFeatures(content: string, filePath: string): Promise<DetectedFeature[]>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get supported file extensions for this parser
|
|
19
|
+
*/
|
|
20
|
+
abstract getSupportedExtensions(): string[];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get parser name for identification
|
|
24
|
+
*/
|
|
25
|
+
abstract getName(): string;
|
|
26
26
|
}
|
|
@@ -1,161 +1,161 @@
|
|
|
1
|
-
import { Parser } from './parser.js';
|
|
2
|
-
import type { DetectedFeature } from '../types/index.js';
|
|
3
|
-
import { LazyLoader } from '../core/lazy-loader.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Optimized React/JSX parser using lazy loading
|
|
7
|
-
*/
|
|
8
|
-
export class ReactParser extends Parser {
|
|
9
|
-
getName(): string {
|
|
10
|
-
return 'ReactParser';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
getSupportedExtensions(): string[] {
|
|
14
|
-
return ['.jsx', '.tsx'];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
canParse(filePath: string): boolean {
|
|
18
|
-
return /\.(jsx|tsx)$/.test(filePath);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async parseFeatures(content: string, filePath: string): Promise<DetectedFeature[]> {
|
|
22
|
-
const features: DetectedFeature[] = [];
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
// Lazy load Babel dependencies only when needed
|
|
26
|
-
const [parser, traverse] = await Promise.all([
|
|
27
|
-
LazyLoader.getBabelParser(),
|
|
28
|
-
LazyLoader.getBabelTraverse()
|
|
29
|
-
]);
|
|
30
|
-
|
|
31
|
-
const ast = parser.parse(content, {
|
|
32
|
-
sourceType: 'module',
|
|
33
|
-
plugins: [
|
|
34
|
-
'jsx',
|
|
35
|
-
'typescript',
|
|
36
|
-
'decorators-legacy',
|
|
37
|
-
'classProperties',
|
|
38
|
-
'objectRestSpread',
|
|
39
|
-
'asyncGenerators',
|
|
40
|
-
'functionBind',
|
|
41
|
-
'exportDefaultFrom',
|
|
42
|
-
'exportNamespaceFrom',
|
|
43
|
-
'dynamicImport',
|
|
44
|
-
'nullishCoalescingOperator',
|
|
45
|
-
'optionalChaining',
|
|
46
|
-
'topLevelAwait'
|
|
47
|
-
]
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Simple feature extraction optimized for performance
|
|
51
|
-
traverse(ast, {
|
|
52
|
-
MemberExpression: (path: any) => {
|
|
53
|
-
const apiName = this.extractAPIName(path.node);
|
|
54
|
-
if (apiName && this.isWebPlatformAPI(apiName)) {
|
|
55
|
-
features.push({
|
|
56
|
-
feature: apiName,
|
|
57
|
-
type: 'js',
|
|
58
|
-
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
59
|
-
line: path.node.loc?.start.line || 0,
|
|
60
|
-
column: path.node.loc?.start.column || 0,
|
|
61
|
-
file: filePath
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
CallExpression: (path: any) => {
|
|
67
|
-
const apiName = this.extractCallName(path.node);
|
|
68
|
-
if (apiName && this.isWebPlatformAPI(apiName)) {
|
|
69
|
-
features.push({
|
|
70
|
-
feature: apiName,
|
|
71
|
-
type: 'js',
|
|
72
|
-
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
73
|
-
line: path.node.loc?.start.line || 0,
|
|
74
|
-
column: path.node.loc?.start.column || 0,
|
|
75
|
-
file: filePath
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
OptionalMemberExpression: (path: any) => {
|
|
81
|
-
features.push({
|
|
82
|
-
feature: 'optional-chaining',
|
|
83
|
-
type: 'js',
|
|
84
|
-
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
85
|
-
line: path.node.loc?.start.line || 0,
|
|
86
|
-
column: path.node.loc?.start.column || 0,
|
|
87
|
-
file: filePath
|
|
88
|
-
});
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
LogicalExpression: (path: any) => {
|
|
92
|
-
if (path.node.operator === '??') {
|
|
93
|
-
features.push({
|
|
94
|
-
feature: 'nullish-coalescing',
|
|
95
|
-
type: 'js',
|
|
96
|
-
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
97
|
-
line: path.node.loc?.start.line || 0,
|
|
98
|
-
column: path.node.loc?.start.column || 0,
|
|
99
|
-
file: filePath
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.warn(`Warning: Could not parse React file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return features;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private extractAPIName(node: any): string | null {
|
|
113
|
-
try {
|
|
114
|
-
if (node.object && node.property) {
|
|
115
|
-
const objectName = node.object.name || 'unknown';
|
|
116
|
-
const propertyName = node.property.name || node.property.value || 'unknown';
|
|
117
|
-
return `${objectName}.${propertyName}`;
|
|
118
|
-
}
|
|
119
|
-
} catch {
|
|
120
|
-
// Ignore errors
|
|
121
|
-
}
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private extractCallName(node: any): string | null {
|
|
126
|
-
try {
|
|
127
|
-
if (node.callee) {
|
|
128
|
-
if (node.callee.name) {
|
|
129
|
-
return node.callee.name;
|
|
130
|
-
}
|
|
131
|
-
if (node.callee.object && node.callee.property) {
|
|
132
|
-
const objectName = node.callee.object.name || 'unknown';
|
|
133
|
-
const propertyName = node.callee.property.name || node.callee.property.value || 'unknown';
|
|
134
|
-
return `${objectName}.${propertyName}`;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
} catch {
|
|
138
|
-
// Ignore errors
|
|
139
|
-
}
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private isWebPlatformAPI(apiName: string): boolean {
|
|
144
|
-
const webAPIs = [
|
|
145
|
-
'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
|
|
146
|
-
'navigator.serviceWorker', 'caches', 'Cache',
|
|
147
|
-
'ResizeObserver', 'IntersectionObserver', 'MutationObserver',
|
|
148
|
-
'canvas.getContext', 'WebGLRenderingContext', 'WebGL2RenderingContext',
|
|
149
|
-
'RTCPeerConnection', 'getUserMedia', 'MediaStream',
|
|
150
|
-
'WebAssembly', 'structuredClone', 'queueMicrotask',
|
|
151
|
-
'requestAnimationFrame', 'requestIdleCallback'
|
|
152
|
-
];
|
|
153
|
-
|
|
154
|
-
return webAPIs.some(api => apiName.includes(api) || api.includes(apiName));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private getContext(content: string, line: number): string {
|
|
158
|
-
const lines = content.split('\n');
|
|
159
|
-
return lines[line - 1]?.trim() || '';
|
|
160
|
-
}
|
|
1
|
+
import { Parser } from './parser.js';
|
|
2
|
+
import type { DetectedFeature } from '../types/index.js';
|
|
3
|
+
import { LazyLoader } from '../core/lazy-loader.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Optimized React/JSX parser using lazy loading
|
|
7
|
+
*/
|
|
8
|
+
export class ReactParser extends Parser {
|
|
9
|
+
getName(): string {
|
|
10
|
+
return 'ReactParser';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getSupportedExtensions(): string[] {
|
|
14
|
+
return ['.jsx', '.tsx'];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
canParse(filePath: string): boolean {
|
|
18
|
+
return /\.(jsx|tsx)$/.test(filePath);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async parseFeatures(content: string, filePath: string): Promise<DetectedFeature[]> {
|
|
22
|
+
const features: DetectedFeature[] = [];
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Lazy load Babel dependencies only when needed
|
|
26
|
+
const [parser, traverse] = await Promise.all([
|
|
27
|
+
LazyLoader.getBabelParser(),
|
|
28
|
+
LazyLoader.getBabelTraverse()
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const ast = parser.parse(content, {
|
|
32
|
+
sourceType: 'module',
|
|
33
|
+
plugins: [
|
|
34
|
+
'jsx',
|
|
35
|
+
'typescript',
|
|
36
|
+
'decorators-legacy',
|
|
37
|
+
'classProperties',
|
|
38
|
+
'objectRestSpread',
|
|
39
|
+
'asyncGenerators',
|
|
40
|
+
'functionBind',
|
|
41
|
+
'exportDefaultFrom',
|
|
42
|
+
'exportNamespaceFrom',
|
|
43
|
+
'dynamicImport',
|
|
44
|
+
'nullishCoalescingOperator',
|
|
45
|
+
'optionalChaining',
|
|
46
|
+
'topLevelAwait'
|
|
47
|
+
]
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Simple feature extraction optimized for performance
|
|
51
|
+
traverse(ast, {
|
|
52
|
+
MemberExpression: (path: any) => {
|
|
53
|
+
const apiName = this.extractAPIName(path.node);
|
|
54
|
+
if (apiName && this.isWebPlatformAPI(apiName)) {
|
|
55
|
+
features.push({
|
|
56
|
+
feature: apiName,
|
|
57
|
+
type: 'js',
|
|
58
|
+
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
59
|
+
line: path.node.loc?.start.line || 0,
|
|
60
|
+
column: path.node.loc?.start.column || 0,
|
|
61
|
+
file: filePath
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
CallExpression: (path: any) => {
|
|
67
|
+
const apiName = this.extractCallName(path.node);
|
|
68
|
+
if (apiName && this.isWebPlatformAPI(apiName)) {
|
|
69
|
+
features.push({
|
|
70
|
+
feature: apiName,
|
|
71
|
+
type: 'js',
|
|
72
|
+
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
73
|
+
line: path.node.loc?.start.line || 0,
|
|
74
|
+
column: path.node.loc?.start.column || 0,
|
|
75
|
+
file: filePath
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
OptionalMemberExpression: (path: any) => {
|
|
81
|
+
features.push({
|
|
82
|
+
feature: 'optional-chaining',
|
|
83
|
+
type: 'js',
|
|
84
|
+
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
85
|
+
line: path.node.loc?.start.line || 0,
|
|
86
|
+
column: path.node.loc?.start.column || 0,
|
|
87
|
+
file: filePath
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
LogicalExpression: (path: any) => {
|
|
92
|
+
if (path.node.operator === '??') {
|
|
93
|
+
features.push({
|
|
94
|
+
feature: 'nullish-coalescing',
|
|
95
|
+
type: 'js',
|
|
96
|
+
context: this.getContext(content, path.node.loc?.start.line || 0),
|
|
97
|
+
line: path.node.loc?.start.line || 0,
|
|
98
|
+
column: path.node.loc?.start.column || 0,
|
|
99
|
+
file: filePath
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.warn(`Warning: Could not parse React file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return features;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private extractAPIName(node: any): string | null {
|
|
113
|
+
try {
|
|
114
|
+
if (node.object && node.property) {
|
|
115
|
+
const objectName = node.object.name || 'unknown';
|
|
116
|
+
const propertyName = node.property.name || node.property.value || 'unknown';
|
|
117
|
+
return `${objectName}.${propertyName}`;
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// Ignore errors
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private extractCallName(node: any): string | null {
|
|
126
|
+
try {
|
|
127
|
+
if (node.callee) {
|
|
128
|
+
if (node.callee.name) {
|
|
129
|
+
return node.callee.name;
|
|
130
|
+
}
|
|
131
|
+
if (node.callee.object && node.callee.property) {
|
|
132
|
+
const objectName = node.callee.object.name || 'unknown';
|
|
133
|
+
const propertyName = node.callee.property.name || node.callee.property.value || 'unknown';
|
|
134
|
+
return `${objectName}.${propertyName}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
// Ignore errors
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private isWebPlatformAPI(apiName: string): boolean {
|
|
144
|
+
const webAPIs = [
|
|
145
|
+
'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
|
|
146
|
+
'navigator.serviceWorker', 'caches', 'Cache',
|
|
147
|
+
'ResizeObserver', 'IntersectionObserver', 'MutationObserver',
|
|
148
|
+
'canvas.getContext', 'WebGLRenderingContext', 'WebGL2RenderingContext',
|
|
149
|
+
'RTCPeerConnection', 'getUserMedia', 'MediaStream',
|
|
150
|
+
'WebAssembly', 'structuredClone', 'queueMicrotask',
|
|
151
|
+
'requestAnimationFrame', 'requestIdleCallback'
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
return webAPIs.some(api => apiName.includes(api) || api.includes(apiName));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private getContext(content: string, line: number): string {
|
|
158
|
+
const lines = content.split('\n');
|
|
159
|
+
return lines[line - 1]?.trim() || '';
|
|
160
|
+
}
|
|
161
161
|
}
|