1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74import type { RulesetDefinition } from '@stoplight/spectral-core';
import { Spectral } from '@stoplight/spectral-core';
const { bundleAndLoadRuleset } = require('@stoplight/spectral-ruleset-bundler/with-loader');
import fs from 'node:fs';
import path from 'node:path';
import { oas } from '@stoplight/spectral-rulesets';
import { DiagnosticSeverity } from '@stoplight/types';
import { InsoError } from '../cli';
import { logger } from '../logger';
export const getRuleSetFileFromFolderByFilename = async (filePath: string) => {
try {
const filesInSpecFolder = await fs.promises.readdir(path.dirname(filePath));
const rulesetFileName = filesInSpecFolder.find(file => file.startsWith('.spectral'));
if (rulesetFileName) {
logger.trace(`Loading ruleset from \`${rulesetFileName}\``);
return path.resolve(path.dirname(filePath), rulesetFileName);
}
logger.info(`Using ruleset: oas, see ${oas.documentationUrl}`);
return;
} catch (error) {
throw new InsoError(`Failed to read "${filePath}"`, error);
}
};
export async function lintSpecification({
specContent,
rulesetFileName,
}: {
specContent: string;
rulesetFileName?: string;
}) {
const spectral = new Spectral();
// Use custom ruleset if present
let ruleset = oas;
try {
if (rulesetFileName) {
ruleset = await bundleAndLoadRuleset(rulesetFileName, { fs });
}
} catch (error) {
logger.fatal(error.message);
return { isValid: false };
}
spectral.setRuleset(ruleset as RulesetDefinition);
const results = await spectral.run(specContent);
if (!results.length) {
logger.log('No linting errors or warnings.');
return { results, isValid: true };
}
// Print Summary
if (results.some(r => r.severity === DiagnosticSeverity.Error)) {
logger.fatal(`${results.filter(r => r.severity === DiagnosticSeverity.Error).length} lint errors found. \n`);
}
if (results.some(r => r.severity === DiagnosticSeverity.Warning)) {
logger.warn(`${results.filter(r => r.severity === DiagnosticSeverity.Warning).length} lint warnings found. \n`);
}
results.forEach(r =>
logger.log(
`${r.range.start.line + 1}:${r.range.start.character + 1} - ${DiagnosticSeverity[r.severity]} - ${r.code} - ${
r.message
} - ${r.path.join('.')}`,
),
);
// Fail if errors present
if (results.some(r => r.severity === DiagnosticSeverity.Error)) {
logger.log('Errors found, failing lint.');
return { results, isValid: false };
}
return { results, isValid: true };
}