UNPKG

@stoplight/spectral

Version:

A flexible object linter with out of the box support for OpenAPI v2 and v3.

148 lines 4.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const types_1 = require("@stoplight/types"); const jp = require("jsonpath"); const lodash_1 = require("lodash"); const message_1 = require("./rulesets/message"); exports.lintNode = (node, rule, then, apply, opts, parsedResult) => { const givenPath = node.path[0] === '$' ? node.path.slice(1) : node.path; const conditioning = exports.whatShouldBeLinted(givenPath, node.value, rule); if (!conditioning.lint) { return []; } const { parsed } = parsedResult; const targetValue = conditioning.value; const targets = []; if (then && then.field) { if (then.field === '@key') { for (const key of Object.keys(targetValue)) { targets.push({ path: key, value: key, }); } } else if (then.field[0] === '$') { const nodes = jp.nodes(targetValue, then.field); for (const n of nodes) { targets.push({ path: n.path, value: n.value, }); } } else { targets.push({ path: typeof then.field === 'string' ? then.field.split('.') : then.field, value: lodash_1.get(targetValue, then.field), }); } } else { targets.push({ path: [], value: targetValue, }); } if (!targets.length) { targets.push({ path: [], value: undefined, }); } let results = []; for (const target of targets) { const targetPath = givenPath.concat(target.path); const targetResults = apply(target.value, then.functionOptions || {}, { given: givenPath, target: targetPath, }, { original: node.value, given: node.value, resolved: opts.resolvedTarget, }) || []; const severity = rule.severity !== undefined ? rule.severity : types_1.DiagnosticSeverity.Warning; results = results.concat(targetResults.map(result => { const path = result.path || targetPath; const location = parsedResult.getLocationForJsonPath(parsed, path, true); return Object.assign({ code: rule.name, get summary() { return this.message; }, message: rule.message === undefined ? rule.summary || result.message : message_1.message(rule.message, { error: result.message, property: path.length > 0 ? path[path.length - 1] : '', description: rule.description, }), path, severity, source: parsedResult.source }, (location || { range: { start: { character: 0, line: 0, }, end: { character: 0, line: 0, }, }, })); })); } return results; }; exports.whatShouldBeLinted = (path, originalValue, rule) => { const leaf = path[path.length - 1]; const when = rule.when; if (!when) { return { lint: true, value: originalValue, }; } const pattern = when.pattern; const field = when.field; const isKey = field === '@key'; if (!pattern) { if (isKey) { return { lint: false, value: originalValue, }; } return { lint: lodash_1.has(originalValue, field), value: originalValue, }; } if (isKey && pattern) { return keyAndOptionalPattern(leaf, pattern, originalValue); } const fieldValue = String(lodash_1.get(originalValue, when.field)); return { lint: fieldValue.match(pattern) !== null, value: originalValue, }; }; function keyAndOptionalPattern(key, pattern, value) { if (typeof key === 'number' && typeof value === 'object') { for (const k of Object.keys(value)) { if (String(k).match(pattern)) { return { lint: true, value, }; } } } else if (String(key).match(pattern)) { return { lint: true, value, }; } return { lint: false, value, }; } //# sourceMappingURL=linter.js.map