diff --git a/src/core/friendly_errors/param_validator.js b/src/core/friendly_errors/param_validator.js index 790b470168..51f11d1dcb 100644 --- a/src/core/friendly_errors/param_validator.js +++ b/src/core/friendly_errors/param_validator.js @@ -573,14 +573,35 @@ function validateParams(p5, fn, lifecycles) { fn._validate = validate; // TEMP: For unit tests + // Suppress FES param checking for the duration of a callback. + // Use this to wrap internal p5 calls that happen after an await. + // NOTE: shares the same _isUserCall flag logic as the decorator below. + fn._internal = function(callback) { + const wasInternalCall = this._isUserCall; + this._isUserCall = true; + try { + return callback(); + } finally { + this._isUserCall = wasInternalCall; + } + }; + + // Skip FES validation for nested (internal) calls. + // NOTE: shares the same _isUserCall flag logic as _internal() above. p5.decorateHelper( /^(?!_).+$/, function(target, { name }){ return function(...args){ - if (!p5.disableFriendlyErrors && !p5.disableParameterValidator) { - validate(name, args); + const wasInternalCall = this._isUserCall; + this._isUserCall = true; + try { + if (!wasInternalCall && !p5.disableFriendlyErrors && !p5.disableParameterValidator) { + validate(name, args); + } + return target.apply(this, args); + } finally { + this._isUserCall = wasInternalCall; } - return target.apply(this, args); }; } ); diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index e01726aa6d..3b9ed18fd6 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -136,13 +136,15 @@ function loadingDisplaying(p5, fn){ pImg.drawingContext.drawImage(img, 0, 0); } - pImg.modified = true; - - if(successCallback){ - return successCallback(pImg); - }else{ - return pImg; - } + const cb = () => { + pImg.modified = true; + if(successCallback){ + return successCallback(pImg); + }else{ + return pImg; + } + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { p5._friendlyFileLoadError(0, path); diff --git a/src/io/files.js b/src/io/files.js index e234d981ac..80c6bb909d 100644 --- a/src/io/files.js +++ b/src/io/files.js @@ -278,8 +278,11 @@ function files(p5, fn){ try{ const { data } = await request(path, 'json'); - if (successCallback) return successCallback(data); - return data; + const cb = () => { + if (successCallback) return successCallback(data); + return data; + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { p5._friendlyFileLoadError(5, path); if(errorCallback) { @@ -414,10 +417,12 @@ function files(p5, fn){ try{ let { data } = await request(path, 'text'); - data = data.split(/\r?\n/); - - if (successCallback) return successCallback(data); - return data; + const cb = () => { + data = data.split(/\r?\n/); + if (successCallback) return successCallback(data); + return data; + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { p5._friendlyFileLoadError(3, path); if(errorCallback) { @@ -501,28 +506,30 @@ function files(p5, fn){ try{ let { data } = await request(path, 'text'); + const cb = () => { + let ret = new p5.Table(); + data = parse(data, { + separator + }); + + if(header){ + ret.columns = data.shift(); + }else{ + ret.columns = Array(data[0].length).fill(null); + } - let ret = new p5.Table(); - data = parse(data, { - separator - }); - - if(header){ - ret.columns = data.shift(); - }else{ - ret.columns = Array(data[0].length).fill(null); - } - - data.forEach(line => { - const row = new p5.TableRow(line); - ret.addRow(row); - }); + data.forEach(line => { + const row = new p5.TableRow(line); + ret.addRow(row); + }); - if (successCallback) { - return successCallback(ret); - } else { - return ret; - } + if (successCallback) { + return successCallback(ret); + } else { + return ret; + } + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { p5._friendlyFileLoadError(2, path); if(errorCallback) { @@ -686,11 +693,13 @@ function files(p5, fn){ const parser = new DOMParser(); let { data } = await request(path, 'text'); - const parsedDOM = parser.parseFromString(data, 'application/xml'); - data = new p5.XML(parsedDOM); - - if (successCallback) return successCallback(data); - return data; + const cb = () => { + const parsedDOM = parser.parseFromString(data, 'application/xml'); + data = new p5.XML(parsedDOM); + if (successCallback) return successCallback(data); + return data; + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { p5._friendlyFileLoadError(1, path); if(errorCallback) { @@ -734,9 +743,12 @@ function files(p5, fn){ fn.loadBytes = async function (path, successCallback, errorCallback) { try{ let { data } = await request(path, 'arrayBuffer'); - data = new Uint8Array(data); - if (successCallback) return successCallback(data); - return data; + const cb = () => { + data = new Uint8Array(data); + if (successCallback) return successCallback(data); + return data; + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { p5._friendlyFileLoadError(6, path); if(errorCallback) { @@ -789,8 +801,11 @@ function files(p5, fn){ fn.loadBlob = async function(path, successCallback, errorCallback) { try{ const { data } = await request(path, 'blob'); - if (successCallback) return successCallback(data); - return data; + const cb = () => { + if (successCallback) return successCallback(data); + return data; + }; + return this._internal ? this._internal(cb) : cb(); } catch(err) { if(errorCallback) { return errorCallback(err); diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index b74bb8d9fb..89b1a830d2 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -1578,9 +1578,11 @@ function font(p5, fn) { throw err; } } - if (success) return success(pfont); - - return pfont; + const cb = () => { + if (success) return success(pfont); + return pfont; + }; + return this._internal ? this._internal(cb) : cb(); }; }; diff --git a/src/webgl/loading.js b/src/webgl/loading.js index 1e804a4c4a..6f726b15cc 100755 --- a/src/webgl/loading.js +++ b/src/webgl/loading.js @@ -419,50 +419,56 @@ function loading(p5, fn){ try{ if (fileType.match(/\.stl$/i)) { const { data } = await request(path, 'arrayBuffer'); - parseSTL(model, data); + const cb = () => { + parseSTL(model, data); - if (normalize) { - model.normalize(); - } + if (normalize) { + model.normalize(); + } - if (flipU) { - model.flipU(); - } + if (flipU) { + model.flipU(); + } - if (flipV) { - model.flipV(); - } - model._makeTriangleEdges(); + if (flipV) { + model.flipV(); + } + model._makeTriangleEdges(); - if (successCallback) { - return successCallback(model); - } else { - return model; - } + if (successCallback) { + return successCallback(model); + } else { + return model; + } + }; + return this._internal ? this._internal(cb) : cb(); } else if (fileType.match(/\.obj$/i)) { const { data } = await request(path, 'text'); const lines = data.split('\n'); const parsedMaterials = await getMaterials(lines); - parseObj(model, lines, parsedMaterials); + const cb = () => { + parseObj(model, lines, parsedMaterials); - if (normalize) { - model.normalize(); - } - if (flipU) { - model.flipU(); - } - if (flipV) { - model.flipV(); - } - model._makeTriangleEdges(); + if (normalize) { + model.normalize(); + } + if (flipU) { + model.flipU(); + } + if (flipV) { + model.flipV(); + } + model._makeTriangleEdges(); - if (successCallback) { - return successCallback(model); - } else { - return model; - } + if (successCallback) { + return successCallback(model); + } else { + return model; + } + }; + return this._internal ? this._internal(cb) : cb(); } } catch(err) { p5._friendlyFileLoadError(3, path); diff --git a/src/webgl/material.js b/src/webgl/material.js index c3dff5b766..cbdc91110d 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -524,11 +524,11 @@ function material(p5, fn) { // Test if we've loaded GLSL or not by checking for the existence of `void main` let loadedShader; if (/void\s+main/.exec(fragString)) { - loadedShader = this.createFilterShader(fragString, true); + loadedShader = this._internal(() => this.createFilterShader(fragString, true)); } else { - loadedShader = withGlobalStrands(this, () => + loadedShader = this._internal(() => withGlobalStrands(this, () => this.baseFilterShader().modify(new Function(fragString)), - ); + )); } if (successCallback) { @@ -1635,7 +1635,7 @@ function material(p5, fn) { fn.loadMaterialShader = async function (url, onSuccess, onFail) { try { const cb = await urlToStrandsCallback(url); - let shader = withGlobalStrands(this, () => this.buildMaterialShader(cb)); + let shader = this._internal(() => withGlobalStrands(this, () => this.buildMaterialShader(cb))); if (onSuccess) { shader = onSuccess(shader) || shader; } @@ -1854,9 +1854,9 @@ function material(p5, fn) { fn.loadNormalShader = async function (url, onSuccess, onFail) { try { const cb = await urlToStrandsCallback(url); - let shader = this.withGlobalStrands(this, () => + let shader = this._internal(() => this.withGlobalStrands(this, () => this.buildNormalShader(cb), - ); + )); if (onSuccess) { shader = onSuccess(shader) || shader; } @@ -2020,7 +2020,7 @@ function material(p5, fn) { fn.loadColorShader = async function (url, onSuccess, onFail) { try { const cb = await urlToStrandsCallback(url); - let shader = withGlobalStrands(this, () => this.buildColorShader(cb)); + let shader = this._internal(() => withGlobalStrands(this, () => this.buildColorShader(cb))); if (onSuccess) { shader = onSuccess(shader) || shader; } @@ -2281,7 +2281,7 @@ function material(p5, fn) { fn.loadStrokeShader = async function (url, onSuccess, onFail) { try { const cb = await urlToStrandsCallback(url); - let shader = withGlobalStrands(this, () => this.buildStrokeShader(cb)); + let shader = this._internal(() => withGlobalStrands(this, () => this.buildStrokeShader(cb))); if (onSuccess) { shader = onSuccess(shader) || shader; }