coffee-coverage
Version:
Istanbul and JSCoverage-style instrumentation for CoffeeScript files.
201 lines (185 loc) • 5.96 kB
JavaScript
// Generated by CoffeeScript 2.3.2
(function() {
// Visitor which looks for pragma directives for skipping coverage, and marks coffeescript nodes
// to be skipped.
var NodeWrapper, PRAGMAS, PRAGMA_PREFIX, SkipVisitor, _;
_ = require('lodash');
NodeWrapper = require('./NodeWrapper');
PRAGMA_PREFIX = '!pragma';
PRAGMAS = [
{
// '!pragma coverage-skip-next', 'istanbul ignore next'
// Mark the next node and all descendants as `skip`.
regex: /^!pragma\s+coverage-skip-next$/,
istanbulRegex: /^istanbul\s+ignore\s+next$/,
fn: function(self,
node,
match,
options = {}) {
var origNode;
origNode = node;
if (node.type === "Value") {
if (node.parent.type === "Assign" || node.parent.type === "Switch" || node.parent.type === "Class") {
node = node.parent;
} else {
node = node.parent.parent;
}
} else if (node.type !== "If") {
node = node.parent;
}
if (!node) {
throw new Error(`Pragma '${match[0]}' at ${self._toLocString(origNode)} has no next statement`);
}
return node.markAll('skip',
true);
}
},
{
// '!pragma coverage-skip-block'
regex: /^!pragma\s+coverage-skip-block$/,
fn: function(self,
node,
match,
options = {}) {
var ifBody,
ifNode,
parent;
parent = node.parent.parent.parent;
parent.markAll('skip',
true);
if (parent.parent.type === 'If') {
ifBody = parent;
ifNode = parent.parent;
if (ifBody.childName === 'body') {
return ifNode.mark('skipIf',
true);
} else {
return ifNode.mark('skipElse',
true);
}
}
}
},
{
// '!pragma no-coverage-next'
// Mark the next node and all descendants as `noCoverage`.
regex: /^!pragma\s+no-coverage-next$/,
fn: function(self,
node,
match,
options = {}) {
if (node.type === "Value") {
if (node.parent.type === "Assign" || node.parent.type === "Switch" || node.parent.type === "Class") {
node = node.parent;
} else {
node = node.parent.parent;
}
} else if (node.type !== "If") {
node = node.parent;
}
return node.markAll('noCoverage',
true);
}
},
{
// 'istanbul ignore if'
// Must be before an `If` statement. Mark the `If` as `skipIf`, and mark all children in
// the `body` as `skip`.
istanbulRegex: /^istanbul\s+ignore\s+if$/,
fn: function(self,
node,
match,
options = {}) {
var ifNode,
ref,
ref1;
if (node.type === "IdentifierLiteral") {
return;
}
if (node.type === "Value" && ((ref = node.node.base.constructor) != null ? ref.name : void 0) === "PassthroughLiteral") {
throw new Error(`Pragma '${match[0]}' at ${self._toLocString(node)} has no next statement`);
}
ifNode = self.getIfNode(node,
match);
ifNode.mark('skipIf',
true);
return (ref1 = ifNode.child('body')) != null ? ref1.markAll('skip',
true) : void 0;
}
},
{
// 'istanbul ignore next'
// Must be before an `If` statement. Mark the `If` as `skipElse`, and mark all children in
// the `elseBody` as `skip`.
istanbulRegex: /^istanbul\s+ignore\s+else$/,
fn: function(self,
node,
match,
options = {}) {
var ifNode,
ref,
ref1;
if (node.type === "IdentifierLiteral") {
return;
}
if (node.type === "Value" && ((ref = node.node.base.constructor) != null ? ref.name : void 0) === "PassthroughLiteral") {
throw new Error(`Pragma '${match[0]}' at ${self._toLocString(node)} has no next statement`);
}
ifNode = self.getIfNode(node,
match);
ifNode.mark('skipElse',
true);
return (ref1 = ifNode.child('elseBody')) != null ? ref1.markAll('skip',
true) : void 0;
}
}
];
module.exports = SkipVisitor = class SkipVisitor {
constructor(fileName) {
this.fileName = fileName;
}
visitComment(node) {
var comment, ref;
if (node.node.comments.visited) {
return;
}
comment = (ref = node.node.comments[0].content.trim().toLowerCase()) != null ? ref : '';
if (_.startsWith(comment, PRAGMA_PREFIX)) {
PRAGMAS.filter(function(pragma) {
return pragma.regex != null;
}).forEach((pragma) => {
var match;
if (match = comment.match(pragma.regex)) {
return pragma.fn(this, node, match, this.options);
}
});
} else if (_.startsWith(comment, 'istanbul')) {
PRAGMAS.filter(function(pragma) {
return pragma.istanbulRegex != null;
}).forEach((pragma) => {
var match;
if (match = comment.match(pragma.istanbulRegex)) {
return pragma.fn(this, node, match, this.options);
}
});
}
return node.node.comments.visited = true;
}
_toLocString(node) {
return `${this.fileName} (${node.locationData.first_line + 1}:${node.locationData.first_column + 1})`;
}
getIfNode(node, match) {
var ref, ref1, ref2, ref3, ref4;
if (node.type === "If") {
return node;
}
if (((ref = node.parent) != null ? (ref1 = ref.parent) != null ? ref1.type : void 0 : void 0) === "If") {
return node.parent.parent;
}
if (((ref2 = node.parent) != null ? (ref3 = ref2.parent) != null ? (ref4 = ref3.parent) != null ? ref4.type : void 0 : void 0 : void 0) === "If") {
return node.parent.parent.parent;
}
throw new Error(`Statement after pragma '${match[0]}' at ${this._toLocString(node)} is not of type If`);
}
};
}).call(this);