@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.cjs.js CHANGED
@@ -12,7 +12,6 @@ var node_fs = require('node:fs');
12
12
  *
13
13
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/console
14
14
  */
15
- // Capture references at module initialization time
16
15
  const _console = globalThis.console;
17
16
  /**
18
17
  * (Safe copy) Outputs a message to the console.
@@ -87,40 +86,6 @@ _console.timeEnd.bind(_console);
87
86
  */
88
87
  _console.timeLog.bind(_console);
89
88
 
90
- /**
91
- * Safe copies of Array built-in static methods.
92
- *
93
- * These references are captured at module initialization time to protect against
94
- * prototype pollution attacks. Import only what you need for tree-shaking.
95
- *
96
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
97
- */
98
- // Capture references at module initialization time
99
- const _Array = globalThis.Array;
100
- /**
101
- * (Safe copy) Determines whether the passed value is an Array.
102
- */
103
- const isArray = _Array.isArray;
104
-
105
- /**
106
- * Safe copies of JSON built-in methods.
107
- *
108
- * These references are captured at module initialization time to protect against
109
- * prototype pollution attacks. Import only what you need for tree-shaking.
110
- *
111
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
112
- */
113
- // Capture references at module initialization time
114
- const _JSON = globalThis.JSON;
115
- /**
116
- * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
117
- */
118
- const parse = _JSON.parse;
119
- /**
120
- * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
121
- */
122
- const stringify = _JSON.stringify;
123
-
124
89
  /**
125
90
  * Safe copies of Object built-in methods.
126
91
  *
@@ -129,7 +94,6 @@ const stringify = _JSON.stringify;
129
94
  *
130
95
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/object
131
96
  */
132
- // Capture references at module initialization time
133
97
  const _Object = globalThis.Object;
134
98
  /**
135
99
  * (Safe copy) Prevents modification of existing property attributes and values,
@@ -153,30 +117,21 @@ const values = _Object.values;
153
117
  */
154
118
  const defineProperties = _Object.defineProperties;
155
119
 
120
+ const registeredClasses = [];
121
+
156
122
  /**
157
- * Safe copies of Set built-in via factory function.
158
- *
159
- * Since constructors cannot be safely captured via Object.assign, this module
160
- * provides a factory function that uses Reflect.construct internally.
123
+ * Safe copies of Array built-in static methods.
161
124
  *
162
125
  * These references are captured at module initialization time to protect against
163
126
  * prototype pollution attacks. Import only what you need for tree-shaking.
164
127
  *
165
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
128
+ * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
166
129
  */
167
- // Capture references at module initialization time
168
- const _Set = globalThis.Set;
169
- const _Reflect$3 = globalThis.Reflect;
130
+ const _Array = globalThis.Array;
170
131
  /**
171
- * (Safe copy) Creates a new Set using the captured Set constructor.
172
- * Use this instead of `new Set()`.
173
- *
174
- * @param iterable - Optional iterable of values.
175
- * @returns A new Set instance.
132
+ * (Safe copy) Determines whether the passed value is an Array.
176
133
  */
177
- const createSet = (iterable) => _Reflect$3.construct(_Set, iterable ? [iterable] : []);
178
-
179
- const registeredClasses = [];
134
+ const isArray = _Array.isArray;
180
135
 
181
136
  /**
182
137
  * Returns the data type of the target.
@@ -212,9 +167,8 @@ const getType = (target) => {
212
167
  *
213
168
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/error
214
169
  */
215
- // Capture references at module initialization time
216
170
  const _Error = globalThis.Error;
217
- const _Reflect$2 = globalThis.Reflect;
171
+ const _Reflect$3 = globalThis.Reflect;
218
172
  /**
219
173
  * (Safe copy) Creates a new Error using the captured Error constructor.
220
174
  * Use this instead of `new Error()`.
@@ -223,7 +177,7 @@ const _Reflect$2 = globalThis.Reflect;
223
177
  * @param options - Optional error options.
224
178
  * @returns A new Error instance.
225
179
  */
226
- const createError = (message, options) => _Reflect$2.construct(_Error, [message, options]);
180
+ const createError = (message, options) => _Reflect$3.construct(_Error, [message, options]);
227
181
 
228
182
  /**
229
183
  * Safe copies of Map built-in via factory function.
@@ -236,9 +190,8 @@ const createError = (message, options) => _Reflect$2.construct(_Error, [message,
236
190
  *
237
191
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/map
238
192
  */
239
- // Capture references at module initialization time
240
193
  const _Map = globalThis.Map;
241
- const _Reflect$1 = globalThis.Reflect;
194
+ const _Reflect$2 = globalThis.Reflect;
242
195
  /**
243
196
  * (Safe copy) Creates a new Map using the captured Map constructor.
244
197
  * Use this instead of `new Map()`.
@@ -246,7 +199,7 @@ const _Reflect$1 = globalThis.Reflect;
246
199
  * @param iterable - Optional iterable of key-value pairs.
247
200
  * @returns A new Map instance.
248
201
  */
249
- const createMap = (iterable) => _Reflect$1.construct(_Map, iterable ? [iterable] : []);
202
+ const createMap = (iterable) => _Reflect$2.construct(_Map, iterable ? [iterable] : []);
250
203
 
251
204
  /**
252
205
  * Safe copies of Date built-in via factory function and static methods.
@@ -259,11 +212,10 @@ const createMap = (iterable) => _Reflect$1.construct(_Map, iterable ? [iterable]
259
212
  *
260
213
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/date
261
214
  */
262
- // Capture references at module initialization time
263
215
  const _Date = globalThis.Date;
264
- const _Reflect = globalThis.Reflect;
216
+ const _Reflect$1 = globalThis.Reflect;
265
217
  function createDate(...args) {
266
- return _Reflect.construct(_Date, args);
218
+ return _Reflect$1.construct(_Date, args);
267
219
  }
268
220
  /**
269
221
  * (Safe copy) Returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
@@ -278,7 +230,6 @@ const dateNow = _Date.now;
278
230
  *
279
231
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/math
280
232
  */
281
- // Capture references at module initialization time
282
233
  const _Math = globalThis.Math;
283
234
  /**
284
235
  * (Safe copy) Returns the value of a number rounded to the nearest integer.
@@ -289,6 +240,28 @@ const round = _Math.round;
289
240
  */
290
241
  const min = _Math.min;
291
242
 
243
+ /**
244
+ * Safe copies of Set built-in via factory function.
245
+ *
246
+ * Since constructors cannot be safely captured via Object.assign, this module
247
+ * provides a factory function that uses Reflect.construct internally.
248
+ *
249
+ * These references are captured at module initialization time to protect against
250
+ * prototype pollution attacks. Import only what you need for tree-shaking.
251
+ *
252
+ * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
253
+ */
254
+ const _Set = globalThis.Set;
255
+ const _Reflect = globalThis.Reflect;
256
+ /**
257
+ * (Safe copy) Creates a new Set using the captured Set constructor.
258
+ * Use this instead of `new Set()`.
259
+ *
260
+ * @param iterable - Optional iterable of values.
261
+ * @returns A new Set instance.
262
+ */
263
+ const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
264
+
292
265
  /* eslint-disable @typescript-eslint/no-explicit-any */
293
266
  /**
294
267
  * Creates a wrapper function that only executes the wrapped function if the condition function returns true.
@@ -452,6 +425,24 @@ function notFnMsg(label) {
452
425
 
453
426
  createLogger(error, warn, log, info, debug);
454
427
 
428
+ /**
429
+ * Safe copies of JSON built-in methods.
430
+ *
431
+ * These references are captured at module initialization time to protect against
432
+ * prototype pollution attacks. Import only what you need for tree-shaking.
433
+ *
434
+ * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
435
+ */
436
+ const _JSON = globalThis.JSON;
437
+ /**
438
+ * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
439
+ */
440
+ const parse = _JSON.parse;
441
+ /**
442
+ * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
443
+ */
444
+ const stringify = _JSON.stringify;
445
+
455
446
  /**
456
447
  * Global log level registry.
457
448
  * Tracks all created scoped loggers to allow global log level changes.
@@ -580,14 +571,11 @@ function formatMessage(namespace, message, meta) {
580
571
  */
581
572
  function createScopedLogger(namespace, options = {}) {
582
573
  const { level = 'error', sanitizeSecrets = true } = options;
583
- // Create wrapper functions that add namespace prefix and sanitization
584
574
  const createLogFn = (baseFn) => (message, meta) => {
585
575
  const processedMeta = sanitizeSecrets && meta ? sanitize(meta) : meta;
586
576
  baseFn(formatMessage(namespace, message, processedMeta));
587
577
  };
588
- // Create base logger with wrapped functions
589
578
  const baseLogger = createLogger(createLogFn(error), createLogFn(warn), createLogFn(log), createLogFn(info), createLogFn(debug));
590
- // Set initial log level (use global override if set)
591
579
  baseLogger.setLogLevel(globalLogLevel ?? level);
592
580
  const scopedLogger = freeze({
593
581
  error: (message, meta) => baseLogger.error(message, meta),
@@ -598,7 +586,6 @@ function createScopedLogger(namespace, options = {}) {
598
586
  setLogLevel: baseLogger.setLogLevel,
599
587
  getLogLevel: baseLogger.getLogLevel,
600
588
  });
601
- // Register logger for global level management
602
589
  loggerRegistry.add(scopedLogger);
603
590
  return scopedLogger;
604
591
  }
@@ -811,7 +798,6 @@ function traverseUpward(startPath, predicate) {
811
798
  }
812
799
  currentPath = node_path.dirname(currentPath);
813
800
  }
814
- // Check root directory
815
801
  if (predicate(rootPath)) {
816
802
  fsTraversalLogger.debug('Upward traversal found match at root', { startPath, foundPath: rootPath });
817
803
  return rootPath;
@@ -1074,7 +1060,6 @@ const cacheRegistry = createSet();
1074
1060
  function createCache(options) {
1075
1061
  const { ttl, maxSize } = options ?? {};
1076
1062
  const store = createMap();
1077
- // Track insertion order for FIFO eviction
1078
1063
  const insertionOrder = [];
1079
1064
  /**
1080
1065
  * Check if an entry is expired.
@@ -1125,12 +1110,10 @@ function createCache(options) {
1125
1110
  return entry.value;
1126
1111
  },
1127
1112
  set(key, value) {
1128
- // If key exists, remove from order first
1129
1113
  if (store.has(key)) {
1130
1114
  removeFromOrder(key);
1131
1115
  }
1132
1116
  else {
1133
- // Evict if needed before adding new entry
1134
1117
  evictIfNeeded();
1135
1118
  }
1136
1119
  // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
@@ -1163,15 +1146,10 @@ function createCache(options) {
1163
1146
  return [...insertionOrder];
1164
1147
  },
1165
1148
  };
1166
- // Register cache for global operations
1167
1149
  cacheRegistry.add(cache);
1168
1150
  return freeze(cache);
1169
1151
  }
1170
1152
 
1171
- /**
1172
- * Pattern matching utilities with ReDoS protection.
1173
- * Uses character-by-character matching instead of regex where possible.
1174
- */
1175
1153
  /**
1176
1154
  * Match path against glob pattern using safe character iteration.
1177
1155
  * Avoids regex to prevent ReDoS attacks.
@@ -1209,17 +1187,14 @@ function matchGlobPattern(path, pattern) {
1209
1187
  * @returns True if remaining segments match
1210
1188
  */
1211
1189
  function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
1212
- // Base cases
1213
1190
  if (pathIdx === pathParts.length && patternIdx === patternParts.length) {
1214
- return true; // Both exhausted = match
1191
+ return true;
1215
1192
  }
1216
1193
  if (patternIdx >= patternParts.length) {
1217
- return false; // Pattern exhausted but path remains
1194
+ return false;
1218
1195
  }
1219
1196
  const patternPart = patternParts[patternIdx];
1220
- // Handle ** (globstar) - matches zero or more directories
1221
1197
  if (patternPart === '**') {
1222
- // Try matching rest of pattern against current position and all future positions
1223
1198
  for (let i = pathIdx; i <= pathParts.length; i++) {
1224
1199
  if (matchSegments(pathParts, patternParts, i, patternIdx + 1)) {
1225
1200
  return true;
@@ -1228,10 +1203,9 @@ function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
1228
1203
  return false;
1229
1204
  }
1230
1205
  if (pathIdx >= pathParts.length) {
1231
- return false; // Path exhausted but pattern remains (and it's not **)
1206
+ return false;
1232
1207
  }
1233
1208
  const pathPart = pathParts[pathIdx];
1234
- // Match current segment
1235
1209
  if (matchSegment(pathPart, patternPart)) {
1236
1210
  return matchSegments(pathParts, patternParts, pathIdx + 1, patternIdx + 1);
1237
1211
  }
@@ -1251,12 +1225,10 @@ function matchSegment(text, pattern) {
1251
1225
  while (patternIdx < pattern.length) {
1252
1226
  const char = pattern[patternIdx];
1253
1227
  if (char === '*') {
1254
- // * matches zero or more characters
1255
1228
  patternIdx++;
1256
1229
  if (patternIdx === pattern.length) {
1257
- return true; // * at end matches rest of string
1230
+ return true;
1258
1231
  }
1259
- // Try matching rest of pattern at each position in text
1260
1232
  for (let i = textIdx; i <= text.length; i++) {
1261
1233
  if (matchSegmentFrom(text, i, pattern, patternIdx)) {
1262
1234
  return true;
@@ -1265,7 +1237,6 @@ function matchSegment(text, pattern) {
1265
1237
  return false;
1266
1238
  }
1267
1239
  else if (char === '?') {
1268
- // ? matches exactly one character
1269
1240
  if (textIdx >= text.length) {
1270
1241
  return false;
1271
1242
  }
@@ -1273,10 +1244,8 @@ function matchSegment(text, pattern) {
1273
1244
  patternIdx++;
1274
1245
  }
1275
1246
  else if (char === '{') {
1276
- // {a,b,c} matches any alternative
1277
1247
  const closeIdx = findClosingBrace(pattern, patternIdx);
1278
1248
  if (closeIdx === -1) {
1279
- // Unmatched brace, treat as literal
1280
1249
  if (textIdx >= text.length || text[textIdx] !== char) {
1281
1250
  return false;
1282
1251
  }
@@ -1294,7 +1263,6 @@ function matchSegment(text, pattern) {
1294
1263
  }
1295
1264
  }
1296
1265
  else {
1297
- // Literal character
1298
1266
  if (textIdx >= text.length || text[textIdx] !== char) {
1299
1267
  return false;
1300
1268
  }
@@ -1842,7 +1810,6 @@ function collectAllDependencies(packageJson) {
1842
1810
  function parseVersionString(versionString) {
1843
1811
  if (versionString === undefined || versionString === null)
1844
1812
  return undefined;
1845
- // Manual parsing instead of regex to avoid ReDoS
1846
1813
  let start = 0;
1847
1814
  while (start < versionString.length) {
1848
1815
  const char = versionString[start];
@@ -1903,7 +1870,6 @@ function expressDetector(projectPath, packageJson) {
1903
1870
  version = parseVersionString(deps['express']);
1904
1871
  sources.push({ type: 'package.json', field: 'dependencies.express' });
1905
1872
  }
1906
- // @types/express (indicates usage)
1907
1873
  if (deps['@types/express']) {
1908
1874
  confidence += 10;
1909
1875
  sources.push({ type: 'package.json', field: 'dependencies.@types/express' });
@@ -1939,13 +1905,11 @@ function nestDetector(projectPath, packageJson) {
1939
1905
  let version;
1940
1906
  let configPath;
1941
1907
  const deps = collectAllDependencies(pkg);
1942
- // @nestjs/core package
1943
1908
  if (deps['@nestjs/core']) {
1944
1909
  confidence += 70;
1945
1910
  version = parseVersionString(deps['@nestjs/core']);
1946
1911
  sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1947
1912
  }
1948
- // @nestjs/common
1949
1913
  if (deps['@nestjs/common']) {
1950
1914
  confidence += 15;
1951
1915
  sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
@@ -1996,7 +1960,6 @@ function fastifyDetector(projectPath, packageJson) {
1996
1960
  confidence += 15;
1997
1961
  sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1998
1962
  }
1999
- // @types/fastify (older versions)
2000
1963
  if (deps['@types/fastify']) {
2001
1964
  confidence += 5;
2002
1965
  sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
@@ -2031,7 +1994,6 @@ function koaDetector(projectPath, packageJson) {
2031
1994
  version = parseVersionString(deps['koa']);
2032
1995
  sources.push({ type: 'package.json', field: 'dependencies.koa' });
2033
1996
  }
2034
- // @types/koa
2035
1997
  if (deps['@types/koa']) {
2036
1998
  confidence += 10;
2037
1999
  sources.push({ type: 'package.json', field: 'dependencies.@types/koa' });
@@ -2574,7 +2536,6 @@ function remixDetector(projectPath, packageJson) {
2574
2536
  let confidence = 0;
2575
2537
  let version;
2576
2538
  const deps = collectAllDependencies(pkg);
2577
- // @remix-run packages
2578
2539
  if (deps['@remix-run/react']) {
2579
2540
  confidence += 70;
2580
2541
  version = parseVersionString(deps['@remix-run/react']);
@@ -2850,7 +2811,6 @@ function sveltekitDetector(projectPath, packageJson) {
2850
2811
  let confidence = 0;
2851
2812
  let version;
2852
2813
  const deps = collectAllDependencies(pkg);
2853
- // @sveltejs/kit package
2854
2814
  if (deps['@sveltejs/kit']) {
2855
2815
  confidence += 70;
2856
2816
  version = parseVersionString(deps['@sveltejs/kit']);
@@ -2929,13 +2889,11 @@ function qwikDetector(projectPath, packageJson) {
2929
2889
  let confidence = 0;
2930
2890
  let version;
2931
2891
  const deps = collectAllDependencies(pkg);
2932
- // @builder.io/qwik package
2933
2892
  if (deps['@builder.io/qwik']) {
2934
2893
  confidence += 70;
2935
2894
  version = parseVersionString(deps['@builder.io/qwik']);
2936
2895
  sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
2937
2896
  }
2938
- // @builder.io/qwik-city
2939
2897
  if (deps['@builder.io/qwik-city']) {
2940
2898
  confidence += 20;
2941
2899
  sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
@@ -3028,23 +2986,19 @@ function angularJSDetector(projectPath, packageJson) {
3028
2986
  let confidence = 0;
3029
2987
  let version;
3030
2988
  const deps = collectAllDependencies(pkg);
3031
- // AngularJS package (angular, not @angular/core)
3032
2989
  if (deps['angular']) {
3033
2990
  confidence += 70;
3034
2991
  version = parseVersionString(deps['angular']);
3035
2992
  sources.push({ type: 'package.json', field: 'dependencies.angular' });
3036
2993
  }
3037
- // AngularJS router
3038
2994
  if (deps['angular-route']) {
3039
2995
  confidence += 15;
3040
2996
  sources.push({ type: 'package.json', field: 'dependencies.angular-route' });
3041
2997
  }
3042
- // AngularJS resource
3043
2998
  if (deps['angular-resource']) {
3044
2999
  confidence += 10;
3045
3000
  sources.push({ type: 'package.json', field: 'dependencies.angular-resource' });
3046
3001
  }
3047
- // AngularJS animate
3048
3002
  if (deps['angular-animate']) {
3049
3003
  confidence += 5;
3050
3004
  sources.push({ type: 'package.json', field: 'dependencies.angular-animate' });
@@ -3075,23 +3029,19 @@ function backboneDetector(projectPath, packageJson) {
3075
3029
  let confidence = 0;
3076
3030
  let version;
3077
3031
  const deps = collectAllDependencies(pkg);
3078
- // Backbone package
3079
3032
  if (deps['backbone']) {
3080
3033
  confidence += 70;
3081
3034
  version = parseVersionString(deps['backbone']);
3082
3035
  sources.push({ type: 'package.json', field: 'dependencies.backbone' });
3083
- // Underscore (commonly used with Backbone)
3084
3036
  if (deps['underscore']) {
3085
3037
  confidence += 15;
3086
3038
  sources.push({ type: 'package.json', field: 'dependencies.underscore' });
3087
3039
  }
3088
- // Lodash can be used as underscore replacement
3089
3040
  if (deps['lodash']) {
3090
3041
  confidence += 5;
3091
3042
  sources.push({ type: 'package.json', field: 'dependencies.lodash' });
3092
3043
  }
3093
3044
  }
3094
- // Marionette (Backbone framework)
3095
3045
  if (deps['backbone.marionette'] || deps['marionette']) {
3096
3046
  confidence += 10;
3097
3047
  sources.push({ type: 'package.json', field: 'dependencies.backbone.marionette' });
@@ -3122,18 +3072,15 @@ function emberDetector(projectPath, packageJson) {
3122
3072
  let confidence = 0;
3123
3073
  let version;
3124
3074
  const deps = collectAllDependencies(pkg);
3125
- // Ember source package
3126
3075
  if (deps['ember-source']) {
3127
3076
  confidence += 70;
3128
3077
  version = parseVersionString(deps['ember-source']);
3129
3078
  sources.push({ type: 'package.json', field: 'dependencies.ember-source' });
3130
3079
  }
3131
- // Ember CLI
3132
3080
  if (deps['ember-cli']) {
3133
3081
  confidence += 20;
3134
3082
  sources.push({ type: 'package.json', field: 'devDependencies.ember-cli' });
3135
3083
  }
3136
- // Ember Data
3137
3084
  if (deps['ember-data']) {
3138
3085
  confidence += 10;
3139
3086
  sources.push({ type: 'package.json', field: 'dependencies.ember-data' });
@@ -3164,18 +3111,15 @@ function jqueryDetector(projectPath, packageJson) {
3164
3111
  let confidence = 0;
3165
3112
  let version;
3166
3113
  const deps = collectAllDependencies(pkg);
3167
- // jQuery package
3168
3114
  if (deps['jquery']) {
3169
3115
  confidence += 80;
3170
3116
  version = parseVersionString(deps['jquery']);
3171
3117
  sources.push({ type: 'package.json', field: 'dependencies.jquery' });
3172
3118
  }
3173
- // jQuery UI
3174
3119
  if (deps['jquery-ui']) {
3175
3120
  confidence += 10;
3176
3121
  sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
3177
3122
  }
3178
- // jQuery plugins
3179
3123
  if (deps['jquery-validation']) {
3180
3124
  confidence += 5;
3181
3125
  sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
@@ -3304,7 +3248,6 @@ function prettierDetector(projectPath, packageJson) {
3304
3248
  confidence += 30;
3305
3249
  sources.push({ type: 'package.json', field: 'prettier' });
3306
3250
  }
3307
- // .prettierignore file
3308
3251
  if (exists(node_path.join(projectPath, '.prettierignore'))) {
3309
3252
  confidence += 10;
3310
3253
  sources.push({ type: 'config-file', path: '.prettierignore' });
@@ -3399,7 +3342,6 @@ function biomeDetector(projectPath, packageJson) {
3399
3342
  let configPath;
3400
3343
  let version;
3401
3344
  const deps = collectAllDependencies(pkg);
3402
- // @biomejs/biome package
3403
3345
  if (deps['@biomejs/biome']) {
3404
3346
  confidence += 70;
3405
3347
  version = parseVersionString(deps['@biomejs/biome']);
@@ -3668,7 +3610,7 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
3668
3610
  sources.push({ type: 'lockfile', path: 'package-lock.json' });
3669
3611
  }
3670
3612
  if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
3671
- return null; // Let yarn workspace detector handle this
3613
+ return null;
3672
3614
  }
3673
3615
  if (confidence === 0) {
3674
3616
  return null;
@@ -4011,7 +3953,6 @@ function checkTsConfigStrict(projectPath) {
4011
3953
  if (!content)
4012
3954
  return undefined;
4013
3955
  try {
4014
- // Simple JSON parsing - doesn't handle comments but good enough for strict check
4015
3956
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
4016
3957
  const parsed = parse(cleanContent);
4017
3958
  return parsed?.compilerOptions?.strict === true;
@@ -4034,19 +3975,16 @@ function typescriptDetector(projectPath, packageJson) {
4034
3975
  let configPath;
4035
3976
  let version;
4036
3977
  const deps = collectAllDependencies(pkg);
4037
- // TypeScript package
4038
3978
  if (deps['typescript']) {
4039
3979
  confidence += 50;
4040
3980
  version = parseVersionString(deps['typescript']);
4041
3981
  sources.push({ type: 'package.json', field: 'dependencies.typescript' });
4042
3982
  }
4043
- // tsconfig.json
4044
3983
  if (exists(node_path.join(projectPath, 'tsconfig.json'))) {
4045
3984
  confidence += 40;
4046
3985
  configPath = 'tsconfig.json';
4047
3986
  sources.push({ type: 'config-file', path: 'tsconfig.json' });
4048
3987
  }
4049
- // tsconfig.*.json variants
4050
3988
  const tsconfigVariants = ['tsconfig.build.json', 'tsconfig.lib.json', 'tsconfig.spec.json', 'tsconfig.app.json'];
4051
3989
  for (const variant of tsconfigVariants) {
4052
3990
  if (exists(node_path.join(projectPath, variant))) {
@@ -4055,7 +3993,6 @@ function typescriptDetector(projectPath, packageJson) {
4055
3993
  break;
4056
3994
  }
4057
3995
  }
4058
- // @types packages
4059
3996
  const typePackages = keys(deps).filter((d) => d.startsWith('@types/'));
4060
3997
  if (typePackages.length > 0) {
4061
3998
  confidence += 10;
@@ -4089,24 +4026,20 @@ function flowDetector(projectPath, packageJson) {
4089
4026
  let configPath;
4090
4027
  let version;
4091
4028
  const deps = collectAllDependencies(pkg);
4092
- // flow-bin package
4093
4029
  if (deps['flow-bin']) {
4094
4030
  confidence += 60;
4095
4031
  version = parseVersionString(deps['flow-bin']);
4096
4032
  sources.push({ type: 'package.json', field: 'dependencies.flow-bin' });
4097
4033
  }
4098
- // .flowconfig
4099
4034
  if (exists(node_path.join(projectPath, '.flowconfig'))) {
4100
4035
  confidence += 40;
4101
4036
  configPath = '.flowconfig';
4102
4037
  sources.push({ type: 'config-file', path: '.flowconfig' });
4103
4038
  }
4104
- // flow-typed directory
4105
4039
  if (exists(node_path.join(projectPath, 'flow-typed'))) {
4106
4040
  confidence += 10;
4107
4041
  sources.push({ type: 'directory', path: 'flow-typed/' });
4108
4042
  }
4109
- // @babel/preset-flow
4110
4043
  if (deps['@babel/preset-flow']) {
4111
4044
  confidence += 10;
4112
4045
  sources.push({ type: 'package.json', field: 'dependencies.@babel/preset-flow' });
@@ -4130,7 +4063,6 @@ function flowDetector(projectPath, packageJson) {
4130
4063
  * @returns `true` if the content contains JSDoc type annotations.
4131
4064
  */
4132
4065
  function hasJsDocTypes(content) {
4133
- // Check for JSDoc type annotations
4134
4066
  return (content.includes('@type {') ||
4135
4067
  content.includes('@param {') ||
4136
4068
  content.includes('@returns {') ||
@@ -4149,14 +4081,11 @@ function jsdocDetector(projectPath, packageJson) {
4149
4081
  const sources = [];
4150
4082
  let confidence = 0;
4151
4083
  const deps = collectAllDependencies(pkg);
4152
- // jsdoc package
4153
4084
  if (deps['jsdoc']) {
4154
4085
  confidence += 30;
4155
4086
  sources.push({ type: 'package.json', field: 'dependencies.jsdoc' });
4156
4087
  }
4157
- // typescript with checkJs (JSDoc type checking)
4158
4088
  if (deps['typescript']) {
4159
- // Check if checkJs is enabled in tsconfig
4160
4089
  const tsconfigPath = node_path.join(projectPath, 'tsconfig.json');
4161
4090
  const content = readFileIfExists(tsconfigPath);
4162
4091
  if (content) {
@@ -4173,12 +4102,10 @@ function jsdocDetector(projectPath, packageJson) {
4173
4102
  }
4174
4103
  }
4175
4104
  }
4176
- // Check for jsconfig.json (VS Code JS type checking)
4177
4105
  if (exists(node_path.join(projectPath, 'jsconfig.json'))) {
4178
4106
  confidence += 40;
4179
4107
  sources.push({ type: 'config-file', path: 'jsconfig.json' });
4180
4108
  }
4181
- // Sample check for JSDoc annotations in source files
4182
4109
  const srcDir = node_path.join(projectPath, 'src');
4183
4110
  if (exists(srcDir)) {
4184
4111
  try {
@@ -4229,8 +4156,6 @@ const detectAllCache = createCache({ ttl: 60000, maxSize: 50 });
4229
4156
  function isDetectAllOptions(value) {
4230
4157
  if (typeof value !== 'object' || value === null)
4231
4158
  return false;
4232
- // DetectAllOptions has skipCache or packageJson fields specifically
4233
- // PackageJson never has skipCache field
4234
4159
  return 'skipCache' in value || 'packageJson' in value;
4235
4160
  }
4236
4161
  /**
@@ -4262,9 +4187,7 @@ function isDetectAllOptions(value) {
4262
4187
  * ```
4263
4188
  */
4264
4189
  function detectAll(projectPath, packageJsonOrOptions) {
4265
- // Handle backward-compatible arguments
4266
4190
  const options = isDetectAllOptions(packageJsonOrOptions) ? packageJsonOrOptions : { packageJson: packageJsonOrOptions };
4267
- // Check cache first (unless skipCache is true)
4268
4191
  if (!options.skipCache) {
4269
4192
  const cached = detectAllCache.get(projectPath);
4270
4193
  if (cached) {
@@ -4315,7 +4238,6 @@ function detectAll(projectPath, packageJsonOrOptions) {
4315
4238
  legacyFrameworks: result.legacyFrameworks.map((f) => f.id),
4316
4239
  testingFrameworks: result.testingFrameworks.map((f) => f.id),
4317
4240
  });
4318
- // Cache the result
4319
4241
  detectAllCache.set(projectPath, result);
4320
4242
  return result;
4321
4243
  }
@@ -4587,7 +4509,6 @@ createScopedLogger('project-scope:nx:config');
4587
4509
  * Known configuration file patterns organized by type.
4588
4510
  */
4589
4511
  const CONFIG_PATTERNS = {
4590
- // Package Management
4591
4512
  'package.json': {
4592
4513
  patterns: ['package.json'],
4593
4514
  format: 'json',
@@ -4614,14 +4535,12 @@ const CONFIG_PATTERNS = {
4614
4535
  description: 'NPM configuration',
4615
4536
  sensitive: true,
4616
4537
  },
4617
- // TypeScript
4618
4538
  tsconfig: {
4619
4539
  patterns: ['tsconfig.json', 'tsconfig.*.json'],
4620
4540
  format: 'jsonc',
4621
4541
  description: 'TypeScript configuration',
4622
4542
  canExtend: true,
4623
4543
  },
4624
- // Monorepo
4625
4544
  nx: {
4626
4545
  patterns: ['nx.json'],
4627
4546
  format: 'json',
@@ -4647,7 +4566,6 @@ const CONFIG_PATTERNS = {
4647
4566
  format: 'json',
4648
4567
  description: 'Lerna configuration',
4649
4568
  },
4650
- // Build Tools
4651
4569
  webpack: {
4652
4570
  patterns: ['webpack.config.js', 'webpack.config.ts', 'webpack.config.cjs', 'webpack.config.mjs'],
4653
4571
  format: 'js',
@@ -4678,7 +4596,6 @@ const CONFIG_PATTERNS = {
4678
4596
  format: 'json',
4679
4597
  description: 'SWC configuration',
4680
4598
  },
4681
- // Testing
4682
4599
  jest: {
4683
4600
  patterns: ['jest.config.js', 'jest.config.ts', 'jest.config.mjs'],
4684
4601
  description: 'Jest configuration',
@@ -4695,7 +4612,6 @@ const CONFIG_PATTERNS = {
4695
4612
  patterns: ['playwright.config.js', 'playwright.config.ts'],
4696
4613
  description: 'Playwright configuration',
4697
4614
  },
4698
- // Framework configs
4699
4615
  next: {
4700
4616
  patterns: ['next.config.js', 'next.config.mjs', 'next.config.ts'],
4701
4617
  format: 'js',
@@ -4721,7 +4637,6 @@ const CONFIG_PATTERNS = {
4721
4637
  format: 'js',
4722
4638
  description: 'Astro configuration',
4723
4639
  },
4724
- // Linting & Formatting
4725
4640
  eslint: {
4726
4641
  patterns: [
4727
4642
  'eslint.config.js',
@@ -4740,14 +4655,12 @@ const CONFIG_PATTERNS = {
4740
4655
  format: 'json',
4741
4656
  description: 'Prettier configuration',
4742
4657
  },
4743
- // Environment (sensitive)
4744
4658
  env: {
4745
4659
  patterns: ['.env', '.env.*', '*.env'],
4746
4660
  format: 'dotenv',
4747
4661
  description: 'Environment variables',
4748
4662
  sensitive: true,
4749
4663
  },
4750
- // Git
4751
4664
  '.gitignore': {
4752
4665
  patterns: ['.gitignore'],
4753
4666
  format: 'text',
@@ -4862,12 +4775,8 @@ function detectConfigs(rootPath, types, options) {
4862
4775
  *
4863
4776
  * @module @hyperfrontend/immutable-api-utils/built-in-copy/number
4864
4777
  */
4865
- // Capture references at module initialization time
4866
4778
  const _parseInt = globalThis.parseInt;
4867
4779
  const _parseFloat = globalThis.parseFloat;
4868
- // ============================================================================
4869
- // Parsing
4870
- // ============================================================================
4871
4780
  /**
4872
4781
  * (Safe copy) Parses a string and returns an integer.
4873
4782
  */
@@ -5195,11 +5104,9 @@ const analyzeLogger = createScopedLogger('project-scope:analyze');
5195
5104
  * @returns Detected workspace type
5196
5105
  */
5197
5106
  function detectWorkspaceType(projectPath) {
5198
- // Check for NX
5199
5107
  if (isNxWorkspace(projectPath) || findNxWorkspaceRoot(projectPath) !== null) {
5200
5108
  return 'nx';
5201
5109
  }
5202
- // Check for common monorepo markers
5203
5110
  if (exists(node_path.resolve(projectPath, 'turbo.json'))) {
5204
5111
  return 'turborepo';
5205
5112
  }
@@ -5209,7 +5116,6 @@ function detectWorkspaceType(projectPath) {
5209
5116
  if (exists(node_path.resolve(projectPath, 'pnpm-workspace.yaml'))) {
5210
5117
  return 'pnpm';
5211
5118
  }
5212
- // Check package.json for workspaces
5213
5119
  const pkg = readPackageJsonIfExists(projectPath);
5214
5120
  if (pkg?.workspaces) {
5215
5121
  if (exists(node_path.resolve(projectPath, 'yarn.lock'))) {
@@ -5218,7 +5124,7 @@ function detectWorkspaceType(projectPath) {
5218
5124
  if (exists(node_path.resolve(projectPath, 'package-lock.json'))) {
5219
5125
  return 'npm';
5220
5126
  }
5221
- return 'npm'; // default for workspaces
5127
+ return 'npm';
5222
5128
  }
5223
5129
  return 'standalone';
5224
5130
  }
@@ -5230,15 +5136,12 @@ function detectWorkspaceType(projectPath) {
5230
5136
  * @returns True if the analysis should be performed
5231
5137
  */
5232
5138
  function shouldInclude(type, options) {
5233
- // If include list is specified, item must be in it
5234
5139
  if (options?.include && options.include.length > 0) {
5235
5140
  return options.include.includes(type);
5236
5141
  }
5237
- // If exclude list is specified, item must not be in it
5238
5142
  if (options?.exclude && options.exclude.length > 0) {
5239
5143
  return !options.exclude.includes(type);
5240
5144
  }
5241
- // Default: include everything
5242
5145
  return true;
5243
5146
  }
5244
5147
  /**
@@ -5287,28 +5190,22 @@ function normalizeConfigFormat(format) {
5287
5190
  function analyzeProject(projectPath, options) {
5288
5191
  const startTime = dateNow();
5289
5192
  const resolvedPath = node_path.resolve(projectPath);
5290
- // Set log level based on verbose option
5291
5193
  if (options?.verbose) {
5292
5194
  analyzeLogger.setLogLevel('debug');
5293
5195
  }
5294
5196
  analyzeLogger.debug('Starting project analysis', { path: resolvedPath, options });
5295
- // Read package.json once for reuse
5296
5197
  const packageJson = readPackageJsonIfExists(resolvedPath);
5297
5198
  analyzeLogger.debug('Package.json loaded', { found: !!packageJson, name: packageJson?.name });
5298
- // Detect project and workspace types
5299
5199
  const projectTypeDetection = detectProjectType(resolvedPath, {
5300
5200
  skipTechDetection: options?.depth === 'basic',
5301
5201
  });
5302
5202
  const projectType = projectTypeDetection.type;
5303
5203
  const workspaceType = detectWorkspaceType(resolvedPath);
5304
5204
  analyzeLogger.debug('Project type detected', { projectType, workspaceType });
5305
- // Get project name from package.json or directory name
5306
5205
  const projectName = packageJson?.name ?? node_path.basename(resolvedPath);
5307
- // Run all technology detectors
5308
5206
  const detections = shouldInclude('frameworks', options) || shouldInclude('buildTools', options) || shouldInclude('testing', options)
5309
5207
  ? detectAll(resolvedPath, packageJson ?? undefined)
5310
5208
  : null;
5311
- // Convert framework detections to FrameworkInfo
5312
5209
  const frameworks = shouldInclude('frameworks', options) && detections
5313
5210
  ? [
5314
5211
  ...detections.frontendFrameworks.map((d) => ({
@@ -5328,7 +5225,6 @@ function analyzeProject(projectPath, options) {
5328
5225
  })),
5329
5226
  ]
5330
5227
  : [];
5331
- // Convert build tool detections
5332
5228
  const buildTools = shouldInclude('buildTools', options) && detections
5333
5229
  ? detections.buildTools.map((d) => ({
5334
5230
  id: d.id,
@@ -5338,7 +5234,6 @@ function analyzeProject(projectPath, options) {
5338
5234
  confidence: d.confidence,
5339
5235
  }))
5340
5236
  : [];
5341
- // Convert testing framework detections
5342
5237
  const testingFrameworks = shouldInclude('testing', options) && detections
5343
5238
  ? detections.testingFrameworks.map((d) => ({
5344
5239
  id: d.id,
@@ -5349,7 +5244,6 @@ function analyzeProject(projectPath, options) {
5349
5244
  confidence: d.confidence,
5350
5245
  }))
5351
5246
  : [];
5352
- // Discover entry points
5353
5247
  const entryPoints = shouldInclude('entryPoints', options)
5354
5248
  ? discoverEntryPoints(resolvedPath).map((e) => ({
5355
5249
  path: e.path,
@@ -5357,7 +5251,6 @@ function analyzeProject(projectPath, options) {
5357
5251
  confidence: e.confidence,
5358
5252
  }))
5359
5253
  : [];
5360
- // Detect configuration files
5361
5254
  const configFiles = shouldInclude('configs', options)
5362
5255
  ? detectConfigs(resolvedPath).map((c) => ({
5363
5256
  path: c.path,
@@ -5366,7 +5259,6 @@ function analyzeProject(projectPath, options) {
5366
5259
  tool: c.type,
5367
5260
  }))
5368
5261
  : [];
5369
- // Get dependency summary
5370
5262
  let dependencies;
5371
5263
  if (shouldInclude('dependencies', options)) {
5372
5264
  const deps = getProjectDependencies(resolvedPath);
@@ -5387,7 +5279,6 @@ function analyzeProject(projectPath, options) {
5387
5279
  total: 0,
5388
5280
  };
5389
5281
  }
5390
- // Build metadata
5391
5282
  const metadata = {
5392
5283
  timestamp: createDate(),
5393
5284
  durationMs: dateNow() - startTime,
@@ -5462,15 +5353,12 @@ function formatWorkspaceType(type) {
5462
5353
  */
5463
5354
  function formatAnalysisText(result) {
5464
5355
  const lines = [];
5465
- // Header
5466
5356
  lines.push(`Project Analysis: ${result.name}`);
5467
5357
  lines.push('='.repeat(30));
5468
5358
  lines.push('');
5469
- // Basic info
5470
5359
  lines.push(`Type: ${formatProjectType(result.projectType)}`);
5471
5360
  lines.push(`Workspace: ${formatWorkspaceType(result.workspaceType)}`);
5472
5361
  lines.push('');
5473
- // Frameworks
5474
5362
  if (result.frameworks.length > 0) {
5475
5363
  lines.push('Frameworks:');
5476
5364
  for (const framework of result.frameworks) {
@@ -5484,7 +5372,6 @@ function formatAnalysisText(result) {
5484
5372
  }
5485
5373
  lines.push('');
5486
5374
  }
5487
- // Build tools
5488
5375
  if (result.buildTools.length > 0) {
5489
5376
  lines.push('Build Tools:');
5490
5377
  for (const tool of result.buildTools) {
@@ -5493,7 +5380,6 @@ function formatAnalysisText(result) {
5493
5380
  }
5494
5381
  lines.push('');
5495
5382
  }
5496
- // Testing
5497
5383
  if (result.testingFrameworks.length > 0) {
5498
5384
  lines.push('Testing:');
5499
5385
  for (const framework of result.testingFrameworks) {
@@ -5502,7 +5388,6 @@ function formatAnalysisText(result) {
5502
5388
  }
5503
5389
  lines.push('');
5504
5390
  }
5505
- // Entry points
5506
5391
  if (result.entryPoints.length > 0) {
5507
5392
  lines.push('Entry Points:');
5508
5393
  for (const entry of result.entryPoints.slice(0, 5)) {
@@ -5513,7 +5398,6 @@ function formatAnalysisText(result) {
5513
5398
  }
5514
5399
  lines.push('');
5515
5400
  }
5516
- // Configurations
5517
5401
  if (result.configFiles.length > 0) {
5518
5402
  lines.push('Configurations:');
5519
5403
  for (const config of result.configFiles.slice(0, 8)) {
@@ -5524,7 +5408,6 @@ function formatAnalysisText(result) {
5524
5408
  }
5525
5409
  lines.push('');
5526
5410
  }
5527
- // Dependencies summary
5528
5411
  lines.push('Dependencies:');
5529
5412
  lines.push(` Production: ${result.dependencies.production}`);
5530
5413
  lines.push(` Development: ${result.dependencies.development}`);
@@ -5611,7 +5494,7 @@ function parseAnalyzeArgs(args) {
5611
5494
  exclude: { type: 'string', short: 'e' },
5612
5495
  },
5613
5496
  allowPositionals: true,
5614
- strict: false, // Allow global options to pass through
5497
+ strict: false,
5615
5498
  });
5616
5499
  const format = values.format;
5617
5500
  const depth = values.depth;
@@ -5670,7 +5553,6 @@ const analyzeCommandDef = {
5670
5553
  description: 'Analyze project structure and tech stack',
5671
5554
  execute(args, globalOptions) {
5672
5555
  const options = parseAnalyzeArgs(args);
5673
- // Global --json flag overrides format
5674
5556
  if (globalOptions.json) {
5675
5557
  options.format = 'json';
5676
5558
  }
@@ -5977,12 +5859,10 @@ Examples:
5977
5859
  function formatDependencyList(deps, maxItems = 20) {
5978
5860
  const lines = [];
5979
5861
  const depEntries = entries(deps);
5980
- // Sort alphabetically
5981
5862
  depEntries.sort((a, b) => a[0].localeCompare(b[0]));
5982
5863
  const displayCount = min(depEntries.length, maxItems);
5983
5864
  for (let i = 0; i < displayCount; i++) {
5984
5865
  const [name, version] = depEntries[i];
5985
- // Pad name to align versions
5986
5866
  const paddedName = name.padEnd(30);
5987
5867
  lines.push(` ${paddedName} ${version}`);
5988
5868
  }
@@ -6225,13 +6105,10 @@ function buildTree(rootPath, walkEntries, options) {
6225
6105
  isDirectory: true,
6226
6106
  children: [],
6227
6107
  };
6228
- // Create a map for quick lookup
6229
6108
  const nodeMap = createMap();
6230
6109
  nodeMap.set('.', root);
6231
- // Sort entries by path for proper parent-child relationships
6232
6110
  const sortedEntries = [...walkEntries].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
6233
6111
  for (const entry of sortedEntries) {
6234
- // Skip based on filters
6235
6112
  if (options.dirsOnly && !entry.isDirectory)
6236
6113
  continue;
6237
6114
  if (options.filesOnly && entry.isDirectory)
@@ -6242,7 +6119,6 @@ function buildTree(rootPath, walkEntries, options) {
6242
6119
  isDirectory: entry.isDirectory,
6243
6120
  children: [],
6244
6121
  };
6245
- // Add size/modified if requested
6246
6122
  if ((options.showSize || options.showModified) && entry.isFile) {
6247
6123
  const stats = getFileStat(entry.path);
6248
6124
  if (stats) {
@@ -6252,9 +6128,8 @@ function buildTree(rootPath, walkEntries, options) {
6252
6128
  node.modified = stats.modified;
6253
6129
  }
6254
6130
  }
6255
- // Find parent
6256
6131
  const parts = entry.relativePath.split('/');
6257
- parts.pop(); // Remove current entry name
6132
+ parts.pop();
6258
6133
  const parentPath = parts.join('/') || '.';
6259
6134
  const parent = nodeMap.get(parentPath);
6260
6135
  if (parent) {
@@ -6275,11 +6150,9 @@ function buildTree(rootPath, walkEntries, options) {
6275
6150
  */
6276
6151
  function renderTreeText(node, options, prefix = '', isLast = true) {
6277
6152
  const lines = [];
6278
- // Current line
6279
6153
  const connector = isLast ? '└── ' : '├── ';
6280
6154
  const dirMark = node.isDirectory ? '/' : '';
6281
6155
  let line = `${prefix}${connector}${node.name}${dirMark}`;
6282
- // Add size/modified
6283
6156
  const meta = [];
6284
6157
  if (options.showSize && node.size !== undefined) {
6285
6158
  meta.push(formatSize(node.size));
@@ -6291,10 +6164,8 @@ function renderTreeText(node, options, prefix = '', isLast = true) {
6291
6164
  line += ` [${meta.join(' ')}]`;
6292
6165
  }
6293
6166
  lines.push(line);
6294
- // Process children
6295
6167
  const childPrefix = prefix + (isLast ? ' ' : '│ ');
6296
6168
  const sortedChildren = [...node.children].sort((a, b) => {
6297
- // Directories first, then alphabetically
6298
6169
  if (a.isDirectory && !b.isDirectory)
6299
6170
  return -1;
6300
6171
  if (!a.isDirectory && b.isDirectory)
@@ -6318,9 +6189,7 @@ function renderTreeText(node, options, prefix = '', isLast = true) {
6318
6189
  */
6319
6190
  function formatTreeText(rootPath, tree, options) {
6320
6191
  const lines = [];
6321
- // Root line
6322
6192
  lines.push(node_path.basename(rootPath));
6323
- // Count stats
6324
6193
  let dirCount = 0;
6325
6194
  let fileCount = 0;
6326
6195
  /**
@@ -6339,7 +6208,6 @@ function formatTreeText(rootPath, tree, options) {
6339
6208
  countNodes(child);
6340
6209
  }
6341
6210
  }
6342
- // Render children of root
6343
6211
  const sortedChildren = [...tree.children].sort((a, b) => {
6344
6212
  if (a.isDirectory && !b.isDirectory)
6345
6213
  return -1;
@@ -6353,7 +6221,6 @@ function formatTreeText(rootPath, tree, options) {
6353
6221
  lines.push(...renderTreeText(child, options, '', isLast));
6354
6222
  countNodes(child);
6355
6223
  }
6356
- // Summary
6357
6224
  lines.push('');
6358
6225
  const dirText = dirCount === 1 ? '1 directory' : `${dirCount} directories`;
6359
6226
  const fileText = fileCount === 1 ? '1 file' : `${fileCount} files`;
@@ -6414,7 +6281,6 @@ function parseTreeArgs(args) {
6414
6281
  function treeCommand(options) {
6415
6282
  const rootPath = options.path ? node_path.resolve(options.path) : process.cwd();
6416
6283
  try {
6417
- // Collect entries via walk
6418
6284
  const walkEntries = [];
6419
6285
  walkDirectory(rootPath, (entry) => {
6420
6286
  walkEntries.push(entry);
@@ -6424,9 +6290,7 @@ function treeCommand(options) {
6424
6290
  ignorePatterns: options.ignore,
6425
6291
  includeHidden: false,
6426
6292
  });
6427
- // Build tree structure
6428
6293
  const tree = buildTree(rootPath, walkEntries, options);
6429
- // Format output
6430
6294
  let output;
6431
6295
  if (options.format === 'json') {
6432
6296
  output = formatTreeJson(tree);
@@ -6485,6 +6349,9 @@ Examples:
6485
6349
 
6486
6350
  /** Logger for CLI operations */
6487
6351
  const cliLogger = createScopedLogger('project-scope:cli');
6352
+ /** Output printer for user-facing CLI output (help, version, command results). */
6353
+ const output = createLogger(error, undefined, log);
6354
+ output.setLogLevel('log');
6488
6355
  /** Library version */
6489
6356
  const VERSION = '0.1.0';
6490
6357
  /**
@@ -6500,7 +6367,7 @@ const commands = {
6500
6367
  * Print general help information.
6501
6368
  */
6502
6369
  function printHelp() {
6503
- log(`
6370
+ output.log(`
6504
6371
  project-scope <command> [options]
6505
6372
 
6506
6373
  A tool for analyzing JavaScript/TypeScript project structure and tech stack.
@@ -6532,7 +6399,7 @@ Examples:
6532
6399
  * Print CLI version.
6533
6400
  */
6534
6401
  function printVersion() {
6535
- log(`project-scope v${VERSION}`);
6402
+ output.log(`project-scope v${VERSION}`);
6536
6403
  }
6537
6404
  /**
6538
6405
  * Parse global options from command line arguments.
@@ -6593,24 +6460,24 @@ function run(args) {
6593
6460
  setGlobalLogLevel('debug');
6594
6461
  }
6595
6462
  cliLogger.debug('CLI invoked', { args, globalOptions });
6463
+ const commandName = args[0];
6596
6464
  if (globalOptions.version) {
6597
6465
  printVersion();
6598
6466
  return { exitCode: 0 };
6599
6467
  }
6600
- if (globalOptions.help && (args.length === 1 || !commands[args[0]])) {
6468
+ if (globalOptions.help && (args.length === 1 || !commands[commandName])) {
6601
6469
  printHelp();
6602
6470
  return { exitCode: 0 };
6603
6471
  }
6604
- const commandName = args[0];
6605
6472
  const command = commands[commandName];
6606
6473
  if (!command) {
6607
6474
  cliLogger.warn('Unknown command requested', { commandName });
6608
- error(`Unknown command: ${commandName}`);
6609
- error('Run "project-scope --help" for usage information.');
6475
+ output.error(`Unknown command: ${commandName}`);
6476
+ output.error('Run "project-scope --help" for usage information.');
6610
6477
  return { exitCode: 1, error: `Unknown command: ${commandName}` };
6611
6478
  }
6612
6479
  if (globalOptions.help) {
6613
- log(command.getHelp());
6480
+ output.log(command.getHelp());
6614
6481
  return { exitCode: 0 };
6615
6482
  }
6616
6483
  const commandArgs = args.slice(1);
@@ -6618,11 +6485,11 @@ function run(args) {
6618
6485
  const result = command.execute(commandArgs, globalOptions);
6619
6486
  cliLogger.debug('Command completed', { commandName, exitCode: result.exitCode });
6620
6487
  if (result.output) {
6621
- log(result.output);
6488
+ output.log(result.output);
6622
6489
  }
6623
6490
  if (result.error) {
6624
6491
  cliLogger.error('Command error', { commandName, error: result.error });
6625
- error(result.error);
6492
+ output.error(result.error);
6626
6493
  }
6627
6494
  return result;
6628
6495
  }