Skip to content

Commit c8c88d8

Browse files
committed
Handle a few types of errors
Show friendly messages for a few reference, syntax and type errors
1 parent 33cc770 commit c8c88d8

File tree

4 files changed

+205
-32
lines changed

4 files changed

+205
-32
lines changed

src/core/friendly_errors/browser_errors.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,40 @@ const strings = {
1616
type: 'NOTDEFINED',
1717
browser: 'Safari'
1818
}
19+
],
20+
SyntaxError: [
21+
{
22+
msg: 'illegal character',
23+
type: 'INVALIDTOKEN',
24+
browser: 'Firefox'
25+
},
26+
{
27+
msg: 'Invalid character',
28+
type: 'INVALIDTOKEN',
29+
browser: 'Safari'
30+
},
31+
{
32+
msg: 'Invalid or unexpected token',
33+
type: 'INVALIDTOKEN',
34+
browser: 'Chrome'
35+
},
36+
{
37+
msg: "Unexpected token '{{.}}'",
38+
type: 'UNEXPECTEDTOKEN',
39+
browser: 'Chrome'
40+
},
41+
{
42+
msg: "expected {{.}}, got '{{.}}'",
43+
type: 'UNEXPECTEDTOKEN',
44+
browser: 'Chrome'
45+
}
46+
],
47+
TypeError: [
48+
{
49+
msg: '{{.}} is not a function',
50+
type: 'NOTFUNC',
51+
browser: 'all'
52+
}
1953
]
2054
};
2155

src/core/friendly_errors/fes_core.js

Lines changed: 147 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,11 @@ if (typeof IS_MINIFIED !== 'undefined') {
155155
// Type to color
156156
color = typeColors[color];
157157
}
158-
if (func.substring(0, 4) === 'load') {
159-
console.log(translator('fes.pre', { message }));
158+
159+
let prefixedMsg;
160+
let style = [`color: ${color}`, 'font-family: Arial', 'font-size: larger'];
161+
if (func == null || func.substring(0, 4) === 'load') {
162+
prefixedMsg = translator('fes.pre', { message });
160163
} else {
161164
const methodParts = func.split('.');
162165
const referenceSection =
@@ -165,12 +168,11 @@ if (typeof IS_MINIFIED !== 'undefined') {
165168
const funcName =
166169
methodParts.length === 1 ? func : methodParts.slice(2).join('/');
167170

168-
console.log(
169-
translator('fes.pre', {
170-
message: `${message} (http://p5js.org/reference/#/${referenceSection}/${funcName})`
171-
})
172-
);
171+
prefixedMsg = translator('fes.pre', {
172+
message: `${message} (http://p5js.org/reference/#/${referenceSection}/${funcName})`
173+
});
173174
}
175+
console.log('%c' + prefixedMsg, style.join(';'));
174176
};
175177
/**
176178
* This is a generic method that can be called from anywhere in the p5
@@ -306,7 +308,7 @@ if (typeof IS_MINIFIED !== 'undefined') {
306308
}
307309
});
308310

309-
if (min > EDIT_DIST_THRESHOLD) return;
311+
if (min > Math.min(EDIT_DIST_THRESHOLD, errSym.length)) return false;
310312

311313
let symbol = misusedAtTopLevelCode[minIndex];
312314

@@ -441,37 +443,152 @@ if (typeof IS_MINIFIED !== 'undefined') {
441443
if (!error) return;
442444
const log = p5._fesLogger;
443445

444-
// Syntax Errors have no stacktrace attached to them, must be handled separately
445-
// TODO
446-
if (error.name === 'SyntaxError') return;
447-
448446
let stacktrace = p5._getErrorStackParser().parse(error);
449447
let [isInternal, friendlyStack] = processStack(error, stacktrace);
450-
if (isInternal || !friendlyStack) return;
451-
printFriendlyStack(friendlyStack);
448+
if (isInternal) {
449+
if (friendlyStack) printFriendlyStack(friendlyStack);
450+
return;
451+
}
452+
453+
const errList = errorTable[error.name];
454+
if (!errList) return; // this type of error can't be handled yet
455+
let matchedError;
456+
for (const obj of errList) {
457+
let string = obj.msg;
458+
// capture the primary symbol mentioned in the error
459+
string = string.replace(new RegExp('{{}}', 'g'), '([a-zA-Z0-9_]+)');
460+
string = string.replace(new RegExp('{{.}}', 'g'), '(.+)');
461+
string = string.replace(new RegExp('{}', 'g'), '(?:[a-zA-Z0-9_]+)');
462+
let matched = error.message.match(string);
463+
464+
if (matched) {
465+
matchedError = Object.assign({}, obj);
466+
matchedError.match = matched;
467+
break;
468+
}
469+
}
470+
471+
if (!matchedError) return;
472+
452473
switch (error.name) {
474+
case 'SyntaxError': {
475+
switch (matchedError.type) {
476+
case 'INVALIDTOKEN': {
477+
let url =
478+
'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Illegal_character#What_went_wrong';
479+
p5._friendlyError(
480+
translator('fes.globalErrors.syntax.invalidToken', {
481+
url
482+
})
483+
);
484+
break;
485+
}
486+
case 'UNEXPECTEDTOKEN': {
487+
let url =
488+
'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Unexpected_token#What_went_wrong';
489+
p5._friendlyError(
490+
translator('fes.globalErrors.syntax.unexpectedToken', {
491+
url
492+
})
493+
);
494+
break;
495+
}
496+
}
497+
break;
498+
}
453499
case 'ReferenceError': {
454-
const errList = errorTable.ReferenceError;
455-
for (const obj of errList) {
456-
let string = obj.msg;
457-
// capture the primary symbol mentioned in the error
458-
string = string.replace('{{}}', '([a-zA-Z0-9_]+)');
459-
string = string.replace('{}', '(?:[a-zA-Z0-9_]+)');
460-
let matched = error.message.match(string);
461-
if (matched && matched[1]) {
462-
switch (obj.type) {
463-
case 'NOTDEFINED':
464-
handleMisspelling(
465-
matched[1],
466-
error,
467-
typeof log === 'function' ? log : undefined
468-
);
469-
break;
500+
switch (matchedError.type) {
501+
case 'NOTDEFINED': {
502+
let errSym = matchedError.match[1];
503+
504+
if (
505+
errSym &&
506+
handleMisspelling(
507+
errSym,
508+
error,
509+
typeof log === 'function' ? log : undefined
510+
)
511+
) {
512+
break;
513+
}
514+
515+
// if the flow gets this far, this is likely not a misspelling
516+
// of a p5 property/function
517+
let url1 = 'https://p5js.org/examples/data-variable-scope.html';
518+
let url2 =
519+
'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_Defined#What_went_wrong';
520+
let location;
521+
if (
522+
stacktrace[0].fileName &&
523+
stacktrace[0].lineNumber &&
524+
stacktrace[0].columnNumber
525+
) {
526+
location = `${stacktrace[0].fileName}:${
527+
stacktrace[0].lineNumber
528+
}:${stacktrace[0].columnNumber}`;
470529
}
530+
p5._friendlyError(
531+
translator('fes.globalErrors.reference.notDefined', {
532+
url1,
533+
url2,
534+
symbol: errSym,
535+
location: location
536+
? translator('fes.location', {
537+
location
538+
})
539+
: ''
540+
})
541+
);
542+
543+
if (friendlyStack) printFriendlyStack(friendlyStack);
544+
545+
break;
471546
}
472547
}
473548
break;
474549
}
550+
551+
case 'TypeError': {
552+
switch (matchedError.type) {
553+
case 'NOTFUNC': {
554+
let errSym = matchedError.match[1];
555+
let splitSym = errSym.split('.');
556+
let location;
557+
let url =
558+
'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_a_function#What_went_wrong';
559+
if (
560+
stacktrace[0].fileName &&
561+
stacktrace[0].lineNumber &&
562+
stacktrace[0].columnNumber
563+
) {
564+
location = `${stacktrace[0].fileName}:${
565+
stacktrace[0].lineNumber
566+
}:${stacktrace[0].columnNumber}`;
567+
}
568+
console.log(splitSym, matchedError);
569+
let translationObj = {
570+
url,
571+
symbol: splitSym[splitSym.length - 1],
572+
obj: splitSym.slice(0, splitSym.length - 1).join('.'),
573+
location: location
574+
? translator('fes.location', {
575+
location
576+
})
577+
: ''
578+
};
579+
580+
if (splitSym.length > 1) {
581+
p5._friendlyError(
582+
translator('fes.globalErrors.type.notfuncObj', translationObj)
583+
);
584+
} else {
585+
p5._friendlyError(
586+
translator('fes.globalErrors.type.notfunc', translationObj)
587+
);
588+
}
589+
}
590+
}
591+
}
475592
}
476593
};
477594

translations/en/translation.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,19 @@
2222
},
2323
"globalErrors": {
2424
"libraryError": "An error with message \"{{error}}\" was thrown inside the p5js library when you called {{func}} {{location}}\nIf not stated otherwise, it is likely an issue with the arguments passed to {{func}}.",
25+
"reference": {
26+
"notDefined": "There's an error due to \"{{symbol}}\" not being defined in the current scope {{location}}.\n\nIf you had defined it in your code, check its scope, spelling, and letter-casing (JavaScript is case-sensitive). For more:\n{{url1}}\n{{url2}}"
27+
},
2528
"stackSubseq": "▶️ Called from line {{line}} in function {{func}} in {{file}} ({{location}})\n\n",
26-
"stackTop": "▶️ Error at line {{line}} in function {{func}} in {{file}} ({{location}})\n\n"
29+
"stackTop": "▶️ Error at line {{line}} in function {{func}} in {{file}} ({{location}})\n\n",
30+
"syntax": {
31+
"invalidToken": "There's a syntax error due to a symbol that JavaScript doesn't recognize or didn't expect at it's place.\nUsually this can when copying code from some other place. For example \" is supported but “ isn't.\nFor more: {{url}}",
32+
"unexpectedToken": "There's a syntax error due to a symbol that wasn't expected at it's place.\nUsually this is due to a typo. Check the line number in the error below for anything missing/extra.\nFor more: {{url}}"
33+
},
34+
"type": {
35+
"notfunc": "There's an error as \"{{symbol}}\" could not be called as a function {{location}}.\nCheck the spelling, letter-casing (Javacript is case-sensitive) and its type.\nFor more: {{url}}",
36+
"notfuncObj": "There's an error as \"{{symbol}}\" could not be called as a function {{location}}.\nVerify whether \"{{obj}}\" has \"{{symbol}}\" in it and check the spelling, letter-casing (Javacript is case-sensitive) and its type.\nFor more: {{url}}"
37+
}
2738
},
2839
"location": "(at {{location}})",
2940
"misspelling": "It seems that you may have accidently written {{name}} instead of {{actualName}} {{location}}.\n\nPlease correct it to {{actualName}} if you wish to use the {{type}} from p5.js",

translations/es/translation.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,19 @@
2222
},
2323
"globalErrors": {
2424
"libraryError": "",
25+
"reference": {
26+
"notDefined": ""
27+
},
2528
"stackSubseq": "",
26-
"stackTop": ""
29+
"stackTop": "",
30+
"syntax": {
31+
"invalidToken": "",
32+
"unexpectedToken": ""
33+
},
34+
"type": {
35+
"notfunc": "",
36+
"notfuncObj": ""
37+
}
2738
},
2839
"location": "",
2940
"misspelling": "",

0 commit comments

Comments
 (0)