@conformetry/cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,662 @@
1
+ import { CommandRunner } from 'nest-commander';
2
+ import { ConfigurationService } from '@conformetry/configuration';
3
+ import { ConsoleLogger } from '@nestjs/common';
4
+ import { GenerationService } from '@conformetry/generation';
5
+ import { InventoryService } from '@conformetry/output';
6
+ import pino from 'pino';
7
+ import { ReportingService } from '@conformetry/output';
8
+ import { ValidationService } from '@conformetry/validation';
9
+
10
+ /**
11
+ * Renders a conformetry template from the configured registry.
12
+ *
13
+ * Unknown options are allowed through deliberately: a template's parameters
14
+ * are not known until the template is chosen, so they cannot be declared as
15
+ * flags ahead of time. They are matched against the template's own schema
16
+ * instead. This is also why the template is selected with `--template` rather
17
+ * than `--name` — nearly every template takes a `name` parameter, and
18
+ * reserving that flag made it impossible to supply.
19
+ *
20
+ * `--template` is optional at the parse layer so a bare `generate` reaches
21
+ * this command and can offer a picker instead of failing at argument parsing
22
+ * with a name the reader would have had to look up elsewhere.
23
+ */
24
+ export declare class GenerateCommand extends CommandRunner {
25
+ private readonly configurationService;
26
+ private readonly generationService;
27
+ private readonly logger;
28
+ constructor(configurationService: ConfigurationService, generationService: GenerationService, logger: LoggerService);
29
+ /** Resolves the template's inputs and writes its files. */
30
+ private generate;
31
+ /**
32
+ * Logs a command line the input service refused, and fails the run.
33
+ *
34
+ * A required input that could not be asked for is the reader's own typing
35
+ * to fix, so it is reported as a rejected command line rather than as a
36
+ * crash. Nothing was generated, and the next move is to pass the flag it
37
+ * named, not to read a stack trace.
38
+ */
39
+ private rejectCommandLine;
40
+ /**
41
+ * Refuses the flag `--template` replaced, rather than ignoring it.
42
+ *
43
+ * Unknown options are allowed through so a template's own inputs can be
44
+ * passed as flags, which means commander does not reject `--generator` for
45
+ * this command the way it would for any other. Without this it would be
46
+ * read as an input nothing declares and quietly discarded, leaving a stale
47
+ * script to prompt or to fail for the wrong reason.
48
+ */
49
+ private rejectRemovedGeneratorOption;
50
+ /**
51
+ * Settles which template to render: the one named, the one picked, or none.
52
+ *
53
+ * The missing case and the unknown case are decided together here rather
54
+ * than split between argument parsing and the command body, which is what
55
+ * lets the picker sit between them. Whether anybody can be asked is read
56
+ * from the one predicate that knows — a non-terminal stdin is what once let
57
+ * a prompt hang a CI job until it timed out.
58
+ */
59
+ private resolveTemplateName;
60
+ /** Parses the optional configuration path. */
61
+ parseConfig(value: string | undefined): string | undefined;
62
+ /** Parses the output directory override. */
63
+ parseDirectory(value: string | undefined): string | undefined;
64
+ /**
65
+ * Parses the name of the template to render.
66
+ *
67
+ * Optional, so a bare `generate` is not rejected at argument parsing with a
68
+ * name the reader has not been shown yet.
69
+ */
70
+ parseTemplate(value: string | undefined): string | undefined;
71
+ /**
72
+ * Renders the template, reporting a refused command line as one.
73
+ *
74
+ * Only an `InputError` is caught: a required input nobody could be asked
75
+ * for is a flag the caller has to pass, where anything else is a genuine
76
+ * failure and keeps its stack.
77
+ */
78
+ run(passedParameters: string[], options: GenerateCommandOptions): Promise<void>;
79
+ }
80
+
81
+ /**
82
+ * Options accepted by the generate command.
83
+ *
84
+ * Keys are the camel-cased long flag names, which is how commander reports
85
+ * parsed options — `--directory` arrives as `directory`.
86
+ */
87
+ export declare interface GenerateCommandOptions {
88
+ config?: string;
89
+ directory?: string;
90
+ /**
91
+ * Optional at the parse layer only. A bare `generate` has to reach the
92
+ * command body so the missing case and the unknown case can be decided
93
+ * together; the template itself is still required, and is either supplied
94
+ * here or chosen at the picker.
95
+ */
96
+ template?: string;
97
+ }
98
+
99
+ /**
100
+ * Provides the generate command.
101
+ */
102
+ export declare class GenerateModule {
103
+ }
104
+
105
+ /**
106
+ * Lists every instance the configured globs find, and which templates explain
107
+ * each one.
108
+ *
109
+ * Each path printed is usable as the `--instances` argument to the templates
110
+ * command, so the two read as one pair: this side answers "what is generated
111
+ * code here", the other answers "what standard does this path answer to".
112
+ *
113
+ * Output goes to standard output rather than through the logger, which asserts
114
+ * every message opens with an emoji and a verb — right for a log line, wrong
115
+ * for a listing.
116
+ */
117
+ export declare class InstancesCommand extends CommandRunner {
118
+ private readonly configurationService;
119
+ private readonly inventoryService;
120
+ private readonly logger;
121
+ constructor(configurationService: ConfigurationService, inventoryService: InventoryService, logger: LoggerService);
122
+ /** Parses the optional configuration path. */
123
+ parseConfig(value: string | undefined): string | undefined;
124
+ /** Selects the machine-readable listing. */
125
+ parseJson(): boolean;
126
+ /** Parses the optional template filter. */
127
+ parseTemplates(value: string | undefined): string[] | undefined;
128
+ /** Writes every instance found, filtered to the given templates. */
129
+ run(_passedParameters: string[], options: InstancesCommandOptions): Promise<void>;
130
+ }
131
+
132
+ /** Options accepted by the instances command. */
133
+ export declare interface InstancesCommandOptions {
134
+ config?: string;
135
+ json?: boolean;
136
+ templates?: string[];
137
+ }
138
+
139
+ /**
140
+ * Provides the instances command.
141
+ */
142
+ export declare class InstancesModule {
143
+ }
144
+
145
+ /**
146
+ * Structured values that belong beside a log line rather than inside it.
147
+ *
148
+ * Counts, percentages, and durations are the values that change on every
149
+ * occurrence, so they are carried as fields: the message stays constant and
150
+ * groupable in telemetry, and the numbers stay queryable instead of having to
151
+ * be parsed back out of prose.
152
+ *
153
+ * The named members are the recurring ones; the index signature keeps the
154
+ * argument open for whatever a given call site needs to attach.
155
+ */
156
+ declare interface LogData {
157
+ [key: string]: unknown;
158
+ /** How many things the operation handled. */
159
+ count?: number;
160
+ /** Wall-clock milliseconds the operation took. */
161
+ durationMs?: number;
162
+ /** Completion between 0 and 100. */
163
+ percent?: number;
164
+ /** How many things the operation set out to handle. */
165
+ total?: number;
166
+ }
167
+
168
+ /**
169
+ * Transient-scoped logger so each injecting class gets its own instance.
170
+ * Each consumer calls `setContext(ClassName.name)` to tag every log line
171
+ * with the originating class. Backed by pino for structured JSON output in
172
+ * production and human-readable pretty-print in development.
173
+ *
174
+ * Messages follow one grammar: an emoji naming the subject, a verb in present
175
+ * progressive or past tense, then the object. Values that vary per call —
176
+ * counts, percentages, durations — go in the `data` argument rather than the
177
+ * message, so the message stays constant enough for telemetry to group on.
178
+ *
179
+ * ```ts
180
+ * this.logger.info("📥 Downloading CSEL sources", undefined, { total: 428 });
181
+ * this.logger.info("📥 Downloaded CSEL sources", undefined, { count: 412 });
182
+ * ```
183
+ */
184
+ declare @Injectable({ scope: Scope.TRANSIENT })
185
+ class LoggerService extends ConsoleLogger {
186
+ // 🏗 Dependency Injection
187
+
188
+ constructor() {
189
+ super();
190
+ }
191
+
192
+ // 🔐 Private Fields
193
+
194
+ private static readonly isProduction =
195
+ process.env["NODE_ENV"] === "production";
196
+
197
+ /**
198
+ * Built on first use, not when this file is evaluated.
199
+ *
200
+ * A destination fixed at import time could only ever be chosen by this
201
+ * package, since every consumer's own code runs after its imports.
202
+ */
203
+ private static rootLogger: pino.Logger | undefined;
204
+
205
+ /** Whether lines go to standard error instead of standard output. */
206
+ private static writesToStandardError = false;
207
+
208
+ private child: pino.Logger = LoggerService.root;
209
+
210
+ // 🔑 Public Fields
211
+
212
+ // 🔏 Private Methods
213
+
214
+ /** Build the pino instance for production or local development output. */
215
+ private static createRootLogger(): pino.Logger {
216
+ const level = process.env["LOG_LEVEL"] ?? "info";
217
+
218
+ if (LoggerService.isProduction) {
219
+ return LoggerService.writesToStandardError
220
+ ? pino({ level }, pino.destination(STANDARD_ERROR_DESCRIPTOR))
221
+ : pino({ level });
222
+ }
223
+
224
+ return pino({
225
+ level,
226
+ transport: {
227
+ options: {
228
+ colorize: true,
229
+ destination: LoggerService.writesToStandardError
230
+ ? STANDARD_ERROR_DESCRIPTOR
231
+ : STANDARD_OUTPUT_DESCRIPTOR,
232
+ // The emoji is a field, not part of the message, so the console can
233
+ // show it while telemetry stores unadorned prose. `ignore` then keeps
234
+ // it from being printed a second time in the trailing object.
235
+ ignore: "pid,hostname,emoji",
236
+ messageFormat: "{emoji} {msg}",
237
+ singleLine: true,
238
+ },
239
+ target: "pino-pretty",
240
+ },
241
+ });
242
+ }
243
+
244
+ /**
245
+ * Sends every subsequent line to standard error instead of standard output.
246
+ *
247
+ * For a command-line application whose standard output *is* its result. A log
248
+ * line sharing that stream is not a diagnostic beside the data, it is a
249
+ * corruption of it. Call it before anything logs — the first statement of the
250
+ * application's bootstrap.
251
+ *
252
+ * A call after the first line warns and changes nothing: the destination is
253
+ * fixed when the pino instance is built, and tearing down a transport
254
+ * somebody is writing through would be worse than refusing. The warning is
255
+ * the point — silently leaving the lines on standard output is how a caller
256
+ * would ship a corrupted pipe without ever being told.
257
+ */
258
+ static logToStandardError(): void {
259
+ if (LoggerService.rootLogger !== undefined) {
260
+ process.emitWarning(
261
+ "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.",
262
+ );
263
+ return;
264
+ }
265
+
266
+ LoggerService.writesToStandardError = true;
267
+ }
268
+
269
+ /**
270
+ * Fails a malformed message in development, and never in production.
271
+ *
272
+ * A logger that throws in production turns an observability call into an
273
+ * outage, so the check runs only where a developer is present to fix it.
274
+ */
275
+ private assertConventionalMessage(args: {
276
+ context: string | undefined;
277
+ parsed: ParsedLogMessage;
278
+ }): void {
279
+ if (
280
+ LoggerService.isProduction ||
281
+ this.shouldSkipConventionalMessageValidation(args.context)
282
+ ) {
283
+ return;
284
+ }
285
+
286
+ const violation = this.getConventionalMessageViolation(args.parsed);
287
+
288
+ if (violation !== undefined) {
289
+ throw new Error(violation);
290
+ }
291
+ }
292
+
293
+ /** Assembles the object pino merges into the line. */
294
+ private buildBindings(args: {
295
+ context: string | undefined;
296
+ data: LogData | undefined;
297
+ parsed: ParsedLogMessage;
298
+ }): Record<string, unknown> {
299
+ this.assertConventionalMessage({
300
+ context: args.context,
301
+ parsed: args.parsed,
302
+ });
303
+
304
+ return {
305
+ ...args.data,
306
+ context: args.context,
307
+ // Telemetry gets prose; only the console-bound transport reads this.
308
+ ...(LoggerService.isProduction ? {} : { emoji: args.parsed.emoji }),
309
+ };
310
+ }
311
+
312
+ /** Returns a human-readable explanation when the message format is invalid. */
313
+ private getConventionalMessageViolation(
314
+ parsed: ParsedLogMessage,
315
+ ): string | undefined {
316
+ const emoji = parsed.emoji;
317
+ const text = parsed.text;
318
+
319
+ if (emoji === undefined) {
320
+ return `Log message must start with an emoji naming its subject, then a verb: "${text}"`;
321
+ }
322
+
323
+ const firstWord = FIRST_WORD_PATTERN.exec(text)?.[1];
324
+
325
+ if (firstWord === undefined || !this.isConventionalVerb(firstWord)) {
326
+ return `Log message must begin with a verb in present progressive or past tense, got "${firstWord ?? ""}": "${emoji} ${text}"`;
327
+ }
328
+
329
+ return undefined;
330
+ }
331
+
332
+ /**
333
+ * Whether a word is a verb in one of the two tenses the convention allows.
334
+ *
335
+ * Present progressive means the operation is under way; past means it
336
+ * finished. Regular morphology covers both, so a new verb needs no
337
+ * registration anywhere — only irregular pasts are enumerated.
338
+ */
339
+ private isConventionalVerb(word: string): boolean {
340
+ const lowercased = word.toLowerCase();
341
+
342
+ return (
343
+ lowercased.endsWith("ing") ||
344
+ lowercased.endsWith("ed") ||
345
+ IRREGULAR_PAST_VERBS.has(lowercased)
346
+ );
347
+ }
348
+
349
+ /** Splits a leading emoji off a message, leaving prose behind. */
350
+ private parseMessage(message: unknown): ParsedLogMessage {
351
+ const text = String(message);
352
+ const match = LEADING_EMOJI_PATTERN.exec(text);
353
+ const emoji = match?.[1];
354
+
355
+ return emoji === undefined
356
+ ? { emoji: undefined, text }
357
+ : { emoji, text: text.slice(match?.[0].length) };
358
+ }
359
+
360
+ /** Whether a context is intentionally exempt from the validation rule. */
361
+ private shouldSkipConventionalMessageValidation(
362
+ context: string | undefined,
363
+ ): boolean {
364
+ return context !== undefined && UNVALIDATED_LOG_CONTEXTS.has(context);
365
+ }
366
+
367
+ // 🌎 Public Methods
368
+
369
+ /** The pino instance every logger's child is taken from. */
370
+ private static get root(): pino.Logger {
371
+ LoggerService.rootLogger ??= LoggerService.createRootLogger();
372
+
373
+ return LoggerService.rootLogger;
374
+ }
375
+
376
+ /** Normalizes unknown errors into a stable message and timestamped log line. */
377
+ buildErrorLogEntry(
378
+ context: string,
379
+ error: unknown,
380
+ ): { errorMessage: string; logLine: string } {
381
+ const errorMessage =
382
+ error instanceof Error ? error.stack || error.message : String(error);
383
+
384
+ return {
385
+ errorMessage,
386
+ logLine: `[${new Date().toISOString()}] ${context}: ${errorMessage}\n`,
387
+ };
388
+ }
389
+
390
+ /** Builds a timestamped output log file path and ensures the output directory exists. */
391
+ createTimestampedOutputLogFilePath(filePrefix: string): string {
392
+ const outputDirectory = path.join(process.cwd(), "output");
393
+ if (!existsSync(outputDirectory)) {
394
+ mkdirSync(outputDirectory, { recursive: true });
395
+ }
396
+
397
+ return path.join(
398
+ outputDirectory,
399
+ `${filePrefix}-${new Date().toISOString().replaceAll(/[:.]/g, "-")}.log`,
400
+ );
401
+ }
402
+
403
+ /** Logs a debug message at the `debug` level. */
404
+ override debug(message: unknown, context?: string, data?: LogData): void {
405
+ const parsed = this.parseMessage(message);
406
+ this.child.debug(
407
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
408
+ parsed.text,
409
+ );
410
+ }
411
+
412
+ /**
413
+ * Logs an error message at the `error` level, optionally including a stack trace.
414
+ *
415
+ * `ConsoleLogger.error` spends a third slot on a context string that the
416
+ * other levels do not have, so this one accepts either: a string keeps
417
+ * NestJS's meaning, an object is structured data like everywhere else.
418
+ */
419
+ override error(
420
+ message: unknown,
421
+ stackOrContext?: string,
422
+ contextOrData?: LogData | string,
423
+ ): void {
424
+ const parsed = this.parseMessage(message);
425
+ const data = typeof contextOrData === "object" ? contextOrData : undefined;
426
+ const context =
427
+ typeof contextOrData === "string" ? contextOrData : this.context;
428
+
429
+ this.child.error(
430
+ {
431
+ ...this.buildBindings({ context, data, parsed }),
432
+ stack: stackOrContext,
433
+ },
434
+ parsed.text,
435
+ );
436
+ }
437
+
438
+ /** Logs an informational message at the `info` level. */
439
+ info(message: unknown, context?: string, data?: LogData): void {
440
+ const parsed = this.parseMessage(message);
441
+ this.child.info(
442
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
443
+ parsed.text,
444
+ );
445
+ }
446
+
447
+ /**
448
+ * Logs an informational message at the `info` level.
449
+ *
450
+ * NestJS and `nest-commander` call this method directly as part of the
451
+ * framework's own `LoggerService` contract, so it must keep working
452
+ * exactly as before. Application code should call `info` instead — the
453
+ * same behavior under a name that says what level it logs at.
454
+ */
455
+ override log(message: unknown, context?: string, data?: LogData): void {
456
+ this.info(message, context, data);
457
+ }
458
+
459
+ /** Sets the context label included in every subsequent log line. */
460
+ override setContext(context: string): void {
461
+ super.setContext(context);
462
+ this.child = LoggerService.root.child({ context });
463
+ }
464
+
465
+ /** Logs a verbose message at the `trace` level. */
466
+ override verbose(message: unknown, context?: string, data?: LogData): void {
467
+ const parsed = this.parseMessage(message);
468
+ this.child.trace(
469
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
470
+ parsed.text,
471
+ );
472
+ }
473
+
474
+ /** Logs a warning message at the `warn` level. */
475
+ override warn(message: unknown, context?: string, data?: LogData): void {
476
+ const parsed = this.parseMessage(message);
477
+ this.child.warn(
478
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
479
+ parsed.text,
480
+ );
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Root NestJS application module.
486
+ */
487
+ export declare class MainModule {
488
+ }
489
+
490
+ /** A message split into the emoji the console shows and the prose telemetry stores. */
491
+ declare interface ParsedLogMessage {
492
+ emoji: string | undefined;
493
+ text: string;
494
+ }
495
+
496
+ /**
497
+ * Names every template the configuration declares, and which instances each
498
+ * explains.
499
+ *
500
+ * With `--instances` it answers the other direction — which templates explain a
501
+ * given path. That is one command rather than two because a path can belong to
502
+ * several templates at once: nothing records where an instance came from, so
503
+ * attribution is inferred from file overlap and ties are real.
504
+ *
505
+ * Output goes to standard output rather than through the logger, which asserts
506
+ * every message opens with an emoji and a verb — right for a log line, wrong
507
+ * for a listing.
508
+ */
509
+ export declare class TemplatesCommand extends CommandRunner {
510
+ private readonly configurationService;
511
+ private readonly inventoryService;
512
+ private readonly logger;
513
+ constructor(configurationService: ConfigurationService, inventoryService: InventoryService, logger: LoggerService);
514
+ /** Parses the optional configuration path. */
515
+ parseConfig(value: string | undefined): string | undefined;
516
+ /** Parses the optional instance filter. */
517
+ parseInstances(value: string | undefined): string[] | undefined;
518
+ /** Selects the machine-readable listing. */
519
+ parseJson(): boolean;
520
+ /** Writes every declared template, filtered to the given instances. */
521
+ run(_passedParameters: string[], options: TemplatesCommandOptions): Promise<void>;
522
+ }
523
+
524
+ /** Options accepted by the templates command. */
525
+ export declare interface TemplatesCommandOptions {
526
+ config?: string;
527
+ instances?: string[];
528
+ json?: boolean;
529
+ }
530
+
531
+ /**
532
+ * Provides the templates command.
533
+ */
534
+ export declare class TemplatesModule {
535
+ }
536
+
537
+ /**
538
+ * Validates instances against their conformetry templates.
539
+ *
540
+ * Which paths are instances comes from the configuration's `instances` globs,
541
+ * which `--instances` overrides for a one-off run, and `--templates` narrows
542
+ * the other half of the pairing. Neither flag overrides the other: each
543
+ * removes candidates from one side before templates and instances are paired,
544
+ * so a run is their intersection.
545
+ *
546
+ * `--templates` is the one option that is asked for when absent, because it
547
+ * is the one whose absence is genuinely a question rather than a default. It
548
+ * is asked only where somebody can answer: with no terminal the run falls
549
+ * back to every template, which is exactly what every invocation predating
550
+ * this flag already did.
551
+ */
552
+ export declare class ValidateCommand extends CommandRunner {
553
+ private readonly configurationService;
554
+ private readonly reportingService;
555
+ private readonly validationService;
556
+ private readonly logger;
557
+ constructor(configurationService: ConfigurationService, reportingService: ReportingService, validationService: ValidationService, logger: LoggerService);
558
+ /**
559
+ * Describes why the run failed, naming the instances that fell short.
560
+ *
561
+ * A file count alone stopped being the whole story once thresholds existed:
562
+ * findings can be printed for an instance that still passed, so the message
563
+ * has to say which instances actually failed and by how much.
564
+ */
565
+ private describeFailure;
566
+ /**
567
+ * Expands every configured glob group into instances, or the single
568
+ * override group `--instances` supplies.
569
+ *
570
+ * Groups exist so that substitutions can differ per glob: `type` is
571
+ * `packages` for one set of paths and `applications` for another, and no
572
+ * generic rule can tell them apart.
573
+ */
574
+ private findInstances;
575
+ /**
576
+ * Offers a picker, or declines to ask where nobody could answer.
577
+ *
578
+ * Declining resolves to no selection rather than to a refusal, which is
579
+ * where this parts company with `generate`: a template that cannot be
580
+ * chosen leaves that command with nothing to render, where this one still
581
+ * has a whole workspace to validate.
582
+ *
583
+ * The loaded configuration is handed over as-is — a definition already
584
+ * carries the name and description a choice needs, so mapping it here would
585
+ * be a second source the picker could disagree with.
586
+ */
587
+ private promptForTemplateNames;
588
+ /**
589
+ * Reports a narrowing that matched nothing, as itself.
590
+ *
591
+ * A run with no instances produces no findings, and a report rendering no
592
+ * findings is indistinguishable from a clean one — which would turn naming
593
+ * a real template that happens to have nothing under it into a green
594
+ * result. The reader is told nothing matched instead.
595
+ */
596
+ private reportEmptySelection;
597
+ /**
598
+ * Writes the report and fails the run when anything fell short.
599
+ *
600
+ * The report is the command's product, not a log line: it is a multi-line
601
+ * document written for a reader, and routing it through the logger would
602
+ * both bury it in log framing and force prose no telemetry can group on.
603
+ */
604
+ private reportResult;
605
+ /**
606
+ * Pairs the two filters into the instances a run covers.
607
+ *
608
+ * With both flags supplied the globbed paths are intersected with the
609
+ * selected templates' own instances, rather than one flag winning: each
610
+ * simply removes candidates from one side.
611
+ */
612
+ private selectInstances;
613
+ /**
614
+ * Narrows the run to the selected templates, or leaves it whole.
615
+ *
616
+ * `undefined` means no narrowing, which is a different thing from an empty
617
+ * selection: it is what an absent flag, the `all` sentinel, and a cancelled
618
+ * picker all mean, and it reproduces the run this command made before the
619
+ * flag existed.
620
+ */
621
+ private selectTemplates;
622
+ /** Parses the optional configuration path. */
623
+ parseConfig(value: string | undefined): string | undefined;
624
+ /** Parses the optional instance glob override. */
625
+ parseInstances(value: string | undefined): string[] | undefined;
626
+ /** Parses the optional language filter. */
627
+ parseLanguages(value: string | undefined): string[] | undefined;
628
+ /**
629
+ * Parses the optional template filter.
630
+ *
631
+ * Comma-delimited like its `--instances` and `--languages` siblings, so all
632
+ * three read the same way on a command line.
633
+ */
634
+ parseTemplates(value: string | undefined): string[] | undefined;
635
+ /** Parses the optional run-level conformance threshold. */
636
+ parseThreshold(value: string | undefined): number | undefined;
637
+ /** Runs validation and reports every difference found. */
638
+ run(_passedParameters: string[], options: ValidateCommandOptions): Promise<void>;
639
+ }
640
+
641
+ /** Options accepted by the validate command. */
642
+ export declare interface ValidateCommandOptions {
643
+ config?: string;
644
+ instances?: string[];
645
+ languages?: string[];
646
+ /**
647
+ * Template names to narrow the run to, or `["all"]` for every one.
648
+ *
649
+ * Absent means the caller has not decided, which is what the picker asks
650
+ * about; `["all"]` means they have, and nothing is asked.
651
+ */
652
+ templates?: string[];
653
+ threshold?: number;
654
+ }
655
+
656
+ /**
657
+ * Provides the validate command.
658
+ */
659
+ export declare class ValidateModule {
660
+ }
661
+
662
+ export { }
@@ -0,0 +1,2 @@
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "../main.module-BIsov6qb.js";
2
+ export { r as GenerateCommand, t as GenerateModule, s as InstancesCommand, a as InstancesModule, c as MainModule, e as TemplatesCommand, n as TemplatesModule, o as ValidateCommand, i as ValidateModule };
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import { t as e, u as t } from "../main.module-BIsov6qb.js";
3
+ import { CommandFactory as n } from "nest-commander";
4
+ import "reflect-metadata";
5
+ //#region packages/ic-suite/conformetry/conformetry-cli/src/main.ts
6
+ async function r() {
7
+ let r = new t();
8
+ r.setContext("CommandFactory"), await n.run(e, {
9
+ bufferLogs: !0,
10
+ errorHandler: (e) => {
11
+ process.exitCode = 1, r.error(e);
12
+ },
13
+ logger: r,
14
+ serviceErrorHandler: (e) => {
15
+ process.exitCode = 1, r.error(e);
16
+ }
17
+ });
18
+ }
19
+ r();
20
+ //#endregion