@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.
Files changed (176) hide show
  1. package/CHANGELOG.md +8 -16
  2. package/analyze.d.ts.map +1 -1
  3. package/cli/commands/analyze.d.ts +8 -0
  4. package/cli/commands/analyze.d.ts.map +1 -1
  5. package/cli/commands/config.d.ts +7 -0
  6. package/cli/commands/config.d.ts.map +1 -1
  7. package/cli/commands/deps.d.ts +6 -0
  8. package/cli/commands/deps.d.ts.map +1 -1
  9. package/cli/commands/tree.d.ts +12 -0
  10. package/cli/commands/tree.d.ts.map +1 -1
  11. package/cli/index.cjs.js +73 -206
  12. package/cli/index.cjs.js.map +1 -1
  13. package/cli/index.esm.js +73 -206
  14. package/cli/index.esm.js.map +1 -1
  15. package/cli/run.d.ts.map +1 -1
  16. package/core/cache.d.ts +1 -0
  17. package/core/cache.d.ts.map +1 -1
  18. package/core/encoding/convert.d.ts.map +1 -1
  19. package/core/encoding/detect.d.ts +5 -0
  20. package/core/encoding/detect.d.ts.map +1 -1
  21. package/core/encoding/index.cjs.js +2 -23
  22. package/core/encoding/index.cjs.js.map +1 -1
  23. package/core/encoding/index.esm.js +2 -23
  24. package/core/encoding/index.esm.js.map +1 -1
  25. package/core/errors/structured-errors.d.ts +2 -0
  26. package/core/errors/structured-errors.d.ts.map +1 -1
  27. package/core/fs/directory.d.ts +3 -0
  28. package/core/fs/directory.d.ts.map +1 -1
  29. package/core/fs/index.cjs.js +0 -14
  30. package/core/fs/index.cjs.js.map +1 -1
  31. package/core/fs/index.esm.js +0 -14
  32. package/core/fs/index.esm.js.map +1 -1
  33. package/core/fs/read.d.ts +11 -3
  34. package/core/fs/read.d.ts.map +1 -1
  35. package/core/fs/traversal.d.ts.map +1 -1
  36. package/core/index.cjs.js +6 -62
  37. package/core/index.cjs.js.map +1 -1
  38. package/core/index.esm.js +6 -62
  39. package/core/index.esm.js.map +1 -1
  40. package/core/logger.d.ts.map +1 -1
  41. package/core/path/index.cjs.js +0 -1
  42. package/core/path/index.cjs.js.map +1 -1
  43. package/core/path/index.esm.js +0 -1
  44. package/core/path/index.esm.js.map +1 -1
  45. package/core/path/normalize.d.ts.map +1 -1
  46. package/core/patterns/glob.d.ts +0 -4
  47. package/core/patterns/glob.d.ts.map +1 -1
  48. package/core/platform/detect.d.ts.map +1 -1
  49. package/core/platform/index.cjs.js +0 -10
  50. package/core/platform/index.cjs.js.map +1 -1
  51. package/core/platform/index.esm.js +0 -10
  52. package/core/platform/index.esm.js.map +1 -1
  53. package/core/platform/line-endings.d.ts.map +1 -1
  54. package/heuristics/dependencies/analyze.d.ts.map +1 -1
  55. package/heuristics/dependencies/index.cjs.js +0 -17
  56. package/heuristics/dependencies/index.cjs.js.map +1 -1
  57. package/heuristics/dependencies/index.esm.js +0 -17
  58. package/heuristics/dependencies/index.esm.js.map +1 -1
  59. package/heuristics/entry-points/discover.d.ts +34 -7
  60. package/heuristics/entry-points/discover.d.ts.map +1 -1
  61. package/heuristics/entry-points/index.cjs.js +6 -34
  62. package/heuristics/entry-points/index.cjs.js.map +1 -1
  63. package/heuristics/entry-points/index.esm.js +6 -34
  64. package/heuristics/entry-points/index.esm.js.map +1 -1
  65. package/heuristics/framework/index.cjs.js +1 -63
  66. package/heuristics/framework/index.cjs.js.map +1 -1
  67. package/heuristics/framework/index.esm.js +1 -63
  68. package/heuristics/framework/index.esm.js.map +1 -1
  69. package/heuristics/index.cjs.js +7 -88
  70. package/heuristics/index.cjs.js.map +1 -1
  71. package/heuristics/index.esm.js +7 -88
  72. package/heuristics/index.esm.js.map +1 -1
  73. package/heuristics/project-type/index.cjs.js +1 -63
  74. package/heuristics/project-type/index.cjs.js.map +1 -1
  75. package/heuristics/project-type/index.esm.js +1 -63
  76. package/heuristics/project-type/index.esm.js.map +1 -1
  77. package/index.cjs.js +81 -293
  78. package/index.cjs.js.map +1 -1
  79. package/index.esm.js +81 -293
  80. package/index.esm.js.map +1 -1
  81. package/nx/detect.d.ts.map +1 -1
  82. package/nx/devkit-loader.d.ts.map +1 -1
  83. package/nx/index.cjs.js +0 -29
  84. package/nx/index.cjs.js.map +1 -1
  85. package/nx/index.esm.js +0 -29
  86. package/nx/index.esm.js.map +1 -1
  87. package/nx/project-config.d.ts +2 -0
  88. package/nx/project-config.d.ts.map +1 -1
  89. package/package.json +1 -1
  90. package/project/config/index.cjs.js +4 -46
  91. package/project/config/index.cjs.js.map +1 -1
  92. package/project/config/index.esm.js +4 -46
  93. package/project/config/index.esm.js.map +1 -1
  94. package/project/config/patterns.d.ts.map +1 -1
  95. package/project/index.cjs.js +4 -47
  96. package/project/index.cjs.js.map +1 -1
  97. package/project/index.esm.js +4 -47
  98. package/project/index.esm.js.map +1 -1
  99. package/project/package/index.cjs.js +0 -11
  100. package/project/package/index.cjs.js.map +1 -1
  101. package/project/package/index.esm.js +0 -11
  102. package/project/package/index.esm.js.map +1 -1
  103. package/project/package/read.d.ts +1 -0
  104. package/project/package/read.d.ts.map +1 -1
  105. package/project/root/index.cjs.js +0 -11
  106. package/project/root/index.cjs.js.map +1 -1
  107. package/project/root/index.esm.js +0 -11
  108. package/project/root/index.esm.js.map +1 -1
  109. package/project/traversal/index.cjs.js +4 -28
  110. package/project/traversal/index.cjs.js.map +1 -1
  111. package/project/traversal/index.esm.js +4 -28
  112. package/project/traversal/index.esm.js.map +1 -1
  113. package/tech/backend/express.d.ts.map +1 -1
  114. package/tech/backend/fastify.d.ts.map +1 -1
  115. package/tech/backend/index.cjs.js +0 -17
  116. package/tech/backend/index.cjs.js.map +1 -1
  117. package/tech/backend/index.esm.js +0 -17
  118. package/tech/backend/index.esm.js.map +1 -1
  119. package/tech/backend/koa.d.ts.map +1 -1
  120. package/tech/backend/nestjs.d.ts.map +1 -1
  121. package/tech/build/index.cjs.js +0 -12
  122. package/tech/build/index.cjs.js.map +1 -1
  123. package/tech/build/index.esm.js +0 -12
  124. package/tech/build/index.esm.js.map +1 -1
  125. package/tech/frontend/index.cjs.js +0 -16
  126. package/tech/frontend/index.cjs.js.map +1 -1
  127. package/tech/frontend/index.esm.js +0 -16
  128. package/tech/frontend/index.esm.js.map +1 -1
  129. package/tech/frontend/qwik.d.ts.map +1 -1
  130. package/tech/frontend/remix.d.ts.map +1 -1
  131. package/tech/frontend/sveltekit.d.ts.map +1 -1
  132. package/tech/index.cjs.js +1 -63
  133. package/tech/index.cjs.js.map +1 -1
  134. package/tech/index.d.ts.map +1 -1
  135. package/tech/index.esm.js +1 -63
  136. package/tech/index.esm.js.map +1 -1
  137. package/tech/legacy/angularjs.d.ts.map +1 -1
  138. package/tech/legacy/backbone.d.ts.map +1 -1
  139. package/tech/legacy/ember.d.ts.map +1 -1
  140. package/tech/legacy/index.cjs.js +0 -26
  141. package/tech/legacy/index.cjs.js.map +1 -1
  142. package/tech/legacy/index.esm.js +0 -26
  143. package/tech/legacy/index.esm.js.map +1 -1
  144. package/tech/legacy/jquery.d.ts.map +1 -1
  145. package/tech/linting/biome.d.ts.map +1 -1
  146. package/tech/linting/index.cjs.js +0 -14
  147. package/tech/linting/index.cjs.js.map +1 -1
  148. package/tech/linting/index.esm.js +0 -14
  149. package/tech/linting/index.esm.js.map +1 -1
  150. package/tech/linting/prettier.d.ts.map +1 -1
  151. package/tech/monorepo/index.cjs.js +1 -13
  152. package/tech/monorepo/index.cjs.js.map +1 -1
  153. package/tech/monorepo/index.esm.js +1 -13
  154. package/tech/monorepo/index.esm.js.map +1 -1
  155. package/tech/monorepo/types.d.ts +1 -1
  156. package/tech/monorepo/types.d.ts.map +1 -1
  157. package/tech/shared-utils/detector-helpers.d.ts.map +1 -1
  158. package/tech/testing/index.cjs.js +0 -12
  159. package/tech/testing/index.cjs.js.map +1 -1
  160. package/tech/testing/index.esm.js +0 -12
  161. package/tech/testing/index.esm.js.map +1 -1
  162. package/tech/types/detectors.d.ts.map +1 -1
  163. package/tech/types/index.cjs.js +0 -27
  164. package/tech/types/index.cjs.js.map +1 -1
  165. package/tech/types/index.esm.js +0 -27
  166. package/tech/types/index.esm.js.map +1 -1
  167. package/vfs/commit.d.ts.map +1 -1
  168. package/vfs/diff.d.ts.map +1 -1
  169. package/vfs/factory.d.ts.map +1 -1
  170. package/vfs/fs-tree.d.ts.map +1 -1
  171. package/vfs/index.cjs.js +0 -45
  172. package/vfs/index.cjs.js.map +1 -1
  173. package/vfs/index.esm.js +0 -45
  174. package/vfs/index.esm.js.map +1 -1
  175. package/vfs/types.d.ts +1 -0
  176. package/vfs/types.d.ts.map +1 -1
package/cli/index.esm.js CHANGED
@@ -10,7 +10,6 @@ import { existsSync, readFileSync, statSync, lstatSync, readdirSync } from 'node
10
10
  *
11
11
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/console
12
12
  */
13
- // Capture references at module initialization time
14
13
  const _console = globalThis.console;
15
14
  /**
16
15
  * (Safe copy) Outputs a message to the console.
@@ -85,40 +84,6 @@ _console.timeEnd.bind(_console);
85
84
  */
86
85
  _console.timeLog.bind(_console);
87
86
 
88
- /**
89
- * Safe copies of Array built-in static methods.
90
- *
91
- * These references are captured at module initialization time to protect against
92
- * prototype pollution attacks. Import only what you need for tree-shaking.
93
- *
94
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
95
- */
96
- // Capture references at module initialization time
97
- const _Array = globalThis.Array;
98
- /**
99
- * (Safe copy) Determines whether the passed value is an Array.
100
- */
101
- const isArray = _Array.isArray;
102
-
103
- /**
104
- * Safe copies of JSON built-in methods.
105
- *
106
- * These references are captured at module initialization time to protect against
107
- * prototype pollution attacks. Import only what you need for tree-shaking.
108
- *
109
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
110
- */
111
- // Capture references at module initialization time
112
- const _JSON = globalThis.JSON;
113
- /**
114
- * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
115
- */
116
- const parse = _JSON.parse;
117
- /**
118
- * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
119
- */
120
- const stringify = _JSON.stringify;
121
-
122
87
  /**
123
88
  * Safe copies of Object built-in methods.
124
89
  *
@@ -127,7 +92,6 @@ const stringify = _JSON.stringify;
127
92
  *
128
93
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/object
129
94
  */
130
- // Capture references at module initialization time
131
95
  const _Object = globalThis.Object;
132
96
  /**
133
97
  * (Safe copy) Prevents modification of existing property attributes and values,
@@ -151,30 +115,21 @@ const values = _Object.values;
151
115
  */
152
116
  const defineProperties = _Object.defineProperties;
153
117
 
118
+ const registeredClasses = [];
119
+
154
120
  /**
155
- * Safe copies of Set built-in via factory function.
156
- *
157
- * Since constructors cannot be safely captured via Object.assign, this module
158
- * provides a factory function that uses Reflect.construct internally.
121
+ * Safe copies of Array built-in static methods.
159
122
  *
160
123
  * These references are captured at module initialization time to protect against
161
124
  * prototype pollution attacks. Import only what you need for tree-shaking.
162
125
  *
163
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
126
+ * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
164
127
  */
165
- // Capture references at module initialization time
166
- const _Set = globalThis.Set;
167
- const _Reflect$3 = globalThis.Reflect;
128
+ const _Array = globalThis.Array;
168
129
  /**
169
- * (Safe copy) Creates a new Set using the captured Set constructor.
170
- * Use this instead of `new Set()`.
171
- *
172
- * @param iterable - Optional iterable of values.
173
- * @returns A new Set instance.
130
+ * (Safe copy) Determines whether the passed value is an Array.
174
131
  */
175
- const createSet = (iterable) => _Reflect$3.construct(_Set, iterable ? [iterable] : []);
176
-
177
- const registeredClasses = [];
132
+ const isArray = _Array.isArray;
178
133
 
179
134
  /**
180
135
  * Returns the data type of the target.
@@ -210,9 +165,8 @@ const getType = (target) => {
210
165
  *
211
166
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/error
212
167
  */
213
- // Capture references at module initialization time
214
168
  const _Error = globalThis.Error;
215
- const _Reflect$2 = globalThis.Reflect;
169
+ const _Reflect$3 = globalThis.Reflect;
216
170
  /**
217
171
  * (Safe copy) Creates a new Error using the captured Error constructor.
218
172
  * Use this instead of `new Error()`.
@@ -221,7 +175,7 @@ const _Reflect$2 = globalThis.Reflect;
221
175
  * @param options - Optional error options.
222
176
  * @returns A new Error instance.
223
177
  */
224
- const createError = (message, options) => _Reflect$2.construct(_Error, [message, options]);
178
+ const createError = (message, options) => _Reflect$3.construct(_Error, [message, options]);
225
179
 
226
180
  /**
227
181
  * Safe copies of Map built-in via factory function.
@@ -234,9 +188,8 @@ const createError = (message, options) => _Reflect$2.construct(_Error, [message,
234
188
  *
235
189
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/map
236
190
  */
237
- // Capture references at module initialization time
238
191
  const _Map = globalThis.Map;
239
- const _Reflect$1 = globalThis.Reflect;
192
+ const _Reflect$2 = globalThis.Reflect;
240
193
  /**
241
194
  * (Safe copy) Creates a new Map using the captured Map constructor.
242
195
  * Use this instead of `new Map()`.
@@ -244,7 +197,7 @@ const _Reflect$1 = globalThis.Reflect;
244
197
  * @param iterable - Optional iterable of key-value pairs.
245
198
  * @returns A new Map instance.
246
199
  */
247
- const createMap = (iterable) => _Reflect$1.construct(_Map, iterable ? [iterable] : []);
200
+ const createMap = (iterable) => _Reflect$2.construct(_Map, iterable ? [iterable] : []);
248
201
 
249
202
  /**
250
203
  * Safe copies of Date built-in via factory function and static methods.
@@ -257,11 +210,10 @@ const createMap = (iterable) => _Reflect$1.construct(_Map, iterable ? [iterable]
257
210
  *
258
211
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/date
259
212
  */
260
- // Capture references at module initialization time
261
213
  const _Date = globalThis.Date;
262
- const _Reflect = globalThis.Reflect;
214
+ const _Reflect$1 = globalThis.Reflect;
263
215
  function createDate(...args) {
264
- return _Reflect.construct(_Date, args);
216
+ return _Reflect$1.construct(_Date, args);
265
217
  }
266
218
  /**
267
219
  * (Safe copy) Returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
@@ -276,7 +228,6 @@ const dateNow = _Date.now;
276
228
  *
277
229
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/math
278
230
  */
279
- // Capture references at module initialization time
280
231
  const _Math = globalThis.Math;
281
232
  /**
282
233
  * (Safe copy) Returns the value of a number rounded to the nearest integer.
@@ -287,6 +238,28 @@ const round = _Math.round;
287
238
  */
288
239
  const min = _Math.min;
289
240
 
241
+ /**
242
+ * Safe copies of Set built-in via factory function.
243
+ *
244
+ * Since constructors cannot be safely captured via Object.assign, this module
245
+ * provides a factory function that uses Reflect.construct internally.
246
+ *
247
+ * These references are captured at module initialization time to protect against
248
+ * prototype pollution attacks. Import only what you need for tree-shaking.
249
+ *
250
+ * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
251
+ */
252
+ const _Set = globalThis.Set;
253
+ const _Reflect = globalThis.Reflect;
254
+ /**
255
+ * (Safe copy) Creates a new Set using the captured Set constructor.
256
+ * Use this instead of `new Set()`.
257
+ *
258
+ * @param iterable - Optional iterable of values.
259
+ * @returns A new Set instance.
260
+ */
261
+ const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
262
+
290
263
  /* eslint-disable @typescript-eslint/no-explicit-any */
291
264
  /**
292
265
  * Creates a wrapper function that only executes the wrapped function if the condition function returns true.
@@ -450,6 +423,24 @@ function notFnMsg(label) {
450
423
 
451
424
  createLogger(error, warn, log, info, debug);
452
425
 
426
+ /**
427
+ * Safe copies of JSON built-in methods.
428
+ *
429
+ * These references are captured at module initialization time to protect against
430
+ * prototype pollution attacks. Import only what you need for tree-shaking.
431
+ *
432
+ * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
433
+ */
434
+ const _JSON = globalThis.JSON;
435
+ /**
436
+ * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
437
+ */
438
+ const parse = _JSON.parse;
439
+ /**
440
+ * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
441
+ */
442
+ const stringify = _JSON.stringify;
443
+
453
444
  /**
454
445
  * Global log level registry.
455
446
  * Tracks all created scoped loggers to allow global log level changes.
@@ -578,14 +569,11 @@ function formatMessage(namespace, message, meta) {
578
569
  */
579
570
  function createScopedLogger(namespace, options = {}) {
580
571
  const { level = 'error', sanitizeSecrets = true } = options;
581
- // Create wrapper functions that add namespace prefix and sanitization
582
572
  const createLogFn = (baseFn) => (message, meta) => {
583
573
  const processedMeta = sanitizeSecrets && meta ? sanitize(meta) : meta;
584
574
  baseFn(formatMessage(namespace, message, processedMeta));
585
575
  };
586
- // Create base logger with wrapped functions
587
576
  const baseLogger = createLogger(createLogFn(error), createLogFn(warn), createLogFn(log), createLogFn(info), createLogFn(debug));
588
- // Set initial log level (use global override if set)
589
577
  baseLogger.setLogLevel(globalLogLevel ?? level);
590
578
  const scopedLogger = freeze({
591
579
  error: (message, meta) => baseLogger.error(message, meta),
@@ -596,7 +584,6 @@ function createScopedLogger(namespace, options = {}) {
596
584
  setLogLevel: baseLogger.setLogLevel,
597
585
  getLogLevel: baseLogger.getLogLevel,
598
586
  });
599
- // Register logger for global level management
600
587
  loggerRegistry.add(scopedLogger);
601
588
  return scopedLogger;
602
589
  }
@@ -809,7 +796,6 @@ function traverseUpward(startPath, predicate) {
809
796
  }
810
797
  currentPath = dirname(currentPath);
811
798
  }
812
- // Check root directory
813
799
  if (predicate(rootPath)) {
814
800
  fsTraversalLogger.debug('Upward traversal found match at root', { startPath, foundPath: rootPath });
815
801
  return rootPath;
@@ -1072,7 +1058,6 @@ const cacheRegistry = createSet();
1072
1058
  function createCache(options) {
1073
1059
  const { ttl, maxSize } = options ?? {};
1074
1060
  const store = createMap();
1075
- // Track insertion order for FIFO eviction
1076
1061
  const insertionOrder = [];
1077
1062
  /**
1078
1063
  * Check if an entry is expired.
@@ -1123,12 +1108,10 @@ function createCache(options) {
1123
1108
  return entry.value;
1124
1109
  },
1125
1110
  set(key, value) {
1126
- // If key exists, remove from order first
1127
1111
  if (store.has(key)) {
1128
1112
  removeFromOrder(key);
1129
1113
  }
1130
1114
  else {
1131
- // Evict if needed before adding new entry
1132
1115
  evictIfNeeded();
1133
1116
  }
1134
1117
  // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
@@ -1161,15 +1144,10 @@ function createCache(options) {
1161
1144
  return [...insertionOrder];
1162
1145
  },
1163
1146
  };
1164
- // Register cache for global operations
1165
1147
  cacheRegistry.add(cache);
1166
1148
  return freeze(cache);
1167
1149
  }
1168
1150
 
1169
- /**
1170
- * Pattern matching utilities with ReDoS protection.
1171
- * Uses character-by-character matching instead of regex where possible.
1172
- */
1173
1151
  /**
1174
1152
  * Match path against glob pattern using safe character iteration.
1175
1153
  * Avoids regex to prevent ReDoS attacks.
@@ -1207,17 +1185,14 @@ function matchGlobPattern(path, pattern) {
1207
1185
  * @returns True if remaining segments match
1208
1186
  */
1209
1187
  function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
1210
- // Base cases
1211
1188
  if (pathIdx === pathParts.length && patternIdx === patternParts.length) {
1212
- return true; // Both exhausted = match
1189
+ return true;
1213
1190
  }
1214
1191
  if (patternIdx >= patternParts.length) {
1215
- return false; // Pattern exhausted but path remains
1192
+ return false;
1216
1193
  }
1217
1194
  const patternPart = patternParts[patternIdx];
1218
- // Handle ** (globstar) - matches zero or more directories
1219
1195
  if (patternPart === '**') {
1220
- // Try matching rest of pattern against current position and all future positions
1221
1196
  for (let i = pathIdx; i <= pathParts.length; i++) {
1222
1197
  if (matchSegments(pathParts, patternParts, i, patternIdx + 1)) {
1223
1198
  return true;
@@ -1226,10 +1201,9 @@ function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
1226
1201
  return false;
1227
1202
  }
1228
1203
  if (pathIdx >= pathParts.length) {
1229
- return false; // Path exhausted but pattern remains (and it's not **)
1204
+ return false;
1230
1205
  }
1231
1206
  const pathPart = pathParts[pathIdx];
1232
- // Match current segment
1233
1207
  if (matchSegment(pathPart, patternPart)) {
1234
1208
  return matchSegments(pathParts, patternParts, pathIdx + 1, patternIdx + 1);
1235
1209
  }
@@ -1249,12 +1223,10 @@ function matchSegment(text, pattern) {
1249
1223
  while (patternIdx < pattern.length) {
1250
1224
  const char = pattern[patternIdx];
1251
1225
  if (char === '*') {
1252
- // * matches zero or more characters
1253
1226
  patternIdx++;
1254
1227
  if (patternIdx === pattern.length) {
1255
- return true; // * at end matches rest of string
1228
+ return true;
1256
1229
  }
1257
- // Try matching rest of pattern at each position in text
1258
1230
  for (let i = textIdx; i <= text.length; i++) {
1259
1231
  if (matchSegmentFrom(text, i, pattern, patternIdx)) {
1260
1232
  return true;
@@ -1263,7 +1235,6 @@ function matchSegment(text, pattern) {
1263
1235
  return false;
1264
1236
  }
1265
1237
  else if (char === '?') {
1266
- // ? matches exactly one character
1267
1238
  if (textIdx >= text.length) {
1268
1239
  return false;
1269
1240
  }
@@ -1271,10 +1242,8 @@ function matchSegment(text, pattern) {
1271
1242
  patternIdx++;
1272
1243
  }
1273
1244
  else if (char === '{') {
1274
- // {a,b,c} matches any alternative
1275
1245
  const closeIdx = findClosingBrace(pattern, patternIdx);
1276
1246
  if (closeIdx === -1) {
1277
- // Unmatched brace, treat as literal
1278
1247
  if (textIdx >= text.length || text[textIdx] !== char) {
1279
1248
  return false;
1280
1249
  }
@@ -1292,7 +1261,6 @@ function matchSegment(text, pattern) {
1292
1261
  }
1293
1262
  }
1294
1263
  else {
1295
- // Literal character
1296
1264
  if (textIdx >= text.length || text[textIdx] !== char) {
1297
1265
  return false;
1298
1266
  }
@@ -1840,7 +1808,6 @@ function collectAllDependencies(packageJson) {
1840
1808
  function parseVersionString(versionString) {
1841
1809
  if (versionString === undefined || versionString === null)
1842
1810
  return undefined;
1843
- // Manual parsing instead of regex to avoid ReDoS
1844
1811
  let start = 0;
1845
1812
  while (start < versionString.length) {
1846
1813
  const char = versionString[start];
@@ -1901,7 +1868,6 @@ function expressDetector(projectPath, packageJson) {
1901
1868
  version = parseVersionString(deps['express']);
1902
1869
  sources.push({ type: 'package.json', field: 'dependencies.express' });
1903
1870
  }
1904
- // @types/express (indicates usage)
1905
1871
  if (deps['@types/express']) {
1906
1872
  confidence += 10;
1907
1873
  sources.push({ type: 'package.json', field: 'dependencies.@types/express' });
@@ -1937,13 +1903,11 @@ function nestDetector(projectPath, packageJson) {
1937
1903
  let version;
1938
1904
  let configPath;
1939
1905
  const deps = collectAllDependencies(pkg);
1940
- // @nestjs/core package
1941
1906
  if (deps['@nestjs/core']) {
1942
1907
  confidence += 70;
1943
1908
  version = parseVersionString(deps['@nestjs/core']);
1944
1909
  sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1945
1910
  }
1946
- // @nestjs/common
1947
1911
  if (deps['@nestjs/common']) {
1948
1912
  confidence += 15;
1949
1913
  sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
@@ -1994,7 +1958,6 @@ function fastifyDetector(projectPath, packageJson) {
1994
1958
  confidence += 15;
1995
1959
  sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1996
1960
  }
1997
- // @types/fastify (older versions)
1998
1961
  if (deps['@types/fastify']) {
1999
1962
  confidence += 5;
2000
1963
  sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
@@ -2029,7 +1992,6 @@ function koaDetector(projectPath, packageJson) {
2029
1992
  version = parseVersionString(deps['koa']);
2030
1993
  sources.push({ type: 'package.json', field: 'dependencies.koa' });
2031
1994
  }
2032
- // @types/koa
2033
1995
  if (deps['@types/koa']) {
2034
1996
  confidence += 10;
2035
1997
  sources.push({ type: 'package.json', field: 'dependencies.@types/koa' });
@@ -2572,7 +2534,6 @@ function remixDetector(projectPath, packageJson) {
2572
2534
  let confidence = 0;
2573
2535
  let version;
2574
2536
  const deps = collectAllDependencies(pkg);
2575
- // @remix-run packages
2576
2537
  if (deps['@remix-run/react']) {
2577
2538
  confidence += 70;
2578
2539
  version = parseVersionString(deps['@remix-run/react']);
@@ -2848,7 +2809,6 @@ function sveltekitDetector(projectPath, packageJson) {
2848
2809
  let confidence = 0;
2849
2810
  let version;
2850
2811
  const deps = collectAllDependencies(pkg);
2851
- // @sveltejs/kit package
2852
2812
  if (deps['@sveltejs/kit']) {
2853
2813
  confidence += 70;
2854
2814
  version = parseVersionString(deps['@sveltejs/kit']);
@@ -2927,13 +2887,11 @@ function qwikDetector(projectPath, packageJson) {
2927
2887
  let confidence = 0;
2928
2888
  let version;
2929
2889
  const deps = collectAllDependencies(pkg);
2930
- // @builder.io/qwik package
2931
2890
  if (deps['@builder.io/qwik']) {
2932
2891
  confidence += 70;
2933
2892
  version = parseVersionString(deps['@builder.io/qwik']);
2934
2893
  sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
2935
2894
  }
2936
- // @builder.io/qwik-city
2937
2895
  if (deps['@builder.io/qwik-city']) {
2938
2896
  confidence += 20;
2939
2897
  sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
@@ -3026,23 +2984,19 @@ function angularJSDetector(projectPath, packageJson) {
3026
2984
  let confidence = 0;
3027
2985
  let version;
3028
2986
  const deps = collectAllDependencies(pkg);
3029
- // AngularJS package (angular, not @angular/core)
3030
2987
  if (deps['angular']) {
3031
2988
  confidence += 70;
3032
2989
  version = parseVersionString(deps['angular']);
3033
2990
  sources.push({ type: 'package.json', field: 'dependencies.angular' });
3034
2991
  }
3035
- // AngularJS router
3036
2992
  if (deps['angular-route']) {
3037
2993
  confidence += 15;
3038
2994
  sources.push({ type: 'package.json', field: 'dependencies.angular-route' });
3039
2995
  }
3040
- // AngularJS resource
3041
2996
  if (deps['angular-resource']) {
3042
2997
  confidence += 10;
3043
2998
  sources.push({ type: 'package.json', field: 'dependencies.angular-resource' });
3044
2999
  }
3045
- // AngularJS animate
3046
3000
  if (deps['angular-animate']) {
3047
3001
  confidence += 5;
3048
3002
  sources.push({ type: 'package.json', field: 'dependencies.angular-animate' });
@@ -3073,23 +3027,19 @@ function backboneDetector(projectPath, packageJson) {
3073
3027
  let confidence = 0;
3074
3028
  let version;
3075
3029
  const deps = collectAllDependencies(pkg);
3076
- // Backbone package
3077
3030
  if (deps['backbone']) {
3078
3031
  confidence += 70;
3079
3032
  version = parseVersionString(deps['backbone']);
3080
3033
  sources.push({ type: 'package.json', field: 'dependencies.backbone' });
3081
- // Underscore (commonly used with Backbone)
3082
3034
  if (deps['underscore']) {
3083
3035
  confidence += 15;
3084
3036
  sources.push({ type: 'package.json', field: 'dependencies.underscore' });
3085
3037
  }
3086
- // Lodash can be used as underscore replacement
3087
3038
  if (deps['lodash']) {
3088
3039
  confidence += 5;
3089
3040
  sources.push({ type: 'package.json', field: 'dependencies.lodash' });
3090
3041
  }
3091
3042
  }
3092
- // Marionette (Backbone framework)
3093
3043
  if (deps['backbone.marionette'] || deps['marionette']) {
3094
3044
  confidence += 10;
3095
3045
  sources.push({ type: 'package.json', field: 'dependencies.backbone.marionette' });
@@ -3120,18 +3070,15 @@ function emberDetector(projectPath, packageJson) {
3120
3070
  let confidence = 0;
3121
3071
  let version;
3122
3072
  const deps = collectAllDependencies(pkg);
3123
- // Ember source package
3124
3073
  if (deps['ember-source']) {
3125
3074
  confidence += 70;
3126
3075
  version = parseVersionString(deps['ember-source']);
3127
3076
  sources.push({ type: 'package.json', field: 'dependencies.ember-source' });
3128
3077
  }
3129
- // Ember CLI
3130
3078
  if (deps['ember-cli']) {
3131
3079
  confidence += 20;
3132
3080
  sources.push({ type: 'package.json', field: 'devDependencies.ember-cli' });
3133
3081
  }
3134
- // Ember Data
3135
3082
  if (deps['ember-data']) {
3136
3083
  confidence += 10;
3137
3084
  sources.push({ type: 'package.json', field: 'dependencies.ember-data' });
@@ -3162,18 +3109,15 @@ function jqueryDetector(projectPath, packageJson) {
3162
3109
  let confidence = 0;
3163
3110
  let version;
3164
3111
  const deps = collectAllDependencies(pkg);
3165
- // jQuery package
3166
3112
  if (deps['jquery']) {
3167
3113
  confidence += 80;
3168
3114
  version = parseVersionString(deps['jquery']);
3169
3115
  sources.push({ type: 'package.json', field: 'dependencies.jquery' });
3170
3116
  }
3171
- // jQuery UI
3172
3117
  if (deps['jquery-ui']) {
3173
3118
  confidence += 10;
3174
3119
  sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
3175
3120
  }
3176
- // jQuery plugins
3177
3121
  if (deps['jquery-validation']) {
3178
3122
  confidence += 5;
3179
3123
  sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
@@ -3302,7 +3246,6 @@ function prettierDetector(projectPath, packageJson) {
3302
3246
  confidence += 30;
3303
3247
  sources.push({ type: 'package.json', field: 'prettier' });
3304
3248
  }
3305
- // .prettierignore file
3306
3249
  if (exists(join$1(projectPath, '.prettierignore'))) {
3307
3250
  confidence += 10;
3308
3251
  sources.push({ type: 'config-file', path: '.prettierignore' });
@@ -3397,7 +3340,6 @@ function biomeDetector(projectPath, packageJson) {
3397
3340
  let configPath;
3398
3341
  let version;
3399
3342
  const deps = collectAllDependencies(pkg);
3400
- // @biomejs/biome package
3401
3343
  if (deps['@biomejs/biome']) {
3402
3344
  confidence += 70;
3403
3345
  version = parseVersionString(deps['@biomejs/biome']);
@@ -3666,7 +3608,7 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
3666
3608
  sources.push({ type: 'lockfile', path: 'package-lock.json' });
3667
3609
  }
3668
3610
  if (exists(join$1(workspacePath, 'yarn.lock'))) {
3669
- return null; // Let yarn workspace detector handle this
3611
+ return null;
3670
3612
  }
3671
3613
  if (confidence === 0) {
3672
3614
  return null;
@@ -4009,7 +3951,6 @@ function checkTsConfigStrict(projectPath) {
4009
3951
  if (!content)
4010
3952
  return undefined;
4011
3953
  try {
4012
- // Simple JSON parsing - doesn't handle comments but good enough for strict check
4013
3954
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
4014
3955
  const parsed = parse(cleanContent);
4015
3956
  return parsed?.compilerOptions?.strict === true;
@@ -4032,19 +3973,16 @@ function typescriptDetector(projectPath, packageJson) {
4032
3973
  let configPath;
4033
3974
  let version;
4034
3975
  const deps = collectAllDependencies(pkg);
4035
- // TypeScript package
4036
3976
  if (deps['typescript']) {
4037
3977
  confidence += 50;
4038
3978
  version = parseVersionString(deps['typescript']);
4039
3979
  sources.push({ type: 'package.json', field: 'dependencies.typescript' });
4040
3980
  }
4041
- // tsconfig.json
4042
3981
  if (exists(join$1(projectPath, 'tsconfig.json'))) {
4043
3982
  confidence += 40;
4044
3983
  configPath = 'tsconfig.json';
4045
3984
  sources.push({ type: 'config-file', path: 'tsconfig.json' });
4046
3985
  }
4047
- // tsconfig.*.json variants
4048
3986
  const tsconfigVariants = ['tsconfig.build.json', 'tsconfig.lib.json', 'tsconfig.spec.json', 'tsconfig.app.json'];
4049
3987
  for (const variant of tsconfigVariants) {
4050
3988
  if (exists(join$1(projectPath, variant))) {
@@ -4053,7 +3991,6 @@ function typescriptDetector(projectPath, packageJson) {
4053
3991
  break;
4054
3992
  }
4055
3993
  }
4056
- // @types packages
4057
3994
  const typePackages = keys(deps).filter((d) => d.startsWith('@types/'));
4058
3995
  if (typePackages.length > 0) {
4059
3996
  confidence += 10;
@@ -4087,24 +4024,20 @@ function flowDetector(projectPath, packageJson) {
4087
4024
  let configPath;
4088
4025
  let version;
4089
4026
  const deps = collectAllDependencies(pkg);
4090
- // flow-bin package
4091
4027
  if (deps['flow-bin']) {
4092
4028
  confidence += 60;
4093
4029
  version = parseVersionString(deps['flow-bin']);
4094
4030
  sources.push({ type: 'package.json', field: 'dependencies.flow-bin' });
4095
4031
  }
4096
- // .flowconfig
4097
4032
  if (exists(join$1(projectPath, '.flowconfig'))) {
4098
4033
  confidence += 40;
4099
4034
  configPath = '.flowconfig';
4100
4035
  sources.push({ type: 'config-file', path: '.flowconfig' });
4101
4036
  }
4102
- // flow-typed directory
4103
4037
  if (exists(join$1(projectPath, 'flow-typed'))) {
4104
4038
  confidence += 10;
4105
4039
  sources.push({ type: 'directory', path: 'flow-typed/' });
4106
4040
  }
4107
- // @babel/preset-flow
4108
4041
  if (deps['@babel/preset-flow']) {
4109
4042
  confidence += 10;
4110
4043
  sources.push({ type: 'package.json', field: 'dependencies.@babel/preset-flow' });
@@ -4128,7 +4061,6 @@ function flowDetector(projectPath, packageJson) {
4128
4061
  * @returns `true` if the content contains JSDoc type annotations.
4129
4062
  */
4130
4063
  function hasJsDocTypes(content) {
4131
- // Check for JSDoc type annotations
4132
4064
  return (content.includes('@type {') ||
4133
4065
  content.includes('@param {') ||
4134
4066
  content.includes('@returns {') ||
@@ -4147,14 +4079,11 @@ function jsdocDetector(projectPath, packageJson) {
4147
4079
  const sources = [];
4148
4080
  let confidence = 0;
4149
4081
  const deps = collectAllDependencies(pkg);
4150
- // jsdoc package
4151
4082
  if (deps['jsdoc']) {
4152
4083
  confidence += 30;
4153
4084
  sources.push({ type: 'package.json', field: 'dependencies.jsdoc' });
4154
4085
  }
4155
- // typescript with checkJs (JSDoc type checking)
4156
4086
  if (deps['typescript']) {
4157
- // Check if checkJs is enabled in tsconfig
4158
4087
  const tsconfigPath = join$1(projectPath, 'tsconfig.json');
4159
4088
  const content = readFileIfExists(tsconfigPath);
4160
4089
  if (content) {
@@ -4171,12 +4100,10 @@ function jsdocDetector(projectPath, packageJson) {
4171
4100
  }
4172
4101
  }
4173
4102
  }
4174
- // Check for jsconfig.json (VS Code JS type checking)
4175
4103
  if (exists(join$1(projectPath, 'jsconfig.json'))) {
4176
4104
  confidence += 40;
4177
4105
  sources.push({ type: 'config-file', path: 'jsconfig.json' });
4178
4106
  }
4179
- // Sample check for JSDoc annotations in source files
4180
4107
  const srcDir = join$1(projectPath, 'src');
4181
4108
  if (exists(srcDir)) {
4182
4109
  try {
@@ -4227,8 +4154,6 @@ const detectAllCache = createCache({ ttl: 60000, maxSize: 50 });
4227
4154
  function isDetectAllOptions(value) {
4228
4155
  if (typeof value !== 'object' || value === null)
4229
4156
  return false;
4230
- // DetectAllOptions has skipCache or packageJson fields specifically
4231
- // PackageJson never has skipCache field
4232
4157
  return 'skipCache' in value || 'packageJson' in value;
4233
4158
  }
4234
4159
  /**
@@ -4260,9 +4185,7 @@ function isDetectAllOptions(value) {
4260
4185
  * ```
4261
4186
  */
4262
4187
  function detectAll(projectPath, packageJsonOrOptions) {
4263
- // Handle backward-compatible arguments
4264
4188
  const options = isDetectAllOptions(packageJsonOrOptions) ? packageJsonOrOptions : { packageJson: packageJsonOrOptions };
4265
- // Check cache first (unless skipCache is true)
4266
4189
  if (!options.skipCache) {
4267
4190
  const cached = detectAllCache.get(projectPath);
4268
4191
  if (cached) {
@@ -4313,7 +4236,6 @@ function detectAll(projectPath, packageJsonOrOptions) {
4313
4236
  legacyFrameworks: result.legacyFrameworks.map((f) => f.id),
4314
4237
  testingFrameworks: result.testingFrameworks.map((f) => f.id),
4315
4238
  });
4316
- // Cache the result
4317
4239
  detectAllCache.set(projectPath, result);
4318
4240
  return result;
4319
4241
  }
@@ -4585,7 +4507,6 @@ createScopedLogger('project-scope:nx:config');
4585
4507
  * Known configuration file patterns organized by type.
4586
4508
  */
4587
4509
  const CONFIG_PATTERNS = {
4588
- // Package Management
4589
4510
  'package.json': {
4590
4511
  patterns: ['package.json'],
4591
4512
  format: 'json',
@@ -4612,14 +4533,12 @@ const CONFIG_PATTERNS = {
4612
4533
  description: 'NPM configuration',
4613
4534
  sensitive: true,
4614
4535
  },
4615
- // TypeScript
4616
4536
  tsconfig: {
4617
4537
  patterns: ['tsconfig.json', 'tsconfig.*.json'],
4618
4538
  format: 'jsonc',
4619
4539
  description: 'TypeScript configuration',
4620
4540
  canExtend: true,
4621
4541
  },
4622
- // Monorepo
4623
4542
  nx: {
4624
4543
  patterns: ['nx.json'],
4625
4544
  format: 'json',
@@ -4645,7 +4564,6 @@ const CONFIG_PATTERNS = {
4645
4564
  format: 'json',
4646
4565
  description: 'Lerna configuration',
4647
4566
  },
4648
- // Build Tools
4649
4567
  webpack: {
4650
4568
  patterns: ['webpack.config.js', 'webpack.config.ts', 'webpack.config.cjs', 'webpack.config.mjs'],
4651
4569
  format: 'js',
@@ -4676,7 +4594,6 @@ const CONFIG_PATTERNS = {
4676
4594
  format: 'json',
4677
4595
  description: 'SWC configuration',
4678
4596
  },
4679
- // Testing
4680
4597
  jest: {
4681
4598
  patterns: ['jest.config.js', 'jest.config.ts', 'jest.config.mjs'],
4682
4599
  description: 'Jest configuration',
@@ -4693,7 +4610,6 @@ const CONFIG_PATTERNS = {
4693
4610
  patterns: ['playwright.config.js', 'playwright.config.ts'],
4694
4611
  description: 'Playwright configuration',
4695
4612
  },
4696
- // Framework configs
4697
4613
  next: {
4698
4614
  patterns: ['next.config.js', 'next.config.mjs', 'next.config.ts'],
4699
4615
  format: 'js',
@@ -4719,7 +4635,6 @@ const CONFIG_PATTERNS = {
4719
4635
  format: 'js',
4720
4636
  description: 'Astro configuration',
4721
4637
  },
4722
- // Linting & Formatting
4723
4638
  eslint: {
4724
4639
  patterns: [
4725
4640
  'eslint.config.js',
@@ -4738,14 +4653,12 @@ const CONFIG_PATTERNS = {
4738
4653
  format: 'json',
4739
4654
  description: 'Prettier configuration',
4740
4655
  },
4741
- // Environment (sensitive)
4742
4656
  env: {
4743
4657
  patterns: ['.env', '.env.*', '*.env'],
4744
4658
  format: 'dotenv',
4745
4659
  description: 'Environment variables',
4746
4660
  sensitive: true,
4747
4661
  },
4748
- // Git
4749
4662
  '.gitignore': {
4750
4663
  patterns: ['.gitignore'],
4751
4664
  format: 'text',
@@ -4860,12 +4773,8 @@ function detectConfigs(rootPath, types, options) {
4860
4773
  *
4861
4774
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/number
4862
4775
  */
4863
- // Capture references at module initialization time
4864
4776
  const _parseInt = globalThis.parseInt;
4865
4777
  const _parseFloat = globalThis.parseFloat;
4866
- // ============================================================================
4867
- // Parsing
4868
- // ============================================================================
4869
4778
  /**
4870
4779
  * (Safe copy) Parses a string and returns an integer.
4871
4780
  */
@@ -5193,11 +5102,9 @@ const analyzeLogger = createScopedLogger('project-scope:analyze');
5193
5102
  * @returns Detected workspace type
5194
5103
  */
5195
5104
  function detectWorkspaceType(projectPath) {
5196
- // Check for NX
5197
5105
  if (isNxWorkspace(projectPath) || findNxWorkspaceRoot(projectPath) !== null) {
5198
5106
  return 'nx';
5199
5107
  }
5200
- // Check for common monorepo markers
5201
5108
  if (exists(resolve(projectPath, 'turbo.json'))) {
5202
5109
  return 'turborepo';
5203
5110
  }
@@ -5207,7 +5114,6 @@ function detectWorkspaceType(projectPath) {
5207
5114
  if (exists(resolve(projectPath, 'pnpm-workspace.yaml'))) {
5208
5115
  return 'pnpm';
5209
5116
  }
5210
- // Check package.json for workspaces
5211
5117
  const pkg = readPackageJsonIfExists(projectPath);
5212
5118
  if (pkg?.workspaces) {
5213
5119
  if (exists(resolve(projectPath, 'yarn.lock'))) {
@@ -5216,7 +5122,7 @@ function detectWorkspaceType(projectPath) {
5216
5122
  if (exists(resolve(projectPath, 'package-lock.json'))) {
5217
5123
  return 'npm';
5218
5124
  }
5219
- return 'npm'; // default for workspaces
5125
+ return 'npm';
5220
5126
  }
5221
5127
  return 'standalone';
5222
5128
  }
@@ -5228,15 +5134,12 @@ function detectWorkspaceType(projectPath) {
5228
5134
  * @returns True if the analysis should be performed
5229
5135
  */
5230
5136
  function shouldInclude(type, options) {
5231
- // If include list is specified, item must be in it
5232
5137
  if (options?.include && options.include.length > 0) {
5233
5138
  return options.include.includes(type);
5234
5139
  }
5235
- // If exclude list is specified, item must not be in it
5236
5140
  if (options?.exclude && options.exclude.length > 0) {
5237
5141
  return !options.exclude.includes(type);
5238
5142
  }
5239
- // Default: include everything
5240
5143
  return true;
5241
5144
  }
5242
5145
  /**
@@ -5285,28 +5188,22 @@ function normalizeConfigFormat(format) {
5285
5188
  function analyzeProject(projectPath, options) {
5286
5189
  const startTime = dateNow();
5287
5190
  const resolvedPath = resolve(projectPath);
5288
- // Set log level based on verbose option
5289
5191
  if (options?.verbose) {
5290
5192
  analyzeLogger.setLogLevel('debug');
5291
5193
  }
5292
5194
  analyzeLogger.debug('Starting project analysis', { path: resolvedPath, options });
5293
- // Read package.json once for reuse
5294
5195
  const packageJson = readPackageJsonIfExists(resolvedPath);
5295
5196
  analyzeLogger.debug('Package.json loaded', { found: !!packageJson, name: packageJson?.name });
5296
- // Detect project and workspace types
5297
5197
  const projectTypeDetection = detectProjectType(resolvedPath, {
5298
5198
  skipTechDetection: options?.depth === 'basic',
5299
5199
  });
5300
5200
  const projectType = projectTypeDetection.type;
5301
5201
  const workspaceType = detectWorkspaceType(resolvedPath);
5302
5202
  analyzeLogger.debug('Project type detected', { projectType, workspaceType });
5303
- // Get project name from package.json or directory name
5304
5203
  const projectName = packageJson?.name ?? basename(resolvedPath);
5305
- // Run all technology detectors
5306
5204
  const detections = shouldInclude('frameworks', options) || shouldInclude('buildTools', options) || shouldInclude('testing', options)
5307
5205
  ? detectAll(resolvedPath, packageJson ?? undefined)
5308
5206
  : null;
5309
- // Convert framework detections to FrameworkInfo
5310
5207
  const frameworks = shouldInclude('frameworks', options) && detections
5311
5208
  ? [
5312
5209
  ...detections.frontendFrameworks.map((d) => ({
@@ -5326,7 +5223,6 @@ function analyzeProject(projectPath, options) {
5326
5223
  })),
5327
5224
  ]
5328
5225
  : [];
5329
- // Convert build tool detections
5330
5226
  const buildTools = shouldInclude('buildTools', options) && detections
5331
5227
  ? detections.buildTools.map((d) => ({
5332
5228
  id: d.id,
@@ -5336,7 +5232,6 @@ function analyzeProject(projectPath, options) {
5336
5232
  confidence: d.confidence,
5337
5233
  }))
5338
5234
  : [];
5339
- // Convert testing framework detections
5340
5235
  const testingFrameworks = shouldInclude('testing', options) && detections
5341
5236
  ? detections.testingFrameworks.map((d) => ({
5342
5237
  id: d.id,
@@ -5347,7 +5242,6 @@ function analyzeProject(projectPath, options) {
5347
5242
  confidence: d.confidence,
5348
5243
  }))
5349
5244
  : [];
5350
- // Discover entry points
5351
5245
  const entryPoints = shouldInclude('entryPoints', options)
5352
5246
  ? discoverEntryPoints(resolvedPath).map((e) => ({
5353
5247
  path: e.path,
@@ -5355,7 +5249,6 @@ function analyzeProject(projectPath, options) {
5355
5249
  confidence: e.confidence,
5356
5250
  }))
5357
5251
  : [];
5358
- // Detect configuration files
5359
5252
  const configFiles = shouldInclude('configs', options)
5360
5253
  ? detectConfigs(resolvedPath).map((c) => ({
5361
5254
  path: c.path,
@@ -5364,7 +5257,6 @@ function analyzeProject(projectPath, options) {
5364
5257
  tool: c.type,
5365
5258
  }))
5366
5259
  : [];
5367
- // Get dependency summary
5368
5260
  let dependencies;
5369
5261
  if (shouldInclude('dependencies', options)) {
5370
5262
  const deps = getProjectDependencies(resolvedPath);
@@ -5385,7 +5277,6 @@ function analyzeProject(projectPath, options) {
5385
5277
  total: 0,
5386
5278
  };
5387
5279
  }
5388
- // Build metadata
5389
5280
  const metadata = {
5390
5281
  timestamp: createDate(),
5391
5282
  durationMs: dateNow() - startTime,
@@ -5460,15 +5351,12 @@ function formatWorkspaceType(type) {
5460
5351
  */
5461
5352
  function formatAnalysisText(result) {
5462
5353
  const lines = [];
5463
- // Header
5464
5354
  lines.push(`Project Analysis: ${result.name}`);
5465
5355
  lines.push('='.repeat(30));
5466
5356
  lines.push('');
5467
- // Basic info
5468
5357
  lines.push(`Type: ${formatProjectType(result.projectType)}`);
5469
5358
  lines.push(`Workspace: ${formatWorkspaceType(result.workspaceType)}`);
5470
5359
  lines.push('');
5471
- // Frameworks
5472
5360
  if (result.frameworks.length > 0) {
5473
5361
  lines.push('Frameworks:');
5474
5362
  for (const framework of result.frameworks) {
@@ -5482,7 +5370,6 @@ function formatAnalysisText(result) {
5482
5370
  }
5483
5371
  lines.push('');
5484
5372
  }
5485
- // Build tools
5486
5373
  if (result.buildTools.length > 0) {
5487
5374
  lines.push('Build Tools:');
5488
5375
  for (const tool of result.buildTools) {
@@ -5491,7 +5378,6 @@ function formatAnalysisText(result) {
5491
5378
  }
5492
5379
  lines.push('');
5493
5380
  }
5494
- // Testing
5495
5381
  if (result.testingFrameworks.length > 0) {
5496
5382
  lines.push('Testing:');
5497
5383
  for (const framework of result.testingFrameworks) {
@@ -5500,7 +5386,6 @@ function formatAnalysisText(result) {
5500
5386
  }
5501
5387
  lines.push('');
5502
5388
  }
5503
- // Entry points
5504
5389
  if (result.entryPoints.length > 0) {
5505
5390
  lines.push('Entry Points:');
5506
5391
  for (const entry of result.entryPoints.slice(0, 5)) {
@@ -5511,7 +5396,6 @@ function formatAnalysisText(result) {
5511
5396
  }
5512
5397
  lines.push('');
5513
5398
  }
5514
- // Configurations
5515
5399
  if (result.configFiles.length > 0) {
5516
5400
  lines.push('Configurations:');
5517
5401
  for (const config of result.configFiles.slice(0, 8)) {
@@ -5522,7 +5406,6 @@ function formatAnalysisText(result) {
5522
5406
  }
5523
5407
  lines.push('');
5524
5408
  }
5525
- // Dependencies summary
5526
5409
  lines.push('Dependencies:');
5527
5410
  lines.push(` Production: ${result.dependencies.production}`);
5528
5411
  lines.push(` Development: ${result.dependencies.development}`);
@@ -5609,7 +5492,7 @@ function parseAnalyzeArgs(args) {
5609
5492
  exclude: { type: 'string', short: 'e' },
5610
5493
  },
5611
5494
  allowPositionals: true,
5612
- strict: false, // Allow global options to pass through
5495
+ strict: false,
5613
5496
  });
5614
5497
  const format = values.format;
5615
5498
  const depth = values.depth;
@@ -5668,7 +5551,6 @@ const analyzeCommandDef = {
5668
5551
  description: 'Analyze project structure and tech stack',
5669
5552
  execute(args, globalOptions) {
5670
5553
  const options = parseAnalyzeArgs(args);
5671
- // Global --json flag overrides format
5672
5554
  if (globalOptions.json) {
5673
5555
  options.format = 'json';
5674
5556
  }
@@ -5975,12 +5857,10 @@ Examples:
5975
5857
  function formatDependencyList(deps, maxItems = 20) {
5976
5858
  const lines = [];
5977
5859
  const depEntries = entries(deps);
5978
- // Sort alphabetically
5979
5860
  depEntries.sort((a, b) => a[0].localeCompare(b[0]));
5980
5861
  const displayCount = min(depEntries.length, maxItems);
5981
5862
  for (let i = 0; i < displayCount; i++) {
5982
5863
  const [name, version] = depEntries[i];
5983
- // Pad name to align versions
5984
5864
  const paddedName = name.padEnd(30);
5985
5865
  lines.push(` ${paddedName} ${version}`);
5986
5866
  }
@@ -6223,13 +6103,10 @@ function buildTree(rootPath, walkEntries, options) {
6223
6103
  isDirectory: true,
6224
6104
  children: [],
6225
6105
  };
6226
- // Create a map for quick lookup
6227
6106
  const nodeMap = createMap();
6228
6107
  nodeMap.set('.', root);
6229
- // Sort entries by path for proper parent-child relationships
6230
6108
  const sortedEntries = [...walkEntries].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
6231
6109
  for (const entry of sortedEntries) {
6232
- // Skip based on filters
6233
6110
  if (options.dirsOnly && !entry.isDirectory)
6234
6111
  continue;
6235
6112
  if (options.filesOnly && entry.isDirectory)
@@ -6240,7 +6117,6 @@ function buildTree(rootPath, walkEntries, options) {
6240
6117
  isDirectory: entry.isDirectory,
6241
6118
  children: [],
6242
6119
  };
6243
- // Add size/modified if requested
6244
6120
  if ((options.showSize || options.showModified) && entry.isFile) {
6245
6121
  const stats = getFileStat(entry.path);
6246
6122
  if (stats) {
@@ -6250,9 +6126,8 @@ function buildTree(rootPath, walkEntries, options) {
6250
6126
  node.modified = stats.modified;
6251
6127
  }
6252
6128
  }
6253
- // Find parent
6254
6129
  const parts = entry.relativePath.split('/');
6255
- parts.pop(); // Remove current entry name
6130
+ parts.pop();
6256
6131
  const parentPath = parts.join('/') || '.';
6257
6132
  const parent = nodeMap.get(parentPath);
6258
6133
  if (parent) {
@@ -6273,11 +6148,9 @@ function buildTree(rootPath, walkEntries, options) {
6273
6148
  */
6274
6149
  function renderTreeText(node, options, prefix = '', isLast = true) {
6275
6150
  const lines = [];
6276
- // Current line
6277
6151
  const connector = isLast ? '└── ' : '├── ';
6278
6152
  const dirMark = node.isDirectory ? '/' : '';
6279
6153
  let line = `${prefix}${connector}${node.name}${dirMark}`;
6280
- // Add size/modified
6281
6154
  const meta = [];
6282
6155
  if (options.showSize && node.size !== undefined) {
6283
6156
  meta.push(formatSize(node.size));
@@ -6289,10 +6162,8 @@ function renderTreeText(node, options, prefix = '', isLast = true) {
6289
6162
  line += ` [${meta.join(' ')}]`;
6290
6163
  }
6291
6164
  lines.push(line);
6292
- // Process children
6293
6165
  const childPrefix = prefix + (isLast ? ' ' : '│ ');
6294
6166
  const sortedChildren = [...node.children].sort((a, b) => {
6295
- // Directories first, then alphabetically
6296
6167
  if (a.isDirectory && !b.isDirectory)
6297
6168
  return -1;
6298
6169
  if (!a.isDirectory && b.isDirectory)
@@ -6316,9 +6187,7 @@ function renderTreeText(node, options, prefix = '', isLast = true) {
6316
6187
  */
6317
6188
  function formatTreeText(rootPath, tree, options) {
6318
6189
  const lines = [];
6319
- // Root line
6320
6190
  lines.push(basename(rootPath));
6321
- // Count stats
6322
6191
  let dirCount = 0;
6323
6192
  let fileCount = 0;
6324
6193
  /**
@@ -6337,7 +6206,6 @@ function formatTreeText(rootPath, tree, options) {
6337
6206
  countNodes(child);
6338
6207
  }
6339
6208
  }
6340
- // Render children of root
6341
6209
  const sortedChildren = [...tree.children].sort((a, b) => {
6342
6210
  if (a.isDirectory && !b.isDirectory)
6343
6211
  return -1;
@@ -6351,7 +6219,6 @@ function formatTreeText(rootPath, tree, options) {
6351
6219
  lines.push(...renderTreeText(child, options, '', isLast));
6352
6220
  countNodes(child);
6353
6221
  }
6354
- // Summary
6355
6222
  lines.push('');
6356
6223
  const dirText = dirCount === 1 ? '1 directory' : `${dirCount} directories`;
6357
6224
  const fileText = fileCount === 1 ? '1 file' : `${fileCount} files`;
@@ -6412,7 +6279,6 @@ function parseTreeArgs(args) {
6412
6279
  function treeCommand(options) {
6413
6280
  const rootPath = options.path ? resolve(options.path) : process.cwd();
6414
6281
  try {
6415
- // Collect entries via walk
6416
6282
  const walkEntries = [];
6417
6283
  walkDirectory(rootPath, (entry) => {
6418
6284
  walkEntries.push(entry);
@@ -6422,9 +6288,7 @@ function treeCommand(options) {
6422
6288
  ignorePatterns: options.ignore,
6423
6289
  includeHidden: false,
6424
6290
  });
6425
- // Build tree structure
6426
6291
  const tree = buildTree(rootPath, walkEntries, options);
6427
- // Format output
6428
6292
  let output;
6429
6293
  if (options.format === 'json') {
6430
6294
  output = formatTreeJson(tree);
@@ -6483,6 +6347,9 @@ Examples:
6483
6347
 
6484
6348
  /** Logger for CLI operations */
6485
6349
  const cliLogger = createScopedLogger('project-scope:cli');
6350
+ /** Output printer for user-facing CLI output (help, version, command results). */
6351
+ const output = createLogger(error, undefined, log);
6352
+ output.setLogLevel('log');
6486
6353
  /** Library version */
6487
6354
  const VERSION = '0.1.0';
6488
6355
  /**
@@ -6498,7 +6365,7 @@ const commands = {
6498
6365
  * Print general help information.
6499
6366
  */
6500
6367
  function printHelp() {
6501
- log(`
6368
+ output.log(`
6502
6369
  project-scope <command> [options]
6503
6370
 
6504
6371
  A tool for analyzing JavaScript/TypeScript project structure and tech stack.
@@ -6530,7 +6397,7 @@ Examples:
6530
6397
  * Print CLI version.
6531
6398
  */
6532
6399
  function printVersion() {
6533
- log(`project-scope v${VERSION}`);
6400
+ output.log(`project-scope v${VERSION}`);
6534
6401
  }
6535
6402
  /**
6536
6403
  * Parse global options from command line arguments.
@@ -6591,24 +6458,24 @@ function run(args) {
6591
6458
  setGlobalLogLevel('debug');
6592
6459
  }
6593
6460
  cliLogger.debug('CLI invoked', { args, globalOptions });
6461
+ const commandName = args[0];
6594
6462
  if (globalOptions.version) {
6595
6463
  printVersion();
6596
6464
  return { exitCode: 0 };
6597
6465
  }
6598
- if (globalOptions.help && (args.length === 1 || !commands[args[0]])) {
6466
+ if (globalOptions.help && (args.length === 1 || !commands[commandName])) {
6599
6467
  printHelp();
6600
6468
  return { exitCode: 0 };
6601
6469
  }
6602
- const commandName = args[0];
6603
6470
  const command = commands[commandName];
6604
6471
  if (!command) {
6605
6472
  cliLogger.warn('Unknown command requested', { commandName });
6606
- error(`Unknown command: ${commandName}`);
6607
- error('Run "project-scope --help" for usage information.');
6473
+ output.error(`Unknown command: ${commandName}`);
6474
+ output.error('Run "project-scope --help" for usage information.');
6608
6475
  return { exitCode: 1, error: `Unknown command: ${commandName}` };
6609
6476
  }
6610
6477
  if (globalOptions.help) {
6611
- log(command.getHelp());
6478
+ output.log(command.getHelp());
6612
6479
  return { exitCode: 0 };
6613
6480
  }
6614
6481
  const commandArgs = args.slice(1);
@@ -6616,11 +6483,11 @@ function run(args) {
6616
6483
  const result = command.execute(commandArgs, globalOptions);
6617
6484
  cliLogger.debug('Command completed', { commandName, exitCode: result.exitCode });
6618
6485
  if (result.output) {
6619
- log(result.output);
6486
+ output.log(result.output);
6620
6487
  }
6621
6488
  if (result.error) {
6622
6489
  cliLogger.error('Command error', { commandName, error: result.error });
6623
- error(result.error);
6490
+ output.error(result.error);
6624
6491
  }
6625
6492
  return result;
6626
6493
  }