1
- import * as espree from 'espree' ;
1
+ import * as acorn from 'acorn' ;
2
+ import * as walk from 'acorn-walk' ;
2
3
3
4
/**
4
5
* @for p5
@@ -14,8 +15,14 @@ function sketchVerifier(p5, fn) {
14
15
*/
15
16
fn . fetchScript = async function ( script ) {
16
17
if ( script . src ) {
17
- const contents = await fetch ( script . src ) . then ( ( res ) => res . text ( ) ) ;
18
- return contents ;
18
+ try {
19
+ const contents = await fetch ( script . src ) . then ( ( res ) => res . text ( ) ) ;
20
+ return contents ;
21
+ } catch ( error ) {
22
+ // TODO: Handle CORS error here.
23
+ console . error ( 'Error fetching script:' , error ) ;
24
+ return '' ;
25
+ }
19
26
} else {
20
27
return script . textContent ;
21
28
}
@@ -30,6 +37,8 @@ function sketchVerifier(p5, fn) {
30
37
* @returns {Promise<string> } The user's code as a string.
31
38
*/
32
39
fn . getUserCode = async function ( ) {
40
+ // TODO: think of a more robust way to get the user's code. Refer to
41
+ // https://github.com/processing/p5.js/pull/7293.
33
42
const scripts = document . querySelectorAll ( 'script' ) ;
34
43
const userCodeScript = scripts [ scripts . length - 1 ] ;
35
44
const userCode = await fn . fetchScript ( userCodeScript ) ;
@@ -42,59 +51,58 @@ function sketchVerifier(p5, fn) {
42
51
* the help of Espree parser.
43
52
*
44
53
* @method extractUserDefinedVariablesAndFuncs
45
- * @param {string } codeStr - The code to extract variables and functions from.
54
+ * @param {string } code - The code to extract variables and functions from.
46
55
* @returns {Object } An object containing the user's defined variables and functions.
47
- * @returns {string[] } [userDefinitions.variables] Array of user-defined variable names.
48
- * @returns {strings[] } [userDefinitions.functions] Array of user-defined function names.
56
+ * @returns {Array<{name: string, line: number}> } [userDefinitions.variables] Array of user-defined variable names and their line numbers .
57
+ * @returns {Array<{name: string, line: number}> } [userDefinitions.functions] Array of user-defined function names and their line numbers .
49
58
*/
50
- fn . extractUserDefinedVariablesAndFuncs = function ( codeStr ) {
59
+ fn . extractUserDefinedVariablesAndFuncs = function ( code ) {
51
60
const userDefinitions = {
52
61
variables : [ ] ,
53
62
functions : [ ]
54
63
} ;
64
+ // The line numbers from the parser are consistently off by one, add
65
+ // `lineOffset` here to correct them.
66
+ const lineOffset = - 1 ;
55
67
56
68
try {
57
- const ast = espree . parse ( codeStr , {
69
+ const ast = acorn . parse ( code , {
58
70
ecmaVersion : 2021 ,
59
71
sourceType : 'module' ,
60
- ecmaFeatures : {
61
- jsx : true
62
- }
72
+ locations : true // This helps us get the line number.
63
73
} ) ;
64
74
65
- function traverse ( node ) {
66
- const { type, declarations, id, init } = node ;
67
-
68
- switch ( type ) {
69
- case 'VariableDeclaration' :
70
- declarations . forEach ( ( { id, init } ) => {
71
- if ( id . type === 'Identifier' ) {
72
- const category = init && [ 'ArrowFunctionExpression' , 'FunctionExpression' ] . includes ( init . type )
73
- ? 'functions'
74
- : 'variables' ;
75
- userDefinitions [ category ] . push ( id . name ) ;
76
- }
75
+ walk . simple ( ast , {
76
+ VariableDeclarator ( node ) {
77
+ if ( node . id . type === 'Identifier' ) {
78
+ const category = node . init && [ 'ArrowFunctionExpression' , 'FunctionExpression' ] . includes ( node . init . type )
79
+ ? 'functions'
80
+ : 'variables' ;
81
+ userDefinitions [ category ] . push ( {
82
+ name : node . id . name ,
83
+ line : node . loc . start . line + lineOffset
84
+ } ) ;
85
+ }
86
+ } ,
87
+ FunctionDeclaration ( node ) {
88
+ if ( node . id && node . id . type === 'Identifier' ) {
89
+ userDefinitions . functions . push ( {
90
+ name : node . id . name ,
91
+ line : node . loc . start . line + lineOffset
92
+ } ) ;
93
+ }
94
+ } ,
95
+ // We consider class declarations to be a special form of variable
96
+ // declaration.
97
+ ClassDeclaration ( node ) {
98
+ if ( node . id && node . id . type === 'Identifier' ) {
99
+ userDefinitions . variables . push ( {
100
+ name : node . id . name ,
101
+ line : node . loc . start . line + lineOffset
77
102
} ) ;
78
- break ;
79
- case 'FunctionDeclaration' :
80
- if ( id ?. type === 'Identifier' ) {
81
- userDefinitions . functions . push ( id . name ) ;
82
- }
83
- break ;
84
- }
85
-
86
- for ( const key in node ) {
87
- if ( node [ key ] && typeof node [ key ] === 'object' ) {
88
- if ( Array . isArray ( node [ key ] ) ) {
89
- node [ key ] . forEach ( child => traverse ( child ) ) ;
90
- } else {
91
- traverse ( node [ key ] ) ;
92
- }
93
103
}
94
104
}
95
- }
96
-
97
- traverse ( ast ) ;
105
+ } ) ;
98
106
} catch ( error ) {
99
107
// TODO: Replace this with a friendly error message.
100
108
console . error ( 'Error parsing code:' , error ) ;
0 commit comments