@codometer/measurement 0.0.76 → 0.0.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.0.78 (2026-11-10)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **codometer:** ✨ gate JSDoc on every declaration kind and shorten long comments ([#2227](https://github.com/organizzolini/codebase/pull/2227), [#2226](https://github.com/organizzolini/codebase/issues/2226))
6
+
7
+ ### 🧱 Updated Dependencies
8
+
9
+ - Updated codometer-configuration to 0.0.78
10
+ - Updated codometer-languages to 0.0.78
11
+ - Updated codometer-core to 0.0.78
12
+
13
+ ## 0.0.77 (2026-11-10)
14
+
15
+ ### 🧱 Updated Dependencies
16
+
17
+ - Updated codometer-configuration to 0.0.77
18
+ - Updated codometer-languages to 0.0.77
19
+ - Updated codometer-core to 0.0.77
20
+
1
21
  ## 0.0.76 (2026-11-10)
2
22
 
3
23
  ### 🧱 Updated Dependencies
@@ -32,14 +32,9 @@ declare interface CreateIgnoreScopeArguments {
32
32
  /** Input to the custom statistics step. */
33
33
  export declare interface CustomizationInput {
34
34
  /**
35
- * Every `comment`-selector counter's own measurements, keyed by its
36
- * statistic's label.
35
+ * Each `comment` counter's measurements, keyed by its statistic's label.
37
36
  *
38
- * Built by measuring the counters `buildCommentCounters` returns, then
39
- * merging the two results back together by label — the languages package
40
- * measures a counter naming a declaration kind and one naming a language
41
- * through two different calls, but a label belongs to exactly one custom
42
- * statistic either way.
37
+ * Merged by label from both measurers, since a label names exactly one statistic.
43
38
  */
44
39
  commentCounts: Record<string, CommentMeasurement[]>;
45
40
  /** Every file of the target being counted over. */
@@ -56,50 +51,26 @@ export declare class CustomizationModule {
56
51
  }
57
52
 
58
53
  /**
59
- * Counts the conventions a repository holds itself to.
54
+ * Counts the conventions a repository holds itself to. Which counters apply comes from configuration, not this package.
60
55
  *
61
- * The languages a repository is written in are the same everywhere; what a
62
- * `*.service.ts` means, or whether a static method is something to keep an
63
- * eye on, is not — which is why these counters come from the configuration
64
- * rather than from this package.
65
- *
66
- * A counter measures files by path, declarations by shape, or a comment
67
- * budget by length. The file half is done here; the declaration half is
68
- * tallied by the TypeScript analyzer during the walk it already makes, and
69
- * the comment half by `@codometer/languages`' comment services — both arrive
70
- * here as counts to be labelled.
56
+ * Files are measured here; declaration and comment counts arrive from `@codometer/languages`.
71
57
  */
72
58
  export declare class CustomizationService {
73
59
  constructor();
74
60
  /** Turn a `comment`-selector statistic's own breaches into its result. */
75
61
  private buildCommentResult;
76
62
  /**
77
- * Counts the target's files that at least one of the globs claims.
78
- *
79
- * A file matching several globs of the same counter is one file, not
80
- * several: the counter asks how many files there are, not how many times
81
- * they matched.
63
+ * Counts the files claimed by at least one glob; a file matching several globs counts once.
82
64
  */
83
65
  private countMatches;
84
66
  /** Count every configured statistic over the discovered files. */
85
67
  analyze({ commentCounts, files, statistics, symbolCounts, }: CustomizationInput): CustomStatisticResult[];
86
68
  /**
87
- * Pick out the counters `@codometer/languages`' comment services have to
88
- * measure.
89
- *
90
- * Handed to those services rather than measured again here: a `comment`
91
- * selector names a language or a documentable kind, and turning that into a
92
- * budget is this package's business, not the tokenizer's. One list, mirroring
93
- * the selector field for field — which counter a given measurer takes is
94
- * decided by each measurer, which selects from the list by reading `kind`.
69
+ * Picks the counters `@codometer/languages`' comment services measure. Each measurer selects its own by `kind`.
95
70
  */
96
71
  buildCommentCounters(statistics: CustomizationInput["statistics"]): CommentCounter[];
97
72
  /**
98
- * Pick out the counters the TypeScript analyzer has to tally.
99
- *
100
- * Handed to that analyzer rather than parsed again here: it already walks
101
- * every source file, and a second walk would double the slowest part of a
102
- * run to learn what the first one passed straight over.
73
+ * Picks the counters the TypeScript analyzer tallies during its existing walk, rather than walking files again.
103
74
  */
104
75
  buildSymbolCounters(statistics: CustomizationInput["statistics"]): TypescriptSymbolCounter[];
105
76
  }
@@ -143,91 +114,45 @@ export declare class DiscoveryService {
143
114
  private readonly logger;
144
115
  constructor(ignoreRulesService: IgnoreRulesService, logger: LoggerService);
145
116
  /**
146
- * Folds a directory's own `.gitignore` into the rule sets already in force.
147
- *
148
- * Appended last so its patterns outrank the ones above it, which is how git
149
- * resolves a nested ignore file: the closest one to the file wins.
117
+ * Folds a directory's `.gitignore` into the rule sets in force, appended last so its patterns outrank the ones above.
150
118
  */
151
119
  private applyDirectoryIgnoreFile;
152
120
  /** Selects the discovered files whose extension belongs to a category. */
153
121
  private filterByExtension;
154
122
  /**
155
- * Whether any exclusion glob claims the given repository-relative path.
156
- *
157
- * Matched with `path.matchesGlob` rather than by substring, so a glob naming
158
- * a `dist` directory removes build output and leaves a `redistribute`
159
- * directory alone.
123
+ * Whether any exclusion glob claims the path. Matched by glob, not substring, so a `dist` glob leaves `redistribute` alone.
160
124
  */
161
125
  private isExcluded;
162
126
  /**
163
- * Whether every file beneath a directory is excluded by a glob already.
164
- *
165
- * A pattern ending in `/**` claims every descendant without exception, so a
166
- * directory matching the pattern with that suffix removed cannot contribute
167
- * a single file and never has to be read. This is a shortcut and not a rule
168
- * of its own: the same files would be dropped one by one afterwards either
169
- * way. It matters in a directory with no `.gitignore` to prune
170
- * `node_modules`, where reading it dwarfs reading the codebase.
127
+ * Whether a `/**` glob excludes every file beneath the directory, so the walk can skip reading it. Matters for an unignored `node_modules`.
171
128
  */
172
129
  private isExhaustivelyExcluded;
173
130
  /**
174
- * Whether either set of ignore rules claims a path.
175
- *
176
- * The two sets are answered independently and the answers combined, rather
177
- * than merged into one set. A configured ignore file subtracts from what the
178
- * repository's own `.gitignore` files leave behind, exactly as the two git
179
- * invocations this replaced did; a negation in one cannot resurrect a file
180
- * the other removed.
131
+ * Whether either ignore rule set claims the path. Checked separately, so a negation in one cannot resurrect a file the other removed.
181
132
  */
182
133
  private isIgnoredPath;
183
134
  /**
184
- * Lists every measurable file in the given directory, in sorted order.
185
- *
186
- * Sorted because the walk visits directories in whatever order the
187
- * filesystem reports them, and every consumer downstream deserves the same
188
- * list from the same tree on any machine.
135
+ * Lists every measurable file under the working directory, sorted so every consumer sees the same order on any machine.
189
136
  */
190
137
  private listDiscoveredFiles;
191
138
  /**
192
- * Reads a directory's entries, or none when the directory cannot be read.
193
- *
194
- * A directory can vanish or refuse to open partway through a walk — one
195
- * being cleaned up by another process, a mount the caller has no permission
196
- * on. Shelling out to git never failed for either reason, so letting one
197
- * unreadable directory abort the whole measurement would be a regression:
198
- * warn, skip it, and keep counting the rest.
139
+ * Reads a directory's entries, or none when it cannot be read, so one vanished directory does not abort the walk.
199
140
  */
200
141
  private readDirectoryEntries;
201
142
  /**
202
- * Reads the configured ignore files into rule sets anchored at the root.
203
- *
204
- * A missing file is a warning rather than a failure: a repository that has
205
- * renamed its ignore file should hear about it, but a report is still worth
206
- * more than a crash.
143
+ * Reads the configured ignore files as rules anchored at the root. A missing file only warns, since a report beats a crash.
207
144
  */
208
145
  private readExcludeFromScopes;
209
146
  /**
210
- * Collects every measurable file under one directory.
211
- *
212
- * Walked directory by directory rather than matched by a single recursive
213
- * glob, because an ignored directory then costs one decision instead of an
214
- * enumeration: `node_modules/` is pruned where it is named, not discovered
215
- * in full and thrown away.
147
+ * Collects every measurable file under one directory. Walking directory by directory prunes ignored trees such as `node_modules/` at their root.
216
148
  */
217
149
  private walkDirectory;
218
150
  /**
219
- * Descends into one subdirectory, or skips it when nothing there counts.
220
- *
221
- * The trailing slash is what makes a `coverage/` pattern claim the directory
222
- * itself: without it the pattern only ever matches a file of that name.
151
+ * Descends into a subdirectory unless nothing there counts. The trailing slash lets a `coverage/` pattern claim the directory itself.
223
152
  */
224
153
  private walkSubdirectory;
225
154
  /**
226
- * Sorts a list of file paths into the categories the analyzers ask for.
227
- *
228
- * Separate from the walk so that any target's files can be categorized, not
229
- * only the ones this service found itself: a target naming its files by glob
230
- * is analyzed by the same language analyzers as the codebase around it.
155
+ * Sorts file paths into analyzer categories. Separate from the walk, so any target's files can be categorized.
231
156
  */
232
157
  categorize(files: string[]): DiscoveryResult;
233
158
  /** Returns categorized file path lists for the given codebase root. */
@@ -253,12 +178,7 @@ export declare class EmptyTargetError extends Error {
253
178
  }
254
179
 
255
180
  /**
256
- * What one limit found once it was pointed at its metric.
257
- *
258
- * A breach is one of these carrying `breached`, and it reports everything a
259
- * breach has to: which metric, held to what, and what the metric actually
260
- * measured. A limit that held is reported the same way, so a report can show
261
- * the headroom rather than only the failures.
181
+ * What one limit found once it was pointed at its metric. A breach carries `breached`; a held limit is reported alike.
262
182
  */
263
183
  export declare interface EvaluatedLimit {
264
184
  /** Whether the measured value came out above the limit. */
@@ -280,60 +200,30 @@ declare interface EvaluateLimitsArguments {
280
200
  }
281
201
 
282
202
  /**
283
- * Reads and applies gitignore-syntax rule sets without invoking git.
284
- *
285
- * Codometer used to hand this problem to `git ls-files`, which meant it could
286
- * only measure a directory that was a git repository. Reading the syntax here
287
- * is what lets it measure any directory at all, and it is the only reading of
288
- * that syntax in the tool — there is no git fast path to disagree with.
203
+ * Reads and applies gitignore-syntax rule sets without invoking git, so any directory can be measured. It is the only reader of that syntax.
289
204
  */
290
205
  declare class IgnoreRulesService {
291
206
  constructor();
292
207
  /**
293
- * The path a rule set sees, or nothing when the path lies outside it.
294
- *
295
- * A rule set anchored at `projects/affirmancy` matches its patterns
296
- * against `output/one.md`, not against the full path, because that is what
297
- * the patterns in that directory's ignore file were written against.
208
+ * The path relative to a rule set's directory, or nothing when it lies outside. Patterns match against this, not the full path.
298
209
  */
299
210
  private toScopedPath;
300
211
  /**
301
- * Builds a rule set from patterns already in hand.
302
- *
303
- * Case-sensitive on every platform, deliberately. Git decides that from the
304
- * filesystem it happens to be on, so the same ignore file can claim a
305
- * different set of files on a developer's Mac and on Linux CI. A measurement
306
- * that disagrees with itself between machines is worse than a strict one.
212
+ * Builds a rule set from patterns in hand. Always case-sensitive, so one ignore file claims the same files on every platform.
307
213
  */
308
214
  createScope(args: CreateIgnoreScopeArguments): IgnoreScope;
309
215
  /**
310
- * Whether the rule sets ignore a path, the innermost one deciding.
311
- *
312
- * gitignore resolution is nested rather than additive: a rule set in a
313
- * subdirectory overrides the one above it, which is what lets a `!pattern`
314
- * re-include a file its parent excluded. Reading the scopes outermost first
315
- * and keeping the last decision reproduces that ordering.
316
- *
317
- * A directory is passed with a trailing slash, so a `build/` pattern claims
318
- * the directory rather than only a file that happens to be named `build`.
216
+ * Whether the rule sets ignore a path, the innermost deciding. Scopes apply outermost first, so a nested `!pattern` can re-include a file.
319
217
  */
320
218
  isIgnored(scopes: readonly IgnoreScope[], relativePath: string): boolean;
321
219
  /**
322
- * Reads a rule set out of a gitignore-syntax file.
323
- *
324
- * Returns nothing when the file is absent, so a configured ignore file that
325
- * was renamed is reported by the caller rather than silently behaving as an
326
- * empty one.
220
+ * Reads a rule set from a gitignore-syntax file, or nothing when it is absent so the caller can report it.
327
221
  */
328
222
  readScope(args: ReadIgnoreScopeArguments): IgnoreScope | undefined;
329
223
  }
330
224
 
331
225
  /**
332
- * A gitignore-syntax rule set together with the directory it is anchored to.
333
- *
334
- * The directory matters because gitignore patterns are relative to the file
335
- * they were written in: `/output` in a project's own ignore file claims that
336
- * project's `output`, not the one at the repository root.
226
+ * A gitignore rule set and the directory its patterns are relative to, so `/output` claims that project's `output`.
337
227
  */
338
228
  declare interface IgnoreScope {
339
229
  /** Directory the patterns are relative to, `/`-separated from the walk root. `""` is the root itself. */
@@ -345,10 +235,7 @@ declare interface IgnoreScope {
345
235
  export declare type InputEntryKind = "directory" | "file" | "other";
346
236
 
347
237
  /**
348
- * What every analysis declared for one input reported over its files.
349
- *
350
- * An analysis an input did not ask for reports `undefined` rather than a zero,
351
- * so an input nobody measured the size of is never mistaken for an empty one.
238
+ * What every analysis declared for one input reported over its files. Analyses not requested report `undefined`, never a zero.
352
239
  */
353
240
  export declare interface InputMeasurement {
354
241
  /** How many files the input's globs claimed. */
@@ -359,14 +246,9 @@ export declare interface InputMeasurement {
359
246
  }
360
247
 
361
248
  /**
362
- * Raised when an input's directory reaches outside the repository.
249
+ * Raised when an input reaches beyond the repository holding it.
363
250
  *
364
- * An input may name its way out of the folder being measured — that is how a
365
- * project reaches build output written above it — but not out of the
366
- * repository holding both. Beyond that boundary a configuration file could
367
- * read any file on the machine and report its size, which is not a measurement
368
- * anybody asked for and is exactly what a tool published as a shared action
369
- * must not be able to do.
251
+ * An input may leave the measured folder, but reading outside the repository would let a shared action measure any file on the machine.
370
252
  */
371
253
  export declare class InputOutsideRepositoryError extends Error {
372
254
  constructor(input: string, directory: string, boundary: string);
@@ -389,56 +271,31 @@ export declare class InputsService {
389
271
  private readonly logger;
390
272
  constructor(logger: LoggerService);
391
273
  /**
392
- * Whether a directory can hold anything the input's globs claim.
393
- *
394
- * A hidden directory is only entered when a glob spells it out. That is what
395
- * every glob library means by excluding dot files, and it is also what stops
396
- * an input over the whole tree from reading the repository's git database.
274
+ * Whether a directory can hold anything the input's globs claim. A hidden directory is entered only when a glob names it.
397
275
  */
398
276
  private canDescend;
399
277
  /**
400
- * The furthest out an input is allowed to reach, from where the run started.
401
- *
402
- * The repository holding the measured directory, or that directory itself
403
- * when nothing above it looks like one. Found by marker rather than by
404
- * asking git, which is never invoked here, and generic to every repository —
405
- * it says where measuring stops, not how any tree beneath it is arranged.
278
+ * The furthest an input may reach: the repository above the measured directory, found by marker files, or the directory itself.
406
279
  */
407
280
  private findBoundary;
408
281
  /** Whether the last segment of a path starts with a dot. */
409
282
  private isHidden;
410
283
  /**
411
- * Whether a symbolic link points at a file.
412
- *
413
- * Links are followed, as every glob library does. Only to files, though: a
414
- * link pointing back at one of its own ancestors would otherwise be walked
415
- * until the stack ran out.
284
+ * Whether a symbolic link points at a file. Links are followed only to files, so a link back to an ancestor cannot recurse.
416
285
  */
417
286
  private isLinkedFile;
418
287
  /**
419
- * Whether the input claims a file.
420
- *
421
- * Both lists are answered in full rather than in order, so where a pattern
422
- * sits within either of them cannot change the answer.
288
+ * Whether the input claims a file. Both lists are answered in full, so pattern order cannot change the answer.
423
289
  */
424
290
  private isMatched;
425
291
  /** Whether the directory is on the way down to a glob's literal prefix. */
426
292
  private leadsToBase;
427
293
  /**
428
- * Reads a directory's entries, or none when the directory cannot be read.
429
- *
430
- * An input naming a directory that was never built is an ordinary state
431
- * rather than a failure — it holds no files, and what that means is decided
432
- * by whoever asked for the measurement.
294
+ * Reads a directory's entries, or none when it cannot be read. An input naming a directory not yet built simply holds no files.
433
295
  */
434
296
  private readEntries;
435
297
  /**
436
- * The measured-directory-relative prefix every matched path carries.
437
- *
438
- * Empty when the input starts where the run does. Otherwise it is the walk
439
- * root written relative to the measured directory — `../../dist` and the
440
- * like — so that every path leaving this service is relative to the same
441
- * directory whether or not the input reached outside it.
298
+ * The prefix every matched path carries, relative to the measured directory. Empty when the input starts where the run does.
442
299
  */
443
300
  private readInputPrefix;
444
301
  /** What a directory entry counts as, once any link has been followed. */
@@ -448,38 +305,19 @@ export declare class InputsService {
448
305
  /** Whether a directory is the boundary or sits somewhere beneath it. */
449
306
  private sitsInsideBoundary;
450
307
  /**
451
- * The literal path prefix of a glob, up to its first magic character.
452
- *
453
- * `dist/projects/common/observability/**` can only match inside `dist/projects/common/observability`, so
454
- * that is the only branch of the tree worth reading — the difference between
455
- * measuring one build directory and enumerating every dependency to find it.
308
+ * The literal path prefix of a glob, up to its first magic character. Only that branch of the tree needs reading.
456
309
  */
457
310
  private toIncludeBase;
458
311
  /** Collects every file one directory of the input's tree contributes. */
459
312
  private walk;
460
313
  /**
461
- * Lists the files an input holds, sorted, relative to the measured directory.
462
- *
463
- * The walk starts at the input's own directory, which is the measured one
464
- * unless the input named a way out of it. Where a repository builds is a
465
- * convention its configuration states and this service is told, never one
466
- * inferred here from a project's position — but the reach is bounded: a
467
- * directory landing outside the repository fails the input by name rather
468
- * than measuring whatever it found there.
469
- *
470
- * Sorted because the walk visits directories in whatever order the
471
- * filesystem reports them, and a size is a sum of every file either way —
472
- * but a list nobody can predict is one nobody can compare.
314
+ * Lists the files an input holds, sorted, relative to the measured directory. The walk may reach outside it, but never beyond the repository.
473
315
  */
474
316
  matchFiles(args: MatchInputFilesArguments): string[];
475
317
  }
476
318
 
477
319
  /**
478
- * One limit that could not be held against anything.
479
- *
480
- * Collected rather than thrown. A configuration carrying three limits that
481
- * bind to nothing is three mistakes to fix, and reporting only the first turns
482
- * one repair into three runs.
320
+ * One limit that could not be held against anything. Collected rather than thrown, so one run reports every such limit.
483
321
  */
484
322
  declare interface LimitFailure {
485
323
  /** The dotted path exactly as the limit was written. */
@@ -488,11 +326,7 @@ declare interface LimitFailure {
488
326
  }
489
327
 
490
328
  /**
491
- * What every declared limit found, alongside the ones that bound to nothing.
492
- *
493
- * Both lists are always present. A limit that could not be bound is neither a
494
- * breach nor a pass, and reporting it as either would be a gate whose verdict
495
- * nobody could trust.
329
+ * Every declared limit's result, plus those that bound to nothing. A limit that could not bind is neither a breach nor a pass.
496
330
  */
497
331
  declare interface LimitsEvaluation {
498
332
  failures: LimitFailure[];
@@ -524,55 +358,26 @@ export declare class LimitsService {
524
358
  /** Names every measured target, for an error that has to list them. */
525
359
  private describeTargets;
526
360
  /**
527
- * Every metric a written path could mean.
528
- *
529
- * Each target is asked whether the path starts with its name, rather than
530
- * the path being split at its first dot: a target's name may hold a dot of
531
- * its own, and so may the metric path that follows it. Whatever the shapes
532
- * involved, every reading is collected and none of them is preferred.
361
+ * Every metric a written path could mean. Targets match by name prefix, never by splitting at the first dot.
533
362
  */
534
363
  private findCandidates;
535
364
  /**
536
- * What the path would mean read as the default target's, if one is set.
537
- *
538
- * A default target that was never measured is refused rather than ignored:
539
- * ignoring it would turn every unqualified path in the configuration into an
540
- * unresolvable one, and report the paths instead of the reason.
365
+ * The path read as the default target's metric, if one is set. An unmeasured default is refused, not ignored.
541
366
  */
542
367
  private findDefaultCandidate;
543
368
  /**
544
- * Points one written path at exactly one measured metric.
545
- *
546
- * Ambiguity is refused rather than settled by a rule about which reading
547
- * wins. Any such rule would be invisible in the configuration file, and a
548
- * limit holding a metric nobody meant to limit reads exactly like one that
549
- * works.
369
+ * Points one written path at exactly one measured metric. Ambiguity is refused, never settled by a hidden rule.
550
370
  */
551
371
  private resolve;
552
372
  /**
553
- * Holds every declared limit against the metric it addresses.
554
- *
555
- * Returns what each limit found rather than a verdict. Severity is carried
556
- * through untouched: whether a breach stops the run is a decision about the
557
- * run, not about the measurement.
558
- *
559
- * A limit that binds to nothing joins `failures` and the rest are evaluated
560
- * anyway, so one run names every path in a configuration that binds to
561
- * nothing instead of the first one and nothing after it.
373
+ * Holds every declared limit against its metric, returning what each found. Unbound limits are collected, not thrown.
562
374
  */
563
375
  evaluate(args: EvaluateLimitsArguments): LimitsEvaluation;
564
376
  }
565
377
 
566
378
  /**
567
- * Structured values that belong beside a log line rather than inside it.
568
- *
569
- * Counts, percentages, and durations are the values that change on every
570
- * occurrence, so they are carried as fields: the message stays constant and
571
- * groupable in telemetry, and the numbers stay queryable instead of having to
572
- * be parsed back out of prose.
573
- *
574
- * The named members are the recurring ones; the index signature keeps the
575
- * argument open for whatever a given call site needs to attach.
379
+ * Values beside a log line rather than inside it: counts and durations change
380
+ * per occurrence, so they stay queryable fields.
576
381
  */
577
382
  declare interface LogData {
578
383
  [key: string]: unknown;
@@ -587,20 +392,11 @@ declare interface LogData {
587
392
  }
588
393
 
589
394
  /**
590
- * Transient-scoped logger so each injecting class gets its own instance.
591
- * Each consumer calls `setContext(ClassName.name)` to tag every log line
592
- * with the originating class. Backed by pino for structured JSON output in
593
- * production and human-readable pretty-print in development.
594
- *
595
- * Messages follow one grammar: an emoji naming the subject, a verb in present
596
- * progressive or past tense, then the object. Values that vary per call —
597
- * counts, percentages, durations — go in the `data` argument rather than the
598
- * message, so the message stays constant enough for telemetry to group on.
599
- *
600
- * ```ts
601
- * this.logger.info("📥 Downloading CSEL sources", undefined, { total: 428 });
602
- * this.logger.info("📥 Downloaded CSEL sources", undefined, { count: 412 });
603
- * ```
395
+ * Transient logger, so each injecting class gets its own instance. Each
396
+ * consumer calls `setContext(ClassName.name)`. Backed by pino: JSON in
397
+ * production, pretty-printed in development. Messages start with an emoji
398
+ * naming the subject, then a verb in present progressive or past tense.
399
+ * Varying values such as counts go in `data`, so messages stay groupable.
604
400
  */
605
401
  declare @Injectable({ scope: Scope.TRANSIENT })
606
402
  class LoggerService
@@ -618,12 +414,7 @@ implements LoggerServiceContract
618
414
  private static readonly isProduction =
619
415
  process.env["NODE_ENV"] === "production";
620
416
 
621
- /**
622
- * Built on first use, not when this file is evaluated.
623
- *
624
- * A destination fixed at import time could only ever be chosen by this
625
- * package, since every consumer's own code runs after its imports.
626
- */
417
+ /** Built on first use, so `logToStandardError` can still choose the destination after import. */
627
418
  private static rootLogger: pino.Logger | undefined;
628
419
 
629
420
  /** Whether lines go to standard error instead of standard output. */
@@ -666,18 +457,8 @@ implements LoggerServiceContract
666
457
  }
667
458
 
668
459
  /**
669
- * Sends every subsequent line to standard error instead of standard output.
670
- *
671
- * For a command-line application whose standard output *is* its result. A log
672
- * line sharing that stream is not a diagnostic beside the data, it is a
673
- * corruption of it. Call it before anything logs — the first statement of the
674
- * application's bootstrap.
675
- *
676
- * A call after the first line warns and changes nothing: the destination is
677
- * fixed when the pino instance is built, and tearing down a transport
678
- * somebody is writing through would be worse than refusing. The warning is
679
- * the point — silently leaving the lines on standard output is how a caller
680
- * would ship a corrupted pipe without ever being told.
460
+ * Sends later lines to standard error, for a command whose stdout is its
461
+ * result. Call it first; later calls warn and change nothing.
681
462
  */
682
463
  static logToStandardError(): void {
683
464
  if (LoggerService.rootLogger !== undefined) {
@@ -691,10 +472,8 @@ implements LoggerServiceContract
691
472
  }
692
473
 
693
474
  /**
694
- * Fails a malformed message in development, and never in production.
695
- *
696
- * A logger that throws in production turns an observability call into an
697
- * outage, so the check runs only where a developer is present to fix it.
475
+ * Fails a malformed message in development only, since a throw in production
476
+ * would turn logging into an outage.
698
477
  */
699
478
  private assertConventionalMessage(args: {
700
479
  context: string | undefined;
@@ -754,11 +533,8 @@ implements LoggerServiceContract
754
533
  }
755
534
 
756
535
  /**
757
- * Whether a word is a verb in one of the two tenses the convention allows.
758
- *
759
- * Present progressive means the operation is under way; past means it
760
- * finished. Regular morphology covers both, so a new verb needs no
761
- * registration anywhere — only irregular pasts are enumerated.
536
+ * Whether a word is a present-progressive or past-tense verb. Only irregular
537
+ * pasts need listing; regular morphology covers the rest.
762
538
  */
763
539
  private isConventionalVerb(word: string): boolean {
764
540
  const lowercased = word.toLowerCase();
@@ -834,11 +610,8 @@ implements LoggerServiceContract
834
610
  }
835
611
 
836
612
  /**
837
- * Logs an error message at the `error` level, optionally including a stack trace.
838
- *
839
- * `ConsoleLogger.error` spends a third slot on a context string that the
840
- * other levels do not have, so this one accepts either: a string keeps
841
- * NestJS's meaning, an object is structured data like everywhere else.
613
+ * Logs at the `error` level. The second argument is a stack, the third a
614
+ * context string or structured data.
842
615
  */
843
616
  override error(
844
617
  message: unknown,
@@ -869,12 +642,8 @@ implements LoggerServiceContract
869
642
  }
870
643
 
871
644
  /**
872
- * Logs an informational message at the `info` level.
873
- *
874
- * NestJS and `nest-commander` call this method directly as part of the
875
- * framework's own `LoggerService` contract, so it must keep working
876
- * exactly as before. Application code should call `info` instead — the
877
- * same behavior under a name that says what level it logs at.
645
+ * Logs at the `info` level, as NestJS and `nest-commander` call it.
646
+ * Application code should call `info` instead.
878
647
  */
879
648
  override log(message: unknown, context?: string, data?: LogData): void {
880
649
  this.info(message, context, data);
@@ -934,20 +703,14 @@ export declare interface MeasureArguments {
934
703
  /**
935
704
  * Files codometer writes itself, relative to the measured directory.
936
705
  *
937
- * Never measured, whether or not this particular run writes them: a run that
938
- * measured a different tree depending on its flags could not tell a stale
939
- * report from a report written by a differently-flagged run.
706
+ * Never measured, so flags never change what is measured.
940
707
  */
941
708
  outputPaths: readonly string[];
942
709
  workingDirectory: string;
943
710
  }
944
711
 
945
712
  /**
946
- * What one target measured, as the limits layer reads it.
947
- *
948
- * Declared here rather than imported from the measurement pipeline: gating a
949
- * number needs the number and its target's name, and nothing about how either
950
- * was produced.
713
+ * What one target measured, as the limits layer reads it. Declared here so this layer needs no measurement types.
951
714
  */
952
715
  declare interface MeasuredTarget {
953
716
  files: number;
@@ -957,20 +720,13 @@ declare interface MeasuredTarget {
957
720
  }
958
721
 
959
722
  /**
960
- * Everything one run measured, input by input.
961
- *
962
- * `statistics` is the `codebase` input's own language metrics, which is the
963
- * report every consumer renders today. It is the same object that input
964
- * carries, held out separately so nothing downstream has to know which input
965
- * it came from.
723
+ * Everything one run measured, input by input. `statistics` holds the codebase's language metrics, held out for consumers.
966
724
  */
967
725
  export declare interface MeasurementResult {
968
726
  /**
969
- * Whatever the run could not do, collected rather than thrown.
727
+ * What the run could not do, collected rather than thrown.
970
728
  *
971
- * An input that will not measure and a limit that binds to nothing are both
972
- * recorded here and stepped over, so one run names every one of them instead
973
- * of stopping at the first and hiding the rest behind it.
729
+ * One run names every failure rather than stopping at the first.
974
730
  */
975
731
  failures: ReportFailure[];
976
732
  /** Every metric each measured input counted, addressable by dotted path. */
@@ -978,24 +734,18 @@ export declare interface MeasurementResult {
978
734
  /** Every input measured, in the order `inputs` declared them. */
979
735
  inputs: InputMeasurement[];
980
736
  /**
981
- * What every declared limit found, in the order they were declared.
737
+ * What every declared limit found, in declaration order.
982
738
  *
983
- * Empty when nothing declared one, which is the ordinary case: a metric with
984
- * no limit is measured and reported like every other, and gated by nothing.
739
+ * Empty when none is declared, which is the ordinary case.
985
740
  */
986
741
  limits: EvaluatedLimit[];
987
742
  statistics: CodeStatisticsResult;
988
743
  }
989
744
 
990
745
  /**
991
- * Wires every analyzer a measurement run joins, and the service that joins
992
- * them.
746
+ * Wires every analyzer a measurement run joins, and the service that joins them.
993
747
  *
994
- * The one module a host has to import to measure anything: discovery finds the
995
- * files, the language and size analyzers count them, the custom counters add
996
- * whatever a configuration declared, and the limits layer holds the result to
997
- * what the configuration gates. None of the five imports another, which is why
998
- * the join lives here rather than inside one of them.
748
+ * Discovery, language, size, custom counters, and limits; none imports another, so the join lives here.
999
749
  */
1000
750
  export declare class MeasureModule {
1001
751
  }
@@ -1003,12 +753,7 @@ export declare class MeasureModule {
1003
753
  /**
1004
754
  * Aggregates every analyzer's report into a single set of statistics.
1005
755
  *
1006
- * The one place the discovery, language, size, and customization analyzers
1007
- * meet. None of the four imports another, so joining them has to happen
1008
- * somewhere, and a call-stack trace reports that join as module spread against
1009
- * `measureInput` and `analyzeFiles` — the two methods that personally name
1010
- * three of the four. That is the arrangement working, not drifting: pushing the
1011
- * join down into one of the analyzers is what would couple them to each other.
756
+ * The one place the analyzers meet. None imports another, so the join lives here.
1012
757
  */
1013
758
  export declare class MeasureService {
1014
759
  private readonly discoveryService;
@@ -1020,17 +765,7 @@ export declare class MeasureService {
1020
765
  private readonly metricIndexService;
1021
766
  constructor(discoveryService: DiscoveryService, languagesService: LanguagesService, customizationService: CustomizationService, inputsService: InputsService, sizeService: SizeService, limitsService: LimitsService, metricIndexService: MetricIndexService);
1022
767
  /**
1023
- * Run every analyzer over one set of files and shape the result.
1024
- *
1025
- * Three analyzers, not one: the language analyzers, the size analyzer that
1026
- * produces the headline byte total, and the custom counters a configuration
1027
- * declares. Named for the file set rather than for any of the three, because
1028
- * this sits directly above `LanguagesService.analyze` in every measurement
1029
- * stack — named for a language it reads there as a forwarding layer instead
1030
- * of as the place all three are joined.
1031
- *
1032
- * Takes the files it is given rather than finding them, so the codebase and
1033
- * an input naming compiled output are counted by exactly the same analyzers.
768
+ * Runs every analyzer over one file set and shapes the result. Takes the files it is given, so codebase and input are counted identically.
1034
769
  */
1035
770
  private analyzeFiles;
1036
771
  /** Project the TypeScript analyzer's counters onto the JavaScript group. */
@@ -1040,22 +775,11 @@ export declare class MeasureService {
1040
775
  /** Reads whatever an input's measurement threw as a printable sentence. */
1041
776
  private describeFailure;
1042
777
  /**
1043
- * Discovers one input's files, minus the ones codometer writes itself.
1044
- *
1045
- * The built-in `codebase` input is discovered by whatever its ignore files
1046
- * leave behind rather than by matching its own `include`/`exclude` globs —
1047
- * those stay placeholders for that one input, exactly as
1048
- * `@codometer/configuration` documents. Every other input's files are
1049
- * whatever its globs claim.
778
+ * Discovers one input's files, minus codometer's own outputs. The built-in `codebase` input uses its ignore files, not its globs.
1050
779
  */
1051
780
  private discoverInputFiles;
1052
781
  /**
1053
- * Drops the files codometer writes from a list of measured ones.
1054
- *
1055
- * Codometer's reports are made of what it measured, so measuring them makes
1056
- * every report an input to the next one: a badge block changes the markdown
1057
- * counters, which changes the badges. Removing them is what makes a second
1058
- * run over an untouched tree produce the same bytes as the first.
782
+ * Drops codometer's own report files from measured ones, so a second run over an untouched tree yields the same bytes.
1059
783
  */
1060
784
  private excludeOutputPaths;
1061
785
  /**
@@ -1063,11 +787,7 @@ export declare class MeasureService {
1063
787
  */
1064
788
  private getFolderCount;
1065
789
  /**
1066
- * Measure one declared input with whichever analyses it asked for.
1067
- *
1068
- * An analysis nobody asked for is not run at all. Compressing a source tree
1069
- * to answer a question nobody put costs more than every other analysis put
1070
- * together.
790
+ * Measures one declared input with only the analyses it asked for. An analysis nobody requested is never run.
1071
791
  */
1072
792
  private measureInput;
1073
793
  /** Restates the limits layer's failures in the report's own vocabulary. */
@@ -1075,14 +795,7 @@ export declare class MeasureService {
1075
795
  /** Whether an input asked for one of the analyses. */
1076
796
  private runsAnalysis;
1077
797
  /**
1078
- * Measure every input the configuration declares.
1079
- *
1080
- * The built-in `codebase` input is not special-cased here — resolution
1081
- * already prepends it unless a configuration replaces it by name, so this
1082
- * simply measures whichever inputs it was handed, in the order given. An
1083
- * input that cannot be measured — a glob pointing at a directory that
1084
- * vanished, a file that will not open — is recorded and stepped over, so one
1085
- * unreadable file never takes the whole run with it.
798
+ * Measures every declared input in declaration order. A failing input is recorded and skipped, so one bad file cannot end the run.
1086
799
  */
1087
800
  measure(args: MeasureArguments): MeasurementResult;
1088
801
  }
@@ -1105,49 +818,27 @@ declare interface MetricIndexResult {
1105
818
  export declare class MetricIndexService {
1106
819
  constructor();
1107
820
  /**
1108
- * Records one metric, or marks its path as answered by more than one.
1109
- *
1110
- * Two counters sharing a path is a configuration mistake rather than a
1111
- * measurement one — two statistics with the same label — and it is caught
1112
- * here so that a limit addressing that path is refused instead of being
1113
- * given whichever counter was indexed first.
821
+ * Records one metric. A path already answered is marked ambiguous, so a limit addressing it is refused rather than given the first counter.
1114
822
  */
1115
823
  private addMetric;
1116
824
  /**
1117
- * Indexes every metric one target measured, by its path within that target.
1118
- *
1119
- * An analysis the target never ran contributes nothing, so a limit written
1120
- * against it is refused rather than being compared against a zero the target
1121
- * never reported.
825
+ * Indexes every metric one target measured, by path. An analysis the target never ran is refused, not compared as zero.
1122
826
  */
1123
827
  private buildTargetIndex;
1124
828
  /**
1125
- * Explains a name two measured targets both answered to.
1126
- *
1127
- * Written where the collision is found rather than raised as an error: the
1128
- * run carries on with the first target of that name, and this is what the
1129
- * report says about the one it had to drop.
829
+ * Explains a name two measured targets both answered to. The second target is dropped; the run continues with the first.
1130
830
  */
1131
831
  private describeDuplicate;
1132
832
  /** Indexes a group of counters, descending into the nested ones. */
1133
833
  private indexCounters;
1134
834
  /**
1135
- * Indexes everything language analysis counted.
1136
- *
1137
- * Configured counters are indexed under a prefix rather than beside the
1138
- * built-in ones, so a counter labelled `files` cannot take the path the file
1139
- * count already answers to.
835
+ * Indexes everything language analysis counted. Configured counters sit under a prefix, so a counter named `files` cannot shadow the file count.
1140
836
  */
1141
837
  private indexLanguage;
1142
838
  /** Whether a statistics entry holds counters of its own. */
1143
839
  private isCounterGroup;
1144
840
  /**
1145
- * Indexes every measured target, by name.
1146
- *
1147
- * A repeated name is collected rather than thrown, so a run reports every
1148
- * naming collision it found instead of the first one. The later target is
1149
- * dropped: a metric is addressed by its target's name, so a name answering
1150
- * to two targets can address neither.
841
+ * Indexes every measured target by name. A repeated name is collected rather than thrown, and the later target is dropped.
1151
842
  */
1152
843
  index(targets: readonly MeasuredTarget[]): MetricIndexResult;
1153
844
  }
@@ -1175,9 +866,7 @@ export declare interface SizeResult {
1175
866
  /**
1176
867
  * Total bytes the target's files occupy under the chosen compression.
1177
868
  *
1178
- * A sum of separately compressed files rather than one compression of all of
1179
- * them: a browser fetches each file on its own, so compressing them together
1180
- * would report a number no client ever receives.
869
+ * A sum of separately compressed files, as browsers fetch them.
1181
870
  */
1182
871
  bytes: number;
1183
872
  compression: CodometerCompression;
@@ -1189,28 +878,15 @@ export declare class SizeService {
1189
878
  private readonly logger;
1190
879
  constructor(logger: LoggerService);
1191
880
  /**
1192
- * Compresses one file's contents and reports the resulting byte count.
1193
- *
1194
- * Written as a lookup rather than a switch so that a compression added to
1195
- * the configuration without an implementation here fails to compile, instead
1196
- * of falling through to whichever branch happened to be last.
881
+ * Compresses one file's contents and returns the byte count. A lookup, not a switch, so a missing compressor fails to compile.
1197
882
  */
1198
883
  private compress;
1199
884
  /**
1200
- * Measures one file, or fails the run.
1201
- *
1202
- * A file can vanish between being matched and being read — a build running
1203
- * beside the measurement is enough. Skipping it would report a total short
1204
- * by that file while still counting it, which is a number that looks
1205
- * consistent and lets a real breach through. Failing is the lesser harm.
885
+ * Measures one file, or fails the run. Skipping a vanished file would understate the total, so failing is the lesser harm.
1206
886
  */
1207
887
  private measureFile;
1208
888
  /**
1209
- * Measures every file of a target and sums the results.
1210
- *
1211
- * Each file is compressed on its own. Compressing them together would let
1212
- * one file's dictionary shrink the next, reporting a total smaller than
1213
- * anything that will ever be transferred.
889
+ * Measures every file of a target and sums the results. Each file is compressed alone, since shared compression would shrink later files.
1214
890
  */
1215
891
  analyze(args: AnalyzeSizeArguments): SizeResult;
1216
892
  }
@@ -1220,20 +896,14 @@ export declare interface TargetMetricIndex {
1220
896
  /**
1221
897
  * Paths more than one metric answers to, which no limit may address.
1222
898
  *
1223
- * Two configured counters sharing a label is the way this happens. Either
1224
- * metric would be a defensible binding, which is exactly why neither is.
899
+ * Two counters sharing a label cause this.
1225
900
  */
1226
901
  ambiguous: Set<string>;
1227
902
  files: number;
1228
903
  /**
1229
- * Where each metric's per-instance measurements were found, keyed by the
1230
- * same dotted path `metrics` uses.
904
+ * Per-instance measurements of each metric, keyed by its dotted path.
1231
905
  *
1232
- * Only a metric a per-instance selector produced has an entry here — a
1233
- * `comment` selector today, and any future selector that measures more
1234
- * than a count. A metric with no entry counted matches and nothing more,
1235
- * so a consumer reading this map can tell the two apart without reading
1236
- * the configuration that produced either.
906
+ * Present only for metrics a per-instance selector produced.
1237
907
  */
1238
908
  instances: Map<string, CustomStatisticResultInstance[]>;
1239
909
  metrics: Map<string, number>;
@@ -1281,8 +951,7 @@ export declare interface WalkInputArguments {
1281
951
  /**
1282
952
  * The literal path prefix of each include glob.
1283
953
  *
1284
- * A glob's prefix is where its matches can begin, so a directory neither
1285
- * leading to a prefix nor sitting inside one holds nothing the input wants.
954
+ * A directory holding nothing under that prefix can be skipped.
1286
955
  */
1287
956
  includeBases: readonly string[];
1288
957
  input: ResolvedCodometerInput;
package/package.json CHANGED
@@ -4,9 +4,9 @@
4
4
  "url": "https://github.com/organizzolini/codebase/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@codometer/configuration": "0.0.76",
8
- "@codometer/core": "0.0.76",
9
- "@codometer/languages": "0.0.76",
7
+ "@codometer/configuration": "0.0.78",
8
+ "@codometer/core": "0.0.78",
9
+ "@codometer/languages": "0.0.78",
10
10
  "@nestjs/common": "^11.1.21 || ^12.0.1",
11
11
  "ignore": "7.0.14",
12
12
  "pino": "^10.3.1",
@@ -22,8 +22,8 @@
22
22
  "@nx/eslint-plugin": "^24.0.0",
23
23
  "@swc/helpers": "^0.5.21",
24
24
  "@types/node": "^26.5.1",
25
- "@vitest/coverage-v8": "^5.0.0",
26
- "vitest": "^5.0.0"
25
+ "@vitest/coverage-v8": "^5.1.0",
26
+ "vitest": "^5.1.0"
27
27
  },
28
28
  "exports": {
29
29
  ".": {
@@ -64,5 +64,5 @@
64
64
  "strict": true
65
65
  },
66
66
  "types": "./dist/src/index.d.ts",
67
- "version": "0.0.76"
67
+ "version": "0.0.78"
68
68
  }