Skip to content

Commit

Permalink
add documentation link in error message for cases where the user prov…
Browse files Browse the repository at this point in the history
…ided too few/too many arguments
  • Loading branch information
sproutleaf committed Sep 27, 2024
1 parent b6e4366 commit 3eef4cb
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 11 deletions.
36 changes: 28 additions & 8 deletions src/core/friendly_errors/param_validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ function validateParams(p5, fn) {
// "first" for 0, "second" for 1, "third" for 2, etc.
const ordinals = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"];

function extractFuncNameAndClass(func) {
const ichDot = func.lastIndexOf('.');
const funcName = func.slice(ichDot + 1);
const funcClass = func.slice(0, ichDot !== -1 ? ichDot : 0) || 'p5';
return { funcName, funcClass };
}

/**
* This is a helper function that generates Zod schemas for a function based on
* the parameter data from `docs/parameterData.json`.
Expand All @@ -105,7 +112,7 @@ function validateParams(p5, fn) {
* Where each array in `overloads` represents a set of valid overloaded
* parameters, and `?` is a shorthand for `Optional`.
*
* @param {String} func - Name of the function.
* @param {String} func - Name of the function. Expect global functions like `sin` and class methods like `p5.Vector.add`
* @returns {z.ZodSchema} Zod schema
*/
function generateZodSchemasForFunc(func) {
Expand All @@ -121,11 +128,7 @@ function validateParams(p5, fn) {
]);
}

// Expect global functions like `sin` and class methods like `p5.Vector.add`
const ichDot = func.lastIndexOf('.');
const funcName = func.slice(ichDot + 1);
const funcClass = func.slice(0, ichDot !== -1 ? ichDot : 0) || 'p5';

const { funcName, funcClass } = extractFuncNameAndClass(func);
let funcInfo = dataDoc[funcClass][funcName];

let overloads = [];
Expand Down Expand Up @@ -322,9 +325,10 @@ function validateParams(p5, fn) {
* @method _friendlyParamError
* @private
* @param {z.ZodError} zodErrorObj - The Zod error object containing validation errors.
* @param {String} func - Name of the function. Expect global functions like `sin` and class methods like `p5.Vector.add`
* @returns {String} The friendly error message.
*/
p5._friendlyParamError = function (zodErrorObj) {
p5._friendlyParamError = function (zodErrorObj, func) {
let message;
// The `zodErrorObj` might contain multiple errors of equal importance
// (after scoring the schema closeness in `findClosestSchema`). Here, we
Expand Down Expand Up @@ -403,6 +407,22 @@ function validateParams(p5, fn) {
}
}

// Generates a link to the documentation based on the given function name.
// TODO: Check if the link is reachable before appending it to the error
// message.
const generateDocumentationLink = (func) => {
const { funcName, funcClass } = extractFuncNameAndClass(func);
const p5BaseUrl = 'https://p5js.org/reference';
const url = `${p5BaseUrl}/${funcClass}/${funcName}`;

return url;
}

if (currentError.code === 'too_big' || currentError.code === 'too_small') {
const documentationLink = generateDocumentationLink(func);
message += ` For more information, see ${documentationLink}.`;
}

return message;
}

Expand Down Expand Up @@ -449,7 +469,7 @@ function validateParams(p5, fn) {
} catch (error) {
const closestSchema = findClosestSchema(funcSchemas, args);
const zodError = closestSchema.safeParse(args).error;
const errorMessage = p5._friendlyParamError(zodError);
const errorMessage = p5._friendlyParamError(zodError, func);

return {
success: false,
Expand Down
6 changes: 3 additions & 3 deletions test/unit/core/param_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ suite('Validate Params', function () {
});

const invalidInputs = [
{ name: 'missing required arc parameters #4, #5', input: [200, 100, 100, 80], msg: 'Expected at least 6 arguments, but received fewer. Please add more arguments!' },
{ name: 'missing required arc parameters #4, #5', input: [200, 100, 100, 80], msg: 'Expected at least 6 arguments, but received fewer. Please add more arguments! For more information, see https://p5js.org/reference/p5/arc.' },
{ name: 'missing required param #0', input: [undefined, 100, 100, 80, 0, Math.PI, constants.PIE, 30], msg: 'Expected number at the first parameter, but received undefined.' },
{ name: 'missing required param #4', input: [200, 100, 100, 80, undefined, 0], msg: 'Expected number at the fifth parameter, but received undefined.' },
{ name: 'missing optional param #5', input: [200, 100, 100, 80, 0, undefined, Math.PI], msg: 'Expected number at the sixth parameter, but received undefined.' },
Expand Down Expand Up @@ -116,7 +116,7 @@ suite('Validate Params', function () {
{ fn: 'color', name: 'superfluous parameter', input: [[0, 0, 0], 0], msg: 'Expected number at the first parameter, but received array.' },
{ fn: 'color', name: 'wrong element types', input: [['A', 'B', 'C']], msg: 'Expected number at the first parameter, but received array.' },
{ fn: 'rect', name: 'null, non-trailing, optional parameter', input: [0, 0, 0, 0, null, 0, 0, 0], msg: 'Expected number at the fifth parameter, but received null.' },
{ fn: 'color', name: 'too many args + wrong types too', input: ['A', 'A', 0, 0, 0, 0, 0, 0, 0, 0], msg: 'Expected at most 4 arguments, but received more. Please delete some arguments!' },
{ fn: 'color', name: 'too many args + wrong types too', input: ['A', 'A', 0, 0, 0, 0, 0, 0, 0, 0], msg: 'Expected at most 4 arguments, but received more. Please delete some arguments! For more information, see https://p5js.org/reference/p5/color.' },
{ fn: 'line', name: 'null string given', input: [1, 2, 4, 'null'], msg: 'Expected number at the fourth parameter, but received string.' },
{ fn: 'line', name: 'NaN value given', input: [1, 2, 4, NaN], msg: 'Expected number at the fourth parameter, but received nan.' }
];
Expand Down Expand Up @@ -164,7 +164,7 @@ suite('Validate Params', function () {
{ name: 'optional parameter, incorrect type', input: [65, 100, 100, 'a'], msg: 'Expected number at the fourth parameter, but received string.' },
{ name: 'extra parameter', input: [[65, 100, 100], 100], msg: 'Expected number at the first parameter, but received array.' },
{ name: 'incorrect element type', input: ['A', 'B', 'C'], msg: 'Expected number at the first parameter, but received string.' },
{ name: 'incorrect parameter count', input: ['A', 'A', 0, 0, 0, 0, 0, 0], msg: 'Expected at most 4 arguments, but received more. Please delete some arguments!' }
{ name: 'incorrect parameter count', input: ['A', 'A', 0, 0, 0, 0, 0, 0], msg: 'Expected at most 4 arguments, but received more. Please delete some arguments! For more information, see https://p5js.org/reference/p5/color.' }
];

invalidInputs.forEach(({ name, input, msg }) => {
Expand Down

0 comments on commit 3eef4cb

Please sign in to comment.