UNPKG

gplint

Version:

A Gherkin linter/validator written in Javascript.

96 lines 3.63 kB
import _ from 'lodash'; import { featureSpread } from './utils/gherkin.js'; export const name = 'related-tags'; export const availableConfigs = { tags: {} }; const REGEXP_EXPRESSION = /^\/(?<pattern>.+)\/(?<flags>.*)/; export function run({ feature }, configuration) { if (!feature) { return []; } const errors = []; const tags = parseTags(configuration.tags); checkTags(feature, tags, errors); const { children, rules } = featureSpread(feature); rules.forEach(rule => { checkTags(rule, tags, errors); }); for (const child of children) { if (child.scenario) { checkTags(child.scenario, tags, errors); for (const example of child.scenario.examples) { checkTags(example, tags, errors); } } } return errors; } function parseTags(tags = {}) { const parsedTags = {}; for (const [tag, relatedTags] of Object.entries(tags)) { parsedTags[tag] = relatedTags.map(rt => { const match = REGEXP_EXPRESSION.exec(rt); return match == null ? rt : new RegExp(match.groups.pattern, match.groups.flags); }); } return parsedTags; } function checkTags(node, tags, errors) { const plainNodeTags = node.tags.map(t => t.name); node.tags .filter(tag => Object.prototype.hasOwnProperty.call(tags, tag.name) ? !tags[tag.name].some(relatedTag => checkRelatedTag(relatedTag, plainNodeTags)) : false) .forEach(tag => { errors.push(createError(tag, tags[tag.name])); }); } function checkRelatedTag(relatedTag, nodeTags) { return _.isRegExp(relatedTag) ? nodeTags.some(t => relatedTag.test(t)) : nodeTags.includes(relatedTag); } function createError(tag, relatedTags) { return { message: `Missing related tag. ${tag.name} requires ${relatedTags}`, rule: name, line: tag.location.line, column: tag.location.column, }; } export const documentation = { description: 'Define a list of tags with a list of related tags that should be present too. The related tags can be a string or a regular expression (represented as a string between slashes `/`.', configuration: [{ name: 'tags', type: 'Record<string, (string|RegExp)[]>', description: 'An object with a tag as a key, and an array of string/regular expression as a value.', default: availableConfigs.tags, }], examples: [{ title: 'Define a tag that requires another tag.', description: `When the tag \`@disabled\` is present, is also required to define the tag \`@TICKET.PROJ-\`, followed by a number (This example is useful to keep tracking issues using a ticketing system).`, config: { [name]: ['error', { tags: { '@disabled': ['/^@TICKET\\.PROJ-[0-9]+$/'], } }], } }, { title: 'Define a tag that requires another tag from a list.', description: `When the tag \`@foo\` is present, is also required to define at least one of the following tags: \`@bar\`, \`@baz\` o \`@qux\`. A regular expression is used to define \`@bar\` and \`@baz\`, and a plain text to define \`@qux\`. `, config: { [name]: ['error', { tags: { '@foo': [['/^@ba[rz]$/', '@qux']], } }], } }], }; //# sourceMappingURL=related-tags.js.map