Skip to content

Commit 0754d1d

Browse files
AayushSaini101asyncapi-bot
andauthored
feat: add new feature to supress the warnings (#1805)
Co-authored-by: AayushSaini101 <[email protected]> Co-authored-by: asyncapi-bot <[email protected]>
1 parent 296af0a commit 0754d1d

File tree

6 files changed

+214
-23
lines changed

6 files changed

+214
-23
lines changed

.changeset/1805.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@asyncapi/cli': minor
3+
---
4+
5+
feat: add new feature to supress the warnings
6+
7+
- ab94c15: Add a new flag that is --x-suppress-warnings to supress the warning in the validate command
8+
- 55819cd: Allow to pass multiple warnings to supress and add check to verify the warning is correct or not
9+
- 885fc71: Update src/core/parser.ts
10+
11+
Co-authored-by: Souvik De <[email protected]>
12+
- 16b22de: Update src/core/flags/validate.flags.ts
13+
14+
Co-authored-by: Souvik De <[email protected]>
15+
- de1caad: Add another flag to supressallwarnings and update test case
16+
17+

docs/usage.md

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -792,33 +792,42 @@ _See code: [src/commands/start/preview.ts](https://github.com/asyncapi/cli/blob/
792792

793793
validate asyncapi file
794794

795-
```
796795
USAGE
797796
$ asyncapi validate [SPEC-FILE] [-h] [-w] [--log-diagnostics] [--diagnostics-format
798797
json|stylish|junit|html|text|teamcity|pretty] [--fail-severity error|warn|info|hint] [-o <value>] [--score]
799-
[--proxyHost <value>] [--proxyPort <value>]
798+
[--proxyHost <value>] [--proxyPort <value>] [--suppressWarnings <value>...] [--suppressAllWarnings]
800799

801800
ARGUMENTS
802801
SPEC-FILE spec path, url, or context-name
803802

804803
FLAGS
805804
-h, --help Show CLI help.
806-
-o, --output=<value> The output file name. Omitting this flag the result will be printed in the console.
807-
-w, --watch Enable watch mode
808-
--diagnostics-format=<option> [default: stylish] format to use for validation diagnostics
805+
-o, --output=<value> The output file name. Omitting this flag will print the result to the console.
806+
-w, --watch Enable watch mode.
807+
--diagnostics-format=<option> [default: stylish] Format to use for validation diagnostics.
809808
<options: json|stylish|junit|html|text|teamcity|pretty>
810-
--fail-severity=<option> [default: error] diagnostics of this level or above will trigger a failure exit
811-
code
809+
--fail-severity=<option> [default: error] Diagnostics of this level or above will trigger a failure exit
810+
code.
812811
<options: error|warn|info|hint>
813-
--[no-]log-diagnostics log validation diagnostics or not
814-
--proxyHost=<value> Name of the ProxyHost
815-
--proxyPort=<value> Port number number for the proxyHost.
812+
--[no-]log-diagnostics Log validation diagnostics or not.
813+
--proxyHost=<value> Name of the proxy host.
814+
--proxyPort=<value> Port number for the proxy host.
816815
--score Compute the score of the AsyncAPI document. Scoring is based on whether the
817-
document has description, license, server and/or channels.
816+
document has description, license, server, and/or channels.
817+
--suppressWarnings=<value> One or more warning codes to suppress from the diagnostics output. Can be passed
818+
multiple times.
819+
--suppressAllWarnings Suppress all warnings from the diagnostics output, regardless of their code.
818820

819821
DESCRIPTION
820-
validate asyncapi file
821-
```
822+
Validate an AsyncAPI file.
823+
824+
EXAMPLES
825+
$ asyncapi validate ./asyncapi.yml
826+
$ asyncapi validate ./asyncapi.yml --suppressWarnings asyncapi-id asyncapi-info-contact
827+
You need to pass the ID(s) of the warning(s) that you want to suppress during validation.
828+
$ asyncapi validate ./asyncapi.yml --suppressAllWarnings
829+
Use this flag to completely suppress all warnings from the validation output.
830+
822831

823-
_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.16.4/src/commands/validate.ts)_
824-
<!-- commandsstop -->
832+
See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.16.4/src/commands/validate.ts)_
833+
<!-- commandsstop -->

src/commands/validate.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,40 @@ export default class Validate extends Command {
1616
};
1717

1818
static args = {
19-
'spec-file': Args.string({description: 'spec path, url, or context-name', required: false}),
19+
'spec-file': Args.string({ description: 'spec path, url, or context-name', required: false }),
2020
};
2121

2222
async run() {
2323
const { args, flags } = await this.parse(Validate); //NOSONAR
2424
let filePath = args['spec-file'];
2525
const proxyHost = flags['proxyHost'];
2626
const proxyPort = flags['proxyPort'];
27+
2728
if (proxyHost && proxyPort) {
2829
const proxyUrl = `http://${proxyHost}:${proxyPort}`;
2930
filePath = `${filePath}+${proxyUrl}`; // Update filePath with proxyUrl
3031
}
32+
3133
this.specFile = await load(filePath);
3234
const watchMode = flags.watch;
35+
3336
if (flags['score']) {
34-
const { document } = await parse(this,this.specFile);
37+
const { document } = await parse(this, this.specFile);
3538
this.log(`The score of the asyncapi document is ${await calculateScore(document)}`);
3639
}
40+
3741
if (watchMode) {
3842
specWatcher({ spec: this.specFile, handler: this, handlerName: 'validate' });
3943
}
40-
const result = await validate(this, this.specFile, flags as ValidateOptions);
44+
45+
// Prepare validate options
46+
const validateOptions: ValidateOptions = {
47+
...flags,
48+
suppressWarnings: flags['suppressWarnings'],
49+
suppressAllWarnings: flags['suppressAllWarnings'],
50+
};
51+
52+
const result = await validate(this, this.specFile, validateOptions);
4153
this.metricsMetadata.validation_result = result;
4254

4355
if (result === ValidationStatus.INVALID) {

src/core/flags/validate.flags.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,17 @@ export const validateFlags = () => {
1010
score: Flags.boolean({
1111
description: 'Compute the score of the AsyncAPI document. Scoring is based on whether the document has description, license, server and/or channels.',
1212
required: false,
13-
default: false
14-
})
13+
default: false,
14+
}),
15+
suppressWarnings: Flags.string({
16+
description: 'List of warning codes to suppress from the validation output.',
17+
required: false,
18+
multiple: true,
19+
}),
20+
suppressAllWarnings: Flags.boolean({
21+
description: 'Suppress all warnings from the validation output.',
22+
required: false,
23+
default: false,
24+
}),
1525
};
1626
};

src/core/parser.ts

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ const parser = new Parser({
4040
resolver: {
4141
cache: false,
4242
}
43-
}
43+
},
44+
4445
});
4546

4647
parser.registerSchemaParser(AvroSchemaParser());
@@ -86,10 +87,73 @@ export interface ValidateOptions {
8687
'diagnostics-format'?: `${OutputFormat}`;
8788
'fail-severity'?: SeverityKind;
8889
'output'?: string;
90+
suppressWarnings?: string[];
91+
suppressAllWarnings?: boolean;
8992
}
9093

91-
export async function validate(command: Command, specFile: Specification, options: ValidateOptions = {}) {
92-
const diagnostics = await parser.validate(specFile.text(), { source: specFile.getSource() });
94+
export async function validate(
95+
command: Command,
96+
specFile: Specification,
97+
options: ValidateOptions = {}
98+
) {
99+
const suppressAllWarnings = options.suppressAllWarnings ?? false;
100+
const suppressedWarnings = options.suppressWarnings ?? [];
101+
let activeParser: Parser;
102+
103+
// Helper to build a parser with given rules turned off
104+
const buildCustomParser = (rulesToSuppress: string[]) =>
105+
new Parser({
106+
ruleset: {
107+
extends: [],
108+
rules: Object.fromEntries(rulesToSuppress.map(rule => [rule, 'off'])),
109+
},
110+
__unstable: {
111+
resolver: {
112+
cache: false,
113+
},
114+
},
115+
});
116+
117+
if (suppressAllWarnings) {
118+
// Run the default parser to discover all rule codes
119+
const diagnostics = await parser.validate(specFile.text(), {
120+
source: specFile.getSource(),
121+
});
122+
const allRuleNames = Array.from(
123+
new Set(diagnostics.map(d => d.code).filter((c): c is string => typeof c === 'string'))
124+
);
125+
activeParser = buildCustomParser(allRuleNames);
126+
} else if (suppressedWarnings.length === 0) {
127+
activeParser = parser;
128+
} else {
129+
try {
130+
activeParser = buildCustomParser(suppressedWarnings);
131+
} catch (e: any) {
132+
const msg = e.message || '';
133+
const matches = [...msg.matchAll(/Cannot extend non-existing rule: "([^"]+)"/g)];
134+
const invalidRules = matches.map(m => m[1]);
135+
if (invalidRules.length > 0) {
136+
for (const rule of invalidRules) {
137+
command.log(`Warning: '${rule}' is not a known rule and will be ignored.`);
138+
}
139+
const validRules = suppressedWarnings.filter(rule => !invalidRules.includes(rule));
140+
activeParser = buildCustomParser(validRules);
141+
} else {
142+
throw e;
143+
}
144+
}
145+
}
146+
147+
// Register schema parsers
148+
activeParser.registerSchemaParser(AvroSchemaParser());
149+
activeParser.registerSchemaParser(OpenAPISchemaParser());
150+
activeParser.registerSchemaParser(RamlDTSchemaParser());
151+
activeParser.registerSchemaParser(ProtoBuffSchemaParser());
152+
153+
const diagnostics = await activeParser.validate(specFile.text(), {
154+
source: specFile.getSource(),
155+
});
156+
93157
return logDiagnostics(diagnostics, command, specFile, options);
94158
}
95159

test/integration/validate.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,4 +273,83 @@ describe('validate', () => {
273273
done();
274274
});
275275
});
276+
277+
describe('validate command and suppression of the single warning', () => {
278+
test
279+
.stdout()
280+
.command([
281+
'validate',
282+
path.join('test', 'fixtures', 'asyncapi_v1.yml'),
283+
'--suppressWarnings',
284+
'asyncapi-id'
285+
])
286+
.it('should suppress specified warnings and still validate correctly', (ctx, done) => {
287+
expect(ctx.stdout).to.include('asyncapi_v1.yml');
288+
expect(ctx.stdout).to.match(/is valid/i); // General validity check
289+
expect(ctx.stdout).to.not.include('asyncapi-id'); // Ensure warning is suppressed
290+
done();
291+
});
292+
});
293+
describe('validate command and suppression of multiple warnings', () => {
294+
test
295+
.stdout()
296+
.command([
297+
'validate',
298+
path.join('test', 'fixtures', 'asyncapi_v1.yml'),
299+
'--suppressWarnings',
300+
'asyncapi-id',
301+
'suppressWarnings',
302+
'asyncapi2-tags'
303+
])
304+
.it('should suppress multiple specified warnings and still validate correctly', (ctx, done) => {
305+
expect(ctx.stdout).to.not.include('asyncapi-id'); // Suppressed warning #1
306+
expect(ctx.stdout).to.not.include('asyncapi2-tags'); // Suppressed warning #2
307+
done();
308+
});
309+
});
310+
311+
describe('validate command without suppression', () => {
312+
test
313+
.stdout()
314+
.command([
315+
'validate',
316+
path.join('test', 'fixtures', 'asyncapi_v1.yml'),
317+
])
318+
.it('should include the asyncapi-id warning when not suppressed', (ctx, done) => {
319+
expect(ctx.stdout).to.include('asyncapi-id'); // Should show up if not suppressed
320+
done();
321+
});
322+
});
323+
describe('validate command with an invalid suppression rule', () => {
324+
test
325+
.stdout()
326+
.command([
327+
'validate',
328+
path.join('test', 'fixtures', 'asyncapi_v1.yml'),
329+
'--suppressWarnings',
330+
'non-existing-rule'
331+
])
332+
.it('should warn about the unknown rule and not suppress anything', (ctx, done) => {
333+
expect(ctx.stdout).to.contains('Warning: \'non-existing-rule\' is not a known rule and will be ignored.');
334+
expect(ctx.stdout).to.include('asyncapi-id');
335+
done();
336+
});
337+
});
338+
describe('validate command with mixed valid and invalid suppressed warnings', () => {
339+
test
340+
.stdout()
341+
.command([
342+
'validate',
343+
path.join('test', 'fixtures', 'asyncapi_v1.yml'),
344+
'--suppressWarnings',
345+
'asyncapi-id',
346+
'--suppressWarnings',
347+
'foobar'
348+
])
349+
.it('should suppress valid rules and warn about invalid ones', (ctx, done) => {
350+
expect(ctx.stdout).to.not.include('asyncapi-id');
351+
expect(ctx.stdout).to.contains('Warning: \'foobar\' is not a known rule');
352+
done();
353+
});
354+
});
276355
});

0 commit comments

Comments
 (0)