Merge pull request #73 from lmccart/console

fixing line numbers in console
This commit is contained in:
Cassie Tarakajian 2016-08-28 11:52:14 -04:00 committed by GitHub
commit 669a7d47e5

View file

@ -3,55 +3,100 @@ import ReactDOM from 'react-dom';
import escapeStringRegexp from 'escape-string-regexp'; import escapeStringRegexp from 'escape-string-regexp';
import srcDoc from 'srcdoc-polyfill'; import srcDoc from 'srcdoc-polyfill';
const hijackConsoleScript = `<script>
document.addEventListener('DOMContentLoaded', function() {
var iframeWindow = window;
var originalConsole = iframeWindow.console;
iframeWindow.console = {};
var methods = [ const startTag = 'filestart-';
'debug', 'clear', 'error', 'info', 'log', 'warn'
];
methods.forEach( function(method) { function getAllScriptOffsets(htmlFile) {
iframeWindow.console[method] = function() { const offs = [];
originalConsole[method].apply(originalConsole, arguments); let found = true;
let lastInd = 0;
let ind = 0;
let endFilenameInd = 0;
let filename = '';
let lineOffset = 0;
while (found) {
ind = htmlFile.indexOf(startTag, lastInd);
if (ind === -1) {
found = false;
} else {
endFilenameInd = htmlFile.indexOf('.js', ind + startTag.length + 3);
filename = htmlFile.substring(ind + startTag.length, endFilenameInd);
lineOffset = htmlFile.substring(0, ind).split('\n').length;
offs.push([lineOffset, filename]);
lastInd = ind + 1;
}
}
return offs;
}
var args = Array.from(arguments); function hijackConsoleScript(offs) {
args = args.map(function(i) { const s = `<script>
// catch objects function getScriptOff(line) {
return (typeof i === 'string') ? i : JSON.stringify(i); var offs = ${offs};
}); var l = 0;
var file = '';
for (var i=0; i<offs.length; i++) {
var n = offs[i][0];
if (n < line && n > l) {
l = n;
file = offs[i][1];
}
}
return [line - l, file];
}
// post message to parent window
window.parent.postMessage({ document.addEventListener('DOMContentLoaded', function() {
method: method, var iframeWindow = window;
arguments: args, var originalConsole = iframeWindow.console;
source: 'sketch' iframeWindow.console = {};
}, '*');
var methods = [
'debug', 'clear', 'error', 'info', 'log', 'warn'
];
methods.forEach( function(method) {
iframeWindow.console[method] = function() {
originalConsole[method].apply(originalConsole, arguments);
var args = Array.from(arguments);
args = args.map(function(i) {
// catch objects
return (typeof i === 'undefined') ? 'undefined' : JSON.stringify(i);
});
// post message to parent window
window.parent.postMessage({
method: method,
arguments: args,
source: 'sketch'
}, '*');
};
});
// catch reference errors, via http://stackoverflow.com/a/12747364/2994108
window.onerror = function (msg, url, lineNumber, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
var data = {};
if (string.indexOf(substring) !== -1){
data = 'Script Error: See Browser Console for Detail';
} else {
var fileInfo = getScriptOff(lineNumber);
data = msg + ' (' + fileInfo[1] + ': line ' + fileInfo[0] + ')';
}
window.parent.postMessage({
method: 'error',
arguments: data,
source: 'sketch'
}, '*');
return false;
}; };
}); });
</script>`;
// catch reference errors, via http://stackoverflow.com/a/12747364/2994108 return s;
window.onerror = function (msg, url, lineNumber, columnNo, error) { }
var string = msg.toLowerCase();
var substring = "script error";
var data = {};
if (string.indexOf(substring) > -1){
data = 'Script Error: See Browser Console for Detail';
} else {
data = msg + ' Line: ' + lineNumber + 'column: ' + columnNo;
}
window.parent.postMessage({
method: 'error',
arguments: data,
source: 'sketch'
}, '*');
return false;
};
});
</script>`;
class PreviewFrame extends React.Component { class PreviewFrame extends React.Component {
@ -95,6 +140,7 @@ class PreviewFrame extends React.Component {
injectLocalFiles() { injectLocalFiles() {
let htmlFile = this.props.htmlFile.content; let htmlFile = this.props.htmlFile.content;
let scriptOffs = [];
// have to build the array manually because the spread operator is only // have to build the array manually because the spread operator is only
// one level down... // one level down...
@ -102,9 +148,10 @@ class PreviewFrame extends React.Component {
this.props.jsFiles.forEach(jsFile => { this.props.jsFiles.forEach(jsFile => {
const newJSFile = { ...jsFile }; const newJSFile = { ...jsFile };
let jsFileStrings = newJSFile.content.match(/(['"])((\\\1|.)*?)\1/gm); let jsFileStrings = newJSFile.content.match(/(['"])((\\\1|.)*?)\1/gm);
const jsFileRegex = /^('|")(?!(http:\/\/|https:\/\/)).*\.(png|jpg|jpeg|gif|bmp|mp3|wav|aiff|ogg|json)('|")$/i;
jsFileStrings = jsFileStrings || []; jsFileStrings = jsFileStrings || [];
jsFileStrings.forEach(jsFileString => { jsFileStrings.forEach(jsFileString => {
if (jsFileString.match(/^('|")(?!(http:\/\/|https:\/\/)).*\.(png|jpg|jpeg|gif|bmp|mp3|wav|aiff|ogg|json)('|")$/i)) { if (jsFileString.match(jsFileRegex)) {
const filePath = jsFileString.substr(1, jsFileString.length - 2); const filePath = jsFileString.substr(1, jsFileString.length - 2);
let fileName = filePath; let fileName = filePath;
if (fileName.match(/^\.\//)) { if (fileName.match(/^\.\//)) {
@ -125,7 +172,8 @@ class PreviewFrame extends React.Component {
jsFiles.forEach(jsFile => { jsFiles.forEach(jsFile => {
const fileName = escapeStringRegexp(jsFile.name); const fileName = escapeStringRegexp(jsFile.name);
const fileRegex = new RegExp(`<script.*?src=('|")((\.\/)|\/)?${fileName}('|").*?>([\s\S]*?)<\/script>`, 'gmi'); const fileRegex = new RegExp(`<script.*?src=('|")((\.\/)|\/)?${fileName}('|").*?>([\s\S]*?)<\/script>`, 'gmi');
htmlFile = htmlFile.replace(fileRegex, `<script>\n${jsFile.content}\n</script>`); const replacementString = `<script data-tag="${startTag}${jsFile.name}">\n${jsFile.content}\n</script>`;
htmlFile = htmlFile.replace(fileRegex, replacementString);
}); });
this.props.cssFiles.forEach(cssFile => { this.props.cssFiles.forEach(cssFile => {
@ -146,7 +194,8 @@ class PreviewFrame extends React.Component {
htmlFile = htmlFile.replace(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi, `<head>\n${htmlHeadContents}\n</head>`); htmlFile = htmlFile.replace(/(?:<head.*?>)([\s\S]*?)(?:<\/head>)/gmi, `<head>\n${htmlHeadContents}\n</head>`);
} }
htmlFile += hijackConsoleScript; scriptOffs = getAllScriptOffsets(htmlFile);
htmlFile += hijackConsoleScript(JSON.stringify(scriptOffs));
return htmlFile; return htmlFile;
} }