You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					673 lines
				
				20 KiB
			
		
		
			
		
	
	
					673 lines
				
				20 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, "__esModule", {
							 | 
						||
| 
								 | 
							
								  value: true
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								exports.default = void 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _crypto = require("crypto");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _template = _interopRequireDefault(require("@babel/template"));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _sourceCoverage = require("./source-coverage");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _constants = require("./constants");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _instrumenter = require("./instrumenter");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// pattern for istanbul to ignore a section
							 | 
						||
| 
								 | 
							
								const COMMENT_RE = /^\s*istanbul\s+ignore\s+(if|else|next)(?=\W|$)/; // pattern for istanbul to ignore the whole file
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const COMMENT_FILE_RE = /^\s*istanbul\s+ignore\s+(file)(?=\W|$)/; // source map URL pattern
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const SOURCE_MAP_RE = /[#@]\s*sourceMappingURL=(.*)\s*$/m; // generate a variable name from hashing the supplied file path
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function genVar(filename) {
							 | 
						||
| 
								 | 
							
								  const hash = (0, _crypto.createHash)(_constants.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.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class VisitState {
							 | 
						||
| 
								 | 
							
								  constructor(types, sourceFilePath, inputSourceMap, ignoreClassMethods = []) {
							 | 
						||
| 
								 | 
							
								    this.varName = genVar(sourceFilePath);
							 | 
						||
| 
								 | 
							
								    this.attrs = {};
							 | 
						||
| 
								 | 
							
								    this.nextIgnore = null;
							 | 
						||
| 
								 | 
							
								    this.cov = new _sourceCoverage.SourceCoverage(sourceFilePath);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (typeof inputSourceMap !== 'undefined') {
							 | 
						||
| 
								 | 
							
								      this.cov.inputSourceMap(inputSourceMap);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this.ignoreClassMethods = ignoreClassMethods;
							 | 
						||
| 
								 | 
							
								    this.types = types;
							 | 
						||
| 
								 | 
							
								    this.sourceMappingURL = null;
							 | 
						||
| 
								 | 
							
								  } // should we ignore the node? Yes, if specifically ignoring
							 | 
						||
| 
								 | 
							
								  // or if the node is generated.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  shouldIgnore(path) {
							 | 
						||
| 
								 | 
							
								    return this.nextIgnore || !path.node.loc;
							 | 
						||
| 
								 | 
							
								  } // extract the ignore comment hint (next|if|else) or null
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  hintFor(node) {
							 | 
						||
| 
								 | 
							
								    let hint = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (node.leadingComments) {
							 | 
						||
| 
								 | 
							
								      node.leadingComments.forEach(c => {
							 | 
						||
| 
								 | 
							
								        const v = (c.value ||
							 | 
						||
| 
								 | 
							
								        /* istanbul ignore next: paranoid check */
							 | 
						||
| 
								 | 
							
								        '').trim();
							 | 
						||
| 
								 | 
							
								        const groups = v.match(COMMENT_RE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (groups) {
							 | 
						||
| 
								 | 
							
								          hint = groups[1];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return hint;
							 | 
						||
| 
								 | 
							
								  } // extract a source map URL from comments and keep track of it
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  maybeAssignSourceMapURL(node) {
							 | 
						||
| 
								 | 
							
								    const extractURL = comments => {
							 | 
						||
| 
								 | 
							
								      if (!comments) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      comments.forEach(c => {
							 | 
						||
| 
								 | 
							
								        const v = (c.value ||
							 | 
						||
| 
								 | 
							
								        /* istanbul ignore next: paranoid check */
							 | 
						||
| 
								 | 
							
								        '').trim();
							 | 
						||
| 
								 | 
							
								        const groups = v.match(SOURCE_MAP_RE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (groups) {
							 | 
						||
| 
								 | 
							
								          this.sourceMappingURL = groups[1];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    extractURL(node.leadingComments);
							 | 
						||
| 
								 | 
							
								    extractURL(node.trailingComments);
							 | 
						||
| 
								 | 
							
								  } // for these expressions the statement counter needs to be hoisted, so
							 | 
						||
| 
								 | 
							
								  // function name inference can be preserved
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  counterNeedsHoisting(path) {
							 | 
						||
| 
								 | 
							
								    return path.isFunctionExpression() || path.isArrowFunctionExpression() || path.isClassExpression();
							 | 
						||
| 
								 | 
							
								  } // all the generic stuff that needs to be done on enter for every node
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  onEnter(path) {
							 | 
						||
| 
								 | 
							
								    const 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
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const 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;
							 | 
						||
| 
								 | 
							
								    } // else check for ignored class methods
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (path.isFunctionExpression() && this.ignoreClassMethods.some(name => path.node.id && name === path.node.id.name)) {
							 | 
						||
| 
								 | 
							
								      this.nextIgnore = n;
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (path.isClassMethod() && this.ignoreClassMethods.some(name => name === path.node.key.name)) {
							 | 
						||
| 
								 | 
							
								      this.nextIgnore = n;
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } // all the generic stuff on exit of a node,
							 | 
						||
| 
								 | 
							
								  // including reseting ignores and custom node attrs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  setAttr(node, name, value) {
							 | 
						||
| 
								 | 
							
								    node.__cov__ = node.__cov__ || {};
							 | 
						||
| 
								 | 
							
								    node.__cov__[name] = value;
							 | 
						||
| 
								 | 
							
								  } // retrieve a node attribute for the supplied node or null
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getAttr(node, name) {
							 | 
						||
| 
								 | 
							
								    const c = node.__cov__;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!c) {
							 | 
						||
| 
								 | 
							
								      return null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c[name];
							 | 
						||
| 
								 | 
							
								  } //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  increase(type, id, index) {
							 | 
						||
| 
								 | 
							
								    const T = this.types;
							 | 
						||
| 
								 | 
							
								    const wrap = index !== null ? // If `index` present, turn `x` into `x[index]`.
							 | 
						||
| 
								 | 
							
								    x => T.memberExpression(x, T.numericLiteral(index), true) : x => x;
							 | 
						||
| 
								 | 
							
								    return T.updateExpression('++', wrap(T.memberExpression(T.memberExpression(T.identifier(this.varName), T.identifier(type)), T.numericLiteral(id), true)));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  insertCounter(path, increment) {
							 | 
						||
| 
								 | 
							
								    const T = this.types;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (path.isBlockStatement()) {
							 | 
						||
| 
								 | 
							
								      path.node.body.unshift(T.expressionStatement(increment));
							 | 
						||
| 
								 | 
							
								    } else if (path.isStatement()) {
							 | 
						||
| 
								 | 
							
								      path.insertBefore(T.expressionStatement(increment));
							 | 
						||
| 
								 | 
							
								    } else if (this.counterNeedsHoisting(path) && T.isVariableDeclarator(path.parentPath)) {
							 | 
						||
| 
								 | 
							
								      // make an attempt to hoist the statement counter, so that
							 | 
						||
| 
								 | 
							
								      // function names are maintained.
							 | 
						||
| 
								 | 
							
								      const parent = path.parentPath.parentPath;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (parent && T.isExportNamedDeclaration(parent.parentPath)) {
							 | 
						||
| 
								 | 
							
								        parent.parentPath.insertBefore(T.expressionStatement(increment));
							 | 
						||
| 
								 | 
							
								      } else if (parent && (T.isProgram(parent.parentPath) || T.isBlockStatement(parent.parentPath))) {
							 | 
						||
| 
								 | 
							
								        parent.insertBefore(T.expressionStatement(increment));
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        path.replaceWith(T.sequenceExpression([increment, path.node]));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /* istanbul ignore else: not expected */
							 | 
						||
| 
								 | 
							
								    else if (path.isExpression()) {
							 | 
						||
| 
								 | 
							
								        path.replaceWith(T.sequenceExpression([increment, path.node]));
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        console.error('Unable to insert counter for node type:', path.node.type);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  insertStatementCounter(path) {
							 | 
						||
| 
								 | 
							
								    /* istanbul ignore if: paranoid check */
							 | 
						||
| 
								 | 
							
								    if (!(path.node && path.node.loc)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const index = this.cov.newStatement(path.node.loc);
							 | 
						||
| 
								 | 
							
								    const increment = this.increase('s', index, null);
							 | 
						||
| 
								 | 
							
								    this.insertCounter(path, increment);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  insertFunctionCounter(path) {
							 | 
						||
| 
								 | 
							
								    const T = this.types;
							 | 
						||
| 
								 | 
							
								    /* istanbul ignore if: paranoid check */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!(path.node && path.node.loc)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const n = path.node;
							 | 
						||
| 
								 | 
							
								    let 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
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const name = path.node.id ? path.node.id.name : path.node.name;
							 | 
						||
| 
								 | 
							
								    const index = this.cov.newFunction(name, dloc, path.node.body.loc);
							 | 
						||
| 
								 | 
							
								    const increment = this.increase('f', index, null);
							 | 
						||
| 
								 | 
							
								    const 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);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  getBranchIncrement(branchName, loc) {
							 | 
						||
| 
								 | 
							
								    const index = this.cov.addBranchPath(branchName, loc);
							 | 
						||
| 
								 | 
							
								    return this.increase('b', branchName, index);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  insertBranchCounter(path, branchName, loc) {
							 | 
						||
| 
								 | 
							
								    const increment = this.getBranchIncrement(branchName, loc || path.node.loc);
							 | 
						||
| 
								 | 
							
								    this.insertCounter(path, increment);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  findLeaves(node, accumulator, parent, property) {
							 | 
						||
| 
								 | 
							
								    if (!node) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (node.type === 'LogicalExpression') {
							 | 
						||
| 
								 | 
							
								      const 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,
							 | 
						||
| 
								 | 
							
								        parent,
							 | 
						||
| 
								 | 
							
								        property
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // 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(...enter) {
							 | 
						||
| 
								 | 
							
								  // the enter function
							 | 
						||
| 
								 | 
							
								  const wrappedEntry = function wrappedEntry(path, node) {
							 | 
						||
| 
								 | 
							
								    this.onEnter(path);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (this.shouldIgnore(path)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    enter.forEach(e => {
							 | 
						||
| 
								 | 
							
								      e.call(this, path, node);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const exit = function exit(path, node) {
							 | 
						||
| 
								 | 
							
								    this.onExit(path, node);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return {
							 | 
						||
| 
								 | 
							
								    enter: wrappedEntry,
							 | 
						||
| 
								 | 
							
								    exit
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function coverStatement(path) {
							 | 
						||
| 
								 | 
							
								  this.insertStatementCounter(path);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/* istanbul ignore next: no node.js support */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function coverAssignmentPattern(path) {
							 | 
						||
| 
								 | 
							
								  const n = path.node;
							 | 
						||
| 
								 | 
							
								  const 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 coverClassPropDeclarator(path) {
							 | 
						||
| 
								 | 
							
								  this.insertStatementCounter(path.get('value'));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function makeBlock(path) {
							 | 
						||
| 
								 | 
							
								  const 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 makeParenthesizedExpressionForNonIdentifier(path) {
							 | 
						||
| 
								 | 
							
								  const T = this.types;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (path.node && !path.isIdentifier()) {
							 | 
						||
| 
								 | 
							
								    path.replaceWith(T.parenthesizedExpression(path.node));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function parenthesizedExpressionProp(prop) {
							 | 
						||
| 
								 | 
							
								  return function (path) {
							 | 
						||
| 
								 | 
							
								    makeParenthesizedExpressionForNonIdentifier.call(this, path.get(prop));
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function convertArrowExpression(path) {
							 | 
						||
| 
								 | 
							
								  const n = path.node;
							 | 
						||
| 
								 | 
							
								  const T = this.types;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!T.isBlockStatement(n.body)) {
							 | 
						||
| 
								 | 
							
								    const bloc = n.body.loc;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (n.expression === true) {
							 | 
						||
| 
								 | 
							
								      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) {
							 | 
						||
| 
								 | 
							
								  const n = path.node;
							 | 
						||
| 
								 | 
							
								  const hint = this.hintFor(n);
							 | 
						||
| 
								 | 
							
								  const ignoreIf = hint === 'if';
							 | 
						||
| 
								 | 
							
								  const ignoreElse = hint === 'else';
							 | 
						||
| 
								 | 
							
								  const 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) {
							 | 
						||
| 
								 | 
							
								  const b = this.cov.newBranch('switch', path.node.loc);
							 | 
						||
| 
								 | 
							
								  this.setAttr(path.node, 'branchName', b);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function coverSwitchCase(path) {
							 | 
						||
| 
								 | 
							
								  const T = this.types;
							 | 
						||
| 
								 | 
							
								  const b = this.getAttr(path.parentPath.node, 'branchName');
							 | 
						||
| 
								 | 
							
								  /* istanbul ignore if: paranoid check */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (b === null) {
							 | 
						||
| 
								 | 
							
								    throw new Error('Unable to get switch branch name');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const increment = this.getBranchIncrement(b, path.node.loc);
							 | 
						||
| 
								 | 
							
								  path.node.consequent.unshift(T.expressionStatement(increment));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function coverTernary(path) {
							 | 
						||
| 
								 | 
							
								  const n = path.node;
							 | 
						||
| 
								 | 
							
								  const branch = this.cov.newBranch('cond-expr', path.node.loc);
							 | 
						||
| 
								 | 
							
								  const cHint = this.hintFor(n.consequent);
							 | 
						||
| 
								 | 
							
								  const 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) {
							 | 
						||
| 
								 | 
							
								  const T = this.types;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (path.parentPath.node.type === 'LogicalExpression') {
							 | 
						||
| 
								 | 
							
								    return; // already processed
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const leaves = [];
							 | 
						||
| 
								 | 
							
								  this.findLeaves(path.node, leaves);
							 | 
						||
| 
								 | 
							
								  const b = this.cov.newBranch('binary-expr', path.node.loc);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (let i = 0; i < leaves.length; i += 1) {
							 | 
						||
| 
								 | 
							
								    const leaf = leaves[i];
							 | 
						||
| 
								 | 
							
								    const hint = this.hintFor(leaf.node);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (hint === 'next') {
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const increment = this.getBranchIncrement(b, leaf.node.loc);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!increment) {
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    leaf.parent[leaf.property] = T.sequenceExpression([increment, leaf.node]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const codeVisitor = {
							 | 
						||
| 
								 | 
							
								  ArrowFunctionExpression: entries(convertArrowExpression, coverFunction),
							 | 
						||
| 
								 | 
							
								  AssignmentPattern: entries(coverAssignmentPattern),
							 | 
						||
| 
								 | 
							
								  BlockStatement: entries(),
							 | 
						||
| 
								 | 
							
								  // ignore processing only
							 | 
						||
| 
								 | 
							
								  ExportDefaultDeclaration: entries(),
							 | 
						||
| 
								 | 
							
								  // ignore processing only
							 | 
						||
| 
								 | 
							
								  ExportNamedDeclaration: entries(),
							 | 
						||
| 
								 | 
							
								  // ignore processing only
							 | 
						||
| 
								 | 
							
								  ClassMethod: entries(coverFunction),
							 | 
						||
| 
								 | 
							
								  ClassDeclaration: entries(parenthesizedExpressionProp('superClass')),
							 | 
						||
| 
								 | 
							
								  ClassProperty: entries(coverClassPropDeclarator),
							 | 
						||
| 
								 | 
							
								  ClassPrivateProperty: entries(coverClassPropDeclarator),
							 | 
						||
| 
								 | 
							
								  ObjectMethod: 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'), coverStatement),
							 | 
						||
| 
								 | 
							
								  ForInStatement: entries(blockProp('body'), coverStatement),
							 | 
						||
| 
								 | 
							
								  ForOfStatement: entries(blockProp('body'), 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)
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								const globalTemplateAlteredFunction = (0, _template.default)(`
							 | 
						||
| 
								 | 
							
								        var Function = (function(){}).constructor;
							 | 
						||
| 
								 | 
							
								        var global = (new Function(GLOBAL_COVERAGE_SCOPE))();
							 | 
						||
| 
								 | 
							
								`);
							 | 
						||
| 
								 | 
							
								const globalTemplateFunction = (0, _template.default)(`
							 | 
						||
| 
								 | 
							
								        var global = (new Function(GLOBAL_COVERAGE_SCOPE))();
							 | 
						||
| 
								 | 
							
								`);
							 | 
						||
| 
								 | 
							
								const globalTemplateVariable = (0, _template.default)(`
							 | 
						||
| 
								 | 
							
								        var global = GLOBAL_COVERAGE_SCOPE;
							 | 
						||
| 
								 | 
							
								`); // the template to insert at the top of the program.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const coverageTemplate = (0, _template.default)(`
							 | 
						||
| 
								 | 
							
								    var COVERAGE_VAR = (function () {
							 | 
						||
| 
								 | 
							
								        var path = PATH;
							 | 
						||
| 
								 | 
							
								        var hash = HASH;
							 | 
						||
| 
								 | 
							
								        GLOBAL_COVERAGE_TEMPLATE
							 | 
						||
| 
								 | 
							
								        var gcv = GLOBAL_COVERAGE_VAR;
							 | 
						||
| 
								 | 
							
								        var coverageData = INITIAL;
							 | 
						||
| 
								 | 
							
								        var coverage = global[gcv] || (global[gcv] = {});
							 | 
						||
| 
								 | 
							
								        if (coverage[path] && coverage[path].hash === hash) {
							 | 
						||
| 
								 | 
							
								            return coverage[path];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return coverage[path] = coverageData;
							 | 
						||
| 
								 | 
							
								    })();
							 | 
						||
| 
								 | 
							
								`); // the rewire plugin (and potentially other babel middleware)
							 | 
						||
| 
								 | 
							
								// may cause files to be instrumented twice, see:
							 | 
						||
| 
								 | 
							
								// https://github.com/istanbuljs/babel-plugin-istanbul/issues/94
							 | 
						||
| 
								 | 
							
								// we should only instrument code for coverage the first time
							 | 
						||
| 
								 | 
							
								// it's run through istanbul-lib-instrument.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function alreadyInstrumented(path, visitState) {
							 | 
						||
| 
								 | 
							
								  return path.scope.hasBinding(visitState.varName);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function shouldIgnoreFile(programNode) {
							 | 
						||
| 
								 | 
							
								  return programNode.parent && programNode.parent.comments.some(c => COMMENT_FILE_RE.test(c.value));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const defaultProgramVisitorOpts = {
							 | 
						||
| 
								 | 
							
								  inputSourceMap: undefined
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * 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.
							 | 
						||
| 
								 | 
							
								 * @param {string} [opts.coverageGlobalScope=this] the global coverage variable scope.
							 | 
						||
| 
								 | 
							
								 * @param {boolean} [opts.coverageGlobalScopeFunc=true] use an evaluated function to find coverageGlobalScope.
							 | 
						||
| 
								 | 
							
								 * @param {Array} [opts.ignoreClassMethods=[]] names of methods to ignore by default on classes.
							 | 
						||
| 
								 | 
							
								 * @param {object} [opts.inputSourceMap=undefined] the input source map, that maps the uninstrumented code back to the
							 | 
						||
| 
								 | 
							
								 * original code.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function programVisitor(types, sourceFilePath = 'unknown.js', opts = defaultProgramVisitorOpts) {
							 | 
						||
| 
								 | 
							
								  const T = types; // This sets some unused options but ensures all required options are initialized
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  opts = Object.assign({}, (0, _instrumenter.defaultOpts)(), defaultProgramVisitorOpts, opts);
							 | 
						||
| 
								 | 
							
								  const visitState = new VisitState(types, sourceFilePath, opts.inputSourceMap, opts.ignoreClassMethods);
							 | 
						||
| 
								 | 
							
								  return {
							 | 
						||
| 
								 | 
							
								    enter(path) {
							 | 
						||
| 
								 | 
							
								      if (shouldIgnoreFile(path.find(p => p.isProgram()))) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (alreadyInstrumented(path, visitState)) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      path.traverse(codeVisitor, visitState);
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    exit(path) {
							 | 
						||
| 
								 | 
							
								      if (alreadyInstrumented(path, visitState)) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      visitState.cov.freeze();
							 | 
						||
| 
								 | 
							
								      const coverageData = visitState.cov.toJSON();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (shouldIgnoreFile(path.find(p => p.isProgram()))) {
							 | 
						||
| 
								 | 
							
								        return {
							 | 
						||
| 
								 | 
							
								          fileCoverage: coverageData,
							 | 
						||
| 
								 | 
							
								          sourceMappingURL: visitState.sourceMappingURL
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      coverageData[_constants.MAGIC_KEY] = _constants.MAGIC_VALUE;
							 | 
						||
| 
								 | 
							
								      const hash = (0, _crypto.createHash)(_constants.SHA).update(JSON.stringify(coverageData)).digest('hex');
							 | 
						||
| 
								 | 
							
								      coverageData.hash = hash;
							 | 
						||
| 
								 | 
							
								      const coverageNode = T.valueToNode(coverageData);
							 | 
						||
| 
								 | 
							
								      delete coverageData[_constants.MAGIC_KEY];
							 | 
						||
| 
								 | 
							
								      delete coverageData.hash;
							 | 
						||
| 
								 | 
							
								      let gvTemplate;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (opts.coverageGlobalScopeFunc) {
							 | 
						||
| 
								 | 
							
								        if (path.scope.getBinding('Function')) {
							 | 
						||
| 
								 | 
							
								          gvTemplate = globalTemplateAlteredFunction({
							 | 
						||
| 
								 | 
							
								            GLOBAL_COVERAGE_SCOPE: T.stringLiteral('return ' + opts.coverageGlobalScope)
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          gvTemplate = globalTemplateFunction({
							 | 
						||
| 
								 | 
							
								            GLOBAL_COVERAGE_SCOPE: T.stringLiteral('return ' + opts.coverageGlobalScope)
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        gvTemplate = globalTemplateVariable({
							 | 
						||
| 
								 | 
							
								          GLOBAL_COVERAGE_SCOPE: opts.coverageGlobalScope
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const cv = coverageTemplate({
							 | 
						||
| 
								 | 
							
								        GLOBAL_COVERAGE_VAR: T.stringLiteral(opts.coverageVariable),
							 | 
						||
| 
								 | 
							
								        GLOBAL_COVERAGE_TEMPLATE: gvTemplate,
							 | 
						||
| 
								 | 
							
								        COVERAGE_VAR: T.identifier(visitState.varName),
							 | 
						||
| 
								 | 
							
								        PATH: T.stringLiteral(sourceFilePath),
							 | 
						||
| 
								 | 
							
								        INITIAL: coverageNode,
							 | 
						||
| 
								 | 
							
								        HASH: T.stringLiteral(hash)
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								      cv._blockHoist = 5;
							 | 
						||
| 
								 | 
							
								      path.node.body.unshift(cv);
							 | 
						||
| 
								 | 
							
								      return {
							 | 
						||
| 
								 | 
							
								        fileCoverage: coverageData,
							 | 
						||
| 
								 | 
							
								        sourceMappingURL: visitState.sourceMappingURL
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _default = programVisitor;
							 | 
						||
| 
								 | 
							
								exports.default = _default;
							 |