From 6cb40a5d5b4ec1c04c5eb2fc5d9b5670e030c732 Mon Sep 17 00:00:00 2001 From: Spongman Date: Tue, 24 Oct 2017 11:52:48 -0700 Subject: [PATCH 01/14] more thorough parameter validation # Conflicts: # src/core/error_helpers.js # src/webgl/p5.Matrix.js # src/webgl/p5.RendererGL.js --- lib/addons/p5.dom.js | 18 +++- src/color/creating_reading.js | 28 +++-- src/color/setting.js | 1 + src/core/attributes.js | 5 + src/core/curves.js | 3 + src/core/environment.js | 3 + src/core/error_helpers.js | 166 +++++++++++++++++++----------- src/core/rendering.js | 4 + src/core/transform.js | 12 ++- src/core/vertex.js | 4 + src/events/keyboard.js | 1 + src/image/image.js | 3 + src/image/loading_displaying.js | 5 + src/image/p5.Image.js | 2 +- src/image/pixels.js | 5 +- src/math/calculation.js | 8 +- src/math/p5.Vector.js | 8 +- src/utilities/string_functions.js | 8 +- src/webgl/material.js | 4 +- src/webgl/p5.Matrix.js | 14 +-- src/webgl/p5.RendererGL.js | 8 +- 21 files changed, 211 insertions(+), 99 deletions(-) diff --git a/lib/addons/p5.dom.js b/lib/addons/p5.dom.js index 04d7bded1a..05610c96eb 100644 --- a/lib/addons/p5.dom.js +++ b/lib/addons/p5.dom.js @@ -69,6 +69,7 @@ * */ p5.prototype.select = function (e, p) { + p5._validateParameters('select', arguments); var res = null; var container = getContainer(p); if (e[0] === '.'){ @@ -135,6 +136,7 @@ * */ p5.prototype.selectAll = function (e, p) { + p5._validateParameters('selectAll', arguments); var arr = []; var res; var container = getContainer(p); @@ -215,6 +217,7 @@ * */ p5.prototype.removeElements = function (e) { + p5._validateParameters('removeElements', arguments); for (var i=0; i */ p5.prototype.createImg = function() { + p5._validateParameters('createImg', arguments); var elt = document.createElement('img'); var args = arguments; var self; @@ -359,6 +363,7 @@ * */ p5.prototype.createA = function(href, html, target) { + p5._validateParameters('createA', arguments); var elt = document.createElement('a'); elt.href = href; elt.innerHTML = html; @@ -412,6 +417,7 @@ * */ p5.prototype.createSlider = function(min, max, value, step) { + p5._validateParameters('createSlider', arguments); var elt = document.createElement('input'); elt.type = 'range'; elt.min = min; @@ -454,6 +460,7 @@ * */ p5.prototype.createButton = function(label, value) { + p5._validateParameters('createButton', arguments); var elt = document.createElement('button'); elt.innerHTML = label; if (value) elt.value = value; @@ -487,6 +494,7 @@ * */ p5.prototype.createCheckbox = function() { + p5._validateParameters('createCheckbox', arguments); var elt = document.createElement('div'); var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; @@ -560,6 +568,7 @@ */ p5.prototype.createSelect = function() { + p5._validateParameters('createSelect', arguments); var elt, self; var arg = arguments[0]; if( typeof arg === 'object' && arg.elt.nodeName === 'SELECT' ) { @@ -680,6 +689,7 @@ * */ p5.prototype.createRadio = function() { + p5._validateParameters('createRadio', arguments); var radios = document.querySelectorAll("input[type=radio]"); var count = 0; if(radios.length > 1){ @@ -780,6 +790,7 @@ * */ p5.prototype.createInput = function(value, type) { + p5._validateParameters('createInput', arguments); var elt = document.createElement('input'); elt.type = type ? type : 'text'; if (value) elt.value = value; @@ -818,7 +829,8 @@ * } */ p5.prototype.createFileInput = function(callback, multiple) { - + p5._validateParameters('createFileInput', arguments); + // Is the file stuff supported? if (window.File && window.FileReader && window.FileList && window.Blob) { // Yup, we're ok and make an input file selector @@ -931,6 +943,7 @@ * @return {p5.MediaElement|p5.Element} pointer to video p5.Element */ p5.prototype.createVideo = function(src, callback) { + p5._validateParameters('createVideo', arguments); return createMedia(this, 'video', src, callback); }; @@ -958,6 +971,7 @@ * @return {p5.MediaElement|p5.Element} pointer to audio p5.Element */ p5.prototype.createAudio = function(src, callback) { + p5._validateParameters('createAudio', arguments); return createMedia(this, 'audio', src, callback); }; @@ -1051,6 +1065,7 @@ * */ p5.prototype.createCapture = function() { + p5._validateParameters('createCapture', arguments); var useVideo = true; var useAudio = true; var constraints; @@ -1123,6 +1138,7 @@ * */ p5.prototype.createElement = function(tag, content) { + p5._validateParameters('createElement', arguments); var elt = document.createElement(tag); if (typeof content !== 'undefined') { elt.innerHTML = content; diff --git a/src/color/creating_reading.js b/src/color/creating_reading.js index d3ba2854f6..ef5e64f9f8 100644 --- a/src/color/creating_reading.js +++ b/src/color/creating_reading.js @@ -17,7 +17,8 @@ require('../core/error_helpers'); * Extracts the alpha value from a color or pixel array. * * @method alpha - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the alpha value * @example *
@@ -61,7 +62,8 @@ p5.prototype.alpha = function(c) { * Extracts the blue value from a color or pixel array. * * @method blue - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the blue value * @example *
@@ -90,7 +92,8 @@ p5.prototype.blue = function(c) { * Extracts the HSB brightness value from a color or pixel array. * * @method brightness - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the brightness value * @example *
@@ -294,7 +297,7 @@ p5.prototype.brightness = function(c) { */ /** * @method color - * @param {Array} values an array containing the red,green,blue & + * @param {Number[]} values an array containing the red,green,blue & * and alpha components of the color * @return {p5.Color} */ @@ -305,6 +308,7 @@ p5.prototype.brightness = function(c) { */ p5.prototype.color = function() { + p5._validateParameters('color', arguments); if (arguments[0] instanceof p5.Color) { return arguments[0]; // Do nothing if argument is already a color object. } else if (arguments[0] instanceof Array) { @@ -314,7 +318,6 @@ p5.prototype.color = function() { return new p5.Color(this._renderer, arguments[0]); } } else { - p5._validateParameters('color', arguments); if (this instanceof p5.Renderer) { return new p5.Color(this, arguments); } else { @@ -327,7 +330,8 @@ p5.prototype.color = function() { * Extracts the green value from a color or pixel array. * * @method green - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the green value * @example *
@@ -363,7 +367,8 @@ p5.prototype.green = function(c) { * maximum hue setting for each system is different.) * * @method hue - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the hue * @example *
@@ -490,7 +495,8 @@ p5.prototype.lerpColor = function(c1, c2, amt) { * Extracts the HSL lightness value from a color or pixel array. * * @method lightness - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the lightness * @example *
@@ -519,7 +525,8 @@ p5.prototype.lightness = function(c) { * Extracts the red value from a color or pixel array. * * @method red - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the red value * @example *
@@ -563,7 +570,8 @@ p5.prototype.red = function(c) { * HSL saturation otherwise. * * @method saturation - * @param {p5.Color|Array} color p5.Color object or pixel array + * @param {p5.Color|Number[]|String} color p5.Color object, color components, + * or CSS color * @return {Number} the saturation value * @example *
diff --git a/src/color/setting.js b/src/color/setting.js index 0eb1739995..6a1c9565c9 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -303,6 +303,7 @@ p5.prototype.clear = function() { * */ p5.prototype.colorMode = function() { + p5._validateParameters('colorMode', arguments); if (arguments[0] === constants.RGB || arguments[0] === constants.HSB || arguments[0] === constants.HSL) { diff --git a/src/core/attributes.js b/src/core/attributes.js index 0d9830a590..71e43ccaa8 100644 --- a/src/core/attributes.js +++ b/src/core/attributes.js @@ -68,6 +68,7 @@ var constants = require('./constants'); * */ p5.prototype.ellipseMode = function(m) { + p5._validateParameters('ellipseMode', arguments); if (m === constants.CORNER || m === constants.CORNERS || m === constants.RADIUS || @@ -162,6 +163,7 @@ p5.prototype.noSmooth = function() { * */ p5.prototype.rectMode = function(m) { + p5._validateParameters('rectMode', arguments); if (m === constants.CORNER || m === constants.CORNERS || m === constants.RADIUS || @@ -226,6 +228,7 @@ p5.prototype.smooth = function() { * */ p5.prototype.strokeCap = function(cap) { + p5._validateParameters('strokeCap', arguments); if (cap === constants.ROUND || cap === constants.SQUARE || cap === constants.PROJECT) { @@ -290,6 +293,7 @@ p5.prototype.strokeCap = function(cap) { * */ p5.prototype.strokeJoin = function(join) { + p5._validateParameters('strokeJoin', arguments); if (join === constants.ROUND || join === constants.BEVEL || join === constants.MITER) { @@ -322,6 +326,7 @@ p5.prototype.strokeJoin = function(join) { * */ p5.prototype.strokeWeight = function(w) { + p5._validateParameters('strokeWeight', arguments); this._renderer.strokeWeight(w); return this; }; diff --git a/src/core/curves.js b/src/core/curves.js index 190d708c1b..5b4ad8f76e 100644 --- a/src/core/curves.js +++ b/src/core/curves.js @@ -117,6 +117,7 @@ p5.prototype.bezier = function() { * */ p5.prototype.bezierDetail = function(d) { + p5._validateParameters('bezierDetail', arguments); bezierDetail = d; return this; }; @@ -371,6 +372,7 @@ p5.prototype.curve = function() { * */ p5.prototype.curveDetail = function(d) { + p5._validateParameters('curveDetail', arguments); curveDetail = d; return this; }; @@ -417,6 +419,7 @@ p5.prototype.curveDetail = function(d) { * Line shaped like right-facing arrow,points move with mouse-x and warp shape. */ p5.prototype.curveTightness = function (t) { + p5._validateParameters('curveTightness', arguments); this._renderer._curveTightness = t; }; diff --git a/src/core/environment.js b/src/core/environment.js index 5bb3ffa885..1cb52d2f37 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -227,6 +227,7 @@ p5.prototype.cursor = function(type, x, y) { * */ p5.prototype.frameRate = function(fps) { + p5._validateParameters('frameRate', arguments); if (typeof fps !== 'number' || fps < 0) { return this._frameRate; } else { @@ -457,6 +458,7 @@ p5.prototype.height = 0; * */ p5.prototype.fullscreen = function(val) { + p5._validateParameters('fullscreen', arguments); // no arguments, return fullscreen or not if (typeof val === 'undefined') { return document.fullscreenElement || @@ -509,6 +511,7 @@ p5.prototype.fullscreen = function(val) { * sharp 50x50 white ellipse with black outline in center of canvas. */ p5.prototype.pixelDensity = function(val) { + p5._validateParameters('pixelDensity', arguments); if (typeof val === 'number') { this._pixelDensity = val; } else { diff --git a/src/core/error_helpers.js b/src/core/error_helpers.js index bee8947e96..ad04b2fc8e 100644 --- a/src/core/error_helpers.js +++ b/src/core/error_helpers.js @@ -6,6 +6,16 @@ 'use strict'; var p5 = require('./core'); + +/* +if (typeof IS_MINIFIED !== 'undefined') { + + p5._validateParameters = + p5._friendlyFileLoadError = + function () { }; + +} else */{ + var doFriendlyWelcome = false; // TEMP until we get it all working LM // for parameter validation var dataDoc = require('../../docs/reference/data.json'); @@ -103,6 +113,7 @@ p5._friendlyFileLoadError = function (errorType, filePath) { report(message, errorInfo.method, FILE_LOAD); }; + var docCache = {}; /** * Validates parameters * param {String} func the name of the function @@ -125,10 +136,10 @@ p5._validateParameters = function validateParameters(func, args) { typeof(IS_MINIFIED) !== 'undefined') { return; // skip FES } - var arrDoc = lookupParamDoc(func); + try { + var arrDoc = docCache[func] || (docCache[func] = lookupParamDoc(func)); var errorArray = []; var minErrCount = 999999; - if (arrDoc.length > 1){ // func has multiple formats for (var i = 0; i < arrDoc.length; i++) { var arrError = testParamFormat(args, arrDoc[i]); if( arrError.length === 0) { @@ -144,11 +155,9 @@ p5._validateParameters = function validateParameters(func, args) { for (var n = 0; n < errorArray.length; n++) { p5._friendlyParamError(errorArray[n], func); } - } else { // func has a single format - errorArray = testParamFormat(args, arrDoc[0]); - for(var m = 0; m < errorArray.length; m++) { - p5._friendlyParamError(errorArray[m], func); } + catch (err) { + console.log('validation error: ' + err); } }; // validateParameters() helper functions: @@ -157,93 +166,130 @@ function lookupParamDoc(func){ var queryResult = arrDoc.classitems. filter(function (x) { return x.name === func; }); // different JSON structure for funct with multi-format - if (queryResult[0].hasOwnProperty('overloads')){ var res = []; + if (queryResult[0].hasOwnProperty('overloads')){ for(var i = 0; i < queryResult[0].overloads.length; i++) { res.push(queryResult[0].overloads[i].params); } - return res; } else { - return [queryResult[0].params]; + res.push(queryResult[0].params); } + var builtinTypes = [ + 'number', 'string', 'boolean', + 'constant', 'function', 'integer' + ]; + res.forEach(function (formats) { + formats.forEach(function (format) { + format.types = format.type.split('|').map(function ct(type) { + + if (type.substr(type.length - 2, 2) === '[]') { + return { + name: type, + array: ct(type.substr(0, type.length - 2)) + }; } -function testParamFormat(args, format){ - var errorArray = []; - var error; - for (var p = 0; p < format.length; p++) { - var argType = typeof(args[p]); - if ('undefined' === argType || null === argType) { - if (format[p].optional !== true) { - error = {type:'EMPTY_VAR', position: p}; - errorArray.push(error); + + var lowerType = type.toLowerCase(); + if (lowerType.substr(0, 'function'.length) === 'function') { + lowerType = 'function'; } - } else { - var types = format[p].type.split('|'); // case accepting multi-types - if (argType === 'object'){ // if object, test for class - if (!testParamClass(args[p], types)) { // if fails to pass - error = {type:'WRONG_CLASS', position: p, - correctClass: types[p], wrongClass: args[p].name}; - errorArray.push(error); + if (builtinTypes.indexOf(lowerType) >= 0) { + return { name: type, builtin: lowerType }; } - }else{ // not object, test for type - if (!testParamType(args[p], types)) { // if fails to pass - error = {type:'WRONG_TYPE', position: p, - correctType: types[p], wrongType: argType}; - errorArray.push(error); + + var t = window; + type.split('.').forEach(function (p) { t = t && t[p]; }); + if (t) { + return { name: type, prototype: t }; } + + return { name: type, type: lowerType }; + }); + }); + }); + return res; } + function testParamFormat(args, formats) { + var errorArray = []; + for (var p = 0; p < formats.length; p++) { + var arg = args[p]; + var format = formats[p]; + var argType = typeof (arg); + if ('undefined' === argType || null === arg) { + if (format.optional !== true) { + errorArray.push({ + type: 'EMPTY_VAR', + position: p, + correctType: format.type, + }); } + } else if (!testParamTypes(arg, format.types)) { + errorArray.push({ + type: 'WRONG_TYPE', + position: p, + correctType: format.type, + wrongType: arg instanceof Array ? 'array' : arg.name || argType + }); } + } return errorArray; } -// testClass() for object type parameter validation + // testType() for non-object type parameter validation // Returns true if PASS, false if FAIL -function testParamClass(param, types){ + function testParamTypes(param, types) { for (var i = 0; i < types.length; i++) { - if (types[i] === 'Array') { - if(param instanceof Array) { + if (testParamType(param, types[i])) { return true; } - } else { - if (param.name === types[i]) { - return true; // class name match, pass - } else if (types[i] === 'Constant') { - return true; // accepts any constant, pass } + return false; } - } + function testParamType(param, type) { + var isArray = param instanceof Array; + if (type.array && isArray) { + for (var i = 0; i < param.length; i++) { + if (!testParamType(param[i], type.array)) { return false; } -// testType() for non-object type parameter validation -// Returns true if PASS, false if FAIL -function testParamType(param, types){ - for (var i = 0; i < types.length; i++) { - if (typeof(param) === types[i].toLowerCase()) { - return true; // type match, pass - } else if (types[i] === 'Constant') { - return true; // accepts any constant, pass } + return true; } - return false; + else if (type.prototype) { + return param instanceof type.prototype; } + else if (type.builtin) { + switch (type.builtin) { + case 'number': + return (typeof param === 'number' || !!param && !isNaN(param)); + case 'integer': + return (typeof param === 'number' || !!param && !isNaN(param)) && + Number(param) === Math.floor(param); + case 'boolean': + return true; + case 'array': + return isArray; + case 'string': + case 'constant': + return typeof param === 'number' || + typeof param === 'string'; + case 'function': + return param instanceof Function; + } + } + + return typeof param === type.t; + } // function for generating console.log() msg p5._friendlyParamError = function (errorObj, func) { var message; switch (errorObj.type){ case 'EMPTY_VAR': - message = 'It looks like ' + func + - '() received an empty variable in spot #' + errorObj.position + - ' (zero-based index). If not intentional, this is often a problem' + + message = func + '() was expecting ' + errorObj.correctType + + ' for parameter #' + errorObj.position + ' (zero-based index), received' + + ' an empty variable instead. If not intentional, this is often a problem' + ' with scope: [https://p5js.org/examples/data-variable-scope.html].'; report(message, func, ERR_PARAMS); break; - case 'WRONG_CLASS': - message = func + '() was expecting ' + errorObj.correctClass + - ' for parameter #' + errorObj.position + ' (zero-based index), received '; - // Wrap strings in quotes - message += 'an object with name '+ errorObj.wrongClass +' instead.'; - report(message, func, ERR_PARAMS); - break; case 'WRONG_TYPE': message = func + '() was expecting ' + errorObj.correctType + ' for parameter #' + errorObj.position + ' (zero-based index), received '; @@ -411,4 +457,6 @@ if (document.readyState !== 'complete') { }); } +} + module.exports = p5; diff --git a/src/core/rendering.js b/src/core/rendering.js index cb2a9102e4..b7fc3c6480 100644 --- a/src/core/rendering.js +++ b/src/core/rendering.js @@ -48,6 +48,7 @@ var defaultId = 'defaultCanvas0'; // this gets set again in createCanvas */ p5.prototype.createCanvas = function(w, h, renderer) { + p5._validateParameters('createCanvas', arguments); //optional: renderer, otherwise defaults to p2d var r = renderer || constants.P2D; var c; @@ -137,6 +138,7 @@ p5.prototype.createCanvas = function(w, h, renderer) { * */ p5.prototype.resizeCanvas = function (w, h, noRedraw) { + p5._validateParameters('resizeCanvas', arguments); if (this._renderer) { // save canvas properties @@ -217,6 +219,7 @@ p5.prototype.noCanvas = function() { * */ p5.prototype.createGraphics = function(w, h, renderer){ + p5._validateParameters('createGraphics', arguments); return new p5.Graphics(w, h, renderer, this); }; @@ -286,6 +289,7 @@ p5.prototype.createGraphics = function(w, h, renderer){ * */ p5.prototype.blendMode = function(mode) { + p5._validateParameters('blendMode', arguments); if (mode === constants.BLEND || mode === constants.DARKEST || mode === constants.LIGHTEST || mode === constants.DIFFERENCE || mode === constants.MULTIPLY || mode === constants.EXCLUSION || diff --git a/src/core/transform.js b/src/core/transform.js index a0f9828434..1c3129b3bb 100644 --- a/src/core/transform.js +++ b/src/core/transform.js @@ -179,7 +179,7 @@ p5.prototype.resetMatrix = function() { * @method rotate * @param {Number} angle the angle of rotation, specified in radians * or degrees, depending on current angleMode - * @param {p5.Vector|Array} [axis] (in 3d) the axis to rotate around + * @param {p5.Vector|Number[]} [axis] (in 3d) the axis to rotate around * @chainable * @example *
@@ -195,6 +195,7 @@ p5.prototype.resetMatrix = function() { * */ p5.prototype.rotate = function(angle, axis) { + p5._validateParameters('rotate', arguments); var args = new Array(arguments.length); var r; for (var i = 0; i < args.length; ++i) { @@ -222,6 +223,7 @@ p5.prototype.rotate = function(angle, axis) { * @chainable */ p5.prototype.rotateX = function(rad) { + p5._validateParameters('rotateX', arguments); if (this._renderer.isP3D) { this._renderer.rotateX(rad); } else { @@ -237,6 +239,7 @@ p5.prototype.rotateX = function(rad) { * @chainable */ p5.prototype.rotateY = function(rad) { + p5._validateParameters('rotateY', arguments); if (this._renderer.isP3D) { this._renderer.rotateY(rad); } else { @@ -252,6 +255,7 @@ p5.prototype.rotateY = function(rad) { * @chainable */ p5.prototype.rotateZ = function(rad) { + p5._validateParameters('rotateZ', arguments); if (this._renderer.isP3D) { this._renderer.rotateZ(rad); } else { @@ -276,7 +280,7 @@ p5.prototype.rotateZ = function(rad) { * This function can be further controlled with push() and pop(). * * @method scale - * @param {Number|p5.Vector|Array} s + * @param {Number|p5.Vector|Number[]} s * percent to scale the object, or percentage to * scale the object in the x-axis if multiple arguments * are given @@ -306,6 +310,7 @@ p5.prototype.rotateZ = function(rad) { * */ p5.prototype.scale = function() { + p5._validateParameters('scale', arguments); var x,y,z; var args = new Array(arguments.length); for(var i = 0; i < args.length; i++) { @@ -376,6 +381,7 @@ p5.prototype.scale = function() { * */ p5.prototype.shearX = function(angle) { + p5._validateParameters('shearX', arguments); if (this._angleMode === constants.DEGREES) { angle = this.radians(angle); } @@ -417,6 +423,7 @@ p5.prototype.shearX = function(angle) { * */ p5.prototype.shearY = function(angle) { + p5._validateParameters('shearY', arguments); if (this._angleMode === constants.DEGREES) { angle = this.radians(angle); } @@ -465,6 +472,7 @@ p5.prototype.shearY = function(angle) { * */ p5.prototype.translate = function(x, y, z) { + p5._validateParameters('translate', arguments); if (this._renderer.isP3D) { this._renderer.translate(x, y, z); } else { diff --git a/src/core/vertex.js b/src/core/vertex.js index d7f50c5462..009c1d803a 100644 --- a/src/core/vertex.js +++ b/src/core/vertex.js @@ -244,6 +244,7 @@ p5.prototype.beginContour = function() { * */ p5.prototype.beginShape = function(kind) { + p5._validateParameters('beginShape', arguments); if (kind === constants.POINTS || kind === constants.LINES || kind === constants.TRIANGLES || @@ -311,6 +312,7 @@ p5.prototype.beginShape = function(kind) { * */ p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) { + p5._validateParameters('bezierVertex', arguments); if (vertices.length === 0) { throw 'vertex() must be used once before calling bezierVertex()'; } else { @@ -366,6 +368,7 @@ p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) { * */ p5.prototype.curveVertex = function(x,y) { + p5._validateParameters('curveVertex', arguments); isCurve = true; this.vertex(x, y); return this; @@ -545,6 +548,7 @@ p5.prototype.endShape = function(mode) { * */ p5.prototype.quadraticVertex = function(cx, cy, x3, y3) { + p5._validateParameters('quadraticVertex', arguments); //if we're drawing a contour, put the points into an // array for inside drawing if(this._contourInited) { diff --git a/src/events/keyboard.js b/src/events/keyboard.js index 398ec55239..3916ed85d1 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -358,6 +358,7 @@ p5.prototype._onblur = function (e) { * */ p5.prototype.keyIsDown = function(code) { + p5._validateParameters('keyIsDown', arguments); return downKeys[code]; }; diff --git a/src/image/image.js b/src/image/image.js index 70e561f6ae..5afcfc2bfc 100644 --- a/src/image/image.js +++ b/src/image/image.js @@ -97,6 +97,7 @@ var frames = []; * */ p5.prototype.createImage = function(width, height) { + p5._validateParameters('createImage', arguments); return new p5.Image(width, height); }; @@ -151,6 +152,7 @@ p5.prototype.createImage = function(width, height) { * */ p5.prototype.saveCanvas = function() { + p5._validateParameters('saveCanvas', arguments); var cnv, filename, extension; if (arguments.length === 3) { @@ -274,6 +276,7 @@ p5.prototype.saveCanvas = function() { * */ p5.prototype.saveFrames = function(fName, ext, _duration, _fps, callback) { + p5._validateParameters('saveFrames', arguments); var duration = _duration || 3; duration = p5.prototype.constrain(duration, 0, 15); duration = duration * 1000; diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 694ccda295..dc17ec4a79 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -64,6 +64,7 @@ require('../core/error_helpers'); * */ p5.prototype.loadImage = function(path, successCallback, failureCallback) { + p5._validateParameters('loadImage', arguments); var img = new Image(); var pImg = new p5.Image(1, 1, this); @@ -233,6 +234,8 @@ p5.prototype.image = function(img, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight) { // set defaults per spec: https://goo.gl/3ykfOq + p5._validateParameters('image', arguments); + var defW = img.width; var defH = img.height; @@ -377,6 +380,7 @@ p5.prototype.image = * */ p5.prototype.tint = function () { + p5._validateParameters('tint', arguments); var c = this.color.apply(this, arguments); this._renderer._tint = c.levels; }; @@ -512,6 +516,7 @@ p5.prototype._getTintedImageCanvas = function(img) { * */ p5.prototype.imageMode = function(m) { + p5._validateParameters('imageMode', arguments); if (m === constants.CORNER || m === constants.CORNERS || m === constants.CENTER) { diff --git a/src/image/p5.Image.js b/src/image/p5.Image.js index ac8309bbb8..bbe98e6bd9 100644 --- a/src/image/p5.Image.js +++ b/src/image/p5.Image.js @@ -323,7 +323,7 @@ p5.Image.prototype.get = function(x, y, w, h){ * @method set * @param {Number} x x-coordinate of the pixel * @param {Number} y y-coordinate of the pixel - * @param {Number|Array|Object} a grayscale value | pixel array | + * @param {Number|Number[]|Object} a grayscale value | pixel array | * a p5.Color | image to copy * @example *
diff --git a/src/image/pixels.js b/src/image/pixels.js index 0c538b759b..f16c667bbb 100644 --- a/src/image/pixels.js +++ b/src/image/pixels.js @@ -171,7 +171,7 @@ p5.prototype.blend = function() { * target region. * * @method copy - * @param {p5.Image|undefined} srcImage source image + * @param {p5.Image|p5.Graphics|undefined} srcImage source image * @param {Integer} sx X coordinate of the source's upper left corner * @param {Integer} sy Y coordinate of the source's upper left corner * @param {Integer} sw source image width @@ -206,6 +206,7 @@ p5.prototype.blend = function() { * */ p5.prototype.copy = function () { + p5._validateParameters('copy', arguments); p5.Renderer2D._copyHelper.apply(this, arguments); }; @@ -519,7 +520,7 @@ p5.prototype.loadPixels = function() { * @method set * @param {Number} x x-coordinate of the pixel * @param {Number} y y-coordinate of the pixel - * @param {Number|Array|Object} c insert a grayscale value | a pixel array | + * @param {Number|Number[]|Object} c insert a grayscale value | a pixel array | * a p5.Color object | a p5.Image to copy * @example *
diff --git a/src/math/calculation.js b/src/math/calculation.js index 91aa6f128f..df71edcd31 100644 --- a/src/math/calculation.js +++ b/src/math/calculation.js @@ -467,8 +467,8 @@ p5.prototype.map = function (n, start1, stop1, start2, stop2, withinBounds) { * of any length. * * @method max - * @param {Number|Array} n0 Numbers to compare - * @return {Number} maximum Number + * @param {Number|Number[]} n0 Numbers to compare + * @return {Number} maximum Number * @example *
* function setup() { @@ -510,8 +510,8 @@ p5.prototype.max = function() { * of any length. * * @method min - * @param {Number|Array} n0 Numbers to compare - * @return {Number} minimum Number + * @param {Number|Number[]} n0 Numbers to compare + * @return {Number} minimum Number * @example *
* function setup() { diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index 6f6d90eb09..e090a3060c 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -106,7 +106,7 @@ p5.Vector.prototype.toString = function p5VectorToString() { * Sets the x, y, and z component of the vector using two or three separate * variables, the data from a p5.Vector, or the values from a float array. * @method set - * @param {Number|p5.Vector|Array} [x] the x component of the vector or a + * @param {Number|p5.Vector|Number[]} [x] the x component of the vector or a * p5.Vector or an Array * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector @@ -174,7 +174,7 @@ p5.Vector.prototype.copy = function () { * acts directly on the vector. See the examples for more context. * * @method add - * @param {Number|p5.Vector|Array} x the x component of the vector to be + * @param {Number|p5.Vector|Number[]} x the x component of the vector to be * added or a p5.Vector or an Array * @param {Number} [y] the y component of the vector to be * added @@ -226,7 +226,7 @@ p5.Vector.prototype.add = function (x, y, z) { * other acts directly on the vector. See the examples for more context. * * @method sub - * @param {Number|p5.Vector|Array} x the x component of the vector or a + * @param {Number|p5.Vector|Number[]} x the x component of the vector or a * p5.Vector or an Array * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector @@ -731,7 +731,7 @@ p5.Vector.prototype.array = function () { * Equality check against a p5.Vector * * @method equals - * @param {Number|p5.Vector|Array} [x] the x component of the vector or a + * @param {Number|p5.Vector|Number[]} [x] the x component of the vector or a * p5.Vector or an Array * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector diff --git a/src/utilities/string_functions.js b/src/utilities/string_functions.js index 61c83ac50a..ae8c28ef14 100644 --- a/src/utilities/string_functions.js +++ b/src/utilities/string_functions.js @@ -148,7 +148,7 @@ p5.prototype.matchAll = function(str, reg) { * @param {Array} nums the Numbers to format * @param {Number|String} [left] * @param {Number|String} [right] - * @return {Array} formatted Strings\ + * @return {String[]} formatted Strings * @example *
* @@ -258,7 +258,7 @@ function doNf() { * @method nfc * @param {Array} nums the Numbers to format * @param {Number|String} [right] - * @return {Array} formatted Strings + * @return {String[]} formatted Strings * @example *
* @@ -406,7 +406,7 @@ function addNfp() { * @param {Array} nums the Numbers to format * @param {Number} [left] * @param {Number} [right] - * @return {Array} formatted Strings + * @return {String[]} formatted Strings * @example *
* @@ -550,7 +550,7 @@ p5.prototype.splitTokens = function() { /** * @method trim * @param {Array} strs an Array of Strings to be trimmed - * @return {Array} an Array of trimmed Strings + * @return {String[]} an Array of trimmed Strings * @example *
* diff --git a/src/webgl/material.js b/src/webgl/material.js index 7e808739ab..9088b1ccdd 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -212,7 +212,7 @@ p5.prototype.texture = function(){ * possible materials in this * example. * @method ambientMaterial - * @param {Number|Array|String|p5.Color} v1 gray value, + * @param {Number|Number[]|String|p5.Color} v1 gray value, * red or hue value (depending on the current color mode), * or color Array, or CSS color string * @param {Number} [v2] green or saturation value @@ -255,7 +255,7 @@ p5.prototype.ambientMaterial = function(v1, v2, v3, a) { * possible materials in this * example. * @method specularMaterial - * @param {Number|Array|String|p5.Color} v1 gray value, + * @param {Number|Number[]|String|p5.Color} v1 gray value, * red or hue value (depending on the current color mode), * or color Array, or CSS color string * @param {Number} [v2] green or saturation value diff --git a/src/webgl/p5.Matrix.js b/src/webgl/p5.Matrix.js index c3980675e7..adcdea02be 100644 --- a/src/webgl/p5.Matrix.js +++ b/src/webgl/p5.Matrix.js @@ -76,7 +76,7 @@ p5.Matrix = function() { * Sets the x, y, and z component of the vector using two or three separate * variables, the data from a p5.Matrix, or the values from a float array. * - * @param {p5.Matrix|Float32Array|Array} [inMatrix] the input p5.Matrix or + * @param {p5.Matrix|Float32Array|Number[]} [inMatrix] the input p5.Matrix or * an Array of length 16 * @param {Number} [n00..n33] 16 numbers passed by value to avoid * array copying. @@ -154,7 +154,8 @@ p5.Matrix.identity = function(){ /** * transpose according to a given matrix - * @param {p5.Matrix|Float32Array|Array} a the matrix to be based on to transpose + * @param {p5.Matrix|Float32Array|Number[]} a the matrix to be based + * on to transpose * @chainable */ p5.Matrix.prototype.transpose = function(a){ @@ -214,7 +215,8 @@ p5.Matrix.prototype.transpose = function(a){ /** * invert matrix according to a give matrix - * @param {p5.Matrix|Float32Array|Array} a the matrix to be based on to invert + * @param {p5.Matrix|Float32Array|Number[]} a the matrix to be based on to + * invert * @chainable */ p5.Matrix.prototype.invert = function(a){ @@ -402,7 +404,7 @@ p5.Matrix.prototype.determinant = function(){ /** * multiply two mat4s - * @param {p5.Matrix|Float32Array|Array} multMatrix The matrix + * @param {p5.Matrix|Float32Array|Number[]} multMatrix The matrix * we want to multiply by * @chainable */ @@ -459,7 +461,7 @@ p5.Matrix.prototype.mult = function(multMatrix){ /** * scales a p5.Matrix by scalars or a vector - * @param {p5.Vector|Float32Array|Array} s vector to scale by + * @param {p5.Vector|Float32Array|Number[]} s vector to scale by * @chainable */ p5.Matrix.prototype.scale = function() { @@ -505,7 +507,7 @@ p5.Matrix.prototype.scale = function() { /** * rotate our Matrix around an axis by the given angle. * @param {Number} a The angle of rotation in radians - * @param {p5.Vector|Array} axis the axis(es) to rotate around + * @param {p5.Vector|Number[]} axis the axis(es) to rotate around * @chainable * inspired by Toji's gl-matrix lib, mat4 rotation */ diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index 91b52ab6b2..fc4d626fd8 100755 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -352,7 +352,7 @@ p5.RendererGL.prototype.background = function() { /** * Basic fill material for geometry with a given color * @method fill - * @param {Number|Array|String|p5.Color} v1 gray value, + * @param {Number|Number[]|String|p5.Color} v1 gray value, * red or hue value (depending on the current color mode), * or color Array, or CSS color string * @param {Number} [v2] green or saturation value @@ -460,7 +460,7 @@ p5.RendererGL.prototype.noStroke = function() { /** * Basic stroke material for geometry with a given color * @method stroke - * @param {Number|Array|String|p5.Color} v1 gray value, + * @param {Number|Number[]|String|p5.Color} v1 gray value, * red or hue value (depending on the current color mode), * or color Array, or CSS color string * @param {Number} [v2] green or saturation value @@ -917,8 +917,8 @@ p5.RendererGL.prototype._flatten = function(arr){ /** * turn a p5.Vector Array into a one dimensional number array - * @param {Array} arr an array of p5.Vector - * @return {Array]} a one dimensional array of numbers + * @param {p5.Vector[]} arr an array of p5.Vector + * @return {Number[]} a one dimensional array of numbers * [p5.Vector(1, 2, 3), p5.Vector(4, 5, 6)] -> * [1, 2, 3, 4, 5, 6] */ From 0631eba3390bbbcb96674aab85c328c5150f312b Mon Sep 17 00:00:00 2001 From: Spongman Date: Tue, 24 Oct 2017 15:53:26 -0700 Subject: [PATCH 02/14] validate constant values, remove some of the debug code from minified build # Conflicts: # src/core/error_helpers.js --- src/core/error_helpers.js | 624 +++++++++++++++++++++----------------- 1 file changed, 341 insertions(+), 283 deletions(-) diff --git a/src/core/error_helpers.js b/src/core/error_helpers.js index ad04b2fc8e..f8b318fb0d 100644 --- a/src/core/error_helpers.js +++ b/src/core/error_helpers.js @@ -7,256 +7,241 @@ var p5 = require('./core'); -/* if (typeof IS_MINIFIED !== 'undefined') { p5._validateParameters = p5._friendlyFileLoadError = function () { }; - -} else */{ - -var doFriendlyWelcome = false; // TEMP until we get it all working LM -// for parameter validation -var dataDoc = require('../../docs/reference/data.json'); -var arrDoc = JSON.parse(JSON.stringify(dataDoc)); - -// -- Borrowed from jQuery 1.11.3 -- -var class2type = {}; -var toString = class2type.toString; -var names = ['Boolean', 'Number', 'String', 'Function', - 'Array', 'Date', 'RegExp', 'Object', 'Error']; -for (var n=0; n p5.js says: '+message+ - '[https://github.com/processing/p5.js/wiki/Local-server]' - ); - } - else{ + var getType = function (obj) { + if (obj == null) { + return obj + ''; + } + return typeof obj === 'object' || typeof obj === 'function' ? + class2type[toString.call(obj)] || 'object' : + typeof obj; + }; + + // -- End borrow -- + + + var friendlyWelcome = function () { + // p5.js brand - magenta: #ED225D + //var astrixBgColor = 'transparent'; + //var astrixTxtColor = '#ED225D'; + //var welcomeBgColor = '#ED225D'; + //var welcomeTextColor = 'white'; console.log( - '> p5.js says: '+message+' [http://p5js.org/reference/#p5/'+func+ - ']' + ' _ \n' + + ' /\\| |/\\ \n' + + ' \\ ` \' / \n' + + ' / , . \\ \n' + + ' \\/|_|\\/ ' + + '\n\n> p5.js says: Welcome! ' + + 'This is your friendly debugger. ' + + 'To turn me off switch to using “p5.min.js”.' ); - } -} - -var errorCases = { - '0': { - fileType: 'image', - method: 'loadImage', - message: ' hosting the image online,' - }, - '1': { - fileType: 'XML file', - method: 'loadXML' - }, - '2': { - fileType: 'table file', - method: 'loadTable' - }, - '3': { - fileType: 'text file', - method: 'loadStrings' - }, - '4': { - fileType: 'font', - method: 'loadFont', - message: ' hosting the font online,' - }, -}; -p5._friendlyFileLoadError = function (errorType, filePath) { - var errorInfo = errorCases[ errorType ]; - var message = 'It looks like there was a problem' + - ' loading your ' + errorInfo.fileType + '.' + - ' Try checking if the file path [' + filePath + '] is correct,' + - (errorInfo.message || '') + ' or running a local server.'; - report(message, errorInfo.method, FILE_LOAD); -}; + }; - var docCache = {}; -/** -* Validates parameters -* param {String} func the name of the function -* param {Array} args user input arguments -* -* example: -* var a; -* ellipse(10,10,a,5); -* console ouput: -* "It looks like ellipse received an empty variable in spot #2." -* -* example: -* ellipse(10,"foo",5,5); -* console output: -* "ellipse was expecting a number for parameter #1, -* received "foo" instead." -*/ -p5._validateParameters = function validateParameters(func, args) { - if (p5.disableFriendlyErrors || - typeof(IS_MINIFIED) !== 'undefined') { - return; // skip FES - } - try { - var arrDoc = docCache[func] || (docCache[func] = lookupParamDoc(func)); - var errorArray = []; - var minErrCount = 999999; - for (var i = 0; i < arrDoc.length; i++) { - var arrError = testParamFormat(args, arrDoc[i]); - if( arrError.length === 0) { - return; // no error - } - // see if this is the format with min number of err - if( minErrCount > arrError.length) { - minErrCount = arrError.length; - errorArray = arrError; - } + /** + * Prints out a fancy, colorful message to the console log + * + * @private + * @param {String} message the words to be said + * @param {String} func the name of the function to link + * @param {Number|String} color CSS color string or error type + * + * @return console logs + */ + // Wrong number of params, undefined param, wrong type + var FILE_LOAD = 3; + var ERR_PARAMS = 3; + // p5.js blue, p5.js orange, auto dark green; fallback p5.js darkened magenta + // See testColors below for all the color codes and names + var typeColors = ['#2D7BB6', '#EE9900', '#4DB200', '#C83C00']; + var report = function (message, func, color) { + if (doFriendlyWelcome) { + friendlyWelcome(); + doFriendlyWelcome = false; } - // generate err msg - for (var n = 0; n < errorArray.length; n++) { - p5._friendlyParamError(errorArray[n], func); + if ('undefined' === getType(color)) { + color = '#B40033'; // dark magenta + } else if (getType(color) === 'number') { // Type to color + color = typeColors[color]; } + if (func.substring(0, 4) === 'load') { + console.log( + '> p5.js says: ' + message + + '[https://github.com/processing/p5.js/wiki/Local-server]' + ); } - catch (err) { - console.log('validation error: ' + err); - } -}; -// validateParameters() helper functions: -// lookupParamDoc() for querying data.json -function lookupParamDoc(func){ - var queryResult = arrDoc.classitems. - filter(function (x) { return x.name === func; }); - // different JSON structure for funct with multi-format - var res = []; - if (queryResult[0].hasOwnProperty('overloads')){ - for(var i = 0; i < queryResult[0].overloads.length; i++) { - res.push(queryResult[0].overloads[i].params); + else { + console.log( + '> p5.js says: ' + message + ' [http://p5js.org/reference/#p5/' + func + + ']' + ); } - } else { + }; + + var errorCases = { + '0': { + fileType: 'image', + method: 'loadImage', + message: ' hosting the image online,' + }, + '1': { + fileType: 'XML file', + method: 'loadXML' + }, + '2': { + fileType: 'table file', + method: 'loadTable' + }, + '3': { + fileType: 'text file', + method: 'loadStrings' + }, + '4': { + fileType: 'font', + method: 'loadFont', + message: ' hosting the font online,' + }, + }; + p5._friendlyFileLoadError = function (errorType, filePath) { + var errorInfo = errorCases[errorType]; + var message = 'It looks like there was a problem' + + ' loading your ' + errorInfo.fileType + '.' + + ' Try checking if the file path [' + filePath + '] is correct,' + + (errorInfo.message || '') + ' or running a local server.'; + report(message, errorInfo.method, FILE_LOAD); + }; + + var docCache = {}; + var builtinTypes = [ + 'number', 'string', 'boolean', + 'constant', 'function', 'integer' + ]; + + // validateParameters() helper functions: + // lookupParamDoc() for querying data.json + var lookupParamDoc = function (func) { + var queryResult = arrDoc.classitems. + filter(function (x) { return x.name === func; }); + // different JSON structure for funct with multi-format + var res = []; + if (queryResult[0].hasOwnProperty('overloads')) { + for (var i = 0; i < queryResult[0].overloads.length; i++) { + res.push(queryResult[0].overloads[i].params); + } + } else { res.push(queryResult[0].params); - } - var builtinTypes = [ - 'number', 'string', 'boolean', - 'constant', 'function', 'integer' - ]; + } + + var mapConstants = {}; res.forEach(function (formats) { formats.forEach(function (format) { format.types = format.type.split('|').map(function ct(type) { + // array if (type.substr(type.length - 2, 2) === '[]') { return { name: type, array: ct(type.substr(0, type.length - 2)) }; -} + } var lowerType = type.toLowerCase(); + + // contant + if (lowerType === 'constant') { + + var constant; + if (mapConstants.hasOwnProperty(format.name)) { + constant = mapConstants[format.name]; + } else { + // parse possible constant values from description + var myRe = /either\s+(?:[A-Z0-9_]+\s*,?\s*(?:or)?\s*)+/g; + var values = {}; + var names = []; + + constant = mapConstants[format.name] = { + values: values, names: names + }; + + var myArray = myRe.exec(format.description); + if (func === 'endShape' && format.name === 'mode') { + values[p5.CLOSE] = true; + names.push('CLOSE'); + } else { + var match = myArray[0]; + var reConst = /[A-Z0-9_]+/g; + var matchConst; + while ((matchConst = reConst.exec(match)) !== null) { + var name = matchConst[0]; + if (p5.prototype.hasOwnProperty(name)) { + values[p5.prototype[name]] = true; + names.push(name); + } + } + } + } + return { + name: type, builtin: lowerType, + names: constant.names, values: constant.values + }; + } + + // function if (lowerType.substr(0, 'function'.length) === 'function') { lowerType = 'function'; - } + } + // builtin if (builtinTypes.indexOf(lowerType) >= 0) { return { name: type, builtin: lowerType }; - } + } + // p5 class type var t = window; type.split('.').forEach(function (p) { t = t && t[p]; }); if (t) { return { name: type, prototype: t }; - } + } return { name: type, type: lowerType }; }); }); }); return res; - } - function testParamFormat(args, formats) { - var errorArray = []; - for (var p = 0; p < formats.length; p++) { - var arg = args[p]; - var format = formats[p]; - var argType = typeof (arg); - if ('undefined' === argType || null === arg) { - if (format.optional !== true) { - errorArray.push({ - type: 'EMPTY_VAR', - position: p, - correctType: format.type, - }); - } - } else if (!testParamTypes(arg, format.types)) { - errorArray.push({ - type: 'WRONG_TYPE', - position: p, - correctType: format.type, - wrongType: arg instanceof Array ? 'array' : arg.name || argType - }); - } - } - return errorArray; -} - // testType() for non-object type parameter validation -// Returns true if PASS, false if FAIL - function testParamTypes(param, types) { - for (var i = 0; i < types.length; i++) { - if (testParamType(param, types[i])) { - return true; - } - } - return false; - } - function testParamType(param, type) { + }; + + var testParamType = function (param, type) { var isArray = param instanceof Array; if (type.array && isArray) { for (var i = 0; i < param.length; i++) { if (!testParamType(param[i], type.array)) { - return false; -} - } + return false; + } + } return true; - } + } else if (type.prototype) { return param instanceof type.prototype; -} + } else if (type.builtin) { switch (type.builtin) { case 'number': @@ -269,76 +254,152 @@ function lookupParamDoc(func){ case 'array': return isArray; case 'string': - case 'constant': return typeof param === 'number' || typeof param === 'string'; + case 'constant': + return type.values.hasOwnProperty(param); case 'function': return param instanceof Function; } } return typeof param === type.t; - } -// function for generating console.log() msg -p5._friendlyParamError = function (errorObj, func) { - var message; - switch (errorObj.type){ - case 'EMPTY_VAR': - message = func + '() was expecting ' + errorObj.correctType + - ' for parameter #' + errorObj.position + ' (zero-based index), received' + - ' an empty variable instead. If not intentional, this is often a problem' + - ' with scope: [https://p5js.org/examples/data-variable-scope.html].'; - report(message, func, ERR_PARAMS); - break; - case 'WRONG_TYPE': - message = func + '() was expecting ' + errorObj.correctType + - ' for parameter #' + errorObj.position + ' (zero-based index), received '; - // Wrap strings in quotes - message += errorObj.wrongType + ' instead.'; - report(message, func, ERR_PARAMS); - } -}; -function friendlyWelcome() { - // p5.js brand - magenta: #ED225D - //var astrixBgColor = 'transparent'; - //var astrixTxtColor = '#ED225D'; - //var welcomeBgColor = '#ED225D'; - //var welcomeTextColor = 'white'; - console.log( - ' _ \n'+ - ' /\\| |/\\ \n'+ - ' \\ ` \' / \n'+ - ' / , . \\ \n'+ - ' \\/|_|\\/ '+ - '\n\n> p5.js says: Welcome! '+ - 'This is your friendly debugger. ' + - 'To turn me off switch to using “p5.min.js”.' - ); + }; + + // testType() for non-object type parameter validation + // Returns true if PASS, false if FAIL + var testParamTypes = function (param, types) { + for (var i = 0; i < types.length; i++) { + if (testParamType(param, types[i])) { + return true; + } + } + return false; + }; + + var testParamFormat = function (args, formats) { + var errorArray = []; + for (var p = 0; p < formats.length; p++) { + var arg = args[p]; + var format = formats[p]; + var argType = typeof (arg); + if ('undefined' === argType || null === arg) { + if (format.optional !== true) { + errorArray.push({ + type: 'EMPTY_VAR', + position: p, + format: format, + }); + } + } else if (!testParamTypes(arg, format.types)) { + errorArray.push({ + type: 'WRONG_TYPE', + position: p, + format: format, + arg: arg + }); + } + } + return errorArray; + }; + + // function for generating console.log() msg + p5._friendlyParamError = function (errorObj, func) { + var message; + var format = errorObj.format; + var formatType = format.types.map(function (type) { + return type.names ? type.names.join('|') : type.name; + }).join('|'); + + switch (errorObj.type) { + case 'EMPTY_VAR': + message = func + '() was expecting ' + formatType + + ' for parameter #' + errorObj.position + + ' (zero-based index), received an empty variable instead.' + + ' If not intentional, this is often a problem with scope:' + + ' [https://p5js.org/examples/data-variable-scope.html].'; + report(message, func, ERR_PARAMS); + break; + case 'WRONG_TYPE': + var arg = errorObj.arg; + var argType = arg instanceof Array ? 'array' : arg.name || typeof arg; + message = func + '() was expecting ' + formatType + + ' for parameter #' + errorObj.position + + ' (zero-based index), received ' + argType + ' instead.'; + report(message, func, ERR_PARAMS); + } + }; + + /** + * Validates parameters + * param {String} func the name of the function + * param {Array} args user input arguments + * + * example: + * var a; + * ellipse(10,10,a,5); + * console ouput: + * "It looks like ellipse received an empty variable in spot #2." + * + * example: + * ellipse(10,"foo",5,5); + * console output: + * "ellipse was expecting a number for parameter #1, + * received "foo" instead." + */ + p5._validateParameters = function validateParameters(func, args) { + if (p5.disableFriendlyErrors) { + return; // skip FES + } + + var arrDoc = docCache[func] || (docCache[func] = lookupParamDoc(func)); + var errorArray = []; + var minErrCount = 999999; + for (var i = 0; i < arrDoc.length; i++) { + var arrError = testParamFormat(args, arrDoc[i]); + if (arrError.length === 0) { + return; // no error + } + // see if this is the format with min number of err + if (minErrCount > arrError.length) { + minErrCount = arrError.length; + errorArray = arrError; + } + } + // generate err msg + for (var n = 0; n < errorArray.length; n++) { + p5._friendlyParamError(errorArray[n], func); + } + }; + + + /** + * Prints out all the colors in the color pallete with white text. + * For color blindness testing. + */ + /* function testColors() { + var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer'; + report(str, 'print', '#ED225D'); // p5.js magenta + report(str, 'print', '#2D7BB6'); // p5.js blue + report(str, 'print', '#EE9900'); // p5.js orange + report(str, 'print', '#A67F59'); // p5.js light brown + report(str, 'print', '#704F21'); // p5.js gold + report(str, 'print', '#1CC581'); // auto cyan + report(str, 'print', '#FF6625'); // auto orange + report(str, 'print', '#79EB22'); // auto green + report(str, 'print', '#B40033'); // p5.js darkened magenta + report(str, 'print', '#084B7F'); // p5.js darkened blue + report(str, 'print', '#945F00'); // p5.js darkened orange + report(str, 'print', '#6B441D'); // p5.js darkened brown + report(str, 'print', '#2E1B00'); // p5.js darkened gold + report(str, 'print', '#008851'); // auto dark cyan + report(str, 'print', '#C83C00'); // auto dark orange + report(str, 'print', '#4DB200'); // auto dark green + } */ + + p5.prototype._validateParameters = p5.validateParameters; } -/** - * Prints out all the colors in the color pallete with white text. - * For color blindness testing. - */ -/* function testColors() { - var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer'; - report(str, 'print', '#ED225D'); // p5.js magenta - report(str, 'print', '#2D7BB6'); // p5.js blue - report(str, 'print', '#EE9900'); // p5.js orange - report(str, 'print', '#A67F59'); // p5.js light brown - report(str, 'print', '#704F21'); // p5.js gold - report(str, 'print', '#1CC581'); // auto cyan - report(str, 'print', '#FF6625'); // auto orange - report(str, 'print', '#79EB22'); // auto green - report(str, 'print', '#B40033'); // p5.js darkened magenta - report(str, 'print', '#084B7F'); // p5.js darkened blue - report(str, 'print', '#945F00'); // p5.js darkened orange - report(str, 'print', '#6B441D'); // p5.js darkened brown - report(str, 'print', '#2E1B00'); // p5.js darkened gold - report(str, 'print', '#008851'); // auto dark cyan - report(str, 'print', '#C83C00'); // auto dark orange - report(str, 'print', '#4DB200'); // auto dark green -} */ // This is a lazily-defined list of p5 symbols that may be // misused by beginners at top-level code, outside of setup/draw. We'd like @@ -348,15 +409,15 @@ function friendlyWelcome() { // For more details, see https://github.com/processing/p5.js/issues/1121. var misusedAtTopLevelCode = null; var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' + - 'Frequently-Asked-Questions' + - '#why-cant-i-assign-variables-using-p5-functions-and-' + - 'variables-before-setup'; + 'Frequently-Asked-Questions' + + '#why-cant-i-assign-variables-using-p5-functions-and-' + + 'variables-before-setup'; -function defineMisusedAtTopLevelCode() { +var defineMisusedAtTopLevelCode = function () { var uniqueNamesFound = {}; - var getSymbols = function(obj) { - return Object.getOwnPropertyNames(obj).filter(function(name) { + var getSymbols = function (obj) { + return Object.getOwnPropertyNames(obj).filter(function (name) { if (name[0] === '_') { return false; } @@ -367,10 +428,10 @@ function defineMisusedAtTopLevelCode() { uniqueNamesFound[name] = true; return true; - }).map(function(name) { + }).map(function (name) { var type; - if (typeof(obj[name]) === 'function') { + if (typeof (obj[name]) === 'function') { type = 'function'; } else if (name === name.toUpperCase()) { type = 'constant'; @@ -378,7 +439,7 @@ function defineMisusedAtTopLevelCode() { type = 'variable'; } - return {name: name, type: type}; + return { name: name, type: type }; }); }; @@ -393,12 +454,12 @@ function defineMisusedAtTopLevelCode() { // This will ultimately ensure that we report the most specific error // possible to the user, e.g. advising them about HALF_PI instead of PI // when their code misuses the former. - misusedAtTopLevelCode.sort(function(a, b) { + misusedAtTopLevelCode.sort(function (a, b) { return b.name.length - a.name.length; }); -} +}; -function helpForMisusedAtTopLevelCode(e, log) { +var helpForMisusedAtTopLevelCode = function (e, log) { if (!log) { log = console.log.bind(console); } @@ -416,7 +477,7 @@ function helpForMisusedAtTopLevelCode(e, log) { // return; //} - misusedAtTopLevelCode.some(function(symbol) { + misusedAtTopLevelCode.some(function (symbol) { // Note that while just checking for the occurrence of the // symbol name in the error message could result in false positives, // a more rigorous test is difficult because different browsers @@ -430,20 +491,19 @@ function helpForMisusedAtTopLevelCode(e, log) { // * ReferenceError: PI is undefined (Firefox) // * Uncaught ReferenceError: PI is not defined (Chrome) - if (e.message && e.message.match('\\W?'+symbol.name+'\\W') !== null) { + if (e.message && e.message.match('\\W?' + symbol.name + '\\W') !== null) { log('Did you just try to use p5.js\'s ' + symbol.name + - (symbol.type === 'function' ? '() ' : ' ') + symbol.type + - '? If so, you may want to ' + - 'move it into your sketch\'s setup() function.\n\n' + - 'For more details, see: ' + FAQ_URL); + (symbol.type === 'function' ? '() ' : ' ') + symbol.type + + '? If so, you may want to ' + + 'move it into your sketch\'s setup() function.\n\n' + + 'For more details, see: ' + FAQ_URL); return true; } }); -} +}; // Exposing this primarily for unit testing. p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode; -p5.prototype._validateParameters = p5.validateParameters; if (document.readyState !== 'complete') { window.addEventListener('error', helpForMisusedAtTopLevelCode, false); @@ -452,11 +512,9 @@ if (document.readyState !== 'complete') { // global (non-instance mode) p5 APIs are used at the top-level // scope of a file, so we'll unbind our error listener now to make // sure we don't log false positives later. - window.addEventListener('load', function() { + window.addEventListener('load', function () { window.removeEventListener('error', helpForMisusedAtTopLevelCode, false); }); } -} - module.exports = p5; From defb773f45c8bb79e8149c5d74e5cb52bb50575d Mon Sep 17 00:00:00 2001 From: Spongman Date: Tue, 24 Oct 2017 15:54:12 -0700 Subject: [PATCH 03/14] specify {Integer} numeric parameter types, where appropriate # Conflicts: # src/io/p5.Table.js --- src/core/environment.js | 2 +- src/events/keyboard.js | 2 +- src/io/p5.Table.js | 44 +++++++++++++++---------------- src/io/p5.TableRow.js | 12 ++++----- src/io/p5.XML.js | 6 ++--- src/math/calculation.js | 14 +++++++--- src/utilities/array_functions.js | 16 +++++------ src/utilities/string_functions.js | 28 ++++++++++---------- src/utilities/time_date.js | 12 ++++----- 9 files changed, 72 insertions(+), 64 deletions(-) diff --git a/src/core/environment.js b/src/core/environment.js index 1cb52d2f37..faf10c8bef 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -53,7 +53,7 @@ p5.prototype.print = function(args) { * been displayed since the program started. Inside setup() the value is 0, * after the first iteration of draw it is 1, etc. * - * @property {Number} frameCount + * @property {Integer} frameCount * @readOnly * @example *
diff --git a/src/events/keyboard.js b/src/events/keyboard.js index 3916ed85d1..e8a010c8fc 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -79,7 +79,7 @@ p5.prototype.key = ''; * You can also check for custom keys by looking up the keyCode of any key * on a site like this: keycode.info. * - * @property {Number} keyCode + * @property {Integer} keyCode * @readOnly * @example *
diff --git a/src/io/p5.Table.js b/src/io/p5.Table.js index 13017c8615..c5c6b8dc19 100644 --- a/src/io/p5.Table.js +++ b/src/io/p5.Table.js @@ -122,7 +122,7 @@ p5.Table.prototype.addRow = function(row) { * Removes a row from the table object. * * @method removeRow - * @param {Number} id ID number of the row to remove + * @param {Integer} id ID number of the row to remove * * @example *
@@ -172,7 +172,7 @@ p5.Table.prototype.removeRow = function(id) { * can then be used to get and set values of the selected row. * * @method getRow - * @param {Number} rowID ID number of the row to get + * @param {Integer} rowID ID number of the row to get * @return {p5.TableRow} p5.TableRow object * * @example @@ -269,7 +269,7 @@ p5.Table.prototype.getRows = function() { * * @method findRow * @param {String} value The value to match - * @param {Number|String} column ID number or title of the + * @param {Integer|String} column ID number or title of the * column to search * @return {p5.TableRow} * @@ -335,7 +335,7 @@ p5.Table.prototype.findRow = function(value, column) { * * @method findRows * @param {String} value The value to match - * @param {Number|String} column ID number or title of the + * @param {Integer|String} column ID number or title of the * column to search * @return {p5.TableRow[]} An Array of TableRow objects * @@ -405,7 +405,7 @@ p5.Table.prototype.findRows = function(value, column) { * * @method matchRow * @param {String} regexp The regular expression to match - * @param {String|Number} column The column ID (number) or + * @param {String|Integer} column The column ID (number) or * title (string) * @return {p5.TableRow} TableRow object */ @@ -436,7 +436,7 @@ p5.Table.prototype.matchRow = function(regexp, column) { * * @method matchRows * @param {String} regexp The regular expression to match - * @param {String|Number} [column] The column ID (number) or + * @param {String|Integer} [column] The column ID (number) or * title (string) * @return {p5.TableRow[]} An Array of TableRow objects * @example @@ -644,7 +644,7 @@ p5.Table.prototype.addColumn = function(title) { /** * Returns the total number of columns in a Table. * - * @return {Number} Number of columns in this table + * @return {Integer} Number of columns in this table */ p5.Table.prototype.getColumnCount = function() { return this.columns.length; @@ -654,7 +654,7 @@ p5.Table.prototype.getColumnCount = function() { * Returns the total number of rows in a Table. * * @method getRowCount - * @return {Number} Number of rows in this table + * @return {Integer} Number of rows in this table */ p5.Table.prototype.getRowCount = function() { @@ -670,7 +670,7 @@ p5.Table.prototype.getRowCount = function() { * * @method removeTokens * @param {String} chars String listing characters to be removed - * @param {String|Number} [column] Column ID (number) + * @param {String|Integer} [column] Column ID (number) * or name (string) */ p5.Table.prototype.removeTokens = function(chars, column) { @@ -719,7 +719,7 @@ p5.Table.prototype.removeTokens = function(chars, column) { * may be referenced by either its ID or title. * * @method trim - * @param {String|Number} column Column ID (number) + * @param {String|Integer} column Column ID (number) * or name (string) */ p5.Table.prototype.trim = function(column) { @@ -762,7 +762,7 @@ p5.Table.prototype.trim = function(column) { * would remove the second column, and so on. * * @method removeColumn - * @param {String|Number} column columnName (string) or ID (number) + * @param {String|Integer} column columnName (string) or ID (number) * * @example *
@@ -829,7 +829,7 @@ p5.Table.prototype.removeColumn = function(c) { * by either its ID or title. * * @method set - * @param {String|Number} column column ID (Number) + * @param {String|Integer} column column ID (Number) * or title (String) * @param {String|Number} value value to assign * @@ -878,8 +878,8 @@ p5.Table.prototype.set = function(row, column, value) { * by either its ID or title. * * @method setNum - * @param {Number} row row ID - * @param {String|Number} column column ID (Number) + * @param {Integer} row row ID + * @param {String|Integer} column column ID (Number) * or title (String) * @param {Number} value value to assign * @@ -925,8 +925,8 @@ p5.Table.prototype.setNum = function(row, column, value){ * by either its ID or title. * * @method setString - * @param {Number} row row ID - * @param {String|Number} column column ID (Number) + * @param {Integer} row row ID + * @param {String|Integer} column column ID (Number) * or title (String) * @param {String} value value to assign */ @@ -940,8 +940,8 @@ p5.Table.prototype.setString = function(row, column, value){ * either its ID or title. * * @method get - * @param {Number} row row ID - * @param {String|Number} column columnName (string) or + * @param {Integer} row row ID + * @param {String|Integer} column columnName (string) or * ID (number) * @return {String|Number} * @@ -987,8 +987,8 @@ p5.Table.prototype.get = function(row, column) { * either its ID or title. * * @method getNum - * @param {Number} row row ID - * @param {String|Number} column columnName (string) or + * @param {Integer} row row ID + * @param {String|Integer} column columnName (string) or * ID (number) * @return {Number} * @@ -1032,8 +1032,8 @@ p5.Table.prototype.getNum = function(row, column) { * either its ID or title. * * @method getString - * @param {Number} row row ID - * @param {String|Number} column columnName (string) or + * @param {Integer} row row ID + * @param {String|Integer} column columnName (string) or * ID (number) * @return {String} * diff --git a/src/io/p5.TableRow.js b/src/io/p5.TableRow.js index 0218bd92db..f72d4787b0 100644 --- a/src/io/p5.TableRow.js +++ b/src/io/p5.TableRow.js @@ -45,7 +45,7 @@ p5.TableRow = function (str, separator) { * The column may be specified by either its ID or title. * * @method set - * @param {String|Number} column Column ID (Number) + * @param {String|Integer} column Column ID (Number) * or Title (String) * @param {String|Number} value The value to be stored */ @@ -81,7 +81,7 @@ p5.TableRow.prototype.set = function(column, value) { * The column may be specified by either its ID or title. * * @method setNum - * @param {String|Number} column Column ID (Number) + * @param {String|Integer} column Column ID (Number) * or Title (String) * @param {Number} value The value to be stored * as a Float @@ -97,7 +97,7 @@ p5.TableRow.prototype.setNum = function(column, value){ * The column may be specified by either its ID or title. * * @method setString - * @param {String|Number} column Column ID (Number) + * @param {String|Integer} column Column ID (Number) * or Title (String) * @param {String} value The value to be stored * as a String @@ -112,7 +112,7 @@ p5.TableRow.prototype.setString = function(column, value){ * The column may be specified by either its ID or title. * * @method get - * @param {String|Number} column columnName (string) or + * @param {String|Integer} column columnName (string) or * ID (number) * @return {String|Number} */ @@ -130,7 +130,7 @@ p5.TableRow.prototype.get = function(column) { * title. * * @method getNum - * @param {String|Number} column columnName (string) or + * @param {String|Integer} column columnName (string) or * ID (number) * @return {Number} Float Floating point number */ @@ -154,7 +154,7 @@ p5.TableRow.prototype.getNum = function(column) { * title. * * @method getString - * @param {String|Number} column columnName (string) or + * @param {String|Integer} column columnName (string) or * ID (number) * @return {String} String */ diff --git a/src/io/p5.XML.js b/src/io/p5.XML.js index 05d989af84..9e28b1b29f 100644 --- a/src/io/p5.XML.js +++ b/src/io/p5.XML.js @@ -302,7 +302,7 @@ p5.XML.prototype.getChildren = function(param) { * child is found. * * @method getChild - * @param {String|Number} name element name or index + * @param {String|Integer} name element name or index * @return {p5.XML} * @example<animal *
@@ -378,7 +378,7 @@ p5.XML.prototype.addChild = function(node) { * Removes the element specified by name or index. * * @method removeChild - * @param {String|Number} name element name or index + * @param {String|Integer} name element name or index * @example *
* // The following short XML file called "mammals.xml" is parsed @@ -451,7 +451,7 @@ p5.XML.prototype.removeChild = function(param) { * Counts the specified element's number of attributes, returned as an Number. * * @method getAttributeCount - * @return {Number} + * @return {Integer} * @example *
* // The following short XML file called "mammals.xml" is parsed diff --git a/src/math/calculation.js b/src/math/calculation.js index df71edcd31..ff9229028e 100644 --- a/src/math/calculation.js +++ b/src/math/calculation.js @@ -40,7 +40,7 @@ p5.prototype.abs = Math.abs; * * @method ceil * @param {Number} n number to round up - * @return {Number} rounded up number + * @return {Integer} rounded up number * @example *
* function draw() { @@ -114,6 +114,7 @@ p5.prototype.ceil = Math.ceil; * */ p5.prototype.constrain = function(n, low, high) { + p5._validateParameters('constrain', arguments); return Math.max(Math.min(n, high), low); }; @@ -172,6 +173,7 @@ p5.prototype.constrain = function(n, low, high) { * */ p5.prototype.dist = function() { + p5._validateParameters('dist', arguments); if (arguments.length === 4) { //2D return hypot(arguments[2]-arguments[0], arguments[3]-arguments[1]); } else if (arguments.length === 6) { //3D @@ -237,7 +239,7 @@ p5.prototype.exp = Math.exp; * * @method floor * @param {Number} n number to round down - * @return {Number} rounded down number + * @return {Integer} rounded down number * @example *
* function draw() { @@ -311,6 +313,7 @@ p5.prototype.floor = Math.floor; * */ p5.prototype.lerp = function(start, stop, amt) { + p5._validateParameters('lerp', arguments); return amt*(stop-start)+start; }; @@ -403,6 +406,7 @@ p5.prototype.log = Math.log; * */ p5.prototype.mag = function(x, y) { + p5._validateParameters('mag', arguments); return hypot(x, y); }; @@ -450,6 +454,7 @@ p5.prototype.mag = function(x, y) { * */ p5.prototype.map = function (n, start1, stop1, start2, stop2, withinBounds) { + p5._validateParameters('map', arguments); var newval = ((n - start1)/(stop1 - start1)) * (stop2 - start2) + start2; if (!withinBounds) { return newval; @@ -497,6 +502,7 @@ p5.prototype.map = function (n, start1, stop1, start2, stop2, withinBounds) { * */ p5.prototype.max = function() { + p5._validateParameters('max', arguments); if (arguments[0] instanceof Array) { return Math.max.apply(null,arguments[0]); } else { @@ -540,6 +546,7 @@ p5.prototype.max = function() { * */ p5.prototype.min = function() { + p5._validateParameters('min', arguments); if (arguments[0] instanceof Array) { return Math.min.apply(null,arguments[0]); } else { @@ -596,6 +603,7 @@ p5.prototype.min = function() { * */ p5.prototype.norm = function(n, start, stop) { + p5._validateParameters('norm', arguments); return this.map(n, start, stop, 0, 1); }; @@ -639,7 +647,7 @@ p5.prototype.pow = Math.pow; * * @method round * @param {Number} n number to round - * @return {Number} rounded number + * @return {Integer} rounded number * @example *
* function draw() { diff --git a/src/utilities/array_functions.js b/src/utilities/array_functions.js index b46c6bd570..3a578e10e9 100644 --- a/src/utilities/array_functions.js +++ b/src/utilities/array_functions.js @@ -51,16 +51,16 @@ p5.prototype.append = function(array, value) { * * @method arrayCopy * @param {Array} src the source Array - * @param {Number} srcPosition starting position in the source Array + * @param {Integer} srcPosition starting position in the source Array * @param {Array} dst the destination Array - * @param {Number} dstPosition starting position in the destination Array - * @param {Number} length number of Array elements to be copied + * @param {Integer} dstPosition starting position in the destination Array + * @param {Integer} length number of Array elements to be copied */ /** * @method arrayCopy * @param {Array} src * @param {Array} dst - * @param {Number} [length] + * @param {Integer} [length] * * @example *
@@ -245,7 +245,7 @@ p5.prototype.shuffle = function(arr, bool) { * * @method sort * @param {Array} list Array to sort - * @param {Number} [count] number of elements to sort, starting from 0 + * @param {Integer} [count] number of elements to sort, starting from 0 * * @example *
@@ -291,7 +291,7 @@ p5.prototype.sort = function(list, count) { * @method splice * @param {Array} list Array to splice into * @param {any} value value to be spliced in - * @param {Number} position in the array from which to insert data + * @param {Integer} position in the array from which to insert data * * @example *
@@ -324,8 +324,8 @@ p5.prototype.splice = function(list, value, index) { * * @method subset * @param {Array} list Array to extract from - * @param {Number} start position to begin - * @param {Number} [count] number of values to extract + * @param {Integer} start position to begin + * @param {Integer} [count] number of values to extract * @return {Array} Array of extracted elements * * @example diff --git a/src/utilities/string_functions.js b/src/utilities/string_functions.js index ae8c28ef14..7b971849b1 100644 --- a/src/utilities/string_functions.js +++ b/src/utilities/string_functions.js @@ -137,17 +137,17 @@ p5.prototype.matchAll = function(str, reg) { * * @method nf * @param {Number|String} num the Number to format - * @param {Number|String} [left] number of digits to the left of the + * @param {Integer|String} [left] number of digits to the left of the * decimal point - * @param {Number|String} [right] number of digits to the right of the + * @param {Integer|String} [right] number of digits to the right of the * decimal point * @return {String} formatted String */ /** * @method nf * @param {Array} nums the Numbers to format - * @param {Number|String} [left] - * @param {Number|String} [right] + * @param {Integer|String} [left] + * @param {Integer|String} [right] * @return {String[]} formatted Strings * @example *
@@ -250,14 +250,14 @@ function doNf() { * * @method nfc * @param {Number|String} num the Number to format - * @param {Number|String} [right] number of digits to the right of the + * @param {Integer|String} [right] number of digits to the right of the * decimal point * @return {String} formatted String */ /** * @method nfc * @param {Array} nums the Numbers to format - * @param {Number|String} [right] + * @param {Integer|String} [right] * @return {String[]} formatted Strings * @example *
@@ -330,17 +330,17 @@ function doNfc() { * * @method nfp * @param {Number} num the Number to format - * @param {Number} [left] number of digits to the left of the decimal + * @param {Integer} [left] number of digits to the left of the decimal * point - * @param {Number} [right] number of digits to the right of the + * @param {Integer} [right] number of digits to the right of the * decimal point * @return {String} formatted String */ /** * @method nfp * @param {Number[]} nums the Numbers to format - * @param {Number} [left] - * @param {Number} [right] + * @param {Integer} [left] + * @param {Integer} [right] * @return {String[]} formatted Strings * @example *
@@ -395,17 +395,17 @@ function addNfp() { * * @method nfs * @param {Number} num the Number to format - * @param {Number} [left] number of digits to the left of the decimal + * @param {Integer} [left] number of digits to the left of the decimal * point - * @param {Number} [right] number of digits to the right of the + * @param {Integer} [right] number of digits to the right of the * decimal point * @return {String} formatted String */ /** * @method nfs * @param {Array} nums the Numbers to format - * @param {Number} [left] - * @param {Number} [right] + * @param {Integer} [left] + * @param {Integer} [right] * @return {String[]} formatted Strings * @example *
diff --git a/src/utilities/time_date.js b/src/utilities/time_date.js index 956df51f3e..03cb306670 100644 --- a/src/utilities/time_date.js +++ b/src/utilities/time_date.js @@ -14,7 +14,7 @@ var p5 = require('../core/core'); * returns the current day as a value from 1 - 31. * * @method day - * @return {Number} the current day + * @return {Integer} the current day * @example *
* @@ -36,7 +36,7 @@ p5.prototype.day = function() { * returns the current hour as a value from 0 - 23. * * @method hour - * @return {Number} the current hour + * @return {Integer} the current hour * @example *
* @@ -58,7 +58,7 @@ p5.prototype.hour = function() { * returns the current minute as a value from 0 - 59. * * @method minute - * @return {Number} the current minute + * @return {Integer} the current minute * @example *
* @@ -103,7 +103,7 @@ p5.prototype.millis = function() { * returns the current month as a value from 1 - 12. * * @method month - * @return {Number} the current month + * @return {Integer} the current month * @example *
* @@ -125,7 +125,7 @@ p5.prototype.month = function() { * returns the current second as a value from 0 - 59. * * @method second - * @return {Number} the current second + * @return {Integer} the current second * @example *
* @@ -147,7 +147,7 @@ p5.prototype.second = function() { * returns the current year as an integer (2014, 2015, 2016, etc). * * @method year - * @return {Number} the current year + * @return {Integer} the current year * @example *
* From 65facf9fc943caeb888368408346086786f92aa8 Mon Sep 17 00:00:00 2001 From: Spongman Date: Tue, 24 Oct 2017 17:45:36 -0700 Subject: [PATCH 04/14] add 'OPEN' to list of arc-mode constants --- src/core/2d_primitives.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/2d_primitives.js b/src/core/2d_primitives.js index 0e39a6f69c..222404dd55 100644 --- a/src/core/2d_primitives.js +++ b/src/core/2d_primitives.js @@ -32,7 +32,7 @@ require('./error_helpers'); * @param {Number} start angle to start the arc, specified in radians * @param {Number} stop angle to stop the arc, specified in radians * @param {Constant} [mode] optional parameter to determine the way of drawing - * the arc. either CHORD or PIE + * the arc. either CHORD, PIE or OPEN * @chainable * @example *
From 32ec2590770dc9f04095d2e03666110f505a5ffe Mon Sep 17 00:00:00 2001 From: Spongman Date: Tue, 24 Oct 2017 21:51:08 -0700 Subject: [PATCH 05/14] remove data.json from minified version --- Gruntfile.js | 4 ++-- tasks/build/browserify.js | 24 +++++++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index ed99cbdea1..95fe664f4e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -265,7 +265,7 @@ module.exports = function(grunt) { }, dist: { files: { - 'lib/p5.min.js': 'lib/p5.js', + 'lib/p5.min.js': 'lib/p5.pre-min.js', 'lib/addons/p5.dom.min.js': 'lib/addons/p5.dom.js' } } @@ -352,7 +352,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-update-json'); // Create the multitasks. - grunt.registerTask('build', ['browserify', 'uglify', 'requirejs']); + grunt.registerTask('build', ['browserify', 'browserify:min', 'uglify', 'requirejs']); grunt.registerTask('test', ['jshint', 'jscs', 'yuidoc:prod', 'build', 'connect', 'mocha', 'mochaTest']); grunt.registerTask('test:nobuild', ['jshint:test', 'jscs:test', 'connect', 'mocha']); grunt.registerTask('yui', ['yuidoc:prod', 'minjson']); diff --git a/tasks/build/browserify.js b/tasks/build/browserify.js index 23c2403913..51ff980810 100644 --- a/tasks/build/browserify.js +++ b/tasks/build/browserify.js @@ -10,10 +10,14 @@ module.exports = function(grunt) { var srcFilePath = require.resolve('../../src/app.js'); - // This file will not exist until it has been built - var libFilePath = path.resolve('lib/p5.js'); + grunt.registerTask('browserify', 'Compile the p5.js source with Browserify', function(param) { + + var isMin = param === 'min'; + var filename = isMin ? 'p5.pre-min.js' : 'p5.js'; + + // This file will not exist until it has been built + var libFilePath = path.resolve('lib/' + filename); - grunt.registerTask('browserify', 'Compile the p5.js source with Browserify', function() { // Reading and writing files is asynchronous var done = this.async(); @@ -21,9 +25,15 @@ module.exports = function(grunt) { var banner = grunt.template.process(bannerTemplate); // Invoke Browserify programatically to bundle the code - var bundle = browserify(srcFilePath, { - standalone: 'p5' - }) + var browseified = browserify(srcFilePath, { + standalone: 'p5' + }); + + if (isMin) { + browseified = browseified.exclude('../../docs/reference/data.json'); + } + + var bundle = browseified .transform('brfs') .bundle(); @@ -43,7 +53,7 @@ module.exports = function(grunt) { grunt.file.write(libFilePath, derequire(code)); // Print a success message - grunt.log.writeln('>>'.green + ' Bundle ' + 'lib/p5.js'.cyan + ' created.'); + grunt.log.writeln('>>'.green + ' Bundle ' + ('lib/' + filename).cyan + ' created.'); // Complete the task done(); From ff9737cbb9c4d93de2f24b1328361dbdbf2e457d Mon Sep 17 00:00:00 2001 From: Spongman Date: Wed, 25 Oct 2017 13:26:34 -0700 Subject: [PATCH 06/14] add FES warning for too many arguments, show error location --- src/core/error_helpers.js | 77 ++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/src/core/error_helpers.js b/src/core/error_helpers.js index f8b318fb0d..e4ae5df698 100644 --- a/src/core/error_helpers.js +++ b/src/core/error_helpers.js @@ -143,17 +143,21 @@ if (typeof IS_MINIFIED !== 'undefined') { var queryResult = arrDoc.classitems. filter(function (x) { return x.name === func; }); // different JSON structure for funct with multi-format - var res = []; + var overloads = []; if (queryResult[0].hasOwnProperty('overloads')) { for (var i = 0; i < queryResult[0].overloads.length; i++) { - res.push(queryResult[0].overloads[i].params); + overloads.push(queryResult[0].overloads[i].params); } } else { - res.push(queryResult[0].params); + overloads.push(queryResult[0].params); } var mapConstants = {}; - res.forEach(function (formats) { + var maxParams = 0; + overloads.forEach(function (formats) { + if (maxParams < formats.length) { + maxParams = formats.length; + } formats.forEach(function (format) { format.types = format.type.split('|').map(function ct(type) { @@ -226,7 +230,10 @@ if (typeof IS_MINIFIED !== 'undefined') { }); }); }); - return res; + return { + overloads: overloads, + maxParams: maxParams, + }; }; var testParamType = function (param, type) { @@ -306,27 +313,45 @@ if (typeof IS_MINIFIED !== 'undefined') { // function for generating console.log() msg p5._friendlyParamError = function (errorObj, func) { var message; - var format = errorObj.format; - var formatType = format.types.map(function (type) { - return type.names ? type.names.join('|') : type.name; - }).join('|'); + + function formatType() { + var format = errorObj.format; + return format.types.map(function (type) { + return type.names ? type.names.join('|') : type.name; + }).join('|'); + } switch (errorObj.type) { case 'EMPTY_VAR': - message = func + '() was expecting ' + formatType + + message = func + '() was expecting ' + formatType() + ' for parameter #' + errorObj.position + ' (zero-based index), received an empty variable instead.' + ' If not intentional, this is often a problem with scope:' + - ' [https://p5js.org/examples/data-variable-scope.html].'; - report(message, func, ERR_PARAMS); + ' [https://p5js.org/examples/data-variable-scope.html]'; break; case 'WRONG_TYPE': var arg = errorObj.arg; var argType = arg instanceof Array ? 'array' : arg.name || typeof arg; - message = func + '() was expecting ' + formatType + + message = func + '() was expecting ' + formatType() + ' for parameter #' + errorObj.position + - ' (zero-based index), received ' + argType + ' instead.'; - report(message, func, ERR_PARAMS); + ' (zero-based index), received ' + argType + ' instead'; + break; + case 'WRONG_ARGUMENT_COUNT': + message = func + '() was expecting ' + errorObj.maxParams + + ' arguments, but received ' + errorObj.argCount; + break; + } + + if (message) { + try { + var re = /Function\.validateParameters.*[\r\n].*[\r\n].*\(([^)]*)/; + var location = re.exec((new Error()).stack)[1]; + if (location) { + message += ' at ' + location; + } + } catch (err) { } + + report(message + '.', func, ERR_PARAMS); } }; @@ -352,20 +377,30 @@ if (typeof IS_MINIFIED !== 'undefined') { return; // skip FES } - var arrDoc = docCache[func] || (docCache[func] = lookupParamDoc(func)); + var docs = docCache[func] || (docCache[func] = lookupParamDoc(func)); var errorArray = []; var minErrCount = 999999; - for (var i = 0; i < arrDoc.length; i++) { - var arrError = testParamFormat(args, arrDoc[i]); - if (arrError.length === 0) { - return; // no error - } + var overloads = docs.overloads; + for (var i = 0; i < overloads.length; i++) { + var arrError = testParamFormat(args, overloads[i]); // see if this is the format with min number of err if (minErrCount > arrError.length) { minErrCount = arrError.length; errorArray = arrError; } + if (arrError.length === 0) { + break; // no error + } } + + if (!errorArray.length && args.length > docs.maxParams) { + errorArray.push({ + type: 'WRONG_ARGUMENT_COUNT', + argCount: args.length, + maxParams: docs.maxParams, + }); + } + // generate err msg for (var n = 0; n < errorArray.length; n++) { p5._friendlyParamError(errorArray[n], func); From a56ad1e80ab8d8b6518a798ac321da6a47b2b0cd Mon Sep 17 00:00:00 2001 From: Spongman Date: Wed, 25 Oct 2017 13:27:53 -0700 Subject: [PATCH 07/14] fix up docs for 3d primitives --- src/core/2d_primitives.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/2d_primitives.js b/src/core/2d_primitives.js index 222404dd55..9ae17c943a 100644 --- a/src/core/2d_primitives.js +++ b/src/core/2d_primitives.js @@ -220,6 +220,16 @@ p5.prototype.ellipse = function() { *3 lines of various stroke sizes. Form top, bottom and right sides of a square. * */ +/** + * @method line + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} z1 the z-coordinate of the first point + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} z2 the z-coordinate of the second point + * @chainable + */ p5.prototype.line = function() { if (!this._renderer._doStroke) { return this; @@ -252,6 +262,7 @@ p5.prototype.line = function() { * @method point * @param {Number} x the x-coordinate * @param {Number} y the y-coordinate + * @param {Number} [z] the z-coordinate * @chainable * @example *
@@ -326,12 +337,16 @@ p5.prototype.point = function() { * @method quad * @param {Number} x1 * @param {Number} y1 + * @param {Number} z1 * @param {Number} x2 * @param {Number} y2 + * @param {Number} z2 * @param {Number} x3 * @param {Number} y3 + * @param {Number} z3 * @param {Number} x4 * @param {Number} y4 + * @param {Number} z4 * @chainable */ p5.prototype.quad = function() { From 19b5a8e23617e0f35348e739050caf0dcdd2c6cd Mon Sep 17 00:00:00 2001 From: Spongman Date: Wed, 25 Oct 2017 13:28:19 -0700 Subject: [PATCH 08/14] fix nfc tests, min/max docs --- src/math/calculation.js | 30 +++++++++++++++++++++--------- src/math/p5.Vector.js | 2 +- src/utilities/string_functions.js | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/math/calculation.js b/src/math/calculation.js index ff9229028e..072eddb76c 100644 --- a/src/math/calculation.js +++ b/src/math/calculation.js @@ -62,8 +62,8 @@ p5.prototype.abs = Math.abs; * * // Reformat the float returned by map and draw it. * noStroke(); - * text(nfc(ax, 2,2), ax, ay - 5); - * text(nfc(bx,1,1), bx, by - 5); + * text(nfc(ax, 2), ax, ay - 5); + * text(nfc(bx, 1), bx, by - 5); * } *
* @@ -162,7 +162,7 @@ p5.prototype.constrain = function(n, low, high) { * push(); * translate( (x1+x2)/2, (y1+y2)/2 ); * rotate( atan2(y2-y1,x2-x1) ); - * text(nfc(d,1,1), 0, -5); + * text(nfc(d,1), 0, -5); * pop(); * // Fancy! * } @@ -261,8 +261,8 @@ p5.prototype.exp = Math.exp; * * // Reformat the float returned by map and draw it. * noStroke(); - * text(nfc(ax, 2,2), ax, ay - 5); - * text(nfc(bx,1,1), bx, by - 5); + * text(nfc(ax, 2), ax, ay - 5); + * text(nfc(bx, 1), bx, by - 5); * } *
* @@ -472,7 +472,8 @@ p5.prototype.map = function (n, start1, stop1, start2, stop2, withinBounds) { * of any length. * * @method max - * @param {Number|Number[]} n0 Numbers to compare + * @param {Number} n0 Number to compare + * @param {Number} n1 Number to compare * @return {Number} maximum Number * @example *
@@ -501,6 +502,11 @@ p5.prototype.map = function (n, start1, stop1, start2, stop2, withinBounds) { * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 9 * */ +/** + * @method max + * @param {Number[]} nums Numbers to compare + * @return {Number} + */ p5.prototype.max = function() { p5._validateParameters('max', arguments); if (arguments[0] instanceof Array) { @@ -516,7 +522,8 @@ p5.prototype.max = function() { * of any length. * * @method min - * @param {Number|Number[]} n0 Numbers to compare + * @param {Number} n0 Number to compare + * @param {Number} n1 Number to compare * @return {Number} minimum Number * @example *
@@ -545,6 +552,11 @@ p5.prototype.max = function() { * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 1 * */ +/** + * @method min + * @param {Number[]} nums Numbers to compare + * @return {Number} + */ p5.prototype.min = function() { p5._validateParameters('min', arguments); if (arguments[0] instanceof Array) { @@ -669,8 +681,8 @@ p5.prototype.pow = Math.pow; * * // Reformat the float returned by map and draw it. * noStroke(); - * text(nfc(ax, 2,2), ax, ay - 5); - * text(nfc(bx,1,1), bx, by - 5); + * text(nfc(ax, 2), ax, ay - 5); + * text(nfc(bx, 1), bx, by - 5); * } *
* diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index e090a3060c..61789815fa 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -798,7 +798,7 @@ p5.Vector.prototype.equals = function (x, y, z) { * // Display that variable in an onscreen text. * // (Note the nfc() function to truncate additional decimal places, * // and the "\xB0" character for the degree symbol.) - * var readout = "angle = " + nfc(myDegrees,1,1) + "\xB0" + * var readout = "angle = " + nfc(myDegrees,1) + "\xB0" * noStroke(); * fill (0); * text (readout, 5, 15); diff --git a/src/utilities/string_functions.js b/src/utilities/string_functions.js index 7b971849b1..c519c6f206 100644 --- a/src/utilities/string_functions.js +++ b/src/utilities/string_functions.js @@ -272,8 +272,8 @@ function doNf() { * textSize(12); * * // Draw formatted numbers - * text(nfc(num, 4, 2), 10, 30); - * text(nfc(numArr, 2, 1), 10, 80); + * text(nfc(num, 4), 10, 30); + * text(nfc(numArr, 2), 10, 80); * * // Draw dividing line * stroke(120); From 2a5beec0cd78370d4ef7f1d1dd7bfd1c6c24fcac Mon Sep 17 00:00:00 2001 From: Spongman Date: Wed, 25 Oct 2017 13:29:01 -0700 Subject: [PATCH 09/14] remove unused argument from createCanvas call --- src/core/core.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/core.js b/src/core/core.js index c976e6a381..a55cd12dc2 100644 --- a/src/core/core.js +++ b/src/core/core.js @@ -304,8 +304,7 @@ var p5 = function(sketch, node, sync) { this.createCanvas( this._defaultCanvasSize.width, this._defaultCanvasSize.height, - 'p2d', - true + 'p2d' ); // return preload functions to their normal vals if switched by preload From 2e733f771ff434bb1ab51629a93a52e834d0494c Mon Sep 17 00:00:00 2001 From: Spongman Date: Mon, 6 Nov 2017 13:38:05 -0800 Subject: [PATCH 10/14] fix bad merge of parameter docs --- src/math/p5.Vector.js | 13 +++++-------- src/webgl/material.js | 22 ++++++++++------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index c9dd6789a5..3ded9b6216 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -107,8 +107,7 @@ p5.Vector.prototype.toString = function p5VectorToString() { * Sets the x, y, and z component of the vector using two or three separate * variables, the data from a p5.Vector, or the values from a float array. * @method set - * @param {Number|p5.Vector|Number[]} [x] the x component of the vector or a - * p5.Vector or an Array + * @param {Number} [x] the x component of the vector * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector * @chainable @@ -180,8 +179,8 @@ p5.Vector.prototype.copy = function () { * acts directly on the vector. See the examples for more context. * * @method add - * @param {Number|p5.Vector|Number[]} x the x component of the vector to be - * added or a p5.Vector or an Array + * @param {Number} x the x component of the vector to be + * added * @param {Number} [y] the y component of the vector to be * added * @param {Number} [z] the z component of the vector to be @@ -237,8 +236,7 @@ p5.Vector.prototype.add = function (x, y, z) { * other acts directly on the vector. See the examples for more context. * * @method sub - * @param {Number|p5.Vector|Number[]} x the x component of the vector or a - * p5.Vector or an Array + * @param {Number} x the x component of the vector * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector * @chainable @@ -752,8 +750,7 @@ p5.Vector.prototype.array = function () { * Equality check against a p5.Vector * * @method equals - * @param {Number|p5.Vector|Number[]} [x] the x component of the vector or a - * p5.Vector or an Array + * @param {Number} [x] the x component of the vector * @param {Number} [y] the y component of the vector * @param {Number} [z] the z component of the vector * @return {Boolean} whether the vectors are equals diff --git a/src/webgl/material.js b/src/webgl/material.js index 6ef3a94d58..97c350a797 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -211,12 +211,11 @@ p5.prototype.texture = function(){ * possible materials in this * example. * @method ambientMaterial - * @param {Number|Number[]|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] green or saturation value - * @param {Number} [v3] blue or brightness value - * @param {Number} [a] opacity + * @param {Number} v1 gray value, red or hue value + * (depending on the current color mode), + * @param {Number} [v2] green or saturation value + * @param {Number} [v3] blue or brightness value + * @param {Number} [a] opacity * @chainable * @example *
@@ -259,12 +258,11 @@ p5.prototype.ambientMaterial = function(v1, v2, v3, a) { * possible materials in this * example. * @method specularMaterial - * @param {Number|Number[]|String|p5.Color} v1 gray value, - * red or hue value (depending on the current color mode), - * or color Array, or CSS color string - * @param {Number} [v2] green or saturation value - * @param {Number} [v3] blue or brightness value - * @param {Number} [a] opacity + * @param {Number} v1 gray value, red or hue value + * (depending on the current color mode), + * @param {Number} [v2] green or saturation value + * @param {Number} [v3] blue or brightness value + * @param {Number} [a] opacity * @chainable * @example *
From c3a0b7722b2c1477966948b9d447b0a5ce7e3552 Mon Sep 17 00:00:00 2001 From: Spongman Date: Mon, 6 Nov 2017 13:39:35 -0800 Subject: [PATCH 11/14] fix bad merge of parameter docs --- src/math/p5.Vector.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index 3ded9b6216..f235988380 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -107,9 +107,9 @@ p5.Vector.prototype.toString = function p5VectorToString() { * Sets the x, y, and z component of the vector using two or three separate * variables, the data from a p5.Vector, or the values from a float array. * @method set - * @param {Number} [x] the x component of the vector - * @param {Number} [y] the y component of the vector - * @param {Number} [z] the z component of the vector + * @param {Number} [x] the x component of the vector + * @param {Number} [y] the y component of the vector + * @param {Number} [z] the z component of the vector * @chainable * @example *
@@ -179,12 +179,9 @@ p5.Vector.prototype.copy = function () { * acts directly on the vector. See the examples for more context. * * @method add - * @param {Number} x the x component of the vector to be - * added - * @param {Number} [y] the y component of the vector to be - * added - * @param {Number} [z] the z component of the vector to be - * added + * @param {Number} x the x component of the vector to be added + * @param {Number} [y] the y component of the vector to be added + * @param {Number} [z] the z component of the vector to be added * @chainable * @example *
From b809cb54e559ca01e6d6fc2313c7b07d3ed93a25 Mon Sep 17 00:00:00 2001 From: Spongman Date: Mon, 6 Nov 2017 13:42:23 -0800 Subject: [PATCH 12/14] more bad merge cleanup --- src/math/p5.Vector.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/math/p5.Vector.js b/src/math/p5.Vector.js index f235988380..b3ccb06512 100644 --- a/src/math/p5.Vector.js +++ b/src/math/p5.Vector.js @@ -233,9 +233,9 @@ p5.Vector.prototype.add = function (x, y, z) { * other acts directly on the vector. See the examples for more context. * * @method sub - * @param {Number} x the x component of the vector - * @param {Number} [y] the y component of the vector - * @param {Number} [z] the z component of the vector + * @param {Number} x the x component of the vector to subtract + * @param {Number} [y] the y component of the vector to subtract + * @param {Number} [z] the z component of the vector to subtract * @chainable * @example *
@@ -747,9 +747,9 @@ p5.Vector.prototype.array = function () { * Equality check against a p5.Vector * * @method equals - * @param {Number} [x] the x component of the vector - * @param {Number} [y] the y component of the vector - * @param {Number} [z] the z component of the vector + * @param {Number} [x] the x component of the vector + * @param {Number} [y] the y component of the vector + * @param {Number} [z] the z component of the vector * @return {Boolean} whether the vectors are equals * @example *
From be11e31492c9a0bcb08f4cf3838710744131b205 Mon Sep 17 00:00:00 2001 From: Spongman Date: Wed, 29 Nov 2017 18:53:32 -0800 Subject: [PATCH 13/14] prettify --- .eslintrc | 1 + Gruntfile.js | 7 +- src/core/error_helpers.js | 297 ++++++++++++++++++-------------- src/image/loading_displaying.js | 2 +- tasks/build/browserify.js | 100 +++++------ 5 files changed, 228 insertions(+), 179 deletions(-) diff --git a/.eslintrc b/.eslintrc index dbae927077..06335b169c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -35,6 +35,7 @@ "no-caller": 2, "no-undef": 2, "no-unused-vars": ["error", { "args": "none" }], + "no-empty": ["error", { "allowEmptyCatch": true }], "no-console": "off" } } diff --git a/Gruntfile.js b/Gruntfile.js index d56ab9e649..30eafaf6ec 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -354,7 +354,12 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-karma'); // Create the multitasks. - grunt.registerTask('build', ['browserify', 'browserify:min', 'uglify', 'requirejs']); + grunt.registerTask('build', [ + 'browserify', + 'browserify:min', + 'uglify', + 'requirejs' + ]); grunt.registerTask('lint-no-fix', [ 'eslint:build', 'eslint:source', diff --git a/src/core/error_helpers.js b/src/core/error_helpers.js index 9d1502a637..6ffbe5ab8a 100644 --- a/src/core/error_helpers.js +++ b/src/core/error_helpers.js @@ -8,13 +8,8 @@ var p5 = require('./core'); if (typeof IS_MINIFIED !== 'undefined') { - - p5._validateParameters = - p5._friendlyFileLoadError = - function () { }; - + p5._validateParameters = p5._friendlyFileLoadError = function() {}; } else { - var doFriendlyWelcome = false; // TEMP until we get it all working LM // for parameter validation var dataDoc = require('../../docs/reference/data.json'); @@ -24,25 +19,31 @@ if (typeof IS_MINIFIED !== 'undefined') { var class2type = {}; var toString = class2type.toString; var names = [ - 'Boolean', 'Number', 'String', 'Function', - 'Array', 'Date', 'RegExp', 'Object', 'Error' + 'Boolean', + 'Number', + 'String', + 'Function', + 'Array', + 'Date', + 'RegExp', + 'Object', + 'Error' ]; for (var n = 0; n < names.length; n++) { class2type['[object ' + names[n] + ']'] = names[n].toLowerCase(); } - var getType = function (obj) { + var getType = function(obj) { if (obj == null) { return obj + ''; } - return typeof obj === 'object' || typeof obj === 'function' ? - class2type[toString.call(obj)] || 'object' : - typeof obj; + return typeof obj === 'object' || typeof obj === 'function' + ? class2type[toString.call(obj)] || 'object' + : typeof obj; }; // -- End borrow -- - - var friendlyWelcome = function () { + var friendlyWelcome = function() { // p5.js brand - magenta: #ED225D //var astrixBgColor = 'transparent'; //var astrixTxtColor = '#ED225D'; @@ -50,13 +51,13 @@ if (typeof IS_MINIFIED !== 'undefined') { //var welcomeTextColor = 'white'; console.log( ' _ \n' + - ' /\\| |/\\ \n' + - ' \\ ` \' / \n' + - ' / , . \\ \n' + - ' \\/|_|\\/ ' + - '\n\n> p5.js says: Welcome! ' + - 'This is your friendly debugger. ' + - 'To turn me off switch to using “p5.min.js”.' + ' /\\| |/\\ \n' + + " \\ ` ' / \n" + + ' / , . \\ \n' + + ' \\/|_|\\/ ' + + '\n\n> p5.js says: Welcome! ' + + 'This is your friendly debugger. ' + + 'To turn me off switch to using “p5.min.js”.' ); }; @@ -76,27 +77,30 @@ if (typeof IS_MINIFIED !== 'undefined') { // p5.js blue, p5.js orange, auto dark green; fallback p5.js darkened magenta // See testColors below for all the color codes and names var typeColors = ['#2D7BB6', '#EE9900', '#4DB200', '#C83C00']; - var report = function (message, func, color) { + var report = function(message, func, color) { if (doFriendlyWelcome) { friendlyWelcome(); doFriendlyWelcome = false; - } if ('undefined' === getType(color)) { color = '#B40033'; // dark magenta - } else if (getType(color) === 'number') { // Type to color + } else if (getType(color) === 'number') { + // Type to color color = typeColors[color]; } if (func.substring(0, 4) === 'load') { console.log( - '> p5.js says: ' + message + - '[https://github.com/processing/p5.js/wiki/Local-server]' + '> p5.js says: ' + + message + + '[https://github.com/processing/p5.js/wiki/Local-server]' ); - } - else { + } else { console.log( - '> p5.js says: ' + message + ' [http://p5js.org/reference/#p5/' + func + - ']' + '> p5.js says: ' + + message + + ' [http://p5js.org/reference/#p5/' + + func + + ']' ); } }; @@ -123,28 +127,39 @@ if (typeof IS_MINIFIED !== 'undefined') { fileType: 'font', method: 'loadFont', message: ' hosting the font online,' - }, + } }; - p5._friendlyFileLoadError = function (errorType, filePath) { + p5._friendlyFileLoadError = function(errorType, filePath) { var errorInfo = errorCases[errorType]; - var message = 'It looks like there was a problem' + - ' loading your ' + errorInfo.fileType + '.' + - ' Try checking if the file path [' + filePath + '] is correct,' + - (errorInfo.message || '') + ' or running a local server.'; + var message = + 'It looks like there was a problem' + + ' loading your ' + + errorInfo.fileType + + '.' + + ' Try checking if the file path [' + + filePath + + '] is correct,' + + (errorInfo.message || '') + + ' or running a local server.'; report(message, errorInfo.method, FILE_LOAD); }; var docCache = {}; var builtinTypes = [ - 'number', 'string', 'boolean', - 'constant', 'function', 'integer' + 'number', + 'string', + 'boolean', + 'constant', + 'function', + 'integer' ]; // validateParameters() helper functions: // lookupParamDoc() for querying data.json - var lookupParamDoc = function (func) { - var queryResult = arrDoc.classitems. - filter(function (x) { return x.name === func; }); + var lookupParamDoc = function(func) { + var queryResult = arrDoc.classitems.filter(function(x) { + return x.name === func; + }); // different JSON structure for funct with multi-format var overloads = []; if (queryResult[0].hasOwnProperty('overloads')) { @@ -157,13 +172,12 @@ if (typeof IS_MINIFIED !== 'undefined') { var mapConstants = {}; var maxParams = 0; - overloads.forEach(function (formats) { + overloads.forEach(function(formats) { if (maxParams < formats.length) { maxParams = formats.length; } - formats.forEach(function (format) { + formats.forEach(function(format) { format.types = format.type.split('|').map(function ct(type) { - // array if (type.substr(type.length - 2, 2) === '[]') { return { @@ -176,7 +190,6 @@ if (typeof IS_MINIFIED !== 'undefined') { // contant if (lowerType === 'constant') { - var constant; if (mapConstants.hasOwnProperty(format.name)) { constant = mapConstants[format.name]; @@ -187,7 +200,8 @@ if (typeof IS_MINIFIED !== 'undefined') { var names = []; constant = mapConstants[format.name] = { - values: values, names: names + values: values, + names: names }; var myArray = myRe.exec(format.description); @@ -208,8 +222,10 @@ if (typeof IS_MINIFIED !== 'undefined') { } } return { - name: type, builtin: lowerType, - names: constant.names, values: constant.values + name: type, + builtin: lowerType, + names: constant.names, + values: constant.values }; } @@ -224,7 +240,9 @@ if (typeof IS_MINIFIED !== 'undefined') { // p5 class type var t = window; - type.split('.').forEach(function (p) { t = t && t[p]; }); + type.split('.').forEach(function(p) { + t = t && t[p]; + }); if (t) { return { name: type, prototype: t }; } @@ -235,11 +253,11 @@ if (typeof IS_MINIFIED !== 'undefined') { }); return { overloads: overloads, - maxParams: maxParams, + maxParams: maxParams }; }; - var testParamType = function (param, type) { + var testParamType = function(param, type) { var isArray = param instanceof Array; if (type.array && isArray) { for (var i = 0; i < param.length; i++) { @@ -248,24 +266,23 @@ if (typeof IS_MINIFIED !== 'undefined') { } } return true; - } - else if (type.prototype) { + } else if (type.prototype) { return param instanceof type.prototype; - } - else if (type.builtin) { + } else if (type.builtin) { switch (type.builtin) { case 'number': - return (typeof param === 'number' || !!param && !isNaN(param)); + return typeof param === 'number' || (!!param && !isNaN(param)); case 'integer': - return (typeof param === 'number' || !!param && !isNaN(param)) && - Number(param) === Math.floor(param); + return ( + (typeof param === 'number' || (!!param && !isNaN(param))) && + Number(param) === Math.floor(param) + ); case 'boolean': return true; case 'array': return isArray; case 'string': - return typeof param === 'number' || - typeof param === 'string'; + return typeof param === 'number' || typeof param === 'string'; case 'constant': return type.values.hasOwnProperty(param); case 'function': @@ -278,7 +295,7 @@ if (typeof IS_MINIFIED !== 'undefined') { // testType() for non-object type parameter validation // Returns true if PASS, false if FAIL - var testParamTypes = function (param, types) { + var testParamTypes = function(param, types) { for (var i = 0; i < types.length; i++) { if (testParamType(param, types[i])) { return true; @@ -287,18 +304,18 @@ if (typeof IS_MINIFIED !== 'undefined') { return false; }; - var testParamFormat = function (args, formats) { + var testParamFormat = function(args, formats) { var errorArray = []; for (var p = 0; p < formats.length; p++) { var arg = args[p]; var format = formats[p]; - var argType = typeof (arg); + var argType = typeof arg; if ('undefined' === argType || null === arg) { if (format.optional !== true) { errorArray.push({ type: 'EMPTY_VAR', position: p, - format: format, + format: format }); } } else if (!testParamTypes(arg, format.types)) { @@ -314,20 +331,26 @@ if (typeof IS_MINIFIED !== 'undefined') { }; // function for generating console.log() msg - p5._friendlyParamError = function (errorObj, func) { + p5._friendlyParamError = function(errorObj, func) { var message; function formatType() { var format = errorObj.format; - return format.types.map(function (type) { - return type.names ? type.names.join('|') : type.name; - }).join('|'); + return format.types + .map(function(type) { + return type.names ? type.names.join('|') : type.name; + }) + .join('|'); } switch (errorObj.type) { case 'EMPTY_VAR': - message = func + '() was expecting ' + formatType() + - ' for parameter #' + errorObj.position + + message = + func + + '() was expecting ' + + formatType() + + ' for parameter #' + + errorObj.position + ' (zero-based index), received an empty variable instead.' + ' If not intentional, this is often a problem with scope:' + ' [https://p5js.org/examples/data-variable-scope.html]'; @@ -335,46 +358,56 @@ if (typeof IS_MINIFIED !== 'undefined') { case 'WRONG_TYPE': var arg = errorObj.arg; var argType = arg instanceof Array ? 'array' : arg.name || typeof arg; - message = func + '() was expecting ' + formatType() + - ' for parameter #' + errorObj.position + - ' (zero-based index), received ' + argType + ' instead'; + message = + func + + '() was expecting ' + + formatType() + + ' for parameter #' + + errorObj.position + + ' (zero-based index), received ' + + argType + + ' instead'; break; case 'WRONG_ARGUMENT_COUNT': - message = func + '() was expecting ' + errorObj.maxParams + - ' arguments, but received ' + errorObj.argCount; + message = + func + + '() was expecting ' + + errorObj.maxParams + + ' arguments, but received ' + + errorObj.argCount; break; } if (message) { try { var re = /Function\.validateParameters.*[\r\n].*[\r\n].*\(([^)]*)/; - var location = re.exec((new Error()).stack)[1]; + var location = re.exec(new Error().stack)[1]; if (location) { message += ' at ' + location; } - } catch (err) { } + } catch (err) {} report(message + '.', func, ERR_PARAMS); } }; /** - * Validates parameters - * param {String} func the name of the function - * param {Array} args user input arguments - * - * example: - * var a; - * ellipse(10,10,a,5); - * console ouput: - * "It looks like ellipse received an empty variable in spot #2." - * - * example: - * ellipse(10,"foo",5,5); - * console output: - * "ellipse was expecting a number for parameter #1, - * received "foo" instead." - */ + * Validates parameters + * param {String} func the name of the function + * param {Array} args user input arguments + * + * example: + * var a; + * ellipse(10,10,a,5); + * console ouput: + * "It looks like ellipse received an empty variable in spot #2." + * + * example: + * ellipse(10,"foo",5,5); + * console output: + * "ellipse was expecting a number for parameter #1, + * received "foo" instead." + */ p5._validateParameters = function validateParameters(func, args) { if (p5.disableFriendlyErrors) { return; // skip FES @@ -400,7 +433,7 @@ if (typeof IS_MINIFIED !== 'undefined') { errorArray.push({ type: 'WRONG_ARGUMENT_COUNT', argCount: args.length, - maxParams: docs.maxParams, + maxParams: docs.maxParams }); } @@ -410,7 +443,6 @@ if (typeof IS_MINIFIED !== 'undefined') { } }; - /** * Prints out all the colors in the color pallete with white text. * For color blindness testing. @@ -438,7 +470,6 @@ if (typeof IS_MINIFIED !== 'undefined') { p5.prototype._validateParameters = p5.validateParameters; } - // This is a lazily-defined list of p5 symbols that may be // misused by beginners at top-level code, outside of setup/draw. We'd like // to detect these errors and help the user by suggesting they move them @@ -446,39 +477,42 @@ if (typeof IS_MINIFIED !== 'undefined') { // // For more details, see https://github.com/processing/p5.js/issues/1121. var misusedAtTopLevelCode = null; -var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' + +var FAQ_URL = + 'https://github.com/processing/p5.js/wiki/' + 'Frequently-Asked-Questions' + '#why-cant-i-assign-variables-using-p5-functions-and-' + 'variables-before-setup'; -var defineMisusedAtTopLevelCode = function () { +var defineMisusedAtTopLevelCode = function() { var uniqueNamesFound = {}; - var getSymbols = function (obj) { - return Object.getOwnPropertyNames(obj).filter(function (name) { - if (name[0] === '_') { - return false; - } - if (name in uniqueNamesFound) { - return false; - } + var getSymbols = function(obj) { + return Object.getOwnPropertyNames(obj) + .filter(function(name) { + if (name[0] === '_') { + return false; + } + if (name in uniqueNamesFound) { + return false; + } - uniqueNamesFound[name] = true; + uniqueNamesFound[name] = true; - return true; - }).map(function (name) { - var type; - - if (typeof (obj[name]) === 'function') { - type = 'function'; - } else if (name === name.toUpperCase()) { - type = 'constant'; - } else { - type = 'variable'; - } + return true; + }) + .map(function(name) { + var type; + + if (typeof obj[name] === 'function') { + type = 'function'; + } else if (name === name.toUpperCase()) { + type = 'constant'; + } else { + type = 'variable'; + } - return { name: name, type: type }; - }); + return { name: name, type: type }; + }); }; misusedAtTopLevelCode = [].concat( @@ -492,12 +526,12 @@ var defineMisusedAtTopLevelCode = function () { // This will ultimately ensure that we report the most specific error // possible to the user, e.g. advising them about HALF_PI instead of PI // when their code misuses the former. - misusedAtTopLevelCode.sort(function (a, b) { + misusedAtTopLevelCode.sort(function(a, b) { return b.name.length - a.name.length; }); }; -var helpForMisusedAtTopLevelCode = function (e, log) { +var helpForMisusedAtTopLevelCode = function(e, log) { if (!log) { log = console.log.bind(console); } @@ -515,7 +549,7 @@ var helpForMisusedAtTopLevelCode = function (e, log) { // return; //} - misusedAtTopLevelCode.some(function (symbol) { + misusedAtTopLevelCode.some(function(symbol) { // Note that while just checking for the occurrence of the // symbol name in the error message could result in false positives, // a more rigorous test is difficult because different browsers @@ -530,11 +564,16 @@ var helpForMisusedAtTopLevelCode = function (e, log) { // * Uncaught ReferenceError: PI is not defined (Chrome) if (e.message && e.message.match('\\W?' + symbol.name + '\\W') !== null) { - log('Did you just try to use p5.js\'s ' + symbol.name + - (symbol.type === 'function' ? '() ' : ' ') + symbol.type + - '? If so, you may want to ' + - 'move it into your sketch\'s setup() function.\n\n' + - 'For more details, see: ' + FAQ_URL); + log( + "Did you just try to use p5.js's " + + symbol.name + + (symbol.type === 'function' ? '() ' : ' ') + + symbol.type + + '? If so, you may want to ' + + "move it into your sketch's setup() function.\n\n" + + 'For more details, see: ' + + FAQ_URL + ); return true; } }); @@ -550,7 +589,7 @@ if (document.readyState !== 'complete') { // global (non-instance mode) p5 APIs are used at the top-level // scope of a file, so we'll unbind our error listener now to make // sure we don't log false positives later. - window.addEventListener('load', function () { + window.addEventListener('load', function() { window.removeEventListener('error', helpForMisusedAtTopLevelCode, false); }); } diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 3c8bfee96c..44610f17ff 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -243,7 +243,7 @@ p5.prototype.image = function( // set defaults per spec: https://goo.gl/3ykfOq p5._validateParameters('image', arguments); - + var defW = img.width; var defH = img.height; diff --git a/tasks/build/browserify.js b/tasks/build/browserify.js index 366e7931b3..9eb192d8ac 100644 --- a/tasks/build/browserify.js +++ b/tasks/build/browserify.js @@ -10,53 +10,57 @@ var bannerTemplate = module.exports = function(grunt) { var srcFilePath = require.resolve('../../src/app.js'); - grunt.registerTask('browserify', 'Compile the p5.js source with Browserify', function(param) { - - var isMin = param === 'min'; - var filename = isMin ? 'p5.pre-min.js' : 'p5.js'; - - // This file will not exist until it has been built - var libFilePath = path.resolve('lib/' + filename); - - // Reading and writing files is asynchronous - var done = this.async(); - - // Render the banner for the top of the file - var banner = grunt.template.process(bannerTemplate); - - // Invoke Browserify programatically to bundle the code - var browseified = browserify(srcFilePath, { - standalone: 'p5' - }); - - if (isMin) { - browseified = browseified.exclude('../../docs/reference/data.json'); + grunt.registerTask( + 'browserify', + 'Compile the p5.js source with Browserify', + function(param) { + var isMin = param === 'min'; + var filename = isMin ? 'p5.pre-min.js' : 'p5.js'; + + // This file will not exist until it has been built + var libFilePath = path.resolve('lib/' + filename); + + // Reading and writing files is asynchronous + var done = this.async(); + + // Render the banner for the top of the file + var banner = grunt.template.process(bannerTemplate); + + // Invoke Browserify programatically to bundle the code + var browseified = browserify(srcFilePath, { + standalone: 'p5' + }); + + if (isMin) { + browseified = browseified.exclude('../../docs/reference/data.json'); + } + + var bundle = browseified.transform('brfs').bundle(); + + // Start the generated output with the banner comment, + var code = banner + '\n'; + + // Then read the bundle into memory so we can run it through derequire + bundle + .on('data', function(data) { + code += data; + }) + .on('end', function() { + // "code" is complete: create the distributable UMD build by running + // the bundle through derequire, then write the bundle to disk. + // (Derequire changes the bundle's internal "require" function to + // something that will not interfere with this module being used + // within a separate browserify bundle.) + grunt.file.write(libFilePath, derequire(code)); + + // Print a success message + grunt.log.writeln( + '>>'.green + ' Bundle ' + ('lib/' + filename).cyan + ' created.' + ); + + // Complete the task + done(); + }); } - - var bundle = browseified - .transform('brfs') - .bundle(); - - // Start the generated output with the banner comment, - var code = banner + '\n'; - - // Then read the bundle into memory so we can run it through derequire - bundle.on('data', function(data) { - code += data; - }).on('end', function() { - - // "code" is complete: create the distributable UMD build by running - // the bundle through derequire, then write the bundle to disk. - // (Derequire changes the bundle's internal "require" function to - // something that will not interfere with this module being used - // within a separate browserify bundle.) - grunt.file.write(libFilePath, derequire(code)); - - // Print a success message - grunt.log.writeln('>>'.green + ' Bundle ' + ('lib/' + filename).cyan + ' created.'); - - // Complete the task - done(); - }); - }); + ); }; From d3f90034b9afeb18eab9137b70174f1763f6549f Mon Sep 17 00:00:00 2001 From: Spongman Date: Fri, 15 Dec 2017 14:37:07 -0800 Subject: [PATCH 14/14] prettify --- lib/addons/p5.dom.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/addons/p5.dom.js b/lib/addons/p5.dom.js index 3507f70bdd..cd7d190556 100644 --- a/lib/addons/p5.dom.js +++ b/lib/addons/p5.dom.js @@ -219,9 +219,9 @@ *
* */ - p5.prototype.removeElements =function (e) { + p5.prototype.removeElements = function(e) { p5._validateParameters('removeElements', arguments); - for (var i=0; i