@bfra.me/workspace-analyzer 0.1.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/README.md +402 -0
- package/lib/chunk-4LSFAAZW.js +1 -0
- package/lib/chunk-JDF7DQ4V.js +27 -0
- package/lib/chunk-WOJ4C7N7.js +7122 -0
- package/lib/cli.d.ts +1 -0
- package/lib/cli.js +318 -0
- package/lib/index.d.ts +3701 -0
- package/lib/index.js +1262 -0
- package/lib/types/index.d.ts +146 -0
- package/lib/types/index.js +28 -0
- package/package.json +89 -0
- package/src/analyzers/analyzer.ts +201 -0
- package/src/analyzers/architectural-analyzer.ts +304 -0
- package/src/analyzers/build-config-analyzer.ts +334 -0
- package/src/analyzers/circular-import-analyzer.ts +463 -0
- package/src/analyzers/config-consistency-analyzer.ts +335 -0
- package/src/analyzers/dead-code-analyzer.ts +565 -0
- package/src/analyzers/duplicate-code-analyzer.ts +626 -0
- package/src/analyzers/duplicate-dependency-analyzer.ts +381 -0
- package/src/analyzers/eslint-config-analyzer.ts +281 -0
- package/src/analyzers/exports-field-analyzer.ts +324 -0
- package/src/analyzers/index.ts +388 -0
- package/src/analyzers/large-dependency-analyzer.ts +535 -0
- package/src/analyzers/package-json-analyzer.ts +349 -0
- package/src/analyzers/peer-dependency-analyzer.ts +275 -0
- package/src/analyzers/tree-shaking-analyzer.ts +623 -0
- package/src/analyzers/tsconfig-analyzer.ts +382 -0
- package/src/analyzers/unused-dependency-analyzer.ts +356 -0
- package/src/analyzers/version-alignment-analyzer.ts +308 -0
- package/src/api/analyze-workspace.ts +245 -0
- package/src/api/index.ts +11 -0
- package/src/cache/cache-manager.ts +495 -0
- package/src/cache/cache-schema.ts +247 -0
- package/src/cache/change-detector.ts +169 -0
- package/src/cache/file-hasher.ts +65 -0
- package/src/cache/index.ts +47 -0
- package/src/cli/commands/analyze.ts +240 -0
- package/src/cli/commands/index.ts +5 -0
- package/src/cli/index.ts +61 -0
- package/src/cli/types.ts +65 -0
- package/src/cli/ui.ts +213 -0
- package/src/cli.ts +9 -0
- package/src/config/defaults.ts +183 -0
- package/src/config/index.ts +81 -0
- package/src/config/loader.ts +270 -0
- package/src/config/merger.ts +229 -0
- package/src/config/schema.ts +263 -0
- package/src/core/incremental-analyzer.ts +462 -0
- package/src/core/index.ts +34 -0
- package/src/core/orchestrator.ts +416 -0
- package/src/graph/dependency-graph.ts +408 -0
- package/src/graph/index.ts +19 -0
- package/src/index.ts +417 -0
- package/src/parser/config-parser.ts +491 -0
- package/src/parser/import-extractor.ts +340 -0
- package/src/parser/index.ts +54 -0
- package/src/parser/typescript-parser.ts +95 -0
- package/src/performance/bundle-estimator.ts +444 -0
- package/src/performance/index.ts +27 -0
- package/src/reporters/console-reporter.ts +355 -0
- package/src/reporters/index.ts +49 -0
- package/src/reporters/json-reporter.ts +273 -0
- package/src/reporters/markdown-reporter.ts +349 -0
- package/src/reporters/reporter.ts +399 -0
- package/src/rules/builtin-rules.ts +709 -0
- package/src/rules/index.ts +52 -0
- package/src/rules/rule-engine.ts +409 -0
- package/src/scanner/index.ts +18 -0
- package/src/scanner/workspace-scanner.ts +403 -0
- package/src/types/index.ts +176 -0
- package/src/types/result.ts +19 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/pattern-matcher.ts +48 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache schema types for workspace analyzer incremental analysis.
|
|
3
|
+
*
|
|
4
|
+
* These types define the structure for storing and retrieving analysis results
|
|
5
|
+
* to enable efficient incremental analysis on large codebases.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {Issue} from '../types/index'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Schema version for cache format migration.
|
|
12
|
+
* Increment when making breaking changes to cache structure.
|
|
13
|
+
*/
|
|
14
|
+
export const CACHE_SCHEMA_VERSION = 1
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Metadata about a cached file's state at analysis time.
|
|
18
|
+
*/
|
|
19
|
+
export interface CachedFileState {
|
|
20
|
+
/** Absolute file path */
|
|
21
|
+
readonly path: string
|
|
22
|
+
/** Content hash (SHA-256) at time of analysis */
|
|
23
|
+
readonly contentHash: string
|
|
24
|
+
/** File modification timestamp (ISO 8601) */
|
|
25
|
+
readonly modifiedAt: string
|
|
26
|
+
/** File size in bytes */
|
|
27
|
+
readonly size: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Metadata about a cached analysis run.
|
|
32
|
+
*/
|
|
33
|
+
export interface CacheMetadata {
|
|
34
|
+
/** Cache schema version for migration support */
|
|
35
|
+
readonly version: number
|
|
36
|
+
/** Workspace root path that was analyzed */
|
|
37
|
+
readonly workspacePath: string
|
|
38
|
+
/** Timestamp when the cache was created (ISO 8601) */
|
|
39
|
+
readonly createdAt: string
|
|
40
|
+
/** Timestamp when the cache was last updated (ISO 8601) */
|
|
41
|
+
readonly updatedAt: string
|
|
42
|
+
/** Hash of the analyzer configuration */
|
|
43
|
+
readonly configHash: string
|
|
44
|
+
/** Workspace analyzer package version */
|
|
45
|
+
readonly analyzerVersion: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A cached analysis result for a single file.
|
|
50
|
+
*/
|
|
51
|
+
export interface CachedFileAnalysis {
|
|
52
|
+
/** File state at time of analysis */
|
|
53
|
+
readonly fileState: CachedFileState
|
|
54
|
+
/** Issues found in this file */
|
|
55
|
+
readonly issues: readonly Issue[]
|
|
56
|
+
/** Analyzer IDs that processed this file */
|
|
57
|
+
readonly analyzersRun: readonly string[]
|
|
58
|
+
/** Analysis timestamp (ISO 8601) */
|
|
59
|
+
readonly analyzedAt: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A cached package-level analysis result.
|
|
64
|
+
*/
|
|
65
|
+
export interface CachedPackageAnalysis {
|
|
66
|
+
/** Package name */
|
|
67
|
+
readonly packageName: string
|
|
68
|
+
/** Package path relative to workspace root */
|
|
69
|
+
readonly packagePath: string
|
|
70
|
+
/** Hash of package.json content */
|
|
71
|
+
readonly packageJsonHash: string
|
|
72
|
+
/** Issues found at the package level */
|
|
73
|
+
readonly issues: readonly Issue[]
|
|
74
|
+
/** Analyzer IDs that processed this package */
|
|
75
|
+
readonly analyzersRun: readonly string[]
|
|
76
|
+
/** Analysis timestamp (ISO 8601) */
|
|
77
|
+
readonly analyzedAt: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Complete analysis cache for a workspace.
|
|
82
|
+
*/
|
|
83
|
+
export interface AnalysisCache {
|
|
84
|
+
/** Cache metadata */
|
|
85
|
+
readonly metadata: CacheMetadata
|
|
86
|
+
/** Per-file analysis results indexed by file path */
|
|
87
|
+
readonly files: Readonly<Record<string, CachedFileAnalysis>>
|
|
88
|
+
/** Per-package analysis results indexed by package name */
|
|
89
|
+
readonly packages: Readonly<Record<string, CachedPackageAnalysis>>
|
|
90
|
+
/** Workspace-level issues not tied to specific files */
|
|
91
|
+
readonly workspaceIssues: readonly Issue[]
|
|
92
|
+
/** Configuration files state for invalidation detection */
|
|
93
|
+
readonly configFiles: readonly CachedFileState[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Result of cache validation check.
|
|
98
|
+
*/
|
|
99
|
+
export interface CacheValidationResult {
|
|
100
|
+
/** Whether the cache is valid and can be used */
|
|
101
|
+
readonly isValid: boolean
|
|
102
|
+
/** Files that have changed since last analysis */
|
|
103
|
+
readonly changedFiles: readonly string[]
|
|
104
|
+
/** Files that are new since last analysis */
|
|
105
|
+
readonly newFiles: readonly string[]
|
|
106
|
+
/** Files that were deleted since last analysis */
|
|
107
|
+
readonly deletedFiles: readonly string[]
|
|
108
|
+
/** Packages that need re-analysis */
|
|
109
|
+
readonly invalidatedPackages: readonly string[]
|
|
110
|
+
/** Configuration files that changed (triggers full invalidation) */
|
|
111
|
+
readonly changedConfigFiles: readonly string[]
|
|
112
|
+
/** Reason for invalidation if not valid */
|
|
113
|
+
readonly invalidationReason?: string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Options for cache operations.
|
|
118
|
+
*/
|
|
119
|
+
export interface CacheOptions {
|
|
120
|
+
/** Directory path for cache storage (default: .workspace-analyzer-cache) */
|
|
121
|
+
readonly cacheDir?: string
|
|
122
|
+
/** Maximum cache age in milliseconds (default: 7 days) */
|
|
123
|
+
readonly maxAge?: number
|
|
124
|
+
/** Whether to compress cache files (default: true) */
|
|
125
|
+
readonly compress?: boolean
|
|
126
|
+
/** Hash algorithm for file content (default: sha256) */
|
|
127
|
+
readonly hashAlgorithm?: 'sha256' | 'md5'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Statistics about cache usage.
|
|
132
|
+
*/
|
|
133
|
+
export interface CacheStatistics {
|
|
134
|
+
/** Number of cached files */
|
|
135
|
+
readonly cachedFiles: number
|
|
136
|
+
/** Number of cached packages */
|
|
137
|
+
readonly cachedPackages: number
|
|
138
|
+
/** Total cache size in bytes */
|
|
139
|
+
readonly totalSizeBytes: number
|
|
140
|
+
/** Cache age in milliseconds */
|
|
141
|
+
readonly ageMs: number
|
|
142
|
+
/** Number of cache hits during last analysis */
|
|
143
|
+
readonly hitCount: number
|
|
144
|
+
/** Number of cache misses during last analysis */
|
|
145
|
+
readonly missCount: number
|
|
146
|
+
/** Cache hit rate (0-1) */
|
|
147
|
+
readonly hitRate: number
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Configuration file patterns for cache invalidation.
|
|
152
|
+
* Changes to these files trigger re-analysis of affected areas.
|
|
153
|
+
*/
|
|
154
|
+
export const CONFIG_FILE_PATTERNS: readonly string[] = [
|
|
155
|
+
'package.json',
|
|
156
|
+
'tsconfig.json',
|
|
157
|
+
'tsconfig.*.json',
|
|
158
|
+
'eslint.config.ts',
|
|
159
|
+
'eslint.config.js',
|
|
160
|
+
'eslint.config.mjs',
|
|
161
|
+
'.eslintrc.*',
|
|
162
|
+
'tsup.config.ts',
|
|
163
|
+
'tsup.config.js',
|
|
164
|
+
'vitest.config.ts',
|
|
165
|
+
'vitest.config.js',
|
|
166
|
+
'workspace-analyzer.config.ts',
|
|
167
|
+
'workspace-analyzer.config.js',
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Default cache options.
|
|
172
|
+
*/
|
|
173
|
+
export const DEFAULT_CACHE_OPTIONS: Required<CacheOptions> = {
|
|
174
|
+
cacheDir: '.workspace-analyzer-cache',
|
|
175
|
+
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
176
|
+
compress: true,
|
|
177
|
+
hashAlgorithm: 'sha256',
|
|
178
|
+
} as const
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creates an empty analysis cache with default metadata.
|
|
182
|
+
*/
|
|
183
|
+
export function createEmptyCache(
|
|
184
|
+
workspacePath: string,
|
|
185
|
+
configHash: string,
|
|
186
|
+
analyzerVersion: string,
|
|
187
|
+
): AnalysisCache {
|
|
188
|
+
const now = new Date().toISOString()
|
|
189
|
+
return {
|
|
190
|
+
metadata: {
|
|
191
|
+
version: CACHE_SCHEMA_VERSION,
|
|
192
|
+
workspacePath,
|
|
193
|
+
createdAt: now,
|
|
194
|
+
updatedAt: now,
|
|
195
|
+
configHash,
|
|
196
|
+
analyzerVersion,
|
|
197
|
+
},
|
|
198
|
+
files: {},
|
|
199
|
+
packages: {},
|
|
200
|
+
workspaceIssues: [],
|
|
201
|
+
configFiles: [],
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Creates a cache entry for a file analysis result.
|
|
207
|
+
*/
|
|
208
|
+
export function createFileAnalysisEntry(
|
|
209
|
+
path: string,
|
|
210
|
+
contentHash: string,
|
|
211
|
+
modifiedAt: Date,
|
|
212
|
+
size: number,
|
|
213
|
+
issues: readonly Issue[],
|
|
214
|
+
analyzersRun: readonly string[],
|
|
215
|
+
): CachedFileAnalysis {
|
|
216
|
+
return {
|
|
217
|
+
fileState: {
|
|
218
|
+
path,
|
|
219
|
+
contentHash,
|
|
220
|
+
modifiedAt: modifiedAt.toISOString(),
|
|
221
|
+
size,
|
|
222
|
+
},
|
|
223
|
+
issues,
|
|
224
|
+
analyzersRun,
|
|
225
|
+
analyzedAt: new Date().toISOString(),
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Creates a cache entry for a package analysis result.
|
|
231
|
+
*/
|
|
232
|
+
export function createPackageAnalysisEntry(
|
|
233
|
+
packageName: string,
|
|
234
|
+
packagePath: string,
|
|
235
|
+
packageJsonHash: string,
|
|
236
|
+
issues: readonly Issue[],
|
|
237
|
+
analyzersRun: readonly string[],
|
|
238
|
+
): CachedPackageAnalysis {
|
|
239
|
+
return {
|
|
240
|
+
packageName,
|
|
241
|
+
packagePath,
|
|
242
|
+
packageJsonHash,
|
|
243
|
+
issues,
|
|
244
|
+
analyzersRun,
|
|
245
|
+
analyzedAt: new Date().toISOString(),
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change detector for incremental analysis.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports from @bfra.me/es/watcher with workspace-analyzer-specific utilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {ChangeDetector, ChangeDetectorOptions} from '@bfra.me/es/watcher'
|
|
8
|
+
import type {CachedFileState, CacheValidationResult} from './cache-schema'
|
|
9
|
+
import {createChangeDetector} from '@bfra.me/es/watcher'
|
|
10
|
+
|
|
11
|
+
import {createWorkspaceHasher} from './file-hasher'
|
|
12
|
+
|
|
13
|
+
// Re-export the core change detector
|
|
14
|
+
export {createChangeDetector}
|
|
15
|
+
export type {ChangeDetector, ChangeDetectorOptions}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Options for creating an analysis change detector.
|
|
19
|
+
*/
|
|
20
|
+
export interface AnalysisChangeDetectorOptions extends ChangeDetectorOptions {
|
|
21
|
+
/** Configuration file patterns to monitor for invalidation */
|
|
22
|
+
readonly configFilePatterns?: readonly string[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extended change detector for workspace analysis.
|
|
27
|
+
*/
|
|
28
|
+
export interface AnalysisChangeDetector extends ChangeDetector {
|
|
29
|
+
/** Validate cache against current file states */
|
|
30
|
+
readonly validateCache: (
|
|
31
|
+
cachedFiles: readonly CachedFileState[],
|
|
32
|
+
currentFiles: readonly string[],
|
|
33
|
+
) => Promise<CacheValidationResult>
|
|
34
|
+
/** Get all recorded file paths */
|
|
35
|
+
readonly getRecordedPaths: () => readonly string[]
|
|
36
|
+
/** Check if configuration files have changed */
|
|
37
|
+
readonly hasConfigChanged: (configFiles: readonly CachedFileState[]) => Promise<boolean>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates an extended change detector for workspace analysis.
|
|
42
|
+
*
|
|
43
|
+
* @param options - Change detector configuration options
|
|
44
|
+
* @returns An AnalysisChangeDetector instance
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const detector = createAnalysisChangeDetector()
|
|
49
|
+
*
|
|
50
|
+
* // Record initial file state
|
|
51
|
+
* await detector.record('src/index.ts')
|
|
52
|
+
*
|
|
53
|
+
* // Later, validate cache
|
|
54
|
+
* const validation = await detector.validateCache(
|
|
55
|
+
* cachedFileStates,
|
|
56
|
+
* currentFilePaths
|
|
57
|
+
* )
|
|
58
|
+
*
|
|
59
|
+
* if (!validation.isValid) {
|
|
60
|
+
* console.log('Cache invalid:', validation.invalidationReason)
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export function createAnalysisChangeDetector(
|
|
65
|
+
options: AnalysisChangeDetectorOptions = {},
|
|
66
|
+
): AnalysisChangeDetector {
|
|
67
|
+
const baseDetector = createChangeDetector(options)
|
|
68
|
+
const hasher = createWorkspaceHasher({algorithm: options.algorithm})
|
|
69
|
+
const recordedPaths = new Set<string>()
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
async hasChanged(path: string): Promise<boolean> {
|
|
73
|
+
return baseDetector.hasChanged(path)
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async record(path: string): Promise<void> {
|
|
77
|
+
recordedPaths.add(path)
|
|
78
|
+
return baseDetector.record(path)
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
clear(path: string): void {
|
|
82
|
+
recordedPaths.delete(path)
|
|
83
|
+
baseDetector.clear(path)
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
clearAll(): void {
|
|
87
|
+
recordedPaths.clear()
|
|
88
|
+
baseDetector.clearAll()
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
getRecordedPaths(): readonly string[] {
|
|
92
|
+
return Array.from(recordedPaths)
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
async validateCache(
|
|
96
|
+
cachedFiles: readonly CachedFileState[],
|
|
97
|
+
currentFiles: readonly string[],
|
|
98
|
+
): Promise<CacheValidationResult> {
|
|
99
|
+
const cachedPaths = new Set(cachedFiles.map(f => f.path))
|
|
100
|
+
const currentPaths = new Set(currentFiles)
|
|
101
|
+
|
|
102
|
+
const changedFiles: string[] = []
|
|
103
|
+
const newFiles: string[] = []
|
|
104
|
+
const deletedFiles: string[] = []
|
|
105
|
+
|
|
106
|
+
// Check for new files
|
|
107
|
+
for (const path of currentPaths) {
|
|
108
|
+
if (!cachedPaths.has(path)) {
|
|
109
|
+
newFiles.push(path)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check for deleted and changed files
|
|
114
|
+
for (const cached of cachedFiles) {
|
|
115
|
+
if (!currentPaths.has(cached.path)) {
|
|
116
|
+
deletedFiles.push(cached.path)
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check if file content has changed
|
|
121
|
+
try {
|
|
122
|
+
const currentHash = await hasher.hash(cached.path)
|
|
123
|
+
if (currentHash !== cached.contentHash) {
|
|
124
|
+
changedFiles.push(cached.path)
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
// File might have been deleted or inaccessible
|
|
128
|
+
deletedFiles.push(cached.path)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const hasChanges = changedFiles.length > 0 || newFiles.length > 0 || deletedFiles.length > 0
|
|
133
|
+
|
|
134
|
+
let invalidationReason: string | undefined
|
|
135
|
+
if (hasChanges) {
|
|
136
|
+
const reasons: string[] = []
|
|
137
|
+
if (changedFiles.length > 0) reasons.push(`${changedFiles.length} files changed`)
|
|
138
|
+
if (newFiles.length > 0) reasons.push(`${newFiles.length} new files`)
|
|
139
|
+
if (deletedFiles.length > 0) reasons.push(`${deletedFiles.length} files deleted`)
|
|
140
|
+
invalidationReason = reasons.join(', ')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
isValid: !hasChanges,
|
|
145
|
+
changedFiles,
|
|
146
|
+
newFiles,
|
|
147
|
+
deletedFiles,
|
|
148
|
+
invalidatedPackages: [], // Computed by cache manager based on file paths
|
|
149
|
+
changedConfigFiles: [],
|
|
150
|
+
invalidationReason,
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
async hasConfigChanged(configFiles: readonly CachedFileState[]): Promise<boolean> {
|
|
155
|
+
for (const config of configFiles) {
|
|
156
|
+
try {
|
|
157
|
+
const currentHash = await hasher.hash(config.path)
|
|
158
|
+
if (currentHash !== config.contentHash) {
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
// Config file was deleted or inaccessible = changed
|
|
163
|
+
return true
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return false
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File hasher for cache invalidation and change detection.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports from @bfra.me/es/watcher with workspace-analyzer-specific utilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {FileHasher} from '@bfra.me/es/watcher'
|
|
8
|
+
import {createFileHasher} from '@bfra.me/es/watcher'
|
|
9
|
+
|
|
10
|
+
// Re-export the core hasher factory
|
|
11
|
+
export {createFileHasher}
|
|
12
|
+
export type {FileHasher}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Options for creating a workspace file hasher.
|
|
16
|
+
*/
|
|
17
|
+
export interface WorkspaceHasherOptions {
|
|
18
|
+
/** Hash algorithm to use (default: sha256) */
|
|
19
|
+
readonly algorithm?: 'sha256' | 'md5'
|
|
20
|
+
/** Whether to normalize line endings before hashing (default: true) */
|
|
21
|
+
readonly normalizeLineEndings?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Extended file hasher with workspace-specific utilities.
|
|
26
|
+
*/
|
|
27
|
+
export interface WorkspaceFileHasher extends FileHasher {
|
|
28
|
+
/** Hash a JSON object consistently (keys sorted) */
|
|
29
|
+
readonly hashJson: (obj: unknown) => string
|
|
30
|
+
/** Hash multiple files and return combined hash */
|
|
31
|
+
readonly hashFiles: (paths: readonly string[]) => Promise<string>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates an extended file hasher with workspace-specific utilities.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Hasher configuration options
|
|
38
|
+
* @returns A WorkspaceFileHasher instance
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const hasher = createWorkspaceHasher()
|
|
43
|
+
* const configHash = hasher.hashJson(analyzerConfig)
|
|
44
|
+
* const filesHash = await hasher.hashFiles(['package.json', 'tsconfig.json'])
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function createWorkspaceHasher(options: WorkspaceHasherOptions = {}): WorkspaceFileHasher {
|
|
48
|
+
const {algorithm = 'sha256'} = options
|
|
49
|
+
const baseHasher = createFileHasher(algorithm)
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
...baseHasher,
|
|
53
|
+
|
|
54
|
+
hashJson(obj: unknown): string {
|
|
55
|
+
const normalized = JSON.stringify(obj, Object.keys(obj as object).sort(), 0)
|
|
56
|
+
return baseHasher.hashContent(normalized)
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
async hashFiles(paths: readonly string[]): Promise<string> {
|
|
60
|
+
const hashes = await Promise.all(paths.map(async path => baseHasher.hash(path)))
|
|
61
|
+
const combined = hashes.join(':')
|
|
62
|
+
return baseHasher.hashContent(combined)
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache module exports for workspace analyzer.
|
|
3
|
+
*
|
|
4
|
+
* Provides caching infrastructure for incremental analysis including
|
|
5
|
+
* file hashing, change detection, and cache management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Cache manager
|
|
9
|
+
export {collectConfigFileStates, createCacheManager, initializeCache} from './cache-manager'
|
|
10
|
+
|
|
11
|
+
export type {CacheError, CacheErrorCode, CacheManager, CacheManagerOptions} from './cache-manager'
|
|
12
|
+
|
|
13
|
+
// Cache schema types and utilities
|
|
14
|
+
export {
|
|
15
|
+
CACHE_SCHEMA_VERSION,
|
|
16
|
+
CONFIG_FILE_PATTERNS,
|
|
17
|
+
createEmptyCache,
|
|
18
|
+
createFileAnalysisEntry,
|
|
19
|
+
createPackageAnalysisEntry,
|
|
20
|
+
DEFAULT_CACHE_OPTIONS,
|
|
21
|
+
} from './cache-schema'
|
|
22
|
+
|
|
23
|
+
export type {
|
|
24
|
+
AnalysisCache,
|
|
25
|
+
CachedFileAnalysis,
|
|
26
|
+
CachedFileState,
|
|
27
|
+
CachedPackageAnalysis,
|
|
28
|
+
CacheMetadata,
|
|
29
|
+
CacheOptions,
|
|
30
|
+
CacheStatistics,
|
|
31
|
+
CacheValidationResult,
|
|
32
|
+
} from './cache-schema'
|
|
33
|
+
|
|
34
|
+
// Change detector utilities
|
|
35
|
+
export {createAnalysisChangeDetector, createChangeDetector} from './change-detector'
|
|
36
|
+
|
|
37
|
+
export type {
|
|
38
|
+
AnalysisChangeDetector,
|
|
39
|
+
AnalysisChangeDetectorOptions,
|
|
40
|
+
ChangeDetector,
|
|
41
|
+
ChangeDetectorOptions,
|
|
42
|
+
} from './change-detector'
|
|
43
|
+
|
|
44
|
+
// File hasher utilities
|
|
45
|
+
export {createFileHasher, createWorkspaceHasher} from './file-hasher'
|
|
46
|
+
|
|
47
|
+
export type {FileHasher, WorkspaceFileHasher, WorkspaceHasherOptions} from './file-hasher'
|