UNPKG

tslint-no-unused-expression-chai

Version:

Custom tslint no-unused-expression rule supports chai's expect assertion

146 lines 6.79 kB
"use strict"; var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; }; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); } return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var Lint = require("tslint"); var tsutils = require("tsutils"); var noUnusedExpressionRule_1 = require("tslint/lib/rules/noUnusedExpressionRule"); var OPTION_SHOULD = 'should'; // START copied from noUnusedExpression.ts var ALLOW_FAST_NULL_CHECKS = 'allow-fast-null-checks'; var ALLOW_NEW = 'allow-new'; var ALLOW_TAGGED_TEMPLATE = 'allow-tagged-template'; var TSLINT_META = { optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\nThe following arguments may be optionally provided:\n\n* `", "` allows to use logical operators to perform fast null checks\n and perform method or function calls for side effects (e.g. `e && e.preventDefault()`).\n* `", "` allows 'new' expressions for side effects (e.g. `new ModifyGlobalState();`.\n* `", "` allows tagged templates for side effects\n (e.g. `this.add\\`foo\\`;`).\n* `", "` supports chai assertions using `should` in addition to `expect`;`.\n"], ["\nThe following arguments may be optionally provided:\n\n* \\`", "\\` allows to use logical operators to perform fast null checks\n and perform method or function calls for side effects (e.g. \\`e && e.preventDefault()\\`).\n* \\`", "\\` allows 'new' expressions for side effects (e.g. \\`new ModifyGlobalState();\\`.\n* \\`", "\\` allows tagged templates for side effects\n (e.g. \\`this.add\\\\\\`foo\\\\\\`;\\`).\n* \\`", "\\` supports chai assertions using \\`should\\` in addition to \\`expect\\`;\\`.\n"])), ALLOW_FAST_NULL_CHECKS, ALLOW_NEW, ALLOW_TAGGED_TEMPLATE, OPTION_SHOULD), options: { type: 'array', items: { type: 'string', enum: [ALLOW_FAST_NULL_CHECKS, ALLOW_NEW, ALLOW_TAGGED_TEMPLATE, OPTION_SHOULD] }, minLength: 0, maxLength: 4 }, optionExamples: [ true, [true, ALLOW_FAST_NULL_CHECKS], [true, OPTION_SHOULD], [true, ALLOW_FAST_NULL_CHECKS, OPTION_SHOULD] ] }; // END copied from noUnusedExpression.ts /** * Predicate to determine given failure is chai's `expect` assertion. * It relies on naive assumptions based on chai assertion syntax. */ var chaiAssertionPredicate = function (failure, source) { var failurePosition = failure.getStartPosition(); var token = tsutils.getTokenAtPosition(source, failurePosition.getPosition()); //for any reason locating token is not available, falls back to default rule if (!token) { return true; } //check very exact token is identifier, `expect` var isTokenIdentifier = tsutils.isIdentifier(token); if (!isTokenIdentifier) { return true; } var parentToken = token.parent; //same as token. located chai assertion should have parent token if (!parentToken) { return true; } //traverse up one parent, check it's call expression var isParentTokenCallExpression = tsutils.isCallExpression(parentToken); if (!isParentTokenCallExpression) { return true; } //finally compare actual token text to chai assertion, return false if given token is `expect` return token.getText() !== 'expect'; }; /** * Predicate to determine given failure is chai's `should` assertion. * It relies on naive assumptions based on chai assertion syntax. */ var withoutShouldAssertions = function (failure, source) { var failurePosition = failure.getStartPosition(); var token = tsutils.getTokenAtPosition(source, failurePosition.getPosition()); // for any reason locating token is not available, falls back to default rule if (!token) { return true; } var current = token; // scan through parents for a property access expression // stop when hitting expression statement while (current && !tsutils.isExpressionStatement(current)) { if (tsutils.isPropertyAccessExpression(current)) { if (current.name.text === 'should') { // make sure there is at least one more property access after should return current.parent && !tsutils.isPropertyAccessExpression(current.parent); } } current = current.parent; } return true; }; /** * Implements no-unused-expression-chai rules * To honor base rule's behavior, it inherits from default no-unused-expression rule * and override specific failure only * */ var Rule = /** @class */ (function (_super) { __extends(Rule, _super); function Rule() { return _super !== null && _super.apply(this, arguments) || this; } /** * Apply rules. Simply walk source by default rule first, and filter out chai expression * */ Rule.prototype.apply = function (sourceFile) { var failures = _super.prototype.apply.call(this, sourceFile); if (failures && failures.length > 0) { var filterShould_1 = this.ruleArguments.indexOf(OPTION_SHOULD) > -1; return failures.filter(function (x) { var expectResult = chaiAssertionPredicate(x, sourceFile); if (expectResult && filterShould_1) { return withoutShouldAssertions(x, sourceFile); } return expectResult; }); } return failures; }; Rule.metadata = __assign({}, noUnusedExpressionRule_1.Rule.metadata, TSLINT_META, { ruleName: 'no-unused-expression-chai' }); return Rule; }(noUnusedExpressionRule_1.Rule)); exports.Rule = Rule; var templateObject_1; //# sourceMappingURL=noUnusedExpressionChaiRule.js.map