@codependix/output 0.0.3

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.
@@ -0,0 +1,1252 @@
1
+ import { AnchorCheckResult } from '@codependix/core';
2
+ import { BoundaryCheckOutcome } from '@codependix/boundaries';
3
+ import { BoundaryReportService } from '@codependix/boundaries';
4
+ import { CodependixGraphType } from '@codependix/configuration';
5
+ import { CodependixRunMode } from '@codependix/core';
6
+ import { ConfigurationService } from '@codependix/configuration';
7
+ import { ConsoleLogger } from '@nestjs/common';
8
+ import { FileImportsWorkspaceGraphService } from '@codependix/file-imports';
9
+ import { GraphRunContext } from '@codependix/boundaries';
10
+ import { GraphRunOutcome } from '@codependix/core';
11
+ import { MarkdownSectionArguments } from '@codependix/core';
12
+ import { ModuleGraphService } from '@codependix/nestjs-modules';
13
+ import { Neighborhood } from '@codependix/nx-projects';
14
+ import { NeighborhoodService } from '@codependix/nx-projects';
15
+ import { NestjsModuleGraph } from '@codependix/nestjs-modules';
16
+ import { NestjsModulesWorkspaceGraphService } from '@codependix/nestjs-modules';
17
+ import { NestjsProjectService } from '@codependix/nestjs-modules';
18
+ import pino from 'pino';
19
+ import { ProjectRunResult } from '@codependix/core';
20
+ import { PythonService } from '@codependix/file-imports';
21
+ import { ResolvedCodependixGraphOutput } from '@codependix/configuration';
22
+ import { TypescriptService } from '@codependix/file-imports';
23
+ import { WorkspaceGraph } from '@codependix/nx-projects';
24
+ import { WorkspaceGraphService } from '@codependix/nx-projects';
25
+
26
+ /** Arguments shared by every method that reads or rewrites an anchor. */
27
+ declare interface AnchorLocationArguments {
28
+ anchorName: string;
29
+ fileContent: string;
30
+ filePath: string;
31
+ }
32
+
33
+ /**
34
+ * Raised when a named anchor block is not present in a Markdown file.
35
+ *
36
+ * `AnchorsService.checkAnchor` and `replaceAnchorContent` still raise this for
37
+ * any missing anchor β€” they are low-level primitives that know nothing about
38
+ * auto-creation. `DeliveryService` is what decides whether this ever reaches a
39
+ * caller: it only lets it surface when the file itself does not exist at all
40
+ * (a project with no `README.md` is a genuinely more serious problem), and
41
+ * intercepts a missing-but-creatable anchor before calling into these
42
+ * primitives β€” auto-creating the `## πŸ•ΈοΈ Codependix` section on `--write` (see
43
+ * `AnchorsService.insertAnchorSection`) and reporting it as stale on
44
+ * `--check` instead.
45
+ */
46
+ export declare class AnchorNotFoundError extends Error {
47
+ constructor(anchorName: string, filePath: string);
48
+ }
49
+
50
+ /** Arguments for auto-creating a missing anchor's section on write. */
51
+ declare interface AnchorSectionInsertArguments {
52
+ anchorName: string;
53
+ content: string;
54
+ fileContent: string;
55
+ introLine: string;
56
+ /**
57
+ * The `### <Subheading>` placed immediately above the anchor block, or
58
+ * `undefined` when the anchor sits directly under the `## πŸ•ΈοΈ Codependix`
59
+ * heading with no subheading of its own β€” the workspace README's shape.
60
+ */
61
+ subheading: string | undefined;
62
+ }
63
+
64
+ /** Provides codependix's own Markdown anchor read/write mechanism. */
65
+ export declare class AnchorsModule {
66
+ }
67
+
68
+ /**
69
+ * Reads and rewrites codependix's own named anchor blocks in a Markdown file.
70
+ *
71
+ * Owns its comment-marker syntax outright β€” a start marker and an end marker,
72
+ * each an HTML comment naming the anchor β€” with zero dependency on any
73
+ * `conformetry-*` package, per issue #242's decision that codependix must be
74
+ * able to evolve its export format without touching, or being constrained by,
75
+ * conformetry's template-conformance mechanism. See `anchors.constants.ts`
76
+ * for the exact marker text.
77
+ *
78
+ * `checkAnchor` and `replaceAnchorContent` still treat a missing anchor as an
79
+ * error β€” they are low-level primitives with no notion of where a new section
80
+ * would safely go. `insertAnchorSection` is the one place that risk is taken
81
+ * on deliberately: it only ever places a new section at one of two safe,
82
+ * well-defined spots β€” the end of the file, or the end of an existing
83
+ * `## πŸ•ΈοΈ Codependix` section β€” never anywhere else in a document someone else
84
+ * is authoring. `DeliveryService` is what decides when to reach for it.
85
+ */
86
+ export declare class AnchorsService {
87
+ constructor();
88
+ /** Appends a brand-new `## πŸ•ΈοΈ Codependix` section to the end of a file. */
89
+ private appendCodependixSection;
90
+ /** Builds the pattern matching a named anchor block and its inner content. */
91
+ private buildAnchorPattern;
92
+ /** Escapes a string so it can be embedded literally in a regular expression. */
93
+ private escapeForPattern;
94
+ /**
95
+ * Inserts a new subsection at the end of an existing `## πŸ•ΈοΈ Codependix`
96
+ * section, before whatever heading comes next in the file (or at the end of
97
+ * the file, when the section is already the last thing in it).
98
+ */
99
+ private insertIntoCodependixSection;
100
+ /**
101
+ * Compares a Markdown file's anchor against a freshly computed export.
102
+ *
103
+ * `--check` reads this and reports drift without writing anything; `--write`
104
+ * is what acts on it. Throws `AnchorNotFoundError` when the anchor is
105
+ * missing, which is what fails a `--check` run against a project that never
106
+ * had the markers placed.
107
+ */
108
+ checkAnchor(args: AnchorLocationArguments & {
109
+ freshContent: string;
110
+ }): AnchorCheckResult;
111
+ /** Reads a named anchor's current content, or `undefined` when it is absent. */
112
+ extractAnchorContent(args: AnchorLocationArguments): string | undefined;
113
+ /** Whether a named anchor block is present in a file's content. */
114
+ hasAnchor(args: AnchorLocationArguments): boolean;
115
+ /**
116
+ * Auto-creates a missing anchor's `## πŸ•ΈοΈ Codependix` section.
117
+ *
118
+ * Called only when the caller has already confirmed the anchor is absent β€”
119
+ * this never checks that itself, and never touches an anchor that already
120
+ * exists. Two safe, well-defined outcomes only:
121
+ *
122
+ * - No `## πŸ•ΈοΈ Codependix` heading anywhere in the file: appends the heading,
123
+ * `introLine`, the `### <subheading>` (when one is given), and the anchor
124
+ * block to the end of the file.
125
+ * - A `## πŸ•ΈοΈ Codependix` heading already exists (from an earlier graph
126
+ * type's write): inserts the new `### <subheading>` and anchor block at
127
+ * the end of that section, before whatever heading comes next β€” never
128
+ * duplicating the heading itself.
129
+ */
130
+ insertAnchorSection(args: AnchorSectionInsertArguments): string;
131
+ /**
132
+ * Replaces a named anchor's content in place, leaving the rest untouched.
133
+ *
134
+ * Idempotent: writing the same content twice produces byte-identical output,
135
+ * since the replacement is always rendered in the same canonical shape β€”
136
+ * marker, trimmed content, marker β€” regardless of what whitespace the
137
+ * anchor held before.
138
+ */
139
+ replaceAnchorContent(args: AnchorLocationArguments & {
140
+ newContent: string;
141
+ }): string;
142
+ /** Wraps content in a fresh pair of markers, for placing a new anchor by hand. */
143
+ wrapInAnchors(anchorName: string, content: string): string;
144
+ }
145
+
146
+ /** Builds the closing marker of a named anchor block. */
147
+ export declare const buildEndMarker: (anchorName: string) => string;
148
+
149
+ /**
150
+ * Message rendered when no connecting path exists between two nodes.
151
+ */
152
+ export declare const buildNoPathMessage: (from: string, to: string) => string;
153
+
154
+ /**
155
+ * Builds the opening marker of a named anchor block.
156
+ *
157
+ * codependix's own comment-marker syntax, independent of conformetry's marker
158
+ * mechanism by design β€” see issue #242. Named anchors let one Markdown file
159
+ * hold more than one block, such as an `nx` block today and an `nestjs` block
160
+ * once `codependix-nestjs-modules` ships, without the blocks colliding.
161
+ */
162
+ export declare const buildStartMarker: (anchorName: string) => string;
163
+
164
+ /**
165
+ * The single heading every project's (and the workspace's) auto-created
166
+ * Codependix section is placed under.
167
+ *
168
+ * Matched literally against a whole line, so a heading a human wrote by hand
169
+ * with this exact text is recognized and reused rather than duplicated β€” see
170
+ * `AnchorsService.insertAnchorSection`.
171
+ */
172
+ export declare const CODEPENDIX_SECTION_HEADING = "## \uD83D\uDD78\uFE0F Codependix";
173
+
174
+ /**
175
+ * One graph type's whole-workspace data, captured once per run for combined
176
+ * output β€” see `CombinedOutputService`.
177
+ *
178
+ * `json` is the same exported shape a workspace-level JSON destination would
179
+ * receive; `markdown` is the same rendered mermaid diagram a workspace-level
180
+ * Markdown destination would receive. Both are captured unconditionally,
181
+ * whether or not this run's configuration names a workspace destination for
182
+ * that graph type, so `--format`/`--json-output`/`--markdown-output` work
183
+ * even for a workspace that configured no destination of its own.
184
+ */
185
+ export declare interface CombinedGraphEntry {
186
+ json: unknown;
187
+ markdown: string;
188
+ }
189
+
190
+ /**
191
+ * Every active graph type's whole-workspace data from one run, keyed by
192
+ * graph type β€” the structure `--json-output`/`--markdown-output`/`--format`
193
+ * read from. A type absent from this map was not active for the run β€” see
194
+ * `GraphRunContext.enabledGraphTypes`.
195
+ */
196
+ export declare type CombinedGraphExports = Partial<Record<CodependixGraphType, CombinedGraphEntry>>;
197
+
198
+ /**
199
+ * What `--format` prints, derived from the list it is validated against β€”
200
+ * see `FORMAT_NAMES`.
201
+ */
202
+ export declare type CombinedOutputFormat = (typeof FORMAT_NAMES)[number];
203
+
204
+ /** Provides the combined JSON/Markdown output and `--format` console pass. */
205
+ export declare class CombinedOutputModule {
206
+ }
207
+
208
+ /** Arguments for producing every combined output a run asked for. */
209
+ declare interface CombinedOutputRunArguments {
210
+ format: CombinedOutputFormat;
211
+ graphs: CombinedGraphExports;
212
+ jsonOutputPath: string | undefined;
213
+ markdownOutputPath: string | undefined;
214
+ workingDirectory: string;
215
+ }
216
+
217
+ /**
218
+ * Combines every active graph type's whole-workspace data into the single
219
+ * JSON object and single Markdown document `--json-output`,
220
+ * `--markdown-output`, and `--format` each read from, and delivers them.
221
+ *
222
+ * Kept apart from `DeliveryService`, which delivers one graph type's export
223
+ * to its own per-project or per-workspace destination: this service instead
224
+ * combines every active type's already-built data β€” see
225
+ * `GraphRunService.run` and `WorkspaceGraphsService` for where that data comes
226
+ * from β€” into one shared destination or one shared stdout write. Neither
227
+ * output is checked for staleness the way a per-project export is:
228
+ * `--json-output`/`--markdown-output` always write, matching
229
+ * `codometer-cli`'s own `--output-json`/`--output-markdown` precedent.
230
+ */
231
+ export declare class CombinedOutputService {
232
+ private readonly anchorsService;
233
+ constructor(anchorsService: AnchorsService);
234
+ /** Prints whatever `--format` asked for. Never touches a file. */
235
+ private printConsole;
236
+ /** Builds the combined JSON object's content, keyed by graph type. */
237
+ private renderJson;
238
+ /** Builds the combined Markdown document's content from every active type. */
239
+ private renderMarkdown;
240
+ /** Writes a combined destination's content, creating its directory first. */
241
+ private writeFile;
242
+ /**
243
+ * Reads `--format` into what the run prints, falling back to
244
+ * `FORMAT_MARKDOWN` when the flag was left off entirely β€” codependix's
245
+ * configuration declares no `format` field of its own for this to read
246
+ * instead, unlike `codometer-cli`'s own `resolveFormat`.
247
+ */
248
+ resolveFormat(value: string | undefined): {
249
+ errors: string[];
250
+ format: CombinedOutputFormat;
251
+ };
252
+ /**
253
+ * Produces every combined output a run asked for: the console print
254
+ * `--format` always names, and the `--json-output`/`--markdown-output`
255
+ * files when their paths were given.
256
+ *
257
+ * A run naming no active graph type at all β€” every `--no-*` flag given β€”
258
+ * still prints and writes, with an empty object or an empty document: the
259
+ * flags are independent of which graph types are active, exactly as
260
+ * `--check`/`--write` are.
261
+ */
262
+ run(args: CombinedOutputRunArguments): void;
263
+ }
264
+
265
+ /** Every active graph type's path query outcome, keyed by type. */
266
+ export declare type CombinedPathResults = Partial<Record<CodependixGraphType, PathQueryResult>>;
267
+
268
+ /**
269
+ * Arguments for delivering one project's (or the workspace's) resolved
270
+ * export configuration.
271
+ *
272
+ * `jsonContent`/`markdownContent` are rendered by the caller β€” every graph
273
+ * type renders its own JSON shape and its own diagram β€” and are only read
274
+ * when the resolved output actually touches that destination, so a caller
275
+ * whose target is `"markdown"` never has to render JSON it will not deliver.
276
+ */
277
+ declare interface DeliverGraphOutputArguments {
278
+ jsonContent: string | undefined;
279
+ markdownContent: string | undefined;
280
+ /**
281
+ * The heading text used to auto-create a missing anchor's section on write.
282
+ *
283
+ * `undefined` for a standalone (non-anchored) Markdown destination, which
284
+ * has no section to create. Required whenever the destination is anchored
285
+ * and might need auto-creation β€” see `DeliveryService.deliverAnchoredMarkdown`.
286
+ */
287
+ markdownSection: MarkdownSectionArguments | undefined;
288
+ mode: CodependixRunMode;
289
+ project: DeliveryProject;
290
+ resolvedOutput: ResolvedCodependixGraphOutput;
291
+ }
292
+
293
+ /** Provides the generic graph-export delivery mechanism every graph type uses. */
294
+ export declare class DeliveryModule {
295
+ }
296
+
297
+ /** The project (or workspace) a graph export is delivered relative to. */
298
+ declare interface DeliveryProject {
299
+ absoluteRoot: string;
300
+ name: string;
301
+ }
302
+
303
+ /**
304
+ * Delivers a resolved graph export to whichever destinations it names.
305
+ *
306
+ * Every codependix graph type β€” the Nx Neighborhood, the Nx Workspace Graph,
307
+ * and the NestJS module graph β€” resolves to the same
308
+ * `ResolvedCodependixGraphOutput` shape and is delivered the same way: a JSON
309
+ * file, an anchored or standalone Markdown file, or both. This service is
310
+ * the one place that shape is turned into file I/O, so `GraphRunService`
311
+ * only has to render each graph type's own JSON and diagram content and hand
312
+ * it over.
313
+ */
314
+ export declare class DeliveryService {
315
+ private readonly anchorsService;
316
+ constructor(anchorsService: AnchorsService);
317
+ /**
318
+ * Checks whether a named anchor block is current against fresh content.
319
+ *
320
+ * A missing anchor is reported as stale rather than throwing, consistent
321
+ * with every other kind of drift this tool reports.
322
+ */
323
+ private checkAnchoredMarkdown;
324
+ /** Classifies whether a difference is formatting or graph structure. */
325
+ private classifyDifference;
326
+ /** Delivers a JSON destination, recording it as stale if needed. */
327
+ private deliverJson;
328
+ /** Delivers a Markdown destination, recording it as stale if needed. */
329
+ private deliverMarkdown;
330
+ /** Reads a file's content, or an empty string when it does not exist yet. */
331
+ private readFileOrEmpty;
332
+ /**
333
+ * Resolves the JSON destination a graph output should deliver to, or
334
+ * `undefined` when the target does not touch JSON, no destination was
335
+ * configured, or the caller rendered no JSON content for it.
336
+ */
337
+ private resolveJsonDelivery;
338
+ /**
339
+ * Resolves the Markdown destination a graph output should deliver to, or
340
+ * `undefined` when the target does not touch Markdown, no destination was
341
+ * configured, or the caller rendered no diagram content for it.
342
+ */
343
+ private resolveMarkdownDelivery;
344
+ /** Splices content into a named anchor block on write. */
345
+ private writeAnchoredMarkdown;
346
+ /**
347
+ * Auto-creates a missing anchor's `## πŸ•ΈοΈ Codependix` section and writes it.
348
+ *
349
+ * Falls back to the historical hard failure when the caller supplied no
350
+ * `markdownSection` β€” there is nothing safe to build without a heading and
351
+ * intro line, and `GraphRunService` always supplies one for every real
352
+ * anchored destination it delivers.
353
+ */
354
+ private writeAutoCreatedAnchorSection;
355
+ /**
356
+ * Delivers whichever destinations a resolved graph output names.
357
+ *
358
+ * `jsonContent`/`markdownContent` are read only when the resolved target
359
+ * actually touches that destination, mirroring how a project whose target
360
+ * is `"json"` never renders a diagram nobody configured.
361
+ */
362
+ deliverGraphOutput(args: DeliverGraphOutputArguments): ProjectRunResult;
363
+ /** Renders an export as JSON the same way every run of codependix would. */
364
+ renderJson(exportedGraph: unknown): string;
365
+ }
366
+
367
+ /** What `--format json` prints: every active graph type's data, keyed by type. */
368
+ export declare const FORMAT_JSON = "json";
369
+
370
+ /**
371
+ * What `--format markdown` prints: every active graph type's rendered
372
+ * diagram. Also what `--format` prints when the flag is left off entirely β€”
373
+ * unlike codometer, whose fallback reads a resolved configuration field,
374
+ * codependix's configuration declares no `format` field of its own, so the
375
+ * default is this same fixed constant instead of a second one aliasing it.
376
+ */
377
+ export declare const FORMAT_MARKDOWN = "markdown";
378
+
379
+ /** What `--format mermaid` prints: each active graph type rendered as a mermaid flowchart. */
380
+ export declare const FORMAT_MERMAID = "mermaid";
381
+
382
+ /**
383
+ * Everything `--format` accepts, in the order an error message lists them.
384
+ *
385
+ * A tuple rather than a bare union: `MapCommand.parseFormat` validates
386
+ * against this array directly, so a format added here is accepted everywhere
387
+ * the moment it is rendered β€” mirroring `codometer-cli`'s own `FORMAT_NAMES`.
388
+ */
389
+ export declare const FORMAT_NAMES: readonly ["json", "markdown"];
390
+
391
+ /** Wires every graph-type export pass together behind one orchestrator. */
392
+ export declare class GraphRunModule {
393
+ }
394
+
395
+ /**
396
+ * Orchestrates every configured graph export, one pass per graph type.
397
+ *
398
+ * Owns none of the per-project or per-workspace rendering itself:
399
+ * `ProjectGraphsService` builds, renders, and delivers each included
400
+ * project's own graph, and `WorkspaceGraphsService` does the same for each
401
+ * type's whole-workspace graph. This service's own job is deciding which
402
+ * types are active, running both passes for each, combining their outcomes,
403
+ * and collecting each active type's whole-workspace data into a
404
+ * `CombinedGraphExports` map β€” for `CombinedOutputService` to print and
405
+ * write, see `MapCommand`.
406
+ *
407
+ * Every pass isolates one project's failure from the rest: a missing anchor
408
+ * or a NestJS project that fails to boot its container is collected as a
409
+ * `ProjectRunFailure` rather than aborting the loop.
410
+ */
411
+ export declare class GraphRunService {
412
+ private readonly logger;
413
+ private readonly neighborhoodService;
414
+ private readonly projectGraphsService;
415
+ private readonly pythonImportsService;
416
+ private readonly workspaceGraphsService;
417
+ constructor(logger: LoggerService, neighborhoodService: NeighborhoodService, projectGraphsService: ProjectGraphsService, pythonImportsService: PythonImportsService, workspaceGraphsService: WorkspaceGraphsService);
418
+ /**
419
+ * Collects every active graph type's whole-workspace data into the map
420
+ * `CombinedOutputService` reads from, dropping a type this run built no
421
+ * whole-workspace graph for at all β€” see `GraphTypePassOutcome`.
422
+ */
423
+ private collectCombinedGraphs;
424
+ /** Turns a raised error into a `ProjectRunFailure` for the given project. */
425
+ private collectProjectFailure;
426
+ /**
427
+ * Runs one synchronous whole-workspace graph builder, pushes its delivery
428
+ * outcome when it produced one, and returns its combined-output entry.
429
+ *
430
+ * Shared by `runNxGraphs` and `runImportGraphs`, whose own
431
+ * `WorkspaceGraphsService` calls are both synchronous;
432
+ * `runNestjsGraphs`'s own call is asynchronous and keeps its own inline
433
+ * `try`/`catch` rather than sharing this one.
434
+ */
435
+ private collectWorkspaceOutcome;
436
+ /**
437
+ * Runs every configured graph export against an already-resolved context.
438
+ *
439
+ * Every pass is attempted regardless of an earlier failure: the four graph
440
+ * types are independent. A type `context.enabledGraphTypes` excludes is
441
+ * skipped entirely, so `--no-nestjs-modules` never boots a container. Also
442
+ * returns `combinedGraphs` β€” every active type's whole-workspace data,
443
+ * collected for `MapCommand` to hand to `CombinedOutputService`.
444
+ */
445
+ run(context: GraphRunContext): Promise<MapRunResult>;
446
+ /**
447
+ * Builds and delivers every configured file-level import graph export β€”
448
+ * each included project's own graph, from `ProjectGraphsService`, and the
449
+ * whole-workspace file-imports graph `WorkspaceGraphsService` combines
450
+ * from every TypeScript and Python project.
451
+ */
452
+ runImportGraphs(context: GraphRunContext): GraphTypePassOutcome;
453
+ /**
454
+ * Builds and delivers every configured NestJS module graph export β€” each
455
+ * included project's own graph, from `ProjectGraphsService`, and the
456
+ * whole-workspace NestJS module graph `WorkspaceGraphsService` combines
457
+ * from every NestJS project.
458
+ */
459
+ runNestjsGraphs(context: GraphRunContext): Promise<GraphTypePassOutcome>;
460
+ /**
461
+ * Builds and delivers every configured Nx graph export β€” each included
462
+ * project's Neighborhood, from `ProjectGraphsService`, and the
463
+ * whole-workspace Workspace Graph, from `WorkspaceGraphsService`.
464
+ */
465
+ runNxGraphs(context: GraphRunContext): GraphTypePassOutcome;
466
+ /**
467
+ * Builds and delivers every configured Python file-level import graph
468
+ * export.
469
+ *
470
+ * Delegates to `PythonImportsService`. Reports no whole-workspace data of
471
+ * its own: the Python graphs it builds are already folded into the
472
+ * `fileImports` combined entry `runImportGraphs` reports β€” see
473
+ * `WorkspaceGraphsService.runFileImportsWorkspaceGraph`.
474
+ */
475
+ runPythonImportGraphs(context: GraphRunContext): GraphRunOutcome;
476
+ }
477
+
478
+ /**
479
+ * One graph-type pass's outcome: the usual per-project delivery outcome,
480
+ * plus this type's whole-workspace data for combined output.
481
+ *
482
+ * `workspaceEntry` is `undefined` both when the pass built no whole-workspace
483
+ * graph of its own (`fileImports`'s Python pass, folded into the TypeScript
484
+ * pass's own `fileImports` entry β€” see `GraphRunService.runImportGraphs`) and
485
+ * when the one it owns resolved to a `"none"` target β€” see
486
+ * `WorkspaceGraphsService`.
487
+ */
488
+ declare interface GraphTypePassOutcome extends GraphRunOutcome {
489
+ workspaceEntry: CombinedGraphEntry | undefined;
490
+ }
491
+
492
+ /**
493
+ * Structured values that belong beside a log line rather than inside it.
494
+ *
495
+ * Counts, percentages, and durations are the values that change on every
496
+ * occurrence, so they are carried as fields: the message stays constant and
497
+ * groupable in telemetry, and the numbers stay queryable instead of having to
498
+ * be parsed back out of prose.
499
+ *
500
+ * The named members are the recurring ones; the index signature keeps the
501
+ * argument open for whatever a given call site needs to attach.
502
+ */
503
+ declare interface LogData {
504
+ [key: string]: unknown;
505
+ /** How many things the operation handled. */
506
+ count?: number;
507
+ /** Wall-clock milliseconds the operation took. */
508
+ durationMs?: number;
509
+ /** Completion between 0 and 100. */
510
+ percent?: number;
511
+ /** How many things the operation set out to handle. */
512
+ total?: number;
513
+ }
514
+
515
+ /**
516
+ * Transient-scoped logger so each injecting class gets its own instance.
517
+ * Each consumer calls `setContext(ClassName.name)` to tag every log line
518
+ * with the originating class. Backed by pino for structured JSON output in
519
+ * production and human-readable pretty-print in development.
520
+ *
521
+ * Messages follow one grammar: an emoji naming the subject, a verb in present
522
+ * progressive or past tense, then the object. Values that vary per call β€”
523
+ * counts, percentages, durations β€” go in the `data` argument rather than the
524
+ * message, so the message stays constant enough for telemetry to group on.
525
+ *
526
+ * ```ts
527
+ * this.logger.info("πŸ“₯ Downloading CSEL sources", undefined, { total: 428 });
528
+ * this.logger.info("πŸ“₯ Downloaded CSEL sources", undefined, { count: 412 });
529
+ * ```
530
+ */
531
+ declare @Injectable({ scope: Scope.TRANSIENT })
532
+ class LoggerService extends ConsoleLogger {
533
+ // πŸ— Dependency Injection
534
+
535
+ constructor() {
536
+ super();
537
+ }
538
+
539
+ // πŸ” Private Fields
540
+
541
+ private static readonly isProduction =
542
+ process.env["NODE_ENV"] === "production";
543
+
544
+ /**
545
+ * Built on first use, not when this file is evaluated.
546
+ *
547
+ * A destination fixed at import time could only ever be chosen by this
548
+ * package, since every consumer's own code runs after its imports.
549
+ */
550
+ private static rootLogger: pino.Logger | undefined;
551
+
552
+ /** Whether lines go to standard error instead of standard output. */
553
+ private static writesToStandardError = false;
554
+
555
+ private child: pino.Logger = LoggerService.root;
556
+
557
+ // πŸ”‘ Public Fields
558
+
559
+ // πŸ” Private Methods
560
+
561
+ /** Build the pino instance for production or local development output. */
562
+ private static createRootLogger(): pino.Logger {
563
+ const level = process.env["LOG_LEVEL"] ?? "info";
564
+
565
+ if (LoggerService.isProduction) {
566
+ return LoggerService.writesToStandardError
567
+ ? pino({ level }, pino.destination(STANDARD_ERROR_DESCRIPTOR))
568
+ : pino({ level });
569
+ }
570
+
571
+ return pino({
572
+ level,
573
+ transport: {
574
+ options: {
575
+ colorize: true,
576
+ destination: LoggerService.writesToStandardError
577
+ ? STANDARD_ERROR_DESCRIPTOR
578
+ : STANDARD_OUTPUT_DESCRIPTOR,
579
+ // The emoji is a field, not part of the message, so the console can
580
+ // show it while telemetry stores unadorned prose. `ignore` then keeps
581
+ // it from being printed a second time in the trailing object.
582
+ ignore: "pid,hostname,emoji",
583
+ messageFormat: "{emoji} {msg}",
584
+ singleLine: true,
585
+ },
586
+ target: "pino-pretty",
587
+ },
588
+ });
589
+ }
590
+
591
+ /**
592
+ * Sends every subsequent line to standard error instead of standard output.
593
+ *
594
+ * For a command-line application whose standard output *is* its result. A log
595
+ * line sharing that stream is not a diagnostic beside the data, it is a
596
+ * corruption of it. Call it before anything logs β€” the first statement of the
597
+ * application's bootstrap.
598
+ *
599
+ * A call after the first line warns and changes nothing: the destination is
600
+ * fixed when the pino instance is built, and tearing down a transport
601
+ * somebody is writing through would be worse than refusing. The warning is
602
+ * the point β€” silently leaving the lines on standard output is how a caller
603
+ * would ship a corrupted pipe without ever being told.
604
+ */
605
+ static logToStandardError(): void {
606
+ if (LoggerService.rootLogger !== undefined) {
607
+ process.emitWarning(
608
+ "LoggerService.logToStandardError() was called after the first log line, so log lines still go to standard output and anything piping that stream will read them as data. Call it as the first statement of the application's bootstrap.",
609
+ );
610
+ return;
611
+ }
612
+
613
+ LoggerService.writesToStandardError = true;
614
+ }
615
+
616
+ /**
617
+ * Fails a malformed message in development, and never in production.
618
+ *
619
+ * A logger that throws in production turns an observability call into an
620
+ * outage, so the check runs only where a developer is present to fix it.
621
+ */
622
+ private assertConventionalMessage(args: {
623
+ context: string | undefined;
624
+ parsed: ParsedLogMessage;
625
+ }): void {
626
+ if (
627
+ LoggerService.isProduction ||
628
+ this.shouldSkipConventionalMessageValidation(args.context)
629
+ ) {
630
+ return;
631
+ }
632
+
633
+ const violation = this.getConventionalMessageViolation(args.parsed);
634
+
635
+ if (violation !== undefined) {
636
+ throw new Error(violation);
637
+ }
638
+ }
639
+
640
+ /** Assembles the object pino merges into the line. */
641
+ private buildBindings(args: {
642
+ context: string | undefined;
643
+ data: LogData | undefined;
644
+ parsed: ParsedLogMessage;
645
+ }): Record<string, unknown> {
646
+ this.assertConventionalMessage({
647
+ context: args.context,
648
+ parsed: args.parsed,
649
+ });
650
+
651
+ return {
652
+ ...args.data,
653
+ context: args.context,
654
+ // Telemetry gets prose; only the console-bound transport reads this.
655
+ ...(LoggerService.isProduction ? {} : { emoji: args.parsed.emoji }),
656
+ };
657
+ }
658
+
659
+ /** Returns a human-readable explanation when the message format is invalid. */
660
+ private getConventionalMessageViolation(
661
+ parsed: ParsedLogMessage,
662
+ ): string | undefined {
663
+ const emoji = parsed.emoji;
664
+ const text = parsed.text;
665
+
666
+ if (emoji === undefined) {
667
+ return `Log message must start with an emoji naming its subject, then a verb: "${text}"`;
668
+ }
669
+
670
+ const firstWord = FIRST_WORD_PATTERN.exec(text)?.[1];
671
+
672
+ if (firstWord === undefined || !this.isConventionalVerb(firstWord)) {
673
+ return `Log message must begin with a verb in present progressive or past tense, got "${firstWord ?? ""}": "${emoji} ${text}"`;
674
+ }
675
+
676
+ return undefined;
677
+ }
678
+
679
+ /**
680
+ * Whether a word is a verb in one of the two tenses the convention allows.
681
+ *
682
+ * Present progressive means the operation is under way; past means it
683
+ * finished. Regular morphology covers both, so a new verb needs no
684
+ * registration anywhere β€” only irregular pasts are enumerated.
685
+ */
686
+ private isConventionalVerb(word: string): boolean {
687
+ const lowercased = word.toLowerCase();
688
+
689
+ return (
690
+ lowercased.endsWith("ing") ||
691
+ lowercased.endsWith("ed") ||
692
+ IRREGULAR_PAST_VERBS.has(lowercased)
693
+ );
694
+ }
695
+
696
+ /** Splits a leading emoji off a message, leaving prose behind. */
697
+ private parseMessage(message: unknown): ParsedLogMessage {
698
+ const text = String(message);
699
+ const match = LEADING_EMOJI_PATTERN.exec(text);
700
+ const emoji = match?.[1];
701
+
702
+ return emoji === undefined
703
+ ? { emoji: undefined, text }
704
+ : { emoji, text: text.slice(match?.[0].length) };
705
+ }
706
+
707
+ /** Whether a context is intentionally exempt from the validation rule. */
708
+ private shouldSkipConventionalMessageValidation(
709
+ context: string | undefined,
710
+ ): boolean {
711
+ return context !== undefined && UNVALIDATED_LOG_CONTEXTS.has(context);
712
+ }
713
+
714
+ // 🌎 Public Methods
715
+
716
+ /** The pino instance every logger's child is taken from. */
717
+ private static get root(): pino.Logger {
718
+ LoggerService.rootLogger ??= LoggerService.createRootLogger();
719
+
720
+ return LoggerService.rootLogger;
721
+ }
722
+
723
+ /** Normalizes unknown errors into a stable message and timestamped log line. */
724
+ buildErrorLogEntry(
725
+ context: string,
726
+ error: unknown,
727
+ ): { errorMessage: string; logLine: string } {
728
+ const errorMessage =
729
+ error instanceof Error ? error.stack || error.message : String(error);
730
+
731
+ return {
732
+ errorMessage,
733
+ logLine: `[${new Date().toISOString()}] ${context}: ${errorMessage}\n`,
734
+ };
735
+ }
736
+
737
+ /** Builds a timestamped output log file path and ensures the output directory exists. */
738
+ createTimestampedOutputLogFilePath(filePrefix: string): string {
739
+ const outputDirectory = path.join(process.cwd(), "output");
740
+ if (!existsSync(outputDirectory)) {
741
+ mkdirSync(outputDirectory, { recursive: true });
742
+ }
743
+
744
+ return path.join(
745
+ outputDirectory,
746
+ `${filePrefix}-${new Date().toISOString().replaceAll(/[:.]/g, "-")}.log`,
747
+ );
748
+ }
749
+
750
+ /** Logs a debug message at the `debug` level. */
751
+ override debug(message: unknown, context?: string, data?: LogData): void {
752
+ const parsed = this.parseMessage(message);
753
+ this.child.debug(
754
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
755
+ parsed.text,
756
+ );
757
+ }
758
+
759
+ /**
760
+ * Logs an error message at the `error` level, optionally including a stack trace.
761
+ *
762
+ * `ConsoleLogger.error` spends a third slot on a context string that the
763
+ * other levels do not have, so this one accepts either: a string keeps
764
+ * NestJS's meaning, an object is structured data like everywhere else.
765
+ */
766
+ override error(
767
+ message: unknown,
768
+ stackOrContext?: string,
769
+ contextOrData?: LogData | string,
770
+ ): void {
771
+ const parsed = this.parseMessage(message);
772
+ const data = typeof contextOrData === "object" ? contextOrData : undefined;
773
+ const context =
774
+ typeof contextOrData === "string" ? contextOrData : this.context;
775
+
776
+ this.child.error(
777
+ {
778
+ ...this.buildBindings({ context, data, parsed }),
779
+ stack: stackOrContext,
780
+ },
781
+ parsed.text,
782
+ );
783
+ }
784
+
785
+ /** Logs an informational message at the `info` level. */
786
+ info(message: unknown, context?: string, data?: LogData): void {
787
+ const parsed = this.parseMessage(message);
788
+ this.child.info(
789
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
790
+ parsed.text,
791
+ );
792
+ }
793
+
794
+ /**
795
+ * Logs an informational message at the `info` level.
796
+ *
797
+ * NestJS and `nest-commander` call this method directly as part of the
798
+ * framework's own `LoggerService` contract, so it must keep working
799
+ * exactly as before. Application code should call `info` instead β€” the
800
+ * same behavior under a name that says what level it logs at.
801
+ */
802
+ override log(message: unknown, context?: string, data?: LogData): void {
803
+ this.info(message, context, data);
804
+ }
805
+
806
+ /** Sets the context label included in every subsequent log line. */
807
+ override setContext(context: string): void {
808
+ super.setContext(context);
809
+ this.child = LoggerService.root.child({ context });
810
+ }
811
+
812
+ /** Logs a verbose message at the `trace` level. */
813
+ override verbose(message: unknown, context?: string, data?: LogData): void {
814
+ const parsed = this.parseMessage(message);
815
+ this.child.trace(
816
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
817
+ parsed.text,
818
+ );
819
+ }
820
+
821
+ /** Logs a warning message at the `warn` level. */
822
+ override warn(message: unknown, context?: string, data?: LogData): void {
823
+ const parsed = this.parseMessage(message);
824
+ this.child.warn(
825
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
826
+ parsed.text,
827
+ );
828
+ }
829
+ }
830
+
831
+ /**
832
+ * What `GraphRunService.run` resolves: the usual delivery outcome, and every
833
+ * active graph type's whole-workspace data for combined output β€” see
834
+ * `CombinedGraphExports`.
835
+ */
836
+ export declare interface MapRunResult {
837
+ combinedGraphs: CombinedGraphExports;
838
+ outcome: GraphRunOutcome;
839
+ }
840
+
841
+ /**
842
+ * The intro line placed under a newly auto-created `## πŸ•ΈοΈ Codependix`
843
+ * heading β€” copied verbatim from the wording a human already placed by hand
844
+ * in `packages/logger/README.md`, so an auto-created section reads exactly
845
+ * like one a person wrote.
846
+ */
847
+ export declare const MARKDOWN_SECTION_INTRO_LINE = "Dependency graphs exported by [codependix](https://github.com/Organizzolini/codebase/tree/main/packages/ic-suite/codependix/codependix-cli), regenerated by `nx run codebase:codependix:write`.";
848
+
849
+ /**
850
+ * The JSON shape a single project's NestJS module graph export is written as.
851
+ *
852
+ * Identical in shape to `NestjsModuleGraph` itself β€” kept as its own named
853
+ * type so the export's JSON shape can evolve independently of
854
+ * `codependix-nestjs-modules`'s internal representation, the same reasoning
855
+ * `NxWorkspaceGraphExport` follows for the Nx Workspace Graph.
856
+ */
857
+ export declare type NestjsModuleGraphExport = NestjsModuleGraph;
858
+
859
+ /** The JSON shape a single project's Nx neighborhood export is written as. */
860
+ export declare interface NxNeighborhoodExport {
861
+ dependencies: string[];
862
+ dependents: string[];
863
+ edges: Neighborhood["edges"];
864
+ projectName: string;
865
+ }
866
+
867
+ /**
868
+ * The JSON shape the whole-workspace Nx Workspace Graph export is written as.
869
+ *
870
+ * Identical in shape to `WorkspaceGraph` itself β€” no extra field is added the
871
+ * way `NxNeighborhoodExport` adds none beyond `Neighborhood` either β€” kept as
872
+ * its own named type so the export's JSON shape can evolve independently of
873
+ * `codependix-nx-projects`'s internal `WorkspaceGraph` representation.
874
+ */
875
+ export declare type NxWorkspaceGraphExport = WorkspaceGraph;
876
+
877
+ /** A message split into the emoji the console shows and the prose telemetry stores. */
878
+ declare interface ParsedLogMessage {
879
+ emoji: string | undefined;
880
+ text: string;
881
+ }
882
+
883
+ /** Arrow connecting successive nodes in a Markdown path. */
884
+ export declare const PATH_ARROW = " \u2192 ";
885
+
886
+ /** Formats accepted by the path command's `--format` flag. */
887
+ export declare const PATH_FORMAT_NAMES: readonly ["json", "markdown", "mermaid"];
888
+
889
+ /** Header declaring the mermaid diagram type for path rendering. */
890
+ export declare const PATH_MERMAID_HEADER = "graph LR";
891
+
892
+ /** What `--format` prints for a path query. */
893
+ export declare type PathFormat = (typeof PATH_FORMAT_NAMES)[number];
894
+
895
+ /** Arguments for executing a path query. */
896
+ export declare interface PathQueryArguments {
897
+ context: GraphRunContext;
898
+ from: string;
899
+ to: string;
900
+ }
901
+
902
+ /** Provides path query and rendering services across graph levels. */
903
+ export declare class PathQueryModule {
904
+ }
905
+
906
+ /** The outcome of querying a connecting path for one graph type. */
907
+ export declare interface PathQueryResult {
908
+ from: string;
909
+ path: null | string[];
910
+ to: string;
911
+ }
912
+
913
+ /**
914
+ * Searches for connecting paths between two nodes in codependix graphs and renders results.
915
+ */
916
+ export declare class PathQueryService {
917
+ private readonly fileImportsWorkspaceGraphService;
918
+ private readonly moduleGraphService;
919
+ private readonly nestjsModulesWorkspaceGraphService;
920
+ private readonly nestjsProjectService;
921
+ private readonly pythonService;
922
+ private readonly typescriptService;
923
+ private readonly workspaceGraphService;
924
+ constructor(fileImportsWorkspaceGraphService: FileImportsWorkspaceGraphService, moduleGraphService: ModuleGraphService, nestjsModulesWorkspaceGraphService: NestjsModulesWorkspaceGraphService, nestjsProjectService: NestjsProjectService, pythonService: PythonService, typescriptService: TypescriptService, workspaceGraphService: WorkspaceGraphService);
925
+ /** Builds an adjacency map from directed edges with sorted targets. */
926
+ private buildAdjacency;
927
+ /**
928
+ * Explores and builds every discovered NestJS project's module graph.
929
+ */
930
+ private buildNestjsModuleGraphs;
931
+ /** Checks whether a node is present in the graph's node list or edges. */
932
+ private isKnownNode;
933
+ /** Queries the file-imports workspace graph for a path between two files. */
934
+ private queryFileImports;
935
+ /** Queries the NestJS modules workspace graph for a path between two modules. */
936
+ private queryNestjsModules;
937
+ /** Queries the Nx project graph for a path between two projects. */
938
+ private queryNxProjects;
939
+ /** Renders every active graph type's path as Markdown text. */
940
+ private renderMarkdown;
941
+ /** Renders every active graph type's path as a Mermaid diagram. */
942
+ private renderMermaid;
943
+ /** Renders a single path entry as a Mermaid diagram block or no-path message. */
944
+ private renderMermaidSection;
945
+ /** Runs deterministic breadth-first search to find the shortest path. */
946
+ private searchBfs;
947
+ /** Converts a node name to a safe Mermaid identifier. */
948
+ private toMermaidId;
949
+ /**
950
+ * Finds the shortest directed path between two nodes in a given edge set.
951
+ */
952
+ findShortestPath(args: {
953
+ edges: readonly {
954
+ source: string;
955
+ target: string;
956
+ }[];
957
+ from: string;
958
+ nodes?: readonly string[] | undefined;
959
+ to: string;
960
+ }): null | string[];
961
+ /**
962
+ * Queries every enabled graph type for a connecting path between two nodes.
963
+ */
964
+ query(args: PathQueryArguments): Promise<CombinedPathResults>;
965
+ /** Renders combined path query results according to the selected format. */
966
+ render(args: PathReportArguments): string;
967
+ /**
968
+ * Reads `--format` into what the run prints, falling back to
969
+ * `FORMAT_MARKDOWN` when the flag was left off entirely.
970
+ */
971
+ resolveFormat(value: string | undefined): {
972
+ errors: string[];
973
+ format: PathFormat;
974
+ };
975
+ }
976
+
977
+ /** Arguments for rendering path query results. */
978
+ export declare interface PathReportArguments {
979
+ format: PathFormat;
980
+ results: CombinedPathResults;
981
+ }
982
+
983
+ /**
984
+ * Builds, renders, and delivers every included project's own graph, for
985
+ * each of the three graph types β€” the Nx Neighborhood, the TypeScript/Python
986
+ * file-level import graph, and the NestJS module graph.
987
+ *
988
+ * Split out of `GraphRunService`, which keeps only orchestration β€” resolving the
989
+ * context once, deciding which graph types are active, and combining this
990
+ * service's per-project outcome with `WorkspaceGraphsService`'s own
991
+ * whole-workspace one β€” purely to stay under this repository's per-file line
992
+ * limit. Every method here isolates one project's failure from the rest: a
993
+ * missing anchor or a NestJS project that fails to boot its container is
994
+ * collected as a `ProjectRunFailure` rather than aborting the loop.
995
+ */
996
+ declare class ProjectGraphsService {
997
+ private readonly configurationService;
998
+ private readonly deliveryService;
999
+ private readonly moduleGraphService;
1000
+ private readonly neighborhoodService;
1001
+ private readonly nestjsProjectService;
1002
+ private readonly typescriptService;
1003
+ constructor(configurationService: ConfigurationService, deliveryService: DeliveryService, moduleGraphService: ModuleGraphService, neighborhoodService: NeighborhoodService, nestjsProjectService: NestjsProjectService, typescriptService: TypescriptService);
1004
+ /**
1005
+ * Builds the section heading a graph type's anchored Markdown destination
1006
+ * auto-creates when it is missing.
1007
+ */
1008
+ private buildMarkdownSection;
1009
+ /** Turns a neighborhood into the JSON shape it is exported as. */
1010
+ private buildNeighborhoodJsonExport;
1011
+ /** Turns a raised error into a `ProjectRunFailure` for the given project. */
1012
+ private collectProjectFailure;
1013
+ /** Resolves one project's export target for a graph type, carrying its root/tags. */
1014
+ private resolveProjectOutput;
1015
+ /** Builds, renders, and delivers one project's file-level import Graph. */
1016
+ private runImportProject;
1017
+ /** Explores, renders, and delivers one NestJS project's module graph. */
1018
+ private runNestjsProject;
1019
+ /** Renders and delivers one project's Nx Neighborhood. */
1020
+ private runNxProject;
1021
+ /** Builds, renders, and delivers every included TypeScript project's own file-level import graph. */
1022
+ runFileImportsProjects(context: GraphRunContext): GraphRunOutcome;
1023
+ /** Explores, builds, renders, and delivers every included NestJS project's own module graph. */
1024
+ runNestjsModulesProjects(context: GraphRunContext): Promise<GraphRunOutcome>;
1025
+ /** Renders and delivers every included project's own Nx Neighborhood. */
1026
+ runNxProjectsGraphs(args: {
1027
+ context: GraphRunContext;
1028
+ neighborhoods: Map<string, Neighborhood>;
1029
+ }): GraphRunOutcome;
1030
+ }
1031
+
1032
+ /**
1033
+ * Builds and delivers every configured Python file-level import graph
1034
+ * export.
1035
+ *
1036
+ * Split out of `GraphRunService` β€” which owns the same pass for every
1037
+ * other graph type β€” purely to keep that file under this repository's
1038
+ * per-file line limit; the pass itself follows
1039
+ * `GraphRunService.runImportGraphs` exactly, one collaborator per language
1040
+ * instead of one compiler-backed `ts.Program` per project.
1041
+ */
1042
+ declare class PythonImportsService {
1043
+ private readonly configurationService;
1044
+ private readonly deliveryService;
1045
+ private readonly pythonService;
1046
+ constructor(configurationService: ConfigurationService, deliveryService: DeliveryService, pythonService: PythonService);
1047
+ /** Builds the section heading a missing anchor auto-creates. */
1048
+ private buildMarkdownSection;
1049
+ /** Turns a raised error into a `ProjectRunFailure` for the given project. */
1050
+ private collectProjectFailure;
1051
+ /**
1052
+ * Resolves one project's export target for this graph type, including its
1053
+ * workspace-relative root and its Nx tags, so `include`/`exclude` globs may
1054
+ * match either and `--tags` reaches the tags β€” the same resolution
1055
+ * `GraphRunService.resolveProjectOutput` performs for every other graph type.
1056
+ */
1057
+ private resolveProjectOutput;
1058
+ /** Builds, renders, and delivers one project's Python import graph. */
1059
+ private runProject;
1060
+ /**
1061
+ * Builds and delivers every configured Python file-level import graph
1062
+ * export.
1063
+ *
1064
+ * Only `language:python`-tagged projects participate, discovered from the
1065
+ * tags `context.projects` carry β€” see `PythonService`. A project that
1066
+ * raises while its own export is being resolved is recorded as a failure
1067
+ * rather than aborting the pass, the same rule `runImportGraphs` follows.
1068
+ */
1069
+ runGraphs(context: GraphRunContext): GraphRunOutcome;
1070
+ }
1071
+
1072
+ /** Provides `MapCommand`'s findings-logging and pass/fail-weighing pass. */
1073
+ export declare class ReportingModule {
1074
+ }
1075
+
1076
+ /**
1077
+ * Logs what `MapCommand`'s passes found, and decides whether each pass
1078
+ * should fail the run.
1079
+ *
1080
+ * Split out of `MapCommand` purely to keep that file under this
1081
+ * repository's per-file line limit: reporting a pass's own findings is a
1082
+ * concern of its own, separate from resolving the command line into a mode
1083
+ * and orchestrating the passes themselves.
1084
+ */
1085
+ export declare class ReportingService {
1086
+ private readonly boundaryReportService;
1087
+ private readonly logger;
1088
+ constructor(boundaryReportService: BoundaryReportService, logger: LoggerService);
1089
+ /**
1090
+ * Logs a boundary pass's violations and failures, and reports whether the
1091
+ * run as a whole should fail.
1092
+ *
1093
+ * Violations go to the console and the exit code and nowhere else: a list of
1094
+ * things currently wrong is not a document worth publishing on the default
1095
+ * branch, and not one worth checking for staleness either.
1096
+ */
1097
+ reportBoundaries(outcome: BoundaryCheckOutcome): boolean;
1098
+ /**
1099
+ * Warns when nothing in the configuration selects a single project.
1100
+ *
1101
+ * `include` defaults to nothing, so a configuration naming only `defaults`
1102
+ * exports for no project at all β€” a run that writes nothing and still exits
1103
+ * zero. Nothing else catches it: `--check boundaries` judges every project
1104
+ * regardless of `include`, so a workspace whose exports have gone silent
1105
+ * still has a green gate.
1106
+ */
1107
+ reportEmptySelection(projectCount: number): void;
1108
+ /**
1109
+ * Logs why a run ended before it started, and fails it.
1110
+ *
1111
+ * A command line the input service refused β€” two modes named, none named
1112
+ * with no terminal to ask at, or a question walked away from β€” is reported
1113
+ * as a rejected command line rather than as a crash. Nothing was
1114
+ * attempted, and the reader's next move is to retype the flags, not to
1115
+ * read a stack trace.
1116
+ */
1117
+ reportFailure(error: unknown): void;
1118
+ /**
1119
+ * Logs an outcome's failures and stale exports, and reports whether the run
1120
+ * as a whole should fail.
1121
+ *
1122
+ * Both are reported together rather than the first one short-circuiting the
1123
+ * other, since `GraphRunService.run` already attempted every project
1124
+ * regardless of an earlier one's failure.
1125
+ */
1126
+ reportOutcome(outcome: GraphRunOutcome): boolean;
1127
+ /**
1128
+ * Weighs what each pass that ran found, reporting neither over the other.
1129
+ *
1130
+ * Both are weighed independently rather than the first failure
1131
+ * short-circuiting the second: a run gating both should report both, not
1132
+ * only the one that happened to run first.
1133
+ */
1134
+ reportPassOutcomes(args: {
1135
+ boundaryOutcome: BoundaryCheckOutcome | undefined;
1136
+ exportRun: MapRunResult | undefined;
1137
+ }): boolean;
1138
+ /** Logs what each pass that ran verified, and nothing for one that did not. */
1139
+ reportSuccess(args: {
1140
+ boundaryOutcome: BoundaryCheckOutcome | undefined;
1141
+ exportOutcome: GraphRunOutcome | undefined;
1142
+ }): void;
1143
+ }
1144
+
1145
+ /** One whole-workspace graph pass's outcome. */
1146
+ declare interface WorkspaceGraphRunOutcome {
1147
+ /**
1148
+ * The graph's own data, for combined output β€” always populated when the
1149
+ * resolved workspace target is not `"none"`, regardless of whether that
1150
+ * target actually touches Markdown, so `--format`/`--json-output`/
1151
+ * `--markdown-output` can read a rendered diagram this run never wrote to a
1152
+ * configured destination.
1153
+ */
1154
+ entry: CombinedGraphEntry | undefined;
1155
+ /** The delivery outcome, or `undefined` when nothing was configured to deliver. */
1156
+ result: ProjectRunResult | undefined;
1157
+ }
1158
+
1159
+ /**
1160
+ * Builds and delivers every whole-workspace graph: the Nx Workspace Graph,
1161
+ * the file-imports graph (every TypeScript and Python project's own import
1162
+ * graph, combined), and the NestJS module graph (every NestJS project's own
1163
+ * module graph, combined).
1164
+ *
1165
+ * Split out of `GraphRunService` purely to keep that file under this
1166
+ * repository's per-file line limit β€” `GraphRunService` still owns every
1167
+ * per-project pass, and hands the whole-workspace pass for each active
1168
+ * graph type over to this service instead of building it inline.
1169
+ *
1170
+ * Each `run*WorkspaceGraph` method also hands back the graph's own rendered
1171
+ * data alongside its delivery outcome β€” see `WorkspaceGraphRunOutcome` β€” so
1172
+ * `GraphRunService.run` can collect it for combined output without building the
1173
+ * same graph a second time.
1174
+ */
1175
+ declare class WorkspaceGraphsService {
1176
+ private readonly configurationService;
1177
+ private readonly deliveryService;
1178
+ private readonly fileImportsWorkspaceGraphService;
1179
+ private readonly moduleGraphService;
1180
+ private readonly nestjsModulesWorkspaceGraphService;
1181
+ private readonly nestjsProjectService;
1182
+ private readonly pythonService;
1183
+ private readonly typescriptService;
1184
+ private readonly workspaceGraphService;
1185
+ constructor(configurationService: ConfigurationService, deliveryService: DeliveryService, fileImportsWorkspaceGraphService: FileImportsWorkspaceGraphService, moduleGraphService: ModuleGraphService, nestjsModulesWorkspaceGraphService: NestjsModulesWorkspaceGraphService, nestjsProjectService: NestjsProjectService, pythonService: PythonService, typescriptService: TypescriptService, workspaceGraphService: WorkspaceGraphService);
1186
+ /** Builds the section heading a graph type's anchored Markdown destination auto-creates when it is missing. */
1187
+ private buildMarkdownSection;
1188
+ /**
1189
+ * Explores and builds every discovered NestJS project's own module graph.
1190
+ *
1191
+ * Kept apart from `runNestjsModulesWorkspaceGraph` so that method's own
1192
+ * direct callees stay under this repository's callidescope breadth limit.
1193
+ */
1194
+ private buildNestjsModuleGraphs;
1195
+ /**
1196
+ * Builds every discovered TypeScript project's own file-level import graph.
1197
+ *
1198
+ * Kept apart from `runFileImportsWorkspaceGraph` for the same breadth
1199
+ * reason `buildNestjsModuleGraphs` is.
1200
+ */
1201
+ private buildTypescriptGraphs;
1202
+ /**
1203
+ * Delivers one already-built whole-workspace graph's configured
1204
+ * destinations, at the workspace root.
1205
+ *
1206
+ * The one place both `runFileImportsWorkspaceGraph` and
1207
+ * `runNestjsModulesWorkspaceGraph` hand off to `DeliveryService`, so
1208
+ * neither of them carries `DeliveryService`'s own three-call shape as
1209
+ * direct callees of its own.
1210
+ */
1211
+ private deliverWorkspaceGraph;
1212
+ /**
1213
+ * Builds, renders, and delivers the whole-workspace file-level import
1214
+ * graph's configured destinations.
1215
+ *
1216
+ * Built from every discovered TypeScript and Python project's own import
1217
+ * graph, combined by `FileImportsWorkspaceGraphService` β€” the same "read
1218
+ * once, draw over the selected projects" shape `runNxWorkspaceGraph`
1219
+ * follows for the Nx Workspace Graph, applied to the two file-level import
1220
+ * builders instead of one Nx project graph read.
1221
+ *
1222
+ * The graph is not built at all when the resolved workspace target is
1223
+ * `"none"` β€” a workspace that never configured this destination pays
1224
+ * nothing for it, matching the target-gated shape every other pass here
1225
+ * follows. Combined output is unavailable for this type in that case too.
1226
+ */
1227
+ runFileImportsWorkspaceGraph(context: GraphRunContext): WorkspaceGraphRunOutcome;
1228
+ /**
1229
+ * Explores, builds, renders, and delivers the whole-workspace NestJS
1230
+ * module graph's configured destinations.
1231
+ *
1232
+ * Built from every discovered NestJS project's own module graph, combined
1233
+ * by `NestjsModulesWorkspaceGraphService` β€” the same shape
1234
+ * `runFileImportsWorkspaceGraph` follows, applied to booting every NestJS
1235
+ * project's container instead of building a `ts.Program` or parsing
1236
+ * Python source. Skipped entirely when the resolved target is `"none"`,
1237
+ * for the same reason `runFileImportsWorkspaceGraph` skips its own build.
1238
+ */
1239
+ runNestjsModulesWorkspaceGraph(context: GraphRunContext): Promise<WorkspaceGraphRunOutcome>;
1240
+ /**
1241
+ * Renders and delivers the Nx Workspace Graph's configured destinations.
1242
+ *
1243
+ * Built from the already-read Nx project graph β€” no discovery pass of its
1244
+ * own, unlike the other two whole-workspace graphs, since `GraphRunService`
1245
+ * already read it once for the whole run. Skipped entirely when the
1246
+ * resolved target is `"none"`, for the same reason
1247
+ * `runFileImportsWorkspaceGraph` skips its own build.
1248
+ */
1249
+ runNxWorkspaceGraph(context: GraphRunContext): WorkspaceGraphRunOutcome;
1250
+ }
1251
+
1252
+ export { }