<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[174852] trunk/Source/WebInspectorUI</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/174852">174852</a></dd>
<dt>Author</dt> <dd>jonowells@apple.com</dd>
<dt>Date</dt> <dd>2014-10-17 16:50:49 -0700 (Fri, 17 Oct 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Web Inspector: Add ESLint open source library to the inspector
https://bugs.webkit.org/show_bug.cgi?id=137714
Reviewed by Joseph Pecoraro.
This adds back the eslint.js external library with a correction to Scripts/copy-user-interface-resources.pl
to prevent a build failure.
* Scripts/copy-user-interface-resources.pl: Added copy commands for ESLint.js.
* UserInterface/External/ESLint/LICENSE: Added.
* UserInterface/External/ESLint/eslint.js: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIScriptscopyuserinterfaceresourcespl">trunk/Source/WebInspectorUI/Scripts/copy-user-interface-resources.pl</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalESLintLICENSE">trunk/Source/WebInspectorUI/UserInterface/External/ESLint/LICENSE</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalESLinteslintjs">trunk/Source/WebInspectorUI/UserInterface/External/ESLint/eslint.js</a></li>
</ul>
<h3>Property Changed</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIScriptscopyuserinterfaceresourcespl">trunk/Source/WebInspectorUI/Scripts/copy-user-interface-resources.pl</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (174851 => 174852)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2014-10-17 23:26:12 UTC (rev 174851)
+++ trunk/Source/WebInspectorUI/ChangeLog        2014-10-17 23:50:49 UTC (rev 174852)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-10-17 Jono Wells <jonowells@apple.com>
+
+ Web Inspector: Add ESLint open source library to the inspector
+ https://bugs.webkit.org/show_bug.cgi?id=137714
+
+ Reviewed by Joseph Pecoraro.
+
+ This adds back the eslint.js external library with a correction to Scripts/copy-user-interface-resources.pl
+ to prevent a build failure.
+
+ * Scripts/copy-user-interface-resources.pl: Added copy commands for ESLint.js.
+ * UserInterface/External/ESLint/LICENSE: Added.
+ * UserInterface/External/ESLint/eslint.js: Added.
+
</ins><span class="cx"> 2014-10-14 Jono Wells <jonowells@apple.com>
</span><span class="cx">
</span><span class="cx"> Web Inspector: Add ESLint open source library to the inspector
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIScriptscopyuserinterfaceresourcespl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Scripts/copy-user-interface-resources.pl (174851 => 174852)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Scripts/copy-user-interface-resources.pl        2014-10-17 23:26:12 UTC (rev 174851)
+++ trunk/Source/WebInspectorUI/Scripts/copy-user-interface-resources.pl        2014-10-17 23:50:49 UTC (rev 174852)
</span><span class="lines">@@ -100,9 +100,11 @@
</span><span class="cx"> my $protocolDir = File::Spec->catdir($targetResourcePath, 'Protocol');
</span><span class="cx"> my $codeMirrorPath = File::Spec->catdir($uiRoot, 'External', 'CodeMirror');
</span><span class="cx"> my $esprimaPath = File::Spec->catdir($uiRoot, 'External', 'Esprima');
</span><ins>+my $eslintPath = File::Spec->catdir($uiRoot, 'External', 'ESLint');
</ins><span class="cx">
</span><span class="cx"> my $codeMirrorLicense = readLicenseFile(File::Spec->catfile($codeMirrorPath, 'LICENSE'));
</span><del>-my $esprimaMirrorLicense = readLicenseFile(File::Spec->catfile($esprimaPath, 'LICENSE'));
</del><ins>+my $esprimaLicense = readLicenseFile(File::Spec->catfile($esprimaPath, 'LICENSE'));
+my $eslintLicense = readLicenseFile(File::Spec->catfile($eslintPath, 'LICENSE'));
</ins><span class="cx">
</span><span class="cx"> make_path($protocolDir, $targetResourcePath);
</span><span class="cx">
</span><span class="lines">@@ -123,6 +125,9 @@
</span><span class="cx"> # Combine the Esprima JavaScript files in Production builds into a single file (Esprima.js).
</span><span class="cx"> system($combineResourcesCmd, '--input-dir', 'External/Esprima', '--input-html', $derivedSourcesMainHTML, '--input-html-dir', $uiRoot, '--derived-sources-dir', $derivedSourcesDir, '--output-dir', $derivedSourcesDir, '--output-script-name', 'Esprima.js');
</span><span class="cx">
</span><ins>+ # Combine the ESLint JavaScript files in Production builds into a single file (ESLint.js).
+ system($combineResourcesCmd, '--input-dir', 'External/ESLint', '--input-html', $derivedSourcesMainHTML, '--input-html-dir', $uiRoot, '--derived-sources-dir', $derivedSourcesDir, '--output-dir', $derivedSourcesDir, '--output-script-name', 'ESLint.js');
+
</ins><span class="cx"> # Remove console.assert calls from the Main.js file.
</span><span class="cx"> my $derivedSourcesMainJS = File::Spec->catfile($derivedSourcesDir, 'Main.js');
</span><span class="cx"> system(File::Spec->catfile($scriptsRoot, 'remove-console-asserts.pl'), '--input-script', $derivedSourcesMainJS, '--output-script', $derivedSourcesMainJS);
</span><span class="lines">@@ -155,8 +160,12 @@
</span><span class="cx">
</span><span class="cx"> # Export the license into Esprima.js.
</span><span class="cx"> my $targetEsprimaJS = File::Spec->catfile($targetResourcePath, 'Esprima.js');
</span><del>- seedFile($targetEsprimaJS, $esprimaMirrorLicense);
</del><ins>+ seedFile($targetEsprimaJS, $esprimaLicense);
</ins><span class="cx">
</span><ins>+ # Export the license into ESLint.js.
+ my $targetESLintJS = File::Spec->catfile($targetResourcePath, 'ESLint.js');
+ seedFile($targetESLintJS, $eslintLicense);
+
</ins><span class="cx"> # Minify the Main.js and Main.css files, with Main.js appending to the license that was exported above.
</span><span class="cx"> my $jsMinScript = File::Spec->catfile($scriptsRoot, 'jsmin.py');
</span><span class="cx"> my $cssMinScript = File::Spec->catfile($scriptsRoot, 'cssmin.py');
</span><span class="lines">@@ -173,6 +182,10 @@
</span><span class="cx"> my $derivedSouressEsprimaJS = File::Spec->catfile($derivedSourcesDir, 'Esprima.js');
</span><span class="cx"> system(qq("$python" "$jsMinScript" < "$derivedSouressEsprimaJS" >> "$targetEsprimaJS")) and die "Failed to minify $derivedSouressEsprimaJS: $!";
</span><span class="cx">
</span><ins>+ # Minify the ESLint.js file, appending to the license that was exported above.
+ my $derivedSouressESLintJS = File::Spec->catfile($derivedSourcesDir, 'ESLint.js');
+ system(qq("$python" "$jsMinScript" < "$derivedSouressESLintJS" >> "$targetESLintJS")) and die "Failed to minify $derivedSouressESLintJS: $!";
+
</ins><span class="cx"> # Copy over Main.html and the Images directory.
</span><span class="cx"> copy($derivedSourcesMainHTML, File::Spec->catfile($targetResourcePath, 'Main.html'));
</span><span class="cx">
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/Scripts/copy-user-interface-resources.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="allowtabs"></a>
<div class="addfile"><h4>Added: allow-tabs</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalESLintLICENSE"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/External/ESLint/LICENSE (0 => 174852)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/ESLint/LICENSE         (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/External/ESLint/LICENSE        2014-10-17 23:50:49 UTC (rev 174852)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the 'Software'), to deal
+in the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalESLinteslintjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/External/ESLint/eslint.js (0 => 174852)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/ESLint/eslint.js         (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/External/ESLint/eslint.js        2014-10-17 23:50:49 UTC (rev 174852)
</span><span class="lines">@@ -0,0 +1,18223 @@
</span><ins>+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.eslint=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+module.exports={
+ "builtin": {
+ "NaN": false,
+ "Infinity": false,
+ "undefined": false,
+ "eval": false,
+
+ "parseFloat": false,
+ "parseInt": false,
+ "isNaN": false,
+ "isFinite": false,
+
+ "decodeURI": false,
+ "decodeURIComponent": false,
+ "encodeURI": false,
+ "encodeURIComponent": false,
+
+ "Object": false,
+ "Function": false,
+ "Array": false,
+ "String": false,
+ "Boolean": false,
+ "Map": false,
+ "Number": false,
+ "Date": false,
+ "RegExp": false,
+ "Error": false,
+ "EvalError": false,
+ "RangeError": false,
+ "ReferenceError": false,
+ "Set": false,
+ "SyntaxError": false,
+ "TypeError": false,
+ "URIError": false,
+ "WeakMap": false,
+ "WeakSet": false,
+
+ "ArrayBuffer": false,
+ "Float32Array": false,
+ "Float64Array": false,
+ "Int16Array": false,
+ "Int32Array": false,
+ "Int8Array": false,
+ "Uint16Array": false,
+ "Uint32Array": false,
+ "Uint8Array": false,
+ "Uint8ClampedArray": false,
+
+ "Math": false,
+ "JSON": false,
+
+ "toString": false,
+ "hasOwnProperty": false,
+ "valueOf": false,
+ "propertyIsEnumerable": false,
+ "constructor": false,
+ "isPrototypeOf": false,
+ "toLocaleString": false
+ },
+
+ "browser": {
+ "globals": {
+ "addEventListener": false,
+ "applicationCache": false,
+ "atob": false,
+ "Audio": false,
+ "Blob": false,
+ "blur": false,
+ "btoa": false,
+ "cancelAnimationFrame": false,
+ "clearInterval": false,
+ "clearTimeout": false,
+ "close": false,
+ "closed": false,
+ "crypto": false,
+ "DataView": false,
+ "defaultStatus": false,
+ "devicePixelRatio": false,
+ "dispatchEvent": false,
+ "document": false,
+ "DOMParser": false,
+ "Element": false,
+ "FileReader": false,
+ "find": false,
+ "focus": false,
+ "FormData": false,
+ "frameElement": false,
+ "frames": false,
+ "getComputedStyle": false,
+ "getSelection": false,
+ "history": false,
+ "HTMLAnchorElement": false,
+ "HTMLBaseElement": false,
+ "HTMLBodyElement": false,
+ "HTMLBRElement": false,
+ "HTMLButtonElement": false,
+ "HTMLCanvasElement": false,
+ "HTMLDirectoryElement": false,
+ "HTMLDivElement": false,
+ "HTMLDListElement": false,
+ "HTMLElement": false,
+ "HTMLFieldSetElement": false,
+ "HTMLFontElement": false,
+ "HTMLFormElement": false,
+ "HTMLFrameElement": false,
+ "HTMLFrameSetElement": false,
+ "HTMLHeadElement": false,
+ "HTMLHeadingElement": false,
+ "HTMLHRElement": false,
+ "HTMLHtmlElement": false,
+ "HTMLIFrameElement": false,
+ "HTMLImageElement": false,
+ "HTMLInputElement": false,
+ "HTMLLabelElement": false,
+ "HTMLLegendElement": false,
+ "HTMLLIElement": false,
+ "HTMLLinkElement": false,
+ "HTMLMapElement": false,
+ "HTMLMenuElement": false,
+ "HTMLMetaElement": false,
+ "HTMLModElement": false,
+ "HTMLObjectElement": false,
+ "HTMLOListElement": false,
+ "HTMLOptGroupElement": false,
+ "HTMLOptionElement": false,
+ "HTMLParagraphElement": false,
+ "HTMLParamElement": false,
+ "HTMLPreElement": false,
+ "HTMLQuoteElement": false,
+ "HTMLScriptElement": false,
+ "HTMLSelectElement": false,
+ "HTMLStyleElement": false,
+ "HTMLTableCaptionElement": false,
+ "HTMLTableCellElement": false,
+ "HTMLTableColElement": false,
+ "HTMLTableElement": false,
+ "HTMLTableRowElement": false,
+ "HTMLTableSectionElement": false,
+ "HTMLTextAreaElement": false,
+ "HTMLTitleElement": false,
+ "HTMLUListElement": false,
+ "HTMLVideoElement": false,
+ "Image": false,
+ "indexedDB": false,
+ "innerHeight": false,
+ "innerWidth": false,
+ "Intl": false,
+ "length": false,
+ "localStorage": false,
+ "location": false,
+ "matchMedia": false,
+ "MessageChannel": false,
+ "MessageEvent": false,
+ "MessagePort": false,
+ "moveBy": false,
+ "moveTo": false,
+ "MutationObserver": false,
+ "name": false,
+ "navigator": false,
+ "Node": false,
+ "NodeFilter": false,
+ "onbeforeunload": true,
+ "onblur": true,
+ "onerror": true,
+ "onfocus": true,
+ "onload": true,
+ "onresize": true,
+ "onunload": true,
+ "open": false,
+ "openDatabase": false,
+ "opener": false,
+ "Option": false,
+ "outerHeight": false,
+ "outerWidth": false,
+ "pageXOffset": false,
+ "pageYOffset": false,
+ "parent": false,
+ "postMessage": false,
+ "print": false,
+ "removeEventListener": false,
+ "requestAnimationFrame": false,
+ "resizeBy": false,
+ "resizeTo": false,
+ "screen": false,
+ "screenX": false,
+ "screenY": false,
+ "scroll": false,
+ "scrollbars": false,
+ "scrollBy": false,
+ "scrollTo": false,
+ "scrollX": false,
+ "scrollY": false,
+ "self": false,
+ "sessionStorage": false,
+ "setInterval": false,
+ "setTimeout": false,
+ "SharedWorker": false,
+ "showModalDialog": false,
+ "stop": false,
+ "SVGAElement": false,
+ "SVGAltGlyphDefElement": false,
+ "SVGAltGlyphElement": false,
+ "SVGAltGlyphItemElement": false,
+ "SVGAngle": false,
+ "SVGAnimateColorElement": false,
+ "SVGAnimatedAngle": false,
+ "SVGAnimatedBoolean": false,
+ "SVGAnimatedEnumeration": false,
+ "SVGAnimatedInteger": false,
+ "SVGAnimatedLength": false,
+ "SVGAnimatedLengthList": false,
+ "SVGAnimatedNumber": false,
+ "SVGAnimatedNumberList": false,
+ "SVGAnimatedPreserveAspectRatio": false,
+ "SVGAnimatedRect": false,
+ "SVGAnimatedString": false,
+ "SVGAnimatedTransformList": false,
+ "SVGAnimateElement": false,
+ "SVGAnimateMotionElement": false,
+ "SVGAnimateTransformElement": false,
+ "SVGAnimationElement": false,
+ "SVGCircleElement": false,
+ "SVGClipPathElement": false,
+ "SVGColor": false,
+ "SVGComponentTransferFunctionElement": false,
+ "SVGCursorElement": false,
+ "SVGDefsElement": false,
+ "SVGDescElement": false,
+ "SVGDocument": false,
+ "SVGElement": false,
+ "SVGElementInstance": false,
+ "SVGElementInstanceList": false,
+ "SVGEllipseElement": false,
+ "SVGFEBlendElement": false,
+ "SVGFEColorMatrixElement": false,
+ "SVGFEComponentTransferElement": false,
+ "SVGFECompositeElement": false,
+ "SVGFEConvolveMatrixElement": false,
+ "SVGFEDiffuseLightingElement": false,
+ "SVGFEDisplacementMapElement": false,
+ "SVGFEDistantLightElement": false,
+ "SVGFEFloodElement": false,
+ "SVGFEFuncAElement": false,
+ "SVGFEFuncBElement": false,
+ "SVGFEFuncGElement": false,
+ "SVGFEFuncRElement": false,
+ "SVGFEGaussianBlurElement": false,
+ "SVGFEImageElement": false,
+ "SVGFEMergeElement": false,
+ "SVGFEMergeNodeElement": false,
+ "SVGFEMorphologyElement": false,
+ "SVGFEOffsetElement": false,
+ "SVGFEPointLightElement": false,
+ "SVGFESpecularLightingElement": false,
+ "SVGFESpotLightElement": false,
+ "SVGFETileElement": false,
+ "SVGFETurbulenceElement": false,
+ "SVGFilterElement": false,
+ "SVGFontElement": false,
+ "SVGFontFaceElement": false,
+ "SVGFontFaceFormatElement": false,
+ "SVGFontFaceNameElement": false,
+ "SVGFontFaceSrcElement": false,
+ "SVGFontFaceUriElement": false,
+ "SVGForeignObjectElement": false,
+ "SVGGElement": false,
+ "SVGGlyphElement": false,
+ "SVGGlyphRefElement": false,
+ "SVGGradientElement": false,
+ "SVGHKernElement": false,
+ "SVGImageElement": false,
+ "SVGLength": false,
+ "SVGLengthList": false,
+ "SVGLinearGradientElement": false,
+ "SVGLineElement": false,
+ "SVGMarkerElement": false,
+ "SVGMaskElement": false,
+ "SVGMatrix": false,
+ "SVGMetadataElement": false,
+ "SVGMissingGlyphElement": false,
+ "SVGMPathElement": false,
+ "SVGNumber": false,
+ "SVGNumberList": false,
+ "SVGPaint": false,
+ "SVGPathElement": false,
+ "SVGPathSeg": false,
+ "SVGPathSegArcAbs": false,
+ "SVGPathSegArcRel": false,
+ "SVGPathSegClosePath": false,
+ "SVGPathSegCurvetoCubicAbs": false,
+ "SVGPathSegCurvetoCubicRel": false,
+ "SVGPathSegCurvetoCubicSmoothAbs": false,
+ "SVGPathSegCurvetoCubicSmoothRel": false,
+ "SVGPathSegCurvetoQuadraticAbs": false,
+ "SVGPathSegCurvetoQuadraticRel": false,
+ "SVGPathSegCurvetoQuadraticSmoothAbs": false,
+ "SVGPathSegCurvetoQuadraticSmoothRel": false,
+ "SVGPathSegLinetoAbs": false,
+ "SVGPathSegLinetoHorizontalAbs": false,
+ "SVGPathSegLinetoHorizontalRel": false,
+ "SVGPathSegLinetoRel": false,
+ "SVGPathSegLinetoVerticalAbs": false,
+ "SVGPathSegLinetoVerticalRel": false,
+ "SVGPathSegList": false,
+ "SVGPathSegMovetoAbs": false,
+ "SVGPathSegMovetoRel": false,
+ "SVGPatternElement": false,
+ "SVGPoint": false,
+ "SVGPointList": false,
+ "SVGPolygonElement": false,
+ "SVGPolylineElement": false,
+ "SVGPreserveAspectRatio": false,
+ "SVGRadialGradientElement": false,
+ "SVGRect": false,
+ "SVGRectElement": false,
+ "SVGRenderingIntent": false,
+ "SVGScriptElement": false,
+ "SVGSetElement": false,
+ "SVGStopElement": false,
+ "SVGStringList": false,
+ "SVGStyleElement": false,
+ "SVGSVGElement": false,
+ "SVGSwitchElement": false,
+ "SVGSymbolElement": false,
+ "SVGTextContentElement": false,
+ "SVGTextElement": false,
+ "SVGTextPathElement": false,
+ "SVGTextPositioningElement": false,
+ "SVGTitleElement": false,
+ "SVGTransform": false,
+ "SVGTransformList": false,
+ "SVGTRefElement": false,
+ "SVGTSpanElement": false,
+ "SVGUnitTypes": false,
+ "SVGUseElement": false,
+ "SVGViewElement": false,
+ "SVGViewSpec": false,
+ "SVGVKernElement": false,
+ "top": false,
+ "WebSocket": false,
+ "window": false,
+ "Worker": false,
+ "XMLHttpRequest": false,
+ "XMLSerializer": false,
+ "XPathEvaluator": false,
+ "XPathExpression": false,
+ "XPathResult": false
+ }
+ },
+
+ "node": {
+ "globals": {
+ "__filename": false,
+ "__dirname": false,
+ "Buffer": false,
+ "DataView": false,
+ "console": false,
+ "exports": true,
+ "GLOBAL": false,
+ "global": false,
+ "module": false,
+ "process": false,
+ "require": false,
+ "setTimeout": false,
+ "clearTimeout": false,
+ "setInterval": false,
+ "clearInterval": false,
+ "setImmediate": false,
+ "clearImmediate": false
+ },
+
+ "rules": {
+ "no-catch-shadow": 0,
+ "no-console": 0,
+ "no-mixed-requires": 2,
+ "no-new-require": 2,
+ "no-path-concat": 2,
+ "no-process-exit": 2,
+ "global-strict": [0, "always"],
+ "handle-callback-err": [2, "err"]
+ }
+ },
+
+ "amd": {
+ "globals": {
+ "require": false,
+ "define": false
+ }
+ },
+
+ "mocha": {
+ "globals": {
+ "describe": false,
+ "it": false,
+ "before": false,
+ "after": false,
+ "beforeEach": false,
+ "afterEach": false,
+
+ "suite": false,
+ "test": false,
+ "setup": false,
+ "teardown": false,
+ "suiteSetup": false,
+ "suiteTeardown": false
+ }
+ },
+
+ "jasmine": {
+ "globals": {
+ "afterEach": false,
+ "beforeEach": false,
+ "describe": false,
+ "expect": false,
+ "it": false,
+ "jasmine": false,
+ "pending": false,
+ "spyOn": false,
+ "waits": false,
+ "waitsFor": false,
+ "xdescribe": false,
+ "xit": false
+ }
+ }
+}
+
+},{}],2:[function(require,module,exports){
+module.exports={
+ "env": {
+ "browser": false,
+ "node": false,
+ "amd": false,
+ "mocha": false,
+ "jasmine": false
+ },
+
+ "rules": {
+ "no-alert": 2,
+ "no-array-constructor": 2,
+ "no-bitwise": 0,
+ "no-caller": 2,
+ "no-catch-shadow": 2,
+ "no-comma-dangle": 2,
+ "no-cond-assign": 2,
+ "no-console": 2,
+ "no-constant-condition": 2,
+ "no-control-regex": 2,
+ "no-debugger": 2,
+ "no-delete-var": 2,
+ "no-div-regex": 0,
+ "no-dupe-keys": 2,
+ "no-else-return": 0,
+ "no-empty": 2,
+ "no-empty-class": 2,
+ "no-empty-label": 2,
+ "no-eq-null": 0,
+ "no-eval": 2,
+ "no-ex-assign": 2,
+ "no-extend-native": 2,
+ "no-extra-bind": 2,
+ "no-extra-boolean-cast": 2,
+ "no-extra-parens": 0,
+ "no-extra-semi": 2,
+ "no-extra-strict": 2,
+ "no-fallthrough": 2,
+ "no-floating-decimal": 0,
+ "no-func-assign": 2,
+ "no-implied-eval": 2,
+ "no-inner-declarations": [2, "functions"],
+ "no-invalid-regexp": 2,
+ "no-iterator": 2,
+ "no-label-var": 2,
+ "no-labels": 2,
+ "no-lone-blocks": 2,
+ "no-lonely-if": 0,
+ "no-loop-func": 2,
+ "no-mixed-requires": [0, false],
+ "no-mixed-spaces-and-tabs": [2, false],
+ "no-multi-spaces": 2,
+ "no-multi-str": 2,
+ "no-multiple-empty-lines": [0, {"max": 2}],
+ "no-native-reassign": 2,
+ "no-negated-in-lhs": 2,
+ "no-nested-ternary": 0,
+ "no-new": 2,
+ "no-new-func": 2,
+ "no-new-object": 2,
+ "no-new-require": 0,
+ "no-new-wrappers": 2,
+ "no-obj-calls": 2,
+ "no-octal": 2,
+ "no-octal-escape": 2,
+ "no-path-concat": 0,
+ "no-plusplus": 0,
+ "no-process-env": 0,
+ "no-process-exit": 2,
+ "no-proto": 2,
+ "no-redeclare": 2,
+ "no-regex-spaces": 2,
+ "no-reserved-keys": 0,
+ "no-restricted-modules": 0,
+ "no-return-assign": 2,
+ "no-script-url": 2,
+ "no-self-compare": 0,
+ "no-sequences": 2,
+ "no-shadow": 2,
+ "no-shadow-restricted-names": 2,
+ "no-space-before-semi": 2,
+ "no-spaced-func": 2,
+ "no-sparse-arrays": 2,
+ "no-sync": 0,
+ "no-ternary": 0,
+ "no-trailing-spaces": 2,
+ "no-undef": 2,
+ "no-undef-init": 2,
+ "no-undefined": 0,
+ "no-underscore-dangle": 2,
+ "no-unreachable": 2,
+ "no-unused-expressions": 2,
+ "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
+ "no-use-before-define": 2,
+ "no-void": 0,
+ "no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
+ "no-with": 2,
+ "no-wrap-func": 2,
+
+ "block-scoped-var": 0,
+ "brace-style": [0, "1tbs"],
+ "camelcase": 2,
+ "comma-spacing": 2,
+ "comma-style": 0,
+ "complexity": [0, 11],
+ "consistent-return": 2,
+ "consistent-this": [0, "that"],
+ "curly": [2, "all"],
+ "default-case": 0,
+ "dot-notation": 2,
+ "eol-last": 2,
+ "eqeqeq": 2,
+ "func-names": 0,
+ "func-style": [0, "declaration"],
+ "global-strict": [2, "never"],
+ "guard-for-in": 0,
+ "handle-callback-err": 0,
+ "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
+ "max-depth": [0, 4],
+ "max-len": [0, 80, 4],
+ "max-nested-callbacks": [0, 2],
+ "max-params": [0, 3],
+ "max-statements": [0, 10],
+ "new-cap": 2,
+ "new-parens": 2,
+ "one-var": 0,
+ "padded-blocks": 0,
+ "quote-props": 0,
+ "quotes": [2, "double"],
+ "radix": 0,
+ "semi": 2,
+ "sort-vars": 0,
+ "space-after-keywords": [0, "always"],
+ "space-before-blocks": [0, "always"],
+ "space-in-brackets": [0, "never"],
+ "space-in-parens": [0, "never"],
+ "space-infix-ops": 2,
+ "space-return-throw-case": 2,
+ "space-unary-word-ops": 0,
+ "spaced-line-comment": [0, "always"],
+ "strict": 2,
+ "use-isnan": 2,
+ "valid-jsdoc": 0,
+ "valid-typeof": 2,
+ "vars-on-top": 0,
+ "wrap-iife": 0,
+ "wrap-regex": 0,
+ "yoda": [2, "never"]
+ }
+}
+
+},{}],3:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+function EventEmitter() {
+ this._events = this._events || {};
+ this._maxListeners = this._maxListeners || undefined;
+}
+module.exports = EventEmitter;
+
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+EventEmitter.defaultMaxListeners = 10;
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function(n) {
+ if (!isNumber(n) || n < 0 || isNaN(n))
+ throw TypeError('n must be a positive number');
+ this._maxListeners = n;
+ return this;
+};
+
+EventEmitter.prototype.emit = function(type) {
+ var er, handler, len, args, i, listeners;
+
+ if (!this._events)
+ this._events = {};
+
+ // If there is no 'error' event listener then throw.
+ if (type === 'error') {
+ if (!this._events.error ||
+ (isObject(this._events.error) && !this._events.error.length)) {
+ er = arguments[1];
+ if (er instanceof Error) {
+ throw er; // Unhandled 'error' event
+ }
+ throw TypeError('Uncaught, unspecified "error" event.');
+ }
+ }
+
+ handler = this._events[type];
+
+ if (isUndefined(handler))
+ return false;
+
+ if (isFunction(handler)) {
+ switch (arguments.length) {
+ // fast cases
+ case 1:
+ handler.call(this);
+ break;
+ case 2:
+ handler.call(this, arguments[1]);
+ break;
+ case 3:
+ handler.call(this, arguments[1], arguments[2]);
+ break;
+ // slower
+ default:
+ len = arguments.length;
+ args = new Array(len - 1);
+ for (i = 1; i < len; i++)
+ args[i - 1] = arguments[i];
+ handler.apply(this, args);
+ }
+ } else if (isObject(handler)) {
+ len = arguments.length;
+ args = new Array(len - 1);
+ for (i = 1; i < len; i++)
+ args[i - 1] = arguments[i];
+
+ listeners = handler.slice();
+ len = listeners.length;
+ for (i = 0; i < len; i++)
+ listeners[i].apply(this, args);
+ }
+
+ return true;
+};
+
+EventEmitter.prototype.addListener = function(type, listener) {
+ var m;
+
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ if (!this._events)
+ this._events = {};
+
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
+ if (this._events.newListener)
+ this.emit('newListener', type,
+ isFunction(listener.listener) ?
+ listener.listener : listener);
+
+ if (!this._events[type])
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ else if (isObject(this._events[type]))
+ // If we've already got an array, just append.
+ this._events[type].push(listener);
+ else
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
+
+ // Check for listener leak
+ if (isObject(this._events[type]) && !this._events[type].warned) {
+ var m;
+ if (!isUndefined(this._maxListeners)) {
+ m = this._maxListeners;
+ } else {
+ m = EventEmitter.defaultMaxListeners;
+ }
+
+ if (m && m > 0 && this._events[type].length > m) {
+ this._events[type].warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ this._events[type].length);
+ if (typeof console.trace === 'function') {
+ // not supported in IE 10
+ console.trace();
+ }
+ }
+ }
+
+ return this;
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.once = function(type, listener) {
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ var fired = false;
+
+ function g() {
+ this.removeListener(type, g);
+
+ if (!fired) {
+ fired = true;
+ listener.apply(this, arguments);
+ }
+ }
+
+ g.listener = listener;
+ this.on(type, g);
+
+ return this;
+};
+
+// emits a 'removeListener' event iff the listener was removed
+EventEmitter.prototype.removeListener = function(type, listener) {
+ var list, position, length, i;
+
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ if (!this._events || !this._events[type])
+ return this;
+
+ list = this._events[type];
+ length = list.length;
+ position = -1;
+
+ if (list === listener ||
+ (isFunction(list.listener) && list.listener === listener)) {
+ delete this._events[type];
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
+
+ } else if (isObject(list)) {
+ for (i = length; i-- > 0;) {
+ if (list[i] === listener ||
+ (list[i].listener && list[i].listener === listener)) {
+ position = i;
+ break;
+ }
+ }
+
+ if (position < 0)
+ return this;
+
+ if (list.length === 1) {
+ list.length = 0;
+ delete this._events[type];
+ } else {
+ list.splice(position, 1);
+ }
+
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
+ }
+
+ return this;
+};
+
+EventEmitter.prototype.removeAllListeners = function(type) {
+ var key, listeners;
+
+ if (!this._events)
+ return this;
+
+ // not listening for removeListener, no need to emit
+ if (!this._events.removeListener) {
+ if (arguments.length === 0)
+ this._events = {};
+ else if (this._events[type])
+ delete this._events[type];
+ return this;
+ }
+
+ // emit removeListener for all listeners on all events
+ if (arguments.length === 0) {
+ for (key in this._events) {
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
+ }
+ this.removeAllListeners('removeListener');
+ this._events = {};
+ return this;
+ }
+
+ listeners = this._events[type];
+
+ if (isFunction(listeners)) {
+ this.removeListener(type, listeners);
+ } else {
+ // LIFO order
+ while (listeners.length)
+ this.removeListener(type, listeners[listeners.length - 1]);
+ }
+ delete this._events[type];
+
+ return this;
+};
+
+EventEmitter.prototype.listeners = function(type) {
+ var ret;
+ if (!this._events || !this._events[type])
+ ret = [];
+ else if (isFunction(this._events[type]))
+ ret = [this._events[type]];
+ else
+ ret = this._events[type].slice();
+ return ret;
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+ var ret;
+ if (!emitter._events || !emitter._events[type])
+ ret = 0;
+ else if (isFunction(emitter._events[type]))
+ ret = 1;
+ else
+ ret = emitter._events[type].length;
+ return ret;
+};
+
+function isFunction(arg) {
+ return typeof arg === 'function';
+}
+
+function isNumber(arg) {
+ return typeof arg === 'number';
+}
+
+function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
+}
+
+function isUndefined(arg) {
+ return arg === void 0;
+}
+
+},{}],4:[function(require,module,exports){
+/*
+ Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
+ Copyright (C) 2014 Dan Tao <daniel.tao@gmail.com>
+ Copyright (C) 2013 Andrew Eisenberg <andrew@eisenberg.as>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*jslint bitwise:true plusplus:true eqeq:true nomen:true*/
+/*global doctrine:true, exports:true, parseTypeExpression:true, parseTop:true*/
+
+(function (exports) {
+ 'use strict';
+
+ var VERSION,
+ Regex,
+ CanAccessStringByIndex,
+ typed,
+ jsdoc,
+ isArray,
+ hasOwnProperty;
+
+ // Sync with package.json.
+ VERSION = '0.5.2-dev';
+
+ // See also tools/generate-unicode-regex.py.
+ Regex = {
+ NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35
-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u
12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\
u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\uf
ad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
+ NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a9
3-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-
\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b
0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u300
5-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f
\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
+ };
+
+ CanAccessStringByIndex = typeof 'doctrine'[0] !== undefined;
+
+ function sliceSource(source, index, last) {
+ var output;
+ if (!CanAccessStringByIndex) {
+ output = source.slice(index, last).join('');
+ } else {
+ output = source.slice(index, last);
+ }
+ return output;
+ }
+
+ isArray = Array.isArray;
+ if (!isArray) {
+ isArray = function isArray(ary) {
+ return Object.prototype.toString.call(ary) === '[object Array]';
+ };
+ }
+
+ hasOwnProperty = (function () {
+ var func = Object.prototype.hasOwnProperty;
+ return function hasOwnProperty(obj, name) {
+ return func.call(obj, name);
+ };
+ }());
+
+ function shallowCopy(obj) {
+ var ret = {}, key;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ ret[key] = obj[key];
+ }
+ }
+ return ret;
+ }
+
+ function isLineTerminator(ch) {
+ return ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029';
+ }
+
+ function isWhiteSpace(ch) {
+ return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
+ (ch === '\u000C') || (ch === '\u00A0') ||
+ (ch.charCodeAt(0) >= 0x1680 &&
+ '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
+ }
+
+ function isDecimalDigit(ch) {
+ return '0123456789'.indexOf(ch) >= 0;
+ }
+
+ function isHexDigit(ch) {
+ return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
+ }
+
+ function isOctalDigit(ch) {
+ return '01234567'.indexOf(ch) >= 0;
+ }
+
+ function isASCIIAlphanumeric(ch) {
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9');
+ }
+
+ function isIdentifierStart(ch) {
+ return (ch === '$') || (ch === '_') || (ch === '\\') ||
+ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+ ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
+ }
+
+ function isIdentifierPart(ch) {
+ return (ch === '$') || (ch === '_') || (ch === '\\') ||
+ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+ ((ch >= '0') && (ch <= '9')) ||
+ ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
+ }
+
+ function isTypeName(ch) {
+ return '><(){}[],:*|?!='.indexOf(ch) === -1 && !isWhiteSpace(ch) && !isLineTerminator(ch);
+ }
+
+ function isParamTitle(title) {
+ return title === 'param' || title === 'argument' || title === 'arg';
+ }
+
+ function isProperty(title) {
+ return title === 'property' || title === 'prop';
+ }
+
+ function isNameParameterRequired(title) {
+ return isParamTitle(title) || isProperty(title) ||
+ title === 'alias' || title === 'this' || title === 'mixes' || title === 'requires';
+ }
+
+ function isAllowedName(title) {
+ return isNameParameterRequired(title) || title === 'const' || title === 'constant';
+ }
+
+ function isAllowedNested(title) {
+ return isProperty(title) || isParamTitle(title);
+ }
+
+ function isTypeParameterRequired(title) {
+ return isParamTitle(title) || title === 'define' || title === 'enum' ||
+ title === 'implements' || title === 'return' ||
+ title === 'this' || title === 'type' || title === 'typedef' ||
+ title === 'returns' || isProperty(title);
+ }
+
+ // Consider deprecation instead using 'isTypeParameterRequired' and 'Rules' declaration to pick when a type is optional/required
+ // This would require changes to 'parseType'
+ function isAllowedType(title) {
+ return isTypeParameterRequired(title) || title === 'throws' || title === 'const' || title === 'constant' ||
+ title === 'namespace' || title === 'member' || title === 'var' || title === 'module' ||
+ title === 'constructor' || title === 'class' || title === 'extends' || title === 'augments' ||
+ title === 'public' || title === 'private' || title === 'protected';
+ }
+
+ function DoctrineError(message) {
+ this.name = 'DoctrineError';
+ this.message = message;
+ }
+ DoctrineError.prototype = new Error();
+ DoctrineError.prototype.constructor = DoctrineError;
+
+ function throwError(message) {
+ throw new DoctrineError(message);
+ }
+
+ function assert(cond, text) {
+ if (VERSION.slice(-3) === 'dev') {
+ if (!cond) {
+ throwError(text);
+ }
+ }
+ }
+
+ function trim(str) {
+ return str.replace(/^\s+/, '').replace(/\s+$/, '');
+ }
+
+ function unwrapComment(doc) {
+ // JSDoc comment is following form
+ // /**
+ // * .......
+ // */
+ // remove /**, */ and *
+ var BEFORE_STAR = 0,
+ STAR = 1,
+ AFTER_STAR = 2,
+ index,
+ len,
+ mode,
+ result,
+ ch;
+
+ doc = doc.replace(/^\/\*\*?/, '').replace(/\*\/$/, '');
+ index = 0;
+ len = doc.length;
+ mode = BEFORE_STAR;
+ result = '';
+
+ while (index < len) {
+ ch = doc[index];
+ switch (mode) {
+ case BEFORE_STAR:
+ if (isLineTerminator(ch)) {
+ result += ch;
+ } else if (ch === '*') {
+ mode = STAR;
+ } else if (!isWhiteSpace(ch)) {
+ result += ch;
+ mode = AFTER_STAR;
+ }
+ break;
+
+ case STAR:
+ if (!isWhiteSpace(ch)) {
+ result += ch;
+ }
+ mode = isLineTerminator(ch) ? BEFORE_STAR : AFTER_STAR;
+ break;
+
+ case AFTER_STAR:
+ result += ch;
+ if (isLineTerminator(ch)) {
+ mode = BEFORE_STAR;
+ }
+ break;
+ }
+ index += 1;
+ }
+
+ return result;
+ }
+
+ // Type Expression Parser
+
+ (function (exports) {
+ var Syntax,
+ Token,
+ source,
+ length,
+ index,
+ previous,
+ token,
+ value;
+
+ Syntax = {
+ NullableLiteral: 'NullableLiteral',
+ AllLiteral: 'AllLiteral',
+ NullLiteral: 'NullLiteral',
+ UndefinedLiteral: 'UndefinedLiteral',
+ VoidLiteral: 'VoidLiteral',
+ UnionType: 'UnionType',
+ ArrayType: 'ArrayType',
+ RecordType: 'RecordType',
+ FieldType: 'FieldType',
+ FunctionType: 'FunctionType',
+ ParameterType: 'ParameterType',
+ RestType: 'RestType',
+ NonNullableType: 'NonNullableType',
+ OptionalType: 'OptionalType',
+ NullableType: 'NullableType',
+ NameExpression: 'NameExpression',
+ TypeApplication: 'TypeApplication'
+ };
+
+ Token = {
+ ILLEGAL: 0, // ILLEGAL
+ DOT: 1, // .
+ DOT_LT: 2, // .<
+ REST: 3, // ...
+ LT: 4, // <
+ GT: 5, // >
+ LPAREN: 6, // (
+ RPAREN: 7, // )
+ LBRACE: 8, // {
+ RBRACE: 9, // }
+ LBRACK: 10, // [
+ RBRACK: 11, // ]
+ COMMA: 12, // ,
+ COLON: 13, // :
+ STAR: 14, // *
+ PIPE: 15, // |
+ QUESTION: 16, // ?
+ BANG: 17, // !
+ EQUAL: 18, // =
+ NAME: 19, // name token
+ STRING: 20, // string
+ NUMBER: 21, // number
+ EOF: 22
+ };
+
+ function Context(previous, index, token, value) {
+ this._previous = previous;
+ this._index = index;
+ this._token = token;
+ this._value = value;
+ }
+
+ Context.prototype.restore = function () {
+ previous = this._previous;
+ index = this._index;
+ token = this._token;
+ value = this._value;
+ };
+
+ Context.save = function () {
+ return new Context(previous, index, token, value);
+ };
+
+ function advance() {
+ var ch = source[index];
+ index += 1;
+ return ch;
+ }
+
+ function scanHexEscape(prefix) {
+ var i, len, ch, code = 0;
+
+ len = (prefix === 'u') ? 4 : 2;
+ for (i = 0; i < len; ++i) {
+ if (index < length && isHexDigit(source[index])) {
+ ch = advance();
+ code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+ } else {
+ return '';
+ }
+ }
+ return String.fromCharCode(code);
+ }
+
+ function scanString() {
+ var str = '', quote, ch, code, unescaped, restore; //TODO review removal octal = false
+ quote = source[index];
+ ++index;
+
+ while (index < length) {
+ ch = advance();
+
+ if (ch === quote) {
+ quote = '';
+ break;
+ } else if (ch === '\\') {
+ ch = advance();
+ if (!isLineTerminator(ch)) {
+ switch (ch) {
+ case 'n':
+ str += '\n';
+ break;
+ case 'r':
+ str += '\r';
+ break;
+ case 't':
+ str += '\t';
+ break;
+ case 'u':
+ case 'x':
+ restore = index;
+ unescaped = scanHexEscape(ch);
+ if (unescaped) {
+ str += unescaped;
+ } else {
+ index = restore;
+ str += ch;
+ }
+ break;
+ case 'b':
+ str += '\b';
+ break;
+ case 'f':
+ str += '\f';
+ break;
+ case 'v':
+ str += '\v';
+ break;
+
+ default:
+ if (isOctalDigit(ch)) {
+ code = '01234567'.indexOf(ch);
+
+ // \0 is not octal escape sequence
+ // Deprecating unused code. TODO review removal
+ //if (code !== 0) {
+ // octal = true;
+ //}
+
+ if (index < length && isOctalDigit(source[index])) {
+ //TODO Review Removal octal = true;
+ code = code * 8 + '01234567'.indexOf(advance());
+
+ // 3 digits are only allowed when string starts
+ // with 0, 1, 2, 3
+ if ('0123'.indexOf(ch) >= 0 &&
+ index < length &&
+ isOctalDigit(source[index])) {
+ code = code * 8 + '01234567'.indexOf(advance());
+ }
+ }
+ str += String.fromCharCode(code);
+ } else {
+ str += ch;
+ }
+ break;
+ }
+ } else {
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ }
+ } else if (isLineTerminator(ch)) {
+ break;
+ } else {
+ str += ch;
+ }
+ }
+
+ if (quote !== '') {
+ throwError('unexpected quote');
+ }
+
+ value = str;
+ return Token.STRING;
+ }
+
+ function scanNumber() {
+ var number, ch;
+
+ number = '';
+ if (ch !== '.') {
+ number = advance();
+ ch = source[index];
+
+ if (number === '0') {
+ if (ch === 'x' || ch === 'X') {
+ number += advance();
+ while (index < length) {
+ ch = source[index];
+ if (!isHexDigit(ch)) {
+ break;
+ }
+ number += advance();
+ }
+
+ if (number.length <= 2) {
+ // only 0x
+ throwError('unexpected token');
+ }
+
+ if (index < length) {
+ ch = source[index];
+ if (isIdentifierStart(ch)) {
+ throwError('unexpected token');
+ }
+ }
+ value = parseInt(number, 16);
+ return Token.NUMBER;
+ }
+
+ if (isOctalDigit(ch)) {
+ number += advance();
+ while (index < length) {
+ ch = source[index];
+ if (!isOctalDigit(ch)) {
+ break;
+ }
+ number += advance();
+ }
+
+ if (index < length) {
+ ch = source[index];
+ if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+ throwError('unexpected token');
+ }
+ }
+ value = parseInt(number, 8);
+ return Token.NUMBER;
+ }
+
+ if (isDecimalDigit(ch)) {
+ throwError('unexpected token');
+ }
+ }
+
+ while (index < length) {
+ ch = source[index];
+ if (!isDecimalDigit(ch)) {
+ break;
+ }
+ number += advance();
+ }
+ }
+
+ if (ch === '.') {
+ number += advance();
+ while (index < length) {
+ ch = source[index];
+ if (!isDecimalDigit(ch)) {
+ break;
+ }
+ number += advance();
+ }
+ }
+
+ if (ch === 'e' || ch === 'E') {
+ number += advance();
+
+ ch = source[index];
+ if (ch === '+' || ch === '-') {
+ number += advance();
+ }
+
+ ch = source[index];
+ if (isDecimalDigit(ch)) {
+ number += advance();
+ while (index < length) {
+ ch = source[index];
+ if (!isDecimalDigit(ch)) {
+ break;
+ }
+ number += advance();
+ }
+ } else {
+ throwError('unexpected token');
+ }
+ }
+
+ if (index < length) {
+ ch = source[index];
+ if (isIdentifierStart(ch)) {
+ throwError('unexpected token');
+ }
+ }
+
+ value = parseFloat(number);
+ return Token.NUMBER;
+ }
+
+
+ function scanTypeName() {
+ var ch, ch2;
+
+ value = advance();
+ while (index < length && isTypeName(source[index])) {
+ ch = source[index];
+ if (ch === '.') {
+ if ((index + 1) < length) {
+ ch2 = source[index + 1];
+ if (ch2 === '<') {
+ break;
+ }
+ }
+ }
+ value += advance();
+ }
+ return Token.NAME;
+ }
+
+ function next() {
+ var ch;
+
+ previous = index;
+
+ while (index < length && isWhiteSpace(source[index])) {
+ advance();
+ }
+ if (index >= length) {
+ token = Token.EOF;
+ return token;
+ }
+
+ ch = source[index];
+ switch (ch) {
+ case '"':
+ token = scanString();
+ return token;
+
+ case ':':
+ advance();
+ token = Token.COLON;
+ return token;
+
+ case ',':
+ advance();
+ token = Token.COMMA;
+ return token;
+
+ case '(':
+ advance();
+ token = Token.LPAREN;
+ return token;
+
+ case ')':
+ advance();
+ token = Token.RPAREN;
+ return token;
+
+ case '[':
+ advance();
+ token = Token.LBRACK;
+ return token;
+
+ case ']':
+ advance();
+ token = Token.RBRACK;
+ return token;
+
+ case '{':
+ advance();
+ token = Token.LBRACE;
+ return token;
+
+ case '}':
+ advance();
+ token = Token.RBRACE;
+ return token;
+
+ case '.':
+ advance();
+ if (index < length) {
+ ch = source[index];
+ if (ch === '<') {
+ advance();
+ token = Token.DOT_LT;
+ return token;
+ }
+
+ if (ch === '.' && index + 1 < length && source[index + 1] === '.') {
+ advance();
+ advance();
+ token = Token.REST;
+ return token;
+ }
+
+ if (isDecimalDigit(ch)) {
+ token = scanNumber();
+ return token;
+ }
+ }
+ token = Token.DOT;
+ return token;
+
+ case '<':
+ advance();
+ token = Token.LT;
+ return token;
+
+ case '>':
+ advance();
+ token = Token.GT;
+ return token;
+
+ case '*':
+ advance();
+ token = Token.STAR;
+ return token;
+
+ case '|':
+ advance();
+ token = Token.PIPE;
+ return token;
+
+ case '?':
+ advance();
+ token = Token.QUESTION;
+ return token;
+
+ case '!':
+ advance();
+ token = Token.BANG;
+ return token;
+
+ case '=':
+ advance();
+ token = Token.EQUAL;
+ return token;
+
+ default:
+ if (isDecimalDigit(ch)) {
+ token = scanNumber();
+ return token;
+ }
+
+ // type string permits following case,
+ //
+ // namespace.module.MyClass
+ //
+ // this reduced 1 token TK_NAME
+ if (isTypeName(ch)) {
+ token = scanTypeName();
+ return token;
+ }
+
+ token = Token.ILLEGAL;
+ return token;
+ }
+ }
+
+ function consume(target, text) {
+ assert(token === target, text || 'consumed token not matched');
+ next();
+ }
+
+ function expect(target) {
+ if (token !== target) {
+ throwError('unexpected token');
+ }
+ next();
+ }
+
+ // UnionType := '(' TypeUnionList ')'
+ //
+ // TypeUnionList :=
+ // <<empty>>
+ // | NonemptyTypeUnionList
+ //
+ // NonemptyTypeUnionList :=
+ // TypeExpression
+ // | TypeExpression '|' NonemptyTypeUnionList
+ function parseUnionType() {
+ var elements;
+ consume(Token.LPAREN, 'UnionType should start with (');
+ elements = [];
+ if (token !== Token.RPAREN) {
+ while (true) {
+ elements.push(parseTypeExpression());
+ if (token === Token.RPAREN) {
+ break;
+ }
+ expect(Token.PIPE);
+ }
+ }
+ consume(Token.RPAREN, 'UnionType should end with )');
+ return {
+ type: Syntax.UnionType,
+ elements: elements
+ };
+ }
+
+ // ArrayType := '[' ElementTypeList ']'
+ //
+ // ElementTypeList :=
+ // <<empty>>
+ // | TypeExpression
+ // | '...' TypeExpression
+ // | TypeExpression ',' ElementTypeList
+ function parseArrayType() {
+ var elements;
+ consume(Token.LBRACK, 'ArrayType should start with [');
+ elements = [];
+ while (token !== Token.RBRACK) {
+ if (token === Token.REST) {
+ consume(Token.REST);
+ elements.push({
+ type: Syntax.RestType,
+ expression: parseTypeExpression()
+ });
+ break;
+ } else {
+ elements.push(parseTypeExpression());
+ }
+ if (token !== Token.RBRACK) {
+ expect(Token.COMMA);
+ }
+ }
+ expect(Token.RBRACK);
+ return {
+ type: Syntax.ArrayType,
+ elements: elements
+ };
+ }
+
+ function parseFieldName() {
+ var v = value;
+ if (token === Token.NAME || token === Token.STRING) {
+ next();
+ return v;
+ }
+
+ if (token === Token.NUMBER) {
+ consume(Token.NUMBER);
+ return String(v);
+ }
+
+ throwError('unexpected token');
+ }
+
+ // FieldType :=
+ // FieldName
+ // | FieldName ':' TypeExpression
+ //
+ // FieldName :=
+ // NameExpression
+ // | StringLiteral
+ // | NumberLiteral
+ // | ReservedIdentifier
+ function parseFieldType() {
+ var key;
+
+ key = parseFieldName();
+ if (token === Token.COLON) {
+ consume(Token.COLON);
+ return {
+ type: Syntax.FieldType,
+ key: key,
+ value: parseTypeExpression()
+ };
+ }
+ return {
+ type: Syntax.FieldType,
+ key: key,
+ value: null
+ };
+ }
+
+ // RecordType := '{' FieldTypeList '}'
+ //
+ // FieldTypeList :=
+ // <<empty>>
+ // | FieldType
+ // | FieldType ',' FieldTypeList
+ function parseRecordType() {
+ var fields;
+
+ consume(Token.LBRACE, 'RecordType should start with {');
+ fields = [];
+ if (token === Token.COMMA) {
+ consume(Token.COMMA);
+ } else {
+ while (token !== Token.RBRACE) {
+ fields.push(parseFieldType());
+ if (token !== Token.RBRACE) {
+ expect(Token.COMMA);
+ }
+ }
+ }
+ expect(Token.RBRACE);
+ return {
+ type: Syntax.RecordType,
+ fields: fields
+ };
+ }
+
+ function parseNameExpression() {
+ var name = value;
+ expect(Token.NAME);
+ return {
+ type: Syntax.NameExpression,
+ name: name
+ };
+ }
+
+ // TypeExpressionList :=
+ // TopLevelTypeExpression
+ // | TopLevelTypeExpression ',' TypeExpressionList
+ function parseTypeExpressionList() {
+ var elements = [];
+
+ elements.push(parseTop());
+ while (token === Token.COMMA) {
+ consume(Token.COMMA);
+ elements.push(parseTop());
+ }
+ return elements;
+ }
+
+ // TypeName :=
+ // NameExpression
+ // | NameExpression TypeApplication
+ //
+ // TypeApplication :=
+ // '.<' TypeExpressionList '>'
+ // | '<' TypeExpressionList '>' // this is extension of doctrine
+ function parseTypeName() {
+ var expr, applications;
+
+ expr = parseNameExpression();
+ if (token === Token.DOT_LT || token === Token.LT) {
+ next();
+ applications = parseTypeExpressionList();
+ expect(Token.GT);
+ return {
+ type: Syntax.TypeApplication,
+ expression: expr,
+ applications: applications
+ };
+ }
+ return expr;
+ }
+
+ // ResultType :=
+ // <<empty>>
+ // | ':' void
+ // | ':' TypeExpression
+ //
+ // BNF is above
+ // but, we remove <<empty>> pattern, so token is always TypeToken::COLON
+ function parseResultType() {
+ consume(Token.COLON, 'ResultType should start with :');
+ if (token === Token.NAME && value === 'void') {
+ consume(Token.NAME);
+ return {
+ type: Syntax.VoidLiteral
+ };
+ }
+ return parseTypeExpression();
+ }
+
+ // ParametersType :=
+ // RestParameterType
+ // | NonRestParametersType
+ // | NonRestParametersType ',' RestParameterType
+ //
+ // RestParameterType :=
+ // '...'
+ // '...' Identifier
+ //
+ // NonRestParametersType :=
+ // ParameterType ',' NonRestParametersType
+ // | ParameterType
+ // | OptionalParametersType
+ //
+ // OptionalParametersType :=
+ // OptionalParameterType
+ // | OptionalParameterType, OptionalParametersType
+ //
+ // OptionalParameterType := ParameterType=
+ //
+ // ParameterType := TypeExpression | Identifier ':' TypeExpression
+ //
+ // Identifier is "new" or "this"
+ function parseParametersType() {
+ var params = [], normal = true, expr, rest = false;
+
+ while (token !== Token.RPAREN) {
+ if (token === Token.REST) {
+ // RestParameterType
+ consume(Token.REST);
+ rest = true;
+ }
+
+ expr = parseTypeExpression();
+ if (expr.type === Syntax.NameExpression && token === Token.COLON) {
+ // Identifier ':' TypeExpression
+ consume(Token.COLON);
+ expr = {
+ type: Syntax.ParameterType,
+ name: expr.name,
+ expression: parseTypeExpression()
+ };
+ }
+ if (token === Token.EQUAL) {
+ consume(Token.EQUAL);
+ expr = {
+ type: Syntax.OptionalType,
+ expression: expr
+ };
+ normal = false;
+ } else {
+ if (!normal) {
+ throwError('unexpected token');
+ }
+ }
+ if (rest) {
+ expr = {
+ type: Syntax.RestType,
+ expression: expr
+ };
+ }
+ params.push(expr);
+ if (token !== Token.RPAREN) {
+ expect(Token.COMMA);
+ }
+ }
+ return params;
+ }
+
+ // FunctionType := 'function' FunctionSignatureType
+ //
+ // FunctionSignatureType :=
+ // | TypeParameters '(' ')' ResultType
+ // | TypeParameters '(' ParametersType ')' ResultType
+ // | TypeParameters '(' 'this' ':' TypeName ')' ResultType
+ // | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType
+ function parseFunctionType() {
+ var isNew, thisBinding, params, result, fnType;
+ assert(token === Token.NAME && value === 'function', 'FunctionType should start with \'function\'');
+ consume(Token.NAME);
+
+ // Google Closure Compiler is not implementing TypeParameters.
+ // So we do not. if we don't get '(', we see it as error.
+ expect(Token.LPAREN);
+
+ isNew = false;
+ params = [];
+ thisBinding = null;
+ if (token !== Token.RPAREN) {
+ // ParametersType or 'this'
+ if (token === Token.NAME &&
+ (value === 'this' || value === 'new')) {
+ // 'this' or 'new'
+ // 'new' is Closure Compiler extension
+ isNew = value === 'new';
+ consume(Token.NAME);
+ expect(Token.COLON);
+ thisBinding = parseTypeName();
+ if (token === Token.COMMA) {
+ consume(Token.COMMA);
+ params = parseParametersType();
+ }
+ } else {
+ params = parseParametersType();
+ }
+ }
+
+ expect(Token.RPAREN);
+
+ result = null;
+ if (token === Token.COLON) {
+ result = parseResultType();
+ }
+
+ fnType = {
+ type: Syntax.FunctionType,
+ params: params,
+ result: result
+ };
+ if (thisBinding) {
+ // avoid adding null 'new' and 'this' properties
+ fnType['this'] = thisBinding;
+ if (isNew) {
+ fnType['new'] = true;
+ }
+ }
+ return fnType;
+ }
+
+ // BasicTypeExpression :=
+ // '*'
+ // | 'null'
+ // | 'undefined'
+ // | TypeName
+ // | FunctionType
+ // | UnionType
+ // | RecordType
+ // | ArrayType
+ function parseBasicTypeExpression() {
+ var context;
+ switch (token) {
+ case Token.STAR:
+ consume(Token.STAR);
+ return {
+ type: Syntax.AllLiteral
+ };
+
+ case Token.LPAREN:
+ return parseUnionType();
+
+ case Token.LBRACK:
+ return parseArrayType();
+
+ case Token.LBRACE:
+ return parseRecordType();
+
+ case Token.NAME:
+ if (value === 'null') {
+ consume(Token.NAME);
+ return {
+ type: Syntax.NullLiteral
+ };
+ }
+
+ if (value === 'undefined') {
+ consume(Token.NAME);
+ return {
+ type: Syntax.UndefinedLiteral
+ };
+ }
+
+ context = Context.save();
+ if (value === 'function') {
+ try {
+ return parseFunctionType();
+ } catch (e) {
+ context.restore();
+ }
+ }
+
+ return parseTypeName();
+
+ default:
+ throwError('unexpected token');
+ }
+ }
+
+ // TypeExpression :=
+ // BasicTypeExpression
+ // | '?' BasicTypeExpression
+ // | '!' BasicTypeExpression
+ // | BasicTypeExpression '?'
+ // | BasicTypeExpression '!'
+ // | '?'
+ // | BasicTypeExpression '[]'
+ function parseTypeExpression() {
+ var expr;
+
+ if (token === Token.QUESTION) {
+ consume(Token.QUESTION);
+ if (token === Token.COMMA || token === Token.EQUAL || token === Token.RBRACE ||
+ token === Token.RPAREN || token === Token.PIPE || token === Token.EOF ||
+ token === Token.RBRACK) {
+ return {
+ type: Syntax.NullableLiteral
+ };
+ }
+ return {
+ type: Syntax.NullableType,
+ expression: parseBasicTypeExpression(),
+ prefix: true
+ };
+ }
+
+ if (token === Token.BANG) {
+ consume(Token.BANG);
+ return {
+ type: Syntax.NonNullableType,
+ expression: parseBasicTypeExpression(),
+ prefix: true
+ };
+ }
+
+ expr = parseBasicTypeExpression();
+ if (token === Token.BANG) {
+ consume(Token.BANG);
+ return {
+ type: Syntax.NonNullableType,
+ expression: expr,
+ prefix: false
+ };
+ }
+
+ if (token === Token.QUESTION) {
+ consume(Token.QUESTION);
+ return {
+ type: Syntax.NullableType,
+ expression: expr,
+ prefix: false
+ };
+ }
+
+ if (token === Token.LBRACK) {
+ consume(Token.LBRACK);
+ consume(Token.RBRACK, 'expected an array-style type declaration (' + value + '[])');
+ return {
+ type: Syntax.TypeApplication,
+ expression: {
+ type: Syntax.NameExpression,
+ name: 'Array'
+ },
+ applications: [expr]
+ };
+ }
+
+ return expr;
+ }
+
+ // TopLevelTypeExpression :=
+ // TypeExpression
+ // | TypeUnionList
+ //
+ // This rule is Google Closure Compiler extension, not ES4
+ // like,
+ // { number | string }
+ // If strict to ES4, we should write it as
+ // { (number|string) }
+ function parseTop() {
+ var expr, elements;
+
+ expr = parseTypeExpression();
+ if (token !== Token.PIPE) {
+ return expr;
+ }
+
+ elements = [ expr ];
+ consume(Token.PIPE);
+ while (true) {
+ elements.push(parseTypeExpression());
+ if (token !== Token.PIPE) {
+ break;
+ }
+ consume(Token.PIPE);
+ }
+
+ return {
+ type: Syntax.UnionType,
+ elements: elements
+ };
+ }
+
+ function parseTopParamType() {
+ var expr;
+
+ if (token === Token.REST) {
+ consume(Token.REST);
+ return {
+ type: Syntax.RestType,
+ expression: parseTop()
+ };
+ }
+
+ expr = parseTop();
+ if (token === Token.EQUAL) {
+ consume(Token.EQUAL);
+ return {
+ type: Syntax.OptionalType,
+ expression: expr
+ };
+ }
+
+ return expr;
+ }
+
+ function parseType(src, opt) {
+ var expr;
+
+ source = src;
+ length = source.length;
+ index = 0;
+ previous = 0;
+
+ if (!CanAccessStringByIndex) {
+ source = source.split('');
+ }
+
+ next();
+ expr = parseTop();
+
+ if (opt && opt.midstream) {
+ return {
+ expression: expr,
+ index: previous
+ };
+ }
+
+ if (token !== Token.EOF) {
+ throwError('not reach to EOF');
+ }
+
+ return expr;
+ }
+
+ function parseParamType(src, opt) {
+ var expr;
+
+ source = src;
+ length = source.length;
+ index = 0;
+ previous = 0;
+
+ if (!CanAccessStringByIndex) {
+ source = source.split('');
+ }
+
+ next();
+ expr = parseTopParamType();
+
+ if (opt && opt.midstream) {
+ return {
+ expression: expr,
+ index: previous
+ };
+ }
+
+ if (token !== Token.EOF) {
+ throwError('not reach to EOF');
+ }
+
+ return expr;
+ }
+
+ function stringifyImpl(node, compact, topLevel) {
+ var result, i, iz;
+
+ switch (node.type) {
+ case Syntax.NullableLiteral:
+ result = '?';
+ break;
+
+ case Syntax.AllLiteral:
+ result = '*';
+ break;
+
+ case Syntax.NullLiteral:
+ result = 'null';
+ break;
+
+ case Syntax.UndefinedLiteral:
+ result = 'undefined';
+ break;
+
+ case Syntax.VoidLiteral:
+ result = 'void';
+ break;
+
+ case Syntax.UnionType:
+ if (!topLevel) {
+ result = '(';
+ } else {
+ result = '';
+ }
+
+ for (i = 0, iz = node.elements.length; i < iz; ++i) {
+ result += stringifyImpl(node.elements[i], compact);
+ if ((i + 1) !== iz) {
+ result += '|';
+ }
+ }
+
+ if (!topLevel) {
+ result += ')';
+ }
+ break;
+
+ case Syntax.ArrayType:
+ result = '[';
+ for (i = 0, iz = node.elements.length; i < iz; ++i) {
+ result += stringifyImpl(node.elements[i], compact);
+ if ((i + 1) !== iz) {
+ result += compact ? ',' : ', ';
+ }
+ }
+ result += ']';
+ break;
+
+ case Syntax.RecordType:
+ result = '{';
+ for (i = 0, iz = node.fields.length; i < iz; ++i) {
+ result += stringifyImpl(node.fields[i], compact);
+ if ((i + 1) !== iz) {
+ result += compact ? ',' : ', ';
+ }
+ }
+ result += '}';
+ break;
+
+ case Syntax.FieldType:
+ if (node.value) {
+ result = node.key + (compact ? ':' : ': ') + stringifyImpl(node.value, compact);
+ } else {
+ result = node.key;
+ }
+ break;
+
+ case Syntax.FunctionType:
+ result = compact ? 'function(' : 'function (';
+
+ if (node['this']) {
+ if (node['new']) {
+ result += (compact ? 'new:' : 'new: ');
+ } else {
+ result += (compact ? 'this:' : 'this: ');
+ }
+
+ result += stringifyImpl(node['this'], compact);
+
+ if (node.params.length !== 0) {
+ result += compact ? ',' : ', ';
+ }
+ }
+
+ for (i = 0, iz = node.params.length; i < iz; ++i) {
+ result += stringifyImpl(node.params[i], compact);
+ if ((i + 1) !== iz) {
+ result += compact ? ',' : ', ';
+ }
+ }
+
+ result += ')';
+
+ if (node.result) {
+ result += (compact ? ':' : ': ') + stringifyImpl(node.result, compact);
+ }
+ break;
+
+ case Syntax.ParameterType:
+ result = node.name + (compact ? ':' : ': ') + stringifyImpl(node.expression, compact);
+ break;
+
+ case Syntax.RestType:
+ result = '...';
+ if (node.expression) {
+ result += stringifyImpl(node.expression, compact);
+ }
+ break;
+
+ case Syntax.NonNullableType:
+ if (node.prefix) {
+ result = '!' + stringifyImpl(node.expression, compact);
+ } else {
+ result = stringifyImpl(node.expression, compact) + '!';
+ }
+ break;
+
+ case Syntax.OptionalType:
+ result = stringifyImpl(node.expression, compact) + '=';
+ break;
+
+ case Syntax.NullableType:
+ if (node.prefix) {
+ result = '?' + stringifyImpl(node.expression, compact);
+ } else {
+ result = stringifyImpl(node.expression, compact) + '?';
+ }
+ break;
+
+ case Syntax.NameExpression:
+ result = node.name;
+ break;
+
+ case Syntax.TypeApplication:
+ result = stringifyImpl(node.expression, compact) + '.<';
+ for (i = 0, iz = node.applications.length; i < iz; ++i) {
+ result += stringifyImpl(node.applications[i], compact);
+ if ((i + 1) !== iz) {
+ result += compact ? ',' : ', ';
+ }
+ }
+ result += '>';
+ break;
+
+ default:
+ throwError('Unknown type ' + node.type);
+ }
+
+ return result;
+ }
+
+ function stringify(node, options) {
+ if (options == null) {
+ options = {};
+ }
+ return stringifyImpl(node, options.compact, options.topLevel);
+ }
+
+ exports.parseType = parseType;
+ exports.parseParamType = parseParamType;
+ exports.stringify = stringify;
+ exports.Syntax = Syntax;
+ }(typed = {}));
+
+ // JSDoc Tag Parser
+
+ (function (exports) {
+ var Rules,
+ index,
+ lineNumber,
+ length,
+ source,
+ recoverable,
+ sloppy,
+ strict;
+
+ function advance() {
+ var ch = source[index];
+ index += 1;
+ if (isLineTerminator(ch)) {
+ lineNumber += 1;
+ }
+ return ch;
+ }
+
+ function scanTitle() {
+ var title = '';
+ // waste '@'
+ advance();
+
+ while (index < length && isASCIIAlphanumeric(source[index])) {
+ title += advance();
+ }
+
+ return title;
+ }
+
+ function seekContent() {
+ var ch, waiting, last = index;
+
+ waiting = false;
+ while (last < length) {
+ ch = source[last];
+ if (isLineTerminator(ch)) {
+ lineNumber += 1;
+ waiting = true;
+ } else if (waiting) {
+ if (ch === '@') {
+ break;
+ }
+ if (!isWhiteSpace(ch)) {
+ waiting = false;
+ }
+ }
+ last += 1;
+ }
+ return last;
+ }
+
+ // type expression may have nest brace, such as,
+ // { { ok: string } }
+ //
+ // therefore, scanning type expression with balancing braces.
+ function parseType(title, last) {
+ var ch, brace, type, direct = false;
+
+ // search '{'
+ while (index < last) {
+ ch = source[index];
+ if (isWhiteSpace(ch)) {
+ advance();
+ } else if (ch === '{') {
+ advance();
+ break;
+ } else {
+ // this is direct pattern
+ direct = true;
+ break;
+ }
+ }
+
+ if (!direct) {
+ // type expression { is found
+ brace = 1;
+ type = '';
+ while (index < last) {
+ ch = source[index];
+ if (isLineTerminator(ch)) {
+ advance();
+ } else {
+ if (ch === '}') {
+ brace -= 1;
+ if (brace === 0) {
+ advance();
+ break;
+ }
+ } else if (ch === '{') {
+ brace += 1;
+ }
+ type += advance();
+ }
+ }
+
+ if (brace !== 0) {
+ // braces is not balanced
+ return throwError('Braces are not balanced');
+ }
+
+ try {
+ if (isParamTitle(title)) {
+ return typed.parseParamType(type);
+ }
+ return typed.parseType(type);
+ } catch (e1) {
+ // parse failed
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ function scanIdentifier(last) {
+ var identifier;
+ if (!isIdentifierStart(source[index])) {
+ return null;
+ }
+ identifier = advance();
+ while (index < last && isIdentifierPart(source[index])) {
+ identifier += advance();
+ }
+ return identifier;
+ }
+
+ function skipWhiteSpace(last) {
+ while (index < last && (isWhiteSpace(source[index]) || isLineTerminator(source[index]))) {
+ advance();
+ }
+ }
+
+ function parseName(last, allowBrackets, allowNestedParams) {
+ var name = '', useBrackets;
+
+ skipWhiteSpace(last);
+
+ if (index >= last) {
+ return null;
+ }
+
+ if (allowBrackets && source[index] === '[') {
+ useBrackets = true;
+ name = advance();
+ }
+
+ if (!isIdentifierStart(source[index])) {
+ return null;
+ }
+
+ name += scanIdentifier(last);
+
+ if (allowNestedParams) {
+ while (source[index] === '.') {
+ name += '.';
+ index += 1;
+ name += scanIdentifier(last);
+ }
+ }
+
+ if (useBrackets) {
+ // do we have a default value for this?
+ if (source[index] === '=') {
+
+ // consume the '='' symbol
+ name += advance();
+ // scan in the default value
+ while (index < last && source[index] !== ']') {
+ name += advance();
+ }
+ }
+
+ if (index >= last || source[index] !== ']') {
+ // we never found a closing ']'
+ return null;
+ }
+
+ // collect the last ']'
+ name += advance();
+ }
+
+ return name;
+ }
+
+ function skipToTag() {
+ while (index < length && source[index] !== '@') {
+ advance();
+ }
+ if (index >= length) {
+ return false;
+ }
+ assert(source[index] === '@');
+ return true;
+ }
+
+ function TagParser(options, title) {
+ this._options = options;
+ this._title = title;
+ this._tag = {
+ title: title,
+ description: null
+ };
+ if (this._options.lineNumbers) {
+ this._tag.lineNumber = lineNumber;
+ }
+ this._last = 0;
+ // space to save special information for title parsers.
+ this._extra = { };
+ }
+
+ // addError(err, ...)
+ TagParser.prototype.addError = function addError(errorText) {
+ var args = Array.prototype.slice.call(arguments, 1),
+ msg = errorText.replace(
+ /%(\d)/g,
+ function (whole, index) {
+ assert(index < args.length, 'Message reference must be in range');
+ return args[index];
+ }
+ );
+
+ if (!this._tag.errors) {
+ this._tag.errors = [];
+ }
+ if (strict) {
+ throwError(msg);
+ }
+ this._tag.errors.push(msg);
+ return recoverable;
+ };
+
+ TagParser.prototype.parseType = function () {
+ // type required titles
+ if (isTypeParameterRequired(this._title)) {
+ try {
+ this._tag.type = parseType(this._title, this._last);
+ if (!this._tag.type) {
+ if (!isParamTitle(this._title)) {
+ if (!this.addError('Missing or invalid tag type')) {
+ return false;
+ }
+ }
+ }
+ } catch (error) {
+ this._tag.type = null;
+ if (!this.addError(error.message)) {
+ return false;
+ }
+ }
+ } else if (isAllowedType(this._title)) {
+ // optional types
+ try {
+ this._tag.type = parseType(this._title, this._last);
+ } catch (e) {
+ //For optional types, lets drop the thrown error when we hit the end of the file
+ }
+ }
+ return true;
+ };
+
+ TagParser.prototype._parseNamePath = function (optional) {
+ var name;
+ name = parseName(this._last, sloppy && isParamTitle(this._title), true);
+ if (!name) {
+ if (!optional) {
+ if (!this.addError('Missing or invalid tag name')) {
+ return false;
+ }
+ }
+ }
+ this._tag.name = name;
+ return true;
+ };
+
+ TagParser.prototype.parseNamePath = function () {
+ return this._parseNamePath(false);
+ };
+
+ TagParser.prototype.parseNamePathOptional = function () {
+ return this._parseNamePath(true);
+ };
+
+
+ TagParser.prototype.parseName = function () {
+ var assign, name;
+
+ // param, property requires name
+ if (isAllowedName(this._title)) {
+ this._tag.name = parseName(this._last, sloppy && isParamTitle(this._title), isAllowedNested(this._title));
+ if (!this._tag.name) {
+ if (!isNameParameterRequired(this._title)) {
+ return true;
+ }
+
+ // it's possible the name has already been parsed but interpreted as a type
+ // it's also possible this is a sloppy declaration, in which case it will be
+ // fixed at the end
+ if (isParamTitle(this._title) && this._tag.type.name) {
+ this._extra.name = this._tag.type;
+ this._tag.name = this._tag.type.name;
+ this._tag.type = null;
+ } else {
+ if (!this.addError('Missing or invalid tag name')) {
+ return false;
+ }
+ }
+ } else {
+ name = this._tag.name;
+ if (name.charAt(0) === '[' && name.charAt(name.length - 1) === ']') {
+ // extract the default value if there is one
+ // example: @param {string} [somebody=John Doe] description
+ assign = name.substring(1, name.length - 1).split('=');
+ if (assign[1]) {
+ this._tag['default'] = assign[1];
+ }
+ this._tag.name = assign[0];
+
+ // convert to an optional type
+ if (this._tag.type.type !== 'OptionalType') {
+ this._tag.type = {
+ type: 'OptionalType',
+ expression: this._tag.type
+ };
+ }
+ }
+ }
+ }
+
+ return true;
+ };
+
+ TagParser.prototype.parseDescription = function parseDescription() {
+ var description = trim(sliceSource(source, index, this._last));
+ if (description) {
+ if ((/^-\s+/).test(description)) {
+ description = description.substring(2);
+ }
+ this._tag.description = description;
+ }
+ return true;
+ };
+
+ TagParser.prototype.parseKind = function parseKind() {
+ var kind, kinds;
+ kinds = {
+ 'class': true,
+ 'constant': true,
+ 'event': true,
+ 'external': true,
+ 'file': true,
+ 'function': true,
+ 'member': true,
+ 'mixin': true,
+ 'module': true,
+ 'namespace': true,
+ 'typedef': true
+ };
+ kind = trim(sliceSource(source, index, this._last));
+ this._tag.kind = kind;
+ if (!hasOwnProperty(kinds, kind)) {
+ if (!this.addError('Invalid kind name \'%0\'', kind)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ TagParser.prototype.parseAccess = function parseAccess() {
+ var access;
+ access = trim(sliceSource(source, index, this._last));
+ this._tag.access = access;
+ if (access !== 'private' && access !== 'protected' && access !== 'public') {
+ if (!this.addError('Invalid access name \'%0\'', access)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ TagParser.prototype.parseVariation = function parseVariation() {
+ var variation, text;
+ text = trim(sliceSource(source, index, this._last));
+ variation = parseFloat(text, 10);
+ this._tag.variation = variation;
+ if (isNaN(variation)) {
+ if (!this.addError('Invalid variation \'%0\'', text)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ TagParser.prototype.ensureEnd = function () {
+ var shouldBeEmpty = trim(sliceSource(source, index, this._last));
+ if (shouldBeEmpty) {
+ if (!this.addError('Unknown content \'%0\'', shouldBeEmpty)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ TagParser.prototype.epilogue = function epilogue() {
+ var description;
+
+ description = this._tag.description;
+ // un-fix potentially sloppy declaration
+ if (isParamTitle(this._title) && !this._tag.type && description && description.charAt(0) === '[') {
+ this._tag.type = this._extra.name;
+ this._tag.name = undefined;
+
+ if (!sloppy) {
+ if (!this.addError('Missing or invalid tag name')) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ };
+
+ Rules = {
+ // http://usejsdoc.org/tags-access.html
+ 'access': ['parseAccess'],
+ // http://usejsdoc.org/tags-alias.html
+ 'alias': ['parseNamePath', 'ensureEnd'],
+ // http://usejsdoc.org/tags-augments.html
+ 'augments': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-constructor.html
+ 'constructor': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // Synonym: http://usejsdoc.org/tags-constructor.html
+ 'class': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // Synonym: http://usejsdoc.org/tags-extends.html
+ 'extends': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-deprecated.html
+ 'deprecated': ['parseDescription'],
+ // http://usejsdoc.org/tags-global.html
+ 'global': ['ensureEnd'],
+ // http://usejsdoc.org/tags-inner.html
+ 'inner': ['ensureEnd'],
+ // http://usejsdoc.org/tags-instance.html
+ 'instance': ['ensureEnd'],
+ // http://usejsdoc.org/tags-kind.html
+ 'kind': ['parseKind'],
+ // http://usejsdoc.org/tags-mixes.html
+ 'mixes': ['parseNamePath', 'ensureEnd'],
+ // http://usejsdoc.org/tags-mixin.html
+ 'mixin': ['parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-member.html
+ 'member': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-method.html
+ 'method': ['parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-module.html
+ 'module': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // Synonym: http://usejsdoc.org/tags-method.html
+ 'func': ['parseNamePathOptional', 'ensureEnd'],
+ // Synonym: http://usejsdoc.org/tags-method.html
+ 'function': ['parseNamePathOptional', 'ensureEnd'],
+ // Synonym: http://usejsdoc.org/tags-member.html
+ 'var': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-name.html
+ 'name': ['parseNamePath', 'ensureEnd'],
+ // http://usejsdoc.org/tags-namespace.html
+ 'namespace': ['parseType', 'parseNamePathOptional', 'ensureEnd'],
+ // http://usejsdoc.org/tags-private.html
+ 'private': ['parseType', 'parseDescription'],
+ // http://usejsdoc.org/tags-protected.html
+ 'protected': ['parseType', 'parseDescription'],
+ // http://usejsdoc.org/tags-public.html
+ 'public': ['parseType', 'parseDescription'],
+ // http://usejsdoc.org/tags-readonly.html
+ 'readonly': ['ensureEnd'],
+ // http://usejsdoc.org/tags-requires.html
+ 'requires': ['parseNamePath', 'ensureEnd'],
+ // http://usejsdoc.org/tags-since.html
+ 'since': ['parseDescription'],
+ // http://usejsdoc.org/tags-static.html
+ 'static': ['ensureEnd'],
+ // http://usejsdoc.org/tags-summary.html
+ 'summary': ['parseDescription'],
+ // http://usejsdoc.org/tags-this.html
+ 'this': ['parseNamePath', 'ensureEnd'],
+ // http://usejsdoc.org/tags-todo.html
+ 'todo': ['parseDescription'],
+ // http://usejsdoc.org/tags-variation.html
+ 'variation': ['parseVariation'],
+ // http://usejsdoc.org/tags-version.html
+ 'version': ['parseDescription']
+ };
+
+ TagParser.prototype.parse = function parse() {
+ var i, iz, sequences, method;
+
+ // empty title
+ if (!this._title) {
+ if (!this.addError('Missing or invalid title')) {
+ return null;
+ }
+ }
+
+ // Seek to content last index.
+ this._last = seekContent(this._title);
+
+ if (hasOwnProperty(Rules, this._title)) {
+ sequences = Rules[this._title];
+ } else {
+ // default sequences
+ sequences = ['parseType', 'parseName', 'parseDescription', 'epilogue'];
+ }
+
+ for (i = 0, iz = sequences.length; i < iz; ++i) {
+ method = sequences[i];
+ if (!this[method]()) {
+ return null;
+ }
+ }
+
+ // Seek global index to end of this tag.
+ index = this._last;
+ return this._tag;
+ };
+
+ function parseTag(options) {
+ var title, parser;
+
+ // skip to tag
+ if (!skipToTag()) {
+ return null;
+ }
+
+ // scan title
+ title = scanTitle();
+
+ // construct tag parser
+ parser = new TagParser(options, title);
+ return parser.parse();
+ }
+
+ //
+ // Parse JSDoc
+ //
+
+ function scanJSDocDescription() {
+ var description = '', ch, atAllowed;
+
+ atAllowed = true;
+ while (index < length) {
+ ch = source[index];
+
+ if (atAllowed && ch === '@') {
+ break;
+ }
+
+ if (isLineTerminator(ch)) {
+ atAllowed = true;
+ } else if (atAllowed && !isWhiteSpace(ch)) {
+ atAllowed = false;
+ }
+
+ description += advance();
+ }
+ return trim(description);
+ }
+
+ function parse(comment, options) {
+ var tags = [], tag, description, interestingTags, i, iz;
+
+ if (options === undefined) {
+ options = {};
+ }
+
+ if (typeof options.unwrap === 'boolean' && options.unwrap) {
+ source = unwrapComment(comment);
+ } else {
+ source = comment;
+ }
+
+ // array of relevant tags
+ if (options.tags) {
+ if (isArray(options.tags)) {
+ interestingTags = { };
+ for (i = 0, iz = options.tags.length; i < iz; i++) {
+ if (typeof options.tags[i] === 'string') {
+ interestingTags[options.tags[i]] = true;
+ } else {
+ throwError('Invalid "tags" parameter: ' + options.tags);
+ }
+ }
+ } else {
+ throwError('Invalid "tags" parameter: ' + options.tags);
+ }
+ }
+
+ if (!CanAccessStringByIndex) {
+ source = source.split('');
+ }
+
+ length = source.length;
+ index = 0;
+ lineNumber = 0;
+ recoverable = options.recoverable;
+ sloppy = options.sloppy;
+ strict = options.strict;
+
+ description = scanJSDocDescription();
+
+ while (true) {
+ tag = parseTag(options);
+ if (!tag) {
+ break;
+ }
+ if (!interestingTags || interestingTags.hasOwnProperty(tag.title)) {
+ tags.push(tag);
+ }
+ }
+
+ return {
+ description: description,
+ tags: tags
+ };
+ }
+ exports.parse = parse;
+ }(jsdoc = {}));
+
+ exports.version = VERSION;
+ exports.parse = jsdoc.parse;
+ exports.parseType = typed.parseType;
+ exports.parseParamType = typed.parseParamType;
+ exports.unwrapComment = unwrapComment;
+ exports.Syntax = shallowCopy(typed.Syntax);
+ exports.Error = DoctrineError;
+ exports.type = {
+ Syntax: exports.Syntax,
+ parseType: typed.parseType,
+ parseParamType: typed.parseParamType,
+ stringify: typed.stringify
+ };
+}(typeof exports === 'undefined' ? (doctrine = {}) : exports));
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+},{}],5:[function(require,module,exports){
+/*
+ Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
+ Copyright (C) 2013 Alex Seville <hi@alexanderseville.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * Escope (<a href="http://github.com/Constellation/escope">escope</a>) is an <a
+ * href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript</a>
+ * scope analyzer extracted from the <a
+ * href="http://github.com/Constellation/esmangle">esmangle project</a/>.
+ * <p>
+ * <em>escope</em> finds lexical scopes in a source program, i.e. areas of that
+ * program where different occurrences of the same identifier refer to the same
+ * variable. With each scope the contained variables are collected, and each
+ * identifier reference in code is linked to its corresponding variable (if
+ * possible).
+ * <p>
+ * <em>escope</em> works on a syntax tree of the parsed source code which has
+ * to adhere to the <a
+ * href="https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API">
+ * Mozilla Parser API</a>. E.g. <a href="http://esprima.org">esprima</a> is a parser
+ * that produces such syntax trees.
+ * <p>
+ * The main interface is the {@link analyze} function.
+ * @module
+ */
+
+/*jslint bitwise:true */
+/*global exports:true, define:true, require:true*/
+(function (factory, global) {
+ 'use strict';
+
+ function namespace(str, obj) {
+ var i, iz, names, name;
+ names = str.split('.');
+ for (i = 0, iz = names.length; i < iz; ++i) {
+ name = names[i];
+ if (obj.hasOwnProperty(name)) {
+ obj = obj[name];
+ } else {
+ obj = (obj[name] = {});
+ }
+ }
+ return obj;
+ }
+
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+ // and plain browser loading,
+ if (typeof define === 'function' && define.amd) {
+ define('escope', ['exports', 'estraverse'], function (exports, estraverse) {
+ factory(exports, global, estraverse);
+ });
+ } else if (typeof exports !== 'undefined') {
+ factory(exports, global, require('estraverse'));
+ } else {
+ factory(namespace('escope', global), global, global.estraverse);
+ }
+}(function (exports, global, estraverse) {
+ 'use strict';
+
+ var Syntax,
+ Map,
+ currentScope,
+ globalScope,
+ scopes,
+ options;
+
+ Syntax = estraverse.Syntax;
+
+ if (typeof global.Map !== 'undefined') {
+ // ES6 Map
+ Map = global.Map;
+ } else {
+ Map = function Map() {
+ this.__data = {};
+ };
+
+ Map.prototype.get = function MapGet(key) {
+ key = '$' + key;
+ if (this.__data.hasOwnProperty(key)) {
+ return this.__data[key];
+ }
+ return undefined;
+ };
+
+ Map.prototype.has = function MapHas(key) {
+ key = '$' + key;
+ return this.__data.hasOwnProperty(key);
+ };
+
+ Map.prototype.set = function MapSet(key, val) {
+ key = '$' + key;
+ this.__data[key] = val;
+ };
+
+ Map.prototype['delete'] = function MapDelete(key) {
+ key = '$' + key;
+ return delete this.__data[key];
+ };
+ }
+
+ function assert(cond, text) {
+ if (!cond) {
+ throw new Error(text);
+ }
+ }
+
+ function defaultOptions() {
+ return {
+ optimistic: false,
+ directive: false
+ };
+ }
+
+ function updateDeeply(target, override) {
+ var key, val;
+
+ function isHashObject(target) {
+ return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
+ }
+
+ for (key in override) {
+ if (override.hasOwnProperty(key)) {
+ val = override[key];
+ if (isHashObject(val)) {
+ if (isHashObject(target[key])) {
+ updateDeeply(target[key], val);
+ } else {
+ target[key] = updateDeeply({}, val);
+ }
+ } else {
+ target[key] = val;
+ }
+ }
+ }
+ return target;
+ }
+
+ /**
+ * A Reference represents a single occurrence of an identifier in code.
+ * @class Reference
+ */
+ function Reference(ident, scope, flag, writeExpr, maybeImplicitGlobal) {
+ /**
+ * Identifier syntax node.
+ * @member {esprima#Identifier} Reference#identifier
+ */
+ this.identifier = ident;
+ /**
+ * Reference to the enclosing Scope.
+ * @member {Scope} Reference#from
+ */
+ this.from = scope;
+ /**
+ * Whether the reference comes from a dynamic scope (such as 'eval',
+ * 'with', etc.), and may be trapped by dynamic scopes.
+ * @member {boolean} Reference#tainted
+ */
+ this.tainted = false;
+ /**
+ * The variable this reference is resolved with.
+ * @member {Variable} Reference#resolved
+ */
+ this.resolved = null;
+ /**
+ * The read-write mode of the reference. (Value is one of {@link
+ * Reference.READ}, {@link Reference.RW}, {@link Reference.WRITE}).
+ * @member {number} Reference#flag
+ * @private
+ */
+ this.flag = flag;
+ if (this.isWrite()) {
+ /**
+ * If reference is writeable, this is the tree being written to it.
+ * @member {esprima#Node} Reference#writeExpr
+ */
+ this.writeExpr = writeExpr;
+ }
+ /**
+ * Whether the Reference might refer to a global variable.
+ * @member {boolean} Reference#__maybeImplicitGlobal
+ * @private
+ */
+ this.__maybeImplicitGlobal = maybeImplicitGlobal;
+ }
+
+ /**
+ * @constant Reference.READ
+ * @private
+ */
+ Reference.READ = 0x1;
+ /**
+ * @constant Reference.WRITE
+ * @private
+ */
+ Reference.WRITE = 0x2;
+ /**
+ * @constant Reference.RW
+ * @private
+ */
+ Reference.RW = 0x3;
+
+ /**
+ * Whether the reference is static.
+ * @method Reference#isStatic
+ * @return {boolean}
+ */
+ Reference.prototype.isStatic = function isStatic() {
+ return !this.tainted && this.resolved && this.resolved.scope.isStatic();
+ };
+
+ /**
+ * Whether the reference is writeable.
+ * @method Reference#isWrite
+ * @return {boolean}
+ */
+ Reference.prototype.isWrite = function isWrite() {
+ return this.flag & Reference.WRITE;
+ };
+
+ /**
+ * Whether the reference is readable.
+ * @method Reference#isRead
+ * @return {boolean}
+ */
+ Reference.prototype.isRead = function isRead() {
+ return this.flag & Reference.READ;
+ };
+
+ /**
+ * Whether the reference is read-only.
+ * @method Reference#isReadOnly
+ * @return {boolean}
+ */
+ Reference.prototype.isReadOnly = function isReadOnly() {
+ return this.flag === Reference.READ;
+ };
+
+ /**
+ * Whether the reference is write-only.
+ * @method Reference#isWriteOnly
+ * @return {boolean}
+ */
+ Reference.prototype.isWriteOnly = function isWriteOnly() {
+ return this.flag === Reference.WRITE;
+ };
+
+ /**
+ * Whether the reference is read-write.
+ * @method Reference#isReadWrite
+ * @return {boolean}
+ */
+ Reference.prototype.isReadWrite = function isReadWrite() {
+ return this.flag === Reference.RW;
+ };
+
+ /**
+ * A Variable represents a locally scoped identifier. These include arguments to
+ * functions.
+ * @class Variable
+ */
+ function Variable(name, scope) {
+ /**
+ * The variable name, as given in the source code.
+ * @member {String} Variable#name
+ */
+ this.name = name;
+ /**
+ * List of defining occurrences of this variable (like in 'var ...'
+ * statements or as parameter), as AST nodes.
+ * @member {esprima.Identifier[]} Variable#identifiers
+ */
+ this.identifiers = [];
+ /**
+ * List of {@link Reference|references} of this variable (excluding parameter entries)
+ * in its defining scope and all nested scopes. For defining
+ * occurrences only see {@link Variable#defs}.
+ * @member {Reference[]} Variable#references
+ */
+ this.references = [];
+
+ /**
+ * List of defining occurrences of this variable (like in 'var ...'
+ * statements or as parameter), as custom objects.
+ * @typedef {Object} DefEntry
+ * @property {String} DefEntry.type - the type of the occurrence (e.g.
+ * "Parameter", "Variable", ...)
+ * @property {esprima.Identifier} DefEntry.name - the identifier AST node of the occurrence
+ * @property {esprima.Node} DefEntry.node - the enclosing node of the
+ * identifier
+ * @property {esprima.Node} [DefEntry.parent] - the enclosing statement
+ * node of the identifier
+ * @member {DefEntry[]} Variable#defs
+ */
+ this.defs = [];
+
+ this.tainted = false;
+ /**
+ * Whether this is a stack variable.
+ * @member {boolean} Variable#stack
+ */
+ this.stack = true;
+ /**
+ * Reference to the enclosing Scope.
+ * @member {Scope} Variable#scope
+ */
+ this.scope = scope;
+ }
+
+ Variable.CatchClause = 'CatchClause';
+ Variable.Parameter = 'Parameter';
+ Variable.FunctionName = 'FunctionName';
+ Variable.Variable = 'Variable';
+ Variable.ImplicitGlobalVariable = 'ImplicitGlobalVariable';
+
+ function isStrictScope(scope, block) {
+ var body, i, iz, stmt, expr;
+
+ // When upper scope is exists and strict, inner scope is also strict.
+ if (scope.upper && scope.upper.isStrict) {
+ return true;
+ }
+
+ if (scope.type === 'function') {
+ body = block.body;
+ } else if (scope.type === 'global') {
+ body = block;
+ } else {
+ return false;
+ }
+
+ if (options.directive) {
+ for (i = 0, iz = body.body.length; i < iz; ++i) {
+ stmt = body.body[i];
+ if (stmt.type !== 'DirectiveStatement') {
+ break;
+ }
+ if (stmt.raw === '"use strict"' || stmt.raw === '\'use strict\'') {
+ return true;
+ }
+ }
+ } else {
+ for (i = 0, iz = body.body.length; i < iz; ++i) {
+ stmt = body.body[i];
+ if (stmt.type !== Syntax.ExpressionStatement) {
+ break;
+ }
+ expr = stmt.expression;
+ if (expr.type !== Syntax.Literal || typeof expr.value !== 'string') {
+ break;
+ }
+ if (expr.raw != null) {
+ if (expr.raw === '"use strict"' || expr.raw === '\'use strict\'') {
+ return true;
+ }
+ } else {
+ if (expr.value === 'use strict') {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @class Scope
+ */
+ function Scope(block, opt) {
+ var variable, body;
+
+ /**
+ * One of 'catch', 'with', 'function' or 'global'.
+ * @member {String} Scope#type
+ */
+ this.type =
+ (block.type === Syntax.CatchClause) ? 'catch' :
+ (block.type === Syntax.WithStatement) ? 'with' :
+ (block.type === Syntax.Program) ? 'global' : 'function';
+ /**
+ * The scoped {@link Variable}s of this scope, as <code>{ Variable.name
+ * : Variable }</code>.
+ * @member {Map} Scope#set
+ */
+ this.set = new Map();
+ /**
+ * The tainted variables of this scope, as <code>{ Variable.name :
+ * boolean }</code>.
+ * @member {Map} Scope#taints */
+ this.taints = new Map();
+ /**
+ * Generally, through the lexical scoping of JS you can always know
+ * which variable an identifier in the source code refers to. There are
+ * a few exceptions to this rule. With 'global' and 'with' scopes you
+ * can only decide at runtime which variable a reference refers to.
+ * Moreover, if 'eval()' is used in a scope, it might introduce new
+ * bindings in this or its prarent scopes.
+ * All those scopes are considered 'dynamic'.
+ * @member {boolean} Scope#dynamic
+ */
+ this.dynamic = this.type === 'global' || this.type === 'with';
+ /**
+ * A reference to the scope-defining syntax node.
+ * @member {esprima.Node} Scope#block
+ */
+ this.block = block;
+ /**
+ * The {@link Reference|references} that are not resolved with this scope.
+ * @member {Reference[]} Scope#through
+ */
+ this.through = [];
+ /**
+ * The scoped {@link Variable}s of this scope. In the case of a
+ * 'function' scope this includes the automatic argument <em>arguments</em> as
+ * its first element, as well as all further formal arguments.
+ * @member {Variable[]} Scope#variables
+ */
+ this.variables = [];
+ /**
+ * Any variable {@link Reference|reference} found in this scope. This
+ * includes occurrences of local variables as well as variables from
+ * parent scopes (including the global scope). For local variables
+ * this also includes defining occurrences (like in a 'var' statement).
+ * In a 'function' scope this does not include the occurrences of the
+ * formal parameter in the parameter list.
+ * @member {Reference[]} Scope#references
+ */
+ this.references = [];
+ /**
+ * List of {@link Reference}s that are left to be resolved (i.e. which
+ * need to be linked to the variable they refer to). Used internally to
+ * resolve bindings during scope analysis. On a finalized scope
+ * analysis, all sopes have <em>left</em> value <strong>null</strong>.
+ * @member {Reference[]} Scope#left
+ */
+ this.left = [];
+ /**
+ * For 'global' and 'function' scopes, this is a self-reference. For
+ * other scope types this is the <em>variableScope</em> value of the
+ * parent scope.
+ * @member {Scope} Scope#variableScope
+ */
+ this.variableScope =
+ (this.type === 'global' || this.type === 'function') ? this : currentScope.variableScope;
+ /**
+ * Whether this scope is created by a FunctionExpression.
+ * @member {boolean} Scope#functionExpressionScope
+ */
+ this.functionExpressionScope = false;
+ /**
+ * Whether this is a scope that contains an 'eval()' invocation.
+ * @member {boolean} Scope#directCallToEvalScope
+ */
+ this.directCallToEvalScope = false;
+ /**
+ * @member {boolean} Scope#thisFound
+ */
+ this.thisFound = false;
+ body = this.type === 'function' ? block.body : block;
+ if (opt.naming) {
+ this.__define(block.id, {
+ type: Variable.FunctionName,
+ name: block.id,
+ node: block
+ });
+ this.functionExpressionScope = true;
+ } else {
+ if (this.type === 'function') {
+ variable = new Variable('arguments', this);
+ this.taints.set('arguments', true);
+ this.set.set('arguments', variable);
+ this.variables.push(variable);
+ }
+
+ if (block.type === Syntax.FunctionExpression && block.id) {
+ new Scope(block, { naming: true });
+ }
+ }
+
+ /**
+ * Reference to the parent {@link Scope|scope}.
+ * @member {Scope} Scope#upper
+ */
+ this.upper = currentScope;
+ /**
+ * Whether 'use strict' is in effect in this scope.
+ * @member {boolean} Scope#isStrict
+ */
+ this.isStrict = isStrictScope(this, block);
+
+ /**
+ * List of nested {@link Scope}s.
+ * @member {Scope[]} Scope#childScopes
+ */
+ this.childScopes = [];
+ if (currentScope) {
+ currentScope.childScopes.push(this);
+ }
+
+
+ // RAII
+ currentScope = this;
+ if (this.type === 'global') {
+ globalScope = this;
+ globalScope.implicit = {
+ set: new Map(),
+ variables: []
+ };
+ }
+ scopes.push(this);
+ }
+
+ Scope.prototype.__close = function __close() {
+ var i, iz, ref, current, node, implicit;
+
+ // Because if this is global environment, upper is null
+ if (!this.dynamic || options.optimistic) {
+ // static resolve
+ for (i = 0, iz = this.left.length; i < iz; ++i) {
+ ref = this.left[i];
+ if (!this.__resolve(ref)) {
+ this.__delegateToUpperScope(ref);
+ }
+ }
+ } else {
+ // this is "global" / "with" / "function with eval" environment
+ if (this.type === 'with') {
+ for (i = 0, iz = this.left.length; i < iz; ++i) {
+ ref = this.left[i];
+ ref.tainted = true;
+ this.__delegateToUpperScope(ref);
+ }
+ } else {
+ for (i = 0, iz = this.left.length; i < iz; ++i) {
+ // notify all names are through to global
+ ref = this.left[i];
+ current = this;
+ do {
+ current.through.push(ref);
+ current = current.upper;
+ } while (current);
+ }
+ }
+ }
+
+ if (this.type === 'global') {
+ implicit = [];
+ for (i = 0, iz = this.left.length; i < iz; ++i) {
+ ref = this.left[i];
+ if (ref.__maybeImplicitGlobal && !this.set.has(ref.identifier.name)) {
+ implicit.push(ref.__maybeImplicitGlobal);
+ }
+ }
+
+ // create an implicit global variable from assignment expression
+ for (i = 0, iz = implicit.length; i < iz; ++i) {
+ node = implicit[i];
+ this.__defineImplicit(node.left, {
+ type: Variable.ImplicitGlobalVariable,
+ name: node.left,
+ node: node
+ });
+ }
+ }
+
+ this.left = null;
+ currentScope = this.upper;
+ };
+
+ Scope.prototype.__resolve = function __resolve(ref) {
+ var variable, name;
+ name = ref.identifier.name;
+ if (this.set.has(name)) {
+ variable = this.set.get(name);
+ variable.references.push(ref);
+ variable.stack = variable.stack && ref.from.variableScope === this.variableScope;
+ if (ref.tainted) {
+ variable.tainted = true;
+ this.taints.set(variable.name, true);
+ }
+ ref.resolved = variable;
+ return true;
+ }
+ return false;
+ };
+
+ Scope.prototype.__delegateToUpperScope = function __delegateToUpperScope(ref) {
+ if (this.upper) {
+ this.upper.left.push(ref);
+ }
+ this.through.push(ref);
+ };
+
+ Scope.prototype.__defineImplicit = function __defineImplicit(node, info) {
+ var name, variable;
+ if (node && node.type === Syntax.Identifier) {
+ name = node.name;
+ if (!this.implicit.set.has(name)) {
+ variable = new Variable(name, this);
+ variable.identifiers.push(node);
+ variable.defs.push(info);
+ this.implicit.set.set(name, variable);
+ this.implicit.variables.push(variable);
+ } else {
+ variable = this.implicit.set.get(name);
+ variable.identifiers.push(node);
+ variable.defs.push(info);
+ }
+ }
+ };
+
+ Scope.prototype.__define = function __define(node, info) {
+ var name, variable;
+ if (node && node.type === Syntax.Identifier) {
+ name = node.name;
+ if (!this.set.has(name)) {
+ variable = new Variable(name, this);
+ variable.identifiers.push(node);
+ variable.defs.push(info);
+ this.set.set(name, variable);
+ this.variables.push(variable);
+ } else {
+ variable = this.set.get(name);
+ variable.identifiers.push(node);
+ variable.defs.push(info);
+ }
+ }
+ };
+
+ Scope.prototype.__referencing = function __referencing(node, assign, writeExpr, maybeImplicitGlobal) {
+ var ref;
+ // because Array element may be null
+ if (node && node.type === Syntax.Identifier) {
+ ref = new Reference(node, this, assign || Reference.READ, writeExpr, maybeImplicitGlobal);
+ this.references.push(ref);
+ this.left.push(ref);
+ }
+ };
+
+ Scope.prototype.__detectEval = function __detectEval() {
+ var current;
+ current = this;
+ this.directCallToEvalScope = true;
+ do {
+ current.dynamic = true;
+ current = current.upper;
+ } while (current);
+ };
+
+ Scope.prototype.__detectThis = function __detectThis() {
+ this.thisFound = true;
+ };
+
+ Scope.prototype.__isClosed = function isClosed() {
+ return this.left === null;
+ };
+
+ // API Scope#resolve(name)
+ // returns resolved reference
+ Scope.prototype.resolve = function resolve(ident) {
+ var ref, i, iz;
+ assert(this.__isClosed(), 'scope should be closed');
+ assert(ident.type === Syntax.Identifier, 'target should be identifier');
+ for (i = 0, iz = this.references.length; i < iz; ++i) {
+ ref = this.references[i];
+ if (ref.identifier === ident) {
+ return ref;
+ }
+ }
+ return null;
+ };
+
+ // API Scope#isStatic
+ // returns this scope is static
+ Scope.prototype.isStatic = function isStatic() {
+ return !this.dynamic;
+ };
+
+ // API Scope#isArgumentsMaterialized
+ // return this scope has materialized arguments
+ Scope.prototype.isArgumentsMaterialized = function isArgumentsMaterialized() {
+ // TODO(Constellation)
+ // We can more aggressive on this condition like this.
+ //
+ // function t() {
+ // // arguments of t is always hidden.
+ // function arguments() {
+ // }
+ // }
+ var variable;
+
+ // This is not function scope
+ if (this.type !== 'function') {
+ return true;
+ }
+
+ if (!this.isStatic()) {
+ return true;
+ }
+
+ variable = this.set.get('arguments');
+ assert(variable, 'always have arguments variable');
+ return variable.tainted || variable.references.length !== 0;
+ };
+
+ // API Scope#isThisMaterialized
+ // return this scope has materialized `this` reference
+ Scope.prototype.isThisMaterialized = function isThisMaterialized() {
+ // This is not function scope
+ if (this.type !== 'function') {
+ return true;
+ }
+ if (!this.isStatic()) {
+ return true;
+ }
+ return this.thisFound;
+ };
+
+ Scope.mangledName = '__$escope$__';
+
+ Scope.prototype.attach = function attach() {
+ if (!this.functionExpressionScope) {
+ this.block[Scope.mangledName] = this;
+ }
+ };
+
+ Scope.prototype.detach = function detach() {
+ if (!this.functionExpressionScope) {
+ delete this.block[Scope.mangledName];
+ }
+ };
+
+ Scope.prototype.isUsedName = function (name) {
+ if (this.set.has(name)) {
+ return true;
+ }
+ for (var i = 0, iz = this.through.length; i < iz; ++i) {
+ if (this.through[i].identifier.name === name) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ /**
+ * @class ScopeManager
+ */
+ function ScopeManager(scopes) {
+ this.scopes = scopes;
+ this.attached = false;
+ }
+
+ // Returns appropliate scope for this node
+ ScopeManager.prototype.__get = function __get(node) {
+ var i, iz, scope;
+ if (this.attached) {
+ return node[Scope.mangledName] || null;
+ }
+ if (Scope.isScopeRequired(node)) {
+ for (i = 0, iz = this.scopes.length; i < iz; ++i) {
+ scope = this.scopes[i];
+ if (!scope.functionExpressionScope) {
+ if (scope.block === node) {
+ return scope;
+ }
+ }
+ }
+ }
+ return null;
+ };
+
+ ScopeManager.prototype.acquire = function acquire(node) {
+ return this.__get(node);
+ };
+
+ ScopeManager.prototype.release = function release(node) {
+ var scope = this.__get(node);
+ if (scope) {
+ scope = scope.upper;
+ while (scope) {
+ if (!scope.functionExpressionScope) {
+ return scope;
+ }
+ scope = scope.upper;
+ }
+ }
+ return null;
+ };
+
+ ScopeManager.prototype.attach = function attach() {
+ var i, iz;
+ for (i = 0, iz = this.scopes.length; i < iz; ++i) {
+ this.scopes[i].attach();
+ }
+ this.attached = true;
+ };
+
+ ScopeManager.prototype.detach = function detach() {
+ var i, iz;
+ for (i = 0, iz = this.scopes.length; i < iz; ++i) {
+ this.scopes[i].detach();
+ }
+ this.attached = false;
+ };
+
+ Scope.isScopeRequired = function isScopeRequired(node) {
+ return Scope.isVariableScopeRequired(node) || node.type === Syntax.WithStatement || node.type === Syntax.CatchClause;
+ };
+
+ Scope.isVariableScopeRequired = function isVariableScopeRequired(node) {
+ return node.type === Syntax.Program || node.type === Syntax.FunctionExpression || node.type === Syntax.FunctionDeclaration;
+ };
+
+ /**
+ * Main interface function. Takes an Esprima syntax tree and returns the
+ * analyzed scopes.
+ * @function analyze
+ * @param {esprima.Tree} tree
+ * @param {Object} providedOptions - Options that tailor the scope analysis
+ * @param {boolean} [providedOptions.optimistic=false] - the optimistic flag
+ * @param {boolean} [providedOptions.directive=false]- the directive flag
+ * @param {boolean} [providedOptions.ignoreEval=false]- whether to check 'eval()' calls
+ * @return {ScopeManager}
+ */
+ function analyze(tree, providedOptions) {
+ var resultScopes;
+
+ options = updateDeeply(defaultOptions(), providedOptions);
+ resultScopes = scopes = [];
+ currentScope = null;
+ globalScope = null;
+
+ // attach scope and collect / resolve names
+ estraverse.traverse(tree, {
+ enter: function enter(node) {
+ var i, iz, decl;
+ if (Scope.isScopeRequired(node)) {
+ new Scope(node, {});
+ }
+
+ switch (node.type) {
+ case Syntax.AssignmentExpression:
+ if (node.operator === '=') {
+ currentScope.__referencing(node.left, Reference.WRITE, node.right, (!currentScope.isStrict && node.left.name != null) && node);
+ } else {
+ currentScope.__referencing(node.left, Reference.RW, node.right);
+ }
+ currentScope.__referencing(node.right);
+ break;
+
+ case Syntax.ArrayExpression:
+ for (i = 0, iz = node.elements.length; i < iz; ++i) {
+ currentScope.__referencing(node.elements[i]);
+ }
+ break;
+
+ case Syntax.BlockStatement:
+ break;
+
+ case Syntax.BinaryExpression:
+ currentScope.__referencing(node.left);
+ currentScope.__referencing(node.right);
+ break;
+
+ case Syntax.BreakStatement:
+ break;
+
+ case Syntax.CallExpression:
+ currentScope.__referencing(node.callee);
+ for (i = 0, iz = node['arguments'].length; i < iz; ++i) {
+ currentScope.__referencing(node['arguments'][i]);
+ }
+
+ // check this is direct call to eval
+ if (!options.ignoreEval && node.callee.type === Syntax.Identifier && node.callee.name === 'eval') {
+ currentScope.variableScope.__detectEval();
+ }
+ break;
+
+ case Syntax.CatchClause:
+ currentScope.__define(node.param, {
+ type: Variable.CatchClause,
+ name: node.param,
+ node: node
+ });
+ break;
+
+ case Syntax.ConditionalExpression:
+ currentScope.__referencing(node.test);
+ currentScope.__referencing(node.consequent);
+ currentScope.__referencing(node.alternate);
+ break;
+
+ case Syntax.ContinueStatement:
+ break;
+
+ case Syntax.DirectiveStatement:
+ break;
+
+ case Syntax.DoWhileStatement:
+ currentScope.__referencing(node.test);
+ break;
+
+ case Syntax.DebuggerStatement:
+ break;
+
+ case Syntax.EmptyStatement:
+ break;
+
+ case Syntax.ExpressionStatement:
+ currentScope.__referencing(node.expression);
+ break;
+
+ case Syntax.ForStatement:
+ currentScope.__referencing(node.init);
+ currentScope.__referencing(node.test);
+ currentScope.__referencing(node.update);
+ break;
+
+ case Syntax.ForInStatement:
+ if (node.left.type === Syntax.VariableDeclaration) {
+ currentScope.__referencing(node.left.declarations[0].id, Reference.WRITE, null, false);
+ } else {
+ currentScope.__referencing(node.left, Reference.WRITE, null, (!currentScope.isStrict && node.left.name != null) && node);
+ }
+ currentScope.__referencing(node.right);
+ break;
+
+ case Syntax.FunctionDeclaration:
+ // FunctionDeclaration name is defined in upper scope
+ currentScope.upper.__define(node.id, {
+ type: Variable.FunctionName,
+ name: node.id,
+ node: node
+ });
+ for (i = 0, iz = node.params.length; i < iz; ++i) {
+ currentScope.__define(node.params[i], {
+ type: Variable.Parameter,
+ name: node.params[i],
+ node: node,
+ index: i
+ });
+ }
+ break;
+
+ case Syntax.FunctionExpression:
+ // id is defined in upper scope
+ for (i = 0, iz = node.params.length; i < iz; ++i) {
+ currentScope.__define(node.params[i], {
+ type: Variable.Parameter,
+ name: node.params[i],
+ node: node,
+ index: i
+ });
+ }
+ break;
+
+ case Syntax.Identifier:
+ break;
+
+ case Syntax.IfStatement:
+ currentScope.__referencing(node.test);
+ break;
+
+ case Syntax.Literal:
+ break;
+
+ case Syntax.LabeledStatement:
+ break;
+
+ case Syntax.LogicalExpression:
+ currentScope.__referencing(node.left);
+ currentScope.__referencing(node.right);
+ break;
+
+ case Syntax.MemberExpression:
+ currentScope.__referencing(node.object);
+ if (node.computed) {
+ currentScope.__referencing(node.property);
+ }
+ break;
+
+ case Syntax.NewExpression:
+ currentScope.__referencing(node.callee);
+ for (i = 0, iz = node['arguments'].length; i < iz; ++i) {
+ currentScope.__referencing(node['arguments'][i]);
+ }
+ break;
+
+ case Syntax.ObjectExpression:
+ break;
+
+ case Syntax.Program:
+ break;
+
+ case Syntax.Property:
+ currentScope.__referencing(node.value);
+ break;
+
+ case Syntax.ReturnStatement:
+ currentScope.__referencing(node.argument);
+ break;
+
+ case Syntax.SequenceExpression:
+ for (i = 0, iz = node.expressions.length; i < iz; ++i) {
+ currentScope.__referencing(node.expressions[i]);
+ }
+ break;
+
+ case Syntax.SwitchStatement:
+ currentScope.__referencing(node.discriminant);
+ break;
+
+ case Syntax.SwitchCase:
+ currentScope.__referencing(node.test);
+ break;
+
+ case Syntax.ThisExpression:
+ currentScope.variableScope.__detectThis();
+ break;
+
+ case Syntax.ThrowStatement:
+ currentScope.__referencing(node.argument);
+ break;
+
+ case Syntax.TryStatement:
+ break;
+
+ case Syntax.UnaryExpression:
+ currentScope.__referencing(node.argument);
+ break;
+
+ case Syntax.UpdateExpression:
+ currentScope.__referencing(node.argument, Reference.RW, null);
+ break;
+
+ case Syntax.VariableDeclaration:
+ for (i = 0, iz = node.declarations.length; i < iz; ++i) {
+ decl = node.declarations[i];
+ currentScope.variableScope.__define(decl.id, {
+ type: Variable.Variable,
+ name: decl.id,
+ node: decl,
+ index: i,
+ parent: node
+ });
+ if (decl.init) {
+ // initializer is found
+ currentScope.__referencing(decl.id, Reference.WRITE, decl.init, false);
+ currentScope.__referencing(decl.init);
+ }
+ }
+ break;
+
+ case Syntax.VariableDeclarator:
+ break;
+
+ case Syntax.WhileStatement:
+ currentScope.__referencing(node.test);
+ break;
+
+ case Syntax.WithStatement:
+ // WithStatement object is referenced at upper scope
+ currentScope.upper.__referencing(node.object);
+ break;
+ }
+ },
+
+ leave: function leave(node) {
+ while (currentScope && node === currentScope.block) {
+ currentScope.__close();
+ }
+ }
+ });
+
+ assert(currentScope === null);
+ globalScope = null;
+ scopes = null;
+ options = null;
+
+ return new ScopeManager(resultScopes);
+ }
+
+ /** @name module:escope.version */
+ exports.version = '1.0.1';
+ /** @name module:escope.Reference */
+ exports.Reference = Reference;
+ /** @name module:escope.Variable */
+ exports.Variable = Variable;
+ /** @name module:escope.Scope */
+ exports.Scope = Scope;
+ /** @name module:escope.ScopeManager */
+ exports.ScopeManager = ScopeManager;
+ /** @name module:escope.analyze */
+ exports.analyze = analyze;
+}, this));
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+},{"estraverse":7}],6:[function(require,module,exports){
+/*
+ Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
+ Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
+ Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be>
+ Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
+ Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
+ Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
+ Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
+ Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
+ Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
+ Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*jslint bitwise:true plusplus:true */
+/*global esprima:true, define:true, exports:true, window: true,
+throwErrorTolerant: true,
+throwError: true, generateStatement: true, peek: true,
+parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
+parseFunctionDeclaration: true, parseFunctionExpression: true,
+parseFunctionSourceElements: true, parseVariableIdentifier: true,
+parseLeftHandSideExpression: true,
+parseUnaryExpression: true,
+parseStatement: true, parseSourceElement: true */
+
+(function (root, factory) {
+ 'use strict';
+
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+ // Rhino, and plain browser loading.
+
+ /* istanbul ignore next */
+ if (typeof define === 'function' && define.amd) {
+ define(['exports'], factory);
+ } else if (typeof exports !== 'undefined') {
+ factory(exports);
+ } else {
+ factory((root.esprima = {}));
+ }
+}(this, function (exports) {
+ 'use strict';
+
+ var Token,
+ TokenName,
+ FnExprTokens,
+ Syntax,
+ PropertyKind,
+ Messages,
+ Regex,
+ SyntaxTreeDelegate,
+ source,
+ strict,
+ index,
+ lineNumber,
+ lineStart,
+ length,
+ delegate,
+ lookahead,
+ state,
+ extra;
+
+ Token = {
+ BooleanLiteral: 1,
+ EOF: 2,
+ Identifier: 3,
+ Keyword: 4,
+ NullLiteral: 5,
+ NumericLiteral: 6,
+ Punctuator: 7,
+ StringLiteral: 8,
+ RegularExpression: 9
+ };
+
+ TokenName = {};
+ TokenName[Token.BooleanLiteral] = 'Boolean';
+ TokenName[Token.EOF] = '<end>';
+ TokenName[Token.Identifier] = 'Identifier';
+ TokenName[Token.Keyword] = 'Keyword';
+ TokenName[Token.NullLiteral] = 'Null';
+ TokenName[Token.NumericLiteral] = 'Numeric';
+ TokenName[Token.Punctuator] = 'Punctuator';
+ TokenName[Token.StringLiteral] = 'String';
+ TokenName[Token.RegularExpression] = 'RegularExpression';
+
+ // A function following one of those tokens is an expression.
+ FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
+ 'return', 'case', 'delete', 'throw', 'void',
+ // assignment operators
+ '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
+ '&=', '|=', '^=', ',',
+ // binary/unary operators
+ '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
+ '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
+ '<=', '<', '>', '!=', '!=='];
+
+ Syntax = {
+ AssignmentExpression: 'AssignmentExpression',
+ ArrayExpression: 'ArrayExpression',
+ BlockStatement: 'BlockStatement',
+ BinaryExpression: 'BinaryExpression',
+ BreakStatement: 'BreakStatement',
+ CallExpression: 'CallExpression',
+ CatchClause: 'CatchClause',
+ ConditionalExpression: 'ConditionalExpression',
+ ContinueStatement: 'ContinueStatement',
+ DoWhileStatement: 'DoWhileStatement',
+ DebuggerStatement: 'DebuggerStatement',
+ EmptyStatement: 'EmptyStatement',
+ ExpressionStatement: 'ExpressionStatement',
+ ForStatement: 'ForStatement',
+ ForInStatement: 'ForInStatement',
+ FunctionDeclaration: 'FunctionDeclaration',
+ FunctionExpression: 'FunctionExpression',
+ Identifier: 'Identifier',
+ IfStatement: 'IfStatement',
+ Literal: 'Literal',
+ LabeledStatement: 'LabeledStatement',
+ LogicalExpression: 'LogicalExpression',
+ MemberExpression: 'MemberExpression',
+ NewExpression: 'NewExpression',
+ ObjectExpression: 'ObjectExpression',
+ Program: 'Program',
+ Property: 'Property',
+ ReturnStatement: 'ReturnStatement',
+ SequenceExpression: 'SequenceExpression',
+ SwitchStatement: 'SwitchStatement',
+ SwitchCase: 'SwitchCase',
+ ThisExpression: 'ThisExpression',
+ ThrowStatement: 'ThrowStatement',
+ TryStatement: 'TryStatement',
+ UnaryExpression: 'UnaryExpression',
+ UpdateExpression: 'UpdateExpression',
+ VariableDeclaration: 'VariableDeclaration',
+ VariableDeclarator: 'VariableDeclarator',
+ WhileStatement: 'WhileStatement',
+ WithStatement: 'WithStatement'
+ };
+
+ PropertyKind = {
+ Data: 1,
+ Get: 2,
+ Set: 4
+ };
+
+ // Error messages should be identical to V8.
+ Messages = {
+ UnexpectedToken: 'Unexpected token %0',
+ UnexpectedNumber: 'Unexpected number',
+ UnexpectedString: 'Unexpected string',
+ UnexpectedIdentifier: 'Unexpected identifier',
+ UnexpectedReserved: 'Unexpected reserved word',
+ UnexpectedEOS: 'Unexpected end of input',
+ NewlineAfterThrow: 'Illegal newline after throw',
+ InvalidRegExp: 'Invalid regular expression',
+ UnterminatedRegExp: 'Invalid regular expression: missing /',
+ InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
+ InvalidLHSInForIn: 'Invalid left-hand side in for-in',
+ MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
+ NoCatchOrFinally: 'Missing catch or finally after try',
+ UnknownLabel: 'Undefined label \'%0\'',
+ Redeclaration: '%0 \'%1\' has already been declared',
+ IllegalContinue: 'Illegal continue statement',
+ IllegalBreak: 'Illegal break statement',
+ IllegalReturn: 'Illegal return statement',
+ StrictModeWith: 'Strict mode code may not include a with statement',
+ StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
+ StrictVarName: 'Variable name may not be eval or arguments in strict mode',
+ StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
+ StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
+ StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
+ StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
+ StrictDelete: 'Delete of an unqualified identifier in strict mode.',
+ StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
+ AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
+ AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
+ StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
+ StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+ StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+ StrictReservedWord: 'Use of future reserved word in strict mode'
+ };
+
+ // See also tools/generate-unicode-regex.py.
+ Regex = {
+ NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35
-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u
12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\
u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uF
AD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'),
+ NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A9
3-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-
\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B
0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u300
5-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F
\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]')
+ };
+
+ // Ensure the condition is true, otherwise throw an error.
+ // This is only to have a better contract semantic, i.e. another safety net
+ // to catch a logic error. The condition shall be fulfilled in normal case.
+ // Do NOT use this to enforce a certain condition on any user input.
+
+ function assert(condition, message) {
+ /* istanbul ignore if */
+ if (!condition) {
+ throw new Error('ASSERT: ' + message);
+ }
+ }
+
+ function isDecimalDigit(ch) {
+ return (ch >= 48 && ch <= 57); // 0..9
+ }
+
+ function isHexDigit(ch) {
+ return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
+ }
+
+ function isOctalDigit(ch) {
+ return '01234567'.indexOf(ch) >= 0;
+ }
+
+
+ // 7.2 White Space
+
+ function isWhiteSpace(ch) {
+ return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
+ (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
+ }
+
+ // 7.3 Line Terminators
+
+ function isLineTerminator(ch) {
+ return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
+ }
+
+ // 7.6 Identifier Names and Identifiers
+
+ function isIdentifierStart(ch) {
+ return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
+ (ch >= 0x41 && ch <= 0x5A) || // A..Z
+ (ch >= 0x61 && ch <= 0x7A) || // a..z
+ (ch === 0x5C) || // \ (backslash)
+ ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
+ }
+
+ function isIdentifierPart(ch) {
+ return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
+ (ch >= 0x41 && ch <= 0x5A) || // A..Z
+ (ch >= 0x61 && ch <= 0x7A) || // a..z
+ (ch >= 0x30 && ch <= 0x39) || // 0..9
+ (ch === 0x5C) || // \ (backslash)
+ ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
+ }
+
+ // 7.6.1.2 Future Reserved Words
+
+ function isFutureReservedWord(id) {
+ switch (id) {
+ case 'class':
+ case 'enum':
+ case 'export':
+ case 'extends':
+ case 'import':
+ case 'super':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function isStrictModeReservedWord(id) {
+ switch (id) {
+ case 'implements':
+ case 'interface':
+ case 'package':
+ case 'private':
+ case 'protected':
+ case 'public':
+ case 'static':
+ case 'yield':
+ case 'let':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function isRestrictedWord(id) {
+ return id === 'eval' || id === 'arguments';
+ }
+
+ // 7.6.1.1 Keywords
+
+ function isKeyword(id) {
+ if (strict && isStrictModeReservedWord(id)) {
+ return true;
+ }
+
+ // 'const' is specialized as Keyword in V8.
+ // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
+ // Some others are from future reserved words.
+
+ switch (id.length) {
+ case 2:
+ return (id === 'if') || (id === 'in') || (id === 'do');
+ case 3:
+ return (id === 'var') || (id === 'for') || (id === 'new') ||
+ (id === 'try') || (id === 'let');
+ case 4:
+ return (id === 'this') || (id === 'else') || (id === 'case') ||
+ (id === 'void') || (id === 'with') || (id === 'enum');
+ case 5:
+ return (id === 'while') || (id === 'break') || (id === 'catch') ||
+ (id === 'throw') || (id === 'const') || (id === 'yield') ||
+ (id === 'class') || (id === 'super');
+ case 6:
+ return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
+ (id === 'switch') || (id === 'export') || (id === 'import');
+ case 7:
+ return (id === 'default') || (id === 'finally') || (id === 'extends');
+ case 8:
+ return (id === 'function') || (id === 'continue') || (id === 'debugger');
+ case 10:
+ return (id === 'instanceof');
+ default:
+ return false;
+ }
+ }
+
+ // 7.4 Comments
+
+ function addComment(type, value, start, end, loc) {
+ var comment, attacher;
+
+ assert(typeof start === 'number', 'Comment must have valid position');
+
+ // Because the way the actual token is scanned, often the comments
+ // (if any) are skipped twice during the lexical analysis.
+ // Thus, we need to skip adding a comment if the comment array already
+ // handled it.
+ if (state.lastCommentStart >= start) {
+ return;
+ }
+ state.lastCommentStart = start;
+
+ comment = {
+ type: type,
+ value: value
+ };
+ if (extra.range) {
+ comment.range = [start, end];
+ }
+ if (extra.loc) {
+ comment.loc = loc;
+ }
+ extra.comments.push(comment);
+ if (extra.attachComment) {
+ extra.leadingComments.push(comment);
+ extra.trailingComments.push(comment);
+ }
+ }
+
+ function skipSingleLineComment(offset) {
+ var start, loc, ch, comment;
+
+ start = index - offset;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart - offset
+ }
+ };
+
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ ++index;
+ if (isLineTerminator(ch)) {
+ if (extra.comments) {
+ comment = source.slice(start + offset, index - 1);
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart - 1
+ };
+ addComment('Line', comment, start, index - 1, loc);
+ }
+ if (ch === 13 && source.charCodeAt(index) === 10) {
+ ++index;
+ }
+ ++lineNumber;
+ lineStart = index;
+ return;
+ }
+ }
+
+ if (extra.comments) {
+ comment = source.slice(start + offset, index);
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+ addComment('Line', comment, start, index, loc);
+ }
+ }
+
+ function skipMultiLineComment() {
+ var start, loc, ch, comment;
+
+ if (extra.comments) {
+ start = index - 2;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart - 2
+ }
+ };
+ }
+
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (isLineTerminator(ch)) {
+ if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
+ ++index;
+ }
+ ++lineNumber;
+ ++index;
+ lineStart = index;
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ } else if (ch === 0x2A) {
+ // Block comment ends with '*/'.
+ if (source.charCodeAt(index + 1) === 0x2F) {
+ ++index;
+ ++index;
+ if (extra.comments) {
+ comment = source.slice(start + 2, index - 2);
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+ addComment('Block', comment, start, index, loc);
+ }
+ return;
+ }
+ ++index;
+ } else {
+ ++index;
+ }
+ }
+
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ function skipComment() {
+ var ch, start;
+
+ start = (index === 0);
+ while (index < length) {
+ ch = source.charCodeAt(index);
+
+ if (isWhiteSpace(ch)) {
+ ++index;
+ } else if (isLineTerminator(ch)) {
+ ++index;
+ if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
+ ++index;
+ }
+ ++lineNumber;
+ lineStart = index;
+ start = true;
+ } else if (ch === 0x2F) { // U+002F is '/'
+ ch = source.charCodeAt(index + 1);
+ if (ch === 0x2F) {
+ ++index;
+ ++index;
+ skipSingleLineComment(2);
+ start = true;
+ } else if (ch === 0x2A) { // U+002A is '*'
+ ++index;
+ ++index;
+ skipMultiLineComment();
+ } else {
+ break;
+ }
+ } else if (start && ch === 0x2D) { // U+002D is '-'
+ // U+003E is '>'
+ if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
+ // '-->' is a single-line comment
+ index += 3;
+ skipSingleLineComment(3);
+ } else {
+ break;
+ }
+ } else if (ch === 0x3C) { // U+003C is '<'
+ if (source.slice(index + 1, index + 4) === '!--') {
+ ++index; // `<`
+ ++index; // `!`
+ ++index; // `-`
+ ++index; // `-`
+ skipSingleLineComment(4);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ function scanHexEscape(prefix) {
+ var i, len, ch, code = 0;
+
+ len = (prefix === 'u') ? 4 : 2;
+ for (i = 0; i < len; ++i) {
+ if (index < length && isHexDigit(source[index])) {
+ ch = source[index++];
+ code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+ } else {
+ return '';
+ }
+ }
+ return String.fromCharCode(code);
+ }
+
+ function getEscapedIdentifier() {
+ var ch, id;
+
+ ch = source.charCodeAt(index++);
+ id = String.fromCharCode(ch);
+
+ // '\u' (U+005C, U+0075) denotes an escaped character.
+ if (ch === 0x5C) {
+ if (source.charCodeAt(index) !== 0x75) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ ++index;
+ ch = scanHexEscape('u');
+ if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ id = ch;
+ }
+
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (!isIdentifierPart(ch)) {
+ break;
+ }
+ ++index;
+ id += String.fromCharCode(ch);
+
+ // '\u' (U+005C, U+0075) denotes an escaped character.
+ if (ch === 0x5C) {
+ id = id.substr(0, id.length - 1);
+ if (source.charCodeAt(index) !== 0x75) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ ++index;
+ ch = scanHexEscape('u');
+ if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ id += ch;
+ }
+ }
+
+ return id;
+ }
+
+ function getIdentifier() {
+ var start, ch;
+
+ start = index++;
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (ch === 0x5C) {
+ // Blackslash (U+005C) marks Unicode escape sequence.
+ index = start;
+ return getEscapedIdentifier();
+ }
+ if (isIdentifierPart(ch)) {
+ ++index;
+ } else {
+ break;
+ }
+ }
+
+ return source.slice(start, index);
+ }
+
+ function scanIdentifier() {
+ var start, id, type;
+
+ start = index;
+
+ // Backslash (U+005C) starts an escaped character.
+ id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
+
+ // There is no keyword or literal with only one character.
+ // Thus, it must be an identifier.
+ if (id.length === 1) {
+ type = Token.Identifier;
+ } else if (isKeyword(id)) {
+ type = Token.Keyword;
+ } else if (id === 'null') {
+ type = Token.NullLiteral;
+ } else if (id === 'true' || id === 'false') {
+ type = Token.BooleanLiteral;
+ } else {
+ type = Token.Identifier;
+ }
+
+ return {
+ type: type,
+ value: id,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+
+ // 7.7 Punctuators
+
+ function scanPunctuator() {
+ var start = index,
+ code = source.charCodeAt(index),
+ code2,
+ ch1 = source[index],
+ ch2,
+ ch3,
+ ch4;
+
+ switch (code) {
+
+ // Check for most common single-character punctuators.
+ case 0x2E: // . dot
+ case 0x28: // ( open bracket
+ case 0x29: // ) close bracket
+ case 0x3B: // ; semicolon
+ case 0x2C: // , comma
+ case 0x7B: // { open curly brace
+ case 0x7D: // } close curly brace
+ case 0x5B: // [
+ case 0x5D: // ]
+ case 0x3A: // :
+ case 0x3F: // ?
+ case 0x7E: // ~
+ ++index;
+ if (extra.tokenize) {
+ if (code === 0x28) {
+ extra.openParenToken = extra.tokens.length;
+ } else if (code === 0x7B) {
+ extra.openCurlyToken = extra.tokens.length;
+ }
+ }
+ return {
+ type: Token.Punctuator,
+ value: String.fromCharCode(code),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+
+ default:
+ code2 = source.charCodeAt(index + 1);
+
+ // '=' (U+003D) marks an assignment or comparison operator.
+ if (code2 === 0x3D) {
+ switch (code) {
+ case 0x2B: // +
+ case 0x2D: // -
+ case 0x2F: // /
+ case 0x3C: // <
+ case 0x3E: // >
+ case 0x5E: // ^
+ case 0x7C: // |
+ case 0x25: // %
+ case 0x26: // &
+ case 0x2A: // *
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: String.fromCharCode(code) + String.fromCharCode(code2),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+
+ case 0x21: // !
+ case 0x3D: // =
+ index += 2;
+
+ // !== and ===
+ if (source.charCodeAt(index) === 0x3D) {
+ ++index;
+ }
+ return {
+ type: Token.Punctuator,
+ value: source.slice(start, index),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+ }
+ }
+
+ // 4-character punctuator: >>>=
+
+ ch4 = source.substr(index, 4);
+
+ if (ch4 === '>>>=') {
+ index += 4;
+ return {
+ type: Token.Punctuator,
+ value: ch4,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ // 3-character punctuators: === !== >>> <<= >>=
+
+ ch3 = ch4.substr(0, 3);
+
+ if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: ch3,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ // Other 2-character punctuators: ++ -- << >> && ||
+ ch2 = ch3.substr(0, 2);
+
+ if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') {
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: ch2,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ // 1-character punctuators: < > = ! + - * % & | ^ /
+ if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
+ ++index;
+ return {
+ type: Token.Punctuator,
+ value: ch1,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ // 7.8.3 Numeric Literals
+
+ function scanHexLiteral(start) {
+ var number = '';
+
+ while (index < length) {
+ if (!isHexDigit(source[index])) {
+ break;
+ }
+ number += source[index++];
+ }
+
+ if (number.length === 0) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ if (isIdentifierStart(source.charCodeAt(index))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt('0x' + number, 16),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ function scanOctalLiteral(start) {
+ var number = '0' + source[index++];
+ while (index < length) {
+ if (!isOctalDigit(source[index])) {
+ break;
+ }
+ number += source[index++];
+ }
+
+ if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt(number, 8),
+ octal: true,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ function scanNumericLiteral() {
+ var number, start, ch;
+
+ ch = source[index];
+ assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
+ 'Numeric literal must start with a decimal digit or a decimal point');
+
+ start = index;
+ number = '';
+ if (ch !== '.') {
+ number = source[index++];
+ ch = source[index];
+
+ // Hex number starts with '0x'.
+ // Octal number starts with '0'.
+ if (number === '0') {
+ if (ch === 'x' || ch === 'X') {
+ ++index;
+ return scanHexLiteral(start);
+ }
+ if (isOctalDigit(ch)) {
+ return scanOctalLiteral(start);
+ }
+
+ // decimal number starts with '0' such as '09' is illegal.
+ if (ch && isDecimalDigit(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+
+ while (isDecimalDigit(source.charCodeAt(index))) {
+ number += source[index++];
+ }
+ ch = source[index];
+ }
+
+ if (ch === '.') {
+ number += source[index++];
+ while (isDecimalDigit(source.charCodeAt(index))) {
+ number += source[index++];
+ }
+ ch = source[index];
+ }
+
+ if (ch === 'e' || ch === 'E') {
+ number += source[index++];
+
+ ch = source[index];
+ if (ch === '+' || ch === '-') {
+ number += source[index++];
+ }
+ if (isDecimalDigit(source.charCodeAt(index))) {
+ while (isDecimalDigit(source.charCodeAt(index))) {
+ number += source[index++];
+ }
+ } else {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+
+ if (isIdentifierStart(source.charCodeAt(index))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseFloat(number),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ // 7.8.4 String Literals
+
+ function scanStringLiteral() {
+ var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart;
+ startLineNumber = lineNumber;
+ startLineStart = lineStart;
+
+ quote = source[index];
+ assert((quote === '\'' || quote === '"'),
+ 'String literal must starts with a quote');
+
+ start = index;
+ ++index;
+
+ while (index < length) {
+ ch = source[index++];
+
+ if (ch === quote) {
+ quote = '';
+ break;
+ } else if (ch === '\\') {
+ ch = source[index++];
+ if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
+ switch (ch) {
+ case 'u':
+ case 'x':
+ restore = index;
+ unescaped = scanHexEscape(ch);
+ if (unescaped) {
+ str += unescaped;
+ } else {
+ index = restore;
+ str += ch;
+ }
+ break;
+ case 'n':
+ str += '\n';
+ break;
+ case 'r':
+ str += '\r';
+ break;
+ case 't':
+ str += '\t';
+ break;
+ case 'b':
+ str += '\b';
+ break;
+ case 'f':
+ str += '\f';
+ break;
+ case 'v':
+ str += '\x0B';
+ break;
+
+ default:
+ if (isOctalDigit(ch)) {
+ code = '01234567'.indexOf(ch);
+
+ // \0 is not octal escape sequence
+ if (code !== 0) {
+ octal = true;
+ }
+
+ if (index < length && isOctalDigit(source[index])) {
+ octal = true;
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+
+ // 3 digits are only allowed when string starts
+ // with 0, 1, 2, 3
+ if ('0123'.indexOf(ch) >= 0 &&
+ index < length &&
+ isOctalDigit(source[index])) {
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+ }
+ }
+ str += String.fromCharCode(code);
+ } else {
+ str += ch;
+ }
+ break;
+ }
+ } else {
+ ++lineNumber;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ lineStart = index;
+ }
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ break;
+ } else {
+ str += ch;
+ }
+ }
+
+ if (quote !== '') {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.StringLiteral,
+ value: str,
+ octal: octal,
+ startLineNumber: startLineNumber,
+ startLineStart: startLineStart,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ function testRegExp(pattern, flags) {
+ var value;
+ try {
+ value = new RegExp(pattern, flags);
+ } catch (e) {
+ throwError({}, Messages.InvalidRegExp);
+ }
+ return value;
+ }
+
+ function scanRegExpBody() {
+ var ch, str, classMarker, terminated, body;
+
+ ch = source[index];
+ assert(ch === '/', 'Regular expression literal must start with a slash');
+ str = source[index++];
+
+ classMarker = false;
+ terminated = false;
+ while (index < length) {
+ ch = source[index++];
+ str += ch;
+ if (ch === '\\') {
+ ch = source[index++];
+ // ECMA-262 7.8.5
+ if (isLineTerminator(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnterminatedRegExp);
+ }
+ str += ch;
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnterminatedRegExp);
+ } else if (classMarker) {
+ if (ch === ']') {
+ classMarker = false;
+ }
+ } else {
+ if (ch === '/') {
+ terminated = true;
+ break;
+ } else if (ch === '[') {
+ classMarker = true;
+ }
+ }
+ }
+
+ if (!terminated) {
+ throwError({}, Messages.UnterminatedRegExp);
+ }
+
+ // Exclude leading and trailing slash.
+ body = str.substr(1, str.length - 2);
+ return {
+ value: body,
+ literal: str
+ };
+ }
+
+ function scanRegExpFlags() {
+ var ch, str, flags, restore;
+
+ str = '';
+ flags = '';
+ while (index < length) {
+ ch = source[index];
+ if (!isIdentifierPart(ch.charCodeAt(0))) {
+ break;
+ }
+
+ ++index;
+ if (ch === '\\' && index < length) {
+ ch = source[index];
+ if (ch === 'u') {
+ ++index;
+ restore = index;
+ ch = scanHexEscape('u');
+ if (ch) {
+ flags += ch;
+ for (str += '\\u'; restore < index; ++restore) {
+ str += source[restore];
+ }
+ } else {
+ index = restore;
+ flags += 'u';
+ str += '\\u';
+ }
+ throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
+ } else {
+ str += '\\';
+ throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ } else {
+ flags += ch;
+ str += ch;
+ }
+ }
+
+ return {
+ value: flags,
+ literal: str
+ };
+ }
+
+ function scanRegExp() {
+ var start, body, flags, pattern, value;
+
+ lookahead = null;
+ skipComment();
+ start = index;
+
+ body = scanRegExpBody();
+ flags = scanRegExpFlags();
+ value = testRegExp(body.value, flags.value);
+
+ if (extra.tokenize) {
+ return {
+ type: Token.RegularExpression,
+ value: value,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: start,
+ end: index
+ };
+ }
+
+ return {
+ literal: body.literal + flags.literal,
+ value: value,
+ start: start,
+ end: index
+ };
+ }
+
+ function collectRegex() {
+ var pos, loc, regex, token;
+
+ skipComment();
+
+ pos = index;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+
+ regex = scanRegExp();
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+
+ /* istanbul ignore next */
+ if (!extra.tokenize) {
+ // Pop the previous token, which is likely '/' or '/='
+ if (extra.tokens.length > 0) {
+ token = extra.tokens[extra.tokens.length - 1];
+ if (token.range[0] === pos && token.type === 'Punctuator') {
+ if (token.value === '/' || token.value === '/=') {
+ extra.tokens.pop();
+ }
+ }
+ }
+
+ extra.tokens.push({
+ type: 'RegularExpression',
+ value: regex.literal,
+ range: [pos, index],
+ loc: loc
+ });
+ }
+
+ return regex;
+ }
+
+ function isIdentifierName(token) {
+ return token.type === Token.Identifier ||
+ token.type === Token.Keyword ||
+ token.type === Token.BooleanLiteral ||
+ token.type === Token.NullLiteral;
+ }
+
+ function advanceSlash() {
+ var prevToken,
+ checkToken;
+ // Using the following algorithm:
+ // https://github.com/mozilla/sweet.js/wiki/design
+ prevToken = extra.tokens[extra.tokens.length - 1];
+ if (!prevToken) {
+ // Nothing before that: it cannot be a division.
+ return collectRegex();
+ }
+ if (prevToken.type === 'Punctuator') {
+ if (prevToken.value === ']') {
+ return scanPunctuator();
+ }
+ if (prevToken.value === ')') {
+ checkToken = extra.tokens[extra.openParenToken - 1];
+ if (checkToken &&
+ checkToken.type === 'Keyword' &&
+ (checkToken.value === 'if' ||
+ checkToken.value === 'while' ||
+ checkToken.value === 'for' ||
+ checkToken.value === 'with')) {
+ return collectRegex();
+ }
+ return scanPunctuator();
+ }
+ if (prevToken.value === '}') {
+ // Dividing a function by anything makes little sense,
+ // but we have to check for that.
+ if (extra.tokens[extra.openCurlyToken - 3] &&
+ extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
+ // Anonymous function.
+ checkToken = extra.tokens[extra.openCurlyToken - 4];
+ if (!checkToken) {
+ return scanPunctuator();
+ }
+ } else if (extra.tokens[extra.openCurlyToken - 4] &&
+ extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
+ // Named function.
+ checkToken = extra.tokens[extra.openCurlyToken - 5];
+ if (!checkToken) {
+ return collectRegex();
+ }
+ } else {
+ return scanPunctuator();
+ }
+ // checkToken determines whether the function is
+ // a declaration or an expression.
+ if (FnExprTokens.indexOf(checkToken.value) >= 0) {
+ // It is an expression.
+ return scanPunctuator();
+ }
+ // It is a declaration.
+ return collectRegex();
+ }
+ return collectRegex();
+ }
+ if (prevToken.type === 'Keyword') {
+ return collectRegex();
+ }
+ return scanPunctuator();
+ }
+
+ function advance() {
+ var ch;
+
+ skipComment();
+
+ if (index >= length) {
+ return {
+ type: Token.EOF,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ start: index,
+ end: index
+ };
+ }
+
+ ch = source.charCodeAt(index);
+
+ if (isIdentifierStart(ch)) {
+ return scanIdentifier();
+ }
+
+ // Very common: ( and ) and ;
+ if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
+ return scanPunctuator();
+ }
+
+ // String literal starts with single quote (U+0027) or double quote (U+0022).
+ if (ch === 0x27 || ch === 0x22) {
+ return scanStringLiteral();
+ }
+
+
+ // Dot (.) U+002E can also start a floating-point number, hence the need
+ // to check the next character.
+ if (ch === 0x2E) {
+ if (isDecimalDigit(source.charCodeAt(index + 1))) {
+ return scanNumericLiteral();
+ }
+ return scanPunctuator();
+ }
+
+ if (isDecimalDigit(ch)) {
+ return scanNumericLiteral();
+ }
+
+ // Slash (/) U+002F can also start a regex.
+ if (extra.tokenize && ch === 0x2F) {
+ return advanceSlash();
+ }
+
+ return scanPunctuator();
+ }
+
+ function collectToken() {
+ var loc, token, range, value;
+
+ skipComment();
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+
+ token = advance();
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+
+ if (token.type !== Token.EOF) {
+ value = source.slice(token.start, token.end);
+ extra.tokens.push({
+ type: TokenName[token.type],
+ value: value,
+ range: [token.start, token.end],
+ loc: loc
+ });
+ }
+
+ return token;
+ }
+
+ function lex() {
+ var token;
+
+ token = lookahead;
+ index = token.end;
+ lineNumber = token.lineNumber;
+ lineStart = token.lineStart;
+
+ lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
+
+ index = token.end;
+ lineNumber = token.lineNumber;
+ lineStart = token.lineStart;
+
+ return token;
+ }
+
+ function peek() {
+ var pos, line, start;
+
+ pos = index;
+ line = lineNumber;
+ start = lineStart;
+ lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
+ index = pos;
+ lineNumber = line;
+ lineStart = start;
+ }
+
+ function Position(line, column) {
+ this.line = line;
+ this.column = column;
+ }
+
+ function SourceLocation(startLine, startColumn, line, column) {
+ this.start = new Position(startLine, startColumn);
+ this.end = new Position(line, column);
+ }
+
+ SyntaxTreeDelegate = {
+
+ name: 'SyntaxTree',
+
+ processComment: function (node) {
+ var lastChild, trailingComments;
+
+ if (node.type === Syntax.Program) {
+ if (node.body.length > 0) {
+ return;
+ }
+ }
+
+ if (extra.trailingComments.length > 0) {
+ if (extra.trailingComments[0].range[0] >= node.range[1]) {
+ trailingComments = extra.trailingComments;
+ extra.trailingComments = [];
+ } else {
+ extra.trailingComments.length = 0;
+ }
+ } else {
+ if (extra.bottomRightStack.length > 0 &&
+ extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments &&
+ extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) {
+ trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
+ delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
+ }
+ }
+
+ // Eating the stack.
+ while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) {
+ lastChild = extra.bottomRightStack.pop();
+ }
+
+ if (lastChild) {
+ if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) {
+ node.leadingComments = lastChild.leadingComments;
+ delete lastChild.leadingComments;
+ }
+ } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) {
+ node.leadingComments = extra.leadingComments;
+ extra.leadingComments = [];
+ }
+
+
+ if (trailingComments) {
+ node.trailingComments = trailingComments;
+ }
+
+ extra.bottomRightStack.push(node);
+ },
+
+ markEnd: function (node, startToken) {
+ if (extra.range) {
+ node.range = [startToken.start, index];
+ }
+ if (extra.loc) {
+ node.loc = new SourceLocation(
+ startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber,
+ startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart),
+ lineNumber,
+ index - lineStart
+ );
+ this.postProcess(node);
+ }
+
+ if (extra.attachComment) {
+ this.processComment(node);
+ }
+ return node;
+ },
+
+ postProcess: function (node) {
+ if (extra.source) {
+ node.loc.source = extra.source;
+ }
+ return node;
+ },
+
+ createArrayExpression: function (elements) {
+ return {
+ type: Syntax.ArrayExpression,
+ elements: elements
+ };
+ },
+
+ createAssignmentExpression: function (operator, left, right) {
+ return {
+ type: Syntax.AssignmentExpression,
+ operator: operator,
+ left: left,
+ right: right
+ };
+ },
+
+ createBinaryExpression: function (operator, left, right) {
+ var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
+ Syntax.BinaryExpression;
+ return {
+ type: type,
+ operator: operator,
+ left: left,
+ right: right
+ };
+ },
+
+ createBlockStatement: function (body) {
+ return {
+ type: Syntax.BlockStatement,
+ body: body
+ };
+ },
+
+ createBreakStatement: function (label) {
+ return {
+ type: Syntax.BreakStatement,
+ label: label
+ };
+ },
+
+ createCallExpression: function (callee, args) {
+ return {
+ type: Syntax.CallExpression,
+ callee: callee,
+ 'arguments': args
+ };
+ },
+
+ createCatchClause: function (param, body) {
+ return {
+ type: Syntax.CatchClause,
+ param: param,
+ body: body
+ };
+ },
+
+ createConditionalExpression: function (test, consequent, alternate) {
+ return {
+ type: Syntax.ConditionalExpression,
+ test: test,
+ consequent: consequent,
+ alternate: alternate
+ };
+ },
+
+ createContinueStatement: function (label) {
+ return {
+ type: Syntax.ContinueStatement,
+ label: label
+ };
+ },
+
+ createDebuggerStatement: function () {
+ return {
+ type: Syntax.DebuggerStatement
+ };
+ },
+
+ createDoWhileStatement: function (body, test) {
+ return {
+ type: Syntax.DoWhileStatement,
+ body: body,
+ test: test
+ };
+ },
+
+ createEmptyStatement: function () {
+ return {
+ type: Syntax.EmptyStatement
+ };
+ },
+
+ createExpressionStatement: function (expression) {
+ return {
+ type: Syntax.ExpressionStatement,
+ expression: expression
+ };
+ },
+
+ createForStatement: function (init, test, update, body) {
+ return {
+ type: Syntax.ForStatement,
+ init: init,
+ test: test,
+ update: update,
+ body: body
+ };
+ },
+
+ createForInStatement: function (left, right, body) {
+ return {
+ type: Syntax.ForInStatement,
+ left: left,
+ right: right,
+ body: body,
+ each: false
+ };
+ },
+
+ createFunctionDeclaration: function (id, params, defaults, body) {
+ return {
+ type: Syntax.FunctionDeclaration,
+ id: id,
+ params: params,
+ defaults: defaults,
+ body: body,
+ rest: null,
+ generator: false,
+ expression: false
+ };
+ },
+
+ createFunctionExpression: function (id, params, defaults, body) {
+ return {
+ type: Syntax.FunctionExpression,
+ id: id,
+ params: params,
+ defaults: defaults,
+ body: body,
+ rest: null,
+ generator: false,
+ expression: false
+ };
+ },
+
+ createIdentifier: function (name) {
+ return {
+ type: Syntax.Identifier,
+ name: name
+ };
+ },
+
+ createIfStatement: function (test, consequent, alternate) {
+ return {
+ type: Syntax.IfStatement,
+ test: test,
+ consequent: consequent,
+ alternate: alternate
+ };
+ },
+
+ createLabeledStatement: function (label, body) {
+ return {
+ type: Syntax.LabeledStatement,
+ label: label,
+ body: body
+ };
+ },
+
+ createLiteral: function (token) {
+ return {
+ type: Syntax.Literal,
+ value: token.value,
+ raw: source.slice(token.start, token.end)
+ };
+ },
+
+ createMemberExpression: function (accessor, object, property) {
+ return {
+ type: Syntax.MemberExpression,
+ computed: accessor === '[',
+ object: object,
+ property: property
+ };
+ },
+
+ createNewExpression: function (callee, args) {
+ return {
+ type: Syntax.NewExpression,
+ callee: callee,
+ 'arguments': args
+ };
+ },
+
+ createObjectExpression: function (properties) {
+ return {
+ type: Syntax.ObjectExpression,
+ properties: properties
+ };
+ },
+
+ createPostfixExpression: function (operator, argument) {
+ return {
+ type: Syntax.UpdateExpression,
+ operator: operator,
+ argument: argument,
+ prefix: false
+ };
+ },
+
+ createProgram: function (body) {
+ return {
+ type: Syntax.Program,
+ body: body
+ };
+ },
+
+ createProperty: function (kind, key, value) {
+ return {
+ type: Syntax.Property,
+ key: key,
+ value: value,
+ kind: kind
+ };
+ },
+
+ createReturnStatement: function (argument) {
+ return {
+ type: Syntax.ReturnStatement,
+ argument: argument
+ };
+ },
+
+ createSequenceExpression: function (expressions) {
+ return {
+ type: Syntax.SequenceExpression,
+ expressions: expressions
+ };
+ },
+
+ createSwitchCase: function (test, consequent) {
+ return {
+ type: Syntax.SwitchCase,
+ test: test,
+ consequent: consequent
+ };
+ },
+
+ createSwitchStatement: function (discriminant, cases) {
+ return {
+ type: Syntax.SwitchStatement,
+ discriminant: discriminant,
+ cases: cases
+ };
+ },
+
+ createThisExpression: function () {
+ return {
+ type: Syntax.ThisExpression
+ };
+ },
+
+ createThrowStatement: function (argument) {
+ return {
+ type: Syntax.ThrowStatement,
+ argument: argument
+ };
+ },
+
+ createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
+ return {
+ type: Syntax.TryStatement,
+ block: block,
+ guardedHandlers: guardedHandlers,
+ handlers: handlers,
+ finalizer: finalizer
+ };
+ },
+
+ createUnaryExpression: function (operator, argument) {
+ if (operator === '++' || operator === '--') {
+ return {
+ type: Syntax.UpdateExpression,
+ operator: operator,
+ argument: argument,
+ prefix: true
+ };
+ }
+ return {
+ type: Syntax.UnaryExpression,
+ operator: operator,
+ argument: argument,
+ prefix: true
+ };
+ },
+
+ createVariableDeclaration: function (declarations, kind) {
+ return {
+ type: Syntax.VariableDeclaration,
+ declarations: declarations,
+ kind: kind
+ };
+ },
+
+ createVariableDeclarator: function (id, init) {
+ return {
+ type: Syntax.VariableDeclarator,
+ id: id,
+ init: init
+ };
+ },
+
+ createWhileStatement: function (test, body) {
+ return {
+ type: Syntax.WhileStatement,
+ test: test,
+ body: body
+ };
+ },
+
+ createWithStatement: function (object, body) {
+ return {
+ type: Syntax.WithStatement,
+ object: object,
+ body: body
+ };
+ }
+ };
+
+ // Return true if there is a line terminator before the next token.
+
+ function peekLineTerminator() {
+ var pos, line, start, found;
+
+ pos = index;
+ line = lineNumber;
+ start = lineStart;
+ skipComment();
+ found = lineNumber !== line;
+ index = pos;
+ lineNumber = line;
+ lineStart = start;
+
+ return found;
+ }
+
+ // Throw an exception
+
+ function throwError(token, messageFormat) {
+ var error,
+ args = Array.prototype.slice.call(arguments, 2),
+ msg = messageFormat.replace(
+ /%(\d)/g,
+ function (whole, index) {
+ assert(index < args.length, 'Message reference must be in range');
+ return args[index];
+ }
+ );
+
+ if (typeof token.lineNumber === 'number') {
+ error = new Error('Line ' + token.lineNumber + ': ' + msg);
+ error.index = token.start;
+ error.lineNumber = token.lineNumber;
+ error.column = token.start - lineStart + 1;
+ } else {
+ error = new Error('Line ' + lineNumber + ': ' + msg);
+ error.index = index;
+ error.lineNumber = lineNumber;
+ error.column = index - lineStart + 1;
+ }
+
+ error.description = msg;
+ throw error;
+ }
+
+ function throwErrorTolerant() {
+ try {
+ throwError.apply(null, arguments);
+ } catch (e) {
+ if (extra.errors) {
+ extra.errors.push(e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+
+ // Throw an exception because of the token.
+
+ function throwUnexpected(token) {
+ if (token.type === Token.EOF) {
+ throwError(token, Messages.UnexpectedEOS);
+ }
+
+ if (token.type === Token.NumericLiteral) {
+ throwError(token, Messages.UnexpectedNumber);
+ }
+
+ if (token.type === Token.StringLiteral) {
+ throwError(token, Messages.UnexpectedString);
+ }
+
+ if (token.type === Token.Identifier) {
+ throwError(token, Messages.UnexpectedIdentifier);
+ }
+
+ if (token.type === Token.Keyword) {
+ if (isFutureReservedWord(token.value)) {
+ throwError(token, Messages.UnexpectedReserved);
+ } else if (strict && isStrictModeReservedWord(token.value)) {
+ throwErrorTolerant(token, Messages.StrictReservedWord);
+ return;
+ }
+ throwError(token, Messages.UnexpectedToken, token.value);
+ }
+
+ // BooleanLiteral, NullLiteral, or Punctuator.
+ throwError(token, Messages.UnexpectedToken, token.value);
+ }
+
+ // Expect the next token to match the specified punctuator.
+ // If not, an exception will be thrown.
+
+ function expect(value) {
+ var token = lex();
+ if (token.type !== Token.Punctuator || token.value !== value) {
+ throwUnexpected(token);
+ }
+ }
+
+ // Expect the next token to match the specified keyword.
+ // If not, an exception will be thrown.
+
+ function expectKeyword(keyword) {
+ var token = lex();
+ if (token.type !== Token.Keyword || token.value !== keyword) {
+ throwUnexpected(token);
+ }
+ }
+
+ // Return true if the next token matches the specified punctuator.
+
+ function match(value) {
+ return lookahead.type === Token.Punctuator && lookahead.value === value;
+ }
+
+ // Return true if the next token matches the specified keyword
+
+ function matchKeyword(keyword) {
+ return lookahead.type === Token.Keyword && lookahead.value === keyword;
+ }
+
+ // Return true if the next token is an assignment operator
+
+ function matchAssign() {
+ var op;
+
+ if (lookahead.type !== Token.Punctuator) {
+ return false;
+ }
+ op = lookahead.value;
+ return op === '=' ||
+ op === '*=' ||
+ op === '/=' ||
+ op === '%=' ||
+ op === '+=' ||
+ op === '-=' ||
+ op === '<<=' ||
+ op === '>>=' ||
+ op === '>>>=' ||
+ op === '&=' ||
+ op === '^=' ||
+ op === '|=';
+ }
+
+ function consumeSemicolon() {
+ var line;
+
+ // Catch the very common case first: immediately a semicolon (U+003B).
+ if (source.charCodeAt(index) === 0x3B || match(';')) {
+ lex();
+ return;
+ }
+
+ line = lineNumber;
+ skipComment();
+ if (lineNumber !== line) {
+ return;
+ }
+
+ if (lookahead.type !== Token.EOF && !match('}')) {
+ throwUnexpected(lookahead);
+ }
+ }
+
+ // Return true if provided expression is LeftHandSideExpression
+
+ function isLeftHandSide(expr) {
+ return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
+ }
+
+ // 11.1.4 Array Initialiser
+
+ function parseArrayInitialiser() {
+ var elements = [], startToken;
+
+ startToken = lookahead;
+ expect('[');
+
+ while (!match(']')) {
+ if (match(',')) {
+ lex();
+ elements.push(null);
+ } else {
+ elements.push(parseAssignmentExpression());
+
+ if (!match(']')) {
+ expect(',');
+ }
+ }
+ }
+
+ lex();
+
+ return delegate.markEnd(delegate.createArrayExpression(elements), startToken);
+ }
+
+ // 11.1.5 Object Initialiser
+
+ function parsePropertyFunction(param, first) {
+ var previousStrict, body, startToken;
+
+ previousStrict = strict;
+ startToken = lookahead;
+ body = parseFunctionSourceElements();
+ if (first && strict && isRestrictedWord(param[0].name)) {
+ throwErrorTolerant(first, Messages.StrictParamName);
+ }
+ strict = previousStrict;
+ return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken);
+ }
+
+ function parseObjectPropertyKey() {
+ var token, startToken;
+
+ startToken = lookahead;
+ token = lex();
+
+ // Note: This function is called only from parseObjectProperty(), where
+ // EOF and Punctuator tokens are already filtered out.
+
+ if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
+ if (strict && token.octal) {
+ throwErrorTolerant(token, Messages.StrictOctalLiteral);
+ }
+ return delegate.markEnd(delegate.createLiteral(token), startToken);
+ }
+
+ return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
+ }
+
+ function parseObjectProperty() {
+ var token, key, id, value, param, startToken;
+
+ token = lookahead;
+ startToken = lookahead;
+
+ if (token.type === Token.Identifier) {
+
+ id = parseObjectPropertyKey();
+
+ // Property Assignment: Getter and Setter.
+
+ if (token.value === 'get' && !match(':')) {
+ key = parseObjectPropertyKey();
+ expect('(');
+ expect(')');
+ value = parsePropertyFunction([]);
+ return delegate.markEnd(delegate.createProperty('get', key, value), startToken);
+ }
+ if (token.value === 'set' && !match(':')) {
+ key = parseObjectPropertyKey();
+ expect('(');
+ token = lookahead;
+ if (token.type !== Token.Identifier) {
+ expect(')');
+ throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
+ value = parsePropertyFunction([]);
+ } else {
+ param = [ parseVariableIdentifier() ];
+ expect(')');
+ value = parsePropertyFunction(param, token);
+ }
+ return delegate.markEnd(delegate.createProperty('set', key, value), startToken);
+ }
+ expect(':');
+ value = parseAssignmentExpression();
+ return delegate.markEnd(delegate.createProperty('init', id, value), startToken);
+ }
+ if (token.type === Token.EOF || token.type === Token.Punctuator) {
+ throwUnexpected(token);
+ } else {
+ key = parseObjectPropertyKey();
+ expect(':');
+ value = parseAssignmentExpression();
+ return delegate.markEnd(delegate.createProperty('init', key, value), startToken);
+ }
+ }
+
+ function parseObjectInitialiser() {
+ var properties = [], property, name, key, kind, map = {}, toString = String, startToken;
+
+ startToken = lookahead;
+
+ expect('{');
+
+ while (!match('}')) {
+ property = parseObjectProperty();
+
+ if (property.key.type === Syntax.Identifier) {
+ name = property.key.name;
+ } else {
+ name = toString(property.key.value);
+ }
+ kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
+
+ key = '$' + name;
+ if (Object.prototype.hasOwnProperty.call(map, key)) {
+ if (map[key] === PropertyKind.Data) {
+ if (strict && kind === PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.StrictDuplicateProperty);
+ } else if (kind !== PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.AccessorDataProperty);
+ }
+ } else {
+ if (kind === PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.AccessorDataProperty);
+ } else if (map[key] & kind) {
+ throwErrorTolerant({}, Messages.AccessorGetSet);
+ }
+ }
+ map[key] |= kind;
+ } else {
+ map[key] = kind;
+ }
+
+ properties.push(property);
+
+ if (!match('}')) {
+ expect(',');
+ }
+ }
+
+ expect('}');
+
+ return delegate.markEnd(delegate.createObjectExpression(properties), startToken);
+ }
+
+ // 11.1.6 The Grouping Operator
+
+ function parseGroupExpression() {
+ var expr;
+
+ expect('(');
+
+ expr = parseExpression();
+
+ expect(')');
+
+ return expr;
+ }
+
+
+ // 11.1 Primary Expressions
+
+ function parsePrimaryExpression() {
+ var type, token, expr, startToken;
+
+ if (match('(')) {
+ return parseGroupExpression();
+ }
+
+ if (match('[')) {
+ return parseArrayInitialiser();
+ }
+
+ if (match('{')) {
+ return parseObjectInitialiser();
+ }
+
+ type = lookahead.type;
+ startToken = lookahead;
+
+ if (type === Token.Identifier) {
+ expr = delegate.createIdentifier(lex().value);
+ } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+ if (strict && lookahead.octal) {
+ throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
+ }
+ expr = delegate.createLiteral(lex());
+ } else if (type === Token.Keyword) {
+ if (matchKeyword('function')) {
+ return parseFunctionExpression();
+ }
+ if (matchKeyword('this')) {
+ lex();
+ expr = delegate.createThisExpression();
+ } else {
+ throwUnexpected(lex());
+ }
+ } else if (type === Token.BooleanLiteral) {
+ token = lex();
+ token.value = (token.value === 'true');
+ expr = delegate.createLiteral(token);
+ } else if (type === Token.NullLiteral) {
+ token = lex();
+ token.value = null;
+ expr = delegate.createLiteral(token);
+ } else if (match('/') || match('/=')) {
+ if (typeof extra.tokens !== 'undefined') {
+ expr = delegate.createLiteral(collectRegex());
+ } else {
+ expr = delegate.createLiteral(scanRegExp());
+ }
+ peek();
+ } else {
+ throwUnexpected(lex());
+ }
+
+ return delegate.markEnd(expr, startToken);
+ }
+
+ // 11.2 Left-Hand-Side Expressions
+
+ function parseArguments() {
+ var args = [];
+
+ expect('(');
+
+ if (!match(')')) {
+ while (index < length) {
+ args.push(parseAssignmentExpression());
+ if (match(')')) {
+ break;
+ }
+ expect(',');
+ }
+ }
+
+ expect(')');
+
+ return args;
+ }
+
+ function parseNonComputedProperty() {
+ var token, startToken;
+
+ startToken = lookahead;
+ token = lex();
+
+ if (!isIdentifierName(token)) {
+ throwUnexpected(token);
+ }
+
+ return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
+ }
+
+ function parseNonComputedMember() {
+ expect('.');
+
+ return parseNonComputedProperty();
+ }
+
+ function parseComputedMember() {
+ var expr;
+
+ expect('[');
+
+ expr = parseExpression();
+
+ expect(']');
+
+ return expr;
+ }
+
+ function parseNewExpression() {
+ var callee, args, startToken;
+
+ startToken = lookahead;
+ expectKeyword('new');
+ callee = parseLeftHandSideExpression();
+ args = match('(') ? parseArguments() : [];
+
+ return delegate.markEnd(delegate.createNewExpression(callee, args), startToken);
+ }
+
+ function parseLeftHandSideExpressionAllowCall() {
+ var previousAllowIn, expr, args, property, startToken;
+
+ startToken = lookahead;
+
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
+ state.allowIn = previousAllowIn;
+
+ for (;;) {
+ if (match('.')) {
+ property = parseNonComputedMember();
+ expr = delegate.createMemberExpression('.', expr, property);
+ } else if (match('(')) {
+ args = parseArguments();
+ expr = delegate.createCallExpression(expr, args);
+ } else if (match('[')) {
+ property = parseComputedMember();
+ expr = delegate.createMemberExpression('[', expr, property);
+ } else {
+ break;
+ }
+ delegate.markEnd(expr, startToken);
+ }
+
+ return expr;
+ }
+
+ function parseLeftHandSideExpression() {
+ var previousAllowIn, expr, property, startToken;
+
+ startToken = lookahead;
+
+ previousAllowIn = state.allowIn;
+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
+ state.allowIn = previousAllowIn;
+
+ while (match('.') || match('[')) {
+ if (match('[')) {
+ property = parseComputedMember();
+ expr = delegate.createMemberExpression('[', expr, property);
+ } else {
+ property = parseNonComputedMember();
+ expr = delegate.createMemberExpression('.', expr, property);
+ }
+ delegate.markEnd(expr, startToken);
+ }
+
+ return expr;
+ }
+
+ // 11.3 Postfix Expressions
+
+ function parsePostfixExpression() {
+ var expr, token, startToken = lookahead;
+
+ expr = parseLeftHandSideExpressionAllowCall();
+
+ if (lookahead.type === Token.Punctuator) {
+ if ((match('++') || match('--')) && !peekLineTerminator()) {
+ // 11.3.1, 11.3.2
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ throwErrorTolerant({}, Messages.StrictLHSPostfix);
+ }
+
+ if (!isLeftHandSide(expr)) {
+ throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
+ }
+
+ token = lex();
+ expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken);
+ }
+ }
+
+ return expr;
+ }
+
+ // 11.4 Unary Operators
+
+ function parseUnaryExpression() {
+ var token, expr, startToken;
+
+ if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
+ expr = parsePostfixExpression();
+ } else if (match('++') || match('--')) {
+ startToken = lookahead;
+ token = lex();
+ expr = parseUnaryExpression();
+ // 11.4.4, 11.4.5
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ throwErrorTolerant({}, Messages.StrictLHSPrefix);
+ }
+
+ if (!isLeftHandSide(expr)) {
+ throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
+ }
+
+ expr = delegate.createUnaryExpression(token.value, expr);
+ expr = delegate.markEnd(expr, startToken);
+ } else if (match('+') || match('-') || match('~') || match('!')) {
+ startToken = lookahead;
+ token = lex();
+ expr = parseUnaryExpression();
+ expr = delegate.createUnaryExpression(token.value, expr);
+ expr = delegate.markEnd(expr, startToken);
+ } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
+ startToken = lookahead;
+ token = lex();
+ expr = parseUnaryExpression();
+ expr = delegate.createUnaryExpression(token.value, expr);
+ expr = delegate.markEnd(expr, startToken);
+ if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
+ throwErrorTolerant({}, Messages.StrictDelete);
+ }
+ } else {
+ expr = parsePostfixExpression();
+ }
+
+ return expr;
+ }
+
+ function binaryPrecedence(token, allowIn) {
+ var prec = 0;
+
+ if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
+ return 0;
+ }
+
+ switch (token.value) {
+ case '||':
+ prec = 1;
+ break;
+
+ case '&&':
+ prec = 2;
+ break;
+
+ case '|':
+ prec = 3;
+ break;
+
+ case '^':
+ prec = 4;
+ break;
+
+ case '&':
+ prec = 5;
+ break;
+
+ case '==':
+ case '!=':
+ case '===':
+ case '!==':
+ prec = 6;
+ break;
+
+ case '<':
+ case '>':
+ case '<=':
+ case '>=':
+ case 'instanceof':
+ prec = 7;
+ break;
+
+ case 'in':
+ prec = allowIn ? 7 : 0;
+ break;
+
+ case '<<':
+ case '>>':
+ case '>>>':
+ prec = 8;
+ break;
+
+ case '+':
+ case '-':
+ prec = 9;
+ break;
+
+ case '*':
+ case '/':
+ case '%':
+ prec = 11;
+ break;
+
+ default:
+ break;
+ }
+
+ return prec;
+ }
+
+ // 11.5 Multiplicative Operators
+ // 11.6 Additive Operators
+ // 11.7 Bitwise Shift Operators
+ // 11.8 Relational Operators
+ // 11.9 Equality Operators
+ // 11.10 Binary Bitwise Operators
+ // 11.11 Binary Logical Operators
+
+ function parseBinaryExpression() {
+ var marker, markers, expr, token, prec, stack, right, operator, left, i;
+
+ marker = lookahead;
+ left = parseUnaryExpression();
+
+ token = lookahead;
+ prec = binaryPrecedence(token, state.allowIn);
+ if (prec === 0) {
+ return left;
+ }
+ token.prec = prec;
+ lex();
+
+ markers = [marker, lookahead];
+ right = parseUnaryExpression();
+
+ stack = [left, token, right];
+
+ while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
+
+ // Reduce: make a binary expression from the three topmost entries.
+ while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
+ right = stack.pop();
+ operator = stack.pop().value;
+ left = stack.pop();
+ expr = delegate.createBinaryExpression(operator, left, right);
+ markers.pop();
+ marker = markers[markers.length - 1];
+ delegate.markEnd(expr, marker);
+ stack.push(expr);
+ }
+
+ // Shift.
+ token = lex();
+ token.prec = prec;
+ stack.push(token);
+ markers.push(lookahead);
+ expr = parseUnaryExpression();
+ stack.push(expr);
+ }
+
+ // Final reduce to clean-up the stack.
+ i = stack.length - 1;
+ expr = stack[i];
+ markers.pop();
+ while (i > 1) {
+ expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
+ i -= 2;
+ marker = markers.pop();
+ delegate.markEnd(expr, marker);
+ }
+
+ return expr;
+ }
+
+
+ // 11.12 Conditional Operator
+
+ function parseConditionalExpression() {
+ var expr, previousAllowIn, consequent, alternate, startToken;
+
+ startToken = lookahead;
+
+ expr = parseBinaryExpression();
+
+ if (match('?')) {
+ lex();
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
+ consequent = parseAssignmentExpression();
+ state.allowIn = previousAllowIn;
+ expect(':');
+ alternate = parseAssignmentExpression();
+
+ expr = delegate.createConditionalExpression(expr, consequent, alternate);
+ delegate.markEnd(expr, startToken);
+ }
+
+ return expr;
+ }
+
+ // 11.13 Assignment Operators
+
+ function parseAssignmentExpression() {
+ var token, left, right, node, startToken;
+
+ token = lookahead;
+ startToken = lookahead;
+
+ node = left = parseConditionalExpression();
+
+ if (matchAssign()) {
+ // LeftHandSideExpression
+ if (!isLeftHandSide(left)) {
+ throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
+ }
+
+ // 11.13.1
+ if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) {
+ throwErrorTolerant(token, Messages.StrictLHSAssignment);
+ }
+
+ token = lex();
+ right = parseAssignmentExpression();
+ node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken);
+ }
+
+ return node;
+ }
+
+ // 11.14 Comma Operator
+
+ function parseExpression() {
+ var expr, startToken = lookahead;
+
+ expr = parseAssignmentExpression();
+
+ if (match(',')) {
+ expr = delegate.createSequenceExpression([ expr ]);
+
+ while (index < length) {
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ expr.expressions.push(parseAssignmentExpression());
+ }
+
+ delegate.markEnd(expr, startToken);
+ }
+
+ return expr;
+ }
+
+ // 12.1 Block
+
+ function parseStatementList() {
+ var list = [],
+ statement;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ statement = parseSourceElement();
+ if (typeof statement === 'undefined') {
+ break;
+ }
+ list.push(statement);
+ }
+
+ return list;
+ }
+
+ function parseBlock() {
+ var block, startToken;
+
+ startToken = lookahead;
+ expect('{');
+
+ block = parseStatementList();
+
+ expect('}');
+
+ return delegate.markEnd(delegate.createBlockStatement(block), startToken);
+ }
+
+ // 12.2 Variable Statement
+
+ function parseVariableIdentifier() {
+ var token, startToken;
+
+ startToken = lookahead;
+ token = lex();
+
+ if (token.type !== Token.Identifier) {
+ throwUnexpected(token);
+ }
+
+ return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
+ }
+
+ function parseVariableDeclaration(kind) {
+ var init = null, id, startToken;
+
+ startToken = lookahead;
+ id = parseVariableIdentifier();
+
+ // 12.2.1
+ if (strict && isRestrictedWord(id.name)) {
+ throwErrorTolerant({}, Messages.StrictVarName);
+ }
+
+ if (kind === 'const') {
+ expect('=');
+ init = parseAssignmentExpression();
+ } else if (match('=')) {
+ lex();
+ init = parseAssignmentExpression();
+ }
+
+ return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken);
+ }
+
+ function parseVariableDeclarationList(kind) {
+ var list = [];
+
+ do {
+ list.push(parseVariableDeclaration(kind));
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ } while (index < length);
+
+ return list;
+ }
+
+ function parseVariableStatement() {
+ var declarations;
+
+ expectKeyword('var');
+
+ declarations = parseVariableDeclarationList();
+
+ consumeSemicolon();
+
+ return delegate.createVariableDeclaration(declarations, 'var');
+ }
+
+ // kind may be `const` or `let`
+ // Both are experimental and not in the specification yet.
+ // see http://wiki.ecmascript.org/doku.php?id=harmony:const
+ // and http://wiki.ecmascript.org/doku.php?id=harmony:let
+ function parseConstLetDeclaration(kind) {
+ var declarations, startToken;
+
+ startToken = lookahead;
+
+ expectKeyword(kind);
+
+ declarations = parseVariableDeclarationList(kind);
+
+ consumeSemicolon();
+
+ return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken);
+ }
+
+ // 12.3 Empty Statement
+
+ function parseEmptyStatement() {
+ expect(';');
+ return delegate.createEmptyStatement();
+ }
+
+ // 12.4 Expression Statement
+
+ function parseExpressionStatement() {
+ var expr = parseExpression();
+ consumeSemicolon();
+ return delegate.createExpressionStatement(expr);
+ }
+
+ // 12.5 If statement
+
+ function parseIfStatement() {
+ var test, consequent, alternate;
+
+ expectKeyword('if');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ consequent = parseStatement();
+
+ if (matchKeyword('else')) {
+ lex();
+ alternate = parseStatement();
+ } else {
+ alternate = null;
+ }
+
+ return delegate.createIfStatement(test, consequent, alternate);
+ }
+
+ // 12.6 Iteration Statements
+
+ function parseDoWhileStatement() {
+ var body, test, oldInIteration;
+
+ expectKeyword('do');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ expectKeyword('while');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ if (match(';')) {
+ lex();
+ }
+
+ return delegate.createDoWhileStatement(body, test);
+ }
+
+ function parseWhileStatement() {
+ var test, body, oldInIteration;
+
+ expectKeyword('while');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ return delegate.createWhileStatement(test, body);
+ }
+
+ function parseForVariableDeclaration() {
+ var token, declarations, startToken;
+
+ startToken = lookahead;
+ token = lex();
+ declarations = parseVariableDeclarationList();
+
+ return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken);
+ }
+
+ function parseForStatement() {
+ var init, test, update, left, right, body, oldInIteration;
+
+ init = test = update = null;
+
+ expectKeyword('for');
+
+ expect('(');
+
+ if (match(';')) {
+ lex();
+ } else {
+ if (matchKeyword('var') || matchKeyword('let')) {
+ state.allowIn = false;
+ init = parseForVariableDeclaration();
+ state.allowIn = true;
+
+ if (init.declarations.length === 1 && matchKeyword('in')) {
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ }
+ } else {
+ state.allowIn = false;
+ init = parseExpression();
+ state.allowIn = true;
+
+ if (matchKeyword('in')) {
+ // LeftHandSideExpression
+ if (!isLeftHandSide(init)) {
+ throwErrorTolerant({}, Messages.InvalidLHSInForIn);
+ }
+
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ }
+ }
+
+ if (typeof left === 'undefined') {
+ expect(';');
+ }
+ }
+
+ if (typeof left === 'undefined') {
+
+ if (!match(';')) {
+ test = parseExpression();
+ }
+ expect(';');
+
+ if (!match(')')) {
+ update = parseExpression();
+ }
+ }
+
+ expect(')');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ return (typeof left === 'undefined') ?
+ delegate.createForStatement(init, test, update, body) :
+ delegate.createForInStatement(left, right, body);
+ }
+
+ // 12.7 The continue statement
+
+ function parseContinueStatement() {
+ var label = null, key;
+
+ expectKeyword('continue');
+
+ // Optimize the most common form: 'continue;'.
+ if (source.charCodeAt(index) === 0x3B) {
+ lex();
+
+ if (!state.inIteration) {
+ throwError({}, Messages.IllegalContinue);
+ }
+
+ return delegate.createContinueStatement(null);
+ }
+
+ if (peekLineTerminator()) {
+ if (!state.inIteration) {
+ throwError({}, Messages.IllegalContinue);
+ }
+
+ return delegate.createContinueStatement(null);
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ label = parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError({}, Messages.UnknownLabel, label.name);
+ }
+ }
+
+ consumeSemicolon();
+
+ if (label === null && !state.inIteration) {
+ throwError({}, Messages.IllegalContinue);
+ }
+
+ return delegate.createContinueStatement(label);
+ }
+
+ // 12.8 The break statement
+
+ function parseBreakStatement() {
+ var label = null, key;
+
+ expectKeyword('break');
+
+ // Catch the very common case first: immediately a semicolon (U+003B).
+ if (source.charCodeAt(index) === 0x3B) {
+ lex();
+
+ if (!(state.inIteration || state.inSwitch)) {
+ throwError({}, Messages.IllegalBreak);
+ }
+
+ return delegate.createBreakStatement(null);
+ }
+
+ if (peekLineTerminator()) {
+ if (!(state.inIteration || state.inSwitch)) {
+ throwError({}, Messages.IllegalBreak);
+ }
+
+ return delegate.createBreakStatement(null);
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ label = parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError({}, Messages.UnknownLabel, label.name);
+ }
+ }
+
+ consumeSemicolon();
+
+ if (label === null && !(state.inIteration || state.inSwitch)) {
+ throwError({}, Messages.IllegalBreak);
+ }
+
+ return delegate.createBreakStatement(label);
+ }
+
+ // 12.9 The return statement
+
+ function parseReturnStatement() {
+ var argument = null;
+
+ expectKeyword('return');
+
+ if (!state.inFunctionBody) {
+ throwErrorTolerant({}, Messages.IllegalReturn);
+ }
+
+ // 'return' followed by a space and an identifier is very common.
+ if (source.charCodeAt(index) === 0x20) {
+ if (isIdentifierStart(source.charCodeAt(index + 1))) {
+ argument = parseExpression();
+ consumeSemicolon();
+ return delegate.createReturnStatement(argument);
+ }
+ }
+
+ if (peekLineTerminator()) {
+ return delegate.createReturnStatement(null);
+ }
+
+ if (!match(';')) {
+ if (!match('}') && lookahead.type !== Token.EOF) {
+ argument = parseExpression();
+ }
+ }
+
+ consumeSemicolon();
+
+ return delegate.createReturnStatement(argument);
+ }
+
+ // 12.10 The with statement
+
+ function parseWithStatement() {
+ var object, body;
+
+ if (strict) {
+ // TODO(ikarienator): Should we update the test cases instead?
+ skipComment();
+ throwErrorTolerant({}, Messages.StrictModeWith);
+ }
+
+ expectKeyword('with');
+
+ expect('(');
+
+ object = parseExpression();
+
+ expect(')');
+
+ body = parseStatement();
+
+ return delegate.createWithStatement(object, body);
+ }
+
+ // 12.10 The swith statement
+
+ function parseSwitchCase() {
+ var test, consequent = [], statement, startToken;
+
+ startToken = lookahead;
+ if (matchKeyword('default')) {
+ lex();
+ test = null;
+ } else {
+ expectKeyword('case');
+ test = parseExpression();
+ }
+ expect(':');
+
+ while (index < length) {
+ if (match('}') || matchKeyword('default') || matchKeyword('case')) {
+ break;
+ }
+ statement = parseStatement();
+ consequent.push(statement);
+ }
+
+ return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken);
+ }
+
+ function parseSwitchStatement() {
+ var discriminant, cases, clause, oldInSwitch, defaultFound;
+
+ expectKeyword('switch');
+
+ expect('(');
+
+ discriminant = parseExpression();
+
+ expect(')');
+
+ expect('{');
+
+ cases = [];
+
+ if (match('}')) {
+ lex();
+ return delegate.createSwitchStatement(discriminant, cases);
+ }
+
+ oldInSwitch = state.inSwitch;
+ state.inSwitch = true;
+ defaultFound = false;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ clause = parseSwitchCase();
+ if (clause.test === null) {
+ if (defaultFound) {
+ throwError({}, Messages.MultipleDefaultsInSwitch);
+ }
+ defaultFound = true;
+ }
+ cases.push(clause);
+ }
+
+ state.inSwitch = oldInSwitch;
+
+ expect('}');
+
+ return delegate.createSwitchStatement(discriminant, cases);
+ }
+
+ // 12.13 The throw statement
+
+ function parseThrowStatement() {
+ var argument;
+
+ expectKeyword('throw');
+
+ if (peekLineTerminator()) {
+ throwError({}, Messages.NewlineAfterThrow);
+ }
+
+ argument = parseExpression();
+
+ consumeSemicolon();
+
+ return delegate.createThrowStatement(argument);
+ }
+
+ // 12.14 The try statement
+
+ function parseCatchClause() {
+ var param, body, startToken;
+
+ startToken = lookahead;
+ expectKeyword('catch');
+
+ expect('(');
+ if (match(')')) {
+ throwUnexpected(lookahead);
+ }
+
+ param = parseVariableIdentifier();
+ // 12.14.1
+ if (strict && isRestrictedWord(param.name)) {
+ throwErrorTolerant({}, Messages.StrictCatchVariable);
+ }
+
+ expect(')');
+ body = parseBlock();
+ return delegate.markEnd(delegate.createCatchClause(param, body), startToken);
+ }
+
+ function parseTryStatement() {
+ var block, handlers = [], finalizer = null;
+
+ expectKeyword('try');
+
+ block = parseBlock();
+
+ if (matchKeyword('catch')) {
+ handlers.push(parseCatchClause());
+ }
+
+ if (matchKeyword('finally')) {
+ lex();
+ finalizer = parseBlock();
+ }
+
+ if (handlers.length === 0 && !finalizer) {
+ throwError({}, Messages.NoCatchOrFinally);
+ }
+
+ return delegate.createTryStatement(block, [], handlers, finalizer);
+ }
+
+ // 12.15 The debugger statement
+
+ function parseDebuggerStatement() {
+ expectKeyword('debugger');
+
+ consumeSemicolon();
+
+ return delegate.createDebuggerStatement();
+ }
+
+ // 12 Statements
+
+ function parseStatement() {
+ var type = lookahead.type,
+ expr,
+ labeledBody,
+ key,
+ startToken;
+
+ if (type === Token.EOF) {
+ throwUnexpected(lookahead);
+ }
+
+ if (type === Token.Punctuator && lookahead.value === '{') {
+ return parseBlock();
+ }
+
+ startToken = lookahead;
+
+ if (type === Token.Punctuator) {
+ switch (lookahead.value) {
+ case ';':
+ return delegate.markEnd(parseEmptyStatement(), startToken);
+ case '(':
+ return delegate.markEnd(parseExpressionStatement(), startToken);
+ default:
+ break;
+ }
+ }
+
+ if (type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'break':
+ return delegate.markEnd(parseBreakStatement(), startToken);
+ case 'continue':
+ return delegate.markEnd(parseContinueStatement(), startToken);
+ case 'debugger':
+ return delegate.markEnd(parseDebuggerStatement(), startToken);
+ case 'do':
+ return delegate.markEnd(parseDoWhileStatement(), startToken);
+ case 'for':
+ return delegate.markEnd(parseForStatement(), startToken);
+ case 'function':
+ return delegate.markEnd(parseFunctionDeclaration(), startToken);
+ case 'if':
+ return delegate.markEnd(parseIfStatement(), startToken);
+ case 'return':
+ return delegate.markEnd(parseReturnStatement(), startToken);
+ case 'switch':
+ return delegate.markEnd(parseSwitchStatement(), startToken);
+ case 'throw':
+ return delegate.markEnd(parseThrowStatement(), startToken);
+ case 'try':
+ return delegate.markEnd(parseTryStatement(), startToken);
+ case 'var':
+ return delegate.markEnd(parseVariableStatement(), startToken);
+ case 'while':
+ return delegate.markEnd(parseWhileStatement(), startToken);
+ case 'with':
+ return delegate.markEnd(parseWithStatement(), startToken);
+ default:
+ break;
+ }
+ }
+
+ expr = parseExpression();
+
+ // 12.12 Labelled Statements
+ if ((expr.type === Syntax.Identifier) && match(':')) {
+ lex();
+
+ key = '$' + expr.name;
+ if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError({}, Messages.Redeclaration, 'Label', expr.name);
+ }
+
+ state.labelSet[key] = true;
+ labeledBody = parseStatement();
+ delete state.labelSet[key];
+ return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken);
+ }
+
+ consumeSemicolon();
+
+ return delegate.markEnd(delegate.createExpressionStatement(expr), startToken);
+ }
+
+ // 13 Function Definition
+
+ function parseFunctionSourceElements() {
+ var sourceElement, sourceElements = [], token, directive, firstRestricted,
+ oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken;
+
+ startToken = lookahead;
+ expect('{');
+
+ while (index < length) {
+ if (lookahead.type !== Token.StringLiteral) {
+ break;
+ }
+ token = lookahead;
+
+ sourceElement = parseSourceElement();
+ sourceElements.push(sourceElement);
+ if (sourceElement.expression.type !== Syntax.Literal) {
+ // this is not directive
+ break;
+ }
+ directive = source.slice(token.start + 1, token.end - 1);
+ if (directive === 'use strict') {
+ strict = true;
+ if (firstRestricted) {
+ throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
+ }
+ } else {
+ if (!firstRestricted && token.octal) {
+ firstRestricted = token;
+ }
+ }
+ }
+
+ oldLabelSet = state.labelSet;
+ oldInIteration = state.inIteration;
+ oldInSwitch = state.inSwitch;
+ oldInFunctionBody = state.inFunctionBody;
+
+ state.labelSet = {};
+ state.inIteration = false;
+ state.inSwitch = false;
+ state.inFunctionBody = true;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ sourceElement = parseSourceElement();
+ if (typeof sourceElement === 'undefined') {
+ break;
+ }
+ sourceElements.push(sourceElement);
+ }
+
+ expect('}');
+
+ state.labelSet = oldLabelSet;
+ state.inIteration = oldInIteration;
+ state.inSwitch = oldInSwitch;
+ state.inFunctionBody = oldInFunctionBody;
+
+ return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken);
+ }
+
+ function parseParams(firstRestricted) {
+ var param, params = [], token, stricted, paramSet, key, message;
+ expect('(');
+
+ if (!match(')')) {
+ paramSet = {};
+ while (index < length) {
+ token = lookahead;
+ param = parseVariableIdentifier();
+ key = '$' + token.value;
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ stricted = token;
+ message = Messages.StrictParamName;
+ }
+ if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
+ stricted = token;
+ message = Messages.StrictParamDupe;
+ }
+ } else if (!firstRestricted) {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictParamName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
+ firstRestricted = token;
+ message = Messages.StrictParamDupe;
+ }
+ }
+ params.push(param);
+ paramSet[key] = true;
+ if (match(')')) {
+ break;
+ }
+ expect(',');
+ }
+ }
+
+ expect(')');
+
+ return {
+ params: params,
+ stricted: stricted,
+ firstRestricted: firstRestricted,
+ message: message
+ };
+ }
+
+ function parseFunctionDeclaration() {
+ var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken;
+
+ startToken = lookahead;
+
+ expectKeyword('function');
+ token = lookahead;
+ id = parseVariableIdentifier();
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ throwErrorTolerant(token, Messages.StrictFunctionName);
+ }
+ } else {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ }
+ }
+
+ tmp = parseParams(firstRestricted);
+ params = tmp.params;
+ stricted = tmp.stricted;
+ firstRestricted = tmp.firstRestricted;
+ if (tmp.message) {
+ message = tmp.message;
+ }
+
+ previousStrict = strict;
+ body = parseFunctionSourceElements();
+ if (strict && firstRestricted) {
+ throwError(firstRestricted, message);
+ }
+ if (strict && stricted) {
+ throwErrorTolerant(stricted, message);
+ }
+ strict = previousStrict;
+
+ return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken);
+ }
+
+ function parseFunctionExpression() {
+ var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken;
+
+ startToken = lookahead;
+ expectKeyword('function');
+
+ if (!match('(')) {
+ token = lookahead;
+ id = parseVariableIdentifier();
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ throwErrorTolerant(token, Messages.StrictFunctionName);
+ }
+ } else {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ }
+ }
+ }
+
+ tmp = parseParams(firstRestricted);
+ params = tmp.params;
+ stricted = tmp.stricted;
+ firstRestricted = tmp.firstRestricted;
+ if (tmp.message) {
+ message = tmp.message;
+ }
+
+ previousStrict = strict;
+ body = parseFunctionSourceElements();
+ if (strict && firstRestricted) {
+ throwError(firstRestricted, message);
+ }
+ if (strict && stricted) {
+ throwErrorTolerant(stricted, message);
+ }
+ strict = previousStrict;
+
+ return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken);
+ }
+
+ // 14 Program
+
+ function parseSourceElement() {
+ if (lookahead.type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'const':
+ case 'let':
+ return parseConstLetDeclaration(lookahead.value);
+ case 'function':
+ return parseFunctionDeclaration();
+ default:
+ return parseStatement();
+ }
+ }
+
+ if (lookahead.type !== Token.EOF) {
+ return parseStatement();
+ }
+ }
+
+ function parseSourceElements() {
+ var sourceElement, sourceElements = [], token, directive, firstRestricted;
+
+ while (index < length) {
+ token = lookahead;
+ if (token.type !== Token.StringLiteral) {
+ break;
+ }
+
+ sourceElement = parseSourceElement();
+ sourceElements.push(sourceElement);
+ if (sourceElement.expression.type !== Syntax.Literal) {
+ // this is not directive
+ break;
+ }
+ directive = source.slice(token.start + 1, token.end - 1);
+ if (directive === 'use strict') {
+ strict = true;
+ if (firstRestricted) {
+ throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
+ }
+ } else {
+ if (!firstRestricted && token.octal) {
+ firstRestricted = token;
+ }
+ }
+ }
+
+ while (index < length) {
+ sourceElement = parseSourceElement();
+ /* istanbul ignore if */
+ if (typeof sourceElement === 'undefined') {
+ break;
+ }
+ sourceElements.push(sourceElement);
+ }
+ return sourceElements;
+ }
+
+ function parseProgram() {
+ var body, startToken;
+
+ skipComment();
+ peek();
+ startToken = lookahead;
+ strict = false;
+
+ body = parseSourceElements();
+ return delegate.markEnd(delegate.createProgram(body), startToken);
+ }
+
+ function filterTokenLocation() {
+ var i, entry, token, tokens = [];
+
+ for (i = 0; i < extra.tokens.length; ++i) {
+ entry = extra.tokens[i];
+ token = {
+ type: entry.type,
+ value: entry.value
+ };
+ if (extra.range) {
+ token.range = entry.range;
+ }
+ if (extra.loc) {
+ token.loc = entry.loc;
+ }
+ tokens.push(token);
+ }
+
+ extra.tokens = tokens;
+ }
+
+ function tokenize(code, options) {
+ var toString,
+ token,
+ tokens;
+
+ toString = String;
+ if (typeof code !== 'string' && !(code instanceof String)) {
+ code = toString(code);
+ }
+
+ delegate = SyntaxTreeDelegate;
+ source = code;
+ index = 0;
+ lineNumber = (source.length > 0) ? 1 : 0;
+ lineStart = 0;
+ length = source.length;
+ lookahead = null;
+ state = {
+ allowIn: true,
+ labelSet: {},
+ inFunctionBody: false,
+ inIteration: false,
+ inSwitch: false,
+ lastCommentStart: -1
+ };
+
+ extra = {};
+
+ // Options matching.
+ options = options || {};
+
+ // Of course we collect tokens here.
+ options.tokens = true;
+ extra.tokens = [];
+ extra.tokenize = true;
+ // The following two fields are necessary to compute the Regex tokens.
+ extra.openParenToken = -1;
+ extra.openCurlyToken = -1;
+
+ extra.range = (typeof options.range === 'boolean') && options.range;
+ extra.loc = (typeof options.loc === 'boolean') && options.loc;
+
+ if (typeof options.comment === 'boolean' && options.comment) {
+ extra.comments = [];
+ }
+ if (typeof options.tolerant === 'boolean' && options.tolerant) {
+ extra.errors = [];
+ }
+
+ try {
+ peek();
+ if (lookahead.type === Token.EOF) {
+ return extra.tokens;
+ }
+
+ token = lex();
+ while (lookahead.type !== Token.EOF) {
+ try {
+ token = lex();
+ } catch (lexError) {
+ token = lookahead;
+ if (extra.errors) {
+ extra.errors.push(lexError);
+ // We have to break on the first error
+ // to avoid infinite loops.
+ break;
+ } else {
+ throw lexError;
+ }
+ }
+ }
+
+ filterTokenLocation();
+ tokens = extra.tokens;
+ if (typeof extra.comments !== 'undefined') {
+ tokens.comments = extra.comments;
+ }
+ if (typeof extra.errors !== 'undefined') {
+ tokens.errors = extra.errors;
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ extra = {};
+ }
+ return tokens;
+ }
+
+ function parse(code, options) {
+ var program, toString;
+
+ toString = String;
+ if (typeof code !== 'string' && !(code instanceof String)) {
+ code = toString(code);
+ }
+
+ delegate = SyntaxTreeDelegate;
+ source = code;
+ index = 0;
+ lineNumber = (source.length > 0) ? 1 : 0;
+ lineStart = 0;
+ length = source.length;
+ lookahead = null;
+ state = {
+ allowIn: true,
+ labelSet: {},
+ inFunctionBody: false,
+ inIteration: false,
+ inSwitch: false,
+ lastCommentStart: -1
+ };
+
+ extra = {};
+ if (typeof options !== 'undefined') {
+ extra.range = (typeof options.range === 'boolean') && options.range;
+ extra.loc = (typeof options.loc === 'boolean') && options.loc;
+ extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
+
+ if (extra.loc && options.source !== null && options.source !== undefined) {
+ extra.source = toString(options.source);
+ }
+
+ if (typeof options.tokens === 'boolean' && options.tokens) {
+ extra.tokens = [];
+ }
+ if (typeof options.comment === 'boolean' && options.comment) {
+ extra.comments = [];
+ }
+ if (typeof options.tolerant === 'boolean' && options.tolerant) {
+ extra.errors = [];
+ }
+ if (extra.attachComment) {
+ extra.range = true;
+ extra.comments = [];
+ extra.bottomRightStack = [];
+ extra.trailingComments = [];
+ extra.leadingComments = [];
+ }
+ }
+
+ try {
+ program = parseProgram();
+ if (typeof extra.comments !== 'undefined') {
+ program.comments = extra.comments;
+ }
+ if (typeof extra.tokens !== 'undefined') {
+ filterTokenLocation();
+ program.tokens = extra.tokens;
+ }
+ if (typeof extra.errors !== 'undefined') {
+ program.errors = extra.errors;
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ extra = {};
+ }
+
+ return program;
+ }
+
+ // Sync with *.json manifests.
+ exports.version = '1.2.2';
+
+ exports.tokenize = tokenize;
+
+ exports.parse = parse;
+
+ // Deep copy.
+ /* istanbul ignore next */
+ exports.Syntax = (function () {
+ var name, types = {};
+
+ if (typeof Object.create === 'function') {
+ types = Object.create(null);
+ }
+
+ for (name in Syntax) {
+ if (Syntax.hasOwnProperty(name)) {
+ types[name] = Syntax[name];
+ }
+ }
+
+ if (typeof Object.freeze === 'function') {
+ Object.freeze(types);
+ }
+
+ return types;
+ }());
+
+}));
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+},{}],7:[function(require,module,exports){
+/*
+ Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
+ Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*jslint vars:false, bitwise:true*/
+/*jshint indent:4*/
+/*global exports:true, define:true*/
+(function (root, factory) {
+ 'use strict';
+
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+ // and plain browser loading,
+ if (typeof define === 'function' && define.amd) {
+ define(['exports'], factory);
+ } else if (typeof exports !== 'undefined') {
+ factory(exports);
+ } else {
+ factory((root.estraverse = {}));
+ }
+}(this, function (exports) {
+ 'use strict';
+
+ var Syntax,
+ isArray,
+ VisitorOption,
+ VisitorKeys,
+ BREAK,
+ SKIP;
+
+ Syntax = {
+ AssignmentExpression: 'AssignmentExpression',
+ ArrayExpression: 'ArrayExpression',
+ ArrayPattern: 'ArrayPattern',
+ ArrowFunctionExpression: 'ArrowFunctionExpression',
+ BlockStatement: 'BlockStatement',
+ BinaryExpression: 'BinaryExpression',
+ BreakStatement: 'BreakStatement',
+ CallExpression: 'CallExpression',
+ CatchClause: 'CatchClause',
+ ClassBody: 'ClassBody',
+ ClassDeclaration: 'ClassDeclaration',
+ ClassExpression: 'ClassExpression',
+ ConditionalExpression: 'ConditionalExpression',
+ ContinueStatement: 'ContinueStatement',
+ DebuggerStatement: 'DebuggerStatement',
+ DirectiveStatement: 'DirectiveStatement',
+ DoWhileStatement: 'DoWhileStatement',
+ EmptyStatement: 'EmptyStatement',
+ ExpressionStatement: 'ExpressionStatement',
+ ForStatement: 'ForStatement',
+ ForInStatement: 'ForInStatement',
+ FunctionDeclaration: 'FunctionDeclaration',
+ FunctionExpression: 'FunctionExpression',
+ Identifier: 'Identifier',
+ IfStatement: 'IfStatement',
+ Literal: 'Literal',
+ LabeledStatement: 'LabeledStatement',
+ LogicalExpression: 'LogicalExpression',
+ MemberExpression: 'MemberExpression',
+ MethodDefinition: 'MethodDefinition',
+ NewExpression: 'NewExpression',
+ ObjectExpression: 'ObjectExpression',
+ ObjectPattern: 'ObjectPattern',
+ Program: 'Program',
+ Property: 'Property',
+ ReturnStatement: 'ReturnStatement',
+ SequenceExpression: 'SequenceExpression',
+ SwitchStatement: 'SwitchStatement',
+ SwitchCase: 'SwitchCase',
+ ThisExpression: 'ThisExpression',
+ ThrowStatement: 'ThrowStatement',
+ TryStatement: 'TryStatement',
+ UnaryExpression: 'UnaryExpression',
+ UpdateExpression: 'UpdateExpression',
+ VariableDeclaration: 'VariableDeclaration',
+ VariableDeclarator: 'VariableDeclarator',
+ WhileStatement: 'WhileStatement',
+ WithStatement: 'WithStatement',
+ YieldExpression: 'YieldExpression'
+ };
+
+ function ignoreJSHintError() { }
+
+ isArray = Array.isArray;
+ if (!isArray) {
+ isArray = function isArray(array) {
+ return Object.prototype.toString.call(array) === '[object Array]';
+ };
+ }
+
+ function deepCopy(obj) {
+ var ret = {}, key, val;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ val = obj[key];
+ if (typeof val === 'object' && val !== null) {
+ ret[key] = deepCopy(val);
+ } else {
+ ret[key] = val;
+ }
+ }
+ }
+ return ret;
+ }
+
+ function shallowCopy(obj) {
+ var ret = {}, key;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ ret[key] = obj[key];
+ }
+ }
+ return ret;
+ }
+ ignoreJSHintError(shallowCopy);
+
+ // based on LLVM libc++ upper_bound / lower_bound
+ // MIT License
+
+ function upperBound(array, func) {
+ var diff, len, i, current;
+
+ len = array.length;
+ i = 0;
+
+ while (len) {
+ diff = len >>> 1;
+ current = i + diff;
+ if (func(array[current])) {
+ len = diff;
+ } else {
+ i = current + 1;
+ len -= diff + 1;
+ }
+ }
+ return i;
+ }
+
+ function lowerBound(array, func) {
+ var diff, len, i, current;
+
+ len = array.length;
+ i = 0;
+
+ while (len) {
+ diff = len >>> 1;
+ current = i + diff;
+ if (func(array[current])) {
+ i = current + 1;
+ len -= diff + 1;
+ } else {
+ len = diff;
+ }
+ }
+ return i;
+ }
+ ignoreJSHintError(lowerBound);
+
+ VisitorKeys = {
+ AssignmentExpression: ['left', 'right'],
+ ArrayExpression: ['elements'],
+ ArrayPattern: ['elements'],
+ ArrowFunctionExpression: ['params', 'defaults', 'rest', 'body'],
+ BlockStatement: ['body'],
+ BinaryExpression: ['left', 'right'],
+ BreakStatement: ['label'],
+ CallExpression: ['callee', 'arguments'],
+ CatchClause: ['param', 'body'],
+ ClassBody: ['body'],
+ ClassDeclaration: ['id', 'body', 'superClass'],
+ ClassExpression: ['id', 'body', 'superClass'],
+ ConditionalExpression: ['test', 'consequent', 'alternate'],
+ ContinueStatement: ['label'],
+ DebuggerStatement: [],
+ DirectiveStatement: [],
+ DoWhileStatement: ['body', 'test'],
+ EmptyStatement: [],
+ ExpressionStatement: ['expression'],
+ ForStatement: ['init', 'test', 'update', 'body'],
+ ForInStatement: ['left', 'right', 'body'],
+ ForOfStatement: ['left', 'right', 'body'],
+ FunctionDeclaration: ['id', 'params', 'defaults', 'rest', 'body'],
+ FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'],
+ Identifier: [],
+ IfStatement: ['test', 'consequent', 'alternate'],
+ Literal: [],
+ LabeledStatement: ['label', 'body'],
+ LogicalExpression: ['left', 'right'],
+ MemberExpression: ['object', 'property'],
+ MethodDefinition: ['key', 'value'],
+ NewExpression: ['callee', 'arguments'],
+ ObjectExpression: ['properties'],
+ ObjectPattern: ['properties'],
+ Program: ['body'],
+ Property: ['key', 'value'],
+ ReturnStatement: ['argument'],
+ SequenceExpression: ['expressions'],
+ SwitchStatement: ['discriminant', 'cases'],
+ SwitchCase: ['test', 'consequent'],
+ ThisExpression: [],
+ ThrowStatement: ['argument'],
+ TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'],
+ UnaryExpression: ['argument'],
+ UpdateExpression: ['argument'],
+ VariableDeclaration: ['declarations'],
+ VariableDeclarator: ['id', 'init'],
+ WhileStatement: ['test', 'body'],
+ WithStatement: ['object', 'body'],
+ YieldExpression: ['argument']
+ };
+
+ // unique id
+ BREAK = {};
+ SKIP = {};
+
+ VisitorOption = {
+ Break: BREAK,
+ Skip: SKIP
+ };
+
+ function Reference(parent, key) {
+ this.parent = parent;
+ this.key = key;
+ }
+
+ Reference.prototype.replace = function replace(node) {
+ this.parent[this.key] = node;
+ };
+
+ function Element(node, path, wrap, ref) {
+ this.node = node;
+ this.path = path;
+ this.wrap = wrap;
+ this.ref = ref;
+ }
+
+ function Controller() { }
+
+ // API:
+ // return property path array from root to current node
+ Controller.prototype.path = function path() {
+ var i, iz, j, jz, result, element;
+
+ function addToPath(result, path) {
+ if (isArray(path)) {
+ for (j = 0, jz = path.length; j < jz; ++j) {
+ result.push(path[j]);
+ }
+ } else {
+ result.push(path);
+ }
+ }
+
+ // root node
+ if (!this.__current.path) {
+ return null;
+ }
+
+ // first node is sentinel, second node is root element
+ result = [];
+ for (i = 2, iz = this.__leavelist.length; i < iz; ++i) {
+ element = this.__leavelist[i];
+ addToPath(result, element.path);
+ }
+ addToPath(result, this.__current.path);
+ return result;
+ };
+
+ // API:
+ // return array of parent elements
+ Controller.prototype.parents = function parents() {
+ var i, iz, result;
+
+ // first node is sentinel
+ result = [];
+ for (i = 1, iz = this.__leavelist.length; i < iz; ++i) {
+ result.push(this.__leavelist[i].node);
+ }
+
+ return result;
+ };
+
+ // API:
+ // return current node
+ Controller.prototype.current = function current() {
+ return this.__current.node;
+ };
+
+ Controller.prototype.__execute = function __execute(callback, element) {
+ var previous, result;
+
+ result = undefined;
+
+ previous = this.__current;
+ this.__current = element;
+ this.__state = null;
+ if (callback) {
+ result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node);
+ }
+ this.__current = previous;
+
+ return result;
+ };
+
+ // API:
+ // notify control skip / break
+ Controller.prototype.notify = function notify(flag) {
+ this.__state = flag;
+ };
+
+ // API:
+ // skip child nodes of current node
+ Controller.prototype.skip = function () {
+ this.notify(SKIP);
+ };
+
+ // API:
+ // break traversals
+ Controller.prototype['break'] = function () {
+ this.notify(BREAK);
+ };
+
+ Controller.prototype.__initialize = function(root, visitor) {
+ this.visitor = visitor;
+ this.root = root;
+ this.__worklist = [];
+ this.__leavelist = [];
+ this.__current = null;
+ this.__state = null;
+ };
+
+ Controller.prototype.traverse = function traverse(root, visitor) {
+ var worklist,
+ leavelist,
+ element,
+ node,
+ nodeType,
+ ret,
+ key,
+ current,
+ current2,
+ candidates,
+ candidate,
+ sentinel;
+
+ this.__initialize(root, visitor);
+
+ sentinel = {};
+
+ // reference
+ worklist = this.__worklist;
+ leavelist = this.__leavelist;
+
+ // initialize
+ worklist.push(new Element(root, null, null, null));
+ leavelist.push(new Element(null, null, null, null));
+
+ while (worklist.length) {
+ element = worklist.pop();
+
+ if (element === sentinel) {
+ element = leavelist.pop();
+
+ ret = this.__execute(visitor.leave, element);
+
+ if (this.__state === BREAK || ret === BREAK) {
+ return;
+ }
+ continue;
+ }
+
+ if (element.node) {
+
+ ret = this.__execute(visitor.enter, element);
+
+ if (this.__state === BREAK || ret === BREAK) {
+ return;
+ }
+
+ worklist.push(sentinel);
+ leavelist.push(element);
+
+ if (this.__state === SKIP || ret === SKIP) {
+ continue;
+ }
+
+ node = element.node;
+ nodeType = element.wrap || node.type;
+ candidates = VisitorKeys[nodeType];
+
+ current = candidates.length;
+ while ((current -= 1) >= 0) {
+ key = candidates[current];
+ candidate = node[key];
+ if (!candidate) {
+ continue;
+ }
+
+ if (!isArray(candidate)) {
+ worklist.push(new Element(candidate, key, null, null));
+ continue;
+ }
+
+ current2 = candidate.length;
+ while ((current2 -= 1) >= 0) {
+ if (!candidate[current2]) {
+ continue;
+ }
+ if ((nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === candidates[current]) {
+ element = new Element(candidate[current2], [key, current2], 'Property', null);
+ } else {
+ element = new Element(candidate[current2], [key, current2], null, null);
+ }
+ worklist.push(element);
+ }
+ }
+ }
+ }
+ };
+
+ Controller.prototype.replace = function replace(root, visitor) {
+ var worklist,
+ leavelist,
+ node,
+ nodeType,
+ target,
+ element,
+ current,
+ current2,
+ candidates,
+ candidate,
+ sentinel,
+ outer,
+ key;
+
+ this.__initialize(root, visitor);
+
+ sentinel = {};
+
+ // reference
+ worklist = this.__worklist;
+ leavelist = this.__leavelist;
+
+ // initialize
+ outer = {
+ root: root
+ };
+ element = new Element(root, null, null, new Reference(outer, 'root'));
+ worklist.push(element);
+ leavelist.push(element);
+
+ while (worklist.length) {
+ element = worklist.pop();
+
+ if (element === sentinel) {
+ element = leavelist.pop();
+
+ target = this.__execute(visitor.leave, element);
+
+ // node may be replaced with null,
+ // so distinguish between undefined and null in this place
+ if (target !== undefined && target !== BREAK && target !== SKIP) {
+ // replace
+ element.ref.replace(target);
+ }
+
+ if (this.__state === BREAK || target === BREAK) {
+ return outer.root;
+ }
+ continue;
+ }
+
+ target = this.__execute(visitor.enter, element);
+
+ // node may be replaced with null,
+ // so distinguish between undefined and null in this place
+ if (target !== undefined && target !== BREAK && target !== SKIP) {
+ // replace
+ element.ref.replace(target);
+ element.node = target;
+ }
+
+ if (this.__state === BREAK || target === BREAK) {
+ return outer.root;
+ }
+
+ // node may be null
+ node = element.node;
+ if (!node) {
+ continue;
+ }
+
+ worklist.push(sentinel);
+ leavelist.push(element);
+
+ if (this.__state === SKIP || target === SKIP) {
+ continue;
+ }
+
+ nodeType = element.wrap || node.type;
+ candidates = VisitorKeys[nodeType];
+
+ current = candidates.length;
+ while ((current -= 1) >= 0) {
+ key = candidates[current];
+ candidate = node[key];
+ if (!candidate) {
+ continue;
+ }
+
+ if (!isArray(candidate)) {
+ worklist.push(new Element(candidate, key, null, new Reference(node, key)));
+ continue;
+ }
+
+ current2 = candidate.length;
+ while ((current2 -= 1) >= 0) {
+ if (!candidate[current2]) {
+ continue;
+ }
+ if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) {
+ element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2));
+ } else {
+ element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2));
+ }
+ worklist.push(element);
+ }
+ }
+ }
+
+ return outer.root;
+ };
+
+ function traverse(root, visitor) {
+ var controller = new Controller();
+ return controller.traverse(root, visitor);
+ }
+
+ function replace(root, visitor) {
+ var controller = new Controller();
+ return controller.replace(root, visitor);
+ }
+
+ function extendCommentRange(comment, tokens) {
+ var target;
+
+ target = upperBound(tokens, function search(token) {
+ return token.range[0] > comment.range[0];
+ });
+
+ comment.extendedRange = [comment.range[0], comment.range[1]];
+
+ if (target !== tokens.length) {
+ comment.extendedRange[1] = tokens[target].range[0];
+ }
+
+ target -= 1;
+ if (target >= 0) {
+ comment.extendedRange[0] = tokens[target].range[1];
+ }
+
+ return comment;
+ }
+
+ function attachComments(tree, providedComments, tokens) {
+ // At first, we should calculate extended comment ranges.
+ var comments = [], comment, len, i, cursor;
+
+ if (!tree.range) {
+ throw new Error('attachComments needs range information');
+ }
+
+ // tokens array is empty, we attach comments to tree as 'leadingComments'
+ if (!tokens.length) {
+ if (providedComments.length) {
+ for (i = 0, len = providedComments.length; i < len; i += 1) {
+ comment = deepCopy(providedComments[i]);
+ comment.extendedRange = [0, tree.range[0]];
+ comments.push(comment);
+ }
+ tree.leadingComments = comments;
+ }
+ return tree;
+ }
+
+ for (i = 0, len = providedComments.length; i < len; i += 1) {
+ comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
+ }
+
+ // This is based on John Freeman's implementation.
+ cursor = 0;
+ traverse(tree, {
+ enter: function (node) {
+ var comment;
+
+ while (cursor < comments.length) {
+ comment = comments[cursor];
+ if (comment.extendedRange[1] > node.range[0]) {
+ break;
+ }
+
+ if (comment.extendedRange[1] === node.range[0]) {
+ if (!node.leadingComments) {
+ node.leadingComments = [];
+ }
+ node.leadingComments.push(comment);
+ comments.splice(cursor, 1);
+ } else {
+ cursor += 1;
+ }
+ }
+
+ // already out of owned node
+ if (cursor === comments.length) {
+ return VisitorOption.Break;
+ }
+
+ if (comments[cursor].extendedRange[0] > node.range[1]) {
+ return VisitorOption.Skip;
+ }
+ }
+ });
+
+ cursor = 0;
+ traverse(tree, {
+ leave: function (node) {
+ var comment;
+
+ while (cursor < comments.length) {
+ comment = comments[cursor];
+ if (node.range[1] < comment.extendedRange[0]) {
+ break;
+ }
+
+ if (node.range[1] === comment.extendedRange[0]) {
+ if (!node.trailingComments) {
+ node.trailingComments = [];
+ }
+ node.trailingComments.push(comment);
+ comments.splice(cursor, 1);
+ } else {
+ cursor += 1;
+ }
+ }
+
+ // already out of owned node
+ if (cursor === comments.length) {
+ return VisitorOption.Break;
+ }
+
+ if (comments[cursor].extendedRange[0] > node.range[1]) {
+ return VisitorOption.Skip;
+ }
+ }
+ });
+
+ return tree;
+ }
+
+ exports.version = '1.5.1-dev';
+ exports.Syntax = Syntax;
+ exports.traverse = traverse;
+ exports.replace = replace;
+ exports.attachComments = attachComments;
+ exports.VisitorKeys = VisitorKeys;
+ exports.VisitorOption = VisitorOption;
+ exports.Controller = Controller;
+}));
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+},{}],8:[function(require,module,exports){
+'use strict';
+
+function ToObject(val) {
+        if (val == null) {
+                throw new TypeError('Object.assign cannot be called with null or undefined');
+        }
+
+        return Object(val);
+}
+
+module.exports = Object.assign || function (target, source) {
+        var pendingException;
+        var from;
+        var keys;
+        var to = ToObject(target);
+
+        for (var s = 1; s < arguments.length; s++) {
+                from = arguments[s];
+                keys = Object.keys(Object(from));
+
+                for (var i = 0; i < keys.length; i++) {
+                        try {
+                                to[keys[i]] = from[keys[i]];
+                        } catch (err) {
+                                if (pendingException === undefined) {
+                                        pendingException = err;
+                                }
+                        }
+                }
+        }
+
+        if (pendingException) {
+                throw pendingException;
+        }
+
+        return to;
+};
+
+},{}],9:[function(require,module,exports){
+/**
+ * @fileoverview Main ESLint object.
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var esprima = require("esprima"),
+ estraverse = require("estraverse"),
+ escope = require("escope"),
+ environments = require("../conf/environments.json"),
+ assign = require("object-assign"),
+ rules = require("./rules"),
+ util = require("./util"),
+ RuleContext = require("./rule-context"),
+ EventEmitter = require("events").EventEmitter;
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+function escapeRegExp(rx) {
+ return rx.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+}
+
+/**
+ * Parses a list of "name:boolean_value" or/and "name" options divided by comma or
+ * whitespace.
+ * @param {string} string The string to parse.
+ * @returns {Object} Result map object of names and boolean values
+ */
+function parseBooleanConfig(string) {
+ var items = {};
+ // Collapse whitespace around : to make parsing easier
+ string = string.replace(/\s*:\s*/g, ":");
+ // Collapse whitespace around ,
+ string = string.replace(/\s*,\s*/g, ",");
+ string.split(/\s|,+/).forEach(function(name) {
+ if (!name) {
+ return;
+ }
+ var pos = name.indexOf(":"),
+ value;
+ if (pos !== -1) {
+ value = name.substring(pos + 1, name.length);
+ name = name.substring(0, pos);
+ }
+
+ items[name] = (value === "true");
+
+ });
+ return items;
+}
+
+/**
+ * Parses a JSON-like config.
+ * @param {string} string The string to parse.
+ * @returns {Object} Result map object
+ */
+function parseJsonConfig(string) {
+ var items = {};
+ string = string.replace(/([a-z0-9\-\/]+):/g, "\"$1\":").replace(/(\]|[0-9])\s+(?=")/, "$1,");
+ try {
+ items = JSON.parse("{" + string + "}");
+ } catch(e) { }
+
+ return items;
+}
+
+/**
+ * Parses a config of values separated by comma.
+ * @param {string} string The string to parse.
+ * @returns {Object} Result map of values and true values
+ */
+function parseListConfig(string) {
+ var items = {};
+ // Collapse whitespace around ,
+ string = string.replace(/\s*,\s*/g, ",");
+ string.split(/,+/).forEach(function(name) {
+ name = name.trim();
+ if (!name) {
+ return;
+ }
+ items[name] = true;
+ });
+ return items;
+}
+
+/**
+ * @param {Scope} scope The scope object to check.
+ * @param {string} name The name of the variable to look up.
+ * @returns {Variable} The variable object if found or null if not.
+ */
+function getVariable(scope, name) {
+ var variable = null;
+ scope.variables.some(function(v) {
+ if (v.name === name) {
+ variable = v;
+ return true;
+ } else {
+ return false;
+ }
+
+ });
+ return variable;
+}
+
+/**
+ * Ensures that variables representing built-in properties of the Global Object,
+ * and any globals declared by special block comments, are present in the global
+ * scope.
+ * @param {ASTNode} program The top node of the AST.
+ * @param {Scope} globalScope The global scope.
+ * @param {Object} config The existing configuration data.
+ * @returns {void}
+ */
+function addDeclaredGlobals(program, globalScope, config) {
+ var declaredGlobals = {},
+ explicitGlobals = {},
+ builtin = environments.builtin;
+
+ assign(declaredGlobals, builtin);
+
+ Object.keys(config.env).forEach(function (name) {
+ if (config.env[name]) {
+ var environmentGlobals = environments[name] && environments[name].globals;
+ if (environmentGlobals) {
+ assign(declaredGlobals, environmentGlobals);
+ }
+ }
+ });
+
+ assign(declaredGlobals, config.globals);
+ assign(explicitGlobals, config.astGlobals);
+
+ Object.keys(declaredGlobals).forEach(function(name) {
+ var variable = getVariable(globalScope, name);
+ if (!variable) {
+ variable = new escope.Variable(name, globalScope);
+ variable.eslintExplicitGlobal = false;
+ globalScope.variables.push(variable);
+ }
+ variable.writeable = declaredGlobals[name];
+ });
+
+ Object.keys(explicitGlobals).forEach(function(name) {
+ var variable = getVariable(globalScope, name);
+ if (!variable) {
+ variable = new escope.Variable(name, globalScope);
+ variable.eslintExplicitGlobal = true;
+ globalScope.variables.push(variable);
+ }
+ variable.writeable = explicitGlobals[name];
+ });
+}
+
+/**
+ * Add data to reporting configuration to disable reporting for list of rules
+ * starting from start location
+ * @param {Object[]} reportingConfig Current reporting configuration
+ * @param {Object} start Position to start
+ * @param {string[]} rules List of rules
+ * @returns {void}
+ */
+function disableReporting(reportingConfig, start, rules) {
+
+ if (rules.length) {
+ rules.forEach(function(rule) {
+ reportingConfig.push({
+ start: start,
+ end: null,
+ rule: rule
+ });
+ });
+ } else {
+ reportingConfig.push({
+ start: start,
+ end: null,
+ rule: null
+ });
+ }
+}
+
+/**
+ * Add data to reporting configuration to enable reporting for list of rules
+ * starting from start location
+ * @param {Object[]} reportingConfig Current reporting configuration
+ * @param {Object} start Position to start
+ * @param {string[]} rules List of rules
+ * @returns {void}
+ */
+function enableReporting(reportingConfig, start, rules) {
+ var i;
+
+ if (rules.length) {
+ rules.forEach(function(rule) {
+ for (i = reportingConfig.length - 1; i >= 0; i--) {
+ if (!reportingConfig[i].end && reportingConfig[i].rule === rule ) {
+ reportingConfig[i].end = start;
+ break;
+ }
+ }
+ });
+ } else {
+ // find all previous disabled locations if they was started as list of rules
+ var prevStart;
+ for (i = reportingConfig.length - 1; i >= 0; i--) {
+ if (prevStart && prevStart !== reportingConfig[i].start) {
+ break;
+ }
+
+ if (!reportingConfig[i].end) {
+ reportingConfig[i].end = start;
+ prevStart = reportingConfig[i].start;
+ }
+ }
+ }
+}
+
+
+/**
+ * Parses comments in file to extract file-specific config of rules, globals
+ * and environments and merges them with global config; also code blocks
+ * where reporting is disabled or enabled and merges them with reporting config.
+ * @param {ASTNode} ast The top node of the AST.
+ * @param {Object} config The existing configuration data.
+ * @param {Object[]} reportingConfig The existing reporting configuration data.
+ * @returns {void}
+ */
+function modifyConfigsFromComments(ast, config, reportingConfig) {
+
+ var commentConfig = {
+ astGlobals: {},
+ rules: {},
+ env: {}
+ };
+ var commentRules = {};
+
+ ast.comments.forEach(function(comment) {
+ if (comment.type === "Block") {
+
+ var value = comment.value.trim();
+ var match = /^(eslint-\w+|eslint|globals?)(\s|$)/.exec(value);
+
+ if (match) {
+ value = value.substring(match.index + match[1].length);
+
+ switch (match[1]) {
+ case "globals":
+ case "global":
+ util.mixin(commentConfig.astGlobals, parseBooleanConfig(value));
+ break;
+
+ case "eslint-env":
+ util.mixin(commentConfig.env, parseListConfig(value));
+ break;
+
+ case "eslint-disable":
+ disableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value)));
+ break;
+
+ case "eslint-enable":
+ enableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value)));
+ break;
+
+ case "eslint":
+ var items = parseJsonConfig(value);
+ Object.keys(items).forEach(function(name) {
+ var ruleValue = items[name];
+ if (typeof ruleValue === "number" || (Array.isArray(ruleValue) && typeof ruleValue[0] === "number")) {
+ commentRules[name] = ruleValue;
+ }
+ });
+ break;
+
+ // no default
+ }
+ }
+ }
+ });
+
+ // apply environment rules before user rules
+ Object.keys(commentConfig.env).forEach(function (name) {
+ var environmentRules = environments[name] && environments[name].rules;
+ if (commentConfig.env[name] && environmentRules) {
+ util.mixin(commentConfig.rules, environmentRules);
+ }
+ });
+ util.mixin(commentConfig.rules, commentRules);
+
+ util.mergeConfigs(config, commentConfig);
+}
+
+/**
+ * Check if message of rule with ruleId should be ignored in location
+ * @param {Object[]} reportingConfig Collection of ignore records
+ * @param {string} ruleId Id of rule
+ * @param {Object} location Location of message
+ * @returns {boolean} True if message should be ignored, false otherwise
+ */
+function isDisabledByReportingConfig(reportingConfig, ruleId, location) {
+
+ for (var i = 0, c = reportingConfig.length; i < c; i++) {
+
+ var ignore = reportingConfig[i];
+ if ((!ignore.rule || ignore.rule === ruleId) &&
+ (location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) &&
+ (!ignore.end || (location.line < ignore.end.line || (location.line === ignore.end.line && location.column <= ignore.end.column)))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Process initial config to make it safe to extend by file comment config
+ * @param {Object} config Initial config
+ * @returns {Object} Processed config
+ */
+function prepareConfig(config) {
+
+ config.globals = config.globals || config.global || {};
+ delete config.global;
+
+ var copiedRules = {};
+ if (typeof config.rules === "object") {
+ Object.keys(config.rules).forEach(function(k) {
+ var rule = config.rules[k];
+ if (Array.isArray(rule)) {
+ copiedRules[k] = rule.slice();
+ } else {
+ copiedRules[k] = rule;
+ }
+ });
+ }
+
+ return {
+ rules: copiedRules,
+ globals: util.mergeConfigs({}, config.globals),
+ env: util.mergeConfigs({}, config.env || {}),
+ settings: util.mergeConfigs({}, config.settings || {})
+ };
+}
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
+/**
+ * Object that is responsible for verifying JavaScript text
+ * @name eslint
+ */
+module.exports = (function() {
+
+ var api = Object.create(new EventEmitter()),
+ messages = [],
+ currentText = null,
+ currentTextLines = [],
+ currentConfig = null,
+ currentTokens = null,
+ currentScopes = null,
+ scopeMap = null,
+ currentFilename = null,
+ controller = null,
+ reportingConfig = [],
+ commentLocsEnter = [],
+ commentLocsExit = [];
+
+ /**
+ * Parses text into an AST. Moved out here because the try-catch prevents
+ * optimization of functions, so it's best to keep the try-catch as isolated
+ * as possible
+ * @param {string} text The text to parse.
+ * @returns {ASTNode} The AST if successful or null if not.
+ * @private
+ */
+ function parse(text) {
+ /*
+ * Check for parsing errors first. If there's a parsing error, nothing
+ * else can happen. However, a parsing error does not throw an error
+ * from this method - it's just considered a fatal error message, a
+ * problem that ESLint identified just like any other.
+ */
+ try {
+ return esprima.parse(text, {
+ loc: true,
+ range: true,
+ raw: true,
+ tokens: true,
+ comment: true,
+ attachComment: true
+ });
+ } catch (ex) {
+
+ messages.push({
+ fatal: true,
+ severity: 2,
+
+ // messages come as "Line X: Unexpected token foo", so strip off leading part
+ message: ex.message.substring(ex.message.indexOf(":") + 1).trim(),
+
+ line: ex.lineNumber,
+ column: ex.column
+ });
+
+ return null;
+ }
+ }
+
+ /**
+ * Check collection of comments to prevent double event for comment as
+ * leading and trailing, then emit event if passing
+ * @param {ASTNode[]} comments Collection of comment nodes
+ * @param {Object[]} locs List of locations of previous comment nodes
+ * @param {string} eventName Event name postfix
+ * @returns {void}
+ */
+ function emitComments(comments, locs, eventName) {
+
+ if (comments.length) {
+ comments.forEach(function(node) {
+ if (locs.indexOf(node.loc) >= 0) {
+ locs.splice(locs.indexOf(node.loc), 1);
+ } else {
+ locs.push(node.loc);
+ api.emit(node.type + eventName, node);
+ }
+ });
+ }
+ }
+
+ /**
+ * Shortcut to check and emit enter of comment nodes
+ * @param {ASTNode[]} comments Collection of comment nodes
+ * @returns {void}
+ */
+ function emitCommentsEnter(comments) {
+ emitComments(comments, commentLocsEnter, "Comment");
+ }
+
+ /**
+ * Shortcut to check and emit exit of comment nodes
+ * @param {ASTNode[]} comments Collection of comment nodes
+ * @returns {void}
+ */
+ function emitCommentsExit(comments) {
+ emitComments(comments, commentLocsExit, "Comment:exit");
+ }
+
+ /**
+ * Get the severity level of a rule (0 - none, 1 - warning, 2 - error)
+ * Returns 0 if the rule config is not valid (an Array or a number)
+ * @param {Array|number} ruleConfig rule configuration
+ * @returns {number} 0, 1, or 2, indicating rule severity
+ */
+ function getRuleSeverity(ruleConfig) {
+ if (typeof ruleConfig === "number") {
+ return ruleConfig;
+ } else if (Array.isArray(ruleConfig)) {
+ return ruleConfig[0];
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Get the options for a rule (not including severity), if any
+ * @param {Array|number} ruleConfig rule configuration
+ * @returns {Array} of rule options, empty Array if none
+ */
+ function getRuleOptions(ruleConfig) {
+ if (Array.isArray(ruleConfig)) {
+ return ruleConfig.slice(1);
+ } else {
+ return [];
+ }
+ }
+
+ // set unlimited listeners (see https://github.com/eslint/eslint/issues/524)
+ api.setMaxListeners(0);
+
+ /**
+ * Resets the internal state of the object.
+ * @returns {void}
+ */
+ api.reset = function() {
+ this.removeAllListeners();
+ messages = [];
+ currentConfig = null;
+ currentText = null;
+ currentTextLines = [];
+ currentTokens = null;
+ currentScopes = null;
+ scopeMap = null;
+ controller = null;
+ reportingConfig = [];
+ commentLocsEnter = [];
+ commentLocsExit = [];
+ };
+
+ /**
+ * Verifies the text against the rules specified by the second argument.
+ * @param {string} text The JavaScript text to verify.
+ * @param {Object} config An object whose keys specify the rules to use.
+ * @param {string=} filename The optional filename of the file being checked.
+ * If this is not set, the filename will default to '<input>' in the rule context.
+ * @param {boolean=} saveState Indicates if the state from the last run should be saved.
+ * Mostly useful for testing purposes.
+ * @returns {Object[]} The results as an array of messages or null if no messages.
+ */
+ api.verify = function(text, config, filename, saveState) {
+
+ var ast;
+
+ // set the current parsed filename
+ currentFilename = filename;
+
+ if (!saveState) {
+ this.reset();
+ }
+
+ ast = parse(text.replace(/^#!([^\r\n]+[\r\n]+)/, "//$1"));
+
+ // if Esprima failed to parse the file, there's no sense in setting up rules
+ if (ast) {
+ // process initial config to make it safe to extend
+ config = prepareConfig(config);
+
+ // parse global comments and modify config
+ modifyConfigsFromComments(ast, config, reportingConfig);
+
+ // enable appropriate rules
+ Object.keys(config.rules).filter(function(key) {
+ return getRuleSeverity(config.rules[key]) > 0;
+ }).forEach(function(key) {
+
+ var ruleCreator = rules.get(key),
+ severity = getRuleSeverity(config.rules[key]),
+ options = getRuleOptions(config.rules[key]),
+ rule;
+
+ if (ruleCreator) {
+ try {
+ rule = ruleCreator(new RuleContext(key, api, severity, options, config.settings));
+
+ // add all the node types as listeners
+ Object.keys(rule).forEach(function(nodeType) {
+ api.on(nodeType, rule[nodeType]);
+ });
+ } catch(ex) {
+ ex.message = "Error while loading rule '" + key + "': " + ex.message;
+ throw ex;
+ }
+
+ } else {
+ throw new Error("Definition for rule '" + key + "' was not found.");
+ }
+ });
+
+ // save config so rules can access as necessary
+ currentConfig = config;
+ currentText = text;
+ controller = new estraverse.Controller();
+
+ // gather data that may be needed by the rules
+ currentScopes = escope.analyze(ast, { ignoreEval: true }).scopes;
+
+ /*
+ * Index the scopes by the start range of their block for efficient
+ * lookup in getScope.
+ */
+ scopeMap = [];
+ currentScopes.forEach(function (scope, index) {
+ var range = scope.block.range[0];
+
+ // Sometimes two scopes are returned for a given node. This is
+ // handled later in a known way, so just don't overwrite here.
+ if (!scopeMap[range]) {
+ scopeMap[range] = index;
+ }
+ });
+
+ /*
+ * Split text here into array of lines so
+ * it's not being done repeatedly
+ * by individual rules.
+ */
+ currentTextLines = currentText.split(/\r?\n/g);
+
+ // Freezing so array isn't accidentally changed by a rule.
+ Object.freeze(currentTextLines);
+
+ /* get all tokens from the ast and store them as a hashtable to
+ * improve traversal speed when wanting to find tokens for a given
+ * node
+ */
+ currentTokens = [];
+ ast.tokens.forEach(function(token) {
+ currentTokens[token.range[0]] = token;
+ });
+
+ // augment global scope with declared global variables
+ addDeclaredGlobals(ast, currentScopes[0], currentConfig);
+
+ /*
+ * Each node has a type property. Whenever a particular type of node is found,
+ * an event is fired. This allows any listeners to automatically be informed
+ * that this type of node has been found and react accordingly.
+ */
+ controller.traverse(ast, {
+ enter: function(node, parent) {
+
+ var comments = api.getComments(node);
+
+ emitCommentsEnter(comments.leading);
+ node.parent = parent;
+ api.emit(node.type, node);
+ emitCommentsEnter(comments.trailing);
+ },
+ leave: function(node) {
+
+ var comments = api.getComments(node);
+
+ emitCommentsExit(comments.trailing);
+ api.emit(node.type + ":exit", node);
+ emitCommentsExit(comments.leading);
+ }
+ });
+
+ }
+
+ return messages;
+ };
+
+ /**
+ * Reports a message from one of the rules.
+ * @param {string} ruleId The ID of the rule causing the message.
+ * @param {number} severity The severity level of the rule as configured.
+ * @param {ASTNode} node The AST node that the message relates to.
+ * @param {Object=} location An object containing the error line and column
+ * numbers. If location is not provided the node's start location will
+ * be used.
+ * @param {string} message The actual message.
+ * @param {Object} opts Optional template data which produces a formatted message
+ * with symbols being replaced by this object's values.
+ * @returns {void}
+ */
+ api.report = function(ruleId, severity, node, location, message, opts) {
+
+ if (typeof location === "string") {
+ opts = message;
+ message = location;
+ location = node.loc.start;
+ }
+
+ Object.keys(opts || {}).forEach(function (key) {
+ var rx = new RegExp("{{" + escapeRegExp(key) + "}}", "g");
+ message = message.replace(rx, opts[key]);
+ });
+
+ if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) {
+ return;
+ }
+
+ messages.push({
+ ruleId: ruleId,
+ severity: severity,
+ node: node,
+ message: message,
+ line: location.line,
+ column: location.column,
+ source: api.getSource(node)
+ });
+ };
+
+ /**
+ * Gets the source code for the given node.
+ * @param {ASTNode=} node The AST node to get the text for.
+ * @param {int=} beforeCount The number of characters before the node to retrieve.
+ * @param {int=} afterCount The number of characters after the node to retrieve.
+ * @returns {string} The text representing the AST node.
+ */
+ api.getSource = function(node, beforeCount, afterCount) {
+ if (node) {
+ return (currentText !== null) ? currentText.slice(node.range[0] - (beforeCount || 0),
+ node.range[1] + (afterCount || 0)) : null;
+ } else {
+ return currentText;
+ }
+
+ };
+
+ /**
+ * Gets the entire source text split into an array of lines.
+ * @returns {Array} The source text as an array of lines.
+ */
+ api.getSourceLines = function() {
+ return currentTextLines;
+ };
+
+ /**
+ * Gets all comments for the given node.
+ * @param {ASTNode} node The AST node to get the comments for.
+ * @returns {Object} The list of comments indexed by their position.
+ */
+ api.getComments = function(node) {
+
+ var leadingComments = node.leadingComments || [],
+ trailingComments = node.trailingComments || [];
+
+ /*
+ * Esprima adds a "comments" array on Program nodes rather than
+ * leadingComments/trailingComments. Comments are only left in the
+ * Program node comments array if there is no executable code.
+ */
+ if (node.type === "Program") {
+ if (node.body.length === 0) {
+ leadingComments = node.comments;
+ }
+ }
+
+ return {
+ leading: leadingComments,
+ trailing: trailingComments
+ };
+ };
+
+ /**
+ * Retrieves the JSDoc comment for a given node.
+ * @param {ASTNode} node The AST node to get the comment for.
+ * @returns {ASTNode} The BlockComment node containing the JSDoc for the
+ * given node or null if not found.
+ */
+ api.getJSDocComment = function(node) {
+
+ var parent = node.parent,
+ line = node.loc.start.line;
+
+ /**
+ * Finds a JSDoc comment node in an array of comment nodes.
+ * @param {ASTNode[]} comments The array of comment nodes to search.
+ * @returns {ASTNode} The node if found, null if not.
+ * @private
+ */
+ function findJSDocComment(comments) {
+
+ if (comments) {
+ for (var i = comments.length - 1; i >= 0; i--) {
+ if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") {
+
+ if (line - comments[i].loc.end.line <= 1) {
+ return comments[i];
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ switch (node.type) {
+ case "FunctionDeclaration":
+ return findJSDocComment(node.leadingComments);
+
+ case "FunctionExpression":
+
+ if (parent.type !== "CallExpression" || parent.callee !== node) {
+ while (parent && !parent.leadingComments && parent.type !== "FunctionExpression" && parent.type !== "FunctionDeclaration") {
+ parent = parent.parent;
+ }
+
+ return parent && (parent.type !== "FunctionDeclaration") ? findJSDocComment(parent.leadingComments) : null;
+ }
+
+ // falls through
+
+ default:
+ return null;
+ }
+ };
+
+ /**
+ * Gets a number of tokens that precede a given node's tokens in the token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [beforeCount=0] The number of tokens before the node to retrieve.
+ * @returns {[Token]} Array of objects representing tokens.
+ */
+ api.getTokensBefore = function(node, beforeCount) {
+ var beforeTokens = [], cursor = node.range[0] - 1;
+ while (beforeCount > 0 && cursor >= 0) {
+ if (currentTokens[cursor]) {
+ beforeTokens.unshift(currentTokens[cursor]);
+ --beforeCount;
+ }
+ --cursor;
+ }
+ return beforeTokens;
+ };
+
+ /**
+ * Gets the token that precedes a given node's tokens in the token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [skip=0] A number of tokens to skip before the given node.
+ * @returns {Token} An object representing the token.
+ */
+ api.getTokenBefore = function(node, skip) {
+ for (var cursor = node.range[0] - 1; cursor >= 0; --cursor) {
+ if (currentTokens[cursor]) {
+ if (skip > 0) {
+ --skip;
+ } else {
+ return currentTokens[cursor];
+ }
+ }
+ }
+ };
+
+ /**
+ * Gets a number of tokens that precede a given node's tokens in the token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [afterCount=0] The number of tokens after the node to retrieve.
+ * @returns {[Token]} Array of objects representing tokens.
+ */
+ api.getTokensAfter = function(node, afterCount) {
+ var afterTokens = [], cursor = node.range[1];
+ while (afterCount > 0 && cursor < currentTokens.length) {
+ if (currentTokens[cursor]) {
+ afterTokens.push(currentTokens[cursor]);
+ --afterCount;
+ cursor = currentTokens[cursor].range[1];
+ } else {
+ ++cursor;
+ }
+ }
+ return afterTokens;
+ };
+
+ /**
+ * Gets the token that follows a given node's tokens in the token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [skip=0] A number of tokens to skip after the given node.
+ * @returns {Token} An object representing the token.
+ */
+ api.getTokenAfter = function(node, skip) {
+ for (var cursor = node.range[1]; cursor < currentTokens.length; ++cursor) {
+ if (currentTokens[cursor]) {
+ if (skip > 0) {
+ --skip;
+ } else {
+ return currentTokens[cursor];
+ }
+ }
+ }
+ };
+
+ /**
+ * Gets all tokens that are related to the given node.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [beforeCount=0] The number of tokens before the node to retrieve.
+ * @param {int} [afterCount=0] The number of tokens after the node to retrieve.
+ * @returns {[Token]} Array of objects representing tokens.
+ */
+ api.getTokens = function(node, beforeCount, afterCount) {
+ var beforeTokens = api.getTokensBefore(node, beforeCount),
+ afterTokens = api.getTokensAfter(node, afterCount),
+ tokens = [],
+ cursor = node.range[0];
+ while (cursor < node.range[1]) {
+ if (currentTokens[cursor]) {
+ tokens.push(currentTokens[cursor]);
+ cursor = currentTokens[cursor].range[1];
+ } else {
+ ++cursor;
+ }
+ }
+ return beforeTokens.concat(tokens, afterTokens);
+ };
+
+ /**
+ * Gets the first `count` tokens of the given node's token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [count=0] The number of tokens of the node to retrieve.
+ * @returns {[Token]} Array of objects representing tokens.
+ */
+ api.getFirstTokens = function(node, count) {
+ var tokens = [], cursor = node.range[0];
+ while (count > 0 && cursor < node.range[1]) {
+ if (currentTokens[cursor]) {
+ tokens.push(currentTokens[cursor]);
+ --count;
+ cursor = currentTokens[cursor].range[1];
+ } else {
+ ++cursor;
+ }
+ }
+ return tokens;
+ };
+
+ /**
+ * Gets the first token of the given node's token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [skip=0] A number of tokens to skip.
+ * @returns {Token} An object representing the token.
+ */
+ api.getFirstToken = function(node, skip) {
+ for (var cursor = node.range[0]; cursor < node.range[1]; ++cursor) {
+ if (currentTokens[cursor]) {
+ if (skip > 0) {
+ --skip;
+ } else {
+ return currentTokens[cursor];
+ }
+ }
+ }
+ };
+
+ /**
+ * Gets the last `count` tokens of the given node.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [count=0] The number of tokens of the node to retrieve.
+ * @returns {[Token]} Array of objects representing tokens.
+ */
+ api.getLastTokens = function(node, count) {
+ var tokens = [], cursor = node.range[1] - 1;
+ while (count > 0 && cursor >= node.range[0]) {
+ if (currentTokens[cursor]) {
+ tokens.unshift(currentTokens[cursor]);
+ --count;
+ }
+ --cursor;
+ }
+ return tokens;
+ };
+
+ /**
+ * Gets the last token of the given node's token stream.
+ * @param {ASTNode} node The AST node.
+ * @param {int} [skip=0] A number of tokens to skip.
+ * @returns {Token} An object representing the token.
+ */
+ api.getLastToken = function(node, skip) {
+ for (var cursor = node.range[1] - 1; cursor >= node.range[0]; --cursor) {
+ if (currentTokens[cursor]) {
+ if (skip > 0) {
+ --skip;
+ } else {
+ return currentTokens[cursor];
+ }
+ }
+ }
+ };
+
+ /**
+ * Gets nodes that are ancestors of current node.
+ * @returns {ASTNode[]} Array of objects representing ancestors.
+ */
+ api.getAncestors = function() {
+ return controller.parents();
+ };
+
+
+ /**
+ * Gets the scope for the current node.
+ * @returns {Object} An object representing the current node's scope.
+ */
+ api.getScope = function() {
+ var parents = controller.parents(),
+ innerBlock = null,
+ selectedScopeIndex;
+
+ // Don't do this for Program nodes - they have no parents
+ if (parents.length) {
+
+ // if current node is function declaration, add it to the list
+ var current = controller.current();
+ if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression") {
+ parents.push(current);
+ }
+
+ // Ascend the current node's parents
+ for (var i = parents.length - 1; i >= 0; --i) {
+
+ // The first node that requires a scope is the node that will be
+ // our current node's innermost scope.
+ if (escope.Scope.isScopeRequired(parents[i])) {
+ innerBlock = parents[i];
+ break;
+ }
+ }
+
+ // Find and return the innermost scope
+ selectedScopeIndex = scopeMap[innerBlock.range[0]];
+
+ // Named function expressions create two nested scope objects. The
+ // outer scope contains only the function expression name. We return
+ // the inner scope.
+ if (innerBlock.type === "FunctionExpression" && innerBlock.id && innerBlock.id.name) {
+ ++selectedScopeIndex;
+ }
+
+ return currentScopes[selectedScopeIndex];
+ } else {
+ return currentScopes[0]; // global scope
+ }
+ };
+
+ /**
+ * Gets the filename for the currently parsed source.
+ * @returns {string} The filename associated with the source being parsed.
+ * Defaults to "<input>" if no filename info is present.
+ */
+ api.getFilename = function() {
+ if (typeof currentFilename === "string") {
+ return currentFilename;
+ } else {
+ return "<input>";
+ }
+ };
+
+ /**
+ * Defines a new linting rule.
+ * @param {string} ruleId A unique rule identifier
+ * @param {Function} ruleModule Function from context to object mapping AST node types to event handlers
+ * @returns {void}
+ */
+ var defineRule = api.defineRule = function(ruleId, ruleModule) {
+ rules.define(ruleId, ruleModule);
+ };
+
+ /**
+ * Defines many new linting rules.
+ * @param {object} rules map from unique rule identifier to rule
+ * @returns {void}
+ */
+ api.defineRules = function(rules) {
+ Object.getOwnPropertyNames(rules).forEach(function(ruleId) {
+ defineRule(ruleId, rules[ruleId]);
+ });
+ };
+
+ /**
+ * Gets the default eslint configuration.
+ * @returns {Object} Object mapping rule IDs to their default configurations
+ */
+ api.defaults = function() {
+ return require("../conf/eslint.json");
+ };
+
+ return api;
+
+}());
+
+},{"../conf/environments.json":1,"../conf/eslint.json":2,"./rule-context":11,"./rules":12,"./util":150,"escope":5,"esprima":6,"estraverse":7,"events":3,"object-assign":8}],10:[function(require,module,exports){
+module.exports = function() {
+ var rules = Object.create(null);
+ rules["block-scoped-var"] = require("./rules/block-scoped-var");
+ rules["brace-style"] = require("./rules/brace-style");
+ rules["camelcase"] = require("./rules/camelcase");
+ rules["comma-spacing"] = require("./rules/comma-spacing");
+ rules["comma-style"] = require("./rules/comma-style");
+ rules["complexity"] = require("./rules/complexity");
+ rules["consistent-return"] = require("./rules/consistent-return");
+ rules["consistent-this"] = require("./rules/consistent-this");
+ rules["curly"] = require("./rules/curly");
+ rules["default-case"] = require("./rules/default-case");
+ rules["dot-notation"] = require("./rules/dot-notation");
+ rules["eol-last"] = require("./rules/eol-last");
+ rules["eqeqeq"] = require("./rules/eqeqeq");
+ rules["func-names"] = require("./rules/func-names");
+ rules["func-style"] = require("./rules/func-style");
+ rules["global-strict"] = require("./rules/global-strict");
+ rules["guard-for-in"] = require("./rules/guard-for-in");
+ rules["handle-callback-err"] = require("./rules/handle-callback-err");
+ rules["key-spacing"] = require("./rules/key-spacing");
+ rules["max-depth"] = require("./rules/max-depth");
+ rules["max-len"] = require("./rules/max-len");
+ rules["max-nested-callbacks"] = require("./rules/max-nested-callbacks");
+ rules["max-params"] = require("./rules/max-params");
+ rules["max-statements"] = require("./rules/max-statements");
+ rules["new-cap"] = require("./rules/new-cap");
+ rules["new-parens"] = require("./rules/new-parens");
+ rules["no-alert"] = require("./rules/no-alert");
+ rules["no-array-constructor"] = require("./rules/no-array-constructor");
+ rules["no-bitwise"] = require("./rules/no-bitwise");
+ rules["no-caller"] = require("./rules/no-caller");
+ rules["no-catch-shadow"] = require("./rules/no-catch-shadow");
+ rules["no-comma-dangle"] = require("./rules/no-comma-dangle");
+ rules["no-cond-assign"] = require("./rules/no-cond-assign");
+ rules["no-console"] = require("./rules/no-console");
+ rules["no-constant-condition"] = require("./rules/no-constant-condition");
+ rules["no-control-regex"] = require("./rules/no-control-regex");
+ rules["no-debugger"] = require("./rules/no-debugger");
+ rules["no-delete-var"] = require("./rules/no-delete-var");
+ rules["no-div-regex"] = require("./rules/no-div-regex");
+ rules["no-dupe-keys"] = require("./rules/no-dupe-keys");
+ rules["no-else-return"] = require("./rules/no-else-return");
+ rules["no-empty-class"] = require("./rules/no-empty-class");
+ rules["no-empty-label"] = require("./rules/no-empty-label");
+ rules["no-empty"] = require("./rules/no-empty");
+ rules["no-eq-null"] = require("./rules/no-eq-null");
+ rules["no-eval"] = require("./rules/no-eval");
+ rules["no-ex-assign"] = require("./rules/no-ex-assign");
+ rules["no-extend-native"] = require("./rules/no-extend-native");
+ rules["no-extra-bind"] = require("./rules/no-extra-bind");
+ rules["no-extra-boolean-cast"] = require("./rules/no-extra-boolean-cast");
+ rules["no-extra-parens"] = require("./rules/no-extra-parens");
+ rules["no-extra-semi"] = require("./rules/no-extra-semi");
+ rules["no-extra-strict"] = require("./rules/no-extra-strict");
+ rules["no-fallthrough"] = require("./rules/no-fallthrough");
+ rules["no-floating-decimal"] = require("./rules/no-floating-decimal");
+ rules["no-func-assign"] = require("./rules/no-func-assign");
+ rules["no-implied-eval"] = require("./rules/no-implied-eval");
+ rules["no-inner-declarations"] = require("./rules/no-inner-declarations");
+ rules["no-invalid-regexp"] = require("./rules/no-invalid-regexp");
+ rules["no-iterator"] = require("./rules/no-iterator");
+ rules["no-label-var"] = require("./rules/no-label-var");
+ rules["no-labels"] = require("./rules/no-labels");
+ rules["no-lone-blocks"] = require("./rules/no-lone-blocks");
+ rules["no-lonely-if"] = require("./rules/no-lonely-if");
+ rules["no-loop-func"] = require("./rules/no-loop-func");
+ rules["no-mixed-requires"] = require("./rules/no-mixed-requires");
+ rules["no-mixed-spaces-and-tabs"] = require("./rules/no-mixed-spaces-and-tabs");
+ rules["no-multi-spaces"] = require("./rules/no-multi-spaces");
+ rules["no-multi-str"] = require("./rules/no-multi-str");
+ rules["no-multiple-empty-lines"] = require("./rules/no-multiple-empty-lines");
+ rules["no-native-reassign"] = require("./rules/no-native-reassign");
+ rules["no-negated-in-lhs"] = require("./rules/no-negated-in-lhs");
+ rules["no-nested-ternary"] = require("./rules/no-nested-ternary");
+ rules["no-new-func"] = require("./rules/no-new-func");
+ rules["no-new-object"] = require("./rules/no-new-object");
+ rules["no-new-require"] = require("./rules/no-new-require");
+ rules["no-new-wrappers"] = require("./rules/no-new-wrappers");
+ rules["no-new"] = require("./rules/no-new");
+ rules["no-obj-calls"] = require("./rules/no-obj-calls");
+ rules["no-octal-escape"] = require("./rules/no-octal-escape");
+ rules["no-octal"] = require("./rules/no-octal");
+ rules["no-path-concat"] = require("./rules/no-path-concat");
+ rules["no-plusplus"] = require("./rules/no-plusplus");
+ rules["no-process-env"] = require("./rules/no-process-env");
+ rules["no-process-exit"] = require("./rules/no-process-exit");
+ rules["no-proto"] = require("./rules/no-proto");
+ rules["no-redeclare"] = require("./rules/no-redeclare");
+ rules["no-regex-spaces"] = require("./rules/no-regex-spaces");
+ rules["no-reserved-keys"] = require("./rules/no-reserved-keys");
+ rules["no-restricted-modules"] = require("./rules/no-restricted-modules");
+ rules["no-return-assign"] = require("./rules/no-return-assign");
+ rules["no-script-url"] = require("./rules/no-script-url");
+ rules["no-self-compare"] = require("./rules/no-self-compare");
+ rules["no-sequences"] = require("./rules/no-sequences");
+ rules["no-shadow-restricted-names"] = require("./rules/no-shadow-restricted-names");
+ rules["no-shadow"] = require("./rules/no-shadow");
+ rules["no-space-before-semi"] = require("./rules/no-space-before-semi");
+ rules["no-spaced-func"] = require("./rules/no-spaced-func");
+ rules["no-sparse-arrays"] = require("./rules/no-sparse-arrays");
+ rules["no-sync"] = require("./rules/no-sync");
+ rules["no-ternary"] = require("./rules/no-ternary");
+ rules["no-trailing-spaces"] = require("./rules/no-trailing-spaces");
+ rules["no-undef-init"] = require("./rules/no-undef-init");
+ rules["no-undef"] = require("./rules/no-undef");
+ rules["no-undefined"] = require("./rules/no-undefined");
+ rules["no-underscore-dangle"] = require("./rules/no-underscore-dangle");
+ rules["no-unreachable"] = require("./rules/no-unreachable");
+ rules["no-unused-expressions"] = require("./rules/no-unused-expressions");
+ rules["no-unused-vars"] = require("./rules/no-unused-vars");
+ rules["no-use-before-define"] = require("./rules/no-use-before-define");
+ rules["no-void"] = require("./rules/no-void");
+ rules["no-warning-comments"] = require("./rules/no-warning-comments");
+ rules["no-with"] = require("./rules/no-with");
+ rules["no-wrap-func"] = require("./rules/no-wrap-func");
+ rules["one-var"] = require("./rules/one-var");
+ rules["padded-blocks"] = require("./rules/padded-blocks");
+ rules["quote-props"] = require("./rules/quote-props");
+ rules["quotes"] = require("./rules/quotes");
+ rules["radix"] = require("./rules/radix");
+ rules["semi"] = require("./rules/semi");
+ rules["sort-vars"] = require("./rules/sort-vars");
+ rules["space-after-keywords"] = require("./rules/space-after-keywords");
+ rules["space-before-blocks"] = require("./rules/space-before-blocks");
+ rules["space-in-brackets"] = require("./rules/space-in-brackets");
+ rules["space-in-parens"] = require("./rules/space-in-parens");
+ rules["space-infix-ops"] = require("./rules/space-infix-ops");
+ rules["space-return-throw-case"] = require("./rules/space-return-throw-case");
+ rules["space-unary-word-ops"] = require("./rules/space-unary-word-ops");
+ rules["spaced-line-comment"] = require("./rules/spaced-line-comment");
+ rules["strict"] = require("./rules/strict");
+ rules["use-isnan"] = require("./rules/use-isnan");
+ rules["valid-jsdoc"] = require("./rules/valid-jsdoc");
+ rules["valid-typeof"] = require("./rules/valid-typeof");
+ rules["vars-on-top"] = require("./rules/vars-on-top");
+ rules["wrap-iife"] = require("./rules/wrap-iife");
+ rules["wrap-regex"] = require("./rules/wrap-regex");
+ rules["yoda"] = require("./rules/yoda");
+
+ return rules;
+};
+},{"./rules/block-scoped-var":13,"./rules/brace-style":14,"./rules/camelcase":15,"./rules/comma-spacing":16,"./rules/comma-style":17,"./rules/complexity":18,"./rules/consistent-return":19,"./rules/consistent-this":20,"./rules/curly":21,"./rules/default-case":22,"./rules/dot-notation":23,"./rules/eol-last":24,"./rules/eqeqeq":25,"./rules/func-names":26,"./rules/func-style":27,"./rules/global-strict":28,"./rules/guard-for-in":29,"./rules/handle-callback-err":30,"./rules/key-spacing":31,"./rules/max-depth":32,"./rules/max-len":33,"./rules/max-nested-callbacks":34,"./rules/max-params":35,"./rules/max-statements":36,"./rules/new-cap":37,"./rules/new-parens":38,"./rules/no-alert":39,"./rules/no-array-constructo
r":40,"./rules/no-bitwise":41,"./rules/no-caller":42,"./rules/no-catch-shadow":43,"./rules/no-comma-dangle":44,"./rules/no-cond-assign":45,"./rules/no-console":46,"./rules/no-constant-condition":47,"./rules/no-control-regex":48,"./rules/no-debugger":49,"./rules/no-delete-var":50,"./rules/no-div-regex":51,"./rules/no-dupe-keys":52,"./rules/no-else-return":53,"./rules/no-empty":56,"./rules/no-empty-class":54,"./rules/no-empty-label":55,"./rules/no-eq-null":57,"./rules/no-eval":58,"./rules/no-ex-assign":59,"./rules/no-extend-native":60,"./rules/no-extra-bind":61,"./rules/no-extra-boolean-cast":62,"./rules/no-extra-parens":63,"./rules/no-extra-semi":64,"./rules/no-extra-strict":65,"./rules/no-fallthrough":66,"./ru
les/no-floating-decimal":67,"./rules/no-func-assign":68,"./rules/no-implied-eval":69,"./rules/no-inner-declarations":70,"./rules/no-invalid-regexp":71,"./rules/no-iterator":72,"./rules/no-label-var":73,"./rules/no-labels":74,"./rules/no-lone-blocks":75,"./rules/no-lonely-if":76,"./rules/no-loop-func":77,"./rules/no-mixed-requires":78,"./rules/no-mixed-spaces-and-tabs":79,"./rules/no-multi-spaces":80,"./rules/no-multi-str":81,"./rules/no-multiple-empty-lines":82,"./rules/no-native-reassign":83,"./rules/no-negated-in-lhs":84,"./rules/no-nested-ternary":85,"./rules/no-new":90,"./rules/no-new-func":86,"./rules/no-new-object":87,"./rules/no-new-require":88,"./rules/no-new-wrappers":89,"./rules/no-obj-calls":91,"./rules/no-octal":
93,"./rules/no-octal-escape":92,"./rules/no-path-concat":94,"./rules/no-plusplus":95,"./rules/no-process-env":96,"./rules/no-process-exit":97,"./rules/no-proto":98,"./rules/no-redeclare":99,"./rules/no-regex-spaces":100,"./rules/no-reserved-keys":101,"./rules/no-restricted-modules":102,"./rules/no-return-assign":103,"./rules/no-script-url":104,"./rules/no-self-compare":105,"./rules/no-sequences":106,"./rules/no-shadow":108,"./rules/no-shadow-restricted-names":107,"./rules/no-space-before-semi":109,"./rules/no-spaced-func":110,"./rules/no-sparse-arrays":111,"./rules/no-sync":112,"./rules/no-ternary":113,"./rules/no-trailing-spaces":114,"./rules/no-undef":116,"./rules/no-undef-init":115,"./rules/no-undefined":117,"./rules/no-u
nderscore-dangle":118,"./rules/no-unreachable":119,"./rules/no-unused-expressions":120,"./rules/no-unused-vars":121,"./rules/no-use-before-define":122,"./rules/no-void":123,"./rules/no-warning-comments":124,"./rules/no-with":125,"./rules/no-wrap-func":126,"./rules/one-var":127,"./rules/padded-blocks":128,"./rules/quote-props":129,"./rules/quotes":130,"./rules/radix":131,"./rules/semi":132,"./rules/sort-vars":133,"./rules/space-after-keywords":134,"./rules/space-before-blocks":135,"./rules/space-in-brackets":136,"./rules/space-in-parens":137,"./rules/space-infix-ops":138,"./rules/space-return-throw-case":139,"./rules/space-unary-word-ops":140,"./rules/spaced-line-comment":141,"./rules/strict":142,"./rules/use-isnan":143,"
;./rules/valid-jsdoc":144,"./rules/valid-typeof":145,"./rules/vars-on-top":146,"./rules/wrap-iife":147,"./rules/wrap-regex":148,"./rules/yoda":149}],11:[function(require,module,exports){
+/**
+ * @fileoverview RuleContext utility for rules
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+var PASSTHROUGHS = [
+ "getSource",
+ "getSourceLines",
+ "getTokens",
+ "getTokensBefore",
+ "getTokenBefore",
+ "getTokensAfter",
+ "getTokenAfter",
+ "getFirstTokens",
+ "getFirstToken",
+ "getLastTokens",
+ "getLastToken",
+ "getComments",
+ "getAncestors",
+ "getScope",
+ "getJSDocComment",
+ "getFilename"
+ ];
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+/**
+ * Acts as an abstraction layer between rules and the main eslint object.
+ * @constructor
+ * @param {string} ruleId The ID of the rule using this object.
+ * @param {eslint} eslint The eslint object.
+ * @param {number} severity The configured severity level of the rule.
+ * @param {array} options The configuration information to be added to the rule.
+ * @param {object} settings The configuration settings passed from the config file.
+ */
+function RuleContext(ruleId, eslint, severity, options, settings) {
+
+ /**
+ * The read-only ID of the rule.
+ */
+ Object.defineProperty(this, "id", {
+ value: ruleId
+ });
+
+ /**
+ * The read-only options of the rule
+ */
+ Object.defineProperty(this, "options", {
+ value: options
+ });
+
+ /**
+ * The read-only settings shared between all rules
+ */
+ Object.defineProperty(this, "settings", {
+ value: settings
+ });
+
+ // copy over passthrough methods
+ PASSTHROUGHS.forEach(function(name) {
+ this[name] = function() {
+ return eslint[name].apply(eslint, arguments);
+ };
+ }, this);
+
+ /**
+ * Passthrough to eslint.report() that automatically assigns the rule ID and severity.
+ * @param {ASTNode} node The AST node related to the message.
+ * @param {Object=} location The location of the error.
+ * @param {string} message The message to display to the user.
+ * @param {Object} opts Optional template data which produces a formatted message
+ * with symbols being replaced by this object's values.
+ * @returns {void}
+ */
+ this.report = function(node, location, message, opts) {
+ eslint.report(ruleId, severity, node, location, message, opts);
+ };
+
+}
+
+RuleContext.prototype = {
+ constructor: RuleContext
+};
+
+module.exports = RuleContext;
+
+},{}],12:[function(require,module,exports){
+/**
+ * @fileoverview Defines a storage for rules.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var loadRules = require("./load-rules");
+
+//------------------------------------------------------------------------------
+// Privates
+//------------------------------------------------------------------------------
+
+var rules = Object.create(null);
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
+/**
+ * Registers a rule module for rule id in storage.
+ * @param {String} ruleId Rule id (file name).
+ * @param {Function} ruleModule Rule handler.
+ * @returns {void}
+ */
+function define(ruleId, ruleModule) {
+ rules[ruleId] = ruleModule;
+}
+
+exports.define = define;
+
+/**
+ * Loads and registers all rules from passed rules directory.
+ * @param {String} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
+ * @returns {void}
+ */
+function load(rulesDir) {
+ var newRules = loadRules(rulesDir);
+ Object.keys(newRules).forEach(function(ruleId) {
+ define(ruleId, newRules[ruleId]);
+ });
+}
+
+exports.load = load;
+
+/**
+ * Registers all given rules of a plugin.
+ * @param {Object} pluginRules A key/value map of rule definitions.
+ * @param {String} pluginName The name of the plugin without prefix (`eslint-plugin-`).
+ * @returns {void}
+ */
+exports.import = function (pluginRules, pluginName) {
+ Object.keys(pluginRules).forEach(function (ruleId) {
+ var qualifiedRuleId = pluginName + "/" + ruleId,
+ rule = pluginRules[ruleId];
+
+ define(qualifiedRuleId, rule);
+ });
+};
+
+/**
+ * Access rule handler by id (file name).
+ * @param {String} ruleId Rule id (file name).
+ * @returns {Function} Rule handler.
+ */
+exports.get = function(ruleId) {
+ return rules[ruleId];
+};
+
+/**
+ * Reset rules storage.
+ * Should be used only in tests.
+ * @returns {void}
+ */
+exports.testClear = function() {
+ rules = Object.create(null);
+};
+
+//------------------------------------------------------------------------------
+// Initialization
+//------------------------------------------------------------------------------
+
+// loads built-in rules
+load();
+
+},{"./load-rules":10}],13:[function(require,module,exports){
+/**
+ * @fileoverview Rule to check for "block scoped" variables by binding context
+ * @author Matt DuVall <http://www.mattduvall.com>
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var scopeStack = [];
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether an identifier is in declaration position or is a non-declaration reference.
+ * @param {ASTNode} id The identifier.
+ * @param {ASTNode} parent The identifier's parent AST node.
+ * @returns {Boolean} true when the identifier is in declaration position.
+ */
+ function isDeclaration(id, parent) {
+ switch (parent.type) {
+ case "FunctionDeclaration":
+ case "FunctionExpression":
+ return parent.params.indexOf(id) > -1 || id === parent.id;
+
+ case "VariableDeclarator":
+ return id === parent.id;
+
+ case "CatchClause":
+ return id === parent.param;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Determines whether an identifier is in property position.
+ * @param {ASTNode} id The identifier.
+ * @param {ASTNode} parent The identifier's parent AST node.
+ * @returns {Boolean} true when the identifier is in property position.
+ */
+ function isProperty(id, parent) {
+ switch (parent.type) {
+ case "MemberExpression":
+ return id === parent.property && !parent.computed;
+
+ case "Property":
+ return id === parent.key;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Pushes a new scope object on the scope stack.
+ * @returns {void}
+ */
+ function pushScope() {
+ scopeStack.push([]);
+ }
+
+ /**
+ * Removes the topmost scope object from the scope stack.
+ * @returns {void}
+ */
+ function popScope() {
+ scopeStack.pop();
+ }
+
+ /**
+ * Declares the given names in the topmost scope object.
+ * @param {[String]} names A list of names to declare.
+ * @returns {void}
+ */
+ function declare(names) {
+ [].push.apply(scopeStack[scopeStack.length - 1], names);
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ function functionHandler(node) {
+ pushScope();
+ declare(node.params.map(function(id) {
+ return id.name;
+ }));
+ declare(node.id ? [node.id.name] : []);
+ declare(["arguments"]);
+ }
+
+ function variableDeclarationHandler(node) {
+ declare(node.declarations.map(function(decl) {
+ return decl.id.name;
+ }));
+ }
+
+ return {
+ "Program": function() {
+ scopeStack = [context.getScope().variables.map(function(v) {
+ return v.name;
+ })];
+ },
+
+ "BlockStatement": function(node) {
+ var statements = node.body;
+ pushScope();
+ statements.forEach(function(stmt) {
+ if (stmt.type === "VariableDeclaration") {
+ variableDeclarationHandler(stmt);
+ } else if (stmt.type === "FunctionDeclaration") {
+ declare([stmt.id.name]);
+ }
+ });
+ },
+
+ "BlockStatement:exit": popScope,
+
+ "CatchClause": function(node) {
+ pushScope();
+ declare([node.param.name]);
+ },
+ "CatchClause:exit": popScope,
+
+ "FunctionDeclaration": functionHandler,
+ "FunctionDeclaration:exit": popScope,
+
+ "FunctionExpression": functionHandler,
+ "FunctionExpression:exit": popScope,
+
+ "ForStatement": function(node) {
+ pushScope();
+ if (node.init && node.init.type === "VariableDeclaration") {
+ variableDeclarationHandler(node.init);
+ }
+ },
+ "ForStatement:exit": popScope,
+
+ "ForInStatement": function(node) {
+ pushScope();
+ if (node.left.type === "VariableDeclaration") {
+ variableDeclarationHandler(node.left);
+ }
+ },
+ "ForInStatement:exit": popScope,
+
+ "Identifier": function(node) {
+ var ancestor = context.getAncestors().pop();
+ if (isDeclaration(node, ancestor) || isProperty(node, ancestor)) {
+ return;
+ }
+ for (var i = 0, l = scopeStack.length; i < l; i++) {
+ if (scopeStack[i].indexOf(node.name) > -1) {
+ return;
+ }
+ }
+
+ context.report(node, "\"" + node.name + "\" used outside of binding context.");
+ }
+ };
+
+};
+
+},{}],14:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag block statements that do not use the one true brace style
+ * @author Ian Christian Myers
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ var style = context.options[0] || "1tbs";
+ var params = context.options[1] || {};
+
+ var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.",
+ BODY_MESSAGE = "Statement inside of curly braces should be on next line.",
+ CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.",
+ CLOSE_MESSAGE_SINGLE = "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.",
+ CLOSE_MESSAGE_STROUSTRUP = "Closing curly brace appears on the same line as the subsequent block.";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Binds a list of properties to a function that verifies that the opening
+ * curly brace is on the same line as its controlling statement of a given
+ * node.
+ * @param {...string} The properties to check on the node.
+ * @returns {Function} A function that will perform the check on a node
+ */
+ function checkBlock() {
+ var blockProperties = arguments;
+ return function(node) {
+ [].forEach.call(blockProperties, function(blockProp) {
+ var block = node[blockProp], previousToken, curlyToken, curlyTokenEnd, curlyTokensOnSameLine;
+ block = node[blockProp];
+ if (block && block.type === "BlockStatement") {
+ previousToken = context.getTokenBefore(block);
+ curlyToken = context.getFirstToken(block);
+ curlyTokenEnd = context.getLastToken(block);
+ curlyTokensOnSameLine = curlyToken.loc.start.line === curlyTokenEnd.loc.start.line;
+
+ if (previousToken.loc.start.line !== curlyToken.loc.start.line) {
+ context.report(node, OPEN_MESSAGE);
+ } else if (block.body.length && params.allowSingleLine) {
+ if (curlyToken.loc.start.line === block.body[0].loc.start.line && !curlyTokensOnSameLine) {
+ context.report(block.body[0], BODY_MESSAGE);
+ } else if (curlyTokenEnd.loc.start.line === block.body[block.body.length - 1].loc.start.line && !curlyTokensOnSameLine) {
+ context.report(block.body[block.body.length - 1], CLOSE_MESSAGE_SINGLE);
+ }
+ } else if (block.body.length && curlyToken.loc.start.line === block.body[0].loc.start.line) {
+ context.report(block.body[0], BODY_MESSAGE);
+ }
+ }
+ });
+ };
+ }
+
+ /**
+ * Enforces the configured brace style on IfStatements
+ * @param {ASTNode} node An IfStatement node.
+ * @returns {void}
+ */
+ function checkIfStatement(node) {
+ var tokens;
+
+ checkBlock("consequent", "alternate")(node);
+
+ if (node.alternate && node.alternate.type === "BlockStatement") {
+ tokens = context.getTokensBefore(node.alternate, 2);
+ if (style === "1tbs") {
+ if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
+ context.report(node.alternate, CLOSE_MESSAGE);
+ }
+ } else if (style === "stroustrup") {
+ if (tokens[0].loc.start.line === tokens[1].loc.start.line) {
+ context.report(node.alternate, CLOSE_MESSAGE_STROUSTRUP);
+ }
+ }
+ }
+ }
+
+ /**
+ * Enforces the configured brace style on TryStatements
+ * @param {ASTNode} node A TryStatement node.
+ * @returns {void}
+ */
+ function checkTryStatement(node) {
+ var tokens;
+
+ checkBlock("block", "finalizer")(node);
+
+ if (node.finalizer && node.finalizer.type === "BlockStatement") {
+ tokens = context.getTokensBefore(node.finalizer, 2);
+ if (style === "1tbs") {
+ if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
+ context.report(node.finalizer, CLOSE_MESSAGE);
+ }
+ } else if (style === "stroustrup") {
+ if (tokens[0].loc.start.line === tokens[1].loc.start.line) {
+ context.report(node.finalizer, CLOSE_MESSAGE_STROUSTRUP);
+ }
+ }
+ }
+ }
+
+ /**
+ * Enforces the configured brace style on CatchClauses
+ * @param {ASTNode} node A CatchClause node.
+ * @returns {void}
+ */
+ function checkCatchClause(node) {
+ var previousToken = context.getTokenBefore(node),
+ firstToken = context.getFirstToken(node);
+
+ checkBlock("body")(node);
+
+ if (node.body && node.body.type === "BlockStatement") {
+ if (style === "1tbs") {
+ if (previousToken.loc.start.line !== firstToken.loc.start.line) {
+ context.report(node, CLOSE_MESSAGE);
+ }
+ } else if (style === "stroustrup") {
+ if (previousToken.loc.start.line === firstToken.loc.start.line) {
+ context.report(node, CLOSE_MESSAGE_STROUSTRUP);
+ }
+ }
+ }
+ }
+
+ /**
+ * Enforces the configured brace style on SwitchStatements
+ * @param {ASTNode} node A SwitchStatement node.
+ * @returns {void}
+ */
+ function checkSwitchStatement(node) {
+ var tokens;
+ if (node.cases && node.cases.length) {
+ tokens = context.getTokensBefore(node.cases[0], 2);
+ if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
+ context.report(node, OPEN_MESSAGE);
+ }
+ } else {
+ tokens = context.getLastTokens(node, 3);
+ if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
+ context.report(node, OPEN_MESSAGE);
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "FunctionDeclaration": checkBlock("body"),
+ "FunctionExpression": checkBlock("body"),
+ "IfStatement": checkIfStatement,
+ "TryStatement": checkTryStatement,
+ "CatchClause": checkCatchClause,
+ "DoWhileStatement": checkBlock("body"),
+ "WhileStatement": checkBlock("body"),
+ "WithStatement": checkBlock("body"),
+ "ForStatement": checkBlock("body"),
+ "ForInStatement": checkBlock("body"),
+ "SwitchStatement": checkSwitchStatement
+ };
+
+};
+
+},{}],15:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag non-camelcased identifiers
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks if a string contains an underscore and isn't all upper-case
+ * @param {String} name The string to check.
+ * @returns {boolean} if the string is underscored
+ * @private
+ */
+ function isUnderscored(name) {
+
+ // if there's an underscore, it might be A_CONSTANT, which is okay
+ return name.indexOf("_") > -1 && name !== name.toUpperCase();
+ }
+
+ /**
+ * Reports an AST node as a rule violation.
+ * @param {ASTNode} node The node to report.
+ * @returns {void}
+ * @private
+ */
+ function report(node) {
+ context.report(node, "Identifier '{{name}}' is not in camel case.", { name: node.name });
+ }
+
+ return {
+
+ "Identifier": function(node) {
+
+ // Leading and trailing underscores are commonly used to flag private/protected identifiers, strip them
+ var name = node.name.replace(/^_+|_+$/g, ""),
+ effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
+
+ // MemberExpressions get special rules
+ if (node.parent.type === "MemberExpression") {
+
+ // Always report underscored object names
+ if (node.parent.object.type === "Identifier" &&
+ node.parent.object.name === node.name &&
+ isUnderscored(name)) {
+ report(node);
+
+ // Report AssignmentExpressions only if they are the left side of the assignment
+ } else if (effectiveParent.type === "AssignmentExpression" &&
+ isUnderscored(name) &&
+ (effectiveParent.right.type !== "MemberExpression" ||
+ effectiveParent.left.type === "MemberExpression" &&
+ effectiveParent.left.property.name === node.name)) {
+ report(node);
+ }
+
+ // Report anything that is underscored that isn't a CallExpression
+ } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") {
+ report(node);
+ }
+ }
+ };
+
+};
+
+},{}],16:[function(require,module,exports){
+/**
+ * @fileoverview Comma spacing - validates spacing before and after comma
+ * @author Vignesh Anand aka vegetableman.
+ * @copyright 2014 Vignesh Anand. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ var options = {
+ before: context.options[0] ? !!context.options[0].before : false,
+ after: context.options[0] ? !!context.options[0].after : true
+ };
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether two adjacent tokens have whitespace between them.
+ * @param {Object} left - The left token object.
+ * @param {Object} right - The right token object.
+ * @returns {boolean} Whether or not there is space between the tokens.
+ */
+ function isSpaced(left, right) {
+ return left.range[1] < right.range[0];
+ }
+
+ /**
+ * Run report.
+ * @param {ASTNode} node The binary expression node to check.
+ * @param {string} msg The error msg to show.
+ * @private
+ * @returns {void}
+ */
+ function report(node, msg) {
+ context.report(node, msg);
+ }
+
+ /**
+ * Show space required message.
+ * @param {string} dir The location of spacing.
+ * @private
+ * @returns {string} The spacing error msg.
+ */
+ function getSpaceReqMsg(dir) {
+ return "A space is required " + dir + " ','.";
+ }
+
+ /**
+ * Show no space message.
+ * @param {string} dir The location of spacing
+ * @private
+ * @returns {string} The spacing error msg.
+ */
+ function getNoSpaceMsg(dir) {
+ return "There should be no space " + dir + " ','.";
+ }
+
+ /**
+ * Validates the spacing before and after commas.
+ * @param {ASTNode} node The binary expression node to check.
+ * @param {string} property The property of the node.
+ * @private
+ * @returns {void}
+ */
+ function validateCommaSpacing(node, property) {
+ var items = node[property];
+
+ if (items && items.length > 1) {
+ items.forEach(function(item, index) {
+ var tokenBefore = context.getTokenBefore(item),
+ itemBefore = items[index - 1],
+ tokenEndLine;
+
+ if (tokenBefore && tokenBefore.value === ",") {
+ tokenEndLine = tokenBefore.loc.end.line;
+
+ // single line
+ if (tokenEndLine === itemBefore.loc.end.line &&
+ tokenEndLine === item.loc.start.line) {
+ if (options.before && options.after) {
+ if (!isSpaced(itemBefore, tokenBefore)) {
+ report(item, getSpaceReqMsg("before"));
+ }
+ if (!isSpaced(tokenBefore, item)) {
+ report(item, getSpaceReqMsg("after"));
+ }
+ } else if (options.before) {
+ if (!isSpaced(itemBefore, tokenBefore)) {
+ report(item, getSpaceReqMsg("before"));
+ }
+ if (isSpaced(tokenBefore, item)) {
+ report(item, getNoSpaceMsg("after"));
+ }
+ } else if (options.after) {
+ if (!isSpaced(tokenBefore, item)) {
+ report(item, getSpaceReqMsg("after"));
+ }
+ if (isSpaced(itemBefore, tokenBefore)) {
+ report(item, getNoSpaceMsg("before"));
+ }
+ } else {
+ if (isSpaced(itemBefore, tokenBefore)) {
+ report(item, getNoSpaceMsg("before"));
+ }
+ if (isSpaced(tokenBefore, item)) {
+ report(item, getNoSpaceMsg("after"));
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "VariableDeclaration": function(node) {
+ validateCommaSpacing(node, "declarations");
+ },
+ "ObjectExpression": function(node) {
+ validateCommaSpacing(node, "properties");
+ },
+ "ArrayExpression": function(node) {
+ validateCommaSpacing(node, "elements");
+ },
+ "SequenceExpression": function(node) {
+ validateCommaSpacing(node, "expressions");
+ },
+ "FunctionExpression": function(node) {
+ validateCommaSpacing(node, "params");
+ },
+ "FunctionDeclaration": function(node) {
+ validateCommaSpacing(node, "params");
+ }
+ };
+
+};
+
+},{}],17:[function(require,module,exports){
+/**
+ * @fileoverview Comma style - enforces comma styles of two types: last and first
+ * @author Vignesh Anand aka vegetableman
+ * @copyright 2014 Vignesh Anand. All rights reserved.
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var style = context.options[0] || "last";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks the comma placement with regards to a declaration/property/element
+ * @param {ASTNode} node The binary expression node to check
+ * @private
+ * @returns {void}
+ */
+ function validateComma(node) {
+ var items = node.declarations || node.properties || node.elements;
+
+ if (items.length > 1) {
+ items.forEach(function(item, index) {
+ var tokenBefore = context.getTokenBefore(item),
+ itemBefore = items[index - 1];
+
+ if (tokenBefore.value === ",") {
+ // if single line
+ if (tokenBefore.loc.end.line === item.loc.start.line &&
+ tokenBefore.loc.end.line === itemBefore.loc.end.line) {
+ return;
+ }
+ // lone comma
+ else if (tokenBefore.loc.end.line !== item.loc.start.line &&
+ tokenBefore.loc.end.line !== itemBefore.loc.end.line) {
+ context.report(item, {
+ line: tokenBefore.loc.end.line,
+ column: tokenBefore.loc.start.column
+ }, "Bad line breaking before and after ','.");
+ }
+ else if (style === "first" &&
+ tokenBefore.loc.start.line !== item.loc.start.line) {
+ context.report(item, "',' should be placed first.");
+ }
+ else if (style === "last" &&
+ tokenBefore.loc.end.line === item.loc.start.line) {
+ context.report(item, {
+ line: itemBefore.loc.end.line,
+ column: itemBefore.loc.end.column
+ }, "',' should be placed last.");
+ }
+ }
+ });
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "VariableDeclaration": validateComma,
+ "ObjectExpression": validateComma,
+ "ArrayExpression": validateComma
+ };
+
+};
+
+},{}],18:[function(require,module,exports){
+/**
+ * @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity.
+ * Counts the number of if, conditional, for, whilte, try, switch/case,
+ * @author Patrick Brosset
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var THRESHOLD = context.options[0];
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ // Using a stack to store complexity (handling nested functions)
+ var fns = [];
+
+ // When parsing a new function, store it in our function stack
+ function startFunction() {
+ fns.push(1);
+ }
+
+ function endFunction(node) {
+ var complexity = fns.pop(), name = "anonymous";
+
+ if (node.id) {
+ name = node.id.name;
+ }
+ if (complexity > THRESHOLD) {
+ context.report(node, "Function '{{name}}' has a complexity of {{complexity}}.", { name: name, complexity: complexity });
+ }
+ }
+
+ function increaseComplexity() {
+ if (fns.length) {
+ fns[fns.length - 1] ++;
+ }
+ }
+
+ function increaseSwitchComplexity(node) {
+ // Avoiding `default`
+ if (node.test) {
+ increaseComplexity(node);
+ }
+ }
+
+ function increaseLogicalComplexity(node) {
+ // Avoiding &&
+ if (node.operator === "||") {
+ increaseComplexity(node);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "FunctionDeclaration": startFunction,
+ "FunctionExpression": startFunction,
+ "FunctionDeclaration:exit": endFunction,
+ "FunctionExpression:exit": endFunction,
+
+ "CatchClause": increaseComplexity,
+ "ConditionalExpression": increaseComplexity,
+ "LogicalExpression": increaseLogicalComplexity,
+ "ForStatement": increaseComplexity,
+ "ForInStatement": increaseComplexity,
+ "IfStatement": increaseComplexity,
+ "SwitchCase": increaseSwitchComplexity,
+ "WhileStatement": increaseComplexity,
+ "DoWhileStatement": increaseComplexity
+ };
+
+};
+
+},{}],19:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag consistent return values
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var functions = [];
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ function enterFunction() {
+ functions.push({});
+ }
+
+ function exitFunction() {
+ functions.pop();
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "FunctionDeclaration": enterFunction,
+ "FunctionExpression": enterFunction,
+ "FunctionDeclaration:exit": exitFunction,
+ "FunctionExpression:exit": exitFunction,
+
+ "ReturnStatement": function(node) {
+
+ var returnInfo = functions[functions.length - 1],
+ returnTypeDefined = "type" in returnInfo;
+
+ if (returnTypeDefined) {
+
+ if (returnInfo.type !== !!node.argument) {
+ context.report(node, "Expected " + (returnInfo.type ? "a" : "no") + " return value.");
+ }
+
+ } else {
+ returnInfo.type = !!node.argument;
+ }
+
+ }
+ };
+
+};
+
+},{}],20:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce consistent naming of "this" context variables
+ * @author Raphael Pigulla
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "VariableDeclaration": function(node) {
+ var alias = context.options[0];
+
+ node.declarations.forEach(function(declaration) {
+ if (declaration.id.name === alias &&
+ !(declaration.init && declaration.init.type === "ThisExpression")) {
+
+ context.report(
+ node,
+ "Designated 'this' alias '{{alias}}' is not assigned " +
+ "to the current execution context.",
+ { alias: declaration.id.name }
+ );
+ }
+
+ if (declaration.init &&
+ declaration.init.type === "ThisExpression" &&
+ declaration.id.name !== alias) {
+
+ context.report(
+ node,
+ "Unexpected alias '{{alias}}' for 'this'.",
+ { alias: declaration.id.name }
+ );
+ }
+ });
+ }
+ };
+
+};
+
+},{}],21:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag statements without curly braces
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var multiOnly = (context.options[0] === "multi");
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks the body of a node to see if it's a block statement. Depending on
+ * the rule options, reports the appropriate problems.
+ * @param {ASTNode} node The node to report if there's a problem.
+ * @param {ASTNode} body The body node to check for blocks.
+ * @param {string} name The name to report if there's a problem.
+ * @param {string} suffix Additional string to add to the end of a report.
+ * @returns {void}
+ */
+ function checkBody(node, body, name, suffix) {
+ var hasBlock = (body.type === "BlockStatement");
+
+ if (multiOnly) {
+ if (hasBlock && body.body.length === 1) {
+ context.report(node, "Unnecessary { after '{{name}}'{{suffix}}.",
+ {
+ name: name,
+ suffix: (suffix ? " " + suffix : "")
+ }
+ );
+ }
+ } else {
+ if (!hasBlock) {
+ context.report(node, "Expected { after '{{name}}'{{suffix}}.",
+ {
+ name: name,
+ suffix: (suffix ? " " + suffix : "")
+ }
+ );
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "IfStatement": function(node) {
+
+ checkBody(node, node.consequent, "if", "condition");
+
+ if (node.alternate && node.alternate.type !== "IfStatement") {
+ checkBody(node, node.alternate, "else");
+ }
+
+ },
+
+ "WhileStatement": function(node) {
+ checkBody(node, node.body, "while", "condition");
+ },
+
+ "DoWhileStatement": function (node) {
+ checkBody(node, node.body, "do");
+ },
+
+ "ForStatement": function(node) {
+ checkBody(node, node.body, "for", "condition");
+ }
+ };
+
+};
+
+},{}],22:[function(require,module,exports){
+/**
+ * @fileoverview require default case in switch statements
+ * @author Aliaksei Shytkin
+ */
+"use strict";
+
+var COMMENT_VALUE = "no default";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Shortcut to get last element of array
+ * @param {*[]} collection Array
+ * @returns {*} Last element
+ */
+ function last(collection) {
+ return collection[collection.length - 1];
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "SwitchStatement": function(node) {
+
+ if (!node.cases.length) {
+ // skip check of empty switch because there is no easy way
+ // to extract comments inside it now
+ return;
+ }
+
+ var hasDefault = node.cases.some(function(v) {
+ return v.test === null;
+ });
+
+ if (!hasDefault) {
+
+ var comment;
+ var comments;
+
+ var lastCase = last(node.cases);
+ comments = context.getComments(lastCase).trailing;
+
+ if (comments.length) {
+ comment = last(comments);
+ }
+
+ if (!comment || comment.value.trim() !== COMMENT_VALUE) {
+ context.report(node, "Expected a default case.");
+ }
+ }
+ }
+ };
+};
+
+},{}],23:[function(require,module,exports){
+/**
+ * @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible.
+ * @author Josh Perez
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+var validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
+var keywords = [
+ "this",
+ "function",
+ "if",
+ "return",
+ "var",
+ "else",
+ "for",
+ "new",
+ "arguments",
+ "in",
+ "typeof",
+ "while",
+ "case",
+ "break",
+ "try",
+ "catch",
+ "delete",
+ "throw",
+ "switch",
+ "continue",
+ "default",
+ "instanceof",
+ "do",
+ "void",
+ "finally",
+ "with",
+ "debugger",
+ "eval",
+ "implements",
+ "interface",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "static",
+ "yield",
+ "let",
+ "class",
+ "enum",
+ "export",
+ "extends",
+ "import",
+ "super",
+ "true",
+ "false",
+ "null",
+ "abstract",
+ "boolean",
+ "byte",
+ "char",
+ "const",
+ "double",
+ "final",
+ "float",
+ "goto",
+ "int",
+ "long",
+ "native",
+ "short",
+ "synchronized",
+ "throws",
+ "transient",
+ "volatile"
+];
+
+function canBeWrittenInDotNotation(node) {
+ return node.computed === true &&
+ node.property.type === "Literal" &&
+ validIdentifier.test(node.property.value) &&
+ keywords.indexOf("" + node.property.value) === -1;
+}
+
+module.exports = function(context) {
+ return {
+ "MemberExpression": function(node) {
+ if (canBeWrittenInDotNotation(node)) {
+ context.report(node, "['" + node.property.value + "'] is better written in dot notation.");
+ }
+ }
+ };
+};
+
+},{}],24:[function(require,module,exports){
+/**
+ * @fileoverview Require file to end with single newline.
+ * @author Nodeca Team <https://github.com/nodeca>
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "Program": function checkBadEOF(node) {
+ // Get the whole source code, not for node only.
+ var src = context.getSource(), location = {column: 1};
+
+ if (src.length === 0) {
+ return;
+ }
+
+ if (src[src.length - 1] !== "\n") {
+ // file is not newline-terminated
+ location.line = src.split(/\n/g).length;
+ context.report(node, location, "Newline required at end of file but not found.");
+ } else if (/\n\s*\n$/.test(src)) {
+ // last line is empty
+ location.line = src.split(/\n/g).length - 1;
+ context.report(node, location, "Unexpected blank line at end of file.");
+ }
+ }
+
+ };
+
+};
+
+},{}],25:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag statements that use != and == instead of !== and ===
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ /**
+ * Checks if either operand of a binary expression is a typeof operation
+ * @param {ASTNode} node The node to check
+ * @returns {boolean} if one of the operands is typeof
+ * @private
+ */
+ function isTypeOf(node) {
+ return [node.left, node.right].some(function(node) {
+ return node.type === "UnaryExpression" && node.operator === "typeof";
+ });
+ }
+
+ /**
+ * Checks if operands are literals of the same type (via typeof)
+ * @param {ASTNode} node The node to check
+ * @returns {boolean} if operands are of same type
+ * @private
+ */
+ function areLiteralsAndSameType(node) {
+ return node.left.type === "Literal" && node.right.type === "Literal" &&
+ typeof node.left.value === typeof node.right.value;
+ }
+
+ /**
+ * Checks if one of the operands is a literal null
+ * @param {ASTNode} node The node to check
+ * @returns {boolean} if operands are null
+ * @private
+ */
+ function isNullCheck(node) {
+ return (node.right.type === "Literal" && node.right.value === null) ||
+ (node.left.type === "Literal" && node.left.value === null);
+ }
+
+ /**
+ * Gets the location (line and column) of the binary expression's operator
+ * @param {ASTNode} node The binary expression node to check
+ * @param {String} operator The operator to find
+ * @returns {Object} { line, column } location of operator
+ * @private
+ */
+ function getOperatorLocation(node) {
+ var opToken = context.getTokens(node)[context.getTokens(node.left).length];
+ return {line: opToken.loc.start.line, column: opToken.loc.start.column};
+ }
+
+ return {
+ "BinaryExpression": function(node) {
+ if (node.operator !== "==" && node.operator !== "!=") {
+ return;
+ }
+
+ if (context.options[0] === "smart" && (isTypeOf(node) ||
+ areLiteralsAndSameType(node)) || isNullCheck(node)) {
+ return;
+ }
+
+ if (context.options[0] === "allow-null" && isNullCheck(node)) {
+ return;
+ }
+
+ context.report(
+ node, getOperatorLocation(node),
+ "Expected '{{op}}=' and instead saw '{{op}}'.",
+ {op: node.operator}
+ );
+ }
+ };
+
+};
+
+},{}],26:[function(require,module,exports){
+/**
+ * @fileoverview Rule to warn when a function expression does not have a name.
+ * @author Kyle T. Nunery
+ */
+ "use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ return {
+ "FunctionExpression": function(node) {
+
+ var name = node.id && node.id.name;
+
+ if (!name) {
+ context.report(node, "Missing function expression name.");
+ }
+ }
+ };
+};
+
+},{}],27:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce a particular function style
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var style = context.options[0],
+ enforceDeclarations = (style === "declaration");
+
+ return {
+
+ "FunctionDeclaration": function(node) {
+ if (!enforceDeclarations) {
+ context.report(node, "Expected a function expression.");
+ }
+ },
+
+ "FunctionExpression": function() {
+ var parent = context.getAncestors().pop();
+
+ if (enforceDeclarations && parent.type === "VariableDeclarator") {
+ context.report(parent, "Expected a function declaration.");
+ }
+ }
+ };
+
+};
+
+},{}],28:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag or require global strict mode.
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var mode = context.options[0];
+
+ if (mode === "always") {
+
+ return {
+ "Program": function(node) {
+ if (node.body.length > 0) {
+ var statement = node.body[0];
+
+ if (!(statement.type === "ExpressionStatement" && statement.expression.value === "use strict")) {
+ context.report(node, "Use the global form of \"use strict\".");
+ }
+ }
+ }
+ };
+
+ } else { // mode = "never"
+
+ return {
+ "ExpressionStatement": function(node) {
+ var parent = context.getAncestors().pop();
+
+ if (node.expression.value === "use strict" && parent.type === "Program") {
+ context.report(node, "Use the function form of \"use strict\".");
+ }
+ }
+ };
+
+ }
+
+};
+
+},{}],29:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag for-in loops without if statements inside
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "ForInStatement": function(node) {
+
+ /*
+ * If the for-in statement has {}, then the real body is the body
+ * of the BlockStatement. Otherwise, just use body as provided.
+ */
+ var body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body;
+
+ if (body && body.type !== "IfStatement") {
+ context.report(node, "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype.");
+ }
+ }
+ };
+
+};
+
+},{}],30:[function(require,module,exports){
+/**
+ * @fileoverview Ensure handling of errors when we know they exist.
+ * @author Jamund Ferguson
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var errorArgument = context.options[0] || "err";
+ var callbacks = [];
+ var scopes = 0;
+
+ /**
+ * Checks if the given argument should be interpreted as a regexp pattern.
+ * @param {string} stringToCheck The string which should be checked.
+ * @returns {boolean} Whether or not the string should be interpreted as a pattern.
+ */
+ function isPattern(stringToCheck) {
+ var firstChar = stringToCheck[0];
+ return firstChar === "^";
+ }
+
+ /**
+ * Checks if the given name matches the configured error argument.
+ * @param {string} name The name which should be compared.
+ * @returns {boolean} Whether or not the given name matches the configured error variable name.
+ */
+ function matchesConfiguredErrorName(name) {
+ if (isPattern(errorArgument)) {
+ var regexp = new RegExp(errorArgument);
+ return regexp.test(name);
+ }
+ return name === errorArgument;
+ }
+
+ /**
+ * Check the arguments to see if we need to start tracking the error object.
+ * @param {ASTNode} node The AST node to check.
+ * @returns {void}
+ */
+ function startFunction(node) {
+
+ // keep track of nested scopes
+ scopes++;
+
+ // check if the first argument matches our argument name
+ var firstArg = node.params && node.params[0];
+ if (firstArg && matchesConfiguredErrorName(firstArg.name)) {
+ callbacks.push({handled: false, depth: scopes, errorVariableName: firstArg.name});
+ }
+ }
+
+ /**
+ * At the end of a function check to see if the error was handled.
+ * @param {ASTNode} node The AST node to check.
+ * @returns {void}
+ */
+ function endFunction(node) {
+
+ var callback = callbacks[callbacks.length - 1] || {};
+
+ // check if a callback is ending, if so pop it off the stack
+ if (callback.depth === scopes) {
+ callbacks.pop();
+
+ // check if there were no handled errors since the last callback
+ if (!callback.handled) {
+ context.report(node, "Expected error to be handled.");
+ }
+ }
+
+ // less nested functions
+ scopes--;
+
+ }
+
+ /**
+ * Check to see if we're handling the error object properly.
+ * @param {ASTNode} node The AST node to check.
+ * @returns {void}
+ */
+ function checkForError(node) {
+ if (callbacks.length > 0) {
+ var callback = callbacks[callbacks.length - 1] || {};
+
+ // make sure the node's name matches our error argument name
+ var isAboutError = node.name === callback.errorVariableName;
+
+ // we don't consider these use cases as "handling" the error
+ var doNotCount = ["FunctionDeclaration", "FunctionExpression", "CatchClause"];
+
+ // make sure this identifier isn't used as part of one of them
+ var isHandled = doNotCount.indexOf(node.parent.type) === -1;
+
+ if (isAboutError && isHandled) {
+ // record that this callback handled its error
+ callback.handled = true;
+ }
+ }
+ }
+
+ return {
+ "FunctionDeclaration": startFunction,
+ "FunctionExpression": startFunction,
+ "Identifier": checkForError,
+ "FunctionDeclaration:exit": endFunction,
+ "FunctionExpression:exit": endFunction
+ };
+
+};
+
+},{}],31:[function(require,module,exports){
+/**
+ * @fileoverview Rule to specify spacing of object literal keys and values
+ * @author Brandon Mills
+ * @copyright 2014 Brandon Mills. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Gets an object literal property's key as the identifier name or string value.
+ * @param {ASTNode} property Property node whose key to retrieve.
+ * @returns {string} The property's key.
+ */
+function getKey(property) {
+ return property.key.name || property.key.value;
+}
+
+/**
+ * Gets the number of characters in a key, including quotes around string keys.
+ * @param {ASTNode} property Property of on object literal.
+ * @returns {int} Width of the key, including string quotes where present.
+ */
+function getKeyWidth(property) {
+ var key = property.key;
+ return (key.type === "Identifier" ? key.name : key.raw).length;
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+var messages = {
+ key: "{{error}} space after key \"{{key}}\".",
+ value: "{{error}} space before value for key \"{{key}}\"."
+};
+
+module.exports = function(context) {
+
+ /**
+ * OPTIONS
+ * "key-spacing": [2, {
+ * beforeColon: false,
+ * afterColon: true,
+ * align: "colon" // Optional, or "value"
+ * }
+ */
+
+ var options = context.options[0] || {},
+ align = options.align,
+ beforeColon = +!!options.beforeColon, // Defaults to false
+ afterColon = +!(options.afterColon === false); // Defaults to true
+
+ /**
+ * Gets the spacing around the colon in an object literal property
+ * @param {ASTNode} property Property node from an object literal
+ * @returns {Object} Spacing before and after the property's colon
+ */
+ function getPropertySpacing(property) {
+ var whitespace = /^(\s*):(\s*)/.exec(context.getSource().slice(
+ property.key.range[1], property.value.range[0]
+ ));
+
+ if (whitespace) {
+ return {
+ beforeColon: whitespace[1].length,
+ afterColon: whitespace[2].length
+ };
+ }
+ }
+
+ /**
+ * Reports an appropriately-formatted error if spacing is incorrect on one
+ * side of the colon.
+ * @param {ASTNode} property Key-value pair in an object literal.
+ * @param {string} side Side being verified - either "key" or "value".
+ * @param {int} diff Difference between actual and expected spacing.
+ * @returns {void}
+ */
+ function report(property, side, diff) {
+ if (diff) {
+ context.report(property[side], messages[side], {
+ error: diff > 0 ? "Extra" : "Missing",
+ key: getKey(property)
+ });
+ }
+ }
+
+ if (align) { // Verify vertical alignment
+
+ return {
+ "ObjectExpression": function(node) {
+ var properties = node.properties,
+ length = properties.length,
+ widths = properties.map(getKeyWidth), // Width of keys, including quotes
+ targetWidth = Math.max.apply(null, widths),
+ i, property, spacing, width;
+
+ // Conditionally include one space before or after colon
+ targetWidth += (align === "colon" ? beforeColon : afterColon);
+
+ for (i = 0; i < length; i++) {
+ property = properties[i];
+ spacing = getPropertySpacing(property);
+
+ if (!spacing) {
+ continue; // Object literal getters/setters lack a colon
+ }
+
+ width = widths[i];
+
+ if (align === "value") {
+ report(property, "key", spacing.beforeColon - beforeColon);
+ report(property, "value", (width + spacing.afterColon) - targetWidth);
+ } else { // align = "colon"
+ report(property, "key", (width + spacing.beforeColon) - targetWidth);
+ report(property, "value", spacing.afterColon - afterColon);
+ }
+ }
+ }
+ };
+
+ } else { // Strictly obey beforeColon and afterColon in each property
+
+ return {
+ "Property": function (node) {
+ var spacing = getPropertySpacing(node);
+ if (spacing) { // Object literal getters/setters lack colon spacing
+ report(node, "key", spacing.beforeColon - beforeColon);
+ report(node, "value", spacing.afterColon - afterColon);
+ }
+ }
+ };
+
+ }
+
+};
+
+},{}],32:[function(require,module,exports){
+/**
+ * @fileoverview A rule to set the maximum depth block can be nested in a function.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ var functionStack = [],
+ maxDepth = context.options[0] || 4;
+
+ function startFunction() {
+ functionStack.push(0);
+ }
+
+ function endFunction() {
+ functionStack.pop();
+ }
+
+ function pushBlock(node) {
+ var len = ++functionStack[functionStack.length - 1];
+
+ if (len > maxDepth) {
+ context.report(node, "Blocks are nested too deeply ({{depth}}).",
+ { depth: len });
+ }
+ }
+
+ function popBlock() {
+ functionStack[functionStack.length - 1]--;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "Program": startFunction,
+ "FunctionDeclaration": startFunction,
+ "FunctionExpression": startFunction,
+
+ "IfStatement": pushBlock,
+ "SwitchStatement": pushBlock,
+ "TryStatement": pushBlock,
+ "DoWhileStatement": pushBlock,
+ "WhileStatement": pushBlock,
+ "WithStatement": pushBlock,
+ "ForStatement": pushBlock,
+ "ForInStatement": pushBlock,
+
+ "IfStatement:exit": popBlock,
+ "SwitchStatement:exit": popBlock,
+ "TryStatement:exit": popBlock,
+ "DoWhileStatement:exit": popBlock,
+ "WhileStatement:exit": popBlock,
+ "WithStatement:exit": popBlock,
+ "ForStatement:exit": popBlock,
+ "ForInStatement:exit": popBlock,
+
+ "FunctionDeclaration:exit": endFunction,
+ "FunctionExpression:exit": endFunction,
+ "Program:exit": endFunction
+ };
+
+};
+
+},{}],33:[function(require,module,exports){
+/**
+ * @fileoverview Rule to check for max length on a line.
+ * @author Matt DuVall <http://www.mattduvall.com>
+ * @copyright 2013 Matt DuVall. All rights reserved.
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ /**
+ * Creates a string that is made up of repeating a given string a certain
+ * number of times. This uses exponentiation of squares to achieve significant
+ * performance gains over the more traditional implementation of such
+ * functionality.
+ * @param {string} str The string to repeat.
+ * @param {int} num The number of times to repeat the string.
+ * @returns {string} The created string.
+ * @private
+ */
+ function stringRepeat(str, num) {
+ var result = "";
+ for (num |= 0; num > 0; num >>>= 1, str += str) {
+ if (num & 1) {
+ result += str;
+ }
+ }
+ return result;
+ }
+
+ var tabWidth = context.options[1];
+
+ var maxLength = context.options[0],
+ tabString = stringRepeat(" ", tabWidth);
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+ function checkProgramForMaxLength(node) {
+ var lines = context.getSourceLines();
+
+ // Replace the tabs
+ // Split (honors line-ending)
+ // Iterate
+ lines.forEach(function(line, i) {
+ if (line.replace(/\t/g, tabString).length > maxLength) {
+ context.report(node, { line: i + 1, col: 1 }, "Line " + (i + 1) + " exceeds the maximum line length of " + maxLength + ".");
+ }
+ });
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "Program": checkProgramForMaxLength
+ };
+
+};
+
+},{}],34:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce a maximum number of nested callbacks.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Constants
+ //--------------------------------------------------------------------------
+
+ var THRESHOLD = context.options[0];
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ var callbackStack = [];
+
+ return {
+
+ "FunctionExpression": function (node) {
+ var parent = context.getAncestors().pop();
+
+ if (parent.type === "CallExpression") {
+ callbackStack.push(node);
+ }
+
+ if (callbackStack.length > THRESHOLD) {
+ var opts = {num: callbackStack.length, max: THRESHOLD};
+ context.report(node, "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.", opts);
+ }
+ },
+
+
+ "FunctionExpression:exit": function() {
+ callbackStack.pop();
+ }
+
+ };
+
+};
+
+},{}],35:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when a function has too many parameters
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var numParams = context.options[0] || 3;
+
+ return {
+
+ "FunctionDeclaration": function(node) {
+ if (node.params.length > numParams) {
+ context.report(node, "This function has too many parameters ({{count}}). Maximum allowed is {{max}}.", {
+ count: node.params.length,
+ max: numParams
+ });
+ }
+ },
+
+ "FunctionExpression": function(node) {
+ if (node.params.length > numParams) {
+ context.report(node, "This function has too many parameters ({{count}}). Maximum allowed is {{max}}.", {
+ count: node.params.length,
+ max: numParams
+ });
+ }
+ }
+ };
+
+};
+
+},{}],36:[function(require,module,exports){
+/**
+ * @fileoverview A rule to set the maximum number of statements in a function.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ var functionStack = [],
+ maxStatements = context.options[0] || 10;
+
+ function startFunction() {
+ functionStack.push(0);
+ }
+
+ function endFunction(node) {
+ var count = functionStack.pop();
+
+ if (count > maxStatements) {
+ context.report(node, "This function has too many statements ({{count}}). Maximum allowed is {{max}}.",
+ { count: count, max: maxStatements });
+ }
+ }
+
+ function countStatements(node) {
+ functionStack[functionStack.length - 1] += node.body.length;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "FunctionDeclaration": startFunction,
+ "FunctionExpression": startFunction,
+
+ "BlockStatement": countStatements,
+
+ "FunctionDeclaration:exit": endFunction,
+ "FunctionExpression:exit": endFunction
+ };
+
+};
+
+},{}],37:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of constructors without capital letters
+ * @author Nicholas C. Zakas
+ * @copyright 2013-2014 Nicholas C. Zakas. All rights reserved.
+ */
+
+"use strict";
+
+var CAPS_ALLOWED = [
+ "Number",
+ "String",
+ "Boolean",
+ "Date",
+ "Array",
+ "Symbol",
+ "RegExp"
+];
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var config = context.options[0] || {};
+ config.newIsCap = config.newIsCap === false ? false : true;
+ config.capIsNew = config.capIsNew === false ? false : true;
+
+ var listeners = {};
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Get exact callee name from expression
+ * @param {ASTNode} node CallExpression or NewExpression node
+ * @returns {String} name
+ */
+ function extractNameFromExpression(node) {
+
+ var name = "",
+ property;
+
+ if (node.callee.type === "MemberExpression") {
+ property = node.callee.property;
+
+ if (property.type === "Literal" && (typeof property.value === "string")) {
+ name = property.value;
+ } else if (property.type === "Identifier" && !node.callee.computed) {
+ name = property.name;
+ }
+ } else {
+ name = node.callee.name;
+ }
+ return name;
+ }
+
+ /**
+ * Returns the capitalization state of the string -
+ * Whether the first character is uppercase, lowercase, or non-alphabetic
+ * @param {String} str String
+ * @returns {String} capitalization state: "non-alpha", "lower", or "upper"
+ */
+ function getCap(str) {
+ var firstChar = str.charAt(0);
+
+ var firstCharLower = firstChar.toLowerCase();
+ var firstCharUpper = firstChar.toUpperCase();
+
+ if (firstCharLower === firstCharUpper) {
+ // char has no uppercase variant, so it's non-alphabetic
+ return "non-alpha";
+ } else if (firstChar === firstCharLower) {
+ return "lower";
+ } else {
+ return "upper";
+ }
+ }
+
+ /**
+ * Check if capitalization is allowed for a CallExpression
+ * @param {ASTNode} node CallExpression node
+ * @param {String} calleeName Capitalized callee name from a CallExpression
+ * @returns {Boolean} Returns true if the callee may be capitalized
+ */
+ function isCapAllowed(node, calleeName) {
+ if (CAPS_ALLOWED.indexOf(calleeName) >= 0) {
+ return true;
+ }
+ if (calleeName === "UTC" && node.callee.type === "MemberExpression") {
+ // allow if callee is Date.UTC
+ return node.callee.object.type === "Identifier" &&
+ node.callee.object.name === "Date";
+ }
+ return false;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ if (config.newIsCap) {
+ listeners.NewExpression = function(node) {
+
+ var constructorName = extractNameFromExpression(node);
+ if (constructorName && getCap(constructorName) === "lower") {
+ context.report(node, "A constructor name should not start with a lowercase letter.");
+ }
+ };
+ }
+
+ if (config.capIsNew) {
+ listeners.CallExpression = function(node) {
+
+ var calleeName = extractNameFromExpression(node);
+ if (calleeName && getCap(calleeName) === "upper" && !isCapAllowed(node, calleeName)) {
+ context.report(node, "A function with a name starting with an uppercase letter should only be used as a constructor.");
+ }
+ };
+ }
+
+ return listeners;
+};
+
+},{}],38:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when using constructor without parentheses
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "NewExpression": function(node) {
+ var tokens = context.getTokens(node);
+ var prenticesTokens = tokens.filter(function(token) {
+ return token.value === "(" || token.value === ")";
+ });
+ if (prenticesTokens.length < 2) {
+ context.report(node, "Missing '()' invoking a constructor");
+ }
+ }
+ };
+
+};
+
+},{}],39:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of alert, confirm, prompt
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+function matchProhibited(name) {
+ return name.match(/^(alert|confirm|prompt)$/);
+}
+
+function report(context, node, result) {
+ context.report(node, "Unexpected {{name}}.", { name: result[1] });
+}
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "CallExpression": function(node) {
+
+ var result;
+
+ // without window.
+ if (node.callee.type === "Identifier") {
+
+ result = matchProhibited(node.callee.name);
+
+ if (result) {
+ report(context, node, result);
+ }
+
+ } else if (node.callee.type === "MemberExpression" && node.callee.property.type === "Identifier") {
+
+ result = matchProhibited(node.callee.property.name);
+
+ if (result && node.callee.object.name === "window") {
+ report(context, node, result);
+ }
+
+ }
+
+ }
+ };
+
+};
+
+},{}],40:[function(require,module,exports){
+/**
+ * @fileoverview Disallow construction of dense arrays using the Array constructor
+ * @author Matt DuVall <http://www.mattduvall.com/>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ function check(node) {
+ if (
+ node.arguments.length !== 1 &&
+ node.callee.type === "Identifier" &&
+ node.callee.name === "Array"
+ ) {
+ context.report(node, "The array literal notation [] is preferrable.");
+ }
+ }
+
+ return {
+ "CallExpression": check,
+ "NewExpression": check
+ };
+
+};
+
+},{}],41:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag bitwise identifiers
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ function report(node) {
+ context.report(node, "Unexpected use of '{{operator}}'.", { operator: node.operator });
+ }
+
+ return {
+ "BinaryExpression": function(node) {
+
+ // warn for ^ | & ~ << >> >>>
+ if (node.operator.match(/^(?:[\^&\|~]|<<|>>>?)$/)) {
+ report(node);
+ }
+
+ },
+
+ "UnaryExpression": function(node) {
+
+ // warn for ~
+ if (node.operator === "~") {
+ report(node);
+ }
+
+ }
+ };
+
+};
+
+},{}],42:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of arguments.callee and arguments.caller.
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "MemberExpression": function(node) {
+ var objectName = node.object.name,
+ propertyName = node.property.name;
+
+ if (objectName === "arguments" && !node.computed && propertyName && propertyName.match(/^calle[er]$/)) {
+ context.report(node, "Avoid arguments.{{property}}.", { property: propertyName });
+ }
+
+ }
+ };
+
+};
+
+},{}],43:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag variable leak in CatchClauses in IE 8 and earlier
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ function paramIsShadowing(scope, name) {
+ var found = scope.variables.some(function(variable) {
+ return variable.name === name;
+ });
+
+ if (found) {
+ return true;
+ }
+
+ if (scope.upper) {
+ return paramIsShadowing(scope.upper, name);
+ }
+
+ return false;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "CatchClause": function(node) {
+ var scope = context.getScope();
+
+ if (paramIsShadowing(scope, node.param.name)) {
+ context.report(node, "Value of '{{name}}' may be overwritten in IE 8 and earlier.",
+ { name: node.param.name });
+ }
+ }
+ };
+
+};
+
+},{}],44:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag trailing commas in object literals.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //-------------------------------------------------------------------------
+ // Helpers
+ //-------------------------------------------------------------------------
+
+ function checkForTrailingComma(node) {
+ var secondToLastToken = context.getLastTokens(node, 2)[0];
+
+ var items = node.properties || node.elements,
+ lastItem = items[items.length - 1];
+ // The last token in an object/array literal will always be a closing
+ // curly, so we check the second to last token for a comma.
+ if (secondToLastToken.value === "," && items.length && lastItem) {
+ context.report(lastItem, secondToLastToken.loc.start, "Trailing comma.");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "ObjectExpression": checkForTrailingComma,
+ "ArrayExpression": checkForTrailingComma
+ };
+
+};
+
+},{}],45:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag assignment in a conditional expression
+ * @author Stephen Murray <spmurrayzzz>
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ function isParenthesised(node) {
+ var previousToken = context.getTokenBefore(node),
+ nextToken = context.getTokenAfter(node);
+
+ return previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
+ nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+ }
+
+ function isParenthesisedTwice(node) {
+ var previousToken = context.getTokenBefore(node, 1),
+ nextToken = context.getTokenAfter(node, 1);
+
+ return isParenthesised(node) &&
+ previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
+ nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+ }
+
+ function testForAssign(node) {
+ if (node.test && (node.test.type === "AssignmentExpression") && !isParenthesisedTwice(node.test)) {
+ context.report(node, "Expected a conditional expression and instead saw an assignment.");
+ }
+ }
+
+ return {
+ "IfStatement": testForAssign,
+ "WhileStatement": testForAssign,
+ "DoWhileStatement": testForAssign,
+ "ForStatement": testForAssign
+ };
+
+};
+
+},{}],46:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of console object
+ * @author Nicholas C. Zakas
+ */
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "MemberExpression": function(node) {
+
+ if (node.object.name === "console") {
+ context.report(node, "Unexpected console statement.");
+ }
+
+ }
+ };
+
+};
+
+},{}],47:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use constant conditions
+ * @author Christian Schulz <http://rndm.de>
+ */
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks if a node has a constant truthiness value.
+ * @param {ASTNode} node The AST node to check.
+ * @returns {Bool} true when node's truthiness is constant
+ * @private
+ */
+ function isConstant(node) {
+ switch (node.type) {
+ case "Literal":
+ case "FunctionExpression":
+ case "ObjectExpression":
+ case "ArrayExpression":
+ return true;
+ case "UnaryExpression":
+ return isConstant(node.argument);
+ case "BinaryExpression":
+ case "LogicalExpression":
+ return isConstant(node.left) && isConstant(node.right);
+ case "AssignmentExpression":
+ return isConstant(node.right);
+ case "SequenceExpression":
+ return isConstant(node.expressions[node.expressions.length - 1]);
+ // no default
+ }
+ return false;
+ }
+
+ /**
+ * Reports when the given node contains a constant condition.
+ * @param {ASTNode} node The AST node to check.
+ * @returns {void}
+ * @private
+ */
+ function checkConstantCondition(node) {
+ if (node.test && isConstant(node.test)) {
+ context.report(node, "Unexpected constant condition.");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "ConditionalExpression": checkConstantCondition,
+ "IfStatement": checkConstantCondition,
+ "WhileStatement": checkConstantCondition,
+ "DoWhileStatement": checkConstantCondition,
+ "ForStatement": checkConstantCondition
+ };
+
+};
+
+},{}],48:[function(require,module,exports){
+/**
+ * @fileoverview Rule to forbid control charactes from regular expressions.
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+
+ function getRegExp(node) {
+
+ if (node.value instanceof RegExp) {
+ return node.value;
+ } else if (typeof node.value === "string") {
+
+ var parent = context.getAncestors().pop();
+ if ((parent.type === "NewExpression" || parent.type === "CallExpression") &&
+ parent.callee.type === "Identifier" && parent.callee.name === "RegExp") {
+
+ // there could be an invalid regular expression string
+ try {
+ return new RegExp(node.value);
+ } catch (ex) {
+ return null;
+ }
+
+ }
+ } else {
+ return null;
+ }
+
+ }
+
+
+
+ return {
+
+ "Literal": function(node) {
+
+ var computedValue,
+ regex = getRegExp(node);
+
+ if (regex) {
+ computedValue = regex.toString();
+ if (/[\x00-\x1f]/.test(computedValue)) {
+ context.report(node, "Unexpected control character in regular expression.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],49:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of a debugger statement
+ * @author Nicholas C. Zakas
+ */
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "DebuggerStatement": function(node) {
+ context.report(node, "Unexpected 'debugger' statement.");
+ }
+ };
+
+};
+
+},{}],50:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when deleting variables
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "UnaryExpression": function(node) {
+ if (node.operator === "delete" && node.argument.type === "Identifier") {
+ context.report(node, "Variables should not be deleted.");
+ }
+ }
+ };
+
+};
+
+},{}],51:[function(require,module,exports){
+/**
+ * @fileoverview Rule to check for ambiguous div operator in regexes
+ * @author Matt DuVall <http://www.mattduvall.com>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ var token = context.getFirstTokens(node, 1)[0],
+ nodeType = token.type,
+ source;
+
+ if (nodeType === "RegularExpression") {
+ source = context.getFirstTokens(node, 1)[0].value;
+
+ if (source[1] === "=") {
+ context.report(node, "A regular expression literal can be confused with '/='.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],52:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of duplicate keys in an object.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "ObjectExpression": function(node) {
+
+ // Object that will be a map of properties--safe because we will
+ // prefix all of the keys.
+ var nodeProps = {};
+
+ node.properties.forEach(function(property) {
+ var keyName = property.key.name || property.key.value;
+ var key = property.kind + "-" + keyName;
+
+ if (nodeProps[key]) {
+ context.report(node, "Duplicate key '{{key}}'.", { key: keyName });
+ } else {
+ nodeProps[key] = true;
+ }
+ });
+
+ }
+ };
+
+};
+
+},{}],53:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag `else` after a `return` in `if`
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ function checkForReturnStatement(node, alternate) {
+ if (node.type === "ReturnStatement") {
+ context.report(alternate, "Unexpected 'else' after 'return'.");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "IfStatement": function(node) {
+
+ // Don't bother finding a ReturnStatement, if there's no `else`
+ // or if the alternate is also an if (indicating an else if).
+ if (node.alternate && node.consequent && node.alternate.type !== "IfStatement") {
+
+ // If we have a BlockStatement, check each consequent body node.
+ if (node.consequent.type === "BlockStatement") {
+ node.consequent.body.forEach(function (bodyNode) {
+ checkForReturnStatement(bodyNode, node.alternate);
+ });
+
+ // If not a block statement, make sure the consequent isn't a
+ // ReturnStatement
+ } else {
+ checkForReturnStatement(node.consequent, node.alternate);
+ }
+ }
+ }
+
+ };
+
+};
+
+},{}],54:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag the use of empty character classes in regular expressions
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ var tokens = context.getTokens(node);
+ tokens.forEach(function (token) {
+ /*
+ plain-English description of the following regexp:
+ 0. `^` fix the match at the beginning of the string
+ 1. `\/`: the `/` that begins the regexp
+ 2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
+ 2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
+ 2.1. `\\.`: an escape sequence
+ 2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
+ 3. `\/` the `/` that ends the regexp
+ 4. `[gimy]*`: optional regexp flags
+ 5. `$`: fix the match at the end of the string
+ */
+ if (token.type === "RegularExpression" &&
+ !/^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimy]*$/.test(token.value)) {
+ context.report(node, "Empty class.");
+ }
+ });
+ }
+
+ };
+
+};
+
+},{}],55:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when label is not used for a loop or switch
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "LabeledStatement": function(node) {
+ if (node.body.type !== "ForStatement" && node.body.type !== "WhileStatement" && node.body.type !== "DoWhileStatement" && node.body.type !== "SwitchStatement" && node.body.type !== "ForInStatement") {
+ context.report(node, "Unexpected label {{l}}", {l: node.label.name});
+ }
+ }
+ };
+
+};
+
+},{}],56:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of an empty block statement
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "BlockStatement": function(node) {
+ var ancestors = context.getAncestors(),
+ parent = ancestors[ancestors.length - 1],
+ parentType = parent.type,
+ isFinallyBlock = (parentType === "TryStatement") && (parent.finalizer === node);
+
+ if (/FunctionExpression|FunctionDeclaration|CatchClause/.test(parentType) ||
+ (isFinallyBlock && !parent.handlers.length)) {
+ return;
+ }
+
+ if (node.body.length === 0) {
+ context.report(node, "Empty block statement.");
+ }
+ },
+
+ "SwitchStatement": function(node) {
+
+ if (typeof node.cases === "undefined" || node.cases.length === 0) {
+ context.report(node, "Empty switch statement.");
+ }
+ }
+ };
+
+};
+
+},{}],57:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag comparisons to null without a type-checking
+ * operator.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ "use strict";
+
+ return {
+
+ "BinaryExpression": function(node) {
+ var badOperator = node.operator === "==" || node.operator === "!=";
+
+ if (node.right.type === "Literal" && node.right.raw === "null" && badOperator ||
+ node.left.type === "Literal" && node.left.raw === "null" && badOperator) {
+ context.report(node, "Use ‘===’ to compare with ‘null’.");
+ }
+ }
+ };
+
+};
+
+},{}],58:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of eval() statement
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var IMPLIED_EVAL = /set(?:Timeout|Interval)/;
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines if a node represents a call to setTimeout/setInterval with
+ * a string argument.
+ * @param {ASTNode} node The node to check.
+ * @returns {boolean} True if the node matches, false if not.
+ * @private
+ */
+ function isImpliedEval(node) {
+
+ var isMemberExpression = (node.callee.type === "MemberExpression"),
+ isIdentifier = (node.callee.type === "Identifier"),
+ isSetMethod = (isIdentifier && IMPLIED_EVAL.test(node.callee.name)) ||
+ (isMemberExpression && node.callee.object.name === "window" &&
+ IMPLIED_EVAL.test(node.callee.property.name)),
+ hasStringArgument = node.arguments.length && (typeof node.arguments[0].value === "string");
+
+ return isSetMethod && hasStringArgument;
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "CallExpression": function(node) {
+ if (node.callee.name === "eval") {
+ context.report(node, "eval can be harmful.");
+ } else if (isImpliedEval(node)) {
+ if (node.arguments.length && (typeof node.arguments[0].value === "string")) {
+ context.report(node, "Implied eval can be harmful. Pass a function instead of a string.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],59:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag assignment of the exception parameter
+ * @author Stephen Murray <spmurrayzzz>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var inCatch = false,
+ exceptionName = null;
+
+ return {
+
+ "CatchClause": function(node) {
+ inCatch = true;
+ exceptionName = node.param.name;
+ },
+
+ "CatchClause:exit": function() {
+ inCatch = false;
+ exceptionName = null;
+ },
+
+ "AssignmentExpression": function(node) {
+
+ if (inCatch) {
+
+ if (node.left.name === exceptionName) {
+ context.report(node, "Do not assign to the exception parameter.");
+ }
+ }
+ }
+
+ };
+
+};
+
+},{}],60:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag adding properties to native object's prototypes.
+ * @author David Nelson
+ */
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var BUILTINS = [
+ "Object", "Function", "Array", "String", "Boolean", "Number", "Date",
+ "RegExp", "Error", "EvalError", "RangeError", "ReferenceError",
+ "SyntaxError", "TypeError", "URIError"
+];
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ // handle the Array.prototype.extra style case
+ "AssignmentExpression": function(node) {
+ var lhs = node.left, affectsProto;
+
+ if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") {
+ return;
+ }
+
+ affectsProto = lhs.object.computed ?
+ lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype" :
+ lhs.object.property.name === "prototype";
+
+ if (!affectsProto) {
+ return;
+ }
+
+ BUILTINS.forEach(function(builtin) {
+ if (lhs.object.object.name === builtin) {
+ context.report(node, builtin + " prototype is read only, properties should not be added.");
+ }
+ });
+ },
+
+ // handle the Object.defineProperty(Array.prototype) case
+ "CallExpression": function(node) {
+
+ var callee = node.callee,
+ subject,
+ object;
+
+ // only worry about Object.defineProperty
+ if (callee.type === "MemberExpression" &&
+ callee.object.name === "Object" &&
+ callee.property.name === "defineProperty") {
+
+ // verify the object being added to is a native prototype
+ subject = node.arguments[0];
+ object = subject.object;
+
+ if (object &&
+ object.type === "Identifier" &&
+ (BUILTINS.indexOf(object.name) > -1) &&
+ subject.property.name === "prototype") {
+
+ context.report(node, object.name + " prototype is read only, properties should not be added.");
+ }
+ }
+
+ }
+ };
+
+};
+
+},{}],61:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag unnecessary bind calls
+ * @author Bence Dányi <bence@danyi.me>
+ * @copyright 2014 Bence Dányi. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var scope = [{
+ depth: -1,
+ found: 0
+ }];
+
+ /**
+ * Get the topmost scope
+ * @returns {Object} The topmost scope
+ */
+ function getTopScope() {
+ return scope[scope.length - 1];
+ }
+
+ /**
+ * Increment the depth of the top scope
+ * @returns {void}
+ */
+ function incrementScopeDepth() {
+ var top = getTopScope();
+ top.depth++;
+ }
+
+ /**
+ * Decrement the depth of the top scope
+ * @returns {void}
+ */
+ function decrementScopeDepth() {
+ var top = getTopScope();
+ top.depth--;
+ }
+
+ return {
+ "CallExpression": function(node) {
+ if (node.arguments.length === 1 &&
+ node.callee.type === "MemberExpression" &&
+ node.callee.property.name === "bind" &&
+ node.callee.object.type === "FunctionExpression") {
+ scope.push({
+ call: node,
+ depth: -1,
+ found: 0
+ });
+ }
+ },
+ "CallExpression:exit": function(node) {
+ var top = getTopScope();
+ if (top.call === node && top.found === 0) {
+ context.report(node, "The function binding is unnecessary.");
+ scope.pop();
+ }
+ },
+ "FunctionExpression": incrementScopeDepth,
+ "FunctionExpression:exit": decrementScopeDepth,
+ "FunctionDeclaration": incrementScopeDepth,
+ "FunctionDeclaration:exit": decrementScopeDepth,
+ "ThisExpression": function() {
+ var top = getTopScope();
+ if (top.depth === 0) {
+ top.found++;
+ }
+ }
+ };
+
+};
+
+},{}],62:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag unnecessary double negation in Boolean contexts
+ * @author Brandon Mills
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "UnaryExpression": function (node) {
+ var ancestors = context.getAncestors(),
+ parent = ancestors.pop(),
+ grandparent = ancestors.pop();
+
+ // Exit early if it's guaranteed not to match
+ if (node.operator !== "!" ||
+ parent.type !== "UnaryExpression" ||
+ parent.operator !== "!") {
+ return;
+ }
+
+ // if (<bool>) ...
+ if (grandparent.type === "IfStatement") {
+ context.report(node, "Redundant double negation in an if statement condition.");
+
+ // do ... while (<bool>)
+ } else if (grandparent.type === "DoWhileStatement") {
+ context.report(node, "Redundant double negation in a do while loop condition.");
+
+ // while (<bool>) ...
+ } else if (grandparent.type === "WhileStatement") {
+ context.report(node, "Redundant double negation in a while loop condition.");
+
+ // <bool> ? ... : ...
+ } else if ((grandparent.type === "ConditionalExpression" &&
+ parent === grandparent.test)) {
+ context.report(node, "Redundant double negation in a ternary condition.");
+
+ // for (...; <bool>; ...) ...
+ } else if ((grandparent.type === "ForStatement" &&
+ parent === grandparent.test)) {
+ context.report(node, "Redundant double negation in a for loop condition.");
+
+ // !<bool>
+ } else if ((grandparent.type === "UnaryExpression" &&
+ grandparent.operator === "!")) {
+ context.report(node, "Redundant multiple negation.");
+
+ // Boolean(<bool>)
+ } else if ((grandparent.type === "CallExpression" &&
+ grandparent.callee.type === "Identifier" &&
+ grandparent.callee.name === "Boolean")) {
+ context.report(node, "Redundant double negation in call to Boolean().");
+
+ // new Boolean(<bool>)
+ } else if ((grandparent.type === "NewExpression" &&
+ grandparent.callee.type === "Identifier" &&
+ grandparent.callee.name === "Boolean")) {
+ context.report(node, "Redundant double negation in Boolean constructor call.");
+ }
+ }
+ };
+
+};
+
+},{}],63:[function(require,module,exports){
+/**
+ * @fileoverview Disallow parenthesesisng higher precedence subexpressions.
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ function isParenthesised(node) {
+ var previousToken = context.getTokenBefore(node),
+ nextToken = context.getTokenAfter(node);
+
+ return previousToken && nextToken &&
+ previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
+ nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+ }
+
+ function isParenthesisedTwice(node) {
+ var previousToken = context.getTokenBefore(node, 1),
+ nextToken = context.getTokenAfter(node, 1);
+
+ return isParenthesised(node) && previousToken && nextToken &&
+ previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
+ nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+ }
+
+ function precedence(node) {
+
+ switch (node.type) {
+ case "SequenceExpression":
+ return 0;
+
+ case "AssignmentExpression":
+ return 1;
+
+ case "ConditionalExpression":
+ return 3;
+
+ case "LogicalExpression":
+ switch (node.operator) {
+ case "||":
+ return 4;
+ case "&&":
+ return 5;
+ // no default
+ }
+
+ /* falls through */
+ case "BinaryExpression":
+ switch (node.operator) {
+ case "|":
+ return 6;
+ case "^":
+ return 7;
+ case "&":
+ return 8;
+ case "==":
+ case "!=":
+ case "===":
+ case "!==":
+ return 9;
+ case "<":
+ case "<=":
+ case ">":
+ case ">=":
+ case "in":
+ case "instanceof":
+ return 10;
+ case "<<":
+ case ">>":
+ case ">>>":
+ return 11;
+ case "+":
+ case "-":
+ return 12;
+ case "*":
+ case "/":
+ case "%":
+ return 13;
+ // no default
+ }
+ /* falls through */
+ case "UnaryExpression":
+ return 14;
+ case "UpdateExpression":
+ return 15;
+ case "CallExpression":
+ // IIFE is allowed to have parens in any position (#655)
+ if (node.callee.type === "FunctionExpression") {
+ return -1;
+ }
+ return 16;
+ case "NewExpression":
+ return 17;
+ // no default
+ }
+ return 18;
+ }
+
+ function report(node) {
+ context.report(node, "Gratuitous parentheses around expression.");
+ }
+
+ function dryUnaryUpdate(node) {
+ if (isParenthesised(node.argument) && precedence(node.argument) >= precedence(node)) {
+ report(node.argument);
+ }
+ }
+
+ function dryCallNew(node) {
+ if (isParenthesised(node.callee) && precedence(node.callee) >= precedence(node) &&
+ !(node.type === "CallExpression" && node.callee.type === "FunctionExpression")) {
+ report(node.callee);
+ }
+ if (node.arguments.length === 1) {
+ if (isParenthesisedTwice(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) {
+ report(node.arguments[0]);
+ }
+ } else {
+ [].forEach.call(node.arguments, function(arg) {
+ if (isParenthesised(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) {
+ report(arg);
+ }
+ });
+ }
+ }
+
+ function dryBinaryLogical(node) {
+ var prec = precedence(node);
+ if (isParenthesised(node.left) && precedence(node.left) >= prec) {
+ report(node.left);
+ }
+ if (isParenthesised(node.right) && precedence(node.right) > prec) {
+ report(node.right);
+ }
+ }
+
+ return {
+ "ArrayExpression": function(node) {
+ [].forEach.call(node.elements, function(e) {
+ if (e && isParenthesised(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) {
+ report(e);
+ }
+ });
+ },
+ "AssignmentExpression": function(node) {
+ if (isParenthesised(node.right) && precedence(node.right) >= precedence(node)) {
+ report(node.right);
+ }
+ },
+ "BinaryExpression": dryBinaryLogical,
+ "CallExpression": dryCallNew,
+ "ConditionalExpression": function(node) {
+ if (isParenthesised(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) {
+ report(node.test);
+ }
+ if (isParenthesised(node.consequent) && precedence(node.consequent) >= precedence({type: "AssignmentExpression"})) {
+ report(node.consequent);
+ }
+ if (isParenthesised(node.alternate) && precedence(node.alternate) >= precedence({type: "AssignmentExpression"})) {
+ report(node.alternate);
+ }
+ },
+ "DoWhileStatement": function(node) {
+ if (isParenthesisedTwice(node.test)) {
+ report(node.test);
+ }
+ },
+ "ExpressionStatement": function(node) {
+ var firstToken;
+ if (isParenthesised(node.expression)) {
+ firstToken = context.getFirstToken(node.expression);
+ if (firstToken.value !== "function" && firstToken.value !== "{") {
+ report(node.expression);
+ }
+ }
+ },
+ "ForInStatement": function(node) {
+ if (isParenthesised(node.right)) {
+ report(node.right);
+ }
+ },
+ "ForStatement": function(node) {
+ if (node.init && isParenthesised(node.init)) {
+ report(node.init);
+ }
+
+ if (node.test && isParenthesised(node.test)) {
+ report(node.test);
+ }
+
+ if (node.update && isParenthesised(node.update)) {
+ report(node.update);
+ }
+ },
+ "IfStatement": function(node) {
+ if (isParenthesisedTwice(node.test)) {
+ report(node.test);
+ }
+ },
+ "LogicalExpression": dryBinaryLogical,
+ "MemberExpression": function(node) {
+ if (
+ isParenthesised(node.object) &&
+ precedence(node.object) >= precedence(node) &&
+ (
+ node.computed ||
+ !(
+ node.object.type === "Literal" &&
+ typeof node.object.value === "number" &&
+ /^[0-9]+$/.test(context.getFirstToken(node.object).value)
+ )
+ )
+ ) {
+ report(node.object);
+ }
+ },
+ "NewExpression": dryCallNew,
+ "ObjectExpression": function(node) {
+ [].forEach.call(node.properties, function(e) {
+ var v = e.value;
+ if (v && isParenthesised(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) {
+ report(v);
+ }
+ });
+ },
+ "ReturnStatement": function(node) {
+ if (node.argument && isParenthesised(node.argument)) {
+ report(node.argument);
+ }
+ },
+ "SequenceExpression": function(node) {
+ [].forEach.call(node.expressions, function(e) {
+ if (isParenthesised(e) && precedence(e) >= precedence(node)) {
+ report(e);
+ }
+ });
+ },
+ "SwitchCase": function(node) {
+ if (node.test && isParenthesised(node.test)) {
+ report(node.test);
+ }
+ },
+ "SwitchStatement": function(node) {
+ if (isParenthesisedTwice(node.discriminant)) {
+ report(node.discriminant);
+ }
+ },
+ "ThrowStatement": function(node) {
+ if (isParenthesised(node.argument)) {
+ report(node.argument);
+ }
+ },
+ "UnaryExpression": dryUnaryUpdate,
+ "UpdateExpression": dryUnaryUpdate,
+ "VariableDeclarator": function(node) {
+ if (node.init && isParenthesised(node.init) && precedence(node.init) >= precedence({type: "AssignmentExpression"})) {
+ report(node.init);
+ }
+ },
+ "WhileStatement": function(node) {
+ if (isParenthesisedTwice(node.test)) {
+ report(node.test);
+ }
+ },
+ "WithStatement": function(node) {
+ if (isParenthesisedTwice(node.object)) {
+ report(node.object);
+ }
+ }
+ };
+
+};
+
+},{}],64:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of unnecessary semicolons
+ * @author Nicholas C. Zakas
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "EmptyStatement": function(node) {
+ context.report(node, "Unnecessary semicolon.");
+ }
+ };
+
+};
+
+},{}],65:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag unnecessary strict directives.
+ * @author Ian Christian Myers
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ function directives(block) {
+ var ds = [], body = block.body, e, i, l;
+
+ for (i = 0, l = body.length; i < l; ++i) {
+ e = body[i];
+
+ if (
+ e.type === "ExpressionStatement" &&
+ e.expression.type === "Literal" &&
+ typeof e.expression.value === "string"
+ ) {
+ ds.push(e.expression);
+ } else {
+ break;
+ }
+ }
+ return ds;
+ }
+
+ function isStrict(directive) {
+ return directive.value === "use strict";
+ }
+
+ function checkForUnnecessaryUseStrict(node) {
+ var useStrictDirectives, scope, upper;
+ useStrictDirectives = directives(node).filter(isStrict);
+
+ switch (useStrictDirectives.length) {
+ case 0:
+ break;
+
+ case 1:
+ scope = context.getScope();
+ upper = scope.upper;
+
+ if (upper && upper.functionExpressionScope) {
+ upper = upper.upper;
+ }
+
+ if (upper && upper.isStrict) {
+ context.report(useStrictDirectives[0], "Unnecessary 'use strict'.");
+ }
+ break;
+
+ default:
+ context.report(useStrictDirectives[1], "Multiple 'use strict' directives.");
+ }
+ }
+
+ return {
+
+ "Program": checkForUnnecessaryUseStrict,
+
+ "FunctionExpression": function(node) {
+ checkForUnnecessaryUseStrict(node.body);
+ },
+
+ "FunctionDeclaration": function(node) {
+ checkForUnnecessaryUseStrict(node.body);
+ }
+ };
+
+};
+
+},{}],66:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag fall-through cases in switch statements.
+ * @author Matt DuVall <http://mattduvall.com/>
+ */
+"use strict";
+
+
+var FALLTHROUGH_COMMENT = /falls\sthrough/;
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var switches = [];
+
+ return {
+
+ "SwitchCase": function(node) {
+
+ var consequent = node.consequent,
+ switchData = switches[switches.length - 1],
+ i,
+ comments,
+ comment;
+
+ /*
+ * Some developers wrap case bodies in blocks, so if there is just one
+ * node and it's a block statement, check inside.
+ */
+ if (consequent.length === 1 && consequent[0].type === "BlockStatement") {
+ consequent = consequent[0];
+ }
+
+ // checking on previous case
+ if (!switchData.lastCaseClosed) {
+
+ // a fall through comment will be the last trailing comment of the last case
+ comments = context.getComments(switchData.lastCase).trailing;
+ comment = comments[comments.length - 1];
+
+ // check for comment
+ if (!comment || !FALLTHROUGH_COMMENT.test(comment.value)) {
+ context.report(switchData.lastCase,
+ "Expected a \"break\" statement before \"{{code}}\".",
+ { code: node.test ? "case" : "default" });
+ }
+ }
+
+ // now dealing with the current case
+ switchData.lastCaseClosed = false;
+ switchData.lastCase = node;
+
+ // try to verify using statements - go backwards as a fast path for the search
+ if (consequent.length) {
+ for (i = consequent.length - 1; i >= 0; i--) {
+ if (/(?:Break|Continue|Return|Throw)Statement/.test(consequent[i].type)) {
+ switchData.lastCaseClosed = true;
+ break;
+ }
+ }
+ } else {
+ // the case statement has no statements, so it must logically fall through
+ switchData.lastCaseClosed = true;
+ }
+
+ /*
+ * Any warnings are triggered when the next SwitchCase occurs.
+ * There is no need to warn on the last SwitchCase, since it can't
+ * fall through to anything.
+ */
+ },
+
+ "SwitchStatement": function(node) {
+ switches.push({
+ node: node,
+ lastCaseClosed: true,
+ lastCase: null
+ });
+ },
+
+ "SwitchStatement:exit": function() {
+ switches.pop();
+ }
+ };
+
+};
+
+},{}],67:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of a leading/trailing decimal point in a numeric literal
+ * @author James Allardice
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "Literal": function(node) {
+
+ if (typeof node.value === "number") {
+ if (node.raw.indexOf(".") === 0) {
+ context.report(node, "A leading decimal point can be confused with a dot.");
+ }
+ if (node.raw.indexOf(".") === node.raw.length - 1) {
+ context.report(node, "A trailing decimal point can be confused with a dot.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],68:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of function declaration identifiers as variables.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /*
+ * Walk the scope chain looking for either a FunctionDeclaration or a
+ * VariableDeclaration with the same name as left-hand side of the
+ * AssignmentExpression. If we find the FunctionDeclaration first, then we
+ * warn, because a FunctionDeclaration is trying to become a Variable or a
+ * FunctionExpression. If we find a VariableDeclaration first, then we have
+ * a legitimate shadow variable.
+ */
+ function checkIfIdentifierIsFunction(scope, name) {
+ var variable,
+ def,
+ i,
+ j;
+
+ // Loop over all of the identifiers available in scope.
+ for (i = 0; i < scope.variables.length; i++) {
+ variable = scope.variables[i];
+
+ // For each identifier, see if it was defined in _this_ scope.
+ for (j = 0; j < variable.defs.length; j++) {
+ def = variable.defs[j];
+
+ // Identifier is a function and was declared in this scope
+ if (def.name.name === name && def.type === "FunctionName") {
+ return true;
+ }
+
+ // Identifier is a variable and was declared in this scope. This
+ // is a legitimate shadow variable.
+ if (def.name.name === name) {
+ return false;
+ }
+ }
+ }
+
+ // Check the upper scope.
+ if (scope.upper) {
+ return checkIfIdentifierIsFunction(scope.upper, name);
+ }
+
+ // We've reached the global scope and haven't found anything.
+ return false;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "AssignmentExpression": function(node) {
+ var scope = context.getScope(),
+ name = node.left.name;
+
+ if (checkIfIdentifierIsFunction(scope, name)) {
+ context.report(node, "'{{name}}' is a function.", { name: name });
+ }
+
+ }
+
+ };
+
+};
+
+},{}],69:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of implied eval via setTimeout and setInterval
+ * @author James Allardice
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "CallExpression": function(node) {
+
+ if (node.callee.type === "Identifier") {
+ var callee = node.callee.name;
+
+ if (callee === "setTimeout" || callee === "setInterval") {
+ var argument = node.arguments[0];
+ if (argument && argument.type === "Literal" && typeof argument.value === "string") {
+ context.report(node, "Implied eval. Consider passing a function instead of a string.");
+ }
+ }
+ }
+ }
+ };
+
+};
+
+},{}],70:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce declarations in program or function body root.
+ * @author Brandon Mills
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ /**
+ * Find the nearest Program or Function ancestor node.
+ * @returns {Object} Ancestor's type and distance from node.
+ */
+ function nearestBody() {
+ var ancestors = context.getAncestors(),
+ ancestor = ancestors.pop(),
+ generation = 1;
+
+ while (ancestor && ["Program", "FunctionDeclaration",
+ "FunctionExpression"].indexOf(ancestor.type) < 0) {
+ generation += 1;
+ ancestor = ancestors.pop();
+ }
+
+ return {
+ // Type of containing ancestor
+ type: ancestor.type,
+ // Separation between ancestor and node
+ distance: generation
+ };
+ }
+
+ /**
+ * Ensure that a given node is at a program or function body's root.
+ * @param {ASTNode} node Declaration node to check.
+ * @returns {void}
+ */
+ function check(node) {
+ var body = nearestBody(node),
+ valid = ((body.type === "Program" && body.distance === 1) ||
+ body.distance === 2);
+
+ if (!valid) {
+ context.report(node, "Move {{type}} declaration to {{body}} root.",
+ {
+ type: (node.type === "FunctionDeclaration" ?
+ "function" : "variable"),
+ body: (body.type === "Program" ?
+ "program" : "function body")
+ }
+ );
+ }
+ }
+
+ return {
+
+ "FunctionDeclaration": check,
+ "VariableDeclaration": function(node) {
+ if (context.options[0] === "both") {
+ check(node);
+ }
+ }
+
+ };
+
+};
+
+},{}],71:[function(require,module,exports){
+/**
+ * @fileoverview Validate strings passed to the RegExp constructor
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ function isString(node) {
+ return node && node.type === "Literal" && typeof node.value === "string";
+ }
+
+ function check(node) {
+ if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) {
+ try {
+ if (isString(node.arguments[1])) {
+ void new RegExp(node.arguments[0].value, node.arguments[1].value);
+ } else {
+ void new RegExp(node.arguments[0].value);
+ }
+ } catch(e) {
+ context.report(node, e.message);
+ }
+ }
+ }
+
+ return {
+ "CallExpression": check,
+ "NewExpression": check
+ };
+
+};
+
+},{}],72:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag usage of __iterator__ property
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "MemberExpression": function(node) {
+
+ if (node.property &&
+ (node.property.type === "Identifier" && node.property.name === "__iterator__" && !node.computed) ||
+ (node.property.type === "Literal" && node.property.value === "__iterator__")) {
+ context.report(node, "Reserved name '__iterator__'.");
+ }
+ }
+ };
+
+};
+
+},{}],73:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag labels that are the same as an identifier
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ function findIdentifier(scope, identifier) {
+ var found = false;
+
+ scope.variables.forEach(function(variable) {
+ if (variable.name === identifier) {
+ found = true;
+ }
+ });
+
+ scope.references.forEach(function(reference) {
+ if (reference.identifier.name === identifier) {
+ found = true;
+ }
+ });
+
+ // If we have not found the identifier in this scope, check the parent
+ // scope.
+ if (scope.upper && !found) {
+ return findIdentifier(scope.upper, identifier);
+ }
+
+ return found;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "LabeledStatement": function(node) {
+
+ // Fetch the innermost scope.
+ var scope = context.getScope();
+
+ // Recursively find the identifier walking up the scope, starting
+ // with the innermost scope.
+ if (findIdentifier(scope, node.label.name)) {
+ context.report(node, "Found identifier with same name as label.");
+ }
+ }
+
+ };
+
+};
+
+},{}],74:[function(require,module,exports){
+/**
+ * @fileoverview Disallow Labeled Statements
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "LabeledStatement": function(node) {
+ context.report(node, "Unexpected labeled statement.");
+ },
+
+ "BreakStatement": function(node) {
+
+ if (node.label) {
+ context.report(node, "Unexpected label in break statement.");
+ }
+
+ },
+
+ "ContinueStatement": function(node) {
+
+ if (node.label) {
+ context.report(node, "Unexpected label in continue statement.");
+ }
+
+ }
+
+
+ };
+
+};
+
+},{}],75:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag blocks with no reason to exist
+ * @author Brandon Mills
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "BlockStatement": function (node) {
+ // Check for any occurrence of BlockStatement > BlockStatement or
+ // Program > BlockStatement
+ var parent = context.getAncestors().pop();
+ if (parent.type === "BlockStatement" || parent.type === "Program") {
+ context.report(node, "Block is nested inside another block.");
+ }
+ }
+ };
+
+};
+
+},{}],76:[function(require,module,exports){
+/**
+ * @fileoverview Rule to disallow if as the only statmenet in an else block
+ * @author Brandon Mills
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+ "IfStatement": function(node) {
+ var ancestors = context.getAncestors(),
+ parent = ancestors.pop(),
+ grandparent = ancestors.pop();
+
+ if (parent && parent.type === "BlockStatement" &&
+ parent.body.length === 1 && grandparent &&
+ grandparent.type === "IfStatement" &&
+ parent === grandparent.alternate) {
+ context.report(node, "Unexpected if as the only statement in an else block.");
+ }
+ }
+ };
+
+};
+
+},{}],77:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag creation of function inside a loop
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ function checkForLoops(node) {
+ var ancestors = context.getAncestors();
+
+ if (ancestors.some(function(ancestor) {
+ return ancestor.type === "ForStatement" || ancestor.type === "WhileStatement" || ancestor.type === "DoWhileStatement";
+ })) {
+ context.report(node, "Don't make functions within a loop");
+ }
+ }
+
+ return {
+ "FunctionExpression": checkForLoops,
+ "FunctionDeclaration": checkForLoops
+ };
+};
+
+},{}],78:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce grouped require statements for Node.JS
+ * @author Raphael Pigulla
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ "use strict";
+
+ /**
+ * Returns the list of built-in modules.
+ *
+ * @returns {string[]} An array of built-in Node.js modules.
+ */
+ function getBuiltinModules() {
+ // This list is generated using `require("repl")._builtinLibs.concat('repl').sort()`
+ // This particular list was generated using node v0.11.9
+ return [
+ "assert", "buffer", "child_process", "cluster", "crypto",
+ "dgram", "dns", "domain", "events", "fs", "http", "https",
+ "net", "os", "path", "punycode", "querystring", "readline",
+ "repl", "smalloc", "stream", "string_decoder", "tls", "tty",
+ "url", "util", "vm", "zlib"
+ ];
+ }
+
+ var BUILTIN_MODULES = getBuiltinModules();
+
+ var DECL_REQUIRE = "require",
+ DECL_UNINITIALIZED = "uninitialized",
+ DECL_OTHER = "other";
+
+ var REQ_CORE = "core",
+ REQ_FILE = "file",
+ REQ_MODULE = "module",
+ REQ_COMPUTED = "computed";
+
+ /**
+ * Determines the type of a declaration statement.
+ * @param {ASTNode} initExpression The init node of the VariableDeclarator.
+ * @returns {string} The type of declaration represented by the expression.
+ */
+ function getDeclarationType(initExpression) {
+ if (!initExpression) {
+ // "var x;"
+ return DECL_UNINITIALIZED;
+ }
+
+ if (initExpression.type === "CallExpression" &&
+ initExpression.callee.type === "Identifier" &&
+ initExpression.callee.name === "require"
+ ) {
+ // "var x = require('util');"
+ return DECL_REQUIRE;
+ } else if (initExpression.type === "MemberExpression") {
+ // "var x = require('glob').Glob;"
+ return getDeclarationType(initExpression.object);
+ }
+
+ // "var x = 42;"
+ return DECL_OTHER;
+ }
+
+ /**
+ * Determines the type of module that is loaded via require.
+ * @param {ASTNode} initExpression The init node of the VariableDeclarator.
+ * @returns {string} The module type.
+ */
+ function inferModuleType(initExpression) {
+ if (initExpression.type === "MemberExpression") {
+ // "var x = require('glob').Glob;"
+ return inferModuleType(initExpression.object);
+ } else if (initExpression["arguments"].length === 0) {
+ // "var x = require();"
+ return REQ_COMPUTED;
+ }
+
+ var arg = initExpression["arguments"][0];
+
+ if (arg.type !== "Literal" || typeof arg.value !== "string") {
+ // "var x = require(42);"
+ return REQ_COMPUTED;
+ }
+
+ if (BUILTIN_MODULES.indexOf(arg.value) !== -1) {
+ // "var fs = require('fs');"
+ return REQ_CORE;
+ } else if (/^\.{0,2}\//.test(arg.value)) {
+ // "var utils = require('./utils');"
+ return REQ_FILE;
+ } else {
+ // "var async = require('async');"
+ return REQ_MODULE;
+ }
+ }
+
+ /**
+ * Check if the list of variable declarations is mixed, i.e. whether it
+ * contains both require and other declarations.
+ * @param {ASTNode} declarations The list of VariableDeclarators.
+ * @returns {boolean} True if the declarations are mixed, false if not.
+ */
+ function isMixed(declarations) {
+ var contains = {};
+
+ declarations.forEach(function (declaration) {
+ var type = getDeclarationType(declaration.init);
+ contains[type] = true;
+ });
+
+ return !!(
+ contains[DECL_REQUIRE] &&
+ (contains[DECL_UNINITIALIZED] || contains[DECL_OTHER])
+ );
+ }
+
+ /**
+ * Check if all require declarations in the given list are of the same
+ * type.
+ * @param {ASTNode} declarations The list of VariableDeclarators.
+ * @returns {boolean} True if the declarations are grouped, false if not.
+ */
+ function isGrouped(declarations) {
+ var found = {};
+
+ declarations.forEach(function (declaration) {
+ if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
+ found[inferModuleType(declaration.init)] = true;
+ }
+ });
+
+ return Object.keys(found).length <= 1;
+ }
+
+
+ return {
+
+ "VariableDeclaration": function(node) {
+ var grouping = !!context.options[0];
+
+ if (isMixed(node.declarations)) {
+ context.report(
+ node,
+ "Do not mix 'require' and other declarations."
+ );
+ } else if (grouping && !isGrouped(node.declarations)) {
+ context.report(
+ node,
+ "Do not mix core, module, file and computed requires."
+ );
+ }
+ }
+ };
+
+};
+
+},{}],79:[function(require,module,exports){
+/**
+ * @fileoverview Disallow mixed spaces and tabs for indentation
+ * @author Jary Niebur
+ * @copyright 2014 Nicholas C. Zakas. All rights reserved.
+ * @copyright 2014 Jary Niebur. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var smartTabs = context.options[0];
+
+ var COMMENT_START = /^\s*\/\*/,
+ MAYBE_COMMENT = /^\s*\*/;
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "Program": function(node) {
+ /*
+ * At least one space followed by a tab
+ * or the reverse before non-tab/-space
+ * characters begin.
+ */
+ var regex = /^(?=[\t ]*(\t | \t))/,
+ match,
+ lines = context.getSourceLines();
+
+ if (smartTabs) {
+ /*
+ * At least one space followed by a tab
+ * before non-tab/-space characters begin.
+ */
+ regex = /^(?=[\t ]* \t)/;
+ }
+
+ lines.forEach(function(line, i) {
+ match = regex.exec(line);
+
+ if (match) {
+
+ if (!MAYBE_COMMENT.test(line) && !COMMENT_START.test(lines[i - 1])) {
+ context.report(node, { line: i + 1, column: match.index + 1 }, "Mixed spaces and tabs.");
+ }
+
+ }
+ });
+ }
+
+ };
+
+};
+
+},{}],80:[function(require,module,exports){
+/**
+ * @fileoverview Disallow use of multiple spaces.
+ * @author Vignesh Anand aka vegetableman.
+ * @copyright 2014 Vignesh Anand. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var OPERATORS = [
+ "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in",
+ "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=",
+ "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=",
+ "?", ":", ","
+ ], errOps = [];
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Reports an AST node as a rule violation.
+ * @param {ASTNode} node The node to report.
+ * @returns {void}
+ * @private
+ */
+ function report(node) {
+ context.report(node, "Multiple spaces found around '" + errOps.shift() + "'.");
+ }
+
+ /**
+ * Checks whether the operator is in same line as two adjacent tokens.
+ * @param {ASTNode} left The token left to the operator.
+ * @param {ASTNode} right The token right to the operator.
+ * @param {ASTNode} operator The operator.
+ * @returns {boolean} Whether the operator is in same line as two adjacent tokens.
+ * @private
+ */
+ function isSameLine(left, right, operator) {
+ return operator.loc.end.line === left.loc.end.line &&
+ operator.loc.end.line === right.loc.start.line;
+ }
+
+ /**
+ * Check whether there are multiple spaces around the operator.
+ * @param {ASTNode} left The token left to the operator.
+ * @param {ASTNode} right The token right to the operator.
+ * @param {ASTNode} operator The operator.
+ * @returns {boolean} Whether there are multiple spaces.
+ * @private
+ */
+ function isMultiSpaced(left, right, operator) {
+ return operator.range[0] - left.range[1] > 1 ||
+ right.range[0] - operator.range[1] > 1;
+ }
+
+ /**
+ * Get tokens and validate the spacing.
+ * @param {ASTNode} left The token left to the operator.
+ * @param {ASTNode} right The token right to the operator.
+ * @returns {boolean} Whether multiple spaces were found.
+ * @private
+ */
+ function validateSpacing(left, right) {
+ var tokens = context.getTokens({range: [left.range[1], right.range[0]]}, 1, 1),
+ operator;
+
+ for (var i = 1, l = tokens.length - 1; i < l; ++i) {
+ left = tokens[i - 1];
+ operator = tokens[i];
+ right = tokens[i + 1];
+
+ if (operator && operator.type === "Punctuator" && OPERATORS.indexOf(operator.value) >= 0 &&
+ isSameLine(left, right, operator) && isMultiSpaced(left, right, operator)) {
+ errOps.push(operator.value);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Report if there are multiple spaces on the expression.
+ * @param {ASTNode} node The node to check.
+ * @returns {void}
+ * @private
+ */
+ function checkExpression(node) {
+ if (validateSpacing(node.left, node.right)) {
+ report(node);
+ }
+ }
+
+ /**
+ * Report if there are multiple spaces around conditional ternary operators.
+ * @param {ASTNode} node The node to check.
+ * @returns {void}
+ * @private
+ */
+ function checkConditional(node) {
+ if (validateSpacing(node.test, node.consequent)) {
+ report(node);
+ }
+ if (validateSpacing(node.consequent, node.alternate)) {
+ report(node);
+ }
+ }
+
+ /**
+ * Report if there are multiple spaces around equal operator in variable declaration.
+ * @param {ASTNode} node The node to check.
+ * @returns {void}
+ * @private
+ */
+ function checkVar(node) {
+ if (node.init && validateSpacing(node.id, node.init)) {
+ report(node);
+ }
+ }
+
+ /**
+ * Report if there are multiple spaces around list of items in objects, arrays,
+ * function parameters, sequences and declarations.
+ * @param {ASTNode} node The node to check.
+ * @param {string} property The property of node.
+ * @returns {void}
+ * @private
+ */
+ function checkList(node, property) {
+ var items = node[property];
+
+ for (var i = 0, l = items.length; i < l; i++) {
+ var left = items[i - 1],
+ right = items[i],
+ operator = context.getTokenBefore(right);
+
+ if (operator && operator.type === "Punctuator" && operator.value === ",") {
+ if (isSameLine(left, right, operator) && isMultiSpaced(left, right, operator)) {
+ errOps.push(operator.value);
+ report(right);
+ }
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "AssignmentExpression": checkExpression,
+ "BinaryExpression": checkExpression,
+ "LogicalExpression": checkExpression,
+ "ConditionalExpression": checkConditional,
+ "VariableDeclarator": checkVar,
+ "ArrayExpression": function(node) {
+ checkList(node, "elements");
+ },
+ "ObjectExpression": function(node) {
+ checkList(node, "properties");
+ },
+ "SequenceExpression": function(node) {
+ checkList(node, "expressions");
+ },
+ "FunctionExpression": function(node) {
+ checkList(node, "params");
+ },
+ "FunctionDeclaration": function(node) {
+ checkList(node, "params");
+ },
+ "VariableDeclaration": function(node) {
+ checkList(node, "declarations");
+ }
+ };
+
+};
+
+},{}],81:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when using multiline strings
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ var lineBreak = /\n/;
+ if (lineBreak.test(node.raw)) {
+ context.report(node, "Multiline support is limited to browsers supporting ES5 only.");
+ }
+ }
+ };
+
+};
+
+},{}],82:[function(require,module,exports){
+/**
+ * @fileoverview Disallows multiple blank lines.
+ * implementation adapted from the no-trailing-spaces rule.
+ * @author Greg Cochard
+ * @copyright 2014 Greg Cochard. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ // Use options.max or 2 as default
+ var numLines = 2;
+
+ if (context.options.length) {
+ numLines = context.options[0].max;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "Program": function checkBlankLines(node) {
+ var lines = context.getSourceLines(),
+ currentLocation = -1,
+ lastLocation,
+ blankCounter = 0,
+ location,
+ trimmedLines = lines.map(function(str) {
+ return str.trim();
+ });
+
+ // Aggregate and count blank lines
+ do {
+ lastLocation = currentLocation;
+ currentLocation = trimmedLines.indexOf("",currentLocation + 1);
+ if (lastLocation === currentLocation - 1) {
+ blankCounter++;
+ } else {
+ if (blankCounter >= numLines) {
+ location = {
+ line: lastLocation + 1,
+ column: lines[lastLocation].length
+ };
+ context.report(node, location, "Multiple blank lines not allowed.");
+ }
+
+ // Finally, reset the blank counter
+ blankCounter = 0;
+ }
+ } while (currentLocation !== -1);
+ }
+ };
+
+};
+
+},{}],83:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when re-assigning native objects
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var nativeObjects = ["Array", "Boolean", "Date", "decodeURI",
+ "decodeURIComponent", "encodeURI", "encodeURIComponent",
+ "Error", "eval", "EvalError", "Function", "isFinite",
+ "isNaN", "JSON", "Math", "Number", "Object", "parseInt",
+ "parseFloat", "RangeError", "ReferenceError", "RegExp",
+ "String", "SyntaxError", "TypeError", "URIError",
+ "Map", "NaN", "Set", "WeakMap", "Infinity", "undefined"];
+
+ return {
+
+ "AssignmentExpression": function(node) {
+ if (nativeObjects.indexOf(node.left.name) >= 0) {
+ context.report(node, node.left.name + " is a read-only native object.");
+ }
+ },
+
+ "VariableDeclarator": function(node) {
+ if (nativeObjects.indexOf(node.id.name) >= 0) {
+ context.report(node, "Redefinition of '{{nativeObject}}'.", { nativeObject: node.id.name });
+ }
+ }
+ };
+
+};
+
+},{}],84:[function(require,module,exports){
+/**
+ * @fileoverview A rule to disallow negated left operands of the `in` operator
+ * @author Michael Ficarra
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "BinaryExpression": function(node) {
+ if (node.operator === "in" && node.left.type === "UnaryExpression" && node.left.operator === "!") {
+ context.report(node, "The `in` expression's left operand is negated");
+ }
+ }
+ };
+
+};
+
+},{}],85:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag nested ternary expressions
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "ConditionalExpression": function(node) {
+ if (node.alternate.type === "ConditionalExpression" ||
+ node.consequent.type === "ConditionalExpression") {
+ context.report(node, "Do not nest ternary expressions");
+ }
+ }
+ };
+};
+
+},{}],86:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when using new Function
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "NewExpression": function(node) {
+ if (node.callee.name === "Function") {
+ context.report(node, "The Function constructor is eval.");
+ }
+ }
+ };
+
+};
+
+},{}],87:[function(require,module,exports){
+/**
+ * @fileoverview A rule to disallow calls to the Object constructor
+ * @author Matt DuVall <http://www.mattduvall.com/>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "NewExpression": function(node) {
+ if (node.callee.name === "Object") {
+ context.report(node, "The object literal notation {} is preferrable.");
+ }
+ }
+ };
+
+};
+
+},{}],88:[function(require,module,exports){
+/**
+ * @fileoverview Rule to disallow use of new operator with the `require` function
+ * @author Wil Moore III
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "NewExpression": function(node) {
+ if (node.callee.type === "Identifier" && node.callee.name === "require") {
+ context.report(node, "Unexpected use of new with require.");
+ }
+ }
+ };
+
+};
+
+},{}],89:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when using constructor for wrapper objects
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "NewExpression": function(node) {
+ var wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"];
+ if (wrapperObjects.indexOf(node.callee.name) > -1) {
+ context.report(node, "Do not use {{fn}} as a constructor.", { fn: node.callee.name });
+ }
+ }
+ };
+
+};
+
+},{}],90:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag statements with function invocation preceded by
+ * "new" and not part of assignment
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "ExpressionStatement": function(node) {
+
+ if (node.expression.type === "NewExpression") {
+ context.report(node, "Do not use 'new' for side effects.");
+ }
+ }
+ };
+
+};
+
+},{}],91:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of an object property of the global object (Math and JSON) as a function
+ * @author James Allardice
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "CallExpression": function(node) {
+
+ if (node.callee.type === "Identifier") {
+ var name = node.callee.name;
+ if (name === "Math" || name === "JSON") {
+ context.report(node, "'{{name}}' is not a function.", { name: name });
+ }
+ }
+ }
+ };
+
+};
+
+},{}],92:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag octal escape sequences in string literals.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ if (typeof node.value !== "string") {
+ return;
+ }
+ var match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7])/),
+ octalDigit;
+
+ if (match) {
+ octalDigit = match[2];
+ context.report(node, "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.",
+ { octalDigit: octalDigit });
+ }
+ }
+
+ };
+
+};
+
+},{}],93:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when initializing octal literal
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ if (typeof node.value === "number" && /^0[0-7]/.test(node.raw)) {
+ context.report(node, "Octal literals should not be used.");
+ }
+ }
+ };
+
+};
+
+},{}],94:[function(require,module,exports){
+/**
+ * @fileoverview Disallow string concatenation when using __dirname and __filename
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var MATCHER = /^__(?:dir|file)name$/;
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "BinaryExpression": function(node) {
+
+ var left = node.left,
+ right = node.right;
+
+ if (node.operator === "+" &&
+ ((left.type === "Identifier" && MATCHER.test(left.name)) ||
+ (right.type === "Identifier" && MATCHER.test(right.name)))
+ ) {
+
+ context.report(node, "Use path.join() or path.resolve() instead of + to create paths.");
+ }
+ }
+
+ };
+
+};
+
+},{}],95:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of unary increment and decrement operators.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "UpdateExpression": function(node) {
+ context.report(node, "Unary operator '" + node.operator + "' used.");
+ }
+
+ };
+
+};
+
+},{}],96:[function(require,module,exports){
+/**
+ * @fileoverview Disallow the use of process.env()
+ * @author Vignesh Anand
+ * @copyright 2014 Vignesh Anand. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "MemberExpression": function(node) {
+ var objectName = node.object.name,
+ propertyName = node.property.name;
+
+ if (objectName === "process" && !node.computed && propertyName && propertyName === "env") {
+ context.report(node, "Unexpected use of process.env.");
+ }
+
+ }
+
+ };
+
+};
+
+},{}],97:[function(require,module,exports){
+/**
+ * @fileoverview Disallow the use of process.exit()
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "CallExpression": function(node) {
+ var callee = node.callee;
+
+ if (callee.type === "MemberExpression" && callee.object.name === "process" &&
+ callee.property.name === "exit"
+ ) {
+ context.report(node, "Don't use process.exit(); throw an error instead.");
+ }
+ }
+
+ };
+
+};
+
+},{}],98:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag usage of __proto__ property
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "MemberExpression": function(node) {
+
+ if (node.property &&
+ (node.property.type === "Identifier" && node.property.name === "__proto__" && !node.computed) ||
+ (node.property.type === "Literal" && node.property.value === "__proto__")) {
+ context.report(node, "The '__proto__' property is deprecated.");
+ }
+ }
+ };
+
+};
+
+},{}],99:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when the same variable is declared more then once.
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ function findVariables() {
+ var scope = context.getScope();
+
+ scope.variables.forEach(function(variable) {
+ if (variable.identifiers && variable.identifiers.length > 1) {
+ variable.identifiers.sort(function(a, b) {
+ return a.range[1] - b.range[1];
+ });
+
+ for (var i = 1, l = variable.identifiers.length; i < l; i++) {
+ context.report(variable.identifiers[i], "{{a}} is already defined", {a: variable.name});
+ }
+ }
+ });
+ }
+
+ return {
+ "Program": findVariables,
+ "FunctionExpression": findVariables,
+ "FunctionDeclaration": findVariables
+ };
+};
+
+},{}],100:[function(require,module,exports){
+/**
+ * @fileoverview Rule to count multiple spaces in regular expressions
+ * @author Matt DuVall <http://www.mattduvall.com/>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ var token = context.getFirstTokens(node, 1)[0],
+ nodeType = token.type,
+ nodeValue = token.value,
+ multipleSpacesRegex = /( {2,})+?/,
+ regexResults;
+
+ if (nodeType === "RegularExpression") {
+ regexResults = multipleSpacesRegex.exec(nodeValue);
+
+ if (regexResults !== null) {
+ context.report(node, "Spaces are hard to count. Use {" + regexResults[0].length + "}.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],101:[function(require,module,exports){
+/**
+ * @fileoverview Rule to disallow reserved words being used as keys
+ * @author Emil Bay
+ * @copyright 2014 Emil Bay. All rights reserved.
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var MESSAGE = "Reserved word '{{key}}' used as key.";
+
+ var reservedWords = [
+ "abstract",
+ "boolean", "break", "byte",
+ "case", "catch", "char", "class", "const", "continue",
+ "debugger", "default", "delete", "do", "double",
+ "else", "enum", "export", "extends",
+ "final", "finally", "float", "for", "function",
+ "goto",
+ "if", "implements", "import", "in", "instanceof", "int", "interface",
+ "long",
+ "native", "new",
+ "package", "private", "protected", "public",
+ "return",
+ "short", "static", "super", "switch", "synchronized",
+ "this", "throw", "throws", "transient", "try", "typeof",
+ "var", "void", "volatile",
+ "while", "with"
+ ];
+
+ return {
+
+ "ObjectExpression": function(node) {
+ node.properties.forEach(function(property) {
+
+ if (property.key.type === "Identifier") {
+ var keyName = property.key.name;
+
+ if (reservedWords.indexOf("" + keyName) !== -1) {
+ context.report(node, MESSAGE, { key: keyName });
+ }
+ }
+
+ });
+
+ }
+ };
+
+};
+
+},{}],102:[function(require,module,exports){
+/**
+ * @fileoverview Restrict usage of specified node modules.
+ * @author Christian Schulz
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function (context) {
+ // trim restricted module names
+ var restrictedModules = context.options;
+
+ // if no modules are restricted we don't need to check the CallExpressions
+ if (restrictedModules.length === 0) {
+ return {};
+ }
+
+ /**
+ * Function to check if a node is a string literal.
+ * @param {ASTNode} node The node to check.
+ * @returns {boolean} If the node is a string literal.
+ */
+ function isString(node) {
+ return node && node.type === "Literal" && typeof node.value === "string";
+ }
+
+ /**
+ * Function to check if a node is a require call.
+ * @param {ASTNode} node The node to check.
+ * @returns {boolean} If the node is a require call.
+ */
+ function isRequireCall(node) {
+ return node.callee.type === "Identifier" && node.callee.name === "require";
+ }
+
+ /**
+ * Function to check if a node has an argument that is an restricted module and return its name.
+ * @param {ASTNode} node The node to check
+ * @returns {undefined|String} restricted module name or undefined if node argument isn't restricted.
+ */
+ function getRestrictedModuleName(node) {
+ var moduleName;
+
+ // node has arguments and first argument is string
+ if (node.arguments.length && isString(node.arguments[0])) {
+ var argumentValue = node.arguments[0].value.trim();
+
+ // check if argument value is in restricted modules array
+ if (restrictedModules.indexOf(argumentValue) !== -1) {
+ moduleName = argumentValue;
+ }
+ }
+
+ return moduleName;
+ }
+
+ return {
+ "CallExpression": function (node) {
+ if (isRequireCall(node)) {
+ var restrictedModuleName = getRestrictedModuleName(node);
+
+ if (restrictedModuleName) {
+ context.report(node, "'{{moduleName}}' module is restricted from being used.", {
+ moduleName: restrictedModuleName
+ });
+ }
+ }
+ }
+ };
+};
+
+},{}],103:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when return statement contains assignment
+ * @author Ilya Volodin
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "ReturnStatement": function(node) {
+ if (node.argument && node.argument.type === "AssignmentExpression") {
+ context.report(node, "Return statement should not contain assignment.");
+ }
+ }
+ };
+
+};
+
+},{}],104:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when using javascript: urls
+ * @author Ilya Volodin
+ */
+/*jshint scripturl: true */
+/*eslint no-script-url: 0*/
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "Literal": function(node) {
+
+ var value;
+
+ if (node.value && typeof(node.value) === "string") {
+ value = node.value.toLowerCase();
+
+ if (value.indexOf("javascript:") === 0) {
+ context.report(node, "Script URL is a form of eval.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],105:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag comparison where left part is the same as the right
+ * part.
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ "use strict";
+
+ return {
+
+ "BinaryExpression": function(node) {
+ var operators = ["===", "==", "!==", "!=", ">", "<", ">=", "<="];
+ if (operators.indexOf(node.operator) > -1 &&
+ (node.left.type === "Identifier" && node.right.type === "Identifier" && node.left.name === node.right.name ||
+ node.left.type === "Literal" && node.right.type === "Literal" && node.left.value === node.right.value)) {
+ context.report(node, "Comparing to itself is potentially pointless.");
+ }
+ }
+ };
+
+};
+
+},{}],106:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of comma operator
+ * @author Brandon Mills
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ /**
+ * Parts of the grammar that are required to have parens.
+ */
+ var parenthesized = {
+ "DoWhileStatement": "test",
+ "IfStatement": "test",
+ "SwitchStatement": "discriminant",
+ "WhileStatement": "test",
+ "WithStatement": "object"
+
+ // Omitting CallExpression - commas are parsed as argument separators
+ // Omitting NewExpression - commas are parsed as argument separators
+ // Omitting ForInStatement - parts aren't individually parenthesised
+ // Omitting ForStatement - parts aren't individually parenthesised
+ };
+
+ /**
+ * Determines whether a node is required by the grammar to be wrapped in
+ * parens, e.g. the test of an if statement.
+ * @param {ASTNode} node - The AST node
+ * @returns {boolean} True if parens around node belong to parent node.
+ */
+ function requiresExtraParens(node) {
+ return node.parent && parenthesized[node.parent.type] != null &&
+ node === node.parent[parenthesized[node.parent.type]];
+ }
+
+ /**
+ * Check if a node is wrapped in parens.
+ * @param {ASTNode} node - The AST node
+ * @returns {boolean} True if the node has a paren on each side.
+ */
+ function isParenthesised(node) {
+ var previousToken = context.getTokenBefore(node),
+ nextToken = context.getTokenAfter(node);
+
+ return previousToken && nextToken &&
+ previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
+ nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+ }
+
+ /**
+ * Check if a node is wrapped in two levels of parens.
+ * @param {ASTNode} node - The AST node
+ * @returns {boolean} True if two parens surround the node on each side.
+ */
+ function isParenthesisedTwice(node) {
+ var previousToken = context.getTokenBefore(node, 1),
+ nextToken = context.getTokenAfter(node, 1);
+
+ return isParenthesised(node) && previousToken && nextToken &&
+ previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
+ nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+ }
+
+ return {
+ "SequenceExpression": function(node) {
+ // Always allow sequences in for statement update
+ if (node.parent.type === "ForStatement" &&
+ (node === node.parent.init || node === node.parent.update)) {
+ return;
+ }
+
+ // Wrapping a sequence in extra parens indicates intent
+ if (requiresExtraParens(node)) {
+ if (isParenthesisedTwice(node)) {
+ return;
+ }
+ } else {
+ if (isParenthesised(node)) {
+ return;
+ }
+ }
+
+ context.report(node, "Unexpected use of comma operator.");
+ }
+ };
+
+};
+
+},{}],107:[function(require,module,exports){
+/**
+ * @fileoverview Disallow shadowing of NaN, undefined, and Infinity (ES5 section 15.1.1)
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"];
+
+ function checkForViolation(id) {
+ if (RESTRICTED.indexOf(id.name) > -1) {
+ context.report(id, "Shadowing of global property \"" + id.name + "\".");
+ }
+ }
+
+ return {
+ "VariableDeclarator": function(node) {
+ checkForViolation(node.id);
+ },
+ "FunctionExpression": function(node) {
+ if (node.id) {
+ checkForViolation(node.id);
+ }
+ [].map.call(node.params, checkForViolation);
+ },
+ "FunctionDeclaration": function(node) {
+ checkForViolation(node.id);
+ [].map.call(node.params, checkForViolation);
+ },
+ "CatchClause": function(node) {
+ checkForViolation(node.param);
+ }
+ };
+
+};
+
+},{}],108:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag on declaring variables already declared in the outer scope
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ /**
+ * Checks if a variable is contained in the list of given scope variables.
+ * @param {Object} variable The variable to check.
+ * @param {Array} scopeVars The scope variables to look for.
+ * @returns {boolean} Whether or not the variable is contains in the list of scope variables.
+ */
+ function isContainedInScopeVars(variable, scopeVars) {
+ return scopeVars.some(function (scopeVar) {
+ if (scopeVar.identifiers.length > 0) {
+ return variable.name === scopeVar.name;
+ }
+ return false;
+ });
+ }
+
+ /**
+ * Checks if the given variables are shadowed in the given scope.
+ * @param {Array} variables The variables to look for
+ * @param {Object} scope The scope to be checked.
+ * @returns {void}
+ */
+ function checkShadowsInScope(variables, scope) {
+ variables.forEach(function (variable) {
+ if (isContainedInScopeVars(variable, scope.variables)) {
+ context.report(variable.identifiers[0], "{{a}} is already declared in the upper scope.", {a: variable.name});
+ }
+ });
+ }
+
+ /**
+ * Filters all variables of a list which already occur in another list.
+ * @param {Array} variableListA List of variables which should be filtered.
+ * @param {Array} variableListB List of variables which should no occur in variableListA.
+ * @returns {Array} Filtered list of variables.
+ */
+ function filterVariableList(variableListA, variableListB) {
+ return variableListA.filter(function (variableA) {
+ return !variableListB.some(function (variableB) {
+ return variableA.name === variableB.name;
+ });
+ });
+ }
+
+ /**
+ * Checks the given node for shadowed variables.
+ * @param {ASTNode} node The AST node of a FunctionDeclaration or FunctionExpression.
+ * @returns {void}
+ */
+ function checkForShadows(node) {
+ var scope = context.getScope(),
+ args = node.params,
+ variables = filterVariableList(scope.variables, args);
+
+ // iterate through the array of variables and find duplicates with the upper scope
+ var upper = scope.upper;
+ while (upper) {
+ checkShadowsInScope(variables, upper);
+ upper = upper.upper;
+ }
+ }
+
+ return {
+ "FunctionDeclaration": checkForShadows,
+ "FunctionExpression": checkForShadows
+ };
+
+};
+
+},{}],109:[function(require,module,exports){
+/**
+ * @fileoverview Rule to require variables declared without whitespace before the lines semicolon
+ * @author Jonathan Kingston
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var semicolonWhitespace = /\s;$/;
+
+ return {
+ "VariableDeclaration": function(node) {
+ var source = context.getSource(node);
+ if (semicolonWhitespace.test(source)) {
+ context.report(node, "Variable declared with trailing whitespace before semicolon");
+ }
+ },
+ "ExpressionStatement": function(node) {
+ var source = context.getSource(node);
+ if (semicolonWhitespace.test(source)) {
+ context.report(node, "Expression called with trailing whitespace before semicolon");
+ }
+ }
+ };
+};
+
+},{}],110:[function(require,module,exports){
+/**
+ * @fileoverview Rule to check that spaced function application
+ * @author Matt DuVall <http://www.mattduvall.com>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ function detectOpenSpaces(node) {
+ var lastCalleeToken = context.getLastToken(node.callee);
+ var tokens = context.getTokens(node);
+ var i = tokens.indexOf(lastCalleeToken), l = tokens.length;
+ while (i < l && tokens[i].value !== "(") {
+ ++i;
+ }
+ if (i >= l) {
+ return;
+ }
+ // look for a space between the callee and the open paren
+ if (tokens[i - 1].range[1] !== tokens[i].range[0]) {
+ context.report(node, "Unexpected space between function name and paren.");
+ }
+ }
+
+ return {
+ "CallExpression": detectOpenSpaces,
+ "NewExpression": detectOpenSpaces
+ };
+
+};
+
+},{}],111:[function(require,module,exports){
+/**
+ * @fileoverview Disallow sparse arrays
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "ArrayExpression": function(node) {
+
+ var emptySpot = node.elements.indexOf(null) > -1;
+
+ if (emptySpot) {
+ context.report(node, "Unexpected comma in middle of array.");
+ }
+ }
+
+ };
+
+};
+
+},{}],112:[function(require,module,exports){
+/**
+ * @fileoverview Rule to check for properties whose identifier ends with the string Sync
+ * @author Matt DuVall<http://mattduvall.com/>
+ */
+
+/*jshint node:true*/
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "MemberExpression": function(node) {
+ var propertyName = node.property.name,
+ syncRegex = /.*Sync$/;
+
+ if (syncRegex.exec(propertyName) !== null) {
+ context.report(node, "Unexpected sync method: '" + propertyName + "'.");
+ }
+ }
+ };
+
+};
+
+},{}],113:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of ternary operators.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "ConditionalExpression": function(node) {
+ context.report(node, "Ternary operator used.");
+ }
+
+ };
+
+};
+
+},{}],114:[function(require,module,exports){
+/**
+ * @fileoverview Disallow trailing spaces at the end of lines.
+ * @author Nodeca Team <https://github.com/nodeca>
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var TRAILER = "[ \t\u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]+$";
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "Program": function checkTrailingSpaces(node) {
+
+ // Let's hack. Since Esprima does not return whitespace nodes,
+ // fetch the source code and do black magic via regexps.
+
+ var src = context.getSource(),
+ re = new RegExp(TRAILER, "mg"),
+ match, lines, location;
+
+ while ((match = re.exec(src)) !== null) {
+ lines = src.slice(0, re.lastIndex).split(/\r?\n/g);
+
+ location = {
+ line: lines.length,
+ column: lines[lines.length - 1].length - match[0].length + 1
+ };
+
+ // Passing node is a bit dirty, because message data will contain
+ // big text in `source`. But... who cares :) ?
+ // One more kludge will not make worse the bloody wizardry of this plugin.
+ context.report(node, location, "Trailing spaces not allowed.");
+ }
+ }
+
+ };
+};
+
+},{}],115:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when initializing to undefined
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "VariableDeclarator": function(node) {
+ var name = node.id.name;
+ var init = node.init && node.init.name;
+
+ if (init === "undefined") {
+ context.report(node, "It's not necessary to initialize '{{name}}' to undefined.", { name: name });
+ }
+ }
+ };
+
+};
+
+},{}],116:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag references to undeclared variables.
+ * @author Mark Macdonald
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+function isImplicitGlobal(variable) {
+ return variable.defs.every(function(def) {
+ return def.type === "ImplicitGlobalVariable";
+ });
+}
+
+/**
+ * Gets the declared variable, defined in `scope`, that `ref` refers to.
+ * @param {Scope} scope The scope in which to search.
+ * @param {Reference} ref The reference to find in the scope.
+ * @returns {Variable} The variable, or null if ref refers to an undeclared variable.
+ */
+function getDeclaredGlobalVariable(scope, ref) {
+ var declaredGlobal = null;
+ scope.variables.some(function(variable) {
+ if (variable.name === ref.identifier.name) {
+ // If it's an implicit global, it must have a `writeable` field (indicating it was declared)
+ if (!isImplicitGlobal(variable) || {}.hasOwnProperty.call(variable, "writeable")) {
+ declaredGlobal = variable;
+ return true;
+ }
+ }
+ return false;
+ });
+ return declaredGlobal;
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "Program": function(/*node*/) {
+
+ var globalScope = context.getScope();
+
+ globalScope.through.forEach(function(ref) {
+ var variable = getDeclaredGlobalVariable(globalScope, ref),
+ name = ref.identifier.name;
+ if (!variable) {
+ context.report(ref.identifier, "'{{name}}' is not defined.", { name: name });
+ } else if (ref.isWrite() && variable.writeable === false) {
+ context.report(ref.identifier, "'{{name}}' is read only.", { name: name });
+ }
+ });
+ }
+ };
+
+};
+
+},{}],117:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag references to the undefined variable.
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ return {
+
+ "Identifier": function(node) {
+ if (node.name === "undefined") {
+ var parent = context.getAncestors().pop();
+ if (!parent || parent.type !== "MemberExpression" || node !== parent.property || parent.computed) {
+ context.report(node, "Unexpected use of undefined.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],118:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag trailing underscores in variable declarations.
+ * @author Matt DuVall <http://www.mattduvall.com>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //-------------------------------------------------------------------------
+ // Helpers
+ //-------------------------------------------------------------------------
+
+ function hasTrailingUnderscore(identifier) {
+ var len = identifier.length;
+
+ return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
+ }
+
+ function isSpecialCaseIdentifierForMemberExpression(identifier) {
+ return identifier === "__proto__";
+ }
+
+ function isSpecialCaseIdentifierInVariableExpression(identifier) {
+ // Checks for the underscore library usage here
+ return identifier === "_";
+ }
+
+ function checkForTrailingUnderscoreInFunctionDeclaration(node) {
+ var identifier = node.id.name;
+
+ if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier)) {
+ context.report(node, "Unexpected dangling '_' in '" + identifier + "'.");
+ }
+ }
+
+ function checkForTrailingUnderscoreInVariableExpression(node) {
+ var identifier = node.id.name;
+
+ if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
+ !isSpecialCaseIdentifierInVariableExpression(identifier)) {
+ context.report(node, "Unexpected dangling '_' in '" + identifier + "'.");
+ }
+ }
+
+ function checkForTrailingUnderscoreInMemberExpression(node) {
+ var identifier = node.property.name;
+
+ if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
+ !isSpecialCaseIdentifierForMemberExpression(identifier)) {
+ context.report(node, "Unexpected dangling '_' in '" + identifier + "'.");
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "FunctionDeclaration": checkForTrailingUnderscoreInFunctionDeclaration,
+ "VariableDeclarator": checkForTrailingUnderscoreInVariableExpression,
+ "MemberExpression": checkForTrailingUnderscoreInMemberExpression
+ };
+
+};
+
+},{}],119:[function(require,module,exports){
+/**
+ * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
+ * @author Joel Feenstra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+
+function report(context, node, unreachableType) {
+ var keyword;
+ switch (unreachableType) {
+ case "BreakStatement":
+ keyword = "break";
+ break;
+ case "ContinueStatement":
+ keyword = "continue";
+ break;
+ case "ReturnStatement":
+ keyword = "return";
+ break;
+ case "ThrowStatement":
+ keyword = "throw";
+ break;
+ default:
+ return;
+ }
+ context.report(node, "Found unexpected statement after a {{type}}.", { type: keyword });
+}
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ /**
+ * Checks if a node is an exception for no-unreachable because of variable/function hoisting
+ * @param {ASTNode} node The AST node to check.
+ * @returns {boolean} if the node doesn't trigger unreachable
+ * @private
+ */
+ function isUnreachableAllowed(node) {
+ return node.type === "FunctionDeclaration" ||
+ node.type === "VariableDeclaration" &&
+ node.declarations.every(function(declaration) {
+ return declaration.type === "VariableDeclarator" && declaration.init === null;
+ });
+ }
+
+ /*
+ * Verifies that the given node is the last node or followed exclusively by
+ * hoisted declarations
+ * @param {ASTNode} node Node that should be the last node
+ * @returns {void}
+ * @private
+ */
+ function checkNode(node) {
+ var parent = context.getAncestors().pop();
+ var field, i, sibling;
+
+ switch (parent.type) {
+ case "SwitchCase":
+ field = "consequent";
+ break;
+ case "Program":
+ case "BlockStatement":
+ field = "body";
+ break;
+ default:
+ return;
+ }
+
+ for (i = parent[field].length - 1; i >= 0; i--) {
+ sibling = parent[field][i];
+ if (sibling === node) {
+ return; // Found the last reachable statement, all done
+ }
+
+ if (!isUnreachableAllowed(sibling)) {
+ report(context, sibling, node.type);
+ }
+ }
+ }
+
+ return {
+ "ReturnStatement": checkNode,
+ "ThrowStatement": checkNode,
+ "ContinueStatement": checkNode,
+ "BreakStatement": checkNode
+ };
+
+};
+
+},{}],120:[function(require,module,exports){
+/**
+ * @fileoverview Flag expressions in statement position that do not side effect
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ /**
+ * @param {ASTNode} node - any node
+ * @returns {Boolean} whether the given node structurally represents a directive
+ */
+ function looksLikeDirective(node) {
+ return node.type === "ExpressionStatement" &&
+ node.expression.type === "Literal" && typeof node.expression.value === "string";
+ }
+
+ /**
+ * @param {Function} predicate - ([a] -> Boolean) the function used to make the determination
+ * @param {a[]} list - the input list
+ * @returns {a[]} the leading sequence of members in the given list that pass the given predicate
+ */
+ function takeWhile(predicate, list) {
+ for (var i = 0, l = list.length; i < l; ++i) {
+ if (!predicate(list[i])) {
+ break;
+ }
+ }
+ return [].slice.call(list, 0, i);
+ }
+
+ /**
+ * @param {ASTNode} node - a Program or BlockStatement node
+ * @returns {ASTNode[]} the leading sequence of directive nodes in the given node's body
+ */
+ function directives(node) {
+ return takeWhile(looksLikeDirective, node.body);
+ }
+
+ /**
+ * @param {ASTNode} node - any node
+ * @param {ASTNode[]} ancestors - the given node's ancestors
+ * @returns {Boolean} whether the given node is considered a directive in its current position
+ */
+ function isDirective(node, ancestors) {
+ var parent = ancestors[ancestors.length - 1],
+ grandparent = ancestors[ancestors.length - 2];
+ return (parent.type === "Program" || parent.type === "BlockStatement" && (grandparent.type === "FunctionExpression" || grandparent.type === "FunctionDeclaration")) &&
+ directives(parent).indexOf(node) >= 0;
+ }
+
+ return {
+ "ExpressionStatement": function(node) {
+
+ var type = node.expression.type,
+ ancestors = context.getAncestors();
+
+ if (
+ !/^(?:Assignment|Call|New|Update)Expression$/.test(type) &&
+ (type !== "UnaryExpression" || ["delete", "void"].indexOf(node.expression.operator) < 0) &&
+ !isDirective(node, ancestors)
+ ) {
+ context.report(node, "Expected an assignment or function call and instead saw an expression.");
+ }
+ }
+ };
+
+};
+
+},{}],121:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag declared but unused variables
+ * @author Ilya Volodin
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var config = {
+ vars: "all",
+ args: "after-used"
+ };
+
+ if (context.options[0]) {
+ if (typeof(context.options[0]) === "string") {
+ config.vars = context.options[0];
+ } else {
+ config.vars = context.options[0].vars || config.vars;
+ config.args = context.options[0].args || config.args;
+ }
+ }
+
+ var MESSAGE = "{{name}} is defined but never used";
+
+ /**
+ * @param {Reference} ref - an escope Reference
+ * @returns {Boolean} whether the given reference represents a read operation
+ */
+ function isReadRef(ref) {
+ return ref.isRead();
+ }
+
+ /**
+ * @param {Scope} scope - an escope Scope object
+ * @returns {Variable[]} most of the local variables with no read references
+ */
+ function unusedLocals(scope) {
+ var unused = [];
+ var variables = scope.variables;
+ if (scope.type !== "global") {
+ for (var i = 0, l = variables.length; i < l; ++i) {
+ // skip function expression names
+ if (scope.functionExpressionScope) {
+ continue;
+ }
+ // skip implicit "arguments" variable
+ if (scope.type === "function" && variables[i].name === "arguments" && variables[i].identifiers.length === 0) {
+ continue;
+ }
+ var type = variables[i].defs[0].type;
+ // skip catch variables
+ if (type === "CatchClause") {
+ continue;
+ }
+ // if "args" option is "none", skip any parameter
+ if (config.args === "none" && type === "Parameter") {
+ continue;
+ }
+ // if "args" option is "after-used", skip all but the last parameter
+ if (config.args === "after-used" && type === "Parameter" && variables[i].defs[0].index < variables[i].defs[0].node.params.length - 1) {
+ continue;
+ }
+ if (variables[i].references.filter(isReadRef).length === 0) {
+ unused.push(variables[i]);
+ }
+ }
+ }
+ return [].concat.apply(unused, [].map.call(scope.childScopes, unusedLocals));
+ }
+
+ return {
+ "Program": function(programNode) {
+ var globalScope = context.getScope();
+ var unused = unusedLocals(globalScope);
+ var i, l;
+
+ // determine unused globals
+ if (config.vars === "all") {
+ var unresolvedRefs = globalScope.through.filter(isReadRef).map(function(ref) {
+ return ref.identifier.name;
+ });
+ for (i = 0, l = globalScope.variables.length; i < l; ++i) {
+ if (unresolvedRefs.indexOf(globalScope.variables[i].name) < 0) {
+ unused.push(globalScope.variables[i]);
+ }
+ }
+ }
+
+ for (i = 0, l = unused.length; i < l; ++i) {
+ if (unused[i].eslintExplicitGlobal) {
+ context.report(programNode, MESSAGE, unused[i]);
+ } else if (unused[i].defs.length > 0) {
+ context.report(unused[i].identifiers[0], MESSAGE, unused[i]);
+ }
+ }
+ }
+ };
+
+};
+
+},{}],122:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of variables before they are defined
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+var NO_FUNC = "nofunc";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ function findDeclaration(name, scope) {
+ // try searching in the current scope first
+ for (var i = 0, l = scope.variables.length; i < l; i++) {
+ if (scope.variables[i].name === name) {
+ return scope.variables[i];
+ }
+ }
+ // check if there's upper scope and call recursivly till we find the variable
+ if (scope.upper) {
+ return findDeclaration(name, scope.upper);
+ }
+ }
+
+ function findVariables() {
+ var scope = context.getScope();
+ var typeOption = context.options[0];
+
+ function checkLocationAndReport(reference, declaration) {
+ if (typeOption !== NO_FUNC || declaration.defs[0].type !== "FunctionName") {
+ if (declaration.identifiers[0].range[1] > reference.identifier.range[1]) {
+ context.report(reference.identifier, "{{a}} was used before it was defined", {a: reference.identifier.name});
+ }
+ }
+ }
+
+ scope.references.forEach(function(reference) {
+ // if the reference is resolved check for declaration location
+ // if not, it could be function invocation, try to find manually
+ if (reference.resolved && reference.resolved.identifiers.length > 0) {
+ checkLocationAndReport(reference, reference.resolved);
+ } else {
+ var declaration = findDeclaration(reference.identifier.name, scope);
+ // if there're no identifiers, this is a global environment variable
+ if (declaration && declaration.identifiers.length !== 0) {
+ checkLocationAndReport(reference, declaration);
+ }
+ }
+ });
+ }
+
+ return {
+ "Program": findVariables,
+ "FunctionExpression": findVariables,
+ "FunctionDeclaration": findVariables
+ };
+};
+
+},{}],123:[function(require,module,exports){
+/**
+ * @fileoverview Rule to disallow use of void operator.
+ * @author Mike Sidorov
+ * @copyright 2014 Mike Sidorov. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "UnaryExpression": function(node) {
+ if (node.operator === "void") {
+ context.report(node, "Expected 'undefined' and instead saw 'void'.");
+ }
+ }
+ };
+
+};
+
+},{}],124:[function(require,module,exports){
+/**
+ * @fileoverview Rule that warns about used warning comments
+ * @author Alexander Schmidt <https://github.com/lxanders>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function (context) {
+ "use strict";
+
+ var configuration = context.options[0] || {},
+ warningTerms = configuration.terms || ["todo", "fixme", "xxx"],
+ location = configuration.location || "start";
+
+ /**
+ * Prepares a specified comment for being checked.
+ * @param {String} comment The comment to prepare.
+ * @returns {String} The specified comment prepared for being checked.
+ */
+ function prepareCommentForChecking(comment) {
+ var commentToCheck;
+
+ commentToCheck = comment.toLowerCase();
+ commentToCheck = commentToCheck.trim();
+
+ return commentToCheck;
+ }
+
+ /**
+ * Checks if the specified comment starts with a specified term.
+ * @param {String} commentToCheck The comment to check.
+ * @param {String} lowerCaseTerm The term to search for.
+ * @returns {Boolean} True if the comment started with the specified term, else false.
+ */
+ function commentStartsWithTerm(commentToCheck, lowerCaseTerm) {
+ return commentToCheck.indexOf(lowerCaseTerm) === 0;
+ }
+
+ /**
+ * Checks if the specified comment contains a specified term at any location.
+ * @param {String} commentToCheck The comment to check.
+ * @param {String} lowerCaseTerm The term to search for.
+ * @returns {Boolean} True if the term was contained in the comment, else false.
+ */
+ function commentContainsTerm(commentToCheck, lowerCaseTerm) {
+ return commentToCheck.indexOf(lowerCaseTerm) !== -1;
+ }
+
+
+ /**
+ * Checks the specified comment for matches of the configured warning terms and returns the matches.
+ * @param {String} comment The comment which is checked.
+ * @returns {Array} All matched warning terms for this comment.
+ */
+ function commentContainsWarningTerm(comment) {
+ var matches = [];
+
+ warningTerms.forEach(function (term) {
+ var lowerCaseTerm = term.toLowerCase(),
+ commentToCheck = prepareCommentForChecking(comment);
+
+ if (location === "start") {
+ if (commentStartsWithTerm(commentToCheck, lowerCaseTerm)) {
+ matches.push(term);
+ }
+ } else if (location === "anywhere") {
+ if (commentContainsTerm(commentToCheck, lowerCaseTerm)) {
+ matches.push(term);
+ }
+ }
+ });
+
+ return matches;
+ }
+
+ /**
+ * Checks the specified node for matching warning comments and reports them.
+ * @param {ASTNode} node The AST node being checked.
+ * @returns {void} undefined.
+ */
+ function checkComment(node) {
+ var matches = commentContainsWarningTerm(node.value);
+
+ matches.forEach(function (matchedTerm) {
+ context.report(node, "Unexpected " + matchedTerm + " comment.");
+ });
+ }
+
+ return {
+ "BlockComment": checkComment,
+ "LineComment": checkComment
+ };
+};
+
+},{}],125:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of with statement
+ * @author Nicholas C. Zakas
+ */
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "WithStatement": function(node) {
+ context.report(node, "Unexpected use of 'with' statement.");
+ }
+ };
+
+};
+
+},{}],126:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag wrapping none-iffe in parens
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "FunctionExpression": function(node) {
+ var ancestors = context.getAncestors(),
+ previousToken, nextToken;
+
+ if (!/CallExpression|NewExpression/.test(ancestors.pop().type)) {
+ previousToken = context.getTokenBefore(node);
+ nextToken = context.getTokenAfter(node);
+ if (previousToken.value === "(" && nextToken.value === ")") {
+ context.report(node, "Wrapping non-IIFE function literals in parens is unnecessary.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],127:[function(require,module,exports){
+/**
+ * @fileoverview A rule to ensure the use of a single variable declaration.
+ * @author Ian Christian Myers
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ var functionStack = [];
+
+ function startFunction() {
+ functionStack.push(false);
+ }
+
+ function endFunction() {
+ functionStack.pop();
+ }
+
+ function checkDeclarations(node) {
+ if (functionStack[functionStack.length - 1]) {
+ context.report(node, "Combine this with the previous 'var' statement.");
+ } else {
+ functionStack[functionStack.length - 1] = true;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "Program": startFunction,
+ "FunctionDeclaration": startFunction,
+ "FunctionExpression": startFunction,
+
+ "VariableDeclaration": checkDeclarations,
+
+ "Program:exit": endFunction,
+ "FunctionDeclaration:exit": endFunction,
+ "FunctionExpression:exit": endFunction
+ };
+
+};
+
+},{}],128:[function(require,module,exports){
+/**
+ * @fileoverview A rule to ensure blank lines within blocks.
+ * @author Mathias Schreck <https://github.com/lo1tuma>
+ * @copyright 2014 Mathias Schreck. All rights reserved.
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function (context) {
+ var requirePadding = context.options[0] !== "never";
+
+ /**
+ * Checks if the given non empty block node has a blank line before its first child node.
+ * @param {ASTNode} node The AST node of a BlockStatement.
+ * @returns {boolean} Whether or not the block starts with a blank line.
+ */
+ function isNonEmptyBlockTopPadded(node) {
+ var blockStart = node.loc.start.line,
+ first = node.body[0],
+ firstLine = first.loc.start.line,
+ expectedFirstLine = blockStart + 2,
+ leadingComments = context.getComments(first).leading;
+
+ if (leadingComments.length > 0) {
+ firstLine = leadingComments[0].loc.start.line;
+ }
+
+ return expectedFirstLine <= firstLine;
+ }
+
+ /**
+ * Checks if the given non empty block node has a blank line after its last child node.
+ * @param {ASTNode} node The AST node of a BlockStatement.
+ * @returns {boolean} Whether or not the block ends with a blank line.
+ */
+ function isNonEmptyBlockBottomPadded(node) {
+ var blockEnd = node.loc.end.line,
+ last = node.body[node.body.length - 1],
+ lastLine = last.loc.end.line,
+ expectedLastLine = blockEnd - 2,
+ trailingComments = context.getComments(last).trailing;
+
+ if (trailingComments.length > 0) {
+ lastLine = trailingComments[trailingComments.length - 1].loc.end.line;
+ }
+
+ return lastLine <= expectedLastLine;
+ }
+
+ /**
+ * Checks if the given non empty block node starts AND ends with a blank line.
+ * @param {ASTNode} node The AST node of a BlockStatement.
+ * @returns {boolean} Whether or not the block starts and ends with a blank line.
+ */
+ function isNonEmptyBlockPadded(node) {
+ return isNonEmptyBlockTopPadded(node) && isNonEmptyBlockBottomPadded(node);
+ }
+
+ /**
+ * Checks if the given non empty block node starts OR ends with a blank line.
+ * @param {ASTNode} node The AST node of a BlockStatement.
+ * @returns {boolean} Whether or not the block starts and ends with a blank line.
+ */
+ function hasNonEmptyBlockExtraPadding(node) {
+ return isNonEmptyBlockTopPadded(node) || isNonEmptyBlockBottomPadded(node);
+ }
+
+ /**
+ * Checks the given BlockStatement node to be padded if the block is not empty.
+ * @param {ASTNode} node The AST node of a BlockStatement.
+ * @returns {void} undefined.
+ */
+ function checkPadding(node) {
+ if (node.body.length > 0) {
+ if (requirePadding) {
+ if (!isNonEmptyBlockPadded(node)) {
+ context.report(node, "Block must be padded by blank lines.");
+ }
+ } else {
+ if (hasNonEmptyBlockExtraPadding(node)) {
+ context.report(node, "Block must not be padded by blank lines.");
+ }
+ }
+ }
+ }
+
+ return {
+ "BlockStatement": checkPadding
+ };
+
+};
+
+},{}],129:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag non-quoted property names in object literals.
+ * @author Mathias Bynens <http://mathiasbynens.be/>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+var esprima = require("esprima");
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var MODE = context.options[0];
+
+ switch (MODE) {
+
+ case "as-needed":
+ return {
+ Property: function(node) {
+ var key = node.key;
+ // Ensure that any quoted property names required quoting
+ if (key.type === "Literal" && typeof key.value === "string") {
+ try {
+ var tokens = esprima.tokenize(key.value);
+ if (tokens.length !== 1) {
+ return;
+ }
+ var t = tokens[0];
+ } catch(e) {
+ return;
+ }
+ if (t.type === "Identifier" || t.type === "Null" || t.type === "Boolean" || t.type === "Numeric" && "" + +t.value === t.value) {
+ context.report(node, "Unnecessarily quoted property `{{name}}` found.", key);
+ }
+ }
+ }
+ };
+
+ default:
+ return {
+ Property: function(node) {
+ var key = node.key;
+ // Ensure all property names are quoted
+ if (key.type !== "Literal" || typeof key.value !== "string") {
+ context.report(node, "Unquoted property `{{name}}` found.", key);
+ }
+ }
+ };
+
+ }
+
+};
+
+},{"esprima":6}],130:[function(require,module,exports){
+/**
+ * @fileoverview A rule to choose between single and double quote marks
+ * @author Matt DuVall <http://www.mattduvall.com/>, Brandon Payton
+ */
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+var QUOTE_SETTINGS = {
+ "double": {
+ quote: "\"",
+ alternateQuote: "'",
+ description: "doublequote"
+ },
+ "single": {
+ quote: "'",
+ alternateQuote: "\"",
+ description: "singlequote"
+ }
+};
+
+var AVOID_ESCAPE = "avoid-escape";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ /**
+ * Validate that a string passed in is surrounded by the specified character
+ * @param {string} val The text to check.
+ * @param {string} character The character to see if it's surrounded by.
+ * @returns {boolean} True if the text is surrounded by the character, false if not.
+ */
+ function isSurroundedBy(val, character) {
+ return val[0] === character && val[val.length - 1] === character;
+ }
+
+ return {
+
+ "Literal": function(node) {
+ var val = node.value,
+ rawVal = node.raw,
+ quoteOption = context.options[0],
+ settings = QUOTE_SETTINGS[quoteOption],
+ avoidEscape = context.options[1] === AVOID_ESCAPE,
+ isValid;
+
+ if (settings && typeof val === "string") {
+ isValid = isSurroundedBy(rawVal, settings.quote);
+
+ if (!isValid && avoidEscape) {
+ isValid = isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.indexOf(settings.quote) >= 0;
+ }
+
+ if (!isValid) {
+ context.report(node, "Strings must use " + settings.description + ".");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],131:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag use of parseInt without a radix argument
+ * @author James Allardice
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "CallExpression": function(node) {
+
+ var radix;
+
+ if (node.callee.name === "parseInt") {
+
+ if (node.arguments.length < 2) {
+ context.report(node, "Missing radix parameter.");
+ } else {
+
+ radix = node.arguments[1];
+
+ // don't allow non-numeric literals or undefined
+ if ((radix.type === "Literal" && typeof radix.value !== "number") ||
+ (radix.type === "Identifier" && radix.name === "undefined")
+ ) {
+ context.report(node, "Invalid radix parameter.");
+ }
+ }
+
+ }
+ }
+ };
+
+};
+
+},{}],132:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag missing semicolons.
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+module.exports = function(context) {
+
+ var OPT_OUT_PATTERN = /[\[\(\/\+\-]/;
+
+ var always = context.options[0] !== "never";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks a node to see if it's followed by a semicolon.
+ * @param {ASTNode} node The node to check.
+ * @returns {void}
+ */
+ function checkForSemicolon(node) {
+ var lastToken = context.getLastToken(node),
+ nextToken = context.getTokenAfter(node);
+
+ if (always) {
+ if (lastToken.type !== "Punctuator" || lastToken.value !== ";") {
+ context.report(node, lastToken.loc.end, "Missing semicolon.");
+ }
+ } else {
+ if (lastToken.type === "Punctuator" && lastToken.value === ";") {
+
+ if (!nextToken || !(OPT_OUT_PATTERN.test(nextToken.value))) {
+ context.report(node, node.loc.end, "Extra semicolon.");
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Checks to see if there's a semicolon after a variable declaration.
+ * @param {ASTNode} node The node to check.
+ * @returns {void}
+ */
+ function checkForSemicolonForVariableDeclaration(node) {
+
+ var ancestors = context.getAncestors(),
+ parentIndex = ancestors.length - 1,
+ parent = ancestors[parentIndex];
+
+ if ((parent.type !== "ForStatement" || parent.init !== node) &&
+ (parent.type !== "ForInStatement" || parent.left !== node)
+ ) {
+ checkForSemicolon(node);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "VariableDeclaration": checkForSemicolonForVariableDeclaration,
+ "ExpressionStatement": checkForSemicolon,
+ "ReturnStatement": checkForSemicolon,
+ "DebuggerStatement": checkForSemicolon,
+ "BreakStatement": checkForSemicolon,
+ "ContinueStatement": checkForSemicolon,
+ "EmptyStatement": function (node) {
+ var nextToken;
+
+ if (!always) {
+ nextToken = context.getTokenAfter(node) || context.getLastToken(node);
+
+ if (!(OPT_OUT_PATTERN.test(nextToken.value))) {
+ context.report(node, "Extra semicolon.");
+ }
+ }
+
+
+ }
+ };
+
+};
+
+},{}],133:[function(require,module,exports){
+/**
+ * @fileoverview Rule to require sorting of variables within a single Variable Declaration block
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ var configuration = context.options[0] || {},
+ ignoreCase = configuration.ignoreCase || false;
+
+ return {
+ "VariableDeclaration": function(node) {
+ node.declarations.reduce(function(memo, decl) {
+ var lastVariableName = memo.id.name,
+ currenVariableName = decl.id.name;
+
+ if (ignoreCase) {
+ lastVariableName = lastVariableName.toLowerCase();
+ currenVariableName = currenVariableName.toLowerCase();
+ }
+
+ if (currenVariableName < lastVariableName) {
+ context.report(decl, "Variables within the same declaration block should be sorted alphabetically");
+ return memo;
+ } else {
+ return decl;
+ }
+ }, node.declarations[0]);
+ }
+ };
+};
+
+},{}],134:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce the number of spaces after certain keywords
+ * @author Nick Fisher
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ // unless the first option is `"never"`, then a space is required
+ var requiresSpace = context.options[0] !== "never",
+ config = context.options[1] || { checkFunctionKeyword: false };
+
+ /**
+ * Check if the separation of two adjacent tokens meets the spacing rules, and report a problem if not.
+ *
+ * @param {ASTNode} node The node to which the potential problem belongs.
+ * @param {Token} left The first token.
+ * @param {Token} right The second token
+ * @returns {void}
+ */
+ function checkTokens(node, left, right) {
+ var hasSpace = left.range[1] < right.range[0],
+ value = left.value;
+
+ if (hasSpace !== requiresSpace) {
+ context.report(node, "Keyword \"{{value}}\" must {{not}}be followed by whitespace.", {
+ value: value,
+ not: requiresSpace ? "" : "not "
+ });
+ }
+ }
+
+ /**
+ * Check if the given node (`if`, `for`, `while`, etc), has the correct spacing after it.
+ * @param {ASTNode} node The node to check.
+ * @returns {void}
+ */
+ function check(node) {
+ var tokens = context.getFirstTokens(node, 2);
+ checkTokens(node, tokens[0], tokens[1]);
+ }
+
+ return {
+ "IfStatement": function (node) {
+ check(node);
+ // check the `else`
+ if (node.alternate && node.alternate.type !== "IfStatement") {
+ checkTokens(node.alternate, context.getTokenBefore(node.alternate), context.getFirstToken(node.alternate));
+ }
+ },
+ "ForStatement": check,
+ "ForOfStatement": check,
+ "ForInStatement": check,
+ "WhileStatement": check,
+ "DoWhileStatement": function (node) {
+ check(node);
+ // check the `while`
+ var whileTokens = context.getTokensBefore(node.test, 2);
+ checkTokens(node, whileTokens[0], whileTokens[1]);
+ },
+ "SwitchStatement": check,
+ "TryStatement": function (node) {
+ check(node);
+ // check the `finally`
+ if (node.finalizer) {
+ checkTokens(node.finalizer, context.getTokenBefore(node.finalizer), context.getFirstToken(node.finalizer));
+ }
+ },
+ "CatchStatement": check,
+ "WithStatement": check,
+ "FunctionExpression": function (node) {
+ if (config.checkFunctionKeyword) {
+ check(node);
+ }
+ }
+ };
+};
+
+},{}],135:[function(require,module,exports){
+/**
+ * @fileoverview A rule to ensure whitespace before blocks.
+ * @author Mathias Schreck <https://github.com/lo1tuma>
+ * @copyright 2014 Mathias Schreck. All rights reserved.
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function (context) {
+ var requireSpace = context.options[0] !== "never";
+
+ /**
+ * Determines whether two adjacent tokens are have whitespace between them.
+ * @param {Object} left - The left token object.
+ * @param {Object} right - The right token object.
+ * @returns {boolean} Whether or not there is space between the tokens.
+ */
+ function isSpaced(left, right) {
+ return left.range[1] < right.range[0];
+ }
+
+ /**
+ * Determines whether two adjacent tokens are on the same line.
+ * @param {Object} left - The left token object.
+ * @param {Object} right - The right token object.
+ * @returns {boolean} Whether or not the tokens are on the same line.
+ */
+ function isSameLine(left, right) {
+ return left.loc.start.line === right.loc.start.line;
+ }
+
+ /**
+ * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line.
+ * @param {ASTNode} node The AST node of a BlockStatement.
+ * @returns {void} undefined.
+ */
+ function checkPrecedingSpace(node) {
+ var precedingToken = context.getTokenBefore(node),
+ hasSpace;
+
+ if (precedingToken && isSameLine(precedingToken, node)) {
+ hasSpace = isSpaced(precedingToken, node);
+
+ if (requireSpace) {
+ if (!hasSpace) {
+ context.report(node, "Missing space before opening brace.");
+ }
+ } else {
+ if (hasSpace) {
+ context.report(node, "Unexpected space before opening brace.");
+ }
+ }
+ }
+ }
+
+ return {
+ "BlockStatement": checkPrecedingSpace
+ };
+
+};
+
+},{}],136:[function(require,module,exports){
+/**
+ * @fileoverview Disallows or enforces spaces inside of brackets.
+ * @author Ian Christian Myers
+ * @copyright 2014 Brandyn Bennett. All rights reserved.
+ * @copyright 2014 Michael Ficarra. No rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var options = {
+ spaced: context.options[0] === "always",
+ singleElementException: context.options[1] != null && !!context.options[1].singleValue,
+ objectsInArraysException: context.options[1] != null && !!context.options[1].objectsInArrays,
+ arraysInArraysException: context.options[1] != null && !!context.options[1].arraysInArrays,
+ propertyName: context.options[1] == null || context.options[1].propertyName == null || !!context.options[1].propertyName
+ };
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether two adjacent tokens are have whitespace between them.
+ * @param {Object} left - The left token object.
+ * @param {Object} right - The right token object.
+ * @returns {boolean} Whether or not there is space between the tokens.
+ */
+ function isSpaced(left, right) {
+ return left.range[1] < right.range[0];
+ }
+
+ /**
+ * Determines whether two adjacent tokens are on the same line.
+ * @param {Object} left - The left token object.
+ * @param {Object} right - The right token object.
+ * @returns {boolean} Whether or not the tokens are on the same line.
+ */
+ function isSameLine(left, right) {
+ return left.loc.start.line === right.loc.start.line;
+ }
+
+ /**
+ * Reports that there shouldn't be a space after the first token
+ * @param {ASTNode} node - The node to report in the event of an error.
+ * @param {Object[]} tokens - The tokens to be checked for spacing.
+ * @returns {void}
+ */
+ function reportNoBeginningSpace(node, tokens) {
+ context.report(node, tokens[0].loc.start,
+ "There should be no space after '" + tokens[0].value + "'");
+ }
+
+ /**
+ * Reports that there shouldn't be a space before the last token
+ * @param {ASTNode} node - The node to report in the event of an error.
+ * @param {Object[]} tokens - The tokens to be checked for spacing.
+ * @returns {void}
+ */
+ function reportNoEndingSpace(node, tokens) {
+ context.report(node, tokens[tokens.length - 1].loc.start,
+ "There should be no space before '" + tokens[tokens.length - 1].value + "'");
+ }
+
+ /**
+ * Reports that there should be a space after the first token
+ * @param {ASTNode} node - The node to report in the event of an error.
+ * @param {Object[]} tokens - The tokens to be checked for spacing.
+ * @returns {void}
+ */
+ function reportRequiredBeginningSpace(node, tokens) {
+ context.report(node, tokens[0].loc.start,
+ "A space is required after '" + tokens[0].value + "'");
+ }
+
+ /**
+ * Reports that there should be a space before the last token
+ * @param {ASTNode} node - The node to report in the event of an error.
+ * @param {Object[]} tokens - The tokens to be checked for spacing.
+ * @returns {void}
+ */
+ function reportRequiredEndingSpace(node, tokens) {
+ context.report(node, tokens[tokens.length - 1].loc.start,
+ "A space is required before '" + tokens[tokens.length - 1].value + "'");
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ MemberExpression: options.propertyName ? function checkMember(node) {
+ if (node.computed) {
+ var tokens = context.getTokens(node.property, 1, 1);
+ var tokenA = tokens[0], tokenB = tokens[1],
+ tokenC = tokens[tokens.length - 2], tokenD = tokens[tokens.length - 1];
+ if (isSameLine(tokenA, tokenB) || isSameLine(tokenC, tokenD)) {
+ if (options.spaced) {
+ if (!isSpaced(tokenA, tokenB) && isSameLine(tokenA, tokenB)) {
+ reportRequiredBeginningSpace(node, tokens);
+ }
+ if (!isSpaced(tokenC, tokenD) && isSameLine(tokenC, tokenD)) {
+ reportRequiredEndingSpace(node, tokens);
+ }
+ } else {
+ if (isSpaced(tokenA, tokenB)) {
+ reportNoBeginningSpace(node, tokens);
+ }
+ if (isSpaced(tokenC, tokenD)) {
+ reportNoEndingSpace(node, tokens);
+ }
+ }
+ }
+ }
+ } : function() {},
+
+ ArrayExpression: function(node) {
+ if (node.elements.length === 0) {
+ return;
+ }
+ var tokens = context.getTokens(node);
+ var tokenA = tokens[0], tokenB = tokens[1],
+ tokenC = tokens[tokens.length - 2], tokenD = tokens[tokens.length - 1];
+
+ var openingBracketMustBeSpaced =
+ options.objectsInArraysException && tokenB.value === "{" ||
+ options.arraysInArraysException && tokenB.value === "[" ||
+ options.singleElementException && node.elements.length === 1
+ ? !options.spaced : options.spaced;
+
+ var closingBracketMustBeSpaced =
+ options.objectsInArraysException && tokenC.value === "}" ||
+ options.arraysInArraysException && tokenC.value === "]" ||
+ options.singleElementException && node.elements.length === 1
+ ? !options.spaced : options.spaced;
+
+ if (isSameLine(tokenA, tokenB) || isSameLine(tokenC, tokenD)) {
+ if (openingBracketMustBeSpaced && !isSpaced(tokenA, tokenB)) {
+ reportRequiredBeginningSpace(node, tokens);
+ } else if (!openingBracketMustBeSpaced && isSpaced(tokenA, tokenB)) {
+ reportNoBeginningSpace(node, tokens);
+ }
+ if (closingBracketMustBeSpaced && !isSpaced(tokenC, tokenD)) {
+ reportRequiredEndingSpace(node, tokens);
+ } else if (!closingBracketMustBeSpaced && isSpaced(tokenC, tokenD)) {
+ reportNoEndingSpace(node, tokens);
+ }
+ }
+ },
+
+ ObjectExpression: function(node) {
+ if (node.properties.length === 0) {
+ return;
+ }
+ var tokens = context.getTokens(node);
+ var tokenA = tokens[0], tokenB = tokens[1],
+ tokenC = tokens[tokens.length - 2], tokenD = tokens[tokens.length - 1];
+ if (isSameLine(tokenA, tokenB) || isSameLine(tokenC, tokenD)) {
+ if (options.spaced) {
+ if (!isSpaced(tokenA, tokenB)) {
+ reportRequiredBeginningSpace(node, tokens);
+ }
+ if (!isSpaced(tokenC, tokenD)) {
+ reportRequiredEndingSpace(node, tokens);
+ }
+ } else {
+ if (isSpaced(tokenA, tokenB)) {
+ reportNoBeginningSpace(node, tokens);
+ }
+ if (isSpaced(tokenC, tokenD)) {
+ reportNoEndingSpace(node, tokens);
+ }
+ }
+ }
+ }
+
+ };
+
+};
+
+},{}],137:[function(require,module,exports){
+/**
+ * @fileoverview Disallows or enforces spaces inside of parentheses.
+ * @author Jonathan Rajavuori
+ * @copyright 2014 Jonathan Rajavuori. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var RE, MESSAGE;
+
+ if (context.options[0] === "always") {
+ RE = /\([^ \)]|[^ \(]\)/mg;
+ MESSAGE = "There must be a space inside this paren.";
+ } else {
+ RE = /\( | \)/mg;
+ MESSAGE = "There should be no spaces inside this paren.";
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ var skipRanges = [];
+
+ /**
+ * Adds the range of a node to the set to be skipped when checking parens
+ * @param {ASTNode} node The node to skip
+ * @returns {void}
+ * @private
+ */
+ function addSkipRange(node) {
+ skipRanges.push(node.range);
+ }
+
+ /**
+ * Sorts the skipRanges array. Must be called before shouldSkip
+ * @returns {void}
+ * @private
+ */
+ function sortSkipRanges() {
+ skipRanges.sort(function (a, b) {
+ return a[0] - b[0];
+ });
+ }
+
+ /**
+ * Checks if a certain position in the source should be skipped
+ * @param {Number} pos The 0-based index in the source
+ * @returns {boolean} whether the position should be skipped
+ * @private
+ */
+ function shouldSkip(pos) {
+ var i, len, range;
+ for (i = 0, len = skipRanges.length; i < len; i += 1) {
+ range = skipRanges[i];
+ if (pos < range[0]) {
+ break;
+ } else if (pos < range[1]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "Program:exit": function checkParenSpaces(node) {
+
+ var match,
+ nextLine,
+ column,
+ line = 1,
+ source = context.getSource(),
+ pos = 0;
+
+ sortSkipRanges();
+
+ while ((match = RE.exec(source)) !== null) {
+ if (source.charAt(match.index) !== "(") {
+ // Matched a closing paren pattern
+ match.index += 1;
+ }
+
+ if (!shouldSkip(match.index)) {
+ while ((nextLine = source.indexOf("\n", pos)) !== -1 && nextLine < match.index) {
+ pos = nextLine + 1;
+ line += 1;
+ }
+ column = match.index - pos;
+
+ context.report(node, { line: line, column: column }, MESSAGE);
+ }
+ }
+
+ },
+
+
+ // These nodes can contain parentheses that this rule doesn't care about
+
+ LineComment: addSkipRange,
+
+ BlockComment: addSkipRange,
+
+ Literal: addSkipRange
+
+ };
+
+};
+
+},{}],138:[function(require,module,exports){
+/**
+ * @fileoverview Require spaces around infix operators
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var OPERATORS = [
+ "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in",
+ "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=",
+ "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=",
+ "?", ":", ","
+ ];
+
+ function isSpaced(left, right) {
+ var op, tokens = context.getTokens({range: [left.range[1], right.range[0]]}, 1, 1);
+ for (var i = 1, l = tokens.length - 1; i < l; ++i) {
+ op = tokens[i];
+ if (
+ op.type === "Punctuator" &&
+ OPERATORS.indexOf(op.value) >= 0 &&
+ (tokens[i - 1].range[1] >= op.range[0] || op.range[1] >= tokens[i + 1].range[0])
+ ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function isRightSpaced(left, right) {
+ var op, tokens = context.getTokens({range: [left.range[1], right.range[0]]}, 1, 1);
+ for (var i = 1, l = tokens.length - 1; i < l; ++i) {
+ op = tokens[i];
+ if (
+ op.type === "Punctuator" &&
+ OPERATORS.indexOf(op.value) >= 0 &&
+ op.range[1] >= tokens[i + 1].range[0]
+ ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function report(node) {
+ context.report(node, "Infix operators must be spaced.");
+ }
+
+ function checkBinary(node) {
+ if (!isSpaced(node.left, node.right)) {
+ report(node);
+ }
+ }
+
+ function checkSequence(node) {
+ for (var i = 0, l = node.expressions.length - 1; i < l; ++i) {
+ if (!isRightSpaced(node.expressions[i], node.expressions[i + 1])) {
+ report(node);
+ break;
+ }
+ }
+ }
+
+ function checkConditional(node) {
+ if (!isSpaced(node.test, node.consequent) || !isSpaced(node.consequent, node.alternate)) {
+ report(node);
+ }
+ }
+
+ function checkVar(node) {
+ if (node.init && !isSpaced(node.id, node.init)) {
+ report(node);
+ }
+ }
+
+ return {
+ "AssignmentExpression": checkBinary,
+ "BinaryExpression": checkBinary,
+ "LogicalExpression": checkBinary,
+ "ConditionalExpression": checkConditional,
+ "SequenceExpression": checkSequence,
+ "VariableDeclarator": checkVar
+ };
+
+};
+
+},{}],139:[function(require,module,exports){
+/**
+ * @fileoverview Require spaces following return, throw, and case
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ function check(node) {
+ var tokens = context.getFirstTokens(node, 2),
+ value = tokens[0].value;
+
+ if (tokens[0].range[1] >= tokens[1].range[0]) {
+ context.report(node, "Keyword \"" + value + "\" must be followed by whitespace.");
+ }
+ }
+
+ return {
+ "ReturnStatement": function(node) {
+ if (node.argument) {
+ check(node);
+ }
+ },
+ "SwitchCase": function(node) {
+ if (node.test) {
+ check(node);
+ }
+ },
+ "ThrowStatement": check
+ };
+
+};
+
+},{}],140:[function(require,module,exports){
+/**
+ * @fileoverview Require spaces following unary word operators
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ function check(node) {
+ var tokens;
+ tokens = context.getFirstTokens(node, 2);
+ if (tokens[0].range[1] >= tokens[1].range[0]) {
+ switch (tokens[0].value) {
+ case "delete":
+ case "new":
+ case "typeof":
+ case "void":
+ context.report(node, "Unary word operator \"" + tokens[0].value + "\" must be followed by whitespace.");
+ break;
+ // no default
+ }
+ }
+ }
+
+ return {
+ "NewExpression": check,
+ "UnaryExpression": check
+ };
+
+};
+
+},{}],141:[function(require,module,exports){
+/**
+ * @fileoverview Enforces or disallows a space beginning a single-line comment.
+ * @author Greg Cochard
+ * @copyright 2014 Greg Cochard. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ // Unless the first option is never, require a space
+ var requireSpace = context.options[0] !== "never";
+
+ // Default to match anything, so all will fail if there are no exceptions
+ var exceptionMatcher = new RegExp(" ");
+
+ // Grab the exceptions array and build a RegExp matcher for it
+ var hasExceptions = context.options.length === 2;
+ var unescapedExceptions = hasExceptions ? context.options[1].exceptions : [];
+ var exceptions;
+
+ if (unescapedExceptions.length) {
+ exceptions = unescapedExceptions.map(function(s) {
+ return s.replace(/([.*+?${}()|\^\[\]\/\\])/g, "\\$1");
+ });
+ exceptionMatcher = new RegExp("(^(" + exceptions.join(")+$)|(^(") + ")+$)");
+ }
+
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "LineComment": function checkCommentForSpace(node) {
+
+ if (node.loc.start.line === 1 && /^#!/.test(context.getSourceLines()[0])) {
+
+ /*
+ * HACK: return if we are on the first line and
+ * encounter a shebang at the beginning.
+ * It seems the parser will return this as a
+ * comment and filter out the # so we must fetch
+ * the actual source line. Is this being caused
+ * by esprima or eslint? Something else?
+ */
+ return;
+ }
+
+ if (requireSpace) {
+
+ // Space expected and not found
+ if (node.value.indexOf(" ") !== 0) {
+
+ /*
+ * Do two tests; one for space starting the line,
+ * and one for a comment comprised only of exceptions
+ */
+ if (hasExceptions && !exceptionMatcher.test(node.value)) {
+ context.report(node, "Expected exception block or space after // in comment.");
+ } else if (!hasExceptions) {
+ context.report(node, "Expected space after // in comment.");
+ }
+ }
+
+ } else {
+
+ if (node.value.indexOf(" ") === 0) {
+ context.report(node, "Unexpected space after // in comment.");
+ }
+ }
+ }
+
+ };
+};
+
+},{}],142:[function(require,module,exports){
+/**
+ * @fileoverview Rule to ensure code is running in strict mode.
+ * @author Nicholas C. Zakas
+ * @copyright 2013-2014 Nicholas C. Zakas. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var scopes = [];
+
+ /**
+ * Determines if a given node is "use strict".
+ * @param {ASTNode} node The node to check.
+ * @returns {boolean} True if the node is a strict pragma, false if not.
+ * @void
+ */
+ function isStrictPragma(node) {
+ return (node && node.type === "ExpressionStatement" &&
+ node.expression.value === "use strict");
+ }
+
+ /**
+ * When you enter a scope, push the strict value from the previous scope
+ * onto the stack.
+ * @param {ASTNode} node The AST node being checked.
+ * @returns {void}
+ * @private
+ */
+ function enterScope(node) {
+
+ var isStrict = false,
+ isProgram = (node.type === "Program"),
+ isParentGlobal = scopes.length === 1,
+ isParentStrict = scopes.length ? scopes[scopes.length - 1] : false;
+
+ // look for the "use strict" pragma
+ if (isProgram) {
+ isStrict = isStrictPragma(node.body[0]) || isParentStrict;
+ } else {
+ isStrict = isStrictPragma(node.body.body[0]) || isParentStrict;
+ }
+
+ scopes.push(isStrict);
+
+ // never warn if the parent is strict or the function is strict
+ if (!isParentStrict && !isStrict && isParentGlobal) {
+ context.report(node, "Missing \"use strict\" statement.");
+ }
+ }
+
+ /**
+ * When you exit a scope, pop off the top scope and see if it's true or
+ * false.
+ * @returns {void}
+ * @private
+ */
+ function exitScope() {
+ scopes.pop();
+ }
+
+ return {
+
+ "Program": enterScope,
+ "FunctionDeclaration": enterScope,
+ "FunctionExpression": enterScope,
+
+ "Program:exit": exitScope,
+ "FunctionDeclaration:exit": exitScope,
+ "FunctionExpression:exit": exitScope
+ };
+
+};
+
+},{}],143:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag comparisons to the value NaN
+ * @author James Allardice
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+ "BinaryExpression": function(node) {
+
+ if (!/^[|&^]$/.test(node.operator) && node.left.name === "NaN" || node.right.name === "NaN") {
+ context.report(node, "Use the isNaN function to compare with NaN.");
+ }
+ }
+ };
+
+};
+
+},{}],144:[function(require,module,exports){
+/**
+ * @fileoverview Validates JSDoc comments are syntactically correct
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var doctrine = require("doctrine");
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var options = context.options[0] || {},
+ prefer = options.prefer || {},
+
+ // these both default to true, so you have to explicitly make them false
+ requireReturn = options.requireReturn === false ? false : true,
+ requireParamDescription = options.requireParamDescription === false ? false : true;
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ // Using a stack to store if a function returns or not (handling nested functions)
+ var fns = [];
+
+ /**
+ * When parsing a new function, store it in our function stack.
+ * @returns {void}
+ * @private
+ */
+ function startFunction() {
+ fns.push({returnPresent: false});
+ }
+
+ /**
+ * Indicate that return has been found in the current function.
+ * @param {ASTNode} node The return node.
+ * @returns {void}
+ * @private
+ */
+ function addReturn(node) {
+ var functionState = fns[fns.length - 1];
+
+ if (functionState && node.argument !== null) {
+ functionState.returnPresent = true;
+ }
+ }
+
+ /**
+ * Validate the JSDoc node and output warnings if anything is wrong.
+ * @param {ASTNode} node The AST node to check.
+ * @returns {void}
+ * @private
+ */
+ function checkJSDoc(node) {
+ var jsdocNode = context.getJSDocComment(node),
+ functionData = fns.pop(),
+ hasReturns = false,
+ hasConstructor = false,
+ params = Object.create(null),
+ jsdoc;
+
+ // make sure only to validate JSDoc comments
+ if (jsdocNode) {
+
+ try {
+ jsdoc = doctrine.parse(jsdocNode.value, {
+ strict: true,
+ unwrap: true,
+ sloppy: true
+ });
+ } catch (ex) {
+
+ if (/braces/i.test(ex.message)) {
+ context.report(jsdocNode, "JSDoc type missing brace.");
+ } else {
+ context.report(jsdocNode, "JSDoc syntax error.");
+ }
+
+ return;
+ }
+
+ jsdoc.tags.forEach(function(tag) {
+
+ switch (tag.title) {
+
+ case "param":
+ if (!tag.type) {
+ context.report(jsdocNode, "Missing JSDoc parameter type for '{{name}}'.", { name: tag.name });
+ }
+
+ if (!tag.description && requireParamDescription) {
+ context.report(jsdocNode, "Missing JSDoc parameter description for '{{name}}'.", { name: tag.name });
+ }
+
+ if (params[tag.name]) {
+ context.report(jsdocNode, "Duplicate JSDoc parameter '{{name}}'.", { name: tag.name });
+ } else if (tag.name.indexOf(".") === - 1) {
+ params[tag.name] = 1;
+ }
+ break;
+
+ case "return":
+ case "returns":
+ hasReturns = true;
+
+ if (!requireReturn && !functionData.returnPresent && tag.type.name !== "void" && tag.type.name !== "undefined") {
+ context.report(jsdocNode, "Unexpected @" + tag.title + " tag; function has no return statement.");
+ } else {
+ if (!tag.type) {
+ context.report(jsdocNode, "Missing JSDoc return type.");
+ }
+
+ if (tag.type.name !== "void" && !tag.description) {
+ context.report(jsdocNode, "Missing JSDoc return description.");
+ }
+ }
+
+ break;
+
+ case "constructor":
+ hasConstructor = true;
+ break;
+
+ // no default
+ }
+
+ // check tag preferences
+ if (prefer.hasOwnProperty(tag.title)) {
+ context.report(jsdocNode, "Use @{{name}} instead.", { name: prefer[tag.title] });
+ }
+
+ });
+
+ // check for functions missing @returns
+ if (!hasReturns && !hasConstructor) {
+ if (requireReturn || functionData.returnPresent) {
+ context.report(jsdocNode, "Missing JSDoc @returns for function.");
+ }
+ }
+
+ // check the parameters
+ var jsdocParams = Object.keys(params);
+
+ node.params.forEach(function(param, i) {
+ var name = param.name;
+
+ if (jsdocParams[i] && (name !== jsdocParams[i])) {
+ context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", {
+ name: name,
+ jsdocName: jsdocParams[i]
+ });
+ } else if (!params[name]) {
+ context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", {
+ name: name
+ });
+ }
+ });
+
+ }
+
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+ "FunctionExpression": startFunction,
+ "FunctionDeclaration": startFunction,
+ "FunctionExpression:exit": checkJSDoc,
+ "FunctionDeclaration:exit": checkJSDoc,
+ "ReturnStatement": addReturn
+ };
+
+};
+
+},{"doctrine":4}],145:[function(require,module,exports){
+/**
+ * @fileoverview Ensures that the results of typeof are compared against a valid string
+ * @author Ian Christian Myers
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ var VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function"],
+ OPERATORS = ["==", "===", "!=", "!=="];
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "UnaryExpression": function (node) {
+ var parent, sibling;
+
+ if (node.operator === "typeof") {
+ parent = context.getAncestors().pop();
+
+ if (parent.type === "BinaryExpression" && OPERATORS.indexOf(parent.operator) !== -1) {
+ sibling = parent.left === node ? parent.right : parent.left;
+
+ if (sibling.type === "Literal" && VALID_TYPES.indexOf(sibling.value) === -1) {
+ context.report(sibling, "Invalid typeof comparison value");
+ }
+ }
+ }
+ }
+
+ };
+
+};
+
+},{}],146:[function(require,module,exports){
+/**
+ * @fileoverview Rule to enforce var declarations are only at the top of a function.
+ * @author Danny Fritz
+ * @author Gyandeep Singh
+ * @copyright 2014 Danny Fritz. All rights reserved.
+ * @copyright 2014 Gyandeep Singh. All rights reserved.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function (context) {
+ var errorMessage = "All \"var\" declarations must be at the top of the function scope.";
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @param {ASTNode} node - any node
+ * @returns {Boolean} whether the given node structurally represents a directive
+ */
+ function looksLikeDirective(node) {
+ return node.type === "ExpressionStatement" &&
+ node.expression.type === "Literal" && typeof node.expression.value === "string";
+ }
+
+ /**
+ * Checks whether this variable is on top of the block body
+ * @param {ASTNode} node - The node to check
+ * @param {ASTNode[]} statements - collection of ASTNodes for the parent node block
+ * @returns {Boolean} True if var is on top otherwise false
+ */
+ function isVarOnTop (node, statements) {
+ var i = 0, l = statements.length;
+
+ // skip over directives
+ for (; i < l; ++i) {
+ if (!looksLikeDirective(statements[i])) {
+ break;
+ }
+ }
+
+ for (; i < l; ++i) {
+ if (statements[i].type !== "VariableDeclaration") {
+ return false;
+ }
+ if (statements[i] === node) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Checks whether variable is on top at the global level
+ * @param {ASTNode} node - The node to check
+ * @param {ASTNode} parent - Parent of the node
+ * @returns {void}
+ */
+ function globalVarCheck (node, parent) {
+ if (!isVarOnTop(node, parent.body)) {
+ context.report(node, errorMessage);
+ }
+ }
+
+ /**
+ * Checks whether variable is on top at functional block scope level
+ * @param {ASTNode} node - The node to check
+ * @param {ASTNode} parent - Parent of the node
+ * @param {ASTNode} grandParent - Parent of the node's parent
+ * @returns {void}
+ */
+ function blockScopeVarCheck (node, parent, grandParent) {
+ if (!((grandParent.type === "FunctionDeclaration"
+ || grandParent.type === "FunctionExpression")
+ && parent.type === "BlockStatement"
+ && isVarOnTop(node, parent.body))) {
+ context.report(node, errorMessage);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Public API
+ //--------------------------------------------------------------------------
+
+ return {
+ "VariableDeclaration": function (node) {
+ var ancestors = context.getAncestors();
+ var parent = ancestors.pop();
+ var grandParent = ancestors.pop();
+
+ if (node.kind === "var") {// check variable is `var` type and not `let` or `const`
+ if (parent.type === "Program") {// That means its a global variable
+ globalVarCheck(node, parent);
+ } else {
+ blockScopeVarCheck(node, parent, grandParent);
+ }
+ }
+ }
+ };
+
+};
+
+},{}],147:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when IIFE is not wrapped in parens
+ * @author Ilya Volodin
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+ var style = context.options[0] || "outside";
+
+ function wrapped(node) {
+ var previousToken = context.getTokenBefore(node),
+ nextToken = context.getTokenAfter(node);
+ return previousToken && previousToken.value === "(" &&
+ nextToken && nextToken.value === ")";
+ }
+
+ return {
+
+ "CallExpression": function(node) {
+ if (node.callee.type === "FunctionExpression") {
+ var callExpressionWrapped = wrapped(node),
+ functionExpressionWrapped = wrapped(node.callee);
+
+ if (!callExpressionWrapped && !functionExpressionWrapped) {
+ context.report(node, "Wrap an immediate function invocation in parentheses.");
+ } else if (style === "inside" && !functionExpressionWrapped) {
+ context.report(node, "Wrap only the function expression in parens.");
+ } else if (style === "outside" && !callExpressionWrapped) {
+ context.report(node, "Move the invocation into the parens that contain the function.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],148:[function(require,module,exports){
+/**
+ * @fileoverview Rule to flag when regex literals are not wrapped in parens
+ * @author Matt DuVall <http://www.mattduvall.com>
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ "use strict";
+
+ return {
+
+ "Literal": function(node) {
+ var token = context.getFirstToken(node),
+ nodeType = token.type,
+ source,
+ grandparent,
+ ancestors;
+
+ if (nodeType === "RegularExpression") {
+ source = context.getTokenBefore(node);
+ ancestors = context.getAncestors();
+ grandparent = ancestors[ancestors.length - 1];
+
+ if (grandparent.type === "MemberExpression" && grandparent.object === node &&
+ (!source || source.value !== "(")) {
+ context.report(node, "Wrap the regexp literal in parens to disambiguate the slash.");
+ }
+ }
+ }
+ };
+
+};
+
+},{}],149:[function(require,module,exports){
+/**
+ * @fileoverview Rule to require or disallow yoda comparisons
+ * @author Nicholas C. Zakas
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function (context) {
+
+ // Default to "never" (!always) if no option
+
+ var always = (context.options[0] === "always");
+
+ //--------------------------------------------------------------------------
+ // Helpers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Determines whether an operator is a comparison operator.
+ * @param {String} operator The operator to check.
+ * @returns {Boolean} Whether or not it is a comparison operator.
+ */
+ function isComparisonOperator(operator) {
+ return (/^(==|===|!=|!==|<|>|<=|>=)$/).test(operator);
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ return {
+
+ "BinaryExpression": function (node) {
+
+ if (always) {
+
+ // Comparisons must always be yoda-style: if ("blue" === color)
+
+ if (node.right.type === "Literal" && isComparisonOperator(node.operator)) {
+ context.report(node, "Expected literal to be on the left side of " + node.operator + ".");
+ }
+
+ } else {
+
+ // Comparisons must never be yoda-style (default)
+
+ if (node.left.type === "Literal" && isComparisonOperator(node.operator)) {
+ context.report(node, "Expected literal to be on the right side of " + node.operator + ".");
+ }
+
+ }
+
+ }
+
+ };
+
+};
+
+},{}],150:[function(require,module,exports){
+/**
+ * @fileoverview Common utilities.
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+/**
+ * Merges two objects together and assigns the result to the initial object. Can be used for shallow cloning.
+ * @param {Object} target of the cloning operation
+ * @param {Object} source object
+ * @returns {void}
+ */
+exports.mixin = function(target, source) {
+ Object.keys(source).forEach(function(key) {
+ target[key] = source[key];
+ });
+};
+
+/**
+ * Merges two config objects. This will not only add missing keys, but will also modify values to match.
+ * @param {Object} base config object
+ * @param {Object} custom config object. Overrides in this config object will take priority over base.
+ * @returns {Object} merged config object.
+ */
+exports.mergeConfigs = function mergeConfigs(base, custom) {
+
+ Object.keys(custom).forEach(function (key) {
+ var property = custom[key];
+
+ if (key === "plugins") {
+ if (!base[key]) {
+ base[key] = [];
+ }
+
+ property.forEach(function (plugin) {
+ // skip duplicates
+ if (base[key].indexOf(plugin) === -1) {
+ base[key].push(plugin);
+ }
+ });
+ return;
+ }
+
+ if (Array.isArray(base[key]) && !Array.isArray(property) && typeof property === "number") {
+ // assume that we are just overriding first attribute
+ base[key][0] = custom[key];
+ return;
+ }
+
+ if (typeof property === "object" && !Array.isArray(property)) {
+ // base[key] might not exist, so be careful with recursion here
+ base[key] = mergeConfigs(base[key] || {}, custom[key]);
+ } else {
+ base[key] = custom[key];
+ }
+ });
+
+ return base;
+};
+
+},{}]},{},[9])(9)
+});
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/ESLint/eslint.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="allowtabs"></a>
<div class="addfile"><h4>Added: allow-tabs</h4></div>
</div>
</body>
</html>