ruby_css_lint 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.document +5 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.rdoc +19 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/csslint/CHANGELOG +286 -0
  8. data/csslint/LICENSE +20 -0
  9. data/csslint/README.md +25 -0
  10. data/csslint/build.xml +242 -0
  11. data/csslint/demos/CSSLintDemo.htm +105 -0
  12. data/csslint/demos/demo.css +43 -0
  13. data/csslint/lib/js.jar +0 -0
  14. data/csslint/lib/jshint.js +3963 -0
  15. data/csslint/lib/parserlib.js +6295 -0
  16. data/csslint/lib/yuitest-rhino-cli.js +3955 -0
  17. data/csslint/lib/yuitest.js +4561 -0
  18. data/csslint/npm/package.json +30 -0
  19. data/csslint/release/csslint-node.js +9125 -0
  20. data/csslint/release/csslint-rhino.js +9390 -0
  21. data/csslint/release/csslint-tests.js +1921 -0
  22. data/csslint/release/csslint-worker.js +9148 -0
  23. data/csslint/release/csslint-wsh.js +9477 -0
  24. data/csslint/release/csslint.js +9127 -0
  25. data/csslint/release/npm/cli.js +307 -0
  26. data/csslint/release/npm/lib/csslint-node.js +9125 -0
  27. data/csslint/release/npm/package.json +30 -0
  28. data/csslint/src/cli/common.js +215 -0
  29. data/csslint/src/cli/node.js +87 -0
  30. data/csslint/src/cli/rhino.js +47 -0
  31. data/csslint/src/cli/wsh.js +134 -0
  32. data/csslint/src/core/CSSLint.js +181 -0
  33. data/csslint/src/core/Reporter.js +161 -0
  34. data/csslint/src/core/Util.js +62 -0
  35. data/csslint/src/formatters/checkstyle-xml.js +109 -0
  36. data/csslint/src/formatters/compact.js +59 -0
  37. data/csslint/src/formatters/csslint-xml.js +68 -0
  38. data/csslint/src/formatters/lint-xml.js +69 -0
  39. data/csslint/src/formatters/text.js +64 -0
  40. data/csslint/src/rules/adjoining-classes.js +45 -0
  41. data/csslint/src/rules/box-model.js +93 -0
  42. data/csslint/src/rules/box-sizing.js +28 -0
  43. data/csslint/src/rules/compatible-vendor-prefixes.js +171 -0
  44. data/csslint/src/rules/display-property-grouping.js +117 -0
  45. data/csslint/src/rules/duplicate-background-images.js +37 -0
  46. data/csslint/src/rules/duplicate-properties.js +46 -0
  47. data/csslint/src/rules/empty-rules.js +34 -0
  48. data/csslint/src/rules/errors.js +23 -0
  49. data/csslint/src/rules/fallback-colors.js +67 -0
  50. data/csslint/src/rules/floats.js +36 -0
  51. data/csslint/src/rules/font-faces.js +30 -0
  52. data/csslint/src/rules/font-sizes.js +35 -0
  53. data/csslint/src/rules/gradients.js +69 -0
  54. data/csslint/src/rules/ids.js +50 -0
  55. data/csslint/src/rules/import.js +23 -0
  56. data/csslint/src/rules/important.js +37 -0
  57. data/csslint/src/rules/known-properties.js +29 -0
  58. data/csslint/src/rules/outline-none.js +73 -0
  59. data/csslint/src/rules/overqualified-elements.js +63 -0
  60. data/csslint/src/rules/qualified-headings.js +38 -0
  61. data/csslint/src/rules/regex-selectors.js +44 -0
  62. data/csslint/src/rules/rules-count.js +28 -0
  63. data/csslint/src/rules/shorthand.js +87 -0
  64. data/csslint/src/rules/star-property-hack.js +27 -0
  65. data/csslint/src/rules/text-indent.js +53 -0
  66. data/csslint/src/rules/underscore-property-hack.js +27 -0
  67. data/csslint/src/rules/unique-headings.js +74 -0
  68. data/csslint/src/rules/universal-selector.js +35 -0
  69. data/csslint/src/rules/unqualified-attributes.js +42 -0
  70. data/csslint/src/rules/vendor-prefix.js +143 -0
  71. data/csslint/src/rules/zero-units.js +34 -0
  72. data/csslint/src/worker/Worker.js +26 -0
  73. data/csslint/tests/all-rules.js +64 -0
  74. data/csslint/tests/core/CSSLint.js +22 -0
  75. data/csslint/tests/core/Reporter.js +36 -0
  76. data/csslint/tests/css/width-100.html +76 -0
  77. data/csslint/tests/formatters/checkstyle-xml.js +44 -0
  78. data/csslint/tests/formatters/compact.js +47 -0
  79. data/csslint/tests/formatters/csslint-xml.js +42 -0
  80. data/csslint/tests/formatters/lint-xml.js +43 -0
  81. data/csslint/tests/formatters/text.js +36 -0
  82. data/csslint/tests/rules/adjoining-classes.js +31 -0
  83. data/csslint/tests/rules/box-model.js +211 -0
  84. data/csslint/tests/rules/box-sizing.js +23 -0
  85. data/csslint/tests/rules/compatible-vendor-prefixes.js +56 -0
  86. data/csslint/tests/rules/display-property-grouping.js +213 -0
  87. data/csslint/tests/rules/duplicate-background-images.js +25 -0
  88. data/csslint/tests/rules/duplicate-properties.js +54 -0
  89. data/csslint/tests/rules/empty-rules.js +18 -0
  90. data/csslint/tests/rules/errors.js +17 -0
  91. data/csslint/tests/rules/fallback-colors.js +162 -0
  92. data/csslint/tests/rules/floats.js +35 -0
  93. data/csslint/tests/rules/font-faces.js +28 -0
  94. data/csslint/tests/rules/font-sizes.js +30 -0
  95. data/csslint/tests/rules/gradients.js +60 -0
  96. data/csslint/tests/rules/ids.js +25 -0
  97. data/csslint/tests/rules/import.js +18 -0
  98. data/csslint/tests/rules/important.js +27 -0
  99. data/csslint/tests/rules/known-properties.js +44 -0
  100. data/csslint/tests/rules/outline-none.js +50 -0
  101. data/csslint/tests/rules/overqualified-elements.js +41 -0
  102. data/csslint/tests/rules/qualified-headings.js +19 -0
  103. data/csslint/tests/rules/regex-selectors.js +52 -0
  104. data/csslint/tests/rules/shorthand.js +36 -0
  105. data/csslint/tests/rules/star-property-hack.js +24 -0
  106. data/csslint/tests/rules/text-indent.js +55 -0
  107. data/csslint/tests/rules/underscore-property-hack.js +24 -0
  108. data/csslint/tests/rules/unique-headings.js +47 -0
  109. data/csslint/tests/rules/universal-selector.js +31 -0
  110. data/csslint/tests/rules/unqualified-attributes.js +37 -0
  111. data/csslint/tests/rules/vendor-prefix.js +76 -0
  112. data/csslint/tests/rules/zero-units.js +44 -0
  113. data/csslint/tests/testrunner.htm +138 -0
  114. data/js.jar +0 -0
  115. data/lib/ruby_css_lint.rb +168 -0
  116. data/test/helper.rb +17 -0
  117. data/test/test_ruby_css_lint.rb +7 -0
  118. metadata +240 -0
@@ -0,0 +1,242 @@
1
+ <project name="csslint" default="build.all">
2
+
3
+ <!-- version number -->
4
+ <property name="csslint.version" value="0.9.8" />
5
+
6
+ <!-- the directories containing the source files -->
7
+ <property name="src.dir" value="./src" />
8
+ <property name="npm.dir" value="./npm" />
9
+ <property name="tests.dir" value="./tests" />
10
+
11
+ <!-- the directories and files to output to -->
12
+ <property name="build.dir" value="./build" />
13
+ <property name="release.dir" value="./release" />
14
+ <property name="build.npm.dir" value="${build.dir}/npm" />
15
+
16
+ <!-- the directory containing library files -->
17
+ <property name="lib.dir" value="./lib" />
18
+
19
+ <!-- library files -->
20
+ <property name="jshint.js" value="jshint.js" />
21
+ <property name="parserlib.js" value="parserlib.js" />
22
+ <property name="yuitest.js" value="yuitest.js" />
23
+
24
+ <!-- external resources -->
25
+ <property name="parser.url" value="https://raw.github.com/nzakas/parser-lib/master/release/parserlib.js"/>
26
+
27
+ <!-- output filenames -->
28
+ <property name="core.build.file" value="csslint.js"/>
29
+ <property name="node.build.file" value="csslint-node.js"/>
30
+ <property name="worker.build.file" value="csslint-worker.js"/>
31
+ <property name="tests.build.file" value="csslint-tests.js"/>
32
+ <property name="rhino.build.file" value="csslint-rhino.js"/>
33
+ <property name="wsh.build.file" value="csslint-wsh.js"/>
34
+
35
+ <!-- embeddable license -->
36
+ <loadfile property="license.text" srcfile="LICENSE" />
37
+
38
+ <!-- get a timestamp -->
39
+ <tstamp>
40
+ <format property="RIGHT_NOW"
41
+ pattern="d-MMMM-yyyy hh:mm:ss"
42
+ locale="en,US"/>
43
+ </tstamp>
44
+ <tstamp>
45
+ <format property="SIMPLE_DATE"
46
+ pattern="MMMM d, yyyy"
47
+ locale="en,US"/>
48
+ </tstamp>
49
+
50
+ <!-- clean -->
51
+ <target name="clean">
52
+ <delete dir="${build.dir}" />
53
+ </target>
54
+
55
+ <target name="changelog.update">
56
+ <exec executable="git" failonerror="true" outputproperty="git.tag">
57
+ <arg line="tag"/>
58
+ </exec>
59
+ <script language="javascript"><![CDATA[
60
+ //get the most recent tag to get the diff
61
+ var tags = csslint.getProperty("git.tag").replace("\r", "").split("\n"),
62
+ lastTag = tags[tags.length-1];
63
+ csslint.setProperty("git.log.range", lastTag + "..HEAD");
64
+ ]]></script>
65
+
66
+ <!-- git log -pretty=format:'* %s (%an)' v0.4.0..v0.5.0-->
67
+ <exec executable="git" failonerror="true" outputproperty="git.changelog">
68
+ <arg line="log --pretty=format:'* %s (%an)' ${git.log.range}"/>
69
+ </exec>
70
+
71
+ <concat destfile="CHANGELOG.tmp" fixlastline="true">
72
+ <header trimleading="yes">${SIMPLE_DATE} - v${csslint.version}
73
+
74
+ ${git.changelog}
75
+
76
+ </header>
77
+ <fileset dir="." includes="CHANGELOG" />
78
+ </concat>
79
+
80
+ <delete file="CHANGELOG"/>
81
+ <move file="CHANGELOG.tmp" tofile="CHANGELOG"/>
82
+
83
+ </target>
84
+
85
+ <!-- validate JS files with JSHint -->
86
+ <target name="lint">
87
+ <fileset dir="${src.dir}" includes="**/*.js" id="jsfiles.raw"/>
88
+ <pathconvert pathsep=" " property="jsfiles.clean" refid="jsfiles.raw" />
89
+ <exec executable="java" failonerror="true">
90
+ <arg line="-jar"/>
91
+ <arg path="${lib.dir}/js.jar"/>
92
+ <arg path="${lib.dir}/jshint.js" />
93
+ <arg line="${jsfiles.clean} curly=true,forin=true,latedef=true,noempty=true,undef=true,rhino=false" />
94
+ </exec>
95
+ </target>
96
+
97
+ <!-- run tests on the command line -->
98
+ <target name="test" depends="build.all,lint,test.general.rules">
99
+ <exec executable="java" failonerror="true">
100
+ <arg line="-jar"/>
101
+ <arg path="${lib.dir}/js.jar"/>
102
+ <arg path="${lib.dir}/yuitest-rhino-cli.js" />
103
+ <arg path="${build.dir}/${core.build.file}" />
104
+ <arg path="${build.dir}/${tests.build.file}" />
105
+ </exec>
106
+ </target>
107
+
108
+ <!-- must be done separately from other tests due to Rhino limitations -->
109
+ <target name="test.general.rules">
110
+ <exec executable="java" failonerror="true">
111
+ <arg line="-jar"/>
112
+ <arg path="${lib.dir}/js.jar"/>
113
+ <arg path="${lib.dir}/yuitest-rhino-cli.js" />
114
+ <arg path="${build.dir}/${core.build.file}" />
115
+ <arg path="${tests.dir}/all-rules.js" />
116
+ </exec>
117
+ </target>
118
+
119
+ <!-- build the core library -->
120
+ <target name="build.core">
121
+ <concat destfile="${build.dir}/${core.build.file}" fixlastline="true">
122
+ <header trimleading="yes">/*!
123
+ ${license.text}
124
+ */
125
+ /* Build time: ${RIGHT_NOW} */
126
+ var CSSLint = (function(){
127
+ </header>
128
+ <fileset dir="${lib.dir}" includes="${parserlib.js}" />
129
+ <filelist dir="${src.dir}/core" files="CSSLint.js" />
130
+ <fileset dir="${src.dir}/core" includes="*.js" excludes="CSSLint.js"/>
131
+ <fileset dir="${src.dir}/rules" includes="*.js" />
132
+ <fileset dir="${src.dir}/formatters" includes="*.js" />
133
+ <footer trimleading="yes">
134
+ return CSSLint;
135
+ })();
136
+ </footer>
137
+
138
+ </concat>
139
+ </target>
140
+
141
+ <!-- build the web worker library -->
142
+ <target name="build.worker">
143
+ <concat destfile="${build.dir}/${worker.build.file}" fixlastline="true">
144
+ <header trimleading="yes">/*!
145
+ ${license.text}
146
+ */
147
+ /* Build time: ${RIGHT_NOW} */
148
+ </header>
149
+ <fileset dir="${lib.dir}" includes="${parserlib.js}" />
150
+ <filelist dir="${src.dir}/core" files="CSSLint.js" />
151
+ <fileset dir="${src.dir}/core" includes="*.js" excludes="CSSLint.js"/>
152
+ <fileset dir="${src.dir}/rules" includes="*.js" />
153
+ <fileset dir="${src.dir}/formatters" includes="*.js" />
154
+ <fileset dir="${src.dir}/worker" includes="*.js" />
155
+ </concat>
156
+ </target>
157
+
158
+
159
+ <!-- build the Node.js package -->
160
+ <target name="build.node">
161
+
162
+ <concat destfile="${build.dir}/${node.build.file}" fixlastline="true">
163
+ <header trimleading="yes">/*!
164
+ ${license.text}
165
+ */
166
+ /* Build time: ${RIGHT_NOW} */
167
+ </header>
168
+ <fileset dir="${lib.dir}" includes="${parserlib.js}" />
169
+ <filelist dir="${src.dir}/core" files="CSSLint.js" />
170
+ <fileset dir="${src.dir}/core" includes="*.js" excludes="CSSLint.js"/>
171
+ <fileset dir="${src.dir}/rules" includes="*.js" />
172
+ <fileset dir="${src.dir}/formatters" includes="*.js" />
173
+ <footer trimleading="yes">
174
+ exports.CSSLint = CSSLint;
175
+ </footer>
176
+ </concat>
177
+
178
+ <mkdir dir="${build.npm.dir}"/>
179
+ <mkdir dir="${build.npm.dir}/lib"/>
180
+ <copy file="${npm.dir}/package.json" todir="${build.npm.dir}"/>
181
+ <concat destfile="${build.npm.dir}/cli.js" fixlastline="true">
182
+ <header trimleading="yes">#!/usr/bin/env node
183
+ /* Build time: ${RIGHT_NOW} */
184
+ </header>
185
+ <filelist dir="${src.dir}/cli" files="common.js,node.js" />
186
+ </concat>
187
+ <copy file="${build.dir}/${node.build.file}" todir="${build.npm.dir}/lib"/>
188
+
189
+ <!-- CRLF will cause Node version to break -->
190
+ <fixcrlf srcdir="${build.dir}" includes="**/*" eol="lf" />
191
+ </target>
192
+
193
+ <!-- build the tests into a single file -->
194
+ <target name="build.tests">
195
+ <concat destfile="${build.dir}/${tests.build.file}" fixlastline="true">
196
+ <fileset dir="${tests.dir}/" includes="**/*.js" excludes="all-rules.js" />
197
+ </concat>
198
+ </target>
199
+
200
+ <!-- build for rhino CLI integration -->
201
+ <target name="build.rhino" depends="build.core">
202
+ <concat destfile="${build.dir}/${rhino.build.file}" fixlastline="true">
203
+ <filelist dir="${build.dir}" files="${core.build.file}" />
204
+ <filelist dir="${src.dir}/cli" files="common.js,rhino.js" />
205
+ </concat>
206
+ </target>
207
+
208
+ <!-- build for WSH CLI integration -->
209
+ <target name="build.wsh" depends="build.core">
210
+ <concat destfile="${build.dir}/${wsh.build.file}" fixlastline="true">
211
+ <filelist dir="${build.dir}" files="${core.build.file}" />
212
+ <filelist dir="${src.dir}/cli" files="common.js,wsh.js" />
213
+ </concat>
214
+ </target>
215
+
216
+ <!-- Create a release with version number embedded -->
217
+ <target name="release" depends="test,build.all,changelog.update">
218
+ <delete dir="${release.dir}" />
219
+ <mkdir dir="${release.dir}"/>
220
+ <copy todir="${release.dir}">
221
+ <fileset dir="${build.dir}" includes="**/*" />
222
+ </copy>
223
+ <replaceregexp match="@VERSION@" replace="${csslint.version}" flags="g" byline="true">
224
+ <fileset dir="${release.dir}" includes="**/*"/>
225
+ </replaceregexp>
226
+ </target>
227
+
228
+ <!-- Update CSS parser with the latest -->
229
+ <target name="parser.update">
230
+ <get src="${parser.url}" dest="${lib.dir}/${parserlib.js}" />
231
+ </target>
232
+
233
+ <!-- Update JSHint with the latest -->
234
+ <target name="jshint.update">
235
+ <get src="${jshint-rhino.url}" dest="${lib.dir}/" />
236
+ <get src="${jshint.url}" dest="${lib.dir}/" />
237
+ </target>
238
+
239
+ <!-- Build all files -->
240
+ <target name="build.all" depends="clean,build.core,build.worker,build.node,build.tests,build.rhino,build.wsh"/>
241
+
242
+ </project>
@@ -0,0 +1,105 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>CSSLint Demo</title>
5
+ <script type="text/javascript" src="../release/csslint.js"></script>
6
+ <style type="text/css">
7
+ .error { color: red; }
8
+ </style>
9
+ </head>
10
+ <body>
11
+ <h1>CSSLint Demo</h1>
12
+ <textarea rows="50" cols="100" id="input">
13
+ @charset "UTF-8";
14
+
15
+ @import url("booya.css") print, screen;
16
+ @import "whatup.css" screen;
17
+ @import "wicked.css";
18
+
19
+ /*Error*/
20
+ @charset "UTF-8";
21
+
22
+
23
+ @namespace "http://www.w3.org/1999/xhtml";
24
+ @namespace svg "http://www.w3.org/2000/svg";
25
+
26
+ /*Warning: empty ruleset */
27
+ .foo {
28
+ }
29
+
30
+ h1 {
31
+ font-weight: bold;
32
+ }
33
+
34
+ /*Warning: qualified heading */
35
+ .foo h1 {
36
+ font-weight: bold;
37
+ }
38
+
39
+ /*Warning: adjoining classes */
40
+ .foo.bar {
41
+ zoom: 1;
42
+ }
43
+
44
+ li.inline {
45
+ width: 100%; /*Warning: 100% can be problematic*/
46
+ }
47
+
48
+ li.last {
49
+ display: inline;
50
+ padding-left: 3px !important;
51
+ padding-right: 3px;
52
+ border-right: 0px;
53
+ }
54
+
55
+ @media print {
56
+ li.inline {
57
+ color: black;
58
+ }
59
+ }
60
+
61
+ @page {
62
+ margin: 10%;
63
+ counter-increment: page;
64
+
65
+ @top-center {
66
+ font-family: sans-serif;
67
+ font-weight: bold;
68
+ font-size: 2em;
69
+ content: counter(page);
70
+ }
71
+ }
72
+ </textarea>
73
+ <input type="button" id="lint-btn" value="Run CSSLint">
74
+ <p>(You may want to keep the CSS kinda small, this could take a while.)</p>
75
+ <div id="output">
76
+
77
+ </div>
78
+ <script>
79
+ (function(){
80
+
81
+ document.body.onclick = function(event) {
82
+ event = event || window.event;
83
+ var target = event.target || event.srcElement,
84
+ results, messages, i, len;
85
+
86
+
87
+ if (target.id == "lint-btn") {
88
+ document.getElementById("output").innerHTML = "";
89
+ results = CSSLint.verify(document.getElementById("input").value);
90
+ messages = results.messages;
91
+ for (i=0, len=messages.length; i < len; i++) {
92
+ log(messages[i].message + " (line " + messages[i].line + ", col " + messages[i].col + ")", messages[i].type);
93
+ }
94
+
95
+ }
96
+ };
97
+
98
+ function log(value, level){
99
+ var output = document.getElementById("output");
100
+ output.innerHTML += "<span class=\"" + level + "\">" + value.replace(/ /g, "&nbsp;") + "</span><br>";
101
+ }
102
+ })();
103
+ </script>
104
+ </body>
105
+ </html>
@@ -0,0 +1,43 @@
1
+ @charset "UTF-8";
2
+
3
+ @import url("booya.css") print,screen;
4
+ @import "whatup.css" screen;
5
+ @import "wicked.css";
6
+
7
+ @namespace "http://www.w3.org/1999/xhtml";
8
+ @namespace svg "http://www.w3.org/2000/svg";
9
+
10
+ li.inline #foo {
11
+ background: rgba(234, 212, 200, 0.5) url("something.png");
12
+ display: inline;
13
+ padding-left: 3px;
14
+ padding-right: 7px;
15
+ border-right: 1px dotted #066;
16
+ }
17
+
18
+ li.last.first {
19
+ display: inline;
20
+ padding-left: 3px !important;
21
+ padding-right: 3px;
22
+ border-right: 0px;
23
+ }
24
+
25
+ @media print {
26
+ li.inline {
27
+ color: black;
28
+ }
29
+
30
+
31
+ @charset "UTF-8";
32
+
33
+ @page {
34
+ margin: 10%;
35
+ counter-increment: page;
36
+
37
+ @top-center {
38
+ font-family: sans-serif;
39
+ font-weight: bold;
40
+ font-size: 2em;
41
+ content: counter(page);
42
+ }
43
+ }
Binary file
@@ -0,0 +1,3963 @@
1
+ /*
2
+ * JSHint, by JSHint Community.
3
+ *
4
+ * Licensed under the same slightly modified MIT license that JSLint is.
5
+ * It stops evil-doers everywhere.
6
+ *
7
+ * JSHint is a derivative work of JSLint:
8
+ *
9
+ * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining
12
+ * a copy of this software and associated documentation files (the "Software"),
13
+ * to deal in the Software without restriction, including without limitation
14
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
+ * and/or sell copies of the Software, and to permit persons to whom
16
+ * the Software is furnished to do so, subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included
19
+ * in all copies or substantial portions of the Software.
20
+ *
21
+ * The Software shall be used for Good, not Evil.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
+ * DEALINGS IN THE SOFTWARE.
30
+ *
31
+ * JSHint was forked from 2010-12-16 edition of JSLint.
32
+ *
33
+ */
34
+
35
+ /*
36
+ JSHINT is a global function. It takes two parameters.
37
+
38
+ var myResult = JSHINT(source, option);
39
+
40
+ The first parameter is either a string or an array of strings. If it is a
41
+ string, it will be split on '\n' or '\r'. If it is an array of strings, it
42
+ is assumed that each string represents one line. The source can be a
43
+ JavaScript text or a JSON text.
44
+
45
+ The second parameter is an optional object of options which control the
46
+ operation of JSHINT. Most of the options are booleans: They are all
47
+ optional and have a default value of false. One of the options, predef,
48
+ can be an array of names, which will be used to declare global variables,
49
+ or an object whose keys are used as global names, with a boolean value
50
+ that determines if they are assignable.
51
+
52
+ If it checks out, JSHINT returns true. Otherwise, it returns false.
53
+
54
+ If false, you can inspect JSHINT.errors to find out the problems.
55
+ JSHINT.errors is an array of objects containing these members:
56
+
57
+ {
58
+ line : The line (relative to 0) at which the lint was found
59
+ character : The character (relative to 0) at which the lint was found
60
+ reason : The problem
61
+ evidence : The text line in which the problem occurred
62
+ raw : The raw message before the details were inserted
63
+ a : The first detail
64
+ b : The second detail
65
+ c : The third detail
66
+ d : The fourth detail
67
+ }
68
+
69
+ If a fatal error was found, a null will be the last element of the
70
+ JSHINT.errors array.
71
+
72
+ You can request a Function Report, which shows all of the functions
73
+ and the parameters and vars that they use. This can be used to find
74
+ implied global variables and other problems. The report is in HTML and
75
+ can be inserted in an HTML <body>.
76
+
77
+ var myReport = JSHINT.report(limited);
78
+
79
+ If limited is true, then the report will be limited to only errors.
80
+
81
+ You can request a data structure which contains JSHint's results.
82
+
83
+ var myData = JSHINT.data();
84
+
85
+ It returns a structure with this form:
86
+
87
+ {
88
+ errors: [
89
+ {
90
+ line: NUMBER,
91
+ character: NUMBER,
92
+ reason: STRING,
93
+ evidence: STRING
94
+ }
95
+ ],
96
+ functions: [
97
+ name: STRING,
98
+ line: NUMBER,
99
+ last: NUMBER,
100
+ param: [
101
+ STRING
102
+ ],
103
+ closure: [
104
+ STRING
105
+ ],
106
+ var: [
107
+ STRING
108
+ ],
109
+ exception: [
110
+ STRING
111
+ ],
112
+ outer: [
113
+ STRING
114
+ ],
115
+ unused: [
116
+ STRING
117
+ ],
118
+ global: [
119
+ STRING
120
+ ],
121
+ label: [
122
+ STRING
123
+ ]
124
+ ],
125
+ globals: [
126
+ STRING
127
+ ],
128
+ member: {
129
+ STRING: NUMBER
130
+ },
131
+ unuseds: [
132
+ {
133
+ name: STRING,
134
+ line: NUMBER
135
+ }
136
+ ],
137
+ implieds: [
138
+ {
139
+ name: STRING,
140
+ line: NUMBER
141
+ }
142
+ ],
143
+ urls: [
144
+ STRING
145
+ ],
146
+ json: BOOLEAN
147
+ }
148
+
149
+ Empty arrays will not be included.
150
+
151
+ */
152
+
153
+ /*jshint
154
+ evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true
155
+ */
156
+
157
+ /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
158
+ "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",
159
+ "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",
160
+ "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
161
+ "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
162
+ __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView,
163
+ Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,
164
+ CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,
165
+ Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, Drag,
166
+ E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
167
+ Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
168
+ FormField, Frame, Function, Fx, GetObject, Group, Hash, HotKey, HTMLElement,
169
+ HtmlTable, Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,
170
+ Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
171
+ MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MoveAnimation, MooTools, Native,
172
+ NEGATIVE_INFINITY, Number, Object, ObjectRange, Option, Options, OverText, PI,
173
+ POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype, RangeError,
174
+ Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,
175
+ SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
176
+ ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
177
+ Slick, Slider, Selector, String, Style, SyntaxError, Sortable, Sortables,
178
+ SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
179
+ Timer, Tips, Type, TypeError, Toggle, Try, URI, URIError, URL, VBArray, WSH,
180
+ WScript, Web, Window, XMLDOM, XMLHttpRequest, XPathEvaluator, XPathException,
181
+ XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, "\\", a,
182
+ addEventListener, address, alert, apply, applicationCache, arguments, arity,
183
+ asi, b, bitwise, block, blur, boolOptions, boss, browser, c, call, callee,
184
+ caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,
185
+ close, closed, closure, comment, condition, confirm, console, constructor,
186
+ content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
187
+ decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
188
+ dojo, dijit, dojox, define, edition, else, emit, encodeURI, encodeURIComponent,
189
+ entityify, eqeqeq, eqnull, errors, es5, escape, eval, event, evidence, evil,
190
+ ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
191
+ forin, fragment, frames, from, fromCharCode, fud, funct, function, functions,
192
+ g, gc, getComputedStyle, getRow, GLOBAL, global, globals, globalstrict,
193
+ hasOwnProperty, help, history, i, id,
194
+ identifier, immed, implieds, include, indent, indexOf, init, ins, instanceOf,
195
+ isAlpha, isApplicationRunning, isArray, isDigit, isFinite, isNaN, join, jshint,
196
+ JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak,
197
+ latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
198
+ log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
199
+ moveTo, mootools, name, navigator, new, newcap, noarg, node, noempty, nomen,
200
+ nonew, nud, onbeforeunload, onblur, onerror, onevar, onfocus, onload, onresize,
201
+ onunload, open, openDatabase, openURL, opener, opera, outer, param, parent,
202
+ parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
203
+ prototype, prototypejs, push, quit, range, raw, reach, reason, regexp,
204
+ readFile, readUrl, regexdash, removeEventListener, replace, report, require,
205
+ reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
206
+ runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal, send,
207
+ serialize, setInterval, setTimeout, shift, slice, sort,spawn, split, stack,
208
+ status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync,
209
+ test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing, type,
210
+ typeOf, Uint16Array, Uint32Array, Uint8Array, undef, unused, urls, value, valueOf,
211
+ var, version, WebSocket, white, window, Worker, wsh*/
212
+
213
+ /*global exports: false */
214
+
215
+ // We build the application inside a function so that we produce only a single
216
+ // global variable. That function will be invoked immediately, and its return
217
+ // value is the JSHINT function itself.
218
+
219
+ var JSHINT = (function () {
220
+ "use strict";
221
+
222
+ var anonname, // The guessed name for anonymous functions.
223
+
224
+ // These are operators that should not be used with the ! operator.
225
+
226
+ bang = {
227
+ '<' : true,
228
+ '<=' : true,
229
+ '==' : true,
230
+ '===': true,
231
+ '!==': true,
232
+ '!=' : true,
233
+ '>' : true,
234
+ '>=' : true,
235
+ '+' : true,
236
+ '-' : true,
237
+ '*' : true,
238
+ '/' : true,
239
+ '%' : true
240
+ },
241
+
242
+ // These are the JSHint boolean options.
243
+
244
+ boolOptions = {
245
+ asi : true, // if automatic semicolon insertion should be tolerated
246
+ bitwise : true, // if bitwise operators should not be allowed
247
+ boss : true, // if advanced usage of assignments should be allowed
248
+ browser : true, // if the standard browser globals should be predefined
249
+ couch : true, // if CouchDB globals should be predefined
250
+ curly : true, // if curly braces around blocks should be required (even in if/for/while)
251
+ debug : true, // if debugger statements should be allowed
252
+ devel : true, // if logging globals should be predefined (console, alert, etc.)
253
+ dojo : true, // if Dojo Toolkit globals should be predefined
254
+ eqeqeq : true, // if === should be required
255
+ eqnull : true, // if == null comparisons should be tolerated
256
+ es5 : true, // if ES5 syntax should be allowed
257
+ evil : true, // if eval should be allowed
258
+ expr : true, // if ExpressionStatement should be allowed as Programs
259
+ forin : true, // if for in statements must filter
260
+ globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict')
261
+ immed : true, // if immediate invocations must be wrapped in parens
262
+ jquery : true, // if jQuery globals should be predefined
263
+ latedef : true, // if the use before definition should not be tolerated
264
+ laxbreak : true, // if line breaks should not be checked
265
+ loopfunc : true, // if functions should be allowed to be defined within loops
266
+ mootools : true, // if MooTools globals should be predefined
267
+ newcap : true, // if constructor names must be capitalized
268
+ noarg : true, // if arguments.caller and arguments.callee should be disallowed
269
+ node : true, // if the Node.js environment globals should be predefined
270
+ noempty : true, // if empty blocks should be disallowed
271
+ nonew : true, // if using `new` for side-effects should be disallowed
272
+ nomen : true, // if names should be checked
273
+ onevar : true, // if only one var statement per function should be allowed
274
+ passfail : true, // if the scan should stop on first error
275
+ plusplus : true, // if increment/decrement should not be allowed
276
+ prototypejs : true, // if Prototype and Scriptaculous globals should be predefined
277
+ regexdash : true, // if unescaped last dash (-) inside brackets should be tolerated
278
+ regexp : true, // if the . should not be allowed in regexp literals
279
+ rhino : true, // if the Rhino environment globals should be predefined
280
+ undef : true, // if variables should be declared before used
281
+ scripturl : true, // if script-targeted URLs should be tolerated
282
+ shadow : true, // if variable shadowing should be tolerated
283
+ strict : true, // require the "use strict"; pragma
284
+ sub : true, // if all forms of subscript notation are tolerated
285
+ supernew : true, // if `new function () { ... };` and `new Object;` should be tolerated
286
+ trailing : true, // if trailing whitespace rules apply
287
+ white : true, // if strict whitespace rules apply
288
+ wsh : true // if the Windows Scripting Host environment globals should be predefined
289
+ },
290
+
291
+ // browser contains a set of global names which are commonly provided by a
292
+ // web browser environment.
293
+
294
+ browser = {
295
+ ArrayBuffer : false,
296
+ ArrayBufferView : false,
297
+ addEventListener: false,
298
+ applicationCache: false,
299
+ blur : false,
300
+ clearInterval : false,
301
+ clearTimeout : false,
302
+ close : false,
303
+ closed : false,
304
+ DataView : false,
305
+ defaultStatus : false,
306
+ document : false,
307
+ event : false,
308
+ FileReader : false,
309
+ Float32Array : false,
310
+ Float64Array : false,
311
+ focus : false,
312
+ frames : false,
313
+ getComputedStyle: false,
314
+ HTMLElement : false,
315
+ history : false,
316
+ Int16Array : false,
317
+ Int32Array : false,
318
+ Int8Array : false,
319
+ Image : false,
320
+ length : false,
321
+ localStorage : false,
322
+ location : false,
323
+ moveBy : false,
324
+ moveTo : false,
325
+ name : false,
326
+ navigator : false,
327
+ onbeforeunload : true,
328
+ onblur : true,
329
+ onerror : true,
330
+ onfocus : true,
331
+ onload : true,
332
+ onresize : true,
333
+ onunload : true,
334
+ open : false,
335
+ openDatabase : false,
336
+ opener : false,
337
+ Option : false,
338
+ parent : false,
339
+ print : false,
340
+ removeEventListener: false,
341
+ resizeBy : false,
342
+ resizeTo : false,
343
+ screen : false,
344
+ scroll : false,
345
+ scrollBy : false,
346
+ scrollTo : false,
347
+ setInterval : false,
348
+ setTimeout : false,
349
+ status : false,
350
+ top : false,
351
+ Uint16Array : false,
352
+ Uint32Array : false,
353
+ Uint8Array : false,
354
+ WebSocket : false,
355
+ window : false,
356
+ Worker : false,
357
+ XMLHttpRequest : false,
358
+ XPathEvaluator : false,
359
+ XPathException : false,
360
+ XPathExpression : false,
361
+ XPathNamespace : false,
362
+ XPathNSResolver : false,
363
+ XPathResult : false
364
+ },
365
+
366
+ couch = {
367
+ "require" : false,
368
+ respond : false,
369
+ getRow : false,
370
+ emit : false,
371
+ send : false,
372
+ start : false,
373
+ sum : false,
374
+ log : false,
375
+ exports : false,
376
+ module : false
377
+ },
378
+
379
+ devel = {
380
+ alert : false,
381
+ confirm : false,
382
+ console : false,
383
+ Debug : false,
384
+ opera : false,
385
+ prompt : false
386
+ },
387
+
388
+ dojo = {
389
+ dojo : false,
390
+ dijit : false,
391
+ dojox : false,
392
+ define : false,
393
+ "require" : false
394
+ },
395
+
396
+ escapes = {
397
+ '\b': '\\b',
398
+ '\t': '\\t',
399
+ '\n': '\\n',
400
+ '\f': '\\f',
401
+ '\r': '\\r',
402
+ '"' : '\\"',
403
+ '/' : '\\/',
404
+ '\\': '\\\\'
405
+ },
406
+
407
+ funct, // The current function
408
+
409
+ functionicity = [
410
+ 'closure', 'exception', 'global', 'label',
411
+ 'outer', 'unused', 'var'
412
+ ],
413
+
414
+ functions, // All of the functions
415
+
416
+ global, // The global scope
417
+ implied, // Implied globals
418
+ inblock,
419
+ indent,
420
+ jsonmode,
421
+
422
+ jquery = {
423
+ '$' : false,
424
+ jQuery : false
425
+ },
426
+
427
+ lines,
428
+ lookahead,
429
+ member,
430
+ membersOnly,
431
+
432
+ mootools = {
433
+ '$' : false,
434
+ '$$' : false,
435
+ Assets : false,
436
+ Browser : false,
437
+ Chain : false,
438
+ Class : false,
439
+ Color : false,
440
+ Cookie : false,
441
+ Core : false,
442
+ Document : false,
443
+ DomReady : false,
444
+ DOMReady : false,
445
+ Drag : false,
446
+ Element : false,
447
+ Elements : false,
448
+ Event : false,
449
+ Events : false,
450
+ Fx : false,
451
+ Group : false,
452
+ Hash : false,
453
+ HtmlTable : false,
454
+ Iframe : false,
455
+ IframeShim : false,
456
+ InputValidator : false,
457
+ instanceOf : false,
458
+ Keyboard : false,
459
+ Locale : false,
460
+ Mask : false,
461
+ MooTools : false,
462
+ Native : false,
463
+ Options : false,
464
+ OverText : false,
465
+ Request : false,
466
+ Scroller : false,
467
+ Slick : false,
468
+ Slider : false,
469
+ Sortables : false,
470
+ Spinner : false,
471
+ Swiff : false,
472
+ Tips : false,
473
+ Type : false,
474
+ typeOf : false,
475
+ URI : false,
476
+ Window : false
477
+ },
478
+
479
+ nexttoken,
480
+
481
+ node = {
482
+ __filename : false,
483
+ __dirname : false,
484
+ exports : false,
485
+ Buffer : false,
486
+ GLOBAL : false,
487
+ global : false,
488
+ module : false,
489
+ process : false,
490
+ require : false
491
+ },
492
+
493
+ noreach,
494
+ option,
495
+ predefined, // Global variables defined by option
496
+ prereg,
497
+ prevtoken,
498
+
499
+ prototypejs = {
500
+ '$' : false,
501
+ '$$' : false,
502
+ '$A' : false,
503
+ '$F' : false,
504
+ '$H' : false,
505
+ '$R' : false,
506
+ '$break' : false,
507
+ '$continue' : false,
508
+ '$w' : false,
509
+ Abstract : false,
510
+ Ajax : false,
511
+ Class : false,
512
+ Enumerable : false,
513
+ Element : false,
514
+ Event : false,
515
+ Field : false,
516
+ Form : false,
517
+ Hash : false,
518
+ Insertion : false,
519
+ ObjectRange : false,
520
+ PeriodicalExecuter: false,
521
+ Position : false,
522
+ Prototype : false,
523
+ Selector : false,
524
+ Template : false,
525
+ Toggle : false,
526
+ Try : false,
527
+ Autocompleter : false,
528
+ Builder : false,
529
+ Control : false,
530
+ Draggable : false,
531
+ Draggables : false,
532
+ Droppables : false,
533
+ Effect : false,
534
+ Sortable : false,
535
+ SortableObserver : false,
536
+ Sound : false,
537
+ Scriptaculous : false
538
+ },
539
+
540
+ rhino = {
541
+ defineClass : false,
542
+ deserialize : false,
543
+ gc : false,
544
+ help : false,
545
+ importPackage: false,
546
+ java : false,
547
+ load : false,
548
+ loadClass : false,
549
+ print : false,
550
+ quit : false,
551
+ readFile : false,
552
+ readUrl : false,
553
+ runCommand : false,
554
+ seal : false,
555
+ serialize : false,
556
+ spawn : false,
557
+ sync : false,
558
+ toint32 : false,
559
+ version : false
560
+ },
561
+
562
+ scope, // The current scope
563
+ src,
564
+ stack,
565
+
566
+ // standard contains the global names that are provided by the
567
+ // ECMAScript standard.
568
+
569
+ standard = {
570
+ Array : false,
571
+ Boolean : false,
572
+ Date : false,
573
+ decodeURI : false,
574
+ decodeURIComponent : false,
575
+ encodeURI : false,
576
+ encodeURIComponent : false,
577
+ Error : false,
578
+ 'eval' : false,
579
+ EvalError : false,
580
+ Function : false,
581
+ hasOwnProperty : false,
582
+ isFinite : false,
583
+ isNaN : false,
584
+ JSON : false,
585
+ Math : false,
586
+ Number : false,
587
+ Object : false,
588
+ parseInt : false,
589
+ parseFloat : false,
590
+ RangeError : false,
591
+ ReferenceError : false,
592
+ RegExp : false,
593
+ String : false,
594
+ SyntaxError : false,
595
+ TypeError : false,
596
+ URIError : false
597
+ },
598
+
599
+ standard_member = {
600
+ E : true,
601
+ LN2 : true,
602
+ LN10 : true,
603
+ LOG2E : true,
604
+ LOG10E : true,
605
+ MAX_VALUE : true,
606
+ MIN_VALUE : true,
607
+ NEGATIVE_INFINITY : true,
608
+ PI : true,
609
+ POSITIVE_INFINITY : true,
610
+ SQRT1_2 : true,
611
+ SQRT2 : true
612
+ },
613
+
614
+ strict_mode,
615
+ syntax = {},
616
+ tab,
617
+ token,
618
+ urls,
619
+ warnings,
620
+
621
+ wsh = {
622
+ ActiveXObject : true,
623
+ Enumerator : true,
624
+ GetObject : true,
625
+ ScriptEngine : true,
626
+ ScriptEngineBuildVersion : true,
627
+ ScriptEngineMajorVersion : true,
628
+ ScriptEngineMinorVersion : true,
629
+ VBArray : true,
630
+ WSH : true,
631
+ WScript : true
632
+ },
633
+
634
+ // Regular expressions. Some of these are stupidly long.
635
+
636
+ // unsafe comment or string
637
+ ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i,
638
+ // unsafe characters that are silently deleted by one or more browsers
639
+ cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
640
+ // token
641
+ tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
642
+ // characters in strings that need escapement
643
+ nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
644
+ nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
645
+ // star slash
646
+ lx = /\*\/|\/\*/,
647
+ // identifier
648
+ ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
649
+ // javascript url
650
+ jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
651
+ // catches /* falls through */ comments
652
+ ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
653
+
654
+ function F() {} // Used by Object.create
655
+
656
+ function is_own(object, name) {
657
+
658
+ // The object.hasOwnProperty method fails when the property under consideration
659
+ // is named 'hasOwnProperty'. So we have to use this more convoluted form.
660
+
661
+ return Object.prototype.hasOwnProperty.call(object, name);
662
+ }
663
+
664
+ // Provide critical ES5 functions to ES3.
665
+
666
+ if (typeof Array.isArray !== 'function') {
667
+ Array.isArray = function (o) {
668
+ return Object.prototype.toString.apply(o) === '[object Array]';
669
+ };
670
+ }
671
+
672
+ if (typeof Object.create !== 'function') {
673
+ Object.create = function (o) {
674
+ F.prototype = o;
675
+ return new F();
676
+ };
677
+ }
678
+
679
+ if (typeof Object.keys !== 'function') {
680
+ Object.keys = function (o) {
681
+ var a = [], k;
682
+ for (k in o) {
683
+ if (is_own(o, k)) {
684
+ a.push(k);
685
+ }
686
+ }
687
+ return a;
688
+ };
689
+ }
690
+
691
+ // Non standard methods
692
+
693
+ if (typeof String.prototype.entityify !== 'function') {
694
+ String.prototype.entityify = function () {
695
+ return this
696
+ .replace(/&/g, '&amp;')
697
+ .replace(/</g, '&lt;')
698
+ .replace(/>/g, '&gt;');
699
+ };
700
+ }
701
+
702
+ if (typeof String.prototype.isAlpha !== 'function') {
703
+ String.prototype.isAlpha = function () {
704
+ return (this >= 'a' && this <= 'z\uffff') ||
705
+ (this >= 'A' && this <= 'Z\uffff');
706
+ };
707
+ }
708
+
709
+ if (typeof String.prototype.isDigit !== 'function') {
710
+ String.prototype.isDigit = function () {
711
+ return (this >= '0' && this <= '9');
712
+ };
713
+ }
714
+
715
+ if (typeof String.prototype.supplant !== 'function') {
716
+ String.prototype.supplant = function (o) {
717
+ return this.replace(/\{([^{}]*)\}/g, function (a, b) {
718
+ var r = o[b];
719
+ return typeof r === 'string' || typeof r === 'number' ? r : a;
720
+ });
721
+ };
722
+ }
723
+
724
+ if (typeof String.prototype.name !== 'function') {
725
+ String.prototype.name = function () {
726
+
727
+ // If the string looks like an identifier, then we can return it as is.
728
+ // If the string contains no control characters, no quote characters, and no
729
+ // backslash characters, then we can simply slap some quotes around it.
730
+ // Otherwise we must also replace the offending characters with safe
731
+ // sequences.
732
+
733
+ if (ix.test(this)) {
734
+ return this;
735
+ }
736
+ if (nx.test(this)) {
737
+ return '"' + this.replace(nxg, function (a) {
738
+ var c = escapes[a];
739
+ if (c) {
740
+ return c;
741
+ }
742
+ return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
743
+ }) + '"';
744
+ }
745
+ return '"' + this + '"';
746
+ };
747
+ }
748
+
749
+
750
+ function combine(t, o) {
751
+ var n;
752
+ for (n in o) {
753
+ if (is_own(o, n)) {
754
+ t[n] = o[n];
755
+ }
756
+ }
757
+ }
758
+
759
+ function assume() {
760
+ if (option.couch)
761
+ combine(predefined, couch);
762
+
763
+ if (option.rhino)
764
+ combine(predefined, rhino);
765
+
766
+ if (option.prototypejs)
767
+ combine(predefined, prototypejs);
768
+
769
+ if (option.node)
770
+ combine(predefined, node);
771
+
772
+ if (option.devel)
773
+ combine(predefined, devel);
774
+
775
+ if (option.dojo)
776
+ combine(predefined, dojo);
777
+
778
+ if (option.browser)
779
+ combine(predefined, browser);
780
+
781
+ if (option.jquery)
782
+ combine(predefined, jquery);
783
+
784
+ if (option.mootools)
785
+ combine(predefined, mootools);
786
+
787
+ if (option.wsh)
788
+ combine(predefined, wsh);
789
+
790
+ if (option.globalstrict && option.strict !== false)
791
+ option.strict = true;
792
+ }
793
+
794
+
795
+ // Produce an error warning.
796
+
797
+ function quit(message, line, chr) {
798
+ var percentage = Math.floor((line / lines.length) * 100);
799
+
800
+ throw {
801
+ name: 'JSHintError',
802
+ line: line,
803
+ character: chr,
804
+ message: message + " (" + percentage + "% scanned)."
805
+ };
806
+ }
807
+
808
+ function warning(m, t, a, b, c, d) {
809
+ var ch, l, w;
810
+ t = t || nexttoken;
811
+ if (t.id === '(end)') { // `~
812
+ t = token;
813
+ }
814
+ l = t.line || 0;
815
+ ch = t.from || 0;
816
+ w = {
817
+ id: '(error)',
818
+ raw: m,
819
+ evidence: lines[l - 1] || '',
820
+ line: l,
821
+ character: ch,
822
+ a: a,
823
+ b: b,
824
+ c: c,
825
+ d: d
826
+ };
827
+ w.reason = m.supplant(w);
828
+ JSHINT.errors.push(w);
829
+ if (option.passfail) {
830
+ quit('Stopping. ', l, ch);
831
+ }
832
+ warnings += 1;
833
+ if (warnings >= option.maxerr) {
834
+ quit("Too many errors.", l, ch);
835
+ }
836
+ return w;
837
+ }
838
+
839
+ function warningAt(m, l, ch, a, b, c, d) {
840
+ return warning(m, {
841
+ line: l,
842
+ from: ch
843
+ }, a, b, c, d);
844
+ }
845
+
846
+ function error(m, t, a, b, c, d) {
847
+ var w = warning(m, t, a, b, c, d);
848
+ quit("Stopping, unable to continue.", w.line, w.character);
849
+ }
850
+
851
+ function errorAt(m, l, ch, a, b, c, d) {
852
+ return error(m, {
853
+ line: l,
854
+ from: ch
855
+ }, a, b, c, d);
856
+ }
857
+
858
+
859
+
860
+ // lexical analysis and token construction
861
+
862
+ var lex = (function lex() {
863
+ var character, from, line, s;
864
+
865
+ // Private lex methods
866
+
867
+ function nextLine() {
868
+ var at,
869
+ tw; // trailing whitespace check
870
+
871
+ if (line >= lines.length)
872
+ return false;
873
+
874
+ character = 1;
875
+ s = lines[line];
876
+ line += 1;
877
+ at = s.search(/ \t/);
878
+
879
+ if (at >= 0)
880
+ warningAt("Mixed spaces and tabs.", line, at + 1);
881
+
882
+ s = s.replace(/\t/g, tab);
883
+ at = s.search(cx);
884
+
885
+ if (at >= 0)
886
+ warningAt("Unsafe character.", line, at);
887
+
888
+ if (option.maxlen && option.maxlen < s.length)
889
+ warningAt("Line too long.", line, s.length);
890
+
891
+ // Check for trailing whitespaces
892
+ tw = s.search(/\s+$/);
893
+ if (option.trailing && ~tw && !~s.search(/^\s+$/))
894
+ warningAt("Trailing whitespace.", line, tw);
895
+
896
+ return true;
897
+ }
898
+
899
+ // Produce a token object. The token inherits from a syntax symbol.
900
+
901
+ function it(type, value) {
902
+ var i, t;
903
+ if (type === '(color)' || type === '(range)') {
904
+ t = {type: type};
905
+ } else if (type === '(punctuator)' ||
906
+ (type === '(identifier)' && is_own(syntax, value))) {
907
+ t = syntax[value] || syntax['(error)'];
908
+ } else {
909
+ t = syntax[type];
910
+ }
911
+ t = Object.create(t);
912
+ if (type === '(string)' || type === '(range)') {
913
+ if (!option.scripturl && jx.test(value)) {
914
+ warningAt("Script URL.", line, from);
915
+ }
916
+ }
917
+ if (type === '(identifier)') {
918
+ t.identifier = true;
919
+ if (value === '__iterator__' || value === '__proto__') {
920
+ errorAt("Reserved name '{a}'.",
921
+ line, from, value);
922
+ } else if (option.nomen &&
923
+ (value.charAt(0) === '_' ||
924
+ value.charAt(value.length - 1) === '_')) {
925
+ warningAt("Unexpected {a} in '{b}'.", line, from,
926
+ "dangling '_'", value);
927
+ }
928
+ }
929
+ t.value = value;
930
+ t.line = line;
931
+ t.character = character;
932
+ t.from = from;
933
+ i = t.id;
934
+ if (i !== '(endline)') {
935
+ prereg = i &&
936
+ (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
937
+ i === 'return');
938
+ }
939
+ return t;
940
+ }
941
+
942
+ // Public lex methods
943
+
944
+ return {
945
+ init: function (source) {
946
+ if (typeof source === 'string') {
947
+ lines = source
948
+ .replace(/\r\n/g, '\n')
949
+ .replace(/\r/g, '\n')
950
+ .split('\n');
951
+ } else {
952
+ lines = source;
953
+ }
954
+
955
+ // If the first line is a shebang (#!), make it a blank and move on.
956
+ // Shebangs are used by Node scripts.
957
+ if (lines[0] && lines[0].substr(0, 2) == '#!')
958
+ lines[0] = '';
959
+
960
+ line = 0;
961
+ nextLine();
962
+ from = 1;
963
+ },
964
+
965
+ range: function (begin, end) {
966
+ var c, value = '';
967
+ from = character;
968
+ if (s.charAt(0) !== begin) {
969
+ errorAt("Expected '{a}' and instead saw '{b}'.",
970
+ line, character, begin, s.charAt(0));
971
+ }
972
+ for (;;) {
973
+ s = s.slice(1);
974
+ character += 1;
975
+ c = s.charAt(0);
976
+ switch (c) {
977
+ case '':
978
+ errorAt("Missing '{a}'.", line, character, c);
979
+ break;
980
+ case end:
981
+ s = s.slice(1);
982
+ character += 1;
983
+ return it('(range)', value);
984
+ case '\\':
985
+ warningAt("Unexpected '{a}'.", line, character, c);
986
+ }
987
+ value += c;
988
+ }
989
+
990
+ },
991
+
992
+ // token -- this is called by advance to get the next token.
993
+
994
+ token: function () {
995
+ var b, c, captures, d, depth, high, i, l, low, q, t;
996
+
997
+ function match(x) {
998
+ var r = x.exec(s), r1;
999
+ if (r) {
1000
+ l = r[0].length;
1001
+ r1 = r[1];
1002
+ c = r1.charAt(0);
1003
+ s = s.substr(l);
1004
+ from = character + l - r1.length;
1005
+ character += l;
1006
+ return r1;
1007
+ }
1008
+ }
1009
+
1010
+ function string(x) {
1011
+ var c, j, r = '';
1012
+
1013
+ if (jsonmode && x !== '"') {
1014
+ warningAt("Strings must use doublequote.",
1015
+ line, character);
1016
+ }
1017
+
1018
+ function esc(n) {
1019
+ var i = parseInt(s.substr(j + 1, n), 16);
1020
+ j += n;
1021
+ if (i >= 32 && i <= 126 &&
1022
+ i !== 34 && i !== 92 && i !== 39) {
1023
+ warningAt("Unnecessary escapement.", line, character);
1024
+ }
1025
+ character += n;
1026
+ c = String.fromCharCode(i);
1027
+ }
1028
+ j = 0;
1029
+ for (;;) {
1030
+ while (j >= s.length) {
1031
+ j = 0;
1032
+ if (!nextLine()) {
1033
+ errorAt("Unclosed string.", line, from);
1034
+ }
1035
+ }
1036
+ c = s.charAt(j);
1037
+ if (c === x) {
1038
+ character += 1;
1039
+ s = s.substr(j + 1);
1040
+ return it('(string)', r, x);
1041
+ }
1042
+ if (c < ' ') {
1043
+ if (c === '\n' || c === '\r') {
1044
+ break;
1045
+ }
1046
+ warningAt("Control character in string: {a}.",
1047
+ line, character + j, s.slice(0, j));
1048
+ } else if (c === '\\') {
1049
+ j += 1;
1050
+ character += 1;
1051
+ c = s.charAt(j);
1052
+ switch (c) {
1053
+ case '\\':
1054
+ case '"':
1055
+ case '/':
1056
+ break;
1057
+ case '\'':
1058
+ if (jsonmode) {
1059
+ warningAt("Avoid \\'.", line, character);
1060
+ }
1061
+ break;
1062
+ case 'b':
1063
+ c = '\b';
1064
+ break;
1065
+ case 'f':
1066
+ c = '\f';
1067
+ break;
1068
+ case 'n':
1069
+ c = '\n';
1070
+ break;
1071
+ case 'r':
1072
+ c = '\r';
1073
+ break;
1074
+ case 't':
1075
+ c = '\t';
1076
+ break;
1077
+ case 'u':
1078
+ esc(4);
1079
+ break;
1080
+ case 'v':
1081
+ if (jsonmode) {
1082
+ warningAt("Avoid \\v.", line, character);
1083
+ }
1084
+ c = '\v';
1085
+ break;
1086
+ case 'x':
1087
+ if (jsonmode) {
1088
+ warningAt("Avoid \\x-.", line, character);
1089
+ }
1090
+ esc(2);
1091
+ break;
1092
+ default:
1093
+ warningAt("Bad escapement.", line, character);
1094
+ }
1095
+ }
1096
+ r += c;
1097
+ character += 1;
1098
+ j += 1;
1099
+ }
1100
+ }
1101
+
1102
+ for (;;) {
1103
+ if (!s) {
1104
+ return it(nextLine() ? '(endline)' : '(end)', '');
1105
+ }
1106
+ t = match(tx);
1107
+ if (!t) {
1108
+ t = '';
1109
+ c = '';
1110
+ while (s && s < '!') {
1111
+ s = s.substr(1);
1112
+ }
1113
+ if (s) {
1114
+ errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
1115
+ }
1116
+ } else {
1117
+
1118
+ // identifier
1119
+
1120
+ if (c.isAlpha() || c === '_' || c === '$') {
1121
+ return it('(identifier)', t);
1122
+ }
1123
+
1124
+ // number
1125
+
1126
+ if (c.isDigit()) {
1127
+ if (!isFinite(Number(t))) {
1128
+ warningAt("Bad number '{a}'.",
1129
+ line, character, t);
1130
+ }
1131
+ if (s.substr(0, 1).isAlpha()) {
1132
+ warningAt("Missing space after '{a}'.",
1133
+ line, character, t);
1134
+ }
1135
+ if (c === '0') {
1136
+ d = t.substr(1, 1);
1137
+ if (d.isDigit()) {
1138
+ if (token.id !== '.') {
1139
+ warningAt("Don't use extra leading zeros '{a}'.",
1140
+ line, character, t);
1141
+ }
1142
+ } else if (jsonmode && (d === 'x' || d === 'X')) {
1143
+ warningAt("Avoid 0x-. '{a}'.",
1144
+ line, character, t);
1145
+ }
1146
+ }
1147
+ if (t.substr(t.length - 1) === '.') {
1148
+ warningAt(
1149
+ "A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
1150
+ }
1151
+ return it('(number)', t);
1152
+ }
1153
+ switch (t) {
1154
+
1155
+ // string
1156
+
1157
+ case '"':
1158
+ case "'":
1159
+ return string(t);
1160
+
1161
+ // // comment
1162
+
1163
+ case '//':
1164
+ if (src) {
1165
+ warningAt("Unexpected comment.", line, character);
1166
+ }
1167
+ s = '';
1168
+ token.comment = true;
1169
+ break;
1170
+
1171
+ // /* comment
1172
+
1173
+ case '/*':
1174
+ if (src) {
1175
+ warningAt("Unexpected comment.", line, character);
1176
+ }
1177
+ for (;;) {
1178
+ i = s.search(lx);
1179
+ if (i >= 0) {
1180
+ break;
1181
+ }
1182
+ if (!nextLine()) {
1183
+ errorAt("Unclosed comment.", line, character);
1184
+ }
1185
+ }
1186
+ character += i + 2;
1187
+ if (s.substr(i, 1) === '/') {
1188
+ errorAt("Nested comment.", line, character);
1189
+ }
1190
+ s = s.substr(i + 2);
1191
+ token.comment = true;
1192
+ break;
1193
+
1194
+ // /*members /*jshint /*global
1195
+
1196
+ case '/*members':
1197
+ case '/*member':
1198
+ case '/*jshint':
1199
+ case '/*jslint':
1200
+ case '/*global':
1201
+ case '*/':
1202
+ return {
1203
+ value: t,
1204
+ type: 'special',
1205
+ line: line,
1206
+ character: character,
1207
+ from: from
1208
+ };
1209
+
1210
+ case '':
1211
+ break;
1212
+ // /
1213
+ case '/':
1214
+ if (token.id === '/=') {
1215
+ errorAt(
1216
+ "A regular expression literal can be confused with '/='.", line, from);
1217
+ }
1218
+ if (prereg) {
1219
+ depth = 0;
1220
+ captures = 0;
1221
+ l = 0;
1222
+ for (;;) {
1223
+ b = true;
1224
+ c = s.charAt(l);
1225
+ l += 1;
1226
+ switch (c) {
1227
+ case '':
1228
+ errorAt("Unclosed regular expression.",
1229
+ line, from);
1230
+ return;
1231
+ case '/':
1232
+ if (depth > 0) {
1233
+ warningAt("Unescaped '{a}'.",
1234
+ line, from + l, '/');
1235
+ }
1236
+ c = s.substr(0, l - 1);
1237
+ q = {
1238
+ g: true,
1239
+ i: true,
1240
+ m: true
1241
+ };
1242
+ while (q[s.charAt(l)] === true) {
1243
+ q[s.charAt(l)] = false;
1244
+ l += 1;
1245
+ }
1246
+ character += l;
1247
+ s = s.substr(l);
1248
+ q = s.charAt(0);
1249
+ if (q === '/' || q === '*') {
1250
+ errorAt("Confusing regular expression.",
1251
+ line, from);
1252
+ }
1253
+ return it('(regexp)', c);
1254
+ case '\\':
1255
+ c = s.charAt(l);
1256
+ if (c < ' ') {
1257
+ warningAt(
1258
+ "Unexpected control character in regular expression.", line, from + l);
1259
+ } else if (c === '<') {
1260
+ warningAt(
1261
+ "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1262
+ }
1263
+ l += 1;
1264
+ break;
1265
+ case '(':
1266
+ depth += 1;
1267
+ b = false;
1268
+ if (s.charAt(l) === '?') {
1269
+ l += 1;
1270
+ switch (s.charAt(l)) {
1271
+ case ':':
1272
+ case '=':
1273
+ case '!':
1274
+ l += 1;
1275
+ break;
1276
+ default:
1277
+ warningAt(
1278
+ "Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
1279
+ }
1280
+ } else {
1281
+ captures += 1;
1282
+ }
1283
+ break;
1284
+ case '|':
1285
+ b = false;
1286
+ break;
1287
+ case ')':
1288
+ if (depth === 0) {
1289
+ warningAt("Unescaped '{a}'.",
1290
+ line, from + l, ')');
1291
+ } else {
1292
+ depth -= 1;
1293
+ }
1294
+ break;
1295
+ case ' ':
1296
+ q = 1;
1297
+ while (s.charAt(l) === ' ') {
1298
+ l += 1;
1299
+ q += 1;
1300
+ }
1301
+ if (q > 1) {
1302
+ warningAt(
1303
+ "Spaces are hard to count. Use {{a}}.", line, from + l, q);
1304
+ }
1305
+ break;
1306
+ case '[':
1307
+ c = s.charAt(l);
1308
+ if (c === '^') {
1309
+ l += 1;
1310
+ if (option.regexp) {
1311
+ warningAt("Insecure '{a}'.",
1312
+ line, from + l, c);
1313
+ } else if (s.charAt(l) === ']') {
1314
+ errorAt("Unescaped '{a}'.",
1315
+ line, from + l, '^');
1316
+ }
1317
+ }
1318
+ q = false;
1319
+ if (c === ']') {
1320
+ warningAt("Empty class.", line,
1321
+ from + l - 1);
1322
+ q = true;
1323
+ }
1324
+ klass: do {
1325
+ c = s.charAt(l);
1326
+ l += 1;
1327
+ switch (c) {
1328
+ case '[':
1329
+ case '^':
1330
+ warningAt("Unescaped '{a}'.",
1331
+ line, from + l, c);
1332
+ q = true;
1333
+ break;
1334
+ case '-':
1335
+ if (q) {
1336
+ q = false;
1337
+ } else {
1338
+ warningAt("Unescaped '{a}'.",
1339
+ line, from + l, '-');
1340
+ q = true;
1341
+ }
1342
+ break;
1343
+ case ']':
1344
+ if (!q && !option.regexdash) {
1345
+ warningAt("Unescaped '{a}'.",
1346
+ line, from + l - 1, '-');
1347
+ }
1348
+ break klass;
1349
+ case '\\':
1350
+ c = s.charAt(l);
1351
+ if (c < ' ') {
1352
+ warningAt(
1353
+ "Unexpected control character in regular expression.", line, from + l);
1354
+ } else if (c === '<') {
1355
+ warningAt(
1356
+ "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1357
+ }
1358
+ l += 1;
1359
+ q = true;
1360
+ break;
1361
+ case '/':
1362
+ warningAt("Unescaped '{a}'.",
1363
+ line, from + l - 1, '/');
1364
+ q = true;
1365
+ break;
1366
+ case '<':
1367
+ q = true;
1368
+ break;
1369
+ default:
1370
+ q = true;
1371
+ }
1372
+ } while (c);
1373
+ break;
1374
+ case '.':
1375
+ if (option.regexp) {
1376
+ warningAt("Insecure '{a}'.", line,
1377
+ from + l, c);
1378
+ }
1379
+ break;
1380
+ case ']':
1381
+ case '?':
1382
+ case '{':
1383
+ case '}':
1384
+ case '+':
1385
+ case '*':
1386
+ warningAt("Unescaped '{a}'.", line,
1387
+ from + l, c);
1388
+ }
1389
+ if (b) {
1390
+ switch (s.charAt(l)) {
1391
+ case '?':
1392
+ case '+':
1393
+ case '*':
1394
+ l += 1;
1395
+ if (s.charAt(l) === '?') {
1396
+ l += 1;
1397
+ }
1398
+ break;
1399
+ case '{':
1400
+ l += 1;
1401
+ c = s.charAt(l);
1402
+ if (c < '0' || c > '9') {
1403
+ warningAt(
1404
+ "Expected a number and instead saw '{a}'.", line, from + l, c);
1405
+ }
1406
+ l += 1;
1407
+ low = +c;
1408
+ for (;;) {
1409
+ c = s.charAt(l);
1410
+ if (c < '0' || c > '9') {
1411
+ break;
1412
+ }
1413
+ l += 1;
1414
+ low = +c + (low * 10);
1415
+ }
1416
+ high = low;
1417
+ if (c === ',') {
1418
+ l += 1;
1419
+ high = Infinity;
1420
+ c = s.charAt(l);
1421
+ if (c >= '0' && c <= '9') {
1422
+ l += 1;
1423
+ high = +c;
1424
+ for (;;) {
1425
+ c = s.charAt(l);
1426
+ if (c < '0' || c > '9') {
1427
+ break;
1428
+ }
1429
+ l += 1;
1430
+ high = +c + (high * 10);
1431
+ }
1432
+ }
1433
+ }
1434
+ if (s.charAt(l) !== '}') {
1435
+ warningAt(
1436
+ "Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
1437
+ } else {
1438
+ l += 1;
1439
+ }
1440
+ if (s.charAt(l) === '?') {
1441
+ l += 1;
1442
+ }
1443
+ if (low > high) {
1444
+ warningAt(
1445
+ "'{a}' should not be greater than '{b}'.", line, from + l, low, high);
1446
+ }
1447
+ }
1448
+ }
1449
+ }
1450
+ c = s.substr(0, l - 1);
1451
+ character += l;
1452
+ s = s.substr(l);
1453
+ return it('(regexp)', c);
1454
+ }
1455
+ return it('(punctuator)', t);
1456
+
1457
+ // punctuator
1458
+
1459
+ case '#':
1460
+ return it('(punctuator)', t);
1461
+ default:
1462
+ return it('(punctuator)', t);
1463
+ }
1464
+ }
1465
+ }
1466
+ }
1467
+ };
1468
+ }());
1469
+
1470
+
1471
+ function addlabel(t, type) {
1472
+
1473
+ if (t === 'hasOwnProperty') {
1474
+ warning("'hasOwnProperty' is a really bad name.");
1475
+ }
1476
+
1477
+ // Define t in the current function in the current scope.
1478
+
1479
+ if (is_own(funct, t) && !funct['(global)']) {
1480
+ if (funct[t] === true) {
1481
+ if (option.latedef)
1482
+ warning("'{a}' was used before it was defined.", nexttoken, t);
1483
+ } else {
1484
+ if (!option.shadow)
1485
+ warning("'{a}' is already defined.", nexttoken, t);
1486
+ }
1487
+ }
1488
+
1489
+ funct[t] = type;
1490
+ if (funct['(global)']) {
1491
+ global[t] = funct;
1492
+ if (is_own(implied, t)) {
1493
+ if (option.latedef)
1494
+ warning("'{a}' was used before it was defined.", nexttoken, t);
1495
+ delete implied[t];
1496
+ }
1497
+ } else {
1498
+ scope[t] = funct;
1499
+ }
1500
+ }
1501
+
1502
+
1503
+ function doOption() {
1504
+ var b, obj, filter, o = nexttoken.value, t, v;
1505
+ switch (o) {
1506
+ case '*/':
1507
+ error("Unbegun comment.");
1508
+ break;
1509
+ case '/*members':
1510
+ case '/*member':
1511
+ o = '/*members';
1512
+ if (!membersOnly) {
1513
+ membersOnly = {};
1514
+ }
1515
+ obj = membersOnly;
1516
+ break;
1517
+ case '/*jshint':
1518
+ case '/*jslint':
1519
+ obj = option;
1520
+ filter = boolOptions;
1521
+ break;
1522
+ case '/*global':
1523
+ obj = predefined;
1524
+ break;
1525
+ default:
1526
+ error("What?");
1527
+ }
1528
+ t = lex.token();
1529
+ loop: for (;;) {
1530
+ for (;;) {
1531
+ if (t.type === 'special' && t.value === '*/') {
1532
+ break loop;
1533
+ }
1534
+ if (t.id !== '(endline)' && t.id !== ',') {
1535
+ break;
1536
+ }
1537
+ t = lex.token();
1538
+ }
1539
+ if (t.type !== '(string)' && t.type !== '(identifier)' &&
1540
+ o !== '/*members') {
1541
+ error("Bad option.", t);
1542
+ }
1543
+ v = lex.token();
1544
+ if (v.id === ':') {
1545
+ v = lex.token();
1546
+ if (obj === membersOnly) {
1547
+ error("Expected '{a}' and instead saw '{b}'.",
1548
+ t, '*/', ':');
1549
+ }
1550
+ if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) {
1551
+ b = +v.value;
1552
+ if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1553
+ Math.floor(b) !== b) {
1554
+ error("Expected a small integer and instead saw '{a}'.",
1555
+ v, v.value);
1556
+ }
1557
+ obj.white = true;
1558
+ obj.indent = b;
1559
+ } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) {
1560
+ b = +v.value;
1561
+ if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1562
+ Math.floor(b) !== b) {
1563
+ error("Expected a small integer and instead saw '{a}'.",
1564
+ v, v.value);
1565
+ }
1566
+ obj.maxerr = b;
1567
+ } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) {
1568
+ b = +v.value;
1569
+ if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
1570
+ Math.floor(b) !== b) {
1571
+ error("Expected a small integer and instead saw '{a}'.",
1572
+ v, v.value);
1573
+ }
1574
+ obj.maxlen = b;
1575
+ } else if (v.value === 'true') {
1576
+ obj[t.value] = true;
1577
+ } else if (v.value === 'false') {
1578
+ obj[t.value] = false;
1579
+ } else {
1580
+ error("Bad option value.", v);
1581
+ }
1582
+ t = lex.token();
1583
+ } else {
1584
+ if (o === '/*jshint' || o === '/*jslint') {
1585
+ error("Missing option value.", t);
1586
+ }
1587
+ obj[t.value] = false;
1588
+ t = v;
1589
+ }
1590
+ }
1591
+ if (filter) {
1592
+ assume();
1593
+ }
1594
+ }
1595
+
1596
+
1597
+ // We need a peek function. If it has an argument, it peeks that much farther
1598
+ // ahead. It is used to distinguish
1599
+ // for ( var i in ...
1600
+ // from
1601
+ // for ( var i = ...
1602
+
1603
+ function peek(p) {
1604
+ var i = p || 0, j = 0, t;
1605
+
1606
+ while (j <= i) {
1607
+ t = lookahead[j];
1608
+ if (!t) {
1609
+ t = lookahead[j] = lex.token();
1610
+ }
1611
+ j += 1;
1612
+ }
1613
+ return t;
1614
+ }
1615
+
1616
+
1617
+
1618
+ // Produce the next token. It looks for programming errors.
1619
+
1620
+ function advance(id, t) {
1621
+ switch (token.id) {
1622
+ case '(number)':
1623
+ if (nexttoken.id === '.') {
1624
+ warning("A dot following a number can be confused with a decimal point.", token);
1625
+ }
1626
+ break;
1627
+ case '-':
1628
+ if (nexttoken.id === '-' || nexttoken.id === '--') {
1629
+ warning("Confusing minusses.");
1630
+ }
1631
+ break;
1632
+ case '+':
1633
+ if (nexttoken.id === '+' || nexttoken.id === '++') {
1634
+ warning("Confusing plusses.");
1635
+ }
1636
+ break;
1637
+ }
1638
+ if (token.type === '(string)' || token.identifier) {
1639
+ anonname = token.value;
1640
+ }
1641
+
1642
+ if (id && nexttoken.id !== id) {
1643
+ if (t) {
1644
+ if (nexttoken.id === '(end)') {
1645
+ warning("Unmatched '{a}'.", t, t.id);
1646
+ } else {
1647
+ warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
1648
+ nexttoken, id, t.id, t.line, nexttoken.value);
1649
+ }
1650
+ } else if (nexttoken.type !== '(identifier)' ||
1651
+ nexttoken.value !== id) {
1652
+ warning("Expected '{a}' and instead saw '{b}'.",
1653
+ nexttoken, id, nexttoken.value);
1654
+ }
1655
+ }
1656
+ prevtoken = token;
1657
+ token = nexttoken;
1658
+ for (;;) {
1659
+ nexttoken = lookahead.shift() || lex.token();
1660
+ if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
1661
+ return;
1662
+ }
1663
+ if (nexttoken.type === 'special') {
1664
+ doOption();
1665
+ } else {
1666
+ if (nexttoken.id !== '(endline)') {
1667
+ break;
1668
+ }
1669
+ }
1670
+ }
1671
+ }
1672
+
1673
+
1674
+ // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
1675
+ // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
1676
+ // like .nud except that it is only used on the first token of a statement.
1677
+ // Having .fud makes it much easier to define statement-oriented languages like
1678
+ // JavaScript. I retained Pratt's nomenclature.
1679
+
1680
+ // .nud Null denotation
1681
+ // .fud First null denotation
1682
+ // .led Left denotation
1683
+ // lbp Left binding power
1684
+ // rbp Right binding power
1685
+
1686
+ // They are elements of the parsing method called Top Down Operator Precedence.
1687
+
1688
+ function expression(rbp, initial) {
1689
+ var left, isArray = false;
1690
+
1691
+ if (nexttoken.id === '(end)')
1692
+ error("Unexpected early end of program.", token);
1693
+
1694
+ advance();
1695
+ if (initial) {
1696
+ anonname = 'anonymous';
1697
+ funct['(verb)'] = token.value;
1698
+ }
1699
+ if (initial === true && token.fud) {
1700
+ left = token.fud();
1701
+ } else {
1702
+ if (token.nud) {
1703
+ left = token.nud();
1704
+ } else {
1705
+ if (nexttoken.type === '(number)' && token.id === '.') {
1706
+ warning("A leading decimal point can be confused with a dot: '.{a}'.",
1707
+ token, nexttoken.value);
1708
+ advance();
1709
+ return token;
1710
+ } else {
1711
+ error("Expected an identifier and instead saw '{a}'.",
1712
+ token, token.id);
1713
+ }
1714
+ }
1715
+ while (rbp < nexttoken.lbp) {
1716
+ isArray = token.value == 'Array';
1717
+ advance();
1718
+ if (isArray && token.id == '(' && nexttoken.id == ')')
1719
+ warning("Use the array literal notation [].", token);
1720
+ if (token.led) {
1721
+ left = token.led(left);
1722
+ } else {
1723
+ error("Expected an operator and instead saw '{a}'.",
1724
+ token, token.id);
1725
+ }
1726
+ }
1727
+ }
1728
+ return left;
1729
+ }
1730
+
1731
+
1732
+ // Functions for conformance of style.
1733
+
1734
+ function adjacent(left, right) {
1735
+ left = left || token;
1736
+ right = right || nexttoken;
1737
+ if (option.white) {
1738
+ if (left.character !== right.from && left.line === right.line) {
1739
+ warning("Unexpected space after '{a}'.", right, left.value);
1740
+ }
1741
+ }
1742
+ }
1743
+
1744
+ function nobreak(left, right) {
1745
+ left = left || token;
1746
+ right = right || nexttoken;
1747
+ if (option.white && (left.character !== right.from || left.line !== right.line)) {
1748
+ warning("Unexpected space before '{a}'.", right, right.value);
1749
+ }
1750
+ }
1751
+
1752
+ function nospace(left, right) {
1753
+ left = left || token;
1754
+ right = right || nexttoken;
1755
+ if (option.white && !left.comment) {
1756
+ if (left.line === right.line) {
1757
+ adjacent(left, right);
1758
+ }
1759
+ }
1760
+ }
1761
+
1762
+ function nonadjacent(left, right) {
1763
+ if (option.white) {
1764
+ left = left || token;
1765
+ right = right || nexttoken;
1766
+ if (left.line === right.line && left.character === right.from) {
1767
+ warning("Missing space after '{a}'.",
1768
+ nexttoken, left.value);
1769
+ }
1770
+ }
1771
+ }
1772
+
1773
+ function nobreaknonadjacent(left, right) {
1774
+ left = left || token;
1775
+ right = right || nexttoken;
1776
+ if (!option.laxbreak && left.line !== right.line) {
1777
+ warning("Bad line breaking before '{a}'.", right, right.id);
1778
+ } else if (option.white) {
1779
+ left = left || token;
1780
+ right = right || nexttoken;
1781
+ if (left.character === right.from) {
1782
+ warning("Missing space after '{a}'.",
1783
+ nexttoken, left.value);
1784
+ }
1785
+ }
1786
+ }
1787
+
1788
+ function indentation(bias) {
1789
+ var i;
1790
+ if (option.white && nexttoken.id !== '(end)') {
1791
+ i = indent + (bias || 0);
1792
+ if (nexttoken.from !== i) {
1793
+ warning(
1794
+ "Expected '{a}' to have an indentation at {b} instead at {c}.",
1795
+ nexttoken, nexttoken.value, i, nexttoken.from);
1796
+ }
1797
+ }
1798
+ }
1799
+
1800
+ function nolinebreak(t) {
1801
+ t = t || token;
1802
+ if (t.line !== nexttoken.line) {
1803
+ warning("Line breaking error '{a}'.", t, t.value);
1804
+ }
1805
+ }
1806
+
1807
+
1808
+ function comma() {
1809
+ if (token.line !== nexttoken.line) {
1810
+ if (!option.laxbreak) {
1811
+ warning("Bad line breaking before '{a}'.", token, nexttoken.id);
1812
+ }
1813
+ } else if (token.character !== nexttoken.from && option.white) {
1814
+ warning("Unexpected space after '{a}'.", nexttoken, token.value);
1815
+ }
1816
+ advance(',');
1817
+ nonadjacent(token, nexttoken);
1818
+ }
1819
+
1820
+
1821
+ // Functional constructors for making the symbols that will be inherited by
1822
+ // tokens.
1823
+
1824
+ function symbol(s, p) {
1825
+ var x = syntax[s];
1826
+ if (!x || typeof x !== 'object') {
1827
+ syntax[s] = x = {
1828
+ id: s,
1829
+ lbp: p,
1830
+ value: s
1831
+ };
1832
+ }
1833
+ return x;
1834
+ }
1835
+
1836
+
1837
+ function delim(s) {
1838
+ return symbol(s, 0);
1839
+ }
1840
+
1841
+
1842
+ function stmt(s, f) {
1843
+ var x = delim(s);
1844
+ x.identifier = x.reserved = true;
1845
+ x.fud = f;
1846
+ return x;
1847
+ }
1848
+
1849
+
1850
+ function blockstmt(s, f) {
1851
+ var x = stmt(s, f);
1852
+ x.block = true;
1853
+ return x;
1854
+ }
1855
+
1856
+
1857
+ function reserveName(x) {
1858
+ var c = x.id.charAt(0);
1859
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1860
+ x.identifier = x.reserved = true;
1861
+ }
1862
+ return x;
1863
+ }
1864
+
1865
+
1866
+ function prefix(s, f) {
1867
+ var x = symbol(s, 150);
1868
+ reserveName(x);
1869
+ x.nud = (typeof f === 'function') ? f : function () {
1870
+ this.right = expression(150);
1871
+ this.arity = 'unary';
1872
+ if (this.id === '++' || this.id === '--') {
1873
+ if (option.plusplus) {
1874
+ warning("Unexpected use of '{a}'.", this, this.id);
1875
+ } else if ((!this.right.identifier || this.right.reserved) &&
1876
+ this.right.id !== '.' && this.right.id !== '[') {
1877
+ warning("Bad operand.", this);
1878
+ }
1879
+ }
1880
+ return this;
1881
+ };
1882
+ return x;
1883
+ }
1884
+
1885
+
1886
+ function type(s, f) {
1887
+ var x = delim(s);
1888
+ x.type = s;
1889
+ x.nud = f;
1890
+ return x;
1891
+ }
1892
+
1893
+
1894
+ function reserve(s, f) {
1895
+ var x = type(s, f);
1896
+ x.identifier = x.reserved = true;
1897
+ return x;
1898
+ }
1899
+
1900
+
1901
+ function reservevar(s, v) {
1902
+ return reserve(s, function () {
1903
+ if (typeof v === 'function') {
1904
+ v(this);
1905
+ }
1906
+ return this;
1907
+ });
1908
+ }
1909
+
1910
+
1911
+ function infix(s, f, p, w) {
1912
+ var x = symbol(s, p);
1913
+ reserveName(x);
1914
+ x.led = function (left) {
1915
+ if (!w) {
1916
+ nobreaknonadjacent(prevtoken, token);
1917
+ nonadjacent(token, nexttoken);
1918
+ }
1919
+ if (typeof f === 'function') {
1920
+ return f(left, this);
1921
+ } else {
1922
+ this.left = left;
1923
+ this.right = expression(p);
1924
+ return this;
1925
+ }
1926
+ };
1927
+ return x;
1928
+ }
1929
+
1930
+
1931
+ function relation(s, f) {
1932
+ var x = symbol(s, 100);
1933
+ x.led = function (left) {
1934
+ nobreaknonadjacent(prevtoken, token);
1935
+ nonadjacent(token, nexttoken);
1936
+ var right = expression(100);
1937
+ if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
1938
+ warning("Use the isNaN function to compare with NaN.", this);
1939
+ } else if (f) {
1940
+ f.apply(this, [left, right]);
1941
+ }
1942
+ if (left.id === '!') {
1943
+ warning("Confusing use of '{a}'.", left, '!');
1944
+ }
1945
+ if (right.id === '!') {
1946
+ warning("Confusing use of '{a}'.", left, '!');
1947
+ }
1948
+ this.left = left;
1949
+ this.right = right;
1950
+ return this;
1951
+ };
1952
+ return x;
1953
+ }
1954
+
1955
+
1956
+ function isPoorRelation(node) {
1957
+ return node &&
1958
+ ((node.type === '(number)' && +node.value === 0) ||
1959
+ (node.type === '(string)' && node.value === '') ||
1960
+ (node.type === 'null' && !option.eqnull) ||
1961
+ node.type === 'true' ||
1962
+ node.type === 'false' ||
1963
+ node.type === 'undefined');
1964
+ }
1965
+
1966
+
1967
+ function assignop(s, f) {
1968
+ symbol(s, 20).exps = true;
1969
+ return infix(s, function (left, that) {
1970
+ var l;
1971
+ that.left = left;
1972
+ if (predefined[left.value] === false &&
1973
+ scope[left.value]['(global)'] === true) {
1974
+ warning("Read only.", left);
1975
+ } else if (left['function']) {
1976
+ warning("'{a}' is a function.", left, left.value);
1977
+ }
1978
+ if (left) {
1979
+ if (left.id === '.' || left.id === '[') {
1980
+ if (!left.left || left.left.value === 'arguments') {
1981
+ warning('Bad assignment.', that);
1982
+ }
1983
+ that.right = expression(19);
1984
+ return that;
1985
+ } else if (left.identifier && !left.reserved) {
1986
+ if (funct[left.value] === 'exception') {
1987
+ warning("Do not assign to the exception parameter.", left);
1988
+ }
1989
+ that.right = expression(19);
1990
+ return that;
1991
+ }
1992
+ if (left === syntax['function']) {
1993
+ warning(
1994
+ "Expected an identifier in an assignment and instead saw a function invocation.",
1995
+ token);
1996
+ }
1997
+ }
1998
+ error("Bad assignment.", that);
1999
+ }, 20);
2000
+ }
2001
+
2002
+
2003
+ function bitwise(s, f, p) {
2004
+ var x = symbol(s, p);
2005
+ reserveName(x);
2006
+ x.led = (typeof f === 'function') ? f : function (left) {
2007
+ if (option.bitwise) {
2008
+ warning("Unexpected use of '{a}'.", this, this.id);
2009
+ }
2010
+ this.left = left;
2011
+ this.right = expression(p);
2012
+ return this;
2013
+ };
2014
+ return x;
2015
+ }
2016
+
2017
+
2018
+ function bitwiseassignop(s) {
2019
+ symbol(s, 20).exps = true;
2020
+ return infix(s, function (left, that) {
2021
+ if (option.bitwise) {
2022
+ warning("Unexpected use of '{a}'.", that, that.id);
2023
+ }
2024
+ nonadjacent(prevtoken, token);
2025
+ nonadjacent(token, nexttoken);
2026
+ if (left) {
2027
+ if (left.id === '.' || left.id === '[' ||
2028
+ (left.identifier && !left.reserved)) {
2029
+ expression(19);
2030
+ return that;
2031
+ }
2032
+ if (left === syntax['function']) {
2033
+ warning(
2034
+ "Expected an identifier in an assignment, and instead saw a function invocation.",
2035
+ token);
2036
+ }
2037
+ return that;
2038
+ }
2039
+ error("Bad assignment.", that);
2040
+ }, 20);
2041
+ }
2042
+
2043
+
2044
+ function suffix(s, f) {
2045
+ var x = symbol(s, 150);
2046
+ x.led = function (left) {
2047
+ if (option.plusplus) {
2048
+ warning("Unexpected use of '{a}'.", this, this.id);
2049
+ } else if ((!left.identifier || left.reserved) &&
2050
+ left.id !== '.' && left.id !== '[') {
2051
+ warning("Bad operand.", this);
2052
+ }
2053
+ this.left = left;
2054
+ return this;
2055
+ };
2056
+ return x;
2057
+ }
2058
+
2059
+
2060
+ // fnparam means that this identifier is being defined as a function
2061
+ // argument (see identifier())
2062
+ function optionalidentifier(fnparam) {
2063
+ if (nexttoken.identifier) {
2064
+ advance();
2065
+ if (token.reserved && !option.es5) {
2066
+ // `undefined` as a function param is a common pattern to protect
2067
+ // against the case when somebody does `undefined = true` and
2068
+ // help with minification. More info: https://gist.github.com/315916
2069
+ if (!fnparam || token.value != 'undefined') {
2070
+ warning("Expected an identifier and instead saw '{a}' (a reserved word).",
2071
+ token, token.id);
2072
+ }
2073
+ }
2074
+ return token.value;
2075
+ }
2076
+ }
2077
+
2078
+ // fnparam means that this identifier is being defined as a function
2079
+ // argument
2080
+ function identifier(fnparam) {
2081
+ var i = optionalidentifier(fnparam);
2082
+ if (i) {
2083
+ return i;
2084
+ }
2085
+ if (token.id === 'function' && nexttoken.id === '(') {
2086
+ warning("Missing name in function declaration.");
2087
+ } else {
2088
+ error("Expected an identifier and instead saw '{a}'.",
2089
+ nexttoken, nexttoken.value);
2090
+ }
2091
+ }
2092
+
2093
+
2094
+ function reachable(s) {
2095
+ var i = 0, t;
2096
+ if (nexttoken.id !== ';' || noreach) {
2097
+ return;
2098
+ }
2099
+ for (;;) {
2100
+ t = peek(i);
2101
+ if (t.reach) {
2102
+ return;
2103
+ }
2104
+ if (t.id !== '(endline)') {
2105
+ if (t.id === 'function') {
2106
+ warning(
2107
+ "Inner functions should be listed at the top of the outer function.", t);
2108
+ break;
2109
+ }
2110
+ warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
2111
+ break;
2112
+ }
2113
+ i += 1;
2114
+ }
2115
+ }
2116
+
2117
+
2118
+ function statement(noindent) {
2119
+ var i = indent, r, s = scope, t = nexttoken;
2120
+
2121
+ // We don't like the empty statement.
2122
+
2123
+ if (t.id === ';') {
2124
+ warning("Unnecessary semicolon.", t);
2125
+ advance(';');
2126
+ return;
2127
+ }
2128
+
2129
+ // Is this a labelled statement?
2130
+
2131
+ if (t.identifier && !t.reserved && peek().id === ':') {
2132
+ advance();
2133
+ advance(':');
2134
+ scope = Object.create(s);
2135
+ addlabel(t.value, 'label');
2136
+ if (!nexttoken.labelled) {
2137
+ warning("Label '{a}' on {b} statement.",
2138
+ nexttoken, t.value, nexttoken.value);
2139
+ }
2140
+ if (jx.test(t.value + ':')) {
2141
+ warning("Label '{a}' looks like a javascript url.",
2142
+ t, t.value);
2143
+ }
2144
+ nexttoken.label = t.value;
2145
+ t = nexttoken;
2146
+ }
2147
+
2148
+ // Parse the statement.
2149
+
2150
+ if (!noindent) {
2151
+ indentation();
2152
+ }
2153
+ r = expression(0, true);
2154
+
2155
+ // Look for the final semicolon.
2156
+
2157
+ if (!t.block) {
2158
+ if (!option.expr && (!r || !r.exps)) {
2159
+ warning("Expected an assignment or function call and instead saw an expression.", token);
2160
+ } else if (option.nonew && r.id === '(' && r.left.id === 'new') {
2161
+ warning("Do not use 'new' for side effects.");
2162
+ }
2163
+ if (nexttoken.id !== ';') {
2164
+ if (!option.asi && !(option.lastsemic && nexttoken.id == '}' && nexttoken.line == token.line)) {
2165
+ warningAt("Missing semicolon.", token.line, token.from + token.value.length);
2166
+ }
2167
+ } else {
2168
+ adjacent(token, nexttoken);
2169
+ advance(';');
2170
+ nonadjacent(token, nexttoken);
2171
+ }
2172
+ }
2173
+
2174
+ // Restore the indentation.
2175
+
2176
+ indent = i;
2177
+ scope = s;
2178
+ return r;
2179
+ }
2180
+
2181
+
2182
+ function use_strict() {
2183
+ if (nexttoken.value === 'use strict') {
2184
+ if (strict_mode) {
2185
+ warning("Unnecessary \"use strict\".");
2186
+ }
2187
+ advance();
2188
+ advance(';');
2189
+ strict_mode = true;
2190
+ option.newcap = true;
2191
+ option.undef = true;
2192
+ return true;
2193
+ } else {
2194
+ return false;
2195
+ }
2196
+ }
2197
+
2198
+
2199
+ function statements(begin) {
2200
+ var a = [], f, p;
2201
+
2202
+ while (!nexttoken.reach && nexttoken.id !== '(end)') {
2203
+ if (nexttoken.id === ';') {
2204
+ warning("Unnecessary semicolon.");
2205
+ advance(';');
2206
+ } else {
2207
+ a.push(statement());
2208
+ }
2209
+ }
2210
+ return a;
2211
+ }
2212
+
2213
+
2214
+ /*
2215
+ * Parses a single block. A block is a sequence of statements wrapped in
2216
+ * braces.
2217
+ *
2218
+ * ordinary - true for everything but function bodies and try blocks.
2219
+ * stmt - true if block can be a single statement (e.g. in if/for/while).
2220
+ */
2221
+ function block(ordinary, stmt) {
2222
+ var a,
2223
+ b = inblock,
2224
+ old_indent = indent,
2225
+ m = strict_mode,
2226
+ s = scope,
2227
+ t;
2228
+
2229
+ inblock = ordinary;
2230
+ scope = Object.create(scope);
2231
+ nonadjacent(token, nexttoken);
2232
+ t = nexttoken;
2233
+
2234
+ if (nexttoken.id === '{') {
2235
+ advance('{');
2236
+ if (nexttoken.id !== '}' || token.line !== nexttoken.line) {
2237
+ indent += option.indent;
2238
+ while (!ordinary && nexttoken.from > indent) {
2239
+ indent += option.indent;
2240
+ }
2241
+ if (!ordinary && !use_strict() && !m && option.strict &&
2242
+ funct['(context)']['(global)']) {
2243
+ warning("Missing \"use strict\" statement.");
2244
+ }
2245
+ a = statements();
2246
+ strict_mode = m;
2247
+ indent -= option.indent;
2248
+ indentation();
2249
+ }
2250
+ advance('}', t);
2251
+ indent = old_indent;
2252
+ } else if (!ordinary) {
2253
+ error("Expected '{a}' and instead saw '{b}'.",
2254
+ nexttoken, '{', nexttoken.value);
2255
+ } else {
2256
+ if (!stmt || option.curly)
2257
+ warning("Expected '{a}' and instead saw '{b}'.",
2258
+ nexttoken, '{', nexttoken.value);
2259
+
2260
+ noreach = true;
2261
+ a = [statement()];
2262
+ noreach = false;
2263
+ }
2264
+ funct['(verb)'] = null;
2265
+ scope = s;
2266
+ inblock = b;
2267
+ if (ordinary && option.noempty && (!a || a.length === 0)) {
2268
+ warning("Empty block.");
2269
+ }
2270
+ return a;
2271
+ }
2272
+
2273
+
2274
+ function countMember(m) {
2275
+ if (membersOnly && typeof membersOnly[m] !== 'boolean') {
2276
+ warning("Unexpected /*member '{a}'.", token, m);
2277
+ }
2278
+ if (typeof member[m] === 'number') {
2279
+ member[m] += 1;
2280
+ } else {
2281
+ member[m] = 1;
2282
+ }
2283
+ }
2284
+
2285
+
2286
+ function note_implied(token) {
2287
+ var name = token.value, line = token.line, a = implied[name];
2288
+ if (typeof a === 'function') {
2289
+ a = false;
2290
+ }
2291
+ if (!a) {
2292
+ a = [line];
2293
+ implied[name] = a;
2294
+ } else if (a[a.length - 1] !== line) {
2295
+ a.push(line);
2296
+ }
2297
+ }
2298
+
2299
+ // Build the syntax table by declaring the syntactic elements of the language.
2300
+
2301
+ type('(number)', function () {
2302
+ return this;
2303
+ });
2304
+ type('(string)', function () {
2305
+ return this;
2306
+ });
2307
+
2308
+ syntax['(identifier)'] = {
2309
+ type: '(identifier)',
2310
+ lbp: 0,
2311
+ identifier: true,
2312
+ nud: function () {
2313
+ var v = this.value,
2314
+ s = scope[v],
2315
+ f;
2316
+ if (typeof s === 'function') {
2317
+
2318
+ // Protection against accidental inheritance.
2319
+
2320
+ s = undefined;
2321
+ } else if (typeof s === 'boolean') {
2322
+ f = funct;
2323
+ funct = functions[0];
2324
+ addlabel(v, 'var');
2325
+ s = funct;
2326
+ funct = f;
2327
+ }
2328
+
2329
+ // The name is in scope and defined in the current function.
2330
+
2331
+ if (funct === s) {
2332
+
2333
+ // Change 'unused' to 'var', and reject labels.
2334
+
2335
+ switch (funct[v]) {
2336
+ case 'unused':
2337
+ funct[v] = 'var';
2338
+ break;
2339
+ case 'unction':
2340
+ funct[v] = 'function';
2341
+ this['function'] = true;
2342
+ break;
2343
+ case 'function':
2344
+ this['function'] = true;
2345
+ break;
2346
+ case 'label':
2347
+ warning("'{a}' is a statement label.", token, v);
2348
+ break;
2349
+ }
2350
+
2351
+ // The name is not defined in the function. If we are in the global scope,
2352
+ // then we have an undefined variable.
2353
+ //
2354
+ // Operators typeof and delete do not raise runtime errors even if the base
2355
+ // object of a reference is null so no need to display warning if we're
2356
+ // inside of typeof or delete.
2357
+
2358
+ } else if (funct['(global)']) {
2359
+ if (anonname != 'typeof' && anonname != 'delete' &&
2360
+ option.undef && typeof predefined[v] !== 'boolean') {
2361
+ warning("'{a}' is not defined.", token, v);
2362
+ }
2363
+ note_implied(token);
2364
+
2365
+ // If the name is already defined in the current
2366
+ // function, but not as outer, then there is a scope error.
2367
+
2368
+ } else {
2369
+ switch (funct[v]) {
2370
+ case 'closure':
2371
+ case 'function':
2372
+ case 'var':
2373
+ case 'unused':
2374
+ warning("'{a}' used out of scope.", token, v);
2375
+ break;
2376
+ case 'label':
2377
+ warning("'{a}' is a statement label.", token, v);
2378
+ break;
2379
+ case 'outer':
2380
+ case 'global':
2381
+ break;
2382
+ default:
2383
+
2384
+ // If the name is defined in an outer function, make an outer entry, and if
2385
+ // it was unused, make it var.
2386
+
2387
+ if (s === true) {
2388
+ funct[v] = true;
2389
+ } else if (s === null) {
2390
+ warning("'{a}' is not allowed.", token, v);
2391
+ note_implied(token);
2392
+ } else if (typeof s !== 'object') {
2393
+
2394
+ // Operators typeof and delete do not raise runtime errors even if the base object of
2395
+ // a reference is null so no need to display warning if we're inside of typeof or delete.
2396
+
2397
+ if (anonname != 'typeof' && anonname != 'delete' && option.undef) {
2398
+ warning("'{a}' is not defined.", token, v);
2399
+ } else {
2400
+ funct[v] = true;
2401
+ }
2402
+ note_implied(token);
2403
+ } else {
2404
+ switch (s[v]) {
2405
+ case 'function':
2406
+ case 'unction':
2407
+ this['function'] = true;
2408
+ s[v] = 'closure';
2409
+ funct[v] = s['(global)'] ? 'global' : 'outer';
2410
+ break;
2411
+ case 'var':
2412
+ case 'unused':
2413
+ s[v] = 'closure';
2414
+ funct[v] = s['(global)'] ? 'global' : 'outer';
2415
+ break;
2416
+ case 'closure':
2417
+ case 'parameter':
2418
+ funct[v] = s['(global)'] ? 'global' : 'outer';
2419
+ break;
2420
+ case 'label':
2421
+ warning("'{a}' is a statement label.", token, v);
2422
+ }
2423
+ }
2424
+ }
2425
+ }
2426
+ return this;
2427
+ },
2428
+ led: function () {
2429
+ error("Expected an operator and instead saw '{a}'.",
2430
+ nexttoken, nexttoken.value);
2431
+ }
2432
+ };
2433
+
2434
+ type('(regexp)', function () {
2435
+ return this;
2436
+ });
2437
+
2438
+
2439
+ // ECMAScript parser
2440
+
2441
+ delim('(endline)');
2442
+ delim('(begin)');
2443
+ delim('(end)').reach = true;
2444
+ delim('</').reach = true;
2445
+ delim('<!');
2446
+ delim('<!--');
2447
+ delim('-->');
2448
+ delim('(error)').reach = true;
2449
+ delim('}').reach = true;
2450
+ delim(')');
2451
+ delim(']');
2452
+ delim('"').reach = true;
2453
+ delim("'").reach = true;
2454
+ delim(';');
2455
+ delim(':').reach = true;
2456
+ delim(',');
2457
+ delim('#');
2458
+ delim('@');
2459
+ reserve('else');
2460
+ reserve('case').reach = true;
2461
+ reserve('catch');
2462
+ reserve('default').reach = true;
2463
+ reserve('finally');
2464
+ reservevar('arguments', function (x) {
2465
+ if (strict_mode && funct['(global)']) {
2466
+ warning("Strict violation.", x);
2467
+ }
2468
+ });
2469
+ reservevar('eval');
2470
+ reservevar('false');
2471
+ reservevar('Infinity');
2472
+ reservevar('NaN');
2473
+ reservevar('null');
2474
+ reservevar('this', function (x) {
2475
+ if (strict_mode && ((funct['(statement)'] &&
2476
+ funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
2477
+ warning("Strict violation.", x);
2478
+ }
2479
+ });
2480
+ reservevar('true');
2481
+ reservevar('undefined');
2482
+ assignop('=', 'assign', 20);
2483
+ assignop('+=', 'assignadd', 20);
2484
+ assignop('-=', 'assignsub', 20);
2485
+ assignop('*=', 'assignmult', 20);
2486
+ assignop('/=', 'assigndiv', 20).nud = function () {
2487
+ error("A regular expression literal can be confused with '/='.");
2488
+ };
2489
+ assignop('%=', 'assignmod', 20);
2490
+ bitwiseassignop('&=', 'assignbitand', 20);
2491
+ bitwiseassignop('|=', 'assignbitor', 20);
2492
+ bitwiseassignop('^=', 'assignbitxor', 20);
2493
+ bitwiseassignop('<<=', 'assignshiftleft', 20);
2494
+ bitwiseassignop('>>=', 'assignshiftright', 20);
2495
+ bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
2496
+ infix('?', function (left, that) {
2497
+ that.left = left;
2498
+ that.right = expression(10);
2499
+ advance(':');
2500
+ that['else'] = expression(10);
2501
+ return that;
2502
+ }, 30);
2503
+
2504
+ infix('||', 'or', 40);
2505
+ infix('&&', 'and', 50);
2506
+ bitwise('|', 'bitor', 70);
2507
+ bitwise('^', 'bitxor', 80);
2508
+ bitwise('&', 'bitand', 90);
2509
+ relation('==', function (left, right) {
2510
+ var eqnull = option.eqnull &&
2511
+ (left.value == 'null' || right.value == 'null');
2512
+
2513
+ if (!eqnull && option.eqeqeq) {
2514
+ warning("Expected '{a}' and instead saw '{b}'.",
2515
+ this, '===', '==');
2516
+ } else if (isPoorRelation(left)) {
2517
+ warning("Use '{a}' to compare with '{b}'.",
2518
+ this, '===', left.value);
2519
+ } else if (isPoorRelation(right)) {
2520
+ warning("Use '{a}' to compare with '{b}'.",
2521
+ this, '===', right.value);
2522
+ }
2523
+ return this;
2524
+ });
2525
+ relation('===');
2526
+ relation('!=', function (left, right) {
2527
+ if (option.eqeqeq) {
2528
+ warning("Expected '{a}' and instead saw '{b}'.",
2529
+ this, '!==', '!=');
2530
+ } else if (isPoorRelation(left)) {
2531
+ warning("Use '{a}' to compare with '{b}'.",
2532
+ this, '!==', left.value);
2533
+ } else if (isPoorRelation(right)) {
2534
+ warning("Use '{a}' to compare with '{b}'.",
2535
+ this, '!==', right.value);
2536
+ }
2537
+ return this;
2538
+ });
2539
+ relation('!==');
2540
+ relation('<');
2541
+ relation('>');
2542
+ relation('<=');
2543
+ relation('>=');
2544
+ bitwise('<<', 'shiftleft', 120);
2545
+ bitwise('>>', 'shiftright', 120);
2546
+ bitwise('>>>', 'shiftrightunsigned', 120);
2547
+ infix('in', 'in', 120);
2548
+ infix('instanceof', 'instanceof', 120);
2549
+ infix('+', function (left, that) {
2550
+ var right = expression(130);
2551
+ if (left && right && left.id === '(string)' && right.id === '(string)') {
2552
+ left.value += right.value;
2553
+ left.character = right.character;
2554
+ if (!option.scripturl && jx.test(left.value)) {
2555
+ warning("JavaScript URL.", left);
2556
+ }
2557
+ return left;
2558
+ }
2559
+ that.left = left;
2560
+ that.right = right;
2561
+ return that;
2562
+ }, 130);
2563
+ prefix('+', 'num');
2564
+ prefix('+++', function () {
2565
+ warning("Confusing pluses.");
2566
+ this.right = expression(150);
2567
+ this.arity = 'unary';
2568
+ return this;
2569
+ });
2570
+ infix('+++', function (left) {
2571
+ warning("Confusing pluses.");
2572
+ this.left = left;
2573
+ this.right = expression(130);
2574
+ return this;
2575
+ }, 130);
2576
+ infix('-', 'sub', 130);
2577
+ prefix('-', 'neg');
2578
+ prefix('---', function () {
2579
+ warning("Confusing minuses.");
2580
+ this.right = expression(150);
2581
+ this.arity = 'unary';
2582
+ return this;
2583
+ });
2584
+ infix('---', function (left) {
2585
+ warning("Confusing minuses.");
2586
+ this.left = left;
2587
+ this.right = expression(130);
2588
+ return this;
2589
+ }, 130);
2590
+ infix('*', 'mult', 140);
2591
+ infix('/', 'div', 140);
2592
+ infix('%', 'mod', 140);
2593
+
2594
+ suffix('++', 'postinc');
2595
+ prefix('++', 'preinc');
2596
+ syntax['++'].exps = true;
2597
+
2598
+ suffix('--', 'postdec');
2599
+ prefix('--', 'predec');
2600
+ syntax['--'].exps = true;
2601
+ prefix('delete', function () {
2602
+ var p = expression(0);
2603
+ if (!p || (p.id !== '.' && p.id !== '[')) {
2604
+ warning("Variables should not be deleted.");
2605
+ }
2606
+ this.first = p;
2607
+ return this;
2608
+ }).exps = true;
2609
+
2610
+ prefix('~', function () {
2611
+ if (option.bitwise) {
2612
+ warning("Unexpected '{a}'.", this, '~');
2613
+ }
2614
+ expression(150);
2615
+ return this;
2616
+ });
2617
+
2618
+ prefix('!', function () {
2619
+ this.right = expression(150);
2620
+ this.arity = 'unary';
2621
+ if (bang[this.right.id] === true) {
2622
+ warning("Confusing use of '{a}'.", this, '!');
2623
+ }
2624
+ return this;
2625
+ });
2626
+ prefix('typeof', 'typeof');
2627
+ prefix('new', function () {
2628
+ var c = expression(155), i;
2629
+ if (c && c.id !== 'function') {
2630
+ if (c.identifier) {
2631
+ c['new'] = true;
2632
+ switch (c.value) {
2633
+ case 'Object':
2634
+ warning("Use the object literal notation {}.", token);
2635
+ break;
2636
+ case 'Number':
2637
+ case 'String':
2638
+ case 'Boolean':
2639
+ case 'Math':
2640
+ case 'JSON':
2641
+ warning("Do not use {a} as a constructor.", token, c.value);
2642
+ break;
2643
+ case 'Function':
2644
+ if (!option.evil) {
2645
+ warning("The Function constructor is eval.");
2646
+ }
2647
+ break;
2648
+ case 'Date':
2649
+ case 'RegExp':
2650
+ break;
2651
+ default:
2652
+ if (c.id !== 'function') {
2653
+ i = c.value.substr(0, 1);
2654
+ if (option.newcap && (i < 'A' || i > 'Z')) {
2655
+ warning("A constructor name should start with an uppercase letter.", token);
2656
+ }
2657
+ }
2658
+ }
2659
+ } else {
2660
+ if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
2661
+ warning("Bad constructor.", token);
2662
+ }
2663
+ }
2664
+ } else {
2665
+ if (!option.supernew)
2666
+ warning("Weird construction. Delete 'new'.", this);
2667
+ }
2668
+ adjacent(token, nexttoken);
2669
+ if (nexttoken.id !== '(' && !option.supernew) {
2670
+ warning("Missing '()' invoking a constructor.");
2671
+ }
2672
+ this.first = c;
2673
+ return this;
2674
+ });
2675
+ syntax['new'].exps = true;
2676
+
2677
+ prefix('void').exps = true;
2678
+
2679
+ infix('.', function (left, that) {
2680
+ adjacent(prevtoken, token);
2681
+ nobreak();
2682
+ var m = identifier();
2683
+ if (typeof m === 'string') {
2684
+ countMember(m);
2685
+ }
2686
+ that.left = left;
2687
+ that.right = m;
2688
+ if (option.noarg && left && left.value === 'arguments' &&
2689
+ (m === 'callee' || m === 'caller')) {
2690
+ warning("Avoid arguments.{a}.", left, m);
2691
+ } else if (!option.evil && left && left.value === 'document' &&
2692
+ (m === 'write' || m === 'writeln')) {
2693
+ warning("document.write can be a form of eval.", left);
2694
+ }
2695
+ if (!option.evil && (m === 'eval' || m === 'execScript')) {
2696
+ warning('eval is evil.');
2697
+ }
2698
+ return that;
2699
+ }, 160, true);
2700
+
2701
+ infix('(', function (left, that) {
2702
+ if (prevtoken.id !== '}' && prevtoken.id !== ')') {
2703
+ nobreak(prevtoken, token);
2704
+ }
2705
+ nospace();
2706
+ if (option.immed && !left.immed && left.id === 'function') {
2707
+ warning("Wrap an immediate function invocation in parentheses " +
2708
+ "to assist the reader in understanding that the expression " +
2709
+ "is the result of a function, and not the function itself.");
2710
+ }
2711
+ var n = 0,
2712
+ p = [];
2713
+ if (left) {
2714
+ if (left.type === '(identifier)') {
2715
+ if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
2716
+ if (left.value !== 'Number' && left.value !== 'String' &&
2717
+ left.value !== 'Boolean' &&
2718
+ left.value !== 'Date') {
2719
+ if (left.value === 'Math') {
2720
+ warning("Math is not a function.", left);
2721
+ } else if (option.newcap) {
2722
+ warning(
2723
+ "Missing 'new' prefix when invoking a constructor.", left);
2724
+ }
2725
+ }
2726
+ }
2727
+ }
2728
+ }
2729
+ if (nexttoken.id !== ')') {
2730
+ for (;;) {
2731
+ p[p.length] = expression(10);
2732
+ n += 1;
2733
+ if (nexttoken.id !== ',') {
2734
+ break;
2735
+ }
2736
+ comma();
2737
+ }
2738
+ }
2739
+ advance(')');
2740
+ nospace(prevtoken, token);
2741
+ if (typeof left === 'object') {
2742
+ if (left.value === 'parseInt' && n === 1) {
2743
+ warning("Missing radix parameter.", left);
2744
+ }
2745
+ if (!option.evil) {
2746
+ if (left.value === 'eval' || left.value === 'Function' ||
2747
+ left.value === 'execScript') {
2748
+ warning("eval is evil.", left);
2749
+ } else if (p[0] && p[0].id === '(string)' &&
2750
+ (left.value === 'setTimeout' ||
2751
+ left.value === 'setInterval')) {
2752
+ warning(
2753
+ "Implied eval is evil. Pass a function instead of a string.", left);
2754
+ }
2755
+ }
2756
+ if (!left.identifier && left.id !== '.' && left.id !== '[' &&
2757
+ left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
2758
+ left.id !== '?') {
2759
+ warning("Bad invocation.", left);
2760
+ }
2761
+ }
2762
+ that.left = left;
2763
+ return that;
2764
+ }, 155, true).exps = true;
2765
+
2766
+ prefix('(', function () {
2767
+ nospace();
2768
+ if (nexttoken.id === 'function') {
2769
+ nexttoken.immed = true;
2770
+ }
2771
+ var v = expression(0);
2772
+ advance(')', this);
2773
+ nospace(prevtoken, token);
2774
+ if (option.immed && v.id === 'function') {
2775
+ if (nexttoken.id === '(') {
2776
+ warning(
2777
+ "Move the invocation into the parens that contain the function.", nexttoken);
2778
+ } else {
2779
+ warning(
2780
+ "Do not wrap function literals in parens unless they are to be immediately invoked.",
2781
+ this);
2782
+ }
2783
+ }
2784
+ return v;
2785
+ });
2786
+
2787
+ infix('[', function (left, that) {
2788
+ nobreak(prevtoken, token);
2789
+ nospace();
2790
+ var e = expression(0), s;
2791
+ if (e && e.type === '(string)') {
2792
+ if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) {
2793
+ warning("eval is evil.", that);
2794
+ }
2795
+ countMember(e.value);
2796
+ if (!option.sub && ix.test(e.value)) {
2797
+ s = syntax[e.value];
2798
+ if (!s || !s.reserved) {
2799
+ warning("['{a}'] is better written in dot notation.",
2800
+ e, e.value);
2801
+ }
2802
+ }
2803
+ }
2804
+ advance(']', that);
2805
+ nospace(prevtoken, token);
2806
+ that.left = left;
2807
+ that.right = e;
2808
+ return that;
2809
+ }, 160, true);
2810
+
2811
+ prefix('[', function () {
2812
+ var b = token.line !== nexttoken.line;
2813
+ this.first = [];
2814
+ if (b) {
2815
+ indent += option.indent;
2816
+ if (nexttoken.from === indent + option.indent) {
2817
+ indent += option.indent;
2818
+ }
2819
+ }
2820
+ while (nexttoken.id !== '(end)') {
2821
+ while (nexttoken.id === ',') {
2822
+ warning("Extra comma.");
2823
+ advance(',');
2824
+ }
2825
+ if (nexttoken.id === ']') {
2826
+ break;
2827
+ }
2828
+ if (b && token.line !== nexttoken.line) {
2829
+ indentation();
2830
+ }
2831
+ this.first.push(expression(10));
2832
+ if (nexttoken.id === ',') {
2833
+ comma();
2834
+ if (nexttoken.id === ']' && !option.es5) {
2835
+ warning("Extra comma.", token);
2836
+ break;
2837
+ }
2838
+ } else {
2839
+ break;
2840
+ }
2841
+ }
2842
+ if (b) {
2843
+ indent -= option.indent;
2844
+ indentation();
2845
+ }
2846
+ advance(']', this);
2847
+ return this;
2848
+ }, 160);
2849
+
2850
+
2851
+ function property_name() {
2852
+ var id = optionalidentifier(true);
2853
+ if (!id) {
2854
+ if (nexttoken.id === '(string)') {
2855
+ id = nexttoken.value;
2856
+ advance();
2857
+ } else if (nexttoken.id === '(number)') {
2858
+ id = nexttoken.value.toString();
2859
+ advance();
2860
+ }
2861
+ }
2862
+ return id;
2863
+ }
2864
+
2865
+
2866
+ function functionparams() {
2867
+ var i, t = nexttoken, p = [];
2868
+ advance('(');
2869
+ nospace();
2870
+ if (nexttoken.id === ')') {
2871
+ advance(')');
2872
+ nospace(prevtoken, token);
2873
+ return;
2874
+ }
2875
+ for (;;) {
2876
+ i = identifier(true);
2877
+ p.push(i);
2878
+ addlabel(i, 'parameter');
2879
+ if (nexttoken.id === ',') {
2880
+ comma();
2881
+ } else {
2882
+ advance(')', t);
2883
+ nospace(prevtoken, token);
2884
+ return p;
2885
+ }
2886
+ }
2887
+ }
2888
+
2889
+
2890
+ function doFunction(i, statement) {
2891
+ var f,
2892
+ oldOption = option,
2893
+ oldScope = scope;
2894
+
2895
+ option = Object.create(option);
2896
+ scope = Object.create(scope);
2897
+
2898
+ funct = {
2899
+ '(name)' : i || '"' + anonname + '"',
2900
+ '(line)' : nexttoken.line,
2901
+ '(context)' : funct,
2902
+ '(breakage)' : 0,
2903
+ '(loopage)' : 0,
2904
+ '(scope)' : scope,
2905
+ '(statement)': statement
2906
+ };
2907
+ f = funct;
2908
+ token.funct = funct;
2909
+ functions.push(funct);
2910
+ if (i) {
2911
+ addlabel(i, 'function');
2912
+ }
2913
+ funct['(params)'] = functionparams();
2914
+
2915
+ block(false);
2916
+ scope = oldScope;
2917
+ option = oldOption;
2918
+ funct['(last)'] = token.line;
2919
+ funct = funct['(context)'];
2920
+ return f;
2921
+ }
2922
+
2923
+
2924
+ (function (x) {
2925
+ x.nud = function () {
2926
+ var b, f, i, j, p, seen = {}, t;
2927
+
2928
+ b = token.line !== nexttoken.line;
2929
+ if (b) {
2930
+ indent += option.indent;
2931
+ if (nexttoken.from === indent + option.indent) {
2932
+ indent += option.indent;
2933
+ }
2934
+ }
2935
+ for (;;) {
2936
+ if (nexttoken.id === '}') {
2937
+ break;
2938
+ }
2939
+ if (b) {
2940
+ indentation();
2941
+ }
2942
+ if (nexttoken.value === 'get' && peek().id !== ':') {
2943
+ advance('get');
2944
+ if (!option.es5) {
2945
+ error("get/set are ES5 features.");
2946
+ }
2947
+ i = property_name();
2948
+ if (!i) {
2949
+ error("Missing property name.");
2950
+ }
2951
+ t = nexttoken;
2952
+ adjacent(token, nexttoken);
2953
+ f = doFunction();
2954
+ if (!option.loopfunc && funct['(loopage)']) {
2955
+ warning("Don't make functions within a loop.", t);
2956
+ }
2957
+ p = f['(params)'];
2958
+ if (p) {
2959
+ warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
2960
+ }
2961
+ adjacent(token, nexttoken);
2962
+ advance(',');
2963
+ indentation();
2964
+ advance('set');
2965
+ j = property_name();
2966
+ if (i !== j) {
2967
+ error("Expected {a} and instead saw {b}.", token, i, j);
2968
+ }
2969
+ t = nexttoken;
2970
+ adjacent(token, nexttoken);
2971
+ f = doFunction();
2972
+ p = f['(params)'];
2973
+ if (!p || p.length !== 1 || p[0] !== 'value') {
2974
+ warning("Expected (value) in set {a} function.", t, i);
2975
+ }
2976
+ } else {
2977
+ i = property_name();
2978
+ if (typeof i !== 'string') {
2979
+ break;
2980
+ }
2981
+ advance(':');
2982
+ nonadjacent(token, nexttoken);
2983
+ expression(10);
2984
+ }
2985
+ if (seen[i] === true) {
2986
+ warning("Duplicate member '{a}'.", nexttoken, i);
2987
+ }
2988
+ seen[i] = true;
2989
+ countMember(i);
2990
+ if (nexttoken.id === ',') {
2991
+ comma();
2992
+ if (nexttoken.id === ',') {
2993
+ warning("Extra comma.", token);
2994
+ } else if (nexttoken.id === '}' && !option.es5) {
2995
+ warning("Extra comma.", token);
2996
+ }
2997
+ } else {
2998
+ break;
2999
+ }
3000
+ }
3001
+ if (b) {
3002
+ indent -= option.indent;
3003
+ indentation();
3004
+ }
3005
+ advance('}', this);
3006
+ return this;
3007
+ };
3008
+ x.fud = function () {
3009
+ error("Expected to see a statement and instead saw a block.", token);
3010
+ };
3011
+ }(delim('{')));
3012
+
3013
+ var varstatement = stmt('var', function (prefix) {
3014
+ // JavaScript does not have block scope. It only has function scope. So,
3015
+ // declaring a variable in a block can have unexpected consequences.
3016
+ var id, name, value;
3017
+
3018
+ if (funct['(onevar)'] && option.onevar) {
3019
+ warning("Too many var statements.");
3020
+ } else if (!funct['(global)']) {
3021
+ funct['(onevar)'] = true;
3022
+ }
3023
+ this.first = [];
3024
+ for (;;) {
3025
+ nonadjacent(token, nexttoken);
3026
+ id = identifier();
3027
+ if (funct['(global)'] && predefined[id] === false) {
3028
+ warning("Redefinition of '{a}'.", token, id);
3029
+ }
3030
+ addlabel(id, 'unused');
3031
+ if (prefix) {
3032
+ break;
3033
+ }
3034
+ name = token;
3035
+ this.first.push(token);
3036
+ if (nexttoken.id === '=') {
3037
+ nonadjacent(token, nexttoken);
3038
+ advance('=');
3039
+ nonadjacent(token, nexttoken);
3040
+ if (nexttoken.id === 'undefined') {
3041
+ warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
3042
+ }
3043
+ if (peek(0).id === '=' && nexttoken.identifier) {
3044
+ error("Variable {a} was not declared correctly.",
3045
+ nexttoken, nexttoken.value);
3046
+ }
3047
+ value = expression(0);
3048
+ name.first = value;
3049
+ }
3050
+ if (nexttoken.id !== ',') {
3051
+ break;
3052
+ }
3053
+ comma();
3054
+ }
3055
+ return this;
3056
+ });
3057
+ varstatement.exps = true;
3058
+
3059
+ blockstmt('function', function () {
3060
+ if (inblock) {
3061
+ warning(
3062
+ "Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token);
3063
+
3064
+ }
3065
+ var i = identifier();
3066
+ adjacent(token, nexttoken);
3067
+ addlabel(i, 'unction');
3068
+ doFunction(i, true);
3069
+ if (nexttoken.id === '(' && nexttoken.line === token.line) {
3070
+ error(
3071
+ "Function declarations are not invocable. Wrap the whole function invocation in parens.");
3072
+ }
3073
+ return this;
3074
+ });
3075
+
3076
+ prefix('function', function () {
3077
+ var i = optionalidentifier();
3078
+ if (i) {
3079
+ adjacent(token, nexttoken);
3080
+ } else {
3081
+ nonadjacent(token, nexttoken);
3082
+ }
3083
+ doFunction(i);
3084
+ if (!option.loopfunc && funct['(loopage)']) {
3085
+ warning("Don't make functions within a loop.");
3086
+ }
3087
+ return this;
3088
+ });
3089
+
3090
+ blockstmt('if', function () {
3091
+ var t = nexttoken;
3092
+ advance('(');
3093
+ nonadjacent(this, t);
3094
+ nospace();
3095
+ expression(20);
3096
+ if (nexttoken.id === '=') {
3097
+ if (!option.boss)
3098
+ warning("Expected a conditional expression and instead saw an assignment.");
3099
+ advance('=');
3100
+ expression(20);
3101
+ }
3102
+ advance(')', t);
3103
+ nospace(prevtoken, token);
3104
+ block(true, true);
3105
+ if (nexttoken.id === 'else') {
3106
+ nonadjacent(token, nexttoken);
3107
+ advance('else');
3108
+ if (nexttoken.id === 'if' || nexttoken.id === 'switch') {
3109
+ statement(true);
3110
+ } else {
3111
+ block(true, true);
3112
+ }
3113
+ }
3114
+ return this;
3115
+ });
3116
+
3117
+ blockstmt('try', function () {
3118
+ var b, e, s;
3119
+
3120
+ block(false);
3121
+ if (nexttoken.id === 'catch') {
3122
+ advance('catch');
3123
+ nonadjacent(token, nexttoken);
3124
+ advance('(');
3125
+ s = scope;
3126
+ scope = Object.create(s);
3127
+ e = nexttoken.value;
3128
+ if (nexttoken.type !== '(identifier)') {
3129
+ warning("Expected an identifier and instead saw '{a}'.",
3130
+ nexttoken, e);
3131
+ } else {
3132
+ addlabel(e, 'exception');
3133
+ }
3134
+ advance();
3135
+ advance(')');
3136
+ block(false);
3137
+ b = true;
3138
+ scope = s;
3139
+ }
3140
+ if (nexttoken.id === 'finally') {
3141
+ advance('finally');
3142
+ block(false);
3143
+ return;
3144
+ } else if (!b) {
3145
+ error("Expected '{a}' and instead saw '{b}'.",
3146
+ nexttoken, 'catch', nexttoken.value);
3147
+ }
3148
+ return this;
3149
+ });
3150
+
3151
+ blockstmt('while', function () {
3152
+ var t = nexttoken;
3153
+ funct['(breakage)'] += 1;
3154
+ funct['(loopage)'] += 1;
3155
+ advance('(');
3156
+ nonadjacent(this, t);
3157
+ nospace();
3158
+ expression(20);
3159
+ if (nexttoken.id === '=') {
3160
+ if (!option.boss)
3161
+ warning("Expected a conditional expression and instead saw an assignment.");
3162
+ advance('=');
3163
+ expression(20);
3164
+ }
3165
+ advance(')', t);
3166
+ nospace(prevtoken, token);
3167
+ block(true, true);
3168
+ funct['(breakage)'] -= 1;
3169
+ funct['(loopage)'] -= 1;
3170
+ return this;
3171
+ }).labelled = true;
3172
+
3173
+ reserve('with');
3174
+
3175
+ blockstmt('switch', function () {
3176
+ var t = nexttoken,
3177
+ g = false;
3178
+ funct['(breakage)'] += 1;
3179
+ advance('(');
3180
+ nonadjacent(this, t);
3181
+ nospace();
3182
+ this.condition = expression(20);
3183
+ advance(')', t);
3184
+ nospace(prevtoken, token);
3185
+ nonadjacent(token, nexttoken);
3186
+ t = nexttoken;
3187
+ advance('{');
3188
+ nonadjacent(token, nexttoken);
3189
+ indent += option.indent;
3190
+ this.cases = [];
3191
+ for (;;) {
3192
+ switch (nexttoken.id) {
3193
+ case 'case':
3194
+ switch (funct['(verb)']) {
3195
+ case 'break':
3196
+ case 'case':
3197
+ case 'continue':
3198
+ case 'return':
3199
+ case 'switch':
3200
+ case 'throw':
3201
+ break;
3202
+ default:
3203
+ // You can tell JSHint that you don't use break intentionally by
3204
+ // adding a comment /* falls through */ on a line just before
3205
+ // the next `case`.
3206
+ if (!ft.test(lines[nexttoken.line - 2])) {
3207
+ warning(
3208
+ "Expected a 'break' statement before 'case'.",
3209
+ token);
3210
+ }
3211
+ }
3212
+ indentation(-option.indent);
3213
+ advance('case');
3214
+ this.cases.push(expression(20));
3215
+ g = true;
3216
+ advance(':');
3217
+ funct['(verb)'] = 'case';
3218
+ break;
3219
+ case 'default':
3220
+ switch (funct['(verb)']) {
3221
+ case 'break':
3222
+ case 'continue':
3223
+ case 'return':
3224
+ case 'throw':
3225
+ break;
3226
+ default:
3227
+ if (!ft.test(lines[nexttoken.line - 2])) {
3228
+ warning(
3229
+ "Expected a 'break' statement before 'default'.",
3230
+ token);
3231
+ }
3232
+ }
3233
+ indentation(-option.indent);
3234
+ advance('default');
3235
+ g = true;
3236
+ advance(':');
3237
+ break;
3238
+ case '}':
3239
+ indent -= option.indent;
3240
+ indentation();
3241
+ advance('}', t);
3242
+ if (this.cases.length === 1 || this.condition.id === 'true' ||
3243
+ this.condition.id === 'false') {
3244
+ warning("This 'switch' should be an 'if'.", this);
3245
+ }
3246
+ funct['(breakage)'] -= 1;
3247
+ funct['(verb)'] = undefined;
3248
+ return;
3249
+ case '(end)':
3250
+ error("Missing '{a}'.", nexttoken, '}');
3251
+ return;
3252
+ default:
3253
+ if (g) {
3254
+ switch (token.id) {
3255
+ case ',':
3256
+ error("Each value should have its own case label.");
3257
+ return;
3258
+ case ':':
3259
+ statements();
3260
+ break;
3261
+ default:
3262
+ error("Missing ':' on a case clause.", token);
3263
+ }
3264
+ } else {
3265
+ error("Expected '{a}' and instead saw '{b}'.",
3266
+ nexttoken, 'case', nexttoken.value);
3267
+ }
3268
+ }
3269
+ }
3270
+ }).labelled = true;
3271
+
3272
+ stmt('debugger', function () {
3273
+ if (!option.debug) {
3274
+ warning("All 'debugger' statements should be removed.");
3275
+ }
3276
+ return this;
3277
+ }).exps = true;
3278
+
3279
+ (function () {
3280
+ var x = stmt('do', function () {
3281
+ funct['(breakage)'] += 1;
3282
+ funct['(loopage)'] += 1;
3283
+ this.first = block(true);
3284
+ advance('while');
3285
+ var t = nexttoken;
3286
+ nonadjacent(token, t);
3287
+ advance('(');
3288
+ nospace();
3289
+ expression(20);
3290
+ if (nexttoken.id === '=') {
3291
+ if (!option.boss)
3292
+ warning("Expected a conditional expression and instead saw an assignment.");
3293
+ advance('=');
3294
+ expression(20);
3295
+ }
3296
+ advance(')', t);
3297
+ nospace(prevtoken, token);
3298
+ funct['(breakage)'] -= 1;
3299
+ funct['(loopage)'] -= 1;
3300
+ return this;
3301
+ });
3302
+ x.labelled = true;
3303
+ x.exps = true;
3304
+ }());
3305
+
3306
+ blockstmt('for', function () {
3307
+ var s, t = nexttoken;
3308
+ funct['(breakage)'] += 1;
3309
+ funct['(loopage)'] += 1;
3310
+ advance('(');
3311
+ nonadjacent(this, t);
3312
+ nospace();
3313
+ if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') {
3314
+ if (nexttoken.id === 'var') {
3315
+ advance('var');
3316
+ varstatement.fud.call(varstatement, true);
3317
+ } else {
3318
+ switch (funct[nexttoken.value]) {
3319
+ case 'unused':
3320
+ funct[nexttoken.value] = 'var';
3321
+ break;
3322
+ case 'var':
3323
+ break;
3324
+ default:
3325
+ warning("Bad for in variable '{a}'.",
3326
+ nexttoken, nexttoken.value);
3327
+ }
3328
+ advance();
3329
+ }
3330
+ advance('in');
3331
+ expression(20);
3332
+ advance(')', t);
3333
+ s = block(true, true);
3334
+ if (option.forin && (s.length > 1 || typeof s[0] !== 'object' ||
3335
+ s[0].value !== 'if')) {
3336
+ warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.", this);
3337
+ }
3338
+ funct['(breakage)'] -= 1;
3339
+ funct['(loopage)'] -= 1;
3340
+ return this;
3341
+ } else {
3342
+ if (nexttoken.id !== ';') {
3343
+ if (nexttoken.id === 'var') {
3344
+ advance('var');
3345
+ varstatement.fud.call(varstatement);
3346
+ } else {
3347
+ for (;;) {
3348
+ expression(0, 'for');
3349
+ if (nexttoken.id !== ',') {
3350
+ break;
3351
+ }
3352
+ comma();
3353
+ }
3354
+ }
3355
+ }
3356
+ nolinebreak(token);
3357
+ advance(';');
3358
+ if (nexttoken.id !== ';') {
3359
+ expression(20);
3360
+ if (nexttoken.id === '=') {
3361
+ if (!option.boss)
3362
+ warning("Expected a conditional expression and instead saw an assignment.");
3363
+ advance('=');
3364
+ expression(20);
3365
+ }
3366
+ }
3367
+ nolinebreak(token);
3368
+ advance(';');
3369
+ if (nexttoken.id === ';') {
3370
+ error("Expected '{a}' and instead saw '{b}'.",
3371
+ nexttoken, ')', ';');
3372
+ }
3373
+ if (nexttoken.id !== ')') {
3374
+ for (;;) {
3375
+ expression(0, 'for');
3376
+ if (nexttoken.id !== ',') {
3377
+ break;
3378
+ }
3379
+ comma();
3380
+ }
3381
+ }
3382
+ advance(')', t);
3383
+ nospace(prevtoken, token);
3384
+ block(true, true);
3385
+ funct['(breakage)'] -= 1;
3386
+ funct['(loopage)'] -= 1;
3387
+ return this;
3388
+ }
3389
+ }).labelled = true;
3390
+
3391
+
3392
+ stmt('break', function () {
3393
+ var v = nexttoken.value;
3394
+ if (funct['(breakage)'] === 0) {
3395
+ warning("Unexpected '{a}'.", nexttoken, this.value);
3396
+ }
3397
+ nolinebreak(this);
3398
+ if (nexttoken.id !== ';') {
3399
+ if (token.line === nexttoken.line) {
3400
+ if (funct[v] !== 'label') {
3401
+ warning("'{a}' is not a statement label.", nexttoken, v);
3402
+ } else if (scope[v] !== funct) {
3403
+ warning("'{a}' is out of scope.", nexttoken, v);
3404
+ }
3405
+ this.first = nexttoken;
3406
+ advance();
3407
+ }
3408
+ }
3409
+ reachable('break');
3410
+ return this;
3411
+ }).exps = true;
3412
+
3413
+
3414
+ stmt('continue', function () {
3415
+ var v = nexttoken.value;
3416
+ if (funct['(breakage)'] === 0) {
3417
+ warning("Unexpected '{a}'.", nexttoken, this.value);
3418
+ }
3419
+ nolinebreak(this);
3420
+ if (nexttoken.id !== ';') {
3421
+ if (token.line === nexttoken.line) {
3422
+ if (funct[v] !== 'label') {
3423
+ warning("'{a}' is not a statement label.", nexttoken, v);
3424
+ } else if (scope[v] !== funct) {
3425
+ warning("'{a}' is out of scope.", nexttoken, v);
3426
+ }
3427
+ this.first = nexttoken;
3428
+ advance();
3429
+ }
3430
+ } else if (!funct['(loopage)']) {
3431
+ warning("Unexpected '{a}'.", nexttoken, this.value);
3432
+ }
3433
+ reachable('continue');
3434
+ return this;
3435
+ }).exps = true;
3436
+
3437
+
3438
+ stmt('return', function () {
3439
+ nolinebreak(this);
3440
+ if (nexttoken.id === '(regexp)') {
3441
+ warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
3442
+ }
3443
+ if (nexttoken.id !== ';' && !nexttoken.reach) {
3444
+ nonadjacent(token, nexttoken);
3445
+ this.first = expression(20);
3446
+ }
3447
+ reachable('return');
3448
+ return this;
3449
+ }).exps = true;
3450
+
3451
+
3452
+ stmt('throw', function () {
3453
+ nolinebreak(this);
3454
+ nonadjacent(token, nexttoken);
3455
+ this.first = expression(20);
3456
+ reachable('throw');
3457
+ return this;
3458
+ }).exps = true;
3459
+
3460
+ // Superfluous reserved words
3461
+
3462
+ reserve('class');
3463
+ reserve('const');
3464
+ reserve('enum');
3465
+ reserve('export');
3466
+ reserve('extends');
3467
+ reserve('import');
3468
+ reserve('super');
3469
+
3470
+ reserve('let');
3471
+ reserve('yield');
3472
+ reserve('implements');
3473
+ reserve('interface');
3474
+ reserve('package');
3475
+ reserve('private');
3476
+ reserve('protected');
3477
+ reserve('public');
3478
+ reserve('static');
3479
+
3480
+
3481
+ // Parse JSON
3482
+
3483
+ function jsonValue() {
3484
+
3485
+ function jsonObject() {
3486
+ var o = {}, t = nexttoken;
3487
+ advance('{');
3488
+ if (nexttoken.id !== '}') {
3489
+ for (;;) {
3490
+ if (nexttoken.id === '(end)') {
3491
+ error("Missing '}' to match '{' from line {a}.",
3492
+ nexttoken, t.line);
3493
+ } else if (nexttoken.id === '}') {
3494
+ warning("Unexpected comma.", token);
3495
+ break;
3496
+ } else if (nexttoken.id === ',') {
3497
+ error("Unexpected comma.", nexttoken);
3498
+ } else if (nexttoken.id !== '(string)') {
3499
+ warning("Expected a string and instead saw {a}.",
3500
+ nexttoken, nexttoken.value);
3501
+ }
3502
+ if (o[nexttoken.value] === true) {
3503
+ warning("Duplicate key '{a}'.",
3504
+ nexttoken, nexttoken.value);
3505
+ } else if (nexttoken.value === '__proto__') {
3506
+ warning("Stupid key '{a}'.",
3507
+ nexttoken, nexttoken.value);
3508
+ } else {
3509
+ o[nexttoken.value] = true;
3510
+ }
3511
+ advance();
3512
+ advance(':');
3513
+ jsonValue();
3514
+ if (nexttoken.id !== ',') {
3515
+ break;
3516
+ }
3517
+ advance(',');
3518
+ }
3519
+ }
3520
+ advance('}');
3521
+ }
3522
+
3523
+ function jsonArray() {
3524
+ var t = nexttoken;
3525
+ advance('[');
3526
+ if (nexttoken.id !== ']') {
3527
+ for (;;) {
3528
+ if (nexttoken.id === '(end)') {
3529
+ error("Missing ']' to match '[' from line {a}.",
3530
+ nexttoken, t.line);
3531
+ } else if (nexttoken.id === ']') {
3532
+ warning("Unexpected comma.", token);
3533
+ break;
3534
+ } else if (nexttoken.id === ',') {
3535
+ error("Unexpected comma.", nexttoken);
3536
+ }
3537
+ jsonValue();
3538
+ if (nexttoken.id !== ',') {
3539
+ break;
3540
+ }
3541
+ advance(',');
3542
+ }
3543
+ }
3544
+ advance(']');
3545
+ }
3546
+
3547
+ switch (nexttoken.id) {
3548
+ case '{':
3549
+ jsonObject();
3550
+ break;
3551
+ case '[':
3552
+ jsonArray();
3553
+ break;
3554
+ case 'true':
3555
+ case 'false':
3556
+ case 'null':
3557
+ case '(number)':
3558
+ case '(string)':
3559
+ advance();
3560
+ break;
3561
+ case '-':
3562
+ advance('-');
3563
+ if (token.character !== nexttoken.from) {
3564
+ warning("Unexpected space after '-'.", token);
3565
+ }
3566
+ adjacent(token, nexttoken);
3567
+ advance('(number)');
3568
+ break;
3569
+ default:
3570
+ error("Expected a JSON value.", nexttoken);
3571
+ }
3572
+ }
3573
+
3574
+
3575
+ // The actual JSHINT function itself.
3576
+
3577
+ var itself = function (s, o, g) {
3578
+ var a, i, k;
3579
+ JSHINT.errors = [];
3580
+ predefined = Object.create(standard);
3581
+ combine(predefined, g || {});
3582
+ if (o) {
3583
+ a = o.predef;
3584
+ if (a) {
3585
+ if (Array.isArray(a)) {
3586
+ for (i = 0; i < a.length; i += 1) {
3587
+ predefined[a[i]] = true;
3588
+ }
3589
+ } else if (typeof a === 'object') {
3590
+ k = Object.keys(a);
3591
+ for (i = 0; i < k.length; i += 1) {
3592
+ predefined[k[i]] = !!a[k[i]];
3593
+ }
3594
+ }
3595
+ }
3596
+ option = o;
3597
+ } else {
3598
+ option = {};
3599
+ }
3600
+ option.indent = option.indent || 4;
3601
+ option.maxerr = option.maxerr || 50;
3602
+
3603
+ tab = '';
3604
+ for (i = 0; i < option.indent; i += 1) {
3605
+ tab += ' ';
3606
+ }
3607
+ indent = 1;
3608
+ global = Object.create(predefined);
3609
+ scope = global;
3610
+ funct = {
3611
+ '(global)': true,
3612
+ '(name)': '(global)',
3613
+ '(scope)': scope,
3614
+ '(breakage)': 0,
3615
+ '(loopage)': 0
3616
+ };
3617
+ functions = [funct];
3618
+ urls = [];
3619
+ src = false;
3620
+ stack = null;
3621
+ member = {};
3622
+ membersOnly = null;
3623
+ implied = {};
3624
+ inblock = false;
3625
+ lookahead = [];
3626
+ jsonmode = false;
3627
+ warnings = 0;
3628
+ lex.init(s);
3629
+ prereg = true;
3630
+ strict_mode = false;
3631
+
3632
+ prevtoken = token = nexttoken = syntax['(begin)'];
3633
+ assume();
3634
+
3635
+ try {
3636
+ advance();
3637
+ switch (nexttoken.id) {
3638
+ case '{':
3639
+ case '[':
3640
+ option.laxbreak = true;
3641
+ jsonmode = true;
3642
+ jsonValue();
3643
+ break;
3644
+ default:
3645
+ if (nexttoken.value === 'use strict') {
3646
+ if (!option.globalstrict)
3647
+ warning("Use the function form of \"use strict\".");
3648
+ use_strict();
3649
+ }
3650
+ statements('lib');
3651
+ }
3652
+ advance('(end)');
3653
+ } catch (e) {
3654
+ if (e) {
3655
+ JSHINT.errors.push({
3656
+ reason : e.message,
3657
+ line : e.line || nexttoken.line,
3658
+ character : e.character || nexttoken.from
3659
+ }, null);
3660
+ }
3661
+ }
3662
+ return JSHINT.errors.length === 0;
3663
+ };
3664
+
3665
+
3666
+ // Data summary.
3667
+
3668
+ itself.data = function () {
3669
+
3670
+ var data = {functions: []}, fu, globals, implieds = [], f, i, j,
3671
+ members = [], n, unused = [], v;
3672
+ if (itself.errors.length) {
3673
+ data.errors = itself.errors;
3674
+ }
3675
+
3676
+ if (jsonmode) {
3677
+ data.json = true;
3678
+ }
3679
+
3680
+ for (n in implied) {
3681
+ if (is_own(implied, n)) {
3682
+ implieds.push({
3683
+ name: n,
3684
+ line: implied[n]
3685
+ });
3686
+ }
3687
+ }
3688
+ if (implieds.length > 0) {
3689
+ data.implieds = implieds;
3690
+ }
3691
+
3692
+ if (urls.length > 0) {
3693
+ data.urls = urls;
3694
+ }
3695
+
3696
+ globals = Object.keys(scope);
3697
+ if (globals.length > 0) {
3698
+ data.globals = globals;
3699
+ }
3700
+
3701
+ for (i = 1; i < functions.length; i += 1) {
3702
+ f = functions[i];
3703
+ fu = {};
3704
+ for (j = 0; j < functionicity.length; j += 1) {
3705
+ fu[functionicity[j]] = [];
3706
+ }
3707
+ for (n in f) {
3708
+ if (is_own(f, n) && n.charAt(0) !== '(') {
3709
+ v = f[n];
3710
+ if (v === 'unction') {
3711
+ v = 'unused';
3712
+ }
3713
+ if (Array.isArray(fu[v])) {
3714
+ fu[v].push(n);
3715
+ if (v === 'unused') {
3716
+ unused.push({
3717
+ name: n,
3718
+ line: f['(line)'],
3719
+ 'function': f['(name)']
3720
+ });
3721
+ }
3722
+ }
3723
+ }
3724
+ }
3725
+ for (j = 0; j < functionicity.length; j += 1) {
3726
+ if (fu[functionicity[j]].length === 0) {
3727
+ delete fu[functionicity[j]];
3728
+ }
3729
+ }
3730
+ fu.name = f['(name)'];
3731
+ fu.param = f['(params)'];
3732
+ fu.line = f['(line)'];
3733
+ fu.last = f['(last)'];
3734
+ data.functions.push(fu);
3735
+ }
3736
+
3737
+ if (unused.length > 0) {
3738
+ data.unused = unused;
3739
+ }
3740
+
3741
+ members = [];
3742
+ for (n in member) {
3743
+ if (typeof member[n] === 'number') {
3744
+ data.member = member;
3745
+ break;
3746
+ }
3747
+ }
3748
+
3749
+ return data;
3750
+ };
3751
+
3752
+ itself.report = function (option) {
3753
+ var data = itself.data();
3754
+
3755
+ var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s;
3756
+
3757
+ function detail(h, array) {
3758
+ var b, i, singularity;
3759
+ if (array) {
3760
+ o.push('<div><i>' + h + '</i> ');
3761
+ array = array.sort();
3762
+ for (i = 0; i < array.length; i += 1) {
3763
+ if (array[i] !== singularity) {
3764
+ singularity = array[i];
3765
+ o.push((b ? ', ' : '') + singularity);
3766
+ b = true;
3767
+ }
3768
+ }
3769
+ o.push('</div>');
3770
+ }
3771
+ }
3772
+
3773
+
3774
+ if (data.errors || data.implieds || data.unused) {
3775
+ err = true;
3776
+ o.push('<div id=errors><i>Error:</i>');
3777
+ if (data.errors) {
3778
+ for (i = 0; i < data.errors.length; i += 1) {
3779
+ c = data.errors[i];
3780
+ if (c) {
3781
+ e = c.evidence || '';
3782
+ o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' +
3783
+ c.line + ' character ' + c.character : '') +
3784
+ ': ' + c.reason.entityify() +
3785
+ '</p><p class=evidence>' +
3786
+ (e && (e.length > 80 ? e.slice(0, 77) + '...' :
3787
+ e).entityify()) + '</p>');
3788
+ }
3789
+ }
3790
+ }
3791
+
3792
+ if (data.implieds) {
3793
+ s = [];
3794
+ for (i = 0; i < data.implieds.length; i += 1) {
3795
+ s[i] = '<code>' + data.implieds[i].name + '</code>&nbsp;<i>' +
3796
+ data.implieds[i].line + '</i>';
3797
+ }
3798
+ o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>');
3799
+ }
3800
+
3801
+ if (data.unused) {
3802
+ s = [];
3803
+ for (i = 0; i < data.unused.length; i += 1) {
3804
+ s[i] = '<code><u>' + data.unused[i].name + '</u></code>&nbsp;<i>' +
3805
+ data.unused[i].line + '</i> <code>' +
3806
+ data.unused[i]['function'] + '</code>';
3807
+ }
3808
+ o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>');
3809
+ }
3810
+ if (data.json) {
3811
+ o.push('<p>JSON: bad.</p>');
3812
+ }
3813
+ o.push('</div>');
3814
+ }
3815
+
3816
+ if (!option) {
3817
+
3818
+ o.push('<br><div id=functions>');
3819
+
3820
+ if (data.urls) {
3821
+ detail("URLs<br>", data.urls, '<br>');
3822
+ }
3823
+
3824
+ if (data.json && !err) {
3825
+ o.push('<p>JSON: good.</p>');
3826
+ } else if (data.globals) {
3827
+ o.push('<div><i>Global</i> ' +
3828
+ data.globals.sort().join(', ') + '</div>');
3829
+ } else {
3830
+ o.push('<div><i>No new global variables introduced.</i></div>');
3831
+ }
3832
+
3833
+ for (i = 0; i < data.functions.length; i += 1) {
3834
+ f = data.functions[i];
3835
+
3836
+ o.push('<br><div class=function><i>' + f.line + '-' +
3837
+ f.last + '</i> ' + (f.name || '') + '(' +
3838
+ (f.param ? f.param.join(', ') : '') + ')</div>');
3839
+ detail('<big><b>Unused</b></big>', f.unused);
3840
+ detail('Closure', f.closure);
3841
+ detail('Variable', f['var']);
3842
+ detail('Exception', f.exception);
3843
+ detail('Outer', f.outer);
3844
+ detail('Global', f.global);
3845
+ detail('Label', f.label);
3846
+ }
3847
+
3848
+ if (data.member) {
3849
+ a = Object.keys(data.member);
3850
+ if (a.length) {
3851
+ a = a.sort();
3852
+ m = '<br><pre id=members>/*members ';
3853
+ l = 10;
3854
+ for (i = 0; i < a.length; i += 1) {
3855
+ k = a[i];
3856
+ n = k.name();
3857
+ if (l + n.length > 72) {
3858
+ o.push(m + '<br>');
3859
+ m = ' ';
3860
+ l = 1;
3861
+ }
3862
+ l += n.length + 2;
3863
+ if (data.member[k] === 1) {
3864
+ n = '<i>' + n + '</i>';
3865
+ }
3866
+ if (i < a.length - 1) {
3867
+ n += ', ';
3868
+ }
3869
+ m += n;
3870
+ }
3871
+ o.push(m + '<br>*/</pre>');
3872
+ }
3873
+ o.push('</div>');
3874
+ }
3875
+ }
3876
+ return o.join('');
3877
+ };
3878
+ itself.jshint = itself;
3879
+
3880
+ itself.edition = '2011-04-16';
3881
+
3882
+ return itself;
3883
+
3884
+ }());
3885
+
3886
+ // Make JSHINT a Node module, if possible.
3887
+ if (typeof exports == 'object' && exports)
3888
+ exports.JSHINT = JSHINT;
3889
+
3890
+
3891
+
3892
+ (function (args) {
3893
+ var filenames = [],
3894
+ optstr, // arg1=val1,arg2=val2,...
3895
+ predef, // global1=override,global2,global3,...
3896
+ opts = { rhino: true },
3897
+ retval = 0;
3898
+
3899
+ args.forEach(function(arg){
3900
+ if (arg.indexOf("=") > -1){
3901
+ //first time it's the options
3902
+ if (!optstr){
3903
+ optstr = arg;
3904
+ } else if (!predef) {
3905
+ predef = arg;
3906
+ }
3907
+ } else {
3908
+ filenames.push(arg);
3909
+ }
3910
+ });
3911
+
3912
+ if (filenames.length === 0) {
3913
+ print('Usage: jshint.js file.js');
3914
+ quit(1);
3915
+ }
3916
+
3917
+ if (optstr) {
3918
+ optstr.split(',').forEach(function (arg) {
3919
+ var o = arg.split('=');
3920
+ opts[o[0]] = (function (ov) {
3921
+ switch (ov) {
3922
+ case 'true':
3923
+ return true;
3924
+ case 'false':
3925
+ return false;
3926
+ default:
3927
+ return ov;
3928
+ }
3929
+ })(o[1]);
3930
+ });
3931
+ }
3932
+
3933
+ if (predef) {
3934
+ opts.predef = {};
3935
+ predef.split(',').forEach(function (arg) {
3936
+ var global = arg.split('=');
3937
+ opts.predef[global[0]] = (function (override) {
3938
+ return (override === 'false') ? false : true;
3939
+ })(global[1]);
3940
+ });
3941
+ }
3942
+
3943
+ filenames.forEach(function(name){
3944
+
3945
+ var input = readFile(name);
3946
+
3947
+ if (!input) {
3948
+ print('jshint: Couldn\'t open file ' + name);
3949
+ quit(1);
3950
+ }
3951
+
3952
+ if (!JSHINT(input, opts)) {
3953
+ for (var i = 0, err; err = JSHINT.errors[i]; i++) {
3954
+ print(err.reason + ' (' + name + ':' + err.line + ':' + err.character + ')');
3955
+ print('> ' + (err.evidence || '').replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
3956
+ print('');
3957
+ }
3958
+ retval = 1;
3959
+ }
3960
+ });
3961
+
3962
+ quit(retval);
3963
+ }(arguments));