Skip to content

Commit 3ecd126

Browse files
feat: implemented logic to output diagnostics log by adding additional output flag to validate cli command. (#1563)
Co-authored-by: Souvik De <souvikde.ns@gmail.com>
1 parent b18c368 commit 3ecd126

File tree

1 file changed

+84
-16
lines changed

1 file changed

+84
-16
lines changed

src/core/parser.ts

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,29 @@ import { red, yellow, green, cyan } from 'chalk';
1212
import type { Diagnostic } from '@asyncapi/parser/cjs';
1313
import type Command from './base';
1414
import type { Specification } from './models/SpecificationFile';
15+
import { promises } from 'fs';
16+
import path from 'path';
17+
18+
type DiagnosticsFormat = 'stylish' | 'json' | 'junit' | 'html' | 'text' | 'teamcity' | 'pretty';
1519

1620
export type SeverityKind = 'error' | 'warn' | 'info' | 'hint';
1721

1822
export { convertToOldAPI };
1923

24+
const { writeFile } = promises;
25+
26+
const formatExtensions: Record<DiagnosticsFormat, string> = {
27+
stylish: '.txt',
28+
json: '.json',
29+
junit: '.xml',
30+
html: '.html',
31+
text: '.txt',
32+
teamcity: '.txt',
33+
pretty: '.txt',
34+
};
35+
36+
const validFormats = ['stylish', 'json', 'junit', 'html', 'text', 'teamcity', 'pretty'];
37+
2038
const parser = new Parser({
2139
__unstable: {
2240
resolver: {
@@ -56,13 +74,18 @@ export function validationFlags({ logDiagnostics = true }: ValidationFlagsOption
5674
options: ['error', 'warn', 'info', 'hint'] as const,
5775
default: 'error',
5876
})(),
77+
output: Flags.string({
78+
description: 'The output file name. Omitting this flag the result will be printed in the console.',
79+
char: 'o'
80+
})
5981
};
6082
}
6183

6284
export interface ValidateOptions {
6385
'log-diagnostics'?: boolean;
6486
'diagnostics-format'?: `${OutputFormat}`;
6587
'fail-severity'?: SeverityKind;
88+
'output'?: string;
6689
}
6790

6891
export async function validate(command: Command, specFile: Specification, options: ValidateOptions = {}) {
@@ -76,30 +99,56 @@ export async function parse(command: Command, specFile: Specification, options:
7699
return { document, diagnostics, status };
77100
}
78101

79-
function logDiagnostics(diagnostics: Diagnostic[], command: Command, specFile: Specification, options: ValidateOptions = {}): 'valid' | 'invalid' {
102+
function logDiagnostics(
103+
diagnostics: Diagnostic[],
104+
command: Command,
105+
specFile: Specification,
106+
options: ValidateOptions = {}
107+
): 'valid' | 'invalid' {
80108
const logDiagnostics = options['log-diagnostics'];
81109
const failSeverity = options['fail-severity'] ?? 'error';
82110
const diagnosticsFormat = options['diagnostics-format'] ?? 'stylish';
83-
84111
const sourceString = specFile.toSourceString();
85-
if (diagnostics.length) {
86-
if (hasFailSeverity(diagnostics, failSeverity)) {
87-
if (logDiagnostics) {
88-
command.logToStderr(`\n${sourceString} and/or referenced documents have governance issues.`);
89-
command.logToStderr(formatOutput(diagnostics, diagnosticsFormat, failSeverity));
90-
}
91-
return ValidationStatus.INVALID;
92-
}
93112

94-
if (logDiagnostics) {
95-
command.log(`\n${sourceString} is valid but has (itself and/or referenced documents) governance issues.`);
96-
command.log(formatOutput(diagnostics, diagnosticsFormat, failSeverity));
97-
}
98-
} else if (logDiagnostics) {
113+
const hasIssues = diagnostics.length > 0;
114+
const isFailSeverity = hasIssues && hasFailSeverity(diagnostics, failSeverity);
115+
116+
if (logDiagnostics) {
117+
logGovernanceMessage(command, sourceString, hasIssues, isFailSeverity);
118+
outputDiagnostics(command, diagnostics, diagnosticsFormat, failSeverity, options);
119+
}
120+
121+
return isFailSeverity ? ValidationStatus.INVALID : ValidationStatus.VALID;
122+
}
123+
124+
function logGovernanceMessage(
125+
command: Command,
126+
sourceString: string,
127+
hasIssues: boolean,
128+
isFailSeverity: boolean
129+
) {
130+
if (!hasIssues) {
99131
command.log(`\n${sourceString} is valid! ${sourceString} and referenced documents don't have governance issues.`);
132+
} else if (isFailSeverity) {
133+
command.logToStderr(`\n${sourceString} and/or referenced documents have governance issues.`);
134+
} else {
135+
command.log(`\n${sourceString} is valid but has (itself and/or referenced documents) governance issues.`);
100136
}
137+
}
101138

102-
return ValidationStatus.VALID;
139+
function outputDiagnostics(
140+
command: Command,
141+
diagnostics: Diagnostic[],
142+
diagnosticsFormat: DiagnosticsFormat,
143+
failSeverity: SeverityKind,
144+
options: ValidateOptions
145+
) {
146+
const diagnosticsOutput = formatOutput(diagnostics, diagnosticsFormat, failSeverity);
147+
if (options.output) {
148+
writeValidationDiagnostic(options.output, command, diagnosticsFormat, diagnosticsOutput);
149+
} else {
150+
command.log(diagnosticsOutput);
151+
}
103152
}
104153

105154
export function formatOutput(diagnostics: Diagnostic[], format: `${OutputFormat}`, failSeverity: SeverityKind) {
@@ -145,3 +194,22 @@ function hasFailSeverity(diagnostics: Diagnostic[], failSeverity: SeverityKind)
145194
const diagnosticSeverity = getDiagnosticSeverity(failSeverity);
146195
return diagnostics.some(diagnostic => diagnostic.severity <= diagnosticSeverity);
147196
}
197+
198+
async function writeValidationDiagnostic(outputPath: string, command: Command, format: DiagnosticsFormat, formatOutput: string) {
199+
if (!validFormats.includes(format)) {
200+
command.logToStderr(`Invalid diagnostics format: "${format}"`);
201+
return;
202+
}
203+
204+
const expectedExtension = formatExtensions[format as keyof typeof formatExtensions];
205+
const actualExtension = path.extname(outputPath);
206+
207+
// Validate file extension against diagnostics format
208+
if (expectedExtension && (actualExtension !== expectedExtension)) {
209+
command.logToStderr(`Invalid file extension for format "${format}". Expected extension: "${expectedExtension}"`);
210+
} else {
211+
await writeFile(path.resolve(process.cwd(), outputPath), formatOutput, {
212+
encoding: 'utf-8',
213+
}).catch(err => console.log(err));
214+
}
215+
}

0 commit comments

Comments
 (0)