├── README.md ├── VBAToJavaScriptTranslator.html └── vb2js.js /README.md: -------------------------------------------------------------------------------- 1 | # VBA-to-JavaScript-Translator 2 | This translator is intended to be used as an educational tool to help VBA developers get familiar with JavaScript. 3 | 4 | The code for this tool is based on regex examples found from multiple sources in forums and online. Sorry to say...I did not keep a record of all the sources I leveraged. Just know that people smarter than I am provided the basis for most of the code found here. I simply adjusted what I needed and slapped it all together into a single utility. 5 | 6 | As with most translation tools, this tool will NOT perform a 100% complete translation. 7 | It is designed to cover common constructs in VBA (enough to get you started). 8 | 9 | The idea is to enter a basic block of VBA code (be sure to include your Function/Sub wrappers) and see how the syntax would look in JavaScript. It's best if you first try something simple then progress into more advanced IF statements, loops, comparison operators, Select Case switches, etc. 10 | 11 | Currently, this translator works with: 12 | * Both Functions and Sub Procedures 13 | * Variable Declarations 14 | * Basic IF THEN Statements 15 | * SELECT CASE Statements 16 | * Most Comparison Operators 17 | * Basic FOR x TO y Loops 18 | * Most variations of DO LOOPS 19 | * Basic MSGBOX calls 20 | 21 | 22 | Known Issues: 23 | This tool currently does NOT accurately translate 24 | * Built in VBA functions 25 | * References to Office Objects 26 | * WITH Statements 27 | * STEP Constructs in FOR Loops 28 | * FOR EACH Loops (in fact these cause the tool to return nothing at all. I'm still working out why that is) 29 | 30 | I offer the source code up to anyone interested in helping make enhancements to this tool in order to develop a more robust utility for the VBA community. 31 | 32 | See working tool here: http://www.datapigtechnologies.com/VBAToJS/VBAToJavaScriptTranslator.html 33 | -------------------------------------------------------------------------------- /VBAToJavaScriptTranslator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VBA to JavaScript Translation Tool 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |

19 | This translator is intended to be used as an educational tool to help VBA developers get familiar with JavaScript. 20 |
21 | This tool will NOT perform a 100% complete translation. It is designed to cover the most used constructs in VBA (enough to get you started). 22 |
23 | Start by entering or pasting a basic block of VBA code (be sure to include your Function/Sub wrappers). 24 |
25 | Review how that code looks in JavaScript. Next, try increasingly more advanced code examples (loops, if statements, etc.). 26 |
27 | Happy Learning! -Mike Alexander datapigtechnologies.com 28 |

29 |

VBA

30 |

31 | 45 |

46 |

47 |

 

48 |

JavaScript

49 |

50 | 51 |

52 | 53 |
54 | 55 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | -------------------------------------------------------------------------------- /vb2js.js: -------------------------------------------------------------------------------- 1 | 2 | var strs=[]; 3 | 4 | function vbsTojs(vbs){ 5 | 6 | 7 | var s = vbs; 8 | var Vars = ''; 9 | var Fx = ''; 10 | var FxHead = ''; 11 | var Args = ''; 12 | 13 | 14 | //prep function block 15 | s = s.replace(/^sub/gim, "function"); 16 | s = HideStrings(s); 17 | //s = s.match(/(?:Function|Sub)[\w\W]+End\s+(?:Function|Sub)/gim)[0]; 18 | s = s.replace(/\&/gm, "+"); 19 | s = s.replace(/_\n/gm,""); 20 | s = s.replace(/:/gm,"\n"); 21 | //single line IF statements need to go to multiple lines 22 | s = s.replace(/\bthen\b[ \t](.+)/gi,"then\n$1\nEnd If"); 23 | 24 | //split block into separate lines 25 | a=s.split('\n'); 26 | 27 | //trim spaces and remove empty lines 28 | for(i=0;i-1){ 52 | a[i]=a[i].replace(/dim\s*/i,""); 53 | Vars += a[i] + ","; 54 | a[i]=''; 55 | 56 | //MSGBOX 57 | } else if (a[i].search(/^msgbox\(/i) > -1) { 58 | a[i] = a[i].replace(/^msgbox\(/i, "alert("); 59 | 60 | } else if (a[i].search(/(^msgbox\s)+(.*)/i) > -1) { 61 | a[i] = a[i].replace(/(^msgbox\s)+(.*)/i, "alert($2)"); 62 | 63 | 64 | //INPUTBOX 65 | } else if (a[i].search(/^inputbox\(/i) > -1) { 66 | a[i] = a[i].replace(/^inputbox\(/i, "prompt("); 67 | 68 | } else if (a[i].search(/(^inputbox\s)+(.*)/i) > -1) { 69 | a[i] = a[i].replace(/(^inputbox\s)+(.*)/i, "prompt($2)"); 70 | 71 | 72 | //SUB AND CALL 73 | } else if (a[i].search(/^sub\s/i) > -1) { 74 | a[i] = a[i].replace(/^sub\s/i, ""); 75 | } else if (a[i].search(/\bEnd Sub\b/i) > -1) { 76 | a[i] = a[i].replace(/\bEnd Sub\b/i, "}"); 77 | } else if (a[i].search(/\bcall \b/i) > -1) { 78 | a[i] = a[i].replace(/\bcall \b/i, ""); 79 | 80 | //OBJECTS 81 | } else if (a[i].search(/\\sSET\\s+/i) > -1) { 82 | a[i] = a[i].replace(/\\sSET\\s+/i, ""); 83 | } else if (a[i].search(/'nothing'/i) > -1) { 84 | a[i] = a[i].replace(/'nothing'/i, "null"); 85 | 86 | //FOR 87 | }else if(a[i].search(/^\bFOR\b\s+/i)>-1){ 88 | a[i]=a[i].replace(/^\bFOR\b\s+/i,""); 89 | counter = a[i].match(/^\w+/)[0]; 90 | from = a[i].match(/=\s*[\w\(\)]+/)[0]; 91 | from=from.replace(/=/,"").replace(/\s+/g,""); 92 | a[i]=a[i].replace(counter,"").replace(from,"").replace(/\bTO\b/i,""); 93 | to = a[i].match(/\s*[\w\(\)]+\s*/)[0]; 94 | to=to.replace(/=/,"").replace(/\s+/g,""); 95 | a[i] = "for(" + counter + "=" + from + "; " + counter + "<=" + to + "; " + counter + "++){" 96 | 97 | 98 | //NEXT 99 | }else if(a[i].search(/^NEXT\b/i)>-1){ 100 | a[i] = "}"; 101 | 102 | 103 | //EXIT FOR 104 | }else if(a[i].search(/\bEXIT\b\s*\bFOR\b/i)>-1){ 105 | a[i] = "break"; 106 | 107 | //IF 108 | } else if (a[i].search(/(IF\\s+\\S+\\s*)=(\\s*\\S+\\s+THEN)/i) > -1) { 109 | a[i] = a[i].replace(/(IF\\s+\\S+\\s*)=(\\s*\\S+\\s+THEN)/i, "$1==$2"); 110 | }else if(a[i].search(/^\bIF\b\s+/i)>-1){ 111 | a[i]=a[i].replace(/^\bIF\b\s+/i,""); 112 | a[i]=a[i].replace(/\bTHEN$\b/i,""); 113 | a[i]=a[i].replace(/=/g,"==").replace(/<>/g,"!="); 114 | a[i]=a[i].replace(/\bOR\b/gi,"||").replace(/\bAND\b/gi,"&&"); 115 | a[i] = "if(" + a[i] + "){"; 116 | 117 | //ELSE and ELSEIF 118 | }else if(a[i].search(/^ELSE/i)>-1){ 119 | a[i] = a[i].replace(/^ELSE/i, "}else{"); 120 | a[i] = a[i].replace(/=/g, "==").replace(/<>/g, "!="); 121 | a[i] = a[i].replace(/\bOR\b/gi, "||").replace(/\bAND\b/gi, "&&"); 122 | } else if (a[i].search(/^ELSEIF/i) > -1) { 123 | a[i] = a[i].replace(/^ELSEIF/i, "}else if{"); 124 | a[i] = a[i].replace(/=/g, "==").replace(/<>/g, "!="); 125 | a[i] = a[i].replace(/\bOR\b/gi, "||").replace(/\bAND\b/gi, "&&"); 126 | 127 | //END IF 128 | }else if(a[i].search(/^END\s*IF/i)>-1){ 129 | a[i] = "}"; 130 | 131 | //WHILE 132 | }else if(a[i].search(/^WHILE\s/i)>-1){ 133 | a[i] = a[i].replace(/^WHILE(.+)/i, "while($1){"); 134 | 135 | //WEND 136 | }else if(a[i].search(/^WEND/i)>-1){ 137 | a[i] = "}"; 138 | 139 | //DO WHILE 140 | }else if(a[i].search(/^DO\s+WHILE\s/i)>-1){ 141 | a[i] = a[i].replace(/^DO\s+WHILE(.+)/i, "while($1){"); 142 | 143 | // there is no DO UNTIL equiv in JavaScript - use DO WHILE instead 144 | } else if (a[i].search(/^DO\s+UNTIL\s/i) > -1) { 145 | a[i] = a[i].replace(/^DO\s+WHILE(.+)/i, "while($1){"); 146 | 147 | //LOOP 148 | }else if(a[i].search(/^LOOP$/i)>-1){ 149 | a[i] = "}"; 150 | 151 | //EXIT FUNCTION 152 | }else if(a[i].search(/\bEXIT\b\s*\bFUNCTION\b/i)>-1){ 153 | a[i] = "return"; 154 | 155 | //STEP 156 | } else if (a[i].search(/\sSTEP\s/i) > -1) { 157 | a[i] = a[i].replace(/\sSTEP\s/i, "+"); 158 | 159 | //SELECT CASE 160 | }else if(a[i].search(/^SELECT\s+CASE(.+$)/i)>-1){ 161 | a[i]=a[i].replace(/^SELECT\s+CASE(.+$)/i,"switch($1){"); 162 | }else if(a[i].search(/^END\s+SELECT/i)>-1){ 163 | a[i] = "}"; 164 | }else if(a[i].search(/^CASE\s+ELSE/i)>-1){ 165 | a[i] = "default:"; 166 | }else if(a[i].search(/^CASE[\w\W]+$/i)>-1){ 167 | a[i] = a[i] + ":" ; 168 | 169 | 170 | //ERROR HANDLING 171 | } else if (a[i].search(/^On\\s+Error\\s+Resume\\s+Next.*[\r\n]/i) > -1) { 172 | a[i] = a[i].replace(/^On\\s+Error\\s+Resume\\s+Next.*[\r\n]/i, "window.onerror=null\r\n"); 173 | } else if (a[i].search(/^On\\s+Error\\s+.+.*[\r\n]/i) > -1) { 174 | a[i] = a[i].replace(/^On\\s+Error\\s+.+.*[\r\n]/i, "window.detachEvent('onerror')\r\n"); 175 | 176 | 177 | //COMPARISON 178 | } else if (a[i].search(/(?=\\s*)&(?!#|[a-z]+;)/i) > -1) { 179 | a[i] = a[i].replace(/(?=\\s*)&(?!#|[a-z]+;)/i, "+"); 180 | } else if (a[i].search(/(\s+)NOT(\s+)/i) > -1) { 181 | a[i] = a[i].replace(/(\s+)NOT(\s+)/i, "$1!$2"); 182 | } else if (a[i].search(/(\s*)<>(\s*)/i) > -1) { 183 | a[i] = a[i].replace(/(\s*)<>(\s*)/i, "$1!=$2"); 184 | } else if (a[i].search(/(\s+)AND(\s+)/i) > -1) { 185 | a[i] = a[i].replace(/(\s+)AND(\s+)/i, "$1&&$2"); 186 | } else if (a[i].search(/(\s+)OR(\s+)/i) > -1) { 187 | a[i] = a[i].replace(/(\s+)OR(\s+)/i, "$1||$2"); 188 | 189 | 190 | //OPTION EXPLICIT AND CONST 191 | } else if (a[i].search(/^CONST/i) > -1) { 192 | a[i] = a[i].replace(/^CONST/i,"const"); 193 | } else if (a[i].search(/^Option\\s+Explicit.*[\r\n]/i) > -1) { 194 | a[i] = a[i].replace(/^Option\\s+Explicit.*[\r\n]/i, ""); 195 | } 196 | 197 | else{ 198 | //alert(a[i]); 199 | } 200 | 201 | 202 | } 203 | 204 | 205 | //OTHER STUFF 206 | for (i = 0; i < a.length; i++) { 207 | //comments 208 | a[i] = a[i].replace(/^\'/i, "//"); 209 | //attempt to catch inline comments 210 | a[i] = a[i].replace(/\s\s\'/i, " //"); 211 | 212 | a[i] = a[i].replace(/\sByVal\s/i, " "); 213 | a[i] = a[i].replace(/\sByRef\s/i, " "); 214 | a[i] = a[i].replace(/vbCRLF/i, "\\r\\n"); 215 | a[i] = a[i].replace(/vbCR/i, "\\r"); 216 | a[i] = a[i].replace(/vbLF/i, "\\n"); 217 | a[i] = a[i].replace(/vbTab/i, "\\t"); 218 | a[i] = a[i].replace(/vbOK/i, "1"); 219 | a[i] = a[i].replace(/vbCancel/i, "2"); 220 | a[i] = a[i].replace(/vbAbort/i, "3"); 221 | a[i] = a[i].replace(/vbRetry/i, "4"); 222 | a[i] = a[i].replace(/vbIgnore/i, "5"); 223 | a[i] = a[i].replace(/vbYes/i, "6"); 224 | a[i] = a[i].replace(/vbNo/i, "7"); 225 | a[i] = a[i].replace(/vbBinaryCompare/i, "0"); 226 | a[i] = a[i].replace(/vbTextCompare/i, "1"); 227 | a[i] = a[i].replace(/vbUseDefault/i, "-2"); 228 | a[i] = a[i].replace(/vbTrue/i, "-1"); 229 | a[i] = a[i].replace(/vbFalse/i, "0"); 230 | } 231 | 232 | 233 | 234 | //alert(a.join("*")); 235 | Vars = Vars.replace(/\s*AS\s+\w+\s*/gi,""); 236 | if(Vars!="") Vars = "var " + Vars.replace(/,$/,";").replace(/,/g,", "); 237 | FxHead + '\n' + Vars; 238 | 239 | a=a.filter(function(val) { return val !== ""; }) //remove empty items 240 | 241 | for(i=0;i-1) a[i]+=";"; 243 | } 244 | 245 | ss = FxHead + '\n' + Vars + '\n' + a.join('\n') + '\n}'; 246 | 247 | ss = ss.replace(new RegExp(Fx+"\\s*=\\s*","gi"),"return "); 248 | 249 | ss = UnHideStrings(ss); 250 | 251 | return jsIndenter(ss); 252 | } 253 | 254 | 255 | 256 | 257 | //----------------------------------------------------- 258 | 259 | function jsIndenter(js){ 260 | 261 | var a=js.split('\n var'); 262 | var s = ''; 263 | 264 | //trim 265 | for(i=0;i-1) margin += 4 ; 273 | 274 | if(a[i].indexOf("}")>-1) { margin -= 4; } 275 | 276 | if(margin<0) margin = 0; 277 | 278 | a[i] = StrFill(margin," ") + a[i] ; 279 | } 280 | return a.join('\n'); 281 | } 282 | 283 | 284 | function StrFill(Count,StrToFill){ 285 | var objStr,idx; 286 | if(StrToFill=="" || Count==0){ 287 | return ""; 288 | } 289 | objStr=""; 290 | for(idx=1;idx<=Count;idx++){ 291 | objStr += StrToFill; 292 | } 293 | return objStr; 294 | } 295 | 296 | function HideStrings(text){ 297 | 298 | const x = String.fromCharCode(7); 299 | const xxx = String.fromCharCode(8); 300 | 301 | text = text.replace(/"""/gim, '"'+xxx); //hide 3 quotes " " " 302 | var idx=0, f=0; 303 | while(f>-1){ 304 | f = text.search(/".+?"/gim); 305 | if(f>-1){ 306 | strs.push(text.match(/".+?"/)[0]); 307 | //alert(strs[idx]); 308 | text = text.replace(/".+?"/, x+idx+x); 309 | idx++; 310 | } 311 | } 312 | //alert(text); 313 | return text; 314 | } 315 | 316 | function UnHideStrings(text){ 317 | for(var i=0; i