Skip to content
This repository was archived by the owner on Apr 3, 2024. It is now read-only.

Commit f8bb4dc

Browse files
Add improved support for transpiled code (#159)
This PR includes the new SourceMapper that is responsible for processing sourcemap files and understanding which files in a project are the input files and output files to a transpilation process. This adds robustness to handling breakpoints set in source files used as the input to Babel, Typescript, and Coffeescript transpilation. This pull request also addresses the bug [#153](#153) "Off-by-one-line error in transpiled breakpoint".
1 parent fd05077 commit f8bb4dc

28 files changed

+1153
-179
lines changed

lib/debuglet.js

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var DebugletApi = require('./debugletapi.js');
2727
var scanner = require('./scanner.js');
2828
var Logger = require('@google/cloud-diagnostics-common').logger;
2929
var StatusMessage = require('./apiclasses.js').StatusMessage;
30+
var SourceMapper = require('./sourcemapper.js');
3031

3132
var assert = require('assert');
3233

@@ -98,40 +99,51 @@ Debuglet.prototype.start = function() {
9899
if (process.env.GAE_MINOR_VERSION) {
99100
id = 'GAE-' + process.env.GAE_MINOR_VERSION;
100101
}
101-
scanner.scan(!id, that.config_.workingDirectory,
102+
scanner.scan(!id, that.config_.workingDirectory, /.js$|.map$/,
102103
function(err, fileStats, hash) {
103104
if (err) {
104105
that.logger_.error('Error scanning the filesystem.', err);
105106
that.emit('initError', err);
106107
return;
107108
}
108-
that.v8debug_ = v8debugapi.create(that.logger_, that.config_, fileStats);
109109

110-
id = id || hash;
111-
112-
that.logger_.info('Unique ID for this Application: ' + id);
113-
114-
that.debugletApi_.init(id, that.logger_, function(err, project) {
110+
var jsStats = fileStats.selectStats(/.js$/);
111+
var mapFiles = fileStats.selectFiles(/.map$/, process.cwd());
112+
SourceMapper.create(mapFiles, function(err, mapper) {
115113
if (err) {
116-
that.logger_.error('Unable to initialize the debuglet api' +
117-
' -- disabling debuglet', err);
114+
that.logger_.error('Error processing the sourcemaps.', err);
118115
that.emit('initError', err);
119116
return;
120117
}
118+
119+
that.v8debug_ = v8debugapi.create(that.logger_, that.config_, jsStats, mapper);
121120

122-
if (semver.satisfies(process.version, '5.2 || <0.12')) {
123-
// Using an unsupported version. We report an error message about the
124-
// Node.js version, but we keep on running. The idea is that the user
125-
// may miss the error message on the console. This way we can report the
126-
// error when the user tries to set a breakpoint.
127-
that.logger_.error(NODE_VERSION_MESSAGE);
128-
}
121+
id = id || hash;
122+
123+
that.logger_.info('Unique ID for this Application: ' + id);
124+
125+
that.debugletApi_.init(id, that.logger_, function(err, project) {
126+
if (err) {
127+
that.logger_.error('Unable to initialize the debuglet api' +
128+
' -- disabling debuglet', err);
129+
that.emit('initError', err);
130+
return;
131+
}
129132

130-
// We can register as a debuggee now.
131-
that.running_ = true;
132-
that.project_ = project;
133-
that.scheduleRegistration_(0 /* immediately */);
134-
that.emit('started');
133+
if (semver.satisfies(process.version, '5.2 || <0.12')) {
134+
// Using an unsupported version. We report an error message about the
135+
// Node.js version, but we keep on running. The idea is that the user
136+
// may miss the error message on the console. This way we can report the
137+
// error when the user tries to set a breakpoint.
138+
that.logger_.error(NODE_VERSION_MESSAGE);
139+
}
140+
141+
// We can register as a debuggee now.
142+
that.running_ = true;
143+
that.project_ = project;
144+
that.scheduleRegistration_(0 /* immediately */);
145+
that.emit('started');
146+
});
135147
});
136148
});
137149
});

lib/scanner.js

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
'use strict';
1717

18+
var _ = require('lodash');
1819
var fs = require('fs');
1920
var path = require('path');
2021
var crypto = require('crypto');
@@ -25,8 +26,69 @@ module.exports = {
2526
scan: scan
2627
};
2728

28-
function scan(shouldHash, baseDir, callback) {
29-
findJSFiles(baseDir, function(err, fileList) {
29+
/**
30+
* Encapsulates the results of a filesystem scan with methods
31+
* to easily select scan information or filenames for a
32+
* specific subset of the files listed in the scan results.
33+
*
34+
* @param {Object} stats An object that contains filenames
35+
* as keys where each key maps to an object containing the
36+
* hash and number of lines for the specified file. This
37+
* information is accessed via the `hash` and `lines`
38+
* attributes respectively
39+
* @constructor
40+
*/
41+
function ScanResults(stats) {
42+
this.stats_ = stats;
43+
}
44+
45+
/**
46+
* Used to get all of the file scan results.
47+
*/
48+
ScanResults.prototype.all = function() {
49+
return this.stats_;
50+
};
51+
52+
/**
53+
* Used to get the file scan results for only the files
54+
* whose filenames match the specified regex.
55+
*
56+
* @param {regex} regex The regex that tests a filename
57+
* to determine if the scan results for that filename
58+
* should be included in the returned results.
59+
*/
60+
ScanResults.prototype.selectStats = function(regex) {
61+
return _.pickBy(this.stats_, function(value, key) {
62+
return regex.test(key);
63+
});
64+
};
65+
66+
/**
67+
* Used to get the only the file paths in the scan results
68+
* where the filenames match the specified regex and are
69+
* returned with the each relative to the specified base
70+
* directory.
71+
*
72+
* @param {regex} regex The regex that tests a filename to
73+
* determine if the scan results for that filename should
74+
* be included in the returned results.
75+
* @param {string} baseDir The absolute path to the directory
76+
* from which all of the returned paths should be relative
77+
* to.
78+
*/
79+
ScanResults.prototype.selectFiles = function(regex, baseDir) {
80+
// ensure the base directory has only a single trailing path separator
81+
baseDir = path.normalize(baseDir + path.sep);
82+
return Object.keys(this.stats_).filter(function(file) {
83+
return file && regex.test(file);
84+
})
85+
.map(function(file) {
86+
return path.normalize(file).replace(baseDir, '');
87+
});
88+
};
89+
90+
function scan(shouldHash, baseDir, regex, callback) {
91+
findFiles(baseDir, regex, function(err, fileList) {
3092
if (err) {
3193
callback(err);
3294
return;
@@ -48,7 +110,7 @@ function computeStats(fileList, shouldHash, callback) {
48110
var pending = fileList.length;
49111
// return a valid, if fake, result when there are no js files to hash.
50112
if (pending === 0) {
51-
callback(null, {}, 'EMPTY-no-js-files');
113+
callback(null, new ScanResults({}), 'EMPTY-no-js-files');
52114
return;
53115
}
54116

@@ -76,7 +138,7 @@ function computeStats(fileList, shouldHash, callback) {
76138
var sha1 = crypto.createHash('sha1').update(buffer).digest('hex');
77139
hash = 'SHA1-' + sha1;
78140
}
79-
callback(null, statistics, hash);
141+
callback(null, new ScanResults(statistics), hash);
80142
}
81143
});
82144
});
@@ -87,9 +149,11 @@ function computeStats(fileList, shouldHash, callback) {
87149
* Given a base-directory, this function scans the subtree and finds all the js
88150
* files. .git and node_module subdirectories are ignored.
89151
* @param {!string} baseDir top-level directory to scan
152+
* @param {!regex} regex the regular expression that specifies the types of
153+
* files to find based on their filename
90154
* @param {!function(?Error, Array<string>)} callback error-back callback
91155
*/
92-
function findJSFiles(baseDir, callback) {
156+
function findFiles(baseDir, regex, callback) {
93157
var errored = false;
94158

95159
if (!baseDir) {
@@ -114,7 +178,7 @@ function findJSFiles(baseDir, callback) {
114178
});
115179

116180
find.on('file', function(file) {
117-
if (/\.js$/.test(file)) {
181+
if (regex.test(file)) {
118182
fileList.push(file);
119183
}
120184
});

0 commit comments

Comments
 (0)