(zodErrorObj, func, args)
| 390 | * @returns {String} The friendly error message. |
| 391 | */ |
| 392 | const friendlyParamError = function (zodErrorObj, func, args) { |
| 393 | let message = '🌸 p5.js says: '; |
| 394 | let isVersionError = false; |
| 395 | // The `zodErrorObj` might contain multiple errors of equal importance |
| 396 | // (after scoring the schema closeness in `findClosestSchema`). Here, we |
| 397 | // always print the first error so that user can work through the errors |
| 398 | // one by one. |
| 399 | let currentError = zodErrorObj.issues[0]; |
| 400 | |
| 401 | // Helper function to build a type mismatch message. |
| 402 | const buildTypeMismatchMessage = |
| 403 | (actualType, expectedTypeStr, position) => { |
| 404 | const positionStr = position ? `at the ${ordinals[position]} parameter` : ''; |
| 405 | const actualTypeStr = actualType ? `, but received ${actualType}` : ''; |
| 406 | return `Expected ${expectedTypeStr} ${positionStr}${actualTypeStr}`; |
| 407 | }; |
| 408 | |
| 409 | // Union errors occur when a parameter can be of multiple types but is not |
| 410 | // of any of them. In this case, aggregate all possible types and print |
| 411 | // a friendly error message that indicates what the expected types are at |
| 412 | // which position (position is not 0-indexed, for accessibility reasons). |
| 413 | |
| 414 | const processUnionError = error => { |
| 415 | const expectedTypes = new Set(); |
| 416 | let actualType; |
| 417 | |
| 418 | const collectIssue = issue => { |
| 419 | if (!issue) return; |
| 420 | if (!actualType) { |
| 421 | actualType = issue.message; |
| 422 | } |
| 423 | |
| 424 | if (issue.code === 'invalid_type') { |
| 425 | actualType = issue.message.split(', received ')[1]; |
| 426 | expectedTypes.add(issue.expected); |
| 427 | } |
| 428 | // The case for constants. Since we don't want to print out the actual |
| 429 | // constant values in the error message, the error message will |
| 430 | // direct users to the documentation. |
| 431 | else if (issue.code === 'invalid_value') { |
| 432 | if (Array.isArray(issue.values) && issue.values.every(v => v === Infinity || v === -Infinity)) { |
| 433 | expectedTypes.add('number'); |
| 434 | } else { |
| 435 | expectedTypes.add('constant (please refer to documentation for allowed values)'); |
| 436 | actualType = args[error.path[0]]; |
| 437 | } |
| 438 | } else if (issue.code === 'custom') { |
| 439 | const match = issue.message.match(/Input not instance of (\w+)/); |
| 440 | if (match) expectedTypes.add(match[1]); |
| 441 | actualType = undefined; |
| 442 | } else if (issue.code === 'invalid_union') { |
| 443 | issue.errors.forEach(nestedErr => { |
| 444 | nestedErr.forEach(nestedIssue => collectIssue(nestedIssue)); |
| 445 | }); |
| 446 | } |
| 447 | }; |
| 448 | |
| 449 | error.errors.forEach(err => { |
no test coverage detected