@redocly/openapi-core
Version:
See https://github.com/Redocly/openapi-cli
127 lines (112 loc) • 3.85 kB
text/typescript
import { BaseResolver, resolveDocument, Document, makeDocumentFromString } from './resolve';
import {
normalizeVisitors,
} from './visitors';
import { Oas3_1Types } from './types/oas3_1';
import { Oas3Types } from './types/oas3';
import { Oas2Types } from './types/oas2';
import { NodeType } from './types';
import { ProblemSeverity, WalkContext, walkDocument } from './walk';
import { LintConfig, Config } from './config/config';
import { normalizeTypes } from './types';
import { initRules } from './config/rules';
import { releaseAjvInstance } from './rules/ajv';
import { detectOpenAPI, OasMajorVersion, OasVersion, openAPIMajor } from './oas-types';
import { ConfigTypes } from './types/redocly-yaml';
import { OasSpec } from './rules/common/spec';
import { defaultPlugin } from './config/builtIn';
export async function lint(opts: {
ref: string;
config: Config;
externalRefResolver?: BaseResolver;
}) {
const { ref, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
const document = (await externalRefResolver.resolveDocument(null, ref, true)) as Document;
return lintDocument({
document,
...opts,
externalRefResolver,
config: opts.config.lint,
});
}
export async function lintFromString(opts: {
source: string;
absoluteRef?: string;
config: Config;
externalRefResolver?: BaseResolver;
}) {
const { source, absoluteRef, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
const document = makeDocumentFromString(source, absoluteRef || '/');
return lintDocument({
document,
...opts,
externalRefResolver,
config: opts.config.lint,
});
}
export async function lintDocument(opts: {
document: Document;
config: LintConfig;
customTypes?: Record<string, NodeType>;
externalRefResolver: BaseResolver;
}) {
releaseAjvInstance(); // FIXME: preprocessors can modify nodes which are then cached to ajv-instance by absolute path
const { document, customTypes, externalRefResolver, config } = opts;
const oasVersion = detectOpenAPI(document.parsed);
const oasMajorVersion = openAPIMajor(oasVersion);
const rules = config.getRulesForOasVersion(oasMajorVersion);
const types = normalizeTypes(
config.extendTypes(
customTypes ?? oasMajorVersion === OasMajorVersion.Version3 ? (oasVersion === OasVersion.Version3_1 ? Oas3_1Types : Oas3Types) : Oas2Types,
oasVersion,
),
config,
);
const ctx: WalkContext = {
problems: [],
oasVersion: oasVersion,
visitorsData: {},
};
const preprocessors = initRules(rules as any, config, 'preprocessors', oasVersion);
const regularRules = initRules(rules as any, config, 'rules', oasVersion);
const normalizedVisitors = normalizeVisitors([...preprocessors, ...regularRules], types);
const resolvedRefMap = await resolveDocument({
rootDocument: document,
rootType: types.DefinitionRoot,
externalRefResolver
});
walkDocument({
document,
rootType: types.DefinitionRoot,
normalizedVisitors,
resolvedRefMap,
ctx,
});
return ctx.problems.map((problem) => config.addProblemToIgnore(problem));
}
export async function lintConfig(opts: {
document: Document,
}) {
const { document } = opts;
const ctx: WalkContext = {
problems: [],
oasVersion: OasVersion.Version3_0,
visitorsData: {},
};
const config = new LintConfig({
plugins: [defaultPlugin],
extends: [],
rules: { spec: 'error' },
});
const types = normalizeTypes(ConfigTypes, config);
const rules = [{ severity: 'error' as ProblemSeverity, ruleId: 'spec', visitor: OasSpec({ severity: 'error' }) }];
const normalizedVisitors = normalizeVisitors(rules, types);
walkDocument({
document,
rootType: types.ConfigRoot,
normalizedVisitors,
resolvedRefMap: new Map(),
ctx,
});
return ctx.problems;
}