X Tutup
Skip to content

Commit 3d3e6bb

Browse files
authored
Merge pull request #4719 from akshay-99/misspelling-multiple-match
FES: Handle multiple nearest matches for a misspelt symbol
2 parents 80026b7 + 1375c58 commit 3d3e6bb

File tree

4 files changed

+114
-42
lines changed

4 files changed

+114
-42
lines changed

src/core/friendly_errors/fes_core.js

Lines changed: 86 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,41 @@ if (typeof IS_MINIFIED !== 'undefined') {
136136
);
137137
};
138138

139+
/**
140+
* Takes a message and a p5 function func, and adds a link pointing to
141+
* the reference documentation of func at the end of the message
142+
*
143+
* @method mapToReference
144+
* @private
145+
* @param {String} message the words to be said
146+
* @param {String} [func] the name of the function to link
147+
*
148+
* @returns {String}
149+
*/
150+
const mapToReference = (message, func) => {
151+
let msgWithReference = '';
152+
if (func == null || func.substring(0, 4) === 'load') {
153+
msgWithReference = message;
154+
} else {
155+
const methodParts = func.split('.');
156+
const referenceSection =
157+
methodParts.length > 1 ? `${methodParts[0]}.${methodParts[1]}` : 'p5';
158+
159+
const funcName =
160+
methodParts.length === 1 ? func : methodParts.slice(2).join('/');
161+
msgWithReference = `${message} (http://p5js.org/reference/#/${referenceSection}/${funcName})`;
162+
}
163+
return msgWithReference;
164+
};
165+
139166
/**
140167
* Prints out a fancy, colorful message to the console log
141168
*
142169
* @method report
143170
* @private
144171
* @param {String} message the words to be said
145-
* @param {String} func the name of the function to link
146-
* @param {Number|String} color CSS color string or error type
172+
* @param {String} [func] the name of the function to link
173+
* @param {Number|String} [color] CSS color string or error type
147174
*
148175
* @return console logs
149176
*/
@@ -164,22 +191,11 @@ if (typeof IS_MINIFIED !== 'undefined') {
164191
color = typeColors[color];
165192
}
166193

167-
let prefixedMsg;
194+
// Add a link to the reference docs of func at the end of the message
195+
message = mapToReference(message, func);
168196
let style = [`color: ${color}`, 'font-family: Arial', 'font-size: larger'];
169-
if (func == null || func.substring(0, 4) === 'load') {
170-
prefixedMsg = translator('fes.pre', { message });
171-
} else {
172-
const methodParts = func.split('.');
173-
const referenceSection =
174-
methodParts.length > 1 ? `${methodParts[0]}.${methodParts[1]}` : 'p5';
175-
176-
const funcName =
177-
methodParts.length === 1 ? func : methodParts.slice(2).join('/');
197+
const prefixedMsg = translator('fes.pre', { message });
178198

179-
prefixedMsg = translator('fes.pre', {
180-
message: `${message} (http://p5js.org/reference/#/${referenceSection}/${funcName})`
181-
});
182-
}
183199
if (ENABLE_FES_STYLING) {
184200
log('%c' + prefixedMsg, style.join(';'));
185201
} else {
@@ -193,7 +209,7 @@ if (typeof IS_MINIFIED !== 'undefined') {
193209
* @method _friendlyError
194210
* @private
195211
* @param {Number} message message to be printed
196-
* @param {String} method name of method
212+
* @param {String} [method] name of method
197213
* @param {Number|String} [color] CSS color string or error type (Optional)
198214
*/
199215
p5._friendlyError = function(message, method, color) {
@@ -304,25 +320,27 @@ if (typeof IS_MINIFIED !== 'undefined') {
304320
defineMisusedAtTopLevelCode();
305321
}
306322

307-
let min = 999999,
308-
minIndex = 0;
323+
const distanceMap = {};
324+
let min = 999999;
309325
// compute the levenshtein distance for the symbol against all known
310326
// public p5 properties. Find the property with the minimum distance
311-
misusedAtTopLevelCode.forEach((symbol, idx) => {
327+
misusedAtTopLevelCode.forEach(symbol => {
312328
let dist = computeEditDistance(errSym, symbol.name);
313-
if (dist < min) {
314-
min = dist;
315-
minIndex = idx;
316-
}
329+
if (distanceMap[dist]) distanceMap[dist].push(symbol);
330+
else distanceMap[dist] = [symbol];
331+
332+
if (dist < min) min = dist;
317333
});
318334

335+
// if the closest match has more "distance" than the max allowed threshold
319336
if (min > Math.min(EDIT_DIST_THRESHOLD, errSym.length)) return false;
320337

321-
let symbol = misusedAtTopLevelCode[minIndex];
322-
323338
// Show a message only if the caught symbol and the matched property name
324339
// differ in their name ( either letter difference or difference of case )
325-
if (errSym !== symbol.name) {
340+
const matchedSymbols = distanceMap[min].filter(
341+
symbol => symbol.name !== errSym
342+
);
343+
if (matchedSymbols.length !== 0) {
326344
const parsed = p5._getErrorStackParser().parse(error);
327345
let locationObj;
328346
if (
@@ -336,18 +354,51 @@ if (typeof IS_MINIFIED !== 'undefined') {
336354
location: `${parsed[0].fileName}:${parsed[0].lineNumber}:${
337355
parsed[0].columnNumber
338356
}`,
339-
file: parsed[0].fileName,
357+
file: parsed[0].fileName.split('/').slice(-1),
340358
line: parsed[0].lineNumber
341359
};
342360
}
343-
const msg = translator('fes.misspelling', {
344-
name: errSym,
345-
actualName: symbol.name,
346-
type: symbol.type,
347-
location: locationObj ? translator('fes.location', locationObj) : ''
348-
});
349361

350-
p5._friendlyError(msg, symbol.name);
362+
let msg;
363+
if (matchedSymbols.length === 1) {
364+
// To be used when there is only one closest match. The count parameter
365+
// allows i18n to pick between the keys "fes.misspelling" and
366+
// "fes.misspelling__plural"
367+
msg = translator('fes.misspelling', {
368+
name: errSym,
369+
actualName: matchedSymbols[0].name,
370+
type: matchedSymbols[0].type,
371+
location: locationObj ? translator('fes.location', locationObj) : '',
372+
count: matchedSymbols.length
373+
});
374+
} else {
375+
// To be used when there are multiple closest matches. Gives each
376+
// suggestion on its own line, the function name followed by a link to
377+
// reference documentation
378+
const suggestions = matchedSymbols
379+
.map(symbol => {
380+
const message =
381+
'▶️ ' + symbol.name + (symbol.type === 'function' ? '()' : '');
382+
return mapToReference(message, symbol.name);
383+
})
384+
.join('\n');
385+
386+
msg = translator('fes.misspelling', {
387+
name: errSym,
388+
suggestions: suggestions,
389+
location: locationObj ? translator('fes.location', locationObj) : '',
390+
count: matchedSymbols.length
391+
});
392+
}
393+
394+
// If there is only one closest match, tell _friendlyError to also add
395+
// a link to the reference documentation. In case of multiple matches,
396+
// this is already done in the suggestions variable, one link for each
397+
// suggestion.
398+
p5._friendlyError(
399+
msg,
400+
matchedSymbols.length === 1 ? matchedSymbols[0].name : undefined
401+
);
351402
return true;
352403
}
353404
return false;

test/unit/core/error_helpers.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,24 +388,43 @@ suite('Error Helpers', function() {
388388
});
389389

390390
testUnMinified('detects capitalization mistakes', function() {
391+
const logMsg = help(new ReferenceError('MouseX is not defined'));
391392
assert.match(
392-
help(new ReferenceError('MouseX is not defined')),
393-
/It seems that you may have accidently written MouseX instead of mouseX/
393+
logMsg,
394+
/It seems that you may have accidently written "MouseX"/
394395
);
396+
assert.match(logMsg, /mouseX/);
395397
});
396398

397399
testUnMinified('detects spelling mistakes', function() {
400+
const logMsg = help(new ReferenceError('colour is not defined'));
398401
assert.match(
399-
help(new ReferenceError('colour is not defined')),
400-
/It seems that you may have accidently written colour instead of color/
402+
logMsg,
403+
/It seems that you may have accidently written "colour"/
401404
);
405+
assert.match(logMsg, /color/);
402406
});
403407

408+
testUnMinified(
409+
'can give more than one closest matches, if applicable',
410+
function() {
411+
const logMsg = help(new ReferenceError('strok is not defined'));
412+
assert.match(
413+
logMsg,
414+
/It seems that you may have accidently written "strok"/
415+
);
416+
assert.match(logMsg, /stroke/);
417+
assert.match(logMsg, /STROKE/);
418+
}
419+
);
420+
404421
testUnMinified('detects spelling + captialization mistakes', function() {
422+
const logMsg = help(new ReferenceError('RandomGossian is not defined'));
405423
assert.match(
406-
help(new ReferenceError('RandomGossian is not defined')),
407-
/It seems that you may have accidently written RandomGossian instead of randomGaussian/
424+
logMsg,
425+
/It seems that you may have accidently written "RandomGossian"/
408426
);
427+
assert.match(logMsg, /randomGaussian/);
409428
});
410429
});
411430

translations/en/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
},
3838
"libraryError": "An error with message \"{{error}}\" occured inside the p5js library when {{func}} was called {{location}}\n\nIf not stated otherwise, it might be an issue with the arguments passed to {{func}}.",
3939
"location": "(on line {{line}} in {{file}} [{{location}}])",
40-
"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",
40+
"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",
41+
"misspelling_plural": "It seems that you may have accidently written \"{{name}}\" {{location}}.\n\nYou may have meant one of the following:\n{{suggestions}}",
4142
"misusedTopLevel": "Did you just try to use p5.js's {{symbolName}} {{symbolType}}? If so, you may want to move it into your sketch's setup() function.\n\nFor more details, see: {{link}}",
4243
"positions": {
4344
"p_1": "first",

translations/es/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"libraryError": "",
3939
"location": "",
4040
"misspelling": "",
41+
"misspelling_plural": "",
4142
"misusedTopLevel": "",
4243
"positions": {
4344
"p_1": "",

0 commit comments

Comments
 (0)
X Tutup