b0VIM 8.0i`K Jmikebruce~mike/projects/oss/jshint/jshint/src/jshint.jsutf-8 3210#"! Utp@vw<%; $,9[Q ;2 l s{:irWr r;;8;#~b =2 { s5 > v s;  u- ] } }| v mom I!p"q=#m$`?|%|&u'q|(@)p*q+ue,-~^.PA*-/lV0o1d12p3m4|r56w7; ad2&vJG[  x u ( K a  r I  l @  TK,+zgTA.ED}TS'  oihPO)|f^XWFBA&% function isString(obj) { } return true; } } return false; error("E001", t, type, name); if (t.type !== "jslint" && !_.has(options.removed, name)) { if (validNames.indexOf(name) === -1) { } return true; if (/^[+-]W\d{3}$/g.test(name)) { name = name.trim(); } validNames = options.unstableNames; type = "unstable "; } else { validNames = options.validNames; type = ""; if (isStable) { var type, validNames; function checkOption(name, isStable, t) { emitter = new events.EventEmitter(); extraModules = [], predefined, // Global variables defined by option membersOnly, member, lex, lookahead, indent, inblock, functions, // All of the functions declared, // Globals that were declared using /*global ... */ syntax. }, "%" : true "/" : true, "*" : true, "-" : true, "+" : true, ">=" : true, ">" : true, "!=" : true, "!==": true, "===": true, "==" : true, "<=" : true, "<" : true, bang = { // These are operators that should not be used with the ! operator. var api, // Extension API "use strict";var JSHINT = (function() {// the JSHINT function itself.// variable. That function will be invoked immediately, and its return value is// We build the application inside a function so that we produce only a singletonvar console = require("console-browserify");// it to log things. It's a sad state of affair, really.// don't necessarilly expose the 'console' API and browserify uses// We need this module here because environments such as IE and Rhinovar prodParams = require("./prod-params.js");var scopeManager = require("./scope-manager.js");var options = require("./options.js");var style = require("./style.js");var state = require("./state.js").state;var reg = require("./reg.js");var Lexer = require("./lex.js").Lexer;var messages = require("./messages.js");var vars = require("./vars.js");var events = require("events");var _ = require("lodash");/*exported console *//*jshint quotmark:double */ */ * * DEALINGS IN THE SOFTWARE. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * in all copies or substantial portions of the Software. * The above copyright notice and this permission notice shall be included * * the Software is furnished to do so, subject to the following conditions: * and/or sell copies of the Software, and to permit persons to whom * the rights to use, copy, modify, merge, publish, distribute, sublicense, * to deal in the Software without restriction, including without limitation * a copy of this software and associated documentation files (the "Software"), * Permission is hereby granted, free of charge, to any person obtaining * * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) * * JSHint is a derivative work of JSLint: * * Licensed under the MIT license. * * JSHint, by JSHint Community./*!adF * 2fCt& . o e d 7 y x g c b a 8 7  g 5 / + * } } warning("W014", right, tokenString(right)); if (!state.option.laxbreak && !sameLine(left, right)) { function nobreaknonadjacent(left, right) { } return first.line === (second.startLine || second.line); function sameLine(first, second) { // Functions for conformance of style. } return left; state.nameStack.pop(); } } } error("E033", state.tokens.curr, state.tokens.curr.id); } else { left = state.tokens.curr.led(context, left); if (left && state.tokens.curr.led) { } warning("W010", state.tokens.curr); if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { } warning("W009", state.tokens.curr); if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { advance(); } } } isObject = false; if (tokenString(left) !== tokenString(state.tokens.curr)) { // are not equal, then safely assume that this not "new Object()" // ...In the case of Object, if the left.value and state.tokens.curr.value isArray = false; (left.first && left.first.id === ".")) { if (left.value !== "new" || // not "new Object()"... // then safely assume that this is not "new Array()" and possibly // If the left.value is not "new", or the left.first.value is a "."ad( rjba3-,c^F@ t ] W ( > %     p j C / I  e T M L * S;:m<871o?XA@h;54m.('  if (left.id === ".") { } state.funct["(scope)"].block.reassign(left.value, left); // order to catch function re-assignment and globals re-assignment // The `reassign` method also calls `modify`, but we are specific in if (left.identifier && !left.isMetaProperty) { } warning("W121", left, nativeObject); if (nativeObject) var nativeObject = findNativePrototype(left); if (state.option.freeze) { assignToken = assignToken || left; var allowDestructuring = options && options.allowDestructuring; function checkLeftSideAssign(context, left, assignToken, options) { */ * @returns {boolean} Whether the left hand side is OK * * destructuring binding * @param {boolean} options.allowDestructuring - whether to allow * @param {object=} options - optional object * reporting * @param {token=} assignToken - the token for the assignment, used for * @param {token} left - the left hand side of the assignment * more information * @param {number} context - the parsing context; see `prod-params.js` for * * and/or warnings as appropriate * Determine if the given token is a valid assignment target; emit errors /** } if (prototype) return walkNative(prototype); var prototype = walkPrototype(left); } } return obj.value; state.funct["(scope)"].isPredefined(obj.value)) { if (obj.identifier && natives.indexOf(obj.value) >= 0 && obj = obj.left; while (!obj.identifier && typeof obj.left === "object") function walkNative(obj) { } return obj.right === "prototype" ? obj : walkPrototype(obj.left); if (typeof obj !== "object") return; function walkPrototype(obj) { ]; "URIError" "TypeError", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray", "ReferenceError", "RegExp", "StopIteration", "String", "SyntaxError", "Iterator", "Number", "NumberFormat", "Object", "RangeError", "Function", "Infinity", "Intl", "Int16Array", "Int32Array", "Int8Array", "DateTimeFormat", "Error", "EvalError", "Float32Array", "Float64Array", "Array", "ArrayBuffer", "Boolean", "Collator", "DataView", "Date", var natives = [ function findNativePrototype(left) { */ * @returns {boolean} * * @param {token} left * * Determine if a given token describes a property of a built-in object. /** } return isGlobal; } } isGlobal = true; else if (state.option.browser && (left.value === "window" || left.value === "document")) { } isGlobal = true; if (state.option.node && left.value === "global") { else if (left.type === "(identifier)") { // permit use of "eval" members of objects } isGlobal = true; if (left.type === "this" && state.funct["(context)"] === null) { // permit methods to refer to an "eval" key in their own context var isGlobal = false; function isGlobalEval(left, state) { */ * @returns {boolean} * * @param {object} state - the global state object (see `state.js`) * @param {token} left * * Determine if a given token describes the built-in `eval` function. /** } return false; } return !_.includes(values, left.value); } return false; } warning("W119", left, "BigInt", "11"); if (!state.inES11()) { if (left.value === "bigint") {ad rd^B'&I6/! C   v p T 8 7 # l k &  s k j M ) !  W R 7 2   ~d~s)ugbK{zt(MHd82ON if (right.type === "(identifier)" && right.value === "typeof" && left.type === "(string)") { values = state.inES6() ? typeofValues.es6 : typeofValues.es3; return false; if (!left || !right) return false; if (state.option.notypeof) var values; function isTypoTypeof(left, right, state) { */ * `true` otherwise * whose value is never returned by that operator; * expression and the first token is a string literal * @returns {boolean} - `false` if the second token describes a `typeof` * * @param {object} state - the global state object (see `state.js`) * @param {token} [right] - the other value being compared * @param {token} [left] - one of the values being compared * * string literal. * Validate comparisons between the result of a `typeof` expression and a /** typeofValues.es6 = typeofValues.es3.concat("symbol", "bigint"); typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy); ]; "undefined", "boolean", "number", "string", "function", "object", typeofValues.es3 = [ ]; "unknown" // http://robertnyman.com/2005/12/21/what-is-typeof-unknown/ // (which does not exist), see: // object existing across a COM+ bridge. In lieu of official documentation // IE<9 reports "unknown" when the `typeof` operator is applied to an "xml", // http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf // Ref: 11.3.2 The typeof Operator // XMLList types it introduced. // E4X extended the `typeof` operator to return "xml" for the XML and typeofValues.legacy = [ var typeofValues = {}; } return token.arity === "unary" && token.id !== "++" && token.id !== "--"; function beginsUnaryExpression(token) { */ * @returns {boolean} * * @param {object} token * * Determine if a given token marks the beginning of a UnaryExpression. /** } return x; }; return this; } warning("W018", right, "!"); if (right.id === "!") { } warning("W018", left, "!"); if (left.id === "!") { } quit("E041", state.tokens.curr); if (!left || !right) { } f.apply(this, [context, left, right]); } else if (f) { warning("W019", this); if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { var right = this.right = expression(context, 100); this.left = left; nobreaknonadjacent(state.tokens.prev, state.tokens.curr); x.led = function(context, left) { x.infix = true; var x = symbol(s, 100); function relation(s, f) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * linting rules. * @param {function} [f] - a function to be invoked to enforce any additional * @param {string} s - the name of the symbol * * Convenience function for defining JSHint symbols for relation operators. /** } return x; }; return this; this.right = doFunction(context, { type: "arrow", loneArg: left }); this.left = left; nobreaknonadjacent(state.tokens.prev, state.tokens.curr); x.led = function(context, left) { x.infix = true; var x = symbol(s, 42); function application(s) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided toad9Uml<(' |, D  { . f e 8  p f ^ )    W A 9 3 2 yZTSB>={zZ,U}I sZYQ1)\VU<U * Use `in` to check for the presence of any explicitly-specified value for /** } combine(predefined, vars.ecmaIdentifiers[8]); if (state.inES8()) { } combine(predefined, vars.ecmaIdentifiers[6]); if (state.inES6()) { } combine(predefined, vars.ecmaIdentifiers[5]); if (state.inES5()) { } quit("E059", state.tokens.next, "esversion", badESOpt); if (badESOpt) { badESOpt = state.inferEsVersion(); */ * TODO: Remove in JSHint 3 /** processenforceall(); var badESOpt = null; function applyOptions() { */ * Apply all linting options according to the status of the `state` object. /** } } } } state.option[relaxopt] = false; if (state.option[relaxopt] === undefined) { for (var relaxopt in options.bool.relaxing) { } } state.option[enforceopt] = true; !options.noenforceall[enforceopt]) { if (state.option[enforceopt] === undefined && for (var enforceopt in options.bool.enforcing) { if (state.option.enforceall) { function processenforceall() { } }); dest[name] = src[name]; if (_.has(JSHINT.blacklist, name)) return; Object.keys(src).forEach(function(name) { function combine(dest, src) { } }); return typeof r === "string" || typeof r === "number" ? r : a; var r = data[b]; return str.replace(/\{([^{}]*)\}/g, function(a, b) { function supplant(str, data) { } return true; } return state.isStrict(); if (token.id === "yield" && (!(context & prodParams.yield))) { } return false; if (token.id === "await" && (!(context & prodParams.async) && !state.option.module)) { } } return false; if (!state.option.strict && !state.isStrict()) { if (meta && meta.strictOnly && state.inES5()) { // Some identifiers are reserved only within a strict mode environment. } return false; } else if (meta && meta.es5 && !state.inES5()) { } } return false; if (token.isProperty) { } return false; if (!meta.es5) { // ES3 FutureReservedWord in an ES5 environment. if (state.inES5()) { if (meta && meta.isFutureReservedWord) { var meta = token.meta; } return false; if (!token.reserved) { function isReserved(context, token) { */ * @param {Token} token * more information * @param {number} context - the parsing context; see `prod-params.js` for * * according to the current state of the parser. * This function determines if a given token describes a reserved word * * the restriction to strict mode code (e.g. `let` and `yield`). * Separately, ES5 introduced new restrictions on certain tokens, but limited * by simply allowing their use as Identifiers (e.g. `int` and `goto`). * define new syntactic forms (e.g. `class` and `const`) and in other cases * ES5 reduced the set of FutureReservedWords, in some cases by using them to * * possibility of future adoption of [proposed] extensions." * ES3 defined a set of "FutureReservedWords" in order "to allow for the /** } return true; return false; if (!tkn.identifier || tkn.value !== value) return false; if (!tkn) function isIdentifier(tkn, value) { } return Object.prototype.toString.call(obj) === "[object String]";adiLFE5$#pdXLA:9 ~ z y L 4 %   s d U A = < r 4 , ( ' ! e _ ' Z L F E  |Y%|{T2!^4*"WC7]\;\RQ1'!   "indent" "maxlen", "maxerr", "maxcomplexity", "maxdepth", "maxparams", "maxstatements", var numvals = [ } }); membersOnly[m] = false; } .replace("\\\"", "\""); .substr(1, m.length - 2) m = m if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { var ch2 = m.charAt(m.length - 1); var ch1 = m.charAt(0); body.forEach(function(m) { membersOnly = membersOnly || {}; if (directiveToken.type === "members") { } }); state.funct["(scope)"].addExported(e); } return; error("E002", directiveToken); } return; if (idx > 0 && idx === body.length - 1) { // Ignore trailing comma if (!e.length) { body.forEach(function(e, idx) { if (directiveToken.type === "exported") { } } } declared[key] = directiveToken; if (_.has(predef, key)) { for (var key in predef) { combine(predefined, predef); }); } predef[key] = parts.length > 1 && parts[1].trim() === "true"; } else { delete predefined[key]; JSHINT.blacklist[key] = key; key = key.slice(1); if (key.charAt(0) === "-") { } return; error("E002", directiveToken); } return; if (idx > 0 && idx === body.length - 1) { // Ignore trailing comma if (key === "-" || !key.length) { var key = parts[0].trim(); var parts = item.split(":"); body.forEach(function(item, idx) { if (directiveToken.type === "globals") { } return; previous.caseFallsThrough = true; if (directiveToken.type === "falls through") { var predef = {}; .map(function(s) { return s.trim(); }); var body = directiveToken.body.split(",") function lintingDirective(directiveToken, previous) { */ * @param {Token} previous - the token that preceeds the directive * @param {Token} directiveToken - the directive-bearing comment token * * Process an inline linting directive /** } }); code: token.value.replace(/([^\\])(\\*)\2\\n/g, "$1\n") token: token, elem: elem, id: "(internal)", JSHINT.internals.push({ function addEvalCode(elem, token) { // Tracking of "internal" scripts, like eval containing a static string } }, a, b, c, d); from: ch line: l, return error(m, { function errorAt(m, l, ch, a, b, c, d) { } warning(m, t, a, b, c, d); function error(m, t, a, b, c, d) { } }, a, b, c, d); from: ch line: l, return warning(m, { function warningAt(m, l, ch, a, b, c, d) { } return w; quit("E043", t); if (JSHINT.errors.length >= state.option.maxerr) removeIgnoredMessages(); JSHINT.errors.push(w); w.reason = supplant(msg.desc, w); }; d: d c: c, b: b, a: a, scope: JSHINT.scope, character: ch, line: l, evidence: state.lines[l - 1] || "", code: msg.code, raw: msg.desc, id: "(error)", w = { ch = t.from; l = t.line; } t = state.tokens.curr; if (t.id === "(end)") { // `~ t = t || state.tokens.next || {}; } msg = messages.info[code]; } else if (/I\d{3}/.test(code)) {adCuQ, ZH>= ; r _ !    l E D  g N 7  { h U *    v^3 thVLK+lU<zaJ!s`M"mH5"~VC break; state.option.strict = true; case "true": switch (val) { if (key === "strict") { } return; } error("E002", directiveToken); default: break; removeIgnoredMessages(); state.ignoredLines[directiveToken.line] = true; case "line": switch (val) { if (key === "ignore") { } return; } error("E002", directiveToken); default: break; state.option.latedef = "nofunc"; case "nofunc": break; state.option.latedef = false; case "false": break; state.option.latedef = true; case "true": switch (val) { if (key === "latedef") { } return; } error("E002", directiveToken); default: break; state.option.unused = val; case "strict": case "vars": break; state.option.unused = false; case "false": break; state.option.unused = true; case "true": switch (val) { if (key === "unused") { } return; } error("E002", directiveToken); default: break; state.option.shadow = "inner"; case "inner": case "false": break; state.option.shadow = "outer"; case "outer": break; state.option.shadow = true; case "true": switch (val) { if (key === "shadow") { } return; } error("E002", directiveToken); default: break; state.option.quotmark = val; case "single": case "double": break; state.option.quotmark = (val === "true"); case "false": case "true": switch (val) { if (key === "quotmark") { } return; state.option.validthis = (val === "true"); return void error("E002", directiveToken); if (val !== "true" && val !== "false") return void error("E009"); if (state.funct["(global)"]) // `validthis` is valid only within a function scope. if (key === "validthis") { } return; } state.option[key] = key === "indent" ? 4 : false; } else { state.option[key] = numberVal; } return; error("E032", directiveToken, val); numberVal <= 0 || Math.floor(numberVal) !== numberVal) { if (typeof numberVal !== "number" || !isFinite(numberVal) || numberVal = +val; if (val !== "false") { // GH988 - numeric options can be disabled by setting them to `false` if (numvals.indexOf(key) >= 0) { } return; if (!checkOption(key, directiveToken.type !== "jshint.unstable", directiveToken)) { var numberVal; var val = parts.length > 1 ? parts[1].trim() : ""; var key = parts[0].trim(); var parts = item.split(":"); body.forEach(function(item) { directiveToken.type === "jshint.unstable") { if (directiveToken.type === "jshint" || directiveToken.type === "jslint" || ];add  $sea`Z=8P 9 j C B  H  v n h g <   \ T S l,{a\D>fF& xrqLf|{iedI  B * Short for "first null denotation," it it similar to the `nud` ("null * based on the Pratt parser, but it extends that model with a `fud` method. * The `expression` function is the heart of JSHint's parsing behaior. It is /** } return token.value; } return token.id; if (token.type === "(punctuator)") { function EITHER(token) { } return false; } return !sameLine(curr, next); (curr.id === "yield" && curr.rbp < next.rbp)) { // `yield` is followed by a newline and a `[` token). // followed by a newline and a comma operator (without enabling it when // effect, this prevents automatic semicolon insertion when `yield` is // of the current expression if allowed by the syntactic grammar. In // Infix operators which follow `yield` should only be consumed as part if (next.infix === curr.infix || } return true; if (next.id === ";" || next.id === "}" || next.id === ":") { } return true; if (next.id === "in" && context & prodParams.noin) { } next = state.tokens.next; curr = state.tokens.curr; if (arguments.length <= 1) { function isEndOfExpr(context, curr, next) { } return token.first || token.right || token.left || token.id === "yield" || token.id === "await"; function isOperator(token) { */ * @returns {boolean} * * @param {token} token * * Determine whether a given token is an operator. /** } } } } break; if (state.tokens.next.id !== "(endline)") { } else { lintingDirective(state.tokens.next, state.tokens.curr); if (state.tokens.next.isSpecial) { } state.tokens.next.check(); if (state.tokens.next.check) { } return; if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { } quit("E041", state.tokens.curr); if (!state.tokens.next) { // No more tokens left, give up state.tokens.next = lookahead.shift() || lex.token(); for (;;) { state.tokens.curr = state.tokens.next; state.tokens.prev = state.tokens.curr; } } error("E021", nextToken, expected, EITHER(nextToken)); } else if (nextToken.type !== "(id relatedToken.line, tokenString(nextToke relatedToken.line, tokenString(nextToken)); error("E020", nextToken, expected, relatedToken.id, } else { error("E019", relatedToken, relatedToken.id); if (nextToken.id === "(end)") { if (relatedToken) { if (expected && nextToken.id !== expected) { var nextToken = state.tokens.next; function advance(expected, relatedToken) { */ * used to produce more meaningful errors * brace when a closing brace is expected); * value, if any (for example: the opening * @param {object} [relatedToken] - the token that informed the expected * be accepted * and literals); if unspecified, any token will * `value` property (in the case of identifiers * property (in the case of punctuators) or * @param {string} [expected] - the expected value of the next token's `id` * * Consume the next token. /** } return t; } while (t.id === "(endline)"); t = peek(i++); do { var t; var i = 0; function peekIgnoreEOL() { } return t;ad;m\W<lg | 1 p j D  h @ ? 0 /  D  d \ [  W EfcUI?>+*B  RH@:9 zvuH  } } warning("W014", right, EITHER(right)); if (!state.option.laxbreak && !sameLine(left, right)) { function nobreaknonadjacent(left, right) { } return first.line === (second.startLine || second.line); function sameLine(first, second) { // Functions for conformance of style. } return left; state.nameStack.pop(); } } } error("E033", state.tokens.curr, state.tokens.curr.id); } else { left = state.tokens.curr.led(context, left); if (left && state.tokens.curr.led) { } warning("W010", state.tokens.curr); if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { } warning("W009", state.tokens.curr); if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { advance(); } } } isObject = false; if (EITHER(left) !== EITHER(state.tokens.curr)) { // are not equal, then safely assume that this not "new Object()" // ...In the case of Object, if the left.value and state.tokens.curr.value isArray = false; (left.first && left.first.id === ".")) { if (left.value !== "new" || // not "new Object()"... // then safely assume that this is not "new Array()" and p if (left && (tokenString(left) || (left.first && tokenString(left.fi if (left && (tokenString(left) || (left.first && tokenString(left.first)))) { // "Line too long." error. // Line breaks in IfStatement heads exist to satisfy the checkJSHint // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() isObject = state.tokens.curr.value === "Object"; isArray = state.tokens.curr.value === "Array"; while (rbp < state.tokens.next.lbp && !isEndOfExpr(context)) { } error("E030", state.tokens.curr, state.tokens.curr.id); } else { left = state.tokens.curr.nud(context, rbp); if (state.tokens.curr.nud) { } else { left = state.tokens.curr.fud(context); if (initial && curr.fud && (!curr.useFud || curr.useFud(context))) { curr = state.tokens.curr; } state.tokens.curr.beginsStmt = true; state.funct["(verb)"] = tokenString(state.tokens.curr); if (initial) { advance(); error("E006", state.tokens.curr); if (state.tokens.next.id === "(end)") state.nameStack.push(); context &= ~prodParams.initial; var curr; var initial = context & prodParams.initial; var left, isArray = false, isObject = false; function expression(context, rbp) { */ * @param {number} rbp - the right-binding power of the token to be consumed * detail) * interpreted); see `prod-params.js` for more * which can influence how the next tokens are * conditions of the current parsing operation * @param {number} context - the parsing context (a bitfield describing * * In addition to parsing, this function applies a number of linting patterns. * * They are elements of the parsing method called Top Down Operator Precedence. * * rbp Right binding power * lbp Left binding power * .led Left denotation * .fud First null denotation * .nud Null denotation * * JavaScript. * statement. This simplifies usage in statement-oriented languages like * denotation") function, but it is only used on the first token of aadMl83{= _ Z  o M +   i _ - %   q ] J 6  m X D 2  J$`JB<+'& =8<S$Tue // Symbols that accept a right-hand side do so with a binding power lbp: p, id: s, state.syntax[s] = x = { if (!x || typeof x !== "object") { var x = state.syntax[s]; function symbol(s, p) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * Pratt parsing semantics * @param {number} p - the left-binding power of the token as used by the * a parenthetical value * "special" tokens (e.g. the end-of-file marker) this is * representation; for literals (e.g. numbers) and other * delimiters (e.g.. `[`), this is the token's text * @param {string} s - the name of the token; for keywords (e.g. `void`) and * * ES2015. * of JSHint and is not related to the ECMAScript value type introduced in * Note that this definition of "symbol" describes an implementation detail * * and set as the prototype of the tokens generated by the lexer. * tokens. The objects created by this function are stored in a symbol table * Factory function for creating "symbols"--objects that will be inherited by /** } return true; } } return false; error("E024", state.tokens.next, state.tokens.next.id); } return true; if (opts.allowTrailing) { case ")": case ",": case "]": case "}": switch (state.tokens.next.id) { if (state.tokens.next.type === "(punctuator)") { } } return false; error("E024", state.tokens.next, state.tokens.next.value); case "with": case "while": case "let": case "var": case "try": case "throw": case "switch": case "return": case "instanceof": case "in": case "if": case "for": case "finally": case "else": case "do": case "default": case "continue": case "catch": case "case": case "break": switch (state.tokens.next.value) { // Keywords that cannot follow a comma operator. if (state.tokens.next.identifier && !(opts.property && state.inES5())) { } } warning("W014", prev, tokenString(curr)); } checkComma.first = false; warning("I001", curr); if (checkComma.first) { if (!state.option.laxcomma) { if (!sameLine(prev, curr)) { opts = opts || {}; var curr = state.tokens.curr; var prev = state.tokens.prev; function checkComma(opts) { */ * error, `true` otherwise * token; `false` if the token directly causes a syntax * @returns {boolean} flag indicating the validity of the current comma * * directly before a delimiter * current comma token may appear * @param {boolean} [opts.allowTrailing] - flag indicating whether the * an object initializer * comma token is situated directly within * @param {boolean} [opts.property] - flag indicating whether the current * @param {object} [opts] * * Validate the comma token in the "current" position of the token stream. /** } } warning("E022", t, t.value); if (!sameLine(t, state.tokens.next)) { function nolinebreak(t) {ad! scvmgYUTN > 8 "  c  y + % ` [ B ^X;#zuHB& 8 A<dPOnD:9S>9  * @param {string} s - the name of the symbol * * literal values. * Convenience function for defining "type" symbols--those that describe /** } return x; }; return this; } } checkLeftSideAssign(context, this.right, this); if (this.right) { } warning("W016", this, this.id); if (state.option.plusplus) { if (this.id === "++" || this.id === "--") { this.right = expression(context, 150); this.arity = "unary"; x.nud = (typeof f === "function") ? f : function(context) { reserveName(x); var x = symbol(s, 150); function prefix(s, f) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * see the `expression` function for more detail * @param {function} [f] - the first null denotation function for the symbol; * @param {string} s - the name of the symbol * * expressions as a right-hand side. * Convenience function for defining "prefix" symbols--operators that accept /** } return x; } x.identifier = x.reserved = true; if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { var c = x.id.charAt(0); function reserveName(x) { */ * @returns {object} - the provided object * * @param {object} - a JSHint symbol value * * Denote a given JSHint symbol as an identifier and a reserved keyword. /** } return x; x.block = true; var x = stmt(s, f); function blockstmt(s, f) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * the `expression` function for more detail * @param {function} - the first null denotation function for the symbol; see * @param {string} s - the name of the symbol * * followed by a block and will not have to end with a semicolon. * A block-statement-denoting symbol is one like 'if' or 'for', which will be * * Convenience function for defining block-statement-denoting symbols. /** } return x; x.fud = f; x.identifier = x.reserved = true; var x = delim(s); function stmt(s, f) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * see the `expression` function for more detail * @param {function} f - the first null denotation function for the symbol; * @param {string} s - the name of the symbol * * Convenience function for defining statement-denoting symbols. /** } return x; x.delim = true; var x = symbol(s, 0); function delim(s) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * @param {string} s - the name of the symbol * * Convenience function for defining delimiter symbols. /** } return x; } }; rbp: p, // are distinct, the values must be encoded separately. // exponentiation operator's left-binding power and right-binding power // to override the precedence of surrounding operators.) Because the // is relevant when determining if the grouping operator is necessary // that is commonly identical to their left-binding power. (This valueadrS@ }2  = n X )   ^ K E D $ #   9 q #   GFje5T#|^D0lA.'OJi5 warning("W016", that, that.id); if (state.option.bitwise) { return infix(s, function(context, left, that) { symbol(s, 20).exps = true; function bitwiseassignop(s) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * @param {string} s - the name of the symbol * * operators. See the `assignop` function for more detail. * Convenience function for defining JSHint symbols for bitwise assignment /** } return x; }; return this; this.right = expression(context, p); this.left = left; } warning("W016", this, this.id); if (state.option.bitwise) { x.led = (typeof f === "function") ? f : function(context, left) { x.infix = true; reserveName(x); var x = symbol(s, p); function bitwise(s, f, p) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * Pratt parsing semantics * @param {number} p - the left-binding power of the token as used by the * the `expression` function for more detail * @param {function} [f] - the left denotation function for the symbol; see * @param {string} s - the name of the symbol * * Convenience function for defining JSHint symbols for bitwise operators. /** } return x; x.assign = true; x.exps = true; }, 20); return that; that.right = expression(context, 10); checkLeftSideAssign(context, left, that, { allowDestructuring: true }); that.left = left; var x = infix(s, typeof f === "function" ? f : function(context, left, that) { function assignop(s, f) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * function) * right-hand side of the operator (see the `infix` * @param {function} [f] - a function to be invoked that consumes the * @param {string} s - the name of the symbol * * Convenience function for defining JSHint symbols for assignment operators. /** } return false; error("E031", assignToken); } return true; state.nameStack.set(left); } } return false; error("E031", assignToken); } else { warning("W143", assignToken); if (!state.isStrict()) { } else if (left.value === "arguments") { return false; error("E031", assignToken); if (left.value === "eval" && state.isStrict()) { } warning("W022", left); if (state.funct["(scope)"].bindingtype(left.value) === "exception") { } else if (left.identifier && !isReserved(context, left) && !left.isMetaProperty) { return true; } state.nameStack.set(left.right); if (left.id === "[") { } } warning("W143", assignToken); } else if (left.left.value === "arguments" && !state.isStrict()) { warning("E031", assignToken); if (left.id === "{" || !left.left) { if (!allowDestructuring || !left.destructAssign) { } else if (left.id === "{" || left.id === "[") { return true; state.nameStack.set(state.tokens.prev); } warning("W143", assignToken); if (!left.left || left.left.value === "arguments" && !state.isStrict()) {adt| ;zvuoO u - } v h d c ] r " J D | o g = <   r#]0*PJ;:yxgcb\ >M@0*)O // should not be consumed in this way so that the parser interprets it as // can continue as though an identifier were found. The semicolon token // The token should be consumed after a warning is issued so the parser error("E030", state.tokens.next, EITHER(state.tokens.next)); } return i; if (i) { var i = optionalidentifier(context, isName, false); function identifier(context, isName) { */ * @returns {string|undefined} - the value of the identifier, if present * * (e.g. object properties) * @param {boolean} [isName] - `true` if an IdentifierName should be consumed * more information * @param {number} context - the parsing context; see `prod-params.js` for * * Ensure that the current token is an identifier and retrieve its value. /** } return true; } } advance(); while (checkPunctuator(state.tokens.next, "...")) { warning("E024", state.tokens.next, "..."); if (checkPunctuator(state.tokens.next, "...")) { advance(); } warning("W119", state.tokens.next, operation + " operator", "6"); if (!state.inES6(true)) { } return false; if (!checkPunctuator(state.tokens.next, "...")) { function spreadrest(operation) { */ * consumed in this way * @returns {boolean} a value describing whether or not any tokens were * * @param {string} operation - either "spread" or "rest" * * issue a single error describing the syntax error. * it is present. If the operator is repeated, consume every repetition, and * Consume the "..." token which designates "spread" and "rest" operations if /** } return curr.valu>>>>>>> 33da48c1... Step one } return val; if (!isReserved(context, curr)) { var val = EITHER(state.tokens.curr);=======<<<<<<< HEAD var curr = state.tokens.curr; } advance(); if (!preserve) { } return; if (!state.tokens.next.identifier) { function optionalidentifier(context, isName, preserve) { */ * @returns {string|undefined} - the value of the identifier, if present * * @param {boolean} [preserve] - `true` if the token should not be consumed * (e.g. object properties) * @param {boolean} [isName] - `true` if an IdentifierName should be consumed * more information * @param {number} context - the parsing context; see `prod-params.js` for * * advance the parser. * Retrieve the value of the next token if it is an identifier and optionally /** } return x; }; return this; this.left = left; checkLeftSideAssign(context, left, this); } warning("W016", this, this.id); if (state.option.plusplus) { // left = symbol operated e.g. "a" identifier or "a.b" punctuator // this = suffix e.g. "++" punctuator x.led = function(context, left) { var x = symbol(s, 150); function suffix(s) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * @param {string} s - the name of the symbol * * have a single operand that appears before them in the source code. * Convenience function for defining JSHint symbols for those operators which /** } }, 20); return that; that.right = expression(context, 10); checkLeftSideAssign(context, left, that); }ad)N'"{mgXM8( { L ,    M   n 3 v 8 7 r q " b`0+cbJ6("!Y*)xgSR8tvUC5) // } // } // ... // case bar: { <= here. // switch (foo) { // // Is it a switch case block? if (t.id === "{") { // Is it a lonely block? } t = state.tokens.next; } warning("W028", state.tokens.next, t.value, tokenString(state.tokens.next)); if (!state.tokens.next.labelled && state.tokens.next.id !== "{") { state.funct["(scope)"].block.addLabel(t.value, { token: state.tokens.curr }); state.funct["(scope)"].stack(); hasOwnScope = true; advance(":"); advance(); if (t.identifier && !res && peek().id === ":") { } res = false; warning("W024", t, t.id); if (res && t.meta && t.meta.isFutureReservedWord && !t.fud) { // as a label, we warn but proceed anyway. // a FutureReservedWord (that is not meant to start a statement) // We're being more tolerant here: if someone uses var res = isReserved(context, t); // Is this a labelled statement? } return; advance(";"); if (t.id === ";") { context |= prodParams.initial; var i = indent, r, t = state.tokens.next, hasOwnScope = false; function statement(context) { */ * @returns {token} - the token describing the statement * * more information * @param {number} context - the parsing context; see `prod-params.js` for * * Consume a statement. /** } } advance(";"); } else { } } warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); if (!(blockEnd && isSameLine && state.option.lastsemic)) { // a warning about missing semicolon. // *and* option lastsemic is on, ignore the warning. Otherwise, issue // If this is the last statement in a block that ends on the same line } else if (!state.option.asi) { errorAt("E058", state.tokens.curr.line, state.tokens.curr.character); if (isSameLine && !blockEnd && !(stmt.id === "do" && state.inES6(true))) { var blockEnd = checkPunctuator(state.tokens.next, "}"); state.tokens.next.id !== "(end)"; var isSameLine = sameLine(state.tokens.curr, state.tokens.next) && if (state.tokens.next.isUnclosed) return advance(); // don't complain about unclosed templates / strings if (state.tokens.next.id !== ";") { function parseFinalSemicolon(stmt) { */ * @param {token} stmt - token describing the statement under consideration * * emitting relevant warnings/errors as appropriate. * Consume the semicolon that delimits the statement currently being parsed, /** } } } break; warning("W027", t, t.value, tokenString(controlToken)); } break; } warning("W026", t); if (state.option.latedef === true) { if (t.id === "function") { if (t.id !== "(endline)") { } return; if (t.reach) { } while (t.id !== "(end)" && t.id === "(comment)"); i += 1; t = peek(i); do { for (;;) { } return; if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) { var i = 0, t; function reachable(controlToken) { */ * @param {token} controlToken * * warning if this is note the case. * Determine if the provided token may be evaluated and emit a linting /** } } advance(); if (state.tokens.next.id !== ";") { // a statement delimiter;ad=Q~qpW-%$f' V * b a Q :  p k  | { 0  r N F @ 2 . - , & |Z.I  EuKCB  G:5< Q * function * @param {boolean} [isfatarrow] - `true` if its a body of a fat arrow * @param {boolean} [isfunc] - `true` if block is a function body * in if/for/while) * @param {boolean} [stmt] - `true` if block can be a single statement (e.g. * try blocks * @param {boolean} ordinary - `true` for everything but function bodies and * @param {number} context - parsing context * * braces. * Parses a single block. A block is a sequence of statements wrapped in /** } } state.option.undef = true; if (state.isStrict()) { } parseFinalSemicolon(current); state.directive[directive] = state.tokens.curr; } error("E065", state.tokens.curr); !state.funct["(global)"] && state.funct["(hasSimpleParams)"] === false) { if (directive === "use strict" && state.inES7() && // > and IsSimpleParameterList of FormalParameters is false. // > - It is a Syntax Error if ContainsUseStrict of FunctionBody is true // > [...] // > // > 14.1.2 Static Semantics: Early Errors // // From ECMAScript 2016: } warning("W034", state.tokens.curr, directive); (directive === "use strict" && state.option.strict === "implied")) { if (state.directive[directive] || var directive = state.tokens.curr.value; advance(); current = next; } break; if (!isEndOfExpr(0, current, next)) { var next = peekIgnoreEOL(); while (state.tokens.next.id === "(string)") { var current = state.tokens.next; function directives() { */ * Parse any directives in a directive prologue. /** } return a; } } a.push(statement(context)); } else { advance(";"); } warning("W032"); if (!p || (p.id !== "(" && p.id !== "[")) { p = peek(); if (state.tokens.next.id === ";") { while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { var a = [], p; function statements(context) { */ * @returns {Array} - the tokens consumed * * more information * @param {number} context - the parsing context; see `prod-params.js` for * * program or a token that interrupts control flow. * Consume a series of statements until encountering either the end of the /** } return r; } state.funct["(scope)"].unstack(); if (hasOwnScope) { indent = i; // Restore the indentation. } parseFinalSemicolon(t); } warning("W031", t); } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { warning("W030", state.tokens.curr); if (!state.option.expr && (!r || !r.exps)) { if (!t.block) { // Look for the final semicolon. } } warning("E007"); if (!state.isStrict() && state.stmtMissingStrict()) { r.left.identifier && r.left.value === "function")) { !(r.type === "(punctuator)" && r.left && if (r && !(r.identifier && r.value === "function") && r = expression(context, 0); // Parse the statement. } return; } state.funct["(scope)"].unstack(); if (hasOwnScope) { block(context, true, true, false, false, iscase); var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.id === ":");adNb|v.#xU!  p I ` T < ;   | ] O C 9 8   d . & %  | { S R 7   ]SR8H'{zPAE=<J! oJI#qkj  // Don't clear and let it propagate out if it is "break", "return" or } state.funct["(scope)"].unstack(); } error("E048", a[0], a[0].id[0].toUpperCase() + a[0].id.slice(1)); !(supportsFnDecl && a[0].id === "function")) { if (a[0] && a[0].declaration && indent -= state.option.indent; a = [statement(context)]; // test indentation only if statement is in new line indent += state.option.indent; state.tokens.next.inBracelessBlock = true; state.tokens.curr.id === "else"; var supportsFnDecl = state.funct["(verb)"] === "if" || // of IfStatements. // where function declarations are permitted in the statement positions // JSHint observes Annex B of the ECMAScript specification by default, } warning("W116", state.tokens.next, "{", EITHER(state.tokens.next)); if (!stmt || stat error("E021", state.tokens.next, "{", tokenString(state.tokens.nex error("E021", state.tokens.next, "{", tokenString(state.tokens.next)); } else { state.funct["(scope)"].unstack(); } } warning("E007"); if (!state.isStrict()) { if (state.option.strict && state.funct["(context)"]["(global)"]) { } warning("W146", expr); expr.identifier && expr.value === "await") { if (state.option.noreturnawait && context & prodParams.async && var expr = expression(context, 10); } state.funct["(scope)"].validateParams(true); if (isfatarrow) { } error("W118", state.tokens.curr, "function closure expressions"); if (stmt && !isfatarrow && !state.inMoz()) { state.funct["(scope)"].stack(); if (isfunc) { } else if (!ordinary) { indent = old_indent; state.funct["(scope)"].unstack(); } } state.directive = m; if (m) { state.funct["(scope)"].validateParams(isfatarrow); if (isfunc) { advance("}", t); } state.funct["(isStrict)"] = state.isStrict(); // Ensure property is set for functions with empty bodies. } else if (isfunc) { indent -= state.option.indent; metrics.statementCount += a.length; a = statements(context); } } } warning("E007"); if (!m["use strict"] && !state.isStrict()) { if (state.option.strict && state.funct["(context)"]["(global)"]) { state.funct["(isStrict)"] = state.isStrict(); directives(); } m[d] = state.directive[d]; for (d in state.directive) { m = {}; if (isfunc) { } indent += state.option.indent; while (!ordinary && state.tokens.next.from > indent) { indent += state.option.indent; if (state.tokens.next.id !== "}") { state.funct["(scope)"].stack(); // create a new block scope advance("{"); if (state.tokens.next.id === "{") { metrics.verifyMaxNestedBlockDepthPerFunction(); metrics.nestedBlockDepth += 1; var metrics = state.funct["(metrics)"]; t = state.tokens.next; inblock = ordinary; d; t, m, old_indent = indent, b = inblock, var a, function block(context, ordinary, stmt, isfunc, isfatarrow, iscase) { */ * @returns {token} - the token describing the block * * @param {boolean} [iscase] - `true` if block is a switch case blockadsq]NFE+rlI;765/ j e : 4  ~ h [ F @ < ; ~ } l f e E 4 . - I &   a + W{upoR;'"ml;/zgML cIH(`E7) s reserve("catch"); reserve("case").reach = true; reserve("else"); delim("#"); delim(":").reach = true; delim(";"); delim("'").reach = true; delim("\"").reach = true; delim("]"); delim(")"); delim("}").reach = true; delim("(error)").reach = true; delim("(end)").reach = true; })(delim("(begin)")); x.line = x.from = 0; (function(x) { delim("(endline)"); // ECMAScript parser }); return this; type("(regexp)", function() { }, baseTemplateSyntax); tail: true // mark as tail, since it's always the last component noSubst: true, led: doTemplateLiteral, nud: doTemplateLiteral, type: "(template)", lbp: 155, state.syntax["(no subst template)"] = _.extend({ }, baseTemplateSyntax); noSubst: false tail: true, type: "(template tail)", lbp: 0, state.syntax["(template tail)"] = _.extend({ }, baseTemplateSyntax); noSubst: false type: "(template middle)", lbp: 0, state.syntax["(template middle)"] = _.extend({ }, baseTemplateSyntax); noSubst: false led: doTemplateLiteral, nud: doTemplateLiteral, type: "(template)", lbp: 155, state.syntax["(template)"] = _.extend({ }; template: true, identifier: false, var baseTemplateSyntax = { }; } error("E033", state.tokens.next, state.tokens.next.value); /* istanbul ignore next */ led: function() { }, return this; } state.funct["(scope)"].block.use(v, state.tokens.curr); } else if (!isLoneArrowParam && !state.funct["(comparray)"].check(v)) { warning("W024", this, v); if (isReserved(context, this)) { var isLoneArrowParam = state.tokens.next.id === "=>"; // parsed, so it can be safely ignored for now. // will be added to the scope of the new function when the next token is // ...it should not be considered as a variable in the current scope. It // // x => x; // // function definition, i.e. // If this identifier is the lone parameter to a shorthand "fat arrow" var v = this.value; nud: function(context) { identifier: true, lbp: 0, type: "(identifier)", state.syntax["(identifier)"] = { }); return this; type("(string)", function() { }); return this; } warning("W005", this); if (state.tokens.next.id === ".") { type("(number)", function() { // Build the syntax table by declaring the syntactic elements of the language. } } member[m] = 1; } else { member[m] += 1; if (typeof member[m] === "number") { } warning("W036", state.tokens.curr, m); if (membersOnly && typeof membersOnly[m] !== "boolean") { function countMember(m) { */ * @param {string} m - the property name * * does not include the given name. * names, and emit a warning if the `members` linting directive is in use and * Update the global state which tracks all statically-identifiable property /** } return a; metrics.nestedBlockDepth -= 1; } warning("W035", state.tokens.prev); if (ordinary && state.option.noempty && (!a || a.length === 0)) { inblock = b; } state.funct["(verb)"] = null; default: /* falls through */ } break; if (iscase) { case "throw": case "return": case "continue": case "break": switch (state.funct["(verb)"]) { // similar in switch casead Ef6[>87&  e F '  N 4  n h g N 5   c ] \ F E -  f P   {e;* m\GF[UT5tnm\RQ T:zYSR< wE relation("==", function(context, left, right) { bitwise("&", "bitand", 90); bitwise("^", "bitxor", 80); bitwise("|", "bitor", 70); state.syntax["**"].rbp = 140; }, 150); return that; that.right = expression(context, that.rbp); that.left = left; } error("E024", that, "**"); if (!left.paren && beginsUnaryExpression(left)) { // Disallow UnaryExpressions which are not wrapped in parenthesis } warning("W119", that, "Exponentiation operator", "7"); if (!state.inES7()) { infix("**", function(context, left, that) { // UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] // UnaryExpression[?Yield] // ExponentiationExpression[Yield] : // // The Exponentiation operator, introduced in ECMAScript 2016 }, 39); return that; } error("E024", that.right, that.right.id); if (!right.paren && (right.id === "||" || right.id === "&&")) { var right = that.right = expression(context, 39); that.left = left; increaseComplexityCount(); } warning("W119", that, "nullish coalescing", "11"); if (!state.inES11()) { } error("E024", that, "??"); if (!left.paren && (left.id === "||" || left.id === "&&")) { infix("??", function(context, left, that) { }, andPrecedence); return that; that.right = expression(context, andPrecedence); that.left = left; increaseComplexityCount(); infix("&&", function(context, left, that) { var andPrecedence = 50; }, 40); return that; that.right = expression(context, 40); that.left = left; increaseComplexityCount(); infix("||", function(context, left, that) { }, 30); return that; expression(context, 10); advance(":"); that.right = expression(context & ~prodParams.noin, 10); that.left = left; increaseComplexityCount(); infix("?", function(context, left, that) { }, 10, true); return that; } that.right = null; } else { that.right = expression(context, 10); if (checkComma()) { that.left = left; } warning("W127", that); if (state.option.nocomma) { infix(",", function(context, left, that) { bitwiseassignop(">>>="); bitwiseassignop(">>="); bitwiseassignop("<<="); bitwiseassignop("^="); bitwiseassignop("|="); bitwiseassignop("&="); }); return that; that.right = expression(context, 10); checkLeftSideAssign(context, left, that); that.left = left; } warning("W119", that, "Exponentiation operator", "7"); if (!state.inES7()) { assignop("**=", function(context, left, that) { assignop("%=", "assignmod"); }; error("E014"); /* istanbul ignore next */ assignop("/=", "assigndiv").nud = function() { assignop("*=", "assignmult"); assignop("-=", "assignsub"); assignop("+=", "assignadd"); assignop("=", "assign"); })); return this; superNud.call(state.tokens.curr, this); })(reserve("super", function() { superSymbol.rbp = 161; (function(superSymbol) { }); return this; } warning("W040", this); state.funct["(name)"].charAt(0) > "Z") || state.funct["(global)"])) { !state.option.validthis && ((state.funct["(statement)"] && if (state.isStrict() && !isMethod() && reserve("this", function() { reserve("null", function() { return this; }); reserve("false", function() { return this; }); reserve("true", function() { return this; }); reserve("finally"); reserve("default").reach = true;ad{uJ&qb5  ~ T ! `   f E  o C   n ] K 9  te=&ua[Z7oAzoB yX0uRLK:/ vSML;5 infix("-", function(context, left, that) { }); return this; } warning("W007", this.right); if (next.id === "+" || next.id === "++") { this.right = expression(context, 150); this.arity = "unary"; var next = state.tokens.next; prefix("+", function(context) { }, 130); return that; } warning("W007", that.right); if (next.id === "+" || next.id === "++") { } return left; } warning("W050", left); if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { left.character = right.character; left.value += right.value; if (left && right && left.id === "(string)" && right.id === "(string)") { that.right = right = expression(context, 130); that.left = left; var right; var next = state.tokens.next; infix("+", function(context, left, that) { }, 120); return token; } warning("W139"); if (right.id === "function") { } error("E060"); (right.id === "(template)" && !right.tag)) { right.id === "(regexp)" || (right.id === "[" && !right.right) || right.id === "{" || right.arity === "unary" || (right.value === "undefined" && !scope.has("undefined")) || right.value === "null" || right.id === "(string)" || if (right.id === "(number)" || } return token; if (!right) { // `expression` function. // This condition reflects a syntax error which will be reported by the token.right = right = expression(context, 120); token.left = left; var scope = state.funct["(scope)"]; var right; infix("instanceof", function(context, left, token) { infix("in", "in", 120); bitwise(">>>", "shiftrightunsigned", 120); bitwise(">>", "shiftright", 120); bitwise("<<", "shiftleft", 120); relation(">="); relation("<="); relation(">"); relation("<"); }); return this; } warning("W122", this, left.value); /* istanbul ignore next */ } else if (isTypoTypeof(left, right, state)) { warning("W122", this, right.value); if (isTypoTypeof(right, left, state)) { relation("!==", function(context, left, right) { }); return this; } warning("W122", this, left.value); } else if (isTypoTypeof(left, right, state)) { warning("W122", this, right.value); /* istanbul ignore next */ } else if (isTypoTypeof(right, left, state)) { warning("W116", this, "!==", "!="); this.from = this.character; if (!eqnull && state.option.eqeqeq) { ((left && left.value) === "null" || (right && right.value) === "null"); var eqnull = state.option.eqnull && relation("!=", function(context, left, right) { }); return this; } warning("W122", this, left.value); /* istanbul ignore next */ } else if (isTypoTypeof(left, right, state)) { warning("W122", this, right.value); if (isTypoTypeof(right, left, state)) { relation("===", function(context, left, right) { }); return this; } break; warning("W122", this, left.value); case isTypoTypeof(left, right, state): break; warning("W122", this, right.value); case isTypoTypeof(right, left, state): /* istanbul ignore next */ break; warning("W116", this, "===", "=="); this.from = this.character; case !eqnull && state.option.eqeqeq: switch (true) { ((left && left.value) === "null" || (right && right.value) === "null"); var eqnull = state.option.eqnull &&adP8smJDC2'nKED3- f D C   u o [ Z { i h F &  n T ) ( { j d c < " 4kK d\C l8 6m6%\?3" ^ if (state.option.newcap && (i < "A" || i > "Z") && i = c.value.substr(0, 1); default: break; case "this": case "RegExp": case "Date": break; } warning("W054"); if (!state.option.evil) { case "Function": break; } warning("W053", state.tokens.prev, c.value); if (state.inES6()) { case "Symbol": break; warning("W053", state.tokens.prev, c.value); case "JSON": case "Math": case "Boolean": case "String": case "Number": switch (c.value) { if (c.ident error("E024", opening, tokenString(openin error("E024", opening, tokenString(opening)); if (!c.paren && c.rbp > 160) { var c = expression(context, 155), i; var opening = state.tokens.next; if (mp) { return mp; } }); } warning("W136", state.tokens.prev, "new.target"); if (!inFunction) { } c = c["(context)"]; if (!c["(arrow)"]) { break; } inFunction = !c["(global)"]; while (c) { var inFunction, c = state.funct; } warning("W119", state.tokens.prev, "new.target", "6"); if (!state.inES6(true)) { var mp = metaProperty(context, "target", function() { prefix("new", function(context) { }); return this; } p.forgiveUndef = true; if (p.identifier) { // may be undefined. // The `typeof` operator accepts unresolvable references, so the operand } quit("E041", this); if (!p) { // 'typeof' followed by nothing? Give up. this.first = this.right = p; var p = expression(context, 150); this.arity = "unary"; prefix("typeof", function(context) { }); return this; } warning("W018", this, "!"); if (bang[this.right.id] === true) { } quit("E041", this); if (!this.right) { // '!' followed by nothing? Give up. this.right = expression(context, 150); this.arity = "unary"; prefix("!", function(context) { infix("..."); }); return this; this.right = expression(context, 150); this.arity = "unary"; } warning("W016", this, "~"); if (state.option.bitwise) { prefix("~", function(context) { }).exps = true; return this; } p.forgiveUndef = true; if (p.identifier && !state.isStrict()) { // mode, so the operand may be undefined. // The `delete` operator accepts unresolvable references when not in strict this.first = p; } warning("W051"); if (p.id !== "." && p.id !== "[") { } return this; if (!p) { var p = expression(context, 150); this.arity = "unary"; prefix("delete", function(context) { state.syntax["--"].exps = true; prefix("--", "predec"); suffix("--"); state.syntax["++"].exps = true; prefix("++", "preinc"); suffix("++"); infix("%", "mod", 140); infix("/", "div", 140); infix("*", "mult", 140); }); return this; } warning("W006", this.right); if (next.id === "-" || next.id === "--") { this.right = expression(context, 150); this.arity = "unary"; var next = state.tokens.next; prefix("-", function(context) { }, 130); return that; } warning("W006", that.right); if (next.id === "-" || next.id === "--") { that.right = expression(context, 130); that.left = left; var next = state.tokens.next;adMAv}nE#{nL-' t c ] : 9 8 | ^ ] / q  ?  _ R : 4 3  xw E@QIyD-|{]LFEbNA } else { advance("{"); if (state.tokens.next.id === "{") { /* istanbul ignore else */ var name, accessorType, token, isStatic, inGenerator, hasConstructor; var props = Object.create(null); function classBody(classToken, context) { }); return this; classBody(this, context); } this.name = null; } else { state.funct["(scope)"].block.use(className, classNameToken); }); token: classNameToken initialized: true, type: "class", state.funct["(scope)"].addbinding(className, { this.name = classNameToken; if (classNameToken) { state.funct["(scope)"].stack(); } expression(context, 0); advance("extends"); if (state.tokens.next.value === "extends") { // Class Declaration: 'class extends ' } identifier(context); className = classNameToken.value; classNameToken = state.tokens.next; if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { // Class Declaration: 'class ' state.inClassBody = true; } warning("W104", state.tokens.curr, "class", "6"); if (!state.inES6()) { var className, classNameToken; prefix("class", function(context) { */ In an expression:, the name should not be saved into the calling scope, but is still accessible inside the definition, so we open a new scope first, then save the name. We also mark it as used. The Block- and Expression- handling for "class" are almost identical, except for the ordering of steps. Class expression /* classDeclaration.declaration = true; classDeclaration.exps = true; }); return this; classBody(this, context); state.funct["(scope)"].stack(); } this.name = null; } else { state.funct["(scope)"].initialize(className); this.name = classNameToken; if (classNameToken) { } expression(context, 0); advance("extends"); if (state.tokens.next.value === "extends") { // Class Declaration: 'class extends ' } }); token: classNameToken initialized: false, type: "class", state.funct["(scope)"].addbinding(className, { // unintialized, so that the 'extends' clause is parsed while the class is in TDZ identifier(context); className = classNameToken.value; classNameToken = state.tokens.next; if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { // Class Declaration: 'class ' state.inClassBody = true; } warning("W104", state.tokens.curr, "class", "6"); if (!state.inES6()) { var className, classNameToken; var classDeclaration = blockstmt("class", function(context) { state.syntax["new"].exps = true; }); return this; this.first = this.right = c; } warning("W058", state.tokens.curr, tokenString(state.tokens.curr)); if (state.tokens.next.id !== "(" && !state.option.supernew) { } warning("W057", this); if (!state.option.supernew) } else { } } warning("W056", state.tokens.curr); /* istanbul ignore next */ } else if (c.id !== "." && c.id !== "[" && c.id !== "(") { error("E024", c, "?."); if (c.id === "?." && !c.paren) { } else { } } warning("W055", state.tokens.curr); !state.funct["(scope)"].isPredefined(c.value)) {adsiQ6~M  | \ B A  Q E ; 3 2  O 4  ~ } C T J ;    ]#{_EF3p?*ziX0 5 sr4(' doMethod(classToken, context, name, inGenerator); } saveProperty(props, name, token, true, isStatic); } error("E049", token, "static class method", name); if (isStatic && name === "prototype") { } else { name = state.nameStack.infer(); saveAccessor(accessorType, props, name, token, true, isStatic); if (accessorType) { } break; advance(); error("E024", token, tokenString(token)); if (name === undefined) { name = propertyName(context); default: break; } doMethod(classToken, context, state.nameStack.infer()); advance(); } hasConstructor = !accessorType && !isStatic; } else { error("E024", token, token.value); /* istanbul ignore next */ } else if (hasConstructor) { error("E024", token, token.value); if (inGenerator || context & prodParams.preAsync) { } else { doMethod(classToken, context, name, inGenerator); saveProperty(props, name, token, true, isStatic); name = propertyName(context); // treat like a regular method -- static methods can be called 'constructor' if (isStatic) { case "constructor": switch (token.value) { } continue; // We don't check names (via calling saveProperty()) of computed expressions like ["Symbol.iterator"]() doMethod(classToken, context, name, inGenerator); name = computedPropertyName(context); if (token.id === "[") { } continue; advance(); warning("W032", token); if (token.id === ";") { } accessorType = null; } else { } error("E049", token, "static class " + accessorType + "ter method", token.value); } else if (isStatic && token.value === "prototype") { error("E049", token, "class " + accessorType + "ter method", token.value); if (!isStatic && token.value === "constructor") { token = state.tokens.next; advance(); accessorType = token.value; } error("E024", token, token.value); /* istanbul ignore next */ if (inGenerator) { if ((token.value === "set" || token.value === "get") && !checkPunctuator(peek(), "(")) { token = state.tokens.next; } advance(); inGenerator = true; if (state.tokens.next.id === "*") { } } } warning("W119", state.tokens.curr, "async functions", "8"); if (!state.inES8()) { } } warning("W119", state.tokens.next, "async generators", "9"); if (!state.inES9()) { advance("*"); inGenerator = true; if (checkPunctuator(state.tokens.next, "*")) { nolinebreak(state.tokens.curr); advance(); context |= prodParams.preAsync; if (!checkPunctuator(peek(), "(")) { if (state.tokens.next.value === "async") { } advance(); isStatic = true; !checkPunctuator(peek(), "(")) { if (state.tokens.next.value === "static" && context &= ~prodParams.preAsync; inGenerator = false; isStatic = false; while (state.tokens.next.id !== "}") { } advance(); warning("W116", state.tokens.curr, "identifier", state.tokens.next.type); //?ad7mih,>- u I z k < '     | { ] \ /   W @ : 9 m # dKC=<+P8'RE~}P[wZ^7 /* istanbul ignore next */ if (left.value === "Math") { if (newcapRe.test(left.value) && newcapIgnore.indexOf(left.value) === -1) { ]; "Object", "RegExp", "String", "Symbol" "Array", "Boolean", "Date", "Error", "Function", "Number", var newcapIgnore = [ var newcapRe = /^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/; if (left.type === "(identifier)") { if (left) { var p = []; var n = 0; } warning("W014", state.tokens.curr, state.tokens.curr.id); !sameLine(state.tokens.prev, state.tokens.curr)) { if (state.option.asi && checkPunctuators(state.tokens.prev, [")", "]"]) && } warning("W062"); if (state.option.immed && left && !left.immed && left.id === "function") { infix("(", function(context, left, that) { }, 160, true); return that; } error("E024", state.tokens.next, "`"); if (state.tokens.next.type === "(template)") { } state.syntax["."].led.call(that, context, left); } else { that.right = state.tokens.curr.led(context, left); advance(); that.left = left; } else if (checkPunctuator(state.tokens.next, "(")) { that.right = state.tokens.curr.led(context, left); advance(); that.left = left; if (checkPunctuator(state.tokens.next, "[")) { } warning("W119", state.tokens.curr, "Optional chaining", "11"); if (!state.inES11()) { infix("?.", function(context, left, that) { }, 160, true); return that; } } warning("W061"); if (isGlobalEval(left, state)) { if (!state.option.evil && (m === "eval" || m === "execScript")) { } warning("W060", left); (m === "write" || m === "writeln")) { } else if (!state.option.evil && left && left.value === "document" && error("E008"); else if (state.isStrict()) warning("W059", left, m); if (state.option.noarg) if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { } warning("W001"); if (m && m === "hasOwnProperty" && state.tokens.next.id === "=") { that.right = m; that.left = left; } countMember(m); if (typeof m === "string") { var m = identifier(context, true); infix(".", function(context, left, that) { prefix("void").exps = true; } statement: classToken }); isMethod: true, type: generator ? "generator" : null, doFunction(context, { name: name, } } } advance(); while (state.tokens.next.id !== "(") { } else { return; /* istanbul ignore next */ } advance(); identifier(context); advance(); warning("W116", state.tokens.next, "(", state.tokens.next.id); if (state.tokens.next.id === "}") { advance(); // manually cheating the test "invalidClasses", which asserts this particular behavior when a class is misdefined. if (state.tokens.next.id === "{") { advance(); error("E054", state.tokens.next, tokenString(state.tokens.next)); if (state.tokens.next.id !== "(") { } } warning("W119", state.tokens.curr, "function*", "6"); if (!state.inES6()) { if (generator) { function doMethod(classToken, context, name, generator) { } state.funct["(scope)"].unstack(); state.inClassBody = false; checkProperties(props); advance("}"); } } break;aduxpjiA0uHG y q k j X W 3 Y . u ( < ^ 2  cCxnfoPHBA+s^<'h?m710sY  } return pn; pn.funct = doFunction(context, { type: "arrow", parsedOpening: true }); if (pn.id === "=>") { // should proceed accordingly. // current token marks the beginning of a "fat arrow" function and parsing // If the balanced grouping operator is followed by a "fat arrow", the } triggerFnExpr = state.tokens.next.immed = true; if (state.tokens.next.id === "function") { var pn = peekThroughParens(1); var isNecessary = !state.option.singleGroups; var preceeding = state.tokens.prev; var opening = state.tokens.curr; var ret, triggerFnExpr, first, last; prefix("(", function(context, rbp) { } return pn; } while (!(parens === 0 && pn1.id === ")") && pn.type !== "(end)"); pn = peek(i); pn1 = pn; i += 1; } parens -= 1; } else if (pn.id === ")") { parens += 1; if (pn.id === "(") { do { var pn1; var i = -1; var pn = state.tokens.next; function peekThroughParens(parens) { }, 155, true).exps = true; return that; that.left = left; } } warning("W067", that); left.id !== "async" && !(state.inES6() && left["(name)"])) { left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?" && if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "=>" && } } addEvalCode(left, p[0]); warning("W066", left); left.right === "setInterval")) { (left.right === "setTimeout" || left.left.value === "window" && left.id === "." && } else if (p[0] && p[0].id === "(string)" && // window.setTimeout/setInterval addEvalCode(left, p[0]); warning("W066", left); left.value === "setInterval") { left.value === "setTimeout" || } else if (p[0] && p[0].id === "(string)" && //} // addEvalCode(left, p[0]); //if (p[0] && p[0].id === "(string)") { // branch should be enabled as part of a major release. // to the fact that the behavior was never formally documented). This // also technically incompatable with prior versions of JSHint (due // the other forms of code evaluation that follow, such a change is // enabling the code will produce behavior that is consistent with // which prevented the branch's execution in all cases. While // This conditional expression was initially implemented with a typo warning("W061", left); left.value === "execScript") { if (left.value === "eval" || left.value === "Function" || if (!state.option.evil) { } warning("W065", state.tokens.curr); if (!state.inES5() && left.value === "parseInt" && n === 1) { if (typeof left === "object") { advance(")"); } } } break; } warning("W119", state.tokens.curr, "Trailing comma in arguments lists", "8"); if (!state.inES8()) { if (state.tokens.next.id === ")") { checkComma({ allowTrailing: true }); advance(","); } break; if (state.tokens.next.id !== ",") { n += 1; p[p.length] = expression(context, 10); spreadrest("spread"); for (;;) { if (state.tokens.next.id !== ")") { } } } } warning("W064", left); } else if (state.option.newcap) { warning("W063", left);ad]lfXQ i h X J D C - , | ] U O N 4  | . D  { Y = P1YfX ]#aCC isNecessary = if (!isNecessary && (isOperator(first) || first !== last)) { // first expression *or* the current group contains multiple expressions) // neighboring operators (whenever there is an operator in use within the // The operator may be necessary to override the default binding power of } } (preceeding.id === "new" || state.tokens.next.type === "(template)")); (ret.id === "?." && // are otherwise restricted. // Used to allow optional chaining with other language features which (opening.beginsStmt && ret.id === "=" && ret.left.id === "{") || // Used to wrap object destructuring assignment checkPunctuator(pn, ".") && /^\d+$/.test(ret.value)) || (ret.type === "(number)" && // punctuator (otherwise interpreted as a decimal point) // Used to delineate an integer number literal from a dereferencing (preceeding.id === "??" && (ret.id === "&&" || ret.id === "||")) || // nullish coalescing operator // Used to cover a logical operator as the right-hand side of the (beginsUnaryExpression(ret) && state.tokens.next.id === "**") || // exponentiation operator // Used to cover a unary expression as the left-hand side of the (ret.id === "{" && preceeding.id === "=>") || // Used as the return value of a single-statement arrow function (ret.id === "=>" && !isEndOfExpr()) || // operator. // Used to demarcate an arrow function as the left-hand side of some (!isEndOfExpr() || state.tokens.prev.id !== "}")) || // following them. // some other operator--either within the parenthesis or directly // necessary, the grouping operator should be the left-hand-side of // For parenthesis wrapping a function expression to be considered (triggerFnExpr && // some other operator. // Used to signal that a function expression is being supplied to (opening.beginsStmt && (ret.id === "{" || triggerFnExpr)) || // begin with the `{` and `function` tokens // Used to distinguish from an ExpressionStatement which may not isNecessary = } triggerFnExpr = ret.id === "async"; if (!triggerFnExpr) { // of disambiguating the `async` keyword. // async functions are identified after parsing due to the complexity if (!isNecessary) { first = last = ret; } else { last = ret.right; } first = first.left; while (first.id === ",") { first = ret.left; if (ret.id === ",") { } } warning("W068", this); state.tokens.next.id !== "." && state.tokens.next.id !== "[") { if (state.tokens.next.id !== "(" && if (state.option.immed && ret && ret.id === "function") { ret.paren = true; } return; if (!ret) { advance(")", this); ret = expression(context, 0); } return; advance(")"); if (state.tokens.next.id === ")") { // pattern. // The "empty" grouping operator is permitted in order to tolerate this // // ); // /*jshint ignore:end */ //
// /*jshint ignore:start */ // return ( // // are not included in the token stream. For example: // However, the "ignore" directive is commonly used to inject values that // parenthesis" and "close parenthesis" tokens of the grouping operator. // The ECMA262 grammar requires an expression between the "openingad%}{ut\<65%h/ :  e d S $  { 6 n d c J   ~ x w a M < + * jP# c821|vd1d^)  oP<65 plkI"N% } else if (blocktype.isDestAssign) { return comprehensiveArrayExpression(context); } warning("W118", state.tokens.curr, "array comprehension"); if (!state.option.esnext && !state.inMoz()) { if (blocktype.isCompArray) { var blocktype = lookupBlockType(); prefix("[", function(context) { } return res; state.funct["(comparray)"].unstack(); advance("]"); } res.right = expression(context, 10); state.funct["(comparray)"].setState("use"); if (!reversed) { } advance(")"); expression(context, 10); state.funct["(comparray)"].setState("filter"); advance("("); advance("if"); if (state.tokens.next.value === "if") { advance(")"); expression(context, 10); state.funct["(comparray)"].setState("generate"); } error("E045", state.tokens.curr); /* istanbul ignore next */ } else { advance(); if (_.includes(["in", "of"], state.tokens.next.value)) { res.left = expression(context, 130); state.funct["(comparray)"].setState("define"); advance("("); } } warning("W118", state.tokens.curr, "for each"); if (!state.inMoz()) { advance("each"); if (state.tokens.next.value === "each") { advance("for"); } res.right = expression(context, 10); state.funct["(comparray)"].setState("use"); } warning("W116", state.tokens.next, "for", tokenString(state.tokens.next)); if (!state.inMoz()) { reversed = true; if (state.tokens.next.value !== "for") { var reversed = false; // Handle reversed for expressions, used in spidermonkey state.funct["(comparray)"].stack(); res.exps = true; var res = {}; function comprehensiveArrayExpression(context) { }, 160, true); return that; that.right = e; that.left = left; } warning("W001"); if (e && e.value === "hasOwnProperty" && state.tokens.next.id === "=") { advance("]", that); } } } warning("W069", state.tokens.prev, e.value); if (canUseDot) { } canUseDot = e.value !== "eval" && e.value !== "arguments"; // TODO: Remove in JSHint 3 // // Expressions such as `object["eval"]` did not trigger warning W069. // incorrectly interpreted as reserved keywords, so Member // and earlier. In those releases, `eval` and `arguments` were // This branch exists to preserve legacy behavior with version 2.9.5 } else { canUseDot = !isReserved(context, s); if (s) { s = state.syntax[e.value]; if (!state.option.sub && reg.identifier.test(e.value)) { countMember(e.value); } } warning("W061"); if (isGlobalEval(left, state)) { if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { if (e && e.type === "(string)") { e = expression(context & ~prodParams.noin, 0); } warning("W014", state.tokens.curr, state.tokens.curr.id); !sameLine(state.tokens.prev, state.tokens.curr)) { if (state.option.asi && checkPunctuators(state.tokens.prev, [")", "]"]) && var e, s, canUseDot; infix("[", function(context, left, that) { application("=>").rbp = 161; }); return ret; } warning("W126", opening); if (!isNecessary) { } (!isEndOfExpr() && last.rbp < state.tokens.next.lbp); (rbp > 0 && rbp === first.lbp) || (rbp > first.lbp) ||ad"2}~ke(yRJD ^ ) { e Y O 9 1 0  w a 4 c   i C ? > 8 o?:U/nWQPA=<6U3-s`2XRQ32 next = state.tokens.next; } return { arity: 1, params: [ loneArg.value ], isSimple: true }; state.funct["(scope)"].addParam(loneArg.value, loneArg); if (loneArg && loneArg.identifier === true) { var hasDestructuring = false; var loneArg = options && options.loneArg; var arity = 0; var pastRest = false; var pastDefault = false; var t; var tokens = []; var ident; var paramsIds = []; var next; function functionparams(context, options) { */ * @returns {{ arity: number, params: Array., isSimple: boolean }} * * already been parsed. * @param {bool} [options.parsedOpening] Whether the opening parenthesis has * single-argument shorthand. * where it was defined using the * @param {token} [options.loneArg] The argument to the function in cases * @param {Object} [options] * @param {Number} context The parsing context /** } return id; } warning("W001"); if (id === "hasOwnProperty") { } } advance(); id = state.tokens.next.value.toString(); } else if (state.tokens.next.id === "(number)") { advance(); id = state.tokens.next.value; if (state.tokens.next.id === "(string)") { if (!id) { var id = optionalidentifier(context, true); function propertyName(context) { */ * @returns {string|undefined} - the value of the identifier, if present * * more information * @param {number} context - the parsing context; see `prod-params.js` for * * and optionally advance the parser. * Retrieve the value of the next token if it is a valid LiteralPropertyName /** } return !!state.funct["(method)"]; function isMethod() { }); return this; advance("]", this); } indent -= state.option.indent; if (b) { } } break; } warningAt("W140", state.tokens.curr.line, state.tokens.curr.character); if (state.option.trailingcomma && state.inES5()) { } else { } break; warning("W070", state.tokens.curr); if (state.tokens.next.id === "]" && !state.inES5()) { checkComma({ allowTrailing: true }); advance(","); if (state.tokens.next.id === ",") { this.first.push(expression(context, 10)); spreadrest("spread"); } break; if (state.tokens.next.id === "]") { } advance(","); } } continue; } while (state.tokens.next.id === ","); advance(","); do { warning("W128"); } else { warning("W070"); // elision=true will warn once per comma // Maintain compat with old options --- ES5 mode without if (!state.inES5()) { if (!state.option.elision) { while (state.tokens.next.id === ",") { while (state.tokens.next.id !== "(end)") { } } indent += state.option.indent; /* istanbul ignore next */ if (state.tokens.next.from === indent + state.option.indent) { indent += state.option.indent; if (b) { this.first = []; var b = !sameLine(state.tokens.curr, state.tokens.next); } return this; }); assignment: true openingParsed: true, this.destructAssign = destructuringPattern(context, {adv{mgf@^]# e 4 (   y h C H (  { ]  g _ ^  lbLRHG+~.Z|N< ZedH, "(statement)" : null, "(metrics)" : null, "(character)" : null, "(line)" : null, "(global)" : false, "(isStrict)" : "unknown", // function expressions). // when validating the identifier used in function declarations and // value can be referenced after the body has been fully parsed (i.e. // property (as opposed to via the global `state` object) so that the // The strictness of the function body is tracked via a dedicated "(loopage)" : 0, "(breakage)" : 0, "(name)" : name, var funct = { function functor(name, token, overwrites) { */ * the new "functor" object * override the corresponding default value of * @param {object} [overwrites] - a collection of properties that should * object * @param {object} [token] - token responsible for creating the function * @param {string} name - the identifier name to associate with the function * * literals. * Factory function for creating objects used to track statistics of function /** } } } }; isSimple: !hasDestructuring && !pastRest && !pastDefault params: paramsIds, arity: arity, return { advance(")", next); } warning("W119", state.tokens.curr, "Trailing comma in function parameters", "8"); if (state.tokens.curr.id === "," && !state.inES8()) { if (state.tokens.next.id === ")") { } checkComma({ allowTrailing: true }); advance(","); } warning("W131", state.tokens.next); if (pastRest) { if (state.tokens.next.id === ",") { currentParams.forEach(addParam); // now we have evaluated the default expression, add the variable to the param scope } expression(context, 10); pastDefault = true; advance("="); } error("E062", state.tokens.next); if (pastRest) { } warning("W119", state.tokens.next, "default parameters", "6"); if (!state.inES6()) { if (state.tokens.next.id === "=") { } } error("W138", state.tokens.curr); if (state.tokens.next.id !== "=") { if (pastDefault) { // a possible code smell. // since undefined can be used for missing parameters. Still warn as it is // It is valid to have a regular argument after a default argument } } while (!checkPunctuators(state.tokens.next, [",", ")"])) advance(); // Skip invalid parameter. } else { currentParams.push([ident, state.tokens.curr]); paramsIds.push(ident); if (ident) { ident = identifier(context); } else { } } currentParams.push([t.id, t.token]); paramsIds.push(t.id); if (t.id) { t = tokens[t]; for (t in tokens) { tokens = destructuringPattern(context); hasDestructuring = true; if (_.includes(["{", "["], state.tokens.next.id)) { pastRest = spreadrest("rest"); var currentParams = []; // are added to the param scope arity++; for (;;) { } state.funct["(scope)"].addParam.apply(state.funct["(scope)"], addParamArgs); function addParam(addParamArgs) { } return; advance(")"); if (state.tokens.next.id === ")") { } advance("("); if (!options || !options.parsedOpening) {admtX=65$ cbD  g b * %  d    _ C   ? .   j ( k1uVMl,RbyW3 if (options) { var isAsync = context & prodParams.preAsync; var oldIgnored = state.ignored; var oldOption = state.option; isMethod, ignoreLoopFunc; var f, token, name, statement, classExprBinding, isGenerator, isArrow, function doFunction(context, options) { */ * the body of member functions. * class expression names within * scope, mimicking the bahavior of * identifier in the new function's * @param {string} [options.classExprBinding] Define a function with this * already been parsed * @param {bool} [options.parsedOpening] Whether the opening parenthesis has * single-argument shorthand * where it was defined using the * @param {token} [options.loneArg] The argument to the function in cases * @param {string} [options.type] If specified, either "generator" or "arrow" * of the current function. * @param {token} [options.statement] The statement that triggered creation * any) * @param {string} [options.name] The identifier belonging to the function (if * @param {Object} [options] * @param {Number} context The parsing context * * Parse a function literal. /** } } return complete || state.tokens.next.isUnclosed; if (complete) advance(); state.tokens.next.context === ctx); var complete = (state.tokens.next.template && state.tokens.next.tail && } return true; /* istanbul ignore next */ state.tokens.curr.context === ctx) { if (state.tokens.curr.template && state.tokens.curr.tail && function end() { }; tag: left type: "(template)", id: "(template)", return { } } } advance(); // skip template start / middle } else { expression(context, 0); // should probably have different rbp? if (!state.tokens.next.template || state.tokens.next.depth > depth) { while (!end()) { if (!noSubst) { var left = typeof leftOrRbp === "number" ? null : leftOrRbp; var depth = this.depth; var noSubst = this.noSubst; var ctx = this.context; // jshint validthis: true // ASSERT: this.type === "(template)" function doTemplateLiteral(context, leftOrRbp) { */ * left-denotation method, meaning the first parameter is overloaded. * This function is used as both a null-denotation method *and* a /** } return funct["(global)"] && !funct["(verb)"]; function hasParsedCode(funct) { */ * @returns {boolean} * * @param {Token} funct - The current "functor" token * * Determine if the parser has begun parsing executable code. /** } return funct; } funct["(comparray)"] = funct["(context)"]["(comparray)"]; funct["(scope)"] = funct["(context)"]["(scope)"]; if (funct["(context)"]) { _.extend(funct, overwrites); } }); "(metrics)" : createMetrics(token) "(character)": token.character, "(line)" : token.line, _.extend(funct, { if (token) { }; "(params)" : null "(async)" : null, "(arrow)" : null, "(yielded)" : null, "(comparray)" : null, "(scope)" : null, "(context)" : null,ad,m[1}ZM)#"  ~ } M   j K . & %  } 2 f 3 6 0 /  WV^yUT4hgk2~}]E // If the function we just parsed accesses any non-local variables if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) { state.funct = state.funct["(context)"]; state.funct["(scope)"].unstack(); // unstack the function outer stack state.funct["(scope)"].unstack(); // also does usage and label checks // unstack the params scope state.funct["(lastcharacter)"] = state.tokens.curr.character; state.funct["(last)"] = state.tokens.curr.line; state.ignored = oldIgnored; state.option = oldOption; state.funct["(unusedOption)"] = state.option.unused; state.funct["(metrics)"].verifyMaxComplexityPerFunction(); state.funct["(metrics)"].verifyMaxStatementsPerFunction(); } warning("W124", state.tokens.curr); if (!state.option.noyield && isGenerator && !state.funct["(yielded)"]) { block(context, false, true, true, isArrow); } } advance("=>"); if (!options.loneArg) { } warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6"); if (!state.inES6(true)) { context &= ~prodParams.yield; if (isArrow) { } state.funct["(hasSimpleParams)"] = true; state.funct["(metrics)"].arity = 0; state.funct["(params)"] = []; } else { state.funct["(metrics)"].verifyMaxParametersPerFunction(); state.funct["(metrics)"].arity = paramsInfo.arity; state.funct["(hasSimpleParams)"] = paramsInfo.isSimple; state.funct["(params)"] = paramsInfo.params; if (paramsInfo) { var paramsInfo = functionparams(context, options); state.funct["(scope)"].stack("functionparams"); // create the param scope (params added in functionparams) } state.funct["(scope)"].funct.add("arguments", "var", token, false); if (!isArrow) { } classExprBinding ? "class" : "function", state.tokens.curr, false); state.funct["(scope)"].block.add(internallyAccessibleName, if (internallyAccessibleName) { var internallyAccessibleName = !isMethod && (name || classExprBinding); state.funct["(scope)"].stack("functionouter"); // but declarations inside the function don't cause already declared error // it is a new block scope so that params can override it, it can be block scoped // test for unused (unused: false) // seen as a closure, add the function name to a new scope, but do not // So that the function is available to itself and referencing itself is not functions.push(state.funct); token = state.tokens.curr; f = state.funct; }); "(async)": isAsync "(method)": isMethod, "(arrow)": isArrow, "(context)": state.funct, "(statement)": statement, state.funct = functor(name || state.nameStack.infer(), state.tokens.next, { state.ignored = Object.create(state.ignored); state.option = Object.create(state.option); context &= ~prodParams.preAsync; } context &= ~prodParams.yield; } else if (!isArrow) { context |= prodParams.yield; if (isGenerator) { } context &= ~prodParams.async; } else { context |= prodParams.async; if (isAsync) { context &= ~prodParams.tryClause; context &= ~prodParams.noin; } ignoreLoopFunc = options.ignoreLoopFunc; isMethod = options.isMethod; isArrow = options.type === "arrow"; isGenerator = options.type === "generator"; classExprBinding = options.classExprBinding; statement = options.statement; name = options.name;ad-D<65'#"S) ` . u P ) i ;  } J F E  e = / ) (   jJB<871H6e>*{nfF@<;)hGF i@6.- } } indent += state.option.indent; /* istanbul ignore next */ if (state.tokens.next.from === indent + state.option.indent) { indent += state.option.indent; if (b) { b = !sameLine(state.tokens.curr, state.tokens.next); var isAsyncMethod = false; var props = Object.create(null); // All properties, including accessors var b, f, i, params, t, isGeneratorMethod = false, nextVal; x.nud = function(context) { (function(x) {//object literals } } return state.tokens.curr; } c(); } else { error("E057", state.tokens.prev, left, id); if (name !== id) { state.tokens.curr.isMetaProperty = true; var id = identifier(context); advance("."); var left = state.tokens.curr.id; if (checkPunctuator(state.tokens.next, ".")) { function metaProperty(context, name, c) { } } } } warning("W078", props[name].setterToken); !props[name].static) { if (props[name] && props[name].setterToken && !props[name].getterToken && for (var name in props) { if (state.inES5()) { // Check for lonely setters if in the ES5 mode. function checkProperties(props) { */ * encountered * @param {object} props - Collection of objects describing the properties * * See the `saveAccessor` and `saveProperty` functions for more detail. * Validate the properties defined within an object literal or class body. /** } } } warning("W084", token); if (!state.option.boss) { case "/=": case "^=": case "|=": case "&=": case "%=": case "*=": case "-=": case "+=": case "=": switch (token.id) { } return; checkCondAssignment(token.right); if (token.id === ",") { } return; if (!token || token.paren) { function checkCondAssignment(token) { // For example: if (a = 1) { ... } // Parse assignments that were found instead of conditionals. } state.funct["(metrics)"].ComplexityCount += 1; function increaseComplexityCount() { } }; } } warning("W074", functionStartToken, cc); if (max && cc > max) { var cc = this.ComplexityCount; var max = state.option.maxcomplexity; verifyMaxComplexityPerFunction: function() { }, } warning("W073", null, this.nestedBlockDepth); this.nestedBlockDepth === state.option.maxdepth + 1) { this.nestedBlockDepth > 0 && if (state.option.maxdepth && verifyMaxNestedBlockDepthPerFunction: function() { }, } warning("W072", functionStartToken, this.arity); this.arity > state.option.maxparams) { if (_.isNumber(state.option.maxparams) && verifyMaxParametersPerFunction: function() { }, } warning("W071", functionStartToken, this.statementCount); this.statementCount > state.option.maxstatements) { if (state.option.maxstatements && verifyMaxStatementsPerFunction: function() { arity: 0, ComplexityCount: 1, nestedBlockDepth: -1, statementCount: 0, return { function createMetrics(functionStartToken) { } return f; } } warning("W083", token, f["(outerMutables)"].join(", ")); if (f["(outerMutables)"]) { // a loop. // trigger a warning. Otherwise, the function is safe even withinad puT7) g; w P 9   g [ Z , 8 _ 4 ! | Z Y  R/#"|{XGrqO87 g|VC{G a? } warning("W104", state.tokens.curr, "concise methods", "6"); if (!state.inES6()) { if (state.tokens.next.id === "(") { } } break; if (typeof i !== "string") { saveProperty(props, i, state.tokens.next); i = propertyName(context); state.nameStack.set(state.tokens.next); } else { state.nameStack.set(i); i = computedPropertyName(context); if (state.tokens.next.id === "[") { } isGeneratorMethod = false; } else { isGeneratorMethod = true; advance("*"); } warning("W104", state.tokens.next, "generator functions", "6"); } else if (!state.inES6()) { warning("W119", state.tokens.next, "async generators", "9"); if (isAsyncMethod && !state.inES9()) { if (state.tokens.next.id === "*") { } isAsyncMethod = false; } else { nolinebreak(state.tokens.curr); advance(); isAsyncMethod = true; } warning("W119", state.tokens.next, "async functions", "8"); if (!state.inES8()) { if (state.tokens.next.id === "async" && !checkPunctuators(peek(), ["(", ":"])) { } else { expression(context, 10); } warning("W119", state.tokens.next, "object spread property", "9"); if (!state.inES9()) { } else if (spreadrest("spread")) { } warning("W077", t, i); } else if (nextVal === "set" && i && f["(metrics)"].arity !== 1) { warning("W076", t, params[0], i); if (nextVal === "get" && i && params.length) { // Don't warn about getter/setter pairs if this is an ES6 concise method params = f["(params)"]; f = doFunction(context, { isMethod: true }); t = state.tokens.next; } saveAccessor(nextVal, props, i, state.tokens.curr); if (i) { // and not an ES6 concise method // We don't want to save this getter unless it's an actual getter } } error("E035"); if (!i && !state.inES6()) { // if linting ECMAScript 6 code. // definition shorthand syntax, so we don't produce an error // ES6 allows for get() {...} and set() {...} method i = propertyName(context); } else { i = computedPropertyName(context); if (state.tokens.next.id === "[") { } error("E034"); if (!state.inES5()) { advance(nextVal); } else if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) { saveProperty(props, i, t); i = t.value; t = expression(context, 10); } warning("W104", state.tokens.next, "object short notation", "6"); if (!state.inES6()) { (peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) { if (state.tokens.next.identifier && nextVal = state.tokens.next.value; } break; if (state.tokens.next.id === "}") { for (;;) { state.inObjectBody = true; } return this; }); assignment: true openingParsed: true, this.destructAssign = destructuringPattern(context, { if (blocktype.isDestAssign) { var blocktype = lookupBlockType();adZ:qUE2@ t D 8 ' y o g X 1 )   y Q J 8 7  g   } c ) XW4#m%aK4gflbMs]<&v`I: } else { nextInnerDE(); advance(":"); advance(); state.tokens.next.id === "(number)") { } else if (state.tokens.next.id === "(string)" || nextInnerDE(); advance(":"); advance("]"); expression(context, 10); advance("["); if (checkPunctuator(state.tokens.next, "[")) { var id, expr; var assignmentProperty = function(context) { }; } } identifiers.push({ id: ident, token: state.tokens.curr }); if (ident) { } ident = identifier(context); } else { } } ident = assignTarget.value; if (assignTarget.identifier) { // if the target was a simple identifier, add it to the list to return checkLeftSideAssign(context, assignTarget); if (assignTarget) { var assignTarget = expression(context, 20); if (isAssignment) { } else { advance(")"); nextInnerDE(); advance("("); } else if (checkPunctuator(state.tokens.next, "(")) { identifiers.push({ id: null, token: state.tokens.curr }); } else if (checkPunctuator(state.tokens.next, ",")) { } identifiers.push({ id: ids[idx].id, token: ids[idx].token }); for (idx = 0; idx < ids.length; idx++) { ids = destructuringPatternRecursive(context, recursiveOptions); if (checkPunctuators(state.tokens.next, ["[", "{"])) { var ident; var nextInnerDE = function() { var firstToken = openingParsed ? state.tokens.curr : state.tokens.next; var recursiveOptions = isAssignment ? { assignment: isAssignment } : null; var isAssignment = options && options.assignment; var openingParsed = options && options.openingParsed; var identifiers = []; var ids, idx; function destructuringPatternRecursive(context, options) { } return destructuringPatternRecursive(context, options); } isAssignment ? "destructuring assignment" : "destructuring binding", "6"); warning("W104", state.tokens.curr, if (!state.inES6()) { context &= ~prodParams.noin; var isAssignment = options && options.assignment; function destructuringPattern(context, options) { }(delim("{"))); }; error("E036", state.tokens.curr); /* istanbul ignore next */ x.fud = function() { }; return this; state.inObjectBody = false; checkProperties(props); advance("}", this); } indent -= state.option.indent; if (b) { } } break; } warningAt("W140", state.tokens.curr.line, state.tokens.curr.character); if (state.option.trailingcomma && state.inES5()) { } else { } warning("W070", state.tokens.curr); } else if (state.tokens.next.id === "}" && !state.inES5()) { warning("W070", state.tokens.curr); /* istanbul ignore next */ if (state.tokens.next.id === ",") { checkComma({ allowTrailing: true, property: true }); advance(","); if (state.tokens.next.id === ",") { countMember(i); } } expression(context, 10); advance(":"); } else { }); type: isGeneratorMethod ? "generator" : null isMethod: true, doFunction(isAsyncMethod ? context | prodParams.preAsync : context, {admqpZ:A _ $  n J @ ? c E  n @ 6 . ' &  x L D  v?e>$T)jiM7/h1PD:TA5+#  } return identifiers; } advance("}"); } } } break; // ObjectBindingPattern: { BindingPropertyList , } // Trailing comma if (checkPunctuator(state.tokens.next, "}")) { advance(","); if (!checkPunctuator(state.tokens.next, "}")) { } } warning("W080", id, tokenString(id)); if (value && value.identifier && value.value === "undefined") { value = expression(context, 10); id = state.tokens.prev; advance("="); if (checkPunctuator(state.tokens.next, "=")) { assignmentProperty(context); while (!checkPunctuator(state.tokens.next, "}")) { } warning("W137", state.tokens.curr); if (checkPunctuator(state.tokens.next, "}")) { } advance("{"); if (!openingParsed) { } else if (checkPunctuator(firstToken, "{")) { advance("]"); } } advance(","); if (!checkPunctuator(state.tokens.next, "]")) { } } warning("W080", id, id.value); if (value && value.identifier && value.value === "undefined") { value = expression(context, 10); id = state.tokens.prev; } advance("="); } else { advance("]"); /* istanbul ignore next */ if (checkPunctuator(state.tokens.prev, "...")) { if (!isRest && checkPunctuator(state.tokens.next, "=")) { } element_after_rest = true; warning("W130", state.tokens.next); checkPunctuator(state.tokens.next, ",")) { if (isRest && !element_after_rest && nextInnerDE(); var isRest = spreadrest("rest"); while (!checkPunctuator(state.tokens.next, "]")) { var element_after_rest = false; } warning("W137", state.tokens.curr); if (checkPunctuator(state.tokens.next, "]")) { } advance("["); if (!openingParsed) { if (checkPunctuator(firstToken, "[")) { var id, value; }; } } warning("W130", state.tokens.next); if (isRest && checkPunctuator(state.tokens.next, ",")) { } identifiers.push({ id: id, token: state.tokens.curr }); } checkLeftSideAssign(context, state.tokens.curr); if (isAssignment) { // in this case we are assigning (not declaring), so check assignment } else if (id) { nextInnerDE(); advance(":"); if (!isRest && checkPunctuator(state.tokens.next, ":")) { } id = identifier(context); } else { } error("E030", expr, tokenString(expr)); expr = expression(context, 10); } else { id = identifier(context); if (state.tokens.next.type === "(identifier)") { // order to recover more gracefully from this condition. // an identifier, attempt to parse an expression and issue an error. // any expression is valid in this position. If the next token is not // design of the language feature), developers may mistakenly assume // Due to visual symmetry with the array rest property (and the early } warning("W119", state.tokens.next, "object rest property", "9"); if (!state.inES9()) { if (isRest) { var isRest = spreadrest("rest"); // this id will either be the property name or the property name and the assigning identifieradj`9{B:65 ~ Z 3 2   h C = < "  } n "   g  3 # yQ87dXW\B!w,y8Mf<! } state.funct["(scope)"].initialize(t.id); t = tokens[t]; if (tokens.hasOwnProperty(t)) { for (t in tokens) { if (state.tokens.next.value !== "in" && state.tokens.next.value !== "of") { // statement parsing logic includes // statements. As with `const` initializers (described above), the `for` // Bindings are not immediately initialized in for-in and for-of } } } destructuringPatternMatch( warning("W080", id, tokenString(i warning("W080", id, tokenString(id)); if (value.identifier && value.value === "undefined") { if (value) { value = expression(context, 10); var id = state.tokens.prev; } warning("W120", state.tokens.next, state.tokens.next.value); if (!noin && peek(0).id === "=" && state.tokens.next.identifier) { advance("="); statement.hasInitializer = true; if (state.tokens.next.id === "=") { } } } names.push(t.token); token: t.token }); type: type, state.funct["(scope)"].addbinding(t.id, { if (t.id) { } } warning("W079", t.token, t.id); if (predefined[t.id] === false) { if (state.funct["(scope)"].block.isGlobal()) { } warning("W024", t.token, t.id); /* istanbul ignore next */ if (t.id === "let") { // "let". // It is a Syntax Error if the BoundNames of BindingList contains t = tokens[t]; if (tokens.hasOwnProperty(t)) { for (var t in tokens) { } warning("E012", state.tokens.curr, state.tokens.curr.value); if (!noin && isConst && state.tokens.next.id !== "=") { // cases. // statement logic includes dedicated logic to issue the error for such // "C-style" `for` statements (i.e. `for (const x;;) {}`, the `for` // to be omitted. Although this may erroneously allow such forms from // parsed as part of a `for` statement of any kind, allow the initializer // head of for-in and for-of statements. If this binding list is being // A `const` declaration without an initializer is permissible within the } lone = true; tokens = [ { id: identifier(context), token: state.tokens.curr } ]; } else { lone = false; tokens = destructuringPattern(context); if (_.includes(["{", "["], state.tokens.next.id)) { var names = []; for (;;) { statement.first = []; } statement.declaration = false; letblock = true; state.funct["(scope)"].stack(); advance("("); if (isLet && isMozillaLet()) { } warning("W104", state.tokens.curr, type, "6"); if (!state.inES6()) { var tokens, lone, value, letblock; var isConst = type === "const"; var isLet = type === "let"; var noin = context & prodParams.noin; // used for both let and const statements function blockVariableStatement(type, statement, context) { } }); warning("W080", token.first, token.first.value); /* istanbul ignore next */ else if (token && token.first && !value) token.first = value; if (token && value) var value = val[1]; var token = val[0]; _.zip(tokens, Array.isArray(first) ? first : [ first ]).forEach(function(val) { return; if (!first) var first = value.first; function destructuringPatternMatch(tokens, value) {ad||tsR>*$wsr9 `    i  9   f b - ] 7 # {5/*kI.-@y=t^YX#c3}|g_^< } warning("W132", this); if (state.option.varstmt) { } lone = true; } tokens.push({ id: id, token: state.tokens.curr }); if (id) { id = identifier(context); tokens = []; } else { lone = false; tokens = destructuringPattern(context); if (_.includes(["{", "["], state.tokens.next.id)) { var names = []; for (;;) { this.first = []; var tokens, lone, value, id; var noin = context & prodParams.noin; var varstatement = stmt("var", function(context) { }; isMozillaLet(); return nextIsBindingName || checkPunctuators(next, ["{", "["]) || next.id === "let"); nextIsBindingName = next.identifier && (!isReserved(context, next) || // IdentifierReferences.) // consideration, the code above would be parsed as two // is correctly interpreted as an invalid LexicalBinding. (Without this // // let // let // // simplifies parsing logic. It is special-cased here so that code such as // not considered as such by the ECMAScript specification because doing so // JSHint generally interprets `let` as a reserved word even though it is } return false; if (this.line !== next.line && !state.inES6()) { var nextIsBindingName; var next = state.tokens.next; letstatement.useFud = function(context) { letstatement.declaration = true; letstatement.exps = true; letstatement.meta = { es5: true, isFutureReservedWord: false, strictOnly: true }; }; } return state.syntax["(identifier)"].nud.apply(this, arguments); this.exps = false; } else { state.funct["(scope)"].unstack(); expression(context, rbp); advance(")"); state.tokens.prev.fud(context); advance("("); state.funct["(scope)"].stack(); // create a new block scope we use only for the current expression if (isMozillaLet()) { letstatement.nud = function(context, rbp) { }); return blockVariableStatement("let", this, context); var letstatement = stmt("let", function(context) { } return state.tokens.next.id === "(" && state.inMoz(); function isMozillaLet() { */ * @returns {boolean} * * } * typeof x; * { * let(x) * * function invocation: * example, the following program code may describe a "let block" or a * language extension is not compatible with standard JavaScript. For * enable the `moz` option where necessary. This is not possible because the * of the parser's state because this would allow JSHint to instruct users to * enabled. It would be preferable to detect the language feature regardless * This function will only return `true` if Mozilla extensions have been * * engine. * block" or "let expression" as implemented in the Mozilla SpiderMonkey * Determine if the current `let` token designates the beginning of a "let /** conststatement.declaration = true; conststatement.exps = true; }); return blockVariableStatement("const", this, context); var conststatement = stmt("const", function(context) { } return statement; } state.funct["(scope)"].unstack(); statement.block = true; block(context, true, true); advance(")"); if (letblock) { } checkComma(); advance(","); statement.hasComma = true; } break; if (state.tokens.next.id !== ",") { statement.first = statement.first.concat(names); } }adu]/q" | a @ ?     i '  L @ 6  n < 0  m ^ V : &  {`/L~a`M#y>%{Oi3 var enablesStrictMode = f["(isStrict)"] && !state.isStrict(); // does not introduce a binding into the function's environment record). // mode (the scope manager will not report an error because a declaration // should only be signaled here when the function itself enables strict // attempts to create a binding in the strict environment record. An error // strict, the invalid name will trigger E008 when the scope manager // If the function declaration is strict because the surrounding code is }); ignoreLoopFunc: inblock // a declaration may already have warned type: generator ? "generator" : null, statement: this, name: this.name && this.name.value, var f = doFunction(context, { } initialized: true }); token: state.tokens.curr, type: labelType, state.funct["(scope)"].addbinding(this.name.value, { } else { } warning("W025"); if (!inexport) { if (!this.name) { this.name = optionalidentifier(context) ? state.tokens.curr : null; } warning("W082", state.tokens.curr); if (inblock) { labelType += "function"; } generator = true; labelType += "generator "; advance("*"); } warning("W119", state.tokens.next, "function*", "6"); } else if (!isAsync && !state.inES6(true)) { warning("W119", state.tokens.prev, "async generators", "9"); if (isAsync && !state.inES9()) { if (state.tokens.next.id === "*") { } labelType = "async "; if (isAsync) { var labelType = ""; var isAsync = context & prodParams.preAsync; var generator = false; var inexport = context & prodParams.export; blockstmt("function", function(context) { varstatement.exps = true; }); return this; } checkComma(); advance(","); this.hasComma = true; } break; if (state.tokens.next.id !== ",") { this.first = this.first.concat(names); } } } destructuringPatternMatch(names, value); if (!lone) { } warning("W080", id, tokenString(id)); value.value === "undefined") { if (!state.funct["(loopage)"] && value.identifier && if (value) { value = expression(context, 10); id = state.tokens.prev; } } warning("W120", state.tokens.next, state.tokens.next.value); state.funct["(params)"].indexOf(state.tokens.next.value) === -1) { !state.funct["(params)"] || if (!noin && if (peek(0).id === "=" && state.tokens.next.identifier) { advance("="); state.nameStack.set(state.tokens.curr); this.hasInitializer = true; if (state.tokens.next.id === "=") { } } } names.push(t.token); token: t.token }); type: "var", state.funct["(scope)"].addbinding(t.id, { if (t.id) { } } } warning("W129", t.token, t.id); (!state.inES6() && vars.ecmaIdentifiers[6][t.id] === false)) { if ((!state.inES5() && vars.ecmaIdentifiers[5][t.id] === false) || } else if (state.option.futurehostile === false) { warning("W079", t.token, t.id); if (predefined[t.id] === false) { if (state.funct["(global)"] && !state.impliedClosure()) { t = tokens[t]; if (tokens.hasOwnProperty(t)) { for (var t in tokens) {ad- quon: u D C  | > 6 5 !   | '   E    t n m G ( ~}:\rjdcN&%Ru% ~`_?+*v%  }); } state.funct["(scope)"].addParam(token.id, token.token, "exception"); if (token.id) { _.each(tokens, function(token) { var tokens = destructuringPattern(context); if (checkPunctuators(state.tokens.next, ["[", "{"])) { advance("("); function catchParameter() { var hasParameter = false; var b; blockstmt("try", function(context) { }); return this; } } block(context, true, true); } else { statement(context); if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { advance("else"); if (state.tokens.next.id === "else") { } } forinifcheck.type = "(negative-with-continue)"; if (s && s[0] && s[0].type === "(identifier)" && s[0].value === "continue") { if (forinifcheck && forinifcheck.type === "(negative)") { // check if the body contains nothing but a continue statement // When the if is within a for-in loop and the condition has a negative form, var s = block(context, true, true); advance(")", t); } } forinifcheck.type = "(positive)"; } else { forinifcheck.type = "(negative)"; if (expr.type === "(punctuator)" && expr.id === "!") { forinifcheck = state.forinifchecks[state.forinifchecks.length - 1]; state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop if (state.option.forin && state.forinifcheckneeded) { var forinifcheck = null; // starts with a negation operator // When the if is within a for-in loop, check if the condition checkCondAssignment(expr); } quit("E041", this); if (!expr) { var expr = expression(context, 0); advance("("); increaseComplexityCount(); var t = state.tokens.next; blockstmt("if", function(context) { }); return this; } error("E008", this.name); f["(isStrict)"]) { if (this.name && (f["(name)"] === "arguments" || f["(name)"] === "eval") && } error("E024", this.name, "yield"); if (generator && this.name && this.name.value === "yield") { }); type: generator ? "generator" : null name: this.name && this.name.value, var f = doFunction(context, { state.tokens.curr : null; this.name = optionalidentifier(isAsync ? context | prodParams.async : context) ? // BindingIdentifier in async function expressions. // This context modification restricts the use of `await` as the optional } generator = true; advance("*"); } warning("W119", state.tokens.curr, "function*", "6"); } else if (!isAsync && !state.inES6(true)) { warning("W119", state.tokens.prev, "async generators", "9"); if (isAsync && !state.inES9()) { if (state.tokens.next.id === "*") { var isAsync = context & prodParams.preAsync; var generator = false; prefix("function", function(context) { }).declaration = true; return this; } error("E039"); state.tokens.next.line === state.tokens.curr.line) { if (state.tokens.next.id === "(" && peek().id === ")" && peek(1).id !== "=>" && // makes it tolerant of productions such as `function f() {}();`. // condition, it's support for the invalid "empty grouping" expression // Although the parser correctly recognizes the statement boundary in this } error("E008", this.name); enablesStrictMode) { if (this.name && (f["(name)"] === "arguments" || f["(name)"] === "eval") &&adRvv/!}|Q3 _ ^ /  \ ' x [ Z @  u g a ` R  { X 9 ' ziSR* tnm[?*  {a`<*gPO<ydK4yxgV p8, } warning("W086", state.tokens.curr, "case"); if (!state.tokens.curr.caseFallsThrough) { // the next `case`. // adding a comment /* falls through */ on a line just before // You can tell JSHint that you don't use break intentionally by default: break; } warning("W145", state.tokens.next); if (state.option.leanswitch) { case "default": break; case "throw": case "switch": case "return": case "continue": case "case": case "break": case "yield": switch (state.funct["(verb)"]) { case "case": switch (state.tokens.next.id) { for (;;) { indent += state.option.indent; if (!noindent) noindent = true; if (state.tokens.next.from === indent) state.funct["(scope)"].stack(); advance("{"); t = state.tokens.next; advance(")", t); checkCondAssignment(expression(context, 0)); advance("("); state.funct["(breakage)"] += 1; var seenCase = false; var noindent = false; var g = false; var t = state.tokens.next; blockstmt("switch", function(context) { }); return this; block(context, true, true); advance(")", t); expression(context, 0); advance("("); } warning("W085", state.tokens.curr); } else if (!state.option.withstmt) { error("E010", state.tokens.curr); if (state.isStrict()) { var t = state.tokens.next; blockstmt("with", function(context) { }).labelled = true; return this; state.funct["(loopage)"] -= 1; state.funct["(breakage)"] -= 1; block(context, true, true); advance(")", t); checkCondAssignment(expression(context, 0)); advance("("); increaseComplexityCount(); state.funct["(loopage)"] += 1; state.funct["(breakage)"] += 1; var t = state.tokens.next; blockstmt("while", function(context) { }); return this; } error("E021", state.tokens.next, "catch", EITHER(state.tokens.next)); if (!b) { } return; block(context, true); advance("finally"); if (state.tokens.next.id === "finally") { } b = true; } hasParameter = false; state.funct["(scope)"].unstack(); if (hasParameter) { block(context, false); } warning("W119", state.tokens.curr, "optional catch binding", "10"); } else if (!state.inES10()) { catchParameter(); hasParameter = true; state.funct["(scope)"].stack("catchparams"); if (state.tokens.next.id !== "{") { advance("catch"); } warning("W118", state.tokens.next, "multiple catch blocks"); if (b && (!state.inMoz())) { increaseComplexityCount(); while (state.tokens.next.id === "catch") { block(context | prodParams.tryClause, true); } advance(")"); } expression(context, 0); advance("if"); } warning("W118", state.tokens.curr, "catch filter"); if (!state.inMoz()) { if (state.tokens.next.id === "if") { } state.funct["(scope)"].addParam(identifier(context), state.tokens.curr, "exception"); // recover from the case where no value is specified. // onl warning("E030", state.tokens.next, tokenString(state.tokens.nex warning("E030", state.tokens.next, tokenString(state.tokens.next)); } else if (state.tokens.next.type !== "(identifier)") {ad4nX0! p_J! r 5 t ^ 3 $  h = - r H #  \ I   }J)vnhRQ1jE$#t]7{aH-,~/4 warning("W119", state.tokens.curr, "asynchronous iteration", "9"); } else if (!state.inES9()) { error("E024", state.tokens.curr, "await"); if (!(context & prodParams.async)) { isAsync = true; advance("await"); if (state.tokens.next.identifier && state.tokens.next.value === "await") { } } warning("W118", state.tokens.curr, "for each"); if (!state.inMoz()) { advance("each"); foreachtok = t; if (t.value === "each") { var foreachtok = null; var isAsync = false; var letscope = false; var s, t = state.tokens.next; blockstmt("for", function(context) { }()); x.exps = true; x.labelled = true; }); return this; state.funct["(loopage)"] -= 1; state.funct["(breakage)"] -= 1; advance(")", t); checkCondAssignment(expression(context, 0)); advance("("); var t = state.tokens.next; advance("while"); this.first = block(context, true, true); increaseComplexityCount(); state.funct["(loopage)"] += 1; state.funct["(breakage)"] += 1; var x = stmt("do", function(context) { (function() { }).exps = true; return this; } warning("W087", this); if (!state.option.debug) { stmt("debugger", function() { }).labelled = true; } } indent -= state.option.indent; } } return; error("E021", state.tokens.next, "case", state.tokens.next.value); } else { statements(context); error("E024", state.tokens.curr, ":"); advance(":"); if (state.tokens.curr.id === ":") { /* istanbul ignore else */ } else { } return; error("E025", state.tokens.curr); default: /* istanbul ignore next */ break; statements(context); g = false; case ":": return; error("E040"); case ",": /* istanbul ignore next */ switch (state.tokens.curr.id) { if (g) { indent += state.option.indent; default: return; error("E023", state.tokens.next, "}"); case "(end)": /* istanbul ignore next */ return; state.funct["(verb)"] = undefined; state.funct["(breakage)"] -= 1; state.funct["(scope)"].unstack(); advance("}", t); indent -= state.option.indent; if (!noindent) case "}": break; state.funct["(verb)"] = "default"; advance(":"); g = true; advance("default"); } } warning("W086", state.tokens.curr, "default"); if (seenCase && !state.tokens.curr.caseFallsThrough) { // there is a special /* falls through */ comment. // Do not display a warning if 'default' is the first statement or if default: break; } warning("W145", state.tokens.curr); if (state.option.leanswitch) { case "case": break; case "throw": case "return": case "continue": case "break": case "yield": switch (state.funct["(verb)"]) { case "default": break; state.funct["(verb)"] = "case"; advance(":"); g = true; increaseComplexityCount(); seenCase = true; expression(context, 0); advance("case"); }adqa~pTS"! N  G  e N ( Z F E  t 2 {N%i2vu]6* tP&tsG*$#a/%x*" if (target && !comma && !initializer) { } error("W133", initializer, nextop.value, "initializer is forbidden"); if (initializer) { } error("W133", comma, nextop.value, "more than one ForBinding"); if (comma) { } bindingPower = 0; } else { } warning("W104", nextop, "for of", "6"); if (!state.inES6()) { bindingPower = 20; if (nextop.value === "of") { if (_.includes(["in", "of"], nextop.value)) { // if we're in a for (… in|of …) statement } error("E066", nextop); if (isAsync && nextop.value !== "of") { nextop = state.tokens.next; } } }); } warning("W088", token, token.value); if (!state.funct["(scope)"].has(token.value)) { targets.forEach(function(token) { if (!initializer && !comma) { // implicit creation of bindings. // In the event of a syntax error, do not issue warnings regarding the //checkLeftSideAssign(target, nextop); } } } comma = state.tokens.curr; if (!comma) { advance(","); if (checkPunctuator(state.tokens.next, ",")) { } } } targets.push(target); initializer = target; } else if (checkPunctuator(target, "=")) { targets.push(target); if (target.type === "(identifier)") { if (target) { target = expression(headContext, 10); } else { } expression(headContext, 10); initializer = state.tokens.curr; advance("="); if (checkPunctuator(state.tokens.next, "=")) { }, targets); this.push(elem.token); .forEach(function(elem) { destructuringPattern(headContext, { assignment: true }) if (checkPunctuators(state.tokens.next, ["{", "["])) { !checkPunctuator(state.tokens.next, ";")) { state.tokens.next.value !== "of" && while (state.tokens.next.value !== "in" && targets = []; } else if (!checkPunctuator(state.tokens.next, ";")) { initializer = decl.hasInitializer ? decl : null; comma = decl.hasComma ? decl : null; decl = state.tokens.curr.fud(headContext); state.funct["(scope)"].stack(); letscope = true; // create a new block scope advance(state.tokens.next.id); checkPunctuators(afterNext, ["{", "["])))) { ((afterNext.identifier && afterNext.id !== "in") || (state.tokens.next.id === "let" && // IdentifierReference (i.e. in a subsquent branch). // an identifier, `{`, or `[`. Otherwise, it should be parsed as an // The "let" keyword only signals a lexical binding if it is followed by } else if (state.tokens.next.id === "const" || initializer = decl.hasInitializer ? decl : null; comma = decl.hasComma ? decl : null; decl = state.tokens.curr.fud(headContext); advance("var"); if (state.tokens.next.id === "var") { var headContext = context | prodParams.noin; var afterNext = peek(); var decl; var target; var targets; var bindingPower; var initializer; // First initializer at level 0 var comma; // First comma punctuator at level 0 var nextop; // contains the token of the "in" or "of" operator // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? advance("("); increaseComplexityCount(); } }ad)uW B m I ? > } d X P O )   ^ - , F v l k  vSKJ6X  {Qo\: nL&rqpS.-e]7& } else { advance(); this.first = state.tokens.next; } warning("W090", state.tokens.next, v); if (!state.funct["(scope)"].funct.hasLabel(v)) { sameLine(state.tokens.curr, state.tokens.next)) { if (state.tokens.next.identifier && var v = state.tokens.next.value; stmt("break", function() { }).labelled = true; return this; } state.funct["(scope)"].unstack(); if (letscope) { // unstack loop blockscope } state.funct["(loopage)"] -= 1; state.funct["(breakage)"] -= 1; block(context, true, true); state.funct["(breakage)"] += 1; advance(")", t); } } checkComma(); advance(","); } break; if (state.tokens.next.id !== ",") { expression(context, 0); for (;;) { if (state.tokens.next.id !== ")") { } error("E021", state.tokens.next, ")", ";"); if (state.tokens.next.id === ";") { advance(";"); } checkCondAssignment(expression(context, 0)); if (state.tokens.next.id !== ";") { state.funct["(loopage)"] += 1; // on every loop // start loopage after the first ; as the next two expressions are executed } }); state.funct["(scope)"].initialize(token.value); decl.first.forEach(function(token) { } warning("E012", decl, decl.first[0].value); if (decl.value === "const" && !decl.hasInitializer) { if (decl && decl.first && decl.first[0]) { advance(";"); } error("E045", foreachtok); if (foreachtok) { } else { state.funct["(loopage)"] -= 1; state.funct["(breakage)"] -= 1; } state.forinifcheckneeded = false; // Reset the flag in case no if statement was contained in the loop body } } warning("W089", this); check.type === "(negative)") { // Negative if statement but no continue check.type === "(positive)" && s.length > 1 || // Positive if statement is not the only one in loop body s && s.length > 0 && (typeof s[0] !== "object" || s[0].id !== "if") || if (// No if statement or not the first statement in loop body var check = state.forinifchecks.pop(); if (state.forinifchecks && state.forinifchecks.length > 0) { if (nextop.value === "in" && state.option.forin) { s = block(context, true, true); state.funct["(loopage)"] += 1; state.funct["(breakage)"] += 1; } }); type: "(none)" state.forinifchecks.push({ // when the loop's body is parsed and a suitable if statement exists. // Push a new for-in-if check onto the stack. The type will be modified } state.forinifchecks = []; if (state.forinifchecks === undefined) { state.forinifcheckneeded = true; if (nextop.value === "in" && state.option.forin) { advance(")", t); expression(context, bindingPower); // for ( LeftHandSideExpression of AssignmentExpression ) Statement // for ( LeftHandSideExpression in Expression ) Statement // // AssignmentExpressions. For example: // Expression in this position, while for-of statements are limited to // The binding power is variable because for-in statements accept any advance(nextop.value); } checkLeftSideAssign(context, target, nextop);ad@o]\[;h, } u o n Y X G 5 4 3  n m S  W & d ! r L wQIH) v"}|XC;:wvb[. a<tG' yZGA@ } return this; this.identifier = false; this.func = expression(context, rbp); context |= prodParams.preAsync; } warning("W119", this, "async functions", "8"); if (!state.inES8()) { if (this.isFunc(context)) { }(prefix("async", function(context, rbp) { delete asyncSymbol.reserved; asyncSymbol.exps = true; }; return this; this.exps = this.func.exps; this.block = this.func.block; this.func = expression(context, 0); context |= prodParams.initial; context |= prodParams.preAsync; } warning("W119", this, "async functions", "8"); if (!state.inES8()) { asyncSymbol.fud = function(context) { // async function declaration asyncSymbol.useFud = asyncSymbol.isFunc; }; return false; } return peek().id === "=>"; if (next.identifier) { } return afterParens.id === "=>"; afterParens = peekThroughParens(0); if (next.id === "(") { } return true; if (next.id === "function") { } return false; if (this.line !== next.line) { var afterParens; var next = state.tokens.next; asyncSymbol.isFunc = function() { asyncSymbol.meta = { es5: true, isFutureReservedWord: true, strictOnly: true }; (function(asyncSymbol) { }).exps = true; } return state.syntax["(identifier)"].nud.apply(this, arguments); this.exps = false; } else { return this; expression(context, 10); } error("E024", this, "await"); if (!state.funct["(params)"]) { // list. // it is because the current expression is contained within the parameter // If the parameters of the current function scope have not been defined, if (context & prodParams.async) { prefix("await", function(context) { }).exps = true; return this; reachable(this); } } nolinebreak(this); // always warn (Line breaking error) ["[", "{", "+", "-"].indexOf(state.tokens.next.id) > -1) { if (state.tokens.next.type === "(punctuator)" && } else { } } warning("W146", this.first); this.first.identifier && this.first.value === "await") { !(context & prodParams.tryClause) && if (state.option.noreturnawait && context & prodParams.async && } warning("W093", this.first); !this.first.paren && !state.option.boss) { this.first.type === "(punctuator)" && this.first.id === "=" && if (this.first && this.first = expression(context, 0); if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { if (sameLine(this, state.tokens.next)) { stmt("return", function(context) { }).exps = true; return this; reachable(this); } } advance(); this.first = state.tokens.next; } warning("W090", state.tokens.next, v); if (!state.funct["(scope)"].funct.hasLabel(v)) { if (sameLine(state.tokens.curr, state.tokens.next)) { if (state.tokens.next.identifier) { } warning("W052", state.tokens.next, this.value); if (state.funct["(breakage)"] === 0 || !state.funct["(loopage)"]) { var v = state.tokens.next.value; stmt("continue", function() { }).exps = true; return this; reachable(this); } warning("W052", state.tokens.next, this.value); if (state.funct["(breakage)"] === 0)ad.B~U8<65 v i E !   W Q , +  y V U  b ; 1  ~ } w 1   c]8k+yx-R5- sIH32!ME#{zB var importSymbol = stmt("import", function(context) { }); return mp; } return state.syntax["(identifier)"].nud.call(this, context); if (!mp) { }); } error("E070", state.tokens.prev); if (!state.option.module) { } warning("W119", state.tokens.prev, "import.meta", "11"); if (!state.inES11(true)) { var mp = metaProperty(context, "meta", function() { prefix("import", function(context) { }).exps = true; return this; reachable(this); this.first = expression(context, 20); nolinebreak(this); stmt("throw", function(context) { }; return this; } nolinebreak(this); // always warn (Line breaking error) } else if (!state.option.asi) { } error("E050", this); (prev.lbp > 30 || (!prev.assign && !isEndOfExpr()))) { if (state.tokens.next.id !== ")" && } } warning("W093", this.first); !this.first.paren && !state.option.boss) { if (this.first.type === "(punctuator)" && this.first.id === "=" && this.first = expression(context, 10); nobreaknonadjacent(state.tokens.curr, state.tokens.next); !state.tokens.next.reach && state.tokens.next.nud)) { (state.tokens.next.id !== ";" && !state.option.asi && if (delegatingYield || if (sameLine(this, state.tokens.next)) { } advance("*"); delegatingYield = true; if (state.tokens.next.id === "*") { var delegatingYield = false; state.funct["(yielded)"] = true; } error("E046", state.tokens.curr, "yield"); if (state.inES6(true) && !(context & prodParams.yield)) { var prev = state.tokens.prev; var mozYield = function(context) { */ * expressions. * Parsing logic for non-standard Mozilla implementation of `yield` /** })); return this; } } } error("W017", state.tokens.next); if (state.tokens.next.id !== ",") { } else if (state.tokens.next.led) { } warning("W093", this.first); !this.first.paren && !state.option.boss) { if (this.first.type === "(punctuator)" && this.first.id === "=" && this.first = expression(context, 10); nobreaknonadjacent(state.tokens.curr, state.tokens.next); if (state.tokens.next.nud) { if (state.tokens.curr.id === "*" || sameLine(state.tokens.curr, state.tokens.next)) { // Parse operand } advance("*"); if (state.tokens.next.id === "*") { state.funct["(yielded)"] = true; } warning("W104", state.tokens.curr, "yield", "6"); if (!state.inES6()) { } error("E061", this); if (!this.beginsStmt && prev.lbp > 30 && !checkPunctuators(prev, ["("])) { } error("E024", this, "yield"); if (!state.funct["(params)"]) { // list. // it is because the current expression is contained within the parameter // If the parameters of the current function scope have not been defined, var prev = state.tokens.prev; } return state.syntax["(identifier)"].nud.apply(this, arguments); this.exps = false; if (!(context & prodParams.yield)) { } return mozYield.call(this, context); if (state.inMoz()) { })(prefix("yield", function(context) { yieldSymbol.exps = true; yieldSymbol.rbp = yieldSymbol.lbp = 25; (function(yieldSymbol) { }))); return state.syntax["(identifier)"].nud.apply(this, arguments); this.exps = false;ad3Py@:9Q* b a 7 O   u ` X R Q ) G  w c R &  xL;uX1038vpT4}|WD5P  } ok = false; error("E053", state.tokens.curr, "Export"); if (!state.funct["(scope)"].block.isGlobal()) { } ok = false; warning("W119", state.tokens.curr, "export", "6"); if (!state.inES6()) { context = context | prodParams.export; var moduleSpecifier; var token; var ok = true; stmt("export", function(context) { }; return !(checkPunctuator(state.tokens.next, ".") && peek().identifier); importSymbol.useFud = function() { importSymbol.meta = { isFutureReservedWord: true, es5: true }; importSymbol.reserved = true; importSymbol.exps = true; }); return this; // } // warning("W142", this, "import", moduleSpecifier); // if (hasBindings) { // TODO: enable this warning in JSHint 3 // constitute a breaking change. // declarations that lack bindings. Issuing a warning would therefor // Support for ES2015 modules was released without warning for `import` advance("(string)"); a error("E024", state.tokens.next, tokenString(state.tokens.nex error("E024", state.tokens.next, tokenString(state.tokens.next)); } else { break; advance("}"); } else if (state.tokens.next.id === "}") { advance(","); if (state.tokens.next.id === ",") { token: state.tokens.curr }); initialized: true, type: "import", state.funct["(scope)"].addbinding(importName, { // Import bindings are immutable (see ES6 8.1.1.5.5) } importName = identifier(context); } else { importName = identifier(context); advance("as"); identifier(context, true); if (peek().value === "as") { var importName; } break; advance("}"); if (state.tokens.next.id === "}") { for (;;) { advance("{"); // ImportClause :: NamedImports } else { } token: state.tokens.curr }); initialized: true, type: "import", state.funct["(scope)"].addbinding(this.name, { // Import bindings are immutable (see ES6 8.1.1.5.5) this.name = identifier(context); if (state.tokens.next.identifier) { advance("as"); advance("*"); // ImportClause :: NameSpaceImport if (state.tokens.next.id === "*") { } } return this; advance("(string)"); advance("from"); } else { // https://github.com/jshint/jshint/pull/2144#discussion_r23978406 // Discussion: // either NameSpaceImport or NamedImports. // At this point, we intentionally fall through to continue matching advance(","); // ImportClause :: ImportedDefaultBinding , NamedImports // ImportClause :: ImportedDefaultBinding , NameSpaceImport if (state.tokens.next.id === ",") { token: state.tokens.curr }); initialized: true, type: "import", state.funct["(scope)"].addbinding(this.name, { // Import bindings are immutable (see ES6 8.1.1.5.5) this.name = identifier(context); // ImportClause :: ImportedDefaultBinding if (state.tokens.next.identifier) { } return this; advance("(string)"); // ModuleSpecifier :: StringLiteral if (state.tokens.next.type === "(string)") { } warning("W119", state.tokens.curr, "import", "6"); if (!state.inES6()) { } error("E053", state.tokens.curr, "Import"); if (!state.funct["(scope)"].block.isGlobal()) {ad$lbNMq,$#  - v 8 x ] @ j P 3 ~ c I  qiVP(]8]6wiTC#nd\Hv_2RA  return this; } } warning("W141", this, "export"); } else { warning("W142", this, "export", moduleSpecifier.value); if (moduleSpecifier) { if (exportedTokens.length === 0) { } }); state.funct["(scope)"].setExported(x.local, x.export); exportedTokens.forEach(function(x) { } else if (ok) { advance("(string)"); moduleSpecifier = state.tokens.next; advance("from"); // ExportDeclaration :: export ExportClause FromClause if (state.tokens.next.value === "from") { advance("}"); } } advance(","); if (!checkPunctuator(state.tokens.next, "}")) { } }); export: state.tokens.curr local: state.tokens.curr, exportedTokens.push({ } else { advance(); }); export: state.tokens.next local: state.tokens.prev, exportedTokens.push({ } error("E030", state.tokens.next, state.tokens.next.value); /* istanbul ignore next */ if (!state.tokens.next.identifier) { advance("as"); if (state.tokens.next.value === "as") { advance(); } error("E030", state.tokens.next, state.tokens.next.value); /* istanbul ignore next */ if (!state.tokens.next.identifier) { while (!checkPunctuator(state.tokens.next, "}")) { var exportedTokens = []; advance("{"); // ExportDeclaration :: export ExportClause if (state.tokens.next.id === "{") { } return this; } state.funct["(scope)"].setExported(null, def); expression(context, 10); } else { state.funct["(scope)"].setExported(token.name, def); token = state.syntax["class"].fud(context); advance("class"); this.block = true; } else if (exportType === "class") { state.funct["(scope)"].setExported(token.name, def); token = state.syntax["function"].fud(context | prodParams.preAsync); advance("function"); advance("async"); this.block = true; } else if (exportType === "async" && peek().id === "function") { state.funct["(scope)"].setExported(token.name, def); token = state.syntax["function"].fud(context); advance("function"); this.block = true; if (exportType === "function") { var exportType = state.tokens.next.id; var def = state.tokens.curr; advance("default"); state.nameStack.set(state.tokens.next); // see https://bocoup.com/blog/whats-in-a-function-name // because the 'name' of a default-exported function is, confusingly, 'default' // export default ClassDeclaration // export default HoistableDeclaration // export default [lookahead ∉ { function, class }] AssignmentExpression[In] ; // ExportDeclaration :: if (state.tokens.next.type === "default") { } return this; advance("(string)"); advance("from"); } state.funct["(scope)"].setExported(null, state.tokens.curr); identifier(context, true); advance("as"); } warning("W119", state.tokens.curr, "export * as ns from", "11"); if (!state.inES11()) { if (state.tokens.next.value === "as") { advance("*"); // ExportDeclaration :: export * as IdentifierName FromClause // ExportDeclaration :: export * FromClause if (state.tokens.next.id === "*") {adoT&v`2 R : ` /  5  m + d "  2oJE-'nhg4~}_=<V91$y[=rS5 FutureReservedWord("implements", { es5: true, strictOnly: true }); FutureReservedWord("goto"); FutureReservedWord("float"); FutureReservedWord("final"); FutureReservedWord("extends", { es5: true }); FutureReservedWord("export", { es5: true }); FutureReservedWord("enum", { es5: true }); FutureReservedWord("double"); FutureReservedWord("char"); FutureReservedWord("byte"); FutureReservedWord("boolean"); FutureReservedWord("abstract"); // Future Reserved Words }; return this; } error("E024", next, tokenString(next)); } else { } error("E064", this); if (!supportsSuper("call", state.funct)) { } else if (checkPunctuator(next, "(")) { } error("E063", this); if (!supportsSuper("property", state.funct)) { if (checkPunctuators(next, ["[", "."])) { var next = state.tokens.next; var superNud = function() { } return false; } return supportsSuper(type, funct["(context)"]); if (funct["(arrow)"]) { } return true; funct["(statement)"].id === "class") { if (type === "call" && funct["(statement)"] && } return true; if (type === "property" && funct["(method)"]) { } return false; if (type === "call" && funct["(async)"]) { function supportsSuper(type, funct) { */ * @returns {boolean} * * context * @param {object} funct - a "functor" object describing the current function * @param {string} type - one of "property" or "call" * * (as described by the provided "functor" object). * Determine if SuperCall or SuperProperty may be used in the current context /** }).exps = true; return this; } error("E024", state.tokens.next, state.tokens.next.value); /* istanbul ignore next */ } else { state.funct["(scope)"].setExported(token.name, token.name); token = state.syntax["class"].fud(context); advance("class"); this.block = true; // ExportDeclaration :: export Declaration } else if (state.tokens.next.id === "class") { state.funct["(scope)"].setExported(token.name, token.name); token = state.syntax["function"].fud(context | prodParams.preAsync); advance("function"); advance("async"); this.block = true; // ExportDeclaration :: export Declaration } else if (state.tokens.next.id === "async" && peek().id === "function") { state.funct["(scope)"].setExported(token.name, token.name); token = state.syntax["function"].fud(context); advance("function"); this.block = true; // ExportDeclaration :: export Declaration } else if (state.tokens.next.id === "function") { }); state.funct["(scope)"].setExported(binding, binding); token.first.forEach(function(binding) { token = state.tokens.curr.fud(context); advance("const"); // ExportDeclaration :: export VariableStatement } else if (state.tokens.next.id === "const") { }); state.funct["(scope)"].setExported(binding, binding); token.first.forEach(function(binding) { token = state.tokens.curr.fud(context); advance("let"); // ExportDeclaration :: export VariableStatement } else if (state.tokens.next.id === "let") { }); state.funct["(scope)"].setExported(binding, binding); token.first.forEach(function(binding) { token = state.tokens.curr.fud(context); advance("var"); // ExportDeclaration :: export VariableStatement } else if (state.tokens.next.id === "var") {addaX9 :  m 2   } O 4 l L 0 !  v e @ "   pkjd{1 S&qk SnhgJ+'& J * class to which the current accessor is being * @param {object} props - a collection of all properties of the object or * @param {string} accessorType - Either "get" or "set" * * and class bodies. Produce warnings in response to duplicated names. * Update an object used to track property names within object initializers /** } props[key].basictkn = tkn; props[key].basic = true; } props[key] = Object.create(null); } else { warning("W075", state.tokens.next, msg, name); msg = msg[(isClass || false) + (isStatic || false)]; var msg = ["key", "class method", "static class method"]; if (props[key] && name !== "__proto__" && !isComputed) { } key = "static " + name; if (isClass && isStatic) { var key = name; } name = tkn.value; if (tkn.identifier) { function saveProperty(props, name, tkn, isClass, isStatic, isComputed) { */ * @param {boolean} [isComputed] - whether the property is a computed expression like [Symbol.iterator] * @param {boolean} [isStatic] - whether the accessor is a static method * definition * @param {boolean} [isClass] - whether the accessor is part of an ES6 Class * @param {object} tkn - the token defining the property * @param {string} name - the property name * assigned * class to which the current property is being * @param {object} props - a collection of all properties of the object or * * and class bodies. Produce warnings in response to duplicated names. * Update an object used to track property names within object initializers /** }; return ret; } while (bracketStack > 0 && pn.id !== "(end)"); } ret.notJson = true; if (checkPunctuator(pn, ";")) { } } break; ret.notJson = true; } else if (pn1.id === ".") { break; ret.notJson = true; ret.isDestAssign = true; if (pn1.id === "=") { if (bracketStack === 0 && checkPunctuators(pn, ["}", "]"])) { } break; ret.notJson = true; ret.isCompArray = true; !checkPunctuator(prev, ".")) { if (bracketStack === 1 && pn.identifier && pn.value === "for" && } bracketStack -= 1; } else if (checkPunctuators(pn, ["]", "}"])) { bracketStack += 1; if (checkPunctuators(pn, ["[", "{"])) { i = i + 1; pn1 = peek(i + 1); pn = i === -1 ? state.tokens.next : peek(i); prev = i === -1 ? state.tokens.curr : pn; do { } bracketStack += 1; if (checkPunctuators(state.tokens.curr, ["[", "{"])) { var ret = {}; var bracketStack = 0; var i = -1; var pn, pn1, prev; var lookupBlockType = function() { // expression is a comprehension array, destructuring assignment or a json value. // this function is used to determine whether a squarebracket or a curlybracket FutureReservedWord("volatile"); FutureReservedWord("transient"); FutureReservedWord("synchronized"); FutureReservedWord("static", { es5: true, strictOnly: true }); FutureReservedWord("short"); FutureReservedWord("public", { es5: true, strictOnly: true }); FutureReservedWord("protected", { es5: true, strictOnly: true }); FutureReservedWord("private", { es5: true, strictOnly: true }); FutureReservedWord("package", { es5: true, strictOnly: true }); FutureReservedWord("native"); FutureReservedWord("long"); FutureReservedWord("interface", { es5: true, strictOnly: true }); FutureReservedWord("int");adp<q& ~ } g   x g P F   w q m l f  o j  _ 1 G5#y, {R'!  fC?>p*eB } warning("W104", state.tokens.curr, "destructuring assignment", "6"); /* istanbul ignore next */ if (!state.inES6() && block.isDestAssign) { if (block.notJson) { var block = lookupBlockType(); // or it's not a block, but there are assignments, check for undeclared variables // if it has semicolons, it is a block, so go parse it as a block // lookup for the assignment (ECMAScript 6 only) function destructuringAssignOrJsonValue(context) { // Check whether this function has been reached for a destructuring assign with undeclared values } return token.type === "(punctuator)" && token.id === id; function checkPunctuator(token, id) { */ * @returns {boolean} * * @param {string} id * @param {Token} token * * false positives. * property so that like-valued string literals (e.g. `";"`) do not produce * the specified value. This function explicitly verifies the token's `type` * Test whether a given token is a punctuator whose `value` property matches /** } return false; } return _.includes(values, token.id); if (token.type === "(punctuator)") { function checkPunctuators(token, values) { */ * @returns {boolean} * * @param {Array.} values * @param {Token} token * * produce false positives. * `type` property so that like-valued string literals (e.g. `";"`) do not * one of the specified values. This function explicitly verifies the token's * Test whether a given token is a punctuator whose `value` property matches /** } return value; advance("]"); var value = expression(context & ~prodParams.noin, 10); } warning("W119", state.tokens.curr, "computed property names", "6"); if (!state.inES6()) { state.tokens.curr.lbp = 0; state.tokens.curr.delim = true; // interpretation as an "infix" operator. // Explicitly reclassify token as a delimeter to prevent its later advance("["); function computedPropertyName(context) { */ * defines the property name * @returns {object} - the token value that describes the expression which * * @param {number} context - the parsing context * * }; * [object.method()]: null * void { * * as introduced by ES2015. For example: * Parse a computed property name within object initializers and class bodies /** } } props[key].static = true; if (isStatic) { props[key][flagName] = tkn; } props[key] = Object.create(null); } else { } warning("W075", state.tokens.next, msg, name); } msg = "key"; } else { msg += accessorType + "ter method"; } msg += "static "; if (isStatic) { if (isClass) { var msg = ""; if ((props[key].basic || props[key][flagName]) && name !== "__proto__") { if (props[key]) { } key = "static " + name; if (isClass && isStatic) { state.nameStack.set(tkn); state.tokens.curr.accessorType = accessorType; var key = name; var flagName = accessorType === "get" ? "getterToken" : "setterToken"; function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) { */ * @param {boolean} [isStatic] - whether the accessor is a static method * definition * @param {boolean} [isClass] - whether the accessor is part of an ES6 Class * @param {object} tkn - the identifier token representing the accessor name * assignedad$mub\XWQ|w2 b A (  ^ ? "   c 6  z t S - P 7 f PxZH:!gH h%[m' } return true; } state.funct["(scope)"].block.use(v, state.tokens.curr); /* istanbul ignore next */ // if not we warn about it if (use(v)) { // we check whether current variable has been declared } else if (_current && _current.mode === "filter") { // When we are in "filter" state, return true; state.funct["(scope)"].block.use(v, state.tokens.curr); } else if (_current && _current.mode === "generate") { // When we are in the "generate" state of the list comp, return true; } }); unused: true undef: false, value: v, token: state.tokens.curr, _current.variables.push({ if (!declare(v)) { // check if the variable has been used previously } else if (_current && _current.mode === "define") { // When we are in "define" state of the list comp, return true; } }); unused: false undef: true, value: v, token: state.tokens.curr, _current.variables.push({ if (use(v)) { if (_current && _current.mode === "use") { // When we are in "use" state of the list comp, we enqueue that var } return; if (!_current) { check: function(v) { }, _current.mode = s; if (_.includes(["use", "define", "generate", "filter"], s)) setState: function(s) { }, _current = _carrays[_carrays.length - 1]; _carrays.splice(-1, 1); }); state.funct["(scope)"].block.use(v.value, v.token); if (v.undef) warning("W098", v.token, v.token.raw_text || v.value); if (v.unused) _current.variables.filter(function(v) { unstack: function() { }, _carrays.push(_current); _current = new CompArray(); return { stack: function() { } return (l === 0); // otherwise we warn about it }).length; } return v; } elt.unused = false; if (elt.unused === true) { if (elt.value === v && !elt.undef) { // and if it has been defined var l = _current.variables.filter(function(elt) { function use(v) { } return l !== 0; }).length; } return v; elt.undef = false; if (elt.value === v) { // if it has, change its undef state var l = _current.variables.filter(function(elt) { function declare(v) { var _current; var _carrays = []; }; this.variables = []; this.mode = "use"; var CompArray = function() { var arrayComprehension = function() { */ * - "filter" - which will help filter out values * comprehension * - "define" - which will define the variables local to the list * comprehension * - "use" - which will be the returned iterative part of the list * * comprehension scope only. The order of the states are as follows: * avoid defining global variables, but keeping them to the list * Parse and define the three states of a list comprehension in order to /** } } jsonValue(); state.jsonMode = true; state.option.laxbreak = true; } else { // otherwise parse json value statements(context);ad)5|rmWQ8p: _ # I  E 2  r f N D < ( " !  b , QE.xjVI;( }bUH Jxr; cb32u;65 }; return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); var escapeRegex = function(str) { } } } JSHINT.errors[jdx].line += internal.token.line - 1; for (jdx = priorErrorCount; jdx < JSHINT.errors.length; jdx += 1) { itself(internal.code, options, globals); priorErrorCount = JSHINT.errors.length; options.scope = internal.elem; internal = internals[idx]; for (idx = 0; idx < internals.length; idx += 1) { var priorErrorCount, idx, jdx, internal; function lintEvalCode(internals, options, globals) { */ * @param {object} globals - globally-defined bindings for the evaluated code * @param {object} options - linting options to apply * string tokens that contain evaluated code * @param {array} internals - collection of "internals" objects describing * * into the global `errors` array. * Lint dynamically-evaluated code, appending any resulting errors/warnings /** } } error("E003", state.tokens.next); default: break; advance("(number)"); advance("-"); case "-": break; advance(); case "(string)": case "(number)": case "null": case "false": case "true": break; jsonArray(); case "[": break; jsonObject(); case "{": switch (state.tokens.next.id) { } advance("]"); } } advance(","); } break; if (state.tokens.next.id !== ",") { jsonValue(); } error("E028", state.tokens.next); } else if (state.tokens.next.id === ",") { break; warning("W094", state.tokens.curr); } else if (state.tokens.next.id === "]") { error("E027", state.tokens.next, t.line); if (state.tokens.next.id === "(end)") { for (;;) { if (state.tokens.next.id !== "]") { advance("["); var t = state.tokens.next; function jsonArray() { } advance("}"); } } advance(","); } break; if (state.tokens.next.id !== ",") { jsonValue(); advance(":"); advance(); } o[state.tokens.next.value] = true; } else { warning("W096", state.tokens.next, state.tokens.next.value); !state.option.iterator)) { !state.option.proto) || (state.tokens.next.value === "__iterator__" && } else if ((state.tokens.next.value === "__proto__" && warning("W075", state.tokens.next, "key", state.tokens.next.value); if (o[state.tokens.next.value] === true) { } warning("W095", state.tokens.next, state.tokens.next.value); } else if (state.tokens.next.id !== "(string)") { error("E028", state.tokens.next); } else if (state.tokens.next.id === ",") { break; warning("W094", state.tokens.curr); } else if (state.tokens.next.id === "}") { error("E026", state.tokens.next, t.line); if (state.tokens.next.id === "(end)") { for (;;) { if (state.tokens.next.id !== "}") { advance("{"); var o = {}, t = state.tokens.next; function jsonObject() { function jsonValue() { */ * http://json.org/ * * Parse input according to the JSON format. /** }; }; } return false; /* istanbul ignore next */ad\baM:{^?98 7 6   r q >  ^ 8 % X 9 / .  z B 1  yxD{:21iM%q\HGyxV+"!\ ld]\ }; } }.bind(this)); emitter.on(name, listener); names.split(" ").forEach(function(name) { on: function(names, listener) { }, warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); warn: function(code, data) { }, state.cache[name] = value; setCache: function(name, value) { }, return state.cache[name]; getCache: function(name) { }, return state.option[name] || null; getOption: function(name) { }, return state.jsonMode; /* istanbul ignore next */ get isJSON() { api = { } return false; errorAt("E004", 0); if (!isString(s) && !Array.isArray(s)) { lookahead = []; inblock = false; membersOnly = null; member = {}; functions = [state.funct]; }); "(metrics)" : createMetrics(state.tokens.next) "(comparray)" : arrayComprehension(), "(scope)" : scopeManagerInst, "(global)" : true, state.funct = functor("(global)", null, { }); error.apply(null, [ ev.code, ev.token ].concat(ev.data)); /* istanbul ignore next */ scopeManagerInst.on("error", function(ev) { }); warning.apply(null, [ ev.code, ev.token].concat(ev.data)); scopeManagerInst.on("warning", function(ev) { var scopeManagerInst = scopeManager(state, predefined, exported, declared); indent = 1; state.option.maxerr = state.option.maxerr || 50; state.option.indent = state.option.indent || 4; state.ignored = newIgnoredObj; state.option = newOptionObj; } } } newOptionObj[optionKey] = o[optionKey]; var optionKey = optionKeys[x]; } else { newIgnoredObj[optionKeys[x].slice(1)] = true; if (/^-W\d{3}$/g.test(optionKeys[x])) { for (x = 0; x < optionKeys.length; x++) { optionKeys = Object.keys(o); delete o.exported; delete o.predef; }); exported[item] = true; each(o.exported || null, function(item) { }); }); } predefined[item] = prop ? prop.value : false; prop = Object.getOwnPropertyDescriptor(dict, item); } else { delete predefined[slice]; // remove from predefined if there JSHINT.blacklist[slice] = slice; slice = item.slice(1); if (item[0] === "-") { var slice, prop; each(dict, function(item) { each([o.predef, o.globals], function(dict) { if (o) { } obj.forEach(cb); obj = Object.keys(obj); if (!Array.isArray(obj) && typeof obj === "object") return; if (!obj) function each(obj, cb) { var exported = Object.create(null); // Variables that live outside the current file declared = Object.create(null); combine(predefined, vars.reservedVars); combine(predefined, vars.ecmaIdentifiers[3]); predefined = Object.create(null); } JSHINT.scope = "(main)"; JSHINT.blacklist = {}; JSHINT.internals = []; JSHINT.errors = []; } else { JSHINT.scope = o.scope; if (o && o.scope) { newIgnoredObj = state.ignored; newOptionObj = state.option; state.reset(); o = _.clone(o); var optionKeys, newOptionObj, newIgnoredObj; var x, reIgnoreStr, reIgnore; var itself = function(s, o, g) { // The actual JSHINT function itself.ad x9K j i 7 6  ~ . & %  o g f >    z r q \ N 8  N D < 6 5 +   sra;+d(ihT%]2b= \[H+yx } data.errors = itself.errors; if (itself.errors.length) { var fu, f, i, n, globals; }; options: state.option functions: [], var data = { itself.data = function() { // Data summary. itself.addModule(style.register); }; extraModules.push(func); itself.addModule = function(func) { // Modules. }; return JSHINT.errors.length === 0; } lintEvalCode(JSHINT.internals, o || {}, g); if (JSHINT.scope === "(main)") { // Loop over the listed "internals", and check them as well. } } throw err; /* istanbul ignore next */ } else { }); character : err.character || nt.from line : err.line || nt.line, reason : err.reason, code : err.code, raw : err.raw, scope : "(main)", JSHINT.errors.push({ var nt = state.tokens.next || {}; if (err && err.name === "JSHintError") { } catch (err) { state.funct["(scope)"].unstack(); } quit("E041", state.tokens.curr); if (state.tokens.next.id !== "(end)") { } statements(0); } } warning("W097", state.directive["use strict"]); if (!state.allowsGlobalUsd()) { if (state.directive["use strict"]) { directives(); default: break; destructuringAssignOrJsonValue(0); case "[": case "{": switch (state.tokens.next.id) { advance(); checkComma.first = true; //reset values combine(predefined, g || {}); // combine the passed globals after we've assumed all our options applyOptions(); try { } } } checkOption(name, false, state.tokens.curr); if (_.has(o.unstable, name)) { for (name in o.unstable) { if (o) { } } checkOption(name, true, state.tokens.curr); if (_.has(o, name)) { for (name in o) { var name; // Check options }); emitter.emit("Number", ev); lex.on("Number", function(ev) { }); emitter.emit("String", ev); lex.on("String", function(ev) { }); emitter.emit("Identifier", ev); lex.on("Identifier", function(ev) { }); quit("E041", ev); lex.on("fatal", function(ev) { }); errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); lex.on("error", function(ev) { }); warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); lex.on("warning", function(ev) { lex = new Lexer(s); } }); }); return match.replace(/./g, " "); s = s.replace(reIgnore, function(match) { reIgnore = new RegExp(reIgnoreStr, "ig"); escapeRegex(delimiterPair.end); "[\\s\\S]*?" + reIgnoreStr = escapeRegex(delimiterPair.start) + return; if (!delimiterPair.start || !delimiterPair.end) o.ignoreDelimiters.forEach(function(delimiterPair) { } o.ignoreDelimiters = [o.ignoreDelimiters]; /* istanbul ignore next */ if (!Array.isArray(o.ignoreDelimiters)) { if (o && o.ignoreDelimiters) { state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; }); func(api); (extraModules || []).forEach(function(func) { emitter.removeAllListeners();ad ;a<\D54 g f Q  Z <    h g V P O $ } exports.JSHINT = JSHINT;if (typeof exports === "object" && exports) {// Make JSHINT a Node module, if possible.}()); return itself; itself.jshint = itself; }; return data; } } break; data.member = member; if (typeof member[n] === "number") { for (n in member) { } data.unused = unuseds; if (unuseds.length > 0) { var unuseds = state.funct["(scope)"].getUnuseds(); } data.functions.push(fu); }; statements: f["(metrics)"].statementCount parameters: f["(metrics)"].arity, complexity: f["(metrics)"].ComplexityCount, fu.metrics = { fu.lastcharacter = f["(lastcharacter)"]; fu.last = f["(last)"]; fu.character = f["(character)"]; fu.line = f["(line)"]; fu.param = f["(params)"]; fu.name = f["(name)"]; fu = {}; f = functions[i]; for (i = 1; i < functions.length; i += 1) { } data.globals = globals; if (globals.length > 0) { globals = state.funct["(scope)"].getUsedOrDefinedGlobals(); } data.implieds = impliedGlobals; if (impliedGlobals.length > 0) { var impliedGlobals = state.funct["(scope)"].getImpliedGlobals(); } data.json = true; /* istanbul ignore next */ if (state.jsonMode) {ad;|vu^ZYS}x=8 b N H G ) e +   O  E ?  t s '  // should not be consumed in this way so that the parser interprets it as // can continue as though an identifier were found. The semicolon token // The token should be consumed after a warning is issued so the parser error("E030", state.tokens.next, tokenString(state.tokens.next)); } return i; if (i) { var i = optionalidentifier(context, isName, false); function identifier(context, isName) { */ * @returns {string|undefined} - the value of the identifier, if present * * (e.g. object properties) * @param {boolean} [isName] - `true` if an IdentifierName should be consumed * more information * @param {number} context - the parsing context; see `prod-params.js` for * * Ensure that the current token is an identifier and retrieve its value. /** } return true; } } advance(); while (checkPunctuator(state.tokens.next, "...")) { warning("E024", state.tokens.next, "..."); if (checkPunctuator(state.tokens.next, "...")) { advance(); } warning("W119", state.tokens.next, operation + " operator", "6"); if (!state.inES6(true)) { } return false; if (!checkPunctuator(state.tokens.next, "...")) { function spreadrest(operation) { */ * consumed in this way * @returns {boolean} a value describing whether or not any tokens were * * @param {string} operation - either "spread" or "rest" * * issue a single error describing the syntax error. * it is present. If the operator is repeated, consume every repetition, and * Consume the "..." token which designates "spread" and "rest" operations if /** } return curr.value; } warning("W024", state.tokens.curr, state.tokens.curr.id); if (isReserved(context, curr) && !(isName && state.inES5())) {ad*[\TNM"kB:9 | { R   f a G B * $  m L ,   q ^ X W 2 L hbaOKJD[D>=t* * Short * Short for "first null denotation," it it similar to the `nud` ("null * based on the Pratt parser, but it extends that model with a `fud` method. * The `expression` function is the heart of JSHint's parsing behaior. It is /** } return String(token.value); } return token.id; if (token.type === "(punctuator)") { function tokenString(token) { */ * @returns {string} * * @param {token} token * * messages. * Return a string representation of a given token, suitable for use in error /** } return false; } return !sameLine(curr, next); (curr.id === "yield" && curr.rbp < next.rbp)) { // `yield` is followed by a newline and a `[` token). // followed by a newline and a comma operator (without enabling it when // effect, this prevents automatic semicolon insertion when `yield` is // of the current expression if allowed by the syntactic grammar. In // Infix operators which follow `yield` should only be consumed as part if (next.infix === curr.infix || } return true; if (next.id === ";" || next.id === "}" || next.id === ":") { } return true; if (next.id === "in" && context & prodParams.noin) { } next = state.tokens.next; curr = state.tokens.curr; if (arguments.length <= 1) { function isEndOfExpr(context, curr, next) { } return token.first || token.right || token.left || token.id === "yield" || token.id === "await"; function isOperator(token) { */ * @returns {boolean} * * @param {token} token * * Determine whether a given token is an operator. /** } } } } break; if (state.tokens.next.id !== "(endline)") { } else { lintingDirective(state.tokens.next, state.tokens.curr); if (state.tokens.next.isSpecial) { } state.tokens.next.check(); if (state.tokens.next.check) { } return; if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { } quit("E041", state.tokens.curr); if (!state.tokens.next) { // No more tokens left, give up state.tokens.next = lookahead.shift() || lex.token(); for (;;) { state.tokens.curr = state.tokens.next; state.tokens.prev = state.tokens.curr; } } error("E021", nextToken, expected, tokenString(nextToken)); } else if (nextToken.type !== "(identifier)" || nextToken.value !== expected) { }adiidqc_^X g  Y  } 1   > u * A;iR?>0,+%ca;6u[G3 pLD~plke  * * @param {string} s - the name of the symbol * * functions. * Convenience function for defining the `=>` token as used in arrow /** } return x; }; } return this; this.right = expression(context, p); this.left = left; } else { return f(context, left, this); if (typeof f === "function") { } warning("W018", left, "!"); if ((s === "in" || s === "instanceof") && left.id === "!") { } nobreaknonadjacent(state.tokens.prev, state.tokens.curr); if (!w) { x.led = function(context, left) { x.infix = true; reserveName(x); var x = symbol(s, p); function infix(s, f, p, w) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * @param {boolean} [w] - if `true` * Pratt parsing semantics * @param {number} p - the left-binding power of the token as used by the * right-hand side of the operator * @param {function} [f] - a function to be invoked that consumes the * @param {string} s - the name of the symbol * * operands as both "land-hand side" and "right-hand side". * Convenience function for defining "infix" symbols--operators that require /** } return x; x.meta = meta; x.reserved = true; x.identifier = true; x.value = name; meta.isFutureReservedWord = true; meta = meta || {}; var x = type(name, state.syntax["(identifier)"].nud); function FutureReservedWord(name, meta) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * reserved in strict mode code. * @param {boolean} [meta.strictOnly] - `true` if the identifier is only * in ECMAScript 5 or later * @param {boolean} [meta.es5] - `true` if the identifier is reserved * see the `expression` function for more detail * @param {function} [meta.nud] -the null denotation function for the symbol; * @param {object} [meta] - a collection of optional arguments * @param {string} name - the name of the symbol * * only reserved in some circumstances. * Convenience function for defining JSHint symbols for keywords that are /** } return x; x.reserved = true; x.identifier = true; var x = type(name, func); function reserve(name, func) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * detail * symbol; see the `expression` function for more * @param {function} func - the first null denotation function for the * @param {string} s - the name of the symbol * * names in ECMAScript 3 environments). * keywords--those that are restricted from use as bindings (and as property * Convenience function for defining JSHint symbols for reserved /** } return x; x.nud = f; x.type = s; var x = symbol(s, 0); function type(s, f) { */ * support cases where further refinement is necessary) * @returns {object} - the object describing the JSHint symbol (provided to * * see the `expression` function for more detail * @param {function} f - the first null denotation function for the symbol;ad+yR?,]O" r ^ J 6 " } f O 8 ! g T A  } | I 4  l : pb ymlZPO(^d_qZY F`XW?1+ } j += 1; lookahead[j] = t; } return lookahead[j - 1]; } return state.tokens.next; if (!lookahead.length) { // available as the next token. // already emitted by the most recent invocation of `advance` and is // If the lookahead buffer is empty, the expected "(end)" token was if (!t) { // the input stream. // token, even in cases where the requested token is beyond the end of // When the lexer is exhausted, this function should produce the "(end)" t = lex.token(); while (j <= i) { } return lookahead[i]; if (i < j) { var i = p || 0, j = lookahead.length, t; function peek(p) { */ * @returns {token} * * @param {number} [p] - offset of desired token; defaults to 0 * * for ( var i = ... * * versus: * * for ( var i in ... * * e.g.: * does not provide sufficient information, as is the case with `for` loops, * determine parsing strategies in cases where the value of the next token * such token exists, return the "(end)" token. This function is used to * Return a token beyond the token available in `state.tokens.next`. If no /** } } applyOptions(); }); error("E002", directiveToken); } return; } state.option[key] = (val === "true"); } else { state.option.unstable[key] = (val === "true"); /* istanbul ignore next */ } else if (directiveToken.type === "jshint.unstable") { } state.option[tn] = !state.option[tn]; if (options.inverted[tn] !== undefined) { state.option[tn] = (val === "true"); tn = options.renamed[key] || key; if (directiveToken.type === "jslint") { if (val === "true" || val === "false") { var tn; } return; state.ignored[match[2]] = (match[1] === "-"); // ignore for -W..., unignore for +W... if (match) { var match = /^([+-])(W\d{3})$/g.exec(key); } return; } error("E055", directiveToken, "esversion"); if (!hasParsedCode(state.funct)) { } error("E002", directiveToken); default: break; state.option.esversion = +val - 2009; // Translate specification publication year to version number. state.option.moz = false; case "2020": case "2019": case "2018": case "2017": case "2016": case "2015": break; state.option.esversion = +val; state.option.moz = false; case "11": case "10": case "9": case "8": case "7": case "6": case "5": case "3": switch (val) { if (key === "esversion") { } } error("E055", directiveToken, "module"); if (!hasParsedCode(state.funct)) { */ * TODO: Extend this restriction to *all* "environmental" options. /** if (key === "module") { } return; } error("E002", directiveToken); default: break; state.option.strict = val; case "implied": case "global": break; state.option.strict = false; case "false":ad[~E=76  f ^ X W 9  z t s S *  i c b >  { T N M 0   i @  nE?>WQP4 {uqpQ,jMmlWSR-ZCB! msg = messages.errors[code]; } else if (/E\d{3}/.test(code)) { msg = messages.warnings[code]; return; if (state.ignored[code]) if (/^W\d{3}$/.test(code)) { var ch, l, w, msg; function warning(code, t, a, b, c, d) { } JSHINT.errors = _.reject(JSHINT.errors, function(err) { return ignored[err.line] }); if (_.isEmpty(ignored)) return; var ignored = state.ignoredLines; function removeIgnoredMessages() { } throw exception; "% scanned)."; exception.reason = supplant(message, exception) + " (" + percentage + }; b: b a: a, code: code, raw: message, message: message + " (" + percentage + "% scanned).", character: token.from, line: token.line, name: "JSHintError", var exception = { var message = messages.errors[code].desc; var percentage = Math.floor((token.line / state.lines.length) * 100); function quit(code, token, a, b) { // Produce an error warning. } } combine(predefined, vars.mocha); if (state.option.mocha) { } combine(predefined, vars.yui); if (state.option.yui) { } combine(predefined, vars.wsh); if (state.option.wsh) { } combine(predefined, vars.worker); if (state.option.worker) { } combine(predefined, vars.mootools); if (state.option.mootools) { } combine(predefined, vars.jquery); if (state.option.jquery) { } combine(predefined, vars.jasmine); if (state.option.jasmine) { } combine(predefined, vars.nonstandard); if (state.option.nonstandard) { } combine(predefined, vars.browserify); combine(predefined, vars.typed); combine(predefined, vars.browser); if (state.option.browserify) { } combine(predefined, vars.typed); combine(predefined, vars.browser); if (state.option.browser) { } combine(predefined, vars.dojo); if (state.option.dojo) { } combine(predefined, vars.devel); if (state.option.devel) { } combine(predefined, vars.typed); combine(predefined, vars.node); if (state.option.node) { } combine(predefined, vars.prototypejs); if (state.option.prototypejs) { } combine(predefined, vars.phantom); if (state.option.phantom) { } combine(predefined, vars.typed); if (state.option.typed) { } combine(predefined, vars.node); combine(predefined, vars.shelljs); if (state.option.shelljs) { } combine(predefined, vars.rhino); if (state.option.rhino) { } combine(predefined, vars.qunit); if (state.option.qunit) { } combine(predefined, vars.couch); if (state.option.couch) { } } warning("W134", state.tokens.next, "regexpu", 6); if (!state.inES6()) { */ * TODO: Extend this restriction to *all* ES6-specific options. /** if (state.option.regexpu) { } } warning("W134", state.tokens.next, "module", 6); if (!state.inES6()) { */ * TODO: Extend this restriction to *all* ES6-specific options. /** if (state.option.module) { } quit("E059", state.tokens.next, "strict", "globalstrict"); if (state.option.strict === "global" && "globalstrict" in state.option) { */ * `globalstrict` because both `true` and `false` should trigger an error.ad $ IA@N%$ s N M ' u o n $ // Don't clear and let it propagate out if it is "break", "return" or } state.funct["(scope)"].unstack(); } error("E048", a[0], a[0].id[0].toUpperCase() + a[0].id.slice(1)); !(supportsFnDecl && a[0].id === "function")) { if (a[0] && a[0].declaration && indent -= state.option.indent; a = [statement(context)]; // test indentation only if statement is in new line indent += state.option.indent; state.tokens.next.inBracelessBlock = true; state.tokens.curr.id === "else"; var supportsFnDecl = state.funct["(verb)"] === "if" || // of IfStatements. // where function declarations are permitted in the statement positions // JSHint observes Annex B of the ECMAScript specification by default, } warning("W116", state.tokens.next, "{", tokenString(state.tokens.next)); if (!stmt || state.option.curly) { state.funct["(scope)"].stack(); } else { }ad ! rZE0ym\C ^ ! if (state.option.newcap && (i < "A" || i > "Z") && i = c.value.substr(0, 1); default: break; case "this": case "RegExp": case "Date": break; } warning("W054"); if (!state.option.evil) { case "Function": break; } warning("W053", state.tokens.prev, c.value); if (state.inES6()) { case "Symbol": break; warning("W053", state.tokens.prev, c.value); case "JSON": case "Math": case "Boolean": case "String": case "Number": switch (c.value) { if (c.identifier) { if (c && c.id !== "function") { }ady Bw[1 } state.funct["(scope)"].initialize(t.id); t = tokens[t]; if (tokens.hasOwnProperty(t)) { for (t in tokens) { if (state.tokens.next.value !== "in" && state.tokens.next.value !== "of") { // statement parsing logic includes // statements. As with `const` initializers (described above), the `for` // Bindings are not immediately initialized in for-in and for-of } } } destructuringPatternMatch(names, value); if (!lone) { }adh zpY910 p + # u Q  } u e _ ^ 0   n h g >  v a A  oGxrqG(ydI7aN%v^5C% } warning("W086", state.tokens.curr, "case"); if (!state.tokens.curr.caseFallsThrough) { // the next `case`. // adding a comment /* falls through */ on a line just before // You can tell JSHint that you don't use break intentionally by default: break; } warning("W145", state.tokens.next); if (state.option.leanswitch) { case "default": break; case "throw": case "switch": case "return": case "continue": case "case": case "break": case "yield": switch (state.funct["(verb)"]) { case "case": switch (state.tokens.next.id) { for (;;) { indent += state.option.indent; if (!noindent) noindent = true; if (state.tokens.next.from === indent) state.funct["(scope)"].stack(); advance("{"); t = state.tokens.next; advance(")", t); checkCondAssignment(expression(context, 0)); advance("("); state.funct["(breakage)"] += 1; var seenCase = false; var noindent = false; var g = false; var t = state.tokens.next; blockstmt("switch", function(context) { }); return this; block(context, true, true); advance(")", t); expression(context, 0); advance("("); } warning("W085", state.tokens.curr); } else if (!state.option.withstmt) { error("E010", state.tokens.curr); if (state.isStrict()) { var t = state.tokens.next; blockstmt("with", function(context) { }).labelled = true; return this; state.funct["(loopage)"] -= 1; state.funct["(breakage)"] -= 1; block(context, true, true); advance(")", t); checkCondAssignment(expression(context, 0)); advance("("); increaseComplexityCount(); state.funct["(loopage)"] += 1; state.funct["(breakage)"] += 1; var t = state.tokens.next; blockstmt("while", function(context) { }); return this; } error("E021", state.tokens.next, "catch", tokenString(state.tokens.next)); if (!b) { } return; block(context, true); advance("finally"); if (state.tokens.next.id === "finally") { } b = true; } hasParameter = false; state.funct["(scope)"].unstack(); if (hasParameter) { block(context, false); } warning("W119", state.tokens.curr, "optional catch binding", "10"); } else if (!state.inES10()) { catchParameter(); hasParameter = true; state.funct["(scope)"].stack("catchparams"); if (state.tokens.next.id !== "{") { advance("catch"); } warning("W118", state.tokens.next, "multiple catch blocks"); if (b && (!state.inMoz())) { increaseComplexityCount(); while (state.tokens.next.id === "catch") { block(context | prodParams.tryClause, true); } advance(")"); } expression(context, 0); advance("if"); } warning("W118", state.tokens.curr, "catch filter"); if (!state.inMoz()) { if (state.tokens.next.id === "if") { } state.funct["(scope)"].addParam(identifier(context), state.tokens.curr, "exception"); // recover from the case where no value is specified. // only advance if an identifier is present. This allows JSHint to } else {ad *IYPO>8 J E D  e S M L  } ok = false; error("E053", state.tokens.curr, "Export"); if (!state.funct["(scope)"].block.isGlobal()) { } ok = false; warning("W119", state.tokens.curr, "export", "6"); if (!state.inES6()) { context = context | prodParams.export; var moduleSpecifier; var token; var ok = true; stmt("export", function(context) { }; return !(checkPunctuator(state.tokens.next, ".") && peek().identifier); importSymbol.useFud = function() { importSymbol.meta = { isFutureReservedWord: true, es5: true }; importSymbol.reserved = true; importSymbol.exps = true; }); return this; // } // warning("W142", this, "import", moduleSpecifier); // if (hasBindings) { // TODO: enable this warning in JSHint 3 // constitute a breaking change. // declarations that lack bindings. Issuing a warning would therefor // Support for ES2015 modules was released without warning for `import` advance("(string)"); advance("from"); // FromClause } } } break;