diff options
Diffstat (limited to 'node_modules/istanbul-lib-instrument/dist')
4 files changed, 874 insertions, 0 deletions
diff --git a/node_modules/istanbul-lib-instrument/dist/index.js b/node_modules/istanbul-lib-instrument/dist/index.js new file mode 100644 index 000000000..8cf21074c --- /dev/null +++ b/node_modules/istanbul-lib-instrument/dist/index.js @@ -0,0 +1,29 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { +  value: true +}); +exports.programVisitor = exports.createInstrumenter = undefined; + +var _instrumenter = require('./instrumenter'); + +var _instrumenter2 = _interopRequireDefault(_instrumenter); + +var _visitor = require('./visitor'); + +var _visitor2 = _interopRequireDefault(_visitor); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * createInstrumenter creates a new instrumenter with the + * supplied options. + * @param {Object} opts - instrumenter options. See the documentation + * for the Instrumenter class. + */ +function createInstrumenter(opts) { +  return new _instrumenter2.default(opts); +} + +exports.createInstrumenter = createInstrumenter; +exports.programVisitor = _visitor2.default;
\ No newline at end of file diff --git a/node_modules/istanbul-lib-instrument/dist/instrumenter.js b/node_modules/istanbul-lib-instrument/dist/instrumenter.js new file mode 100644 index 000000000..f4c14d950 --- /dev/null +++ b/node_modules/istanbul-lib-instrument/dist/instrumenter.js @@ -0,0 +1,199 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { +    value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /* +                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      Copyright 2012-2015, Yahoo Inc. +                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. +                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */ + + +var _babylon = require('babylon'); + +var babylon = _interopRequireWildcard(_babylon); + +var _babelTypes = require('babel-types'); + +var t = _interopRequireWildcard(_babelTypes); + +var _babelTraverse = require('babel-traverse'); + +var _babelTraverse2 = _interopRequireDefault(_babelTraverse); + +var _babelGenerator = require('babel-generator'); + +var _babelGenerator2 = _interopRequireDefault(_babelGenerator); + +var _visitor = require('./visitor'); + +var _visitor2 = _interopRequireDefault(_visitor); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function defaultOpts() { +    return { +        coverageVariable: "__coverage__", +        preserveComments: false, +        compact: true, +        esModules: false, +        autoWrap: false, +        produceSourceMap: false, +        sourceMapUrlCallback: null, +        debug: false +    }; +} +/** + * Instrumenter is the public API for the instrument library. + * It is typically used for ES5 code. For ES6 code that you + * are already running under `babel` use the coverage plugin + * instead. + * @param {Object} opts optional. + * @param {string} [opts.coverageVariable=__coverage__] name of global coverage variable. + * @param {boolean} [opts.preserveComments=false] preserve comments in output + * @param {boolean} [opts.compact=true] generate compact code. + * @param {boolean} [opts.esModules=false] set to true to instrument ES6 modules. + * @param {boolean} [opts.autoWrap=false] set to true to allow `return` statements outside of functions. + * @param {boolean} [opts.produceSourceMap=false] set to true to produce a source map for the instrumented code. + * @param {Function} [opts.sourceMapUrlCallback=null] a callback function that is called when a source map URL + *     is found in the original code. This function is called with the source file name and the source map URL. + * @param {boolean} [opts.debug=false] - turn debugging on + */ + +var Instrumenter = function () { +    function Instrumenter() { +        var opts = arguments.length <= 0 || arguments[0] === undefined ? defaultOpts() : arguments[0]; + +        _classCallCheck(this, Instrumenter); + +        this.opts = this.normalizeOpts(opts); +        this.fileCoverage = null; +        this.sourceMap = null; +    } +    /** +     * normalize options passed in and assign defaults. +     * @param opts +     * @private +     */ + + +    _createClass(Instrumenter, [{ +        key: 'normalizeOpts', +        value: function normalizeOpts(opts) { +            var normalize = function normalize(name, defaultValue) { +                if (!opts.hasOwnProperty(name)) { +                    opts[name] = defaultValue; +                } +            }; +            var defOpts = defaultOpts(); +            Object.keys(defOpts).forEach(function (k) { +                normalize(k, defOpts[k]); +            }); +            return opts; +        } +        /** +         * instrument the supplied code and track coverage against the supplied +         * filename. It throws if invalid code is passed to it. ES5 and ES6 syntax +         * is supported. To instrument ES6 modules, make sure that you set the +         * `esModules` property to `true` when creating the instrumenter. +         * +         * @param {string} code - the code to instrument +         * @param {string} filename - the filename against which to track coverage. +         * @returns {string} the instrumented code. +         */ + +    }, { +        key: 'instrumentSync', +        value: function instrumentSync(code, filename) { +            if (typeof code !== 'string') { +                throw new Error('Code must be a string'); +            } +            filename = filename || String(new Date().getTime()) + '.js'; +            var opts = this.opts; +            var ast = babylon.parse(code, { +                allowReturnOutsideFunction: opts.autoWrap, +                sourceType: opts.esModules ? "module" : "script" +            }); +            var ee = (0, _visitor2.default)(t, filename, { +                coverageVariable: opts.coverageVariable +            }); +            var output = {}; +            var visitor = { +                Program: { +                    enter: ee.enter, +                    exit: function exit(path) { +                        output = ee.exit(path); +                    } +                } +            }; +            (0, _babelTraverse2.default)(ast, visitor); + +            var generateOptions = { +                compact: opts.compact, +                sourceMaps: opts.produceSourceMap, +                sourceFileName: filename +            }; +            var codeMap = (0, _babelGenerator2.default)(ast, generateOptions, code); +            this.fileCoverage = output.fileCoverage; +            this.sourceMap = codeMap.map; +            var cb = this.opts.sourceMapUrlCallback; +            if (cb && output.sourceMappingURL) { +                cb(filename, output.sourceMappingURL); +            } +            return codeMap.code; +        } +        /** +         * callback-style instrument method that calls back with an error +         * as opposed to throwing one. Note that in the current implementation, +         * the callback will be called in the same process tick and is not asynchronous. +         * +         * @param {string} code - the code to instrument +         * @param {string} filename - the filename against which to track coverage. +         * @param {Function} callback - the callback +         */ + +    }, { +        key: 'instrument', +        value: function instrument(code, filename, callback) { +            if (!callback && typeof filename === 'function') { +                callback = filename; +                filename = null; +            } +            try { +                var out = this.instrumentSync(code, filename); +                callback(null, out); +            } catch (ex) { +                callback(ex); +            } +        } +        /** +         * returns the file coverage object for the last file instrumented. +         * @returns {Object} the file coverage object. +         */ + +    }, { +        key: 'lastFileCoverage', +        value: function lastFileCoverage() { +            return this.fileCoverage; +        } +        /** +         * returns the source map produced for the last file instrumented. +         * @returns {null|Object} the source map object. +         */ + +    }, { +        key: 'lastSourceMap', +        value: function lastSourceMap() { +            return this.sourceMap; +        } +    }]); + +    return Instrumenter; +}(); + +exports.default = Instrumenter;
\ No newline at end of file diff --git a/node_modules/istanbul-lib-instrument/dist/source-coverage.js b/node_modules/istanbul-lib-instrument/dist/source-coverage.js new file mode 100644 index 000000000..eac98f551 --- /dev/null +++ b/node_modules/istanbul-lib-instrument/dist/source-coverage.js @@ -0,0 +1,127 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { +    value: true +}); +exports.SourceCoverage = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _istanbulLibCoverage = require('istanbul-lib-coverage'); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function cloneLocation(loc) { +    return { +        start: { +            line: loc && loc.start.line, +            column: loc && loc.start.column +        }, +        end: { +            line: loc && loc.end.line, +            column: loc && loc.end.column +        } +    }; +} +/** + * SourceCoverage provides mutation methods to manipulate the structure of + * a file coverage object. Used by the instrumenter to create a full coverage + * object for a file incrementally. + * + * @private + * @param pathOrObj {String|Object} - see the argument for {@link FileCoverage} + * @extends FileCoverage + * @constructor + */ + +var SourceCoverage = function (_classes$FileCoverage) { +    _inherits(SourceCoverage, _classes$FileCoverage); + +    function SourceCoverage(pathOrObj) { +        _classCallCheck(this, SourceCoverage); + +        var _this = _possibleConstructorReturn(this, (SourceCoverage.__proto__ || Object.getPrototypeOf(SourceCoverage)).call(this, pathOrObj)); + +        _this.meta = { +            last: { +                s: 0, +                f: 0, +                b: 0 +            } +        }; +        return _this; +    } + +    _createClass(SourceCoverage, [{ +        key: 'newStatement', +        value: function newStatement(loc) { +            var s = this.meta.last.s; +            this.data.statementMap[s] = cloneLocation(loc); +            this.data.s[s] = 0; +            this.meta.last.s += 1; +            return s; +        } +    }, { +        key: 'newFunction', +        value: function newFunction(name, decl, loc) { +            var f = this.meta.last.f; +            name = name || '(anonymous_' + f + ')'; +            this.data.fnMap[f] = { +                name: name, +                decl: cloneLocation(decl), +                loc: cloneLocation(loc) +            }; +            this.data.f[f] = 0; +            this.meta.last.f += 1; +            return f; +        } +    }, { +        key: 'newBranch', +        value: function newBranch(type, loc) { +            var b = this.meta.last.b; +            this.data.b[b] = []; +            this.data.branchMap[b] = { +                loc: cloneLocation(loc), +                type: type, +                locations: [] +            }; +            this.meta.last.b += 1; +            return b; +        } +    }, { +        key: 'addBranchPath', +        value: function addBranchPath(name, location) { +            var bMeta = this.data.branchMap[name], +                counts = this.data.b[name]; + +            /* istanbul ignore if: paranoid check */ +            if (!bMeta) { +                throw new Error("Invalid branch " + name); +            } +            bMeta.locations.push(cloneLocation(location)); +            counts.push(0); +            return counts.length - 1; +        } +    }, { +        key: 'freeze', +        value: function freeze() { +            // prune empty branches +            var map = this.data.branchMap, +                branches = this.data.b; +            Object.keys(map).forEach(function (b) { +                if (map[b].locations.length === 0) { +                    delete map[b]; +                    delete branches[b]; +                } +            }); +        } +    }]); + +    return SourceCoverage; +}(_istanbulLibCoverage.classes.FileCoverage); + +exports.SourceCoverage = SourceCoverage;
\ No newline at end of file diff --git a/node_modules/istanbul-lib-instrument/dist/visitor.js b/node_modules/istanbul-lib-instrument/dist/visitor.js new file mode 100644 index 000000000..c1308b24c --- /dev/null +++ b/node_modules/istanbul-lib-instrument/dist/visitor.js @@ -0,0 +1,519 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { +    value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _sourceCoverage = require('./source-coverage'); + +var _crypto = require('crypto'); + +var _babelTemplate = require('babel-template'); + +var _babelTemplate2 = _interopRequireDefault(_babelTemplate); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// function to use for creating hashes +var SHA = 'sha1'; +// istanbul ignore comment pattern +var COMMENT_RE = /^\s*istanbul\s+ignore\s+(if|else|next)(?=\W|$)/; +// source map URL pattern +var SOURCE_MAP_RE = /[#@]\s*sourceMappingURL=(.*)\s*$/m; + +// generate a variable name from hashing the supplied file path +function genVar(filename) { +    var hash = (0, _crypto.createHash)(SHA); +    hash.update(filename); +    return 'cov_' + parseInt(hash.digest('hex').substr(0, 12), 16).toString(36); +} + +// VisitState holds the state of the visitor, provides helper functions +// and is the `this` for the individual coverage visitors. + +var VisitState = function () { +    function VisitState(types, sourceFilePath) { +        _classCallCheck(this, VisitState); + +        this.varName = genVar(sourceFilePath); +        this.attrs = {}; +        this.nextIgnore = null; +        this.cov = new _sourceCoverage.SourceCoverage(sourceFilePath); +        this.types = types; +        this.sourceMappingURL = null; +    } + +    // should we ignore the node? Yes, if specifically ignoring +    // or if the node is generated. + + +    _createClass(VisitState, [{ +        key: 'shouldIgnore', +        value: function shouldIgnore(path) { +            return this.nextIgnore || !path.node.loc; +        } + +        // extract the ignore comment hint (next|if|else) or null + +    }, { +        key: 'hintFor', +        value: function hintFor(node) { +            var hint = null; +            if (node.leadingComments) { +                node.leadingComments.forEach(function (c) { +                    var v = (c.value || /* istanbul ignore next: paranoid check */"").trim(); +                    var groups = v.match(COMMENT_RE); +                    if (groups) { +                        hint = groups[1]; +                    } +                }); +            } +            return hint; +        } + +        // extract a source map URL from comments and keep track of it + +    }, { +        key: 'maybeAssignSourceMapURL', +        value: function maybeAssignSourceMapURL(node) { +            var that = this; +            var extractURL = function extractURL(comments) { +                if (!comments) { +                    return; +                } +                comments.forEach(function (c) { +                    var v = (c.value || /* istanbul ignore next: paranoid check */"").trim(); +                    var groups = v.match(SOURCE_MAP_RE); +                    if (groups) { +                        that.sourceMappingURL = groups[1]; +                    } +                }); +            }; +            extractURL(node.leadingComments); +            extractURL(node.trailingComments); +        } + +        // all the generic stuff that needs to be done on enter for every node + +    }, { +        key: 'onEnter', +        value: function onEnter(path) { +            var n = path.node; + +            this.maybeAssignSourceMapURL(n); + +            // if already ignoring, nothing more to do +            if (this.nextIgnore !== null) { +                return; +            } +            // check hint to see if ignore should be turned on +            var hint = this.hintFor(n); +            if (hint === 'next') { +                this.nextIgnore = n; +                return; +            } +            // else check custom node attribute set by a prior visitor +            if (this.getAttr(path.node, 'skip-all') !== null) { +                this.nextIgnore = n; +            } +        } + +        // all the generic stuff on exit of a node, +        // including reseting ignores and custom node attrs + +    }, { +        key: 'onExit', +        value: function onExit(path) { +            // restore ignore status, if needed +            if (path.node === this.nextIgnore) { +                this.nextIgnore = null; +            } +            // nuke all attributes for the node +            delete path.node.__cov__; +        } + +        // set a node attribute for the supplied node + +    }, { +        key: 'setAttr', +        value: function setAttr(node, name, value) { +            node.__cov__ = node.__cov__ || {}; +            node.__cov__[name] = value; +        } + +        // retrieve a node attribute for the supplied node or null + +    }, { +        key: 'getAttr', +        value: function getAttr(node, name) { +            var c = node.__cov__; +            if (!c) { +                return null; +            } +            return c[name]; +        } + +        // + +    }, { +        key: 'increase', +        value: function increase(type, id, index) { +            var T = this.types; +            var wrap = index !== null +            // If `index` present, turn `x` into `x[index]`. +            ? function (x) { +                return T.memberExpression(x, T.numericLiteral(index), true); +            } : function (x) { +                return x; +            }; +            return T.unaryExpression('++', wrap(T.memberExpression(T.memberExpression(T.identifier(this.varName), T.identifier(type)), T.numericLiteral(id), true))); +        } +    }, { +        key: 'insertCounter', +        value: function insertCounter(path, increment) { +            var T = this.types; +            if (path.isBlockStatement()) { +                path.node.body.unshift(T.expressionStatement(increment)); +            } else if (path.isStatement()) { +                path.insertBefore(T.expressionStatement(increment)); +            } else /* istanbul ignore else: not expected */if (path.isExpression()) { +                    path.replaceWith(T.sequenceExpression([increment, path.node])); +                } else { +                    console.error('Unable to insert counter for node type:', path.node.type); +                } +        } +    }, { +        key: 'insertStatementCounter', +        value: function insertStatementCounter(path) { +            /* istanbul ignore if: paranoid check */ +            if (!(path.node && path.node.loc)) { +                return; +            } +            var index = this.cov.newStatement(path.node.loc); +            var increment = this.increase('s', index, null); +            this.insertCounter(path, increment); +        } +    }, { +        key: 'insertFunctionCounter', +        value: function insertFunctionCounter(path) { +            var T = this.types; +            /* istanbul ignore if: paranoid check */ +            if (!(path.node && path.node.loc)) { +                return; +            } +            var n = path.node; +            var dloc = null; +            // get location for declaration +            switch (n.type) { +                case "FunctionDeclaration": +                    /* istanbul ignore else: paranoid check */ +                    if (n.id) { +                        dloc = n.id.loc; +                    } +                    break; +                case "FunctionExpression": +                    if (n.id) { +                        dloc = n.id.loc; +                    } +                    break; +            } +            if (!dloc) { +                dloc = { +                    start: n.loc.start, +                    end: { line: n.loc.start.line, column: n.loc.start.column + 1 } +                }; +            } +            var name = path.node.id ? path.node.id.name : path.node.name; +            var index = this.cov.newFunction(name, dloc, path.node.body.loc); +            var increment = this.increase('f', index, null); +            var body = path.get('body'); +            /* istanbul ignore else: not expected */ +            if (body.isBlockStatement()) { +                body.node.body.unshift(T.expressionStatement(increment)); +            } else { +                console.error('Unable to process function body node type:', path.node.type); +            } +        } +    }, { +        key: 'getBranchIncrement', +        value: function getBranchIncrement(branchName, loc) { +            var index = this.cov.addBranchPath(branchName, loc); +            return this.increase('b', branchName, index); +        } +    }, { +        key: 'insertBranchCounter', +        value: function insertBranchCounter(path, branchName, loc) { +            var increment = this.getBranchIncrement(branchName, loc || path.node.loc); +            this.insertCounter(path, increment); +        } +    }, { +        key: 'findLeaves', +        value: function findLeaves(node, accumulator, parent, property) { +            if (!node) { +                return; +            } +            if (node.type === "LogicalExpression") { +                var hint = this.hintFor(node); +                if (hint !== 'next') { +                    this.findLeaves(node.left, accumulator, node, 'left'); +                    this.findLeaves(node.right, accumulator, node, 'right'); +                } +            } else { +                accumulator.push({ +                    node: node, +                    parent: parent, +                    property: property +                }); +            } +        } +    }]); + +    return VisitState; +}(); + +// generic function that takes a set of visitor methods and +// returns a visitor object with `enter` and `exit` properties, +// such that: +// +// * standard entry processing is done +// * the supplied visitors are called only when ignore is not in effect +//   This relieves them from worrying about ignore states and generated nodes. +// * standard exit processing is done +// + + +function entries() { +    var enter = Array.prototype.slice.call(arguments); +    // the enter function +    var wrappedEntry = function wrappedEntry(path, node) { +        this.onEnter(path); +        if (this.shouldIgnore(path)) { +            return; +        } +        var that = this; +        enter.forEach(function (e) { +            e.call(that, path, node); +        }); +    }; +    var exit = function exit(path, node) { +        this.onExit(path, node); +    }; +    return { +        enter: wrappedEntry, +        exit: exit +    }; +} + +function coverStatement(path) { +    this.insertStatementCounter(path); +} + +/* istanbul ignore next: no node.js support */ +function coverAssignmentPattern(path) { +    var n = path.node; +    var b = this.cov.newBranch('default-arg', n.loc); +    this.insertBranchCounter(path.get('right'), b); +} + +function coverFunction(path) { +    this.insertFunctionCounter(path); +} + +function coverVariableDeclarator(path) { +    this.insertStatementCounter(path.get('init')); +} + +function skipInit(path) { +    if (path.node.init) { +        this.setAttr(path.node.init, 'skip-all', true); +    } +} + +function makeBlock(path) { +    var T = this.types; +    if (!path.node) { +        path.replaceWith(T.blockStatement([])); +    } +    if (!path.isBlockStatement()) { +        path.replaceWith(T.blockStatement([path.node])); +        path.node.loc = path.node.body[0].loc; +    } +} + +function blockProp(prop) { +    return function (path) { +        makeBlock.call(this, path.get(prop)); +    }; +} + +function convertArrowExpression(path) { +    var n = path.node; +    var T = this.types; +    if (n.expression) { +        var bloc = n.body.loc; +        n.expression = false; +        n.body = T.blockStatement([T.returnStatement(n.body)]); +        // restore body location +        n.body.loc = bloc; +        // set up the location for the return statement so it gets +        // instrumented +        n.body.body[0].loc = bloc; +    } +} + +function coverIfBranches(path) { +    var n = path.node, +        hint = this.hintFor(n), +        ignoreIf = hint === 'if', +        ignoreElse = hint === 'else', +        branch = this.cov.newBranch('if', n.loc); + +    if (ignoreIf) { +        this.setAttr(n.consequent, 'skip-all', true); +    } else { +        this.insertBranchCounter(path.get('consequent'), branch, n.loc); +    } +    if (ignoreElse) { +        this.setAttr(n.alternate, 'skip-all', true); +    } else { +        this.insertBranchCounter(path.get('alternate'), branch, n.loc); +    } +} + +function createSwitchBranch(path) { +    var b = this.cov.newBranch('switch', path.node.loc); +    this.setAttr(path.node, 'branchName', b); +} + +function coverSwitchCase(path) { +    var T = this.types; +    var b = this.getAttr(path.parentPath.node, 'branchName'); +    /* istanbul ignore if: paranoid check */ +    if (b === null) { +        throw new Error('Unable to get switch branch name'); +    } +    var increment = this.getBranchIncrement(b, path.node.loc); +    path.node.consequent.unshift(T.expressionStatement(increment)); +} + +function coverTernary(path) { +    var n = path.node, +        branch = this.cov.newBranch('cond-expr', path.node.loc), +        cHint = this.hintFor(n.consequent), +        aHint = this.hintFor(n.alternate); + +    if (cHint !== 'next') { +        this.insertBranchCounter(path.get('consequent'), branch); +    } +    if (aHint !== 'next') { +        this.insertBranchCounter(path.get('alternate'), branch); +    } +} + +function coverLogicalExpression(path) { +    var T = this.types; +    if (path.parentPath.node.type === "LogicalExpression") { +        return; // already processed +    } +    var leaves = []; +    this.findLeaves(path.node, leaves); +    var b = this.cov.newBranch("binary-expr", path.node.loc); +    for (var i = 0; i < leaves.length; i += 1) { +        var leaf = leaves[i]; +        var hint = this.hintFor(leaf.node); +        if (hint === 'next') { +            continue; +        } +        var increment = this.getBranchIncrement(b, leaf.node.loc); +        if (!increment) { +            continue; +        } +        leaf.parent[leaf.property] = T.sequenceExpression([increment, leaf.node]); +    } +} + +var codeVisitor = { +    ArrowFunctionExpression: entries(convertArrowExpression, coverFunction), +    AssignmentPattern: entries(coverAssignmentPattern), +    BlockStatement: entries(), // ignore processing only +    ClassMethod: entries(coverFunction), +    ExpressionStatement: entries(coverStatement), +    BreakStatement: entries(coverStatement), +    ContinueStatement: entries(coverStatement), +    DebuggerStatement: entries(coverStatement), +    ReturnStatement: entries(coverStatement), +    ThrowStatement: entries(coverStatement), +    TryStatement: entries(coverStatement), +    VariableDeclaration: entries(), // ignore processing only +    VariableDeclarator: entries(coverVariableDeclarator), +    IfStatement: entries(blockProp('consequent'), blockProp('alternate'), coverStatement, coverIfBranches), +    ForStatement: entries(blockProp('body'), skipInit, coverStatement), +    ForInStatement: entries(blockProp('body'), skipInit, coverStatement), +    ForOfStatement: entries(blockProp('body'), skipInit, coverStatement), +    WhileStatement: entries(blockProp('body'), coverStatement), +    DoWhileStatement: entries(blockProp('body'), coverStatement), +    SwitchStatement: entries(createSwitchBranch, coverStatement), +    SwitchCase: entries(coverSwitchCase), +    WithStatement: entries(blockProp('body'), coverStatement), +    FunctionDeclaration: entries(coverFunction), +    FunctionExpression: entries(coverFunction), +    LabeledStatement: entries(coverStatement), +    ConditionalExpression: entries(coverTernary), +    LogicalExpression: entries(coverLogicalExpression) +}; +// the template to insert at the top of the program. +var coverageTemplate = (0, _babelTemplate2.default)('\n    var COVERAGE_VAR = (function () {\n        var path = PATH,\n            hash = HASH,\n            global = (new Function(\'return this\'))(),\n            gcv = GLOBAL_COVERAGE_VAR,\n            coverageData = INITIAL,\n            coverage = global[gcv] || (global[gcv] = {});\n        if (coverage[path] && coverage[path].hash === hash) {\n            return coverage[path];\n        }\n        coverageData.hash = hash;\n        return coverage[path] = coverageData;\n    })();\n'); +/** + * programVisitor is a `babel` adaptor for instrumentation. + * It returns an object with two methods `enter` and `exit`. + * These should be assigned to or called from `Program` entry and exit functions + * in a babel visitor. + * These functions do not make assumptions about the state set by Babel and thus + * can be used in a context other than a Babel plugin. + * + * The exit function returns an object that currently has the following keys: + * + * `fileCoverage` - the file coverage object created for the source file. + * `sourceMappingURL` - any source mapping URL found when processing the file. + * + * @param {Object} types - an instance of babel-types + * @param {string} sourceFilePath - the path to source file + * @param {Object} opts - additional options + * @param {string} [opts.coverageVariable=__coverage__] the global coverage variable name. + */ +function programVisitor(types) { +    var sourceFilePath = arguments.length <= 1 || arguments[1] === undefined ? 'unknown.js' : arguments[1]; +    var opts = arguments.length <= 2 || arguments[2] === undefined ? { coverageVariable: '__coverage__' } : arguments[2]; + +    var T = types; +    var visitState = new VisitState(types, sourceFilePath); +    return { +        enter: function enter(path) { +            path.traverse(codeVisitor, visitState); +        }, +        exit: function exit(path) { +            visitState.cov.freeze(); +            var coverageData = visitState.cov.toJSON(); +            var hash = (0, _crypto.createHash)(SHA).update(JSON.stringify(coverageData)).digest('hex'); +            var coverageNode = T.valueToNode(coverageData); +            var cv = coverageTemplate({ +                GLOBAL_COVERAGE_VAR: T.stringLiteral(opts.coverageVariable), +                COVERAGE_VAR: T.identifier(visitState.varName), +                PATH: T.stringLiteral(sourceFilePath), +                INITIAL: coverageNode, +                HASH: T.stringLiteral(hash) +            }); +            path.node.body.unshift(cv); +            return { +                fileCoverage: coverageData, +                sourceMappingURL: visitState.sourceMappingURL +            }; +        } +    }; +} + +exports.default = programVisitor;
\ No newline at end of file  | 
