UNPKG

9.42 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _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; }; }(); /*
8 Copyright 2012-2015, Yahoo Inc.
9 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
10 */
11
12
13var _babylon = require('babylon');
14
15var babylon = _interopRequireWildcard(_babylon);
16
17var _babelTypes = require('babel-types');
18
19var t = _interopRequireWildcard(_babelTypes);
20
21var _babelTraverse = require('babel-traverse');
22
23var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
24
25var _babelGenerator = require('babel-generator');
26
27var _babelGenerator2 = _interopRequireDefault(_babelGenerator);
28
29var _visitor = require('./visitor');
30
31var _visitor2 = _interopRequireDefault(_visitor);
32
33function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
34
35function _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; } }
36
37function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
38
39function defaultOpts() {
40 return {
41 coverageVariable: "__coverage__",
42 preserveComments: false,
43 compact: true,
44 esModules: false,
45 autoWrap: false,
46 produceSourceMap: false,
47 sourceMapUrlCallback: null,
48 debug: false
49 };
50}
51/**
52 * Instrumenter is the public API for the instrument library.
53 * It is typically used for ES5 code. For ES6 code that you
54 * are already running under `babel` use the coverage plugin
55 * instead.
56 * @param {Object} opts optional.
57 * @param {string} [opts.coverageVariable=__coverage__] name of global coverage variable.
58 * @param {boolean} [opts.preserveComments=false] preserve comments in output
59 * @param {boolean} [opts.compact=true] generate compact code.
60 * @param {boolean} [opts.esModules=false] set to true to instrument ES6 modules.
61 * @param {boolean} [opts.autoWrap=false] set to true to allow `return` statements outside of functions.
62 * @param {boolean} [opts.produceSourceMap=false] set to true to produce a source map for the instrumented code.
63 * @param {Function} [opts.sourceMapUrlCallback=null] a callback function that is called when a source map URL
64 * is found in the original code. This function is called with the source file name and the source map URL.
65 * @param {boolean} [opts.debug=false] - turn debugging on
66 */
67
68var Instrumenter = function () {
69 function Instrumenter() {
70 var opts = arguments.length <= 0 || arguments[0] === undefined ? defaultOpts() : arguments[0];
71
72 _classCallCheck(this, Instrumenter);
73
74 this.opts = this.normalizeOpts(opts);
75 this.fileCoverage = null;
76 this.sourceMap = null;
77 }
78 /**
79 * normalize options passed in and assign defaults.
80 * @param opts
81 * @private
82 */
83
84
85 _createClass(Instrumenter, [{
86 key: 'normalizeOpts',
87 value: function normalizeOpts(opts) {
88 var normalize = function normalize(name, defaultValue) {
89 if (!opts.hasOwnProperty(name)) {
90 opts[name] = defaultValue;
91 }
92 };
93 var defOpts = defaultOpts();
94 Object.keys(defOpts).forEach(function (k) {
95 normalize(k, defOpts[k]);
96 });
97 return opts;
98 }
99 /**
100 * instrument the supplied code and track coverage against the supplied
101 * filename. It throws if invalid code is passed to it. ES5 and ES6 syntax
102 * is supported. To instrument ES6 modules, make sure that you set the
103 * `esModules` property to `true` when creating the instrumenter.
104 *
105 * @param {string} code - the code to instrument
106 * @param {string} filename - the filename against which to track coverage.
107 * @returns {string} the instrumented code.
108 */
109
110 }, {
111 key: 'instrumentSync',
112 value: function instrumentSync(code, filename) {
113 if (typeof code !== 'string') {
114 throw new Error('Code must be a string');
115 }
116 filename = filename || String(new Date().getTime()) + '.js';
117 var opts = this.opts;
118 var ast = babylon.parse(code, {
119 allowReturnOutsideFunction: opts.autoWrap,
120 sourceType: opts.esModules ? "module" : "script"
121 });
122 var ee = (0, _visitor2.default)(t, filename, {
123 coverageVariable: opts.coverageVariable
124 });
125 var output = {};
126 var visitor = {
127 Program: {
128 enter: ee.enter,
129 exit: function exit(path) {
130 output = ee.exit(path);
131 }
132 }
133 };
134 (0, _babelTraverse2.default)(ast, visitor);
135
136 var generateOptions = {
137 compact: opts.compact,
138 sourceMaps: opts.produceSourceMap,
139 sourceFileName: filename
140 };
141 var codeMap = (0, _babelGenerator2.default)(ast, generateOptions, code);
142 this.fileCoverage = output.fileCoverage;
143 this.sourceMap = codeMap.map;
144 var cb = this.opts.sourceMapUrlCallback;
145 if (cb && output.sourceMappingURL) {
146 cb(filename, output.sourceMappingURL);
147 }
148 return codeMap.code;
149 }
150 /**
151 * callback-style instrument method that calls back with an error
152 * as opposed to throwing one. Note that in the current implementation,
153 * the callback will be called in the same process tick and is not asynchronous.
154 *
155 * @param {string} code - the code to instrument
156 * @param {string} filename - the filename against which to track coverage.
157 * @param {Function} callback - the callback
158 */
159
160 }, {
161 key: 'instrument',
162 value: function instrument(code, filename, callback) {
163 if (!callback && typeof filename === 'function') {
164 callback = filename;
165 filename = null;
166 }
167 try {
168 var out = this.instrumentSync(code, filename);
169 callback(null, out);
170 } catch (ex) {
171 callback(ex);
172 }
173 }
174 /**
175 * returns the file coverage object for the last file instrumented.
176 * @returns {Object} the file coverage object.
177 */
178
179 }, {
180 key: 'lastFileCoverage',
181 value: function lastFileCoverage() {
182 return this.fileCoverage;
183 }
184 /**
185 * returns the source map produced for the last file instrumented.
186 * @returns {null|Object} the source map object.
187 */
188
189 }, {
190 key: 'lastSourceMap',
191 value: function lastSourceMap() {
192 return this.sourceMap;
193 }
194 }]);
195
196 return Instrumenter;
197}();
198
199exports.default = Instrumenter;
\No newline at end of file