1
- import * as acorn from 'acorn' ;
2
- import * as walk from 'acorn-walk' ;
1
+ import { parse } from 'acorn' ;
2
+ import { simple as walk } from 'acorn-walk' ;
3
3
import * as constants from '../constants' ;
4
+ import { loadP5Constructors } from './friendly_errors_utils' ;
4
5
5
6
/**
6
7
* @for p5
@@ -38,27 +39,6 @@ function sketchVerifier(p5, fn) {
38
39
'onended'
39
40
] ;
40
41
41
- // Mapping names of p5 types to their constructor functions.
42
- // p5Constructors:
43
- // - Color: f()
44
- // - Graphics: f()
45
- // - Vector: f()
46
- // and so on.
47
- const p5Constructors = { } ;
48
-
49
- fn . loadP5Constructors = function ( ) {
50
- // Make a list of all p5 classes to be used for argument validation
51
- // This must be done only when everything has loaded otherwise we get
52
- // an empty array
53
- for ( let key of Object . keys ( p5 ) ) {
54
- // Get a list of all constructors in p5. They are functions whose names
55
- // start with a capital letter
56
- if ( typeof p5 [ key ] === 'function' && key [ 0 ] !== key [ 0 ] . toLowerCase ( ) ) {
57
- p5Constructors [ key ] = p5 [ key ] ;
58
- }
59
- }
60
- }
61
-
62
42
/**
63
43
* Fetches the contents of a script element in the user's sketch.
64
44
*
@@ -119,13 +99,13 @@ function sketchVerifier(p5, fn) {
119
99
const lineOffset = - 1 ;
120
100
121
101
try {
122
- const ast = acorn . parse ( code , {
102
+ const ast = parse ( code , {
123
103
ecmaVersion : 2021 ,
124
104
sourceType : 'module' ,
125
105
locations : true // This helps us get the line number.
126
106
} ) ;
127
107
128
- walk . simple ( ast , {
108
+ walk ( ast , {
129
109
VariableDeclarator ( node ) {
130
110
if ( node . id . type === 'Identifier' ) {
131
111
const category = node . init && [ 'ArrowFunctionExpression' , 'FunctionExpression' ] . includes ( node . init . type )
@@ -181,7 +161,7 @@ function sketchVerifier(p5, fn) {
181
161
* @param {Array<{name: string, line: number}> } userDefinitions.functions - Array of user-defined function names and their line numbers.
182
162
* @returns {boolean } - Returns true if a conflict is found, false otherwise.
183
163
*/
184
- fn . checkForConstsAndFuncs = function ( userDefinitions ) {
164
+ fn . checkForConstsAndFuncs = function ( userDefinitions , p5Constructors ) {
185
165
const allDefinitions = [
186
166
...userDefinitions . variables ,
187
167
...userDefinitions . functions
@@ -193,7 +173,7 @@ function sketchVerifier(p5, fn) {
193
173
// reference on the p5.js website.
194
174
function generateFriendlyError ( errorType , name , line ) {
195
175
const url = `https://p5js.org/reference/#/p5/${ name } ` ;
196
- const message = `${ errorType } "${ name } " on line ${ line } is being redeclared and conflicts with a p5.js ${ errorType . toLowerCase ( ) } . JavaScript does not declaring a ${ errorType . toLowerCase ( ) } more than once. p5.js reference: ${ url } .` ;
176
+ const message = `${ errorType } "${ name } " on line ${ line } is being redeclared and conflicts with a p5.js ${ errorType . toLowerCase ( ) } . JavaScript does not support declaring a ${ errorType . toLowerCase ( ) } more than once. p5.js reference: ${ url } .` ;
197
177
return message ;
198
178
}
199
179
@@ -224,36 +204,19 @@ function sketchVerifier(p5, fn) {
224
204
}
225
205
}
226
206
227
- // Get the names of all p5.js functions which are available globally
228
- const classesWithGlobalFns = [ 'Renderer' , 'Renderer2D' , 'RendererGL' ] ;
207
+ // The new rules for attaching anything to global are (if true for both of
208
+ // the following):
209
+ // - It is a member of p5.prototype
210
+ // - Its name does not start with `_`
229
211
const globalFunctions = new Set (
230
- classesWithGlobalFns . flatMap ( className =>
231
- Object . keys ( p5Constructors [ className ] ?. prototype || { } )
232
- )
212
+ Object . keys ( p5 . prototype ) . filter ( key => ! key . startsWith ( '_' ) )
233
213
) ;
234
214
235
215
for ( let { name, line } of allDefinitions ) {
236
216
if ( ! ignoreFunction . includes ( name ) && globalFunctions . has ( name ) ) {
237
- for ( let className of classesWithGlobalFns ) {
238
- const prototypeFunc = p5Constructors [ className ] ?. prototype [ name ] ;
239
- if ( prototypeFunc && checkForRedefinition ( name , prototypeFunc , line , "Function" ) ) {
240
- return true ;
241
- }
242
- }
243
- }
244
- }
245
-
246
- // Additional check for other p5 constructors
247
- const otherP5ConstructorKeys = Object . keys ( p5Constructors ) . filter (
248
- key => ! classesWithGlobalFns . includes ( key )
249
- ) ;
250
- for ( let { name, line } of allDefinitions ) {
251
- for ( let key of otherP5ConstructorKeys ) {
252
- if ( p5Constructors [ key ] . prototype [ name ] !== undefined ) {
253
- const prototypeFunc = p5Constructors [ key ] . prototype [ name ] ;
254
- if ( prototypeFunc && checkForRedefinition ( name , prototypeFunc , line , "Function" ) ) {
255
- return true ;
256
- }
217
+ const prototypeFunc = p5 . prototype [ name ] ;
218
+ if ( prototypeFunc && checkForRedefinition ( name , prototypeFunc , line , "Function" ) ) {
219
+ return true ;
257
220
}
258
221
}
259
222
}
@@ -262,10 +225,18 @@ function sketchVerifier(p5, fn) {
262
225
}
263
226
264
227
fn . run = async function ( ) {
228
+ const p5Constructors = await new Promise ( resolve => {
229
+ if ( document . readyState === 'complete' ) {
230
+ resolve ( loadP5Constructors ( p5 ) ) ;
231
+ } else {
232
+ window . addEventListener ( 'load' , ( ) => resolve ( loadP5Constructors ( p5 ) ) ) ;
233
+ }
234
+ } ) ;
235
+
265
236
const userCode = await fn . getUserCode ( ) ;
266
237
const userDefinedVariablesAndFuncs = fn . extractUserDefinedVariablesAndFuncs ( userCode ) ;
267
238
268
- if ( fn . checkForConstsAndFuncs ( userDefinedVariablesAndFuncs ) ) {
239
+ if ( fn . checkForConstsAndFuncs ( userDefinedVariablesAndFuncs , p5Constructors ) ) {
269
240
return ;
270
241
}
271
242
}
@@ -275,5 +246,4 @@ export default sketchVerifier;
275
246
276
247
if ( typeof p5 !== 'undefined' ) {
277
248
sketchVerifier ( p5 , p5 . prototype ) ;
278
- p5 . prototype . loadP5Constructors ( ) ;
279
249
}
0 commit comments