UNPKG

gherkin-lint-ts

Version:

Gherkin features linter written in Typescript

135 lines 6.05 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.run = exports.availableConfigs = exports.name = void 0; const gherkinUtils = __importStar(require("./utils/gherkin")); const chalk_1 = __importDefault(require("chalk")); exports.name = "no-restricted-patterns"; exports.availableConfigs = { "Global": [], "Scenario": [], "ScenarioOutline": [], "Background": [], "Feature": [], }; function run(feature, unused, configuration) { var _a; if (!feature) { return []; } let errors = []; const restrictedPatterns = getRestrictedPatterns(configuration); const language = feature.language || "en"; // Check the feature itself checkNameAndDescription(feature, restrictedPatterns, language, errors); // Check the feature children (_a = feature.children) === null || _a === void 0 ? void 0 : _a.forEach(child => { var _a; if (child.rule) { (_a = child.rule.children) === null || _a === void 0 ? void 0 : _a.forEach(childRule => { checkNode(childRule, restrictedPatterns, language, errors); }); } else { checkNode(child, restrictedPatterns, language, errors); } }); return errors; } exports.run = run; function checkNode(child, restrictedPatterns, language, errors) { var _a; const node = child.background || child.scenario; if (node) { checkNameAndDescription(node, restrictedPatterns, language, errors); // And all the steps of each child (_a = node.steps) === null || _a === void 0 ? void 0 : _a.forEach(step => { checkStepNode(step, node, restrictedPatterns, language, errors); }); } } function getRestrictedPatterns(configuration) { // Patterns applied to everything; feature, scenarios, etc. let globalPatterns = (configuration.Global || []).map(pattern => new RegExp(pattern, "i")); let restrictedPatterns = {}; Object.keys(exports.availableConfigs).forEach(key => { const resolvedKey = key.toLowerCase().replace(/ /g, ""); const resolvedConfig = (configuration[key] || []); restrictedPatterns[resolvedKey] = resolvedConfig.map(pattern => new RegExp(pattern, "i")); restrictedPatterns[resolvedKey] = restrictedPatterns[resolvedKey].concat(globalPatterns); }); return restrictedPatterns; } function getRestrictedPatternsForNode(node, restrictedPatterns, language) { let key = gherkinUtils.getLanguageInsensitiveKeyword(node, language).toLowerCase(); return restrictedPatterns[key]; } function checkNameAndDescription(node, restrictedPatterns, language, errors) { getRestrictedPatternsForNode(node, restrictedPatterns, language) .forEach(pattern => { check(node, "name", pattern, language, errors); check(node, "description", pattern, language, errors); }); } function checkStepNode(node, parentNode, restrictedPatterns, language, errors) { // Use the node keyword of the parent to determine which rule configuration to use getRestrictedPatternsForNode(parentNode, restrictedPatterns, language) .forEach(pattern => { check(node, "text", pattern, language, errors); }); } function check(node, property, pattern, language, errors) { if (!node[property]) { return; } let strings = [node[property]]; const type = gherkinUtils.getNodeType(node, language); if (property === "description") { // Descriptions can be multiline, in which case the description will contain escaped // newline characters "\n". If a multiline description matches one of the restricted patterns // when the error message gets printed in the console, it will break the message into multiple lines. // So let's split the description on newline chars and test each line separately. // To make sure we don't accidentally pick up a doubly escaped new line "\\n" which would appear // if a user wrote the string "\n" in a description, let's replace all escaped new lines // with a sentinel, split lines and then restore the doubly escaped new line const escapedNewLineSentinel = "<!gherkin-lint new line sentinel!>"; const escapedNewLine = "\\n"; strings = node[property] .replace(escapedNewLine, escapedNewLineSentinel) .split("\n") .map(string => string.replace(escapedNewLineSentinel, escapedNewLine)); } strings.forEach(item => { // We use trim() on the examined string because names and descriptions can contain // white space before and after, unlike steps if (item.trim().match(pattern)) { errors.push({ message: `${type} ${property}: "${chalk_1.default.cyan(item.trim())}" matches restricted pattern "${chalk_1.default.yellow(pattern)}"`, rule: exports.name, line: node.location.line, }); } }); } //# sourceMappingURL=no-restricted-patterns.js.map