1 // (C)2002 Douglas Crockford |
1 // jslint.js |
2 // www.JSLint.com |
2 // 2009-08-22 |
3 // Rhino Edition |
3 |
4 "use strict";var JSLINT=(function(){var adsafe_id,adsafe_may,adsafe_went,anonname,approved,atrule={'import':true,media:true,'font-face':true,page:true},banned={'arguments':true,callee:true,caller:true,constructor:true,'eval':true,prototype:true,unwatch:true,valueOf:true,watch:true},boolOptions={adsafe:true,bitwise:true,browser:true,cap:true,css:true,debug:true,eqeqeq:true,evil:true,forin:true,fragment:true,immed:true,laxbreak:true,newcap:true,nomen:true,on:true,onevar:true,passfail:true,plusplus:true,regexp:true,rhino:true,undef:true,safe:true,sidebar:true,strict:true,sub:true,white:true,widget:true},browser={addEventListener:true,alert:true,blur:true,clearInterval:true,clearTimeout:true,close:true,closed:true,confirm:true,console:true,Debug:true,defaultStatus:true,document:true,event:true,focus:true,frames:true,getComputedStyle:true,history:true,Image:true,length:true,location:true,moveBy:true,moveTo:true,name:true,navigator:true,onblur:true,onerror:true,onfocus:true,onload:true,onresize:true,onunload:true,open:true,opener:true,opera:true,Option:true,parent:true,print:true,prompt:true,resizeBy:true,resizeTo:true,screen:true,scroll:true,scrollBy:true,scrollTo:true,setInterval:true,setTimeout:true,status:true,top:true,XMLHttpRequest:true},cssAttributeData,cssAny,cssColorData={"aliceblue":true,"antiquewhite":true,"aqua":true,"aquamarine":true,"azure":true,"beige":true,"bisque":true,"black":true,"blanchedalmond":true,"blue":true,"blueviolet":true,"brown":true,"burlywood":true,"cadetblue":true,"chartreuse":true,"chocolate":true,"coral":true,"cornflowerblue":true,"cornsilk":true,"crimson":true,"cyan":true,"darkblue":true,"darkcyan":true,"darkgoldenrod":true,"darkgray":true,"darkgreen":true,"darkkhaki":true,"darkmagenta":true,"darkolivegreen":true,"darkorange":true,"darkorchid":true,"darkred":true,"darksalmon":true,"darkseagreen":true,"darkslateblue":true,"darkslategray":true,"darkturquoise":true,"darkviolet":true,"deeppink":true,"deepskyblue":true,"dimgray":true,"dodgerblue":true,"firebrick":true,"floralwhite":true,"forestgreen":true,"fuchsia":true,"gainsboro":true,"ghostwhite":true,"gold":true,"goldenrod":true,"gray":true,"green":true,"greenyellow":true,"honeydew":true,"hotpink":true,"indianred":true,"indigo":true,"ivory":true,"khaki":true,"lavender":true,"lavenderblush":true,"lawngreen":true,"lemonchiffon":true,"lightblue":true,"lightcoral":true,"lightcyan":true,"lightgoldenrodyellow":true,"lightgreen":true,"lightpink":true,"lightsalmon":true,"lightseagreen":true,"lightskyblue":true,"lightslategray":true,"lightsteelblue":true,"lightyellow":true,"lime":true,"limegreen":true,"linen":true,"magenta":true,"maroon":true,"mediumaquamarine":true,"mediumblue":true,"mediumorchid":true,"mediumpurple":true,"mediumseagreen":true,"mediumslateblue":true,"mediumspringgreen":true,"mediumturquoise":true,"mediumvioletred":true,"midnightblue":true,"mintcream":true,"mistyrose":true,"moccasin":true,"navajowhite":true,"navy":true,"oldlace":true,"olive":true,"olivedrab":true,"orange":true,"orangered":true,"orchid":true,"palegoldenrod":true,"palegreen":true,"paleturquoise":true,"palevioletred":true,"papayawhip":true,"peachpuff":true,"peru":true,"pink":true,"plum":true,"powderblue":true,"purple":true,"red":true,"rosybrown":true,"royalblue":true,"saddlebrown":true,"salmon":true,"sandybrown":true,"seagreen":true,"seashell":true,"sienna":true,"silver":true,"skyblue":true,"slateblue":true,"slategray":true,"snow":true,"springgreen":true,"steelblue":true,"tan":true,"teal":true,"thistle":true,"tomato":true,"turquoise":true,"violet":true,"wheat":true,"white":true,"whitesmoke":true,"yellow":true,"yellowgreen":true},cssBorderStyle,cssLengthData={'%':true,'cm':true,'em':true,'ex':true,'in':true,'mm':true,'pc':true,'pt':true,'px':true},escapes={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','/':'\\/','\\':'\\\\'},funct,functions,global,htmltag={a:{},abbr:{},acronym:{},address:{},applet:{},area:{empty:true,parent:' map '},b:{},base:{empty:true,parent:' head '},bdo:{},big:{},blockquote:{},body:{parent:' html noframes '},br:{empty:true},button:{},canvas:{parent:' body p div th td '},caption:{parent:' table '},center:{},cite:{},code:{},col:{empty:true,parent:' table colgroup '},colgroup:{parent:' table '},dd:{parent:' dl '},del:{},dfn:{},dir:{},div:{},dl:{},dt:{parent:' dl '},em:{},embed:{},fieldset:{},font:{},form:{},frame:{empty:true,parent:' frameset '},frameset:{parent:' html frameset '},h1:{},h2:{},h3:{},h4:{},h5:{},h6:{},head:{parent:' html '},html:{parent:'*'},hr:{empty:true},i:{},iframe:{},img:{empty:true},input:{empty:true},ins:{},kbd:{},label:{},legend:{parent:' fieldset '},li:{parent:' dir menu ol ul '},link:{empty:true,parent:' head '},map:{},menu:{},meta:{empty:true,parent:' head noframes noscript '},noframes:{parent:' html body '},noscript:{parent:' body head noframes '},object:{},ol:{},optgroup:{parent:' select '},option:{parent:' optgroup select '},p:{},param:{empty:true,parent:' applet object '},pre:{},q:{},samp:{},script:{empty:true,parent:' body div frame head iframe p pre span '},select:{},small:{},span:{},strong:{},style:{parent:' head ',empty:true},sub:{},sup:{},table:{},tbody:{parent:' table '},td:{parent:' tr '},textarea:{},tfoot:{parent:' table '},th:{parent:' tr '},thead:{parent:' table '},title:{parent:' head '},tr:{parent:' table tbody thead tfoot '},tt:{},u:{},ul:{},'var':{}},ids,implied,inblock,indent,jsonmode,lines,lookahead,member,membersOnly,nexttoken,noreach,option,predefined,prereg,prevtoken,pseudorule={'first-child':true,link:true,visited:true,hover:true,active:true,focus:true,lang:true,'first-letter':true,'first-line':true,before:true,after:true},rhino={defineClass:true,deserialize:true,gc:true,help:true,load:true,loadClass:true,print:true,quit:true,readFile:true,readUrl:true,runCommand:true,seal:true,serialize:true,spawn:true,sync:true,toint32:true,version:true},scope,sidebar={System:true},src,stack,standard={Array:true,Boolean:true,Date:true,decodeURI:true,decodeURIComponent:true,encodeURI:true,encodeURIComponent:true,Error:true,'eval':true,EvalError:true,Function:true,isFinite:true,isNaN:true,JSON:true,Math:true,Number:true,Object:true,parseInt:true,parseFloat:true,RangeError:true,ReferenceError:true,RegExp:true,String:true,SyntaxError:true,TypeError:true,URIError:true},standard_member={E:true,LN2:true,LN10:true,LOG2E:true,LOG10E:true,PI:true,SQRT1_2:true,SQRT2:true,MAX_VALUE:true,MIN_VALUE:true,NEGATIVE_INFINITY:true,POSITIVE_INFINITY:true},syntax={},tab,token,urls,warnings,widget={alert:true,animator:true,appleScript:true,beep:true,bytesToUIString:true,Canvas:true,chooseColor:true,chooseFile:true,chooseFolder:true,closeWidget:true,COM:true,convertPathToHFS:true,convertPathToPlatform:true,CustomAnimation:true,escape:true,FadeAnimation:true,filesystem:true,Flash:true,focusWidget:true,form:true,FormField:true,Frame:true,HotKey:true,Image:true,include:true,isApplicationRunning:true,iTunes:true,konfabulatorVersion:true,log:true,md5:true,MenuItem:true,MoveAnimation:true,openURL:true,play:true,Point:true,popupMenu:true,preferenceGroups:true,preferences:true,print:true,prompt:true,random:true,Rectangle:true,reloadWidget:true,ResizeAnimation:true,resolvePath:true,resumeUpdates:true,RotateAnimation:true,runCommand:true,runCommandInBg:true,saveAs:true,savePreferences:true,screen:true,ScrollBar:true,showWidgetPreferences:true,sleep:true,speak:true,Style:true,suppressUpdates:true,system:true,tellWidget:true,Text:true,TextArea:true,Timer:true,unescape:true,updateNow:true,URL:true,Web:true,widget:true,Window:true,XMLDOM:true,XMLHttpRequest:true,yahooCheckLogin:true,yahooLogin:true,yahooLogout:true},xmode,xquote,ax=/@cc|<\/?|script|\]*s\]|<\s*!|</i,cx=/[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,tx=/^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|members?|global)?|=|\/)?|\*[\/=]?|\+[+=]?|-[\-=]?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,hx=/^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-]*|[0-9]+|--|.)/,nx=/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,nxg=/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,ox=/[>&]|<[\/!]?|--/,lx=/\*\/|\/\*/,ix=/^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,jx=/^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,ux=/&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i,sx=/^\s*([{:#*%.=,>+\[\]@()"';*]|[a-zA-Z0-9_][a-zA-Z0-9_\-]*|<\/|\/\*)/,ssx=/^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/,qx=/[^a-zA-Z0-9-_\/ ]/,dx=/[\[\]\/\\"'*<>.&:(){}+=#]/,rx={outer:hx,html:hx,style:sx,styleproperty:ssx};function F(){} |
4 /* |
5 if(typeof Object.create!=='function'){Object.create=function(o){F.prototype=o;return new F();};} |
5 Copyright (c) 2002 Douglas Crockford (www.JSLint.com) |
6 function combine(t,o){var n;for(n in o){if(o.hasOwnProperty(n)){t[n]=o[n];}}} |
6 |
7 String.prototype.entityify=function(){return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');};String.prototype.isAlpha=function(){return(this>='a'&&this<='z\uffff')||(this>='A'&&this<='Z\uffff');};String.prototype.isDigit=function(){return(this>='0'&&this<='9');};String.prototype.supplant=function(o){return this.replace(/\{([^{}]*)\}/g,function(a,b){var r=o[b];return typeof r==='string'||typeof r==='number'?r:a;});};String.prototype.name=function(){if(ix.test(this)){return this;} |
7 Permission is hereby granted, free of charge, to any person obtaining a copy of |
8 if(nx.test(this)){return'"'+this.replace(nxg,function(a){var c=escapes[a];if(c){return c;} |
8 this software and associated documentation files (the "Software"), to deal in |
9 return'\\u'+('0000'+a.charCodeAt().toString(16)).slice(-4);})+'"';} |
9 the Software without restriction, including without limitation the rights to |
10 return'"'+this+'"';};function assume(){if(!option.safe){if(option.rhino){combine(predefined,rhino);} |
10 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
11 if(option.browser||option.sidebar){combine(predefined,browser);} |
11 of the Software, and to permit persons to whom the Software is furnished to do |
12 if(option.sidebar){combine(predefined,sidebar);} |
12 so, subject to the following conditions: |
13 if(option.widget){combine(predefined,widget);}}} |
13 |
14 function quit(m,l,ch){throw{name:'JSLintError',line:l,character:ch,message:m+" ("+Math.floor((l/lines.length)*100)+"% scanned)."};} |
14 The above copyright notice and this permission notice shall be included in all |
15 function warning(m,t,a,b,c,d){var ch,l,w;t=t||nexttoken;if(t.id==='(end)'){t=token;} |
15 copies or substantial portions of the Software. |
16 l=t.line||0;ch=t.from||0;w={id:'(error)',raw:m,evidence:lines[l]||'',line:l,character:ch,a:a,b:b,c:c,d:d};w.reason=m.supplant(w);JSLINT.errors.push(w);if(option.passfail){quit('Stopping. ',l,ch);} |
16 |
17 warnings+=1;if(warnings===50){quit("Too many errors.",l,ch);} |
17 The Software shall be used for Good, not Evil. |
18 return w;} |
18 |
19 function warningAt(m,l,ch,a,b,c,d){return warning(m,{line:l,from:ch},a,b,c,d);} |
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 function error(m,t,a,b,c,d){var w=warning(m,t,a,b,c,d);quit("Stopping, unable to continue.",w.line,w.character);} |
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 function errorAt(m,l,ch,a,b,c,d){return error(m,{line:l,from:ch},a,b,c,d);} |
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 var lex=(function lex(){var character,from,line,s;function nextLine(){var at;line+=1;if(line>=lines.length){return false;} |
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 character=0;s=lines[line].replace(/\t/g,tab);at=s.search(cx);if(at>=0){warningAt("Unsafe character.",line,at);} |
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 return true;} |
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
25 function it(type,value){var i,t;if(type==='(color)'){t={type:type};}else if(type==='(punctuator)'||(type==='(identifier)'&&syntax.hasOwnProperty(value))){t=syntax[value]||syntax['(error)'];}else{t=syntax[type];} |
25 SOFTWARE. |
26 t=Object.create(t);if(type==='(string)'||type==='(range)'){if(jx.test(value)){warningAt("Script URL.",line,from);}} |
26 */ |
27 if(type==='(identifier)'){t.identifier=true;if(option.nomen&&value.charAt(0)==='_'){warningAt("Unexpected '_' in '{a}'.",line,from,value);}} |
27 |
28 t.value=value;t.line=line;t.character=character;t.from=from;i=t.id;if(i!=='(endline)'){prereg=i&&(('(,=:[!&|?{};'.indexOf(i.charAt(i.length-1))>=0)||i==='return');} |
28 /* |
29 return t;} |
29 JSLINT is a global function. It takes two parameters. |
30 return{init:function(source){if(typeof source==='string'){lines=source.replace(/\r\n/g,'\n').replace(/\r/g,'\n').split('\n');}else{lines=source;} |
30 |
31 line=-1;nextLine();from=0;},range:function(begin,end){var c,value='';from=character;if(s.charAt(0)!==begin){errorAt("Expected '{a}' and instead saw '{b}'.",line,character,begin,s.charAt(0));} |
31 var myResult = JSLINT(source, option); |
32 for(;;){s=s.slice(1);character+=1;c=s.charAt(0);switch(c){case'':errorAt("Missing '{a}'.",line,character,c);break;case end:s=s.slice(1);character+=1;return it('(range)',value);case xquote:case'\\':case'\'':case'"':warningAt("Unexpected '{a}'.",line,character,c);} |
32 |
33 value+=c;}},token:function(){var b,c,captures,d,depth,high,i,l,low,q,t;function match(x){var r=x.exec(s),r1;if(r){l=r[0].length;r1=r[1];c=r1.charAt(0);s=s.substr(l);character+=l;from=character-r1.length;return r1;}} |
33 The first parameter is either a string or an array of strings. If it is a |
34 function string(x){var c,j,r='';if(jsonmode&&x!=='"'){warningAt("Strings must use doublequote.",line,character);} |
34 string, it will be split on '\n' or '\r'. If it is an array of strings, it |
35 if(xquote===x||(xmode==='scriptstring'&&!xquote)){return it('(punctuator)',x);} |
35 is assumed that each string represents one line. The source can be a |
36 function esc(n){var i=parseInt(s.substr(j+1,n),16);j+=n;if(i>=32&&i<=126&&i!==34&&i!==92&&i!==39){warningAt("Unnecessary escapement.",line,character);} |
36 JavaScript text, or HTML text, or a Konfabulator text. |
37 character+=n;c=String.fromCharCode(i);} |
37 |
38 j=0;for(;;){while(j>=s.length){j=0;if(xmode!=='html'||!nextLine()){errorAt("Unclosed string.",line,from);}} |
38 The second parameter is an optional object of options which control the |
39 c=s.charAt(j);if(c===x){character+=1;s=s.substr(j+1);return it('(string)',r,x);} |
39 operation of JSLINT. Most of the options are booleans: They are all are |
40 if(c<' '){if(c==='\n'||c==='\r'){break;} |
40 optional and have a default value of false. |
41 warningAt("Control character in string: {a}.",line,character+j,s.slice(0,j));}else if(c===xquote){warningAt("Bad HTML string",line,character+j);}else if(c==='<'){if(option.safe&&xmode==='html'){warningAt("ADsafe string violation.",line,character+j);}else if(s.charAt(j+1)==='/'&&(xmode||option.safe)){warningAt("Expected '<\\/' and instead saw '</'.",line,character);}else if(s.charAt(j+1)==='!'&&(xmode||option.safe)){warningAt("Unexpected '<!' in a string.",line,character);}}else if(c==='\\'){if(xmode==='html'){if(option.safe){warningAt("ADsafe string violation.",line,character+j);}}else if(xmode==='styleproperty'){j+=1;character+=1;c=s.charAt(j);if(c!==x){warningAt("Escapement in style string.",line,character+j);}}else{j+=1;character+=1;c=s.charAt(j);switch(c){case xquote:warningAt("Bad HTML string",line,character+j);break;case'\\':case'\'':case'"':case'/':break;case'b':c='\b';break;case'f':c='\f';break;case'n':c='\n';break;case'r':c='\r';break;case't':c='\t';break;case'u':esc(4);break;case'v':c='\v';break;case'x':if(jsonmode){warningAt("Avoid \\x-.",line,character);} |
41 |
42 esc(2);break;default:warningAt("Bad escapement.",line,character);}}} |
42 If it checks out, JSLINT returns true. Otherwise, it returns false. |
43 r+=c;character+=1;j+=1;}} |
43 |
44 for(;;){if(!s){return it(nextLine()?'(endline)':'(end)','');} |
44 If false, you can inspect JSLINT.errors to find out the problems. |
45 while(xmode==='outer'){i=s.search(ox);if(i===0){break;}else if(i>0){character+=1;s=s.slice(i);break;}else{if(!nextLine()){return it('(end)','');}}} |
45 JSLINT.errors is an array of objects containing these members: |
46 t=match(rx[xmode]||tx);if(!t){if(xmode==='html'){return it('(error)',s.charAt(0));}else{t='';c='';while(s&&s<'!'){s=s.substr(1);} |
46 |
47 if(s){errorAt("Unexpected '{a}'.",line,character,s.substr(0,1));}}}else{if(c.isAlpha()||c==='_'||c==='$'){return it('(identifier)',t);} |
47 { |
48 if(c.isDigit()){if(xmode!=='style'&&!isFinite(Number(t))){warningAt("Bad number '{a}'.",line,character,t);} |
48 line : The line (relative to 0) at which the lint was found |
49 if(xmode!=='styleproperty'&&s.substr(0,1).isAlpha()){warningAt("Missing space after '{a}'.",line,character,t);} |
49 character : The character (relative to 0) at which the lint was found |
50 if(c==='0'){d=t.substr(1,1);if(d.isDigit()){if(token.id!=='.'&&xmode!=='styleproperty'){warningAt("Don't use extra leading zeros '{a}'.",line,character,t);}}else if(jsonmode&&(d==='x'||d==='X')){warningAt("Avoid 0x-. '{a}'.",line,character,t);}} |
50 reason : The problem |
51 if(t.substr(t.length-1)==='.'){warningAt("A trailing decimal point can be confused with a dot '{a}'.",line,character,t);} |
51 evidence : The text line in which the problem occurred |
52 return it('(number)',t);} |
52 raw : The raw message before the details were inserted |
53 switch(t){case'"':case"'":return string(t);case'//':if(src||(xmode&&xmode!=='script')){warningAt("Unexpected comment.",line,character);}else if(xmode==='script'&&/<\s*\//i.test(s)){warningAt("Unexpected <\/ in comment.",line,character);}else if((option.safe||xmode==='script')&&ax.test(s)){warningAt("Dangerous comment.",line,character);} |
53 a : The first detail |
54 s='';token.comment=true;break;case'/*':if(src||(xmode&&xmode!=='script'&&xmode!=='style'&&xmode!=='styleproperty')){warningAt("Unexpected comment.",line,character);} |
54 b : The second detail |
55 if(option.safe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);} |
55 c : The third detail |
56 for(;;){i=s.search(lx);if(i>=0){break;} |
56 d : The fourth detail |
57 if(!nextLine()){errorAt("Unclosed comment.",line,character);}else{if(option.safe&&ax.test(s)){warningAt("ADsafe comment violation.",line,character);}}} |
57 } |
58 character+=i+2;if(s.substr(i,1)==='/'){errorAt("Nested comment.",line,character);} |
58 |
59 s=s.substr(i+2);token.comment=true;break;case'/*members':case'/*member':case'/*jslint':case'/*global':case'*/':return{value:t,type:'special',line:line,character:character,from:from};case'':break;case'/':if(prereg){depth=0;captures=0;l=0;for(;;){b=true;c=s.charAt(l);l+=1;switch(c){case'':errorAt("Unclosed regular expression.",line,from);return;case'/':if(depth>0){warningAt("Unescaped '{a}'.",line,from+l,'/');} |
59 If a fatal error was found, a null will be the last element of the |
60 c=s.substr(0,l-1);q={g:true,i:true,m:true};while(q[s.charAt(l)]===true){q[s.charAt(l)]=false;l+=1;} |
60 JSLINT.errors array. |
61 character+=l;s=s.substr(l);return it('(regexp)',c);case'\\':c=s.charAt(l);if(c<' '){warningAt("Unexpected control character in regular expression.",line,from+l);}else if(c==='<'){warningAt("Unexpected escaped character '{a}' in regular expression.",line,from+l,c);} |
61 |
62 l+=1;break;case'(':depth+=1;b=false;if(s.charAt(l)==='?'){l+=1;switch(s.charAt(l)){case':':case'=':case'!':l+=1;break;default:warningAt("Expected '{a}' and instead saw '{b}'.",line,from+l,':',s.charAt(l));}}else{captures+=1;} |
62 You can request a Function Report, which shows all of the functions |
63 break;case')':if(depth===0){warningAt("Unescaped '{a}'.",line,from+l,')');}else{depth-=1;} |
63 and the parameters and vars that they use. This can be used to find |
64 break;case' ':q=1;while(s.charAt(l)===' '){l+=1;q+=1;} |
64 implied global variables and other problems. The report is in HTML and |
65 if(q>1){warningAt("Spaces are hard to count. Use {{a}}.",line,from+l,q);} |
65 can be inserted in an HTML <body>. |
66 break;case'[':if(s.charAt(l)==='^'){l+=1;} |
66 |
67 q=false;klass:do{c=s.charAt(l);l+=1;switch(c){case'[':case'^':warningAt("Unescaped '{a}'.",line,from+l,c);q=true;break;case'-':if(q){q=false;}else{warningAt("Unescaped '{a}'.",line,from+l,'-');q=true;} |
67 var myReport = JSLINT.report(limited); |
68 break;case']':if(!q){warningAt("Unescaped '{a}'.",line,from+l-1,'-');} |
68 |
69 break klass;case'\\':c=s.charAt(l);if(c<' '){warningAt("Unexpected control character in regular expression.",line,from+l);}else if(c==='<'){warningAt("Unexpected escaped character '{a}' in regular expression.",line,from+l,c);} |
69 If limited is true, then the report will be limited to only errors. |
70 l+=1;q=true;break;case'/':warningAt("Unescaped '{a}'.",line,from+l-1,'/');q=true;break;case'<':if(xmode==='script'){c=s.charAt(l);if(c==='!'||c==='/'){warningAt("HTML confusion in regular expression '<{a}'.",line,from+l,c);}} |
70 |
71 q=true;break;default:q=true;}}while(c);break;case'.':if(option.regexp){warningAt("Unexpected '{a}'.",line,from+l,c);} |
71 You can request a data structure which contains JSLint's results. |
72 break;case']':case'?':case'{':case'}':case'+':case'*':warningAt("Unescaped '{a}'.",line,from+l,c);break;case'<':if(xmode==='script'){c=s.charAt(l);if(c==='!'||c==='/'){warningAt("HTML confusion in regular expression '<{a}'.",line,from+l,c);}}} |
72 |
73 if(b){switch(s.charAt(l)){case'?':case'+':case'*':l+=1;if(s.charAt(l)==='?'){l+=1;} |
73 var myData = JSLINT.data(); |
74 break;case'{':l+=1;c=s.charAt(l);if(c<'0'||c>'9'){warningAt("Expected a number and instead saw '{a}'.",line,from+l,c);} |
74 |
75 l+=1;low=+c;for(;;){c=s.charAt(l);if(c<'0'||c>'9'){break;} |
75 It returns a structure with this form: |
76 l+=1;low=+c+(low*10);} |
76 |
77 high=low;if(c===','){l+=1;high=Infinity;c=s.charAt(l);if(c>='0'&&c<='9'){l+=1;high=+c;for(;;){c=s.charAt(l);if(c<'0'||c>'9'){break;} |
77 { |
78 l+=1;high=+c+(high*10);}}} |
78 errors: [ |
79 if(s.charAt(l)!=='}'){warningAt("Expected '{a}' and instead saw '{b}'.",line,from+l,'}',c);}else{l+=1;} |
79 { |
80 if(s.charAt(l)==='?'){l+=1;} |
80 line: NUMBER, |
81 if(low>high){warningAt("'{a}' should not be greater than '{b}'.",line,from+l,low,high);}}}} |
81 character: NUMBER, |
82 c=s.substr(0,l-1);character+=l;s=s.substr(l);return it('(regexp)',c);} |
82 reason: STRING, |
83 return it('(punctuator)',t);case'#':if(xmode==='html'||xmode==='styleproperty'){for(;;){c=s.charAt(0);if((c<'0'||c>'9')&&(c<'a'||c>'f')&&(c<'A'||c>'F')){break;} |
83 evidence: STRING |
84 character+=1;s=s.substr(1);t+=c;} |
84 } |
85 if(t.length!==4&&t.length!==7){warningAt("Bad hex color '{a}'.",line,from+l,t);} |
85 ], |
86 return it('(color)',t);} |
86 functions: [ |
87 return it('(punctuator)',t);default:if(xmode==='outer'&&c==='&'){character+=1;s=s.substr(1);for(;;){c=s.charAt(0);character+=1;s=s.substr(1);if(c===';'){break;} |
87 name: STRING, |
88 if(!((c>='0'&&c<='9')||(c>='a'&&c<='z')||c==='#')){errorAt("Bad entity",line,from+l,character);}} |
88 line: NUMBER, |
89 break;} |
89 last: NUMBER, |
90 return it('(punctuator)',t);}}}}};}());function addlabel(t,type){if(t==='hasOwnProperty'){error("'hasOwnProperty' is a really bad name.");} |
90 param: [ |
91 if(option.safe&&funct['(global)']){warning('ADsafe global: '+t+'.',token);} |
91 STRING |
92 if(funct.hasOwnProperty(t)&&!funct['(global)']){warning(funct[t]===true?"'{a}' was used before it was defined.":"'{a}' is already defined.",nexttoken,t);} |
92 ], |
93 funct[t]=type;if(type==='label'){scope[t]=funct;}else if(funct['(global)']){global[t]=funct;if(implied.hasOwnProperty(t)){warning("'{a}' was used before it was defined.",nexttoken,t);delete implied[t];}}else{funct['(scope)'][t]=funct;}} |
93 closure: [ |
94 function doOption(){var b,obj,filter,o=nexttoken.value,t,v;switch(o){case'*/':error("Unbegun comment.");break;case'/*members':case'/*member':o='/*members';if(!membersOnly){membersOnly={};} |
94 STRING |
95 obj=membersOnly;break;case'/*jslint':if(option.safe){warning("ADsafe restriction.");} |
95 ], |
96 obj=option;filter=boolOptions;break;case'/*global':if(option.safe){warning("ADsafe restriction.");} |
96 var: [ |
97 obj=predefined;break;} |
97 STRING |
98 for(;;){t=lex.token();if(t.id===','){t=lex.token();} |
98 ], |
99 while(t.id==='(endline)'){t=lex.token();} |
99 exception: [ |
100 if(t.type==='special'&&t.value==='*/'){break;} |
100 STRING |
101 if(t.type!=='(string)'&&t.type!=='(identifier)'&&o!=='/*members'){error("Bad option.",t);} |
101 ], |
102 if(filter){if(filter[t.value]!==true&&t.value!=='indent'){error("Bad option.",t);} |
102 outer: [ |
103 v=lex.token();if(v.id!==':'){error("Expected '{a}' and instead saw '{b}'.",t,':',t.value);} |
103 STRING |
104 v=lex.token();if(t.value==='indent'){b=+v.value;if(typeof b!=='number'||!isFinite(b)||b<=0||Math.floor(b)!==b){error("Expected a small integer and instead saw '{a}'.",v,v.value);} |
104 ], |
105 obj.white=true;}else if(v.value==='true'){b=true;}else if(v.value==='false'){b=false;}else{error("Expected '{a}' and instead saw '{b}'.",t,'true',t.value);}}else{b=true;} |
105 unused: [ |
106 obj[t.value]=b;} |
106 STRING |
107 if(filter){assume();}} |
107 ], |
108 function peek(p){var i=p||0,j=0,t;while(j<=i){t=lookahead[j];if(!t){t=lookahead[j]=lex.token();} |
108 global: [ |
109 j+=1;} |
109 STRING |
110 return t;} |
110 ], |
111 function advance(id,t){switch(token.id){case'(number)':if(nexttoken.id==='.'){warning("A dot following a number can be confused with a decimal point.",token);} |
111 label: [ |
112 break;case'-':if(nexttoken.id==='-'||nexttoken.id==='--'){warning("Confusing minusses.");} |
112 STRING |
113 break;case'+':if(nexttoken.id==='+'||nexttoken.id==='++'){warning("Confusing plusses.");} |
113 ] |
114 break;} |
114 ], |
115 if(token.type==='(string)'||token.identifier){anonname=token.value;} |
115 globals: [ |
116 if(id&&nexttoken.id!==id){if(t){if(nexttoken.id==='(end)'){warning("Unmatched '{a}'.",t,t.id);}else{warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",nexttoken,id,t.id,t.line+1,nexttoken.value);}}else if(nexttoken.type!=='(identifier)'||nexttoken.value!==id){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,id,nexttoken.value);}} |
116 STRING |
117 prevtoken=token;token=nexttoken;for(;;){nexttoken=lookahead.shift()||lex.token();if(nexttoken.id==='(end)'||nexttoken.id==='(error)'){return;} |
117 ], |
118 if(nexttoken.type==='special'){doOption();}else{if(nexttoken.id!=='(endline)'){break;}}}} |
118 member: { |
119 function parse(rbp,initial){var left,o;if(nexttoken.id==='(end)'){error("Unexpected early end of program.",token);} |
119 STRING: NUMBER |
120 advance();if(option.safe&&predefined[token.value]===true&&(nexttoken.id!=='('&&nexttoken.id!=='.')){warning('ADsafe violation.',token);} |
120 }, |
121 if(initial){anonname='anonymous';funct['(verb)']=token.value;} |
121 unuseds: [ |
122 if(initial===true&&token.fud){left=token.fud();}else{if(token.nud){o=token.exps;left=token.nud();}else{if(nexttoken.type==='(number)'&&token.id==='.'){warning("A leading decimal point can be confused with a dot: '.{a}'.",token,nexttoken.value);advance();return token;}else{error("Expected an identifier and instead saw '{a}'.",token,token.id);}} |
122 { |
123 while(rbp<nexttoken.lbp){o=nexttoken.exps;advance();if(token.led){left=token.led(left);}else{error("Expected an operator and instead saw '{a}'.",token,token.id);}} |
123 name: STRING, |
124 if(initial&&!o){warning("Expected an assignment or function call and instead saw an expression.",token);}} |
124 line: NUMBER |
125 return left;} |
125 } |
126 function abut(left,right){left=left||token;right=right||nexttoken;if(left.line!==right.line||left.character!==right.from){warning("Unexpected space after '{a}'.",right,left.value);}} |
126 ], |
127 function adjacent(left,right){left=left||token;right=right||nexttoken;if(option.white||xmode==='styleproperty'||xmode==='style'){if(left.character!==right.from&&left.line===right.line){warning("Unexpected space after '{a}'.",right,left.value);}}} |
127 implieds: [ |
128 function nospace(left,right){left=left||token;right=right||nexttoken;if(option.white&&!left.comment){if(left.line===right.line){adjacent(left,right);}}} |
128 { |
129 function nonadjacent(left,right){if(option.white){left=left||token;right=right||nexttoken;if(left.character===right.from){warning("Missing space after '{a}'.",nexttoken,left.value);}}} |
129 name: STRING, |
130 function nobreaknonadjacent(left,right){left=left||token;right=right||nexttoken;if(!option.laxbreak&&left.line!==right.line){warning("Bad line breaking before '{a}'.",right,right.id);}else if(option.white){left=left||token;right=right||nexttoken;if(left.character===right.from){warning("Missing space after '{a}'.",nexttoken,left.value);}}} |
130 line: NUMBER |
131 function indentation(bias){var i;if(option.white&&nexttoken.id!=='(end)'){i=indent+(bias||0);if(nexttoken.from!==i){warning("Expected '{a}' to have an indentation of {b} instead of {c}.",nexttoken,nexttoken.value,i,nexttoken.from);}}} |
131 } |
132 function nolinebreak(t){if(t.line!==nexttoken.line){warning("Line breaking error '{a}'.",t,t.value);}} |
132 ], |
133 function comma(){if(token.line!==nexttoken.line){if(!option.laxbreak){warning("Bad line breaking before '{a}'.",token,nexttoken.id);}}else if(token.character!==nexttoken.from&&option.white){warning("Unexpected space after '{a}'.",nexttoken,token.value);} |
133 urls: [ |
134 advance(',');nonadjacent(token,nexttoken);} |
134 STRING |
135 function symbol(s,p){var x=syntax[s];if(!x||typeof x!=='object'){syntax[s]=x={id:s,lbp:p,value:s};} |
135 ], |
136 return x;} |
136 json: BOOLEAN |
137 function delim(s){return symbol(s,0);} |
137 } |
138 function stmt(s,f){var x=delim(s);x.identifier=x.reserved=true;x.fud=f;return x;} |
138 |
139 function blockstmt(s,f){var x=stmt(s,f);x.block=true;return x;} |
139 Empty arrays will not be included. |
140 function reserveName(x){var c=x.id.charAt(0);if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){x.identifier=x.reserved=true;} |
140 |
141 return x;} |
141 */ |
142 function prefix(s,f){var x=symbol(s,150);reserveName(x);x.nud=(typeof f==='function')?f:function(){if(option.plusplus&&(this.id==='++'||this.id==='--')){warning("Unexpected use of '{a}'.",this,this.id);} |
142 |
143 this.right=parse(150);this.arity='unary';return this;};return x;} |
143 /*jslint |
144 function type(s,f){var x=delim(s);x.type=s;x.nud=f;return x;} |
144 evil: true, nomen: false, onevar: false, regexp: false, strict: true |
145 function reserve(s,f){var x=type(s,f);x.identifier=x.reserved=true;return x;} |
145 */ |
146 function reservevar(s,v){return reserve(s,function(){if(this.id==='this'){if(option.safe){warning("ADsafe violation.",this);}} |
146 |
147 return this;});} |
147 /*members "\b", "\t", "\n", "\f", "\r", "\"", "%", "(begin)", |
148 function infix(s,f,p,w){var x=symbol(s,p);reserveName(x);x.led=function(left){if(!w){nobreaknonadjacent(prevtoken,token);nonadjacent(token,nexttoken);} |
148 "(breakage)", "(context)", "(error)", "(global)", "(identifier)", |
149 if(typeof f==='function'){return f(left,this);}else{this.left=left;this.right=parse(p);return this;}};return x;} |
149 "(last)", "(line)", "(loopage)", "(name)", "(onevar)", "(params)", |
150 function relation(s,f){var x=symbol(s,100);x.led=function(left){nobreaknonadjacent(prevtoken,token);nonadjacent(token,nexttoken);var right=parse(100);if((left&&left.id==='NaN')||(right&&right.id==='NaN')){warning("Use the isNaN function to compare with NaN.",this);}else if(f){f.apply(this,[left,right]);} |
150 "(scope)", "(verb)", "++", "--", "\/", ADSAFE, Array, Boolean, COM, |
151 this.left=left;this.right=right;return this;};return x;} |
151 Canvas, CustomAnimation, Date, Debug, E, Error, EvalError, |
152 function isPoorRelation(node){return(node.type==='(number)'&&!+node.value)||(node.type==='(string)'&&!node.value)||node.type==='true'||node.type==='false'||node.type==='undefined'||node.type==='null';} |
152 FadeAnimation, Flash, FormField, Frame, Function, HotKey, Image, JSON, |
153 function assignop(s,f){symbol(s,20).exps=true;return infix(s,function(left,that){var l;that.left=left;if(predefined[left.value]===true&&scope[left.value]===true){warning('Global violation.',left);} |
153 LN10, LN2, LOG10E, LOG2E, MAX_VALUE, MIN_VALUE, Math, MenuItem, |
154 if(option.safe){l=left;do{if(predefined[l.value]===true){warning('ADsafe violation.',l);} |
154 MoveAnimation, NEGATIVE_INFINITY, Number, Object, Option, PI, |
155 l=l.left;}while(l);} |
155 POSITIVE_INFINITY, Point, RangeError, Rectangle, ReferenceError, RegExp, |
156 if(left){if(left.id==='.'||left.id==='['){if(left.left.value==='arguments'){warning('Bad assignment.',that);} |
156 ResizeAnimation, RotateAnimation, SQRT1_2, SQRT2, ScrollBar, String, |
157 that.right=parse(19);return that;}else if(left.identifier&&!left.reserved){if(funct[left.value]==='exception'){warning("Do not assign to the exception parameter.",left);} |
157 Style, SyntaxError, System, Text, TextArea, Timer, TypeError, URIError, |
158 that.right=parse(19);return that;} |
158 URL, Web, Window, XMLDOM, XMLHttpRequest, "\\", a, abbr, acronym, |
159 if(left===syntax['function']){warning("Expected an identifier in an assignment and instead saw a function invocation.",token);}} |
159 addEventListener, address, adsafe, alert, aliceblue, animator, |
160 error("Bad assignment.",that);},20);} |
160 antiquewhite, appleScript, applet, apply, approved, aqua, aquamarine, |
161 function bitwise(s,f,p){var x=symbol(s,p);reserveName(x);x.led=(typeof f==='function')?f:function(left){if(option.bitwise){warning("Unexpected use of '{a}'.",this,this.id);} |
161 area, arguments, arity, autocomplete, azure, b, background, |
162 this.left=left;this.right=parse(p);return this;};return x;} |
162 "background-attachment", "background-color", "background-image", |
163 function bitwiseassignop(s){symbol(s,20).exps=true;return infix(s,function(left,that){if(option.bitwise){warning("Unexpected use of '{a}'.",that,that.id);} |
163 "background-position", "background-repeat", base, bdo, beep, beige, big, |
164 nonadjacent(prevtoken,token);nonadjacent(token,nexttoken);if(left){if(left.id==='.'||left.id==='['||(left.identifier&&!left.reserved)){parse(19);return left;} |
164 bisque, bitwise, black, blanchedalmond, block, blockquote, blue, |
165 if(left===syntax['function']){warning("Expected an identifier in an assignment, and instead saw a function invocation.",token);}} |
165 blueviolet, blur, body, border, "border-bottom", "border-bottom-color", |
166 error("Bad assignment.",that);},20);} |
166 "border-bottom-style", "border-bottom-width", "border-collapse", |
167 function suffix(s,f){var x=symbol(s,150);x.led=function(left){if(option.plusplus){warning("Unexpected use of '{a}'.",this,this.id);} |
167 "border-color", "border-left", "border-left-color", "border-left-style", |
168 this.left=left;return this;};return x;} |
168 "border-left-width", "border-right", "border-right-color", |
169 function optionalidentifier(){if(nexttoken.reserved){warning("Expected an identifier and instead saw '{a}' (a reserved word).",nexttoken,nexttoken.id);} |
169 "border-right-style", "border-right-width", "border-spacing", |
170 if(nexttoken.identifier){advance();return token.value;}} |
170 "border-style", "border-top", "border-top-color", "border-top-style", |
171 function identifier(){var i=optionalidentifier();if(i){return i;} |
171 "border-top-width", "border-width", bottom, br, brown, browser, |
172 if(token.id==='function'&&nexttoken.id==='('){warning("Missing name in function statement.");}else{error("Expected an identifier and instead saw '{a}'.",nexttoken,nexttoken.value);}} |
172 burlywood, button, bytesToUIString, c, cadetblue, call, callee, caller, |
173 function reachable(s){var i=0,t;if(nexttoken.id!==';'||noreach){return;} |
173 canvas, cap, caption, "caption-side", cases, center, charAt, charCodeAt, |
174 for(;;){t=peek(i);if(t.reach){return;} |
174 character, chartreuse, chocolate, chooseColor, chooseFile, chooseFolder, |
175 if(t.id!=='(endline)'){if(t.id==='function'){warning("Inner functions should be listed at the top of the outer function.",t);break;} |
175 cite, clear, clearInterval, clearTimeout, clip, close, closeWidget, |
176 warning("Unreachable '{a}' after '{b}'.",t,t.value,s);break;} |
176 closed, closure, cm, code, col, colgroup, color, comment, condition, |
177 i+=1;}} |
177 confirm, console, constructor, content, convertPathToHFS, |
178 function statement(noindent){var i=indent,r,s=scope,t=nexttoken;if(t.id===';'){warning("Unnecessary semicolon.",t);advance(';');return;} |
178 convertPathToPlatform, coral, cornflowerblue, cornsilk, |
179 if(t.identifier&&!t.reserved&&peek().id===':'){advance();advance(':');scope=Object.create(s);addlabel(t.value,'label');if(!nexttoken.labelled){warning("Label '{a}' on {b} statement.",nexttoken,t.value,nexttoken.value);} |
179 "counter-increment", "counter-reset", create, crimson, css, cursor, |
180 if(jx.test(t.value+':')){warning("Label '{a}' looks like a javascript url.",t,t.value);} |
180 cyan, d, darkblue, darkcyan, darkgoldenrod, darkgray, darkgreen, |
181 nexttoken.label=t.value;t=nexttoken;} |
181 darkkhaki, darkmagenta, darkolivegreen, darkorange, darkorchid, darkred, |
182 if(!noindent){indentation();} |
182 darksalmon, darkseagreen, darkslateblue, darkslategray, darkturquoise, |
183 r=parse(0,true);if(!t.block){if(nexttoken.id!==';'){warningAt("Missing semicolon.",token.line,token.from+token.value.length);}else{adjacent(token,nexttoken);advance(';');nonadjacent(token,nexttoken);}} |
183 darkviolet, data, dd, debug, decodeURI, decodeURIComponent, deeppink, |
184 indent=i;scope=s;return r;} |
184 deepskyblue, defaultStatus, defineClass, del, deserialize, dfn, |
185 function use_strict(){if(nexttoken.value==='use strict'){advance();advance(';');return true;}else{return false;}} |
185 dimension, dimgray, dir, direction, display, div, dl, document, |
186 function statements(begin){var a=[],f,p;if(begin&&!use_strict()&&option.strict){warning('Missing "use strict" statement.',nexttoken);} |
186 dodgerblue, dt, edition, else, em, embed, empty, "empty-cells", |
187 if(option.adsafe){switch(begin){case'script':if(!adsafe_may){if(nexttoken.value!=='ADSAFE'||peek(0).id!=='.'||(peek(1).value!=='id'&&peek(1).value!=='go')){error('ADsafe violation: Missing ADSAFE.id or ADSAFE.go.',nexttoken);}} |
187 encodeURI, encodeURIComponent, entityify, eqeqeq, errors, escape, eval, |
188 if(nexttoken.value==='ADSAFE'&&peek(0).id==='.'&&peek(1).value==='id'){if(adsafe_may){error('ADsafe violation.',nexttoken);} |
188 event, evidence, evil, ex, exception, exec, exps, fieldset, filesystem, |
189 advance('ADSAFE');advance('.');advance('id');advance('(');if(nexttoken.value!==adsafe_id){error('ADsafe violation: id does not match.',nexttoken);} |
189 firebrick, first, float, floor, floralwhite, focus, focusWidget, font, |
190 advance('(string)');advance(')');advance(';');adsafe_may=true;} |
190 "font-face", "font-family", "font-size", "font-size-adjust", |
191 break;case'lib':if(nexttoken.value==='ADSAFE'){advance('ADSAFE');advance('.');advance('lib');advance('(');advance('(string)');comma();f=parse(0);if(f.id!=='function'){error('The second argument to lib must be a function.',f);} |
191 "font-stretch", "font-style", "font-variant", "font-weight", |
192 p=f.funct['(params)'];if(p&&p!=='lib'){error("Expected '{a}' and instead saw '{b}'.",f,'lib',p);} |
192 forestgreen, forin, form, fragment, frame, frames, frameset, from, |
193 advance(')');advance(';');return a;}else{error("ADsafe lib violation.");}}} |
193 fromCharCode, fuchsia, fud, funct, function, functions, g, gainsboro, |
194 while(!nexttoken.reach&&nexttoken.id!=='(end)'){if(nexttoken.id===';'){warning("Unnecessary semicolon.");advance(';');}else{a.push(statement());}} |
194 gc, getComputedStyle, ghostwhite, global, globals, gold, goldenrod, |
195 return a;} |
195 gray, green, greenyellow, h1, h2, h3, h4, h5, h6, hasOwnProperty, head, |
196 function block(f){var a,b=inblock,s=scope,t;inblock=f;if(f){scope=Object.create(scope);} |
196 height, help, history, honeydew, hotpink, hr, html, i, iTunes, id, |
197 nonadjacent(token,nexttoken);t=nexttoken;if(nexttoken.id==='{'){advance('{');if(nexttoken.id!=='}'||token.line!==nexttoken.line){indent+=option.indent;if(!f&&nexttoken.from===indent+option.indent){indent+=option.indent;} |
197 identifier, iframe, img, immed, implieds, import, in, include, indent, |
198 if(!f){use_strict();} |
198 indexOf, indianred, indigo, init, input, ins, isAlpha, |
199 a=statements();indent-=option.indent;indentation();} |
199 isApplicationRunning, isDigit, isFinite, isNaN, ivory, join, jslint, |
200 advance('}',t);}else{warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'{',nexttoken.value);noreach=true;a=[statement()];noreach=false;} |
200 json, kbd, khaki, konfabulatorVersion, label, labelled, lang, last, |
201 funct['(verb)']=null;scope=s;inblock=b;return a;} |
201 lavender, lavenderblush, lawngreen, laxbreak, lbp, led, left, legend, |
202 function idValue(){return this;} |
202 lemonchiffon, length, "letter-spacing", li, lib, lightblue, lightcoral, |
203 function countMember(m){if(membersOnly&&membersOnly[m]!==true){warning("Unexpected /*member '{a}'.",nexttoken,m);} |
203 lightcyan, lightgoldenrodyellow, lightgreen, lightpink, lightsalmon, |
204 if(typeof member[m]==='number'){member[m]+=1;}else{member[m]=1;}} |
204 lightseagreen, lightskyblue, lightslategray, lightsteelblue, |
205 function note_implied(token){var name=token.value,line=token.line+1,a=implied[name];if(typeof a==='function'){a=false;} |
205 lightyellow, lime, limegreen, line, "line-height", linen, link, |
206 if(!a){a=[line];implied[name]=a;}else if(a[a.length-1]!==line){a.push(line);}} |
206 "list-style", "list-style-image", "list-style-position", |
207 function cssName(){if(nexttoken.identifier){advance();return true;}} |
207 "list-style-type", load, loadClass, location, log, m, magenta, map, |
208 function cssNumber(){if(nexttoken.id==='-'){advance('-');advance('(number)');} |
208 margin, "margin-bottom", "margin-left", "margin-right", "margin-top", |
209 if(nexttoken.type==='(number)'){advance();return true;}} |
209 "marker-offset", maroon, match, "max-height", "max-width", maxerr, md5, |
210 function cssString(){if(nexttoken.type==='(string)'){advance();return true;}} |
210 media, mediumaquamarine, mediumblue, mediumorchid, mediumpurple, |
211 function cssColor(){var i,number;if(nexttoken.identifier){if(nexttoken.value==='rgb'){advance();advance('(');for(i=0;i<3;i+=1){number=nexttoken.value;if(nexttoken.type!=='(number)'||number<0){warning("Expected a positive number and instead saw '{a}'",nexttoken,number);advance();}else{advance();if(nexttoken.id==='%'){advance('%');if(number>100){warning("Expected a percentage and instead saw '{a}'",token,number);}}else{if(number>255){warning("Expected a small number and instead saw '{a}'",token,number);}}}} |
211 mediumseagreen, mediumslateblue, mediumspringgreen, mediumturquoise, |
212 advance(')');return true;}else if(cssColorData[nexttoken.value]===true){advance();return true;}}else if(nexttoken.type==='(color)'){advance();return true;} |
212 mediumvioletred, member, menu, message, meta, midnightblue, |
213 return false;} |
213 "min-height", "min-width", mintcream, mistyrose, mm, moccasin, moveBy, |
214 function cssLength(){if(nexttoken.id==='-'){advance('-');adjacent();} |
214 moveTo, name, navajowhite, navigator, navy, new, newcap, noframes, |
215 if(nexttoken.type==='(number)'){advance();if(nexttoken.type!=='(string)'&&cssLengthData[nexttoken.value]===true){adjacent();advance();}else if(+token.value!==0){warning("Expected a linear unit and instead saw '{a}'.",nexttoken,nexttoken.value);} |
215 nomen, noscript, nud, object, ol, oldlace, olive, olivedrab, on, |
216 return true;} |
216 onbeforeunload, onblur, onerror, onevar, onfocus, onload, onresize, |
217 return false;} |
217 onunload, opacity, open, openURL, opener, opera, optgroup, option, |
218 function cssLineHeight(){if(nexttoken.id==='-'){advance('-');adjacent();} |
218 orange, orangered, orchid, outer, outline, "outline-color", |
219 if(nexttoken.type==='(number)'){advance();if(nexttoken.type!=='(string)'&&cssLengthData[nexttoken.value]===true){adjacent();advance();} |
219 "outline-style", "outline-width", overflow, "overflow-x", "overflow-y", |
220 return true;} |
220 p, padding, "padding-bottom", "padding-left", "padding-right", |
221 return false;} |
221 "padding-top", page, "page-break-after", "page-break-before", |
222 function cssWidth(){if(nexttoken.identifier){switch(nexttoken.value){case'thin':case'medium':case'thick':advance();return true;}}else{return cssLength();}} |
222 palegoldenrod, palegreen, paleturquoise, palevioletred, papayawhip, |
223 function cssMargin(){if(nexttoken.identifier){if(nexttoken.value==='auto'){advance();return true;}}else{return cssLength();}} |
223 param, parent, parseFloat, parseInt, passfail, pc, peachpuff, peru, |
224 function cssAttr(){if(nexttoken.identifier&&nexttoken.value==='attr'){advance();advance('(');if(!nexttoken.identifier){warning("Expected a name and instead saw '{a}'.",nexttoken,nexttoken.value);} |
224 pink, play, plum, plusplus, pop, popupMenu, position, powderblue, pre, |
225 advance();advance(')');return true;} |
225 predef, preferenceGroups, preferences, print, prompt, prototype, pt, |
226 return false;} |
226 purple, push, px, q, quit, quotes, random, range, raw, reach, readFile, |
227 function cssCommaList(){while(nexttoken.id!==';'){if(!cssName()&&!cssString()){warning("Expected a name and instead saw '{a}'.",nexttoken,nexttoken.value);} |
227 readUrl, reason, red, regexp, reloadWidget, removeEventListener, |
228 if(nexttoken.id!==','){return true;} |
228 replace, report, reserved, resizeBy, resizeTo, resolvePath, |
229 comma();}} |
229 resumeUpdates, rhino, right, rosybrown, royalblue, runCommand, |
230 function cssCounter(){if(nexttoken.identifier&&nexttoken.value==='counter'){advance();advance('(');if(!nexttoken.identifier){} |
230 runCommandInBg, saddlebrown, safe, salmon, samp, sandybrown, saveAs, |
231 advance();if(nexttoken.id===','){comma();if(nexttoken.type!=='(string)'){warning("Expected a string and instead saw '{a}'.",nexttoken,nexttoken.value);} |
231 savePreferences, screen, script, scroll, scrollBy, scrollTo, seagreen, |
232 advance();} |
232 seal, search, seashell, select, serialize, setInterval, setTimeout, |
233 advance(')');return true;} |
233 shift, showWidgetPreferences, sidebar, sienna, silver, skyblue, |
234 if(nexttoken.identifier&&nexttoken.value==='counters'){advance();advance('(');if(!nexttoken.identifier){warning("Expected a name and instead saw '{a}'.",nexttoken,nexttoken.value);} |
234 slateblue, slategray, sleep, slice, small, snow, sort, span, spawn, |
235 advance();if(nexttoken.id===','){comma();if(nexttoken.type!=='(string)'){warning("Expected a string and instead saw '{a}'.",nexttoken,nexttoken.value);} |
235 speak, split, springgreen, src, status, steelblue, strict, strong, |
236 advance();} |
236 style, styleproperty, sub, substr, sup, supplant, suppressUpdates, sync, |
237 if(nexttoken.id===','){comma();if(nexttoken.type!=='(string)'){warning("Expected a string and instead saw '{a}'.",nexttoken,nexttoken.value);} |
237 system, table, "table-layout", tan, tbody, td, teal, tellWidget, test, |
238 advance();} |
238 "text-align", "text-decoration", "text-indent", "text-shadow", |
239 advance(')');return true;} |
239 "text-transform", textarea, tfoot, th, thead, thistle, title, |
240 return false;} |
240 toLowerCase, toString, toUpperCase, toint32, token, tomato, top, tr, tt, |
241 function cssShape(){var i;if(nexttoken.identifier&&nexttoken.value==='rect'){advance();advance('(');for(i=0;i<4;i+=1){if(!cssLength()){warning("Expected a number and instead saw '{a}'.",nexttoken,nexttoken.value);break;}} |
241 turquoise, type, u, ul, undef, unescape, "unicode-bidi", unused, |
242 advance(')');return true;} |
242 unwatch, updateNow, urls, value, valueOf, var, version, |
243 return false;} |
243 "vertical-align", violet, visibility, watch, wheat, white, |
244 function cssUrl(){var url;if(nexttoken.identifier&&nexttoken.value==='url'){nexttoken=lex.range('(',')');url=nexttoken.value;advance();if(option.safe&&ux.test(url)){error("ADsafe URL violation.");} |
244 "white-space", whitesmoke, widget, width, "word-spacing", "word-wrap", |
245 urls.push(url);return true;} |
245 yahooCheckLogin, yahooLogin, yahooLogout, yellow, yellowgreen, |
246 return false;} |
246 "z-index" |
247 cssAny=[cssUrl,function(){for(;;){if(nexttoken.identifier){switch(nexttoken.value.toLowerCase()){case'url':cssUrl();break;case'expression':warning("Unexpected expression '{a}'.",nexttoken,nexttoken.value);advance();break;default:advance();}}else{if(nexttoken.id===';'||nexttoken.id==='!'||nexttoken.id==='(end)'||nexttoken.id==='}'){return true;} |
247 */ |
248 advance();}}}];cssBorderStyle=['none','hidden','dotted','dashed','solid','double','ridge','inset','outset'];cssAttributeData={background:[true,'background-attachment','background-color','background-image','background-position','background-repeat'],'background-attachment':['scroll','fixed'],'background-color':['transparent',cssColor],'background-image':['none',cssUrl],'background-position':[2,[cssLength,'top','bottom','left','right','center']],'background-repeat':['repeat','repeat-x','repeat-y','no-repeat'],'border':[true,'border-color','border-style','border-width'],'border-bottom':[true,'border-bottom-color','border-bottom-style','border-bottom-width'],'border-bottom-color':cssColor,'border-bottom-style':cssBorderStyle,'border-bottom-width':cssWidth,'border-collapse':['collapse','separate'],'border-color':['transparent',4,cssColor],'border-left':[true,'border-left-color','border-left-style','border-left-width'],'border-left-color':cssColor,'border-left-style':cssBorderStyle,'border-left-width':cssWidth,'border-right':[true,'border-right-color','border-right-style','border-right-width'],'border-right-color':cssColor,'border-right-style':cssBorderStyle,'border-right-width':cssWidth,'border-spacing':[2,cssLength],'border-style':[4,cssBorderStyle],'border-top':[true,'border-top-color','border-top-style','border-top-width'],'border-top-color':cssColor,'border-top-style':cssBorderStyle,'border-top-width':cssWidth,'border-width':[4,cssWidth],bottom:[cssLength,'auto'],'caption-side':['bottom','left','right','top'],clear:['both','left','none','right'],clip:[cssShape,'auto'],color:cssColor,content:['open-quote','close-quote','no-open-quote','no-close-quote',cssString,cssUrl,cssCounter,cssAttr],'counter-increment':[cssName,'none'],'counter-reset':[cssName,'none'],cursor:[cssUrl,'auto','crosshair','default','e-resize','help','move','n-resize','ne-resize','nw-resize','pointer','s-resize','se-resize','sw-resize','w-resize','text','wait'],direction:['ltr','rtl'],display:['block','compact','inline','inline-block','inline-table','list-item','marker','none','run-in','table','table-caption','table-cell','table-column','table-column-group','table-footer-group','table-header-group','table-row','table-row-group'],'empty-cells':['show','hide'],'float':['left','none','right'],font:['caption','icon','menu','message-box','small-caption','status-bar',true,'font-size','font-style','font-weight','font-family'],'font-family':cssCommaList,'font-size':['xx-small','x-small','small','medium','large','x-large','xx-large','larger','smaller',cssLength],'font-size-adjust':['none',cssNumber],'font-stretch':['normal','wider','narrower','ultra-condensed','extra-condensed','condensed','semi-condensed','semi-expanded','expanded','extra-expanded'],'font-style':['normal','italic','oblique'],'font-variant':['normal','small-caps'],'font-weight':['normal','bold','bolder','lighter',cssNumber],height:[cssLength,'auto'],left:[cssLength,'auto'],'letter-spacing':['normal',cssLength],'line-height':['normal',cssLineHeight],'list-style':[true,'list-style-image','list-style-position','list-style-type'],'list-style-image':['none',cssUrl],'list-style-position':['inside','outside'],'list-style-type':['circle','disc','square','decimal','decimal-leading-zero','lower-roman','upper-roman','lower-greek','lower-alpha','lower-latin','upper-alpha','upper-latin','hebrew','katakana','hiragana-iroha','katakana-oroha','none'],margin:[4,cssMargin],'margin-bottom':cssMargin,'margin-left':cssMargin,'margin-right':cssMargin,'margin-top':cssMargin,'marker-offset':[cssLength,'auto'],'max-height':[cssLength,'none'],'max-width':[cssLength,'none'],'min-height':cssLength,'min-width':cssLength,opacity:cssNumber,outline:[true,'outline-color','outline-style','outline-width'],'outline-color':['invert',cssColor],'outline-style':['dashed','dotted','double','groove','inset','none','outset','ridge','solid'],'outline-width':cssWidth,overflow:['auto','hidden','scroll','visible'],padding:[4,cssLength],'padding-bottom':cssLength,'padding-left':cssLength,'padding-right':cssLength,'padding-top':cssLength,position:['absolute','fixed','relative','static'],quotes:[8,cssString],right:[cssLength,'auto'],'table-layout':['auto','fixed'],'text-align':['center','justify','left','right'],'text-decoration':['none','underline','overline','line-through','blink'],'text-indent':cssLength,'text-shadow':['none',4,[cssColor,cssLength]],'text-transform':['capitalize','uppercase','lowercase','none'],top:[cssLength,'auto'],'unicode-bidi':['normal','embed','bidi-override'],'vertical-align':['baseline','bottom','sub','super','top','text-top','middle','text-bottom',cssLength],visibility:['visible','hidden','collapse'],'white-space':['normal','pre','nowrap'],width:[cssLength,'auto'],'word-spacing':['normal',cssLength],'z-index':['auto',cssNumber]};function styleAttribute(){var v;while(nexttoken.id==='*'||nexttoken.id==='#'||nexttoken.value==='_'){if(!option.css){warning("Unexpected '{a}'.",nexttoken,nexttoken.value);} |
248 |
249 advance();} |
249 |
250 if(nexttoken.id==='-'){if(!option.css){warning("Unexpected '{a}'.",nexttoken,nexttoken.value);} |
250 |
251 advance('-');if(!nexttoken.identifier){warning("Expected a non-standard style attribute and instead saw '{a}'.",nexttoken,nexttoken.value);} |
251 // We build the application inside a function so that we produce only a single |
252 advance();return cssAny;}else{if(!nexttoken.identifier){warning("Excepted a style attribute, and instead saw '{a}'.",nexttoken,nexttoken.value);}else{if(cssAttributeData.hasOwnProperty(nexttoken.value)){v=cssAttributeData[nexttoken.value];}else{v=cssAny;if(!option.css){warning("Unrecognized style attribute '{a}'.",nexttoken,nexttoken.value);}}} |
252 // global variable. The function will be invoked, its return value is the JSLINT |
253 advance();return v;}} |
253 // application itself. |
254 function styleValue(v){var i=0,n,once,match,round,start=0,vi;switch(typeof v){case'function':return v();case'string':if(nexttoken.identifier&&nexttoken.value===v){advance();return true;} |
254 |
255 return false;} |
255 "use strict"; |
256 for(;;){if(i>=v.length){return false;} |
256 |
257 vi=v[i];i+=1;if(vi===true){break;}else if(typeof vi==='number'){n=vi;vi=v[i];i+=1;}else{n=1;} |
257 var JSLINT = (function () { |
258 match=false;while(n>0){if(styleValue(vi)){match=true;n-=1;}else{break;}} |
258 var adsafe_id, // The widget's ADsafe id. |
259 if(match){return true;}} |
259 adsafe_may, // The widget may load approved scripts. |
260 start=i;once=[];for(;;){round=false;for(i=start;i<v.length;i+=1){if(!once[i]){if(styleValue(cssAttributeData[v[i]])){match=true;round=true;once[i]=true;break;}}} |
260 adsafe_went, // ADSAFE.go has been called. |
261 if(!round){return match;}}} |
261 anonname, // The guessed name for anonymous functions. |
262 function substyle(){var v;for(;;){if(nexttoken.id==='}'||nexttoken.id==='(end)'||xquote&&nexttoken.id===xquote){return;} |
262 approved, // ADsafe approved urls. |
263 while(nexttoken.id===';'){warning("Misplaced ';'.");advance(';');} |
263 |
264 v=styleAttribute();advance(':');if(nexttoken.identifier&&nexttoken.value==='inherit'){advance();}else{styleValue(v);} |
264 atrule = { |
265 while(nexttoken.id!==';'&&nexttoken.id!=='!'&&nexttoken.id!=='}'&&nexttoken.id!=='(end)'&&nexttoken.id!==xquote){warning("Unexpected token '{a}'.",nexttoken,nexttoken.value);advance();} |
265 media : true, |
266 if(nexttoken.id==='!'){advance('!');adjacent();if(nexttoken.identifier&&nexttoken.value==='important'){advance();}else{warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'important',nexttoken.value);}} |
266 'font-face': true, |
267 if(nexttoken.id==='}'||nexttoken.id===xquote){warning("Missing '{a}'.",nexttoken,';');}else{advance(';');}}} |
267 page : true |
268 function stylePattern(){var name;if(nexttoken.id==='{'){warning("Expected a style pattern, and instead saw '{a}'.",nexttoken,nexttoken.id);}else if(nexttoken.id==='@'){advance('@');name=nexttoken.value;if(nexttoken.identifier&&atrule[name]===true){advance();return name;} |
268 }, |
269 warning("Expected an at-rule, and instead saw @{a}.",nexttoken,name);} |
269 |
270 for(;;){if(nexttoken.identifier){if(!htmltag.hasOwnProperty(nexttoken.value)){warning("Expected a tagName, and instead saw {a}.",nexttoken,nexttoken.value);} |
270 // These are members that should not be permitted in the safe subset. |
271 advance();}else{switch(nexttoken.id){case'>':case'+':advance();if(!nexttoken.identifier||!htmltag.hasOwnProperty(nexttoken.value)){warning("Expected a tagName, and instead saw {a}.",nexttoken,nexttoken.value);} |
271 |
272 advance();break;case':':advance(':');if(pseudorule[nexttoken.value]!==true){warning("Expected a pseudo, and instead saw :{a}.",nexttoken,nexttoken.value);} |
272 banned = { // the member names that ADsafe prohibits. |
273 advance();if(nexttoken.value==='lang'){advance('(');if(!nexttoken.identifier){warning("Expected a lang code, and instead saw :{a}.",nexttoken,nexttoken.value);} |
273 'arguments' : true, |
274 advance(')');} |
274 callee : true, |
275 break;case'#':advance('#');if(!nexttoken.identifier){warning("Expected an id, and instead saw #{a}.",nexttoken,nexttoken.value);} |
275 caller : true, |
276 advance();break;case'*':advance('*');break;case'.':advance('.');if(!nexttoken.identifier){warning("Expected a class, and instead saw #.{a}.",nexttoken,nexttoken.value);} |
276 constructor : true, |
277 advance();break;case'[':advance('[');if(!nexttoken.identifier){warning("Expected an attribute, and instead saw [{a}].",nexttoken,nexttoken.value);} |
277 'eval' : true, |
278 advance();if(nexttoken.id==='='||nexttoken.id==='~='||nexttoken.id==='|='){advance();if(nexttoken.type!=='(string)'){warning("Expected a string, and instead saw {a}.",nexttoken,nexttoken.value);} |
278 prototype : true, |
279 advance();} |
279 unwatch : true, |
280 advance(']');break;default:error("Expected a CSS selector, and instead saw {a}.",nexttoken,nexttoken.value);}} |
280 valueOf : true, |
281 if(nexttoken.id==='</'||nexttoken.id==='{'||nexttoken.id==='(end)'){return'';} |
281 watch : true |
282 if(nexttoken.id===','){comma();}}} |
282 }, |
283 function styles(){while(nexttoken.id!=='</'&&nexttoken.id!=='(end)'){stylePattern();xmode='styleproperty';if(nexttoken.id===';'){advance(';');}else{advance('{');substyle();xmode='style';advance('}');}}} |
283 |
284 function doBegin(n){if(n!=='html'&&!option.fragment){if(n==='div'&&option.adsafe){error("ADSAFE: Use the fragment option.");}else{error("Expected '{a}' and instead saw '{b}'.",token,'html',n);}} |
284 |
285 if(option.adsafe){if(n==='html'){error("Currently, ADsafe does not operate on whole HTML documents. It operates on <div> fragments and .js files.",token);} |
285 // These are the JSLint boolean options. |
286 if(option.fragment){if(n!=='div'){error("ADsafe violation: Wrap the widget in a div.",token);}}else{error("Use the fragment option.",token);}} |
286 |
287 option.browser=true;assume();} |
287 boolOptions = { |
288 function doAttribute(n,a,v){var u,x;if(a==='id'){u=typeof v==='string'?v.toUpperCase():'';if(ids[u]===true){warning("Duplicate id='{a}'.",nexttoken,v);} |
288 adsafe : true, // if ADsafe should be enforced |
289 if(option.adsafe){if(adsafe_id){if(v.slice(0,adsafe_id.length)!==adsafe_id){warning("ADsafe violation: An id must have a '{a}' prefix",nexttoken,adsafe_id);}else if(!/^[A-Z]+_[A-Z]+$/.test(v)){warning("ADSAFE violation: bad id.");}}else{adsafe_id=v;if(!/^[A-Z]+_$/.test(v)){warning("ADSAFE violation: bad id.");}}} |
289 bitwise : true, // if bitwise operators should not be allowed |
290 x=v.search(dx);if(x>=0){warning("Unexpected character '{a}' in {b}.",token,v.charAt(x),a);} |
290 browser : true, // if the standard browser globals should be predefined |
291 ids[u]=true;}else if(a==='class'||a==='type'||a==='name'){x=v.search(qx);if(x>=0){warning("Unexpected character '{a}' in {b}.",token,v.charAt(x),a);} |
291 cap : true, // if upper case HTML should be allowed |
292 ids[u]=true;}else if(a==='href'||a==='background'||a==='content'||a==='data'||a.indexOf('src')>=0||a.indexOf('url')>=0){if(option.safe&&ux.test(v)){error("ADsafe URL violation.");} |
292 css : true, // if CSS workarounds should be tolerated |
293 urls.push(v);}else if(a==='for'){if(option.adsafe){if(adsafe_id){if(v.slice(0,adsafe_id.length)!==adsafe_id){warning("ADsafe violation: An id must have a '{a}' prefix",nexttoken,adsafe_id);}else if(!/^[A-Z]+_[A-Z]+$/.test(v)){warning("ADSAFE violation: bad id.");}}else{warning("ADSAFE violation: bad id.");}}}else if(a==='name'){if(option.adsafe&&v.indexOf('_')>=0){warning("ADsafe name violation.");}}} |
293 debug : true, // if debugger statements should be allowed |
294 function doTag(n,a){var i,t=htmltag[n],x;src=false;if(!t){error("Unrecognized tag '<{a}>'.",nexttoken,n===n.toLowerCase()?n:n+' (capitalization error)');} |
294 eqeqeq : true, // if === should be required |
295 if(stack.length>0){if(n==='html'){error("Too many <html> tags.",token);} |
295 evil : true, // if eval should be allowed |
296 x=t.parent;if(x){if(x.indexOf(' '+stack[stack.length-1].name+' ')<0){error("A '<{a}>' must be within '<{b}>'.",token,n,x);}}else if(!option.adsafe&&!option.fragment){i=stack.length;do{if(i<=0){error("A '<{a}>' must be within '<{b}>'.",token,n,'body');} |
296 forin : true, // if for in statements must filter |
297 i-=1;}while(stack[i].name!=='body');}} |
297 fragment : true, // if HTML fragments should be allowed |
298 switch(n){case'div':if(option.adsafe&&stack.length===1&&!adsafe_id){warning("ADSAFE violation: missing ID_.");} |
298 immed : true, // if immediate invocations must be wrapped in parens |
299 break;case'script':xmode='script';advance('>');indent=nexttoken.from;if(a.lang){warning("lang is deprecated.",token);} |
299 laxbreak : true, // if line breaks should not be checked |
300 if(option.adsafe&&stack.length!==1){warning("ADsafe script placement violation.",token);} |
300 newcap : true, // if constructor names must be capitalized |
301 if(a.src){if(option.adsafe&&(!adsafe_may||!approved[a.src])){warning("ADsafe unapproved script source.",token);} |
301 nomen : true, // if names should be checked |
302 if(a.type){warning("type is unnecessary.",token);}}else{if(adsafe_went){error("ADsafe script violation.",token);} |
302 on : true, // if HTML event handlers should be allowed |
303 statements('script');} |
303 onevar : true, // if only one var statement per function should be allowed |
304 xmode='html';advance('</');if(!nexttoken.identifier&&nexttoken.value!=='script'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'script',nexttoken.value);} |
304 passfail : true, // if the scan should stop on first error |
305 advance();xmode='outer';break;case'style':xmode='style';advance('>');styles();xmode='html';advance('</');if(!nexttoken.identifier&&nexttoken.value!=='style'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'style',nexttoken.value);} |
305 plusplus : true, // if increment/decrement should not be allowed |
306 advance();xmode='outer';break;case'input':switch(a.type){case'radio':case'checkbox':case'text':case'button':case'file':case'reset':case'submit':case'password':case'file':case'hidden':case'image':break;default:warning("Bad input type.");} |
306 regexp : true, // if the . should not be allowed in regexp literals |
307 if(option.adsafe&&a.autocomplete!=='off'){warning("ADsafe autocomplete violation.");} |
307 rhino : true, // if the Rhino environment globals should be predefined |
308 break;case'applet':case'body':case'embed':case'frame':case'frameset':case'head':case'iframe':case'img':case'noembed':case'noframes':case'object':case'param':if(option.adsafe){warning("ADsafe violation: Disallowed tag: "+n);} |
308 undef : true, // if variables should be declared before used |
309 break;}} |
309 safe : true, // if use of some browser features should be restricted |
310 function closetag(n){return'</'+n+'>';} |
310 sidebar : true, // if the System object should be predefined |
311 function html(){var a,attributes,e,n,q,t,v,w=option.white,wmode;xmode='html';xquote='';stack=null;for(;;){switch(nexttoken.value){case'<':xmode='html';advance('<');attributes={};t=nexttoken;if(!t.identifier){warning("Bad identifier {a}.",t,t.value);} |
311 strict : true, // require the "use strict"; pragma |
312 n=t.value;if(option.cap){n=n.toLowerCase();} |
312 sub : true, // if all forms of subscript notation are tolerated |
313 t.name=n;advance();if(!stack){stack=[];doBegin(n);} |
313 white : true, // if strict whitespace rules apply |
314 v=htmltag[n];if(typeof v!=='object'){error("Unrecognized tag '<{a}>'.",t,n);} |
314 widget : true // if the Yahoo Widgets globals should be predefined |
315 e=v.empty;t.type=n;for(;;){if(nexttoken.id==='/'){advance('/');if(nexttoken.id!=='>'){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'>',nexttoken.value);} |
315 }, |
316 break;} |
316 |
317 if(nexttoken.id&&nexttoken.id.substr(0,1)==='>'){break;} |
317 // browser contains a set of global names which are commonly provided by a |
318 if(!nexttoken.identifier){if(nexttoken.id==='(end)'||nexttoken.id==='(error)'){error("Missing '>'.",nexttoken);} |
318 // web browser environment. |
319 warning("Bad identifier.");} |
319 |
320 option.white=true;nonadjacent(token,nexttoken);a=nexttoken.value;option.white=w;advance();if(!option.cap&&a!==a.toLowerCase()){warning("Attribute '{a}' not all lower case.",nexttoken,a);} |
320 browser = { |
321 a=a.toLowerCase();xquote='';if(attributes.hasOwnProperty(a)){warning("Attribute '{a}' repeated.",nexttoken,a);} |
321 addEventListener: false, |
322 if(a.slice(0,2)==='on'){if(!option.on){warning("Avoid HTML event handlers.");} |
322 alert : false, |
323 xmode='scriptstring';advance('=');q=nexttoken.id;if(q!=='"'&&q!=="'"){error("Missing quote.");} |
323 blur : false, |
324 xquote=q;wmode=option.white;option.white=false;advance(q);statements('on');option.white=wmode;if(nexttoken.id!==q){error("Missing close quote on script attribute.");} |
324 clearInterval : false, |
325 xmode='html';xquote='';advance(q);v=false;}else if(a==='style'){xmode='scriptstring';advance('=');q=nexttoken.id;if(q!=='"'&&q!=="'"){error("Missing quote.");} |
325 clearTimeout : false, |
326 xmode='styleproperty';xquote=q;advance(q);substyle();xmode='html';xquote='';advance(q);v=false;}else{if(nexttoken.id==='='){advance('=');v=nexttoken.value;if(!nexttoken.identifier&&nexttoken.id!=='"'&&nexttoken.id!=='\''&&nexttoken.type!=='(string)'&&nexttoken.type!=='(number)'&&nexttoken.type!=='(color)'){warning("Expected an attribute value and instead saw '{a}'.",token,a);} |
326 close : false, |
327 advance();}else{v=true;}} |
327 closed : false, |
328 attributes[a]=v;doAttribute(n,a,v);} |
328 confirm : false, |
329 doTag(n,attributes);if(!e){stack.push(t);} |
329 console : false, |
330 xmode='outer';advance('>');break;case'</':xmode='html';advance('</');if(!nexttoken.identifier){warning("Bad identifier.");} |
330 Debug : false, |
331 n=nexttoken.value;if(option.cap){n=n.toLowerCase();} |
331 defaultStatus : false, |
332 advance();if(!stack){error("Unexpected '{a}'.",nexttoken,closetag(n));} |
332 document : false, |
333 t=stack.pop();if(!t){error("Unexpected '{a}'.",nexttoken,closetag(n));} |
333 event : false, |
334 if(t.name!==n){error("Expected '{a}' and instead saw '{b}'.",nexttoken,closetag(t.name),closetag(n));} |
334 focus : false, |
335 if(nexttoken.id!=='>'){error("Missing '{a}'.",nexttoken,'>');} |
335 frames : false, |
336 xmode='outer';advance('>');break;case'<!':if(option.safe){warning("ADsafe HTML violation.");} |
336 getComputedStyle: false, |
337 xmode='html';for(;;){advance();if(nexttoken.id==='>'||nexttoken.id==='(end)'){break;} |
337 history : false, |
338 if(nexttoken.id==='--'){warning("Unexpected --.");}} |
338 Image : false, |
339 xmode='outer';advance('>');break;case'<!--':xmode='html';if(option.safe){warning("ADsafe HTML violation.");} |
339 length : false, |
340 for(;;){advance();if(nexttoken.id==='(end)'){error("Missing '-->'.");} |
340 location : false, |
341 if(nexttoken.id==='<!'||nexttoken.id==='<!--'){error("Unexpected '<!' in HTML comment.");} |
341 moveBy : false, |
342 if(nexttoken.id==='--'){advance('--');break;}} |
342 moveTo : false, |
343 abut();xmode='outer';advance('>');break;case'(end)':return;default:if(nexttoken.id==='(end)'){error("Missing '{a}'.",nexttoken,'</'+stack[stack.length-1].value+'>');}else{advance();}} |
343 name : false, |
344 if(stack&&stack.length===0&&(option.adsafe||!option.fragment||nexttoken.id==='(end)')){break;}} |
344 navigator : false, |
345 if(nexttoken.id!=='(end)'){error("Unexpected material after the end.");}} |
345 onbeforeunload : true, |
346 type('(number)',idValue);type('(string)',idValue);syntax['(identifier)']={type:'(identifier)',lbp:0,identifier:true,nud:function(){var v=this.value,s=scope[v];if(typeof s==='function'){s=false;} |
346 onblur : true, |
347 if(s&&(s===funct||s===funct['(global)'])){if(!funct['(global)']){switch(funct[v]){case'unused':funct[v]='var';break;case'label':warning("'{a}' is a statement label.",token,v);break;}}}else if(funct['(global)']){if(option.undef){warning("'{a}' is not defined.",token,v);} |
347 onerror : true, |
348 note_implied(token);}else{switch(funct[v]){case'closure':case'function':case'var':case'unused':warning("'{a}' used out of scope.",token,v);break;case'label':warning("'{a}' is a statement label.",token,v);break;case'outer':case true:break;default:if(s===true){funct[v]=true;}else if(typeof s!=='object'){if(option.undef){warning("'{a}' is not defined.",token,v);}else{funct[v]=true;} |
348 onfocus : true, |
349 note_implied(token);}else{switch(s[v]){case'function':case'var':case'unused':s[v]='closure';funct[v]='outer';break;case'closure':case'parameter':funct[v]='outer';break;case'label':warning("'{a}' is a statement label.",token,v);}}}} |
349 onload : true, |
350 return this;},led:function(){error("Expected an operator and instead saw '{a}'.",nexttoken,nexttoken.value);}};type('(regexp)',function(){return this;});delim('(endline)');delim('(begin)');delim('(end)').reach=true;delim('</').reach=true;delim('<!');delim('<!--');delim('-->');delim('(error)').reach=true;delim('}').reach=true;delim(')');delim(']');delim('"').reach=true;delim("'").reach=true;delim(';');delim(':').reach=true;delim(',');delim('#');delim('@');reserve('else');reserve('case').reach=true;reserve('catch');reserve('default').reach=true;reserve('finally');reservevar('arguments');reservevar('eval');reservevar('false');reservevar('Infinity');reservevar('NaN');reservevar('null');reservevar('this');reservevar('true');reservevar('undefined');assignop('=','assign',20);assignop('+=','assignadd',20);assignop('-=','assignsub',20);assignop('*=','assignmult',20);assignop('/=','assigndiv',20).nud=function(){error("A regular expression literal can be confused with '/='.");};assignop('%=','assignmod',20);bitwiseassignop('&=','assignbitand',20);bitwiseassignop('|=','assignbitor',20);bitwiseassignop('^=','assignbitxor',20);bitwiseassignop('<<=','assignshiftleft',20);bitwiseassignop('>>=','assignshiftright',20);bitwiseassignop('>>>=','assignshiftrightunsigned',20);infix('?',function(left,that){that.left=left;that.right=parse(10);advance(':');that['else']=parse(10);return that;},30);infix('||','or',40);infix('&&','and',50);bitwise('|','bitor',70);bitwise('^','bitxor',80);bitwise('&','bitand',90);relation('==',function(left,right){if(option.eqeqeq){warning("Expected '{a}' and instead saw '{b}'.",this,'===','==');}else if(isPoorRelation(left)){warning("Use '{a}' to compare with '{b}'.",this,'===',left.value);}else if(isPoorRelation(right)){warning("Use '{a}' to compare with '{b}'.",this,'===',right.value);} |
350 onresize : true, |
351 return this;});relation('===');relation('!=',function(left,right){if(option.eqeqeq){warning("Expected '{a}' and instead saw '{b}'.",this,'!==','!=');}else if(isPoorRelation(left)){warning("Use '{a}' to compare with '{b}'.",this,'!==',left.value);}else if(isPoorRelation(right)){warning("Use '{a}' to compare with '{b}'.",this,'!==',right.value);} |
351 onunload : true, |
352 return this;});relation('!==');relation('<');relation('>');relation('<=');relation('>=');bitwise('<<','shiftleft',120);bitwise('>>','shiftright',120);bitwise('>>>','shiftrightunsigned',120);infix('in','in',120);infix('instanceof','instanceof',120);infix('+',function(left,that){var right=parse(130);if(left&&right&&left.id==='(string)'&&right.id==='(string)'){left.value+=right.value;left.character=right.character;if(jx.test(left.value)){warning("JavaScript URL.",left);} |
352 open : false, |
353 return left;} |
353 opener : false, |
354 that.left=left;that.right=right;return that;},130);prefix('+','num');infix('-','sub',130);prefix('-','neg');infix('*','mult',140);infix('/','div',140);infix('%','mod',140);suffix('++','postinc');prefix('++','preinc');syntax['++'].exps=true;suffix('--','postdec');prefix('--','predec');syntax['--'].exps=true;prefix('delete',function(){var p=parse(0);if(!p||(p.id!=='.'&&p.id!=='[')){warning("Expected '{a}' and instead saw '{b}'.",nexttoken,'.',nexttoken.value);}}).exps=true;prefix('~',function(){if(option.bitwise){warning("Unexpected '{a}'.",this,'~');} |
354 opera : false, |
355 parse(150);return this;});prefix('!','not');prefix('typeof','typeof');prefix('new',function(){var c=parse(155),i;if(c&&c.id!=='function'){if(c.identifier){c['new']=true;switch(c.value){case'Object':warning("Use the object literal notation {}.",token);break;case'Array':if(nexttoken.id!=='('){warning("Use the array literal notation [].",token);}else{advance('(');if(nexttoken.id===')'){warning("Use the array literal notation [].",token);}else{i=parse(0);c.dimension=i;if((i.id==='(number)'&&/[.+\-Ee]/.test(i.value))||(i.id==='-'&&!i.right)||i.id==='(string)'||i.id==='['||i.id==='{'||i.id==='true'||i.id==='false'||i.id==='null'||i.id==='undefined'||i.id==='Infinity'){warning("Use the array literal notation [].",token);} |
355 Option : false, |
356 if(nexttoken.id!==')'){error("Use the array literal notation [].",token);}} |
356 parent : false, |
357 advance(')');} |
357 print : false, |
358 this.first=c;return this;case'Number':case'String':case'Boolean':case'Math':warning("Do not use {a} as a constructor.",token,c.value);break;case'Function':if(!option.evil){warning("The Function constructor is eval.");} |
358 prompt : false, |
359 break;case'Date':case'RegExp':break;default:if(c.id!=='function'){i=c.value.substr(0,1);if(option.newcap&&(i<'A'||i>'Z')){warning("A constructor name should start with an uppercase letter.",token);}}}}else{if(c.id!=='.'&&c.id!=='['&&c.id!=='('){warning("Bad constructor.",token);}}}else{warning("Weird construction. Delete 'new'.",this);} |
359 removeEventListener: false, |
360 adjacent(token,nexttoken);if(nexttoken.id!=='('){warning("Missing '()' invoking a constructor.");} |
360 resizeBy : false, |
361 this.first=c;return this;});syntax['new'].exps=true;infix('.',function(left,that){adjacent(prevtoken,token);var m=identifier();if(typeof m==='string'){countMember(m);} |
361 resizeTo : false, |
362 that.left=left;that.right=m;if(!option.evil&&left&&left.value==='document'&&(m==='write'||m==='writeln')){warning("document.write can be a form of eval.",left);}else if(option.adsafe){if(left&&left.value==='ADSAFE'){if(m==='id'||m==='lib'){warning("ADsafe violation.",that);}else if(m==='go'){if(xmode!=='script'){warning("ADsafe violation.",that);}else if(adsafe_went||nexttoken.id!=='('||peek(0).id!=='(string)'||peek(0).value!==adsafe_id||peek(1).id!==','){error("ADsafe violation: go.",that);} |
362 screen : false, |
363 adsafe_went=true;adsafe_may=false;}}}else if(!option.evil&&(m==='eval'||m==='execScript')){warning('eval is evil.');}else if(option.safe){for(;;){if(banned[m]===true){warning("ADsafe restricted word '{a}'.",token,m);} |
363 scroll : false, |
364 if(predefined[left.value]!==true||nexttoken.id==='('){break;} |
364 scrollBy : false, |
365 if(standard_member[m]===true){if(nexttoken.id==='.'){warning("ADsafe violation.",that);} |
365 scrollTo : false, |
366 break;} |
366 setInterval : false, |
367 if(nexttoken.id!=='.'){warning("ADsafe violation.",that);break;} |
367 setTimeout : false, |
368 advance('.');token.left=that;token.right=m;that=token;m=identifier();if(typeof m==='string'){countMember(m);}}} |
368 status : false, |
369 return that;},160,true);infix('(',function(left,that){adjacent(prevtoken,token);nospace();var n=0,p=[];if(left){if(left.type==='(identifier)'){if(left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)){if(left.value!=='Number'&&left.value!=='String'&&left.value!=='Boolean'&&left.value!=='Date'){if(left.value==='Math'){warning("Math is not a function.",left);}else if(option.newcap){warning("Missing 'new' prefix when invoking a constructor.",left);}}}}else if(left.id==='.'){if(option.safe&&left.left.value==='Math'&&left.right==='random'){warning("ADsafe violation.",left);}}} |
369 top : false, |
370 if(nexttoken.id!==')'){for(;;){p[p.length]=parse(10);n+=1;if(nexttoken.id!==','){break;} |
370 XMLHttpRequest : false |
371 comma();}} |
371 }, |
372 advance(')');if(option.immed&&left.id==='function'&&nexttoken.id!==')'){warning("Wrap the entire immediate function invocation in parens.",that);} |
372 |
373 nospace(prevtoken,token);if(typeof left==='object'){if(left.value==='parseInt'&&n===1){warning("Missing radix parameter.",left);} |
373 cssAttributeData, |
374 if(!option.evil){if(left.value==='eval'||left.value==='Function'||left.value==='execScript'){warning("eval is evil.",left);}else if(p[0]&&p[0].id==='(string)'&&(left.value==='setTimeout'||left.value==='setInterval')){warning("Implied eval is evil. Pass a function instead of a string.",left);}} |
374 cssAny, |
375 if(!left.identifier&&left.id!=='.'&&left.id!=='['&&left.id!=='('&&left.id!=='&&'&&left.id!=='||'&&left.id!=='?'){warning("Bad invocation.",left);}} |
375 |
376 that.left=left;return that;},155,true).exps=true;prefix('(',function(){nospace();var v=parse(0);advance(')',this);nospace(prevtoken,token);if(option.immed&&v.id==='function'){if(nexttoken.id==='('){warning("Move the invocation into the parens that contain the function.",nexttoken);}else{warning("Do not wrap function literals in parens unless they are to be immediately invoked.",this);}} |
376 cssColorData = { |
377 return v;});infix('[',function(left,that){nospace();var e=parse(0),s;if(e&&e.type==='(string)'){if(option.safe&&banned[e.value]===true){warning("ADsafe restricted word '{a}'.",that,e.value);}else if(!option.evil&&(e.value==='eval'||e.value==='execScript')){warning("eval is evil.",that);} |
377 "aliceblue" : true, |
378 countMember(e.value);if(!option.sub&&ix.test(e.value)){s=syntax[e.value];if(!s||!s.reserved){warning("['{a}'] is better written in dot notation.",e,e.value);}}}else if(!e||(e.type!=='(number)'&&(e.id!=='+'||e.arity!=='unary'))){if(option.safe){warning('ADsafe subscripting.');}} |
378 "antiquewhite" : true, |
379 advance(']',that);nospace(prevtoken,token);that.left=left;that.right=e;return that;},160,true);prefix('[',function(){this.first=[];if(nexttoken.id===']'){advance(']');return this;} |
379 "aqua" : true, |
380 var b=token.line!==nexttoken.line;if(b){indent+=option.indent;if(nexttoken.from===indent+option.indent){indent+=option.indent;}} |
380 "aquamarine" : true, |
381 for(;;){if(b&&token.line!==nexttoken.line){indentation();} |
381 "azure" : true, |
382 parse(10);if(nexttoken.id===','){comma();if(nexttoken.id===','){warning("Extra comma.",token);}else if(nexttoken.id===']'){warning("Extra comma.",token);break;}}else{if(b){indent-=option.indent;indentation();} |
382 "beige" : true, |
383 break;}} |
383 "bisque" : true, |
384 advance(']',this);return this;},160);(function(x){x.nud=function(){var b,i,s,seen={};b=token.line!==nexttoken.line;if(b){indent+=option.indent;if(nexttoken.from===indent+option.indent){indent+=option.indent;}} |
384 "black" : true, |
385 for(;;){if(nexttoken.id==='}'){break;} |
385 "blanchedalmond" : true, |
386 if(b){indentation();} |
386 "blue" : true, |
387 i=optionalidentifier(true);if(!i){if(nexttoken.id==='(string)'){i=nexttoken.value;if(ix.test(i)){s=syntax[i];} |
387 "blueviolet" : true, |
388 advance();}else if(nexttoken.id==='(number)'){i=nexttoken.value.toString();advance();}else{error("Expected '{a}' and instead saw '{b}'.",nexttoken,'}',nexttoken.value);}} |
388 "brown" : true, |
389 if(seen[i]===true){warning("Duplicate member '{a}'.",nexttoken,i);} |
389 "burlywood" : true, |
390 seen[i]=true;countMember(i);advance(':');nonadjacent(token,nexttoken);parse(10);if(nexttoken.id===','){comma();if(nexttoken.id===','||nexttoken.id==='}'){warning("Extra comma.",token);}}else{break;}} |
390 "cadetblue" : true, |
391 if(b){indent-=option.indent;indentation();} |
391 "chartreuse" : true, |
392 advance('}',this);return this;};x.fud=function(){error("Expected to see a statement and instead saw a block.",token);};}(delim('{')));function varstatement(prefix){var name,value;if(funct['(onevar)']&&option.onevar){warning("Too many var statements.");}else if(!funct['(global)']){funct['(onevar)']=true;} |
392 "chocolate" : true, |
393 this.first=[];for(;;){nonadjacent(token,nexttoken);addlabel(identifier(),'unused');if(prefix){break;} |
393 "coral" : true, |
394 name=token;this.first.push(token);if(nexttoken.id==='='){nonadjacent(token,nexttoken);advance('=');nonadjacent(token,nexttoken);if(peek(0).id==='='&&nexttoken.identifier){error("Variable {a} was not declared correctly.",nexttoken,nexttoken.value);} |
394 "cornflowerblue" : true, |
395 value=parse(0);name.first=value;} |
395 "cornsilk" : true, |
396 if(nexttoken.id!==','){break;} |
396 "crimson" : true, |
397 comma();} |
397 "cyan" : true, |
398 return this;} |
398 "darkblue" : true, |
399 stmt('var',varstatement);stmt('new',function(){warning("'new' should not be used as a statement.");});function functionparams(){var i,t=nexttoken,p=[];advance('(');nospace();if(nexttoken.id===')'){advance(')');nospace(prevtoken,token);return;} |
399 "darkcyan" : true, |
400 for(;;){i=identifier();p.push(i);addlabel(i,'parameter');if(nexttoken.id===','){comma();}else{advance(')',t);nospace(prevtoken,token);return p.join(', ');}}} |
400 "darkgoldenrod" : true, |
401 function doFunction(i){var s=scope;scope=Object.create(s);funct={'(name)':i||'"'+anonname+'"','(line)':nexttoken.line+1,'(context)':funct,'(breakage)':0,'(loopage)':0,'(scope)':scope};token.funct=funct;functions.push(funct);if(i){addlabel(i,'function');} |
401 "darkgray" : true, |
402 funct['(params)']=functionparams();block(false);scope=s;funct=funct['(context)'];} |
402 "darkgreen" : true, |
403 blockstmt('function',function(){if(inblock){warning("Function statements cannot be placed in blocks. Use a function expression or move the statement to the top of the outer function.",token);} |
403 "darkkhaki" : true, |
404 var i=identifier();adjacent(token,nexttoken);addlabel(i,'unused');doFunction(i);if(nexttoken.id==='('&&nexttoken.line===token.line){error("Function statements are not invocable. Wrap the whole function invocation in parens.");}});prefix('function',function(){var i=optionalidentifier();if(i){adjacent(token,nexttoken);}else{nonadjacent(token,nexttoken);} |
404 "darkmagenta" : true, |
405 doFunction(i);if(funct['(loopage)']&&nexttoken.id!=='('){warning("Be careful when making functions within a loop. Consider putting the function in a closure.");} |
405 "darkolivegreen" : true, |
406 return this;});blockstmt('if',function(){var t=nexttoken;advance('(');nonadjacent(this,t);nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);} |
406 "darkorange" : true, |
407 advance(')',t);nospace(prevtoken,token);block(true);if(nexttoken.id==='else'){nonadjacent(token,nexttoken);advance('else');if(nexttoken.id==='if'||nexttoken.id==='switch'){statement(true);}else{block(true);}} |
407 "darkorchid" : true, |
408 return this;});blockstmt('try',function(){var b,e,s;if(option.adsafe){warning("ADsafe try violation.",this);} |
408 "darkred" : true, |
409 block(false);if(nexttoken.id==='catch'){advance('catch');nonadjacent(token,nexttoken);advance('(');s=scope;scope=Object.create(s);e=nexttoken.value;if(nexttoken.type!=='(identifier)'){warning("Expected an identifier and instead saw '{a}'.",nexttoken,e);}else{addlabel(e,'exception');} |
409 "darksalmon" : true, |
410 advance();advance(')');block(false);b=true;scope=s;} |
410 "darkseagreen" : true, |
411 if(nexttoken.id==='finally'){advance('finally');block(false);return;}else if(!b){error("Expected '{a}' and instead saw '{b}'.",nexttoken,'catch',nexttoken.value);}});blockstmt('while',function(){var t=nexttoken;funct['(breakage)']+=1;funct['(loopage)']+=1;advance('(');nonadjacent(this,t);nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);} |
411 "darkslateblue" : true, |
412 advance(')',t);nospace(prevtoken,token);block(true);funct['(breakage)']-=1;funct['(loopage)']-=1;}).labelled=true;reserve('with');blockstmt('switch',function(){var t=nexttoken,g=false;funct['(breakage)']+=1;advance('(');nonadjacent(this,t);nospace();this.condition=parse(20);advance(')',t);nospace(prevtoken,token);nonadjacent(token,nexttoken);t=nexttoken;advance('{');nonadjacent(token,nexttoken);indent+=option.indent;this.cases=[];for(;;){switch(nexttoken.id){case'case':switch(funct['(verb)']){case'break':case'case':case'continue':case'return':case'switch':case'throw':break;default:warning("Expected a 'break' statement before 'case'.",token);} |
412 "darkslategray" : true, |
413 indentation(-option.indent);advance('case');this.cases.push(parse(20));g=true;advance(':');funct['(verb)']='case';break;case'default':switch(funct['(verb)']){case'break':case'continue':case'return':case'throw':break;default:warning("Expected a 'break' statement before 'default'.",token);} |
413 "darkturquoise" : true, |
414 indentation(-option.indent);advance('default');g=true;advance(':');break;case'}':indent-=option.indent;indentation();advance('}',t);if(this.cases.length===1||this.condition.id==='true'||this.condition.id==='false'){warning("This 'switch' should be an 'if'.",this);} |
414 "darkviolet" : true, |
415 funct['(breakage)']-=1;funct['(verb)']=undefined;return;case'(end)':error("Missing '{a}'.",nexttoken,'}');return;default:if(g){switch(token.id){case',':error("Each value should have its own case label.");return;case':':statements();break;default:error("Missing ':' on a case clause.",token);}}else{error("Expected '{a}' and instead saw '{b}'.",nexttoken,'case',nexttoken.value);}}}}).labelled=true;stmt('debugger',function(){if(!option.debug){warning("All 'debugger' statements should be removed.");}});stmt('do',function(){funct['(breakage)']+=1;funct['(loopage)']+=1;block(true);advance('while');var t=nexttoken;nonadjacent(token,t);advance('(');nospace();parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);} |
415 "deeppink" : true, |
416 advance(')',t);nospace(prevtoken,token);funct['(breakage)']-=1;funct['(loopage)']-=1;}).labelled=true;blockstmt('for',function(){var s,t=nexttoken;funct['(breakage)']+=1;funct['(loopage)']+=1;advance('(');nonadjacent(this,t);nospace();if(peek(nexttoken.id==='var'?1:0).id==='in'){if(nexttoken.id==='var'){advance('var');varstatement(true);}else{switch(funct[nexttoken.value]){case'unused':funct[nexttoken.value]='var';break;case'var':break;default:warning("Bad for in variable '{a}'.",nexttoken,nexttoken.value);} |
416 "deepskyblue" : true, |
417 advance();} |
417 "dimgray" : true, |
418 advance('in');parse(20);advance(')',t);s=block(true);if(!option.forin&&(s.length>1||typeof s[0]!=='object'||s[0].value!=='if')){warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.",this);} |
418 "dodgerblue" : true, |
419 funct['(breakage)']-=1;funct['(loopage)']-=1;return this;}else{if(nexttoken.id!==';'){if(nexttoken.id==='var'){advance('var');varstatement();}else{for(;;){parse(0,'for');if(nexttoken.id!==','){break;} |
419 "firebrick" : true, |
420 comma();}}} |
420 "floralwhite" : true, |
421 nolinebreak(token);advance(';');if(nexttoken.id!==';'){parse(20);if(nexttoken.id==='='){warning("Expected a conditional expression and instead saw an assignment.");advance('=');parse(20);}} |
421 "forestgreen" : true, |
422 nolinebreak(token);advance(';');if(nexttoken.id===';'){error("Expected '{a}' and instead saw '{b}'.",nexttoken,')',';');} |
422 "fuchsia" : true, |
423 if(nexttoken.id!==')'){for(;;){parse(0,'for');if(nexttoken.id!==','){break;} |
423 "gainsboro" : true, |
424 comma();}} |
424 "ghostwhite" : true, |
425 advance(')',t);nospace(prevtoken,token);block(true);funct['(breakage)']-=1;funct['(loopage)']-=1;}}).labelled=true;stmt('break',function(){var v=nexttoken.value;if(funct['(breakage)']===0){warning("Unexpected '{a}'.",nexttoken,this.value);} |
425 "gold" : true, |
426 nolinebreak(this);if(nexttoken.id!==';'){if(token.line===nexttoken.line){if(funct[v]!=='label'){warning("'{a}' is not a statement label.",nexttoken,v);}else if(scope[v]!==funct){warning("'{a}' is out of scope.",nexttoken,v);} |
426 "goldenrod" : true, |
427 advance();}} |
427 "gray" : true, |
428 reachable('break');});stmt('continue',function(){var v=nexttoken.value;if(funct['(breakage)']===0){warning("Unexpected '{a}'.",nexttoken,this.value);} |
428 "green" : true, |
429 nolinebreak(this);if(nexttoken.id!==';'){if(token.line===nexttoken.line){if(funct[v]!=='label'){warning("'{a}' is not a statement label.",nexttoken,v);}else if(scope[v]!==funct){warning("'{a}' is out of scope.",nexttoken,v);} |
429 "greenyellow" : true, |
430 advance();}} |
430 "honeydew" : true, |
431 reachable('continue');});stmt('return',function(){nolinebreak(this);if(nexttoken.id==='(regexp)'){warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");} |
431 "hotpink" : true, |
432 if(nexttoken.id!==';'&&!nexttoken.reach){nonadjacent(token,nexttoken);parse(20);} |
432 "indianred" : true, |
433 reachable('return');});stmt('throw',function(){nolinebreak(this);nonadjacent(token,nexttoken);parse(20);reachable('throw');});reserve('void');reserve('class');reserve('const');reserve('enum');reserve('export');reserve('extends');reserve('import');reserve('super');reserve('let');reserve('yield');reserve('implements');reserve('interface');reserve('package');reserve('private');reserve('protected');reserve('public');reserve('static');function jsonValue(){function jsonObject(){var o={},t=nexttoken;advance('{');if(nexttoken.id!=='}'){for(;;){if(nexttoken.id==='(end)'){error("Missing '}' to match '{' from line {a}.",nexttoken,t.line+1);}else if(nexttoken.id==='}'){warning("Unexpected comma.",token);break;}else if(nexttoken.id===','){error("Unexpected comma.",nexttoken);}else if(nexttoken.id!=='(string)'){warning("Expected a string and instead saw {a}.",nexttoken,nexttoken.value);} |
433 "indigo" : true, |
434 if(o[nexttoken.value]===true){warning("Duplicate key '{a}'.",nexttoken,nexttoken.value);}else if(nexttoken.value==='__proto__'){warning("Stupid key '{a}'.",nexttoken,nexttoken.value);}else{o[nexttoken.value]=true;} |
434 "ivory" : true, |
435 advance();advance(':');jsonValue();if(nexttoken.id!==','){break;} |
435 "khaki" : true, |
436 advance(',');}} |
436 "lavender" : true, |
437 advance('}');} |
437 "lavenderblush" : true, |
438 function jsonArray(){var t=nexttoken;advance('[');if(nexttoken.id!==']'){for(;;){if(nexttoken.id==='(end)'){error("Missing ']' to match '[' from line {a}.",nexttoken,t.line+1);}else if(nexttoken.id===']'){warning("Unexpected comma.",token);break;}else if(nexttoken.id===','){error("Unexpected comma.",nexttoken);} |
438 "lawngreen" : true, |
439 jsonValue();if(nexttoken.id!==','){break;} |
439 "lemonchiffon" : true, |
440 advance(',');}} |
440 "lightblue" : true, |
441 advance(']');} |
441 "lightcoral" : true, |
442 switch(nexttoken.id){case'{':jsonObject();break;case'[':jsonArray();break;case'true':case'false':case'null':case'(number)':case'(string)':advance();break;case'-':advance('-');if(token.character!==nexttoken.from){warning("Unexpected space after '-'.",token);} |
442 "lightcyan" : true, |
443 adjacent(token,nexttoken);advance('(number)');break;default:error("Expected a JSON value.",nexttoken);}} |
443 "lightgoldenrodyellow" : true, |
444 var itself=function(s,o){var a,i;JSLINT.errors=[];predefined=Object.create(standard);if(o){a=o.predef;if(a instanceof Array){for(i=0;i<a.length;i+=1){predefined[a[i]]=true;}} |
444 "lightgreen" : true, |
445 if(o.adsafe){o.safe=true;} |
445 "lightpink" : true, |
446 if(o.safe){o.browser=false;o.css=false;o.debug=false;o.eqeqeq=true;o.evil=false;o.forin=false;o.nomen=true;o.on=false;o.rhino=false;o.safe=true;o.sidebar=false;o.strict=true;o.sub=false;o.undef=true;o.widget=false;predefined.Date=false;predefined['eval']=false;predefined.Function=false;predefined.Object=false;predefined.ADSAFE=true;predefined.lib=true;} |
446 "lightsalmon" : true, |
447 option=o;}else{option={};} |
447 "lightseagreen" : true, |
448 option.indent=option.indent||4;adsafe_id='';adsafe_may=false;adsafe_went=false;approved={};if(option.approved){for(i=0;i<option.approved.length;i+=1){approved[option.approved[i]]=option.approved[i];}}else{approved.test='test';} |
448 "lightskyblue" : true, |
449 tab='';for(i=0;i<option.indent;i+=1){tab+=' ';} |
449 "lightslategray" : true, |
450 indent=0;global=Object.create(predefined);scope=global;funct={'(global)':true,'(name)':'(global)','(scope)':scope,'(breakage)':0,'(loopage)':0};functions=[];ids={};urls=[];src=false;xmode=false;stack=null;member={};membersOnly=null;implied={};inblock=false;lookahead=[];jsonmode=false;warnings=0;lex.init(s);prereg=true;prevtoken=token=nexttoken=syntax['(begin)'];assume();try{advance();if(nexttoken.value.charAt(0)==='<'){html();if(option.adsafe&&!adsafe_went){warning("ADsafe violation: Missing ADSAFE.go.",this);}}else{switch(nexttoken.id){case'{':case'[':option.laxbreak=true;jsonmode=true;jsonValue();break;case'@':case'*':case'#':case'.':case':':xmode='style';advance();if(token.id!=='@'||!nexttoken.identifier||nexttoken.value!=='charset'){error('A css file should begin with @charset "UTF-8";');} |
450 "lightsteelblue" : true, |
451 advance();if(nexttoken.type!=='(string)'&&nexttoken.value!=='UTF-8'){error('A css file should begin with @charset "UTF-8";');} |
451 "lightyellow" : true, |
452 advance();advance(';');styles();break;default:if(option.adsafe&&option.fragment){error("Expected '{a}' and instead saw '{b}'.",nexttoken,'<div>',nexttoken.value);} |
452 "lime" : true, |
453 statements('lib');}} |
453 "limegreen" : true, |
454 advance('(end)');}catch(e){if(e){JSLINT.errors.push({reason:e.message,line:e.line||nexttoken.line,character:e.character||nexttoken.from},null);}} |
454 "linen" : true, |
455 return JSLINT.errors.length===0;};function to_array(o){var a=[],k;for(k in o){if(o.hasOwnProperty(k)){a.push(k);}} |
455 "magenta" : true, |
456 return a;} |
456 "maroon" : true, |
457 itself.report=function(option,sep){var a=[],c,e,f,i,k,l,m='',n,o=[],s,v,cl,ex,va,un,ou,gl,la;function detail(h,s,sep){if(s.length){o.push('<div><i>'+h+'</i> '+ |
457 "mediumaquamarine" : true, |
458 s.sort().join(sep||', ')+'</div>');}} |
458 "mediumblue" : true, |
459 s=to_array(implied);k=JSLINT.errors.length;if(k||s.length>0){o.push('<div id=errors><i>Error:</i>');if(s.length>0){s.sort();for(i=0;i<s.length;i+=1){s[i]='<code>'+s[i]+'</code> <i>'+ |
459 "mediumorchid" : true, |
460 implied[s[i]].join(' ')+'</i>';} |
460 "mediumpurple" : true, |
461 o.push('<p><i>Implied global:</i> '+s.join(', ')+'</p>');c=true;} |
461 "mediumseagreen" : true, |
462 for(i=0;i<k;i+=1){c=JSLINT.errors[i];if(c){e=c.evidence||'';o.push('<p>Problem'+(isFinite(c.line)?' at line '+(c.line+1)+' character '+(c.character+1):'')+': '+c.reason.entityify()+'</p><p class=evidence>'+ |
462 "mediumslateblue" : true, |
463 (e&&(e.length>80?e.slice(0,77)+'...':e).entityify())+'</p>');}} |
463 "mediumspringgreen" : true, |
464 o.push('</div>');if(!c){return o.join('');}} |
464 "mediumturquoise" : true, |
465 if(!option){o.push('<br><div id=functions>');if(urls.length>0){detail("URLs<br>",urls,'<br>');} |
465 "mediumvioletred" : true, |
466 s=to_array(scope);if(s.length===0){if(jsonmode){if(k===0){o.push('<p>JSON: good.</p>');}else{o.push('<p>JSON: bad.</p>');}}else{o.push('<div><i>No new global variables introduced.</i></div>');}}else{o.push('<div><i>Global</i> '+s.sort().join(', ')+'</div>');} |
466 "midnightblue" : true, |
467 for(i=0;i<functions.length;i+=1){f=functions[i];cl=[];ex=[];va=[];un=[];ou=[];gl=[];la=[];for(k in f){if(f.hasOwnProperty(k)&&k.charAt(0)!=='('){v=f[k];switch(v){case'closure':cl.push(k);break;case'exception':ex.push(k);break;case'var':va.push(k);break;case'unused':un.push(k);break;case'label':la.push(k);break;case'outer':ou.push(k);break;case true:gl.push(k);break;}}} |
467 "mintcream" : true, |
468 o.push('<br><div class=function><i>'+f['(line)']+'</i> '+ |
468 "mistyrose" : true, |
469 (f['(name)']||'')+'('+ |
469 "moccasin" : true, |
470 (f['(params)']||'')+')</div>');detail('Closure',cl);detail('Variable',va);detail('Exception',ex);detail('Outer',ou);detail('Global',gl);detail('<big><b>Unused</b></big>',un);detail('Label',la);} |
470 "navajowhite" : true, |
471 a=[];for(k in member){if(typeof member[k]==='number'){a.push(k);}} |
471 "navy" : true, |
472 if(a.length){a=a.sort();m='<br><pre id=members>/*members ';l=10;for(i=0;i<a.length;i+=1){k=a[i];n=k.name();if(l+n.length>72){o.push(m+'<br>');m=' ';l=1;} |
472 "oldlace" : true, |
473 l+=n.length+2;if(member[k]===1){n='<i>'+n+'</i>';} |
473 "olive" : true, |
474 if(i<a.length-1){n+=', ';} |
474 "olivedrab" : true, |
475 m+=n;} |
475 "orange" : true, |
476 o.push(m+'<br>*/</pre>');} |
476 "orangered" : true, |
477 o.push('</div>');} |
477 "orchid" : true, |
478 return o.join('');};itself.edition='2009-06-02';return itself;}());(function(a){if(!a[0]){print("Usage: jslint.js file.js");quit(1);} |
478 "palegoldenrod" : true, |
479 var input=readFile(a[0]);if(!input){print("jslint: Couldn't open file '"+a[0]+"'.");quit(1);} |
479 "palegreen" : true, |
480 if(!JSLINT(input,{bitwise:false,eqeqeq:true,immed:true,laxbreak:false,newcap:false,nomen:false,onevar:false,plusplus:false,regexp:false,browser:true,undef:true,white:true,indent:2,predef:['window','jQuery','google']})){for(var i=0;i<JSLINT.errors.length;i+=1){var e=JSLINT.errors[i];if(e){print('Lint at line '+(e.line+1)+' character '+ |
480 "paleturquoise" : true, |
481 (e.character+1)+': '+e.reason);print((e.evidence||'').replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"));print('');}} |
481 "palevioletred" : true, |
482 quit(2);}else{print("jslint: No problems found in "+a[0]);quit();}}(arguments)); |
482 "papayawhip" : true, |
|
483 "peachpuff" : true, |
|
484 "peru" : true, |
|
485 "pink" : true, |
|
486 "plum" : true, |
|
487 "powderblue" : true, |
|
488 "purple" : true, |
|
489 "red" : true, |
|
490 "rosybrown" : true, |
|
491 "royalblue" : true, |
|
492 "saddlebrown" : true, |
|
493 "salmon" : true, |
|
494 "sandybrown" : true, |
|
495 "seagreen" : true, |
|
496 "seashell" : true, |
|
497 "sienna" : true, |
|
498 "silver" : true, |
|
499 "skyblue" : true, |
|
500 "slateblue" : true, |
|
501 "slategray" : true, |
|
502 "snow" : true, |
|
503 "springgreen" : true, |
|
504 "steelblue" : true, |
|
505 "tan" : true, |
|
506 "teal" : true, |
|
507 "thistle" : true, |
|
508 "tomato" : true, |
|
509 "turquoise" : true, |
|
510 "violet" : true, |
|
511 "wheat" : true, |
|
512 "white" : true, |
|
513 "whitesmoke" : true, |
|
514 "yellow" : true, |
|
515 "yellowgreen" : true |
|
516 }, |
|
517 |
|
518 cssBorderStyle, |
|
519 cssBreak, |
|
520 |
|
521 cssLengthData = { |
|
522 '%': true, |
|
523 'cm': true, |
|
524 'em': true, |
|
525 'ex': true, |
|
526 'in': true, |
|
527 'mm': true, |
|
528 'pc': true, |
|
529 'pt': true, |
|
530 'px': true |
|
531 }, |
|
532 |
|
533 cssOverflow, |
|
534 |
|
535 escapes = { |
|
536 '\b': '\\b', |
|
537 '\t': '\\t', |
|
538 '\n': '\\n', |
|
539 '\f': '\\f', |
|
540 '\r': '\\r', |
|
541 '"' : '\\"', |
|
542 '/' : '\\/', |
|
543 '\\': '\\\\' |
|
544 }, |
|
545 |
|
546 funct, // The current function |
|
547 |
|
548 functionicity = [ |
|
549 'closure', 'exception', 'global', 'label', |
|
550 'outer', 'unused', 'var' |
|
551 ], |
|
552 |
|
553 functions, // All of the functions |
|
554 |
|
555 global, // The global scope |
|
556 htmltag = { |
|
557 a: {}, |
|
558 abbr: {}, |
|
559 acronym: {}, |
|
560 address: {}, |
|
561 applet: {}, |
|
562 area: {empty: true, parent: ' map '}, |
|
563 b: {}, |
|
564 base: {empty: true, parent: ' head '}, |
|
565 bdo: {}, |
|
566 big: {}, |
|
567 blockquote: {}, |
|
568 body: {parent: ' html noframes '}, |
|
569 br: {empty: true}, |
|
570 button: {}, |
|
571 canvas: {parent: ' body p div th td '}, |
|
572 caption: {parent: ' table '}, |
|
573 center: {}, |
|
574 cite: {}, |
|
575 code: {}, |
|
576 col: {empty: true, parent: ' table colgroup '}, |
|
577 colgroup: {parent: ' table '}, |
|
578 dd: {parent: ' dl '}, |
|
579 del: {}, |
|
580 dfn: {}, |
|
581 dir: {}, |
|
582 div: {}, |
|
583 dl: {}, |
|
584 dt: {parent: ' dl '}, |
|
585 em: {}, |
|
586 embed: {}, |
|
587 fieldset: {}, |
|
588 font: {}, |
|
589 form: {}, |
|
590 frame: {empty: true, parent: ' frameset '}, |
|
591 frameset: {parent: ' html frameset '}, |
|
592 h1: {}, |
|
593 h2: {}, |
|
594 h3: {}, |
|
595 h4: {}, |
|
596 h5: {}, |
|
597 h6: {}, |
|
598 head: {parent: ' html '}, |
|
599 html: {parent: '*'}, |
|
600 hr: {empty: true}, |
|
601 i: {}, |
|
602 iframe: {}, |
|
603 img: {empty: true}, |
|
604 input: {empty: true}, |
|
605 ins: {}, |
|
606 kbd: {}, |
|
607 label: {}, |
|
608 legend: {parent: ' fieldset '}, |
|
609 li: {parent: ' dir menu ol ul '}, |
|
610 link: {empty: true, parent: ' head '}, |
|
611 map: {}, |
|
612 menu: {}, |
|
613 meta: {empty: true, parent: ' head noframes noscript '}, |
|
614 noframes: {parent: ' html body '}, |
|
615 noscript: {parent: ' body head noframes '}, |
|
616 object: {}, |
|
617 ol: {}, |
|
618 optgroup: {parent: ' select '}, |
|
619 option: {parent: ' optgroup select '}, |
|
620 p: {}, |
|
621 param: {empty: true, parent: ' applet object '}, |
|
622 pre: {}, |
|
623 q: {}, |
|
624 samp: {}, |
|
625 script: {empty: true, parent: ' body div frame head iframe p pre span '}, |
|
626 select: {}, |
|
627 small: {}, |
|
628 span: {}, |
|
629 strong: {}, |
|
630 style: {parent: ' head ', empty: true}, |
|
631 sub: {}, |
|
632 sup: {}, |
|
633 table: {}, |
|
634 tbody: {parent: ' table '}, |
|
635 td: {parent: ' tr '}, |
|
636 textarea: {}, |
|
637 tfoot: {parent: ' table '}, |
|
638 th: {parent: ' tr '}, |
|
639 thead: {parent: ' table '}, |
|
640 title: {parent: ' head '}, |
|
641 tr: {parent: ' table tbody thead tfoot '}, |
|
642 tt: {}, |
|
643 u: {}, |
|
644 ul: {}, |
|
645 'var': {} |
|
646 }, |
|
647 |
|
648 ids, // HTML ids |
|
649 implied, // Implied globals |
|
650 inblock, |
|
651 indent, |
|
652 jsonmode, |
|
653 lines, |
|
654 lookahead, |
|
655 member, |
|
656 membersOnly, |
|
657 nexttoken, |
|
658 noreach, |
|
659 option, |
|
660 predefined, // Global variables defined by option |
|
661 prereg, |
|
662 prevtoken, |
|
663 |
|
664 rhino = { |
|
665 defineClass : false, |
|
666 deserialize : false, |
|
667 gc : false, |
|
668 help : false, |
|
669 load : false, |
|
670 loadClass : false, |
|
671 print : false, |
|
672 quit : false, |
|
673 readFile : false, |
|
674 readUrl : false, |
|
675 runCommand : false, |
|
676 seal : false, |
|
677 serialize : false, |
|
678 spawn : false, |
|
679 sync : false, |
|
680 toint32 : false, |
|
681 version : false |
|
682 }, |
|
683 |
|
684 scope, // The current scope |
|
685 |
|
686 sidebar = { |
|
687 System : false |
|
688 }, |
|
689 |
|
690 src, |
|
691 stack, |
|
692 |
|
693 // standard contains the global names that are provided by the |
|
694 // ECMAScript standard. |
|
695 |
|
696 standard = { |
|
697 Array : false, |
|
698 Boolean : false, |
|
699 Date : false, |
|
700 decodeURI : false, |
|
701 decodeURIComponent : false, |
|
702 encodeURI : false, |
|
703 encodeURIComponent : false, |
|
704 Error : false, |
|
705 'eval' : false, |
|
706 EvalError : false, |
|
707 Function : false, |
|
708 hasOwnProperty : false, |
|
709 isFinite : false, |
|
710 isNaN : false, |
|
711 JSON : false, |
|
712 Math : false, |
|
713 Number : false, |
|
714 Object : false, |
|
715 parseInt : false, |
|
716 parseFloat : false, |
|
717 RangeError : false, |
|
718 ReferenceError : false, |
|
719 RegExp : false, |
|
720 String : false, |
|
721 SyntaxError : false, |
|
722 TypeError : false, |
|
723 URIError : false |
|
724 }, |
|
725 |
|
726 standard_member = { |
|
727 E : true, |
|
728 LN2 : true, |
|
729 LN10 : true, |
|
730 LOG2E : true, |
|
731 LOG10E : true, |
|
732 PI : true, |
|
733 SQRT1_2 : true, |
|
734 SQRT2 : true, |
|
735 MAX_VALUE : true, |
|
736 MIN_VALUE : true, |
|
737 NEGATIVE_INFINITY : true, |
|
738 POSITIVE_INFINITY : true |
|
739 }, |
|
740 |
|
741 syntax = {}, |
|
742 tab, |
|
743 token, |
|
744 urls, |
|
745 warnings, |
|
746 |
|
747 // widget contains the global names which are provided to a Yahoo |
|
748 // (fna Konfabulator) widget. |
|
749 |
|
750 widget = { |
|
751 alert : true, |
|
752 animator : true, |
|
753 appleScript : true, |
|
754 beep : true, |
|
755 bytesToUIString : true, |
|
756 Canvas : true, |
|
757 chooseColor : true, |
|
758 chooseFile : true, |
|
759 chooseFolder : true, |
|
760 closeWidget : true, |
|
761 COM : true, |
|
762 convertPathToHFS : true, |
|
763 convertPathToPlatform : true, |
|
764 CustomAnimation : true, |
|
765 escape : true, |
|
766 FadeAnimation : true, |
|
767 filesystem : true, |
|
768 Flash : true, |
|
769 focusWidget : true, |
|
770 form : true, |
|
771 FormField : true, |
|
772 Frame : true, |
|
773 HotKey : true, |
|
774 Image : true, |
|
775 include : true, |
|
776 isApplicationRunning : true, |
|
777 iTunes : true, |
|
778 konfabulatorVersion : true, |
|
779 log : true, |
|
780 md5 : true, |
|
781 MenuItem : true, |
|
782 MoveAnimation : true, |
|
783 openURL : true, |
|
784 play : true, |
|
785 Point : true, |
|
786 popupMenu : true, |
|
787 preferenceGroups : true, |
|
788 preferences : true, |
|
789 print : true, |
|
790 prompt : true, |
|
791 random : true, |
|
792 Rectangle : true, |
|
793 reloadWidget : true, |
|
794 ResizeAnimation : true, |
|
795 resolvePath : true, |
|
796 resumeUpdates : true, |
|
797 RotateAnimation : true, |
|
798 runCommand : true, |
|
799 runCommandInBg : true, |
|
800 saveAs : true, |
|
801 savePreferences : true, |
|
802 screen : true, |
|
803 ScrollBar : true, |
|
804 showWidgetPreferences : true, |
|
805 sleep : true, |
|
806 speak : true, |
|
807 Style : true, |
|
808 suppressUpdates : true, |
|
809 system : true, |
|
810 tellWidget : true, |
|
811 Text : true, |
|
812 TextArea : true, |
|
813 Timer : true, |
|
814 unescape : true, |
|
815 updateNow : true, |
|
816 URL : true, |
|
817 Web : true, |
|
818 widget : true, |
|
819 Window : true, |
|
820 XMLDOM : true, |
|
821 XMLHttpRequest : true, |
|
822 yahooCheckLogin : true, |
|
823 yahooLogin : true, |
|
824 yahooLogout : true |
|
825 }, |
|
826 |
|
827 // xmode is used to adapt to the exceptions in html parsing. |
|
828 // It can have these states: |
|
829 // false .js script file |
|
830 // html |
|
831 // outer |
|
832 // script |
|
833 // style |
|
834 // scriptstring |
|
835 // styleproperty |
|
836 |
|
837 xmode, |
|
838 xquote, |
|
839 |
|
840 // unsafe comment or string |
|
841 ax = /@cc|<\/?|script|\]*s\]|<\s*!|</i, |
|
842 // unsafe characters that are silently deleted by one or more browsers |
|
843 cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/, |
|
844 // token |
|
845 tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|members?|global)?|=|\/)?|\*[\/=]?|\+[+=]?|-[\-=]?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/, |
|
846 // html token |
|
847 hx = /^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-]*|[0-9]+|--|.)/, |
|
848 // characters in strings that need escapement |
|
849 nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/, |
|
850 nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, |
|
851 // outer html token |
|
852 ox = /[>&]|<[\/!]?|--/, |
|
853 // star slash |
|
854 lx = /\*\/|\/\*/, |
|
855 // identifier |
|
856 ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/, |
|
857 // javascript url |
|
858 jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i, |
|
859 // url badness |
|
860 ux = /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i, |
|
861 // style |
|
862 sx = /^\s*([{:#%.=,>+\[\]@()"';]|\*=?|\$=|\|=|\^=|~=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/, |
|
863 ssx = /^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/, |
|
864 // attributes characters |
|
865 qx = /[^a-zA-Z0-9-_\/ ]/, |
|
866 // query characters for ids |
|
867 dx = /[\[\]\/\\"'*<>.&:(){}+=#]/, |
|
868 |
|
869 rx = { |
|
870 outer: hx, |
|
871 html: hx, |
|
872 style: sx, |
|
873 styleproperty: ssx |
|
874 }; |
|
875 |
|
876 function F() {} |
|
877 |
|
878 if (typeof Object.create !== 'function') { |
|
879 Object.create = function (o) { |
|
880 F.prototype = o; |
|
881 return new F(); |
|
882 }; |
|
883 } |
|
884 |
|
885 |
|
886 function is_own(object, name) { |
|
887 return Object.prototype.hasOwnProperty.call(object, name); |
|
888 } |
|
889 |
|
890 |
|
891 function combine(t, o) { |
|
892 var n; |
|
893 for (n in o) { |
|
894 if (is_own(o, n)) { |
|
895 t[n] = o[n]; |
|
896 } |
|
897 } |
|
898 } |
|
899 |
|
900 String.prototype.entityify = function () { |
|
901 return this. |
|
902 replace(/&/g, '&'). |
|
903 replace(/</g, '<'). |
|
904 replace(/>/g, '>'); |
|
905 }; |
|
906 |
|
907 String.prototype.isAlpha = function () { |
|
908 return (this >= 'a' && this <= 'z\uffff') || |
|
909 (this >= 'A' && this <= 'Z\uffff'); |
|
910 }; |
|
911 |
|
912 |
|
913 String.prototype.isDigit = function () { |
|
914 return (this >= '0' && this <= '9'); |
|
915 }; |
|
916 |
|
917 |
|
918 String.prototype.supplant = function (o) { |
|
919 return this.replace(/\{([^{}]*)\}/g, function (a, b) { |
|
920 var r = o[b]; |
|
921 return typeof r === 'string' || typeof r === 'number' ? r : a; |
|
922 }); |
|
923 }; |
|
924 |
|
925 String.prototype.name = function () { |
|
926 |
|
927 // If the string looks like an identifier, then we can return it as is. |
|
928 // If the string contains no control characters, no quote characters, and no |
|
929 // backslash characters, then we can simply slap some quotes around it. |
|
930 // Otherwise we must also replace the offending characters with safe |
|
931 // sequences. |
|
932 |
|
933 if (ix.test(this)) { |
|
934 return this; |
|
935 } |
|
936 if (nx.test(this)) { |
|
937 return '"' + this.replace(nxg, function (a) { |
|
938 var c = escapes[a]; |
|
939 if (c) { |
|
940 return c; |
|
941 } |
|
942 return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4); |
|
943 }) + '"'; |
|
944 } |
|
945 return '"' + this + '"'; |
|
946 }; |
|
947 |
|
948 |
|
949 function assume() { |
|
950 if (!option.safe) { |
|
951 if (option.rhino) { |
|
952 combine(predefined, rhino); |
|
953 } |
|
954 if (option.browser || option.sidebar) { |
|
955 combine(predefined, browser); |
|
956 } |
|
957 if (option.sidebar) { |
|
958 combine(predefined, sidebar); |
|
959 } |
|
960 if (option.widget) { |
|
961 combine(predefined, widget); |
|
962 } |
|
963 } |
|
964 } |
|
965 |
|
966 |
|
967 // Produce an error warning. |
|
968 |
|
969 function quit(m, l, ch) { |
|
970 throw { |
|
971 name: 'JSLintError', |
|
972 line: l, |
|
973 character: ch, |
|
974 message: m + " (" + Math.floor((l / lines.length) * 100) + |
|
975 "% scanned)." |
|
976 }; |
|
977 } |
|
978 |
|
979 function warning(m, t, a, b, c, d) { |
|
980 var ch, l, w; |
|
981 t = t || nexttoken; |
|
982 if (t.id === '(end)') { // `~ |
|
983 t = token; |
|
984 } |
|
985 l = t.line || 0; |
|
986 ch = t.from || 0; |
|
987 w = { |
|
988 id: '(error)', |
|
989 raw: m, |
|
990 evidence: lines[l - 1] || '', |
|
991 line: l, |
|
992 character: ch, |
|
993 a: a, |
|
994 b: b, |
|
995 c: c, |
|
996 d: d |
|
997 }; |
|
998 w.reason = m.supplant(w); |
|
999 JSLINT.errors.push(w); |
|
1000 if (option.passfail) { |
|
1001 quit('Stopping. ', l, ch); |
|
1002 } |
|
1003 warnings += 1; |
|
1004 if (warnings >= option.maxerr) { |
|
1005 quit("Too many errors.", l, ch); |
|
1006 } |
|
1007 return w; |
|
1008 } |
|
1009 |
|
1010 function warningAt(m, l, ch, a, b, c, d) { |
|
1011 return warning(m, { |
|
1012 line: l, |
|
1013 from: ch |
|
1014 }, a, b, c, d); |
|
1015 } |
|
1016 |
|
1017 function error(m, t, a, b, c, d) { |
|
1018 var w = warning(m, t, a, b, c, d); |
|
1019 quit("Stopping, unable to continue.", w.line, w.character); |
|
1020 } |
|
1021 |
|
1022 function errorAt(m, l, ch, a, b, c, d) { |
|
1023 return error(m, { |
|
1024 line: l, |
|
1025 from: ch |
|
1026 }, a, b, c, d); |
|
1027 } |
|
1028 |
|
1029 |
|
1030 |
|
1031 // lexical analysis |
|
1032 |
|
1033 var lex = (function lex() { |
|
1034 var character, from, line, s; |
|
1035 |
|
1036 // Private lex methods |
|
1037 |
|
1038 function nextLine() { |
|
1039 var at; |
|
1040 if (line >= lines.length) { |
|
1041 return false; |
|
1042 } |
|
1043 character = 1; |
|
1044 s = lines[line].replace(/\t/g, tab); |
|
1045 line += 1; |
|
1046 at = s.search(cx); |
|
1047 if (at >= 0) { |
|
1048 warningAt("Unsafe character.", line, at); |
|
1049 } |
|
1050 return true; |
|
1051 } |
|
1052 |
|
1053 // Produce a token object. The token inherits from a syntax symbol. |
|
1054 |
|
1055 function it(type, value) { |
|
1056 var i, t; |
|
1057 if (type === '(color)') { |
|
1058 t = {type: type}; |
|
1059 } else if (type === '(punctuator)' || |
|
1060 (type === '(identifier)' && is_own(syntax, value))) { |
|
1061 t = syntax[value] || syntax['(error)']; |
|
1062 } else { |
|
1063 t = syntax[type]; |
|
1064 } |
|
1065 t = Object.create(t); |
|
1066 if (type === '(string)' || type === '(range)') { |
|
1067 if (jx.test(value)) { |
|
1068 warningAt("Script URL.", line, from); |
|
1069 } |
|
1070 } |
|
1071 if (type === '(identifier)') { |
|
1072 t.identifier = true; |
|
1073 if (option.nomen && value.charAt(0) === '_') { |
|
1074 warningAt("Unexpected '_' in '{a}'.", line, from, value); |
|
1075 } |
|
1076 } |
|
1077 t.value = value; |
|
1078 t.line = line; |
|
1079 t.character = character; |
|
1080 t.from = from; |
|
1081 i = t.id; |
|
1082 if (i !== '(endline)') { |
|
1083 prereg = i && |
|
1084 (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) || |
|
1085 i === 'return'); |
|
1086 } |
|
1087 return t; |
|
1088 } |
|
1089 |
|
1090 // Public lex methods |
|
1091 |
|
1092 return { |
|
1093 init: function (source) { |
|
1094 if (typeof source === 'string') { |
|
1095 lines = source. |
|
1096 replace(/\r\n/g, '\n'). |
|
1097 replace(/\r/g, '\n'). |
|
1098 split('\n'); |
|
1099 } else { |
|
1100 lines = source; |
|
1101 } |
|
1102 line = 0; |
|
1103 nextLine(); |
|
1104 from = 1; |
|
1105 }, |
|
1106 |
|
1107 range: function (begin, end) { |
|
1108 var c, value = ''; |
|
1109 from = character; |
|
1110 if (s.charAt(0) !== begin) { |
|
1111 errorAt("Expected '{a}' and instead saw '{b}'.", |
|
1112 line, character, begin, s.charAt(0)); |
|
1113 } |
|
1114 for (;;) { |
|
1115 s = s.slice(1); |
|
1116 character += 1; |
|
1117 c = s.charAt(0); |
|
1118 switch (c) { |
|
1119 case '': |
|
1120 errorAt("Missing '{a}'.", line, character, c); |
|
1121 break; |
|
1122 case end: |
|
1123 s = s.slice(1); |
|
1124 character += 1; |
|
1125 return it('(range)', value); |
|
1126 case xquote: |
|
1127 case '\\': |
|
1128 warningAt("Unexpected '{a}'.", line, character, c); |
|
1129 } |
|
1130 value += c; |
|
1131 } |
|
1132 |
|
1133 }, |
|
1134 |
|
1135 // token -- this is called by advance to get the next token. |
|
1136 |
|
1137 token: function () { |
|
1138 var b, c, captures, d, depth, high, i, l, low, q, t; |
|
1139 |
|
1140 function match(x) { |
|
1141 var r = x.exec(s), r1; |
|
1142 if (r) { |
|
1143 l = r[0].length; |
|
1144 r1 = r[1]; |
|
1145 c = r1.charAt(0); |
|
1146 s = s.substr(l); |
|
1147 from = character + l - r1.length; |
|
1148 character += l; |
|
1149 return r1; |
|
1150 } |
|
1151 } |
|
1152 |
|
1153 function string(x) { |
|
1154 var c, j, r = ''; |
|
1155 |
|
1156 if (jsonmode && x !== '"') { |
|
1157 warningAt("Strings must use doublequote.", |
|
1158 line, character); |
|
1159 } |
|
1160 |
|
1161 if (xquote === x || (xmode === 'scriptstring' && !xquote)) { |
|
1162 return it('(punctuator)', x); |
|
1163 } |
|
1164 |
|
1165 function esc(n) { |
|
1166 var i = parseInt(s.substr(j + 1, n), 16); |
|
1167 j += n; |
|
1168 if (i >= 32 && i <= 126 && |
|
1169 i !== 34 && i !== 92 && i !== 39) { |
|
1170 warningAt("Unnecessary escapement.", line, character); |
|
1171 } |
|
1172 character += n; |
|
1173 c = String.fromCharCode(i); |
|
1174 } |
|
1175 j = 0; |
|
1176 for (;;) { |
|
1177 while (j >= s.length) { |
|
1178 j = 0; |
|
1179 if (xmode !== 'html' || !nextLine()) { |
|
1180 errorAt("Unclosed string.", line, from); |
|
1181 } |
|
1182 } |
|
1183 c = s.charAt(j); |
|
1184 if (c === x) { |
|
1185 character += 1; |
|
1186 s = s.substr(j + 1); |
|
1187 return it('(string)', r, x); |
|
1188 } |
|
1189 if (c < ' ') { |
|
1190 if (c === '\n' || c === '\r') { |
|
1191 break; |
|
1192 } |
|
1193 warningAt("Control character in string: {a}.", |
|
1194 line, character + j, s.slice(0, j)); |
|
1195 } else if (c === xquote) { |
|
1196 warningAt("Bad HTML string", line, character + j); |
|
1197 } else if (c === '<') { |
|
1198 if (option.safe && xmode === 'html') { |
|
1199 warningAt("ADsafe string violation.", |
|
1200 line, character + j); |
|
1201 } else if (s.charAt(j + 1) === '/' && (xmode || option.safe)) { |
|
1202 warningAt("Expected '<\\/' and instead saw '</'.", line, character); |
|
1203 } else if (s.charAt(j + 1) === '!' && (xmode || option.safe)) { |
|
1204 warningAt("Unexpected '<!' in a string.", line, character); |
|
1205 } |
|
1206 } else if (c === '\\') { |
|
1207 if (xmode === 'html') { |
|
1208 if (option.safe) { |
|
1209 warningAt("ADsafe string violation.", |
|
1210 line, character + j); |
|
1211 } |
|
1212 } else if (xmode === 'styleproperty') { |
|
1213 j += 1; |
|
1214 character += 1; |
|
1215 c = s.charAt(j); |
|
1216 if (c !== x) { |
|
1217 warningAt("Escapement in style string.", |
|
1218 line, character + j); |
|
1219 } |
|
1220 } else { |
|
1221 j += 1; |
|
1222 character += 1; |
|
1223 c = s.charAt(j); |
|
1224 switch (c) { |
|
1225 case xquote: |
|
1226 warningAt("Bad HTML string", line, |
|
1227 character + j); |
|
1228 break; |
|
1229 case '\\': |
|
1230 case '\'': |
|
1231 case '"': |
|
1232 case '/': |
|
1233 break; |
|
1234 case 'b': |
|
1235 c = '\b'; |
|
1236 break; |
|
1237 case 'f': |
|
1238 c = '\f'; |
|
1239 break; |
|
1240 case 'n': |
|
1241 c = '\n'; |
|
1242 break; |
|
1243 case 'r': |
|
1244 c = '\r'; |
|
1245 break; |
|
1246 case 't': |
|
1247 c = '\t'; |
|
1248 break; |
|
1249 case 'u': |
|
1250 esc(4); |
|
1251 break; |
|
1252 case 'v': |
|
1253 c = '\v'; |
|
1254 break; |
|
1255 case 'x': |
|
1256 if (jsonmode) { |
|
1257 warningAt("Avoid \\x-.", line, character); |
|
1258 } |
|
1259 esc(2); |
|
1260 break; |
|
1261 default: |
|
1262 warningAt("Bad escapement.", line, character); |
|
1263 } |
|
1264 } |
|
1265 } |
|
1266 r += c; |
|
1267 character += 1; |
|
1268 j += 1; |
|
1269 } |
|
1270 } |
|
1271 |
|
1272 for (;;) { |
|
1273 if (!s) { |
|
1274 return it(nextLine() ? '(endline)' : '(end)', ''); |
|
1275 } |
|
1276 while (xmode === 'outer') { |
|
1277 i = s.search(ox); |
|
1278 if (i === 0) { |
|
1279 break; |
|
1280 } else if (i > 0) { |
|
1281 character += 1; |
|
1282 s = s.slice(i); |
|
1283 break; |
|
1284 } else { |
|
1285 if (!nextLine()) { |
|
1286 return it('(end)', ''); |
|
1287 } |
|
1288 } |
|
1289 } |
|
1290 t = match(rx[xmode] || tx); |
|
1291 if (!t) { |
|
1292 if (xmode === 'html') { |
|
1293 return it('(error)', s.charAt(0)); |
|
1294 } else { |
|
1295 t = ''; |
|
1296 c = ''; |
|
1297 while (s && s < '!') { |
|
1298 s = s.substr(1); |
|
1299 } |
|
1300 if (s) { |
|
1301 errorAt("Unexpected '{a}'.", |
|
1302 line, character, s.substr(0, 1)); |
|
1303 } |
|
1304 } |
|
1305 } else { |
|
1306 |
|
1307 // identifier |
|
1308 |
|
1309 if (c.isAlpha() || c === '_' || c === '$') { |
|
1310 return it('(identifier)', t); |
|
1311 } |
|
1312 |
|
1313 // number |
|
1314 |
|
1315 if (c.isDigit()) { |
|
1316 if (xmode !== 'style' && !isFinite(Number(t))) { |
|
1317 warningAt("Bad number '{a}'.", |
|
1318 line, character, t); |
|
1319 } |
|
1320 if (xmode !== 'style' && |
|
1321 xmode !== 'styleproperty' && |
|
1322 s.substr(0, 1).isAlpha()) { |
|
1323 warningAt("Missing space after '{a}'.", |
|
1324 line, character, t); |
|
1325 } |
|
1326 if (c === '0') { |
|
1327 d = t.substr(1, 1); |
|
1328 if (d.isDigit()) { |
|
1329 if (token.id !== '.' && xmode !== 'styleproperty') { |
|
1330 warningAt("Don't use extra leading zeros '{a}'.", |
|
1331 line, character, t); |
|
1332 } |
|
1333 } else if (jsonmode && (d === 'x' || d === 'X')) { |
|
1334 warningAt("Avoid 0x-. '{a}'.", |
|
1335 line, character, t); |
|
1336 } |
|
1337 } |
|
1338 if (t.substr(t.length - 1) === '.') { |
|
1339 warningAt( |
|
1340 "A trailing decimal point can be confused with a dot '{a}'.", |
|
1341 line, character, t); |
|
1342 } |
|
1343 return it('(number)', t); |
|
1344 } |
|
1345 switch (t) { |
|
1346 |
|
1347 // string |
|
1348 |
|
1349 case '"': |
|
1350 case "'": |
|
1351 return string(t); |
|
1352 |
|
1353 // // comment |
|
1354 |
|
1355 case '//': |
|
1356 if (src || (xmode && xmode !== 'script')) { |
|
1357 warningAt("Unexpected comment.", line, character); |
|
1358 } else if (xmode === 'script' && /<\s*\//i.test(s)) { |
|
1359 warningAt("Unexpected <\/ in comment.", line, character); |
|
1360 } else if ((option.safe || xmode === 'script') && ax.test(s)) { |
|
1361 warningAt("Dangerous comment.", line, character); |
|
1362 } |
|
1363 s = ''; |
|
1364 token.comment = true; |
|
1365 break; |
|
1366 |
|
1367 // /* comment |
|
1368 |
|
1369 case '/*': |
|
1370 if (src || (xmode && xmode !== 'script' && xmode !== 'style' && xmode !== 'styleproperty')) { |
|
1371 warningAt("Unexpected comment.", line, character); |
|
1372 } |
|
1373 if (option.safe && ax.test(s)) { |
|
1374 warningAt("ADsafe comment violation.", line, character); |
|
1375 } |
|
1376 for (;;) { |
|
1377 i = s.search(lx); |
|
1378 if (i >= 0) { |
|
1379 break; |
|
1380 } |
|
1381 if (!nextLine()) { |
|
1382 errorAt("Unclosed comment.", line, character); |
|
1383 } else { |
|
1384 if (option.safe && ax.test(s)) { |
|
1385 warningAt("ADsafe comment violation.", line, character); |
|
1386 } |
|
1387 } |
|
1388 } |
|
1389 character += i + 2; |
|
1390 if (s.substr(i, 1) === '/') { |
|
1391 errorAt("Nested comment.", line, character); |
|
1392 } |
|
1393 s = s.substr(i + 2); |
|
1394 token.comment = true; |
|
1395 break; |
|
1396 |
|
1397 // /*members /*jslint /*global |
|
1398 |
|
1399 case '/*members': |
|
1400 case '/*member': |
|
1401 case '/*jslint': |
|
1402 case '/*global': |
|
1403 case '*/': |
|
1404 return { |
|
1405 value: t, |
|
1406 type: 'special', |
|
1407 line: line, |
|
1408 character: character, |
|
1409 from: from |
|
1410 }; |
|
1411 |
|
1412 case '': |
|
1413 break; |
|
1414 // / |
|
1415 case '/': |
|
1416 if (prereg) { |
|
1417 depth = 0; |
|
1418 captures = 0; |
|
1419 l = 0; |
|
1420 for (;;) { |
|
1421 b = true; |
|
1422 c = s.charAt(l); |
|
1423 l += 1; |
|
1424 switch (c) { |
|
1425 case '': |
|
1426 errorAt("Unclosed regular expression.", line, from); |
|
1427 return; |
|
1428 case '/': |
|
1429 if (depth > 0) { |
|
1430 warningAt("Unescaped '{a}'.", line, from + l, '/'); |
|
1431 } |
|
1432 c = s.substr(0, l - 1); |
|
1433 q = { |
|
1434 g: true, |
|
1435 i: true, |
|
1436 m: true |
|
1437 }; |
|
1438 while (q[s.charAt(l)] === true) { |
|
1439 q[s.charAt(l)] = false; |
|
1440 l += 1; |
|
1441 } |
|
1442 character += l; |
|
1443 s = s.substr(l); |
|
1444 return it('(regexp)', c); |
|
1445 case '\\': |
|
1446 c = s.charAt(l); |
|
1447 if (c < ' ') { |
|
1448 warningAt("Unexpected control character in regular expression.", line, from + l); |
|
1449 } else if (c === '<') { |
|
1450 warningAt("Unexpected escaped character '{a}' in regular expression.", line, from + l, c); |
|
1451 } |
|
1452 l += 1; |
|
1453 break; |
|
1454 case '(': |
|
1455 depth += 1; |
|
1456 b = false; |
|
1457 if (s.charAt(l) === '?') { |
|
1458 l += 1; |
|
1459 switch (s.charAt(l)) { |
|
1460 case ':': |
|
1461 case '=': |
|
1462 case '!': |
|
1463 l += 1; |
|
1464 break; |
|
1465 default: |
|
1466 warningAt("Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l)); |
|
1467 } |
|
1468 } else { |
|
1469 captures += 1; |
|
1470 } |
|
1471 break; |
|
1472 case '|': |
|
1473 b = false; |
|
1474 break; |
|
1475 case ')': |
|
1476 if (depth === 0) { |
|
1477 warningAt("Unescaped '{a}'.", line, from + l, ')'); |
|
1478 } else { |
|
1479 depth -= 1; |
|
1480 } |
|
1481 break; |
|
1482 case ' ': |
|
1483 q = 1; |
|
1484 while (s.charAt(l) === ' ') { |
|
1485 l += 1; |
|
1486 q += 1; |
|
1487 } |
|
1488 if (q > 1) { |
|
1489 warningAt("Spaces are hard to count. Use {{a}}.", line, from + l, q); |
|
1490 } |
|
1491 break; |
|
1492 case '[': |
|
1493 c = s.charAt(l); |
|
1494 if (c === '^') { |
|
1495 l += 1; |
|
1496 } |
|
1497 q = false; |
|
1498 if (c === ']') { |
|
1499 warningAt("Empty class.", line, from + l - 1); |
|
1500 q = true; |
|
1501 } |
|
1502 klass: do { |
|
1503 c = s.charAt(l); |
|
1504 l += 1; |
|
1505 switch (c) { |
|
1506 case '[': |
|
1507 case '^': |
|
1508 warningAt("Unescaped '{a}'.", line, from + l, c); |
|
1509 q = true; |
|
1510 break; |
|
1511 case '-': |
|
1512 if (q) { |
|
1513 q = false; |
|
1514 } else { |
|
1515 warningAt("Unescaped '{a}'.", line, from + l, '-'); |
|
1516 q = true; |
|
1517 } |
|
1518 break; |
|
1519 case ']': |
|
1520 if (!q) { |
|
1521 warningAt("Unescaped '{a}'.", line, from + l - 1, ']'); |
|
1522 } |
|
1523 break klass; |
|
1524 case '\\': |
|
1525 c = s.charAt(l); |
|
1526 if (c < ' ') { |
|
1527 warningAt("Unexpected control character in regular expression.", line, from + l); |
|
1528 } else if (c === '<') { |
|
1529 warningAt("Unexpected escaped character '{a}' in regular expression.", line, from + l, c); |
|
1530 } |
|
1531 l += 1; |
|
1532 q = true; |
|
1533 break; |
|
1534 case '/': |
|
1535 warningAt("Unescaped '{a}'.", line, from + l - 1, '/'); |
|
1536 q = true; |
|
1537 break; |
|
1538 case '<': |
|
1539 if (xmode === 'script') { |
|
1540 c = s.charAt(l); |
|
1541 if (c === '!' || c === '/') { |
|
1542 warningAt("HTML confusion in regular expression '<{a}'.", line, from + l, c); |
|
1543 } |
|
1544 } |
|
1545 q = true; |
|
1546 break; |
|
1547 default: |
|
1548 q = true; |
|
1549 } |
|
1550 } while (c); |
|
1551 break; |
|
1552 case '.': |
|
1553 if (option.regexp) { |
|
1554 warningAt("Unexpected '{a}'.", line, from + l, c); |
|
1555 } |
|
1556 break; |
|
1557 case ']': |
|
1558 case '?': |
|
1559 case '{': |
|
1560 case '}': |
|
1561 case '+': |
|
1562 case '*': |
|
1563 warningAt("Unescaped '{a}'.", line, from + l, c); |
|
1564 break; |
|
1565 case '<': |
|
1566 if (xmode === 'script') { |
|
1567 c = s.charAt(l); |
|
1568 if (c === '!' || c === '/') { |
|
1569 warningAt("HTML confusion in regular expression '<{a}'.", line, from + l, c); |
|
1570 } |
|
1571 } |
|
1572 } |
|
1573 if (b) { |
|
1574 switch (s.charAt(l)) { |
|
1575 case '?': |
|
1576 case '+': |
|
1577 case '*': |
|
1578 l += 1; |
|
1579 if (s.charAt(l) === '?') { |
|
1580 l += 1; |
|
1581 } |
|
1582 break; |
|
1583 case '{': |
|
1584 l += 1; |
|
1585 c = s.charAt(l); |
|
1586 if (c < '0' || c > '9') { |
|
1587 warningAt("Expected a number and instead saw '{a}'.", line, from + l, c); |
|
1588 } |
|
1589 l += 1; |
|
1590 low = +c; |
|
1591 for (;;) { |
|
1592 c = s.charAt(l); |
|
1593 if (c < '0' || c > '9') { |
|
1594 break; |
|
1595 } |
|
1596 l += 1; |
|
1597 low = +c + (low * 10); |
|
1598 } |
|
1599 high = low; |
|
1600 if (c === ',') { |
|
1601 l += 1; |
|
1602 high = Infinity; |
|
1603 c = s.charAt(l); |
|
1604 if (c >= '0' && c <= '9') { |
|
1605 l += 1; |
|
1606 high = +c; |
|
1607 for (;;) { |
|
1608 c = s.charAt(l); |
|
1609 if (c < '0' || c > '9') { |
|
1610 break; |
|
1611 } |
|
1612 l += 1; |
|
1613 high = +c + (high * 10); |
|
1614 } |
|
1615 } |
|
1616 } |
|
1617 if (s.charAt(l) !== '}') { |
|
1618 warningAt("Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c); |
|
1619 } else { |
|
1620 l += 1; |
|
1621 } |
|
1622 if (s.charAt(l) === '?') { |
|
1623 l += 1; |
|
1624 } |
|
1625 if (low > high) { |
|
1626 warningAt("'{a}' should not be greater than '{b}'.", line, from + l, low, high); |
|
1627 } |
|
1628 } |
|
1629 } |
|
1630 } |
|
1631 c = s.substr(0, l - 1); |
|
1632 character += l; |
|
1633 s = s.substr(l); |
|
1634 return it('(regexp)', c); |
|
1635 } |
|
1636 return it('(punctuator)', t); |
|
1637 |
|
1638 // punctuator |
|
1639 |
|
1640 case '<!--': |
|
1641 l = line; |
|
1642 c = character; |
|
1643 for (;;) { |
|
1644 i = s.indexOf('--'); |
|
1645 if (i >= 0) { |
|
1646 break; |
|
1647 } |
|
1648 i = s.indexOf('<!'); |
|
1649 if (i >= 0) { |
|
1650 errorAt("Nested HTML comment.", |
|
1651 line, character + i); |
|
1652 } |
|
1653 if (!nextLine()) { |
|
1654 errorAt("Unclosed HTML comment.", l, c); |
|
1655 } |
|
1656 } |
|
1657 l = s.indexOf('<!'); |
|
1658 if (l >= 0 && l < i) { |
|
1659 errorAt("Nested HTML comment.", |
|
1660 line, character + l); |
|
1661 } |
|
1662 character += i; |
|
1663 if (s[i + 2] !== '>') { |
|
1664 errorAt("Expected -->.", line, character); |
|
1665 } |
|
1666 character += 3; |
|
1667 s = s.slice(i + 3); |
|
1668 break; |
|
1669 case '#': |
|
1670 if (xmode === 'html' || xmode === 'styleproperty') { |
|
1671 for (;;) { |
|
1672 c = s.charAt(0); |
|
1673 if ((c < '0' || c > '9') && |
|
1674 (c < 'a' || c > 'f') && |
|
1675 (c < 'A' || c > 'F')) { |
|
1676 break; |
|
1677 } |
|
1678 character += 1; |
|
1679 s = s.substr(1); |
|
1680 t += c; |
|
1681 } |
|
1682 if (t.length !== 4 && t.length !== 7) { |
|
1683 warningAt("Bad hex color '{a}'.", line, |
|
1684 from + l, t); |
|
1685 } |
|
1686 return it('(color)', t); |
|
1687 } |
|
1688 return it('(punctuator)', t); |
|
1689 default: |
|
1690 if (xmode === 'outer' && c === '&') { |
|
1691 character += 1; |
|
1692 s = s.substr(1); |
|
1693 for (;;) { |
|
1694 c = s.charAt(0); |
|
1695 character += 1; |
|
1696 s = s.substr(1); |
|
1697 if (c === ';') { |
|
1698 break; |
|
1699 } |
|
1700 if (!((c >= '0' && c <= '9') || |
|
1701 (c >= 'a' && c <= 'z') || |
|
1702 c === '#')) { |
|
1703 errorAt("Bad entity", line, from + l, |
|
1704 character); |
|
1705 } |
|
1706 } |
|
1707 break; |
|
1708 } |
|
1709 return it('(punctuator)', t); |
|
1710 } |
|
1711 } |
|
1712 } |
|
1713 } |
|
1714 }; |
|
1715 }()); |
|
1716 |
|
1717 |
|
1718 function addlabel(t, type) { |
|
1719 |
|
1720 if (option.safe && funct['(global)'] && typeof predefined[t] !== 'boolean') { |
|
1721 warning('ADsafe global: ' + t + '.', token); |
|
1722 } else if (t === 'hasOwnProperty') { |
|
1723 warning("'hasOwnProperty' is a really bad name."); |
|
1724 } |
|
1725 |
|
1726 // Define t in the current function in the current scope. |
|
1727 |
|
1728 if (is_own(funct, t) && !funct['(global)']) { |
|
1729 warning(funct[t] === true ? |
|
1730 "'{a}' was used before it was defined." : |
|
1731 "'{a}' is already defined.", |
|
1732 nexttoken, t); |
|
1733 } |
|
1734 funct[t] = type; |
|
1735 if (type === 'label') { |
|
1736 scope[t] = funct; |
|
1737 } else if (funct['(global)']) { |
|
1738 global[t] = funct; |
|
1739 if (is_own(implied, t)) { |
|
1740 warning("'{a}' was used before it was defined.", nexttoken, t); |
|
1741 delete implied[t]; |
|
1742 } |
|
1743 } else { |
|
1744 funct['(scope)'][t] = funct; |
|
1745 } |
|
1746 } |
|
1747 |
|
1748 |
|
1749 function doOption() { |
|
1750 var b, obj, filter, o = nexttoken.value, t, v; |
|
1751 switch (o) { |
|
1752 case '*/': |
|
1753 error("Unbegun comment."); |
|
1754 break; |
|
1755 case '/*members': |
|
1756 case '/*member': |
|
1757 o = '/*members'; |
|
1758 if (!membersOnly) { |
|
1759 membersOnly = {}; |
|
1760 } |
|
1761 obj = membersOnly; |
|
1762 break; |
|
1763 case '/*jslint': |
|
1764 if (option.safe) { |
|
1765 warning("ADsafe restriction."); |
|
1766 } |
|
1767 obj = option; |
|
1768 filter = boolOptions; |
|
1769 break; |
|
1770 case '/*global': |
|
1771 if (option.safe) { |
|
1772 warning("ADsafe restriction."); |
|
1773 } |
|
1774 obj = predefined; |
|
1775 break; |
|
1776 default: |
|
1777 } |
|
1778 t = lex.token(); |
|
1779 loop: for (;;) { |
|
1780 for (;;) { |
|
1781 if (t.type === 'special' && t.value === '*/') { |
|
1782 break loop; |
|
1783 } |
|
1784 if (t.id !== '(endline)' && t.id !== ',') { |
|
1785 break; |
|
1786 } |
|
1787 t = lex.token(); |
|
1788 } |
|
1789 if (t.type !== '(string)' && t.type !== '(identifier)' && |
|
1790 o !== '/*members') { |
|
1791 error("Bad option.", t); |
|
1792 } |
|
1793 v = lex.token(); |
|
1794 if (v.id === ':') { |
|
1795 v = lex.token(); |
|
1796 if (obj === membersOnly) { |
|
1797 error("Expected '{a}' and instead saw '{b}'.", |
|
1798 t, '*/', ':'); |
|
1799 } |
|
1800 if (t.value === 'indent' && o === '/*jslint') { |
|
1801 b = +v.value; |
|
1802 if (typeof b !== 'number' || !isFinite(b) || b <= 0 || |
|
1803 Math.floor(b) !== b) { |
|
1804 error("Expected a small integer and instead saw '{a}'.", |
|
1805 v, v.value); |
|
1806 } |
|
1807 obj.white = true; |
|
1808 obj.indent = b; |
|
1809 } else if (t.value === 'maxerr' && o === '/*jslint') { |
|
1810 b = +v.value; |
|
1811 if (typeof b !== 'number' || !isFinite(b) || b <= 0 || |
|
1812 Math.floor(b) !== b) { |
|
1813 error("Expected a small integer and instead saw '{a}'.", |
|
1814 v, v.value); |
|
1815 } |
|
1816 obj.maxerr = b; |
|
1817 } else if (v.value === 'true') { |
|
1818 obj[t.value] = true; |
|
1819 } else if (v.value === 'false') { |
|
1820 obj[t.value] = false; |
|
1821 } else { |
|
1822 error("Bad option value.", v); |
|
1823 } |
|
1824 t = lex.token(); |
|
1825 } else { |
|
1826 if (o === '/*jslint') { |
|
1827 error("Missing option value.", t); |
|
1828 } |
|
1829 obj[t.value] = false; |
|
1830 t = v; |
|
1831 } |
|
1832 } |
|
1833 if (filter) { |
|
1834 assume(); |
|
1835 } |
|
1836 } |
|
1837 |
|
1838 |
|
1839 // We need a peek function. If it has an argument, it peeks that much farther |
|
1840 // ahead. It is used to distinguish |
|
1841 // for ( var i in ... |
|
1842 // from |
|
1843 // for ( var i = ... |
|
1844 |
|
1845 function peek(p) { |
|
1846 var i = p || 0, j = 0, t; |
|
1847 |
|
1848 while (j <= i) { |
|
1849 t = lookahead[j]; |
|
1850 if (!t) { |
|
1851 t = lookahead[j] = lex.token(); |
|
1852 } |
|
1853 j += 1; |
|
1854 } |
|
1855 return t; |
|
1856 } |
|
1857 |
|
1858 |
|
1859 |
|
1860 // Produce the next token. It looks for programming errors. |
|
1861 |
|
1862 function advance(id, t) { |
|
1863 switch (token.id) { |
|
1864 case '(number)': |
|
1865 if (nexttoken.id === '.') { |
|
1866 warning( |
|
1867 "A dot following a number can be confused with a decimal point.", token); |
|
1868 } |
|
1869 break; |
|
1870 case '-': |
|
1871 if (nexttoken.id === '-' || nexttoken.id === '--') { |
|
1872 warning("Confusing minusses."); |
|
1873 } |
|
1874 break; |
|
1875 case '+': |
|
1876 if (nexttoken.id === '+' || nexttoken.id === '++') { |
|
1877 warning("Confusing plusses."); |
|
1878 } |
|
1879 break; |
|
1880 } |
|
1881 if (token.type === '(string)' || token.identifier) { |
|
1882 anonname = token.value; |
|
1883 } |
|
1884 |
|
1885 if (id && nexttoken.id !== id) { |
|
1886 if (t) { |
|
1887 if (nexttoken.id === '(end)') { |
|
1888 warning("Unmatched '{a}'.", t, t.id); |
|
1889 } else { |
|
1890 warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", |
|
1891 nexttoken, id, t.id, t.line, nexttoken.value); |
|
1892 } |
|
1893 } else if (nexttoken.type !== '(identifier)' || |
|
1894 nexttoken.value !== id) { |
|
1895 warning("Expected '{a}' and instead saw '{b}'.", |
|
1896 nexttoken, id, nexttoken.value); |
|
1897 } |
|
1898 } |
|
1899 prevtoken = token; |
|
1900 token = nexttoken; |
|
1901 for (;;) { |
|
1902 nexttoken = lookahead.shift() || lex.token(); |
|
1903 if (nexttoken.id === '(end)' || nexttoken.id === '(error)') { |
|
1904 return; |
|
1905 } |
|
1906 if (nexttoken.type === 'special') { |
|
1907 doOption(); |
|
1908 } else { |
|
1909 if (nexttoken.id !== '(endline)') { |
|
1910 break; |
|
1911 } |
|
1912 } |
|
1913 } |
|
1914 } |
|
1915 |
|
1916 |
|
1917 // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it |
|
1918 // is looking for ad hoc lint patterns. We add to Pratt's model .fud, which is |
|
1919 // like nud except that it is only used on the first token of a statement. |
|
1920 // Having .fud makes it much easier to define JavaScript. I retained Pratt's |
|
1921 // nomenclature. |
|
1922 |
|
1923 // .nud Null denotation |
|
1924 // .fud First null denotation |
|
1925 // .led Left denotation |
|
1926 // lbp Left binding power |
|
1927 // rbp Right binding power |
|
1928 |
|
1929 // They are key to the parsing method called Top Down Operator Precedence. |
|
1930 |
|
1931 function parse(rbp, initial) { |
|
1932 var left, o; |
|
1933 if (nexttoken.id === '(end)') { |
|
1934 error("Unexpected early end of program.", token); |
|
1935 } |
|
1936 advance(); |
|
1937 if (option.safe && typeof predefined[token.value] === 'boolean' && |
|
1938 (nexttoken.id !== '(' && nexttoken.id !== '.')) { |
|
1939 warning('ADsafe violation.', token); |
|
1940 } |
|
1941 if (initial) { |
|
1942 anonname = 'anonymous'; |
|
1943 funct['(verb)'] = token.value; |
|
1944 } |
|
1945 if (initial === true && token.fud) { |
|
1946 left = token.fud(); |
|
1947 } else { |
|
1948 if (token.nud) { |
|
1949 o = token.exps; |
|
1950 left = token.nud(); |
|
1951 } else { |
|
1952 if (nexttoken.type === '(number)' && token.id === '.') { |
|
1953 warning( |
|
1954 "A leading decimal point can be confused with a dot: '.{a}'.", |
|
1955 token, nexttoken.value); |
|
1956 advance(); |
|
1957 return token; |
|
1958 } else { |
|
1959 error("Expected an identifier and instead saw '{a}'.", |
|
1960 token, token.id); |
|
1961 } |
|
1962 } |
|
1963 while (rbp < nexttoken.lbp) { |
|
1964 o = nexttoken.exps; |
|
1965 advance(); |
|
1966 if (token.led) { |
|
1967 left = token.led(left); |
|
1968 } else { |
|
1969 error("Expected an operator and instead saw '{a}'.", |
|
1970 token, token.id); |
|
1971 } |
|
1972 } |
|
1973 if (initial && !o) { |
|
1974 warning( |
|
1975 "Expected an assignment or function call and instead saw an expression.", |
|
1976 token); |
|
1977 } |
|
1978 } |
|
1979 return left; |
|
1980 } |
|
1981 |
|
1982 |
|
1983 // Functions for conformance of style. |
|
1984 |
|
1985 function adjacent(left, right) { |
|
1986 left = left || token; |
|
1987 right = right || nexttoken; |
|
1988 if (option.white || xmode === 'styleproperty' || xmode === 'style') { |
|
1989 if (left.character !== right.from && left.line === right.line) { |
|
1990 warning("Unexpected space after '{a}'.", right, left.value); |
|
1991 } |
|
1992 } |
|
1993 } |
|
1994 |
|
1995 function nospace(left, right) { |
|
1996 left = left || token; |
|
1997 right = right || nexttoken; |
|
1998 if (option.white && !left.comment) { |
|
1999 if (left.line === right.line) { |
|
2000 adjacent(left, right); |
|
2001 } |
|
2002 } |
|
2003 } |
|
2004 |
|
2005 |
|
2006 function nonadjacent(left, right) { |
|
2007 if (option.white) { |
|
2008 left = left || token; |
|
2009 right = right || nexttoken; |
|
2010 if (left.character === right.from) { |
|
2011 warning("Missing space after '{a}'.", |
|
2012 nexttoken, left.value); |
|
2013 } |
|
2014 } |
|
2015 } |
|
2016 |
|
2017 function nobreaknonadjacent(left, right) { |
|
2018 left = left || token; |
|
2019 right = right || nexttoken; |
|
2020 if (!option.laxbreak && left.line !== right.line) { |
|
2021 warning("Bad line breaking before '{a}'.", right, right.id); |
|
2022 } else if (option.white) { |
|
2023 left = left || token; |
|
2024 right = right || nexttoken; |
|
2025 if (left.character === right.from) { |
|
2026 warning("Missing space after '{a}'.", |
|
2027 nexttoken, left.value); |
|
2028 } |
|
2029 } |
|
2030 } |
|
2031 |
|
2032 function indentation(bias) { |
|
2033 var i; |
|
2034 if (option.white && nexttoken.id !== '(end)') { |
|
2035 i = indent + (bias || 0); |
|
2036 if (nexttoken.from !== i) { |
|
2037 warning("Expected '{a}' to have an indentation at {b} instead at {c}.", |
|
2038 nexttoken, nexttoken.value, i, nexttoken.from); |
|
2039 } |
|
2040 } |
|
2041 } |
|
2042 |
|
2043 function nolinebreak(t) { |
|
2044 t = t || token; |
|
2045 if (t.line !== nexttoken.line) { |
|
2046 warning("Line breaking error '{a}'.", t, t.value); |
|
2047 } |
|
2048 } |
|
2049 |
|
2050 |
|
2051 function comma() { |
|
2052 if (token.line !== nexttoken.line) { |
|
2053 if (!option.laxbreak) { |
|
2054 warning("Bad line breaking before '{a}'.", token, nexttoken.id); |
|
2055 } |
|
2056 } else if (token.character !== nexttoken.from && option.white) { |
|
2057 warning("Unexpected space after '{a}'.", nexttoken, token.value); |
|
2058 } |
|
2059 advance(','); |
|
2060 nonadjacent(token, nexttoken); |
|
2061 } |
|
2062 |
|
2063 |
|
2064 // Functional constructors for making the symbols that will be inherited by |
|
2065 // tokens. |
|
2066 |
|
2067 function symbol(s, p) { |
|
2068 var x = syntax[s]; |
|
2069 if (!x || typeof x !== 'object') { |
|
2070 syntax[s] = x = { |
|
2071 id: s, |
|
2072 lbp: p, |
|
2073 value: s |
|
2074 }; |
|
2075 } |
|
2076 return x; |
|
2077 } |
|
2078 |
|
2079 |
|
2080 function delim(s) { |
|
2081 return symbol(s, 0); |
|
2082 } |
|
2083 |
|
2084 |
|
2085 function stmt(s, f) { |
|
2086 var x = delim(s); |
|
2087 x.identifier = x.reserved = true; |
|
2088 x.fud = f; |
|
2089 return x; |
|
2090 } |
|
2091 |
|
2092 |
|
2093 function blockstmt(s, f) { |
|
2094 var x = stmt(s, f); |
|
2095 x.block = true; |
|
2096 return x; |
|
2097 } |
|
2098 |
|
2099 |
|
2100 function reserveName(x) { |
|
2101 var c = x.id.charAt(0); |
|
2102 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { |
|
2103 x.identifier = x.reserved = true; |
|
2104 } |
|
2105 return x; |
|
2106 } |
|
2107 |
|
2108 |
|
2109 function prefix(s, f) { |
|
2110 var x = symbol(s, 150); |
|
2111 reserveName(x); |
|
2112 x.nud = (typeof f === 'function') ? f : function () { |
|
2113 this.right = parse(150); |
|
2114 this.arity = 'unary'; |
|
2115 if (this.id === '++' || this.id === '--') { |
|
2116 if (option.plusplus) { |
|
2117 warning("Unexpected use of '{a}'.", this, this.id); |
|
2118 } else if ((!this.right.identifier || this.right.reserved) && |
|
2119 this.right.id !== '.' && this.right.id !== '[') { |
|
2120 warning("Bad operand.", this); |
|
2121 } |
|
2122 } |
|
2123 return this; |
|
2124 }; |
|
2125 return x; |
|
2126 } |
|
2127 |
|
2128 |
|
2129 function type(s, f) { |
|
2130 var x = delim(s); |
|
2131 x.type = s; |
|
2132 x.nud = f; |
|
2133 return x; |
|
2134 } |
|
2135 |
|
2136 |
|
2137 function reserve(s, f) { |
|
2138 var x = type(s, f); |
|
2139 x.identifier = x.reserved = true; |
|
2140 return x; |
|
2141 } |
|
2142 |
|
2143 |
|
2144 function reservevar(s, v) { |
|
2145 return reserve(s, function () { |
|
2146 if (option.safe && |
|
2147 (this.id === 'this' || this.id === 'arguments')) { |
|
2148 warning("ADsafe violation.", this); |
|
2149 } |
|
2150 return this; |
|
2151 }); |
|
2152 } |
|
2153 |
|
2154 |
|
2155 function infix(s, f, p, w) { |
|
2156 var x = symbol(s, p); |
|
2157 reserveName(x); |
|
2158 x.led = function (left) { |
|
2159 if (!w) { |
|
2160 nobreaknonadjacent(prevtoken, token); |
|
2161 nonadjacent(token, nexttoken); |
|
2162 } |
|
2163 if (typeof f === 'function') { |
|
2164 return f(left, this); |
|
2165 } else { |
|
2166 this.left = left; |
|
2167 this.right = parse(p); |
|
2168 return this; |
|
2169 } |
|
2170 }; |
|
2171 return x; |
|
2172 } |
|
2173 |
|
2174 |
|
2175 function relation(s, f) { |
|
2176 var x = symbol(s, 100); |
|
2177 x.led = function (left) { |
|
2178 nobreaknonadjacent(prevtoken, token); |
|
2179 nonadjacent(token, nexttoken); |
|
2180 var right = parse(100); |
|
2181 if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) { |
|
2182 warning("Use the isNaN function to compare with NaN.", this); |
|
2183 } else if (f) { |
|
2184 f.apply(this, [left, right]); |
|
2185 } |
|
2186 this.left = left; |
|
2187 this.right = right; |
|
2188 return this; |
|
2189 }; |
|
2190 return x; |
|
2191 } |
|
2192 |
|
2193 |
|
2194 function isPoorRelation(node) { |
|
2195 return (node.type === '(number)' && !+node.value) || |
|
2196 (node.type === '(string)' && !node.value) || |
|
2197 node.type === 'true' || |
|
2198 node.type === 'false' || |
|
2199 node.type === 'undefined' || |
|
2200 node.type === 'null'; |
|
2201 } |
|
2202 |
|
2203 |
|
2204 function assignop(s, f) { |
|
2205 symbol(s, 20).exps = true; |
|
2206 return infix(s, function (left, that) { |
|
2207 var l; |
|
2208 that.left = left; |
|
2209 if (predefined[left.value] === false && |
|
2210 scope[left.value]['(global)'] === true) { |
|
2211 warning('Read only.', left); |
|
2212 } |
|
2213 if (option.safe) { |
|
2214 l = left; |
|
2215 do { |
|
2216 if (typeof predefined[l.value] === 'boolean') { |
|
2217 warning('ADsafe violation.', l); |
|
2218 } |
|
2219 l = l.left; |
|
2220 } while (l); |
|
2221 } |
|
2222 if (left) { |
|
2223 if (left.id === '.' || left.id === '[') { |
|
2224 if (left.left.value === 'arguments') { |
|
2225 warning('Bad assignment.', that); |
|
2226 } |
|
2227 that.right = parse(19); |
|
2228 return that; |
|
2229 } else if (left.identifier && !left.reserved) { |
|
2230 if (funct[left.value] === 'exception') { |
|
2231 warning("Do not assign to the exception parameter.", left); |
|
2232 } |
|
2233 that.right = parse(19); |
|
2234 return that; |
|
2235 } |
|
2236 if (left === syntax['function']) { |
|
2237 warning( |
|
2238 "Expected an identifier in an assignment and instead saw a function invocation.", |
|
2239 token); |
|
2240 } |
|
2241 } |
|
2242 error("Bad assignment.", that); |
|
2243 }, 20); |
|
2244 } |
|
2245 |
|
2246 function bitwise(s, f, p) { |
|
2247 var x = symbol(s, p); |
|
2248 reserveName(x); |
|
2249 x.led = (typeof f === 'function') ? f : function (left) { |
|
2250 if (option.bitwise) { |
|
2251 warning("Unexpected use of '{a}'.", this, this.id); |
|
2252 } |
|
2253 this.left = left; |
|
2254 this.right = parse(p); |
|
2255 return this; |
|
2256 }; |
|
2257 return x; |
|
2258 } |
|
2259 |
|
2260 function bitwiseassignop(s) { |
|
2261 symbol(s, 20).exps = true; |
|
2262 return infix(s, function (left, that) { |
|
2263 if (option.bitwise) { |
|
2264 warning("Unexpected use of '{a}'.", that, that.id); |
|
2265 } |
|
2266 nonadjacent(prevtoken, token); |
|
2267 nonadjacent(token, nexttoken); |
|
2268 if (left) { |
|
2269 if (left.id === '.' || left.id === '[' || |
|
2270 (left.identifier && !left.reserved)) { |
|
2271 parse(19); |
|
2272 return left; |
|
2273 } |
|
2274 if (left === syntax['function']) { |
|
2275 warning( |
|
2276 "Expected an identifier in an assignment, and instead saw a function invocation.", |
|
2277 token); |
|
2278 } |
|
2279 } |
|
2280 error("Bad assignment.", that); |
|
2281 }, 20); |
|
2282 } |
|
2283 |
|
2284 |
|
2285 function suffix(s, f) { |
|
2286 var x = symbol(s, 150); |
|
2287 x.led = function (left) { |
|
2288 if (option.plusplus) { |
|
2289 warning("Unexpected use of '{a}'.", this, this.id); |
|
2290 } else if ((!left.identifier || left.reserved) && left.id !== '.' && left.id !== '[') { |
|
2291 warning("Bad operand.", this); |
|
2292 } |
|
2293 this.left = left; |
|
2294 return this; |
|
2295 }; |
|
2296 return x; |
|
2297 } |
|
2298 |
|
2299 |
|
2300 function optionalidentifier() { |
|
2301 if (nexttoken.reserved) { |
|
2302 warning("Expected an identifier and instead saw '{a}' (a reserved word).", |
|
2303 nexttoken, nexttoken.id); |
|
2304 } |
|
2305 if (nexttoken.identifier) { |
|
2306 advance(); |
|
2307 return token.value; |
|
2308 } |
|
2309 } |
|
2310 |
|
2311 |
|
2312 function identifier() { |
|
2313 var i = optionalidentifier(); |
|
2314 if (i) { |
|
2315 return i; |
|
2316 } |
|
2317 if (token.id === 'function' && nexttoken.id === '(') { |
|
2318 warning("Missing name in function statement."); |
|
2319 } else { |
|
2320 error("Expected an identifier and instead saw '{a}'.", |
|
2321 nexttoken, nexttoken.value); |
|
2322 } |
|
2323 } |
|
2324 |
|
2325 function reachable(s) { |
|
2326 var i = 0, t; |
|
2327 if (nexttoken.id !== ';' || noreach) { |
|
2328 return; |
|
2329 } |
|
2330 for (;;) { |
|
2331 t = peek(i); |
|
2332 if (t.reach) { |
|
2333 return; |
|
2334 } |
|
2335 if (t.id !== '(endline)') { |
|
2336 if (t.id === 'function') { |
|
2337 warning( |
|
2338 "Inner functions should be listed at the top of the outer function.", t); |
|
2339 break; |
|
2340 } |
|
2341 warning("Unreachable '{a}' after '{b}'.", t, t.value, s); |
|
2342 break; |
|
2343 } |
|
2344 i += 1; |
|
2345 } |
|
2346 } |
|
2347 |
|
2348 |
|
2349 function statement(noindent) { |
|
2350 var i = indent, r, s = scope, t = nexttoken; |
|
2351 |
|
2352 // We don't like the empty statement. |
|
2353 |
|
2354 if (t.id === ';') { |
|
2355 warning("Unnecessary semicolon.", t); |
|
2356 advance(';'); |
|
2357 return; |
|
2358 } |
|
2359 |
|
2360 // Is this a labelled statement? |
|
2361 |
|
2362 if (t.identifier && !t.reserved && peek().id === ':') { |
|
2363 advance(); |
|
2364 advance(':'); |
|
2365 scope = Object.create(s); |
|
2366 addlabel(t.value, 'label'); |
|
2367 if (!nexttoken.labelled) { |
|
2368 warning("Label '{a}' on {b} statement.", |
|
2369 nexttoken, t.value, nexttoken.value); |
|
2370 } |
|
2371 if (jx.test(t.value + ':')) { |
|
2372 warning("Label '{a}' looks like a javascript url.", |
|
2373 t, t.value); |
|
2374 } |
|
2375 nexttoken.label = t.value; |
|
2376 t = nexttoken; |
|
2377 } |
|
2378 |
|
2379 // Parse the statement. |
|
2380 |
|
2381 if (!noindent) { |
|
2382 indentation(); |
|
2383 } |
|
2384 r = parse(0, true); |
|
2385 |
|
2386 // Look for the final semicolon. |
|
2387 |
|
2388 if (!t.block) { |
|
2389 if (nexttoken.id !== ';') { |
|
2390 warningAt("Missing semicolon.", token.line, |
|
2391 token.from + token.value.length); |
|
2392 } else { |
|
2393 adjacent(token, nexttoken); |
|
2394 advance(';'); |
|
2395 nonadjacent(token, nexttoken); |
|
2396 } |
|
2397 } |
|
2398 |
|
2399 // Restore the indentation. |
|
2400 |
|
2401 indent = i; |
|
2402 scope = s; |
|
2403 return r; |
|
2404 } |
|
2405 |
|
2406 |
|
2407 function use_strict() { |
|
2408 if (nexttoken.value === 'use strict') { |
|
2409 advance(); |
|
2410 advance(';'); |
|
2411 return true; |
|
2412 } else { |
|
2413 return false; |
|
2414 } |
|
2415 } |
|
2416 |
|
2417 |
|
2418 function statements(begin) { |
|
2419 var a = [], f, p; |
|
2420 if (begin && !use_strict() && option.strict) { |
|
2421 warning('Missing "use strict" statement.', nexttoken); |
|
2422 } |
|
2423 if (option.adsafe) { |
|
2424 switch (begin) { |
|
2425 case 'script': |
|
2426 if (!adsafe_may) { |
|
2427 if (nexttoken.value !== 'ADSAFE' || |
|
2428 peek(0).id !== '.' || |
|
2429 (peek(1).value !== 'id' && |
|
2430 peek(1).value !== 'go')) { |
|
2431 error('ADsafe violation: Missing ADSAFE.id or ADSAFE.go.', |
|
2432 nexttoken); |
|
2433 } |
|
2434 } |
|
2435 if (nexttoken.value === 'ADSAFE' && |
|
2436 peek(0).id === '.' && |
|
2437 peek(1).value === 'id') { |
|
2438 if (adsafe_may) { |
|
2439 error('ADsafe violation.', nexttoken); |
|
2440 } |
|
2441 advance('ADSAFE'); |
|
2442 advance('.'); |
|
2443 advance('id'); |
|
2444 advance('('); |
|
2445 if (nexttoken.value !== adsafe_id) { |
|
2446 error('ADsafe violation: id does not match.', nexttoken); |
|
2447 } |
|
2448 advance('(string)'); |
|
2449 advance(')'); |
|
2450 advance(';'); |
|
2451 adsafe_may = true; |
|
2452 } |
|
2453 break; |
|
2454 case 'lib': |
|
2455 if (nexttoken.value === 'ADSAFE') { |
|
2456 advance('ADSAFE'); |
|
2457 advance('.'); |
|
2458 advance('lib'); |
|
2459 advance('('); |
|
2460 advance('(string)'); |
|
2461 comma(); |
|
2462 f = parse(0); |
|
2463 if (f.id !== 'function') { |
|
2464 error('The second argument to lib must be a function.', f); |
|
2465 } |
|
2466 p = f.funct['(params)']; |
|
2467 p = p && p.join(', '); |
|
2468 if (p && p !== 'lib') { |
|
2469 error("Expected '{a}' and instead saw '{b}'.", |
|
2470 f, '(lib)', '(' + p + ')'); |
|
2471 } |
|
2472 advance(')'); |
|
2473 advance(';'); |
|
2474 return a; |
|
2475 } else { |
|
2476 error("ADsafe lib violation."); |
|
2477 } |
|
2478 } |
|
2479 } |
|
2480 while (!nexttoken.reach && nexttoken.id !== '(end)') { |
|
2481 if (nexttoken.id === ';') { |
|
2482 warning("Unnecessary semicolon."); |
|
2483 advance(';'); |
|
2484 } else { |
|
2485 a.push(statement()); |
|
2486 } |
|
2487 } |
|
2488 return a; |
|
2489 } |
|
2490 |
|
2491 |
|
2492 function block(f) { |
|
2493 var a, b = inblock, s = scope, t; |
|
2494 inblock = f; |
|
2495 if (f) { |
|
2496 scope = Object.create(scope); |
|
2497 } |
|
2498 nonadjacent(token, nexttoken); |
|
2499 t = nexttoken; |
|
2500 if (nexttoken.id === '{') { |
|
2501 advance('{'); |
|
2502 if (nexttoken.id !== '}' || token.line !== nexttoken.line) { |
|
2503 indent += option.indent; |
|
2504 if (!f && nexttoken.from === indent + option.indent) { |
|
2505 indent += option.indent; |
|
2506 } |
|
2507 if (!f) { |
|
2508 use_strict(); |
|
2509 } |
|
2510 a = statements(); |
|
2511 indent -= option.indent; |
|
2512 indentation(); |
|
2513 } |
|
2514 advance('}', t); |
|
2515 } else { |
|
2516 warning("Expected '{a}' and instead saw '{b}'.", |
|
2517 nexttoken, '{', nexttoken.value); |
|
2518 noreach = true; |
|
2519 a = [statement()]; |
|
2520 noreach = false; |
|
2521 } |
|
2522 funct['(verb)'] = null; |
|
2523 scope = s; |
|
2524 inblock = b; |
|
2525 return a; |
|
2526 } |
|
2527 |
|
2528 |
|
2529 // An identity function, used by string and number tokens. |
|
2530 |
|
2531 function idValue() { |
|
2532 return this; |
|
2533 } |
|
2534 |
|
2535 |
|
2536 function countMember(m) { |
|
2537 if (membersOnly && typeof membersOnly[m] !== 'boolean') { |
|
2538 warning("Unexpected /*member '{a}'.", token, m); |
|
2539 } |
|
2540 if (typeof member[m] === 'number') { |
|
2541 member[m] += 1; |
|
2542 } else { |
|
2543 member[m] = 1; |
|
2544 } |
|
2545 } |
|
2546 |
|
2547 function note_implied(token) { |
|
2548 var name = token.value, line = token.line, a = implied[name]; |
|
2549 if (typeof a === 'function') { |
|
2550 a = false; |
|
2551 } |
|
2552 if (!a) { |
|
2553 a = [line]; |
|
2554 implied[name] = a; |
|
2555 } else if (a[a.length - 1] !== line) { |
|
2556 a.push(line); |
|
2557 } |
|
2558 } |
|
2559 |
|
2560 // CSS parsing. |
|
2561 |
|
2562 |
|
2563 function cssName() { |
|
2564 if (nexttoken.identifier) { |
|
2565 advance(); |
|
2566 return true; |
|
2567 } |
|
2568 } |
|
2569 |
|
2570 function cssNumber() { |
|
2571 if (nexttoken.id === '-') { |
|
2572 advance('-'); |
|
2573 adjacent(); |
|
2574 nolinebreak(); |
|
2575 } |
|
2576 if (nexttoken.type === '(number)') { |
|
2577 advance('(number)'); |
|
2578 return true; |
|
2579 } |
|
2580 } |
|
2581 |
|
2582 function cssString() { |
|
2583 if (nexttoken.type === '(string)') { |
|
2584 advance(); |
|
2585 return true; |
|
2586 } |
|
2587 } |
|
2588 |
|
2589 function cssColor() { |
|
2590 var i, number; |
|
2591 if (nexttoken.identifier) { |
|
2592 if (nexttoken.value === 'rgb') { |
|
2593 advance(); |
|
2594 advance('('); |
|
2595 for (i = 0; i < 3; i += 1) { |
|
2596 number = nexttoken.value; |
|
2597 if (nexttoken.type !== '(number)' || number < 0) { |
|
2598 warning("Expected a positive number and instead saw '{a}'", |
|
2599 nexttoken, number); |
|
2600 advance(); |
|
2601 } else { |
|
2602 advance(); |
|
2603 if (nexttoken.id === '%') { |
|
2604 advance('%'); |
|
2605 if (number > 100) { |
|
2606 warning("Expected a percentage and instead saw '{a}'", |
|
2607 token, number); |
|
2608 } |
|
2609 } else { |
|
2610 if (number > 255) { |
|
2611 warning("Expected a small number and instead saw '{a}'", |
|
2612 token, number); |
|
2613 } |
|
2614 } |
|
2615 } |
|
2616 } |
|
2617 advance(')'); |
|
2618 return true; |
|
2619 } else if (cssColorData[nexttoken.value] === true) { |
|
2620 advance(); |
|
2621 return true; |
|
2622 } |
|
2623 } else if (nexttoken.type === '(color)') { |
|
2624 advance(); |
|
2625 return true; |
|
2626 } |
|
2627 return false; |
|
2628 } |
|
2629 |
|
2630 function cssLength() { |
|
2631 if (nexttoken.id === '-') { |
|
2632 advance('-'); |
|
2633 adjacent(); |
|
2634 nolinebreak(); |
|
2635 } |
|
2636 if (nexttoken.type === '(number)') { |
|
2637 advance(); |
|
2638 if (nexttoken.type !== '(string)' && |
|
2639 cssLengthData[nexttoken.value] === true) { |
|
2640 adjacent(); |
|
2641 advance(); |
|
2642 } else if (+token.value !== 0) { |
|
2643 warning("Expected a linear unit and instead saw '{a}'.", |
|
2644 nexttoken, nexttoken.value); |
|
2645 } |
|
2646 return true; |
|
2647 } |
|
2648 return false; |
|
2649 } |
|
2650 |
|
2651 function cssLineHeight() { |
|
2652 if (nexttoken.id === '-') { |
|
2653 advance('-'); |
|
2654 adjacent(); |
|
2655 } |
|
2656 if (nexttoken.type === '(number)') { |
|
2657 advance(); |
|
2658 if (nexttoken.type !== '(string)' && |
|
2659 cssLengthData[nexttoken.value] === true) { |
|
2660 adjacent(); |
|
2661 advance(); |
|
2662 } |
|
2663 return true; |
|
2664 } |
|
2665 return false; |
|
2666 } |
|
2667 |
|
2668 function cssWidth() { |
|
2669 if (nexttoken.identifier) { |
|
2670 switch (nexttoken.value) { |
|
2671 case 'thin': |
|
2672 case 'medium': |
|
2673 case 'thick': |
|
2674 advance(); |
|
2675 return true; |
|
2676 } |
|
2677 } else { |
|
2678 return cssLength(); |
|
2679 } |
|
2680 } |
|
2681 |
|
2682 function cssMargin() { |
|
2683 if (nexttoken.identifier) { |
|
2684 if (nexttoken.value === 'auto') { |
|
2685 advance(); |
|
2686 return true; |
|
2687 } |
|
2688 } else { |
|
2689 return cssLength(); |
|
2690 } |
|
2691 } |
|
2692 |
|
2693 function cssAttr() { |
|
2694 if (nexttoken.identifier && nexttoken.value === 'attr') { |
|
2695 advance(); |
|
2696 advance('('); |
|
2697 if (!nexttoken.identifier) { |
|
2698 warning("Expected a name and instead saw '{a}'.", |
|
2699 nexttoken, nexttoken.value); |
|
2700 } |
|
2701 advance(); |
|
2702 advance(')'); |
|
2703 return true; |
|
2704 } |
|
2705 return false; |
|
2706 } |
|
2707 |
|
2708 function cssCommaList() { |
|
2709 while (nexttoken.id !== ';') { |
|
2710 if (!cssName() && !cssString()) { |
|
2711 warning("Expected a name and instead saw '{a}'.", |
|
2712 nexttoken, nexttoken.value); |
|
2713 } |
|
2714 if (nexttoken.id !== ',') { |
|
2715 return true; |
|
2716 } |
|
2717 comma(); |
|
2718 } |
|
2719 } |
|
2720 |
|
2721 function cssCounter() { |
|
2722 if (nexttoken.identifier && nexttoken.value === 'counter') { |
|
2723 advance(); |
|
2724 advance('('); |
|
2725 if (!nexttoken.identifier) { |
|
2726 } |
|
2727 advance(); |
|
2728 if (nexttoken.id === ',') { |
|
2729 comma(); |
|
2730 if (nexttoken.type !== '(string)') { |
|
2731 warning("Expected a string and instead saw '{a}'.", |
|
2732 nexttoken, nexttoken.value); |
|
2733 } |
|
2734 advance(); |
|
2735 } |
|
2736 advance(')'); |
|
2737 return true; |
|
2738 } |
|
2739 if (nexttoken.identifier && nexttoken.value === 'counters') { |
|
2740 advance(); |
|
2741 advance('('); |
|
2742 if (!nexttoken.identifier) { |
|
2743 warning("Expected a name and instead saw '{a}'.", |
|
2744 nexttoken, nexttoken.value); |
|
2745 } |
|
2746 advance(); |
|
2747 if (nexttoken.id === ',') { |
|
2748 comma(); |
|
2749 if (nexttoken.type !== '(string)') { |
|
2750 warning("Expected a string and instead saw '{a}'.", |
|
2751 nexttoken, nexttoken.value); |
|
2752 } |
|
2753 advance(); |
|
2754 } |
|
2755 if (nexttoken.id === ',') { |
|
2756 comma(); |
|
2757 if (nexttoken.type !== '(string)') { |
|
2758 warning("Expected a string and instead saw '{a}'.", |
|
2759 nexttoken, nexttoken.value); |
|
2760 } |
|
2761 advance(); |
|
2762 } |
|
2763 advance(')'); |
|
2764 return true; |
|
2765 } |
|
2766 return false; |
|
2767 } |
|
2768 |
|
2769 |
|
2770 function cssShape() { |
|
2771 var i; |
|
2772 if (nexttoken.identifier && nexttoken.value === 'rect') { |
|
2773 advance(); |
|
2774 advance('('); |
|
2775 for (i = 0; i < 4; i += 1) { |
|
2776 if (!cssLength()) { |
|
2777 warning("Expected a number and instead saw '{a}'.", |
|
2778 nexttoken, nexttoken.value); |
|
2779 break; |
|
2780 } |
|
2781 } |
|
2782 advance(')'); |
|
2783 return true; |
|
2784 } |
|
2785 return false; |
|
2786 } |
|
2787 |
|
2788 function cssUrl() { |
|
2789 var c, url; |
|
2790 if (nexttoken.identifier && nexttoken.value === 'url') { |
|
2791 nexttoken = lex.range('(', ')'); |
|
2792 url = nexttoken.value; |
|
2793 c = url.charAt(0); |
|
2794 if (c === '"' || c === '\'') { |
|
2795 if (url.slice(-1) !== c) { |
|
2796 warning("Bad url string."); |
|
2797 } else { |
|
2798 url = url.slice(1, -1); |
|
2799 if (url.indexOf(c) >= 0) { |
|
2800 warning("Bad url string."); |
|
2801 } |
|
2802 } |
|
2803 } |
|
2804 if (!url) { |
|
2805 warning("Missing url."); |
|
2806 } |
|
2807 advance(); |
|
2808 if (option.safe && ux.test(url)) { |
|
2809 error("ADsafe URL violation."); |
|
2810 } |
|
2811 urls.push(url); |
|
2812 return true; |
|
2813 } |
|
2814 return false; |
|
2815 } |
|
2816 |
|
2817 cssAny = [cssUrl, function () { |
|
2818 for (;;) { |
|
2819 if (nexttoken.identifier) { |
|
2820 switch (nexttoken.value.toLowerCase()) { |
|
2821 case 'url': |
|
2822 cssUrl(); |
|
2823 break; |
|
2824 case 'expression': |
|
2825 warning("Unexpected expression '{a}'.", |
|
2826 nexttoken, nexttoken.value); |
|
2827 advance(); |
|
2828 break; |
|
2829 default: |
|
2830 advance(); |
|
2831 } |
|
2832 } else { |
|
2833 if (nexttoken.id === ';' || nexttoken.id === '!' || |
|
2834 nexttoken.id === '(end)' || nexttoken.id === '}') { |
|
2835 return true; |
|
2836 } |
|
2837 advance(); |
|
2838 } |
|
2839 } |
|
2840 }]; |
|
2841 |
|
2842 cssBorderStyle = [ |
|
2843 'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'ridge', |
|
2844 'inset', 'outset' |
|
2845 ]; |
|
2846 |
|
2847 cssBreak = [ |
|
2848 'auto', 'always', 'avoid', 'left', 'right' |
|
2849 ]; |
|
2850 |
|
2851 cssOverflow = [ |
|
2852 'auto', 'hidden', 'scroll', 'visible' |
|
2853 ]; |
|
2854 |
|
2855 cssAttributeData = { |
|
2856 background: [ |
|
2857 true, 'background-attachment', 'background-color', |
|
2858 'background-image', 'background-position', 'background-repeat' |
|
2859 ], |
|
2860 'background-attachment': ['scroll', 'fixed'], |
|
2861 'background-color': ['transparent', cssColor], |
|
2862 'background-image': ['none', cssUrl], |
|
2863 'background-position': [ |
|
2864 2, [cssLength, 'top', 'bottom', 'left', 'right', 'center'] |
|
2865 ], |
|
2866 'background-repeat': [ |
|
2867 'repeat', 'repeat-x', 'repeat-y', 'no-repeat' |
|
2868 ], |
|
2869 'border': [true, 'border-color', 'border-style', 'border-width'], |
|
2870 'border-bottom': [ |
|
2871 true, 'border-bottom-color', 'border-bottom-style', |
|
2872 'border-bottom-width' |
|
2873 ], |
|
2874 'border-bottom-color': cssColor, |
|
2875 'border-bottom-style': cssBorderStyle, |
|
2876 'border-bottom-width': cssWidth, |
|
2877 'border-collapse': ['collapse', 'separate'], |
|
2878 'border-color': ['transparent', 4, cssColor], |
|
2879 'border-left': [ |
|
2880 true, 'border-left-color', 'border-left-style', 'border-left-width' |
|
2881 ], |
|
2882 'border-left-color': cssColor, |
|
2883 'border-left-style': cssBorderStyle, |
|
2884 'border-left-width': cssWidth, |
|
2885 'border-right': [ |
|
2886 true, 'border-right-color', 'border-right-style', |
|
2887 'border-right-width' |
|
2888 ], |
|
2889 'border-right-color': cssColor, |
|
2890 'border-right-style': cssBorderStyle, |
|
2891 'border-right-width': cssWidth, |
|
2892 'border-spacing': [2, cssLength], |
|
2893 'border-style': [4, cssBorderStyle], |
|
2894 'border-top': [ |
|
2895 true, 'border-top-color', 'border-top-style', 'border-top-width' |
|
2896 ], |
|
2897 'border-top-color': cssColor, |
|
2898 'border-top-style': cssBorderStyle, |
|
2899 'border-top-width': cssWidth, |
|
2900 'border-width': [4, cssWidth], |
|
2901 bottom: [cssLength, 'auto'], |
|
2902 'caption-side' : ['bottom', 'left', 'right', 'top'], |
|
2903 clear: ['both', 'left', 'none', 'right'], |
|
2904 clip: [cssShape, 'auto'], |
|
2905 color: cssColor, |
|
2906 content: [ |
|
2907 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote', |
|
2908 cssString, cssUrl, cssCounter, cssAttr |
|
2909 ], |
|
2910 'counter-increment': [ |
|
2911 cssName, 'none' |
|
2912 ], |
|
2913 'counter-reset': [ |
|
2914 cssName, 'none' |
|
2915 ], |
|
2916 cursor: [ |
|
2917 cssUrl, 'auto', 'crosshair', 'default', 'e-resize', 'help', 'move', |
|
2918 'n-resize', 'ne-resize', 'nw-resize', 'pointer', 's-resize', |
|
2919 'se-resize', 'sw-resize', 'w-resize', 'text', 'wait' |
|
2920 ], |
|
2921 direction: ['ltr', 'rtl'], |
|
2922 display: [ |
|
2923 'block', 'compact', 'inline', 'inline-block', 'inline-table', |
|
2924 'list-item', 'marker', 'none', 'run-in', 'table', 'table-caption', |
|
2925 'table-cell', 'table-column', 'table-column-group', |
|
2926 'table-footer-group', 'table-header-group', 'table-row', |
|
2927 'table-row-group' |
|
2928 ], |
|
2929 'empty-cells': ['show', 'hide'], |
|
2930 'float': ['left', 'none', 'right'], |
|
2931 font: [ |
|
2932 'caption', 'icon', 'menu', 'message-box', 'small-caption', |
|
2933 'status-bar', true, 'font-size', 'font-style', 'font-weight', |
|
2934 'font-family' |
|
2935 ], |
|
2936 'font-family': cssCommaList, |
|
2937 'font-size': [ |
|
2938 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', |
|
2939 'xx-large', 'larger', 'smaller', cssLength |
|
2940 ], |
|
2941 'font-size-adjust': ['none', cssNumber], |
|
2942 'font-stretch': [ |
|
2943 'normal', 'wider', 'narrower', 'ultra-condensed', |
|
2944 'extra-condensed', 'condensed', 'semi-condensed', |
|
2945 'semi-expanded', 'expanded', 'extra-expanded' |
|
2946 ], |
|
2947 'font-style': [ |
|
2948 'normal', 'italic', 'oblique' |
|
2949 ], |
|
2950 'font-variant': [ |
|
2951 'normal', 'small-caps' |
|
2952 ], |
|
2953 'font-weight': [ |
|
2954 'normal', 'bold', 'bolder', 'lighter', cssNumber |
|
2955 ], |
|
2956 height: [cssLength, 'auto'], |
|
2957 left: [cssLength, 'auto'], |
|
2958 'letter-spacing': ['normal', cssLength], |
|
2959 'line-height': ['normal', cssLineHeight], |
|
2960 'list-style': [ |
|
2961 true, 'list-style-image', 'list-style-position', 'list-style-type' |
|
2962 ], |
|
2963 'list-style-image': ['none', cssUrl], |
|
2964 'list-style-position': ['inside', 'outside'], |
|
2965 'list-style-type': [ |
|
2966 'circle', 'disc', 'square', 'decimal', 'decimal-leading-zero', |
|
2967 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha', |
|
2968 'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'katakana', |
|
2969 'hiragana-iroha', 'katakana-oroha', 'none' |
|
2970 ], |
|
2971 margin: [4, cssMargin], |
|
2972 'margin-bottom': cssMargin, |
|
2973 'margin-left': cssMargin, |
|
2974 'margin-right': cssMargin, |
|
2975 'margin-top': cssMargin, |
|
2976 'marker-offset': [cssLength, 'auto'], |
|
2977 'max-height': [cssLength, 'none'], |
|
2978 'max-width': [cssLength, 'none'], |
|
2979 'min-height': cssLength, |
|
2980 'min-width': cssLength, |
|
2981 opacity: cssNumber, |
|
2982 outline: [true, 'outline-color', 'outline-style', 'outline-width'], |
|
2983 'outline-color': ['invert', cssColor], |
|
2984 'outline-style': [ |
|
2985 'dashed', 'dotted', 'double', 'groove', 'inset', 'none', |
|
2986 'outset', 'ridge', 'solid' |
|
2987 ], |
|
2988 'outline-width': cssWidth, |
|
2989 overflow: cssOverflow, |
|
2990 'overflow-x': cssOverflow, |
|
2991 'overflow-y': cssOverflow, |
|
2992 padding: [4, cssLength], |
|
2993 'padding-bottom': cssLength, |
|
2994 'padding-left': cssLength, |
|
2995 'padding-right': cssLength, |
|
2996 'padding-top': cssLength, |
|
2997 'page-break-after': cssBreak, |
|
2998 'page-break-before': cssBreak, |
|
2999 position: ['absolute', 'fixed', 'relative', 'static'], |
|
3000 quotes: [8, cssString], |
|
3001 right: [cssLength, 'auto'], |
|
3002 'table-layout': ['auto', 'fixed'], |
|
3003 'text-align': ['center', 'justify', 'left', 'right'], |
|
3004 'text-decoration': [ |
|
3005 'none', 'underline', 'overline', 'line-through', 'blink' |
|
3006 ], |
|
3007 'text-indent': cssLength, |
|
3008 'text-shadow': ['none', 4, [cssColor, cssLength]], |
|
3009 'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'], |
|
3010 top: [cssLength, 'auto'], |
|
3011 'unicode-bidi': ['normal', 'embed', 'bidi-override'], |
|
3012 'vertical-align': [ |
|
3013 'baseline', 'bottom', 'sub', 'super', 'top', 'text-top', 'middle', |
|
3014 'text-bottom', cssLength |
|
3015 ], |
|
3016 visibility: ['visible', 'hidden', 'collapse'], |
|
3017 'white-space': [ |
|
3018 'normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'inherit' |
|
3019 ], |
|
3020 width: [cssLength, 'auto'], |
|
3021 'word-spacing': ['normal', cssLength], |
|
3022 'word-wrap': ['break-word', 'normal'], |
|
3023 'z-index': ['auto', cssNumber] |
|
3024 }; |
|
3025 |
|
3026 function styleAttribute() { |
|
3027 var v; |
|
3028 while (nexttoken.id === '*' || nexttoken.id === '#' || |
|
3029 nexttoken.value === '_') { |
|
3030 if (!option.css) { |
|
3031 warning("Unexpected '{a}'.", nexttoken, nexttoken.value); |
|
3032 } |
|
3033 advance(); |
|
3034 } |
|
3035 if (nexttoken.id === '-') { |
|
3036 if (!option.css) { |
|
3037 warning("Unexpected '{a}'.", nexttoken, nexttoken.value); |
|
3038 } |
|
3039 advance('-'); |
|
3040 if (!nexttoken.identifier) { |
|
3041 warning( |
|
3042 "Expected a non-standard style attribute and instead saw '{a}'.", |
|
3043 nexttoken, nexttoken.value); |
|
3044 } |
|
3045 advance(); |
|
3046 return cssAny; |
|
3047 } else { |
|
3048 if (!nexttoken.identifier) { |
|
3049 warning("Excepted a style attribute, and instead saw '{a}'.", |
|
3050 nexttoken, nexttoken.value); |
|
3051 } else { |
|
3052 if (is_own(cssAttributeData, nexttoken.value)) { |
|
3053 v = cssAttributeData[nexttoken.value]; |
|
3054 } else { |
|
3055 v = cssAny; |
|
3056 if (!option.css) { |
|
3057 warning("Unrecognized style attribute '{a}'.", |
|
3058 nexttoken, nexttoken.value); |
|
3059 } |
|
3060 } |
|
3061 } |
|
3062 advance(); |
|
3063 return v; |
|
3064 } |
|
3065 } |
|
3066 |
|
3067 function styleValue(v) { |
|
3068 var i = 0, |
|
3069 n, |
|
3070 once, |
|
3071 match, |
|
3072 round, |
|
3073 start = 0, |
|
3074 vi; |
|
3075 switch (typeof v) { |
|
3076 case 'function': |
|
3077 return v(); |
|
3078 case 'string': |
|
3079 if (nexttoken.identifier && nexttoken.value === v) { |
|
3080 advance(); |
|
3081 return true; |
|
3082 } |
|
3083 return false; |
|
3084 } |
|
3085 for (;;) { |
|
3086 if (i >= v.length) { |
|
3087 return false; |
|
3088 } |
|
3089 vi = v[i]; |
|
3090 i += 1; |
|
3091 if (vi === true) { |
|
3092 break; |
|
3093 } else if (typeof vi === 'number') { |
|
3094 n = vi; |
|
3095 vi = v[i]; |
|
3096 i += 1; |
|
3097 } else { |
|
3098 n = 1; |
|
3099 } |
|
3100 match = false; |
|
3101 while (n > 0) { |
|
3102 if (styleValue(vi)) { |
|
3103 match = true; |
|
3104 n -= 1; |
|
3105 } else { |
|
3106 break; |
|
3107 } |
|
3108 } |
|
3109 if (match) { |
|
3110 return true; |
|
3111 } |
|
3112 } |
|
3113 start = i; |
|
3114 once = []; |
|
3115 for (;;) { |
|
3116 round = false; |
|
3117 for (i = start; i < v.length; i += 1) { |
|
3118 if (!once[i]) { |
|
3119 if (styleValue(cssAttributeData[v[i]])) { |
|
3120 match = true; |
|
3121 round = true; |
|
3122 once[i] = true; |
|
3123 break; |
|
3124 } |
|
3125 } |
|
3126 } |
|
3127 if (!round) { |
|
3128 return match; |
|
3129 } |
|
3130 } |
|
3131 } |
|
3132 |
|
3133 function styleChild() { |
|
3134 if (nexttoken.id === '(number)') { |
|
3135 advance(); |
|
3136 if (nexttoken.value === 'n' && nexttoken.identifier) { |
|
3137 adjacent(); |
|
3138 advance(); |
|
3139 if (nexttoken.id === '+') { |
|
3140 adjacent(); |
|
3141 advance('+'); |
|
3142 adjacent(); |
|
3143 advance('(number)'); |
|
3144 } |
|
3145 } |
|
3146 return; |
|
3147 } else { |
|
3148 switch (nexttoken.value) { |
|
3149 case 'odd': |
|
3150 case 'even': |
|
3151 if (nexttoken.identifier) { |
|
3152 advance(); |
|
3153 return; |
|
3154 } |
|
3155 } |
|
3156 } |
|
3157 warning("Unexpected token '{a}'.", nexttoken, nexttoken.value); |
|
3158 } |
|
3159 |
|
3160 function substyle() { |
|
3161 var v; |
|
3162 for (;;) { |
|
3163 if (nexttoken.id === '}' || nexttoken.id === '(end)' || |
|
3164 xquote && nexttoken.id === xquote) { |
|
3165 return; |
|
3166 } |
|
3167 while (nexttoken.id === ';') { |
|
3168 warning("Misplaced ';'."); |
|
3169 advance(';'); |
|
3170 } |
|
3171 v = styleAttribute(); |
|
3172 advance(':'); |
|
3173 if (nexttoken.identifier && nexttoken.value === 'inherit') { |
|
3174 advance(); |
|
3175 } else { |
|
3176 if (!styleValue(v)) { |
|
3177 warning("Unexpected token '{a}'.", nexttoken, |
|
3178 nexttoken.value); |
|
3179 advance(); |
|
3180 } |
|
3181 } |
|
3182 if (nexttoken.id === '!') { |
|
3183 advance('!'); |
|
3184 adjacent(); |
|
3185 if (nexttoken.identifier && nexttoken.value === 'important') { |
|
3186 advance(); |
|
3187 } else { |
|
3188 warning("Expected '{a}' and instead saw '{b}'.", |
|
3189 nexttoken, 'important', nexttoken.value); |
|
3190 } |
|
3191 } |
|
3192 if (nexttoken.id === '}' || nexttoken.id === xquote) { |
|
3193 warning("Missing '{a}'.", nexttoken, ';'); |
|
3194 } else { |
|
3195 advance(';'); |
|
3196 } |
|
3197 } |
|
3198 } |
|
3199 |
|
3200 function styleSelector() { |
|
3201 if (nexttoken.identifier) { |
|
3202 if (!is_own(htmltag, nexttoken.value)) { |
|
3203 warning("Expected a tagName, and instead saw {a}.", |
|
3204 nexttoken, nexttoken.value); |
|
3205 } |
|
3206 advance(); |
|
3207 } else { |
|
3208 switch (nexttoken.id) { |
|
3209 case '>': |
|
3210 case '+': |
|
3211 advance(); |
|
3212 styleSelector(); |
|
3213 break; |
|
3214 case ':': |
|
3215 advance(':'); |
|
3216 switch (nexttoken.value) { |
|
3217 case 'active': |
|
3218 case 'after': |
|
3219 case 'before': |
|
3220 case 'checked': |
|
3221 case 'disabled': |
|
3222 case 'empty': |
|
3223 case 'enabled': |
|
3224 case 'first-child': |
|
3225 case 'first-letter': |
|
3226 case 'first-line': |
|
3227 case 'first-of-type': |
|
3228 case 'focus ': |
|
3229 case 'hover': |
|
3230 case 'last-of-type': |
|
3231 case 'link': |
|
3232 case 'only-of-type': |
|
3233 case 'root': |
|
3234 case 'target': |
|
3235 case 'visited': |
|
3236 advance(); |
|
3237 break; |
|
3238 case 'lang': |
|
3239 advance(); |
|
3240 advance('('); |
|
3241 if (!nexttoken.identifier) { |
|
3242 warning("Expected a lang code, and instead saw :{a}.", |
|
3243 nexttoken, nexttoken.value); |
|
3244 } |
|
3245 advance(')'); |
|
3246 break; |
|
3247 case 'nth-child': |
|
3248 case 'nth-last-child': |
|
3249 case 'nth-last-of-type': |
|
3250 case 'nth-of-type': |
|
3251 advance(); |
|
3252 advance('('); |
|
3253 styleChild(); |
|
3254 advance(')'); |
|
3255 break; |
|
3256 case 'not': |
|
3257 advance(); |
|
3258 advance('('); |
|
3259 if (nexttoken.id === ':' && peek(0).value === 'not') { |
|
3260 warning("Nested not."); |
|
3261 } |
|
3262 styleSelector(); |
|
3263 advance(')'); |
|
3264 break; |
|
3265 default: |
|
3266 warning("Expected a pseudo, and instead saw :{a}.", |
|
3267 nexttoken, nexttoken.value); |
|
3268 } |
|
3269 break; |
|
3270 case '#': |
|
3271 advance('#'); |
|
3272 if (!nexttoken.identifier) { |
|
3273 warning("Expected an id, and instead saw #{a}.", |
|
3274 nexttoken, nexttoken.value); |
|
3275 } |
|
3276 advance(); |
|
3277 break; |
|
3278 case '*': |
|
3279 advance('*'); |
|
3280 break; |
|
3281 case '.': |
|
3282 advance('.'); |
|
3283 if (!nexttoken.identifier) { |
|
3284 warning("Expected a class, and instead saw #.{a}.", |
|
3285 nexttoken, nexttoken.value); |
|
3286 } |
|
3287 advance(); |
|
3288 break; |
|
3289 case '[': |
|
3290 advance('['); |
|
3291 if (!nexttoken.identifier) { |
|
3292 warning("Expected an attribute, and instead saw [{a}].", |
|
3293 nexttoken, nexttoken.value); |
|
3294 } |
|
3295 advance(); |
|
3296 if (nexttoken.id === '=' || nexttoken.value === '~=' || |
|
3297 nexttoken.value === '$=' || |
|
3298 nexttoken.value === '|=' || |
|
3299 nexttoken.id === '*=' || |
|
3300 nexttoken.id === '^=') { |
|
3301 advance(); |
|
3302 if (nexttoken.type !== '(string)') { |
|
3303 warning("Expected a string, and instead saw {a}.", |
|
3304 nexttoken, nexttoken.value); |
|
3305 } |
|
3306 advance(); |
|
3307 } |
|
3308 advance(']'); |
|
3309 break; |
|
3310 default: |
|
3311 error("Expected a CSS selector, and instead saw {a}.", |
|
3312 nexttoken, nexttoken.value); |
|
3313 } |
|
3314 } |
|
3315 } |
|
3316 |
|
3317 function stylePattern() { |
|
3318 var name; |
|
3319 if (nexttoken.id === '{') { |
|
3320 warning("Expected a style pattern, and instead saw '{a}'.", nexttoken, |
|
3321 nexttoken.id); |
|
3322 } else if (nexttoken.id === '@') { |
|
3323 advance('@'); |
|
3324 name = nexttoken.value; |
|
3325 if (nexttoken.identifier && atrule[name] === true) { |
|
3326 advance(); |
|
3327 return name; |
|
3328 } |
|
3329 warning("Expected an at-rule, and instead saw @{a}.", nexttoken, name); |
|
3330 } |
|
3331 for (;;) { |
|
3332 styleSelector(); |
|
3333 if (nexttoken.id === '</' || nexttoken.id === '{' || |
|
3334 nexttoken.id === '(end)') { |
|
3335 return ''; |
|
3336 } |
|
3337 if (nexttoken.id === ',') { |
|
3338 comma(); |
|
3339 } |
|
3340 } |
|
3341 } |
|
3342 |
|
3343 function styles() { |
|
3344 var i; |
|
3345 while (nexttoken.id === '@') { |
|
3346 i = peek(); |
|
3347 if (i.identifier && i.value === 'import') { |
|
3348 advance('@'); |
|
3349 advance(); |
|
3350 if (!cssUrl()) { |
|
3351 warning("Expected '{a}' and instead saw '{b}'.", nexttoken, |
|
3352 'url', nexttoken.value); |
|
3353 advance(); |
|
3354 } |
|
3355 advance(';'); |
|
3356 } else { |
|
3357 break; |
|
3358 } |
|
3359 } |
|
3360 while (nexttoken.id !== '</' && nexttoken.id !== '(end)') { |
|
3361 stylePattern(); |
|
3362 xmode = 'styleproperty'; |
|
3363 if (nexttoken.id === ';') { |
|
3364 advance(';'); |
|
3365 } else { |
|
3366 advance('{'); |
|
3367 substyle(); |
|
3368 xmode = 'style'; |
|
3369 advance('}'); |
|
3370 } |
|
3371 } |
|
3372 } |
|
3373 |
|
3374 |
|
3375 // HTML parsing. |
|
3376 |
|
3377 function doBegin(n) { |
|
3378 if (n !== 'html' && !option.fragment) { |
|
3379 if (n === 'div' && option.adsafe) { |
|
3380 error("ADSAFE: Use the fragment option."); |
|
3381 } else { |
|
3382 error("Expected '{a}' and instead saw '{b}'.", |
|
3383 token, 'html', n); |
|
3384 } |
|
3385 } |
|
3386 if (option.adsafe) { |
|
3387 if (n === 'html') { |
|
3388 error( |
|
3389 "Currently, ADsafe does not operate on whole HTML documents. It operates on <div> fragments and .js files.", token); |
|
3390 } |
|
3391 if (option.fragment) { |
|
3392 if (n !== 'div') { |
|
3393 error("ADsafe violation: Wrap the widget in a div.", token); |
|
3394 } |
|
3395 } else { |
|
3396 error("Use the fragment option.", token); |
|
3397 } |
|
3398 } |
|
3399 option.browser = true; |
|
3400 assume(); |
|
3401 } |
|
3402 |
|
3403 function doAttribute(n, a, v) { |
|
3404 var u, x; |
|
3405 if (a === 'id') { |
|
3406 u = typeof v === 'string' ? v.toUpperCase() : ''; |
|
3407 if (ids[u] === true) { |
|
3408 warning("Duplicate id='{a}'.", nexttoken, v); |
|
3409 } |
|
3410 if (option.adsafe) { |
|
3411 if (adsafe_id) { |
|
3412 if (v.slice(0, adsafe_id.length) !== adsafe_id) { |
|
3413 warning("ADsafe violation: An id must have a '{a}' prefix", |
|
3414 nexttoken, adsafe_id); |
|
3415 } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) { |
|
3416 warning("ADSAFE violation: bad id."); |
|
3417 } |
|
3418 } else { |
|
3419 adsafe_id = v; |
|
3420 if (!/^[A-Z]+_$/.test(v)) { |
|
3421 warning("ADSAFE violation: bad id."); |
|
3422 } |
|
3423 } |
|
3424 } |
|
3425 x = v.search(dx); |
|
3426 if (x >= 0) { |
|
3427 warning("Unexpected character '{a}' in {b}.", token, v.charAt(x), a); |
|
3428 } |
|
3429 ids[u] = true; |
|
3430 } else if (a === 'class' || a === 'type' || a === 'name') { |
|
3431 x = v.search(qx); |
|
3432 if (x >= 0) { |
|
3433 warning("Unexpected character '{a}' in {b}.", token, v.charAt(x), a); |
|
3434 } |
|
3435 ids[u] = true; |
|
3436 } else if (a === 'href' || a === 'background' || |
|
3437 a === 'content' || a === 'data' || |
|
3438 a.indexOf('src') >= 0 || a.indexOf('url') >= 0) { |
|
3439 if (option.safe && ux.test(v)) { |
|
3440 error("ADsafe URL violation."); |
|
3441 } |
|
3442 urls.push(v); |
|
3443 } else if (a === 'for') { |
|
3444 if (option.adsafe) { |
|
3445 if (adsafe_id) { |
|
3446 if (v.slice(0, adsafe_id.length) !== adsafe_id) { |
|
3447 warning("ADsafe violation: An id must have a '{a}' prefix", |
|
3448 nexttoken, adsafe_id); |
|
3449 } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) { |
|
3450 warning("ADSAFE violation: bad id."); |
|
3451 } |
|
3452 } else { |
|
3453 warning("ADSAFE violation: bad id."); |
|
3454 } |
|
3455 } |
|
3456 } else if (a === 'name') { |
|
3457 if (option.adsafe && v.indexOf('_') >= 0) { |
|
3458 warning("ADsafe name violation."); |
|
3459 } |
|
3460 } |
|
3461 } |
|
3462 |
|
3463 function doTag(n, a) { |
|
3464 var i, t = htmltag[n], x; |
|
3465 src = false; |
|
3466 if (!t) { |
|
3467 error("Unrecognized tag '<{a}>'.", |
|
3468 nexttoken, |
|
3469 n === n.toLowerCase() ? n : |
|
3470 n + ' (capitalization error)'); |
|
3471 } |
|
3472 if (stack.length > 0) { |
|
3473 if (n === 'html') { |
|
3474 error("Too many <html> tags.", token); |
|
3475 } |
|
3476 x = t.parent; |
|
3477 if (x) { |
|
3478 if (x.indexOf(' ' + stack[stack.length - 1].name + ' ') < 0) { |
|
3479 error("A '<{a}>' must be within '<{b}>'.", |
|
3480 token, n, x); |
|
3481 } |
|
3482 } else if (!option.adsafe && !option.fragment) { |
|
3483 i = stack.length; |
|
3484 do { |
|
3485 if (i <= 0) { |
|
3486 error("A '<{a}>' must be within '<{b}>'.", |
|
3487 token, n, 'body'); |
|
3488 } |
|
3489 i -= 1; |
|
3490 } while (stack[i].name !== 'body'); |
|
3491 } |
|
3492 } |
|
3493 switch (n) { |
|
3494 case 'div': |
|
3495 if (option.adsafe && stack.length === 1 && !adsafe_id) { |
|
3496 warning("ADSAFE violation: missing ID_."); |
|
3497 } |
|
3498 break; |
|
3499 case 'script': |
|
3500 xmode = 'script'; |
|
3501 advance('>'); |
|
3502 indent = nexttoken.from; |
|
3503 if (a.lang) { |
|
3504 warning("lang is deprecated.", token); |
|
3505 } |
|
3506 if (option.adsafe && stack.length !== 1) { |
|
3507 warning("ADsafe script placement violation.", token); |
|
3508 } |
|
3509 if (a.src) { |
|
3510 if (option.adsafe && (!adsafe_may || !approved[a.src])) { |
|
3511 warning("ADsafe unapproved script source.", token); |
|
3512 } |
|
3513 if (a.type) { |
|
3514 warning("type is unnecessary.", token); |
|
3515 } |
|
3516 } else { |
|
3517 if (adsafe_went) { |
|
3518 error("ADsafe script violation.", token); |
|
3519 } |
|
3520 statements('script'); |
|
3521 } |
|
3522 xmode = 'html'; |
|
3523 advance('</'); |
|
3524 if (!nexttoken.identifier && nexttoken.value !== 'script') { |
|
3525 warning("Expected '{a}' and instead saw '{b}'.", |
|
3526 nexttoken, 'script', nexttoken.value); |
|
3527 } |
|
3528 advance(); |
|
3529 xmode = 'outer'; |
|
3530 break; |
|
3531 case 'style': |
|
3532 xmode = 'style'; |
|
3533 advance('>'); |
|
3534 styles(); |
|
3535 xmode = 'html'; |
|
3536 advance('</'); |
|
3537 if (!nexttoken.identifier && nexttoken.value !== 'style') { |
|
3538 warning("Expected '{a}' and instead saw '{b}'.", |
|
3539 nexttoken, 'style', nexttoken.value); |
|
3540 } |
|
3541 advance(); |
|
3542 xmode = 'outer'; |
|
3543 break; |
|
3544 case 'input': |
|
3545 switch (a.type) { |
|
3546 case 'radio': |
|
3547 case 'checkbox': |
|
3548 case 'button': |
|
3549 case 'reset': |
|
3550 case 'submit': |
|
3551 break; |
|
3552 case 'text': |
|
3553 case 'file': |
|
3554 case 'password': |
|
3555 case 'file': |
|
3556 case 'hidden': |
|
3557 case 'image': |
|
3558 if (option.adsafe && a.autocomplete !== 'off') { |
|
3559 warning("ADsafe autocomplete violation."); |
|
3560 } |
|
3561 break; |
|
3562 default: |
|
3563 warning("Bad input type."); |
|
3564 } |
|
3565 break; |
|
3566 case 'applet': |
|
3567 case 'body': |
|
3568 case 'embed': |
|
3569 case 'frame': |
|
3570 case 'frameset': |
|
3571 case 'head': |
|
3572 case 'iframe': |
|
3573 case 'noembed': |
|
3574 case 'noframes': |
|
3575 case 'object': |
|
3576 case 'param': |
|
3577 if (option.adsafe) { |
|
3578 warning("ADsafe violation: Disallowed tag: " + n); |
|
3579 } |
|
3580 break; |
|
3581 } |
|
3582 } |
|
3583 |
|
3584 |
|
3585 function closetag(n) { |
|
3586 return '</' + n + '>'; |
|
3587 } |
|
3588 |
|
3589 function html() { |
|
3590 var a, attributes, e, n, q, t, v, w = option.white, wmode; |
|
3591 xmode = 'html'; |
|
3592 xquote = ''; |
|
3593 stack = null; |
|
3594 for (;;) { |
|
3595 switch (nexttoken.value) { |
|
3596 case '<': |
|
3597 xmode = 'html'; |
|
3598 advance('<'); |
|
3599 attributes = {}; |
|
3600 t = nexttoken; |
|
3601 if (!t.identifier) { |
|
3602 warning("Bad identifier {a}.", t, t.value); |
|
3603 } |
|
3604 n = t.value; |
|
3605 if (option.cap) { |
|
3606 n = n.toLowerCase(); |
|
3607 } |
|
3608 t.name = n; |
|
3609 advance(); |
|
3610 if (!stack) { |
|
3611 stack = []; |
|
3612 doBegin(n); |
|
3613 } |
|
3614 v = htmltag[n]; |
|
3615 if (typeof v !== 'object') { |
|
3616 error("Unrecognized tag '<{a}>'.", t, n); |
|
3617 } |
|
3618 e = v.empty; |
|
3619 t.type = n; |
|
3620 for (;;) { |
|
3621 if (nexttoken.id === '/') { |
|
3622 advance('/'); |
|
3623 if (nexttoken.id !== '>') { |
|
3624 warning("Expected '{a}' and instead saw '{b}'.", |
|
3625 nexttoken, '>', nexttoken.value); |
|
3626 } |
|
3627 break; |
|
3628 } |
|
3629 if (nexttoken.id && nexttoken.id.substr(0, 1) === '>') { |
|
3630 break; |
|
3631 } |
|
3632 if (!nexttoken.identifier) { |
|
3633 if (nexttoken.id === '(end)' || nexttoken.id === '(error)') { |
|
3634 error("Missing '>'.", nexttoken); |
|
3635 } |
|
3636 warning("Bad identifier."); |
|
3637 } |
|
3638 option.white = true; |
|
3639 nonadjacent(token, nexttoken); |
|
3640 a = nexttoken.value; |
|
3641 option.white = w; |
|
3642 advance(); |
|
3643 if (!option.cap && a !== a.toLowerCase()) { |
|
3644 warning("Attribute '{a}' not all lower case.", nexttoken, a); |
|
3645 } |
|
3646 a = a.toLowerCase(); |
|
3647 xquote = ''; |
|
3648 if (is_own(attributes, a)) { |
|
3649 warning("Attribute '{a}' repeated.", nexttoken, a); |
|
3650 } |
|
3651 if (a.slice(0, 2) === 'on') { |
|
3652 if (!option.on) { |
|
3653 warning("Avoid HTML event handlers."); |
|
3654 } |
|
3655 xmode = 'scriptstring'; |
|
3656 advance('='); |
|
3657 q = nexttoken.id; |
|
3658 if (q !== '"' && q !== "'") { |
|
3659 error("Missing quote."); |
|
3660 } |
|
3661 xquote = q; |
|
3662 wmode = option.white; |
|
3663 option.white = false; |
|
3664 advance(q); |
|
3665 statements('on'); |
|
3666 option.white = wmode; |
|
3667 if (nexttoken.id !== q) { |
|
3668 error("Missing close quote on script attribute."); |
|
3669 } |
|
3670 xmode = 'html'; |
|
3671 xquote = ''; |
|
3672 advance(q); |
|
3673 v = false; |
|
3674 } else if (a === 'style') { |
|
3675 xmode = 'scriptstring'; |
|
3676 advance('='); |
|
3677 q = nexttoken.id; |
|
3678 if (q !== '"' && q !== "'") { |
|
3679 error("Missing quote."); |
|
3680 } |
|
3681 xmode = 'styleproperty'; |
|
3682 xquote = q; |
|
3683 advance(q); |
|
3684 substyle(); |
|
3685 xmode = 'html'; |
|
3686 xquote = ''; |
|
3687 advance(q); |
|
3688 v = false; |
|
3689 } else { |
|
3690 if (nexttoken.id === '=') { |
|
3691 advance('='); |
|
3692 v = nexttoken.value; |
|
3693 if (!nexttoken.identifier && |
|
3694 nexttoken.id !== '"' && |
|
3695 nexttoken.id !== '\'' && |
|
3696 nexttoken.type !== '(string)' && |
|
3697 nexttoken.type !== '(number)' && |
|
3698 nexttoken.type !== '(color)') { |
|
3699 warning("Expected an attribute value and instead saw '{a}'.", token, a); |
|
3700 } |
|
3701 advance(); |
|
3702 } else { |
|
3703 v = true; |
|
3704 } |
|
3705 } |
|
3706 attributes[a] = v; |
|
3707 doAttribute(n, a, v); |
|
3708 } |
|
3709 doTag(n, attributes); |
|
3710 if (!e) { |
|
3711 stack.push(t); |
|
3712 } |
|
3713 xmode = 'outer'; |
|
3714 advance('>'); |
|
3715 break; |
|
3716 case '</': |
|
3717 xmode = 'html'; |
|
3718 advance('</'); |
|
3719 if (!nexttoken.identifier) { |
|
3720 warning("Bad identifier."); |
|
3721 } |
|
3722 n = nexttoken.value; |
|
3723 if (option.cap) { |
|
3724 n = n.toLowerCase(); |
|
3725 } |
|
3726 advance(); |
|
3727 if (!stack) { |
|
3728 error("Unexpected '{a}'.", nexttoken, closetag(n)); |
|
3729 } |
|
3730 t = stack.pop(); |
|
3731 if (!t) { |
|
3732 error("Unexpected '{a}'.", nexttoken, closetag(n)); |
|
3733 } |
|
3734 if (t.name !== n) { |
|
3735 error("Expected '{a}' and instead saw '{b}'.", |
|
3736 nexttoken, closetag(t.name), closetag(n)); |
|
3737 } |
|
3738 if (nexttoken.id !== '>') { |
|
3739 error("Missing '{a}'.", nexttoken, '>'); |
|
3740 } |
|
3741 xmode = 'outer'; |
|
3742 advance('>'); |
|
3743 break; |
|
3744 case '<!': |
|
3745 if (option.safe) { |
|
3746 warning("ADsafe HTML violation."); |
|
3747 } |
|
3748 xmode = 'html'; |
|
3749 for (;;) { |
|
3750 advance(); |
|
3751 if (nexttoken.id === '>' || nexttoken.id === '(end)') { |
|
3752 break; |
|
3753 } |
|
3754 if (nexttoken.value.indexOf('--') >= 0) { |
|
3755 warning("Unexpected --."); |
|
3756 } |
|
3757 if (nexttoken.value.indexOf('<') >= 0) { |
|
3758 warning("Unexpected <."); |
|
3759 } |
|
3760 if (nexttoken.value.indexOf('>') >= 0) { |
|
3761 warning("Unexpected >."); |
|
3762 } |
|
3763 } |
|
3764 xmode = 'outer'; |
|
3765 advance('>'); |
|
3766 break; |
|
3767 case '(end)': |
|
3768 return; |
|
3769 default: |
|
3770 if (nexttoken.id === '(end)') { |
|
3771 error("Missing '{a}'.", nexttoken, |
|
3772 '</' + stack[stack.length - 1].value + '>'); |
|
3773 } else { |
|
3774 advance(); |
|
3775 } |
|
3776 } |
|
3777 if (stack && stack.length === 0 && (option.adsafe || |
|
3778 !option.fragment || nexttoken.id === '(end)')) { |
|
3779 break; |
|
3780 } |
|
3781 } |
|
3782 if (nexttoken.id !== '(end)') { |
|
3783 error("Unexpected material after the end."); |
|
3784 } |
|
3785 } |
|
3786 |
|
3787 |
|
3788 // Build the syntax table by declaring the syntactic elements of the language. |
|
3789 |
|
3790 type('(number)', idValue); |
|
3791 type('(string)', idValue); |
|
3792 |
|
3793 syntax['(identifier)'] = { |
|
3794 type: '(identifier)', |
|
3795 lbp: 0, |
|
3796 identifier: true, |
|
3797 nud: function () { |
|
3798 var v = this.value, |
|
3799 s = scope[v], |
|
3800 f; |
|
3801 if (typeof s === 'function') { |
|
3802 s = undefined; |
|
3803 } else if (typeof s === 'boolean') { |
|
3804 f = funct; |
|
3805 funct = functions[0]; |
|
3806 addlabel(v, 'var'); |
|
3807 s = funct; |
|
3808 funct = f; |
|
3809 } |
|
3810 |
|
3811 // The name is in scope and defined in the current function. |
|
3812 |
|
3813 if (funct === s) { |
|
3814 |
|
3815 // Change 'unused' to 'var', and reject labels. |
|
3816 |
|
3817 switch (funct[v]) { |
|
3818 case 'unused': |
|
3819 funct[v] = 'var'; |
|
3820 break; |
|
3821 case 'label': |
|
3822 warning("'{a}' is a statement label.", token, v); |
|
3823 break; |
|
3824 } |
|
3825 |
|
3826 // The name is not defined in the function. If we are in the global scope, |
|
3827 // then we have an undefined variable. |
|
3828 |
|
3829 } else if (funct['(global)']) { |
|
3830 if (option.undef && predefined[v] !== 'boolean') { |
|
3831 warning("'{a}' is not defined.", token, v); |
|
3832 } |
|
3833 note_implied(token); |
|
3834 |
|
3835 // If the name is already defined in the current |
|
3836 // function, but not as outer, then there is a scope error. |
|
3837 |
|
3838 } else { |
|
3839 switch (funct[v]) { |
|
3840 case 'closure': |
|
3841 case 'function': |
|
3842 case 'var': |
|
3843 case 'unused': |
|
3844 warning("'{a}' used out of scope.", token, v); |
|
3845 break; |
|
3846 case 'label': |
|
3847 warning("'{a}' is a statement label.", token, v); |
|
3848 break; |
|
3849 case 'outer': |
|
3850 case 'global': |
|
3851 break; |
|
3852 default: |
|
3853 |
|
3854 // If the name is defined in an outer function, make an outer entry, and if |
|
3855 // it was unused, make it var. |
|
3856 |
|
3857 if (s === true) { |
|
3858 funct[v] = true; |
|
3859 } else if (typeof s !== 'object') { |
|
3860 if (option.undef) { |
|
3861 warning("'{a}' is not defined.", token, v); |
|
3862 } else { |
|
3863 funct[v] = true; |
|
3864 } |
|
3865 note_implied(token); |
|
3866 } else { |
|
3867 switch (s[v]) { |
|
3868 case 'function': |
|
3869 case 'var': |
|
3870 case 'unused': |
|
3871 s[v] = 'closure'; |
|
3872 funct[v] = s['(global)'] ? 'global' : 'outer'; |
|
3873 break; |
|
3874 case 'closure': |
|
3875 case 'parameter': |
|
3876 funct[v] = s['(global)'] ? 'global' : 'outer'; |
|
3877 break; |
|
3878 case 'label': |
|
3879 warning("'{a}' is a statement label.", token, v); |
|
3880 } |
|
3881 } |
|
3882 } |
|
3883 } |
|
3884 return this; |
|
3885 }, |
|
3886 led: function () { |
|
3887 error("Expected an operator and instead saw '{a}'.", |
|
3888 nexttoken, nexttoken.value); |
|
3889 } |
|
3890 }; |
|
3891 |
|
3892 type('(regexp)', function () { |
|
3893 return this; |
|
3894 }); |
|
3895 |
|
3896 delim('(endline)'); |
|
3897 delim('(begin)'); |
|
3898 delim('(end)').reach = true; |
|
3899 delim('</').reach = true; |
|
3900 delim('<!'); |
|
3901 delim('<!--'); |
|
3902 delim('-->'); |
|
3903 delim('(error)').reach = true; |
|
3904 delim('}').reach = true; |
|
3905 delim(')'); |
|
3906 delim(']'); |
|
3907 delim('"').reach = true; |
|
3908 delim("'").reach = true; |
|
3909 delim(';'); |
|
3910 delim(':').reach = true; |
|
3911 delim(','); |
|
3912 delim('#'); |
|
3913 delim('@'); |
|
3914 reserve('else'); |
|
3915 reserve('case').reach = true; |
|
3916 reserve('catch'); |
|
3917 reserve('default').reach = true; |
|
3918 reserve('finally'); |
|
3919 reservevar('arguments'); |
|
3920 reservevar('eval'); |
|
3921 reservevar('false'); |
|
3922 reservevar('Infinity'); |
|
3923 reservevar('NaN'); |
|
3924 reservevar('null'); |
|
3925 reservevar('this'); |
|
3926 reservevar('true'); |
|
3927 reservevar('undefined'); |
|
3928 assignop('=', 'assign', 20); |
|
3929 assignop('+=', 'assignadd', 20); |
|
3930 assignop('-=', 'assignsub', 20); |
|
3931 assignop('*=', 'assignmult', 20); |
|
3932 assignop('/=', 'assigndiv', 20).nud = function () { |
|
3933 error("A regular expression literal can be confused with '/='."); |
|
3934 }; |
|
3935 assignop('%=', 'assignmod', 20); |
|
3936 bitwiseassignop('&=', 'assignbitand', 20); |
|
3937 bitwiseassignop('|=', 'assignbitor', 20); |
|
3938 bitwiseassignop('^=', 'assignbitxor', 20); |
|
3939 bitwiseassignop('<<=', 'assignshiftleft', 20); |
|
3940 bitwiseassignop('>>=', 'assignshiftright', 20); |
|
3941 bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20); |
|
3942 infix('?', function (left, that) { |
|
3943 that.left = left; |
|
3944 that.right = parse(10); |
|
3945 advance(':'); |
|
3946 that['else'] = parse(10); |
|
3947 return that; |
|
3948 }, 30); |
|
3949 |
|
3950 infix('||', 'or', 40); |
|
3951 infix('&&', 'and', 50); |
|
3952 bitwise('|', 'bitor', 70); |
|
3953 bitwise('^', 'bitxor', 80); |
|
3954 bitwise('&', 'bitand', 90); |
|
3955 relation('==', function (left, right) { |
|
3956 if (option.eqeqeq) { |
|
3957 warning("Expected '{a}' and instead saw '{b}'.", |
|
3958 this, '===', '=='); |
|
3959 } else if (isPoorRelation(left)) { |
|
3960 warning("Use '{a}' to compare with '{b}'.", |
|
3961 this, '===', left.value); |
|
3962 } else if (isPoorRelation(right)) { |
|
3963 warning("Use '{a}' to compare with '{b}'.", |
|
3964 this, '===', right.value); |
|
3965 } |
|
3966 return this; |
|
3967 }); |
|
3968 relation('==='); |
|
3969 relation('!=', function (left, right) { |
|
3970 if (option.eqeqeq) { |
|
3971 warning("Expected '{a}' and instead saw '{b}'.", |
|
3972 this, '!==', '!='); |
|
3973 } else if (isPoorRelation(left)) { |
|
3974 warning("Use '{a}' to compare with '{b}'.", |
|
3975 this, '!==', left.value); |
|
3976 } else if (isPoorRelation(right)) { |
|
3977 warning("Use '{a}' to compare with '{b}'.", |
|
3978 this, '!==', right.value); |
|
3979 } |
|
3980 return this; |
|
3981 }); |
|
3982 relation('!=='); |
|
3983 relation('<'); |
|
3984 relation('>'); |
|
3985 relation('<='); |
|
3986 relation('>='); |
|
3987 bitwise('<<', 'shiftleft', 120); |
|
3988 bitwise('>>', 'shiftright', 120); |
|
3989 bitwise('>>>', 'shiftrightunsigned', 120); |
|
3990 infix('in', 'in', 120); |
|
3991 infix('instanceof', 'instanceof', 120); |
|
3992 infix('+', function (left, that) { |
|
3993 var right = parse(130); |
|
3994 if (left && right && left.id === '(string)' && right.id === '(string)') { |
|
3995 left.value += right.value; |
|
3996 left.character = right.character; |
|
3997 if (jx.test(left.value)) { |
|
3998 warning("JavaScript URL.", left); |
|
3999 } |
|
4000 return left; |
|
4001 } |
|
4002 that.left = left; |
|
4003 that.right = right; |
|
4004 return that; |
|
4005 }, 130); |
|
4006 prefix('+', 'num'); |
|
4007 infix('-', 'sub', 130); |
|
4008 prefix('-', 'neg'); |
|
4009 infix('*', 'mult', 140); |
|
4010 infix('/', 'div', 140); |
|
4011 infix('%', 'mod', 140); |
|
4012 |
|
4013 suffix('++', 'postinc'); |
|
4014 prefix('++', 'preinc'); |
|
4015 syntax['++'].exps = true; |
|
4016 |
|
4017 suffix('--', 'postdec'); |
|
4018 prefix('--', 'predec'); |
|
4019 syntax['--'].exps = true; |
|
4020 prefix('delete', function () { |
|
4021 var p = parse(0); |
|
4022 if (!p || (p.id !== '.' && p.id !== '[')) { |
|
4023 warning("Expected '{a}' and instead saw '{b}'.", |
|
4024 nexttoken, '.', nexttoken.value); |
|
4025 } |
|
4026 }).exps = true; |
|
4027 |
|
4028 |
|
4029 prefix('~', function () { |
|
4030 if (option.bitwise) { |
|
4031 warning("Unexpected '{a}'.", this, '~'); |
|
4032 } |
|
4033 parse(150); |
|
4034 return this; |
|
4035 }); |
|
4036 prefix('!', 'not'); |
|
4037 prefix('typeof', 'typeof'); |
|
4038 prefix('new', function () { |
|
4039 var c = parse(155), i; |
|
4040 if (c && c.id !== 'function') { |
|
4041 if (c.identifier) { |
|
4042 c['new'] = true; |
|
4043 switch (c.value) { |
|
4044 case 'Object': |
|
4045 warning("Use the object literal notation {}.", token); |
|
4046 break; |
|
4047 case 'Array': |
|
4048 if (nexttoken.id !== '(') { |
|
4049 warning("Use the array literal notation [].", token); |
|
4050 } else { |
|
4051 advance('('); |
|
4052 if (nexttoken.id === ')') { |
|
4053 warning("Use the array literal notation [].", token); |
|
4054 } else { |
|
4055 i = parse(0); |
|
4056 c.dimension = i; |
|
4057 if ((i.id === '(number)' && /[.+\-Ee]/.test(i.value)) || |
|
4058 (i.id === '-' && !i.right) || |
|
4059 i.id === '(string)' || i.id === '[' || |
|
4060 i.id === '{' || i.id === 'true' || |
|
4061 i.id === 'false' || |
|
4062 i.id === 'null' || i.id === 'undefined' || |
|
4063 i.id === 'Infinity') { |
|
4064 warning("Use the array literal notation [].", token); |
|
4065 } |
|
4066 if (nexttoken.id !== ')') { |
|
4067 error("Use the array literal notation [].", token); |
|
4068 } |
|
4069 } |
|
4070 advance(')'); |
|
4071 } |
|
4072 this.first = c; |
|
4073 return this; |
|
4074 case 'Number': |
|
4075 case 'String': |
|
4076 case 'Boolean': |
|
4077 case 'Math': |
|
4078 case 'JSON': |
|
4079 warning("Do not use {a} as a constructor.", token, c.value); |
|
4080 break; |
|
4081 case 'Function': |
|
4082 if (!option.evil) { |
|
4083 warning("The Function constructor is eval."); |
|
4084 } |
|
4085 break; |
|
4086 case 'Date': |
|
4087 case 'RegExp': |
|
4088 break; |
|
4089 default: |
|
4090 if (c.id !== 'function') { |
|
4091 i = c.value.substr(0, 1); |
|
4092 if (option.newcap && (i < 'A' || i > 'Z')) { |
|
4093 warning( |
|
4094 "A constructor name should start with an uppercase letter.", |
|
4095 token); |
|
4096 } |
|
4097 } |
|
4098 } |
|
4099 } else { |
|
4100 if (c.id !== '.' && c.id !== '[' && c.id !== '(') { |
|
4101 warning("Bad constructor.", token); |
|
4102 } |
|
4103 } |
|
4104 } else { |
|
4105 warning("Weird construction. Delete 'new'.", this); |
|
4106 } |
|
4107 adjacent(token, nexttoken); |
|
4108 if (nexttoken.id !== '(') { |
|
4109 warning("Missing '()' invoking a constructor."); |
|
4110 } |
|
4111 this.first = c; |
|
4112 return this; |
|
4113 }); |
|
4114 syntax['new'].exps = true; |
|
4115 |
|
4116 infix('.', function (left, that) { |
|
4117 adjacent(prevtoken, token); |
|
4118 var m = identifier(); |
|
4119 if (typeof m === 'string') { |
|
4120 countMember(m); |
|
4121 } |
|
4122 that.left = left; |
|
4123 that.right = m; |
|
4124 if (!option.evil && left && left.value === 'document' && |
|
4125 (m === 'write' || m === 'writeln')) { |
|
4126 warning("document.write can be a form of eval.", left); |
|
4127 } else if (option.adsafe) { |
|
4128 if (left && left.value === 'ADSAFE') { |
|
4129 if (m === 'id' || m === 'lib') { |
|
4130 warning("ADsafe violation.", that); |
|
4131 } else if (m === 'go') { |
|
4132 if (xmode !== 'script') { |
|
4133 warning("ADsafe violation.", that); |
|
4134 } else if (adsafe_went || nexttoken.id !== '(' || |
|
4135 peek(0).id !== '(string)' || |
|
4136 peek(0).value !== adsafe_id || |
|
4137 peek(1).id !== ',') { |
|
4138 error("ADsafe violation: go.", that); |
|
4139 } |
|
4140 adsafe_went = true; |
|
4141 adsafe_may = false; |
|
4142 } |
|
4143 } |
|
4144 } |
|
4145 if (!option.evil && (m === 'eval' || m === 'execScript')) { |
|
4146 warning('eval is evil.'); |
|
4147 } else if (option.safe) { |
|
4148 for (;;) { |
|
4149 if (banned[m] === true) { |
|
4150 warning("ADsafe restricted word '{a}'.", token, m); |
|
4151 } |
|
4152 if (typeof predefined[left.value] !== 'boolean' || |
|
4153 nexttoken.id === '(') { |
|
4154 break; |
|
4155 } |
|
4156 if (standard_member[m] === true) { |
|
4157 if (nexttoken.id === '.') { |
|
4158 warning("ADsafe violation.", that); |
|
4159 } |
|
4160 break; |
|
4161 } |
|
4162 if (nexttoken.id !== '.') { |
|
4163 warning("ADsafe violation.", that); |
|
4164 break; |
|
4165 } |
|
4166 advance('.'); |
|
4167 token.left = that; |
|
4168 token.right = m; |
|
4169 that = token; |
|
4170 m = identifier(); |
|
4171 if (typeof m === 'string') { |
|
4172 countMember(m); |
|
4173 } |
|
4174 } |
|
4175 } |
|
4176 return that; |
|
4177 }, 160, true); |
|
4178 |
|
4179 infix('(', function (left, that) { |
|
4180 adjacent(prevtoken, token); |
|
4181 nospace(); |
|
4182 var n = 0, |
|
4183 p = []; |
|
4184 if (left) { |
|
4185 if (left.type === '(identifier)') { |
|
4186 if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { |
|
4187 if (left.value !== 'Number' && left.value !== 'String' && |
|
4188 left.value !== 'Boolean' && |
|
4189 left.value !== 'Date') { |
|
4190 if (left.value === 'Math') { |
|
4191 warning("Math is not a function.", left); |
|
4192 } else if (option.newcap) { |
|
4193 warning( |
|
4194 "Missing 'new' prefix when invoking a constructor.", left); |
|
4195 } |
|
4196 } |
|
4197 } |
|
4198 } else if (left.id === '.') { |
|
4199 if (option.safe && left.left.value === 'Math' && |
|
4200 left.right === 'random') { |
|
4201 warning("ADsafe violation.", left); |
|
4202 } |
|
4203 } |
|
4204 } |
|
4205 if (nexttoken.id !== ')') { |
|
4206 for (;;) { |
|
4207 p[p.length] = parse(10); |
|
4208 n += 1; |
|
4209 if (nexttoken.id !== ',') { |
|
4210 break; |
|
4211 } |
|
4212 comma(); |
|
4213 } |
|
4214 } |
|
4215 advance(')'); |
|
4216 if (option.immed && left.id === 'function' && nexttoken.id !== ')') { |
|
4217 warning("Wrap the entire immediate function invocation in parens.", |
|
4218 that); |
|
4219 } |
|
4220 nospace(prevtoken, token); |
|
4221 if (typeof left === 'object') { |
|
4222 if (left.value === 'parseInt' && n === 1) { |
|
4223 warning("Missing radix parameter.", left); |
|
4224 } |
|
4225 if (!option.evil) { |
|
4226 if (left.value === 'eval' || left.value === 'Function' || |
|
4227 left.value === 'execScript') { |
|
4228 warning("eval is evil.", left); |
|
4229 } else if (p[0] && p[0].id === '(string)' && |
|
4230 (left.value === 'setTimeout' || |
|
4231 left.value === 'setInterval')) { |
|
4232 warning( |
|
4233 "Implied eval is evil. Pass a function instead of a string.", left); |
|
4234 } |
|
4235 } |
|
4236 if (!left.identifier && left.id !== '.' && left.id !== '[' && |
|
4237 left.id !== '(' && left.id !== '&&' && left.id !== '||' && |
|
4238 left.id !== '?') { |
|
4239 warning("Bad invocation.", left); |
|
4240 } |
|
4241 } |
|
4242 that.left = left; |
|
4243 return that; |
|
4244 }, 155, true).exps = true; |
|
4245 |
|
4246 prefix('(', function () { |
|
4247 nospace(); |
|
4248 var v = parse(0); |
|
4249 advance(')', this); |
|
4250 nospace(prevtoken, token); |
|
4251 if (option.immed && v.id === 'function') { |
|
4252 if (nexttoken.id === '(') { |
|
4253 warning( |
|
4254 "Move the invocation into the parens that contain the function.", nexttoken); |
|
4255 } else { |
|
4256 warning( |
|
4257 "Do not wrap function literals in parens unless they are to be immediately invoked.", |
|
4258 this); |
|
4259 } |
|
4260 } |
|
4261 return v; |
|
4262 }); |
|
4263 |
|
4264 infix('[', function (left, that) { |
|
4265 nospace(); |
|
4266 var e = parse(0), s; |
|
4267 if (e && e.type === '(string)') { |
|
4268 if (option.safe && banned[e.value] === true) { |
|
4269 warning("ADsafe restricted word '{a}'.", that, e.value); |
|
4270 } else if (!option.evil && |
|
4271 (e.value === 'eval' || e.value === 'execScript')) { |
|
4272 warning("eval is evil.", that); |
|
4273 } else if (option.safe && |
|
4274 (e.value.charAt(0) === '_' || e.value.charAt(0) === '-')) { |
|
4275 warning("ADsafe restricted subscript '{a}'.", that, e.value); |
|
4276 } |
|
4277 countMember(e.value); |
|
4278 if (!option.sub && ix.test(e.value)) { |
|
4279 s = syntax[e.value]; |
|
4280 if (!s || !s.reserved) { |
|
4281 warning("['{a}'] is better written in dot notation.", |
|
4282 e, e.value); |
|
4283 } |
|
4284 } |
|
4285 } else if (!e || e.type !== '(number)' || e.value < 0) { |
|
4286 if (option.safe) { |
|
4287 warning('ADsafe subscripting.'); |
|
4288 } |
|
4289 } |
|
4290 advance(']', that); |
|
4291 nospace(prevtoken, token); |
|
4292 that.left = left; |
|
4293 that.right = e; |
|
4294 return that; |
|
4295 }, 160, true); |
|
4296 |
|
4297 prefix('[', function () { |
|
4298 this.first = []; |
|
4299 if (nexttoken.id === ']') { |
|
4300 advance(']'); |
|
4301 return this; |
|
4302 } |
|
4303 var b = token.line !== nexttoken.line; |
|
4304 if (b) { |
|
4305 indent += option.indent; |
|
4306 if (nexttoken.from === indent + option.indent) { |
|
4307 indent += option.indent; |
|
4308 } |
|
4309 } |
|
4310 for (;;) { |
|
4311 if (b && token.line !== nexttoken.line) { |
|
4312 indentation(); |
|
4313 } |
|
4314 parse(10); |
|
4315 if (nexttoken.id === ',') { |
|
4316 comma(); |
|
4317 if (nexttoken.id === ',') { |
|
4318 warning("Extra comma.", token); |
|
4319 } else if (nexttoken.id === ']') { |
|
4320 warning("Extra comma.", token); |
|
4321 break; |
|
4322 } |
|
4323 } else { |
|
4324 if (b) { |
|
4325 indent -= option.indent; |
|
4326 indentation(); |
|
4327 } |
|
4328 break; |
|
4329 } |
|
4330 } |
|
4331 advance(']', this); |
|
4332 return this; |
|
4333 }, 160); |
|
4334 |
|
4335 (function (x) { |
|
4336 x.nud = function () { |
|
4337 var b, i, s, seen = {}; |
|
4338 b = token.line !== nexttoken.line; |
|
4339 if (b) { |
|
4340 indent += option.indent; |
|
4341 if (nexttoken.from === indent + option.indent) { |
|
4342 indent += option.indent; |
|
4343 } |
|
4344 } |
|
4345 for (;;) { |
|
4346 if (nexttoken.id === '}') { |
|
4347 break; |
|
4348 } |
|
4349 if (b) { |
|
4350 indentation(); |
|
4351 } |
|
4352 i = optionalidentifier(true); |
|
4353 if (!i) { |
|
4354 if (nexttoken.id === '(string)') { |
|
4355 i = nexttoken.value; |
|
4356 if (ix.test(i)) { |
|
4357 s = syntax[i]; |
|
4358 } |
|
4359 advance(); |
|
4360 } else if (nexttoken.id === '(number)') { |
|
4361 i = nexttoken.value.toString(); |
|
4362 advance(); |
|
4363 } else { |
|
4364 error("Expected '{a}' and instead saw '{b}'.", |
|
4365 nexttoken, '}', nexttoken.value); |
|
4366 } |
|
4367 } |
|
4368 if (seen[i] === true) { |
|
4369 warning("Duplicate member '{a}'.", nexttoken, i); |
|
4370 } |
|
4371 seen[i] = true; |
|
4372 countMember(i); |
|
4373 advance(':'); |
|
4374 nonadjacent(token, nexttoken); |
|
4375 parse(10); |
|
4376 if (nexttoken.id === ',') { |
|
4377 comma(); |
|
4378 if (nexttoken.id === ',' || nexttoken.id === '}') { |
|
4379 warning("Extra comma.", token); |
|
4380 } |
|
4381 } else { |
|
4382 break; |
|
4383 } |
|
4384 } |
|
4385 if (b) { |
|
4386 indent -= option.indent; |
|
4387 indentation(); |
|
4388 } |
|
4389 advance('}', this); |
|
4390 return this; |
|
4391 }; |
|
4392 x.fud = function () { |
|
4393 error("Expected to see a statement and instead saw a block.", token); |
|
4394 }; |
|
4395 }(delim('{'))); |
|
4396 |
|
4397 |
|
4398 function varstatement(prefix) { |
|
4399 |
|
4400 // JavaScript does not have block scope. It only has function scope. So, |
|
4401 // declaring a variable in a block can have unexpected consequences. |
|
4402 |
|
4403 var id, name, value; |
|
4404 |
|
4405 if (funct['(onevar)'] && option.onevar) { |
|
4406 warning("Too many var statements."); |
|
4407 } else if (!funct['(global)']) { |
|
4408 funct['(onevar)'] = true; |
|
4409 } |
|
4410 this.first = []; |
|
4411 for (;;) { |
|
4412 nonadjacent(token, nexttoken); |
|
4413 id = identifier(); |
|
4414 if (funct['(global)'] && predefined[id] === false) { |
|
4415 warning("Redefinition of '{a}'.", token, id); |
|
4416 } |
|
4417 addlabel(id, 'unused'); |
|
4418 if (prefix) { |
|
4419 break; |
|
4420 } |
|
4421 name = token; |
|
4422 this.first.push(token); |
|
4423 if (nexttoken.id === '=') { |
|
4424 nonadjacent(token, nexttoken); |
|
4425 advance('='); |
|
4426 nonadjacent(token, nexttoken); |
|
4427 if (peek(0).id === '=' && nexttoken.identifier) { |
|
4428 error("Variable {a} was not declared correctly.", |
|
4429 nexttoken, nexttoken.value); |
|
4430 } |
|
4431 value = parse(0); |
|
4432 name.first = value; |
|
4433 } |
|
4434 if (nexttoken.id !== ',') { |
|
4435 break; |
|
4436 } |
|
4437 comma(); |
|
4438 } |
|
4439 return this; |
|
4440 } |
|
4441 |
|
4442 |
|
4443 stmt('var', varstatement); |
|
4444 |
|
4445 stmt('new', function () { |
|
4446 warning("'new' should not be used as a statement."); |
|
4447 }); |
|
4448 |
|
4449 |
|
4450 function functionparams() { |
|
4451 var i, t = nexttoken, p = []; |
|
4452 advance('('); |
|
4453 nospace(); |
|
4454 if (nexttoken.id === ')') { |
|
4455 advance(')'); |
|
4456 nospace(prevtoken, token); |
|
4457 return; |
|
4458 } |
|
4459 for (;;) { |
|
4460 i = identifier(); |
|
4461 p.push(i); |
|
4462 addlabel(i, 'parameter'); |
|
4463 if (nexttoken.id === ',') { |
|
4464 comma(); |
|
4465 } else { |
|
4466 advance(')', t); |
|
4467 nospace(prevtoken, token); |
|
4468 return p; |
|
4469 } |
|
4470 } |
|
4471 } |
|
4472 |
|
4473 function doFunction(i) { |
|
4474 var s = scope; |
|
4475 scope = Object.create(s); |
|
4476 funct = { |
|
4477 '(name)' : i || '"' + anonname + '"', |
|
4478 '(line)' : nexttoken.line, |
|
4479 '(context)' : funct, |
|
4480 '(breakage)': 0, |
|
4481 '(loopage)' : 0, |
|
4482 '(scope)' : scope |
|
4483 }; |
|
4484 token.funct = funct; |
|
4485 functions.push(funct); |
|
4486 if (i) { |
|
4487 addlabel(i, 'function'); |
|
4488 } |
|
4489 funct['(params)'] = functionparams(); |
|
4490 |
|
4491 block(false); |
|
4492 scope = s; |
|
4493 funct['(last)'] = token.line; |
|
4494 funct = funct['(context)']; |
|
4495 } |
|
4496 |
|
4497 |
|
4498 blockstmt('function', function () { |
|
4499 if (inblock) { |
|
4500 warning( |
|
4501 "Function statements cannot be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token); |
|
4502 |
|
4503 } |
|
4504 var i = identifier(); |
|
4505 adjacent(token, nexttoken); |
|
4506 addlabel(i, 'unused'); |
|
4507 doFunction(i); |
|
4508 if (nexttoken.id === '(' && nexttoken.line === token.line) { |
|
4509 error( |
|
4510 "Function statements are not invocable. Wrap the whole function invocation in parens."); |
|
4511 } |
|
4512 }); |
|
4513 |
|
4514 prefix('function', function () { |
|
4515 var i = optionalidentifier(); |
|
4516 if (i) { |
|
4517 adjacent(token, nexttoken); |
|
4518 } else { |
|
4519 nonadjacent(token, nexttoken); |
|
4520 } |
|
4521 doFunction(i); |
|
4522 if (funct['(loopage)'] && nexttoken.id !== '(') { |
|
4523 warning("Be careful when making functions within a loop. Consider putting the function in a closure."); |
|
4524 } |
|
4525 return this; |
|
4526 }); |
|
4527 |
|
4528 blockstmt('if', function () { |
|
4529 var t = nexttoken; |
|
4530 advance('('); |
|
4531 nonadjacent(this, t); |
|
4532 nospace(); |
|
4533 parse(20); |
|
4534 if (nexttoken.id === '=') { |
|
4535 warning("Expected a conditional expression and instead saw an assignment."); |
|
4536 advance('='); |
|
4537 parse(20); |
|
4538 } |
|
4539 advance(')', t); |
|
4540 nospace(prevtoken, token); |
|
4541 block(true); |
|
4542 if (nexttoken.id === 'else') { |
|
4543 nonadjacent(token, nexttoken); |
|
4544 advance('else'); |
|
4545 if (nexttoken.id === 'if' || nexttoken.id === 'switch') { |
|
4546 statement(true); |
|
4547 } else { |
|
4548 block(true); |
|
4549 } |
|
4550 } |
|
4551 return this; |
|
4552 }); |
|
4553 |
|
4554 blockstmt('try', function () { |
|
4555 var b, e, s; |
|
4556 if (option.adsafe) { |
|
4557 warning("ADsafe try violation.", this); |
|
4558 } |
|
4559 block(false); |
|
4560 if (nexttoken.id === 'catch') { |
|
4561 advance('catch'); |
|
4562 nonadjacent(token, nexttoken); |
|
4563 advance('('); |
|
4564 s = scope; |
|
4565 scope = Object.create(s); |
|
4566 e = nexttoken.value; |
|
4567 if (nexttoken.type !== '(identifier)') { |
|
4568 warning("Expected an identifier and instead saw '{a}'.", |
|
4569 nexttoken, e); |
|
4570 } else { |
|
4571 addlabel(e, 'exception'); |
|
4572 } |
|
4573 advance(); |
|
4574 advance(')'); |
|
4575 block(false); |
|
4576 b = true; |
|
4577 scope = s; |
|
4578 } |
|
4579 if (nexttoken.id === 'finally') { |
|
4580 advance('finally'); |
|
4581 block(false); |
|
4582 return; |
|
4583 } else if (!b) { |
|
4584 error("Expected '{a}' and instead saw '{b}'.", |
|
4585 nexttoken, 'catch', nexttoken.value); |
|
4586 } |
|
4587 }); |
|
4588 |
|
4589 blockstmt('while', function () { |
|
4590 var t = nexttoken; |
|
4591 funct['(breakage)'] += 1; |
|
4592 funct['(loopage)'] += 1; |
|
4593 advance('('); |
|
4594 nonadjacent(this, t); |
|
4595 nospace(); |
|
4596 parse(20); |
|
4597 if (nexttoken.id === '=') { |
|
4598 warning("Expected a conditional expression and instead saw an assignment."); |
|
4599 advance('='); |
|
4600 parse(20); |
|
4601 } |
|
4602 advance(')', t); |
|
4603 nospace(prevtoken, token); |
|
4604 block(true); |
|
4605 funct['(breakage)'] -= 1; |
|
4606 funct['(loopage)'] -= 1; |
|
4607 }).labelled = true; |
|
4608 |
|
4609 reserve('with'); |
|
4610 |
|
4611 blockstmt('switch', function () { |
|
4612 var t = nexttoken, |
|
4613 g = false; |
|
4614 funct['(breakage)'] += 1; |
|
4615 advance('('); |
|
4616 nonadjacent(this, t); |
|
4617 nospace(); |
|
4618 this.condition = parse(20); |
|
4619 advance(')', t); |
|
4620 nospace(prevtoken, token); |
|
4621 nonadjacent(token, nexttoken); |
|
4622 t = nexttoken; |
|
4623 advance('{'); |
|
4624 nonadjacent(token, nexttoken); |
|
4625 indent += option.indent; |
|
4626 this.cases = []; |
|
4627 for (;;) { |
|
4628 switch (nexttoken.id) { |
|
4629 case 'case': |
|
4630 switch (funct['(verb)']) { |
|
4631 case 'break': |
|
4632 case 'case': |
|
4633 case 'continue': |
|
4634 case 'return': |
|
4635 case 'switch': |
|
4636 case 'throw': |
|
4637 break; |
|
4638 default: |
|
4639 warning( |
|
4640 "Expected a 'break' statement before 'case'.", |
|
4641 token); |
|
4642 } |
|
4643 indentation(-option.indent); |
|
4644 advance('case'); |
|
4645 this.cases.push(parse(20)); |
|
4646 g = true; |
|
4647 advance(':'); |
|
4648 funct['(verb)'] = 'case'; |
|
4649 break; |
|
4650 case 'default': |
|
4651 switch (funct['(verb)']) { |
|
4652 case 'break': |
|
4653 case 'continue': |
|
4654 case 'return': |
|
4655 case 'throw': |
|
4656 break; |
|
4657 default: |
|
4658 warning( |
|
4659 "Expected a 'break' statement before 'default'.", |
|
4660 token); |
|
4661 } |
|
4662 indentation(-option.indent); |
|
4663 advance('default'); |
|
4664 g = true; |
|
4665 advance(':'); |
|
4666 break; |
|
4667 case '}': |
|
4668 indent -= option.indent; |
|
4669 indentation(); |
|
4670 advance('}', t); |
|
4671 if (this.cases.length === 1 || this.condition.id === 'true' || |
|
4672 this.condition.id === 'false') { |
|
4673 warning("This 'switch' should be an 'if'.", this); |
|
4674 } |
|
4675 funct['(breakage)'] -= 1; |
|
4676 funct['(verb)'] = undefined; |
|
4677 return; |
|
4678 case '(end)': |
|
4679 error("Missing '{a}'.", nexttoken, '}'); |
|
4680 return; |
|
4681 default: |
|
4682 if (g) { |
|
4683 switch (token.id) { |
|
4684 case ',': |
|
4685 error("Each value should have its own case label."); |
|
4686 return; |
|
4687 case ':': |
|
4688 statements(); |
|
4689 break; |
|
4690 default: |
|
4691 error("Missing ':' on a case clause.", token); |
|
4692 } |
|
4693 } else { |
|
4694 error("Expected '{a}' and instead saw '{b}'.", |
|
4695 nexttoken, 'case', nexttoken.value); |
|
4696 } |
|
4697 } |
|
4698 } |
|
4699 }).labelled = true; |
|
4700 |
|
4701 stmt('debugger', function () { |
|
4702 if (!option.debug) { |
|
4703 warning("All 'debugger' statements should be removed."); |
|
4704 } |
|
4705 }); |
|
4706 |
|
4707 stmt('do', function () { |
|
4708 funct['(breakage)'] += 1; |
|
4709 funct['(loopage)'] += 1; |
|
4710 block(true); |
|
4711 advance('while'); |
|
4712 var t = nexttoken; |
|
4713 nonadjacent(token, t); |
|
4714 advance('('); |
|
4715 nospace(); |
|
4716 parse(20); |
|
4717 if (nexttoken.id === '=') { |
|
4718 warning("Expected a conditional expression and instead saw an assignment."); |
|
4719 advance('='); |
|
4720 parse(20); |
|
4721 } |
|
4722 advance(')', t); |
|
4723 nospace(prevtoken, token); |
|
4724 funct['(breakage)'] -= 1; |
|
4725 funct['(loopage)'] -= 1; |
|
4726 }).labelled = true; |
|
4727 |
|
4728 blockstmt('for', function () { |
|
4729 var s, t = nexttoken; |
|
4730 funct['(breakage)'] += 1; |
|
4731 funct['(loopage)'] += 1; |
|
4732 advance('('); |
|
4733 nonadjacent(this, t); |
|
4734 nospace(); |
|
4735 if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') { |
|
4736 if (nexttoken.id === 'var') { |
|
4737 advance('var'); |
|
4738 varstatement(true); |
|
4739 } else { |
|
4740 switch (funct[nexttoken.value]) { |
|
4741 case 'unused': |
|
4742 funct[nexttoken.value] = 'var'; |
|
4743 break; |
|
4744 case 'var': |
|
4745 break; |
|
4746 default: |
|
4747 warning("Bad for in variable '{a}'.", |
|
4748 nexttoken, nexttoken.value); |
|
4749 } |
|
4750 advance(); |
|
4751 } |
|
4752 advance('in'); |
|
4753 parse(20); |
|
4754 advance(')', t); |
|
4755 s = block(true); |
|
4756 if (!option.forin && (s.length > 1 || typeof s[0] !== 'object' || |
|
4757 s[0].value !== 'if')) { |
|
4758 warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.", this); |
|
4759 } |
|
4760 funct['(breakage)'] -= 1; |
|
4761 funct['(loopage)'] -= 1; |
|
4762 return this; |
|
4763 } else { |
|
4764 if (nexttoken.id !== ';') { |
|
4765 if (nexttoken.id === 'var') { |
|
4766 advance('var'); |
|
4767 varstatement(); |
|
4768 } else { |
|
4769 for (;;) { |
|
4770 parse(0, 'for'); |
|
4771 if (nexttoken.id !== ',') { |
|
4772 break; |
|
4773 } |
|
4774 comma(); |
|
4775 } |
|
4776 } |
|
4777 } |
|
4778 nolinebreak(token); |
|
4779 advance(';'); |
|
4780 if (nexttoken.id !== ';') { |
|
4781 parse(20); |
|
4782 if (nexttoken.id === '=') { |
|
4783 warning("Expected a conditional expression and instead saw an assignment."); |
|
4784 advance('='); |
|
4785 parse(20); |
|
4786 } |
|
4787 } |
|
4788 nolinebreak(token); |
|
4789 advance(';'); |
|
4790 if (nexttoken.id === ';') { |
|
4791 error("Expected '{a}' and instead saw '{b}'.", |
|
4792 nexttoken, ')', ';'); |
|
4793 } |
|
4794 if (nexttoken.id !== ')') { |
|
4795 for (;;) { |
|
4796 parse(0, 'for'); |
|
4797 if (nexttoken.id !== ',') { |
|
4798 break; |
|
4799 } |
|
4800 comma(); |
|
4801 } |
|
4802 } |
|
4803 advance(')', t); |
|
4804 nospace(prevtoken, token); |
|
4805 block(true); |
|
4806 funct['(breakage)'] -= 1; |
|
4807 funct['(loopage)'] -= 1; |
|
4808 } |
|
4809 }).labelled = true; |
|
4810 |
|
4811 |
|
4812 stmt('break', function () { |
|
4813 var v = nexttoken.value; |
|
4814 if (funct['(breakage)'] === 0) { |
|
4815 warning("Unexpected '{a}'.", nexttoken, this.value); |
|
4816 } |
|
4817 nolinebreak(this); |
|
4818 if (nexttoken.id !== ';') { |
|
4819 if (token.line === nexttoken.line) { |
|
4820 if (funct[v] !== 'label') { |
|
4821 warning("'{a}' is not a statement label.", nexttoken, v); |
|
4822 } else if (scope[v] !== funct) { |
|
4823 warning("'{a}' is out of scope.", nexttoken, v); |
|
4824 } |
|
4825 advance(); |
|
4826 } |
|
4827 } |
|
4828 reachable('break'); |
|
4829 }); |
|
4830 |
|
4831 |
|
4832 stmt('continue', function () { |
|
4833 var v = nexttoken.value; |
|
4834 if (funct['(breakage)'] === 0) { |
|
4835 warning("Unexpected '{a}'.", nexttoken, this.value); |
|
4836 } |
|
4837 nolinebreak(this); |
|
4838 if (nexttoken.id !== ';') { |
|
4839 if (token.line === nexttoken.line) { |
|
4840 if (funct[v] !== 'label') { |
|
4841 warning("'{a}' is not a statement label.", nexttoken, v); |
|
4842 } else if (scope[v] !== funct) { |
|
4843 warning("'{a}' is out of scope.", nexttoken, v); |
|
4844 } |
|
4845 advance(); |
|
4846 } |
|
4847 } |
|
4848 reachable('continue'); |
|
4849 }); |
|
4850 |
|
4851 |
|
4852 stmt('return', function () { |
|
4853 nolinebreak(this); |
|
4854 if (nexttoken.id === '(regexp)') { |
|
4855 warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator."); |
|
4856 } |
|
4857 if (nexttoken.id !== ';' && !nexttoken.reach) { |
|
4858 nonadjacent(token, nexttoken); |
|
4859 parse(20); |
|
4860 } |
|
4861 reachable('return'); |
|
4862 }); |
|
4863 |
|
4864 |
|
4865 stmt('throw', function () { |
|
4866 nolinebreak(this); |
|
4867 nonadjacent(token, nexttoken); |
|
4868 parse(20); |
|
4869 reachable('throw'); |
|
4870 }); |
|
4871 |
|
4872 reserve('void'); |
|
4873 |
|
4874 // Superfluous reserved words |
|
4875 |
|
4876 reserve('class'); |
|
4877 reserve('const'); |
|
4878 reserve('enum'); |
|
4879 reserve('export'); |
|
4880 reserve('extends'); |
|
4881 reserve('import'); |
|
4882 reserve('super'); |
|
4883 |
|
4884 reserve('let'); |
|
4885 reserve('yield'); |
|
4886 reserve('implements'); |
|
4887 reserve('interface'); |
|
4888 reserve('package'); |
|
4889 reserve('private'); |
|
4890 reserve('protected'); |
|
4891 reserve('public'); |
|
4892 reserve('static'); |
|
4893 |
|
4894 function jsonValue() { |
|
4895 |
|
4896 function jsonObject() { |
|
4897 var o = {}, t = nexttoken; |
|
4898 advance('{'); |
|
4899 if (nexttoken.id !== '}') { |
|
4900 for (;;) { |
|
4901 if (nexttoken.id === '(end)') { |
|
4902 error("Missing '}' to match '{' from line {a}.", |
|
4903 nexttoken, t.line); |
|
4904 } else if (nexttoken.id === '}') { |
|
4905 warning("Unexpected comma.", token); |
|
4906 break; |
|
4907 } else if (nexttoken.id === ',') { |
|
4908 error("Unexpected comma.", nexttoken); |
|
4909 } else if (nexttoken.id !== '(string)') { |
|
4910 warning("Expected a string and instead saw {a}.", |
|
4911 nexttoken, nexttoken.value); |
|
4912 } |
|
4913 if (o[nexttoken.value] === true) { |
|
4914 warning("Duplicate key '{a}'.", |
|
4915 nexttoken, nexttoken.value); |
|
4916 } else if (nexttoken.value === '__proto__') { |
|
4917 warning("Stupid key '{a}'.", |
|
4918 nexttoken, nexttoken.value); |
|
4919 } else { |
|
4920 o[nexttoken.value] = true; |
|
4921 } |
|
4922 advance(); |
|
4923 advance(':'); |
|
4924 jsonValue(); |
|
4925 if (nexttoken.id !== ',') { |
|
4926 break; |
|
4927 } |
|
4928 advance(','); |
|
4929 } |
|
4930 } |
|
4931 advance('}'); |
|
4932 } |
|
4933 |
|
4934 function jsonArray() { |
|
4935 var t = nexttoken; |
|
4936 advance('['); |
|
4937 if (nexttoken.id !== ']') { |
|
4938 for (;;) { |
|
4939 if (nexttoken.id === '(end)') { |
|
4940 error("Missing ']' to match '[' from line {a}.", |
|
4941 nexttoken, t.line); |
|
4942 } else if (nexttoken.id === ']') { |
|
4943 warning("Unexpected comma.", token); |
|
4944 break; |
|
4945 } else if (nexttoken.id === ',') { |
|
4946 error("Unexpected comma.", nexttoken); |
|
4947 } |
|
4948 jsonValue(); |
|
4949 if (nexttoken.id !== ',') { |
|
4950 break; |
|
4951 } |
|
4952 advance(','); |
|
4953 } |
|
4954 } |
|
4955 advance(']'); |
|
4956 } |
|
4957 |
|
4958 switch (nexttoken.id) { |
|
4959 case '{': |
|
4960 jsonObject(); |
|
4961 break; |
|
4962 case '[': |
|
4963 jsonArray(); |
|
4964 break; |
|
4965 case 'true': |
|
4966 case 'false': |
|
4967 case 'null': |
|
4968 case '(number)': |
|
4969 case '(string)': |
|
4970 advance(); |
|
4971 break; |
|
4972 case '-': |
|
4973 advance('-'); |
|
4974 if (token.character !== nexttoken.from) { |
|
4975 warning("Unexpected space after '-'.", token); |
|
4976 } |
|
4977 adjacent(token, nexttoken); |
|
4978 advance('(number)'); |
|
4979 break; |
|
4980 default: |
|
4981 error("Expected a JSON value.", nexttoken); |
|
4982 } |
|
4983 } |
|
4984 |
|
4985 |
|
4986 // The actual JSLINT function itself. |
|
4987 |
|
4988 var itself = function (s, o) { |
|
4989 var a, i; |
|
4990 JSLINT.errors = []; |
|
4991 predefined = Object.create(standard); |
|
4992 if (o) { |
|
4993 a = o.predef; |
|
4994 if (a instanceof Array) { |
|
4995 for (i = 0; i < a.length; i += 1) { |
|
4996 predefined[a[i]] = true; |
|
4997 } |
|
4998 } |
|
4999 if (o.adsafe) { |
|
5000 o.safe = true; |
|
5001 } |
|
5002 if (o.safe) { |
|
5003 o.browser = false; |
|
5004 o.css = false; |
|
5005 o.debug = false; |
|
5006 o.eqeqeq = true; |
|
5007 o.evil = false; |
|
5008 o.forin = false; |
|
5009 o.nomen = true; |
|
5010 o.on = false; |
|
5011 o.rhino = false; |
|
5012 o.safe = true; |
|
5013 o.sidebar = false; |
|
5014 o.strict = true; |
|
5015 o.sub = false; |
|
5016 o.undef = true; |
|
5017 o.widget = false; |
|
5018 predefined.Date = null; |
|
5019 predefined['eval'] = null; |
|
5020 predefined.Function = null; |
|
5021 predefined.Object = null; |
|
5022 predefined.ADSAFE = false; |
|
5023 predefined.lib = false; |
|
5024 } |
|
5025 option = o; |
|
5026 } else { |
|
5027 option = {}; |
|
5028 } |
|
5029 option.indent = option.indent || 4; |
|
5030 option.maxerr = option.maxerr || 50; |
|
5031 adsafe_id = ''; |
|
5032 adsafe_may = false; |
|
5033 adsafe_went = false; |
|
5034 approved = {}; |
|
5035 if (option.approved) { |
|
5036 for (i = 0; i < option.approved.length; i += 1) { |
|
5037 approved[option.approved[i]] = option.approved[i]; |
|
5038 } |
|
5039 } else { |
|
5040 approved.test = 'test'; |
|
5041 } |
|
5042 tab = ''; |
|
5043 for (i = 0; i < option.indent; i += 1) { |
|
5044 tab += ' '; |
|
5045 } |
|
5046 indent = 1; |
|
5047 global = Object.create(predefined); |
|
5048 scope = global; |
|
5049 funct = { |
|
5050 '(global)': true, |
|
5051 '(name)': '(global)', |
|
5052 '(scope)': scope, |
|
5053 '(breakage)': 0, |
|
5054 '(loopage)': 0 |
|
5055 }; |
|
5056 functions = [funct]; |
|
5057 ids = {}; |
|
5058 urls = []; |
|
5059 src = false; |
|
5060 xmode = false; |
|
5061 stack = null; |
|
5062 member = {}; |
|
5063 membersOnly = null; |
|
5064 implied = {}; |
|
5065 inblock = false; |
|
5066 lookahead = []; |
|
5067 jsonmode = false; |
|
5068 warnings = 0; |
|
5069 lex.init(s); |
|
5070 prereg = true; |
|
5071 |
|
5072 prevtoken = token = nexttoken = syntax['(begin)']; |
|
5073 assume(); |
|
5074 |
|
5075 try { |
|
5076 advance(); |
|
5077 if (nexttoken.value.charAt(0) === '<') { |
|
5078 html(); |
|
5079 if (option.adsafe && !adsafe_went) { |
|
5080 warning("ADsafe violation: Missing ADSAFE.go.", this); |
|
5081 } |
|
5082 } else { |
|
5083 switch (nexttoken.id) { |
|
5084 case '{': |
|
5085 case '[': |
|
5086 option.laxbreak = true; |
|
5087 jsonmode = true; |
|
5088 jsonValue(); |
|
5089 break; |
|
5090 case '@': |
|
5091 case '*': |
|
5092 case '#': |
|
5093 case '.': |
|
5094 case ':': |
|
5095 xmode = 'style'; |
|
5096 advance(); |
|
5097 if (token.id !== '@' || !nexttoken.identifier || |
|
5098 nexttoken.value !== 'charset' || token.line !== 1 || |
|
5099 token.from !== 1) { |
|
5100 error('A css file should begin with @charset "UTF-8";'); |
|
5101 } |
|
5102 advance(); |
|
5103 if (nexttoken.type !== '(string)' && |
|
5104 nexttoken.value !== 'UTF-8') { |
|
5105 error('A css file should begin with @charset "UTF-8";'); |
|
5106 } |
|
5107 advance(); |
|
5108 advance(';'); |
|
5109 styles(); |
|
5110 break; |
|
5111 |
|
5112 default: |
|
5113 if (option.adsafe && option.fragment) { |
|
5114 error("Expected '{a}' and instead saw '{b}'.", |
|
5115 nexttoken, '<div>', nexttoken.value); |
|
5116 } |
|
5117 statements('lib'); |
|
5118 } |
|
5119 } |
|
5120 advance('(end)'); |
|
5121 } catch (e) { |
|
5122 if (e) { |
|
5123 JSLINT.errors.push({ |
|
5124 reason : e.message, |
|
5125 line : e.line || nexttoken.line, |
|
5126 character : e.character || nexttoken.from |
|
5127 }, null); |
|
5128 } |
|
5129 } |
|
5130 return JSLINT.errors.length === 0; |
|
5131 }; |
|
5132 |
|
5133 function is_array(o) { |
|
5134 return Object.prototype.toString.apply(o) === '[object Array]'; |
|
5135 } |
|
5136 |
|
5137 function to_array(o) { |
|
5138 var a = [], k; |
|
5139 for (k in o) { |
|
5140 if (is_own(o, k)) { |
|
5141 a.push(k); |
|
5142 } |
|
5143 } |
|
5144 return a; |
|
5145 } |
|
5146 |
|
5147 // Data summary. |
|
5148 |
|
5149 itself.data = function () { |
|
5150 |
|
5151 var data = {functions: []}, fu, globals, implieds = [], f, i, j, |
|
5152 members = [], n, unused = [], v; |
|
5153 if (itself.errors.length) { |
|
5154 data.errors = itself.errors; |
|
5155 } |
|
5156 |
|
5157 if (jsonmode) { |
|
5158 data.json = true; |
|
5159 } |
|
5160 |
|
5161 for (n in implied) { |
|
5162 if (is_own(implied, n)) { |
|
5163 implieds.push({ |
|
5164 name: n, |
|
5165 line: implied[n] |
|
5166 }); |
|
5167 } |
|
5168 } |
|
5169 if (implieds.length > 0) { |
|
5170 data.implieds = implieds; |
|
5171 } |
|
5172 |
|
5173 if (urls.length > 0) { |
|
5174 data.urls = urls; |
|
5175 } |
|
5176 |
|
5177 globals = to_array(scope); |
|
5178 if (globals.length > 0) { |
|
5179 data.globals = globals; |
|
5180 } |
|
5181 |
|
5182 for (i = 1; i < functions.length; i += 1) { |
|
5183 f = functions[i]; |
|
5184 fu = {}; |
|
5185 for (j = 0; j < functionicity.length; j += 1) { |
|
5186 fu[functionicity[j]] = []; |
|
5187 } |
|
5188 for (n in f) { |
|
5189 if (is_own(f, n) && n.charAt(0) !== '(') { |
|
5190 v = f[n]; |
|
5191 if (is_array(fu[v])) { |
|
5192 fu[v].push(n); |
|
5193 if (v === 'unused') { |
|
5194 unused.push({ |
|
5195 name: n, |
|
5196 line: f['(line)'], |
|
5197 'function': f['(name)'] |
|
5198 }); |
|
5199 } |
|
5200 } |
|
5201 } |
|
5202 } |
|
5203 for (j = 0; j < functionicity.length; j += 1) { |
|
5204 if (fu[functionicity[j]].length === 0) { |
|
5205 delete fu[functionicity[j]]; |
|
5206 } |
|
5207 } |
|
5208 fu.name = f['(name)']; |
|
5209 fu.param = f['(params)']; |
|
5210 fu.line = f['(line)']; |
|
5211 fu.last = f['(last)']; |
|
5212 data.functions.push(fu); |
|
5213 } |
|
5214 |
|
5215 if (unused.length > 0) { |
|
5216 data.unused = unused; |
|
5217 } |
|
5218 |
|
5219 members = []; |
|
5220 for (n in member) { |
|
5221 if (typeof member[n] === 'number') { |
|
5222 data.member = member; |
|
5223 break; |
|
5224 } |
|
5225 } |
|
5226 |
|
5227 return data; |
|
5228 }; |
|
5229 |
|
5230 itself.report = function (option) { |
|
5231 var data = itself.data(); |
|
5232 |
|
5233 var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s; |
|
5234 |
|
5235 function detail(h, s) { |
|
5236 if (s) { |
|
5237 o.push('<div><i>' + h + '</i> ' + |
|
5238 s.sort().join(', ') + '</div>'); |
|
5239 } |
|
5240 } |
|
5241 |
|
5242 |
|
5243 if (data.errors || data.implieds || data.unused) { |
|
5244 err = true; |
|
5245 o.push('<div id=errors><i>Error:</i>'); |
|
5246 if (data.errors) { |
|
5247 for (i = 0; i < data.errors.length; i += 1) { |
|
5248 c = data.errors[i]; |
|
5249 if (c) { |
|
5250 e = c.evidence || ''; |
|
5251 o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' + |
|
5252 c.line + ' character ' + c.character : '') + |
|
5253 ': ' + c.reason.entityify() + |
|
5254 '</p><p class=evidence>' + |
|
5255 (e && (e.length > 80 ? e.slice(0, 77) + '...' : |
|
5256 e).entityify()) + '</p>'); |
|
5257 } |
|
5258 } |
|
5259 } |
|
5260 |
|
5261 if (data.implieds) { |
|
5262 s = []; |
|
5263 for (i = 0; i < data.implieds.length; i += 1) { |
|
5264 s[i] = '<code>' + data.implieds[i].name + '</code> <i>' + |
|
5265 data.implieds[i].line + '</i>'; |
|
5266 } |
|
5267 o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>'); |
|
5268 } |
|
5269 |
|
5270 if (data.unused) { |
|
5271 s = []; |
|
5272 for (i = 0; i < data.unused.length; i += 1) { |
|
5273 s[i] = '<code>' + data.unused[i].name + '</code> <i>' + |
|
5274 data.unused[i].line + '</i> <code>' + |
|
5275 data.unused[i]['function'] + '</code>'; |
|
5276 } |
|
5277 o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>'); |
|
5278 } |
|
5279 if (data.json) { |
|
5280 o.push('<p>JSON: bad.</p>'); |
|
5281 } |
|
5282 o.push('</div>'); |
|
5283 } |
|
5284 |
|
5285 if (!option) { |
|
5286 |
|
5287 o.push('<br><div id=functions>'); |
|
5288 |
|
5289 if (data.urls) { |
|
5290 detail("URLs<br>", data.urls, '<br>'); |
|
5291 } |
|
5292 |
|
5293 if (data.json && !err) { |
|
5294 o.push('<p>JSON: good.</p>'); |
|
5295 } else if (data.globals) { |
|
5296 o.push('<div><i>Global</i> ' + |
|
5297 data.globals.sort().join(', ') + '</div>'); |
|
5298 } else { |
|
5299 o.push('<div><i>No new global variables introduced.</i></div>'); |
|
5300 } |
|
5301 |
|
5302 for (i = 0; i < data.functions.length; i += 1) { |
|
5303 f = data.functions[i]; |
|
5304 |
|
5305 o.push('<br><div class=function><i>' + f.line + '-' + |
|
5306 f.last + '</i> ' + (f.name || '') + '(' + |
|
5307 (f.param ? f.param.join(', ') : '') + ')</div>'); |
|
5308 detail('<big><b>Unused</b></big>', f.unused); |
|
5309 detail('Closure', f.closure); |
|
5310 detail('Variable', f['var']); |
|
5311 detail('Exception', f.exception); |
|
5312 detail('Outer', f.outer); |
|
5313 detail('Global', f.global); |
|
5314 detail('Label', f.label); |
|
5315 } |
|
5316 |
|
5317 if (data.member) { |
|
5318 a = to_array(data.member); |
|
5319 if (a.length) { |
|
5320 a = a.sort(); |
|
5321 m = '<br><pre id=members>/*members '; |
|
5322 l = 10; |
|
5323 for (i = 0; i < a.length; i += 1) { |
|
5324 k = a[i]; |
|
5325 n = k.name(); |
|
5326 if (l + n.length > 72) { |
|
5327 o.push(m + '<br>'); |
|
5328 m = ' '; |
|
5329 l = 1; |
|
5330 } |
|
5331 l += n.length + 2; |
|
5332 if (data.member[k] === 1) { |
|
5333 n = '<i>' + n + '</i>'; |
|
5334 } |
|
5335 if (i < a.length - 1) { |
|
5336 n += ', '; |
|
5337 } |
|
5338 m += n; |
|
5339 } |
|
5340 o.push(m + '<br>*/</pre>'); |
|
5341 } |
|
5342 o.push('</div>'); |
|
5343 } |
|
5344 } |
|
5345 return o.join(''); |
|
5346 }; |
|
5347 itself.jslint = itself; |
|
5348 |
|
5349 itself.edition = '2009-08-22'; |
|
5350 |
|
5351 return itself; |
|
5352 |
|
5353 }()); |
|
5354 (function (a) { |
|
5355 if (!a[0]) { |
|
5356 print("Usage: jslint.js file.js"); |
|
5357 quit(1); |
|
5358 } |
|
5359 var input = readFile(a[0]); |
|
5360 if (!input) { |
|
5361 print("jslint: Couldn't open file '" + a[0] + "'."); |
|
5362 quit(1); |
|
5363 } |
|
5364 if (!JSLINT(input, {bitwise: false, eqeqeq: true, immed: true, |
|
5365 laxbreak:false, newcap: false, nomen: false, onevar: false, plusplus: false, |
|
5366 regexp: false, browser: true, undef: true, white: true, indent:2,predef:['window','jQuery','google']})) { |
|
5367 for (var i = 0; i < JSLINT.errors.length; i += 1) { |
|
5368 var e = JSLINT.errors[i]; |
|
5369 if (e) { |
|
5370 print('Lint at line ' + (e.line + 1) + ' character ' + |
|
5371 (e.character + 1) + ': ' + e.reason); |
|
5372 print((e.evidence || ''). |
|
5373 replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1")); |
|
5374 print(''); |
|
5375 } |
|
5376 } |
|
5377 quit(2); |
|
5378 } else { |
|
5379 print("jslint: No problems found in " + a[0]); |
|
5380 quit(); |
|
5381 } |
|
5382 }(arguments)); |