@codependix/cli 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.
- package/LICENSE +21 -0
- package/README.md +894 -0
- package/dist/main.module-B07sXqnE.js +718 -0
- package/dist/src/index.d.ts +511 -0
- package/dist/src/index.js +2 -0
- package/dist/src/main.d.ts +1 -0
- package/dist/src/main.js +15 -0
- package/package.json +77 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import { BoundaryCheckService } from '@codependix/boundaries';
|
|
2
|
+
import { CombinedOutputService } from '@codependix/output';
|
|
3
|
+
import { CommandRunner } from 'nest-commander';
|
|
4
|
+
import { ConfigurationService } from '@codependix/configuration';
|
|
5
|
+
import { ConsoleLogger } from '@nestjs/common';
|
|
6
|
+
import { GraphRunService } from '@codependix/output';
|
|
7
|
+
import { MapCommandOptions } from '@codependix/configuration';
|
|
8
|
+
import pino from 'pino';
|
|
9
|
+
import { ReportingService } from '@codependix/output';
|
|
10
|
+
import { RunContextService } from '@codependix/boundaries';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Structured values that belong beside a log line rather than inside it.
|
|
14
|
+
*
|
|
15
|
+
* Counts, percentages, and durations are the values that change on every
|
|
16
|
+
* occurrence, so they are carried as fields: the message stays constant and
|
|
17
|
+
* groupable in telemetry, and the numbers stay queryable instead of having to
|
|
18
|
+
* be parsed back out of prose.
|
|
19
|
+
*
|
|
20
|
+
* The named members are the recurring ones; the index signature keeps the
|
|
21
|
+
* argument open for whatever a given call site needs to attach.
|
|
22
|
+
*/
|
|
23
|
+
declare interface LogData {
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
/** How many things the operation handled. */
|
|
26
|
+
count?: number;
|
|
27
|
+
/** Wall-clock milliseconds the operation took. */
|
|
28
|
+
durationMs?: number;
|
|
29
|
+
/** Completion between 0 and 100. */
|
|
30
|
+
percent?: number;
|
|
31
|
+
/** How many things the operation set out to handle. */
|
|
32
|
+
total?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Transient-scoped logger so each injecting class gets its own instance.
|
|
37
|
+
* Each consumer calls `setContext(ClassName.name)` to tag every log line
|
|
38
|
+
* with the originating class. Backed by pino for structured JSON output in
|
|
39
|
+
* production and human-readable pretty-print in development.
|
|
40
|
+
*
|
|
41
|
+
* Messages follow one grammar: an emoji naming the subject, a verb in present
|
|
42
|
+
* progressive or past tense, then the object. Values that vary per call —
|
|
43
|
+
* counts, percentages, durations — go in the `data` argument rather than the
|
|
44
|
+
* message, so the message stays constant enough for telemetry to group on.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* this.logger.info("📥 Downloading CSEL sources", undefined, { total: 428 });
|
|
48
|
+
* this.logger.info("📥 Downloaded CSEL sources", undefined, { count: 412 });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare @Injectable({ scope: Scope.TRANSIENT })
|
|
52
|
+
class LoggerService extends ConsoleLogger {
|
|
53
|
+
// 🏗 Dependency Injection
|
|
54
|
+
|
|
55
|
+
constructor() {
|
|
56
|
+
super();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 🔐 Private Fields
|
|
60
|
+
|
|
61
|
+
private static readonly isProduction =
|
|
62
|
+
process.env["NODE_ENV"] === "production";
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Built on first use, not when this file is evaluated.
|
|
66
|
+
*
|
|
67
|
+
* A destination fixed at import time could only ever be chosen by this
|
|
68
|
+
* package, since every consumer's own code runs after its imports.
|
|
69
|
+
*/
|
|
70
|
+
private static rootLogger: pino.Logger | undefined;
|
|
71
|
+
|
|
72
|
+
/** Whether lines go to standard error instead of standard output. */
|
|
73
|
+
private static writesToStandardError = false;
|
|
74
|
+
|
|
75
|
+
private child: pino.Logger = LoggerService.root;
|
|
76
|
+
|
|
77
|
+
// 🔑 Public Fields
|
|
78
|
+
|
|
79
|
+
// 🔏 Private Methods
|
|
80
|
+
|
|
81
|
+
/** Build the pino instance for production or local development output. */
|
|
82
|
+
private static createRootLogger(): pino.Logger {
|
|
83
|
+
const level = process.env["LOG_LEVEL"] ?? "info";
|
|
84
|
+
|
|
85
|
+
if (LoggerService.isProduction) {
|
|
86
|
+
return LoggerService.writesToStandardError
|
|
87
|
+
? pino({ level }, pino.destination(STANDARD_ERROR_DESCRIPTOR))
|
|
88
|
+
: pino({ level });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return pino({
|
|
92
|
+
level,
|
|
93
|
+
transport: {
|
|
94
|
+
options: {
|
|
95
|
+
colorize: true,
|
|
96
|
+
destination: LoggerService.writesToStandardError
|
|
97
|
+
? STANDARD_ERROR_DESCRIPTOR
|
|
98
|
+
: STANDARD_OUTPUT_DESCRIPTOR,
|
|
99
|
+
// The emoji is a field, not part of the message, so the console can
|
|
100
|
+
// show it while telemetry stores unadorned prose. `ignore` then keeps
|
|
101
|
+
// it from being printed a second time in the trailing object.
|
|
102
|
+
ignore: "pid,hostname,emoji",
|
|
103
|
+
messageFormat: "{emoji} {msg}",
|
|
104
|
+
singleLine: true,
|
|
105
|
+
},
|
|
106
|
+
target: "pino-pretty",
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Sends every subsequent line to standard error instead of standard output.
|
|
113
|
+
*
|
|
114
|
+
* For a command-line application whose standard output *is* its result. A log
|
|
115
|
+
* line sharing that stream is not a diagnostic beside the data, it is a
|
|
116
|
+
* corruption of it. Call it before anything logs — the first statement of the
|
|
117
|
+
* application's bootstrap.
|
|
118
|
+
*
|
|
119
|
+
* A call after the first line warns and changes nothing: the destination is
|
|
120
|
+
* fixed when the pino instance is built, and tearing down a transport
|
|
121
|
+
* somebody is writing through would be worse than refusing. The warning is
|
|
122
|
+
* the point — silently leaving the lines on standard output is how a caller
|
|
123
|
+
* would ship a corrupted pipe without ever being told.
|
|
124
|
+
*/
|
|
125
|
+
static logToStandardError(): void {
|
|
126
|
+
if (LoggerService.rootLogger !== undefined) {
|
|
127
|
+
process.emitWarning(
|
|
128
|
+
"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.",
|
|
129
|
+
);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
LoggerService.writesToStandardError = true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Fails a malformed message in development, and never in production.
|
|
138
|
+
*
|
|
139
|
+
* A logger that throws in production turns an observability call into an
|
|
140
|
+
* outage, so the check runs only where a developer is present to fix it.
|
|
141
|
+
*/
|
|
142
|
+
private assertConventionalMessage(args: {
|
|
143
|
+
context: string | undefined;
|
|
144
|
+
parsed: ParsedLogMessage;
|
|
145
|
+
}): void {
|
|
146
|
+
if (
|
|
147
|
+
LoggerService.isProduction ||
|
|
148
|
+
this.shouldSkipConventionalMessageValidation(args.context)
|
|
149
|
+
) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const violation = this.getConventionalMessageViolation(args.parsed);
|
|
154
|
+
|
|
155
|
+
if (violation !== undefined) {
|
|
156
|
+
throw new Error(violation);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Assembles the object pino merges into the line. */
|
|
161
|
+
private buildBindings(args: {
|
|
162
|
+
context: string | undefined;
|
|
163
|
+
data: LogData | undefined;
|
|
164
|
+
parsed: ParsedLogMessage;
|
|
165
|
+
}): Record<string, unknown> {
|
|
166
|
+
this.assertConventionalMessage({
|
|
167
|
+
context: args.context,
|
|
168
|
+
parsed: args.parsed,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
...args.data,
|
|
173
|
+
context: args.context,
|
|
174
|
+
// Telemetry gets prose; only the console-bound transport reads this.
|
|
175
|
+
...(LoggerService.isProduction ? {} : { emoji: args.parsed.emoji }),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Returns a human-readable explanation when the message format is invalid. */
|
|
180
|
+
private getConventionalMessageViolation(
|
|
181
|
+
parsed: ParsedLogMessage,
|
|
182
|
+
): string | undefined {
|
|
183
|
+
const emoji = parsed.emoji;
|
|
184
|
+
const text = parsed.text;
|
|
185
|
+
|
|
186
|
+
if (emoji === undefined) {
|
|
187
|
+
return `Log message must start with an emoji naming its subject, then a verb: "${text}"`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const firstWord = FIRST_WORD_PATTERN.exec(text)?.[1];
|
|
191
|
+
|
|
192
|
+
if (firstWord === undefined || !this.isConventionalVerb(firstWord)) {
|
|
193
|
+
return `Log message must begin with a verb in present progressive or past tense, got "${firstWord ?? ""}": "${emoji} ${text}"`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Whether a word is a verb in one of the two tenses the convention allows.
|
|
201
|
+
*
|
|
202
|
+
* Present progressive means the operation is under way; past means it
|
|
203
|
+
* finished. Regular morphology covers both, so a new verb needs no
|
|
204
|
+
* registration anywhere — only irregular pasts are enumerated.
|
|
205
|
+
*/
|
|
206
|
+
private isConventionalVerb(word: string): boolean {
|
|
207
|
+
const lowercased = word.toLowerCase();
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
lowercased.endsWith("ing") ||
|
|
211
|
+
lowercased.endsWith("ed") ||
|
|
212
|
+
IRREGULAR_PAST_VERBS.has(lowercased)
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Splits a leading emoji off a message, leaving prose behind. */
|
|
217
|
+
private parseMessage(message: unknown): ParsedLogMessage {
|
|
218
|
+
const text = String(message);
|
|
219
|
+
const match = LEADING_EMOJI_PATTERN.exec(text);
|
|
220
|
+
const emoji = match?.[1];
|
|
221
|
+
|
|
222
|
+
return emoji === undefined
|
|
223
|
+
? { emoji: undefined, text }
|
|
224
|
+
: { emoji, text: text.slice(match?.[0].length) };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Whether a context is intentionally exempt from the validation rule. */
|
|
228
|
+
private shouldSkipConventionalMessageValidation(
|
|
229
|
+
context: string | undefined,
|
|
230
|
+
): boolean {
|
|
231
|
+
return context !== undefined && UNVALIDATED_LOG_CONTEXTS.has(context);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 🌎 Public Methods
|
|
235
|
+
|
|
236
|
+
/** The pino instance every logger's child is taken from. */
|
|
237
|
+
private static get root(): pino.Logger {
|
|
238
|
+
LoggerService.rootLogger ??= LoggerService.createRootLogger();
|
|
239
|
+
|
|
240
|
+
return LoggerService.rootLogger;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Normalizes unknown errors into a stable message and timestamped log line. */
|
|
244
|
+
buildErrorLogEntry(
|
|
245
|
+
context: string,
|
|
246
|
+
error: unknown,
|
|
247
|
+
): { errorMessage: string; logLine: string } {
|
|
248
|
+
const errorMessage =
|
|
249
|
+
error instanceof Error ? error.stack || error.message : String(error);
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
errorMessage,
|
|
253
|
+
logLine: `[${new Date().toISOString()}] ${context}: ${errorMessage}\n`,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Builds a timestamped output log file path and ensures the output directory exists. */
|
|
258
|
+
createTimestampedOutputLogFilePath(filePrefix: string): string {
|
|
259
|
+
const outputDirectory = path.join(process.cwd(), "output");
|
|
260
|
+
if (!existsSync(outputDirectory)) {
|
|
261
|
+
mkdirSync(outputDirectory, { recursive: true });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return path.join(
|
|
265
|
+
outputDirectory,
|
|
266
|
+
`${filePrefix}-${new Date().toISOString().replaceAll(/[:.]/g, "-")}.log`,
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Logs a debug message at the `debug` level. */
|
|
271
|
+
override debug(message: unknown, context?: string, data?: LogData): void {
|
|
272
|
+
const parsed = this.parseMessage(message);
|
|
273
|
+
this.child.debug(
|
|
274
|
+
this.buildBindings({ context: context ?? this.context, data, parsed }),
|
|
275
|
+
parsed.text,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Logs an error message at the `error` level, optionally including a stack trace.
|
|
281
|
+
*
|
|
282
|
+
* `ConsoleLogger.error` spends a third slot on a context string that the
|
|
283
|
+
* other levels do not have, so this one accepts either: a string keeps
|
|
284
|
+
* NestJS's meaning, an object is structured data like everywhere else.
|
|
285
|
+
*/
|
|
286
|
+
override error(
|
|
287
|
+
message: unknown,
|
|
288
|
+
stackOrContext?: string,
|
|
289
|
+
contextOrData?: LogData | string,
|
|
290
|
+
): void {
|
|
291
|
+
const parsed = this.parseMessage(message);
|
|
292
|
+
const data = typeof contextOrData === "object" ? contextOrData : undefined;
|
|
293
|
+
const context =
|
|
294
|
+
typeof contextOrData === "string" ? contextOrData : this.context;
|
|
295
|
+
|
|
296
|
+
this.child.error(
|
|
297
|
+
{
|
|
298
|
+
...this.buildBindings({ context, data, parsed }),
|
|
299
|
+
stack: stackOrContext,
|
|
300
|
+
},
|
|
301
|
+
parsed.text,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Logs an informational message at the `info` level. */
|
|
306
|
+
info(message: unknown, context?: string, data?: LogData): void {
|
|
307
|
+
const parsed = this.parseMessage(message);
|
|
308
|
+
this.child.info(
|
|
309
|
+
this.buildBindings({ context: context ?? this.context, data, parsed }),
|
|
310
|
+
parsed.text,
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Logs an informational message at the `info` level.
|
|
316
|
+
*
|
|
317
|
+
* NestJS and `nest-commander` call this method directly as part of the
|
|
318
|
+
* framework's own `LoggerService` contract, so it must keep working
|
|
319
|
+
* exactly as before. Application code should call `info` instead — the
|
|
320
|
+
* same behavior under a name that says what level it logs at.
|
|
321
|
+
*/
|
|
322
|
+
override log(message: unknown, context?: string, data?: LogData): void {
|
|
323
|
+
this.info(message, context, data);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** Sets the context label included in every subsequent log line. */
|
|
327
|
+
override setContext(context: string): void {
|
|
328
|
+
super.setContext(context);
|
|
329
|
+
this.child = LoggerService.root.child({ context });
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Logs a verbose message at the `trace` level. */
|
|
333
|
+
override verbose(message: unknown, context?: string, data?: LogData): void {
|
|
334
|
+
const parsed = this.parseMessage(message);
|
|
335
|
+
this.child.trace(
|
|
336
|
+
this.buildBindings({ context: context ?? this.context, data, parsed }),
|
|
337
|
+
parsed.text,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Logs a warning message at the `warn` level. */
|
|
342
|
+
override warn(message: unknown, context?: string, data?: LogData): void {
|
|
343
|
+
const parsed = this.parseMessage(message);
|
|
344
|
+
this.child.warn(
|
|
345
|
+
this.buildBindings({ context: context ?? this.context, data, parsed }),
|
|
346
|
+
parsed.text,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Root NestJS application module.
|
|
353
|
+
*/
|
|
354
|
+
export declare class MainModule {
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* CLI entry point for the codependix dependency graph workflow.
|
|
359
|
+
*
|
|
360
|
+
* `--write` publishes every configured export; `--check` names which finding
|
|
361
|
+
* fails the run — `boundaries` for an edge breaking a declared rule, `reports`
|
|
362
|
+
* for a configured destination that has gone stale. No per-graph-type
|
|
363
|
+
* subcommand: which graphs run, where each project's export lands, and which
|
|
364
|
+
* rules judge them is entirely a function of `codependix.config.ts`, read by
|
|
365
|
+
* `@codependix/configuration`.
|
|
366
|
+
*
|
|
367
|
+
* The two findings are named apart because they belong on opposite sides of a
|
|
368
|
+
* pull request. An export moves with the workspace it describes, so gating
|
|
369
|
+
* staleness on a branch fails every branch that touched a project graph; a
|
|
370
|
+
* broken boundary is caused by the branch and fixed by it. This is the split
|
|
371
|
+
* `callidescope` already made between `--check depth` and `--check reports`,
|
|
372
|
+
* copied wholesale down to the spelling of `reports`.
|
|
373
|
+
*/
|
|
374
|
+
export declare class MapCommand extends CommandRunner {
|
|
375
|
+
private readonly graphRunService;
|
|
376
|
+
private readonly boundaryCheckService;
|
|
377
|
+
private readonly combinedOutputService;
|
|
378
|
+
private readonly configurationService;
|
|
379
|
+
private readonly logger;
|
|
380
|
+
private readonly reportingService;
|
|
381
|
+
private readonly runContextService;
|
|
382
|
+
constructor(graphRunService: GraphRunService, boundaryCheckService: BoundaryCheckService, combinedOutputService: CombinedOutputService, configurationService: ConfigurationService, logger: LoggerService, reportingService: ReportingService, runContextService: RunContextService);
|
|
383
|
+
/**
|
|
384
|
+
* Prints and writes every active graph type's combined output, when the
|
|
385
|
+
* export pass ran at all.
|
|
386
|
+
*
|
|
387
|
+
* A `--check boundaries`-only run never reaches this: nothing was built to
|
|
388
|
+
* combine, so `--format`/`--json-output`/`--markdown-output` are silently
|
|
389
|
+
* inert on a run that touched no export at all — the same way `--write`
|
|
390
|
+
* and `--check reports` are inert on one that never named a destination.
|
|
391
|
+
*/
|
|
392
|
+
private runCombinedOutput;
|
|
393
|
+
/**
|
|
394
|
+
* Runs the export pass, warning when nothing was selected.
|
|
395
|
+
*
|
|
396
|
+
* Returns both the usual delivery outcome and every active graph type's
|
|
397
|
+
* whole-workspace data, so `runMode` can hand the latter to
|
|
398
|
+
* `CombinedOutputService` without running the export pass a second time.
|
|
399
|
+
*/
|
|
400
|
+
private runExports;
|
|
401
|
+
/**
|
|
402
|
+
* Runs the passes a resolved mode selected, and reports what they found.
|
|
403
|
+
*
|
|
404
|
+
* Split from `run` so the command line's own rejection path stays a
|
|
405
|
+
* handful of lines: everything below here has a mode to act on. Both
|
|
406
|
+
* passes are run directly here, rather than through a further-nested
|
|
407
|
+
* helper, to keep `MapCommand.run`'s own call stack inside this project's
|
|
408
|
+
* callidescope depth limit — see `packages/codependix-cli/callidescope.config.ts`.
|
|
409
|
+
*/
|
|
410
|
+
private runMode;
|
|
411
|
+
/**
|
|
412
|
+
* Parses the set of findings the run fails on.
|
|
413
|
+
*
|
|
414
|
+
* The parser runs only when `--check` carries a value, so anything reaching
|
|
415
|
+
* it is a written set. A `--check` with no value never arrives here and is
|
|
416
|
+
* refused later: a set with nothing in it is indistinguishable from the flag
|
|
417
|
+
* having been left off, which is how one flag came to gate two findings.
|
|
418
|
+
*/
|
|
419
|
+
parseCheck(value: string): string;
|
|
420
|
+
/** Parses the optional configuration path from command-line input. */
|
|
421
|
+
parseConfig(value: string | undefined): string | undefined;
|
|
422
|
+
/** Parses the directory whose Nx workspace this run reads. */
|
|
423
|
+
parseDirectory(value: string | undefined): string;
|
|
424
|
+
/**
|
|
425
|
+
* Parses `--exclude`, a comma-separated list of globs overriding the
|
|
426
|
+
* configured `exclude`.
|
|
427
|
+
*
|
|
428
|
+
* Refused later, by `ConfigurationService.loadConfiguration`, when the
|
|
429
|
+
* configuration this run reads never declared `exclude` in the first
|
|
430
|
+
* place — matching callidescope's `--exclude` refusal exactly.
|
|
431
|
+
*/
|
|
432
|
+
parseExclude(value: string | undefined): string[];
|
|
433
|
+
/** Enables the `fileImports` graph type for this run. */
|
|
434
|
+
parseFileImports(): true;
|
|
435
|
+
/**
|
|
436
|
+
* Parses what `--format` prints to standard output.
|
|
437
|
+
*
|
|
438
|
+
* Defaults to Markdown when the flag was left off entirely — see
|
|
439
|
+
* `MapCommand.resolveFormat`, which validates the value this returns.
|
|
440
|
+
*/
|
|
441
|
+
parseFormat(value: string | undefined): string | undefined;
|
|
442
|
+
/**
|
|
443
|
+
* Parses `--include`, a comma-separated list of globs overriding the
|
|
444
|
+
* configured `include`.
|
|
445
|
+
*
|
|
446
|
+
* Refused later, alongside `--exclude`, when the configuration this run
|
|
447
|
+
* reads never declared `include`.
|
|
448
|
+
*/
|
|
449
|
+
parseInclude(value: string | undefined): string[];
|
|
450
|
+
/**
|
|
451
|
+
* Parses `--json-output`, the path to write every active graph type's
|
|
452
|
+
* combined JSON data to, keyed by graph type name.
|
|
453
|
+
*/
|
|
454
|
+
parseJsonOutput(value: string | undefined): string | undefined;
|
|
455
|
+
/**
|
|
456
|
+
* Parses `--markdown-output`, the path to write every active graph type's
|
|
457
|
+
* combined, anchor-spliced Markdown diagram to.
|
|
458
|
+
*/
|
|
459
|
+
parseMarkdownOutput(value: string | undefined): string | undefined;
|
|
460
|
+
/** Enables the `nestjsModules` graph type for this run. */
|
|
461
|
+
parseNestjsModules(): true;
|
|
462
|
+
/** Disables the `fileImports` graph type for this run. */
|
|
463
|
+
parseNoFileImports(): false;
|
|
464
|
+
/** Disables the `nestjsModules` graph type for this run. */
|
|
465
|
+
parseNoNestjsModules(): false;
|
|
466
|
+
/** Disables the `nxProjects` graph type for this run. */
|
|
467
|
+
parseNoNxProjects(): false;
|
|
468
|
+
/** Enables the `nxProjects` graph type for this run. */
|
|
469
|
+
parseNxProjects(): true;
|
|
470
|
+
/**
|
|
471
|
+
* Parses the projects a run exports for beyond `include`.
|
|
472
|
+
*
|
|
473
|
+
* **Widening, and narrowing.** A named project is added to whatever
|
|
474
|
+
* `include` already selected, and `exclude` still wins over it. It also
|
|
475
|
+
* narrows what a run draws and judges: the Workspace Graph's node set and
|
|
476
|
+
* every level `--check boundaries` judges become the named set. A narrowed
|
|
477
|
+
* gate sees fewer edges than a whole-workspace one — fine for a local run,
|
|
478
|
+
* and worth thinking twice about in CI.
|
|
479
|
+
*/
|
|
480
|
+
parseProjects(value: string | undefined): string | undefined;
|
|
481
|
+
/**
|
|
482
|
+
* Parses the Nx tags a run exports for, matched exactly against a project's
|
|
483
|
+
* own tags. Widens and narrows exactly as `--projects` does.
|
|
484
|
+
*/
|
|
485
|
+
parseTags(value: string | undefined): string | undefined;
|
|
486
|
+
/** Parses the `--write` flag from command-line input. */
|
|
487
|
+
parseWrite(value: boolean | undefined): boolean;
|
|
488
|
+
/**
|
|
489
|
+
* Runs whatever the command line asked for: exports, boundaries, or both.
|
|
490
|
+
*
|
|
491
|
+
* Every project is attempted regardless of whether an earlier one failed —
|
|
492
|
+
* both passes isolate a project's failure to itself — so this only decides
|
|
493
|
+
* the exit code from what came back. The two passes are also weighed
|
|
494
|
+
* independently rather than the first failure short-circuiting the second:
|
|
495
|
+
* a run gating both should report both, not the one that happened to run
|
|
496
|
+
* first.
|
|
497
|
+
*/
|
|
498
|
+
run(_passedParameters: string[], options?: MapCommandOptions): Promise<void>;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** Wires the codependix CLI command together with its collaborators. */
|
|
502
|
+
export declare class MapModule {
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/** A message split into the emoji the console shows and the prose telemetry stores. */
|
|
506
|
+
declare interface ParsedLogMessage {
|
|
507
|
+
emoji: string | undefined;
|
|
508
|
+
text: string;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/src/main.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as e, t } from "../main.module-B07sXqnE.js";
|
|
3
|
+
import { CommandFactory as n } from "nest-commander";
|
|
4
|
+
import "reflect-metadata";
|
|
5
|
+
//#region packages/ic-suite/codependix/codependix-cli/src/main.ts
|
|
6
|
+
async function r() {
|
|
7
|
+
e.logToStandardError();
|
|
8
|
+
let r = new e();
|
|
9
|
+
r.setContext("CommandFactory"), await n.run(t, {
|
|
10
|
+
bufferLogs: !0,
|
|
11
|
+
logger: r
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
r();
|
|
15
|
+
//#endregion
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Jimmy Paolini",
|
|
3
|
+
"bin": {
|
|
4
|
+
"codependix": "./dist/src/main.js"
|
|
5
|
+
},
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/organizzolini/codebase/issues"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@codependix/boundaries": "0.0.3",
|
|
11
|
+
"@codependix/configuration": "0.0.3",
|
|
12
|
+
"@codependix/core": "0.0.3",
|
|
13
|
+
"@codependix/output": "0.0.3",
|
|
14
|
+
"@nestjs/common": "^11.1.21 || ^12.0.1",
|
|
15
|
+
"@nestjs/config": "^12.0.0",
|
|
16
|
+
"@nestjs/core": "^11.1.21 || ^12.0.1",
|
|
17
|
+
"nest-commander": "^3.21.0",
|
|
18
|
+
"pino": "^10.3.1",
|
|
19
|
+
"pino-pretty": "^13.1.3",
|
|
20
|
+
"reflect-metadata": "^0.2.2",
|
|
21
|
+
"zod": "^4.4.3"
|
|
22
|
+
},
|
|
23
|
+
"description": "Command-line tool for exporting and validating Nx, NestJS, and file-level dependency graphs and boundaries",
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@codebase/logger": "0.0.1",
|
|
26
|
+
"@golevelup/ts-vitest": "^4.0.0",
|
|
27
|
+
"@nestjs/testing": "^12.0.1",
|
|
28
|
+
"@nx/eslint-plugin": "^23.0.0",
|
|
29
|
+
"@swc-node/register": "^1.11.1",
|
|
30
|
+
"@swc/core": "^1.15.40",
|
|
31
|
+
"@swc/helpers": "^0.5.21",
|
|
32
|
+
"@types/node": "^26.5.1",
|
|
33
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
34
|
+
"typescript": "^6.0.3",
|
|
35
|
+
"vitest": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/src/index.d.ts",
|
|
40
|
+
"default": "./dist/src/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
49
|
+
"homepage": "https://github.com/organizzolini/codebase/tree/main/packages/ic-suite/codependix/codependix-cli#readme",
|
|
50
|
+
"keywords": [
|
|
51
|
+
"architecture-linter",
|
|
52
|
+
"boundaries",
|
|
53
|
+
"cli",
|
|
54
|
+
"codependix",
|
|
55
|
+
"dependency-graph",
|
|
56
|
+
"mermaid"
|
|
57
|
+
],
|
|
58
|
+
"license": "MIT",
|
|
59
|
+
"main": "./dist/src/index.js",
|
|
60
|
+
"name": "@codependix/cli",
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public",
|
|
63
|
+
"registry": "https://registry.npmjs.org"
|
|
64
|
+
},
|
|
65
|
+
"repository": {
|
|
66
|
+
"directory": "packages/ic-suite/codependix/codependix-cli",
|
|
67
|
+
"type": "git",
|
|
68
|
+
"url": "git+https://github.com/organizzolini/codebase.git"
|
|
69
|
+
},
|
|
70
|
+
"type": "module",
|
|
71
|
+
"typeCoverage": {
|
|
72
|
+
"atLeast": 100,
|
|
73
|
+
"strict": true
|
|
74
|
+
},
|
|
75
|
+
"types": "./dist/src/index.d.ts",
|
|
76
|
+
"version": "0.0.3"
|
|
77
|
+
}
|