@hyperfrontend/project-scope 0.2.0 → 0.2.1
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/CHANGELOG.md +8 -16
- package/analyze.d.ts.map +1 -1
- package/cli/commands/analyze.d.ts +8 -0
- package/cli/commands/analyze.d.ts.map +1 -1
- package/cli/commands/config.d.ts +7 -0
- package/cli/commands/config.d.ts.map +1 -1
- package/cli/commands/deps.d.ts +6 -0
- package/cli/commands/deps.d.ts.map +1 -1
- package/cli/commands/tree.d.ts +12 -0
- package/cli/commands/tree.d.ts.map +1 -1
- package/cli/index.cjs.js +73 -206
- package/cli/index.cjs.js.map +1 -1
- package/cli/index.esm.js +73 -206
- package/cli/index.esm.js.map +1 -1
- package/cli/run.d.ts.map +1 -1
- package/core/cache.d.ts +1 -0
- package/core/cache.d.ts.map +1 -1
- package/core/encoding/convert.d.ts.map +1 -1
- package/core/encoding/detect.d.ts +5 -0
- package/core/encoding/detect.d.ts.map +1 -1
- package/core/encoding/index.cjs.js +2 -23
- package/core/encoding/index.cjs.js.map +1 -1
- package/core/encoding/index.esm.js +2 -23
- package/core/encoding/index.esm.js.map +1 -1
- package/core/errors/structured-errors.d.ts +2 -0
- package/core/errors/structured-errors.d.ts.map +1 -1
- package/core/fs/directory.d.ts +3 -0
- package/core/fs/directory.d.ts.map +1 -1
- package/core/fs/index.cjs.js +0 -14
- package/core/fs/index.cjs.js.map +1 -1
- package/core/fs/index.esm.js +0 -14
- package/core/fs/index.esm.js.map +1 -1
- package/core/fs/read.d.ts +11 -3
- package/core/fs/read.d.ts.map +1 -1
- package/core/fs/traversal.d.ts.map +1 -1
- package/core/index.cjs.js +6 -62
- package/core/index.cjs.js.map +1 -1
- package/core/index.esm.js +6 -62
- package/core/index.esm.js.map +1 -1
- package/core/logger.d.ts.map +1 -1
- package/core/path/index.cjs.js +0 -1
- package/core/path/index.cjs.js.map +1 -1
- package/core/path/index.esm.js +0 -1
- package/core/path/index.esm.js.map +1 -1
- package/core/path/normalize.d.ts.map +1 -1
- package/core/patterns/glob.d.ts +0 -4
- package/core/patterns/glob.d.ts.map +1 -1
- package/core/platform/detect.d.ts.map +1 -1
- package/core/platform/index.cjs.js +0 -10
- package/core/platform/index.cjs.js.map +1 -1
- package/core/platform/index.esm.js +0 -10
- package/core/platform/index.esm.js.map +1 -1
- package/core/platform/line-endings.d.ts.map +1 -1
- package/heuristics/dependencies/analyze.d.ts.map +1 -1
- package/heuristics/dependencies/index.cjs.js +0 -17
- package/heuristics/dependencies/index.cjs.js.map +1 -1
- package/heuristics/dependencies/index.esm.js +0 -17
- package/heuristics/dependencies/index.esm.js.map +1 -1
- package/heuristics/entry-points/discover.d.ts +34 -7
- package/heuristics/entry-points/discover.d.ts.map +1 -1
- package/heuristics/entry-points/index.cjs.js +6 -34
- package/heuristics/entry-points/index.cjs.js.map +1 -1
- package/heuristics/entry-points/index.esm.js +6 -34
- package/heuristics/entry-points/index.esm.js.map +1 -1
- package/heuristics/framework/index.cjs.js +1 -63
- package/heuristics/framework/index.cjs.js.map +1 -1
- package/heuristics/framework/index.esm.js +1 -63
- package/heuristics/framework/index.esm.js.map +1 -1
- package/heuristics/index.cjs.js +7 -88
- package/heuristics/index.cjs.js.map +1 -1
- package/heuristics/index.esm.js +7 -88
- package/heuristics/index.esm.js.map +1 -1
- package/heuristics/project-type/index.cjs.js +1 -63
- package/heuristics/project-type/index.cjs.js.map +1 -1
- package/heuristics/project-type/index.esm.js +1 -63
- package/heuristics/project-type/index.esm.js.map +1 -1
- package/index.cjs.js +81 -293
- package/index.cjs.js.map +1 -1
- package/index.esm.js +81 -293
- package/index.esm.js.map +1 -1
- package/nx/detect.d.ts.map +1 -1
- package/nx/devkit-loader.d.ts.map +1 -1
- package/nx/index.cjs.js +0 -29
- package/nx/index.cjs.js.map +1 -1
- package/nx/index.esm.js +0 -29
- package/nx/index.esm.js.map +1 -1
- package/nx/project-config.d.ts +2 -0
- package/nx/project-config.d.ts.map +1 -1
- package/package.json +1 -1
- package/project/config/index.cjs.js +4 -46
- package/project/config/index.cjs.js.map +1 -1
- package/project/config/index.esm.js +4 -46
- package/project/config/index.esm.js.map +1 -1
- package/project/config/patterns.d.ts.map +1 -1
- package/project/index.cjs.js +4 -47
- package/project/index.cjs.js.map +1 -1
- package/project/index.esm.js +4 -47
- package/project/index.esm.js.map +1 -1
- package/project/package/index.cjs.js +0 -11
- package/project/package/index.cjs.js.map +1 -1
- package/project/package/index.esm.js +0 -11
- package/project/package/index.esm.js.map +1 -1
- package/project/package/read.d.ts +1 -0
- package/project/package/read.d.ts.map +1 -1
- package/project/root/index.cjs.js +0 -11
- package/project/root/index.cjs.js.map +1 -1
- package/project/root/index.esm.js +0 -11
- package/project/root/index.esm.js.map +1 -1
- package/project/traversal/index.cjs.js +4 -28
- package/project/traversal/index.cjs.js.map +1 -1
- package/project/traversal/index.esm.js +4 -28
- package/project/traversal/index.esm.js.map +1 -1
- package/tech/backend/express.d.ts.map +1 -1
- package/tech/backend/fastify.d.ts.map +1 -1
- package/tech/backend/index.cjs.js +0 -17
- package/tech/backend/index.cjs.js.map +1 -1
- package/tech/backend/index.esm.js +0 -17
- package/tech/backend/index.esm.js.map +1 -1
- package/tech/backend/koa.d.ts.map +1 -1
- package/tech/backend/nestjs.d.ts.map +1 -1
- package/tech/build/index.cjs.js +0 -12
- package/tech/build/index.cjs.js.map +1 -1
- package/tech/build/index.esm.js +0 -12
- package/tech/build/index.esm.js.map +1 -1
- package/tech/frontend/index.cjs.js +0 -16
- package/tech/frontend/index.cjs.js.map +1 -1
- package/tech/frontend/index.esm.js +0 -16
- package/tech/frontend/index.esm.js.map +1 -1
- package/tech/frontend/qwik.d.ts.map +1 -1
- package/tech/frontend/remix.d.ts.map +1 -1
- package/tech/frontend/sveltekit.d.ts.map +1 -1
- package/tech/index.cjs.js +1 -63
- package/tech/index.cjs.js.map +1 -1
- package/tech/index.d.ts.map +1 -1
- package/tech/index.esm.js +1 -63
- package/tech/index.esm.js.map +1 -1
- package/tech/legacy/angularjs.d.ts.map +1 -1
- package/tech/legacy/backbone.d.ts.map +1 -1
- package/tech/legacy/ember.d.ts.map +1 -1
- package/tech/legacy/index.cjs.js +0 -26
- package/tech/legacy/index.cjs.js.map +1 -1
- package/tech/legacy/index.esm.js +0 -26
- package/tech/legacy/index.esm.js.map +1 -1
- package/tech/legacy/jquery.d.ts.map +1 -1
- package/tech/linting/biome.d.ts.map +1 -1
- package/tech/linting/index.cjs.js +0 -14
- package/tech/linting/index.cjs.js.map +1 -1
- package/tech/linting/index.esm.js +0 -14
- package/tech/linting/index.esm.js.map +1 -1
- package/tech/linting/prettier.d.ts.map +1 -1
- package/tech/monorepo/index.cjs.js +1 -13
- package/tech/monorepo/index.cjs.js.map +1 -1
- package/tech/monorepo/index.esm.js +1 -13
- package/tech/monorepo/index.esm.js.map +1 -1
- package/tech/monorepo/types.d.ts +1 -1
- package/tech/monorepo/types.d.ts.map +1 -1
- package/tech/shared-utils/detector-helpers.d.ts.map +1 -1
- package/tech/testing/index.cjs.js +0 -12
- package/tech/testing/index.cjs.js.map +1 -1
- package/tech/testing/index.esm.js +0 -12
- package/tech/testing/index.esm.js.map +1 -1
- package/tech/types/detectors.d.ts.map +1 -1
- package/tech/types/index.cjs.js +0 -27
- package/tech/types/index.cjs.js.map +1 -1
- package/tech/types/index.esm.js +0 -27
- package/tech/types/index.esm.js.map +1 -1
- package/vfs/commit.d.ts.map +1 -1
- package/vfs/diff.d.ts.map +1 -1
- package/vfs/factory.d.ts.map +1 -1
- package/vfs/fs-tree.d.ts.map +1 -1
- package/vfs/index.cjs.js +0 -45
- package/vfs/index.cjs.js.map +1 -1
- package/vfs/index.esm.js +0 -45
- package/vfs/index.esm.js.map +1 -1
- package/vfs/types.d.ts +1 -0
- package/vfs/types.d.ts.map +1 -1
package/index.esm.js
CHANGED
|
@@ -11,7 +11,6 @@ import { tmpdir, platform, arch } from 'node:os';
|
|
|
11
11
|
*
|
|
12
12
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/console
|
|
13
13
|
*/
|
|
14
|
-
// Capture references at module initialization time
|
|
15
14
|
const _console = globalThis.console;
|
|
16
15
|
/**
|
|
17
16
|
* (Safe copy) Outputs a message to the console.
|
|
@@ -86,44 +85,6 @@ _console.timeEnd.bind(_console);
|
|
|
86
85
|
*/
|
|
87
86
|
_console.timeLog.bind(_console);
|
|
88
87
|
|
|
89
|
-
/**
|
|
90
|
-
* Safe copies of Array built-in static methods.
|
|
91
|
-
*
|
|
92
|
-
* These references are captured at module initialization time to protect against
|
|
93
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
94
|
-
*
|
|
95
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/array
|
|
96
|
-
*/
|
|
97
|
-
// Capture references at module initialization time
|
|
98
|
-
const _Array = globalThis.Array;
|
|
99
|
-
/**
|
|
100
|
-
* (Safe copy) Determines whether the passed value is an Array.
|
|
101
|
-
*/
|
|
102
|
-
const isArray = _Array.isArray;
|
|
103
|
-
/**
|
|
104
|
-
* (Safe copy) Creates an array from an array-like or iterable object.
|
|
105
|
-
*/
|
|
106
|
-
const from = _Array.from;
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Safe copies of JSON built-in methods.
|
|
110
|
-
*
|
|
111
|
-
* These references are captured at module initialization time to protect against
|
|
112
|
-
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
113
|
-
*
|
|
114
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/json
|
|
115
|
-
*/
|
|
116
|
-
// Capture references at module initialization time
|
|
117
|
-
const _JSON = globalThis.JSON;
|
|
118
|
-
/**
|
|
119
|
-
* (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
|
|
120
|
-
*/
|
|
121
|
-
const parse = _JSON.parse;
|
|
122
|
-
/**
|
|
123
|
-
* (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
|
|
124
|
-
*/
|
|
125
|
-
const stringify = _JSON.stringify;
|
|
126
|
-
|
|
127
88
|
/**
|
|
128
89
|
* Safe copies of Object built-in methods.
|
|
129
90
|
*
|
|
@@ -132,7 +93,6 @@ const stringify = _JSON.stringify;
|
|
|
132
93
|
*
|
|
133
94
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/object
|
|
134
95
|
*/
|
|
135
|
-
// Capture references at module initialization time
|
|
136
96
|
const _Object = globalThis.Object;
|
|
137
97
|
/**
|
|
138
98
|
* (Safe copy) Prevents modification of existing property attributes and values,
|
|
@@ -160,30 +120,25 @@ const defineProperty = _Object.defineProperty;
|
|
|
160
120
|
*/
|
|
161
121
|
const defineProperties = _Object.defineProperties;
|
|
162
122
|
|
|
123
|
+
const registeredClasses = [];
|
|
124
|
+
|
|
163
125
|
/**
|
|
164
|
-
* Safe copies of
|
|
165
|
-
*
|
|
166
|
-
* Since constructors cannot be safely captured via Object.assign, this module
|
|
167
|
-
* provides a factory function that uses Reflect.construct internally.
|
|
126
|
+
* Safe copies of Array built-in static methods.
|
|
168
127
|
*
|
|
169
128
|
* These references are captured at module initialization time to protect against
|
|
170
129
|
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
171
130
|
*
|
|
172
|
-
* @module @hyperfrontend/immutable-api-utils/built-in-copy/
|
|
131
|
+
* @module @hyperfrontend/immutable-api-utils/built-in-copy/array
|
|
173
132
|
*/
|
|
174
|
-
|
|
175
|
-
const _Set = globalThis.Set;
|
|
176
|
-
const _Reflect$3 = globalThis.Reflect;
|
|
133
|
+
const _Array = globalThis.Array;
|
|
177
134
|
/**
|
|
178
|
-
* (Safe copy)
|
|
179
|
-
* Use this instead of `new Set()`.
|
|
180
|
-
*
|
|
181
|
-
* @param iterable - Optional iterable of values.
|
|
182
|
-
* @returns A new Set instance.
|
|
135
|
+
* (Safe copy) Determines whether the passed value is an Array.
|
|
183
136
|
*/
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
137
|
+
const isArray = _Array.isArray;
|
|
138
|
+
/**
|
|
139
|
+
* (Safe copy) Creates an array from an array-like or iterable object.
|
|
140
|
+
*/
|
|
141
|
+
const from = _Array.from;
|
|
187
142
|
|
|
188
143
|
/**
|
|
189
144
|
* Returns the data type of the target.
|
|
@@ -219,9 +174,8 @@ const getType = (target) => {
|
|
|
219
174
|
*
|
|
220
175
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/error
|
|
221
176
|
*/
|
|
222
|
-
// Capture references at module initialization time
|
|
223
177
|
const _Error = globalThis.Error;
|
|
224
|
-
const _Reflect$
|
|
178
|
+
const _Reflect$3 = globalThis.Reflect;
|
|
225
179
|
/**
|
|
226
180
|
* (Safe copy) Creates a new Error using the captured Error constructor.
|
|
227
181
|
* Use this instead of `new Error()`.
|
|
@@ -230,7 +184,7 @@ const _Reflect$2 = globalThis.Reflect;
|
|
|
230
184
|
* @param options - Optional error options.
|
|
231
185
|
* @returns A new Error instance.
|
|
232
186
|
*/
|
|
233
|
-
const createError = (message, options) => _Reflect$
|
|
187
|
+
const createError = (message, options) => _Reflect$3.construct(_Error, [message, options]);
|
|
234
188
|
|
|
235
189
|
/**
|
|
236
190
|
* Safe copies of Map built-in via factory function.
|
|
@@ -243,9 +197,8 @@ const createError = (message, options) => _Reflect$2.construct(_Error, [message,
|
|
|
243
197
|
*
|
|
244
198
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/map
|
|
245
199
|
*/
|
|
246
|
-
// Capture references at module initialization time
|
|
247
200
|
const _Map = globalThis.Map;
|
|
248
|
-
const _Reflect$
|
|
201
|
+
const _Reflect$2 = globalThis.Reflect;
|
|
249
202
|
/**
|
|
250
203
|
* (Safe copy) Creates a new Map using the captured Map constructor.
|
|
251
204
|
* Use this instead of `new Map()`.
|
|
@@ -253,7 +206,7 @@ const _Reflect$1 = globalThis.Reflect;
|
|
|
253
206
|
* @param iterable - Optional iterable of key-value pairs.
|
|
254
207
|
* @returns A new Map instance.
|
|
255
208
|
*/
|
|
256
|
-
const createMap = (iterable) => _Reflect$
|
|
209
|
+
const createMap = (iterable) => _Reflect$2.construct(_Map, iterable ? [iterable] : []);
|
|
257
210
|
|
|
258
211
|
/**
|
|
259
212
|
* Safe copies of Date built-in via factory function and static methods.
|
|
@@ -266,11 +219,10 @@ const createMap = (iterable) => _Reflect$1.construct(_Map, iterable ? [iterable]
|
|
|
266
219
|
*
|
|
267
220
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/date
|
|
268
221
|
*/
|
|
269
|
-
// Capture references at module initialization time
|
|
270
222
|
const _Date = globalThis.Date;
|
|
271
|
-
const _Reflect = globalThis.Reflect;
|
|
223
|
+
const _Reflect$1 = globalThis.Reflect;
|
|
272
224
|
function createDate(...args) {
|
|
273
|
-
return _Reflect.construct(_Date, args);
|
|
225
|
+
return _Reflect$1.construct(_Date, args);
|
|
274
226
|
}
|
|
275
227
|
/**
|
|
276
228
|
* (Safe copy) Returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
|
|
@@ -285,15 +237,11 @@ const dateNow = _Date.now;
|
|
|
285
237
|
*
|
|
286
238
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/math
|
|
287
239
|
*/
|
|
288
|
-
// Capture references at module initialization time
|
|
289
240
|
const _Math = globalThis.Math;
|
|
290
241
|
/**
|
|
291
242
|
* (Safe copy) Returns the value of a number rounded to the nearest integer.
|
|
292
243
|
*/
|
|
293
244
|
const round = _Math.round;
|
|
294
|
-
// ============================================================================
|
|
295
|
-
// Min/Max
|
|
296
|
-
// ============================================================================
|
|
297
245
|
/**
|
|
298
246
|
* (Safe copy) Returns the larger of zero or more numbers.
|
|
299
247
|
*/
|
|
@@ -303,6 +251,28 @@ const max = _Math.max;
|
|
|
303
251
|
*/
|
|
304
252
|
const min = _Math.min;
|
|
305
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Safe copies of Set built-in via factory function.
|
|
256
|
+
*
|
|
257
|
+
* Since constructors cannot be safely captured via Object.assign, this module
|
|
258
|
+
* provides a factory function that uses Reflect.construct internally.
|
|
259
|
+
*
|
|
260
|
+
* These references are captured at module initialization time to protect against
|
|
261
|
+
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
262
|
+
*
|
|
263
|
+
* @module @hyperfrontend/immutable-api-utils/built-in-copy/set
|
|
264
|
+
*/
|
|
265
|
+
const _Set = globalThis.Set;
|
|
266
|
+
const _Reflect = globalThis.Reflect;
|
|
267
|
+
/**
|
|
268
|
+
* (Safe copy) Creates a new Set using the captured Set constructor.
|
|
269
|
+
* Use this instead of `new Set()`.
|
|
270
|
+
*
|
|
271
|
+
* @param iterable - Optional iterable of values.
|
|
272
|
+
* @returns A new Set instance.
|
|
273
|
+
*/
|
|
274
|
+
const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
|
|
275
|
+
|
|
306
276
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
307
277
|
/**
|
|
308
278
|
* Creates a wrapper function that only executes the wrapped function if the condition function returns true.
|
|
@@ -466,6 +436,24 @@ function notFnMsg(label) {
|
|
|
466
436
|
|
|
467
437
|
createLogger(error, warn, log, info, debug);
|
|
468
438
|
|
|
439
|
+
/**
|
|
440
|
+
* Safe copies of JSON built-in methods.
|
|
441
|
+
*
|
|
442
|
+
* These references are captured at module initialization time to protect against
|
|
443
|
+
* prototype pollution attacks. Import only what you need for tree-shaking.
|
|
444
|
+
*
|
|
445
|
+
* @module @hyperfrontend/immutable-api-utils/built-in-copy/json
|
|
446
|
+
*/
|
|
447
|
+
const _JSON = globalThis.JSON;
|
|
448
|
+
/**
|
|
449
|
+
* (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
|
|
450
|
+
*/
|
|
451
|
+
const parse = _JSON.parse;
|
|
452
|
+
/**
|
|
453
|
+
* (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
|
|
454
|
+
*/
|
|
455
|
+
const stringify = _JSON.stringify;
|
|
456
|
+
|
|
469
457
|
/**
|
|
470
458
|
* Global log level registry.
|
|
471
459
|
* Tracks all created scoped loggers to allow global log level changes.
|
|
@@ -609,14 +597,11 @@ function formatMessage(namespace, message, meta) {
|
|
|
609
597
|
*/
|
|
610
598
|
function createScopedLogger(namespace, options = {}) {
|
|
611
599
|
const { level = 'error', sanitizeSecrets = true } = options;
|
|
612
|
-
// Create wrapper functions that add namespace prefix and sanitization
|
|
613
600
|
const createLogFn = (baseFn) => (message, meta) => {
|
|
614
601
|
const processedMeta = sanitizeSecrets && meta ? sanitize(meta) : meta;
|
|
615
602
|
baseFn(formatMessage(namespace, message, processedMeta));
|
|
616
603
|
};
|
|
617
|
-
// Create base logger with wrapped functions
|
|
618
604
|
const baseLogger = createLogger(createLogFn(error), createLogFn(warn), createLogFn(log), createLogFn(info), createLogFn(debug));
|
|
619
|
-
// Set initial log level (use global override if set)
|
|
620
605
|
baseLogger.setLogLevel(globalLogLevel ?? level);
|
|
621
606
|
const scopedLogger = freeze({
|
|
622
607
|
error: (message, meta) => baseLogger.error(message, meta),
|
|
@@ -627,7 +612,6 @@ function createScopedLogger(namespace, options = {}) {
|
|
|
627
612
|
setLogLevel: baseLogger.setLogLevel,
|
|
628
613
|
getLogLevel: baseLogger.getLogLevel,
|
|
629
614
|
});
|
|
630
|
-
// Register logger for global level management
|
|
631
615
|
loggerRegistry.add(scopedLogger);
|
|
632
616
|
return scopedLogger;
|
|
633
617
|
}
|
|
@@ -1063,17 +1047,14 @@ function readDirectoryRecursive(dirPath, options) {
|
|
|
1063
1047
|
entries = readDirectory(currentPath);
|
|
1064
1048
|
}
|
|
1065
1049
|
catch {
|
|
1066
|
-
// Skip inaccessible directories
|
|
1067
1050
|
fsDirLogger.debug('Skipping inaccessible directory', { path: currentPath });
|
|
1068
1051
|
return;
|
|
1069
1052
|
}
|
|
1070
1053
|
for (const entry of entries) {
|
|
1071
|
-
// Skip hidden files/dirs if not included
|
|
1072
1054
|
if (!includeHidden && entry.name.startsWith('.')) {
|
|
1073
1055
|
continue;
|
|
1074
1056
|
}
|
|
1075
1057
|
results.push({ ...entry, depth });
|
|
1076
|
-
// Recurse into directories
|
|
1077
1058
|
if (entry.isDirectory || (entry.isSymlink && followSymlinks && isDirectory(entry.path))) {
|
|
1078
1059
|
walk(entry.path, depth + 1);
|
|
1079
1060
|
}
|
|
@@ -1141,7 +1122,6 @@ function joinPosix(...paths) {
|
|
|
1141
1122
|
function normalizePath(filePath) {
|
|
1142
1123
|
if (!filePath)
|
|
1143
1124
|
return '';
|
|
1144
|
-
// Normalize path and convert backslashes to forward slashes
|
|
1145
1125
|
const normalized = normalize(filePath);
|
|
1146
1126
|
return sep === '\\' ? normalized.replace(/\\/g, '/') : normalized;
|
|
1147
1127
|
}
|
|
@@ -1353,7 +1333,6 @@ function traverseUpward(startPath, predicate) {
|
|
|
1353
1333
|
}
|
|
1354
1334
|
currentPath = dirname(currentPath);
|
|
1355
1335
|
}
|
|
1356
|
-
// Check root directory
|
|
1357
1336
|
if (predicate(rootPath)) {
|
|
1358
1337
|
fsTraversalLogger.debug('Upward traversal found match at root', { startPath, foundPath: rootPath });
|
|
1359
1338
|
return rootPath;
|
|
@@ -1725,29 +1704,23 @@ const depsLogger = createScopedLogger('project-scope:heuristics:deps');
|
|
|
1725
1704
|
*/
|
|
1726
1705
|
function extractImports(content) {
|
|
1727
1706
|
const imports = [];
|
|
1728
|
-
// ES import with 'from': import X from 'path' or import { X } from 'path'
|
|
1729
|
-
// Use non-greedy match and avoid nested quantifiers by matching "from" keyword directly
|
|
1730
1707
|
const esImportFromRegex = /import\s+.+?\s+from\s+['"]([^'"]+)['"]/g;
|
|
1731
1708
|
let match;
|
|
1732
1709
|
while ((match = esImportFromRegex.exec(content)) !== null) {
|
|
1733
1710
|
imports.push(match[1]);
|
|
1734
1711
|
}
|
|
1735
|
-
// Side-effect import: import 'path'
|
|
1736
1712
|
const sideEffectImportRegex = /import\s+['"]([^'"]+)['"]/g;
|
|
1737
1713
|
while ((match = sideEffectImportRegex.exec(content)) !== null) {
|
|
1738
1714
|
imports.push(match[1]);
|
|
1739
1715
|
}
|
|
1740
|
-
// Dynamic import: import('path')
|
|
1741
1716
|
const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1742
1717
|
while ((match = dynamicImportRegex.exec(content)) !== null) {
|
|
1743
1718
|
imports.push(match[1]);
|
|
1744
1719
|
}
|
|
1745
|
-
// require: require('path')
|
|
1746
1720
|
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1747
1721
|
while ((match = requireRegex.exec(content)) !== null) {
|
|
1748
1722
|
imports.push(match[1]);
|
|
1749
1723
|
}
|
|
1750
|
-
// Re-export: export * from 'path' or export { X } from 'path'
|
|
1751
1724
|
const exportFromRegex = /export\s+.+?\s+from\s+['"]([^'"]+)['"]/g;
|
|
1752
1725
|
while ((match = exportFromRegex.exec(content)) !== null) {
|
|
1753
1726
|
imports.push(match[1]);
|
|
@@ -2061,7 +2034,6 @@ const cacheRegistry = createSet();
|
|
|
2061
2034
|
function createCache(options) {
|
|
2062
2035
|
const { ttl, maxSize } = options ?? {};
|
|
2063
2036
|
const store = createMap();
|
|
2064
|
-
// Track insertion order for FIFO eviction
|
|
2065
2037
|
const insertionOrder = [];
|
|
2066
2038
|
/**
|
|
2067
2039
|
* Check if an entry is expired.
|
|
@@ -2112,12 +2084,10 @@ function createCache(options) {
|
|
|
2112
2084
|
return entry.value;
|
|
2113
2085
|
},
|
|
2114
2086
|
set(key, value) {
|
|
2115
|
-
// If key exists, remove from order first
|
|
2116
2087
|
if (store.has(key)) {
|
|
2117
2088
|
removeFromOrder(key);
|
|
2118
2089
|
}
|
|
2119
2090
|
else {
|
|
2120
|
-
// Evict if needed before adding new entry
|
|
2121
2091
|
evictIfNeeded();
|
|
2122
2092
|
}
|
|
2123
2093
|
// eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
|
|
@@ -2150,7 +2120,6 @@ function createCache(options) {
|
|
|
2150
2120
|
return [...insertionOrder];
|
|
2151
2121
|
},
|
|
2152
2122
|
};
|
|
2153
|
-
// Register cache for global operations
|
|
2154
2123
|
cacheRegistry.add(cache);
|
|
2155
2124
|
return freeze(cache);
|
|
2156
2125
|
}
|
|
@@ -2230,7 +2199,6 @@ function memoize(fn, options) {
|
|
|
2230
2199
|
cache.set(key, result);
|
|
2231
2200
|
return result;
|
|
2232
2201
|
};
|
|
2233
|
-
// Attach cache for direct access
|
|
2234
2202
|
defineProperty(memoized, 'cache', {
|
|
2235
2203
|
value: cache,
|
|
2236
2204
|
writable: false,
|
|
@@ -2239,10 +2207,6 @@ function memoize(fn, options) {
|
|
|
2239
2207
|
return memoized;
|
|
2240
2208
|
}
|
|
2241
2209
|
|
|
2242
|
-
/**
|
|
2243
|
-
* Pattern matching utilities with ReDoS protection.
|
|
2244
|
-
* Uses character-by-character matching instead of regex where possible.
|
|
2245
|
-
*/
|
|
2246
2210
|
/**
|
|
2247
2211
|
* Match path against glob pattern using safe character iteration.
|
|
2248
2212
|
* Avoids regex to prevent ReDoS attacks.
|
|
@@ -2280,17 +2244,14 @@ function matchGlobPattern(path, pattern) {
|
|
|
2280
2244
|
* @returns True if remaining segments match
|
|
2281
2245
|
*/
|
|
2282
2246
|
function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
|
|
2283
|
-
// Base cases
|
|
2284
2247
|
if (pathIdx === pathParts.length && patternIdx === patternParts.length) {
|
|
2285
|
-
return true;
|
|
2248
|
+
return true;
|
|
2286
2249
|
}
|
|
2287
2250
|
if (patternIdx >= patternParts.length) {
|
|
2288
|
-
return false;
|
|
2251
|
+
return false;
|
|
2289
2252
|
}
|
|
2290
2253
|
const patternPart = patternParts[patternIdx];
|
|
2291
|
-
// Handle ** (globstar) - matches zero or more directories
|
|
2292
2254
|
if (patternPart === '**') {
|
|
2293
|
-
// Try matching rest of pattern against current position and all future positions
|
|
2294
2255
|
for (let i = pathIdx; i <= pathParts.length; i++) {
|
|
2295
2256
|
if (matchSegments(pathParts, patternParts, i, patternIdx + 1)) {
|
|
2296
2257
|
return true;
|
|
@@ -2299,10 +2260,9 @@ function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
|
|
|
2299
2260
|
return false;
|
|
2300
2261
|
}
|
|
2301
2262
|
if (pathIdx >= pathParts.length) {
|
|
2302
|
-
return false;
|
|
2263
|
+
return false;
|
|
2303
2264
|
}
|
|
2304
2265
|
const pathPart = pathParts[pathIdx];
|
|
2305
|
-
// Match current segment
|
|
2306
2266
|
if (matchSegment(pathPart, patternPart)) {
|
|
2307
2267
|
return matchSegments(pathParts, patternParts, pathIdx + 1, patternIdx + 1);
|
|
2308
2268
|
}
|
|
@@ -2322,12 +2282,10 @@ function matchSegment(text, pattern) {
|
|
|
2322
2282
|
while (patternIdx < pattern.length) {
|
|
2323
2283
|
const char = pattern[patternIdx];
|
|
2324
2284
|
if (char === '*') {
|
|
2325
|
-
// * matches zero or more characters
|
|
2326
2285
|
patternIdx++;
|
|
2327
2286
|
if (patternIdx === pattern.length) {
|
|
2328
|
-
return true;
|
|
2287
|
+
return true;
|
|
2329
2288
|
}
|
|
2330
|
-
// Try matching rest of pattern at each position in text
|
|
2331
2289
|
for (let i = textIdx; i <= text.length; i++) {
|
|
2332
2290
|
if (matchSegmentFrom(text, i, pattern, patternIdx)) {
|
|
2333
2291
|
return true;
|
|
@@ -2336,7 +2294,6 @@ function matchSegment(text, pattern) {
|
|
|
2336
2294
|
return false;
|
|
2337
2295
|
}
|
|
2338
2296
|
else if (char === '?') {
|
|
2339
|
-
// ? matches exactly one character
|
|
2340
2297
|
if (textIdx >= text.length) {
|
|
2341
2298
|
return false;
|
|
2342
2299
|
}
|
|
@@ -2344,10 +2301,8 @@ function matchSegment(text, pattern) {
|
|
|
2344
2301
|
patternIdx++;
|
|
2345
2302
|
}
|
|
2346
2303
|
else if (char === '{') {
|
|
2347
|
-
// {a,b,c} matches any alternative
|
|
2348
2304
|
const closeIdx = findClosingBrace(pattern, patternIdx);
|
|
2349
2305
|
if (closeIdx === -1) {
|
|
2350
|
-
// Unmatched brace, treat as literal
|
|
2351
2306
|
if (textIdx >= text.length || text[textIdx] !== char) {
|
|
2352
2307
|
return false;
|
|
2353
2308
|
}
|
|
@@ -2365,7 +2320,6 @@ function matchSegment(text, pattern) {
|
|
|
2365
2320
|
}
|
|
2366
2321
|
}
|
|
2367
2322
|
else {
|
|
2368
|
-
// Literal character
|
|
2369
2323
|
if (textIdx >= text.length || text[textIdx] !== char) {
|
|
2370
2324
|
return false;
|
|
2371
2325
|
}
|
|
@@ -2791,7 +2745,8 @@ const entryPointLogger = createScopedLogger('project-scope:heuristics:entry-poin
|
|
|
2791
2745
|
*/
|
|
2792
2746
|
const entryPointCache = createCache({ ttl: 60000, maxSize: 50 });
|
|
2793
2747
|
/**
|
|
2794
|
-
* Common entry point patterns.
|
|
2748
|
+
* Common entry point patterns by project type.
|
|
2749
|
+
* Used for convention-based entry point discovery.
|
|
2795
2750
|
*/
|
|
2796
2751
|
const ENTRY_POINT_PATTERNS = {
|
|
2797
2752
|
/** Library entry patterns */
|
|
@@ -3074,7 +3029,6 @@ function collectAllDependencies(packageJson) {
|
|
|
3074
3029
|
function parseVersionString(versionString) {
|
|
3075
3030
|
if (versionString === undefined || versionString === null)
|
|
3076
3031
|
return undefined;
|
|
3077
|
-
// Manual parsing instead of regex to avoid ReDoS
|
|
3078
3032
|
let start = 0;
|
|
3079
3033
|
while (start < versionString.length) {
|
|
3080
3034
|
const char = versionString[start];
|
|
@@ -3135,7 +3089,6 @@ function expressDetector(projectPath, packageJson) {
|
|
|
3135
3089
|
version = parseVersionString(deps['express']);
|
|
3136
3090
|
sources.push({ type: 'package.json', field: 'dependencies.express' });
|
|
3137
3091
|
}
|
|
3138
|
-
// @types/express (indicates usage)
|
|
3139
3092
|
if (deps['@types/express']) {
|
|
3140
3093
|
confidence += 10;
|
|
3141
3094
|
sources.push({ type: 'package.json', field: 'dependencies.@types/express' });
|
|
@@ -3171,13 +3124,11 @@ function nestDetector(projectPath, packageJson) {
|
|
|
3171
3124
|
let version;
|
|
3172
3125
|
let configPath;
|
|
3173
3126
|
const deps = collectAllDependencies(pkg);
|
|
3174
|
-
// @nestjs/core package
|
|
3175
3127
|
if (deps['@nestjs/core']) {
|
|
3176
3128
|
confidence += 70;
|
|
3177
3129
|
version = parseVersionString(deps['@nestjs/core']);
|
|
3178
3130
|
sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
|
|
3179
3131
|
}
|
|
3180
|
-
// @nestjs/common
|
|
3181
3132
|
if (deps['@nestjs/common']) {
|
|
3182
3133
|
confidence += 15;
|
|
3183
3134
|
sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
|
|
@@ -3228,7 +3179,6 @@ function fastifyDetector(projectPath, packageJson) {
|
|
|
3228
3179
|
confidence += 15;
|
|
3229
3180
|
sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
|
|
3230
3181
|
}
|
|
3231
|
-
// @types/fastify (older versions)
|
|
3232
3182
|
if (deps['@types/fastify']) {
|
|
3233
3183
|
confidence += 5;
|
|
3234
3184
|
sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
|
|
@@ -3263,7 +3213,6 @@ function koaDetector(projectPath, packageJson) {
|
|
|
3263
3213
|
version = parseVersionString(deps['koa']);
|
|
3264
3214
|
sources.push({ type: 'package.json', field: 'dependencies.koa' });
|
|
3265
3215
|
}
|
|
3266
|
-
// @types/koa
|
|
3267
3216
|
if (deps['@types/koa']) {
|
|
3268
3217
|
confidence += 10;
|
|
3269
3218
|
sources.push({ type: 'package.json', field: 'dependencies.@types/koa' });
|
|
@@ -3842,7 +3791,6 @@ function remixDetector(projectPath, packageJson) {
|
|
|
3842
3791
|
let confidence = 0;
|
|
3843
3792
|
let version;
|
|
3844
3793
|
const deps = collectAllDependencies(pkg);
|
|
3845
|
-
// @remix-run packages
|
|
3846
3794
|
if (deps['@remix-run/react']) {
|
|
3847
3795
|
confidence += 70;
|
|
3848
3796
|
version = parseVersionString(deps['@remix-run/react']);
|
|
@@ -4118,7 +4066,6 @@ function sveltekitDetector(projectPath, packageJson) {
|
|
|
4118
4066
|
let confidence = 0;
|
|
4119
4067
|
let version;
|
|
4120
4068
|
const deps = collectAllDependencies(pkg);
|
|
4121
|
-
// @sveltejs/kit package
|
|
4122
4069
|
if (deps['@sveltejs/kit']) {
|
|
4123
4070
|
confidence += 70;
|
|
4124
4071
|
version = parseVersionString(deps['@sveltejs/kit']);
|
|
@@ -4197,13 +4144,11 @@ function qwikDetector(projectPath, packageJson) {
|
|
|
4197
4144
|
let confidence = 0;
|
|
4198
4145
|
let version;
|
|
4199
4146
|
const deps = collectAllDependencies(pkg);
|
|
4200
|
-
// @builder.io/qwik package
|
|
4201
4147
|
if (deps['@builder.io/qwik']) {
|
|
4202
4148
|
confidence += 70;
|
|
4203
4149
|
version = parseVersionString(deps['@builder.io/qwik']);
|
|
4204
4150
|
sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
|
|
4205
4151
|
}
|
|
4206
|
-
// @builder.io/qwik-city
|
|
4207
4152
|
if (deps['@builder.io/qwik-city']) {
|
|
4208
4153
|
confidence += 20;
|
|
4209
4154
|
sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
|
|
@@ -4314,23 +4259,19 @@ function angularJSDetector(projectPath, packageJson) {
|
|
|
4314
4259
|
let confidence = 0;
|
|
4315
4260
|
let version;
|
|
4316
4261
|
const deps = collectAllDependencies(pkg);
|
|
4317
|
-
// AngularJS package (angular, not @angular/core)
|
|
4318
4262
|
if (deps['angular']) {
|
|
4319
4263
|
confidence += 70;
|
|
4320
4264
|
version = parseVersionString(deps['angular']);
|
|
4321
4265
|
sources.push({ type: 'package.json', field: 'dependencies.angular' });
|
|
4322
4266
|
}
|
|
4323
|
-
// AngularJS router
|
|
4324
4267
|
if (deps['angular-route']) {
|
|
4325
4268
|
confidence += 15;
|
|
4326
4269
|
sources.push({ type: 'package.json', field: 'dependencies.angular-route' });
|
|
4327
4270
|
}
|
|
4328
|
-
// AngularJS resource
|
|
4329
4271
|
if (deps['angular-resource']) {
|
|
4330
4272
|
confidence += 10;
|
|
4331
4273
|
sources.push({ type: 'package.json', field: 'dependencies.angular-resource' });
|
|
4332
4274
|
}
|
|
4333
|
-
// AngularJS animate
|
|
4334
4275
|
if (deps['angular-animate']) {
|
|
4335
4276
|
confidence += 5;
|
|
4336
4277
|
sources.push({ type: 'package.json', field: 'dependencies.angular-animate' });
|
|
@@ -4361,23 +4302,19 @@ function backboneDetector(projectPath, packageJson) {
|
|
|
4361
4302
|
let confidence = 0;
|
|
4362
4303
|
let version;
|
|
4363
4304
|
const deps = collectAllDependencies(pkg);
|
|
4364
|
-
// Backbone package
|
|
4365
4305
|
if (deps['backbone']) {
|
|
4366
4306
|
confidence += 70;
|
|
4367
4307
|
version = parseVersionString(deps['backbone']);
|
|
4368
4308
|
sources.push({ type: 'package.json', field: 'dependencies.backbone' });
|
|
4369
|
-
// Underscore (commonly used with Backbone)
|
|
4370
4309
|
if (deps['underscore']) {
|
|
4371
4310
|
confidence += 15;
|
|
4372
4311
|
sources.push({ type: 'package.json', field: 'dependencies.underscore' });
|
|
4373
4312
|
}
|
|
4374
|
-
// Lodash can be used as underscore replacement
|
|
4375
4313
|
if (deps['lodash']) {
|
|
4376
4314
|
confidence += 5;
|
|
4377
4315
|
sources.push({ type: 'package.json', field: 'dependencies.lodash' });
|
|
4378
4316
|
}
|
|
4379
4317
|
}
|
|
4380
|
-
// Marionette (Backbone framework)
|
|
4381
4318
|
if (deps['backbone.marionette'] || deps['marionette']) {
|
|
4382
4319
|
confidence += 10;
|
|
4383
4320
|
sources.push({ type: 'package.json', field: 'dependencies.backbone.marionette' });
|
|
@@ -4408,18 +4345,15 @@ function emberDetector(projectPath, packageJson) {
|
|
|
4408
4345
|
let confidence = 0;
|
|
4409
4346
|
let version;
|
|
4410
4347
|
const deps = collectAllDependencies(pkg);
|
|
4411
|
-
// Ember source package
|
|
4412
4348
|
if (deps['ember-source']) {
|
|
4413
4349
|
confidence += 70;
|
|
4414
4350
|
version = parseVersionString(deps['ember-source']);
|
|
4415
4351
|
sources.push({ type: 'package.json', field: 'dependencies.ember-source' });
|
|
4416
4352
|
}
|
|
4417
|
-
// Ember CLI
|
|
4418
4353
|
if (deps['ember-cli']) {
|
|
4419
4354
|
confidence += 20;
|
|
4420
4355
|
sources.push({ type: 'package.json', field: 'devDependencies.ember-cli' });
|
|
4421
4356
|
}
|
|
4422
|
-
// Ember Data
|
|
4423
4357
|
if (deps['ember-data']) {
|
|
4424
4358
|
confidence += 10;
|
|
4425
4359
|
sources.push({ type: 'package.json', field: 'dependencies.ember-data' });
|
|
@@ -4450,18 +4384,15 @@ function jqueryDetector(projectPath, packageJson) {
|
|
|
4450
4384
|
let confidence = 0;
|
|
4451
4385
|
let version;
|
|
4452
4386
|
const deps = collectAllDependencies(pkg);
|
|
4453
|
-
// jQuery package
|
|
4454
4387
|
if (deps['jquery']) {
|
|
4455
4388
|
confidence += 80;
|
|
4456
4389
|
version = parseVersionString(deps['jquery']);
|
|
4457
4390
|
sources.push({ type: 'package.json', field: 'dependencies.jquery' });
|
|
4458
4391
|
}
|
|
4459
|
-
// jQuery UI
|
|
4460
4392
|
if (deps['jquery-ui']) {
|
|
4461
4393
|
confidence += 10;
|
|
4462
4394
|
sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
|
|
4463
4395
|
}
|
|
4464
|
-
// jQuery plugins
|
|
4465
4396
|
if (deps['jquery-validation']) {
|
|
4466
4397
|
confidence += 5;
|
|
4467
4398
|
sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
|
|
@@ -4608,7 +4539,6 @@ function prettierDetector(projectPath, packageJson) {
|
|
|
4608
4539
|
confidence += 30;
|
|
4609
4540
|
sources.push({ type: 'package.json', field: 'prettier' });
|
|
4610
4541
|
}
|
|
4611
|
-
// .prettierignore file
|
|
4612
4542
|
if (exists(join$1(projectPath, '.prettierignore'))) {
|
|
4613
4543
|
confidence += 10;
|
|
4614
4544
|
sources.push({ type: 'config-file', path: '.prettierignore' });
|
|
@@ -4703,7 +4633,6 @@ function biomeDetector(projectPath, packageJson) {
|
|
|
4703
4633
|
let configPath;
|
|
4704
4634
|
let version;
|
|
4705
4635
|
const deps = collectAllDependencies(pkg);
|
|
4706
|
-
// @biomejs/biome package
|
|
4707
4636
|
if (deps['@biomejs/biome']) {
|
|
4708
4637
|
confidence += 70;
|
|
4709
4638
|
version = parseVersionString(deps['@biomejs/biome']);
|
|
@@ -4990,7 +4919,7 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
|
|
|
4990
4919
|
sources.push({ type: 'lockfile', path: 'package-lock.json' });
|
|
4991
4920
|
}
|
|
4992
4921
|
if (exists(join$1(workspacePath, 'yarn.lock'))) {
|
|
4993
|
-
return null;
|
|
4922
|
+
return null;
|
|
4994
4923
|
}
|
|
4995
4924
|
if (confidence === 0) {
|
|
4996
4925
|
return null;
|
|
@@ -5369,7 +5298,6 @@ function checkTsConfigStrict(projectPath) {
|
|
|
5369
5298
|
if (!content)
|
|
5370
5299
|
return undefined;
|
|
5371
5300
|
try {
|
|
5372
|
-
// Simple JSON parsing - doesn't handle comments but good enough for strict check
|
|
5373
5301
|
const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
|
|
5374
5302
|
const parsed = parse(cleanContent);
|
|
5375
5303
|
return parsed?.compilerOptions?.strict === true;
|
|
@@ -5392,19 +5320,16 @@ function typescriptDetector(projectPath, packageJson) {
|
|
|
5392
5320
|
let configPath;
|
|
5393
5321
|
let version;
|
|
5394
5322
|
const deps = collectAllDependencies(pkg);
|
|
5395
|
-
// TypeScript package
|
|
5396
5323
|
if (deps['typescript']) {
|
|
5397
5324
|
confidence += 50;
|
|
5398
5325
|
version = parseVersionString(deps['typescript']);
|
|
5399
5326
|
sources.push({ type: 'package.json', field: 'dependencies.typescript' });
|
|
5400
5327
|
}
|
|
5401
|
-
// tsconfig.json
|
|
5402
5328
|
if (exists(join$1(projectPath, 'tsconfig.json'))) {
|
|
5403
5329
|
confidence += 40;
|
|
5404
5330
|
configPath = 'tsconfig.json';
|
|
5405
5331
|
sources.push({ type: 'config-file', path: 'tsconfig.json' });
|
|
5406
5332
|
}
|
|
5407
|
-
// tsconfig.*.json variants
|
|
5408
5333
|
const tsconfigVariants = ['tsconfig.build.json', 'tsconfig.lib.json', 'tsconfig.spec.json', 'tsconfig.app.json'];
|
|
5409
5334
|
for (const variant of tsconfigVariants) {
|
|
5410
5335
|
if (exists(join$1(projectPath, variant))) {
|
|
@@ -5413,7 +5338,6 @@ function typescriptDetector(projectPath, packageJson) {
|
|
|
5413
5338
|
break;
|
|
5414
5339
|
}
|
|
5415
5340
|
}
|
|
5416
|
-
// @types packages
|
|
5417
5341
|
const typePackages = keys(deps).filter((d) => d.startsWith('@types/'));
|
|
5418
5342
|
if (typePackages.length > 0) {
|
|
5419
5343
|
confidence += 10;
|
|
@@ -5447,24 +5371,20 @@ function flowDetector(projectPath, packageJson) {
|
|
|
5447
5371
|
let configPath;
|
|
5448
5372
|
let version;
|
|
5449
5373
|
const deps = collectAllDependencies(pkg);
|
|
5450
|
-
// flow-bin package
|
|
5451
5374
|
if (deps['flow-bin']) {
|
|
5452
5375
|
confidence += 60;
|
|
5453
5376
|
version = parseVersionString(deps['flow-bin']);
|
|
5454
5377
|
sources.push({ type: 'package.json', field: 'dependencies.flow-bin' });
|
|
5455
5378
|
}
|
|
5456
|
-
// .flowconfig
|
|
5457
5379
|
if (exists(join$1(projectPath, '.flowconfig'))) {
|
|
5458
5380
|
confidence += 40;
|
|
5459
5381
|
configPath = '.flowconfig';
|
|
5460
5382
|
sources.push({ type: 'config-file', path: '.flowconfig' });
|
|
5461
5383
|
}
|
|
5462
|
-
// flow-typed directory
|
|
5463
5384
|
if (exists(join$1(projectPath, 'flow-typed'))) {
|
|
5464
5385
|
confidence += 10;
|
|
5465
5386
|
sources.push({ type: 'directory', path: 'flow-typed/' });
|
|
5466
5387
|
}
|
|
5467
|
-
// @babel/preset-flow
|
|
5468
5388
|
if (deps['@babel/preset-flow']) {
|
|
5469
5389
|
confidence += 10;
|
|
5470
5390
|
sources.push({ type: 'package.json', field: 'dependencies.@babel/preset-flow' });
|
|
@@ -5488,7 +5408,6 @@ function flowDetector(projectPath, packageJson) {
|
|
|
5488
5408
|
* @returns `true` if the content contains JSDoc type annotations.
|
|
5489
5409
|
*/
|
|
5490
5410
|
function hasJsDocTypes(content) {
|
|
5491
|
-
// Check for JSDoc type annotations
|
|
5492
5411
|
return (content.includes('@type {') ||
|
|
5493
5412
|
content.includes('@param {') ||
|
|
5494
5413
|
content.includes('@returns {') ||
|
|
@@ -5507,14 +5426,11 @@ function jsdocDetector(projectPath, packageJson) {
|
|
|
5507
5426
|
const sources = [];
|
|
5508
5427
|
let confidence = 0;
|
|
5509
5428
|
const deps = collectAllDependencies(pkg);
|
|
5510
|
-
// jsdoc package
|
|
5511
5429
|
if (deps['jsdoc']) {
|
|
5512
5430
|
confidence += 30;
|
|
5513
5431
|
sources.push({ type: 'package.json', field: 'dependencies.jsdoc' });
|
|
5514
5432
|
}
|
|
5515
|
-
// typescript with checkJs (JSDoc type checking)
|
|
5516
5433
|
if (deps['typescript']) {
|
|
5517
|
-
// Check if checkJs is enabled in tsconfig
|
|
5518
5434
|
const tsconfigPath = join$1(projectPath, 'tsconfig.json');
|
|
5519
5435
|
const content = readFileIfExists(tsconfigPath);
|
|
5520
5436
|
if (content) {
|
|
@@ -5531,12 +5447,10 @@ function jsdocDetector(projectPath, packageJson) {
|
|
|
5531
5447
|
}
|
|
5532
5448
|
}
|
|
5533
5449
|
}
|
|
5534
|
-
// Check for jsconfig.json (VS Code JS type checking)
|
|
5535
5450
|
if (exists(join$1(projectPath, 'jsconfig.json'))) {
|
|
5536
5451
|
confidence += 40;
|
|
5537
5452
|
sources.push({ type: 'config-file', path: 'jsconfig.json' });
|
|
5538
5453
|
}
|
|
5539
|
-
// Sample check for JSDoc annotations in source files
|
|
5540
5454
|
const srcDir = join$1(projectPath, 'src');
|
|
5541
5455
|
if (exists(srcDir)) {
|
|
5542
5456
|
try {
|
|
@@ -5618,8 +5532,6 @@ const allDetectors = {
|
|
|
5618
5532
|
function isDetectAllOptions(value) {
|
|
5619
5533
|
if (typeof value !== 'object' || value === null)
|
|
5620
5534
|
return false;
|
|
5621
|
-
// DetectAllOptions has skipCache or packageJson fields specifically
|
|
5622
|
-
// PackageJson never has skipCache field
|
|
5623
5535
|
return 'skipCache' in value || 'packageJson' in value;
|
|
5624
5536
|
}
|
|
5625
5537
|
/**
|
|
@@ -5651,9 +5563,7 @@ function isDetectAllOptions(value) {
|
|
|
5651
5563
|
* ```
|
|
5652
5564
|
*/
|
|
5653
5565
|
function detectAll(projectPath, packageJsonOrOptions) {
|
|
5654
|
-
// Handle backward-compatible arguments
|
|
5655
5566
|
const options = isDetectAllOptions(packageJsonOrOptions) ? packageJsonOrOptions : { packageJson: packageJsonOrOptions };
|
|
5656
|
-
// Check cache first (unless skipCache is true)
|
|
5657
5567
|
if (!options.skipCache) {
|
|
5658
5568
|
const cached = detectAllCache.get(projectPath);
|
|
5659
5569
|
if (cached) {
|
|
@@ -5704,7 +5614,6 @@ function detectAll(projectPath, packageJsonOrOptions) {
|
|
|
5704
5614
|
legacyFrameworks: result.legacyFrameworks.map((f) => f.id),
|
|
5705
5615
|
testingFrameworks: result.testingFrameworks.map((f) => f.id),
|
|
5706
5616
|
});
|
|
5707
|
-
// Cache the result
|
|
5708
5617
|
detectAllCache.set(projectPath, result);
|
|
5709
5618
|
return result;
|
|
5710
5619
|
}
|
|
@@ -6121,7 +6030,6 @@ function detectNxVersion(workspacePath) {
|
|
|
6121
6030
|
if (packageJson) {
|
|
6122
6031
|
const nxVersion = packageJson.devDependencies?.['nx'] ?? packageJson.dependencies?.['nx'];
|
|
6123
6032
|
if (nxVersion) {
|
|
6124
|
-
// Strip semver range characters (^, ~, >=, etc.)
|
|
6125
6033
|
return nxVersion.replace(/^[\^~>=<]+/, '');
|
|
6126
6034
|
}
|
|
6127
6035
|
}
|
|
@@ -6150,14 +6058,12 @@ function getNxWorkspaceInfo(workspacePath) {
|
|
|
6150
6058
|
}
|
|
6151
6059
|
const nxJson = readJsonFileIfExists(join$1(workspacePath, 'nx.json'));
|
|
6152
6060
|
if (!nxJson) {
|
|
6153
|
-
// Check for workspace.json as fallback (older NX)
|
|
6154
6061
|
const workspaceJson = readJsonFileIfExists(join$1(workspacePath, 'workspace.json'));
|
|
6155
6062
|
if (!workspaceJson) {
|
|
6156
6063
|
nxLogger.debug('No nx.json or workspace.json found', { workspacePath });
|
|
6157
6064
|
return null;
|
|
6158
6065
|
}
|
|
6159
6066
|
nxLogger.debug('Using legacy workspace.json', { workspacePath });
|
|
6160
|
-
// Create minimal nx.json from workspace.json
|
|
6161
6067
|
return {
|
|
6162
6068
|
root: workspacePath,
|
|
6163
6069
|
version: detectNxVersion(workspacePath),
|
|
@@ -6206,7 +6112,6 @@ function tryLoadDevkit() {
|
|
|
6206
6112
|
}
|
|
6207
6113
|
devkitLogger.debug('Attempting to load @nx/devkit');
|
|
6208
6114
|
try {
|
|
6209
|
-
// Dynamic require to avoid bundling
|
|
6210
6115
|
const devkit = require('@nx/devkit');
|
|
6211
6116
|
devkitLogger.debug('@nx/devkit loaded successfully');
|
|
6212
6117
|
cachedResult = { available: true, devkit };
|
|
@@ -6303,7 +6208,6 @@ function readProjectJson(projectPath) {
|
|
|
6303
6208
|
*/
|
|
6304
6209
|
function getProjectConfig(projectPath, workspacePath) {
|
|
6305
6210
|
nxConfigLogger.debug('Getting project config', { projectPath, workspacePath });
|
|
6306
|
-
// Try project.json first
|
|
6307
6211
|
const projectJson = readProjectJson(projectPath);
|
|
6308
6212
|
if (projectJson) {
|
|
6309
6213
|
nxConfigLogger.debug('Using project.json config', { projectPath, name: projectJson.name });
|
|
@@ -6312,7 +6216,6 @@ function getProjectConfig(projectPath, workspacePath) {
|
|
|
6312
6216
|
root: projectJson.root ?? relative(workspacePath, projectPath),
|
|
6313
6217
|
};
|
|
6314
6218
|
}
|
|
6315
|
-
// Try to infer from package.json nx field
|
|
6316
6219
|
const packageJson = readPackageJsonIfExists(projectPath);
|
|
6317
6220
|
if (packageJson && typeof packageJson['nx'] === 'object') {
|
|
6318
6221
|
nxConfigLogger.debug('Using package.json nx field', { projectPath, name: packageJson.name });
|
|
@@ -6341,13 +6244,11 @@ function scanForProjects(dirPath, workspacePath, projects, maxDepth, currentDept
|
|
|
6341
6244
|
try {
|
|
6342
6245
|
const entries = readDirectory(dirPath);
|
|
6343
6246
|
for (const entry of entries) {
|
|
6344
|
-
// Skip node_modules and hidden directories
|
|
6345
6247
|
if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist') {
|
|
6346
6248
|
continue;
|
|
6347
6249
|
}
|
|
6348
6250
|
const fullPath = join$1(dirPath, entry.name);
|
|
6349
6251
|
if (entry.isDirectory) {
|
|
6350
|
-
// Check if this directory is an NX project
|
|
6351
6252
|
if (isNxProject(fullPath)) {
|
|
6352
6253
|
const config = getProjectConfig(fullPath, workspacePath);
|
|
6353
6254
|
if (config) {
|
|
@@ -6359,7 +6260,6 @@ function scanForProjects(dirPath, workspacePath, projects, maxDepth, currentDept
|
|
|
6359
6260
|
});
|
|
6360
6261
|
}
|
|
6361
6262
|
}
|
|
6362
|
-
// Recursively scan subdirectories
|
|
6363
6263
|
scanForProjects(fullPath, workspacePath, projects, maxDepth, currentDepth + 1);
|
|
6364
6264
|
}
|
|
6365
6265
|
}
|
|
@@ -6377,12 +6277,10 @@ function scanForProjects(dirPath, workspacePath, projects, maxDepth, currentDept
|
|
|
6377
6277
|
*/
|
|
6378
6278
|
function discoverNxProjects(workspacePath) {
|
|
6379
6279
|
const projects = createMap();
|
|
6380
|
-
// Check for workspace.json (older NX format)
|
|
6381
6280
|
const workspaceJson = readJsonFileIfExists(join$1(workspacePath, 'workspace.json'));
|
|
6382
6281
|
if (workspaceJson?.projects) {
|
|
6383
6282
|
for (const [name, config] of entries(workspaceJson.projects)) {
|
|
6384
6283
|
if (typeof config === 'string') {
|
|
6385
|
-
// Path reference to project directory
|
|
6386
6284
|
const projectPath = join$1(workspacePath, config);
|
|
6387
6285
|
const projectConfig = getProjectConfig(projectPath, workspacePath);
|
|
6388
6286
|
if (projectConfig) {
|
|
@@ -6390,18 +6288,15 @@ function discoverNxProjects(workspacePath) {
|
|
|
6390
6288
|
}
|
|
6391
6289
|
}
|
|
6392
6290
|
else if (typeof config === 'object' && config !== null) {
|
|
6393
|
-
// Inline config
|
|
6394
6291
|
projects.set(name, { name, ...config });
|
|
6395
6292
|
}
|
|
6396
6293
|
}
|
|
6397
6294
|
return projects;
|
|
6398
6295
|
}
|
|
6399
|
-
// Scan for project.json files (newer NX format)
|
|
6400
6296
|
const workspaceInfo = getNxWorkspaceInfo(workspacePath);
|
|
6401
6297
|
const appsDir = workspaceInfo?.workspaceLayout.appsDir ?? 'apps';
|
|
6402
6298
|
const libsDir = workspaceInfo?.workspaceLayout.libsDir ?? 'libs';
|
|
6403
6299
|
const searchDirs = [appsDir, libsDir];
|
|
6404
|
-
// Also check packages directory (common in some setups)
|
|
6405
6300
|
if (exists(join$1(workspacePath, 'packages'))) {
|
|
6406
6301
|
searchDirs.push('packages');
|
|
6407
6302
|
}
|
|
@@ -6416,7 +6311,6 @@ function discoverNxProjects(workspacePath) {
|
|
|
6416
6311
|
}
|
|
6417
6312
|
}
|
|
6418
6313
|
}
|
|
6419
|
-
// Also check root-level projects (standalone projects in monorepo root)
|
|
6420
6314
|
if (isNxProject(workspacePath)) {
|
|
6421
6315
|
const config = readProjectJson(workspacePath);
|
|
6422
6316
|
if (config) {
|
|
@@ -6449,10 +6343,8 @@ function buildSimpleProjectGraph(workspacePath, projects) {
|
|
|
6449
6343
|
data: config,
|
|
6450
6344
|
};
|
|
6451
6345
|
dependencies[name] = [];
|
|
6452
|
-
// Add implicit dependencies
|
|
6453
6346
|
if (config.implicitDependencies) {
|
|
6454
6347
|
for (const dep of config.implicitDependencies) {
|
|
6455
|
-
// Skip negative dependencies (those starting with !)
|
|
6456
6348
|
if (!dep.startsWith('!')) {
|
|
6457
6349
|
dependencies[name].push({
|
|
6458
6350
|
target: dep,
|
|
@@ -6469,7 +6361,6 @@ function buildSimpleProjectGraph(workspacePath, projects) {
|
|
|
6469
6361
|
* Known configuration file patterns organized by type.
|
|
6470
6362
|
*/
|
|
6471
6363
|
const CONFIG_PATTERNS = {
|
|
6472
|
-
// Package Management
|
|
6473
6364
|
'package.json': {
|
|
6474
6365
|
patterns: ['package.json'],
|
|
6475
6366
|
format: 'json',
|
|
@@ -6496,14 +6387,12 @@ const CONFIG_PATTERNS = {
|
|
|
6496
6387
|
description: 'NPM configuration',
|
|
6497
6388
|
sensitive: true,
|
|
6498
6389
|
},
|
|
6499
|
-
// TypeScript
|
|
6500
6390
|
tsconfig: {
|
|
6501
6391
|
patterns: ['tsconfig.json', 'tsconfig.*.json'],
|
|
6502
6392
|
format: 'jsonc',
|
|
6503
6393
|
description: 'TypeScript configuration',
|
|
6504
6394
|
canExtend: true,
|
|
6505
6395
|
},
|
|
6506
|
-
// Monorepo
|
|
6507
6396
|
nx: {
|
|
6508
6397
|
patterns: ['nx.json'],
|
|
6509
6398
|
format: 'json',
|
|
@@ -6529,7 +6418,6 @@ const CONFIG_PATTERNS = {
|
|
|
6529
6418
|
format: 'json',
|
|
6530
6419
|
description: 'Lerna configuration',
|
|
6531
6420
|
},
|
|
6532
|
-
// Build Tools
|
|
6533
6421
|
webpack: {
|
|
6534
6422
|
patterns: ['webpack.config.js', 'webpack.config.ts', 'webpack.config.cjs', 'webpack.config.mjs'],
|
|
6535
6423
|
format: 'js',
|
|
@@ -6560,7 +6448,6 @@ const CONFIG_PATTERNS = {
|
|
|
6560
6448
|
format: 'json',
|
|
6561
6449
|
description: 'SWC configuration',
|
|
6562
6450
|
},
|
|
6563
|
-
// Testing
|
|
6564
6451
|
jest: {
|
|
6565
6452
|
patterns: ['jest.config.js', 'jest.config.ts', 'jest.config.mjs'],
|
|
6566
6453
|
description: 'Jest configuration',
|
|
@@ -6577,7 +6464,6 @@ const CONFIG_PATTERNS = {
|
|
|
6577
6464
|
patterns: ['playwright.config.js', 'playwright.config.ts'],
|
|
6578
6465
|
description: 'Playwright configuration',
|
|
6579
6466
|
},
|
|
6580
|
-
// Framework configs
|
|
6581
6467
|
next: {
|
|
6582
6468
|
patterns: ['next.config.js', 'next.config.mjs', 'next.config.ts'],
|
|
6583
6469
|
format: 'js',
|
|
@@ -6603,7 +6489,6 @@ const CONFIG_PATTERNS = {
|
|
|
6603
6489
|
format: 'js',
|
|
6604
6490
|
description: 'Astro configuration',
|
|
6605
6491
|
},
|
|
6606
|
-
// Linting & Formatting
|
|
6607
6492
|
eslint: {
|
|
6608
6493
|
patterns: [
|
|
6609
6494
|
'eslint.config.js',
|
|
@@ -6622,14 +6507,12 @@ const CONFIG_PATTERNS = {
|
|
|
6622
6507
|
format: 'json',
|
|
6623
6508
|
description: 'Prettier configuration',
|
|
6624
6509
|
},
|
|
6625
|
-
// Environment (sensitive)
|
|
6626
6510
|
env: {
|
|
6627
6511
|
patterns: ['.env', '.env.*', '*.env'],
|
|
6628
6512
|
format: 'dotenv',
|
|
6629
6513
|
description: 'Environment variables',
|
|
6630
6514
|
sensitive: true,
|
|
6631
6515
|
},
|
|
6632
|
-
// Git
|
|
6633
6516
|
'.gitignore': {
|
|
6634
6517
|
patterns: ['.gitignore'],
|
|
6635
6518
|
format: 'text',
|
|
@@ -6800,12 +6683,8 @@ function getConfigPaths(type) {
|
|
|
6800
6683
|
*
|
|
6801
6684
|
* @module @hyperfrontend/immutable-api-utils/built-in-copy/number
|
|
6802
6685
|
*/
|
|
6803
|
-
// Capture references at module initialization time
|
|
6804
6686
|
const _parseInt = globalThis.parseInt;
|
|
6805
6687
|
const _parseFloat = globalThis.parseFloat;
|
|
6806
|
-
// ============================================================================
|
|
6807
|
-
// Parsing
|
|
6808
|
-
// ============================================================================
|
|
6809
6688
|
/**
|
|
6810
6689
|
* (Safe copy) Parses a string and returns an integer.
|
|
6811
6690
|
*/
|
|
@@ -7160,11 +7039,9 @@ const analyzeLogger = createScopedLogger('project-scope:analyze');
|
|
|
7160
7039
|
* @returns Detected workspace type
|
|
7161
7040
|
*/
|
|
7162
7041
|
function detectWorkspaceType(projectPath) {
|
|
7163
|
-
// Check for NX
|
|
7164
7042
|
if (isNxWorkspace(projectPath) || findNxWorkspaceRoot(projectPath) !== null) {
|
|
7165
7043
|
return 'nx';
|
|
7166
7044
|
}
|
|
7167
|
-
// Check for common monorepo markers
|
|
7168
7045
|
if (exists(resolve(projectPath, 'turbo.json'))) {
|
|
7169
7046
|
return 'turborepo';
|
|
7170
7047
|
}
|
|
@@ -7174,7 +7051,6 @@ function detectWorkspaceType(projectPath) {
|
|
|
7174
7051
|
if (exists(resolve(projectPath, 'pnpm-workspace.yaml'))) {
|
|
7175
7052
|
return 'pnpm';
|
|
7176
7053
|
}
|
|
7177
|
-
// Check package.json for workspaces
|
|
7178
7054
|
const pkg = readPackageJsonIfExists(projectPath);
|
|
7179
7055
|
if (pkg?.workspaces) {
|
|
7180
7056
|
if (exists(resolve(projectPath, 'yarn.lock'))) {
|
|
@@ -7183,7 +7059,7 @@ function detectWorkspaceType(projectPath) {
|
|
|
7183
7059
|
if (exists(resolve(projectPath, 'package-lock.json'))) {
|
|
7184
7060
|
return 'npm';
|
|
7185
7061
|
}
|
|
7186
|
-
return 'npm';
|
|
7062
|
+
return 'npm';
|
|
7187
7063
|
}
|
|
7188
7064
|
return 'standalone';
|
|
7189
7065
|
}
|
|
@@ -7195,15 +7071,12 @@ function detectWorkspaceType(projectPath) {
|
|
|
7195
7071
|
* @returns True if the analysis should be performed
|
|
7196
7072
|
*/
|
|
7197
7073
|
function shouldInclude(type, options) {
|
|
7198
|
-
// If include list is specified, item must be in it
|
|
7199
7074
|
if (options?.include && options.include.length > 0) {
|
|
7200
7075
|
return options.include.includes(type);
|
|
7201
7076
|
}
|
|
7202
|
-
// If exclude list is specified, item must not be in it
|
|
7203
7077
|
if (options?.exclude && options.exclude.length > 0) {
|
|
7204
7078
|
return !options.exclude.includes(type);
|
|
7205
7079
|
}
|
|
7206
|
-
// Default: include everything
|
|
7207
7080
|
return true;
|
|
7208
7081
|
}
|
|
7209
7082
|
/**
|
|
@@ -7252,28 +7125,22 @@ function normalizeConfigFormat(format) {
|
|
|
7252
7125
|
function analyzeProject(projectPath, options) {
|
|
7253
7126
|
const startTime = dateNow();
|
|
7254
7127
|
const resolvedPath = resolve(projectPath);
|
|
7255
|
-
// Set log level based on verbose option
|
|
7256
7128
|
if (options?.verbose) {
|
|
7257
7129
|
analyzeLogger.setLogLevel('debug');
|
|
7258
7130
|
}
|
|
7259
7131
|
analyzeLogger.debug('Starting project analysis', { path: resolvedPath, options });
|
|
7260
|
-
// Read package.json once for reuse
|
|
7261
7132
|
const packageJson = readPackageJsonIfExists(resolvedPath);
|
|
7262
7133
|
analyzeLogger.debug('Package.json loaded', { found: !!packageJson, name: packageJson?.name });
|
|
7263
|
-
// Detect project and workspace types
|
|
7264
7134
|
const projectTypeDetection = detectProjectType(resolvedPath, {
|
|
7265
7135
|
skipTechDetection: options?.depth === 'basic',
|
|
7266
7136
|
});
|
|
7267
7137
|
const projectType = projectTypeDetection.type;
|
|
7268
7138
|
const workspaceType = detectWorkspaceType(resolvedPath);
|
|
7269
7139
|
analyzeLogger.debug('Project type detected', { projectType, workspaceType });
|
|
7270
|
-
// Get project name from package.json or directory name
|
|
7271
7140
|
const projectName = packageJson?.name ?? basename(resolvedPath);
|
|
7272
|
-
// Run all technology detectors
|
|
7273
7141
|
const detections = shouldInclude('frameworks', options) || shouldInclude('buildTools', options) || shouldInclude('testing', options)
|
|
7274
7142
|
? detectAll(resolvedPath, packageJson ?? undefined)
|
|
7275
7143
|
: null;
|
|
7276
|
-
// Convert framework detections to FrameworkInfo
|
|
7277
7144
|
const frameworks = shouldInclude('frameworks', options) && detections
|
|
7278
7145
|
? [
|
|
7279
7146
|
...detections.frontendFrameworks.map((d) => ({
|
|
@@ -7293,7 +7160,6 @@ function analyzeProject(projectPath, options) {
|
|
|
7293
7160
|
})),
|
|
7294
7161
|
]
|
|
7295
7162
|
: [];
|
|
7296
|
-
// Convert build tool detections
|
|
7297
7163
|
const buildTools = shouldInclude('buildTools', options) && detections
|
|
7298
7164
|
? detections.buildTools.map((d) => ({
|
|
7299
7165
|
id: d.id,
|
|
@@ -7303,7 +7169,6 @@ function analyzeProject(projectPath, options) {
|
|
|
7303
7169
|
confidence: d.confidence,
|
|
7304
7170
|
}))
|
|
7305
7171
|
: [];
|
|
7306
|
-
// Convert testing framework detections
|
|
7307
7172
|
const testingFrameworks = shouldInclude('testing', options) && detections
|
|
7308
7173
|
? detections.testingFrameworks.map((d) => ({
|
|
7309
7174
|
id: d.id,
|
|
@@ -7314,7 +7179,6 @@ function analyzeProject(projectPath, options) {
|
|
|
7314
7179
|
confidence: d.confidence,
|
|
7315
7180
|
}))
|
|
7316
7181
|
: [];
|
|
7317
|
-
// Discover entry points
|
|
7318
7182
|
const entryPoints = shouldInclude('entryPoints', options)
|
|
7319
7183
|
? discoverEntryPoints(resolvedPath).map((e) => ({
|
|
7320
7184
|
path: e.path,
|
|
@@ -7322,7 +7186,6 @@ function analyzeProject(projectPath, options) {
|
|
|
7322
7186
|
confidence: e.confidence,
|
|
7323
7187
|
}))
|
|
7324
7188
|
: [];
|
|
7325
|
-
// Detect configuration files
|
|
7326
7189
|
const configFiles = shouldInclude('configs', options)
|
|
7327
7190
|
? detectConfigs(resolvedPath).map((c) => ({
|
|
7328
7191
|
path: c.path,
|
|
@@ -7331,7 +7194,6 @@ function analyzeProject(projectPath, options) {
|
|
|
7331
7194
|
tool: c.type,
|
|
7332
7195
|
}))
|
|
7333
7196
|
: [];
|
|
7334
|
-
// Get dependency summary
|
|
7335
7197
|
let dependencies;
|
|
7336
7198
|
if (shouldInclude('dependencies', options)) {
|
|
7337
7199
|
const deps = getProjectDependencies(resolvedPath);
|
|
@@ -7352,7 +7214,6 @@ function analyzeProject(projectPath, options) {
|
|
|
7352
7214
|
total: 0,
|
|
7353
7215
|
};
|
|
7354
7216
|
}
|
|
7355
|
-
// Build metadata
|
|
7356
7217
|
const metadata = {
|
|
7357
7218
|
timestamp: createDate(),
|
|
7358
7219
|
durationMs: dateNow() - startTime,
|
|
@@ -7427,15 +7288,12 @@ function formatWorkspaceType(type) {
|
|
|
7427
7288
|
*/
|
|
7428
7289
|
function formatAnalysisText(result) {
|
|
7429
7290
|
const lines = [];
|
|
7430
|
-
// Header
|
|
7431
7291
|
lines.push(`Project Analysis: ${result.name}`);
|
|
7432
7292
|
lines.push('='.repeat(30));
|
|
7433
7293
|
lines.push('');
|
|
7434
|
-
// Basic info
|
|
7435
7294
|
lines.push(`Type: ${formatProjectType(result.projectType)}`);
|
|
7436
7295
|
lines.push(`Workspace: ${formatWorkspaceType(result.workspaceType)}`);
|
|
7437
7296
|
lines.push('');
|
|
7438
|
-
// Frameworks
|
|
7439
7297
|
if (result.frameworks.length > 0) {
|
|
7440
7298
|
lines.push('Frameworks:');
|
|
7441
7299
|
for (const framework of result.frameworks) {
|
|
@@ -7449,7 +7307,6 @@ function formatAnalysisText(result) {
|
|
|
7449
7307
|
}
|
|
7450
7308
|
lines.push('');
|
|
7451
7309
|
}
|
|
7452
|
-
// Build tools
|
|
7453
7310
|
if (result.buildTools.length > 0) {
|
|
7454
7311
|
lines.push('Build Tools:');
|
|
7455
7312
|
for (const tool of result.buildTools) {
|
|
@@ -7458,7 +7315,6 @@ function formatAnalysisText(result) {
|
|
|
7458
7315
|
}
|
|
7459
7316
|
lines.push('');
|
|
7460
7317
|
}
|
|
7461
|
-
// Testing
|
|
7462
7318
|
if (result.testingFrameworks.length > 0) {
|
|
7463
7319
|
lines.push('Testing:');
|
|
7464
7320
|
for (const framework of result.testingFrameworks) {
|
|
@@ -7467,7 +7323,6 @@ function formatAnalysisText(result) {
|
|
|
7467
7323
|
}
|
|
7468
7324
|
lines.push('');
|
|
7469
7325
|
}
|
|
7470
|
-
// Entry points
|
|
7471
7326
|
if (result.entryPoints.length > 0) {
|
|
7472
7327
|
lines.push('Entry Points:');
|
|
7473
7328
|
for (const entry of result.entryPoints.slice(0, 5)) {
|
|
@@ -7478,7 +7333,6 @@ function formatAnalysisText(result) {
|
|
|
7478
7333
|
}
|
|
7479
7334
|
lines.push('');
|
|
7480
7335
|
}
|
|
7481
|
-
// Configurations
|
|
7482
7336
|
if (result.configFiles.length > 0) {
|
|
7483
7337
|
lines.push('Configurations:');
|
|
7484
7338
|
for (const config of result.configFiles.slice(0, 8)) {
|
|
@@ -7489,7 +7343,6 @@ function formatAnalysisText(result) {
|
|
|
7489
7343
|
}
|
|
7490
7344
|
lines.push('');
|
|
7491
7345
|
}
|
|
7492
|
-
// Dependencies summary
|
|
7493
7346
|
lines.push('Dependencies:');
|
|
7494
7347
|
lines.push(` Production: ${result.dependencies.production}`);
|
|
7495
7348
|
lines.push(` Development: ${result.dependencies.development}`);
|
|
@@ -7576,7 +7429,7 @@ function parseAnalyzeArgs(args) {
|
|
|
7576
7429
|
exclude: { type: 'string', short: 'e' },
|
|
7577
7430
|
},
|
|
7578
7431
|
allowPositionals: true,
|
|
7579
|
-
strict: false,
|
|
7432
|
+
strict: false,
|
|
7580
7433
|
});
|
|
7581
7434
|
const format = values.format;
|
|
7582
7435
|
const depth = values.depth;
|
|
@@ -7635,7 +7488,6 @@ const analyzeCommandDef = {
|
|
|
7635
7488
|
description: 'Analyze project structure and tech stack',
|
|
7636
7489
|
execute(args, globalOptions) {
|
|
7637
7490
|
const options = parseAnalyzeArgs(args);
|
|
7638
|
-
// Global --json flag overrides format
|
|
7639
7491
|
if (globalOptions.json) {
|
|
7640
7492
|
options.format = 'json';
|
|
7641
7493
|
}
|
|
@@ -7942,12 +7794,10 @@ Examples:
|
|
|
7942
7794
|
function formatDependencyList(deps, maxItems = 20) {
|
|
7943
7795
|
const lines = [];
|
|
7944
7796
|
const depEntries = entries(deps);
|
|
7945
|
-
// Sort alphabetically
|
|
7946
7797
|
depEntries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
7947
7798
|
const displayCount = min(depEntries.length, maxItems);
|
|
7948
7799
|
for (let i = 0; i < displayCount; i++) {
|
|
7949
7800
|
const [name, version] = depEntries[i];
|
|
7950
|
-
// Pad name to align versions
|
|
7951
7801
|
const paddedName = name.padEnd(30);
|
|
7952
7802
|
lines.push(` ${paddedName} ${version}`);
|
|
7953
7803
|
}
|
|
@@ -8190,13 +8040,10 @@ function buildTree(rootPath, walkEntries, options) {
|
|
|
8190
8040
|
isDirectory: true,
|
|
8191
8041
|
children: [],
|
|
8192
8042
|
};
|
|
8193
|
-
// Create a map for quick lookup
|
|
8194
8043
|
const nodeMap = createMap();
|
|
8195
8044
|
nodeMap.set('.', root);
|
|
8196
|
-
// Sort entries by path for proper parent-child relationships
|
|
8197
8045
|
const sortedEntries = [...walkEntries].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
8198
8046
|
for (const entry of sortedEntries) {
|
|
8199
|
-
// Skip based on filters
|
|
8200
8047
|
if (options.dirsOnly && !entry.isDirectory)
|
|
8201
8048
|
continue;
|
|
8202
8049
|
if (options.filesOnly && entry.isDirectory)
|
|
@@ -8207,7 +8054,6 @@ function buildTree(rootPath, walkEntries, options) {
|
|
|
8207
8054
|
isDirectory: entry.isDirectory,
|
|
8208
8055
|
children: [],
|
|
8209
8056
|
};
|
|
8210
|
-
// Add size/modified if requested
|
|
8211
8057
|
if ((options.showSize || options.showModified) && entry.isFile) {
|
|
8212
8058
|
const stats = getFileStat(entry.path);
|
|
8213
8059
|
if (stats) {
|
|
@@ -8217,9 +8063,8 @@ function buildTree(rootPath, walkEntries, options) {
|
|
|
8217
8063
|
node.modified = stats.modified;
|
|
8218
8064
|
}
|
|
8219
8065
|
}
|
|
8220
|
-
// Find parent
|
|
8221
8066
|
const parts = entry.relativePath.split('/');
|
|
8222
|
-
parts.pop();
|
|
8067
|
+
parts.pop();
|
|
8223
8068
|
const parentPath = parts.join('/') || '.';
|
|
8224
8069
|
const parent = nodeMap.get(parentPath);
|
|
8225
8070
|
if (parent) {
|
|
@@ -8240,11 +8085,9 @@ function buildTree(rootPath, walkEntries, options) {
|
|
|
8240
8085
|
*/
|
|
8241
8086
|
function renderTreeText(node, options, prefix = '', isLast = true) {
|
|
8242
8087
|
const lines = [];
|
|
8243
|
-
// Current line
|
|
8244
8088
|
const connector = isLast ? '└── ' : '├── ';
|
|
8245
8089
|
const dirMark = node.isDirectory ? '/' : '';
|
|
8246
8090
|
let line = `${prefix}${connector}${node.name}${dirMark}`;
|
|
8247
|
-
// Add size/modified
|
|
8248
8091
|
const meta = [];
|
|
8249
8092
|
if (options.showSize && node.size !== undefined) {
|
|
8250
8093
|
meta.push(formatSize(node.size));
|
|
@@ -8256,10 +8099,8 @@ function renderTreeText(node, options, prefix = '', isLast = true) {
|
|
|
8256
8099
|
line += ` [${meta.join(' ')}]`;
|
|
8257
8100
|
}
|
|
8258
8101
|
lines.push(line);
|
|
8259
|
-
// Process children
|
|
8260
8102
|
const childPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
8261
8103
|
const sortedChildren = [...node.children].sort((a, b) => {
|
|
8262
|
-
// Directories first, then alphabetically
|
|
8263
8104
|
if (a.isDirectory && !b.isDirectory)
|
|
8264
8105
|
return -1;
|
|
8265
8106
|
if (!a.isDirectory && b.isDirectory)
|
|
@@ -8283,9 +8124,7 @@ function renderTreeText(node, options, prefix = '', isLast = true) {
|
|
|
8283
8124
|
*/
|
|
8284
8125
|
function formatTreeText(rootPath, tree, options) {
|
|
8285
8126
|
const lines = [];
|
|
8286
|
-
// Root line
|
|
8287
8127
|
lines.push(basename(rootPath));
|
|
8288
|
-
// Count stats
|
|
8289
8128
|
let dirCount = 0;
|
|
8290
8129
|
let fileCount = 0;
|
|
8291
8130
|
/**
|
|
@@ -8304,7 +8143,6 @@ function formatTreeText(rootPath, tree, options) {
|
|
|
8304
8143
|
countNodes(child);
|
|
8305
8144
|
}
|
|
8306
8145
|
}
|
|
8307
|
-
// Render children of root
|
|
8308
8146
|
const sortedChildren = [...tree.children].sort((a, b) => {
|
|
8309
8147
|
if (a.isDirectory && !b.isDirectory)
|
|
8310
8148
|
return -1;
|
|
@@ -8318,7 +8156,6 @@ function formatTreeText(rootPath, tree, options) {
|
|
|
8318
8156
|
lines.push(...renderTreeText(child, options, '', isLast));
|
|
8319
8157
|
countNodes(child);
|
|
8320
8158
|
}
|
|
8321
|
-
// Summary
|
|
8322
8159
|
lines.push('');
|
|
8323
8160
|
const dirText = dirCount === 1 ? '1 directory' : `${dirCount} directories`;
|
|
8324
8161
|
const fileText = fileCount === 1 ? '1 file' : `${fileCount} files`;
|
|
@@ -8379,7 +8216,6 @@ function parseTreeArgs(args) {
|
|
|
8379
8216
|
function treeCommand(options) {
|
|
8380
8217
|
const rootPath = options.path ? resolve(options.path) : process.cwd();
|
|
8381
8218
|
try {
|
|
8382
|
-
// Collect entries via walk
|
|
8383
8219
|
const walkEntries = [];
|
|
8384
8220
|
walkDirectory(rootPath, (entry) => {
|
|
8385
8221
|
walkEntries.push(entry);
|
|
@@ -8389,9 +8225,7 @@ function treeCommand(options) {
|
|
|
8389
8225
|
ignorePatterns: options.ignore,
|
|
8390
8226
|
includeHidden: false,
|
|
8391
8227
|
});
|
|
8392
|
-
// Build tree structure
|
|
8393
8228
|
const tree = buildTree(rootPath, walkEntries, options);
|
|
8394
|
-
// Format output
|
|
8395
8229
|
let output;
|
|
8396
8230
|
if (options.format === 'json') {
|
|
8397
8231
|
output = formatTreeJson(tree);
|
|
@@ -8450,6 +8284,9 @@ Examples:
|
|
|
8450
8284
|
|
|
8451
8285
|
/** Logger for CLI operations */
|
|
8452
8286
|
const cliLogger = createScopedLogger('project-scope:cli');
|
|
8287
|
+
/** Output printer for user-facing CLI output (help, version, command results). */
|
|
8288
|
+
const output = createLogger(error, undefined, log);
|
|
8289
|
+
output.setLogLevel('log');
|
|
8453
8290
|
/** Library version */
|
|
8454
8291
|
const VERSION = '0.1.0';
|
|
8455
8292
|
/**
|
|
@@ -8465,7 +8302,7 @@ const commands = {
|
|
|
8465
8302
|
* Print general help information.
|
|
8466
8303
|
*/
|
|
8467
8304
|
function printHelp() {
|
|
8468
|
-
log(`
|
|
8305
|
+
output.log(`
|
|
8469
8306
|
project-scope <command> [options]
|
|
8470
8307
|
|
|
8471
8308
|
A tool for analyzing JavaScript/TypeScript project structure and tech stack.
|
|
@@ -8497,7 +8334,7 @@ Examples:
|
|
|
8497
8334
|
* Print CLI version.
|
|
8498
8335
|
*/
|
|
8499
8336
|
function printVersion() {
|
|
8500
|
-
log(`project-scope v${VERSION}`);
|
|
8337
|
+
output.log(`project-scope v${VERSION}`);
|
|
8501
8338
|
}
|
|
8502
8339
|
/**
|
|
8503
8340
|
* Parse global options from command line arguments.
|
|
@@ -8558,24 +8395,24 @@ function run(args) {
|
|
|
8558
8395
|
setGlobalLogLevel('debug');
|
|
8559
8396
|
}
|
|
8560
8397
|
cliLogger.debug('CLI invoked', { args, globalOptions });
|
|
8398
|
+
const commandName = args[0];
|
|
8561
8399
|
if (globalOptions.version) {
|
|
8562
8400
|
printVersion();
|
|
8563
8401
|
return { exitCode: 0 };
|
|
8564
8402
|
}
|
|
8565
|
-
if (globalOptions.help && (args.length === 1 || !commands[
|
|
8403
|
+
if (globalOptions.help && (args.length === 1 || !commands[commandName])) {
|
|
8566
8404
|
printHelp();
|
|
8567
8405
|
return { exitCode: 0 };
|
|
8568
8406
|
}
|
|
8569
|
-
const commandName = args[0];
|
|
8570
8407
|
const command = commands[commandName];
|
|
8571
8408
|
if (!command) {
|
|
8572
8409
|
cliLogger.warn('Unknown command requested', { commandName });
|
|
8573
|
-
error(`Unknown command: ${commandName}`);
|
|
8574
|
-
error('Run "project-scope --help" for usage information.');
|
|
8410
|
+
output.error(`Unknown command: ${commandName}`);
|
|
8411
|
+
output.error('Run "project-scope --help" for usage information.');
|
|
8575
8412
|
return { exitCode: 1, error: `Unknown command: ${commandName}` };
|
|
8576
8413
|
}
|
|
8577
8414
|
if (globalOptions.help) {
|
|
8578
|
-
log(command.getHelp());
|
|
8415
|
+
output.log(command.getHelp());
|
|
8579
8416
|
return { exitCode: 0 };
|
|
8580
8417
|
}
|
|
8581
8418
|
const commandArgs = args.slice(1);
|
|
@@ -8583,11 +8420,11 @@ function run(args) {
|
|
|
8583
8420
|
const result = command.execute(commandArgs, globalOptions);
|
|
8584
8421
|
cliLogger.debug('Command completed', { commandName, exitCode: result.exitCode });
|
|
8585
8422
|
if (result.output) {
|
|
8586
|
-
log(result.output);
|
|
8423
|
+
output.log(result.output);
|
|
8587
8424
|
}
|
|
8588
8425
|
if (result.error) {
|
|
8589
8426
|
cliLogger.error('Command error', { commandName, error: result.error });
|
|
8590
|
-
error(result.error);
|
|
8427
|
+
output.error(result.error);
|
|
8591
8428
|
}
|
|
8592
8429
|
return result;
|
|
8593
8430
|
}
|
|
@@ -8623,25 +8460,22 @@ const BINARY_SIGNATURES = [
|
|
|
8623
8460
|
*/
|
|
8624
8461
|
function detectEncodingInfo(buffer) {
|
|
8625
8462
|
encodingLogger.debug('Detecting encoding info', { bufferSize: buffer.length });
|
|
8626
|
-
// Check for UTF-8 BOM
|
|
8627
8463
|
if (buffer.length >= 3) {
|
|
8628
8464
|
if (buffer[0] === UTF8_BOM_BYTES[0] && buffer[1] === UTF8_BOM_BYTES[1] && buffer[2] === UTF8_BOM_BYTES[2]) {
|
|
8629
8465
|
encodingLogger.debug('Detected UTF-8 BOM');
|
|
8630
8466
|
return { type: 'text', encoding: 'utf-8', hasBom: true };
|
|
8631
8467
|
}
|
|
8632
8468
|
}
|
|
8633
|
-
// Check for UTF-16 BOMs
|
|
8634
8469
|
if (buffer.length >= 2) {
|
|
8635
8470
|
if (buffer[0] === UTF16_BE_BOM_BYTES[0] && buffer[1] === UTF16_BE_BOM_BYTES[1]) {
|
|
8636
8471
|
encodingLogger.debug('Detected UTF-16 BE BOM');
|
|
8637
|
-
return { type: 'text', encoding: 'utf16le', hasBom: true };
|
|
8472
|
+
return { type: 'text', encoding: 'utf16le', hasBom: true };
|
|
8638
8473
|
}
|
|
8639
8474
|
if (buffer[0] === UTF16_LE_BOM_BYTES[0] && buffer[1] === UTF16_LE_BOM_BYTES[1]) {
|
|
8640
8475
|
encodingLogger.debug('Detected UTF-16 LE BOM');
|
|
8641
8476
|
return { type: 'text', encoding: 'utf16le', hasBom: true };
|
|
8642
8477
|
}
|
|
8643
8478
|
}
|
|
8644
|
-
// Check for binary signatures
|
|
8645
8479
|
for (const { signature, description } of BINARY_SIGNATURES) {
|
|
8646
8480
|
if (buffer.length >= signature.length) {
|
|
8647
8481
|
let matches = true;
|
|
@@ -8657,7 +8491,6 @@ function detectEncodingInfo(buffer) {
|
|
|
8657
8491
|
}
|
|
8658
8492
|
}
|
|
8659
8493
|
}
|
|
8660
|
-
// Check for null bytes (usually indicates binary)
|
|
8661
8494
|
const sampleSize = min(buffer.length, 8000);
|
|
8662
8495
|
for (let i = 0; i < sampleSize; i++) {
|
|
8663
8496
|
if (buffer[i] === 0) {
|
|
@@ -8676,22 +8509,18 @@ function detectEncodingInfo(buffer) {
|
|
|
8676
8509
|
*/
|
|
8677
8510
|
function detectEncoding(buffer) {
|
|
8678
8511
|
if (buffer.length >= 3) {
|
|
8679
|
-
// Check for UTF-8 BOM
|
|
8680
8512
|
if (buffer[0] === UTF8_BOM_BYTES[0] && buffer[1] === UTF8_BOM_BYTES[1] && buffer[2] === UTF8_BOM_BYTES[2]) {
|
|
8681
8513
|
return 'utf-8';
|
|
8682
8514
|
}
|
|
8683
8515
|
}
|
|
8684
8516
|
if (buffer.length >= 2) {
|
|
8685
|
-
// Check for UTF-16 LE BOM
|
|
8686
8517
|
if (buffer[0] === UTF16_LE_BOM_BYTES[0] && buffer[1] === UTF16_LE_BOM_BYTES[1]) {
|
|
8687
8518
|
return 'utf16le';
|
|
8688
8519
|
}
|
|
8689
|
-
// Check for UTF-16 BE BOM
|
|
8690
8520
|
if (buffer[0] === UTF16_BE_BOM_BYTES[0] && buffer[1] === UTF16_BE_BOM_BYTES[1]) {
|
|
8691
|
-
return 'utf16le';
|
|
8521
|
+
return 'utf16le';
|
|
8692
8522
|
}
|
|
8693
8523
|
}
|
|
8694
|
-
// Default to UTF-8
|
|
8695
8524
|
return 'utf-8';
|
|
8696
8525
|
}
|
|
8697
8526
|
/**
|
|
@@ -8761,10 +8590,8 @@ function bufferToString(content, encoding) {
|
|
|
8761
8590
|
convertLogger.debug('Using provided encoding', { encoding });
|
|
8762
8591
|
return content.toString(encoding);
|
|
8763
8592
|
}
|
|
8764
|
-
// Auto-detect and convert
|
|
8765
8593
|
const info = detectEncodingInfo(content);
|
|
8766
8594
|
if (info.type === 'text') {
|
|
8767
|
-
// Remove BOM if present
|
|
8768
8595
|
let offset = 0;
|
|
8769
8596
|
if (info.hasBom) {
|
|
8770
8597
|
offset = info.encoding === 'utf-8' ? 3 : 2;
|
|
@@ -8817,19 +8644,14 @@ function detectCaseSensitivity() {
|
|
|
8817
8644
|
if (cachedCaseSensitive !== null) {
|
|
8818
8645
|
return cachedCaseSensitive;
|
|
8819
8646
|
}
|
|
8820
|
-
// Quick check based on platform
|
|
8821
8647
|
if (process.platform === 'win32') {
|
|
8822
8648
|
cachedCaseSensitive = false;
|
|
8823
8649
|
return false;
|
|
8824
8650
|
}
|
|
8825
|
-
// macOS is typically case-insensitive by default
|
|
8826
8651
|
if (process.platform === 'darwin') {
|
|
8827
|
-
// Could be case-sensitive HFS+/APFS, but assume insensitive by default
|
|
8828
8652
|
cachedCaseSensitive = false;
|
|
8829
8653
|
return false;
|
|
8830
8654
|
}
|
|
8831
|
-
// Test actual file system behavior for Linux and others
|
|
8832
|
-
// Use mkdtempSync to create a secure temporary directory
|
|
8833
8655
|
let secureTestDir = null;
|
|
8834
8656
|
try {
|
|
8835
8657
|
secureTestDir = mkdtempSync(join$1(tmpdir(), 'case-sensitivity-test-'));
|
|
@@ -8840,12 +8662,9 @@ function detectCaseSensitivity() {
|
|
|
8840
8662
|
unlinkSync(testFile);
|
|
8841
8663
|
}
|
|
8842
8664
|
catch {
|
|
8843
|
-
// Default to case-sensitive on Linux/Unix if test fails
|
|
8844
|
-
// (win32 and darwin already returned early, so we're on a case-sensitive platform)
|
|
8845
8665
|
cachedCaseSensitive = true;
|
|
8846
8666
|
}
|
|
8847
8667
|
finally {
|
|
8848
|
-
// Clean up the secure temporary directory
|
|
8849
8668
|
if (secureTestDir) {
|
|
8850
8669
|
try {
|
|
8851
8670
|
rmdirSync(secureTestDir);
|
|
@@ -8980,7 +8799,6 @@ function normalizeLineEndings(content, style = 'lf') {
|
|
|
8980
8799
|
else {
|
|
8981
8800
|
target = style === 'crlf' ? CRLF : LF;
|
|
8982
8801
|
}
|
|
8983
|
-
// First normalize all to LF, then convert to target
|
|
8984
8802
|
const normalized = content.replace(/\r\n/g, LF).replace(/\r/g, LF);
|
|
8985
8803
|
if (target === LF) {
|
|
8986
8804
|
return normalized;
|
|
@@ -8995,7 +8813,6 @@ function normalizeLineEndings(content, style = 'lf') {
|
|
|
8995
8813
|
*/
|
|
8996
8814
|
function detectLineEnding(content) {
|
|
8997
8815
|
const hasCRLF = content.includes(CRLF);
|
|
8998
|
-
// Check for LF that is NOT part of CRLF
|
|
8999
8816
|
const hasLFOnly = content.includes('\n') && content.replace(/\r\n/g, '').includes('\n');
|
|
9000
8817
|
if (hasCRLF && hasLFOnly)
|
|
9001
8818
|
return 'mixed';
|
|
@@ -9473,7 +9290,6 @@ function createFsTree(root, options) {
|
|
|
9473
9290
|
}
|
|
9474
9291
|
const prefix = normalPath === '.' || normalPath === '' ? '' : normalPath + '/';
|
|
9475
9292
|
for (const [changedPath, change] of _changes) {
|
|
9476
|
-
// Handle root-level files
|
|
9477
9293
|
if (prefix === '') {
|
|
9478
9294
|
const childName = changedPath.split('/')[0];
|
|
9479
9295
|
if (change.type === 'DELETE' && !changedPath.includes('/')) {
|
|
@@ -9490,7 +9306,6 @@ function createFsTree(root, options) {
|
|
|
9490
9306
|
const relativePath = changedPath.slice(prefix.length);
|
|
9491
9307
|
const childName = relativePath.split('/')[0];
|
|
9492
9308
|
if (change.type === 'DELETE') {
|
|
9493
|
-
// Only remove if it's a direct child being deleted
|
|
9494
9309
|
if (!relativePath.includes('/')) {
|
|
9495
9310
|
childSet.delete(childName);
|
|
9496
9311
|
}
|
|
@@ -9576,12 +9391,10 @@ const factoryLogger = createScopedLogger('project-scope:vfs:factory');
|
|
|
9576
9391
|
function createTree(root, options) {
|
|
9577
9392
|
const normalizedRoot = normalizePath(root);
|
|
9578
9393
|
factoryLogger.debug('createTree', { root: normalizedRoot });
|
|
9579
|
-
// Validate root exists
|
|
9580
9394
|
if (!exists(normalizedRoot)) {
|
|
9581
9395
|
factoryLogger.warn('createTree failed: root does not exist', { root: normalizedRoot });
|
|
9582
9396
|
throw createError(`Root directory does not exist: ${normalizedRoot}`);
|
|
9583
9397
|
}
|
|
9584
|
-
// Validate root is a directory
|
|
9585
9398
|
if (!isDirectory(normalizedRoot)) {
|
|
9586
9399
|
factoryLogger.warn('createTree failed: root is not a directory', { root: normalizedRoot });
|
|
9587
9400
|
throw createError(`Root path is not a directory: ${normalizedRoot}`);
|
|
@@ -9628,7 +9441,6 @@ const vfsLogger = createScopedLogger('project-scope:vfs');
|
|
|
9628
9441
|
function commitChanges(tree, options) {
|
|
9629
9442
|
const changes = tree.listChanges();
|
|
9630
9443
|
const appliedChanges = [];
|
|
9631
|
-
// Set log level based on verbose option
|
|
9632
9444
|
if (options?.verbose) {
|
|
9633
9445
|
vfsLogger.setLogLevel('debug');
|
|
9634
9446
|
}
|
|
@@ -9640,7 +9452,6 @@ function commitChanges(tree, options) {
|
|
|
9640
9452
|
changes: [],
|
|
9641
9453
|
dryRun: options?.dryRun ?? false,
|
|
9642
9454
|
};
|
|
9643
|
-
// Dry run - just count changes without writing
|
|
9644
9455
|
if (options?.dryRun) {
|
|
9645
9456
|
for (const change of changes) {
|
|
9646
9457
|
switch (change.type) {
|
|
@@ -9658,7 +9469,6 @@ function commitChanges(tree, options) {
|
|
|
9658
9469
|
result.changes = changes;
|
|
9659
9470
|
return result;
|
|
9660
9471
|
}
|
|
9661
|
-
// Sort changes: deletes first (to free names), then creates, then updates
|
|
9662
9472
|
const sortedChanges = [...changes].sort((a, b) => {
|
|
9663
9473
|
const order = { DELETE: 0, CREATE: 1, UPDATE: 2 };
|
|
9664
9474
|
return order[a.type] - order[b.type];
|
|
@@ -9671,11 +9481,9 @@ function commitChanges(tree, options) {
|
|
|
9671
9481
|
case 'UPDATE':
|
|
9672
9482
|
/* istanbul ignore if -- content is always defined for CREATE/UPDATE from tree.write() */
|
|
9673
9483
|
if (change.content !== undefined) {
|
|
9674
|
-
// Ensure directory exists
|
|
9675
9484
|
const dir = dirname(absPath);
|
|
9676
9485
|
ensureDir(dir);
|
|
9677
9486
|
writeFileSync(absPath, change.content);
|
|
9678
|
-
// Apply permissions if specified
|
|
9679
9487
|
if (change.mode !== undefined) {
|
|
9680
9488
|
chmodSync(absPath, change.mode);
|
|
9681
9489
|
}
|
|
@@ -9693,7 +9501,6 @@ function commitChanges(tree, options) {
|
|
|
9693
9501
|
unlinkSync(absPath);
|
|
9694
9502
|
}
|
|
9695
9503
|
catch {
|
|
9696
|
-
// Try recursive delete for directories
|
|
9697
9504
|
rmSync(absPath, { recursive: true });
|
|
9698
9505
|
}
|
|
9699
9506
|
}
|
|
@@ -9707,7 +9514,6 @@ function commitChanges(tree, options) {
|
|
|
9707
9514
|
}
|
|
9708
9515
|
}
|
|
9709
9516
|
catch (error) {
|
|
9710
|
-
// On error, throw with context
|
|
9711
9517
|
vfsLogger.error('Commit failed', { path: change.path, type: change.type });
|
|
9712
9518
|
const message = error instanceof Error
|
|
9713
9519
|
? `Failed to ${change.type.toLowerCase()} ${change.path}: ${error.message}`
|
|
@@ -9716,7 +9522,6 @@ function commitChanges(tree, options) {
|
|
|
9716
9522
|
}
|
|
9717
9523
|
}
|
|
9718
9524
|
result.changes = appliedChanges;
|
|
9719
|
-
// Clear the tree's pending changes after successful commit
|
|
9720
9525
|
tree.clearChanges();
|
|
9721
9526
|
return result;
|
|
9722
9527
|
}
|
|
@@ -9792,18 +9597,14 @@ function backtrackLcs(table, oldLines, newLines) {
|
|
|
9792
9597
|
* @returns Filtered DiffLine array
|
|
9793
9598
|
*/
|
|
9794
9599
|
function operationsToDiffLines(operations, contextLines) {
|
|
9795
|
-
// Mark which lines should be included (changes + context)
|
|
9796
9600
|
const include = new Array(operations.length).fill(false);
|
|
9797
|
-
// First pass: mark all changes
|
|
9798
9601
|
for (let i = 0; i < operations.length; i++) {
|
|
9799
9602
|
if (operations[i].type !== 'same') {
|
|
9800
|
-
// Mark this line and context around it
|
|
9801
9603
|
for (let j = max(0, i - contextLines); j <= min(operations.length - 1, i + contextLines); j++) {
|
|
9802
9604
|
include[j] = true;
|
|
9803
9605
|
}
|
|
9804
9606
|
}
|
|
9805
9607
|
}
|
|
9806
|
-
// Second pass: convert to DiffLine
|
|
9807
9608
|
const lines = [];
|
|
9808
9609
|
let oldLineNum = 1;
|
|
9809
9610
|
let newLineNum = 1;
|
|
@@ -9825,7 +9626,6 @@ function operationsToDiffLines(operations, contextLines) {
|
|
|
9825
9626
|
}
|
|
9826
9627
|
}
|
|
9827
9628
|
else {
|
|
9828
|
-
// Skip but update line numbers
|
|
9829
9629
|
if (op.type === 'same') {
|
|
9830
9630
|
oldLineNum++;
|
|
9831
9631
|
newLineNum++;
|
|
@@ -9852,7 +9652,6 @@ function bufferToLines(content) {
|
|
|
9852
9652
|
if (!content)
|
|
9853
9653
|
return [];
|
|
9854
9654
|
const text = content.toString('utf-8');
|
|
9855
|
-
// Split by newline, keeping empty last line if present
|
|
9856
9655
|
return text.split('\n');
|
|
9857
9656
|
}
|
|
9858
9657
|
/**
|
|
@@ -9879,9 +9678,7 @@ function generateDiff(change, options = {}) {
|
|
|
9879
9678
|
diffLogger.debug('generateDiff', { path: change.path, type: change.type, contextLines });
|
|
9880
9679
|
const oldLines = bufferToLines(change.originalContent);
|
|
9881
9680
|
const newLines = bufferToLines(change.content);
|
|
9882
|
-
// Handle edge cases
|
|
9883
9681
|
if (change.type === 'CREATE') {
|
|
9884
|
-
// All lines are additions
|
|
9885
9682
|
const lines = newLines
|
|
9886
9683
|
.filter((line) => line !== '' || newLines.indexOf(line) !== newLines.length - 1 || newLines.length === 1)
|
|
9887
9684
|
.map((content, idx) => ({
|
|
@@ -9889,7 +9686,6 @@ function generateDiff(change, options = {}) {
|
|
|
9889
9686
|
line: idx + 1,
|
|
9890
9687
|
content,
|
|
9891
9688
|
}));
|
|
9892
|
-
// Filter out empty trailing line from split
|
|
9893
9689
|
const filteredLines = lines.filter((l, i) => !(i === lines.length - 1 && l.content === '' && lines.length > 1));
|
|
9894
9690
|
return {
|
|
9895
9691
|
path: change.path,
|
|
@@ -9899,13 +9695,11 @@ function generateDiff(change, options = {}) {
|
|
|
9899
9695
|
};
|
|
9900
9696
|
}
|
|
9901
9697
|
if (change.type === 'DELETE') {
|
|
9902
|
-
// All lines are deletions
|
|
9903
9698
|
const lines = oldLines.map((content, idx) => ({
|
|
9904
9699
|
type: 'remove',
|
|
9905
9700
|
line: idx + 1,
|
|
9906
9701
|
content,
|
|
9907
9702
|
}));
|
|
9908
|
-
// Filter out empty trailing line from split
|
|
9909
9703
|
const filteredLines = lines.filter((l, i) => !(i === lines.length - 1 && l.content === '' && lines.length > 1));
|
|
9910
9704
|
return {
|
|
9911
9705
|
path: change.path,
|
|
@@ -9914,7 +9708,6 @@ function generateDiff(change, options = {}) {
|
|
|
9914
9708
|
deletions: filteredLines.length,
|
|
9915
9709
|
};
|
|
9916
9710
|
}
|
|
9917
|
-
// UPDATE: compute actual diff
|
|
9918
9711
|
const table = computeLcsTable(oldLines, newLines);
|
|
9919
9712
|
const operations = backtrackLcs(table, oldLines, newLines);
|
|
9920
9713
|
const lines = operationsToDiffLines(operations, contextLines);
|
|
@@ -9948,13 +9741,11 @@ function generateDiff(change, options = {}) {
|
|
|
9948
9741
|
*/
|
|
9949
9742
|
function formatUnifiedDiff(diff) {
|
|
9950
9743
|
const lines = [];
|
|
9951
|
-
// Header
|
|
9952
9744
|
lines.push(`--- a/${diff.path}`);
|
|
9953
9745
|
lines.push(`+++ b/${diff.path}`);
|
|
9954
9746
|
if (diff.lines.length === 0) {
|
|
9955
9747
|
return lines.join('\n');
|
|
9956
9748
|
}
|
|
9957
|
-
// Group lines into hunks
|
|
9958
9749
|
const hunks = [];
|
|
9959
9750
|
const currentHunk = [];
|
|
9960
9751
|
for (const line of diff.lines) {
|
|
@@ -9963,9 +9754,7 @@ function formatUnifiedDiff(diff) {
|
|
|
9963
9754
|
if (currentHunk.length > 0) {
|
|
9964
9755
|
hunks.push(currentHunk);
|
|
9965
9756
|
}
|
|
9966
|
-
// Output hunks
|
|
9967
9757
|
for (const hunk of hunks) {
|
|
9968
|
-
// Calculate hunk header
|
|
9969
9758
|
const contextAndRemove = hunk.filter((l) => l.type === 'context' || l.type === 'remove');
|
|
9970
9759
|
const contextAndAdd = hunk.filter((l) => l.type === 'context' || l.type === 'add');
|
|
9971
9760
|
const oldStart = hunk.find((l) => l.type === 'context' || l.type === 'remove')?.line ?? 1;
|
|
@@ -9973,7 +9762,6 @@ function formatUnifiedDiff(diff) {
|
|
|
9973
9762
|
const oldCount = contextAndRemove.length;
|
|
9974
9763
|
const newCount = contextAndAdd.length;
|
|
9975
9764
|
lines.push(`@@ -${oldStart},${oldCount} +${newStart},${newCount} @@`);
|
|
9976
|
-
// Output lines
|
|
9977
9765
|
for (const line of hunk) {
|
|
9978
9766
|
const prefix = line.type === 'add' ? '+' : line.type === 'remove' ? '-' : ' ';
|
|
9979
9767
|
lines.push(`${prefix}${line.content}`);
|