baseguard 1.0.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.
- package/.eslintrc.json +25 -0
- package/.prettierrc +8 -0
- package/README.md +94 -0
- package/bin/base.js +494 -0
- package/dist/ai/fix-manager.d.ts +67 -0
- package/dist/ai/fix-manager.d.ts.map +1 -0
- package/dist/ai/fix-manager.js +326 -0
- package/dist/ai/fix-manager.js.map +1 -0
- package/dist/ai/gemini-analyzer.d.ts +116 -0
- package/dist/ai/gemini-analyzer.d.ts.map +1 -0
- package/dist/ai/gemini-analyzer.js +572 -0
- package/dist/ai/gemini-analyzer.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +115 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -0
- package/dist/ai/jules-implementer.js +387 -0
- package/dist/ai/jules-implementer.js.map +1 -0
- package/dist/commands/automation.d.ts +5 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +305 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/check.d.ts +9 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +113 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +324 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/fix.d.ts +9 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +207 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/core/api-key-manager.d.ts +83 -0
- package/dist/core/api-key-manager.d.ts.map +1 -0
- package/dist/core/api-key-manager.js +244 -0
- package/dist/core/api-key-manager.js.map +1 -0
- package/dist/core/baseguard.d.ts +46 -0
- package/dist/core/baseguard.d.ts.map +1 -0
- package/dist/core/baseguard.js +132 -0
- package/dist/core/baseguard.js.map +1 -0
- package/dist/core/baseline-checker.d.ts +63 -0
- package/dist/core/baseline-checker.d.ts.map +1 -0
- package/dist/core/baseline-checker.js +502 -0
- package/dist/core/baseline-checker.js.map +1 -0
- package/dist/core/cache-manager.d.ts +88 -0
- package/dist/core/cache-manager.d.ts.map +1 -0
- package/dist/core/cache-manager.js +213 -0
- package/dist/core/cache-manager.js.map +1 -0
- package/dist/core/configuration.d.ts +140 -0
- package/dist/core/configuration.d.ts.map +1 -0
- package/dist/core/configuration.js +474 -0
- package/dist/core/configuration.js.map +1 -0
- package/dist/core/directory-filter.d.ts +90 -0
- package/dist/core/directory-filter.d.ts.map +1 -0
- package/dist/core/directory-filter.js +319 -0
- package/dist/core/directory-filter.js.map +1 -0
- package/dist/core/error-handler.d.ts +110 -0
- package/dist/core/error-handler.d.ts.map +1 -0
- package/dist/core/error-handler.js +392 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/file-processor.d.ts +80 -0
- package/dist/core/file-processor.d.ts.map +1 -0
- package/dist/core/file-processor.js +259 -0
- package/dist/core/file-processor.js.map +1 -0
- package/dist/core/gitignore-manager.d.ts +44 -0
- package/dist/core/gitignore-manager.d.ts.map +1 -0
- package/dist/core/gitignore-manager.js +147 -0
- package/dist/core/gitignore-manager.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lazy-loader.d.ts +68 -0
- package/dist/core/lazy-loader.d.ts.map +1 -0
- package/dist/core/lazy-loader.js +260 -0
- package/dist/core/lazy-loader.js.map +1 -0
- package/dist/core/memory-manager.d.ts +1 -0
- package/dist/core/memory-manager.d.ts.map +1 -0
- package/dist/core/memory-manager.js +2 -0
- package/dist/core/memory-manager.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts +45 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -0
- package/dist/core/startup-optimizer.js +140 -0
- package/dist/core/startup-optimizer.js.map +1 -0
- package/dist/git/automation-engine.d.ts +58 -0
- package/dist/git/automation-engine.d.ts.map +1 -0
- package/dist/git/automation-engine.js +318 -0
- package/dist/git/automation-engine.js.map +1 -0
- package/dist/git/github-manager.d.ts +71 -0
- package/dist/git/github-manager.d.ts.map +1 -0
- package/dist/git/github-manager.js +226 -0
- package/dist/git/github-manager.js.map +1 -0
- package/dist/git/hook-manager.d.ts +43 -0
- package/dist/git/hook-manager.d.ts.map +1 -0
- package/dist/git/hook-manager.js +191 -0
- package/dist/git/hook-manager.js.map +1 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +5 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/feature-validator.d.ts +60 -0
- package/dist/parsers/feature-validator.d.ts.map +1 -0
- package/dist/parsers/feature-validator.js +483 -0
- package/dist/parsers/feature-validator.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +9 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/parser-manager.d.ts +103 -0
- package/dist/parsers/parser-manager.d.ts.map +1 -0
- package/dist/parsers/parser-manager.js +321 -0
- package/dist/parsers/parser-manager.js.map +1 -0
- package/dist/parsers/parser.d.ts +23 -0
- package/dist/parsers/parser.d.ts.map +1 -0
- package/dist/parsers/parser.js +6 -0
- package/dist/parsers/parser.js.map +1 -0
- package/dist/parsers/react-parser.d.ts +22 -0
- package/dist/parsers/react-parser.d.ts.map +1 -0
- package/dist/parsers/react-parser.js +307 -0
- package/dist/parsers/react-parser.js.map +1 -0
- package/dist/parsers/svelte-parser.d.ts +33 -0
- package/dist/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/parsers/svelte-parser.js +408 -0
- package/dist/parsers/svelte-parser.js.map +1 -0
- package/dist/parsers/vanilla-parser.d.ts +31 -0
- package/dist/parsers/vanilla-parser.d.ts.map +1 -0
- package/dist/parsers/vanilla-parser.js +590 -0
- package/dist/parsers/vanilla-parser.js.map +1 -0
- package/dist/parsers/vue-parser.d.ts +9 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -0
- package/dist/parsers/vue-parser.js +16 -0
- package/dist/parsers/vue-parser.js.map +1 -0
- package/dist/terminal-header.d.ts +12 -0
- package/dist/terminal-header.js +45 -0
- package/dist/types/index.d.ts +83 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/components.d.ts +133 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js +482 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/help.d.ts +11 -0
- package/dist/ui/help.d.ts.map +1 -0
- package/dist/ui/help.js +161 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/prompts.d.ts +63 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +611 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/terminal-header.d.ts +13 -0
- package/dist/ui/terminal-header.d.ts.map +1 -0
- package/dist/ui/terminal-header.js +46 -0
- package/dist/ui/terminal-header.js.map +1 -0
- package/package.json +80 -0
- package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
- package/src/ai/fix-manager.ts +362 -0
- package/src/ai/gemini-analyzer.ts +671 -0
- package/src/ai/index.ts +4 -0
- package/src/ai/jules-implementer.ts +459 -0
- package/src/commands/automation.ts +344 -0
- package/src/commands/check.ts +299 -0
- package/src/commands/config.ts +365 -0
- package/src/commands/fix.ts +234 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/init.ts +142 -0
- package/src/commands/status.ts +0 -0
- package/src/core/api-key-manager.ts +298 -0
- package/src/core/baseguard.ts +742 -0
- package/src/core/baseline-checker.ts +563 -0
- package/src/core/cache-manager.ts +270 -0
- package/src/core/configuration-recovery.ts +676 -0
- package/src/core/configuration.ts +559 -0
- package/src/core/debug-logger.ts +590 -0
- package/src/core/directory-filter.ts +421 -0
- package/src/core/error-handler.ts +517 -0
- package/src/core/file-processor.ts +331 -0
- package/src/core/gitignore-manager.ts +169 -0
- package/src/core/graceful-degradation-manager.ts +596 -0
- package/src/core/index.ts +13 -0
- package/src/core/lazy-loader.ts +307 -0
- package/src/core/logger.ts +0 -0
- package/src/core/memory-manager.ts +294 -0
- package/src/core/startup-optimizer.ts +173 -0
- package/src/core/system-error-handler.ts +746 -0
- package/src/git/automation-engine.ts +361 -0
- package/src/git/github-manager.ts +260 -0
- package/src/git/hook-manager.ts +210 -0
- package/src/git/index.ts +4 -0
- package/src/index.ts +8 -0
- package/src/parsers/feature-validator.ts +559 -0
- package/src/parsers/index.ts +8 -0
- package/src/parsers/parser-manager.ts +419 -0
- package/src/parsers/parser.ts +26 -0
- package/src/parsers/react-parser-optimized.ts +161 -0
- package/src/parsers/react-parser.ts +359 -0
- package/src/parsers/svelte-parser.ts +506 -0
- package/src/parsers/vanilla-parser.ts +682 -0
- package/src/parsers/vue-parser.ts +472 -0
- package/src/types/index.ts +92 -0
- package/src/ui/components.ts +567 -0
- package/src/ui/help.ts +193 -0
- package/src/ui/index.ts +4 -0
- package/src/ui/prompts.ts +688 -0
- package/src/ui/terminal-header.ts +59 -0
- package/test-config-commands.js +56 -0
- package/test-header-simple.js +33 -0
- package/test-terminal-header.js +12 -0
- package/test-ui.js +29 -0
- package/tests/e2e/baseguard.e2e.test.ts +516 -0
- package/tests/e2e/cross-platform.e2e.test.ts +420 -0
- package/tests/e2e/git-integration.e2e.test.ts +487 -0
- package/tests/fixtures/react-project/package.json +14 -0
- package/tests/fixtures/react-project/src/App.css +76 -0
- package/tests/fixtures/react-project/src/App.tsx +77 -0
- package/tests/fixtures/svelte-project/package.json +11 -0
- package/tests/fixtures/svelte-project/src/App.svelte +369 -0
- package/tests/fixtures/vanilla-project/index.html +76 -0
- package/tests/fixtures/vanilla-project/script.js +331 -0
- package/tests/fixtures/vanilla-project/styles.css +359 -0
- package/tests/fixtures/vue-project/package.json +12 -0
- package/tests/fixtures/vue-project/src/App.vue +216 -0
- package/tsconfig.json +36 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy loading system for heavy dependencies and parsers
|
|
3
|
+
*/
|
|
4
|
+
export class LazyLoader {
|
|
5
|
+
private static instances = new Map<string, any>();
|
|
6
|
+
private static loadPromises = new Map<string, Promise<any>>();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Lazy load web-features package
|
|
10
|
+
*/
|
|
11
|
+
static async getWebFeatures(): Promise<any> {
|
|
12
|
+
const key = 'web-features';
|
|
13
|
+
|
|
14
|
+
if (this.instances.has(key)) {
|
|
15
|
+
return this.instances.get(key);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (this.loadPromises.has(key)) {
|
|
19
|
+
return this.loadPromises.get(key);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const loadPromise = this.loadWebFeatures();
|
|
23
|
+
this.loadPromises.set(key, loadPromise);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const webFeatures = await loadPromise;
|
|
27
|
+
this.instances.set(key, webFeatures);
|
|
28
|
+
this.loadPromises.delete(key);
|
|
29
|
+
return webFeatures;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
this.loadPromises.delete(key);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Lazy load Babel parser
|
|
38
|
+
*/
|
|
39
|
+
static async getBabelParser(): Promise<any> {
|
|
40
|
+
const key = 'babel-parser';
|
|
41
|
+
|
|
42
|
+
if (this.instances.has(key)) {
|
|
43
|
+
return this.instances.get(key);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (this.loadPromises.has(key)) {
|
|
47
|
+
return this.loadPromises.get(key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const loadPromise = import('@babel/parser');
|
|
51
|
+
this.loadPromises.set(key, loadPromise);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const parser = await loadPromise;
|
|
55
|
+
this.instances.set(key, parser);
|
|
56
|
+
this.loadPromises.delete(key);
|
|
57
|
+
return parser;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
this.loadPromises.delete(key);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Lazy load Babel traverse
|
|
66
|
+
*/
|
|
67
|
+
static async getBabelTraverse(): Promise<any> {
|
|
68
|
+
const key = 'babel-traverse';
|
|
69
|
+
|
|
70
|
+
if (this.instances.has(key)) {
|
|
71
|
+
return this.instances.get(key);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (this.loadPromises.has(key)) {
|
|
75
|
+
return this.loadPromises.get(key);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const loadPromise = import('@babel/traverse');
|
|
79
|
+
this.loadPromises.set(key, loadPromise);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const traverse = await loadPromise;
|
|
83
|
+
this.instances.set(key, traverse.default || traverse);
|
|
84
|
+
this.loadPromises.delete(key);
|
|
85
|
+
return this.instances.get(key);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
this.loadPromises.delete(key);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Lazy load PostCSS
|
|
94
|
+
*/
|
|
95
|
+
static async getPostCSS(): Promise<any> {
|
|
96
|
+
const key = 'postcss';
|
|
97
|
+
|
|
98
|
+
if (this.instances.has(key)) {
|
|
99
|
+
return this.instances.get(key);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.loadPromises.has(key)) {
|
|
103
|
+
return this.loadPromises.get(key);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const loadPromise = import('postcss');
|
|
107
|
+
this.loadPromises.set(key, loadPromise);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const postcss = await loadPromise;
|
|
111
|
+
this.instances.set(key, postcss.default || postcss);
|
|
112
|
+
this.loadPromises.delete(key);
|
|
113
|
+
return this.instances.get(key);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
this.loadPromises.delete(key);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Lazy load Vue compiler
|
|
122
|
+
*/
|
|
123
|
+
static async getVueCompiler(): Promise<any> {
|
|
124
|
+
const key = 'vue-compiler';
|
|
125
|
+
|
|
126
|
+
if (this.instances.has(key)) {
|
|
127
|
+
return this.instances.get(key);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (this.loadPromises.has(key)) {
|
|
131
|
+
return this.loadPromises.get(key);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const loadPromise = import('@vue/compiler-sfc');
|
|
135
|
+
this.loadPromises.set(key, loadPromise);
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const compiler = await loadPromise;
|
|
139
|
+
this.instances.set(key, compiler);
|
|
140
|
+
this.loadPromises.delete(key);
|
|
141
|
+
return compiler;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
this.loadPromises.delete(key);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Lazy load Svelte compiler
|
|
150
|
+
*/
|
|
151
|
+
static async getSvelteCompiler(): Promise<any> {
|
|
152
|
+
const key = 'svelte-compiler';
|
|
153
|
+
|
|
154
|
+
if (this.instances.has(key)) {
|
|
155
|
+
return this.instances.get(key);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (this.loadPromises.has(key)) {
|
|
159
|
+
return this.loadPromises.get(key);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const loadPromise = import('svelte/compiler');
|
|
163
|
+
this.loadPromises.set(key, loadPromise);
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const compiler = await loadPromise;
|
|
167
|
+
this.instances.set(key, compiler);
|
|
168
|
+
this.loadPromises.delete(key);
|
|
169
|
+
return compiler;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.loadPromises.delete(key);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Preload commonly used dependencies
|
|
178
|
+
*/
|
|
179
|
+
static async preloadCommon(): Promise<void> {
|
|
180
|
+
// Preload in background without blocking
|
|
181
|
+
Promise.all([
|
|
182
|
+
this.getWebFeatures().catch(() => {}),
|
|
183
|
+
this.getBabelParser().catch(() => {}),
|
|
184
|
+
this.getPostCSS().catch(() => {})
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Clear all cached instances (for testing)
|
|
190
|
+
*/
|
|
191
|
+
static clearCache(): void {
|
|
192
|
+
this.instances.clear();
|
|
193
|
+
this.loadPromises.clear();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get memory usage statistics
|
|
198
|
+
*/
|
|
199
|
+
static getStats(): {
|
|
200
|
+
loadedModules: string[];
|
|
201
|
+
pendingLoads: string[];
|
|
202
|
+
memoryUsage?: NodeJS.MemoryUsage;
|
|
203
|
+
} {
|
|
204
|
+
return {
|
|
205
|
+
loadedModules: Array.from(this.instances.keys()),
|
|
206
|
+
pendingLoads: Array.from(this.loadPromises.keys()),
|
|
207
|
+
memoryUsage: process.memoryUsage ? process.memoryUsage() : undefined
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Load web-features with optimized loading
|
|
213
|
+
*/
|
|
214
|
+
private static async loadWebFeatures(): Promise<any> {
|
|
215
|
+
try {
|
|
216
|
+
// Try to load web-features package
|
|
217
|
+
const webFeatures = await import('web-features');
|
|
218
|
+
|
|
219
|
+
// Extract only the data we need to reduce memory usage
|
|
220
|
+
const optimizedData = this.optimizeWebFeaturesData(webFeatures.default || webFeatures);
|
|
221
|
+
|
|
222
|
+
return optimizedData;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
console.warn('Failed to load web-features package:', error);
|
|
225
|
+
// Return minimal fallback data
|
|
226
|
+
return {
|
|
227
|
+
features: {},
|
|
228
|
+
browsers: {},
|
|
229
|
+
groups: {}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Optimize web-features data to reduce memory usage
|
|
236
|
+
*/
|
|
237
|
+
private static optimizeWebFeaturesData(webFeatures: any): any {
|
|
238
|
+
if (!webFeatures) {
|
|
239
|
+
return { features: {}, browsers: {}, groups: {} };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Handle both direct export and features property
|
|
243
|
+
const featuresData = webFeatures.features || webFeatures;
|
|
244
|
+
|
|
245
|
+
if (!featuresData || typeof featuresData !== 'object') {
|
|
246
|
+
return { features: {}, browsers: {}, groups: {} };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Create optimized structure with only essential data
|
|
250
|
+
const optimized = {
|
|
251
|
+
features: {} as any,
|
|
252
|
+
browsers: webFeatures.browsers || {},
|
|
253
|
+
groups: webFeatures.groups || {}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Only keep essential feature data to reduce memory footprint
|
|
257
|
+
for (const [featureId, feature] of Object.entries(featuresData)) {
|
|
258
|
+
const f = feature as any;
|
|
259
|
+
|
|
260
|
+
// Skip if not a valid feature object
|
|
261
|
+
if (!f || typeof f !== 'object') {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Only store essential compatibility data
|
|
266
|
+
optimized.features[featureId] = {
|
|
267
|
+
name: f.name,
|
|
268
|
+
status: f.status ? {
|
|
269
|
+
baseline: f.status.baseline,
|
|
270
|
+
support: f.status.support
|
|
271
|
+
} : null,
|
|
272
|
+
// Skip heavy data like descriptions, specs, caniuse data, etc.
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return optimized;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Get startup performance statistics
|
|
281
|
+
*/
|
|
282
|
+
static getStartupStats(): {
|
|
283
|
+
loadedModules: string[];
|
|
284
|
+
pendingLoads: string[];
|
|
285
|
+
startupTime?: number;
|
|
286
|
+
} {
|
|
287
|
+
return {
|
|
288
|
+
loadedModules: Array.from(this.instances.keys()),
|
|
289
|
+
pendingLoads: Array.from(this.loadPromises.keys()),
|
|
290
|
+
startupTime: process.uptime ? Math.round(process.uptime() * 1000) : undefined
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Optimize startup by preloading critical dependencies
|
|
296
|
+
*/
|
|
297
|
+
static async optimizeStartup(): Promise<void> {
|
|
298
|
+
// Start loading critical dependencies in background
|
|
299
|
+
const criticalLoads = [
|
|
300
|
+
this.getWebFeatures().catch(() => {}),
|
|
301
|
+
this.getBabelParser().catch(() => {})
|
|
302
|
+
];
|
|
303
|
+
|
|
304
|
+
// Don't wait for all to complete, just start the process
|
|
305
|
+
Promise.all(criticalLoads);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { createReadStream } from 'fs';
|
|
2
|
+
import { createInterface } from 'readline';
|
|
3
|
+
|
|
4
|
+
// Add global type declaration for gc
|
|
5
|
+
declare global {
|
|
6
|
+
var gc: (() => void) | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Memory-efficient file processing and streaming
|
|
11
|
+
*/
|
|
12
|
+
export class MemoryManager {
|
|
13
|
+
private static readonly MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
|
14
|
+
private static readonly CHUNK_SIZE = 64 * 1024; // 64KB chunks
|
|
15
|
+
private static readonly GC_THRESHOLD = 100 * 1024 * 1024; // 100MB
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if file should be processed in streaming mode
|
|
19
|
+
*/
|
|
20
|
+
static shouldStream(fileSize: number): boolean {
|
|
21
|
+
return fileSize > this.MAX_FILE_SIZE;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Read large file in chunks using streaming
|
|
26
|
+
*/
|
|
27
|
+
static async readFileStreaming(
|
|
28
|
+
filePath: string,
|
|
29
|
+
processor: (chunk: string, lineNumber: number) => Promise<void>
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const fileStream = createReadStream(filePath, {
|
|
33
|
+
encoding: 'utf8',
|
|
34
|
+
highWaterMark: this.CHUNK_SIZE
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const rl = createInterface({
|
|
38
|
+
input: fileStream,
|
|
39
|
+
crlfDelay: Infinity
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
let lineNumber = 0;
|
|
43
|
+
let currentChunk = '';
|
|
44
|
+
let chunkLineCount = 0;
|
|
45
|
+
|
|
46
|
+
rl.on('line', async (line) => {
|
|
47
|
+
lineNumber++;
|
|
48
|
+
currentChunk += line + '\n';
|
|
49
|
+
chunkLineCount++;
|
|
50
|
+
|
|
51
|
+
// Process in chunks to avoid memory buildup
|
|
52
|
+
if (chunkLineCount >= 1000) {
|
|
53
|
+
try {
|
|
54
|
+
await processor(currentChunk, lineNumber - chunkLineCount + 1);
|
|
55
|
+
currentChunk = '';
|
|
56
|
+
chunkLineCount = 0;
|
|
57
|
+
|
|
58
|
+
// Force garbage collection if available
|
|
59
|
+
this.tryGarbageCollect();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
rl.close();
|
|
62
|
+
reject(error);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
rl.on('close', async () => {
|
|
69
|
+
try {
|
|
70
|
+
// Process remaining chunk
|
|
71
|
+
if (currentChunk.trim()) {
|
|
72
|
+
await processor(currentChunk, lineNumber - chunkLineCount + 1);
|
|
73
|
+
}
|
|
74
|
+
resolve();
|
|
75
|
+
} catch (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
rl.on('error', reject);
|
|
81
|
+
fileStream.on('error', reject);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Process array in memory-efficient batches
|
|
87
|
+
*/
|
|
88
|
+
static async processBatches<T, R>(
|
|
89
|
+
items: T[],
|
|
90
|
+
processor: (batch: T[]) => Promise<R[]>,
|
|
91
|
+
batchSize: number = 100
|
|
92
|
+
): Promise<R[]> {
|
|
93
|
+
const results: R[] = [];
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
96
|
+
const batch = items.slice(i, i + batchSize);
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const batchResults = await processor(batch);
|
|
100
|
+
results.push(...batchResults);
|
|
101
|
+
|
|
102
|
+
// Force garbage collection between batches
|
|
103
|
+
this.tryGarbageCollect();
|
|
104
|
+
|
|
105
|
+
// Small delay to prevent overwhelming the system
|
|
106
|
+
if (i + batchSize < items.length) {
|
|
107
|
+
await this.sleep(1);
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.warn(`Error processing batch ${i}-${i + batchSize}: ${error}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return results;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Monitor memory usage and warn if high
|
|
119
|
+
*/
|
|
120
|
+
static checkMemoryUsage(): {
|
|
121
|
+
usage: NodeJS.MemoryUsage;
|
|
122
|
+
warning?: string;
|
|
123
|
+
} {
|
|
124
|
+
const usage = process.memoryUsage();
|
|
125
|
+
let warning: string | undefined;
|
|
126
|
+
|
|
127
|
+
// Check if memory usage is high (over 100MB heap used)
|
|
128
|
+
if (usage.heapUsed > this.GC_THRESHOLD) {
|
|
129
|
+
warning = `High memory usage detected: ${Math.round(usage.heapUsed / 1024 / 1024)}MB heap used`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { usage, warning };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Try to trigger garbage collection if available
|
|
137
|
+
*/
|
|
138
|
+
static tryGarbageCollect(): void {
|
|
139
|
+
if (global.gc) {
|
|
140
|
+
try {
|
|
141
|
+
global.gc();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
// Ignore GC errors
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Sleep utility for batch processing
|
|
150
|
+
*/
|
|
151
|
+
static sleep(ms: number): Promise<void> {
|
|
152
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create memory-efficient data structure for violations
|
|
157
|
+
*/
|
|
158
|
+
static createViolationTracker(): ViolationTracker {
|
|
159
|
+
return new ViolationTracker();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Optimize object for memory usage by removing undefined properties
|
|
164
|
+
*/
|
|
165
|
+
static optimizeObject<T extends Record<string, any>>(obj: T): T {
|
|
166
|
+
const optimized = {} as T;
|
|
167
|
+
|
|
168
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
169
|
+
if (value !== undefined && value !== null) {
|
|
170
|
+
optimized[key as keyof T] = value;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return optimized;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get memory usage statistics
|
|
179
|
+
*/
|
|
180
|
+
static getMemoryStats(): {
|
|
181
|
+
heapUsed: string;
|
|
182
|
+
heapTotal: string;
|
|
183
|
+
external: string;
|
|
184
|
+
rss: string;
|
|
185
|
+
} {
|
|
186
|
+
const usage = process.memoryUsage();
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
|
|
190
|
+
heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
|
|
191
|
+
external: `${Math.round(usage.external / 1024 / 1024)}MB`,
|
|
192
|
+
rss: `${Math.round(usage.rss / 1024 / 1024)}MB`
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Memory-efficient violation tracking
|
|
199
|
+
*/
|
|
200
|
+
class ViolationTracker {
|
|
201
|
+
private violations = new Map<string, any>();
|
|
202
|
+
private fileIndex = new Map<string, number>();
|
|
203
|
+
private nextFileId = 0;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Add violation with memory optimization
|
|
207
|
+
*/
|
|
208
|
+
addViolation(violation: any): void {
|
|
209
|
+
// Optimize file path storage using indices
|
|
210
|
+
let fileId = this.fileIndex.get(violation.file);
|
|
211
|
+
if (fileId === undefined) {
|
|
212
|
+
fileId = this.nextFileId++;
|
|
213
|
+
this.fileIndex.set(violation.file, fileId);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Create optimized violation object
|
|
217
|
+
const optimized = {
|
|
218
|
+
f: violation.feature,
|
|
219
|
+
fid: violation.featureId,
|
|
220
|
+
fi: fileId, // file index instead of full path
|
|
221
|
+
l: violation.line,
|
|
222
|
+
c: violation.column,
|
|
223
|
+
ctx: violation.context?.substring(0, 100), // Limit context length
|
|
224
|
+
b: violation.browser,
|
|
225
|
+
r: violation.required,
|
|
226
|
+
a: violation.actual,
|
|
227
|
+
bs: violation.baselineStatus,
|
|
228
|
+
rs: violation.reason?.substring(0, 200) // Limit reason length
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const key = `${fileId}-${violation.line}-${violation.feature}`;
|
|
232
|
+
this.violations.set(key, optimized);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get all violations with full data
|
|
237
|
+
*/
|
|
238
|
+
getViolations(): any[] {
|
|
239
|
+
const result: any[] = [];
|
|
240
|
+
const fileIdToPath = new Map<number, string>();
|
|
241
|
+
|
|
242
|
+
// Create reverse mapping
|
|
243
|
+
for (const [path, id] of this.fileIndex) {
|
|
244
|
+
fileIdToPath.set(id, path);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for (const optimized of this.violations.values()) {
|
|
248
|
+
result.push({
|
|
249
|
+
feature: optimized.f,
|
|
250
|
+
featureId: optimized.fid,
|
|
251
|
+
file: fileIdToPath.get(optimized.fi) || 'unknown',
|
|
252
|
+
line: optimized.l,
|
|
253
|
+
column: optimized.c,
|
|
254
|
+
context: optimized.ctx,
|
|
255
|
+
browser: optimized.b,
|
|
256
|
+
required: optimized.r,
|
|
257
|
+
actual: optimized.a,
|
|
258
|
+
baselineStatus: optimized.bs,
|
|
259
|
+
reason: optimized.rs
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get memory usage statistics
|
|
268
|
+
*/
|
|
269
|
+
getStats(): {
|
|
270
|
+
violationCount: number;
|
|
271
|
+
fileCount: number;
|
|
272
|
+
memoryEstimate: string;
|
|
273
|
+
} {
|
|
274
|
+
const violationCount = this.violations.size;
|
|
275
|
+
const fileCount = this.fileIndex.size;
|
|
276
|
+
|
|
277
|
+
// Rough memory estimate (each violation ~200 bytes)
|
|
278
|
+
const memoryEstimate = `${Math.round(violationCount * 200 / 1024)}KB`;
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
violationCount,
|
|
282
|
+
fileCount,
|
|
283
|
+
memoryEstimate
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Clear all data
|
|
289
|
+
*/
|
|
290
|
+
clear(): void {
|
|
291
|
+
this.violations.clear();
|
|
292
|
+
this.fileIndex.clear();
|
|
293
|
+
this.nextFileId = 0;
|
|
294
|
+
}
|