1- import * as espree from 'espree' ;
1+ import * as acorn from 'acorn' ;
2+ import * as walk from 'acorn-walk' ;
23
34/**
45 * @for p5
@@ -14,8 +15,14 @@ function sketchVerifier(p5, fn) {
1415 */
1516 fn . fetchScript = async function ( script ) {
1617 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+ }
1926 } else {
2027 return script . textContent ;
2128 }
@@ -30,6 +37,8 @@ function sketchVerifier(p5, fn) {
3037 * @returns {Promise<string> } The user's code as a string.
3138 */
3239 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.
3342 const scripts = document . querySelectorAll ( 'script' ) ;
3443 const userCodeScript = scripts [ scripts . length - 1 ] ;
3544 const userCode = await fn . fetchScript ( userCodeScript ) ;
@@ -42,59 +51,58 @@ function sketchVerifier(p5, fn) {
4251 * the help of Espree parser.
4352 *
4453 * @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.
4655 * @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 .
4958 */
50- fn . extractUserDefinedVariablesAndFuncs = function ( codeStr ) {
59+ fn . extractUserDefinedVariablesAndFuncs = function ( code ) {
5160 const userDefinitions = {
5261 variables : [ ] ,
5362 functions : [ ]
5463 } ;
64+ // The line numbers from the parser are consistently off by one, add
65+ // `lineOffset` here to correct them.
66+ const lineOffset = - 1 ;
5567
5668 try {
57- const ast = espree . parse ( codeStr , {
69+ const ast = acorn . parse ( code , {
5870 ecmaVersion : 2021 ,
5971 sourceType : 'module' ,
60- ecmaFeatures : {
61- jsx : true
62- }
72+ locations : true // This helps us get the line number.
6373 } ) ;
6474
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
77102 } ) ;
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- }
93103 }
94104 }
95- }
96-
97- traverse ( ast ) ;
105+ } ) ;
98106 } catch ( error ) {
99107 // TODO: Replace this with a friendly error message.
100108 console . error ( 'Error parsing code:' , error ) ;
0 commit comments