Skip to content

Commit 7194832

Browse files
committed
send structured error meta alongside log strings
1 parent 4279ff3 commit 7194832

2 files changed

Lines changed: 115 additions & 63 deletions

File tree

client/modules/IDE/components/Editor/index.jsx

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -148,27 +148,42 @@ function Editor({
148148
useEffect(() => {
149149
const consoleErrors = consoleEvents.filter((e) => e.method === 'error');
150150

151-
if (consoleErrors.length > 0) {
152-
const firstError = consoleErrors[0];
153-
const errorObj = { stack: firstError.data[0].toString() };
154-
StackTrace.fromError(errorObj).then((stackLines) => {
155-
expandConsole();
156-
const line = stackLines.find(
157-
(l) => l.fileName && l.fileName.startsWith('/')
158-
);
159-
if (!line) return;
160-
const fileNameArray = line.fileName.split('/');
161-
const fileName = fileNameArray.slice(-1)[0];
162-
const filePath = fileNameArray.slice(0, -1).join('/');
163-
const fileWithError = files.find(
164-
(f) => f.name === fileName && f.filePath === filePath
165-
);
166-
setSelectedFile(fileWithError.id);
167-
addErrorDecoration(codemirrorView.current, line.lineNumber);
168-
});
169-
} else {
151+
if (consoleErrors.length === 0) {
170152
removeErrorDecorations(codemirrorView.current);
153+
return;
171154
}
155+
156+
const applyDecoration = (frame) => {
157+
if (!frame || !frame.fileName) return;
158+
expandConsole();
159+
const fileNameArray = frame.fileName.split('/');
160+
const fileName = fileNameArray.slice(-1)[0];
161+
const filePath = fileNameArray.slice(0, -1).join('/');
162+
const fileWithError = files.find(
163+
(f) => f.name === fileName && f.filePath === filePath
164+
);
165+
if (!fileWithError) return;
166+
setSelectedFile(fileWithError.id);
167+
addErrorDecoration(codemirrorView.current, frame.lineNumber);
168+
};
169+
170+
const firstError = consoleErrors[0];
171+
const metaStack = firstError.meta && firstError.meta.stack;
172+
if (Array.isArray(metaStack) && metaStack.length > 0) {
173+
const frame =
174+
metaStack.find((f) => f.fileName && f.fileName.startsWith('/')) ||
175+
metaStack[0];
176+
applyDecoration(frame);
177+
return;
178+
}
179+
180+
const errorObj = { stack: firstError.data[0].toString() };
181+
StackTrace.fromError(errorObj).then((stackLines) => {
182+
const frame = stackLines.find(
183+
(l) => l.fileName && l.fileName.startsWith('/')
184+
);
185+
applyDecoration(frame);
186+
});
172187
}, [consoleEvents]);
173188

174189
const editorSectionClass = classNames({

client/utils/previewEntry.js

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,24 @@ if (Array.isArray(window.__jshintErrors) && window.__jshintErrors.length > 0) {
3939
const errorLogs = window.__jshintErrors.map((err) => {
4040
const location = `${err.file}:${err.line}:${err.character}`;
4141
const data = `SyntaxError: ${err.reason}\n at ${location}`;
42-
return {
43-
log: [
44-
{
45-
method: 'error',
46-
data: [data],
47-
id: `${Date.now()}-${err.file}-${err.line}-${err.character}`
48-
}
49-
]
42+
const log = {
43+
method: 'error',
44+
data: [data],
45+
id: `${Date.now()}-${err.file}-${err.line}-${err.character}`,
46+
meta: {
47+
name: 'SyntaxError',
48+
message: err.reason,
49+
stack: [
50+
{
51+
fileName: err.file,
52+
functionName: null,
53+
lineNumber: err.line,
54+
columnNumber: err.character
55+
}
56+
]
57+
}
5058
};
59+
return { log: [log] };
5160
});
5261
editor.postMessage(
5362
{
@@ -84,32 +93,51 @@ function handleMessageEvent(e) {
8493

8594
window.addEventListener('message', handleMessageEvent);
8695

87-
function formatStackLine({ fileName, functionName, lineNumber, columnNumber }) {
96+
function resolveStackFrame({
97+
fileName,
98+
functionName,
99+
lineNumber,
100+
columnNumber
101+
}) {
88102
const resolvedFileName = window.objectUrls[fileName] || fileName;
89-
const resolvedFuncName = functionName || '(anonymous function)';
103+
let resolvedLineNumber = lineNumber;
104+
if (resolvedFileName === 'index.html' && lineNumber) {
105+
resolvedLineNumber = lineNumber - htmlOffset;
106+
}
107+
return {
108+
fileName: resolvedFileName,
109+
functionName: functionName || null,
110+
lineNumber: resolvedLineNumber || null,
111+
columnNumber: columnNumber || null
112+
};
113+
}
114+
115+
function formatStackFrame({
116+
fileName,
117+
functionName,
118+
lineNumber,
119+
columnNumber
120+
}) {
121+
const name = functionName || '(anonymous function)';
90122
if (lineNumber && columnNumber) {
91-
let resolvedLineNumber = lineNumber;
92-
if (resolvedFileName === 'index.html') {
93-
resolvedLineNumber = lineNumber - htmlOffset;
94-
}
95-
return `\n at ${resolvedFuncName} (${resolvedFileName}:${resolvedLineNumber}:${columnNumber})`;
123+
return `\n at ${name} (${fileName}:${lineNumber}:${columnNumber})`;
96124
}
97-
return `\n at ${resolvedFuncName} (${resolvedFileName})`;
125+
return `\n at ${name} (${fileName})`;
98126
}
99127

100-
function postErrorMessage(data) {
128+
function postErrorMessage(data, meta) {
129+
const log = {
130+
method: 'error',
131+
data: [data],
132+
id: Date.now().toString()
133+
};
134+
if (meta) log.meta = meta;
101135
editor.postMessage(
102136
{
103137
source: 'sketch',
104138
messages: [
105139
{
106-
log: [
107-
{
108-
method: 'error',
109-
data: [data],
110-
id: Date.now().toString()
111-
}
112-
]
140+
log: [log]
113141
}
114142
]
115143
},
@@ -129,48 +157,57 @@ window.onerror = async function onError(
129157
postErrorMessage(msg);
130158
return false;
131159
}
132-
let data = `${error.name}: ${error.message}`;
133-
let stackLines = [];
160+
let rawStack = [];
134161
if (error.stack) {
135162
try {
136-
stackLines = await StackTrace.fromError(error);
163+
rawStack = await StackTrace.fromError(error);
137164
} catch (e) {
138-
stackLines = [];
165+
rawStack = [];
139166
}
140167
}
141-
if (stackLines.length > 0) {
142-
stackLines.forEach((stackLine) => {
143-
data = data.concat(formatStackLine(stackLine));
144-
});
145-
} else {
146-
data = data.concat(
147-
formatStackLine({
168+
if (rawStack.length === 0) {
169+
rawStack = [
170+
{
148171
fileName: source,
149172
functionName: null,
150173
lineNumber,
151174
columnNumber: columnNo
152-
})
153-
);
175+
}
176+
];
154177
}
155-
postErrorMessage(data);
178+
const resolvedStack = rawStack.map(resolveStackFrame);
179+
let data = `${error.name}: ${error.message}`;
180+
resolvedStack.forEach((frame) => {
181+
data = data.concat(formatStackFrame(frame));
182+
});
183+
postErrorMessage(data, {
184+
name: error.name,
185+
message: error.message,
186+
stack: resolvedStack
187+
});
156188
return false;
157189
};
158190
// catch rejected promises
159191
window.onunhandledrejection = async function onUnhandledRejection(event) {
160192
if (!event.reason || !event.reason.message) return;
161-
let stackLines = [];
193+
let rawStack = [];
162194
if (event.reason.stack) {
163195
try {
164-
stackLines = await StackTrace.fromError(event.reason);
196+
rawStack = await StackTrace.fromError(event.reason);
165197
} catch (e) {
166-
stackLines = [];
198+
rawStack = [];
167199
}
168200
}
201+
const resolvedStack = rawStack.map(resolveStackFrame);
169202
let data = `${event.reason.name}: ${event.reason.message}`;
170-
stackLines.forEach((stackLine) => {
171-
data = data.concat(formatStackLine(stackLine));
203+
resolvedStack.forEach((frame) => {
204+
data = data.concat(formatStackFrame(frame));
205+
});
206+
postErrorMessage(data, {
207+
name: event.reason.name,
208+
message: event.reason.message,
209+
stack: resolvedStack
172210
});
173-
postErrorMessage(data);
174211
};
175212

176213
// Monkeypatch p5._friendlyError

0 commit comments

Comments
 (0)