Skip to content

Commit

Permalink
feat(core): add documentUrl to JS api and cli formatters
Browse files Browse the repository at this point in the history
  • Loading branch information
dweber019 committed Mar 29, 2023
1 parent e368204 commit 38abb2c
Show file tree
Hide file tree
Showing 24 changed files with 84 additions and 50 deletions.
6 changes: 6 additions & 0 deletions packages/cli/src/formatters/__tests__/html.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,42 @@ describe('HTML formatter', () => {
<td>3:10</td>
<td class="severity clr-hint">hint</td>
<td>Info object should contain \`contact\` object.</td>
<td></td>
</tr>
<tr style="display:none" class="f-0">
<td>3:10</td>
<td class="severity clr-warning">warning</td>
<td>OpenAPI object info \`description\` must be present and non-empty string.</td>
<td></td>
</tr>
<tr style="display:none" class="f-0">
<td>5:14</td>
<td class="severity clr-error">error</td>
<td>Info must contain Stoplight</td>
<td></td>
</tr>
<tr style="display:none" class="f-0">
<td>17:13</td>
<td class="severity clr-information">information</td>
<td>Operation \`description\` must be present and non-empty string.</td>
<td></td>
</tr>
<tr style="display:none" class="f-0">
<td>64:14</td>
<td class="severity clr-information">information</td>
<td>Operation \`description\` must be present and non-empty string.</td>
<td></td>
</tr>
<tr style="display:none" class="f-0">
<td>86:13</td>
<td class="severity clr-information">information</td>
<td>Operation \`description\` must be present and non-empty string.</td>
<td></td>
</tr>`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
<td><%= line %>:<%= character %></td>
<td class="severity clr-<%= severity %>"><%= severity %></td>
<td><%- message %></td>
<td><% if(documentationUrl) { %><a href="<%- documentationUrl %>" target="_blank">documentation</a><% } %></td>
</tr>
1 change: 1 addition & 0 deletions packages/cli/src/formatters/html/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function renderMessages(messages: IRuleResult[], parentIndex: number): string {
severity: getSeverityName(message.severity),
message: message.message,
code: message.code,
documentationUrl: message.documentationUrl,
});
})
.join('\n');
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/formatters/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const json: Formatter = results => {
severity: result.severity,
range: result.range,
source: result.source,
documentationUrl: result.documentationUrl,
};
});
return JSON.stringify(outputJson, null, '\t');
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/formatters/junit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ export const junit: Formatter = (results, { failSeverity }) => {
output += `line ${result.range.start.line + 1}, col ${result.range.start.character + 1}, `;
output += `${prepareForCdata(result.message)} (${result.code}) `;
output += `at path ${prepareForCdata(path)}`;
if (result.documentationUrl) {
output += `, ${result.documentationUrl}`;
}
output += ']]>';
output += `</failure>`;
output += '</testcase>\n';
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/formatters/pretty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ export const pretty: Formatter = results => {
{ text: chalk[color].bold(result.code), padding: PAD_TOP0_LEFT2, width: COLUMNS[2] },
{ text: chalk.gray(result.message), padding: PAD_TOP0_LEFT2, width: COLUMNS[3] },
{ text: chalk.cyan(printPath(result.path, PrintStyle.Dot)), padding: PAD_TOP0_LEFT2 },
{
text: chalk.gray(result.documentationUrl ?? ''),
padding: PAD_TOP0_LEFT2,
width: result.documentationUrl ? undefined : 0.1,
},
);
ui.div();
});
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/formatters/stylish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const stylish: Formatter = results => {
result.code ?? '',
result.message,
printPath(result.path, PrintStyle.Dot),
result.documentationUrl ?? '',
]);

output += `${table(pathTableData, {
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/formatters/teamcity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ function inspectionType(result: IRuleResult & { source: string }): string {
const code = escapeString(result.code);
const severity = getSeverityName(result.severity);
const message = escapeString(result.message);
return `##teamcity[inspectionType category='openapi' id='${code}' name='${code}' description='${severity} -- ${message}']`;
const documentationUrl = result.documentationUrl ? ` -- ${escapeString(result.documentationUrl)}` : '';
return `##teamcity[inspectionType category='openapi' id='${code}' name='${code}' description='${severity} -- ${message}${documentationUrl}']`;
}

function inspection(result: IRuleResult & { source: string }): string {
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/formatters/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ function renderResults(results: IRuleResult[]): string {
const line = result.range.start.line + 1;
const character = result.range.start.character + 1;
const severity = getSeverityName(result.severity);
return `${result.source}:${line}:${character} ${severity} ${result.code} "${result.message}"`;
const documentationUrl = result.documentationUrl ? ` ${result.documentationUrl}` : '';
return `${result.source}:${line}:${character} ${severity} ${result.code} "${result.message}"${documentationUrl}`;
})
.join('\n');
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/runner/lintNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ function processTargetResults(
severity,
...(source !== null ? { source } : null),
range,
documentationUrl: rule.documentationUrl ?? undefined,
});
}
}
1 change: 1 addition & 0 deletions packages/core/src/types/spectral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface IRunOpts {
export interface ISpectralDiagnostic extends IDiagnostic {
path: JsonPath;
code: string | number;
documentationUrl?: string;
}

export type IRuleResult = ISpectralDiagnostic;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('asyncApi2DocumentSchema', () => {
).toEqual([
{
code: 'asyncapi-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-schema',
message: '"info" property must have required property "title"',
path: ['info'],
severity: DiagnosticSeverity.Error,
Expand Down Expand Up @@ -131,13 +132,15 @@ describe('asyncApi2DocumentSchema', () => {
).toEqual([
{
code: 'asyncapi-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-schema',
message: '"0" property type must be string',
path: ['channels', '/user/signedup', 'servers', '0'],
severity: DiagnosticSeverity.Error,
range: expect.any(Object),
},
{
code: 'asyncapi-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-schema',
message: '"2" property type must be string',
path: ['channels', '/user/signedup', 'servers', '2'],
severity: DiagnosticSeverity.Error,
Expand Down Expand Up @@ -184,6 +187,7 @@ describe('asyncApi2DocumentSchema', () => {
).toEqual([
{
code: 'asyncapi-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-schema',
message: '"kafka" property must have required property "url"',
path: ['components', 'servers', 'kafka'],
severity: DiagnosticSeverity.Error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ describe('oasDocumentSchema', () => {
).toEqual([
{
code: 'oas2-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-schema',
message: 'Invalid basic authentication security definition.',
path: ['securityDefinitions', 'basic'],
severity: DiagnosticSeverity.Error,
Expand Down Expand Up @@ -82,6 +83,7 @@ describe('oasDocumentSchema', () => {
).toEqual([
{
code: 'oas3-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas3-schema',
message: '"type" property type must be string.',
path: ['paths', '/user', 'get', 'parameters', '0', 'schema', 'type'],
severity: DiagnosticSeverity.Error,
Expand Down Expand Up @@ -120,13 +122,15 @@ describe('oasDocumentSchema', () => {
).toEqual([
{
code: 'oas3-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas3-schema',
message: 'Invalid security scheme.',
path: ['components', 'securitySchemes', 'basic'],
severity: DiagnosticSeverity.Error,
range: expect.any(Object),
},
{
code: 'oas3-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas3-schema',
message: 'Property "foo" is not expected to be here.',
path: ['components', 'securitySchemes', 'basic', 'foo'],
severity: DiagnosticSeverity.Error,
Expand Down Expand Up @@ -157,6 +161,7 @@ describe('oasDocumentSchema', () => {
).toEqual([
{
code: 'oas3-schema',
documentationUrl: 'https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas3-schema',
message: '"200" property must have required property "description".',
path: ['paths', '/user', 'get', 'responses', '200'],
severity: DiagnosticSeverity.Error,
Expand Down
14 changes: 7 additions & 7 deletions test-harness/scenarios/asyncapi2-streetlights.scenario
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,12 @@ module.exports = asyncapi;
{bin} lint {document} --ruleset "{asset:ruleset}"
====stdout====
{document}
1:1 warning asyncapi-tags AsyncAPI object must have non-empty "tags" array.
1:11 information asyncapi-latest-version The latest version is not used. You should update to the "2.6.0" version. asyncapi
2:6 warning asyncapi-info-contact Info object must have "contact" object. info
45:13 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured.publish
57:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/on.subscribe
68:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/off.subscribe
79:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/dim.subscribe
1:1 warning asyncapi-tags AsyncAPI object must have non-empty "tags" array. https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-tags
1:11 information asyncapi-latest-version The latest version is not used. You should update to the "2.6.0" version. asyncapi https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-latest-version
2:6 warning asyncapi-info-contact Info object must have "contact" object. info https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-info-contact
45:13 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured.publish https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-operation-description
57:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/on.subscribe https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-operation-description
68:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/turn/off.subscribe https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-operation-description
79:15 warning asyncapi-operation-description Operation "description" must be present and non-empty string. channels.smartylighting/streetlights/1/0/action/{streetlightId}/dim.subscribe https://meta.stoplight.io/docs/spectral/docs/reference/asyncapi-rules.md#asyncapi-operation-description

✖ 7 problems (0 errors, 6 warnings, 1 info, 0 hints)
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ components:
{bin} lint {document} --ruleset "{asset:ruleset}"
====stdout====
{document}
10:16 error duplicated-entry-in-enum "enum" property must not have duplicate items (items ## 1 and 5 are identical) components.schemas.a_model.properties.id.enum
10:16 error duplicated-entry-in-enum "enum" property must not have duplicate items (items ## 1 and 5 are identical) components.schemas.a_model.properties.id.enum https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#duplicated-entry-in-enum

✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints)
16 changes: 8 additions & 8 deletions test-harness/scenarios/examples.oas2.scenario
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,13 @@ module.exports = oas;
{bin} lint {document} --ruleset "{asset:ruleset}"
====stdout====
{document}
83:26 error oas2-valid-schema-example "completed" property type must be boolean paths./schema-example.get.responses[500].schema.example.completed
91:26 error oas2-valid-schema-example "example" property type must be boolean paths./schema-example.get.responses[501].schema.properties.some-bool.example
95:26 error oas2-valid-schema-example "example" property must match format "date-time" paths./schema-example.get.responses[501].schema.properties.some-date.example
99:26 error oas2-valid-schema-example "example" property must match format "url" paths./schema-example.get.responses[501].schema.properties.some-url.example
106:11 warning operation-tag-defined Operation tags must be defined in global tags. paths./param-examples.get.tags[0]
120:22 error oas2-valid-schema-example "x-example" property must be equal to one of the allowed values: "foo", "bar" paths./param-examples.get.parameters[1].x-example
177:30 error oas2-valid-media-example "application/json" property must have required property "name" paths./response-examples.get.responses[500].examples.application/json
194:30 error oas2-valid-media-example "application/json" property must have required property "user" paths./response-examples-via-$ref.get.responses[200].examples.application/json
83:26 error oas2-valid-schema-example "completed" property type must be boolean paths./schema-example.get.responses[500].schema.example.completed https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-schema-example
91:26 error oas2-valid-schema-example "example" property type must be boolean paths./schema-example.get.responses[501].schema.properties.some-bool.example https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-schema-example
95:26 error oas2-valid-schema-example "example" property must match format "date-time" paths./schema-example.get.responses[501].schema.properties.some-date.example https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-schema-example
99:26 error oas2-valid-schema-example "example" property must match format "url" paths./schema-example.get.responses[501].schema.properties.some-url.example https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-schema-example
106:11 warning operation-tag-defined Operation tags must be defined in global tags. paths./param-examples.get.tags[0] https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#operation-tag-defined
120:22 error oas2-valid-schema-example "x-example" property must be equal to one of the allowed values: "foo", "bar" paths./param-examples.get.parameters[1].x-example https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-schema-example
177:30 error oas2-valid-media-example "application/json" property must have required property "name" paths./response-examples.get.responses[500].examples.application/json https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-media-example
194:30 error oas2-valid-media-example "application/json" property must have required property "user" paths./response-examples-via-$ref.get.responses[200].examples.application/json https://meta.stoplight.io/docs/spectral/docs/reference/openapi-rules.md#oas2-valid-media-example

✖ 8 problems (7 errors, 1 warning, 0 infos, 0 hints)
Loading

0 comments on commit 38abb2c

Please sign in to comment.