tslint-microsoft-contrib
Version:
TSLint Rules for Microsoft
113 lines • 4.92 kB
JavaScript
;
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 __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("typescript");
var Lint = require("tslint");
var tsutils = require("tsutils");
var Utils_1 = require("./utils/Utils");
var JsxAttribute_1 = require("./utils/JsxAttribute");
var OPTION_FORCE_REL_REDUNDANCY = 'force-rel-redundancy';
var Rule = (function (_super) {
__extends(Rule, _super);
function Rule() {
return _super !== null && _super.apply(this, arguments) || this;
}
Rule.prototype.apply = function (sourceFile) {
if (sourceFile.languageVariant === ts.LanguageVariant.JSX) {
return this.applyWithFunction(sourceFile, walk, this.parseOptions(this.getOptions()));
}
return [];
};
Rule.prototype.parseOptions = function (options) {
var parsed = {
forceRelRedundancy: false
};
if (options.ruleArguments !== undefined && options.ruleArguments.length > 0) {
parsed.forceRelRedundancy = options.ruleArguments.indexOf(OPTION_FORCE_REL_REDUNDANCY) > -1;
}
return parsed;
};
Rule.metadata = {
ruleName: 'react-anchor-blank-noopener',
type: 'functionality',
description: 'Anchor tags with target="_blank" should also include rel="noreferrer"',
options: {
type: 'array',
items: {
type: 'string',
enum: [OPTION_FORCE_REL_REDUNDANCY]
},
minLength: 0,
maxLength: 1
},
optionsDescription: "One argument may be optionally provided: \n\n' +\n '* `" + OPTION_FORCE_REL_REDUNDANCY + "` ignores the default `rel=\"noreferrer\"`\n behaviour which implies `rel=\"noreferrer noopener\"`. Instead, force redundancy\n for `rel` attribute.",
typescriptOnly: true,
issueClass: 'SDL',
issueType: 'Error',
severity: 'Critical',
level: 'Mandatory',
group: 'Security',
commonWeaknessEnumeration: '242,676'
};
return Rule;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
function walk(ctx) {
var failureString = ctx.options.forceRelRedundancy
? 'Anchor tags with target="_blank" should also include rel="noopener noreferrer"'
: 'Anchor tags with target="_blank" should also include rel="noreferrer"';
function validateOpeningElement(openingElement) {
if (openingElement.tagName.getText() === 'a') {
var allAttributes = JsxAttribute_1.getJsxAttributesFromJsxElement(openingElement);
var target = allAttributes['target'];
var rel = allAttributes['rel'];
if (target !== undefined &&
JsxAttribute_1.getStringLiteral(target) === '_blank' &&
!isRelAttributeValue(rel, ctx.options.forceRelRedundancy)) {
ctx.addFailureAt(openingElement.getStart(), openingElement.getWidth(), failureString);
}
}
}
function cb(node) {
if (tsutils.isJsxElement(node)) {
validateOpeningElement(node.openingElement);
}
else if (tsutils.isJsxSelfClosingElement(node)) {
validateOpeningElement(node);
}
return ts.forEachChild(node, cb);
}
return ts.forEachChild(ctx.sourceFile, cb);
}
function isRelAttributeValue(attribute, forceRedundancy) {
if (JsxAttribute_1.isEmpty(attribute)) {
return false;
}
if (attribute.initializer !== undefined && attribute.initializer.kind === ts.SyntaxKind.JsxExpression) {
var expression = attribute.initializer;
if (expression.expression !== undefined && expression.expression.kind !== ts.SyntaxKind.StringLiteral) {
return true;
}
}
var stringValue = JsxAttribute_1.getStringLiteral(attribute);
if (stringValue === undefined || stringValue.length === 0) {
return false;
}
var relValues = stringValue.split(/\s+/);
return forceRedundancy
? Utils_1.Utils.contains(relValues, 'noreferrer') && Utils_1.Utils.contains(relValues, 'noopener')
: Utils_1.Utils.contains(relValues, 'noreferrer');
}
//# sourceMappingURL=reactAnchorBlankNoopenerRule.js.map