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,270 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { stat } from 'fs/promises';
|
|
3
|
+
import type { DetectedFeature } from '../types/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* LRU Cache implementation for web-features data and parsing results
|
|
7
|
+
*/
|
|
8
|
+
export class LRUCache<K, V> {
|
|
9
|
+
private cache = new Map<K, V>();
|
|
10
|
+
private readonly maxSize: number;
|
|
11
|
+
|
|
12
|
+
constructor(maxSize: number = 1000) {
|
|
13
|
+
this.maxSize = maxSize;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get(key: K): V | undefined {
|
|
17
|
+
const value = this.cache.get(key);
|
|
18
|
+
if (value !== undefined) {
|
|
19
|
+
// Move to end (most recently used)
|
|
20
|
+
this.cache.delete(key);
|
|
21
|
+
this.cache.set(key, value);
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
set(key: K, value: V): void {
|
|
27
|
+
if (this.cache.has(key)) {
|
|
28
|
+
this.cache.delete(key);
|
|
29
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
30
|
+
// Remove least recently used (first item)
|
|
31
|
+
const firstKey = this.cache.keys().next().value;
|
|
32
|
+
this.cache.delete(firstKey);
|
|
33
|
+
}
|
|
34
|
+
this.cache.set(key, value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
has(key: K): boolean {
|
|
38
|
+
return this.cache.has(key);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
clear(): void {
|
|
42
|
+
this.cache.clear();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
size(): number {
|
|
46
|
+
return this.cache.size;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* File metadata for incremental scanning
|
|
52
|
+
*/
|
|
53
|
+
interface FileMetadata {
|
|
54
|
+
path: string;
|
|
55
|
+
mtime: number;
|
|
56
|
+
size: number;
|
|
57
|
+
hash: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Cached parsing result
|
|
62
|
+
*/
|
|
63
|
+
interface CachedResult {
|
|
64
|
+
features: DetectedFeature[];
|
|
65
|
+
metadata: FileMetadata;
|
|
66
|
+
timestamp: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Cache manager for efficient file processing and incremental scanning
|
|
71
|
+
*/
|
|
72
|
+
export class CacheManager {
|
|
73
|
+
private readonly parseCache: LRUCache<string, CachedResult>;
|
|
74
|
+
private readonly webFeaturesCache: LRUCache<string, any>;
|
|
75
|
+
private readonly fileMetadataCache: Map<string, FileMetadata>;
|
|
76
|
+
private readonly maxCacheSize: number;
|
|
77
|
+
private readonly cacheValidityMs: number;
|
|
78
|
+
|
|
79
|
+
constructor(options: {
|
|
80
|
+
maxCacheSize?: number;
|
|
81
|
+
cacheValidityMs?: number;
|
|
82
|
+
} = {}) {
|
|
83
|
+
this.maxCacheSize = options.maxCacheSize || 1000;
|
|
84
|
+
this.cacheValidityMs = options.cacheValidityMs || 5 * 60 * 1000; // 5 minutes
|
|
85
|
+
this.parseCache = new LRUCache(this.maxCacheSize);
|
|
86
|
+
this.webFeaturesCache = new LRUCache(500);
|
|
87
|
+
this.fileMetadataCache = new Map();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get cached parsing result if file hasn't changed
|
|
92
|
+
*/
|
|
93
|
+
async getCachedParseResult(filePath: string): Promise<DetectedFeature[] | null> {
|
|
94
|
+
try {
|
|
95
|
+
const currentMetadata = await this.getFileMetadata(filePath);
|
|
96
|
+
const cached = this.parseCache.get(filePath);
|
|
97
|
+
|
|
98
|
+
if (!cached) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check if file has changed
|
|
103
|
+
if (this.hasFileChanged(cached.metadata, currentMetadata)) {
|
|
104
|
+
this.parseCache.set(filePath, { ...cached, metadata: currentMetadata });
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check cache validity
|
|
109
|
+
if (Date.now() - cached.timestamp > this.cacheValidityMs) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return cached.features;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
// File doesn't exist or can't be accessed
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Cache parsing result
|
|
122
|
+
*/
|
|
123
|
+
async setCachedParseResult(filePath: string, features: DetectedFeature[]): Promise<void> {
|
|
124
|
+
try {
|
|
125
|
+
const metadata = await this.getFileMetadata(filePath);
|
|
126
|
+
const cached: CachedResult = {
|
|
127
|
+
features,
|
|
128
|
+
metadata,
|
|
129
|
+
timestamp: Date.now()
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.parseCache.set(filePath, cached);
|
|
133
|
+
this.fileMetadataCache.set(filePath, metadata);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
// Ignore caching errors
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get cached web-features data
|
|
141
|
+
*/
|
|
142
|
+
getCachedWebFeature(featureId: string): any | null {
|
|
143
|
+
return this.webFeaturesCache.get(featureId) || null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Cache web-features data
|
|
148
|
+
*/
|
|
149
|
+
setCachedWebFeature(featureId: string, data: any): void {
|
|
150
|
+
this.webFeaturesCache.set(featureId, data);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check if files have changed since last scan
|
|
155
|
+
*/
|
|
156
|
+
async getChangedFiles(filePaths: string[]): Promise<{
|
|
157
|
+
changed: string[];
|
|
158
|
+
unchanged: string[];
|
|
159
|
+
}> {
|
|
160
|
+
const changed: string[] = [];
|
|
161
|
+
const unchanged: string[] = [];
|
|
162
|
+
|
|
163
|
+
await Promise.all(
|
|
164
|
+
filePaths.map(async (filePath) => {
|
|
165
|
+
try {
|
|
166
|
+
const currentMetadata = await this.getFileMetadata(filePath);
|
|
167
|
+
const cachedMetadata = this.fileMetadataCache.get(filePath);
|
|
168
|
+
|
|
169
|
+
if (!cachedMetadata || this.hasFileChanged(cachedMetadata, currentMetadata)) {
|
|
170
|
+
changed.push(filePath);
|
|
171
|
+
this.fileMetadataCache.set(filePath, currentMetadata);
|
|
172
|
+
} else {
|
|
173
|
+
unchanged.push(filePath);
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
// File doesn't exist or can't be accessed, consider it changed
|
|
177
|
+
changed.push(filePath);
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return { changed, unchanged };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Clear all caches
|
|
187
|
+
*/
|
|
188
|
+
clearAll(): void {
|
|
189
|
+
this.parseCache.clear();
|
|
190
|
+
this.webFeaturesCache.clear();
|
|
191
|
+
this.fileMetadataCache.clear();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Clear expired cache entries
|
|
196
|
+
*/
|
|
197
|
+
clearExpired(): void {
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
const expiredKeys: string[] = [];
|
|
200
|
+
|
|
201
|
+
// Find expired parse cache entries
|
|
202
|
+
for (const [key, value] of this.parseCache['cache']) {
|
|
203
|
+
if (now - value.timestamp > this.cacheValidityMs) {
|
|
204
|
+
expiredKeys.push(key);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Remove expired entries
|
|
209
|
+
expiredKeys.forEach(key => {
|
|
210
|
+
this.parseCache['cache'].delete(key);
|
|
211
|
+
this.fileMetadataCache.delete(key);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get cache statistics
|
|
217
|
+
*/
|
|
218
|
+
getStats(): {
|
|
219
|
+
parseCache: { size: number; maxSize: number };
|
|
220
|
+
webFeaturesCache: { size: number; maxSize: number };
|
|
221
|
+
fileMetadataCache: { size: number };
|
|
222
|
+
} {
|
|
223
|
+
return {
|
|
224
|
+
parseCache: {
|
|
225
|
+
size: this.parseCache.size(),
|
|
226
|
+
maxSize: this.maxCacheSize
|
|
227
|
+
},
|
|
228
|
+
webFeaturesCache: {
|
|
229
|
+
size: this.webFeaturesCache.size(),
|
|
230
|
+
maxSize: 500
|
|
231
|
+
},
|
|
232
|
+
fileMetadataCache: {
|
|
233
|
+
size: this.fileMetadataCache.size
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get file metadata for change detection
|
|
240
|
+
*/
|
|
241
|
+
private async getFileMetadata(filePath: string): Promise<FileMetadata> {
|
|
242
|
+
const stats = await stat(filePath);
|
|
243
|
+
const hash = this.generateFileHash(filePath, stats.mtime.getTime(), stats.size);
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
path: filePath,
|
|
247
|
+
mtime: stats.mtime.getTime(),
|
|
248
|
+
size: stats.size,
|
|
249
|
+
hash
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Check if file has changed based on metadata
|
|
255
|
+
*/
|
|
256
|
+
private hasFileChanged(cached: FileMetadata, current: FileMetadata): boolean {
|
|
257
|
+
return cached.mtime !== current.mtime ||
|
|
258
|
+
cached.size !== current.size ||
|
|
259
|
+
cached.hash !== current.hash;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Generate hash for file identification
|
|
264
|
+
*/
|
|
265
|
+
private generateFileHash(filePath: string, mtime: number, size: number): string {
|
|
266
|
+
return createHash('md5')
|
|
267
|
+
.update(`${filePath}:${mtime}:${size}`)
|
|
268
|
+
.digest('hex');
|
|
269
|
+
}
|
|
270
|
+
}
|