From 46f930040c638b1ab1c333bc5c292208793677a0 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 23 Aug 2011 07:35:02 +0200 Subject: [PATCH] imported from svn 'pve-jslint/trunk' --- Makefile | 61 + changelog.Debian | 12 + control.in | 10 + copyright | 29 + jslint | 3 + jslint.js | 6904 ++++++++++++++++++++++++++++++++++++++++++++++ rhino.js | 52 + 7 files changed, 7071 insertions(+) create mode 100644 Makefile create mode 100644 changelog.Debian create mode 100644 control.in create mode 100644 copyright create mode 100755 jslint create mode 100644 jslint.js create mode 100644 rhino.js diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0992aa1 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +RELEASE=2.0 + +PACKAGE=pve-jslint +VERSION=1.0 +PACKAGERELEASE=2 + +PKGREL=${VERSION}-${PACKAGERELEASE} +DEB=${PACKAGE}_${VERSION}-${PKGREL}_all.deb + +all: ${DEB} + +.PHONY: dinstall +dinstall: ${DEB} + dpkg -i ${DEB} + +.PHONY: ${DEB} +${DEB} deb: + make clean + rm -rf dest + mkdir dest + make DESTDIR=`pwd`/dest install + mkdir dest/DEBIAN + sed -e 's/@PKGREL@/${PKGREL}/' dest/DEBIAN/control + mkdir -p dest/usr/share/doc/${PACKAGE} + install -m 0644 copyright dest/usr/share/doc/${PACKAGE} + install -m 0644 changelog.Debian dest/usr/share/doc/${PACKAGE} + gzip --best dest/usr/share/doc/${PACKAGE}/changelog.Debian + dpkg-deb --build dest + mv dest.deb ${DEB} + rm -rf dest + lintian ${DEB} + +rhinoed_jslint.js: jslint.js rhino.js + cat jslint.js rhino.js >$@.tmp + mv $@.tmp $@ + +install: rhinoed_jslint.js jslint + mkdir -p ${DESTDIR}/usr/share/${PACKAGE} + install -m 0644 rhinoed_jslint.js ${DESTDIR}/usr/share/${PACKAGE}/rhinoed_jslint.js + mkdir -p ${DESTDIR}/usr/bin + install -m 0755 jslint /usr/bin + +jslint.js download: + wget -O jslint.js http://jslint.com/jslint.js + +.PHONY: distclean +distclean: clean + +.PHONY: clean +clean: + rm -rf *~ dest control rhinoed_jslint.js *.deb + +.PHONY: upload +upload: ${DEB} + umount /pve/${RELEASE}; mount /pve/${RELEASE} -o rw + mkdir -p /pve/${RELEASE}/extra + rm -f /pve/${RELEASE}/extra/${PACKAGE}_*.deb + rm -f /pve/${RELEASE}/extra/Packages* + cp ${DEB} /pve/${RELEASE}/extra + cd /pve/${RELEASE}/extra; dpkg-scanpackages . /dev/null > Packages; gzip -9c Packages > Packages.gz + umount /pve/${RELEASE}; mount /pve/${RELEASE} -o ro diff --git a/changelog.Debian b/changelog.Debian new file mode 100644 index 0000000..97850d6 --- /dev/null +++ b/changelog.Debian @@ -0,0 +1,12 @@ +pve-jslint (1.0-2) unstable; urgency=low + + * download from http://jslint.com/jslint.js + + -- Proxmox Support Team Fri, 08 Jul 2011 08:22:17 +0200 + +pve-jslint (1.0-1) unstable; urgency=low + + * first try + + -- Proxmox Support Team Thu, 07 Jul 2011 14:47:58 +0200 + diff --git a/control.in b/control.in new file mode 100644 index 0000000..c89fd20 --- /dev/null +++ b/control.in @@ -0,0 +1,10 @@ +Package: pve-jslint +Version: @PKGREL@ +Section: devel +Priority: optional +Architecture: all +Depends: rhino +Maintainer: Proxmox Support Team +Description: JSLint for Proxmox Virtual Environment development + This package contains a version of jslint used to develop the + Proxmox Virtual Environment GUI. diff --git a/copyright b/copyright new file mode 100644 index 0000000..5ccd8dd --- /dev/null +++ b/copyright @@ -0,0 +1,29 @@ +This package was debianized by the Proxmox Support Team + on Mon, 30 Mar 2009 06:55:24 -0400. + +It was downloaded from + +JSLint Copyright: + +Copyright (c) 2002 Douglas Crockford (www.JSLint.com) + +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 shall be used for Good, not Evil. + +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. + diff --git a/jslint b/jslint new file mode 100755 index 0000000..a53d462 --- /dev/null +++ b/jslint @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/bin/rhino /usr/share/pve-jslint/rhinoed_jslint.js $@ \ No newline at end of file diff --git a/jslint.js b/jslint.js new file mode 100644 index 0000000..a1291ba --- /dev/null +++ b/jslint.js @@ -0,0 +1,6904 @@ +// jslint.js +// 2011-07-04 + +// Copyright (c) 2002 Douglas Crockford (www.JSLint.com) + +// 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 shall be used for Good, not Evil. + +// 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. + +// WARNING: JSLint will hurt your feelings. + +// JSLINT is a global function. It takes two parameters. + +// var myResult = JSLINT(source, option); + +// The first parameter is either a string or an array of strings. If it is a +// string, it will be split on '\n' or '\r'. If it is an array of strings, it +// is assumed that each string represents one line. The source can be a +// JavaScript text, or HTML text, or a JSON text, or a CSS text. + +// The second parameter is an optional object of options that control the +// operation of JSLINT. Most of the options are booleans: They are all +// optional and have a default value of false. One of the options, predef, +// can be an array of names, which will be used to declare global variables, +// or an object whose keys are used as global names, with a boolean value +// that determines if they are assignable. + +// If it checks out, JSLINT returns true. Otherwise, it returns false. + +// If false, you can inspect JSLINT.errors to find out the problems. +// JSLINT.errors is an array of objects containing these properties: + +// { +// line : The line (relative to 0) at which the lint was found +// character : The character (relative to 0) at which the lint was found +// reason : The problem +// evidence : The text line in which the problem occurred +// raw : The raw message before the details were inserted +// a : The first detail +// b : The second detail +// c : The third detail +// d : The fourth detail +// } + +// If a stopping error was found, a null will be the last element of the +// JSLINT.errors array. A stopping error means that JSLint was not confident +// enough to continue. It does not necessarily mean that the error was +// especially heinous. + +// You can request a Function Report, which shows all of the functions +// and the parameters and vars that they use. This can be used to find +// implied global variables and other problems. The report is in HTML and +// can be inserted in an HTML . + +// var myReport = JSLINT.report(errors_only); + +// If errors_only is true, then the report will be limited to only errors. + +// You can request a data structure that contains JSLint's results. + +// var myData = JSLINT.data(); + +// It returns a structure with this form: + +// { +// errors: [ +// { +// line: NUMBER, +// character: NUMBER, +// reason: STRING, +// evidence: STRING +// } +// ], +// functions: [ +// { +// name: STRING, +// line: NUMBER, +// last: NUMBER, +// params: [ +// { +// string: STRING +// } +// ], +// closure: [ +// STRING +// ], +// var: [ +// STRING +// ], +// exception: [ +// STRING +// ], +// outer: [ +// STRING +// ], +// unused: [ +// STRING +// ], +// undef: [ +// STRING +// ], +// global: [ +// STRING +// ], +// label: [ +// STRING +// ] +// } +// ], +// globals: [ +// STRING +// ], +// member: { +// STRING: NUMBER +// }, +// urls: [ +// STRING +// ], +// json: BOOLEAN +// } + +// Empty arrays will not be included. + +// You can obtain the parse tree that JSLint constructed while parsing. The +// latest tree is kept in JSLINT.tree. A nice stringication can be produced +// with + +// JSON.stringify(JSLINT.tree, [ +// 'string', 'arity', 'name', 'first', +// 'second', 'third', 'block', 'else' +// ], 4)); + +// JSLint provides three directives. They look like slashstar comments, and +// allow for setting options, declaring global variables, and establishing a +// set of allowed property names. + +// These directives respect function scope. + +// The jslint directive is a special comment that can set one or more options. +// The current option set is + +// adsafe true, if ADsafe rules should be enforced +// bitwise true, if bitwise operators should be allowed +// browser true, if the standard browser globals should be predefined +// cap true, if upper case HTML should be allowed +// confusion true, if types can be used inconsistently +// 'continue' true, if the continuation statement should be tolerated +// css true, if CSS workarounds should be tolerated +// debug true, if debugger statements should be allowed +// devel true, if logging should be allowed (console, alert, etc.) +// eqeq true, if == should be allowed +// es5 true, if ES5 syntax should be allowed +// evil true, if eval should be allowed +// forin true, if for in statements need not filter +// fragment true, if HTML fragments should be allowed +// indent the indentation factor +// maxerr the maximum number of errors to allow +// maxlen the maximum length of a source line +// newcap true, if constructor names capitalization is ignored +// node true, if Node.js globals should be predefined +// nomen true, if names may have dangling _ +// on true, if HTML event handlers should be allowed +// passfail true, if the scan should stop on first error +// plusplus true, if increment/decrement should be allowed +// properties true, if all property names must be declared with /*properties*/ +// regexp true, if the . should be allowed in regexp literals +// rhino true, if the Rhino environment globals should be predefined +// undef true, if variables can be declared out of order +// unparam true, if unused parameters should be tolerated +// safe true, if use of some browser features should be restricted +// sloppy true, if the 'use strict'; pragma is optional +// sub true, if all forms of subscript notation are tolerated +// vars true, if multiple var statements per function should be allowed +// white true, if sloppy whitespace is tolerated +// widget true if the Yahoo Widgets globals should be predefined +// windows true, if MS Windows-specific globals should be predefined + +// For example: + +/*jslint + evil: true, nomen: true, regexp: true +*/ + +// The properties directive declares an exclusive list of property names. +// Any properties named in the program that are not in the list will +// produce a warning. + +// For example: + +/*properties + '\b': string, '\t': string, '\n': string, '\f': string, '\r': string, + '!=': boolean, '!==': boolean, '"': string, '%': boolean, '\'': string, + '(begin)', '(breakage)': number, '(complexity)', + '(confusion)': boolean, '(context)': object, + '(error)', '(identifier)', '(line)': number, '(loopage)': number, '(name)', + '(old_property_type)', '(params)', '(return_type)', '(scope)': object, + '(statement)', '(token)', '(vars)', '(verb)', '*': boolean, '+': boolean, + '-': boolean, '/': *, '<': boolean, '<=': boolean, '==': boolean, + '===': boolean, '>': boolean, '>=': boolean, ADSAFE: boolean, Array, + Date, E: string, Function, LN10: string, LN2: string, LOG10E: string, + LOG2E: string, MAX_VALUE: string, MIN_VALUE: string, + NEGATIVE_INFINITY: string, Object, PI: string, POSITIVE_INFINITY: string, + SQRT1_2: string, SQRT2: string, '\\': string, a: object, a_label: string, + a_not_allowed: string, a_not_defined: string, a_scope: string, + abbr: object, acronym: object, address: object, adsafe, adsafe_a: string, + adsafe_autocomplete: string, adsafe_bad_id: string, adsafe_div: string, + adsafe_fragment: string, adsafe_go: string, adsafe_html: string, + adsafe_id: string, adsafe_id_go: string, adsafe_lib: string, + adsafe_lib_second: string, adsafe_missing_id: string, + adsafe_name_a: string, adsafe_placement: string, adsafe_prefix_a: string, + adsafe_script: string, adsafe_source: string, adsafe_subscript_a: string, + adsafe_tag: string, all: boolean, already_defined: string, and: string, + applet: object, apply: string, approved: array, area: object, + arity: string, article: object, aside: object, assign: boolean, + assign_exception: string, assignment_function_expression: string, + at: number, attribute_case_a: string, audio: object, autocomplete: string, + avoid_a: string, b: *, background: array, 'background-attachment': array, + 'background-color': array, 'background-image': array, + 'background-position': array, 'background-repeat': array, + bad_assignment: string, bad_color_a: string, bad_constructor: string, + bad_entity: string, bad_html: string, bad_id_a: string, bad_in_a: string, + bad_invocation: string, bad_name_a: string, bad_new: string, + bad_number: string, bad_operand: string, bad_type: string, bad_url: string, + bad_wrap: string, base: object, bdo: object, big: object, bind: string, + bitwise: boolean, block: array, blockquote: object, body: object, + border: array, 'border-bottom': array, 'border-bottom-color', + 'border-bottom-style': array, 'border-bottom-width', + 'border-collapse': array, 'border-color': array, 'border-left': array, + 'border-left-color', 'border-left-style': array, 'border-left-width', + 'border-right': array, 'border-right-color', 'border-right-style': array, + 'border-right-width', 'border-spacing': array, 'border-style': array, + 'border-top': array, 'border-top-color', 'border-top-style': array, + 'border-top-width', 'border-width': array, bottom: array, br: object, + braille: boolean, browser: boolean, button: object, c, call: string, + canvas: object, cap, caption: object, 'caption-side': array, ceil: string, + center: object, charAt: *, charCodeAt: *, character, cite: object, + clear: array, clip: array, closure, cm: boolean, code: object, col: object, + colgroup: object, color, combine_var: string, command: object, comment, + comments: array, concat: string, conditional_assignment: string, + confusing_a: string, confusing_regexp: string, confusion: boolean, + constructor: string, constructor_name_a: string, content: array, continue, + control_a: string, 'counter-increment': array, 'counter-reset': array, + create: *, css: string, cursor: array, d, dangerous_comment: string, + dangling_a: string, data: function object, datalist: object, dd: object, + debug, defineProperties: string, defineProperty: string, del: object, + deleted: string, details: object, devel: boolean, dfn: object, + dialog: object, dir: object, direction: array, display: array, + disrupt: boolean, div: object, dl: object, dt: object, duplicate_a: string, + edge: string, edition: string, else, em: *, embed: object, + embossed: boolean, empty: boolean, 'empty-cells': array, + empty_block: string, empty_case: string, empty_class: string, + entityify: function, eqeq, errors: array, es5: string, eval, every: string, + evidence, evil: string, ex: boolean, exception, exec: *, + expected_a: string, expected_a_at_b_c: string, expected_a_b: string, + expected_a_b_from_c_d: string, expected_at_a: string, + expected_attribute_a: string, expected_attribute_value_a: string, + expected_class_a: string, expected_fraction_a: string, + expected_id_a: string, expected_identifier_a: string, + expected_identifier_a_reserved: string, expected_lang_a: string, + expected_linear_a: string, expected_media_a: string, + expected_name_a: string, expected_nonstandard_style_attribute: string, + expected_number_a: string, expected_operator_a: string, + expected_percent_a: string, expected_positive_a: string, + expected_pseudo_a: string, expected_selector_a: string, + expected_small_a: string, expected_space_a_b: string, + expected_string_a: string, expected_style_attribute: string, + expected_style_pattern: string, expected_tagname_a: string, + expected_type_a: string, f: string, fieldset: object, figure: object, + filter: *, first: *, float: array, floor: *, font: *, 'font-family', + 'font-size': array, 'font-size-adjust': array, 'font-stretch': array, + 'font-style': array, 'font-variant': array, 'font-weight': array, + footer: object, forEach: *, for_if: string, forin, form: object, fragment, + frame: object, frameset: object, freeze: string, from: number, + fromCharCode: function, fud: function, funct: object, function, + function_block: string, function_eval: string, function_loop: string, + function_statement: string, function_strict: string, functions: array, + getDate: string, getDay: string, getFullYear: string, getHours: string, + getMilliseconds: string, getMinutes: string, getMonth: string, + getOwnPropertyDescriptor: string, getOwnPropertyNames: string, + getPrototypeOf: string, getSeconds: string, getTime: string, + getTimezoneOffset: string, getUTCDate: string, getUTCDay: string, + getUTCFullYear: string, getUTCHours: string, getUTCMilliseconds: string, + getUTCMinutes: string, getUTCMonth: string, getUTCSeconds: string, + getYear: string, global, globals, h1: object, h2: object, h3: object, + h4: object, h5: object, h6: object, handheld: boolean, hasOwnProperty: *, + head: object, header: object, height: array, hgroup: object, hr: object, + 'hta:application': object, html: *, html_confusion_a: string, + html_handlers: string, i: object, id: string, identifier: boolean, + identifier_function: string, iframe: object, img: object, immed: boolean, + implied_evil: string, in: boolean, indent: number, indexOf: *, + infix_in: string, init: function, input: object, ins: object, + insecure_a: string, isAlpha: function, isArray: function boolean, + isDigit: function, isExtensible: string, isFrozen: string, isNaN: string, + isPrototypeOf: string, isSealed: string, join: *, jslint: function boolean, + json: boolean, kbd: object, keygen: object, keys: *, label: object, + label_a_b: string, labeled: boolean, lang: string, lastIndex: string, + lastIndexOf: *, lbp: number, leading_decimal_a: string, led: function, + left: array, legend: object, length: *, 'letter-spacing': array, + li: object, lib: boolean, line: number, 'line-height': array, link: object, + 'list-style': array, 'list-style-image': array, + 'list-style-position': array, 'list-style-type': array, map: *, + margin: array, 'margin-bottom', 'margin-left', 'margin-right', + 'margin-top', mark: object, 'marker-offset': array, match: function, + 'max-height': array, 'max-width': array, maxerr: number, maxlen: number, + member: object, menu: object, message, meta: object, meter: object, + 'min-height': function, 'min-width': function, missing_a: string, + missing_a_after_b: string, missing_option: string, + missing_property: string, missing_space_a_b: string, missing_url: string, + missing_use_strict: string, mixed: string, mm: boolean, mode: string, + move_invocation: string, move_var: string, n: string, name: string, + name_function: string, nav: object, nested_comment: string, + newcap: boolean, next, node: boolean, noframes: object, nomen, + noscript: object, not: string, not_a_constructor: string, + not_a_defined: string, not_a_function: string, not_a_label: string, + not_a_scope: string, not_greater: string, now: string, nud: function, + number: number, object: object, ol: object, on, opacity, open: boolean, + optgroup: object, option: object, outer: regexp, outline: array, + 'outline-color': array, 'outline-style': array, 'outline-width', + output: object, overflow: array, 'overflow-x': array, 'overflow-y': array, + p: object, padding: array, 'padding-bottom': function, + 'padding-left': function, 'padding-right': function, + 'padding-top': function, 'page-break-after': array, + 'page-break-before': array, param: object, parameter_a_get_b: string, + parameter_set_a: string, params: array, paren: boolean, parent: string, + parse: string, passfail, pc: boolean, plusplus, pop: *, position: array, + postscript: boolean, pre: object, predef, prev, preventExtensions: string, + print: boolean, progress: object, projection: boolean, properties: boolean, + propertyIsEnumerable: string, prototype: string, pt: boolean, push: *, + px: boolean, q: object, quote, quotes: array, r: string, radix: string, + range: function, raw, read_only: string, reason, redefinition_a: string, + reduce: string, reduceRight: string, regexp, replace: function, + report: function, reserved: boolean, reserved_a: string, reverse: string, + rhino: boolean, right: array, rp: object, rt: object, ruby: object, + safe: boolean, samp: object, scanned_a_b: string, screen: boolean, + script: object, seal: string, search: function, second: *, section: object, + select: object, setDate: string, setDay: string, setFullYear: string, + setHours: string, setMilliseconds: string, setMinutes: string, + setMonth: string, setSeconds: string, setTime: string, + setTimezoneOffset: string, setUTCDate: string, setUTCDay: string, + setUTCFullYear: string, setUTCHours: string, setUTCMilliseconds: string, + setUTCMinutes: string, setUTCMonth: string, setUTCSeconds: string, + setYear: string, shift: *, slash_equal: string, slice: string, sloppy, + small: object, some: string, sort: *, source: object, span: object, + speech: boolean, splice: string, split: function, src, + statement_block: string, stopping: string, strange_loop: string, + strict: string, string: string, stringify: string, strong: object, style: *, + styleproperty: regexp, sub: object, subscript: string, substr: *, + substring: string, sup: object, supplant: function, t: string, + table: object, 'table-layout': array, tag_a_in_b: string, tbody: object, + td: object, test: *, 'text-align': array, 'text-decoration': array, + 'text-indent': function, 'text-shadow': array, 'text-transform': array, + textarea: object, tfoot: object, th: object, thead: object, third: array, + thru: number, time: object, title: object, toDateString: string, + toExponential: string, toFixed: string, toISOString: string, + toJSON: string, toLocaleDateString: string, toLocaleLowerCase: string, + toLocaleString: string, toLocaleTimeString: string, + toLocaleUpperCase: string, toLowerCase: *, toPrecision: string, + toString: function, toTimeString: string, toUTCString: string, + toUpperCase: *, token: function, too_long: string, too_many: string, + top: array, tr: object, trailing_decimal_a: string, tree: string, + trim: string, tt: object, tty: boolean, tv: boolean, type: string, + type_confusion_a_b: string, u: object, ul: object, unclosed: string, + unclosed_comment: string, unclosed_regexp: string, undef: boolean, + undefined, unescaped_a: string, unexpected_a: string, + unexpected_char_a_b: string, unexpected_comment: string, + unexpected_property_a: string, unexpected_space_a_b: string, + 'unicode-bidi': array, unnecessary_initialize: string, + unnecessary_use: string, unparam, unreachable_a_b: string, + unrecognized_style_attribute_a: string, unrecognized_tag_a: string, + unsafe: string, unshift: string, unused: array, url: string, urls: array, + use_array: string, use_braces: string, use_charAt: string, + use_object: string, use_or: string, use_param: string, + used_before_a: string, valueOf: string, var: object, + var_a_not: string, vars, 'vertical-align': array, video: object, + visibility: array, was: object, weird_assignment: string, + weird_condition: string, weird_new: string, weird_program: string, + weird_relation: string, weird_ternary: string, white: boolean, + 'white-space': array, widget: boolean, width: array, windows: boolean, + 'word-spacing': array, 'word-wrap': array, wrap: boolean, + wrap_immediate: string, wrap_regexp: string, write_is_wrong: string, + writeable: boolean, 'z-index': array +*/ + +// The global directive is used to declare global variables that can +// be accessed by the program. If a declaration is true, then the variable +// is writeable. Otherwise, it is read-only. + +// We build the application inside a function so that we produce only a single +// global variable. That function will be invoked immediately, and its return +// value is the JSLINT function itself. That function is also an object that +// can contain data and other functions. + +var JSLINT = (function () { + 'use strict'; + + function array_to_object(array, value) { + var i, object = {}; + for (i = 0; i < array.length; i += 1) { + object[array[i]] = value; + } + return object; + } + + + var adsafe_id, // The widget's ADsafe id. + adsafe_may, // The widget may load approved scripts. + adsafe_top, // At the top of the widget script. + adsafe_went, // ADSAFE.go has been called. + anonname, // The guessed name for anonymous functions. + approved, // ADsafe approved urls. + +// These are operators that should not be used with the ! operator. + + bang = { + '<' : true, + '<=' : true, + '==' : true, + '===': true, + '!==': true, + '!=' : true, + '>' : true, + '>=' : true, + '+' : true, + '-' : true, + '*' : true, + '/' : true, + '%' : true + }, + +// These are property names that should not be permitted in the safe subset. + + banned = array_to_object([ + 'arguments', 'callee', 'caller', 'constructor', 'eval', 'prototype', + 'stack', 'unwatch', 'valueOf', 'watch' + ], true), + begin, // The root token + +// browser contains a set of global names that are commonly provided by a +// web browser environment. + + browser = array_to_object([ + 'clearInterval', 'clearTimeout', 'document', 'event', 'frames', + 'history', 'Image', 'localStorage', 'location', 'name', 'navigator', + 'Option', 'parent', 'screen', 'sessionStorage', 'setInterval', + 'setTimeout', 'Storage', 'window', 'XMLHttpRequest' + ], false), + +// bundle contains the text messages. + + bundle = { + a_label: "'{a}' is a statement label.", + a_not_allowed: "'{a}' is not allowed.", + a_not_defined: "'{a}' is not defined.", + a_scope: "'{a}' used out of scope.", + adsafe_a: "ADsafe violation: '{a}'.", + adsafe_autocomplete: "ADsafe autocomplete violation.", + adsafe_bad_id: "ADSAFE violation: bad id.", + adsafe_div: "ADsafe violation: Wrap the widget in a div.", + adsafe_fragment: "ADSAFE: Use the fragment option.", + adsafe_go: "ADsafe violation: Misformed ADSAFE.go.", + adsafe_html: "Currently, ADsafe does not operate on whole HTML " + + "documents. It operates on
fragments and .js files.", + adsafe_id: "ADsafe violation: id does not match.", + adsafe_id_go: "ADsafe violation: Missing ADSAFE.id or ADSAFE.go.", + adsafe_lib: "ADsafe lib violation.", + adsafe_lib_second: "ADsafe: The second argument to lib must be a function.", + adsafe_missing_id: "ADSAFE violation: missing ID_.", + adsafe_name_a: "ADsafe name violation: '{a}'.", + adsafe_placement: "ADsafe script placement violation.", + adsafe_prefix_a: "ADsafe violation: An id must have a '{a}' prefix", + adsafe_script: "ADsafe script violation.", + adsafe_source: "ADsafe unapproved script source.", + adsafe_subscript_a: "ADsafe subscript '{a}'.", + adsafe_tag: "ADsafe violation: Disallowed tag '{a}'.", + already_defined: "'{a}' is already defined.", + and: "The '&&' subexpression should be wrapped in parens.", + assign_exception: "Do not assign to the exception parameter.", + assignment_function_expression: "Expected an assignment or " + + "function call and instead saw an expression.", + attribute_case_a: "Attribute '{a}' not all lower case.", + avoid_a: "Avoid '{a}'.", + bad_assignment: "Bad assignment.", + bad_color_a: "Bad hex color '{a}'.", + bad_constructor: "Bad constructor.", + bad_entity: "Bad entity.", + bad_html: "Bad HTML string", + bad_id_a: "Bad id: '{a}'.", + bad_in_a: "Bad for in variable '{a}'.", + bad_invocation: "Bad invocation.", + bad_name_a: "Bad name: '{a}'.", + bad_new: "Do not use 'new' for side effects.", + bad_number: "Bad number '{a}'.", + bad_operand: "Bad operand.", + bad_type: "Bad type.", + bad_url: "Bad url string.", + bad_wrap: "Do not wrap function literals in parens unless they " + + "are to be immediately invoked.", + combine_var: "Combine this with the previous 'var' statement.", + conditional_assignment: "Expected a conditional expression and " + + "instead saw an assignment.", + confusing_a: "Confusing use of '{a}'.", + confusing_regexp: "Confusing regular expression.", + constructor_name_a: "A constructor name '{a}' should start with " + + "an uppercase letter.", + control_a: "Unexpected control character '{a}'.", + css: "A css file should begin with @charset 'UTF-8';", + dangling_a: "Unexpected dangling '_' in '{a}'.", + dangerous_comment: "Dangerous comment.", + deleted: "Only properties should be deleted.", + duplicate_a: "Duplicate '{a}'.", + empty_block: "Empty block.", + empty_case: "Empty case.", + empty_class: "Empty class.", + es5: "This is an ES5 feature.", + evil: "eval is evil.", + expected_a: "Expected '{a}'.", + expected_a_b: "Expected '{a}' and instead saw '{b}'.", + expected_a_b_from_c_d: "Expected '{a}' to match '{b}' from line " + + "{c} and instead saw '{d}'.", + expected_at_a: "Expected an at-rule, and instead saw @{a}.", + expected_a_at_b_c: "Expected '{a}' at column {b}, not column {c}.", + expected_attribute_a: "Expected an attribute, and instead saw [{a}].", + expected_attribute_value_a: "Expected an attribute value and " + + "instead saw '{a}'.", + expected_class_a: "Expected a class, and instead saw .{a}.", + expected_fraction_a: "Expected a number between 0 and 1 and " + + "instead saw '{a}'", + expected_id_a: "Expected an id, and instead saw #{a}.", + expected_identifier_a: "Expected an identifier and instead saw '{a}'.", + expected_identifier_a_reserved: "Expected an identifier and " + + "instead saw '{a}' (a reserved word).", + expected_linear_a: "Expected a linear unit and instead saw '{a}'.", + expected_lang_a: "Expected a lang code, and instead saw :{a}.", + expected_media_a: "Expected a CSS media type, and instead saw '{a}'.", + expected_name_a: "Expected a name and instead saw '{a}'.", + expected_nonstandard_style_attribute: "Expected a non-standard " + + "style attribute and instead saw '{a}'.", + expected_number_a: "Expected a number and instead saw '{a}'.", + expected_operator_a: "Expected an operator and instead saw '{a}'.", + expected_percent_a: "Expected a percentage and instead saw '{a}'", + expected_positive_a: "Expected a positive number and instead saw '{a}'", + expected_pseudo_a: "Expected a pseudo, and instead saw :{a}.", + expected_selector_a: "Expected a CSS selector, and instead saw {a}.", + expected_small_a: "Expected a small number and instead saw '{a}'", + expected_space_a_b: "Expected exactly one space between '{a}' and '{b}'.", + expected_string_a: "Expected a string and instead saw {a}.", + expected_style_attribute: "Excepted a style attribute, and instead saw '{a}'.", + expected_style_pattern: "Expected a style pattern, and instead saw '{a}'.", + expected_tagname_a: "Expected a tagName, and instead saw {a}.", + expected_type_a: "Expected a type, and instead saw {a}.", + for_if: "The body of a for in should be wrapped in an if " + + "statement to filter unwanted properties from the prototype.", + function_block: "Function statements should not be placed in blocks. " + + "Use a function expression or move the statement to the top of " + + "the outer function.", + function_eval: "The Function constructor is eval.", + function_loop: "Don't make functions within a loop.", + function_statement: "Function statements are not invocable. " + + "Wrap the whole function invocation in parens.", + function_strict: "Use the function form of 'use strict'.", + html_confusion_a: "HTML confusion in regular expression '<{a}'.", + html_handlers: "Avoid HTML event handlers.", + identifier_function: "Expected an identifier in an assignment " + + "and instead saw a function invocation.", + implied_evil: "Implied eval is evil. Pass a function instead of a string.", + infix_in: "Unexpected 'in'. Compare with undefined, or use the " + + "hasOwnProperty method instead.", + insecure_a: "Insecure '{a}'.", + isNaN: "Use the isNaN function to compare with NaN.", + label_a_b: "Label '{a}' on '{b}' statement.", + lang: "lang is deprecated.", + leading_decimal_a: "A leading decimal point can be confused with a dot: '.{a}'.", + missing_a: "Missing '{a}'.", + missing_a_after_b: "Missing '{a}' after '{b}'.", + missing_option: "Missing option value.", + missing_property: "Missing property name.", + missing_space_a_b: "Missing space between '{a}' and '{b}'.", + missing_url: "Missing url.", + missing_use_strict: "Missing 'use strict' statement.", + mixed: "Mixed spaces and tabs.", + move_invocation: "Move the invocation into the parens that " + + "contain the function.", + move_var: "Move 'var' declarations to the top of the function.", + name_function: "Missing name in function statement.", + nested_comment: "Nested comment.", + not: "Nested not.", + not_a_constructor: "Do not use {a} as a constructor.", + not_a_defined: "'{a}' has not been fully defined yet.", + not_a_function: "'{a}' is not a function.", + not_a_label: "'{a}' is not a label.", + not_a_scope: "'{a}' is out of scope.", + not_greater: "'{a}' should not be greater than '{b}'.", + parameter_a_get_b: "Unexpected parameter '{a}' in get {b} function.", + parameter_set_a: "Expected parameter (value) in set {a} function.", + radix: "Missing radix parameter.", + read_only: "Read only.", + redefinition_a: "Redefinition of '{a}'.", + reserved_a: "Reserved name '{a}'.", + scanned_a_b: "{a} ({b}% scanned).", + slash_equal: "A regular expression literal can be confused with '/='.", + statement_block: "Expected to see a statement and instead saw a block.", + stopping: "Stopping. ", + strange_loop: "Strange loop.", + strict: "Strict violation.", + subscript: "['{a}'] is better written in dot notation.", + tag_a_in_b: "A '<{a}>' must be within '<{b}>'.", + too_long: "Line too long.", + too_many: "Too many errors.", + trailing_decimal_a: "A trailing decimal point can be confused " + + "with a dot: '.{a}'.", + type: "type is unnecessary.", + type_confusion_a_b: "Type confusion: {a} and {b}.", + unclosed: "Unclosed string.", + unclosed_comment: "Unclosed comment.", + unclosed_regexp: "Unclosed regular expression.", + unescaped_a: "Unescaped '{a}'.", + unexpected_a: "Unexpected '{a}'.", + unexpected_char_a_b: "Unexpected character '{a}' in {b}.", + unexpected_comment: "Unexpected comment.", + unexpected_property_a: "Unexpected /*property*/ '{a}'.", + unexpected_space_a_b: "Unexpected space between '{a}' and '{b}'.", + unnecessary_initialize: "It is not necessary to initialize '{a}' " + + "to 'undefined'.", + unnecessary_use: "Unnecessary 'use strict'.", + unreachable_a_b: "Unreachable '{a}' after '{b}'.", + unrecognized_style_attribute_a: "Unrecognized style attribute '{a}'.", + unrecognized_tag_a: "Unrecognized tag '<{a}>'.", + unsafe: "Unsafe character.", + url: "JavaScript URL.", + use_array: "Use the array literal notation [].", + use_braces: "Spaces are hard to count. Use {{a}}.", + use_charAt: "Use the charAt method.", + use_object: "Use the object literal notation {}.", + use_or: "Use the || operator.", + use_param: "Use a named parameter.", + used_before_a: "'{a}' was used before it was defined.", + var_a_not: "Variable {a} was not declared correctly.", + weird_assignment: "Weird assignment.", + weird_condition: "Weird condition.", + weird_new: "Weird construction. Delete 'new'.", + weird_program: "Weird program.", + weird_relation: "Weird relation.", + weird_ternary: "Weird ternary.", + wrap_immediate: "Wrap an immediate function invocation in parentheses " + + "to assist the reader in understanding that the expression " + + "is the result of a function, and not the function itself.", + wrap_regexp: "Wrap the /regexp/ literal in parens to " + + "disambiguate the slash operator.", + write_is_wrong: "document.write can be a form of eval." + }, + comments_off, + css_attribute_data, + css_any, + + css_colorData = array_to_object([ + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", + "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", + "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", + "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", + "darkred", "darksalmon", "darkseagreen", "darkslateblue", + "darkslategray", "darkturquoise", "darkviolet", "deeppink", + "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", + "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", + "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink", + "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", + "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen", + "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", + "lightslategray", "lightsteelblue", "lightyellow", "lime", + "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", + "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", + "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", + "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", + "orange", "orangered", "orchid", "palegoldenrod", "palegreen", + "paleturquoise", "palevioletred", "papayawhip", "peachpuff", + "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown", + "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", + "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", + "snow", "springgreen", "steelblue", "tan", "teal", "thistle", + "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", + "yellow", "yellowgreen", + + "activeborder", "activecaption", "appworkspace", "background", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", + "captiontext", "graytext", "highlight", "highlighttext", + "inactiveborder", "inactivecaption", "inactivecaptiontext", + "infobackground", "infotext", "menu", "menutext", "scrollbar", + "threeddarkshadow", "threedface", "threedhighlight", + "threedlightshadow", "threedshadow", "window", "windowframe", + "windowtext" + ], true), + + css_border_style, + css_break, + + css_lengthData = { + '%': true, + 'cm': true, + 'em': true, + 'ex': true, + 'in': true, + 'mm': true, + 'pc': true, + 'pt': true, + 'px': true + }, + + css_media, + css_overflow, + + descapes = { + 'b': '\b', + 't': '\t', + 'n': '\n', + 'f': '\f', + 'r': '\r', + '"': '"', + '/': '/', + '\\': '\\' + }, + + devel = array_to_object([ + 'alert', 'confirm', 'console', 'Debug', 'opera', 'prompt' + ], false), + + escapes = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\'': '\\\'', + '"' : '\\"', + '/' : '\\/', + '\\': '\\\\' + }, + + funct, // The current function, including the labels used + // in the function, as well as (verb), (context), + // (statement), (name), (params), (complexity), + // (loopage), (breakage), (vars) + + functionicity = [ + 'closure', 'exception', 'global', 'label', 'outer', 'undef', + 'unused', 'var' + ], + + functions, // All of the functions + global_funct, // The global body + global_scope, // The global scope + html_tag = { + a: {}, + abbr: {}, + acronym: {}, + address: {}, + applet: {}, + area: {empty: true, parent: ' map '}, + article: {}, + aside: {}, + audio: {}, + b: {}, + base: {empty: true, parent: ' head '}, + bdo: {}, + big: {}, + blockquote: {}, + body: {parent: ' html noframes '}, + br: {empty: true}, + button: {}, + canvas: {parent: ' body p div th td '}, + caption: {parent: ' table '}, + center: {}, + cite: {}, + code: {}, + col: {empty: true, parent: ' table colgroup '}, + colgroup: {parent: ' table '}, + command: {parent: ' menu '}, + datalist: {}, + dd: {parent: ' dl '}, + del: {}, + details: {}, + dialog: {}, + dfn: {}, + dir: {}, + div: {}, + dl: {}, + dt: {parent: ' dl '}, + em: {}, + embed: {}, + fieldset: {}, + figure: {}, + font: {}, + footer: {}, + form: {}, + frame: {empty: true, parent: ' frameset '}, + frameset: {parent: ' html frameset '}, + h1: {}, + h2: {}, + h3: {}, + h4: {}, + h5: {}, + h6: {}, + head: {parent: ' html '}, + header: {}, + hgroup: {}, + hr: {empty: true}, + 'hta:application': + {empty: true, parent: ' head '}, + html: {parent: '*'}, + i: {}, + iframe: {}, + img: {empty: true}, + input: {empty: true}, + ins: {}, + kbd: {}, + keygen: {}, + label: {}, + legend: {parent: ' details fieldset figure '}, + li: {parent: ' dir menu ol ul '}, + link: {empty: true, parent: ' head '}, + map: {}, + mark: {}, + menu: {}, + meta: {empty: true, parent: ' head noframes noscript '}, + meter: {}, + nav: {}, + noframes: {parent: ' html body '}, + noscript: {parent: ' body head noframes '}, + object: {}, + ol: {}, + optgroup: {parent: ' select '}, + option: {parent: ' optgroup select '}, + output: {}, + p: {}, + param: {empty: true, parent: ' applet object '}, + pre: {}, + progress: {}, + q: {}, + rp: {}, + rt: {}, + ruby: {}, + samp: {}, + script: {empty: true, parent: ' body div frame head iframe p pre span '}, + section: {}, + select: {}, + small: {}, + span: {}, + source: {}, + strong: {}, + style: {parent: ' head ', empty: true}, + sub: {}, + sup: {}, + table: {}, + tbody: {parent: ' table '}, + td: {parent: ' tr '}, + textarea: {}, + tfoot: {parent: ' table '}, + th: {parent: ' tr '}, + thead: {parent: ' table '}, + time: {}, + title: {parent: ' head '}, + tr: {parent: ' table tbody thead tfoot '}, + tt: {}, + u: {}, + ul: {}, + 'var': {}, + video: {} + }, + + ids, // HTML ids + in_block, + indent, + is_type = array_to_object([ + '*', 'array', 'boolean', 'function', 'number', 'object', + 'regexp', 'string' + ], true), + itself, // JSLint itself + json_mode, + lex, // the tokenizer + lines, + lookahead, + member, + node = array_to_object([ + 'Buffer', 'clearInterval', 'clearTimeout', 'console', 'exports', + 'global', 'module', 'process', 'querystring', 'require', + 'setInterval', 'setTimeout', '__dirname', '__filename' + ], false), + node_js, + numbery = array_to_object(['indexOf', 'lastIndexOf', 'search'], true), + next_token, + older_token, + option, + predefined, // Global variables defined by option + prereg, + prev_token, + property_type, + regexp_flag = array_to_object(['g', 'i', 'm'], true), + rhino = array_to_object([ + 'defineClass', 'deserialize', 'gc', 'help', 'load', 'loadClass', + 'print', 'quit', 'readFile', 'readUrl', 'runCommand', 'seal', + 'serialize', 'spawn', 'sync', 'toint32', 'version' + ], false), + + scope, // An object containing an object for each variable in scope + semicolon_coda = array_to_object([';', '"', '\'', ')'], true), + src, + stack, + +// standard contains the global names that are provided by the +// ECMAScript standard. + + standard = array_to_object([ + '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' + ], false), + + standard_property_type = { + E : 'number', + LN2 : 'number', + LN10 : 'number', + LOG2E : 'number', + LOG10E : 'number', + MAX_VALUE : 'number', + MIN_VALUE : 'number', + NEGATIVE_INFINITY : 'number', + PI : 'number', + POSITIVE_INFINITY : 'number', + SQRT1_2 : 'number', + SQRT2 : 'number', + apply : 'function', + bind : 'function function', + call : 'function', + ceil : 'function number', + charAt : 'function string', + concat : 'function', + constructor : 'function object', + create : 'function object', + defineProperty : 'function object', + defineProperties : 'function object', + every : 'function boolean', + exec : 'function array', + filter : 'function array', + floor : 'function number', + forEach : 'function', + freeze : 'function object', + getDate : 'function number', + getDay : 'function number', + getFullYear : 'function number', + getHours : 'function number', + getMilliseconds : 'function number', + getMinutes : 'function number', + getMonth : 'function number', + getOwnPropertyDescriptor + : 'function object', + getOwnPropertyNames : 'function array', + getPrototypeOf : 'function object', + getSeconds : 'function number', + getTime : 'function number', + getTimezoneOffset : 'function number', + getUTCDate : 'function number', + getUTCDay : 'function number', + getUTCFullYear : 'function number', + getUTCHours : 'function number', + getUTCMilliseconds : 'function number', + getUTCMinutes : 'function number', + getUTCMonth : 'function number', + getUTCSeconds : 'function number', + getYear : 'function number', + hasOwnProperty : 'function boolean', + indexOf : 'function number', + isExtensible : 'function boolean', + isFrozen : 'function boolean', + isPrototypeOf : 'function boolean', + isSealed : 'function boolean', + join : 'function string', + keys : 'function array', + lastIndexOf : 'function number', + lastIndex : 'number', + length : 'number', + map : 'function array', + now : 'function number', + parse : 'function', + pop : 'function', + preventExtensions : 'function object', + propertyIsEnumerable: 'function boolean', + prototype : 'object', + push : 'function number', + reduce : 'function', + reduceRight : 'function', + reverse : 'function', + seal : 'function object', + setDate : 'function', + setDay : 'function', + setFullYear : 'function', + setHours : 'function', + setMilliseconds : 'function', + setMinutes : 'function', + setMonth : 'function', + setSeconds : 'function', + setTime : 'function', + setTimezoneOffset : 'function', + setUTCDate : 'function', + setUTCDay : 'function', + setUTCFullYear : 'function', + setUTCHours : 'function', + setUTCMilliseconds : 'function', + setUTCMinutes : 'function', + setUTCMonth : 'function', + setUTCSeconds : 'function', + setYear : 'function', + shift : 'function', + slice : 'function', + some : 'function boolean', + sort : 'function', + splice : 'function', + stringify : 'function string', + substr : 'function string', + substring : 'function string', + test : 'function boolean', + toDateString : 'function string', + toExponential : 'function string', + toFixed : 'function string', + toJSON : 'function', + toISOString : 'function string', + toLocaleDateString : 'function string', + toLocaleLowerCase : 'function string', + toLocaleUpperCase : 'function string', + toLocaleString : 'function string', + toLocaleTimeString : 'function string', + toLowerCase : 'function string', + toPrecision : 'function string', + toTimeString : 'function string', + toUpperCase : 'function string', + toUTCString : 'function string', + trim : 'function string', + unshift : 'function number', + valueOf : 'function' + }, + + strict_mode, + syntax = {}, + tab, + token, + urls, + var_mode, + warnings, + +// widget contains the global names which are provided to a Yahoo +// (fna Konfabulator) widget. + + widget = array_to_object([ + 'alert', 'animator', 'appleScript', 'beep', 'bytesToUIString', + 'Canvas', 'chooseColor', 'chooseFile', 'chooseFolder', + 'closeWidget', 'COM', 'convertPathToHFS', 'convertPathToPlatform', + 'CustomAnimation', 'escape', 'FadeAnimation', 'filesystem', 'Flash', + 'focusWidget', 'form', 'FormField', 'Frame', 'HotKey', 'Image', + 'include', 'isApplicationRunning', 'iTunes', 'konfabulatorVersion', + 'log', 'md5', 'MenuItem', 'MoveAnimation', 'openURL', 'play', + 'Point', 'popupMenu', 'preferenceGroups', 'preferences', 'print', + 'prompt', 'random', 'Rectangle', 'reloadWidget', 'ResizeAnimation', + 'resolvePath', 'resumeUpdates', 'RotateAnimation', 'runCommand', + 'runCommandInBg', 'saveAs', 'savePreferences', 'screen', + 'ScrollBar', 'showWidgetPreferences', 'sleep', 'speak', 'Style', + 'suppressUpdates', 'system', 'tellWidget', 'Text', 'TextArea', + 'Timer', 'unescape', 'updateNow', 'URL', 'Web', 'widget', 'Window', + 'XMLDOM', 'XMLHttpRequest', 'yahooCheckLogin', 'yahooLogin', + 'yahooLogout' + ], true), + + windows = array_to_object([ + 'ActiveXObject', 'CScript', 'Debug', 'Enumerator', 'System', + 'VBArray', 'WScript' + ], false), + +// xmode is used to adapt to the exceptions in html parsing. +// It can have these states: +// '' .js script file +// 'html' +// 'outer' +// 'script' +// 'style' +// 'scriptstring' +// 'styleproperty' + + xmode, + xquote, + +// Regular expressions. Some of these are stupidly long. + +// unsafe comment or string + ax = /@cc|<\/?|script|\]\s*\]|<\s*!|</i, +// carriage return, or carriage return linefeed + crx = /\r/g, + crlfx = /\r\n/g, +// unsafe characters that are silently deleted by one or more browsers + cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/, +// query characters for ids + dx = /[\[\]\/\\"'*<>.&:(){}+=#]/, +// html token + hx = /^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-:]*|[0-9]+|--)/, +// identifier + ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/, +// javascript url + jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i, +// star slash + lx = /\*\/|\/\*/, +// characters in strings that need escapement + nx = /[\u0000-\u001f'\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, +// outer html token + ox = /[>&]|<[\/!]?|--/, +// attributes characters + qx = /[^a-zA-Z0-9+\-_\/ ]/, +// style + sx = /^\s*([{:#%.=,>+\[\]@()"';]|\*=?|\$=|\|=|\^=|~=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/, + ssx = /^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/, +// token + tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|properties|property|members?|globals?)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/, +// url badness + ux = /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i, + + rx = { + outer: hx, + html: hx, + style: sx, + styleproperty: ssx + }; + + + function return_this() { + return this; + } + + function F() {} // Used by Object.create + +// Provide critical ES5 functions to ES3. + + if (typeof Array.prototype.filter !== 'function') { + Array.prototype.filter = function (f) { + var i, length = this.length, result = [], value; + for (i = 0; i < length; i += 1) { + try { + value = this[i]; + if (f(value)) { + result.push(value); + } + } catch (ignore) { + } + } + return result; + }; + } + + if (typeof Array.prototype.forEach !== 'function') { + Array.prototype.forEach = function (f) { + var i, length = this.length; + for (i = 0; i < length; i += 1) { + try { + f(this[i]); + } catch (ignore) { + } + } + }; + } + + if (typeof Array.isArray !== 'function') { + Array.isArray = function (o) { + return Object.prototype.toString.apply(o) === '[object Array]'; + }; + } + + if (!Object.prototype.hasOwnProperty.call(Object, 'create')) { + Object.create = function (o) { + F.prototype = o; + return new F(); + }; + } + + if (typeof Object.keys !== 'function') { + Object.keys = function (o) { + var array = [], key; + for (key in o) { + if (Object.prototype.hasOwnProperty.call(o, key)) { + array.push(key); + } + } + return array; + }; + } + + if (typeof String.prototype.entityify !== 'function') { + String.prototype.entityify = function () { + return this + .replace(/&/g, '&') + .replace(//g, '>'); + }; + } + + if (typeof String.prototype.isAlpha !== 'function') { + String.prototype.isAlpha = function () { + return (this >= 'a' && this <= 'z\uffff') || + (this >= 'A' && this <= 'Z\uffff'); + }; + } + + if (typeof String.prototype.isDigit !== 'function') { + String.prototype.isDigit = function () { + return (this >= '0' && this <= '9'); + }; + } + + if (typeof String.prototype.supplant !== 'function') { + String.prototype.supplant = function (o) { + return this.replace(/\{([^{}]*)\}/g, function (a, b) { + var replacement = o[b]; + return typeof replacement === 'string' || + typeof replacement === 'number' ? replacement : a; + }); + }; + } + + + function sanitize(a) { + +// Escapify a troublesome character. + + return escapes[a] || + '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4); + } + + + function add_to_predefined(group) { + Object.keys(group).forEach(function (name) { + predefined[name] = group[name]; + }); + } + + + function assume() { + if (!option.safe) { + if (option.rhino) { + add_to_predefined(rhino); + option.rhino = false; + } + if (option.devel) { + add_to_predefined(devel); + option.devel = false; + } + if (option.browser) { + add_to_predefined(browser); + option.browser = false; + } + if (option.windows) { + add_to_predefined(windows); + option.windows = false; + } + if (option.node) { + add_to_predefined(node); + option.node = false; + node_js = true; + } + if (option.widget) { + add_to_predefined(widget); + option.widget = false; + } + } + if (option.type) { + option.confusion = true; + } + } + + +// Produce an error warning. + + function quit(message, line, character) { + throw { + name: 'JSLintError', + line: line, + character: character, + message: bundle.scanned_a_b.supplant({ + a: message, + b: Math.floor((line / lines.length) * 100) + }) + }; + } + + function warn(message, offender, a, b, c, d) { + var character, line, warning; + offender = offender || next_token; // `~ + line = offender.line || 0; + character = offender.from || 0; + warning = { + id: '(error)', + raw: bundle[message] || message, + evidence: lines[line - 1] || '', + line: line, + character: character, + a: a || (offender.id === '(number)' ? + String(offender.number) : offender.string), + b: b, + c: c, + d: d + }; + warning.reason = warning.raw.supplant(warning); + JSLINT.errors.push(warning); + if (option.passfail) { + quit(bundle.stopping, line, character); + } + warnings += 1; + if (warnings >= option.maxerr) { + quit(bundle.too_many, line, character); + } + return warning; + } + + function warn_at(message, line, character, a, b, c, d) { + return warn(message, { + line: line, + from: character + }, a, b, c, d); + } + + function stop(message, offender, a, b, c, d) { + var warning = warn(message, offender, a, b, c, d); + quit(bundle.stopping, warning.line, warning.character); + } + + function stop_at(message, line, character, a, b, c, d) { + return stop(message, { + line: line, + from: character + }, a, b, c, d); + } + + function expected_at(at) { + if (!option.white && next_token.from !== at) { + warn('expected_a_at_b_c', next_token, '', at, + next_token.from); + } + } + + function aint(it, name, expected) { + if (it[name] !== expected) { + warn('expected_a_b', it, expected, it[name]); + return true; + } else { + return false; + } + } + + +// lexical analysis and token construction + + lex = (function lex() { + var character, c, from, length, line, pos, source_row; + +// Private lex methods + + function collect_comment(comment, quote, line, at) { + var comment_object = { + comment: comment, + quote: quote, + at: at, + line: line + }; + if (comments_off || src || (xmode && xmode !== 'script' && + xmode !== 'style' && xmode !== 'styleproperty')) { + warn_at('unexpected_comment', line, character); + } else if (xmode === 'script' && /<\//i.test(source_row)) { + warn_at('unexpected_a', line, character, '<\/'); + } else if (option.safe && ax.test(comment)) { + warn_at('dangerous_comment', line, at); + } + if (older_token.comments) { + older_token.comments.push(comment_object); + } else { + older_token.comments = [comment_object]; + } + JSLINT.comments.push(comment_object); + } + + function next_line() { + var at; + if (line >= lines.length) { + return false; + } + character = 1; + source_row = lines[line]; + line += 1; + at = source_row.search(/ \t/); + if (at >= 0) { + warn_at('mixed', line, at + 1); + } + source_row = source_row.replace(/\t/g, tab); + at = source_row.search(cx); + if (at >= 0) { + warn_at('unsafe', line, at); + } + if (option.maxlen && option.maxlen < source_row.length) { + warn_at('too_long', line, source_row.length); + } + return true; + } + +// Produce a token object. The token inherits from a syntax symbol. + + function it(type, value, quote) { + var id, the_token; + if (type === '(string)' || type === '(range)') { + if (jx.test(value)) { + warn_at('url', line, from); + } + } + the_token = Object.create(syntax[( + type === '(punctuator)' || + (type === '(identifier)' && + Object.prototype.hasOwnProperty.call(syntax, value)) ? + value : + type + )] || syntax['(error)']); + if (type === '(identifier)') { + the_token.identifier = true; + if (value === '__iterator__' || value === '__proto__') { + stop_at('reserved_a', line, from, value); + } else if (!option.nomen && + (value.charAt(0) === '_' || + value.charAt(value.length - 1) === '_')) { + warn_at('dangling_a', line, from, value); + } + } + if (type === '(number)') { + the_token.number = +value; + } else if (value !== undefined) { + the_token.string = String(value); + } + if (quote) { + the_token.quote = quote; + } + the_token.line = line; + the_token.from = from; + the_token.thru = character; + the_token.prev = older_token; + id = the_token.id; + prereg = id && ( + ('(,=:[!&|?{};'.indexOf(id.charAt(id.length - 1)) >= 0) || + id === 'return' + ); + older_token.next = the_token; + older_token = the_token; + return the_token; + } + + function match(x) { + var exec = x.exec(source_row), first; + if (exec) { + length = exec[0].length; + first = exec[1]; + c = first.charAt(0); + source_row = source_row.slice(length); + from = character + length - first.length; + character += length; + return first; + } + } + + function string(x) { + var c, pos = 0, r = ''; + + function hex(n) { + var i = parseInt(source_row.substr(pos + 1, n), 16); + pos += n; + if (i >= 32 && i <= 126 && + i !== 34 && i !== 92 && i !== 39) { + warn_at('unexpected_a', line, character, '\\'); + } + character += n; + c = String.fromCharCode(i); + } + + if (json_mode && x !== '"') { + warn_at('expected_a', line, character, '"'); + } + + if (xquote === x || (xmode === 'scriptstring' && !xquote)) { + return it('(punctuator)', x); + } + + for (;;) { + while (pos >= source_row.length) { + pos = 0; + if (xmode !== 'html' || !next_line()) { + stop_at('unclosed', line, from); + } + } + c = source_row.charAt(pos); + if (c === x) { + character += 1; + source_row = source_row.slice(pos + 1); + return it('(string)', r, x); + } + if (c < ' ') { + if (c === '\n' || c === '\r') { + break; + } + warn_at('control_a', + line, character + pos, source_row.slice(0, pos)); + } else if (c === xquote) { + warn_at('bad_html', line, character + pos); + } else if (c === '<') { + if (option.safe && xmode === 'html') { + warn_at('adsafe_a', line, character + pos, c); + } else if (source_row.charAt(pos + 1) === '/' && (xmode || option.safe)) { + warn_at('expected_a_b', line, character, + '<\\/', ' 0) { + warn_at('unescaped_a', + line, from + length, '/'); + } + c = source_row.slice(0, length - 1); + flag = Object.create(regexp_flag); + while (flag[source_row.charAt(length)] === true) { + flag[source_row.charAt(length)] = false; + length += 1; + } + if (source_row.charAt(length).isAlpha()) { + stop_at('unexpected_a', + line, from, source_row.charAt(length)); + } + character += length; + source_row = source_row.slice(length); + quote = source_row.charAt(0); + if (quote === '/' || quote === '*') { + stop_at('confusing_regexp', + line, from); + } + return it('(regexp)', c); + case '\\': + c = source_row.charAt(length); + if (c < ' ') { + warn_at('control_a', + line, from + length, String(c)); + } else if (c === '<') { + warn_at( + bundle.unexpected_a, + line, + from + length, + '\\' + ); + } + length += 1; + break; + case '(': + depth += 1; + b = false; + if (source_row.charAt(length) === '?') { + length += 1; + switch (source_row.charAt(length)) { + case ':': + case '=': + case '!': + length += 1; + break; + default: + warn_at( + bundle.expected_a_b, + line, + from + length, + ':', + source_row.charAt(length) + ); + } + } else { + captures += 1; + } + break; + case '|': + b = false; + break; + case ')': + if (depth === 0) { + warn_at('unescaped_a', + line, from + length, ')'); + } else { + depth -= 1; + } + break; + case ' ': + pos = 1; + while (source_row.charAt(length) === ' ') { + length += 1; + pos += 1; + } + if (pos > 1) { + warn_at('use_braces', + line, from + length, pos); + } + break; + case '[': + c = source_row.charAt(length); + if (c === '^') { + length += 1; + if (!option.regexp) { + warn_at('insecure_a', + line, from + length, c); + } else if (source_row.charAt(length) === ']') { + stop_at('unescaped_a', + line, from + length, '^'); + } + } + bit = false; + if (c === ']') { + warn_at('empty_class', line, + from + length - 1); + bit = true; + } +klass: do { + c = source_row.charAt(length); + length += 1; + switch (c) { + case '[': + case '^': + warn_at('unescaped_a', + line, from + length, c); + bit = true; + break; + case '-': + if (bit) { + bit = false; + } else { + warn_at('unescaped_a', + line, from + length, '-'); + bit = true; + } + break; + case ']': + if (!bit) { + warn_at('unescaped_a', + line, from + length - 1, '-'); + } + break klass; + case '\\': + c = source_row.charAt(length); + if (c < ' ') { + warn_at( + bundle.control_a, + line, + from + length, + String(c) + ); + } else if (c === '<') { + warn_at( + bundle.unexpected_a, + line, + from + length, + '\\' + ); + } + length += 1; + bit = true; + break; + case '/': + warn_at('unescaped_a', + line, from + length - 1, '/'); + bit = true; + break; + case '<': + if (xmode === 'script') { + c = source_row.charAt(length); + if (c === '!' || c === '/') { + warn_at( + bundle.html_confusion_a, + line, + from + length, + c + ); + } + } + bit = true; + break; + default: + bit = true; + } + } while (c); + break; + case '.': + if (!option.regexp) { + warn_at('insecure_a', line, + from + length, c); + } + break; + case ']': + case '?': + case '{': + case '}': + case '+': + case '*': + warn_at('unescaped_a', line, + from + length, c); + break; + case '<': + if (xmode === 'script') { + c = source_row.charAt(length); + if (c === '!' || c === '/') { + warn_at( + bundle.html_confusion_a, + line, + from + length, + c + ); + } + } + break; + } + if (b) { + switch (source_row.charAt(length)) { + case '?': + case '+': + case '*': + length += 1; + if (source_row.charAt(length) === '?') { + length += 1; + } + break; + case '{': + length += 1; + c = source_row.charAt(length); + if (c < '0' || c > '9') { + warn_at( + bundle.expected_number_a, + line, + from + length, + c + ); + } + length += 1; + low = +c; + for (;;) { + c = source_row.charAt(length); + if (c < '0' || c > '9') { + break; + } + length += 1; + low = +c + (low * 10); + } + high = low; + if (c === ',') { + length += 1; + high = Infinity; + c = source_row.charAt(length); + if (c >= '0' && c <= '9') { + length += 1; + high = +c; + for (;;) { + c = source_row.charAt(length); + if (c < '0' || c > '9') { + break; + } + length += 1; + high = +c + (high * 10); + } + } + } + if (source_row.charAt(length) !== '}') { + warn_at( + bundle.expected_a_b, + line, + from + length, + '}', + c + ); + } else { + length += 1; + } + if (source_row.charAt(length) === '?') { + length += 1; + } + if (low > high) { + warn_at( + bundle.not_greater, + line, + from + length, + low, + high + ); + } + break; + } + } + } + c = source_row.slice(0, length - 1); + character += length; + source_row = source_row.slice(length); + return it('(regexp)', c); + } + +// Public lex methods + + return { + init: function (source) { + if (typeof source === 'string') { + lines = source + .replace(crlfx, '\n') + .replace(crx, '\n') + .split('\n'); + } else { + lines = source; + } + line = 0; + next_line(); + from = 1; + }, + + range: function (begin, end) { + var c, value = ''; + from = character; + if (source_row.charAt(0) !== begin) { + stop_at('expected_a_b', line, character, begin, + source_row.charAt(0)); + } + for (;;) { + source_row = source_row.slice(1); + character += 1; + c = source_row.charAt(0); + switch (c) { + case '': + stop_at('missing_a', line, character, c); + break; + case end: + source_row = source_row.slice(1); + character += 1; + return it('(range)', value); + case xquote: + case '\\': + warn_at('unexpected_a', line, character, c); + break; + } + value += c; + } + }, + +// token -- this is called by advance to get the next token. + + token: function () { + var c, i, quote, snippet; + + for (;;) { + while (!source_row) { + if (!next_line()) { + return it('(end)'); + } + } + while (xmode === 'outer') { + i = source_row.search(ox); + if (i === 0) { + break; + } else if (i > 0) { + character += 1; + source_row = source_row.slice(i); + break; + } else { + if (!next_line()) { + return it('(end)', ''); + } + } + } + snippet = match(rx[xmode] || tx); + if (!snippet) { + snippet = ''; + c = ''; + while (source_row && source_row < '!') { + source_row = source_row.slice(1); + } + if (source_row) { + if (xmode === 'html') { + return it('(error)', source_row.charAt(0)); + } else { + stop_at('unexpected_a', + line, character, source_row.charAt(0)); + } + } + } else { + +// identifier + + c = snippet.charAt(0); + if (c.isAlpha() || c === '_' || c === '$') { + return it('(identifier)', snippet); + } + +// number + + if (c.isDigit()) { + return number(snippet); + } + switch (snippet) { + +// string + + case '"': + case "'": + return string(snippet); + +// // comment + + case '//': + collect_comment(source_row, '//', line, character); + source_row = ''; + break; + +// /* comment + + case '/*': + quote = '/*'; + for (;;) { + i = source_row.search(lx); + if (i >= 0) { + break; + } + collect_comment(source_row, quote, line, character); + quote = ''; + if (!next_line()) { + stop_at('unclosed_comment', line, character); + } + } + collect_comment(source_row.slice(0, i), quote, character, line); + character += i + 2; + if (source_row.charAt(i) === '/') { + stop_at('nested_comment', line, character); + } + source_row = source_row.slice(i + 2); + break; + + case '': + break; +// / + case '/': + if (token.id === '/=') { + stop_at( + bundle.slash_equal, + line, + from + ); + } + return prereg ? regexp() : it('(punctuator)', snippet); + +// punctuator + + case ''); + } + character += 3; + source_row = source_row.slice(i + 3); + break; + case '#': + if (xmode === 'html' || xmode === 'styleproperty') { + for (;;) { + c = source_row.charAt(0); + if ((c < '0' || c > '9') && + (c < 'a' || c > 'f') && + (c < 'A' || c > 'F')) { + break; + } + character += 1; + source_row = source_row.slice(1); + snippet += c; + } + if (snippet.length !== 4 && snippet.length !== 7) { + warn_at('bad_color_a', line, + from + length, snippet); + } + return it('(color)', snippet); + } + return it('(punctuator)', snippet); + + default: + if (xmode === 'outer' && c === '&') { + character += 1; + source_row = source_row.slice(1); + for (;;) { + c = source_row.charAt(0); + character += 1; + source_row = source_row.slice(1); + if (c === ';') { + break; + } + if (!((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + c === '#')) { + stop_at('bad_entity', line, from + length, + character); + } + } + break; + } + return it('(punctuator)', snippet); + } + } + } + } + }; + }()); + + + function add_label(token, kind, name) { + +// Define the symbol in the current function in the current scope. + + name = name || token.string; + +// Global variables cannot be created in the safe subset. If a global variable +// already exists, do nothing. If it is predefined, define it. + + if (funct === global_funct) { + if (option.safe) { + warn('adsafe_a', token, name); + } + if (typeof global_funct[name] !== 'string') { + token.writeable = typeof predefined[name] === 'boolean' ? + predefined[name] : true; + token.funct = funct; + global_scope[name] = token; + } + if (kind === 'becoming') { + kind = 'var'; + } + +// Ordinary variables. + + } else { + +// Warn if the variable already exists. + + if (typeof funct[name] === 'string') { + if (funct[name] === 'undef') { + if (!option.undef) { + warn('used_before_a', token, name); + } + kind = 'var'; + } else { + warn('already_defined', token, name); + } + } else { + +// Add the symbol to the current function. + + token.funct = funct; + token.writeable = true; + scope[name] = token; + } + } + funct[name] = kind; + } + + + function peek(distance) { + +// Peek ahead to a future token. The distance is how far ahead to look. The +// default is the next token. + + var found, slot = 0; + + distance = distance || 0; + while (slot <= distance) { + found = lookahead[slot]; + if (!found) { + found = lookahead[slot] = lex.token(); + } + slot += 1; + } + return found; + } + + + function discard(it) { + +// The token will not be included in the parse tree, so move the comments +// that are attached to the token to tokens that are in the tree. + + it = it || token; + if (it.comments) { + var prev = it.prev; + while (prev.comments === null) { + prev = prev.prev; + } + if (prev.comments) { + prev.comments = prev.comments.concat(it.comments); + } else { + prev.comments = it.comments; + } + } + it.comments = null; + } + + + function advance(id, match) { + +// Produce the next token, also looking for programming errors. + + if (indent) { + +// In indentation checking was requested, then inspect all of the line breakings. +// The var statement is tricky because the names might be aligned or not. We +// look at the first line break after the var to determine the programmer's +// intention. + + if (var_mode && next_token.line !== token.line) { + if ((var_mode !== indent || !next_token.edge) && + next_token.from === indent.at - + (next_token.edge ? option.indent : 0)) { + var dent = indent; + for (;;) { + dent.at -= option.indent; + if (dent === var_mode) { + break; + } + dent = dent.was; + } + dent.open = false; + } + var_mode = null; + } + if (indent.open) { + +// If the token is an edge. + + if (next_token.edge) { + if (next_token.edge === 'label') { + expected_at(1); + } else if (next_token.edge === 'case') { + expected_at(indent.at - option.indent); + } else if (indent.mode !== 'array' || next_token.line !== token.line) { + expected_at(indent.at); + } + +// If the token is not an edge, but is the first token on the line. + + } else if (next_token.line !== token.line) { + if (next_token.from < indent.at + (indent.mode === + 'expression' ? 0 : option.indent)) { + expected_at(indent.at + option.indent); + } + indent.wrap = true; + } + } else if (next_token.line !== token.line) { + if (next_token.edge) { + expected_at(indent.at); + } else { + indent.wrap = true; + if (indent.mode === 'statement' || indent.mode === 'var') { + expected_at(indent.at + option.indent); + } else if (next_token.from < indent.at + (indent.mode === + 'expression' ? 0 : option.indent)) { + expected_at(indent.at + option.indent); + } + } + } + } + + switch (token.id) { + case '(number)': + if (next_token.id === '.') { + warn('trailing_decimal_a'); + } + break; + case '-': + if (next_token.id === '-' || next_token.id === '--') { + warn('confusing_a'); + } + break; + case '+': + if (next_token.id === '+' || next_token.id === '++') { + warn('confusing_a'); + } + break; + } + if (token.id === '(string)' || token.identifier) { + anonname = token.string; + } + + if (id && next_token.id !== id) { + if (match) { + warn('expected_a_b_from_c_d', next_token, id, + match.id, match.line, next_token.string); + } else if (!next_token.identifier || next_token.string !== id) { + warn('expected_a_b', next_token, id, next_token.string); + } + } + prev_token = token; + token = next_token; + next_token = lookahead.shift() || lex.token(); + if (token.id === '(end)') { + discard(); + } + } + + + function do_safe() { + if (option.adsafe) { + option.safe = true; + } + if (option.safe) { + option.browser = + option['continue'] = + option.css = + option.debug = + option.devel = + option.evil = + option.forin = + option.newcap = + option.nomen = + option.on = + option.rhino = + option.sloppy = + option.sub = + option.undef = + option.widget = + option.windows = false; + + + delete predefined.Array; + delete predefined.Date; + delete predefined.Function; + delete predefined.Object; + delete predefined['eval']; + + add_to_predefined({ + ADSAFE: false, + lib: false + }); + } + } + + + function do_globals() { + var name, writeable; + for (;;) { + if (next_token.id !== '(string)' && !next_token.identifier) { + return; + } + name = next_token.string; + advance(); + writeable = false; + if (next_token.id === ':') { + advance(':'); + switch (next_token.id) { + case 'true': + writeable = predefined[name] !== false; + advance('true'); + break; + case 'false': + advance('false'); + break; + default: + stop('unexpected_a'); + } + } + predefined[name] = writeable; + if (next_token.id !== ',') { + return; + } + advance(','); + } + } + + + function do_jslint() { + var name, value; + while (next_token.id === '(string)' || next_token.identifier) { + name = next_token.string; + advance(); + if (next_token.id !== ':') { + stop('expected_a_b', next_token, ':', next_token.string); + } + advance(':'); + switch (name) { + case 'indent': + value = next_token.number; + if (!isFinite(value) || value < 0 || Math.floor(value) !== value) { + stop('expected_small_a'); + } + option.indent = value; + break; + case 'maxerr': + value = +next_token.string; + value = next_token.number; + if (!isFinite(value) || value <= 0 || Math.floor(value) !== value) { + stop('expected_small_a'); + } + option.maxerr = value; + break; + case 'maxlen': + value = next_token.number; + if (!isFinite(value) || value <= 0 || Math.floor(value) !== value) { + stop('expected_small_a'); + } + option.maxlen = value; + break; + default: + if (next_token.id === 'true') { + option[name] = true; + } else if (next_token.id === 'false') { + option[name] = false; + } else { + stop('unexpected_a'); + } + switch (name) { + case 'adsafe': + option.adsafe = option.safe = true; + do_safe(); + break; + case 'safe': + do_safe(); + break; + } + } + advance(); + if (next_token.id === ',') { + advance(','); + } + } + assume(); + } + + + function do_properties() { + var name, type; + option.properties = true; + if (!funct['(old_property_type)']) { + funct['(old_property_type)'] = property_type; + property_type = Object.create(property_type); + } + for (;;) { + if (next_token.id !== '(string)' && !next_token.identifier) { + return; + } + name = next_token.string; + type = ''; + advance(); + if (next_token.id === ':') { + advance(':'); + if (next_token.id === 'function') { + advance('function'); + if (is_type[next_token.string] === true) { + type = 'function ' + next_token.string; + advance(); + } else { + type = 'function'; + } + } else { + type = next_token.string; + if (is_type[type] !== true) { + warn('expected_type_a', next_token); + type = ''; + } + advance(); + } + } + property_type[name] = type; + if (next_token.id !== ',') { + return; + } + advance(','); + } + } + + + function directive() { + var command = this.id, + old_comments_off = comments_off, + old_indent = indent; + comments_off = true; + indent = null; + if (next_token.line === token.line && next_token.from === token.thru) { + warn('missing_space_a_b', next_token, token.string, next_token.string); + } + if (lookahead.length > 0 || next_token.comments) { + warn('unexpected_a', this); + } + switch (command) { + case '/*properties': + case '/*property': + case '/*members': + case '/*member': + do_properties(); + break; + case '/*jslint': + if (option.safe) { + warn('adsafe_a', this); + } + do_jslint(); + break; + case '/*globals': + case '/*global': + if (option.safe) { + warn('adsafe_a', this); + } + do_globals(); + break; + default: + stop('unexpected_a', this); + } + comments_off = old_comments_off; + advance('*/'); + indent = old_indent; + } + + +// Indentation intention + + function edge(mode) { + next_token.edge = indent ? indent.open && (mode || 'edge') : ''; + } + + + function step_in(mode) { + var open, was; + if (typeof mode === 'number') { + indent = { + at: +mode, + open: true, + was: was + }; + } else if (!indent) { + indent = { + at: 1, + mode: 'statement', + open: true + }; + } else { + was = indent; + open = mode === 'var' || + (next_token.line !== token.line && mode !== 'statement'); + indent = { + at: (open || mode === 'control' ? + was.at + option.indent : was.at) + + (was.wrap ? option.indent : 0), + mode: mode, + open: open, + was: was + }; + if (mode === 'var' && open) { + var_mode = indent; + } + } + } + + function step_out(id, symbol) { + if (id) { + if (indent && indent.open) { + indent.at -= option.indent; + edge(); + } + advance(id, symbol); + } + if (indent) { + indent = indent.was; + } + } + +// Functions for conformance of whitespace. + + function one_space(left, right) { + left = left || token; + right = right || next_token; + if (right.id !== '(end)' && !option.white && + (token.line !== right.line || + token.thru + 1 !== right.from)) { + warn('expected_space_a_b', right, token.string, right.string); + } + } + + function one_space_only(left, right) { + left = left || token; + right = right || next_token; + if (right.id !== '(end)' && (left.line !== right.line || + (!option.white && left.thru + 1 !== right.from))) { + warn('expected_space_a_b', right, left.string, right.string); + } + } + + function no_space(left, right) { + left = left || token; + right = right || next_token; + if ((!option.white || xmode === 'styleproperty' || xmode === 'style') && + left.thru !== right.from && left.line === right.line) { + warn('unexpected_space_a_b', right, left.string, right.string); + } + } + + function no_space_only(left, right) { + left = left || token; + right = right || next_token; + if (right.id !== '(end)' && (left.line !== right.line || + (!option.white && left.thru !== right.from))) { + warn('unexpected_space_a_b', right, left.string, right.string); + } + } + + function spaces(left, right) { + if (!option.white) { + left = left || token; + right = right || next_token; + if (left.thru === right.from && left.line === right.line) { + warn('missing_space_a_b', right, left.string, right.string); + } + } + } + + function comma() { + if (next_token.id !== ',') { + warn_at('expected_a_b', token.line, token.thru, ',', next_token.string); + } else { + if (!option.white) { + no_space_only(); + } + advance(','); + discard(); + spaces(); + } + } + + + function semicolon() { + if (next_token.id !== ';') { + warn_at('expected_a_b', token.line, token.thru, ';', next_token.string); + } else { + if (!option.white) { + no_space_only(); + } + advance(';'); + discard(); + if (semicolon_coda[next_token.id] !== true) { + spaces(); + } + } + } + + function use_strict() { + if (next_token.string === 'use strict') { + if (strict_mode) { + warn('unnecessary_use'); + } + edge(); + advance(); + semicolon(); + strict_mode = true; + option.newcap = false; + option.undef = false; + return true; + } else { + return false; + } + } + + + function are_similar(a, b) { + if (a === b) { + return true; + } + if (Array.isArray(a)) { + if (Array.isArray(b) && a.length === b.length) { + var i; + for (i = 0; i < a.length; i += 1) { + if (!are_similar(a[i], b[i])) { + return false; + } + } + return true; + } + return false; + } + if (Array.isArray(b)) { + return false; + } + if (a.id === '(number)' && b.id === '(number)') { + return a.number === b.number; + } + if (a.arity === b.arity && a.string === b.string) { + switch (a.arity) { + case 'prefix': + case 'suffix': + case undefined: + return a.id === b.id && are_similar(a.first, b.first); + case 'infix': + return are_similar(a.first, b.first) && + are_similar(a.second, b.second); + case 'ternary': + return are_similar(a.first, b.first) && + are_similar(a.second, b.second) && + are_similar(a.third, b.third); + case 'function': + case 'regexp': + return false; + default: + return true; + } + } else { + if (a.id === '.' && b.id === '[' && b.arity === 'infix') { + return a.second.string === b.second.string && b.second.id === '(string)'; + } else if (a.id === '[' && a.arity === 'infix' && b.id === '.') { + return a.second.string === b.second.string && a.second.id === '(string)'; + } + } + return false; + } + + +// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it +// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is +// like .nud except that it is only used on the first token of a statement. +// Having .fud makes it much easier to define statement-oriented languages like +// JavaScript. I retained Pratt's nomenclature. + +// .nud Null denotation +// .fud First null denotation +// .led Left denotation +// lbp Left binding power +// rbp Right binding power + +// They are elements of the parsing method called Top Down Operator Precedence. + + function expression(rbp, initial) { + +// rbp is the right binding power. +// initial indicates that this is the first expression of a statement. + + var left; + if (next_token.id === '(end)') { + stop('unexpected_a', token, next_token.id); + } + advance(); + if (option.safe && scope[token.string] && + scope[token.string] === global_scope[token.string] && + (next_token.id !== '(' && next_token.id !== '.')) { + warn('adsafe_a', token); + } + if (initial) { + anonname = 'anonymous'; + funct['(verb)'] = token.string; + } + if (initial === true && token.fud) { + left = token.fud(); + } else { + if (token.nud) { + left = token.nud(); + } else { + if (next_token.id === '(number)' && token.id === '.') { + warn('leading_decimal_a', token, + next_token.string); + advance(); + return token; + } else { + stop('expected_identifier_a', token, token.id); + } + } + while (rbp < next_token.lbp) { + advance(); + if (token.led) { + left = token.led(left); + } else { + stop('expected_operator_a', token, token.id); + } + } + } + return left; + } + + +// Functional constructors for making the symbols that will be inherited by +// tokens. + + function symbol(s, p) { + var x = syntax[s]; + if (!x || typeof x !== 'object') { + syntax[s] = x = { + id: s, + lbp: p, + string: s + }; + } + return x; + } + + + function delim(s) { + return symbol(s, 0); + } + + + function postscript(x) { + x.postscript = true; + return x; + } + + function ultimate(s) { + var x = symbol(s, 0); + x.from = 1; + x.thru = 1; + x.line = 0; + x.edge = 'edge'; + s.string = s; + return postscript(x); + } + + + function stmt(s, f) { + var x = delim(s); + x.identifier = x.reserved = true; + x.fud = f; + return x; + } + + function labeled_stmt(s, f) { + var x = stmt(s, f); + x.labeled = true; + } + + function disrupt_stmt(s, f) { + var x = stmt(s, f); + x.disrupt = true; + } + + + function reserve_name(x) { + var c = x.id.charAt(0); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + x.identifier = x.reserved = true; + } + return x; + } + + + function prefix(s, f, type) { + var x = symbol(s, 150); + reserve_name(x); + x.nud = (typeof f === 'function') ? f : function () { + if (s === 'typeof') { + one_space(); + } else { + no_space_only(); + } + this.first = expression(150); + this.arity = 'prefix'; + if (this.id === '++' || this.id === '--') { + if (!option.plusplus) { + warn('unexpected_a', this); + } else if ((!this.first.identifier || this.first.reserved) && + this.first.id !== '.' && this.first.id !== '[') { + warn('bad_operand', this); + } + } + this.type = type; + return this; + }; + return x; + } + + + function type(s, t, nud) { + var x = delim(s); + x.arity = x.type = t; + if (nud) { + x.nud = nud; + } + return x; + } + + + function get_type(one) { + var type; + if (typeof one !== 'object') { + return one; + } if (one.id === '.') { + type = property_type[one.second.string]; + return typeof type === 'string' ? type : ''; + } else { + return ((one.identifier && scope[one.string]) || one).type; + } + } + + + function set_type(one, type) { + if (type && typeof one === 'object') { + if (one.id === '.') { + property_type[one.second.string] = type; + } else { + ((one.identifier && scope[one.string]) || one).type = type; + } + } + return type; + } + + + function conform_type(one, two) { + +// This takes a type string or a token, or two tokens. + + var one_type = get_type(one), + two_type = get_type(two), + one_string, + two_string; + if (one_type) { + if (two_type) { + if (one_type === two_type || one_type === '*') { + return two_type !== '*' ? two_type : ''; + } else if (one_type === 'function' && + two_type.slice(0, 8) === 'function') { + return set_type(one, two_type); + } else if (two_type === 'function' && + one_type.slice(0, 8) === 'function') { + return set_type(two, one_type); + } else { + if (two_type !== '*' && !option.confusion) { + if (typeof one === 'string') { + one_string = one_type; + } else if (one.id === '.') { + one_string = '.' + one.second.string + ': ' + one_type; + } else { + one_string = '\'' + (one.number || one.string) + '\': ' + one_type; + } + if (two.id === '.') { + two_string = '.' + two.second.string + ': ' + two_type; + } else { + two_string = '\'' + (two.number || two.string) + '\': ' + two_type; + } + warn('type_confusion_a_b', two, one_string, two_string); + } + return one_type; + } + } else if (one_type !== '*') { + return set_type(two, one_type); + } + } else if (two_type && two_type !== '*') { + return set_type(one, two_type); + } + } + + + function reserve(s, f) { + var x = delim(s); + x.identifier = x.reserved = true; + if (typeof f === 'function') { + x.nud = f; + } + return x; + } + + + function constant(name, type) { + var x = reserve(name); + x.type = type; + x.string = name; + x.nud = return_this; + return x; + } + + + function reservevar(s, v) { + return reserve(s, function () { + if (typeof v === 'function') { + v(this); + } + return this; + }); + } + + + function infix(s, p, f, type, w) { + var x = symbol(s, p); + reserve_name(x); + x.led = function (left) { + this.arity = 'infix'; + if (!w) { + spaces(prev_token, token); + spaces(); + } + if (!option.bitwise && this.bitwise) { + warn('unexpected_a', this); + } + if (typeof f === 'function') { + return f(left, this); + } else { + this.first = left; + this.second = expression(p); + return this; + } + }; + if (type) { + x.type = type; + } + return x; + } + + function expected_relation(node, message) { + if (node.assign) { + warn(message || bundle.conditional_assignment, node); + } + return node; + } + + function expected_condition(node, message) { + switch (node.id) { + case '[': + case '-': + if (node.arity !== 'infix') { + warn(message || bundle.weird_condition, node); + } + break; + case 'false': + case 'function': + case 'Infinity': + case 'NaN': + case 'null': + case 'true': + case 'undefined': + case 'void': + case '(number)': + case '(regexp)': + case '(string)': + case '{': + warn(message || bundle.weird_condition, node); + break; + case '(': + if (node.first.id === '.' && numbery[node.first.second.string] === true) { + warn(message || bundle.weird_condition, node); + } + break; + } + return node; + } + + function check_relation(node) { + switch (node.arity) { + case 'prefix': + switch (node.id) { + case '{': + case '[': + warn('unexpected_a', node); + break; + case '!': + warn('confusing_a', node); + break; + } + break; + case 'function': + case 'regexp': + warn('unexpected_a', node); + break; + default: + if (node.id === 'NaN') { + warn('isnan', node); + } + } + return node; + } + + + function relation(s, eqeq) { + return infix(s, 100, function (left, that) { + check_relation(left); + if (eqeq && !option.eqeq) { + warn('expected_a_b', that, eqeq, that.id); + } + var right = expression(100); + if (are_similar(left, right) || + ((left.id === '(string)' || left.id === '(number)') && + (right.id === '(string)' || right.id === '(number)'))) { + warn('weird_relation', that); + } + that.first = left; + that.second = check_relation(right); + conform_type(left, that.second, that); + return that; + }, 'boolean'); + } + + + function assignop(s, op) { + var x = infix(s, 20, function (left, that) { + var l; + that.first = left; + if (left.identifier) { + if (scope[left.string]) { + if (scope[left.string].writeable === false) { + warn('read_only', left); + } + } else { + stop('read_only'); + } + } else if (option.safe) { + l = left; + do { + if (typeof predefined[l.string] === 'boolean') { + warn('adsafe_a', l); + } + l = l.first; + } while (l); + } + if (left === syntax['function']) { + warn('identifier_function', token); + } + if (left.id === '.' || left.id === '[') { + if (!left.first || left.first.string === 'arguments') { + warn('bad_assignment', that); + } + } else if (left.identifier && !left.reserved) { + if (funct[left.string] === 'exception') { + warn('assign_exception', left); + } + } + that.second = expression(19); + if (that.id === '=' && are_similar(that.first, that.second)) { + warn('weird_assignment', that); + } + if (that.type) { + conform_type(left, that); + conform_type(that, that.second); + } else { + conform_type(left, that.second); + } + return that; + }); + x.assign = true; + if (op) { + if (syntax[op].type) { + x.type = syntax[op].type; + } + if (syntax[op].bitwise) { + x.bitwise = true; + } + } + return x; + } + + + function bitwise(s, p) { + var x = infix(s, p, 'number'); + x.bitwise = true; + return x; + } + + + function suffix(s) { + var x = symbol(s, 150); + x.led = function (left) { + no_space_only(prev_token, token); + if (!option.plusplus) { + warn('unexpected_a', this); + } else if ((!left.identifier || left.reserved) && + left.id !== '.' && left.id !== '[') { + warn('bad_operand', this); + } + this.first = left; + this.arity = 'suffix'; + return this; + }; + return x; + } + + + function optional_identifier() { + if (next_token.identifier) { + advance(); + if (option.safe && banned[token.string]) { + warn('adsafe_a', token); + } else if (token.reserved && !option.es5) { + warn('expected_identifier_a_reserved', token); + } + return token.string; + } + } + + + function identifier() { + var i = optional_identifier(); + if (!i) { + stop(token.id === 'function' && next_token.id === '(' ? + 'name_function' : 'expected_identifier_a'); + } + return i; + } + + + function statement() { + + var label, old_scope = scope, the_statement; + +// We don't like the empty statement. + + if (next_token.id === ';') { + warn('unexpected_a'); + semicolon(); + return; + } + +// Is this a labeled statement? + + if (next_token.identifier && !next_token.reserved && peek().id === ':') { + edge('label'); + label = next_token; + advance(); + discard(); + advance(':'); + discard(); + scope = Object.create(old_scope); + add_label(label, 'label'); + if (next_token.labeled !== true) { + warn('label_a_b', next_token, label.string, next_token.string); + } else if (jx.test(label.string + ':')) { + warn('url', label); + } else if (funct === global_funct) { + stop('unexpected_a', token); + } + next_token.label = label; + } + +// Parse the statement. + + edge(); + step_in('statement'); + the_statement = expression(0, true); + if (the_statement) { + +// Look for the final semicolon. + + if (the_statement.arity === 'statement') { + if (the_statement.id === 'switch' || + (the_statement.block && the_statement.id !== 'do')) { + spaces(); + } else { + semicolon(); + } + } else { + +// If this is an expression statement, determine if it is acceptable. +// We do not like +// new Blah(); +// statments. If it is to be used at all, new should only be used to make +// objects, not side effects. The expression statements we do like do +// assignment or invocation or delete. + + if (the_statement.id === '(') { + if (the_statement.first.id === 'new') { + warn('bad_new'); + } + } else if (!the_statement.assign && + the_statement.id !== 'delete' && + the_statement.id !== '++' && + the_statement.id !== '--') { + warn('assignment_function_expression', token); + } + semicolon(); + } + } + step_out(); + scope = old_scope; + return the_statement; + } + + + function statements() { + var array = [], disruptor, the_statement; + +// A disrupt statement may not be followed by any other statement. +// If the last statement is disrupt, then the sequence is disrupt. + + while (next_token.postscript !== true) { + if (next_token.id === ';') { + warn('unexpected_a', next_token); + semicolon(); + } else { + if (next_token.string === 'use strict') { + if (!node_js || funct !== global_funct || array.length > 0) { + warn('function_strict'); + } + use_strict(); + } + if (disruptor) { + warn('unreachable_a_b', next_token, next_token.string, + disruptor.string); + disruptor = null; + } + the_statement = statement(); + if (the_statement) { + array.push(the_statement); + if (the_statement.disrupt) { + disruptor = the_statement; + array.disrupt = true; + } + } + } + } + return array; + } + + + function block(ordinary) { + +// array block is array sequence of statements wrapped in braces. +// ordinary is false for function bodies and try blocks. +// ordinary is true for if statements, while, etc. + + var array, + curly = next_token, + old_inblock = in_block, + old_scope = scope, + old_strict_mode = strict_mode; + + in_block = ordinary; + scope = Object.create(scope); + spaces(); + if (next_token.id === '{') { + advance('{'); + step_in(); + if (!ordinary && !use_strict() && !old_strict_mode && + !option.sloppy && funct['(context)'] === global_funct) { + warn('missing_use_strict'); + } + array = statements(); + strict_mode = old_strict_mode; + step_out('}', curly); + discard(); + } else if (!ordinary) { + stop('expected_a_b', next_token, '{', next_token.string); + } else { + warn('expected_a_b', next_token, '{', next_token.string); + array = [statement()]; + array.disrupt = array[0].disrupt; + } + funct['(verb)'] = null; + scope = old_scope; + in_block = old_inblock; + if (ordinary && array.length === 0) { + warn('empty_block'); + } + return array; + } + + + function tally_property(name) { + if (option.properties && typeof property_type[name] !== 'string') { + warn('unexpected_property_a', token, name); + } + if (typeof member[name] === 'number') { + member[name] += 1; + } else { + member[name] = 1; + } + } + + +// ECMAScript parser + + syntax['(identifier)'] = { + lbp: 0, + identifier: true, + nud: function () { + var name = this.string, + variable = scope[name], + site, + writeable; + +// If the variable is not in scope, then we may have an undeclared variable. +// Check the predefined list. If it was predefined, create the global +// variable. + + if (typeof variable !== 'object') { + writeable = predefined[name]; + if (typeof writeable === 'boolean') { + global_scope[name] = variable = { + string: name, + writeable: writeable, + funct: global_funct + }; + global_funct[name] = 'var'; + +// But if the variable is not in scope, and is not predefined, and if we are not +// in the global scope, then we have an undefined variable error. + + } else { + if (!option.undef) { + warn('used_before_a', token); + } + scope[name] = variable = { + string: name, + writeable: true, + funct: funct + }; + funct[name] = 'undef'; + } + + } + site = variable.funct; + +// The name is in scope and defined in the current function. + + if (funct === site) { + +// Change 'unused' to 'var', and reject labels. + + switch (funct[name]) { + case 'becoming': + warn('unexpected_a', token); + funct[name] = 'var'; + break; + case 'unused': + funct[name] = 'var'; + break; + case 'unparam': + funct[name] = 'parameter'; + break; + case 'unction': + funct[name] = 'function'; + break; + case 'label': + warn('a_label', token, name); + break; + } + +// If the name is already defined in the current +// function, but not as outer, then there is a scope error. + + } else { + switch (funct[name]) { + case 'closure': + case 'function': + case 'var': + case 'unused': + warn('a_scope', token, name); + break; + case 'label': + warn('a_label', token, name); + break; + case 'outer': + case 'global': + break; + default: + +// If the name is defined in an outer function, make an outer entry, and if +// it was unused, make it var. + + switch (site[name]) { + case 'becoming': + case 'function': + case 'unction': + case 'var': + case 'unused': + case 'closure': + case 'parameter': + site[name] = 'closure'; + funct[name] = site === global_funct ? 'global' : 'outer'; + break; + case 'unparam': + site[name] = 'parameter'; + funct[name] = 'outer'; + break; + case 'undef': + funct[name] = 'undef'; + break; + case 'label': + warn('a_label', token, name); + break; + } + } + } + return this; + }, + led: function () { + stop('expected_operator_a'); + } + }; + +// Build the syntax table by declaring the syntactic elements. + + type('(array)', 'array'); + type('(color)', 'color'); + type('(function)', 'function'); + type('(number)', 'number', return_this); + type('(object)', 'object'); + type('(string)', 'string', return_this); + type('(boolean)', 'boolean', return_this); + type('(range)', 'range'); + type('(regexp)', 'regexp', return_this); + + ultimate('(begin)'); + ultimate('(end)'); + ultimate('(error)'); + postscript(delim(''); + postscript(delim('}')); + delim(')'); + delim(']'); + postscript(delim('"')); + postscript(delim('\'')); + delim(';'); + delim(':'); + delim(','); + delim('#'); + delim('@'); + delim('*/'); + postscript(reserve('case')); + reserve('catch'); + postscript(reserve('default')); + reserve('else'); + reserve('finally'); + + reservevar('arguments', function (x) { + if (strict_mode && funct === global_funct) { + warn('strict', x); + } else if (option.safe) { + warn('adsafe_a', x); + } + }); + reservevar('eval', function (x) { + if (option.safe) { + warn('adsafe_a', x); + } + }); + constant('false', 'boolean'); + constant('Infinity', 'number'); + constant('NaN', 'number'); + constant('null', ''); + reservevar('this', function (x) { + if (strict_mode && ((funct['(statement)'] && + funct['(name)'].charAt(0) > 'Z') || funct === global_funct)) { + warn('strict', x); + } else if (option.safe) { + warn('adsafe_a', x); + } + }); + constant('true', 'boolean'); + constant('undefined', ''); + + infix('?', 30, function (left, that) { + that.first = expected_condition(expected_relation(left)); + that.second = expression(0); + spaces(); + var colon = next_token; + advance(':'); + discard(); + spaces(); + that.third = expression(10); + that.arity = 'ternary'; + set_type(that, conform_type(that.second, that.third)); + if (are_similar(that.second, that.third)) { + warn('weird_ternary', colon); + } else if (are_similar(that.first, that.second)) { + warn('use_or', that); + } + return that; + }); + + infix('||', 40, function (left, that) { + function paren_check(that) { + if (that.id === '&&' && !that.paren) { + warn('and', that); + } + return that; + } + + that.first = paren_check(expected_condition(expected_relation(left))); + that.second = paren_check(expected_relation(expression(40))); + if (are_similar(that.first, that.second)) { + warn('weird_condition', that); + } + return that; + }); + + infix('&&', 50, function (left, that) { + that.first = expected_condition(expected_relation(left)); + that.second = expected_relation(expression(50)); + if (are_similar(that.first, that.second)) { + warn('weird_condition', that); + } + return that; + }); + + prefix('void', function () { + this.first = expression(0); + this.arity = 'prefix'; + if (this.first.id !== '(number)' || this.first.string) { + warn('unexpected_a', this); + return this; + } + this.type = 'undefined'; + return this; + }); + + bitwise('|', 70); + bitwise('^', 80); + bitwise('&', 90); + + relation('==', '==='); + relation('==='); + relation('!=', '!=='); + relation('!=='); + relation('<'); + relation('>'); + relation('<='); + relation('>='); + + bitwise('<<', 120); + bitwise('>>', 120); + bitwise('>>>', 120); + + infix('in', 120, function (left, that) { + warn('infix_in', that); + that.left = left; + that.right = expression(130); + return that; + }, 'boolean'); + infix('instanceof', 120, null, 'boolean'); + infix('+', 130, function (left, that) { + if (left.id === '(number)') { + if (left.number === 0) { + warn('unexpected_a', left, '0'); + } + } else if (left.id === '(string)') { + if (left.string === '') { + warn('expected_a_b', left, 'String', '\'\''); + } + } + var right = expression(130); + if (right.id === '(number)') { + if (right.number === 0) { + warn('unexpected_a', right, '0'); + } + } else if (right.id === '(string)') { + if (right.string === '') { + warn('expected_a_b', right, 'String', '\'\''); + } + } + if (left.id === right.id) { + if (left.id === '(string)' || left.id === '(number)') { + if (left.id === '(string)') { + left.string += right.string; + if (jx.test(left.string)) { + warn('url', left); + } + } else { + left.number += right.number; + } + left.thru = right.thru; + discard(right); + discard(that); + return left; + } + } + that.first = left; + that.second = right; + set_type(that, conform_type(left, right)); + return that; + }); + prefix('+', 'num'); + prefix('+++', function () { + warn('confusing_a', token); + this.first = expression(150); + this.arity = 'prefix'; + return this; + }); + infix('+++', 130, function (left) { + warn('confusing_a', token); + this.first = left; + this.second = expression(130); + return this; + }); + infix('-', 130, function (left, that) { + if ((left.id === '(number)' && left.number === 0) || left.id === '(string)') { + warn('unexpected_a', left); + } + var right = expression(130); + if ((right.id === '(number)' && right.number === 0) || right.id === '(string)') { + warn('unexpected_a', left); + } + if (left.id === right.id && left.id === '(number)') { + left.number -= right.number; + left.thru = right.thru; + discard(right); + discard(that); + return left; + } + that.first = left; + that.second = right; + return that; + }, 'number'); + prefix('-'); + prefix('---', function () { + warn('confusing_a', token); + this.first = expression(150); + this.arity = 'prefix'; + return this; + }); + infix('---', 130, function (left) { + warn('confusing_a', token); + this.first = left; + this.second = expression(130); + return this; + }); + infix('*', 140, function (left, that) { + if ((left.id === '(number)' && (left.number === 0 || left.number === 1)) || left.id === '(string)') { + warn('unexpected_a', left); + } + var right = expression(140); + if ((right.id === '(number)' && (right.number === 0 || right.number === 1)) || right.id === '(string)') { + warn('unexpected_a', right); + } + if (left.id === right.id && left.id === '(number)') { + left.number *= right.number; + left.thru = right.thru; + discard(right); + discard(that); + return left; + } + that.first = left; + that.second = right; + return that; + }, 'number'); + infix('/', 140, function (left, that) { + if ((left.id === '(number)' && left.number === 0) || left.id === '(string)') { + warn('unexpected_a', left); + } + var right = expression(140); + if ((right.id === '(number)' && (right.number === 0 || right.number === 1)) || right.id === '(string)') { + warn('unexpected_a', right); + } + if (left.id === right.id && left.id === '(number)') { + left.number /= right.number; + left.thru = right.thru; + discard(right); + discard(that); + return left; + } + that.first = left; + that.second = right; + return that; + }, 'number'); + infix('%', 140, function (left, that) { + if ((left.id === '(number)' && (left.number === 0 || left.number === 1)) || left.id === '(string)') { + warn('unexpected_a', left); + } + var right = expression(140); + if ((right.id === '(number)' && right.number === 0) || right.id === '(string)') { + warn('unexpected_a', right); + } + if (left.id === right.id && left.id === '(number)') { + left.number %= right.number; + left.thru = right.thru; + discard(right); + discard(that); + return left; + } + that.first = left; + that.second = right; + return that; + }, 'number'); + + suffix('++'); + prefix('++'); + + suffix('--'); + prefix('--'); + prefix('delete', function () { + one_space(); + var p = expression(0); + if (!p || (p.id !== '.' && p.id !== '[')) { + warn('deleted'); + } + this.first = p; + return this; + }); + + + prefix('~', function () { + no_space_only(); + if (!option.bitwise) { + warn('unexpected_a', this); + } + expression(150); + return this; + }, 'number'); + prefix('!', function () { + no_space_only(); + this.first = expected_condition(expression(150)); + this.arity = 'prefix'; + if (bang[this.first.id] === true) { + warn('confusing_a', this); + } + return this; + }, 'boolean'); + prefix('typeof', null, 'string'); + prefix('new', function () { + one_space(); + var c = expression(160), n, p, v; + this.first = c; + if (c.id !== 'function') { + if (c.identifier) { + switch (c.string) { + case 'Object': + warn('use_object', token); + break; + case 'Array': + if (next_token.id === '(') { + p = next_token; + p.first = this; + advance('('); + if (next_token.id !== ')') { + n = expression(0); + p.second = [n]; + if (get_type(n) !== 'number' || next_token.id === ',') { + warn('use_array', p); + } + while (next_token.id === ',') { + advance(','); + p.second.push(expression(0)); + } + } else { + warn('use_array', token); + } + advance(')', p); + discard(); + return p; + } + warn('use_array', token); + break; + case 'Number': + case 'String': + case 'Boolean': + case 'Math': + case 'JSON': + warn('not_a_constructor', c); + break; + case 'Function': + if (!option.evil) { + warn('function_eval'); + } + break; + case 'Date': + case 'RegExp': + break; + default: + if (c.id !== 'function') { + v = c.string.charAt(0); + if (!option.newcap && (v < 'A' || v > 'Z')) { + warn('constructor_name_a', token); + } + } + } + } else { + if (c.id !== '.' && c.id !== '[' && c.id !== '(') { + warn('bad_constructor', token); + } + } + } else { + warn('weird_new', this); + } + if (next_token.id !== '(') { + warn('missing_a', next_token, '()'); + } + return this; + }); + + infix('(', 160, function (left, that) { + var p; + if (indent && indent.mode === 'expression') { + no_space(prev_token, token); + } else { + no_space_only(prev_token, token); + } + if (!left.immed && left.id === 'function') { + warn('wrap_immediate'); + } + p = []; + if (left.identifier) { + if (left.string === 'String') { + conform_type('string', that); + } else if (left.string === 'Number') { + conform_type('number', that); + } else if (left.string === 'Boolean') { + conform_type('boolean', that); + } else { + set_type(that, conform_type('function', left).slice(9)); + } + } else if (left.id === '.') { + switch (left.second.string) { + case 'apply': + case 'call': + set_type(that, conform_type('function', left.first).slice(9)); + break; + case 'concat': + case 'slice': + conform_type(that, left.first); + break; + case 'parse': + case 'toJSON': + conform_type('function', left); + break; + default: + set_type(that, conform_type('function', left).slice(9)); + } + } else { + set_type(that, conform_type('function', left).slice(9)); + } + if (left.identifier) { + if (left.string.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { + if (left.string !== 'Number' && left.string !== 'String' && + left.string !== 'Boolean' && left.string !== 'Date') { + if (left.string === 'Math' || left.string === 'JSON') { + warn('not_a_function', left); + } else if (left.string === 'Object') { + warn('use_object', token); + } else if (left.string === 'Array' || !option.newcap) { + warn('missing_a', left, 'new'); + } + } + } + } else if (left.id === '.') { + if (option.safe && left.first.string === 'Math' && + left.second === 'random') { + warn('adsafe_a', left); + } else if (left.second.string === 'split' && + left.first.id === '(string)') { + warn('use_array', left.second); + } + } + step_in(); + if (next_token.id !== ')') { + no_space(); + for (;;) { + edge(); + p.push(expression(10)); + if (next_token.id !== ',') { + break; + } + comma(); + } + } + no_space(); + step_out(')', that); + if (typeof left === 'object') { + if (left.string === 'parseInt' && p.length === 1) { + warn('radix', left); + } + if (!option.evil) { + if (left.string === 'eval' || left.string === 'Function' || + left.string === 'execScript') { + warn('evil', left); + } else if (p[0] && p[0].id === '(string)' && + (left.string === 'setTimeout' || + left.string === 'setInterval')) { + warn('implied_evil', left); + } + } + if (!left.identifier && left.id !== '.' && left.id !== '[' && + left.id !== '(' && left.id !== '&&' && left.id !== '||' && + left.id !== '?') { + warn('bad_invocation', left); + } + } + that.first = left; + that.second = p; + return that; + }, '', true); + + prefix('(', function () { + step_in('expression'); + discard(); + no_space(); + edge(); + if (next_token.id === 'function') { + next_token.immed = true; + } + var value = expression(0); + value.paren = true; + no_space(); + step_out(')', this); + discard(); + if (value.id === 'function') { + if (next_token.id === '(') { + warn('move_invocation'); + } else { + warn('bad_wrap', this); + } + } + return value; + }); + + infix('.', 170, function (left, that) { + no_space(prev_token, token); + no_space(); + var name = identifier(), type; + if (typeof name === 'string') { + tally_property(name); + } + that.first = left; + that.second = token; + if (left && left.string === 'arguments' && + (name === 'callee' || name === 'caller')) { + warn('avoid_a', left, 'arguments.' + name); + } else if (!option.evil && left && left.string === 'document' && + (name === 'write' || name === 'writeln')) { + warn('write_is_wrong', left); + } else if (option.adsafe) { + if (!adsafe_top && left.string === 'ADSAFE') { + if (name === 'id' || name === 'lib') { + warn('adsafe_a', that); + } else if (name === 'go') { + if (xmode !== 'script') { + warn('adsafe_a', that); + } else if (adsafe_went || next_token.id !== '(' || + peek(0).id !== '(string)' || + peek(0).string !== adsafe_id || + peek(1).id !== ',') { + stop('adsafe_a', that, 'go'); + } + adsafe_went = true; + adsafe_may = false; + } + } + adsafe_top = false; + } + if (!option.evil && (name === 'eval' || name === 'execScript')) { + warn('evil'); + } else if (option.safe) { + for (;;) { + if (banned[name] === true) { + warn('adsafe_a', token, name); + } + if (typeof predefined[left.string] !== 'boolean' || //// check for writeable + next_token.id === '(') { + break; + } + if (next_token.id !== '.') { + warn('adsafe_a', that); + break; + } + advance('.'); + token.first = that; + token.second = name; + that = token; + name = identifier(); + if (typeof name === 'string') { + tally_property(name); + } + } + } + type = property_type[name]; + if (type && typeof type === 'string' && type !== '*') { + that.type = type; + } + return that; + }, '', true); + + infix('[', 170, function (left, that) { + var e, s; + no_space_only(prev_token, token); + no_space(); + step_in(); + edge(); + e = expression(0); + switch (get_type(e)) { + case 'number': + if (e.id === '(number)' && left.id === 'arguments') { + warn('use_param', left); + } + conform_type('array', left); + break; + case 'string': + if (e.id === '(string)') { + if (option.safe && (banned[e.string] || + e.string.charAt(0) === '_' || e.string.slice(-1) === '_')) { + warn('adsafe_subscript_a', e); + } else if (!option.evil && + (e.string === 'eval' || e.string === 'execScript')) { + warn('evil', e); + } else if (!option.sub && ix.test(e.string)) { + s = syntax[e.string]; + if (!s || !s.reserved) { + warn('subscript', e); + } + } + tally_property(e.string); + } else if (option.safe && e.id !== 'typeof') { + warn('adsafe_subscript_a', e); + } + conform_type('object', left); + break; + case undefined: + switch (get_type(left)) { + case 'array': + conform_type('number', e); + break; + case 'object': + conform_type('string', e); + break; + case 'string': + if (!option.confusion) { + warn('use_charAt', that); + } + set_type(that, 'string'); + break; + } + if (option.safe) { + warn('adsafe_subscript_a', e); + } + break; + default: + if (option.safe) { + warn('adsafe_subscript_a', e); + } + } + step_out(']', that); + discard(); + no_space(prev_token, token); + that.first = left; + that.second = e; + return that; + }, '', true); + + prefix('[', function () { + this.arity = 'prefix'; + this.first = []; + set_type(this, 'array'); + step_in('array'); + while (next_token.id !== '(end)') { + while (next_token.id === ',') { + warn('unexpected_a', next_token); + advance(','); + discard(); + } + if (next_token.id === ']') { + break; + } + indent.wrap = false; + edge(); + this.first.push(expression(10)); + if (next_token.id === ',') { + comma(); + if (next_token.id === ']' && !option.es5) { + warn('unexpected_a', token); + break; + } + } else { + break; + } + } + step_out(']', this); + discard(); + return this; + }, 170); + + + function property_name() { + var id = optional_identifier(true); + if (!id) { + if (next_token.id === '(string)') { + id = next_token.string; + if (option.safe) { + if (banned[id]) { + warn('adsafe_a'); + } else if (id.charAt(0) === '_' || + id.charAt(id.length - 1) === '_') { + warn('dangling_a'); + } + } + advance(); + } else if (next_token.id === '(number)') { + id = next_token.number.toString(); + advance(); + } + } + return id; + } + + + function function_params() { + var id, paren = next_token, params = []; + advance('('); + step_in(); + discard(); + no_space(); + if (next_token.id === ')') { + no_space(); + step_out(')', paren); + discard(); + return; + } + for (;;) { + edge(); + id = identifier(); + params.push(token); + add_label(token, option.unparam ? 'parameter' : 'unparam'); + if (next_token.id === ',') { + comma(); + } else { + no_space(); + step_out(')', paren); + discard(); + return params; + } + } + } + + + function complexity(exp) { + var score = 0; + if (exp) { + if (Array.isArray(exp)) { + exp.forEach(function (tok) { + score += complexity(tok); + }); + } else { + switch (exp.arity) { + case 'statement': + switch (exp.id) { + case 'if': + score += complexity(exp.first) + complexity(exp.block) + + complexity(exp['else']) + 1; + break; + case 'while': + case 'do': + if (exp.first.id !== 'true' && exp.first.number !== 1) { + score += 1; + } + score += complexity(exp.first) + complexity(exp.block); + break; + case 'for': + if (exp.second !== undefined && + exp.second.id !== 'true' && + exp.second.number !== 1) { + score += 1; + } + score += complexity(exp.first) + complexity(exp.second) + + complexity(exp.third) + complexity(exp.block); + break; + case 'switch': + score += complexity(exp.first) + + complexity(exp.second) + exp.second.length; + if (exp.second[exp.second.length - 1].id === 'default') { + score -= 1; + } + break; + case 'try': + if (exp.second) { + score += 1; + } + if (exp.third) { + score += 1; + } + score += complexity(exp.first) + complexity(exp.second) + + complexity(exp.third) + complexity(exp.block); + break; + } + break; + case 'prefix': + score += complexity(exp.first); + break; + case 'case': + case 'infix': + score += complexity(exp.first) + complexity(exp.second); + if (exp.id === '&&' || exp.id === '||') { + score += 1; + } + break; + case 'ternary': + score += complexity(exp.first) + complexity(exp.second) + complexity(exp.third); + break; + } + } + } + return score; + } + + + function do_function(func, name) { + var old_funct = funct, + old_option = option, + old_scope = scope; + funct = { + '(name)' : name || '\'' + (anonname || '').replace(nx, sanitize) + '\'', + '(line)' : next_token.line, + '(context)' : old_funct, + '(breakage)' : 0, + '(loopage)' : 0, + '(scope)' : scope, + '(token)' : func + }; + option = Object.create(old_option); + scope = Object.create(old_scope); + functions.push(funct); + func.name = name; + if (name) { + add_label(func, 'function', name); + } + func.writeable = false; + func.first = funct['(params)'] = function_params(); + one_space(); + func.block = block(false); + set_type(func, funct['(return_type)'] ? + 'function ' + funct['(return_type)'] : + 'function'); + if (funct['(old_property_type)']) { + property_type = funct['(old_property_type)']; + delete funct['(old_property_type)']; + } + funct['(complexity)'] = complexity(func.block) + 1; + if (option.confusion) { + funct['(confusion)'] = true; + } + funct = old_funct; + option = old_option; + scope = old_scope; + } + + + assignop('='); + assignop('+=', '+'); + assignop('-=', '-'); + assignop('*=', '*'); + assignop('/=', '/').nud = function () { + stop('slash_equal'); + }; + assignop('%=', '%'); + assignop('&=', '&'); + assignop('|=', '|'); + assignop('^=', '^'); + assignop('<<=', '<<'); + assignop('>>=', '>>'); + assignop('>>>=', '>>>'); + + + prefix('{', function () { + var get, i, j, name, p, set, seen = {}, type; + this.arity = 'prefix'; + this.first = []; + set_type(this, 'object'); + step_in(); + while (next_token.id !== '}') { + indent.wrap = false; + +// JSLint recognizes the ES5 extension for get/set in object literals, +// but requires that they be used in pairs. + + edge(); + if (next_token.string === 'get' && peek().id !== ':') { + if (!option.es5) { + warn('es5'); + } + get = next_token; + advance('get'); + one_space_only(); + name = next_token; + i = property_name(); + if (!i) { + stop('missing_property'); + } + get.string = ''; + do_function(get); + if (funct['(loopage)']) { + warn('function_loop', get); + } + p = get.first; + if (p) { + warn('parameter_a_get_b', p[0], p[0].string, i); + } + comma(); + set = next_token; + set.string = ''; + spaces(); + edge(); + advance('set'); + one_space_only(); + j = property_name(); + if (i !== j) { + stop('expected_a_b', token, i, j || next_token.string); + } + do_function(set); + p = set.first; + if (!p || p.length !== 1) { + stop('parameter_set_a', set, 'value'); + } else if (p[0].string !== 'value') { + stop('expected_a_b', p[0], 'value', p[0].string); + } + name.first = [get, set]; + } else { + name = next_token; + i = property_name(); + if (typeof i !== 'string') { + stop('missing_property'); + } + advance(':'); + discard(); + spaces(); + name.first = expression(10); + type = property_type[i]; + if (type) { + name.type = conform_type(type, name.first); + } else { + type = get_type(name.first); + if (type && type !== '*') { + property_type[i] = name.type = type; + } + } + } + this.first.push(name); + if (seen[i] === true) { + warn('duplicate_a', next_token, i); + } + seen[i] = true; + tally_property(i); + if (next_token.id !== ',') { + break; + } + for (;;) { + comma(); + if (next_token.id !== ',') { + break; + } + warn('unexpected_a', next_token); + } + if (next_token.id === '}' && !option.es5) { + warn('unexpected_a', token); + } + } + step_out('}', this); + discard(); + return this; + }); + + stmt('{', function () { + discard(); + warn('statement_block'); + this.arity = 'statement'; + this.block = statements(); + this.disrupt = this.block.disrupt; + advance('}', this); + discard(); + return this; + }); + + stmt('/*global', directive); + stmt('/*globals', directive); + stmt('/*jslint', directive); + stmt('/*member', directive); + stmt('/*members', directive); + stmt('/*property', directive); + stmt('/*properties', directive); + + stmt('var', function () { + +// JavaScript does not have block scope. It only has function scope. So, +// declaring a variable in a block can have unexpected consequences. + +// var.first will contain an array, the array containing name tokens +// and assignment tokens. + + var assign, id, name; + + if (funct['(vars)'] && !option.vars) { + warn('combine_var'); + } else if (funct !== global_funct) { + funct['(vars)'] = true; + } + this.arity = 'statement'; + this.first = []; + step_in('var'); + for (;;) { + name = next_token; + id = identifier(); + add_label(name, 'becoming'); + + if (next_token.id === '=') { + assign = next_token; + assign.first = name; + spaces(); + advance('='); + spaces(); + if (next_token.id === 'undefined') { + warn('unnecessary_initialize', token, id); + } + if (peek(0).id === '=' && next_token.identifier) { + stop('var_a_not'); + } + assign.second = expression(0); + assign.arity = 'infix'; + this.first.push(assign); + conform_type(name, assign.second); + } else { + this.first.push(name); + } + if (funct[id] === 'becoming') { + funct[id] = 'unused'; + } + if (next_token.id !== ',') { + break; + } + comma(); + indent.wrap = false; + if (var_mode && next_token.line === token.line && + this.first.length === 1) { + var_mode = null; + indent.open = false; + indent.at -= option.indent; + } + spaces(); + edge(); + } + var_mode = null; + step_out(); + return this; + }); + + stmt('function', function () { + one_space(); + if (in_block) { + warn('function_block', token); + } + var name = next_token, id = identifier(); + add_label(name, 'unction'); + no_space(); + do_function(this, id); + if (next_token.id === '(' && next_token.line === token.line) { + stop('function_statement'); + } + this.arity = 'statement'; + return this; + }); + + prefix('function', function () { + one_space(); + var id = optional_identifier(); + if (id) { + no_space(); + } else { + id = ''; + } + do_function(this, id); + if (funct['(loopage)']) { + warn('function_loop'); + } + this.arity = 'function'; + return this; + }); + + stmt('if', function () { + var paren = next_token; + one_space(); + advance('('); + step_in('control'); + discard(); + no_space(); + edge(); + this.arity = 'statement'; + this.first = expected_condition(expected_relation(expression(0))); + no_space(); + step_out(')', paren); + discard(); + one_space(); + this.block = block(true); + if (next_token.id === 'else') { + one_space(); + advance('else'); + discard(); + one_space(); + this['else'] = next_token.id === 'if' || next_token.id === 'switch' ? + statement(true) : block(true); + if (this['else'].disrupt && this.block.disrupt) { + this.disrupt = true; + } + } + return this; + }); + + stmt('try', function () { + +// try.first The catch variable +// try.second The catch clause +// try.third The finally clause +// try.block The try block + + var exception_variable, old_scope, paren; + if (option.adsafe) { + warn('adsafe_a', this); + } + one_space(); + this.arity = 'statement'; + this.block = block(false); + if (next_token.id === 'catch') { + one_space(); + advance('catch'); + discard(); + one_space(); + paren = next_token; + advance('('); + step_in('control'); + discard(); + no_space(); + edge(); + old_scope = scope; + scope = Object.create(old_scope); + exception_variable = next_token.string; + this.first = exception_variable; + if (!next_token.identifier) { + warn('expected_identifier_a', next_token); + } else { + add_label(next_token, 'exception'); + } + advance(); + no_space(); + step_out(')', paren); + discard(); + one_space(); + this.second = block(false); + scope = old_scope; + } + if (next_token.id === 'finally') { + discard(); + one_space(); + advance('finally'); + discard(); + one_space(); + this.third = block(false); + } else if (!this.second) { + stop('expected_a_b', next_token, 'catch', next_token.string); + } + return this; + }); + + labeled_stmt('while', function () { + one_space(); + var paren = next_token; + funct['(breakage)'] += 1; + funct['(loopage)'] += 1; + advance('('); + step_in('control'); + discard(); + no_space(); + edge(); + this.arity = 'statement'; + this.first = expected_relation(expression(0)); + if (this.first.id !== 'true') { + expected_condition(this.first, bundle.unexpected_a); + } + no_space(); + step_out(')', paren); + discard(); + one_space(); + this.block = block(true); + if (this.block.disrupt) { + warn('strange_loop', prev_token); + } + funct['(breakage)'] -= 1; + funct['(loopage)'] -= 1; + return this; + }); + + reserve('with'); + + labeled_stmt('switch', function () { + +// switch.first the switch expression +// switch.second the array of cases. A case is 'case' or 'default' token: +// case.first the array of case expressions +// case.second the array of statements +// If all of the arrays of statements are disrupt, then the switch is disrupt. + + var cases = [], + particular, + the_case = next_token, + unbroken = true; + + function find_duplicate_case(value) { + if (are_similar(particular, value)) { + warn('duplicate_a', value); + } + } + + funct['(breakage)'] += 1; + one_space(); + advance('('); + discard(); + no_space(); + step_in(); + this.arity = 'statement'; + this.first = expected_condition(expected_relation(expression(0))); + no_space(); + step_out(')', the_case); + discard(); + one_space(); + advance('{'); + step_in(); + this.second = []; + while (next_token.id === 'case') { + the_case = next_token; + cases.forEach(find_duplicate_case); + the_case.first = []; + the_case.arity = 'case'; + spaces(); + edge('case'); + advance('case'); + for (;;) { + one_space(); + particular = expression(0); + cases.forEach(find_duplicate_case); + cases.push(particular); + the_case.first.push(particular); + if (particular.id === 'NaN') { + warn('unexpected_a', particular); + } + no_space_only(); + advance(':'); + discard(); + if (next_token.id !== 'case') { + break; + } + spaces(); + edge('case'); + advance('case'); + discard(); + } + spaces(); + the_case.second = statements(); + if (the_case.second && the_case.second.length > 0) { + particular = the_case.second[the_case.second.length - 1]; + if (particular.disrupt) { + if (particular.id === 'break') { + unbroken = false; + } + } else { + warn('missing_a_after_b', next_token, 'break', 'case'); + } + } else { + warn('empty_case'); + } + this.second.push(the_case); + } + if (this.second.length === 0) { + warn('missing_a', next_token, 'case'); + } + if (next_token.id === 'default') { + spaces(); + the_case = next_token; + the_case.arity = 'case'; + edge('case'); + advance('default'); + discard(); + no_space_only(); + advance(':'); + discard(); + spaces(); + the_case.second = statements(); + if (the_case.second && the_case.second.length > 0) { + particular = the_case.second[the_case.second.length - 1]; + if (unbroken && particular.disrupt && particular.id !== 'break') { + this.disrupt = true; + } + } + this.second.push(the_case); + } + funct['(breakage)'] -= 1; + spaces(); + step_out('}', this); + return this; + }); + + stmt('debugger', function () { + if (!option.debug) { + warn('unexpected_a', this); + } + this.arity = 'statement'; + return this; + }); + + labeled_stmt('do', function () { + funct['(breakage)'] += 1; + funct['(loopage)'] += 1; + one_space(); + this.arity = 'statement'; + this.block = block(true); + if (this.block.disrupt) { + warn('strange_loop', prev_token); + } + one_space(); + advance('while'); + discard(); + var paren = next_token; + one_space(); + advance('('); + step_in(); + discard(); + no_space(); + edge(); + this.first = expected_condition(expected_relation(expression(0)), bundle.unexpected_a); + no_space(); + step_out(')', paren); + discard(); + funct['(breakage)'] -= 1; + funct['(loopage)'] -= 1; + return this; + }); + + labeled_stmt('for', function () { + + var blok, filter, ok = false, paren = next_token, the_in, value; + this.arity = 'statement'; + funct['(breakage)'] += 1; + funct['(loopage)'] += 1; + advance('('); + step_in('control'); + discard(); + spaces(this, paren); + no_space(); + if (next_token.id === 'var') { + stop('move_var'); + } + edge(); + if (peek(0).id === 'in') { + value = next_token; + switch (funct[value.string]) { + case 'unused': + funct[value.string] = 'var'; + break; + case 'closure': + case 'var': + break; + default: + warn('bad_in_a', value); + } + conform_type('string', value); + advance(); + the_in = next_token; + advance('in'); + the_in.first = value; + the_in.second = expression(20); + conform_type('object', the_in.second); + step_out(')', paren); + discard(); + this.first = the_in; + blok = block(true); + if (!option.forin) { + if (blok.length === 1 && typeof blok[0] === 'object' && + blok[0].string === 'if' && !blok[0]['else']) { + filter = blok[0].first; + while (filter.id === '&&') { + filter = filter.first; + } + switch (filter.id) { + case '===': + case '!==': + ok = filter.first.id === '[' ? ( + filter.first.first.string === the_in.second.string && + filter.first.second.string === the_in.first.string + ) : ( + filter.first.id === 'typeof' && + filter.first.first.id === '[' && + filter.first.first.first.string === the_in.second.string && + filter.first.first.second.string === the_in.first.string + ); + break; + case '(': + ok = filter.first.id === '.' && (( + filter.first.first.string === the_in.second.string && + filter.first.second.string === 'hasOwnProperty' && + filter.second[0].string === the_in.first.string + ) || ( + filter.first.first.string === 'ADSAFE' && + filter.first.second.string === 'has' && + filter.second[0].string === the_in.second.string && + filter.second[1].string === the_in.first.string + ) || ( + filter.first.first.id === '.' && + filter.first.first.first.id === '.' && + filter.first.first.first.first.string === 'Object' && + filter.first.first.first.second.string === 'prototype' && + filter.first.first.second.string === 'hasOwnProperty' && + filter.first.second.string === 'call' && + filter.second[0].string === the_in.second.string && + filter.second[1].string === the_in.first.string + )); + break; + } + } + if (!ok) { + warn('for_if', this); + } + } + } else { + if (next_token.id !== ';') { + edge(); + this.first = []; + for (;;) { + this.first.push(expression(0, 'for')); + if (next_token.id !== ',') { + break; + } + comma(); + } + } + semicolon(); + if (next_token.id !== ';') { + edge(); + this.second = expected_relation(expression(0)); + if (this.second.id !== 'true') { + expected_condition(this.second, bundle.unexpected_a); + } + } + semicolon(token); + if (next_token.id === ';') { + stop('expected_a_b', next_token, ')', ';'); + } + if (next_token.id !== ')') { + this.third = []; + edge(); + for (;;) { + this.third.push(expression(0, 'for')); + if (next_token.id !== ',') { + break; + } + comma(); + } + } + no_space(); + step_out(')', paren); + discard(); + one_space(); + blok = block(true); + } + if (blok.disrupt) { + warn('strange_loop', prev_token); + } + this.block = blok; + funct['(breakage)'] -= 1; + funct['(loopage)'] -= 1; + return this; + }); + + disrupt_stmt('break', function () { + var label = next_token.string; + this.arity = 'statement'; + if (funct['(breakage)'] === 0) { + warn('unexpected_a', this); + } + if (next_token.identifier && token.line === next_token.line) { + one_space_only(); + if (funct[label] !== 'label') { + warn('not_a_label', next_token); + } else if (scope[label].funct !== funct) { + warn('not_a_scope', next_token); + } + this.first = next_token; + advance(); + } + return this; + }); + + disrupt_stmt('continue', function () { + if (!option['continue']) { + warn('unexpected_a', this); + } + var label = next_token.string; + this.arity = 'statement'; + if (funct['(breakage)'] === 0) { + warn('unexpected_a', this); + } + if (next_token.identifier && token.line === next_token.line) { + one_space_only(); + if (funct[label] !== 'label') { + warn('not_a_label', next_token); + } else if (scope[label].funct !== funct) { + warn('not_a_scope', next_token); + } + this.first = next_token; + advance(); + } + return this; + }); + + disrupt_stmt('return', function () { + if (funct === global_funct) { + warn('unexpected_a', this); + } + this.arity = 'statement'; + if (next_token.id !== ';' && next_token.line === token.line) { + one_space_only(); + if (next_token.id === '/' || next_token.id === '(regexp)') { + warn('wrap_regexp'); + } + this.first = expression(20); + funct['(return_type)'] = conform_type(funct['(return_type)'], this.first); + } + return this; + }); + + disrupt_stmt('throw', function () { + this.arity = 'statement'; + one_space_only(); + this.first = expression(20); + return this; + }); + + +// Superfluous reserved words + + reserve('class'); + reserve('const'); + reserve('enum'); + reserve('export'); + reserve('extends'); + reserve('import'); + reserve('super'); + +// Harmony reserved words + + reserve('let'); + reserve('yield'); + reserve('implements'); + reserve('interface'); + reserve('package'); + reserve('private'); + reserve('protected'); + reserve('public'); + reserve('static'); + + +// Parse JSON + + function json_value() { + + function json_object() { + var brace = next_token, object = {}; + advance('{'); + if (next_token.id !== '}') { + while (next_token.id !== '(end)') { + while (next_token.id === ',') { + warn('unexpected_a', next_token); + comma(); + } + if (next_token.id !== '(string)') { + warn('expected_string_a'); + } + if (object[next_token.string] === true) { + warn('duplicate_a'); + } else if (next_token.string === '__proto__') { + warn('dangling_a'); + } else { + object[next_token.string] = true; + } + advance(); + advance(':'); + json_value(); + if (next_token.id !== ',') { + break; + } + comma(); + if (next_token.id === '}') { + warn('unexpected_a', token); + break; + } + } + } + advance('}', brace); + } + + function json_array() { + var bracket = next_token; + advance('['); + if (next_token.id !== ']') { + while (next_token.id !== '(end)') { + while (next_token.id === ',') { + warn('unexpected_a', next_token); + comma(); + } + json_value(); + if (next_token.id !== ',') { + break; + } + comma(); + if (next_token.id === ']') { + warn('unexpected_a', token); + break; + } + } + } + advance(']', bracket); + } + + switch (next_token.id) { + case '{': + json_object(); + break; + case '[': + json_array(); + break; + case 'true': + case 'false': + case 'null': + case '(number)': + case '(string)': + advance(); + break; + case '-': + advance('-'); + no_space_only(); + advance('(number)'); + break; + default: + stop('unexpected_a'); + } + } + + +// CSS parsing. + + function css_name() { + if (next_token.identifier) { + advance(); + return true; + } + } + + + function css_number() { + if (next_token.id === '-') { + advance('-'); + no_space_only(); + } + if (next_token.id === '(number)') { + advance('(number)'); + return true; + } + } + + + function css_string() { + if (next_token.id === '(string)') { + advance(); + return true; + } + } + + function css_color() { + var i, number, paren, value; + if (next_token.identifier) { + value = next_token.string; + if (value === 'rgb' || value === 'rgba') { + advance(); + paren = next_token; + advance('('); + for (i = 0; i < 3; i += 1) { + if (i) { + comma(); + } + number = next_token.number; + if (next_token.id !== '(string)' || number < 0) { + warn('expected_positive_a', next_token); + advance(); + } else { + advance(); + if (next_token.id === '%') { + advance('%'); + if (number > 100) { + warn('expected_percent_a', token, number); + } + } else { + if (number > 255) { + warn('expected_small_a', token, number); + } + } + } + } + if (value === 'rgba') { + comma(); + number = next_token.number; + if (next_token.id !== '(string)' || number < 0 || number > 1) { + warn('expected_fraction_a', next_token); + } + advance(); + if (next_token.id === '%') { + warn('unexpected_a'); + advance('%'); + } + } + advance(')', paren); + return true; + } else if (css_colorData[next_token.string] === true) { + advance(); + return true; + } + } else if (next_token.id === '(color)') { + advance(); + return true; + } + return false; + } + + + function css_length() { + if (next_token.id === '-') { + advance('-'); + no_space_only(); + } + if (next_token.id === '(number)') { + advance(); + if (next_token.id !== '(string)' && + css_lengthData[next_token.string] === true) { + no_space_only(); + advance(); + } else if (+token.number !== 0) { + warn('expected_linear_a'); + } + return true; + } + return false; + } + + + function css_line_height() { + if (next_token.id === '-') { + advance('-'); + no_space_only(); + } + if (next_token.id === '(number)') { + advance(); + if (next_token.id !== '(string)' && + css_lengthData[next_token.string] === true) { + no_space_only(); + advance(); + } + return true; + } + return false; + } + + + function css_width() { + if (next_token.identifier) { + switch (next_token.string) { + case 'thin': + case 'medium': + case 'thick': + advance(); + return true; + } + } else { + return css_length(); + } + } + + + function css_margin() { + if (next_token.identifier) { + if (next_token.string === 'auto') { + advance(); + return true; + } + } else { + return css_length(); + } + } + + function css_attr() { + if (next_token.identifier && next_token.string === 'attr') { + advance(); + advance('('); + if (!next_token.identifier) { + warn('expected_name_a'); + } + advance(); + advance(')'); + return true; + } + return false; + } + + + function css_comma_list() { + while (next_token.id !== ';') { + if (!css_name() && !css_string()) { + warn('expected_name_a'); + } + if (next_token.id !== ',') { + return true; + } + comma(); + } + } + + + function css_counter() { + if (next_token.identifier && next_token.string === 'counter') { + advance(); + advance('('); + advance(); + if (next_token.id === ',') { + comma(); + if (next_token.id !== '(string)') { + warn('expected_string_a'); + } + advance(); + } + advance(')'); + return true; + } + if (next_token.identifier && next_token.string === 'counters') { + advance(); + advance('('); + if (!next_token.identifier) { + warn('expected_name_a'); + } + advance(); + if (next_token.id === ',') { + comma(); + if (next_token.id !== '(string)') { + warn('expected_string_a'); + } + advance(); + } + if (next_token.id === ',') { + comma(); + if (next_token.id !== '(string)') { + warn('expected_string_a'); + } + advance(); + } + advance(')'); + return true; + } + return false; + } + + + function css_shape() { + var i; + if (next_token.identifier && next_token.string === 'rect') { + advance(); + advance('('); + for (i = 0; i < 4; i += 1) { + if (!css_length()) { + warn('expected_number_a'); + break; + } + } + advance(')'); + return true; + } + return false; + } + + + function css_url() { + var c, url; + if (next_token.identifier && next_token.string === 'url') { + next_token = lex.range('(', ')'); + url = next_token.string; + c = url.charAt(0); + if (c === '"' || c === '\'') { + if (url.slice(-1) !== c) { + warn('bad_url'); + } else { + url = url.slice(1, -1); + if (url.indexOf(c) >= 0) { + warn('bad_url'); + } + } + } + if (!url) { + warn('missing_url'); + } + if (option.safe && ux.test(url)) { + stop('adsafe_a', next_token, url); + } + urls.push(url); + advance(); + return true; + } + return false; + } + + + css_any = [css_url, function () { + for (;;) { + if (next_token.identifier) { + switch (next_token.string.toLowerCase()) { + case 'url': + css_url(); + break; + case 'expression': + warn('unexpected_a'); + advance(); + break; + default: + advance(); + } + } else { + if (next_token.id === ';' || next_token.id === '!' || + next_token.id === '(end)' || next_token.id === '}') { + return true; + } + advance(); + } + } + }]; + + + css_border_style = [ + 'none', 'dashed', 'dotted', 'double', 'groove', + 'hidden', 'inset', 'outset', 'ridge', 'solid' + ]; + + css_break = [ + 'auto', 'always', 'avoid', 'left', 'right' + ]; + + css_media = { + 'all': true, + 'braille': true, + 'embossed': true, + 'handheld': true, + 'print': true, + 'projection': true, + 'screen': true, + 'speech': true, + 'tty': true, + 'tv': true + }; + + css_overflow = [ + 'auto', 'hidden', 'scroll', 'visible' + ]; + + css_attribute_data = { + background: [ + true, 'background-attachment', 'background-color', + 'background-image', 'background-position', 'background-repeat' + ], + 'background-attachment': ['scroll', 'fixed'], + 'background-color': ['transparent', css_color], + 'background-image': ['none', css_url], + 'background-position': [ + 2, [css_length, 'top', 'bottom', 'left', 'right', 'center'] + ], + 'background-repeat': [ + 'repeat', 'repeat-x', 'repeat-y', 'no-repeat' + ], + 'border': [true, 'border-color', 'border-style', 'border-width'], + 'border-bottom': [ + true, 'border-bottom-color', 'border-bottom-style', + 'border-bottom-width' + ], + 'border-bottom-color': css_color, + 'border-bottom-style': css_border_style, + 'border-bottom-width': css_width, + 'border-collapse': ['collapse', 'separate'], + 'border-color': ['transparent', 4, css_color], + 'border-left': [ + true, 'border-left-color', 'border-left-style', 'border-left-width' + ], + 'border-left-color': css_color, + 'border-left-style': css_border_style, + 'border-left-width': css_width, + 'border-right': [ + true, 'border-right-color', 'border-right-style', + 'border-right-width' + ], + 'border-right-color': css_color, + 'border-right-style': css_border_style, + 'border-right-width': css_width, + 'border-spacing': [2, css_length], + 'border-style': [4, css_border_style], + 'border-top': [ + true, 'border-top-color', 'border-top-style', 'border-top-width' + ], + 'border-top-color': css_color, + 'border-top-style': css_border_style, + 'border-top-width': css_width, + 'border-width': [4, css_width], + bottom: [css_length, 'auto'], + 'caption-side' : ['bottom', 'left', 'right', 'top'], + clear: ['both', 'left', 'none', 'right'], + clip: [css_shape, 'auto'], + color: css_color, + content: [ + 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote', + css_string, css_url, css_counter, css_attr + ], + 'counter-increment': [ + css_name, 'none' + ], + 'counter-reset': [ + css_name, 'none' + ], + cursor: [ + css_url, 'auto', 'crosshair', 'default', 'e-resize', 'help', 'move', + 'n-resize', 'ne-resize', 'nw-resize', 'pointer', 's-resize', + 'se-resize', 'sw-resize', 'w-resize', 'text', 'wait' + ], + direction: ['ltr', 'rtl'], + display: [ + 'block', 'compact', 'inline', 'inline-block', 'inline-table', + 'list-item', 'marker', 'none', 'run-in', 'table', 'table-caption', + 'table-cell', 'table-column', 'table-column-group', + 'table-footer-group', 'table-header-group', 'table-row', + 'table-row-group' + ], + 'empty-cells': ['show', 'hide'], + 'float': ['left', 'none', 'right'], + font: [ + 'caption', 'icon', 'menu', 'message-box', 'small-caption', + 'status-bar', true, 'font-size', 'font-style', 'font-weight', + 'font-family' + ], + 'font-family': css_comma_list, + 'font-size': [ + 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', + 'xx-large', 'larger', 'smaller', css_length + ], + 'font-size-adjust': ['none', css_number], + 'font-stretch': [ + 'normal', 'wider', 'narrower', 'ultra-condensed', + 'extra-condensed', 'condensed', 'semi-condensed', + 'semi-expanded', 'expanded', 'extra-expanded' + ], + 'font-style': [ + 'normal', 'italic', 'oblique' + ], + 'font-variant': [ + 'normal', 'small-caps' + ], + 'font-weight': [ + 'normal', 'bold', 'bolder', 'lighter', css_number + ], + height: [css_length, 'auto'], + left: [css_length, 'auto'], + 'letter-spacing': ['normal', css_length], + 'line-height': ['normal', css_line_height], + 'list-style': [ + true, 'list-style-image', 'list-style-position', 'list-style-type' + ], + 'list-style-image': ['none', css_url], + 'list-style-position': ['inside', 'outside'], + 'list-style-type': [ + 'circle', 'disc', 'square', 'decimal', 'decimal-leading-zero', + 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha', + 'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'katakana', + 'hiragana-iroha', 'katakana-oroha', 'none' + ], + margin: [4, css_margin], + 'margin-bottom': css_margin, + 'margin-left': css_margin, + 'margin-right': css_margin, + 'margin-top': css_margin, + 'marker-offset': [css_length, 'auto'], + 'max-height': [css_length, 'none'], + 'max-width': [css_length, 'none'], + 'min-height': css_length, + 'min-width': css_length, + opacity: css_number, + outline: [true, 'outline-color', 'outline-style', 'outline-width'], + 'outline-color': ['invert', css_color], + 'outline-style': [ + 'dashed', 'dotted', 'double', 'groove', 'inset', 'none', + 'outset', 'ridge', 'solid' + ], + 'outline-width': css_width, + overflow: css_overflow, + 'overflow-x': css_overflow, + 'overflow-y': css_overflow, + padding: [4, css_length], + 'padding-bottom': css_length, + 'padding-left': css_length, + 'padding-right': css_length, + 'padding-top': css_length, + 'page-break-after': css_break, + 'page-break-before': css_break, + position: ['absolute', 'fixed', 'relative', 'static'], + quotes: [8, css_string], + right: [css_length, 'auto'], + 'table-layout': ['auto', 'fixed'], + 'text-align': ['center', 'justify', 'left', 'right'], + 'text-decoration': [ + 'none', 'underline', 'overline', 'line-through', 'blink' + ], + 'text-indent': css_length, + 'text-shadow': ['none', 4, [css_color, css_length]], + 'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'], + top: [css_length, 'auto'], + 'unicode-bidi': ['normal', 'embed', 'bidi-override'], + 'vertical-align': [ + 'baseline', 'bottom', 'sub', 'super', 'top', 'text-top', 'middle', + 'text-bottom', css_length + ], + visibility: ['visible', 'hidden', 'collapse'], + 'white-space': [ + 'normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'inherit' + ], + width: [css_length, 'auto'], + 'word-spacing': ['normal', css_length], + 'word-wrap': ['break-word', 'normal'], + 'z-index': ['auto', css_number] + }; + + function style_attribute() { + var v; + while (next_token.id === '*' || next_token.id === '#' || + next_token.string === '_') { + if (!option.css) { + warn('unexpected_a'); + } + advance(); + } + if (next_token.id === '-') { + if (!option.css) { + warn('unexpected_a'); + } + advance('-'); + if (!next_token.identifier) { + warn('expected_nonstandard_style_attribute'); + } + advance(); + return css_any; + } else { + if (!next_token.identifier) { + warn('expected_style_attribute'); + } else { + if (Object.prototype.hasOwnProperty.call(css_attribute_data, next_token.string)) { + v = css_attribute_data[next_token.string]; + } else { + v = css_any; + if (!option.css) { + warn('unrecognized_style_attribute_a'); + } + } + } + advance(); + return v; + } + } + + + function style_value(v) { + + /*jslint confusion: true */ + + var i = 0, + n, + once, + match, + round, + start = 0, + vi; + switch (typeof v) { + case 'function': + return v(); + case 'string': + if (next_token.identifier && next_token.string === v) { + advance(); + return true; + } + return false; + } + for (;;) { + if (i >= v.length) { + return false; + } + vi = v[i]; + i += 1; + if (typeof vi === 'boolean') { + break; + } else if (typeof vi === 'number') { + n = vi; + vi = v[i]; + i += 1; + } else { + n = 1; + } + match = false; + while (n > 0) { + if (style_value(vi)) { + match = true; + n -= 1; + } else { + break; + } + } + if (match) { + return true; + } + } + start = i; + once = []; + for (;;) { + round = false; + for (i = start; i < v.length; i += 1) { + if (!once[i]) { + if (style_value(css_attribute_data[v[i]])) { + match = true; + round = true; + once[i] = true; + break; + } + } + } + if (!round) { + return match; + } + } + } + + function style_child() { + if (next_token.id === '(number)') { + advance(); + if (next_token.string === 'n' && next_token.identifier) { + no_space_only(); + advance(); + if (next_token.id === '+') { + no_space_only(); + advance('+'); + no_space_only(); + advance('(number)'); + } + } + return; + } else { + if (next_token.identifier && + (next_token.string === 'odd' || next_token.string === 'even')) { + advance(); + return; + } + } + warn('unexpected_a'); + } + + function substyle() { + var v; + for (;;) { + if (next_token.id === '}' || next_token.id === '(end)' || + (xquote && next_token.id === xquote)) { + return; + } + while (next_token.id === ';') { + warn('unexpected_a'); + semicolon(); + } + v = style_attribute(); + advance(':'); + if (next_token.identifier && next_token.string === 'inherit') { + advance(); + } else { + if (!style_value(v)) { + warn('unexpected_a'); + advance(); + } + } + if (next_token.id === '!') { + advance('!'); + no_space_only(); + if (next_token.identifier && next_token.string === 'important') { + advance(); + } else { + warn('expected_a_b', + next_token, 'important', next_token.string); + } + } + if (next_token.id === '}' || next_token.id === xquote) { + warn('expected_a_b', next_token, ';', next_token.string); + } else { + semicolon(); + } + } + } + + function style_selector() { + if (next_token.identifier) { + if (!Object.prototype.hasOwnProperty.call(html_tag, option.cap ? + next_token.string.toLowerCase() : next_token.string)) { + warn('expected_tagname_a'); + } + advance(); + } else { + switch (next_token.id) { + case '>': + case '+': + advance(); + style_selector(); + break; + case ':': + advance(':'); + switch (next_token.string) { + case 'active': + case 'after': + case 'before': + case 'checked': + case 'disabled': + case 'empty': + case 'enabled': + case 'first-child': + case 'first-letter': + case 'first-line': + case 'first-of-type': + case 'focus': + case 'hover': + case 'last-child': + case 'last-of-type': + case 'link': + case 'only-of-type': + case 'root': + case 'target': + case 'visited': + advance(); + break; + case 'lang': + advance(); + advance('('); + if (!next_token.identifier) { + warn('expected_lang_a'); + } + advance(')'); + break; + case 'nth-child': + case 'nth-last-child': + case 'nth-last-of-type': + case 'nth-of-type': + advance(); + advance('('); + style_child(); + advance(')'); + break; + case 'not': + advance(); + advance('('); + if (next_token.id === ':' && peek(0).string === 'not') { + warn('not'); + } + style_selector(); + advance(')'); + break; + default: + warn('expected_pseudo_a'); + } + break; + case '#': + advance('#'); + if (!next_token.identifier) { + warn('expected_id_a'); + } + advance(); + break; + case '*': + advance('*'); + break; + case '.': + advance('.'); + if (!next_token.identifier) { + warn('expected_class_a'); + } + advance(); + break; + case '[': + advance('['); + if (!next_token.identifier) { + warn('expected_attribute_a'); + } + advance(); + if (next_token.id === '=' || next_token.string === '~=' || + next_token.string === '$=' || + next_token.string === '|=' || + next_token.id === '*=' || + next_token.id === '^=') { + advance(); + if (next_token.id !== '(string)') { + warn('expected_string_a'); + } + advance(); + } + advance(']'); + break; + default: + stop('expected_selector_a'); + } + } + } + + function style_pattern() { + if (next_token.id === '{') { + warn('expected_style_pattern'); + } + for (;;) { + style_selector(); + if (next_token.id === '= 0) { + warn('unexpected_char_a_b', token, v.charAt(x), a); + } + ids[u] = true; + } else if (a === 'class' || a === 'type' || a === 'name') { + x = v.search(qx); + if (x >= 0) { + warn('unexpected_char_a_b', token, v.charAt(x), a); + } + ids[u] = true; + } else if (a === 'href' || a === 'background' || + a === 'content' || a === 'data' || + a.indexOf('src') >= 0 || a.indexOf('url') >= 0) { + if (option.safe && ux.test(v)) { + stop('bad_url', next_token, v); + } + urls.push(v); + } else if (a === 'for') { + if (option.adsafe) { + if (adsafe_id) { + if (v.slice(0, adsafe_id.length) !== adsafe_id) { + warn('adsafe_prefix_a', next_token, adsafe_id); + } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) { + warn('adsafe_bad_id'); + } + } else { + warn('adsafe_bad_id'); + } + } + } else if (a === 'name') { + if (option.adsafe && v.indexOf('_') >= 0) { + warn('adsafe_name_a', next_token, v); + } + } + } + + function do_tag(name, attribute) { + var i, tag = html_tag[name], script, x; + src = false; + if (!tag) { + stop( + bundle.unrecognized_tag_a, + next_token, + name === name.toLowerCase() ? name : name + ' (capitalization error)' + ); + } + if (stack.length > 0) { + if (name === 'html') { + stop('unexpected_a', token, name); + } + x = tag.parent; + if (x) { + if (x.indexOf(' ' + stack[stack.length - 1].name + ' ') < 0) { + stop('tag_a_in_b', token, name, x); + } + } else if (!option.adsafe && !option.fragment) { + i = stack.length; + do { + if (i <= 0) { + stop('tag_a_in_b', token, name, 'body'); + } + i -= 1; + } while (stack[i].name !== 'body'); + } + } + switch (name) { + case 'div': + if (option.adsafe && stack.length === 1 && !adsafe_id) { + warn('adsafe_missing_id'); + } + break; + case 'script': + xmode = 'script'; + advance('>'); + if (attribute.lang) { + warn('lang', token); + } + if (option.adsafe && stack.length !== 1) { + warn('adsafe_placement', token); + } + if (attribute.src) { + if (option.adsafe && (!adsafe_may || !approved[attribute.src])) { + warn('adsafe_source', token); + } + if (attribute.type) { + warn('type', token); + } + } else { + step_in(next_token.from); + edge(); + use_strict(); + adsafe_top = true; + script = statements(); + +// JSLint is also the static analyzer for ADsafe. See www.ADsafe.org. + + if (option.adsafe) { + if (adsafe_went) { + stop('adsafe_script', token); + } + if (script.length !== 1 || + aint(script[0], 'id', '(') || + aint(script[0].first, 'id', '.') || + aint(script[0].first.first, 'string', 'ADSAFE') || + aint(script[0].second[0], 'string', adsafe_id)) { + stop('adsafe_id_go'); + } + switch (script[0].first.second.string) { + case 'id': + if (adsafe_may || adsafe_went || + script[0].second.length !== 1) { + stop('adsafe_id', next_token); + } + adsafe_may = true; + break; + case 'go': + if (adsafe_went) { + stop('adsafe_go'); + } + if (script[0].second.length !== 2 || + aint(script[0].second[1], 'id', 'function') || + !script[0].second[1].first || + script[0].second[1].first.length !== 2 || + aint(script[0].second[1].first[0], 'string', 'dom') || + aint(script[0].second[1].first[1], 'string', 'lib')) { + stop('adsafe_go', next_token); + } + adsafe_went = true; + break; + default: + stop('adsafe_id_go'); + } + } + indent = null; + } + xmode = 'html'; + advance(''); + styles(); + xmode = 'html'; + advance(''; + } + + function html() { + + /*jslint confusion: true */ + + var attribute, attributes, is_empty, name, old_white = option.white, + quote, tag_name, tag, wmode; + xmode = 'html'; + xquote = ''; + stack = null; + for (;;) { + switch (next_token.string) { + case '<': + xmode = 'html'; + advance('<'); + attributes = {}; + tag_name = next_token; + if (!tag_name.identifier) { + warn('bad_name_a', tag_name); + } + name = tag_name.string; + if (option.cap) { + name = name.toLowerCase(); + } + tag_name.name = name; + advance(); + if (!stack) { + stack = []; + do_begin(name); + } + tag = html_tag[name]; + if (typeof tag !== 'object') { + stop('unrecognized_tag_a', tag_name, name); + } + is_empty = tag.empty; + tag_name.type = name; + for (;;) { + if (next_token.id === '/') { + advance('/'); + if (next_token.id !== '>') { + warn('expected_a_b', next_token, '>', next_token.string); + } + break; + } + if (next_token.id && next_token.id.charAt(0) === '>') { + break; + } + if (!next_token.identifier) { + if (next_token.id === '(end)' || next_token.id === '(error)') { + warn('expected_a_b', next_token, '>', next_token.string); + } + warn('bad_name_a'); + } + option.white = false; + spaces(); + attribute = next_token.string; + option.white = old_white; + advance(); + if (!option.cap && attribute !== attribute.toLowerCase()) { + warn('attribute_case_a', token); + } + attribute = attribute.toLowerCase(); + xquote = ''; + if (Object.prototype.hasOwnProperty.call(attributes, attribute)) { + warn('duplicate_a', token, attribute); + } + if (attribute.slice(0, 2) === 'on') { + if (!option.on) { + warn('html_handlers'); + } + xmode = 'scriptstring'; + advance('='); + quote = next_token.id; + if (quote !== '"' && quote !== '\'') { + stop('expected_a_b', next_token, '"', next_token.string); + } + xquote = quote; + wmode = option.white; + option.white = true; + advance(quote); + use_strict(); + statements(); + option.white = wmode; + if (next_token.id !== quote) { + stop('expected_a_b', next_token, quote, next_token.string); + } + xmode = 'html'; + xquote = ''; + advance(quote); + tag = false; + } else if (attribute === 'style') { + xmode = 'scriptstring'; + advance('='); + quote = next_token.id; + if (quote !== '"' && quote !== '\'') { + stop('expected_a_b', next_token, '"', next_token.string); + } + xmode = 'styleproperty'; + xquote = quote; + advance(quote); + substyle(); + xmode = 'html'; + xquote = ''; + advance(quote); + tag = false; + } else { + if (next_token.id === '=') { + advance('='); + tag = next_token.string; + if (!next_token.identifier && + next_token.id !== '"' && + next_token.id !== '\'' && + next_token.id !== '(string)' && + next_token.id !== '(string)' && + next_token.id !== '(color)') { + warn('expected_attribute_value_a', token, attribute); + } + advance(); + } else { + tag = true; + } + } + attributes[attribute] = tag; + do_attribute(attribute, tag); + } + do_tag(name, attributes); + if (!is_empty) { + stack.push(tag_name); + } + xmode = 'outer'; + advance('>'); + break; + case '') { + stop('expected_a_b', next_token, '>', next_token.string); + } + xmode = 'outer'; + advance('>'); + break; + case '' || next_token.id === '(end)') { + break; + } + if (next_token.string.indexOf('--') >= 0) { + stop('unexpected_a', next_token, '--'); + } + if (next_token.string.indexOf('<') >= 0) { + stop('unexpected_a', next_token, '<'); + } + if (next_token.string.indexOf('>') >= 0) { + stop('unexpected_a', next_token, '>'); + } + } + xmode = 'outer'; + advance('>'); + break; + case '(end)': + return; + default: + if (next_token.id === '(end)') { + stop('missing_a', next_token, + ''); + } else { + advance(); + } + } + if (stack && stack.length === 0 && (option.adsafe || + !option.fragment || next_token.id === '(end)')) { + break; + } + } + if (next_token.id !== '(end)') { + stop('unexpected_a'); + } + } + + +// The actual JSLINT function itself. + + itself = function JSLint(the_source, the_option) { + + var i, predef, tree; + JSLINT.comments = []; + JSLINT.errors = []; + JSLINT.tree = ''; + begin = older_token = prev_token = token = next_token = + Object.create(syntax['(begin)']); + predefined = {}; + add_to_predefined(standard); + property_type = Object.create(standard_property_type); + if (the_option) { + option = Object.create(the_option); + predef = option.predef; + if (predef) { + if (Array.isArray(predef)) { + for (i = 0; i < predef.length; i += 1) { + predefined[predef[i]] = true; + } + } else if (typeof predef === 'object') { + add_to_predefined(predef); + } + } + do_safe(); + } else { + option = {}; + } + option.indent = +option.indent || 0; + option.maxerr = option.maxerr || 50; + adsafe_id = ''; + adsafe_may = adsafe_top = adsafe_went = false; + approved = {}; + if (option.approved) { + for (i = 0; i < option.approved.length; i += 1) { + approved[option.approved[i]] = option.approved[i]; + } + } else { + approved.test = 'test'; + } + tab = ''; + for (i = 0; i < option.indent; i += 1) { + tab += ' '; + } + global_scope = scope = {}; + global_funct = funct = { + '(scope)': scope, + '(breakage)': 0, + '(loopage)': 0 + }; + functions = [funct]; + + comments_off = false; + ids = {}; + in_block = false; + indent = null; + json_mode = false; + lookahead = []; + member = {}; + node_js = false; + prereg = true; + src = false; + stack = null; + strict_mode = false; + urls = []; + var_mode = null; + warnings = 0; + xmode = ''; + lex.init(the_source); + + assume(); + + try { + advance(); + if (next_token.id === '(number)') { + stop('unexpected_a'); + } else if (next_token.string.charAt(0) === '<') { + html(); + if (option.adsafe && !adsafe_went) { + warn('adsafe_go', this); + } + } else { + switch (next_token.id) { + case '{': + case '[': + json_mode = true; + json_value(); + break; + case '@': + case '*': + case '#': + case '.': + case ':': + xmode = 'style'; + advance(); + if (token.id !== '@' || !next_token.identifier || + next_token.string !== 'charset' || token.line !== 1 || + token.from !== 1) { + stop('css'); + } + advance(); + if (next_token.id !== '(string)' && + next_token.string !== 'UTF-8') { + stop('css'); + } + advance(); + semicolon(); + styles(); + break; + + default: + if (option.adsafe && option.fragment) { + stop('expected_a_b', + next_token, '
', next_token.string); + } + +// If the first token is predef semicolon, ignore it. This is sometimes used when +// files are intended to be appended to files that may be sloppy. predef sloppy +// file may be depending on semicolon insertion on its last line. + + step_in(1); + if (next_token.id === ';' && !node_js) { + semicolon(); + } + adsafe_top = true; + tree = statements(); + begin.first = tree; + JSLINT.tree = begin; + if (option.adsafe && (tree.length !== 1 || + aint(tree[0], 'id', '(') || + aint(tree[0].first, 'id', '.') || + aint(tree[0].first.first, 'string', 'ADSAFE') || + aint(tree[0].first.second, 'string', 'lib') || + tree[0].second.length !== 2 || + tree[0].second[0].id !== '(string)' || + aint(tree[0].second[1], 'id', 'function'))) { + stop('adsafe_lib'); + } + if (tree.disrupt) { + warn('weird_program', prev_token); + } + } + } + indent = null; + advance('(end)'); + } catch (e) { + if (e) { // `~ + JSLINT.errors.push({ + reason : e.message, + line : e.line || next_token.line, + character : e.character || next_token.from + }, null); + } + } + return JSLINT.errors.length === 0; + }; + + +// Data summary. + + itself.data = function () { + var data = {functions: []}, + function_data, + globals, + i, + j, + kind, + members = [], + name, + the_function, + undef = [], + unused = []; + if (itself.errors.length) { + data.errors = itself.errors; + } + + if (json_mode) { + data.json = true; + } + + if (urls.length > 0) { + data.urls = urls; + } + + globals = Object.keys(global_scope).filter(function (value) { + return value.charAt(0) !== '(' && typeof standard[value] !== 'boolean'; + }); + if (globals.length > 0) { + data.globals = globals; + } + + for (i = 1; i < functions.length; i += 1) { + the_function = functions[i]; + function_data = {}; + for (j = 0; j < functionicity.length; j += 1) { + function_data[functionicity[j]] = []; + } + for (name in the_function) { + if (Object.prototype.hasOwnProperty.call(the_function, name)) { + if (name.charAt(0) !== '(') { + kind = the_function[name]; + if (kind === 'unction' || kind === 'unparam') { + kind = 'unused'; + } + if (Array.isArray(function_data[kind])) { + function_data[kind].push(name); + if (kind === 'unused') { + unused.push({ + name: name, + line: the_function['(line)'], + 'function': the_function['(name)'] + }); + } else if (kind === 'undef') { + undef.push({ + name: name, + line: the_function['(line)'], + 'function': the_function['(name)'] + }); + } + } + } + } + } + for (j = 0; j < functionicity.length; j += 1) { + if (function_data[functionicity[j]].length === 0) { + delete function_data[functionicity[j]]; + } + } + function_data.name = the_function['(name)']; + function_data.params = the_function['(params)']; + function_data.line = the_function['(line)']; + function_data['(complexity)'] = the_function['(complexity)']; + data.functions.push(function_data); + } + + if (unused.length > 0) { + data.unused = unused; + } + if (undef.length > 0) { + data['undefined'] = undef; + } + + members = []; + for (name in member) { + if (typeof member[name] === 'number') { + data.member = member; + break; + } + } + + return data; + }; + + + itself.report = function (errors_only) { + var data = itself.data(), err, evidence, i, italics, j, key, keys, length, + mem = '', name, names, output = [], snippets, the_function, type, + warning; + + function detail(h, value) { + var comma_needed, singularity; + if (Array.isArray(value)) { + output.push('
' + h + ' '); + value.sort().forEach(function (item) { + if (item !== singularity) { + singularity = item; + output.push((comma_needed ? ', ' : '') + singularity); + comma_needed = true; + } + }); + output.push('
'); + } else if (value) { + output.push('
' + h + ' ' + value + '
'); + } + } + + if (data.errors || data.unused || data['undefined']) { + err = true; + output.push('
Error:'); + if (data.errors) { + for (i = 0; i < data.errors.length; i += 1) { + warning = data.errors[i]; + if (warning) { + evidence = warning.evidence || ''; + output.push('

Problem' + (isFinite(warning.line) ? + ' at line ' + String(warning.line) + ' character ' + + String(warning.character) : '') + + ': ' + warning.reason.entityify() + + '

' + + (evidence && (evidence.length > 80 ? evidence.slice(0, 77) + '...' : + evidence).entityify()) + '

'); + } + } + } + + if (data['undefined']) { + snippets = []; + for (i = 0; i < data['undefined'].length; i += 1) { + snippets[i] = '' + data['undefined'][i].name + ' ' + + String(data['undefined'][i].line) + ' ' + + data['undefined'][i]['function'] + ''; + } + output.push('

Undefined variable: ' + snippets.join(', ') + '

'); + } + if (data.unused) { + snippets = []; + for (i = 0; i < data.unused.length; i += 1) { + snippets[i] = '' + data.unused[i].name + ' ' + + String(data.unused[i].line) + ' ' + + data.unused[i]['function'] + ''; + } + output.push('

Unused variable: ' + snippets.join(', ') + '

'); + } + if (data.json) { + output.push('

JSON: bad.

'); + } + output.push('
'); + } + + if (!errors_only) { + + output.push('
'); + + if (data.urls) { + detail("URLs
", data.urls, '
'); + } + + if (xmode === 'style') { + output.push('

CSS.

'); + } else if (data.json && !err) { + output.push('

JSON: good.

'); + } else if (data.globals) { + output.push('
Global ' + + data.globals.sort().join(', ') + '
'); + } else { + output.push('
No new global variables introduced.
'); + } + + for (i = 0; i < data.functions.length; i += 1) { + the_function = data.functions[i]; + names = []; + if (the_function.params) { + for (j = 0; j < the_function.params.length; j += 1) { + names[j] = the_function.params[j].string; + } + } + output.push('
' + + String(the_function.line) + ' ' + + the_function.name.entityify() + + '(' + names.join(', ') + ')
'); + detail('Undefined', the_function['undefined']); + detail('Unused', the_function.unused); + detail('Closure', the_function.closure); + detail('Variable', the_function['var']); + detail('Exception', the_function.exception); + detail('Outer', the_function.outer); + detail('Global', the_function.global); + detail('Label', the_function.label); + detail('Complexity', the_function['(complexity)']); + } + + if (data.member) { + keys = Object.keys(data.member); + if (keys.length) { + keys = keys.sort(); + output.push('
/*properties
'); + mem = ' '; + italics = 0; + j = 0; + if (option.confusion) { + for (i = 0; i < keys.length; i += 1) { + key = keys[i]; + if (typeof standard_property_type[key] !== 'string') { + name = ix.test(key) ? key : + '\'' + key.entityify().replace(nx, sanitize) + '\''; + if (data.member[key] === 1) { + name = '' + name + ''; + italics += 1; + j = 1; + } + if (i < keys.length - 1) { + name += ', '; + } + if (mem.length + name.length - (italics * 7) > 80) { + output.push(mem + '
'); + mem = ' '; + italics = j; + } + mem += name; + j = 0; + } + } + } else { + for (i = 0; i < keys.length; i += 1) { + key = keys[i]; + type = property_type[key]; + if (typeof type !== 'string') { + type = ''; + } + if (standard_property_type[key] !== type) { + name = ix.test(key) ? key : + '\'' + key.entityify().replace(nx, sanitize) + '\''; + length += name.length + 2; + if (data.member[key] === 1) { + name = '' + name + ''; + italics += 1; + j = 1; + } + if (type) { + name += ': ' + type; + } + if (i < keys.length - 1) { + name += ', '; + } + if (mem.length + name.length - (italics * 7) > 80) { + output.push(mem + '
'); + mem = ' '; + italics = j; + } + mem += name; + j = 0; + } + } + } + output.push(mem + '
*/
'); + } + output.push('
'); + } + } + return output.join(''); + }; + itself.jslint = itself; + + itself.edition = '2011-07-04'; + + return itself; + +}()); \ No newline at end of file diff --git a/rhino.js b/rhino.js new file mode 100644 index 0000000..e6b43a7 --- /dev/null +++ b/rhino.js @@ -0,0 +1,52 @@ +(function (a) { + var e, i, input, filename, defaults; + if (!a[0]) { + print("Usage: jslint.js file.js ..."); + quit(1); + } + + defaults = { + predef: ['Ext', 'PVE', 'PVE_vnc_console_event'], + devel: true, + 'continue': true, /// Allow continue statement + bitwise: true, // Allow bitwise operators + browser: true, // Assume a browser + css: true, // Tolerate CSS workarounds + eqeq: true, // Allow `==` && `!=` + //immed: true, // Immediate invocations must be wrapped in parens. + //nomen: true, // Allow dangling `_` in identifiers + newcap: false, // Require initial caps for constructors + vars: true, // Allow multiple `var` statements. + plusplus: true, // Allow `++` and `--` + regexp: true, // Allow `.` and `[^...]` in regex + sloppy: true, // Don't require `use strict;` + undef: false, // Disallow undeclared variables + white: true // Don't apply strict whitespace rules + }; + + for (i = 0; i < a.length; ++i) { + filename = a[i]; + input = readFile( filename ); + if (!input) { + print("jslint: Couldn't open file '" + filename + "'."); + quit(1); + } + + if (!JSLINT(input, defaults)) { + for (i = 0; i < JSLINT.errors.length; i += 1) { + e = JSLINT.errors[i]; + if (e) { + print('[' + filename + '] Lint at line ' + e.line + ' character ' + + e.character + ': ' + e.reason); + print((e.evidence || ''). + replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1")); + print(''); + } + } + quit(2); + } else { + print("jslint: " + filename + " OK"); + } + } + quit(); +}(arguments)); -- 2.39.5