@@ -116,8 +116,43 @@ if (typeof IS_MINIFIED !== 'undefined') {
116116
117117 //these regex are used to perform variable extraction
118118 //visit https://regexr.com/ for the detailed view
119- const varName = / (?: (?: l e t | c o n s t | v a r ) \s + ) ? ( [ \w $ ] + ) / ;
120- const varNameWithComma = / (?: (?: l e t | c o n s t | v a r ) \s + ) ? ( [ \w $ , ] + ) / ;
119+ const optionalVarKeyword = / (?: (?: l e t | c o n s t | v a r ) \s + ) ? / ;
120+
121+ // Bracketed expressions start with an opening bracket, some amount of non
122+ // bracket characters, then a closing bracket. Note that this won't properly
123+ // parse nested brackets: `constrain(millis(), 0, 1000)` will match
124+ // `constrain(millis()` only, but will still fail gracefully and not try to
125+ // mistakenly read any subsequent code as assignment expressions.
126+ const roundBracketedExpr = / (?: \( [ ^ ) ] * \) ) / ;
127+ const squareBracketedExpr = / (?: \[ [ ^ \] ] * \] ) / ;
128+ const curlyBracketedExpr = / (?: \{ [ ^ } ] * \} ) / ;
129+ const bracketedExpr = new RegExp (
130+ [ roundBracketedExpr , squareBracketedExpr , curlyBracketedExpr ]
131+ . map ( regex => regex . source )
132+ . join ( '|' )
133+ ) ;
134+
135+ // In an a = b expression, `b` can be any character up to a newline or comma,
136+ // unless the comma is inside of a bracketed expression of some kind (to make
137+ // sure we parse function calls with multiple arguments properly.)
138+ const rightHandSide = new RegExp ( '(?:' + bracketedExpr . source + '|[^\\n,])+' ) ;
139+
140+ const leftHandSide = / ( [ \w $ ] + ) / ;
141+ const assignmentOperator = / \s * = \s * / ;
142+ const singleAssignment = new RegExp (
143+ leftHandSide . source + assignmentOperator . source + rightHandSide . source
144+ ) ;
145+ const listSeparator = / , \s * / ;
146+ const oneOrMoreAssignments = new RegExp (
147+ '(?:' +
148+ singleAssignment . source +
149+ listSeparator . source +
150+ ')*' +
151+ singleAssignment . source
152+ ) ;
153+ const assignmentStatement = new RegExp (
154+ '^' + optionalVarKeyword . source + oneOrMoreAssignments . source
155+ ) ;
121156 const letConstName = / (?: (?: l e t | c o n s t ) \s + ) ( [ \w $ ] + ) / ;
122157
123158 /**
@@ -133,27 +168,12 @@ if (typeof IS_MINIFIED !== 'undefined') {
133168 //extract variable names from the user's code
134169 let matches = [ ] ;
135170 linesArray . forEach ( ele => {
136- if ( ele . includes ( ',' ) ) {
137- matches . push (
138- ...ele . split ( ',' ) . flatMap ( s => {
139- //below RegExps extract a, b, c from let/const a=10, b=20, c;
140- //visit https://regexr.com/ for the detailed view.
141- let match ;
142- if ( s . includes ( '=' ) ) {
143- match = s . match ( / ( \w + ) \s * (? = = ) / i) ;
144- if ( match !== null ) return match [ 1 ] ;
145- } else if ( ! s . match ( new RegExp ( '[[]{}]' ) ) ) {
146- let m = s . match ( varName ) ;
147- if ( m !== null ) return s . match ( varNameWithComma ) [ 1 ] ;
148- } else return [ ] ;
149- } )
150- ) ;
151- } else {
152- //extract a from let/const a=10;
153- //visit https://regexr.com/ for the detailed view.
154- const match = ele . match ( letConstName ) ;
155- if ( match !== null ) matches . push ( match [ 1 ] ) ;
156- }
171+ // Match 0 is the part of the line of code that the regex looked at.
172+ // Matches 1 and onward will be only the variable names on the left hand
173+ // side of assignment expressions.
174+ const match = ele . match ( assignmentStatement ) ;
175+ if ( ! match ) return ;
176+ matches . push ( ...match . slice ( 1 ) . filter ( group => group !== undefined ) ) ;
157177 } ) ;
158178 //check if the obtained variables are a part of p5.js or not
159179 checkForConstsAndFuncs ( matches ) ;
0 commit comments