| 1 | Index: syntax.js |
|---|
| 2 | =================================================================== |
|---|
| 3 | --- syntax.js (revision 0) |
|---|
| 4 | +++ syntax.js (revision 1277) |
|---|
| 5 | @@ -0,0 +1,3 @@ |
|---|
| 6 | +dojo.provide("dojo.syntax"); |
|---|
| 7 | +dojo.require('dojo.syntax.*'); |
|---|
| 8 | + |
|---|
| 9 | |
|---|
| 10 | Property changes on: syntax.js |
|---|
| 11 | ___________________________________________________________________ |
|---|
| 12 | Name: svn:eol-style |
|---|
| 13 | + native |
|---|
| 14 | |
|---|
| 15 | Index: syntax/LICENSE |
|---|
| 16 | =================================================================== |
|---|
| 17 | --- syntax/LICENSE (revision 0) |
|---|
| 18 | +++ syntax/LICENSE (revision 1277) |
|---|
| 19 | @@ -0,0 +1,28 @@ |
|---|
| 20 | +License Disclaimer: |
|---|
| 21 | + |
|---|
| 22 | + All contents of this directory are Copyright (c) the Dojo Foundation, with the |
|---|
| 23 | + following exceptions: |
|---|
| 24 | + ------------------------------------------------------------------------------- |
|---|
| 25 | + |
|---|
| 26 | + jslint.js: |
|---|
| 27 | + * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) |
|---|
| 28 | + * Distributed under a BSD like license: |
|---|
| 29 | + Permission is hereby granted, free of charge, to any person obtaining a copy of |
|---|
| 30 | + this software and associated documentation files (the "Software"), to deal in |
|---|
| 31 | + the Software without restriction, including without limitation the rights to |
|---|
| 32 | + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|---|
| 33 | + of the Software, and to permit persons to whom the Software is furnished to do |
|---|
| 34 | + so, subject to the following conditions: |
|---|
| 35 | + |
|---|
| 36 | + The above copyright notice and this permission notice shall be included in all |
|---|
| 37 | + copies or substantial portions of the Software. |
|---|
| 38 | + |
|---|
| 39 | + The Software shall be used for Good, not Evil. |
|---|
| 40 | + |
|---|
| 41 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|---|
| 42 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|---|
| 43 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|---|
| 44 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|---|
| 45 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|---|
| 46 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|---|
| 47 | + SOFTWARE. |
|---|
| 48 | \ No newline at end of file |
|---|
| 49 | |
|---|
| 50 | Property changes on: syntax/LICENSE |
|---|
| 51 | ___________________________________________________________________ |
|---|
| 52 | Name: svn:eol-style |
|---|
| 53 | + native |
|---|
| 54 | |
|---|
| 55 | Index: syntax/__package__.js |
|---|
| 56 | =================================================================== |
|---|
| 57 | --- syntax/__package__.js (revision 0) |
|---|
| 58 | +++ syntax/__package__.js (revision 1277) |
|---|
| 59 | @@ -0,0 +1,8 @@ |
|---|
| 60 | +dojo.kwCompoundRequire({ |
|---|
| 61 | + common: [ |
|---|
| 62 | + "dojo.syntax", |
|---|
| 63 | + "dojo.syntax.common", |
|---|
| 64 | + "dojo.syntax.jslint" |
|---|
| 65 | + ] |
|---|
| 66 | +}); |
|---|
| 67 | +dojo.provide("dojo.syntax.*"); |
|---|
| 68 | \ No newline at end of file |
|---|
| 69 | |
|---|
| 70 | Property changes on: syntax/__package__.js |
|---|
| 71 | ___________________________________________________________________ |
|---|
| 72 | Name: svn:eol-style |
|---|
| 73 | + native |
|---|
| 74 | |
|---|
| 75 | Index: syntax/common.js |
|---|
| 76 | =================================================================== |
|---|
| 77 | --- syntax/common.js (revision 0) |
|---|
| 78 | +++ syntax/common.js (revision 1277) |
|---|
| 79 | @@ -0,0 +1,188 @@ |
|---|
| 80 | +dojo.provide('dojo.syntax.common'); |
|---|
| 81 | +dojo.require('dojo.syntax.jslint'); |
|---|
| 82 | +dojo.require('dojo.lang.*'); |
|---|
| 83 | +// The override happens at the very end... |
|---|
| 84 | + |
|---|
| 85 | + |
|---|
| 86 | +dojo.syntax.check = function(/* string */ code, /* string */name,/* string */checker){ |
|---|
| 87 | + //summary: check code against checker. |
|---|
| 88 | + // code is the actual JS code to check. |
|---|
| 89 | + // name is the uri generally. |
|---|
| 90 | + // checker is which checker to use. currently only 'jslint' is supported. |
|---|
| 91 | + // |
|---|
| 92 | + // in djConfig: syntaxWarn is a boolean. |
|---|
| 93 | + // if true, it will continue running on error.. otherwise it will stop |
|---|
| 94 | + // in djConfig: syntaxOptions: |
|---|
| 95 | + // { |
|---|
| 96 | + // browser : true if the standard browser globals should be predefined |
|---|
| 97 | + // cap : true if upper case HTML should be allowed |
|---|
| 98 | + // debug : true if debugger statements should be allowed |
|---|
| 99 | + // eqeqeq : true if === should be required |
|---|
| 100 | + // evil : true if eval should be allowed |
|---|
| 101 | + // jscript : true if jscript deviations should be allowed |
|---|
| 102 | + // laxLineEnd : true if line breaks should not be checked |
|---|
| 103 | + // passfail : true if the scan should stop on first error |
|---|
| 104 | + // plusplus : true if increment/decrement should not be allowed |
|---|
| 105 | + // redef : true if var redefinition should be allowed |
|---|
| 106 | + // rhino : true if the Rhino environment globals should be predefined |
|---|
| 107 | + // undef : true if undefined variables are errors |
|---|
| 108 | + // white : true if strict whitespace rules apply |
|---|
| 109 | + // widget : true if the Yahoo Widgets globals should be predefined |
|---|
| 110 | + // skipDojo : true if skipping dojo sources should be done. |
|---|
| 111 | + // strict : true if we should be VERY strict about syntax. |
|---|
| 112 | + // warn : true if we should only warn, and keep loading despite errors. |
|---|
| 113 | + //} |
|---|
| 114 | + // returns false on error. |
|---|
| 115 | + if (checker == 'jslint'){ |
|---|
| 116 | + options = djConfig.syntaxOptions; |
|---|
| 117 | + //dojo.debug('syntax options:',options); |
|---|
| 118 | + if (!options) { |
|---|
| 119 | + options = { |
|---|
| 120 | + widget:false, |
|---|
| 121 | + undef:true, |
|---|
| 122 | + browser:true, |
|---|
| 123 | + skipDojo:true, |
|---|
| 124 | + strict:false |
|---|
| 125 | + }; |
|---|
| 126 | + } |
|---|
| 127 | + if (!options.strict){ |
|---|
| 128 | + //NOT strict mode |
|---|
| 129 | + options.jscript = true; |
|---|
| 130 | + options.skipDojo = true; |
|---|
| 131 | + } |
|---|
| 132 | + else{ |
|---|
| 133 | + //Strict mode. |
|---|
| 134 | + options.jscript = false; |
|---|
| 135 | + options.skipDojo = false; |
|---|
| 136 | + } |
|---|
| 137 | + if ((options.skipDojo)&&(name.indexOf('dojo/src') != -1)) { |
|---|
| 138 | + //dojo.debug('skipping:',name); |
|---|
| 139 | + return true; |
|---|
| 140 | + } |
|---|
| 141 | + //Time to actually check. |
|---|
| 142 | + var err = dojo.syntax.jslint(code,options); |
|---|
| 143 | + if (!err) { |
|---|
| 144 | + //dojo.debug('error'); |
|---|
| 145 | + //var errs = dojo.syntax.jslint.errors; |
|---|
| 146 | + dojo.syntax.prettyPrint(dojo.syntax.jslint.errors,name); |
|---|
| 147 | + if (options.warn){ |
|---|
| 148 | + //return a fake clean.. |
|---|
| 149 | + return true; |
|---|
| 150 | + } |
|---|
| 151 | + return false; |
|---|
| 152 | + } else { |
|---|
| 153 | + //no error happened. |
|---|
| 154 | + return true; |
|---|
| 155 | + } |
|---|
| 156 | + } else { |
|---|
| 157 | + dojo.debug('ERROR, jslint is the only checker supported right now'); |
|---|
| 158 | + } |
|---|
| 159 | +}; |
|---|
| 160 | + |
|---|
| 161 | +dojo.syntax.moduleExists = function(name){ |
|---|
| 162 | + for (var module in dojo.hostenv.modulePrefixes_) { |
|---|
| 163 | + if (module == name){ |
|---|
| 164 | + return true; |
|---|
| 165 | + } |
|---|
| 166 | + else if (module.indexOf('.')){ |
|---|
| 167 | + var arr = []; |
|---|
| 168 | + arr = module.split('.'); |
|---|
| 169 | + if (arr[0] == name){ |
|---|
| 170 | + return true; |
|---|
| 171 | + } |
|---|
| 172 | + } |
|---|
| 173 | + else { |
|---|
| 174 | + return false; |
|---|
| 175 | + } |
|---|
| 176 | + } |
|---|
| 177 | +}; |
|---|
| 178 | + |
|---|
| 179 | +dojo.syntax.prettyPrint = function(errs,name){ |
|---|
| 180 | + //summary: pretty print the errors. |
|---|
| 181 | + // errs is a [] of {}'s that have these elements: |
|---|
| 182 | + //{ |
|---|
| 183 | + // line : The line (relative to 0) at which the lint was found |
|---|
| 184 | + // character : The character (relative to 0) at which the lint was found |
|---|
| 185 | + // reason : The problem |
|---|
| 186 | + // evidence : The text line in which the problem occurred |
|---|
| 187 | + //} |
|---|
| 188 | + var node = document.createElement('div'); |
|---|
| 189 | + var p = document.createElement('h1'); |
|---|
| 190 | + p.innerHTML = 'error in:'+name; |
|---|
| 191 | + node.appendChild(p); |
|---|
| 192 | + var t = dojo.syntax.makeTable(errs); |
|---|
| 193 | + node.appendChild(t); |
|---|
| 194 | + //we may not have a document.body element to append to, if not, then we well do evil stuff. |
|---|
| 195 | + if (document.body){ |
|---|
| 196 | + document.body.appendChild(node); |
|---|
| 197 | + } |
|---|
| 198 | + else { |
|---|
| 199 | + // I am EVIL, but I am a worst case. |
|---|
| 200 | + document.write(node.innerHTML); |
|---|
| 201 | + } |
|---|
| 202 | +}; |
|---|
| 203 | + |
|---|
| 204 | +dojo.syntax.makeTableHeader = function(obj){ |
|---|
| 205 | + var th = document.createElement('TR'); |
|---|
| 206 | + for (var i in obj) { |
|---|
| 207 | + var newelt = document.createElement('TD'); |
|---|
| 208 | + newelt.innerHTML=i; |
|---|
| 209 | + th.appendChild(newelt); |
|---|
| 210 | + } |
|---|
| 211 | + return th; |
|---|
| 212 | +}; |
|---|
| 213 | +dojo.syntax.makeTable = function(list,opts){ |
|---|
| 214 | + //if opts.edit, then I need: |
|---|
| 215 | + // opts.id which item(by number) is the cp_id for this row. |
|---|
| 216 | + var table = document.createElement('TABLE'); |
|---|
| 217 | + table.border=1; |
|---|
| 218 | + var nums=0; |
|---|
| 219 | + for (var obj in list) { |
|---|
| 220 | + obj = list[obj]; |
|---|
| 221 | + if (nums === 0) {table.appendChild(dojo.syntax.makeTableHeader(obj))}; |
|---|
| 222 | + var newRow = document.createElement('TR'); |
|---|
| 223 | + for (var i in obj) { |
|---|
| 224 | + //dojo.debug('new td %s:%s',i,obj[i]); |
|---|
| 225 | + var newelt = document.createElement('TD'); |
|---|
| 226 | + newelt.innerHTML=obj[i]; |
|---|
| 227 | + newRow.appendChild(newelt); |
|---|
| 228 | + } |
|---|
| 229 | + nums += 1; |
|---|
| 230 | + table.appendChild(newRow); |
|---|
| 231 | + } |
|---|
| 232 | +return table; |
|---|
| 233 | +}; |
|---|
| 234 | + |
|---|
| 235 | +dojo.syntax._realGetText = dojo.hostenv.getText; |
|---|
| 236 | +dojo.syntax.getText = function(uri, async_cb, fail_ok){ |
|---|
| 237 | + //dojo.debug('syntax getText called:',uri,async_cb,fail_ok); |
|---|
| 238 | + var contents = dojo.syntax._realGetText.apply(dojo.hostenv, arguments); |
|---|
| 239 | + //dojo.debug('contents gotten',contents); |
|---|
| 240 | + if(contents){ |
|---|
| 241 | + if (dojo.lang.isString(uri)){ |
|---|
| 242 | + uri = uri.toLowerCase(); |
|---|
| 243 | + } |
|---|
| 244 | + else { |
|---|
| 245 | + //assume it's a dojo.uri.Uri object. |
|---|
| 246 | + uri = uri.toString(); |
|---|
| 247 | + } |
|---|
| 248 | + if (uri.indexOf('.js') != -1){ |
|---|
| 249 | + dojo.debug('syntax checking:',uri); |
|---|
| 250 | + if (dojo.syntax.check(contents,uri,'jslint') == false){ |
|---|
| 251 | + //check failed. |
|---|
| 252 | + if (!fail_ok){ |
|---|
| 253 | + var err = Error("Unable to load "+uri+" because of a syntax error"); |
|---|
| 254 | + throw err; |
|---|
| 255 | + } |
|---|
| 256 | + //we return null, unless we are not supposed to. |
|---|
| 257 | + //dojo.debug('returning badness'); |
|---|
| 258 | + return null; |
|---|
| 259 | + } |
|---|
| 260 | + } |
|---|
| 261 | + } |
|---|
| 262 | +//dojo.debug('syntax: all done'); |
|---|
| 263 | +return contents; |
|---|
| 264 | + |
|---|
| 265 | +}; |
|---|
| 266 | + |
|---|
| 267 | +dojo.hostenv.getText = dojo.syntax.getText; |
|---|
| 268 | \ No newline at end of file |
|---|
| 269 | |
|---|
| 270 | Property changes on: syntax/common.js |
|---|
| 271 | ___________________________________________________________________ |
|---|
| 272 | Name: svn:eol-style |
|---|
| 273 | + native |
|---|
| 274 | |
|---|
| 275 | Index: syntax/TODO |
|---|
| 276 | =================================================================== |
|---|
| 277 | --- syntax/TODO (revision 0) |
|---|
| 278 | +++ syntax/TODO (revision 1277) |
|---|
| 279 | @@ -0,0 +1,47 @@ |
|---|
| 280 | +http://trac.dojotoolkit.org/ticket/2571 |
|---|
| 281 | +jamestag (jburke on trac) is my contact |
|---|
| 282 | + |
|---|
| 283 | +slightlyoff: birlcathy: and bug jamestag early next week for status on what hooks will be available |
|---|
| 284 | + |
|---|
| 285 | +Hi all! |
|---|
| 286 | + |
|---|
| 287 | +I started work on a new feature, that I want to help me with JS syntax(since I never can remember it..) I hack into dojo.hostenv.loadUri and put a syntax checker in before an eval() is called. |
|---|
| 288 | + |
|---|
| 289 | +Anyways, I never expected to find all sorts of errors in dojo itself! |
|---|
| 290 | + http://www.yuma.ca/tech/js/baddojo.html |
|---|
| 291 | + |
|---|
| 292 | +is a list of most of the packages, and the problems.. It's not pretty.. so I made: |
|---|
| 293 | +http://www.yuma.ca/tech/js/testsyntax.html |
|---|
| 294 | + |
|---|
| 295 | +Which will let you test a particular module. (you will prolly want to refresh the page before trying another one or check the bottom!). |
|---|
| 296 | + |
|---|
| 297 | +anyways, there is lot's of errors. It doesn't do formatting errors, only syntax. It's totally hacked into dojo right now, but dojo.syntax.* is the module. |
|---|
| 298 | + |
|---|
| 299 | + |
|---|
| 300 | + |
|---|
| 301 | +Syntax feature |
|---|
| 302 | + |
|---|
| 303 | +Alter dojo.require() so that when code is pulled in from sources, we verify it against a syntax checker.. the beauty is then, your code STAYS clean because everytime you run it, it will get mad. This is only true on debug versions(djConfig.isDebug:true). Uses jslint.com's syntax checker currently. Other checkers could be used, but no others are supported currently. |
|---|
| 304 | + |
|---|
| 305 | +features: |
|---|
| 306 | + allow stopping on error, or just warning on error. djConfig.syntaxWarn ? |
|---|
| 307 | + Follow dojo JS guidelines as much as possible. |
|---|
| 308 | + allow it to skip dojo srcs, and only get upset with stuff in your custom namespace? |
|---|
| 309 | + |
|---|
| 310 | + |
|---|
| 311 | + |
|---|
| 312 | +current implementation at: http://www.yuma.ca/tech/js/dojo/src/syntax/ |
|---|
| 313 | +demo/testcase: http://www.yuma.ca/tech/js/testsyntax.html |
|---|
| 314 | + |
|---|
| 315 | + |
|---|
| 316 | + |
|---|
| 317 | +QUESTIONS (for non strict mode): |
|---|
| 318 | + allow variable declaration in block? (JS is not block-scoped) |
|---|
| 319 | + if (blah){ |
|---|
| 320 | + var tito = blah; |
|---|
| 321 | + } |
|---|
| 322 | + using == to compare (type coercion bad?) |
|---|
| 323 | + if (blah == 0) |
|---|
| 324 | + unnecessary semicolons: |
|---|
| 325 | + try { this.domNode.focus(); } catch(e2) {}; |
|---|
| 326 | + |
|---|
| 327 | Index: syntax/jslint.js |
|---|
| 328 | =================================================================== |
|---|
| 329 | --- syntax/jslint.js (revision 0) |
|---|
| 330 | +++ syntax/jslint.js (revision 1277) |
|---|
| 331 | @@ -0,0 +1,2745 @@ |
|---|
| 332 | +dojo.provide("dojo.syntax.jslint"); |
|---|
| 333 | +// jslint.js |
|---|
| 334 | +// 2007-03-05 |
|---|
| 335 | +/* |
|---|
| 336 | +Copyright (c) 2002 Douglas Crockford (www.JSLint.com) |
|---|
| 337 | + |
|---|
| 338 | +Permission is hereby granted, free of charge, to any person obtaining a copy of |
|---|
| 339 | +this software and associated documentation files (the "Software"), to deal in |
|---|
| 340 | +the Software without restriction, including without limitation the rights to |
|---|
| 341 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|---|
| 342 | +of the Software, and to permit persons to whom the Software is furnished to do |
|---|
| 343 | +so, subject to the following conditions: |
|---|
| 344 | + |
|---|
| 345 | +The above copyright notice and this permission notice shall be included in all |
|---|
| 346 | +copies or substantial portions of the Software. |
|---|
| 347 | + |
|---|
| 348 | +The Software shall be used for Good, not Evil. |
|---|
| 349 | + |
|---|
| 350 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|---|
| 351 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|---|
| 352 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|---|
| 353 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|---|
| 354 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|---|
| 355 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|---|
| 356 | +SOFTWARE. |
|---|
| 357 | +*/ |
|---|
| 358 | + |
|---|
| 359 | + |
|---|
| 360 | +/* |
|---|
| 361 | + JSLINT is a global function. It takes two parameters. |
|---|
| 362 | + |
|---|
| 363 | + var myResult = JSLINT(source, option); |
|---|
| 364 | + |
|---|
| 365 | + The first parameter is either a string or an array of strings. If it is a |
|---|
| 366 | + string, it will be split on '\n' or '\r'. If it is an array of strings, it |
|---|
| 367 | + is assumed that each string represents one line. The source can be a |
|---|
| 368 | + JavaScript text, or HTML text, or a Konfabulator text. |
|---|
| 369 | + |
|---|
| 370 | + The second parameter is an optional object of options which control the |
|---|
| 371 | + operation of JSLINT. All of the options are booleans. All are optional and |
|---|
| 372 | + have a default value of false. |
|---|
| 373 | + |
|---|
| 374 | + { |
|---|
| 375 | + browser : true if the standard browser globals should be predefined |
|---|
| 376 | + cap : true if upper case HTML should be allowed |
|---|
| 377 | + debug : true if debugger statements should be allowed |
|---|
| 378 | + eqeqeq : true if === should be required |
|---|
| 379 | + evil : true if eval should be allowed |
|---|
| 380 | + jscript : true if jscript deviations should be allowed |
|---|
| 381 | + laxLineEnd : true if line breaks should not be checked |
|---|
| 382 | + passfail : true if the scan should stop on first error |
|---|
| 383 | + plusplus : true if increment/decrement should not be allowed |
|---|
| 384 | + redef : true if var redefinition should be allowed |
|---|
| 385 | + rhino : true if the Rhino environment globals should be predefined |
|---|
| 386 | + undef : true if undefined variables are errors |
|---|
| 387 | + white : true if strict whitespace rules apply |
|---|
| 388 | + widget : true if the Yahoo Widgets globals should be predefined |
|---|
| 389 | + strict : true if we should be normal jslint mode, false and we be very very lax... |
|---|
| 390 | + } |
|---|
| 391 | + |
|---|
| 392 | + If it checks out, JSLINT returns true. Otherwise, it returns false. |
|---|
| 393 | + |
|---|
| 394 | + If false, you can inspect JSLINT.errors to find out the problems. |
|---|
| 395 | + JSLINT.errors is an array of objects containing these members: |
|---|
| 396 | + |
|---|
| 397 | + { |
|---|
| 398 | + line : The line (relative to 0) at which the lint was found |
|---|
| 399 | + character : The character (relative to 0) at which the lint was found |
|---|
| 400 | + reason : The problem |
|---|
| 401 | + evidence : The text line in which the problem occurred |
|---|
| 402 | + } |
|---|
| 403 | + |
|---|
| 404 | + If a fatal error was found, a null will be the last element of the |
|---|
| 405 | + JSLINT.errors array. |
|---|
| 406 | + |
|---|
| 407 | + You can request a Function Report, which shows all of the functions |
|---|
| 408 | + and the parameters and vars that they use. This can be used to find |
|---|
| 409 | + implied global variables and other problems. The report is in HTML and |
|---|
| 410 | + can be inserted in a <body>. |
|---|
| 411 | + |
|---|
| 412 | + var myReport = JSLINT.report(option); |
|---|
| 413 | + |
|---|
| 414 | + If the option is true, then the report will be limited to only errors. |
|---|
| 415 | +*/ |
|---|
| 416 | + |
|---|
| 417 | +String.prototype.entityify = function () { |
|---|
| 418 | + return this. |
|---|
| 419 | + replace(/&/g, '&'). |
|---|
| 420 | + replace(/</g, '<'). |
|---|
| 421 | + replace(/>/g, '>'); |
|---|
| 422 | +}; |
|---|
| 423 | + |
|---|
| 424 | +String.prototype.isAlpha = function () { |
|---|
| 425 | + return (this >= 'a' && this <= 'z\uffff') || |
|---|
| 426 | + (this >= 'A' && this <= 'Z\uffff'); |
|---|
| 427 | +}; |
|---|
| 428 | + |
|---|
| 429 | + |
|---|
| 430 | +String.prototype.isDigit = function () { |
|---|
| 431 | + return (this >= '0' && this <= '9'); |
|---|
| 432 | +}; |
|---|
| 433 | + |
|---|
| 434 | + |
|---|
| 435 | +// We build the application inside a function so that we produce only a single |
|---|
| 436 | +// global variable. The function will be invoked, its return value is the JSLINT |
|---|
| 437 | +// function itself. |
|---|
| 438 | + |
|---|
| 439 | +//var dojo.JSLINT; |
|---|
| 440 | +dojo.syntax.jslint = function () { |
|---|
| 441 | + |
|---|
| 442 | + var anonname, |
|---|
| 443 | + |
|---|
| 444 | +// browser contains a set of global names which are commonly provided by a |
|---|
| 445 | +// web browser environment. |
|---|
| 446 | + |
|---|
| 447 | + browser = { |
|---|
| 448 | + alert: true, |
|---|
| 449 | + blur: true, |
|---|
| 450 | + clearInterval: true, |
|---|
| 451 | + clearTimeout: true, |
|---|
| 452 | + close: true, |
|---|
| 453 | + closed: true, |
|---|
| 454 | + confirm: true, |
|---|
| 455 | + console: true, |
|---|
| 456 | + Debug: true, |
|---|
| 457 | + defaultStatus: true, |
|---|
| 458 | + document: true, |
|---|
| 459 | + event: true, |
|---|
| 460 | + focus: true, |
|---|
| 461 | + frames: true, |
|---|
| 462 | + history: true, |
|---|
| 463 | + Image: true, |
|---|
| 464 | + length: true, |
|---|
| 465 | + location: true, |
|---|
| 466 | + moveBy: true, |
|---|
| 467 | + moveTo: true, |
|---|
| 468 | + name: true, |
|---|
| 469 | + navigator: true, |
|---|
| 470 | + onblur: true, |
|---|
| 471 | + onerror: true, |
|---|
| 472 | + onfocus: true, |
|---|
| 473 | + onload: true, |
|---|
| 474 | + onresize: true, |
|---|
| 475 | + onunload: true, |
|---|
| 476 | + open: true, |
|---|
| 477 | + opener: true, |
|---|
| 478 | + opera: true, |
|---|
| 479 | + parent: true, |
|---|
| 480 | + print: true, |
|---|
| 481 | + prompt: true, |
|---|
| 482 | + resizeBy: true, |
|---|
| 483 | + resizeTo: true, |
|---|
| 484 | + screen: true, |
|---|
| 485 | + scroll: true, |
|---|
| 486 | + scrollBy: true, |
|---|
| 487 | + scrollTo: true, |
|---|
| 488 | + self: true, |
|---|
| 489 | + setInterval: true, |
|---|
| 490 | + setTimeout: true, |
|---|
| 491 | + status: true, |
|---|
| 492 | + top: true, |
|---|
| 493 | + window: true, |
|---|
| 494 | + XMLHttpRequest: true, |
|---|
| 495 | + dojo: true, |
|---|
| 496 | + dj_undef: true, |
|---|
| 497 | + djConfig: true |
|---|
| 498 | + }, |
|---|
| 499 | + funlab, funstack, functions, globals, |
|---|
| 500 | + |
|---|
| 501 | +// konfab contains the global names which are provided to a Yahoo |
|---|
| 502 | +// (fna Konfabulator) widget. |
|---|
| 503 | + |
|---|
| 504 | + konfab = { |
|---|
| 505 | + alert: true, |
|---|
| 506 | + animator: true, |
|---|
| 507 | + appleScript: true, |
|---|
| 508 | + beep: true, |
|---|
| 509 | + bytesToUIString: true, |
|---|
| 510 | + chooseColor: true, |
|---|
| 511 | + chooseFile: true, |
|---|
| 512 | + chooseFolder: true, |
|---|
| 513 | + convertPathToHFS: true, |
|---|
| 514 | + convertPathToPlatform: true, |
|---|
| 515 | + closeWidget: true, |
|---|
| 516 | + CustomAnimation: true, |
|---|
| 517 | + escape: true, |
|---|
| 518 | + FadeAnimation: true, |
|---|
| 519 | + focusWidget: true, |
|---|
| 520 | + form: true, |
|---|
| 521 | + include: true, |
|---|
| 522 | + isApplicationRunning: true, |
|---|
| 523 | + iTunes: true, |
|---|
| 524 | + konfabulatorVersion: true, |
|---|
| 525 | + log: true, |
|---|
| 526 | + MoveAnimation: true, |
|---|
| 527 | + openURL: true, |
|---|
| 528 | + play: true, |
|---|
| 529 | + popupMenu: true, |
|---|
| 530 | + print: true, |
|---|
| 531 | + prompt: true, |
|---|
| 532 | + reloadWidget: true, |
|---|
| 533 | + resolvePath: true, |
|---|
| 534 | + resumeUpdates: true, |
|---|
| 535 | + RotateAnimation: true, |
|---|
| 536 | + runCommand: true, |
|---|
| 537 | + runCommandInBg: true, |
|---|
| 538 | + saveAs: true, |
|---|
| 539 | + savePreferences: true, |
|---|
| 540 | + showWidgetPreferences: true, |
|---|
| 541 | + sleep: true, |
|---|
| 542 | + speak: true, |
|---|
| 543 | + suppressUpdates: true, |
|---|
| 544 | + tellWidget: true, |
|---|
| 545 | + unescape: true, |
|---|
| 546 | + updateNow: true, |
|---|
| 547 | + yahooCheckLogin: true, |
|---|
| 548 | + yahooLogin: true, |
|---|
| 549 | + yahooLogout: true, |
|---|
| 550 | + COM: true, |
|---|
| 551 | + filesystem: true, |
|---|
| 552 | + preferenceGroups: true, |
|---|
| 553 | + preferences: true, |
|---|
| 554 | + screen: true, |
|---|
| 555 | + system: true, |
|---|
| 556 | + URL: true, |
|---|
| 557 | + XMLDOM: true, |
|---|
| 558 | + XMLHttpRequest: true |
|---|
| 559 | + }, |
|---|
| 560 | + lines, lookahead, member, nexttoken, noreach, option, quit, |
|---|
| 561 | + rhino = { |
|---|
| 562 | + defineClass: true, |
|---|
| 563 | + deserialize: true, |
|---|
| 564 | + gc: true, |
|---|
| 565 | + help: true, |
|---|
| 566 | + load: true, |
|---|
| 567 | + loadClass: true, |
|---|
| 568 | + print: true, |
|---|
| 569 | + quit: true, |
|---|
| 570 | + readFile: true, |
|---|
| 571 | + readUrl: true, |
|---|
| 572 | + runCommand: true, |
|---|
| 573 | + seal: true, |
|---|
| 574 | + serialize: true, |
|---|
| 575 | + spawn: true, |
|---|
| 576 | + sync: true, |
|---|
| 577 | + toint32: true, |
|---|
| 578 | + version: true |
|---|
| 579 | + }, |
|---|
| 580 | + stack, |
|---|
| 581 | + |
|---|
| 582 | +// standard contains the global names that are provided by standard JavaScript. |
|---|
| 583 | + |
|---|
| 584 | + standard = { |
|---|
| 585 | + Array: true, |
|---|
| 586 | + Boolean: true, |
|---|
| 587 | + Date: true, |
|---|
| 588 | + decodeURI: true, |
|---|
| 589 | + decodeURIComponent: true, |
|---|
| 590 | + encodeURI: true, |
|---|
| 591 | + encodeURIComponent: true, |
|---|
| 592 | + Error: true, |
|---|
| 593 | + escape: true, |
|---|
| 594 | + 'eval': true, |
|---|
| 595 | + EvalError: true, |
|---|
| 596 | + Function: true, |
|---|
| 597 | + isFinite: true, |
|---|
| 598 | + isNaN: true, |
|---|
| 599 | + Math: true, |
|---|
| 600 | + Number: true, |
|---|
| 601 | + Object: true, |
|---|
| 602 | + parseInt: true, |
|---|
| 603 | + parseFloat: true, |
|---|
| 604 | + RangeError: true, |
|---|
| 605 | + ReferenceError: true, |
|---|
| 606 | + RegExp: true, |
|---|
| 607 | + String: true, |
|---|
| 608 | + SyntaxError: true, |
|---|
| 609 | + TypeError: true, |
|---|
| 610 | + unescape: true, |
|---|
| 611 | + URIError: true |
|---|
| 612 | + }, |
|---|
| 613 | + syntax = {}, token, verb, warnings, |
|---|
| 614 | + |
|---|
| 615 | +// xmode is used to adapt to the exceptions in XML parsing. |
|---|
| 616 | +// It can have these states: |
|---|
| 617 | +// false .js script file |
|---|
| 618 | +// " A " attribute |
|---|
| 619 | +// ' A ' attribute |
|---|
| 620 | +// content The content of a script tag |
|---|
| 621 | +// CDATA A CDATA block |
|---|
| 622 | + |
|---|
| 623 | + xmode, |
|---|
| 624 | + |
|---|
| 625 | +// xtype identifies the type of document being analyzed. |
|---|
| 626 | +// It can have these states: |
|---|
| 627 | +// false .js script file |
|---|
| 628 | +// html .html file |
|---|
| 629 | +// widget .kon Konfabulator file |
|---|
| 630 | + |
|---|
| 631 | + xtype, |
|---|
| 632 | +// token |
|---|
| 633 | + tx = /^([(){}[.,:;'"~]|\](\]>)?|\?>?|==?=?|\/(\*(global|extern)*|=|)|\*[\/=]?|\+[+=]?|-[-=]?|%[=>]?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=%\?]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+-]?[0-9]+)?)/, |
|---|
| 634 | +// string ending in single quote |
|---|
| 635 | + sx = /^((\\[^\x00-\x1f]|[^\x00-\x1f'\\])*)'/, |
|---|
| 636 | + sxx = /^(([^\x00-\x1f'])*)'/, |
|---|
| 637 | +// string ending in double quote |
|---|
| 638 | + qx = /^((\\[^\x00-\x1f]|[^\x00-\x1f"\\])*)"/, |
|---|
| 639 | + qxx = /^(([^\x00-\x1f"])*)"/, |
|---|
| 640 | +// regular expression |
|---|
| 641 | + rx = /^(\\[^\x00-\x1f]|\[(\\[^\x00-\x1f]|[^\x00-\x1f\\\/])*\]|[^\x00-\x1f\\\/\[])+\/[gim]*/, |
|---|
| 642 | +// star slash |
|---|
| 643 | + lx = /\*\/|\/\*/, |
|---|
| 644 | +// global identifier |
|---|
| 645 | + gx = /^([a-zA-Z_$][a-zA-Z0-9_$]*)/, |
|---|
| 646 | +// identifier |
|---|
| 647 | + ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*$)/, |
|---|
| 648 | +// global separators |
|---|
| 649 | + hx = /^[\x00-\x20,]*(\*\/)?/, |
|---|
| 650 | +// whitespace |
|---|
| 651 | + wx = /^\s*(\/\/.*\r*$)?/; |
|---|
| 652 | + |
|---|
| 653 | +// Make a new object that inherits from an existing object. |
|---|
| 654 | + |
|---|
| 655 | + function object(o) { |
|---|
| 656 | + function F() {} |
|---|
| 657 | + F.prototype = o; |
|---|
| 658 | + return new F(); |
|---|
| 659 | + } |
|---|
| 660 | + |
|---|
| 661 | +// Produce an error warning. |
|---|
| 662 | + |
|---|
| 663 | + |
|---|
| 664 | + function warning(m, x, y) { |
|---|
| 665 | + var l, c, t = typeof x === 'object' ? x : nexttoken, w; |
|---|
| 666 | + if (typeof x === 'number') { |
|---|
| 667 | + l = x; |
|---|
| 668 | + c = y || 0; |
|---|
| 669 | + } else { |
|---|
| 670 | + if (t.id === '(end)') { |
|---|
| 671 | + t = token; |
|---|
| 672 | + } |
|---|
| 673 | + l = t.line || 0; |
|---|
| 674 | + c = t.from || 0; |
|---|
| 675 | + } |
|---|
| 676 | + w = { |
|---|
| 677 | + id: '(error)', |
|---|
| 678 | + reason: m, |
|---|
| 679 | + evidence: lines[l] || '', |
|---|
| 680 | + line: l, |
|---|
| 681 | + character: c |
|---|
| 682 | + }; |
|---|
| 683 | + dojo.syntax.jslint.errors.push(w); |
|---|
| 684 | + if (option.passfail) { |
|---|
| 685 | + quit('Stopping. ', l, c); |
|---|
| 686 | + } |
|---|
| 687 | + warnings += 1; |
|---|
| 688 | + if (warnings === 50) { |
|---|
| 689 | + quit("Too many errors.", l, c); |
|---|
| 690 | + } |
|---|
| 691 | + return w; |
|---|
| 692 | + } |
|---|
| 693 | + |
|---|
| 694 | + function error(m, x, y) { |
|---|
| 695 | + var w = warning(m, x, y); |
|---|
| 696 | + quit("Stopping, unable to continue.", w.line, w.character); |
|---|
| 697 | + } |
|---|
| 698 | + |
|---|
| 699 | + quit = function quit(m, l, c) { |
|---|
| 700 | + warning(m + ' (' + Math.floor((l / lines.length) * 100) + '% scanned)', l, c); |
|---|
| 701 | + dojo.syntax.jslint.errors.push(null); |
|---|
| 702 | + throw null; |
|---|
| 703 | + }; |
|---|
| 704 | + |
|---|
| 705 | + |
|---|
| 706 | + |
|---|
| 707 | +// lexical analysis |
|---|
| 708 | + |
|---|
| 709 | + var lex = function () { |
|---|
| 710 | + var character, from, line, s; |
|---|
| 711 | + |
|---|
| 712 | +// Private lex methods |
|---|
| 713 | + |
|---|
| 714 | + function nextLine() { |
|---|
| 715 | + line += 1; |
|---|
| 716 | + if (line >= lines.length) { |
|---|
| 717 | + return false; |
|---|
| 718 | + } |
|---|
| 719 | + character = 0; |
|---|
| 720 | + s = lines[line]; |
|---|
| 721 | + return true; |
|---|
| 722 | + } |
|---|
| 723 | + |
|---|
| 724 | +// Produce a token object. The token inherits from a syntax symbol. |
|---|
| 725 | + |
|---|
| 726 | + function it(type, value) { |
|---|
| 727 | + var t; |
|---|
| 728 | + if (type === '(punctuator)') { |
|---|
| 729 | + t = syntax[value]; |
|---|
| 730 | + } else if (type === '(identifier)') { |
|---|
| 731 | + t = syntax[value]; |
|---|
| 732 | + if (!t || typeof t !== 'object') { |
|---|
| 733 | + t = syntax[type]; |
|---|
| 734 | + } |
|---|
| 735 | + } else { |
|---|
| 736 | + t = syntax[type]; |
|---|
| 737 | + } |
|---|
| 738 | + if (!t || typeof t !== 'object') { |
|---|
| 739 | + error("Unrecognized symbol: '" + value + "' " + type); |
|---|
| 740 | + } |
|---|
| 741 | + t = object(t); |
|---|
| 742 | + if (value || type === '(string)') { |
|---|
| 743 | + if (value.charAt(10) === ':' && |
|---|
| 744 | + value.substring(0, 10).toLowerCase() === 'javascript') { |
|---|
| 745 | + warning("JavaScript URL."); |
|---|
| 746 | + } |
|---|
| 747 | + t.value = value; |
|---|
| 748 | + } |
|---|
| 749 | + t.line = line; |
|---|
| 750 | + t.character = character; |
|---|
| 751 | + t.from = from; |
|---|
| 752 | + return t; |
|---|
| 753 | + } |
|---|
| 754 | + |
|---|
| 755 | +// Public lex methods |
|---|
| 756 | + |
|---|
| 757 | + return { |
|---|
| 758 | + init: function (source) { |
|---|
| 759 | + if (typeof source === 'string') { |
|---|
| 760 | + lines = source.split('\n'); |
|---|
| 761 | + if (lines.length === 1) { |
|---|
| 762 | + lines = lines[0].split('\r'); |
|---|
| 763 | + } |
|---|
| 764 | + } else { |
|---|
| 765 | + lines = source; |
|---|
| 766 | + } |
|---|
| 767 | + line = 0; |
|---|
| 768 | + character = 0; |
|---|
| 769 | + from = 0; |
|---|
| 770 | + s = lines[0]; |
|---|
| 771 | + }, |
|---|
| 772 | + |
|---|
| 773 | +// token -- this is called by advance to get the next token. |
|---|
| 774 | + |
|---|
| 775 | + token: function () { |
|---|
| 776 | + var c, i, l, r, t; |
|---|
| 777 | + |
|---|
| 778 | + function string(x) { |
|---|
| 779 | + var a, j; |
|---|
| 780 | + r = x.exec(s); |
|---|
| 781 | + if (r) { |
|---|
| 782 | + t = r[1]; |
|---|
| 783 | + l = r[0].length; |
|---|
| 784 | + s = s.substr(l); |
|---|
| 785 | + character += l; |
|---|
| 786 | + if (xmode === 'script') { |
|---|
| 787 | + if (t.indexOf('<\/') >= 0) { |
|---|
| 788 | + warning( |
|---|
| 789 | + 'Expected "...<\\/..." and instead saw "...<\/...".', nexttoken); |
|---|
| 790 | + } |
|---|
| 791 | + } |
|---|
| 792 | + return it('(string)', r[1]); |
|---|
| 793 | + } else { |
|---|
| 794 | + for (j = 0; j < s.length; j += 1) { |
|---|
| 795 | + a = s.charAt(j); |
|---|
| 796 | + if (a < ' ') { |
|---|
| 797 | + if (a === '\n' || a === '\r') { |
|---|
| 798 | + break; |
|---|
| 799 | + } |
|---|
| 800 | + warning("Control character in string: " + |
|---|
| 801 | + s.substring(0, j), line, character + j); |
|---|
| 802 | + } |
|---|
| 803 | + } |
|---|
| 804 | + error("Unclosed string: " + s, line, character); |
|---|
| 805 | + } |
|---|
| 806 | + } |
|---|
| 807 | + |
|---|
| 808 | + for (;;) { |
|---|
| 809 | + if (!s) { |
|---|
| 810 | + return it(nextLine() ? '(endline)' : '(end)', ''); |
|---|
| 811 | + } |
|---|
| 812 | + r = wx.exec(s); |
|---|
| 813 | + if (!r || !r[0]) { |
|---|
| 814 | + break; |
|---|
| 815 | + } |
|---|
| 816 | + l = r[0].length; |
|---|
| 817 | + s = s.substr(l); |
|---|
| 818 | + character += l; |
|---|
| 819 | + if (s) { |
|---|
| 820 | + break; |
|---|
| 821 | + } |
|---|
| 822 | + } |
|---|
| 823 | + from = character; |
|---|
| 824 | + r = tx.exec(s); |
|---|
| 825 | + if (r) { |
|---|
| 826 | + t = r[0]; |
|---|
| 827 | + l = t.length; |
|---|
| 828 | + s = s.substr(l); |
|---|
| 829 | + character += l; |
|---|
| 830 | + c = t.substr(0, 1); |
|---|
| 831 | + |
|---|
| 832 | +// identifier |
|---|
| 833 | + |
|---|
| 834 | + if (c.isAlpha() || c === '_' || c === '$') { |
|---|
| 835 | + return it('(identifier)', t); |
|---|
| 836 | + } |
|---|
| 837 | + |
|---|
| 838 | +// number |
|---|
| 839 | + |
|---|
| 840 | + if (c.isDigit()) { |
|---|
| 841 | + if (nexttoken.id === '.') { |
|---|
| 842 | + warning( |
|---|
| 843 | + "A decimal fraction should have a zero before the decimal point.", |
|---|
| 844 | + nexttoken); |
|---|
| 845 | + } |
|---|
| 846 | + if (!isFinite(Number(t))) { |
|---|
| 847 | + warning("Bad number: '" + t + "'.", |
|---|
| 848 | + line, character); |
|---|
| 849 | + } |
|---|
| 850 | + if (s.substr(0, 1).isAlpha()) { |
|---|
| 851 | + warning("Space is required after a number: '" + |
|---|
| 852 | + t + "'.", line, character); |
|---|
| 853 | + } |
|---|
| 854 | + if (c === '0' && t.substr(1,1).isDigit()) { |
|---|
| 855 | + warning("Don't use extra leading zeros: '" + |
|---|
| 856 | + t + "'.", line, character); |
|---|
| 857 | + } |
|---|
| 858 | + if (t.substr(t.length - 1) === '.') { |
|---|
| 859 | + warning( |
|---|
| 860 | + "A trailing decimal point can be confused with a dot: '" + t + "'.", |
|---|
| 861 | + line, character); |
|---|
| 862 | + } |
|---|
| 863 | + return it('(number)', t); |
|---|
| 864 | + } |
|---|
| 865 | + |
|---|
| 866 | +// string |
|---|
| 867 | + |
|---|
| 868 | + if (t === '"') { |
|---|
| 869 | + return (xmode === '"' || xmode === 'string') ? |
|---|
| 870 | + it('(punctuator)', t) : |
|---|
| 871 | + string(xmode === 'xml' ? qxx : qx); |
|---|
| 872 | + } |
|---|
| 873 | + if (t === "'") { |
|---|
| 874 | + return (xmode === "'" || xmode === 'string') ? |
|---|
| 875 | + it('(punctuator)', t) : |
|---|
| 876 | + string(xmode === 'xml' ? sxx : sx); |
|---|
| 877 | + } |
|---|
| 878 | + |
|---|
| 879 | +// unbegun comment |
|---|
| 880 | + |
|---|
| 881 | + if (t === '/*') { |
|---|
| 882 | + for (;;) { |
|---|
| 883 | + i = s.search(lx); |
|---|
| 884 | + if (i >= 0) { |
|---|
| 885 | + break; |
|---|
| 886 | + } |
|---|
| 887 | + if (!nextLine()) { |
|---|
| 888 | + error("Unclosed comment.", nexttoken); |
|---|
| 889 | + } |
|---|
| 890 | + } |
|---|
| 891 | + character += i + 2; |
|---|
| 892 | + if (s.substr(i, 1) === '/') { |
|---|
| 893 | + error("Nested comment."); |
|---|
| 894 | + } |
|---|
| 895 | + s = s.substr(i + 2); |
|---|
| 896 | + return this.token(); |
|---|
| 897 | + } |
|---|
| 898 | + |
|---|
| 899 | +// /*extern |
|---|
| 900 | + |
|---|
| 901 | + if (t === '/*extern' || t === '/*global') { |
|---|
| 902 | + for (;;) { |
|---|
| 903 | + r = hx.exec(s); |
|---|
| 904 | + if (r) { |
|---|
| 905 | + l = r[0].length; |
|---|
| 906 | + s = s.substr(l); |
|---|
| 907 | + character += l; |
|---|
| 908 | + if (r[1] === '*/') { |
|---|
| 909 | + return this.token(); |
|---|
| 910 | + } |
|---|
| 911 | + } |
|---|
| 912 | + if (s) { |
|---|
| 913 | + r = gx.exec(s); |
|---|
| 914 | + if (r) { |
|---|
| 915 | + l = r[0].length; |
|---|
| 916 | + s = s.substr(l); |
|---|
| 917 | + character += l; |
|---|
| 918 | + globals[r[1]] = true; |
|---|
| 919 | + } else { |
|---|
| 920 | + error("Bad extern identifier: '" + |
|---|
| 921 | + s + "'.", line, character); |
|---|
| 922 | + } |
|---|
| 923 | + } else if (!nextLine()) { |
|---|
| 924 | + error("Unclosed comment."); |
|---|
| 925 | + } |
|---|
| 926 | + } |
|---|
| 927 | + } |
|---|
| 928 | + |
|---|
| 929 | +// punctuator |
|---|
| 930 | + |
|---|
| 931 | + return it('(punctuator)', t); |
|---|
| 932 | + } |
|---|
| 933 | + error("Unexpected token: " + (t || s.substr(0, 1)), |
|---|
| 934 | + line, character); |
|---|
| 935 | + }, |
|---|
| 936 | + |
|---|
| 937 | +// skip -- skip past the next occurrence of a particular string. |
|---|
| 938 | +// If the argument is empty, skip to just before the next '<' character. |
|---|
| 939 | +// This is used to ignore HTML content. Return false if it isn't found. |
|---|
| 940 | + |
|---|
| 941 | + skip: function (t) { |
|---|
| 942 | + if (nexttoken.id) { |
|---|
| 943 | + if (!t) { |
|---|
| 944 | + t = ''; |
|---|
| 945 | + if (nexttoken.id.substr(0, 1) === '<') { |
|---|
| 946 | + lookahead.push(nexttoken); |
|---|
| 947 | + return true; |
|---|
| 948 | + } |
|---|
| 949 | + } else if (nexttoken.id.indexOf(t) >= 0) { |
|---|
| 950 | + return true; |
|---|
| 951 | + } |
|---|
| 952 | + } |
|---|
| 953 | + token = nexttoken; |
|---|
| 954 | + nexttoken = syntax['(error)']; |
|---|
| 955 | + for (;;) { |
|---|
| 956 | + var i = s.indexOf(t || '<'); |
|---|
| 957 | + if (i >= 0) { |
|---|
| 958 | + character += i + t.length; |
|---|
| 959 | + s = s.substr(i + t.length); |
|---|
| 960 | + return true; |
|---|
| 961 | + } |
|---|
| 962 | + if (!nextLine()) { |
|---|
| 963 | + break; |
|---|
| 964 | + } |
|---|
| 965 | + } |
|---|
| 966 | + return false; |
|---|
| 967 | + }, |
|---|
| 968 | + |
|---|
| 969 | +// regex -- this is called by parse when it sees '/' being used as a prefix. |
|---|
| 970 | + |
|---|
| 971 | + regex: function () { |
|---|
| 972 | + var l, r = rx.exec(s), x; |
|---|
| 973 | + if (r) { |
|---|
| 974 | + l = r[0].length; |
|---|
| 975 | + character += l; |
|---|
| 976 | + s = s.substr(l); |
|---|
| 977 | + x = r[1]; |
|---|
| 978 | + return it('(regex)', x); |
|---|
| 979 | + } |
|---|
| 980 | + error("Bad regular expression: " + s); |
|---|
| 981 | + } |
|---|
| 982 | + }; |
|---|
| 983 | + }(); |
|---|
| 984 | + |
|---|
| 985 | + function builtin(name) { |
|---|
| 986 | + var ret = standard[name] === true || |
|---|
| 987 | + globals[name] === true || |
|---|
| 988 | + (option.rhino && rhino[name] === true) || |
|---|
| 989 | + ((xtype === 'widget' || option.widget) && konfab[name] === true) || |
|---|
| 990 | + ((xtype === 'html' || option.browser) && browser[name] === true); |
|---|
| 991 | + if (dojo.syntax.moduleExists(name)){ |
|---|
| 992 | + return true; |
|---|
| 993 | + } |
|---|
| 994 | + return ret; |
|---|
| 995 | + } |
|---|
| 996 | + |
|---|
| 997 | + function addlabel(t, type) { |
|---|
| 998 | + if (t) { |
|---|
| 999 | + if (typeof funlab[t] === 'string') { |
|---|
| 1000 | + switch (funlab[t]) { |
|---|
| 1001 | + case 'var': |
|---|
| 1002 | + case 'var*': |
|---|
| 1003 | + if (type === 'global') { |
|---|
| 1004 | + funlab[t] = 'var*'; |
|---|
| 1005 | + return; |
|---|
| 1006 | + } |
|---|
| 1007 | + break; |
|---|
| 1008 | + case 'global': |
|---|
| 1009 | + if (type === 'var') { |
|---|
| 1010 | + warning('Var ' + t + |
|---|
| 1011 | + ' was used before it was declared.', token); |
|---|
| 1012 | + return; |
|---|
| 1013 | + } |
|---|
| 1014 | + if (type === 'var*' || type === 'global') { |
|---|
| 1015 | + return; |
|---|
| 1016 | + } |
|---|
| 1017 | + break; |
|---|
| 1018 | + case 'function': |
|---|
| 1019 | + case 'parameter': |
|---|
| 1020 | + if (type === 'global') { |
|---|
| 1021 | + return; |
|---|
| 1022 | + } |
|---|
| 1023 | + break; |
|---|
| 1024 | + } |
|---|
| 1025 | + warning("Identifier '" + t + "' already declared as " + |
|---|
| 1026 | + funlab[t], token); |
|---|
| 1027 | + } |
|---|
| 1028 | + funlab[t] = type; |
|---|
| 1029 | + } |
|---|
| 1030 | + } |
|---|
| 1031 | + |
|---|
| 1032 | + |
|---|
| 1033 | +// We need a peek function. If it has an argument, it peeks that much farther |
|---|
| 1034 | +// ahead. It is used to distinguish |
|---|
| 1035 | +// for ( var i in ... |
|---|
| 1036 | +// from |
|---|
| 1037 | +// for ( var i = ... |
|---|
| 1038 | + |
|---|
| 1039 | + function peek(i) { |
|---|
| 1040 | + var j = 0, t; |
|---|
| 1041 | + if (nexttoken === syntax['(error)']) { |
|---|
| 1042 | + return nexttoken; |
|---|
| 1043 | + } |
|---|
| 1044 | + if (typeof i === 'undefined') { |
|---|
| 1045 | + i = 0; |
|---|
| 1046 | + } |
|---|
| 1047 | + while (j <= i) { |
|---|
| 1048 | + t = lookahead[j]; |
|---|
| 1049 | + if (!t) { |
|---|
| 1050 | + t = lookahead[j] = lex.token(); |
|---|
| 1051 | + } |
|---|
| 1052 | + j += 1; |
|---|
| 1053 | + } |
|---|
| 1054 | + return t; |
|---|
| 1055 | + } |
|---|
| 1056 | + |
|---|
| 1057 | + |
|---|
| 1058 | + var badbreak = {')': true, ']': true, '++': true, '--': true}; |
|---|
| 1059 | + |
|---|
| 1060 | +// Produce the next token. It looks for programming errors. |
|---|
| 1061 | + |
|---|
| 1062 | + function advance(id, t) { |
|---|
| 1063 | + var l; |
|---|
| 1064 | + switch (token.id) { |
|---|
| 1065 | + case '(number)': |
|---|
| 1066 | + if (nexttoken.id === '.') { |
|---|
| 1067 | + warning( |
|---|
| 1068 | +"A dot following a number can be confused with a decimal point.", token); |
|---|
| 1069 | + } |
|---|
| 1070 | + break; |
|---|
| 1071 | + case '-': |
|---|
| 1072 | + if (nexttoken.id === '-' || nexttoken.id === '--') { |
|---|
| 1073 | + warning("Confusing minusses."); |
|---|
| 1074 | + } |
|---|
| 1075 | + break; |
|---|
| 1076 | + case '+': |
|---|
| 1077 | + if (nexttoken.id === '+' || nexttoken.id === '++') { |
|---|
| 1078 | + warning("Confusing plusses."); |
|---|
| 1079 | + } |
|---|
| 1080 | + break; |
|---|
| 1081 | + } |
|---|
| 1082 | + if (token.type === '(string)' || token.identifier) { |
|---|
| 1083 | + anonname = token.value; |
|---|
| 1084 | + } |
|---|
| 1085 | + |
|---|
| 1086 | + if (id && nexttoken.value !== id) { |
|---|
| 1087 | + if (t) { |
|---|
| 1088 | + if (nexttoken.id === '(end)') { |
|---|
| 1089 | + warning("Unmatched '" + t.id + "'.", t); |
|---|
| 1090 | + } else { |
|---|
| 1091 | + warning("Expected '" + id + "' to match '" + |
|---|
| 1092 | + t.id + "' from line " + (t.line + 1) + |
|---|
| 1093 | + " and instead saw '" + nexttoken.value + "'."); |
|---|
| 1094 | + } |
|---|
| 1095 | + } else { |
|---|
| 1096 | + warning("Expected '" + id + "' and instead saw '" + |
|---|
| 1097 | + nexttoken.value + "'."); |
|---|
| 1098 | + } |
|---|
| 1099 | + } |
|---|
| 1100 | + token = nexttoken; |
|---|
| 1101 | + for (;;) { |
|---|
| 1102 | + nexttoken = lookahead.shift() || lex.token(); |
|---|
| 1103 | + if (nexttoken.id === '<![') { |
|---|
| 1104 | + if (xtype === 'html') { |
|---|
| 1105 | + error("Unexpected token '<!['"); |
|---|
| 1106 | + } |
|---|
| 1107 | + if (xmode === 'script') { |
|---|
| 1108 | + nexttoken = lex.token(); |
|---|
| 1109 | + if (nexttoken.value !== 'CDATA') { |
|---|
| 1110 | + error("Expected 'CDATA'"); |
|---|
| 1111 | + } |
|---|
| 1112 | + nexttoken = lex.token(); |
|---|
| 1113 | + if (nexttoken.id !== '[') { |
|---|
| 1114 | + error("Expected '['"); |
|---|
| 1115 | + } |
|---|
| 1116 | + xmode = 'CDATA'; |
|---|
| 1117 | + } else if (xmode === 'xml') { |
|---|
| 1118 | + lex.skip(']]>'); |
|---|
| 1119 | + } else { |
|---|
| 1120 | + error("Unexpected token '<!['"); |
|---|
| 1121 | + } |
|---|
| 1122 | + } else if (nexttoken.id === ']]>') { |
|---|
| 1123 | + if (xmode === 'CDATA') { |
|---|
| 1124 | + xmode = 'script'; |
|---|
| 1125 | + } else { |
|---|
| 1126 | + error("Unexpected token ']]>"); |
|---|
| 1127 | + } |
|---|
| 1128 | + } else if (nexttoken.id !== '(endline)') { |
|---|
| 1129 | + break; |
|---|
| 1130 | + } |
|---|
| 1131 | + if (xmode === '"' || xmode === "'") { |
|---|
| 1132 | + error("Missing '" + xmode + "'.", token); |
|---|
| 1133 | + } |
|---|
| 1134 | + l = !xmode && !option.laxLineEnd && |
|---|
| 1135 | + (token.type === '(string)' || token.type === '(number)' || |
|---|
| 1136 | + token.type === '(identifier)' || badbreak[token.id]); |
|---|
| 1137 | + } |
|---|
| 1138 | + if (l) { |
|---|
| 1139 | + switch (nexttoken.id) { |
|---|
| 1140 | + case '{': |
|---|
| 1141 | + case '}': |
|---|
| 1142 | + case ']': |
|---|
| 1143 | + break; |
|---|
| 1144 | + case ')': |
|---|
| 1145 | + switch (token.id) { |
|---|
| 1146 | + case ')': |
|---|
| 1147 | + case '}': |
|---|
| 1148 | + case ']': |
|---|
| 1149 | + break; |
|---|
| 1150 | + default: |
|---|
| 1151 | + warning("Line breaking error: ')'.", token); |
|---|
| 1152 | + } |
|---|
| 1153 | + break; |
|---|
| 1154 | + default: |
|---|
| 1155 | + warning("Line breaking error: '" + token.value + "'.", |
|---|
| 1156 | + token); |
|---|
| 1157 | + } |
|---|
| 1158 | + } |
|---|
| 1159 | + if (xtype === 'widget' && xmode === 'script' && nexttoken.id) { |
|---|
| 1160 | + l = nexttoken.id.charAt(0); |
|---|
| 1161 | + if (l === '<' || l === '&') { |
|---|
| 1162 | + nexttoken.nud = nexttoken.led = null; |
|---|
| 1163 | + nexttoken.lbp = 0; |
|---|
| 1164 | + nexttoken.reach = true; |
|---|
| 1165 | + } |
|---|
| 1166 | + } |
|---|
| 1167 | + } |
|---|
| 1168 | + |
|---|
| 1169 | + |
|---|
| 1170 | + function advanceregex() { |
|---|
| 1171 | + nexttoken = lex.regex(); |
|---|
| 1172 | + } |
|---|
| 1173 | + |
|---|
| 1174 | + |
|---|
| 1175 | + function beginfunction(i) { |
|---|
| 1176 | + var f = {'(name)': i, '(line)': nexttoken.line + 1, '(context)': funlab}; |
|---|
| 1177 | + funstack.push(funlab); |
|---|
| 1178 | + funlab = f; |
|---|
| 1179 | + functions.push(funlab); |
|---|
| 1180 | + } |
|---|
| 1181 | + |
|---|
| 1182 | + |
|---|
| 1183 | + function endfunction() { |
|---|
| 1184 | + funlab = funstack.pop(); |
|---|
| 1185 | + } |
|---|
| 1186 | + |
|---|
| 1187 | + |
|---|
| 1188 | +// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it |
|---|
| 1189 | +// is looking for ad hoc lint patterns. We add to Pratt's model .fud, which is |
|---|
| 1190 | +// like nud except that it is only used on the first token of a statement. |
|---|
| 1191 | +// Having .fud makes it much easier to define JavaScript. I retained Pratt's |
|---|
| 1192 | +// nomenclature, even though it isn't very descriptive. |
|---|
| 1193 | + |
|---|
| 1194 | +// .nud Null denotation |
|---|
| 1195 | +// .fud First null denotation |
|---|
| 1196 | +// .led Left denotation |
|---|
| 1197 | +// lbp Left binding power |
|---|
| 1198 | +// rbp Right binding power |
|---|
| 1199 | + |
|---|
| 1200 | +// They are key to the parsing method called Top Down Operator Precedence. |
|---|
| 1201 | + |
|---|
| 1202 | + function parse(rbp, initial) { |
|---|
| 1203 | + var l, left, o; |
|---|
| 1204 | + if (nexttoken.id && nexttoken.id === '/') { |
|---|
| 1205 | + if (token.id !== '(' && token.id !== '=' && |
|---|
| 1206 | + token.id !== ':' && token.id !== ',' && |
|---|
| 1207 | + token.id !== '=' && token.id !== '[') { |
|---|
| 1208 | + warning( |
|---|
| 1209 | +"Expected to see a '(' or '=' or ':' or ',' or '[' preceding a regular expression literal, and instead saw '" + |
|---|
| 1210 | + token.value + "'.", token); |
|---|
| 1211 | + } |
|---|
| 1212 | + advanceregex(); |
|---|
| 1213 | + } |
|---|
| 1214 | + if (nexttoken.id === '(end)') { |
|---|
| 1215 | + warning("Unexpected early end of program", token); |
|---|
| 1216 | + } |
|---|
| 1217 | + advance(); |
|---|
| 1218 | + if (initial) { |
|---|
| 1219 | + anonname = 'anonymous'; |
|---|
| 1220 | + verb = token.value; |
|---|
| 1221 | + } |
|---|
| 1222 | + if (initial && token.fud) { |
|---|
| 1223 | + token.fud(); |
|---|
| 1224 | + } else { |
|---|
| 1225 | + if (token.nud) { |
|---|
| 1226 | + o = token.exps; |
|---|
| 1227 | + left = token.nud(); |
|---|
| 1228 | + } else { |
|---|
| 1229 | + if (nexttoken.type === '(number)' && token.id === '.') { |
|---|
| 1230 | + warning( |
|---|
| 1231 | +"A leading decimal point can be confused with a dot: ." + nexttoken.value, |
|---|
| 1232 | + token); |
|---|
| 1233 | + } |
|---|
| 1234 | + error("Expected an identifier and instead saw '" + |
|---|
| 1235 | + token.id + "'.", token); |
|---|
| 1236 | + } |
|---|
| 1237 | + while (rbp < nexttoken.lbp) { |
|---|
| 1238 | + o = nexttoken.exps; |
|---|
| 1239 | + advance(); |
|---|
| 1240 | + if (token.led) { |
|---|
| 1241 | + left = token.led(left); |
|---|
| 1242 | + } else { |
|---|
| 1243 | + error("Expected an operator and instead saw '" + |
|---|
| 1244 | + token.id + "'."); |
|---|
| 1245 | + } |
|---|
| 1246 | + } |
|---|
| 1247 | + if (initial && !o) { |
|---|
| 1248 | + warning( |
|---|
| 1249 | +"Expected an assignment or function call and instead saw an expression.", |
|---|
| 1250 | + token); |
|---|
| 1251 | + } |
|---|
| 1252 | + } |
|---|
| 1253 | + if (l) { |
|---|
| 1254 | + funlab[l] = 'label'; |
|---|
|
|---|