diff --git a/lib/client/edit/ace.js b/lib/client/edit/ace.js index 886d89d3..a1beaabc 100644 --- a/lib/client/edit/ace.js +++ b/lib/client/edit/ace.js @@ -30,7 +30,7 @@ (function() { -var ACE_NAMESPACE = ""; +var ACE_NAMESPACE = "ace"; var global = (function() { return this; @@ -169,7 +169,7 @@ exportAce(ACE_NAMESPACE); })(); -define('ace/ace', ['require', 'exports', 'module' , 'ace/lib/fixoldbrowsers', 'ace/lib/dom', 'ace/lib/event', 'ace/editor', 'ace/edit_session', 'ace/undomanager', 'ace/virtual_renderer', 'ace/multi_select', 'ace/worker/worker_client', 'ace/keyboard/hash_handler', 'ace/placeholder', 'ace/mode/folding/fold_mode', 'ace/theme/textmate', 'ace/config'], function(require, exports, module) { +ace.define('ace/ace', ['require', 'exports', 'module' , 'ace/lib/fixoldbrowsers', 'ace/lib/dom', 'ace/lib/event', 'ace/editor', 'ace/edit_session', 'ace/undomanager', 'ace/virtual_renderer', 'ace/multi_select', 'ace/worker/worker_client', 'ace/keyboard/hash_handler', 'ace/placeholder', 'ace/mode/folding/fold_mode', 'ace/theme/textmate', 'ace/config'], function(require, exports, module) { require("./lib/fixoldbrowsers"); @@ -229,7 +229,7 @@ exports.EditSession = EditSession; exports.UndoManager = UndoManager; }); -define('ace/lib/fixoldbrowsers', ['require', 'exports', 'module' , 'ace/lib/regexp', 'ace/lib/es5-shim'], function(require, exports, module) { +ace.define('ace/lib/fixoldbrowsers', ['require', 'exports', 'module' , 'ace/lib/regexp', 'ace/lib/es5-shim'], function(require, exports, module) { require("./regexp"); @@ -237,7 +237,7 @@ require("./es5-shim"); }); -define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) { var real = { exec: RegExp.prototype.exec, @@ -309,7 +309,7 @@ define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, ex }); -define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) { function Empty() {} @@ -1006,7 +1006,7 @@ var toObject = function (o) { }); -define('ace/lib/dom', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/dom', ['require', 'exports', 'module' ], function(require, exports, module) { if (typeof document == "undefined") @@ -1239,7 +1239,7 @@ exports.getParentWindow = function(document) { }); -define('ace/lib/event', ['require', 'exports', 'module' , 'ace/lib/keys', 'ace/lib/useragent', 'ace/lib/dom'], function(require, exports, module) { +ace.define('ace/lib/event', ['require', 'exports', 'module' , 'ace/lib/keys', 'ace/lib/useragent', 'ace/lib/dom'], function(require, exports, module) { var keys = require("./keys"); @@ -1341,9 +1341,9 @@ else { } exports.addMouseWheelListener = function(el, callback) { - var factor = 8; - var listener = function(e) { - if (e.wheelDelta !== undefined) { + if ("onmousewheel" in el) { + var factor = 8; + exports.addListener(el, "mousewheel", function(e) { if (e.wheelDeltaX !== undefined) { e.wheelX = -e.wheelDeltaX / factor; e.wheelY = -e.wheelDeltaY / factor; @@ -1351,8 +1351,16 @@ exports.addMouseWheelListener = function(el, callback) { e.wheelX = 0; e.wheelY = -e.wheelDelta / factor; } - } - else { + callback(e); + }); + } else if ("onwheel" in el) { + exports.addListener(el, "wheel", function(e) { + e.wheelX = (e.deltaX || 0) * 5; + e.wheelY = (e.deltaY || 0) * 5; + callback(e); + }); + } else { + exports.addListener(el, "DOMMouseScroll", function(e) { if (e.axis && e.axis == e.HORIZONTAL_AXIS) { e.wheelX = (e.detail || 0) * 5; e.wheelY = 0; @@ -1360,11 +1368,9 @@ exports.addMouseWheelListener = function(el, callback) { e.wheelX = 0; e.wheelY = (e.detail || 0) * 5; } - } - callback(e); - }; - exports.addListener(el, "DOMMouseScroll", listener); - exports.addListener(el, "mousewheel", listener); + callback(e); + }); + } }; exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) { @@ -1426,6 +1432,29 @@ function normalizeCommandKeys(callback, e, keyCode) { | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); } + if (!useragent.isMac && pressedKeys) { + if (pressedKeys[91] || pressedKeys[92]) + hashId |= 8; + if (pressedKeys.altGr) { + if ((3 & hashId) != 3) + pressedKeys.altGr = 0 + else + return; + } + if (keyCode == 18 || keyCode == 17) { + var location = e.location || e.keyLocation; + if (keyCode == 17 && location == 1) { + ts = e.timeStamp; + } else if (keyCode == 18 && hashId == 3 && location == 2) { + var dt = -ts; + ts = e.timeStamp; + dt += ts; + if (dt < 3) + pressedKeys.altGr = true; + } + } + } + if (keyCode in keys.MODIFIER_KEYS) { switch (keys.MODIFIER_KEYS[keyCode]) { case "Alt": @@ -1444,19 +1473,28 @@ function normalizeCommandKeys(callback, e, keyCode) { keyCode = 0; } - if (!useragent.isMac && pressedKeys[91] || pressedKeys[92]) - hashId |= 8; - if (hashId & 8 && (keyCode == 91 || keyCode == 93)) { keyCode = 0; } + + if (!hashId && keyCode == 13) { + if (e.keyLocation || e.location == 3) { + callback(e, hashId, -keyCode) + if (e.defaultPrevented) + return; + } + } if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) { return false; } + + + return callback(e, hashId, keyCode); } -var pressedKeys = Object.create(null); +var pressedKeys = null; +var ts = 0; exports.addCommandKeyListener = function(el, callback) { var addListener = exports.addListener; if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { @@ -1488,9 +1526,12 @@ exports.addCommandKeyListener = function(el, callback) { pressedKeys[e.keyCode] = null; }); - addListener(el, "focus", function(e) { + if (!pressedKeys) { pressedKeys = Object.create(null); - }); + addListener(window, "focus", function(e) { + pressedKeys = Object.create(null); + }); + } } }; @@ -1525,7 +1566,7 @@ else }; }); -define('ace/lib/keys', ['require', 'exports', 'module' , 'ace/lib/oop'], function(require, exports, module) { +ace.define('ace/lib/keys', ['require', 'exports', 'module' , 'ace/lib/oop'], function(require, exports, module) { var oop = require("./oop"); @@ -1568,6 +1609,7 @@ var Keys = (function() { 103: "Numpad7", 104: "Numpad8", 105: "Numpad9", + '-13': "NumpadEnter", 112: "F1", 113: "F2", 114: "F3", @@ -1617,7 +1659,7 @@ exports.keyCodeToString = function(keyCode) { }); -define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) { exports.inherits = (function() { @@ -1643,7 +1685,7 @@ exports.implement = function(proto, mixin) { }); -define('ace/lib/useragent', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/useragent', ['require', 'exports', 'module' ], function(require, exports, module) { exports.OS = { LINUX: "LINUX", MAC: "MAC", @@ -1686,7 +1728,7 @@ exports.isTouchPad = ua.indexOf("TouchPad") >= 0; }); -define('ace/editor', ['require', 'exports', 'module' , 'ace/lib/fixoldbrowsers', 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/lang', 'ace/lib/useragent', 'ace/keyboard/textinput', 'ace/mouse/mouse_handler', 'ace/mouse/fold_handler', 'ace/keyboard/keybinding', 'ace/edit_session', 'ace/search', 'ace/range', 'ace/lib/event_emitter', 'ace/commands/command_manager', 'ace/commands/default_commands', 'ace/config'], function(require, exports, module) { +ace.define('ace/editor', ['require', 'exports', 'module' , 'ace/lib/fixoldbrowsers', 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/lang', 'ace/lib/useragent', 'ace/keyboard/textinput', 'ace/mouse/mouse_handler', 'ace/mouse/fold_handler', 'ace/keyboard/keybinding', 'ace/edit_session', 'ace/search', 'ace/range', 'ace/lib/event_emitter', 'ace/commands/command_manager', 'ace/commands/default_commands', 'ace/config'], function(require, exports, module) { require("./lib/fixoldbrowsers"); @@ -1723,6 +1765,11 @@ var Editor = function(renderer, session) { wrap: true }); + this.$historyTracker = this.$historyTracker.bind(this); + this.commands.on("exec", this.$historyTracker); + + this.$initOperationListeners(); + this.setSession(session || new EditSession("")); config.resetOptions(this); config._emit("editor", this); @@ -1731,6 +1778,114 @@ var Editor = function(renderer, session) { (function(){ oop.implement(this, EventEmitter); + + this.$initOperationListeners = function() { + function last(a) {return a[a.length - 1]}; + + this.selections = []; + this.commands.on("exec", function(e) { + this.startOperation(e); + + var command = e.command; + if (command.group == "fileJump") { + var prev = this.prevOp; + if (!prev || prev.command.group != "fileJump") { + this.lastFileJumpPos = last(this.selections) + } + } else { + this.lastFileJumpPos = null; + } + }.bind(this), true); + + this.commands.on("afterExec", function(e) { + var command = e.command; + + if (command.group == "fileJump") { + if (this.lastFileJumpPos && !this.curOp.selectionChanged) { + this.selection.fromJSON(this.lastFileJumpPos); + return + } + } + this.endOperation(e); + }.bind(this), true); + + this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this)); + + this.on("change", function() { + this.curOp || this.startOperation(); + this.curOp.docChanged = true; + }.bind(this), true); + + this.on("changeSelection", function() { + this.curOp || this.startOperation(); + this.curOp.selectionChanged = true; + }.bind(this), true); + } + + this.curOp = null; + this.prevOp = {}; + this.startOperation = function(commadEvent) { + if (this.curOp) { + if (!commadEvent || this.curOp.command) + return; + this.prevOp = this.curOp; + } + if (!commadEvent) { + this.previousCommand = null; + commadEvent = {}; + } + + this.$opResetTimer.schedule(); + this.curOp = { + command: commadEvent.command || {}, + args: commadEvent.args + }; + + this.selections.push(this.selection.toJSON()); + }; + + this.endOperation = function() { + if (this.curOp) { + this.prevOp = this.curOp; + this.curOp = null; + } + }; + + this.$historyTracker = function(e) { + if (!this.$mergeUndoDeltas) + return; + + + var prev = this.prevOp; + var mergeableCommands = ["backspace", "del", "insertstring"]; + var shouldMerge = prev.command && (e.command.name == prev.command.name); + if (e.command.name == "insertstring") { + var text = e.args; + if (this.mergeNextCommand === undefined) + this.mergeNextCommand = true; + + shouldMerge = shouldMerge + && this.mergeNextCommand // previous command allows to coalesce with + && (!/\s/.test(text) || /\s/.test(prev.args)) // previous insertion was of same type + + this.mergeNextCommand = true; + } else { + shouldMerge = shouldMerge + && mergeableCommands.indexOf(e.command.name) !== -1// the command is mergeable + } + + if ( + this.$mergeUndoDeltas != "always" + && Date.now() - this.sequenceStartTime > 2000 + ) { + shouldMerge = false; // the sequence is too long + } + + if (shouldMerge) + this.session.mergeUndoDeltas = true; + else if (mergeableCommands.indexOf(e.command.name) !== -1) + this.sequenceStartTime = Date.now(); + }; this.setKeyboardHandler = function(keyboardHandler) { if (!keyboardHandler) { this.keyBinding.setKeyboardHandler(null); @@ -1995,6 +2150,8 @@ var Editor = function(renderer, session) { if (this.$highlightActiveLine) { if ((this.$selectionStyle != "line" || !this.selection.isMultiLine())) highlight = this.getCursorPosition(); + if (this.renderer.$maxLines && this.session.getLength() === 1) + highlight = false; } if (session.$highlightLineMarker && !highlight) { @@ -2135,13 +2292,21 @@ var Editor = function(renderer, session) { if (this.getBehavioursEnabled()) { var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); - if (transform) + if (transform) { + if (text !== transform.text) { + this.session.mergeUndoDeltas = false; + this.$mergeNextCommand = false; + } text = transform.text; - } - text = text.replace("\t", this.session.getTabString()); + } + } + + if (text == "\t") + text = this.session.getTabString(); if (!this.selection.isEmpty()) { - cursor = this.session.remove(this.getSelectionRange()); + var range = this.getSelectionRange(); + cursor = this.session.remove(range); this.clearSelection(); } else if (this.session.getOverwrite()) { @@ -2150,6 +2315,13 @@ var Editor = function(renderer, session) { this.session.remove(range); } + if (text == "\n" || text == "\r\n") { + var line = session.getLine(cursor.row) + if (cursor.column > line.search(/\S|$/)) { + var d = line.substr(cursor.column).search(/\S|$/); + session.doc.removeInLine(cursor.row, cursor.column, cursor.column + d); + } + } this.clearSelection(); var start = cursor.column; @@ -2171,41 +2343,11 @@ var Editor = function(renderer, session) { transform.selection[3])); } } + if (session.getDocument().isNewLine(text)) { var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); - this.moveCursorTo(cursor.row+1, 0); - - var size = session.getTabSize(); - var minIndent = Number.MAX_VALUE; - - for (var row = cursor.row + 1; row <= end.row; ++row) { - var indent = 0; - - line = session.getLine(row); - for (var i = 0; i < line.length; ++i) - if (line.charAt(i) == '\t') - indent += size; - else if (line.charAt(i) == ' ') - indent += 1; - else - break; - if (/[^\s]/.test(line)) - minIndent = Math.min(indent, minIndent); - } - - for (var row = cursor.row + 1; row <= end.row; ++row) { - var outdent = minIndent; - - line = session.getLine(row); - for (var i = 0; i < line.length && outdent > 0; ++i) - if (line.charAt(i) == '\t') - outdent -= size; - else if (line.charAt(i) == ' ') - outdent -= 1; - session.remove(new Range(row, 0, row, i)); - } - session.indentRows(cursor.row + 1, end.row, lineIndent); + session.insert({row: cursor.row+1, column: 0}, lineIndent); } if (shouldOutdent) mode.autoOutdent(lineState, session, cursor.row); @@ -2344,6 +2486,16 @@ var Editor = function(renderer, session) { var session = this.session; var state = session.getState(range.start.row); var new_range = session.getMode().transformAction(state, 'deletion', this, session, range); + + if (range.end.column == 0) { + var text = session.getTextRange(range); + if (text[text.length - 1] == "\n") { + var line = session.getLine(range.end.row) + if (/^\s+$/.test(line)) { + range.end.column = line.length + } + } + } if (new_range) range = new_range; } @@ -2443,23 +2595,37 @@ var Editor = function(renderer, session) { var session = this.session; var range = this.getSelectionRange(); - if (range.start.row < range.end.row || range.start.column < range.end.column) { + if (range.start.row < range.end.row) { var rows = this.$getSelectedRows(); session.indentRows(rows.first, rows.last, "\t"); - } else { - var indentString; - - if (this.session.getUseSoftTabs()) { - var size = session.getTabSize(), - position = this.getCursorPosition(), - column = session.documentToScreenColumn(position.row, position.column), - count = (size - column % size); - - indentString = lang.stringRepeat(" ", count); - } else - indentString = "\t"; - return this.insert(indentString); + return; + } else if (range.start.column < range.end.column) { + var text = session.getTextRange(range) + if (!/^\s+$/.test(text)) { + var rows = this.$getSelectedRows(); + session.indentRows(rows.first, rows.last, "\t"); + return; + } } + + var line = session.getLine(range.start.row) + var position = range.start; + var size = session.getTabSize(); + var column = session.documentToScreenColumn(position.row, position.column); + + if (this.session.getUseSoftTabs()) { + var count = (size - column % size); + var indentString = lang.stringRepeat(" ", count); + } else { + var count = column % size; + while (line[range.start.column] == " " && count) { + range.start.column--; + count--; + } + this.selection.setSelectionRange(range); + indentString = "\t"; + } + return this.insert(indentString); }; this.blockIndent = function() { var rows = this.$getSelectedRows(); @@ -3099,6 +3265,10 @@ config.defineOptions(Editor.prototype, "editor", { values: ["ace", "slim", "smooth", "wide"], initialValue: "ace" }, + mergeUndoDeltas: { + values: [false, true, "always"], + initialValue: true + }, behavioursEnabled: {initialValue: true}, wrapBehavioursEnabled: {initialValue: true}, @@ -3115,6 +3285,9 @@ config.defineOptions(Editor.prototype, "editor", { displayIndentGuides: "renderer", fontSize: "renderer", fontFamily: "renderer", + maxLines: "renderer", + minLines: "renderer", + scrollPastEnd: "renderer", scrollSpeed: "$mouseHandler", dragDelay: "$mouseHandler", @@ -3133,7 +3306,7 @@ config.defineOptions(Editor.prototype, "editor", { exports.Editor = Editor; }); -define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) { exports.stringReverse = function(string) { @@ -3310,7 +3483,7 @@ exports.delayedCall = function(fcn, defaultTimeout) { }; }); -define('ace/keyboard/textinput', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent', 'ace/lib/dom', 'ace/lib/lang'], function(require, exports, module) { +ace.define('ace/keyboard/textinput', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent', 'ace/lib/dom', 'ace/lib/lang'], function(require, exports, module) { var event = require("../lib/event"); @@ -3445,10 +3618,13 @@ var TextInput = function(parentNode, host) { if (inComposition && (!text.value || keytable[e.keyCode])) setTimeout(onCompositionEnd, 0); if ((text.value.charCodeAt(0)||0) < 129) { - return; + return syncProperty.call(); } inComposition ? onCompositionUpdate() : onCompositionStart(); }); + event.addListener(text, "keydown", function (e) { + syncProperty.schedule(50); + }); } var onSelect = function(e) { @@ -3692,7 +3868,7 @@ var TextInput = function(parentNode, host) { text.style.cssText = "z-index:100000;" + (useragent.isIE ? "opacity:0.1;" : ""); resetSelection(host.selection.isEmpty()); - host._emit("nativecontextmenu", {target: host}); + host._emit("nativecontextmenu", {target: host, domEvent: e}); var rect = host.container.getBoundingClientRect(); var style = dom.computedStyle(host.container); var top = rect.top + (parseInt(style.borderTopWidth) || 0); @@ -3726,7 +3902,7 @@ var TextInput = function(parentNode, host) { } }, 0); } - if (!useragent.isGecko) { + if (!useragent.isGecko || useragent.isMac) { event.addListener(text, "contextmenu", function(e) { host.textInput.onContextMenu(e); onContextMenuClose(); @@ -3737,7 +3913,7 @@ var TextInput = function(parentNode, host) { exports.TextInput = TextInput; }); -define('ace/mouse/mouse_handler', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent', 'ace/mouse/default_handlers', 'ace/mouse/default_gutter_handler', 'ace/mouse/mouse_event', 'ace/mouse/dragdrop', 'ace/config'], function(require, exports, module) { +ace.define('ace/mouse/mouse_handler', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent', 'ace/mouse/default_handlers', 'ace/mouse/default_gutter_handler', 'ace/mouse/mouse_event', 'ace/mouse/dragdrop', 'ace/config'], function(require, exports, module) { var event = require("../lib/event"); @@ -3755,11 +3931,6 @@ var MouseHandler = function(editor) { new DefaultGutterHandler(this); new DragdropHandler(this); - event.addListener(editor.container, "mousedown", function(e) { - editor.focus(); - return event.preventDefault(e); - }); - var mouseTarget = editor.renderer.getMouseEventTarget(); event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click")); event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove")); @@ -3771,6 +3942,16 @@ var MouseHandler = function(editor) { event.addListener(gutterEl, "click", this.onMouseEvent.bind(this, "gutterclick")); event.addListener(gutterEl, "dblclick", this.onMouseEvent.bind(this, "gutterdblclick")); event.addListener(gutterEl, "mousemove", this.onMouseEvent.bind(this, "guttermousemove")); + + event.addListener(mouseTarget, "mousedown", function(e) { + editor.focus(); + return event.preventDefault(e); + }); + + event.addListener(gutterEl, "mousedown", function(e) { + editor.focus(); + return event.preventDefault(e); + }); }; (function() { @@ -3835,7 +4016,7 @@ var MouseHandler = function(editor) { }; if (useragent.isOldIE && ev.domEvent.type == "dblclick") { - return setTimeout(function() {onCaptureEnd(ev.domEvent);}); + return setTimeout(function() {onCaptureEnd(ev);}); } event.capture(this.editor.container, onMouseMove, onCaptureEnd); @@ -3853,7 +4034,7 @@ config.defineOptions(MouseHandler.prototype, "mouseHandler", { exports.MouseHandler = MouseHandler; }); -define('ace/mouse/default_handlers', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/useragent'], function(require, exports, module) { +ace.define('ace/mouse/default_handlers', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/useragent'], function(require, exports, module) { var dom = require("../lib/dom"); @@ -4153,7 +4334,7 @@ function calcRangeOrientation(range, cursor) { }); -define('ace/mouse/default_gutter_handler', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/event'], function(require, exports, module) { +ace.define('ace/mouse/default_gutter_handler', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/event'], function(require, exports, module) { var dom = require("../lib/dom"); var event = require("../lib/event"); @@ -4163,7 +4344,7 @@ function GutterHandler(mouseHandler) { var gutter = editor.renderer.$gutterLayer; mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { - if (!editor.isFocused()) + if (!editor.isFocused() || e.getButton() != 0) return; var gutterRegion = gutter.getRegion(e); @@ -4275,14 +4456,15 @@ function GutterHandler(mouseHandler) { hideTooltip(); }, 50); }); - + + editor.on("changeSession", hideTooltip); } exports.GutterHandler = GutterHandler; }); -define('ace/mouse/mouse_event', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent'], function(require, exports, module) { +ace.define('ace/mouse/mouse_event', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent'], function(require, exports, module) { var event = require("../lib/event"); @@ -4359,7 +4541,7 @@ var MouseEvent = exports.MouseEvent = function(domEvent, editor) { }); -define('ace/mouse/dragdrop', ['require', 'exports', 'module' , 'ace/lib/event'], function(require, exports, module) { +ace.define('ace/mouse/dragdrop', ['require', 'exports', 'module' , 'ace/lib/event'], function(require, exports, module) { var event = require("../lib/event"); @@ -4451,7 +4633,7 @@ var DragdropHandler = function(mouseHandler) { exports.DragdropHandler = DragdropHandler; }); -define('ace/config', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/lib/oop', 'ace/lib/net', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/config', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/lib/oop', 'ace/lib/net', 'ace/lib/event_emitter'], function(require, exports, module) { "no use strict"; var lang = require("./lib/lang"); @@ -4498,16 +4680,24 @@ exports.moduleUrl = function(name, component) { var parts = name.split("/"); component = component || parts[parts.length - 2] || ""; - var base = parts[parts.length - 1].replace(component, "").replace(/(^[\-_])|([\-_]$)/, ""); + var sep = component == "snippets" ? "/" : "-"; + var base = parts[parts.length - 1]; + if (sep == "-") { + var re = new RegExp("^" + component + "[\-_]|[\-_]" + component + "$", "g"); + base = base.replace(re, ""); + } - if (!base && parts.length > 1) + if ((!base || base == component) && parts.length > 1) base = parts[parts.length - 2]; var path = options[component + "Path"]; - if (path == null) + if (path == null) { path = options.basePath; + } else if (sep == "/") { + component = sep = ""; + } if (path && path.slice(-1) != "/") path += "/"; - return path + component + "-" + base + this.get("suffix"); + return path + component + sep + base + this.get("suffix"); }; exports.setModuleUrl = function(name, subst) { @@ -4689,7 +4879,7 @@ exports.setDefaultValues = function(path, optionHash) { }; }); -define('ace/lib/net', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { +ace.define('ace/lib/net', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { var dom = require("./dom"); @@ -4722,7 +4912,7 @@ exports.loadScript = function(path, callback) { }); -define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) { var EventEmitter = {}; @@ -4847,7 +5037,7 @@ exports.EventEmitter = EventEmitter; }); -define('ace/mouse/fold_handler', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/mouse/fold_handler', ['require', 'exports', 'module' ], function(require, exports, module) { function FoldHandler(editor) { @@ -4909,7 +5099,7 @@ exports.FoldHandler = FoldHandler; }); -define('ace/keyboard/keybinding', ['require', 'exports', 'module' , 'ace/lib/keys', 'ace/lib/event'], function(require, exports, module) { +ace.define('ace/keyboard/keybinding', ['require', 'exports', 'module' , 'ace/lib/keys', 'ace/lib/event'], function(require, exports, module) { var keyUtil = require("../lib/keys"); @@ -5010,7 +5200,7 @@ var KeyBinding = function(editor) { exports.KeyBinding = KeyBinding; }); -define('ace/edit_session', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/config', 'ace/lib/event_emitter', 'ace/selection', 'ace/mode/text', 'ace/range', 'ace/document', 'ace/background_tokenizer', 'ace/search_highlight', 'ace/edit_session/folding', 'ace/edit_session/bracket_match'], function(require, exports, module) { +ace.define('ace/edit_session', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/config', 'ace/lib/event_emitter', 'ace/selection', 'ace/mode/text', 'ace/range', 'ace/document', 'ace/background_tokenizer', 'ace/search_highlight', 'ace/edit_session/folding', 'ace/edit_session/bracket_match'], function(require, exports, module) { var oop = require("./lib/oop"); @@ -5216,10 +5406,11 @@ var EditSession = function(text, mode) { if (self.$deltas.length > 0) { undoManager.execute({ action: "aceupdate", - args: [self.$deltas, self] + args: [self.$deltas, self], + merge: self.mergeUndoDeltas }); } - + self.mergeUndoDeltas = false; self.$deltas = []; } this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager); @@ -5249,7 +5440,7 @@ var EditSession = function(text, mode) { this.setOption("useSoftTabs", val); }; this.getUseSoftTabs = function() { - return this.$useSoftTabs; + return this.$useSoftTabs && !this.$mode.$indentWithTabs; }; this.setTabSize = function(tabSize) { this.setOption("tabSize", tabSize) @@ -5458,7 +5649,7 @@ var EditSession = function(text, mode) { this.$modes = {}; this.$mode = null; this.$modeId = null; - this.setMode = function(mode) { + this.setMode = function(mode, cb) { if (mode && typeof mode === "object") { if (mode.getTokenizer) return this.$onChangeMode(mode); @@ -5475,7 +5666,7 @@ var EditSession = function(text, mode) { this.$modeId = path; config.loadModule(["mode", path], function(m) { if (this.$modeId !== path) - return; + return cb && cb(); if (this.$modes[path] && !options) return this.$onChangeMode(this.$modes[path]); if (m && m.Mode) { @@ -5484,7 +5675,8 @@ var EditSession = function(text, mode) { this.$modes[path] = m; m.$id = path; } - this.$onChangeMode(m) + this.$onChangeMode(m); + cb && cb(this.mode); } }.bind(this)); if (!this.$mode) @@ -5492,7 +5684,11 @@ var EditSession = function(text, mode) { }; this.$onChangeMode = function(mode, $isPlaceholder) { - if (this.$mode === mode) return; + if (!$isPlaceholder) + this.$modeId = mode.$id; + if (this.$mode === mode) + return; + this.$mode = mode; this.$stopWorker(); @@ -5524,7 +5720,6 @@ var EditSession = function(text, mode) { if (!$isPlaceholder) { - this.$modeId = mode.$id; this.$setFolding(mode.foldingRules); this._emit("changeMode"); this.bgTokenizer.start(0); @@ -5558,7 +5753,7 @@ var EditSession = function(text, mode) { this.$scrollTop = 0; this.setScrollTop = function(scrollTop) { - scrollTop = Math.round(Math.max(0, scrollTop)); + scrollTop = Math.round(scrollTop); if (this.$scrollTop === scrollTop || isNaN(scrollTop)) return; @@ -5571,7 +5766,7 @@ var EditSession = function(text, mode) { this.$scrollLeft = 0; this.setScrollLeft = function(scrollLeft) { - scrollLeft = Math.round(Math.max(0, scrollLeft)); + scrollLeft = Math.round(scrollLeft); if (this.$scrollLeft === scrollLeft || isNaN(scrollLeft)) return; @@ -5698,7 +5893,7 @@ var EditSession = function(text, mode) { var range, point; var lastDeltaIsInsert = false; if (isInsert(delta)) { - range = delta.range.clone(); + range = Range.fromPoints(delta.range.start, delta.range.end); lastDeltaIsInsert = true; } else { range = Range.fromPoints(delta.range.start, delta.range.start); @@ -5727,6 +5922,11 @@ var EditSession = function(text, mode) { } } if (lastUndoRange != null) { + if (Range.comparePoints(lastUndoRange.start, range.start) == 0) { + lastUndoRange.start.column += range.end.column - range.start.column; + lastUndoRange.end.column += range.end.column - range.start.column; + } + var cmp = lastUndoRange.compareRange(range); if (cmp == 1) { range.setStart(lastUndoRange.start); @@ -6631,7 +6831,7 @@ config.defineOptions(EditSession.prototype, "session", { exports.EditSession = EditSession; }); -define('ace/selection', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/lib/event_emitter', 'ace/range'], function(require, exports, module) { +ace.define('ace/selection', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/lib/event_emitter', 'ace/range'], function(require, exports, module) { var oop = require("./lib/oop"); @@ -6756,6 +6956,8 @@ var Selection = function(session) { this.setSelectionAnchor(range.start.row, range.start.column); this.selectTo(range.end.row, range.end.column); } + if (this.getRange().isEmpty()) + this.$isEmpty = true; this.$desiredColumn = null; }; @@ -7007,7 +7209,7 @@ var Selection = function(session) { while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) index ++; - if (index <= 1) { + if (index < 1) { tokenRe.lastIndex = 0; while ((ch = rightOfCursor[index]) && !tokenRe.test(ch)) { tokenRe.lastIndex = 0; @@ -7043,11 +7245,11 @@ var Selection = function(session) { if (column == line.length) { var l = this.doc.getLength(); - do { + do { row++; rightOfCursor = this.doc.getLine(row) } while (row < l && /^\s*$/.test(rightOfCursor)) - + if (!/^\s+/.test(rightOfCursor)) rightOfCursor = "" column = 0; @@ -7068,11 +7270,11 @@ var Selection = function(session) { var line = this.session.getLine(row).substring(0, column); if (column == 0) { - do { + do { row--; line = this.doc.getLine(row); } while (row > 0 && /^\s*$/.test(line)) - + column = line.length; if (!/\s+$/.test(line)) line = "" @@ -7161,12 +7363,58 @@ var Selection = function(session) { return range; } + this.toJSON = function() { + if (this.rangeCount) { + var data = this.ranges.map(function(r) { + var r1 = r.clone(); + r1.isBackwards = r.cursor == r.start; + return r1; + }); + } else { + var data = this.getRange(); + data.isBackwards = this.isBackwards(); + } + return data; + }; + + this.fromJSON = function(data) { + if (data.start == undefined) { + if (this.rangeList) { + this.toSingleRange(data[0]); + for (var i = data.length; i--; ) { + var r = Range.fromPoints(data[i].start, data[i].end); + if (data.isBackwards) + r.cursor = r.start; + this.addRange(r, true); + } + return; + } else + data = data[0]; + } + if (this.rangeList) + this.toSingleRange(data); + this.setSelectionRange(data, data.isBackwards); + }; + + this.isEqual = function(data) { + if ((data.length || this.rangeCount) && data.length != this.rangeCount) + return false; + if (!data.length || !this.ranges) + return this.getRange().isEqual(data); + + for (var i = this.ranges.length; i--; ) { + if (!this.ranges[i].isEqual(data[i])) + return false + } + return true; + } + }).call(Selection.prototype); exports.Selection = Selection; }); -define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) { var comparePoints = function(p1, p2) { return p1.row - p2.row || p1.column - p2.column; @@ -7405,7 +7653,7 @@ Range.comparePoints = function(p1, p2) { exports.Range = Range; }); -define('ace/mode/text', ['require', 'exports', 'module' , 'ace/tokenizer', 'ace/mode/text_highlight_rules', 'ace/mode/behaviour', 'ace/unicode', 'ace/lib/lang', 'ace/token_iterator', 'ace/range'], function(require, exports, module) { +ace.define('ace/mode/text', ['require', 'exports', 'module' , 'ace/tokenizer', 'ace/mode/text_highlight_rules', 'ace/mode/behaviour', 'ace/unicode', 'ace/lib/lang', 'ace/token_iterator', 'ace/range'], function(require, exports, module) { var Tokenizer = require("../tokenizer").Tokenizer; @@ -7701,13 +7949,41 @@ var Mode = function() { } } }; - + + this.getKeywords = function(append) { + if (!this.completionKeywords) { + var rules = this.$tokenizer.rules; + var completionKeywords = []; + for (var rule in rules) { + var ruleItr = rules[rule]; + for (var r = 0, l = ruleItr.length; r < l; r++) { + if (typeof ruleItr[r].token === "string") { + if (/keyword|support|storage/.test(ruleItr[r].token)) + completionKeywords.push(ruleItr[r].regex); + } + else if (typeof ruleItr[r].token === "object") { + for (var a = 0, aLength = ruleItr[r].token.length; a < aLength; a++) { + if (/keyword|support|storage/.test(ruleItr[r].token[a])) { + var rule = ruleItr[r].regex.match(/\(.+?\)/g)[a]; + completionKeywords.push(rule.substr(1, rule.length - 2)); + } + } + } + } + } + this.completionKeywords = completionKeywords; + } + if (!append) + return this.$keywordList; + return completionKeywords.concat(this.$keywordList || []); + }; + }).call(Mode.prototype); exports.Mode = Mode; }); -define('ace/tokenizer', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/tokenizer', ['require', 'exports', 'module' ], function(require, exports, module) { var MAX_TOKEN_COUNT = 1000; var Tokenizer = function(rules) { this.states = rules; @@ -7979,7 +8255,7 @@ var Tokenizer = function(rules) { exports.Tokenizer = Tokenizer; }); -define('ace/mode/text_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/lang'], function(require, exports, module) { +ace.define('ace/mode/text_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/lang'], function(require, exports, module) { var lang = require("../lib/lang"); @@ -7999,15 +8275,23 @@ var TextHighlightRules = function() { (function() { this.addRules = function(rules, prefix) { + if (!prefix) { + for (var key in rules) + this.$rules[key] = rules[key]; + return; + } for (var key in rules) { var state = rules[key]; for (var i = 0; i < state.length; i++) { var rule = state[i]; if (rule.next) { - if (typeof rule.next != "string") - rule.nextState = prefix + rule.nextState; - else - rule.next = prefix + rule.next; + if (typeof rule.next != "string") { + if (rule.nextState && rule.nextState.indexOf(prefix) !== 0) + rule.nextState = prefix + rule.nextState; + } else { + if (rule.next.indexOf(prefix) !== 0) + rule.next = prefix + rule.next; + } } } @@ -8041,7 +8325,7 @@ var TextHighlightRules = function() { if (!this.$embeds) this.$embeds = []; this.$embeds.push(prefix); - } + }; this.getEmbeds = function() { return this.$embeds; @@ -8150,6 +8434,7 @@ var TextHighlightRules = function() { for (var i = list.length; i--; ) keywords[list[i]] = className; }); + this.$keywordList = Object.keys(keywords); map = null; return ignoreCase ? function(value) {return keywords[value.toLowerCase()] || defaultToken } @@ -8165,7 +8450,7 @@ var TextHighlightRules = function() { exports.TextHighlightRules = TextHighlightRules; }); -define('ace/mode/behaviour', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/mode/behaviour', ['require', 'exports', 'module' ], function(require, exports, module) { var Behaviour = function() { @@ -8225,7 +8510,7 @@ var Behaviour = function() { exports.Behaviour = Behaviour; }); -define('ace/unicode', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/unicode', ['require', 'exports', 'module' ], function(require, exports, module) { exports.packages = {}; addUnicodePackage({ @@ -8276,7 +8561,7 @@ function addUnicodePackage (pack) { }); -define('ace/token_iterator', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/token_iterator', ['require', 'exports', 'module' ], function(require, exports, module) { var TokenIterator = function(session, initialRow, initialColumn) { this.$session = session; this.$row = initialRow; @@ -8348,7 +8633,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { exports.TokenIterator = TokenIterator; }); -define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) { +ace.define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) { var oop = require("./lib/oop"); @@ -8434,7 +8719,7 @@ var Document = function(text) { }; this.getTextRange = function(range) { if (range.start.row == range.end.row) { - return this.$lines[range.start.row] + return this.getLine(range.start.row) .substring(range.start.column, range.end.column); } var lines = this.getLines(range.start.row, range.end.row); @@ -8700,36 +8985,31 @@ var Document = function(text) { exports.Document = Document; }); -define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Anchor = exports.Anchor = function(doc, row, column) { - this.document = doc; - + this.$onChange = this.onChange.bind(this); + this.attach(doc); + if (typeof column == "undefined") this.setPosition(row.row, row.column); else this.setPosition(row, column); - - this.$onChange = this.onChange.bind(this); - doc.on("change", this.$onChange); }; (function() { oop.implement(this, EventEmitter); - this.getPosition = function() { return this.$clipPositionToDocument(this.row, this.column); }; - this.getDocument = function() { return this.document; }; - this.onChange = function(e) { var delta = e.data; var range = delta.range; @@ -8791,7 +9071,6 @@ var Anchor = exports.Anchor = function(doc, row, column) { this.setPosition(row, column, true); }; - this.setPosition = function(row, column, noClip) { var pos; if (noClip) { @@ -8818,10 +9097,13 @@ var Anchor = exports.Anchor = function(doc, row, column) { value: pos }); }; - this.detach = function() { this.document.removeEventListener("change", this.$onChange); }; + this.attach = function(doc) { + this.document = doc || this.document; + this.document.on("change", this.$onChange); + }; this.$clipPositionToDocument = function(row, column) { var pos = {}; @@ -8848,7 +9130,7 @@ var Anchor = exports.Anchor = function(doc, row, column) { }); -define('ace/background_tokenizer', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/background_tokenizer', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("./lib/oop"); @@ -8867,27 +9149,35 @@ var BackgroundTokenizer = function(tokenizer, editor) { if (!self.running) { return; } var workerStart = new Date(); - var startLine = self.currentLine; + var currentLine = self.currentLine; + var endLine = -1; var doc = self.doc; - var processedLines = 0; + while (self.lines[currentLine]) + currentLine++; + + var startLine = currentLine; var len = doc.getLength(); - while (self.currentLine < len) { - self.$tokenizeRow(self.currentLine); - while (self.lines[self.currentLine]) - self.currentLine++; + var processedLines = 0; + self.running = false; + while (currentLine < len) { + self.$tokenizeRow(currentLine); + endLine = currentLine; + do { + currentLine++; + } while (self.lines[currentLine]); processedLines ++; - if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) { - self.fireUpdateEvent(startLine, self.currentLine-1); + if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) { self.running = setTimeout(self.$worker, 20); + self.currentLine = currentLine; return; } } - - self.running = false; - - self.fireUpdateEvent(startLine, len - 1); + self.currentLine = currentLine; + + if (startLine <= endLine) + self.fireUpdateEvent(startLine, endLine); }; }; @@ -8983,7 +9273,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { exports.BackgroundTokenizer = BackgroundTokenizer; }); -define('ace/search_highlight', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/lib/oop', 'ace/range'], function(require, exports, module) { +ace.define('ace/search_highlight', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/lib/oop', 'ace/range'], function(require, exports, module) { var lang = require("./lib/lang"); @@ -9035,7 +9325,7 @@ var SearchHighlight = function(regExp, clazz, type) { exports.SearchHighlight = SearchHighlight; }); -define('ace/edit_session/folding', ['require', 'exports', 'module' , 'ace/range', 'ace/edit_session/fold_line', 'ace/edit_session/fold', 'ace/token_iterator'], function(require, exports, module) { +ace.define('ace/edit_session/folding', ['require', 'exports', 'module' , 'ace/range', 'ace/edit_session/fold_line', 'ace/edit_session/fold', 'ace/token_iterator'], function(require, exports, module) { var Range = require("../range").Range; @@ -9562,8 +9852,8 @@ function Folding() { if (range && range.end.row <= endRow) try { var fold = this.addFold("...", range); fold.collapseChildren = depth; + row = range.end.row; } catch(e) {} - row = range.end.row; } }; this.$foldStyles = { @@ -9709,7 +9999,7 @@ exports.Folding = Folding; }); -define('ace/edit_session/fold_line', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { +ace.define('ace/edit_session/fold_line', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { var Range = require("../range").Range; @@ -9927,7 +10217,7 @@ function FoldLine(foldData, folds) { exports.FoldLine = FoldLine; }); -define('ace/edit_session/fold', ['require', 'exports', 'module' , 'ace/range', 'ace/range_list', 'ace/lib/oop'], function(require, exports, module) { +ace.define('ace/edit_session/fold', ['require', 'exports', 'module' , 'ace/range', 'ace/range_list', 'ace/lib/oop'], function(require, exports, module) { var Range = require("../range").Range; @@ -10031,7 +10321,7 @@ function restoreRange(range, anchor) { }); -define('ace/range_list', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { +ace.define('ace/range_list', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { var Range = require("./range").Range; var comparePoints = Range.comparePoints; @@ -10233,7 +10523,7 @@ var RangeList = function() { exports.RangeList = RangeList; }); -define('ace/edit_session/bracket_match', ['require', 'exports', 'module' , 'ace/token_iterator', 'ace/range'], function(require, exports, module) { +ace.define('ace/edit_session/bracket_match', ['require', 'exports', 'module' , 'ace/token_iterator', 'ace/range'], function(require, exports, module) { var TokenIterator = require("../token_iterator").TokenIterator; @@ -10413,7 +10703,7 @@ exports.BracketMatch = BracketMatch; }); -define('ace/search', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/lib/oop', 'ace/range'], function(require, exports, module) { +ace.define('ace/search', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/lib/oop', 'ace/range'], function(require, exports, module) { var lang = require("./lib/lang"); @@ -10702,7 +10992,7 @@ var Search = function() { exports.Search = Search; }); -define('ace/commands/command_manager', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/keyboard/hash_handler', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/commands/command_manager', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/keyboard/hash_handler', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -10806,7 +11096,7 @@ exports.CommandManager = CommandManager; }); -define('ace/keyboard/hash_handler', ['require', 'exports', 'module' , 'ace/lib/keys', 'ace/lib/useragent'], function(require, exports, module) { +ace.define('ace/keyboard/hash_handler', ['require', 'exports', 'module' , 'ace/lib/keys', 'ace/lib/useragent'], function(require, exports, module) { var keyUtil = require("../lib/keys"); @@ -10941,7 +11231,7 @@ function HashHandler(config, platform) { exports.HashHandler = HashHandler; }); -define('ace/commands/default_commands', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/config'], function(require, exports, module) { +ace.define('ace/commands/default_commands', ['require', 'exports', 'module' , 'ace/lib/lang', 'ace/config'], function(require, exports, module) { var lang = require("../lib/lang"); @@ -11031,13 +11321,15 @@ exports.commands = [{ bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"), exec: function(editor) { editor.getSelection().selectFileStart(); }, multiSelectAction: "forEach", - readOnly: true + readOnly: true, + group: "fileJump" }, { name: "gotostart", bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), exec: function(editor) { editor.navigateFileStart(); }, multiSelectAction: "forEach", - readOnly: true + readOnly: true, + group: "fileJump" }, { name: "selectup", bindKey: bindKey("Shift-Up", "Shift-Up"), @@ -11055,13 +11347,15 @@ exports.commands = [{ bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"), exec: function(editor) { editor.getSelection().selectFileEnd(); }, multiSelectAction: "forEach", - readOnly: true + readOnly: true, + group: "fileJump" }, { name: "gotoend", bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"), exec: function(editor) { editor.navigateFileEnd(); }, multiSelectAction: "forEach", - readOnly: true + readOnly: true, + group: "fileJump" }, { name: "selectdown", bindKey: bindKey("Shift-Down", "Shift-Down"), @@ -11306,8 +11600,8 @@ exports.commands = [{ }, { name: "backspace", bindKey: bindKey( - "Command-Backspace|Option-Backspace|Shift-Backspace|Backspace", - "Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H" + "Shift-Backspace|Backspace", + "Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H" ), exec: function(editor) { editor.remove("left"); }, multiSelectAction: "forEach" @@ -11385,7 +11679,7 @@ exports.commands = [{ }); -define('ace/undomanager', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/undomanager', ['require', 'exports', 'module' ], function(require, exports, module) { var UndoManager = function() { this.reset(); }; @@ -11394,6 +11688,9 @@ var UndoManager = function() { this.execute = function(options) { var deltas = options.args[0]; this.$doc = options.args[1]; + if (options.merge && this.hasUndo()){ + deltas = this.$undoStack.pop().concat(deltas); + } this.$undoStack.push(deltas); this.$redoStack = []; @@ -11449,19 +11746,19 @@ var UndoManager = function() { exports.UndoManager = UndoManager; }); -define('ace/virtual_renderer', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/event', 'ace/lib/useragent', 'ace/config', 'ace/layer/gutter', 'ace/layer/marker', 'ace/layer/text', 'ace/layer/cursor', 'ace/scrollbar', 'ace/renderloop', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/virtual_renderer', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/useragent', 'ace/config', 'ace/layer/gutter', 'ace/layer/marker', 'ace/layer/text', 'ace/layer/cursor', 'ace/scrollbar', 'ace/renderloop', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("./lib/oop"); var dom = require("./lib/dom"); -var event = require("./lib/event"); var useragent = require("./lib/useragent"); var config = require("./config"); var GutterLayer = require("./layer/gutter").Gutter; var MarkerLayer = require("./layer/marker").Marker; var TextLayer = require("./layer/text").Text; var CursorLayer = require("./layer/cursor").Cursor; -var ScrollBar = require("./scrollbar").ScrollBar; +var ScrollBarH = require("./scrollbar").ScrollBarH; +var ScrollBarV = require("./scrollbar").ScrollBarV; var RenderLoop = require("./renderloop").RenderLoop; var EventEmitter = require("./lib/event_emitter").EventEmitter; var editorCss = ".ace_editor {\ @@ -11527,8 +11824,8 @@ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCA }\ .ace_scrollbar {\ position: absolute;\ -overflow-x: hidden;\ -overflow-y: scroll;\ +overflow: hidden;\ +overflow-y: auto;\ right: 0;\ top: 0;\ bottom: 0;\ @@ -11538,6 +11835,19 @@ position: absolute;\ width: 1px;\ left: 0;\ }\ +.ace_scrollbar-h {\ +position: absolute;\ +overflow-x: auto;\ +overflow-y: hidden;\ +right: 0;\ +left: 0;\ +bottom: 0;\ +}\ +.ace_scrollbar-inner {\ +position: absolute;\ +height: 1px;\ +left: 0;\ +}\ .ace_print-margin {\ position: absolute;\ height: 100%;\ @@ -11621,7 +11931,7 @@ border-left-width: 1px;\ .ace_line {\ white-space: nowrap;\ }\ -.ace_marker-layer .ace_step {\ +.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {\ position: absolute;\ z-index: 3;\ }\ @@ -11795,6 +12105,16 @@ font-weight: normal;\ .ace_italic {\ font-style: italic;\ }\ +.ace_error-marker {\ +background-color: rgba(255, 0, 0,0.2);\ +position: absolute;\ +z-index: 9;\ +}\ +.ace_highlight-marker {\ +background-color: rgba(255, 255, 0,0.2);\ +position: absolute;\ +z-index: 8;\ +}\ "; dom.importCssString(editorCss, "ace_editor"); @@ -11833,22 +12153,23 @@ var VirtualRenderer = function(container, theme) { this.$cursorLayer = new CursorLayer(this.content); this.$horizScroll = false; + this.$vScroll = false; - this.scrollBar = new ScrollBar(this.container); - this.scrollBar.addEventListener("scroll", function(e) { + this.scrollBar = + this.scrollBarV = new ScrollBarV(this.container, this); + this.scrollBarH = new ScrollBarH(this.container, this); + this.scrollBarV.addEventListener("scroll", function(e) { if (!_self.$scrollAnimation) - _self.session.setScrollTop(e.data); + _self.session.setScrollTop(e.data - _self.scrollMargin.top); + }); + this.scrollBarH.addEventListener("scroll", function(e) { + if (!_self.$scrollAnimation) + _self.session.setScrollLeft(e.data - _self.scrollMargin.left); }); this.scrollTop = 0; this.scrollLeft = 0; - event.addListener(this.scroller, "scroll", function() { - var scrollLeft = _self.scroller.scrollLeft; - _self.scrollLeft = scrollLeft; - _self.session.setScrollLeft(scrollLeft); - }); - this.cursorPos = { row : 0, column : 0 @@ -11857,6 +12178,7 @@ var VirtualRenderer = function(container, theme) { this.$textLayer.addEventListener("changeCharacterSize", function() { _self.updateCharacterSize(); _self.onResize(true); + _self._signal("changeCharacterSize"); }); this.$size = { @@ -11879,6 +12201,15 @@ var VirtualRenderer = function(container, theme) { offset : 0, height : 1 }; + + this.scrollMargin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; this.$loop = new RenderLoop( this.$renderChanges.bind(this), @@ -11914,7 +12245,9 @@ var VirtualRenderer = function(container, theme) { this.setStyle("ace_nobold", !this.$allowBoldFonts); } + this.layerConfig.characterWidth = this.characterWidth = this.$textLayer.getCharacterWidth(); + this.layerConfig.lineHeight = this.lineHeight = this.$textLayer.getLineHeight(); this.$updatePrintMargin(); }; @@ -11971,78 +12304,94 @@ var VirtualRenderer = function(container, theme) { this.updateFontSize = function() { this.$textLayer.checkForSizeChanges(); }; - this.onResize = function(force, gutterWidth, width, height) { - var changes = 0; - var size = this.$size; + this.$changes = 0; + this.onResize = function(force, gutterWidth, width, height) { if (this.resizing > 2) return; - else if (this.resizing > 1) + else if (this.resizing > 0) this.resizing++; else this.resizing = force ? 1 : 0; + var el = this.container; if (!height) - height = dom.getInnerHeight(this.container); - - if (height && (force || size.height != height)) { - size.height = height; - changes = this.CHANGE_SIZE; - - size.scrollerHeight = this.scroller.clientHeight; - if (force || !size.scrollerHeight) { - size.scrollerHeight = size.height; - if (this.$horizScroll) - size.scrollerHeight -= this.scrollBar.getWidth(); - } - this.scrollBar.setHeight(size.scrollerHeight); - - if (this.session) { - this.session.setScrollTop(this.getScrollTop()); - changes = changes | this.CHANGE_FULL; - } - } - + height = el.clientHeight || el.scrollHeight; if (!width) - width = dom.getInnerWidth(this.container); + width = el.clientWidth || el.scrollWidth; - if (width && (force || this.resizing > 1 || size.width != width)) { - changes = this.CHANGE_SIZE; - size.width = width; - - var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; - this.scroller.style.left = gutterWidth + "px"; - size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBar.getWidth()); - this.scroller.style.right = this.scrollBar.getWidth() + "px"; - - if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) - changes = changes | this.CHANGE_FULL; - } - - if (!this.$size.scrollerHeight) - return; - - if (force) - this.$renderChanges(changes, true); - else - this.$loop.schedule(changes); + var changes = this.$updateCachedSize(force, gutterWidth, width, height); + + if (!this.$size.scrollerHeight || (!width && !height)) + return this.resizing = 0; if (force) this.$gutterLayer.$padding = null; if (force) - delete this.resizing; + this.$renderChanges(changes, true); + else + this.$loop.schedule(changes || this.$changes); + + if (this.resizing) + this.resizing = 0; + }; + + this.$updateCachedSize = function(force, gutterWidth, width, height) { + var changes = 0; + var size = this.$size; + if (height && (force || size.height != height)) { + size.height = height; + changes = this.CHANGE_SIZE; + + size.scrollerHeight = size.height; + if (this.$horizScroll) + size.scrollerHeight -= this.scrollBarH.getHeight(); + this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; + + if (this.session) { + this.session.setScrollTop(this.getScrollTop()); + changes = changes | this.CHANGE_SCROLL; + } + } + + if (width && (force || size.width != width)) { + changes = this.CHANGE_SIZE; + size.width = width; + + if (gutterWidth == null) + gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; + + this.gutterWidth = gutterWidth; + + this.scrollBarH.element.style.left = + this.scroller.style.left = gutterWidth + "px"; + size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth()); + + this.scrollBarH.element.style.right = + this.scroller.style.right = this.scrollBarV.getWidth() + "px"; + this.scroller.style.bottom = this.scrollBarH.getHeight() + "px"; + + if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) + changes = changes | this.CHANGE_FULL; + } + + if (changes) + this._signal("resize"); + + return changes; }; this.onGutterResize = function() { - var width = this.$size.width; var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; - this.scroller.style.left = gutterWidth + "px"; - this.$size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBar.getWidth()); + if (gutterWidth != this.gutterWidth) + this.$changes != this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); if (this.session.getUseWrapMode() && this.adjustWrapLimit()) this.$loop.schedule(this.CHANGE_FULL); - else + else { + this.$computeLayerConfig(); this.$loop.schedule(this.CHANGE_MARKER); + } }; this.adjustWrapLimit = function() { var availableWidth = this.$size.scrollerWidth - this.$padding * 2; @@ -12199,41 +12548,69 @@ var VirtualRenderer = function(container, theme) { this.$loop.schedule(this.CHANGE_FULL); this.$updatePrintMargin(); }; + + this.setScrollMargin = function(top, bottom, left, right) { + var sm = this.scrollMargin; + sm.top = top|0; + sm.bottom = bottom|0; + sm.right = right|0; + sm.left = left|0; + sm.v = sm.top + sm.bottom; + sm.h = sm.left + sm.right; + this.updateFull(); + }; this.getHScrollBarAlwaysVisible = function() { return this.$hScrollBarAlwaysVisible; }; this.setHScrollBarAlwaysVisible = function(alwaysVisible) { this.setOption("hScrollBarAlwaysVisible", alwaysVisible); }; + this.getVScrollBarAlwaysVisible = function() { + return this.$hScrollBarAlwaysVisible; + }; + this.setVScrollBarAlwaysVisible = function(alwaysVisible) { + this.setOption("vScrollBarAlwaysVisible", alwaysVisible); + }; - this.$updateScrollBar = function() { - this.scrollBar.setInnerHeight(this.layerConfig.maxHeight); - this.scrollBar.setScrollTop(this.scrollTop); + this.$updateScrollBarV = function() { + this.scrollBarV.setInnerHeight(this.layerConfig.maxHeight + this.scrollMargin.v); + this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top); + }; + this.$updateScrollBarH = function() { + this.scrollBarH.setInnerWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h); + this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left); }; this.$renderChanges = function(changes, force) { - if (!force && (!changes || !this.session || !this.container.offsetWidth)) - return; - + if (this.$changes) { + changes |= this.$changes; + this.$changes = 0; + } + if ((!this.session || !this.container.offsetWidth) || (!changes && !force)) { + this.$changes |= changes; + return; + } + if (!this.$size.width) + return this.onResize(true); + this._signal("beforeRender"); if (changes & this.CHANGE_FULL || changes & this.CHANGE_SIZE || changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES || - changes & this.CHANGE_SCROLL + changes & this.CHANGE_SCROLL || + changes & this.CHANGE_H_SCROLL ) - this.$computeLayerConfig(); + changes |= this.$computeLayerConfig(); if (changes & this.CHANGE_H_SCROLL) { - this.scroller.scrollLeft = this.scrollLeft; - var scrollLeft = this.scroller.scrollLeft; - this.scrollLeft = scrollLeft; - this.session.setScrollLeft(scrollLeft); - - this.scroller.className = this.scrollLeft == 0 ? "ace_scroller" : "ace_scroller ace_scroll-left"; + this.$updateScrollBarH(); + this.content.style.marginLeft = -this.scrollLeft + "px"; + this.scroller.className = this.scrollLeft <= 0 ? "ace_scroller" : "ace_scroller ace_scroll-left"; } if (changes & this.CHANGE_FULL) { this.$textLayer.checkForSizeChanges(); - this.$updateScrollBar(); + this.$updateScrollBarV(); + this.$updateScrollBarH(); this.$textLayer.update(this.layerConfig); if (this.$showGutter) this.$gutterLayer.update(this.layerConfig); @@ -12246,6 +12623,7 @@ var VirtualRenderer = function(container, theme) { return; } if (changes & this.CHANGE_SCROLL) { + this.$updateScrollBarV(); if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) this.$textLayer.update(this.layerConfig); else @@ -12258,7 +12636,6 @@ var VirtualRenderer = function(container, theme) { this.$cursorLayer.update(this.layerConfig); this.$highlightGutterLine && this.$updateGutterLineHighlight(); this.$moveTextAreaToCursor(); - this.$updateScrollBar(); this._signal("afterRender"); return; } @@ -12291,33 +12668,83 @@ var VirtualRenderer = function(container, theme) { this.$markerBack.update(this.layerConfig); } - if (changes & this.CHANGE_SIZE) - this.$updateScrollBar(); + if (changes & this.CHANGE_SIZE || changes & this.CHANGE_LINES) { + this.$updateScrollBarV(); + this.$updateScrollBarH(); + } this._signal("afterRender"); }; + + this.$autosize = function(height, width) { + var height = this.session.getScreenLength() * this.lineHeight; + var maxHeight = this.$maxLines * this.lineHeight; + var desiredHeight = Math.max( + (this.$minLines||1) * this.lineHeight, + Math.min(maxHeight, height) + ); + var vScroll = height > maxHeight; + + if (desiredHeight != this.desiredHeight || + this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { + if (vScroll != this.$vScroll) { + this.$vScroll = vScroll; + this.scrollBarV.setVisible(vScroll); + } + + var w = this.container.clientWidth; + this.container.style.height = desiredHeight + "px"; + this.$updateCachedSize(true, this.$gutterWidth, w, desiredHeight); + this.desiredHeight = desiredHeight; + } + }; + this.$computeLayerConfig = function() { - if (!this.$size.scrollerHeight) - return this.onResize(true); + if (this.$maxLines && this.lineHeight > 1) + this.$autosize(); var session = this.session; + + var hideScrollbars = this.$size.height <= 2 * this.lineHeight; + var screenLines = this.session.getScreenLength() + var maxHeight = screenLines * this.lineHeight; var offset = this.scrollTop % this.lineHeight; var minHeight = this.$size.scrollerHeight + this.lineHeight; var longestLine = this.$getLongestLine(); + + var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || + this.$size.scrollerWidth - longestLine - 2 * this.$padding < 0); - var horizScroll = this.$hScrollBarAlwaysVisible || this.$size.scrollerWidth - longestLine < 0; - var horizScrollChanged = this.$horizScroll !== horizScroll; - this.$horizScroll = horizScroll; - if (horizScrollChanged) { - this.scroller.style.overflowX = horizScroll ? "scroll" : "hidden"; - if (!horizScroll) - this.session.setScrollLeft(0); + var hScrollChanged = this.$horizScroll !== horizScroll; + if (hScrollChanged) { + this.$horizScroll = horizScroll; + this.scrollBarH.setVisible(horizScroll); } - var maxHeight = this.session.getScreenLength() * this.lineHeight; - this.session.setScrollTop(Math.max(0, Math.min(this.scrollTop, maxHeight - this.$size.scrollerHeight))); + + if (!this.$maxLines && this.$scrollPastEnd) { + if (this.scrollTop > maxHeight - this.$size.scrollerHeight) + maxHeight += Math.min( + (this.$size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd, + this.scrollTop - maxHeight + this.$size.scrollerHeight + ); + } + + var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || + this.$size.scrollerHeight - maxHeight < 0); + var vScrollChanged = this.$vScroll !== vScroll; + if (vScrollChanged) { + this.$vScroll = vScroll; + this.scrollBarV.setVisible(vScroll); + } + + this.session.setScrollTop(Math.max(-this.scrollMargin.top, + Math.min(this.scrollTop, maxHeight - this.$size.scrollerHeight + this.scrollMargin.v))); + + this.session.setScrollLeft(Math.max(-this.scrollMargin.left, Math.min(this.scrollLeft, + longestLine + 2 * this.$padding - this.$size.scrollerWidth + this.scrollMargin.h))); var lineCount = Math.ceil(minHeight / this.lineHeight) - 1; var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight)); @@ -12339,6 +12766,14 @@ var VirtualRenderer = function(container, theme) { offset = this.scrollTop - firstRowScreen * lineHeight; + var changes = 0; + if (hScrollChanged || vScrollChanged) { + changes = this.$updateCachedSize(true, this.gutterWidth, this.$size.width, this.$size.height); + this._signal("scrollbarVisibilityChanged"); + if (vScrollChanged) + longestLine = this.$getLongestLine(); + } + this.layerConfig = { width : longestLine, padding : this.$padding, @@ -12357,8 +12792,8 @@ var VirtualRenderer = function(container, theme) { this.content.style.marginTop = (-offset) + "px"; this.content.style.width = longestLine + 2 * this.$padding + "px"; this.content.style.height = minHeight + "px"; - if (horizScrollChanged) - this.onResize(true); + + return changes; }; this.$updateLines = function() { @@ -12430,12 +12865,18 @@ var VirtualRenderer = function(container, theme) { var left = pos.left; var top = pos.top; + + var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; - if (this.scrollTop > top) { + if (scrollTop > top) { if (offset) top -= offset * this.$size.scrollerHeight; + if (top == 0) + top = - this.scrollMargin.top; + else if (top == 0) + top = + this.scrollMargin.bottom; this.session.setScrollTop(top); - } else if (this.scrollTop + this.$size.scrollerHeight < top + this.lineHeight) { + } else if (scrollTop + this.$size.scrollerHeight < top + this.lineHeight) { if (offset) top += offset * this.$size.scrollerHeight; this.session.setScrollTop(top + this.lineHeight - this.$size.scrollerHeight); @@ -12445,10 +12886,12 @@ var VirtualRenderer = function(container, theme) { if (scrollLeft > left) { if (left < this.$padding + 2 * this.layerConfig.characterWidth) - left = 0; + left = -this.scrollMargin.left; this.session.setScrollLeft(left); } else if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) { this.session.setScrollLeft(Math.round(left + this.characterWidth - this.$size.scrollerWidth)); + } else if (scrollLeft <= this.$padding && left - scrollLeft < this.characterWidth) { + this.session.setScrollLeft(0); } }; this.getScrollTop = function() { @@ -12508,29 +12951,42 @@ var VirtualRenderer = function(container, theme) { this.animateScrolling = function(fromValue, callback) { var toValue = this.scrollTop; - if (this.$animatedScroll) { - var _self = this; - var steps = _self.$calcSteps(fromValue, toValue); - this.$scrollAnimation = {from: fromValue, to: toValue}; - - clearInterval(this.$timer); - - _self.session.setScrollTop(steps.shift()); - this.$timer = setInterval(function() { - if (steps.length) { - _self.session.setScrollTop(steps.shift()); - _self.session.$scrollTop = toValue; - } else if (toValue != null) { - _self.session.$scrollTop = -1; - _self.session.setScrollTop(toValue); - toValue = null; - } else { - _self.$timer = clearInterval(_self.$timer); - _self.$scrollAnimation = null; - callback && callback(); - } - }, 10); + if (!this.$animatedScroll) + return; + var _self = this; + + if (fromValue == toValue) + return; + + if (this.$scrollAnimation) { + var oldSteps = this.$scrollAnimation.steps; + if (oldSteps.length) { + fromValue = oldSteps[0]; + if (fromValue == toValue) + return; + } } + + var steps = _self.$calcSteps(fromValue, toValue); + this.$scrollAnimation = {from: fromValue, to: toValue, steps: steps}; + + clearInterval(this.$timer); + + _self.session.setScrollTop(steps.shift()); + this.$timer = setInterval(function() { + if (steps.length) { + _self.session.setScrollTop(steps.shift()); + _self.session.$scrollTop = toValue; + } else if (toValue != null) { + _self.session.$scrollTop = -1; + _self.session.setScrollTop(toValue); + toValue = null; + } else { + _self.$timer = clearInterval(_self.$timer); + _self.$scrollAnimation = null; + callback && callback(); + } + }, 10); }; this.scrollToY = function(scrollTop) { if (this.scrollTop !== scrollTop) { @@ -12539,9 +12995,6 @@ var VirtualRenderer = function(container, theme) { } }; this.scrollToX = function(scrollLeft) { - if (scrollLeft < 0) - scrollLeft = 0; - if (this.scrollLeft !== scrollLeft) this.scrollLeft = scrollLeft; this.$loop.schedule(this.CHANGE_H_SCROLL); @@ -12551,9 +13004,13 @@ var VirtualRenderer = function(container, theme) { deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX); }; this.isScrollableBy = function(deltaX, deltaY) { - if (deltaY < 0 && this.session.getScrollTop() >= 1) + if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top) return true; - if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight - this.layerConfig.maxHeight < -1) + if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight + - this.layerConfig.maxHeight - (this.$size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd + < -1 + this.scrollMargin.bottom) + return true; + if (deltaX) return true; }; @@ -12621,7 +13078,7 @@ var VirtualRenderer = function(container, theme) { this.textarea.style.cssText = this.$composition.cssText; this.$composition = null; }; - this.setTheme = function(theme) { + this.setTheme = function(theme, cb) { var _self = this; this.$themeValue = theme; _self._dispatchEvent('themeChange',{theme:theme}); @@ -12635,7 +13092,7 @@ var VirtualRenderer = function(container, theme) { function afterLoad(module) { if (_self.$themeValue != theme) - return; + return cb && cb(); if (!module.cssClass) return; dom.importCssString( @@ -12660,7 +13117,8 @@ var VirtualRenderer = function(container, theme) { _self.onResize(); } - _self._dispatchEvent('themeLoaded',{theme:module}); + _self._dispatchEvent('themeLoaded', {theme:module}); + cb && cb(); } }; this.getTheme = function() { @@ -12749,13 +13207,19 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { value: true }, hScrollBarAlwaysVisible: { - set: function(alwaysVisible) { - this.$hScrollBarAlwaysVisible = alwaysVisible; + set: function(val) { if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll) this.$loop.schedule(this.CHANGE_SCROLL); }, initialValue: false }, + vScrollBarAlwaysVisible: { + set: function(val) { + if (!this.$vScrollBarAlwaysVisible || !this.$vScroll) + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: false + }, fontSize: { set: function(size) { if (typeof size == "number") @@ -12770,13 +13234,34 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", { this.container.style.fontFamily = name; this.updateFontSize(); } + }, + maxLines: { + set: function(val) { + this.updateFull(); + } + }, + minLines: { + set: function(val) { + this.updateFull(); + } + }, + scrollPastEnd: { + set: function(val) { + val = +val || 0; + if (this.$scrollPastEnd == val) + return; + this.$scrollPastEnd = val; + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: 0, + handlesSet: true } }); exports.VirtualRenderer = VirtualRenderer; }); -define('ace/layer/gutter', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/oop', 'ace/lib/lang', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/layer/gutter', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/oop', 'ace/lib/lang', 'ace/lib/event_emitter'], function(require, exports, module) { var dom = require("../lib/dom"); @@ -12919,7 +13404,7 @@ var Gutter = function(parentEl) { var gutterWidth = ("" + lastLineNumber).length * config.characterWidth; var padding = this.$padding || this.$computePadding(); gutterWidth += padding.left + padding.right; - if (gutterWidth !== this.gutterWidth) { + if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) { this.gutterWidth = gutterWidth; this.element.style.width = Math.ceil(this.gutterWidth) + "px"; this._emit("changeGutterWidth", gutterWidth); @@ -12945,9 +13430,9 @@ var Gutter = function(parentEl) { if (!this.element.firstChild) return {left: 0, right: 0}; var style = dom.computedStyle(this.element.firstChild); - this.$padding = {} - this.$padding.left = parseInt(style.paddingLeft) + 1; - this.$padding.right = parseInt(style.paddingRight); + this.$padding = {}; + this.$padding.left = parseInt(style.paddingLeft) + 1 || 0; + this.$padding.right = parseInt(style.paddingRight) || 0; return this.$padding; }; @@ -12966,7 +13451,7 @@ exports.Gutter = Gutter; }); -define('ace/layer/marker', ['require', 'exports', 'module' , 'ace/range', 'ace/lib/dom'], function(require, exports, module) { +ace.define('ace/layer/marker', ['require', 'exports', 'module' , 'ace/range', 'ace/lib/dom'], function(require, exports, module) { var Range = require("../range").Range; @@ -13141,7 +13626,7 @@ exports.Marker = Marker; }); -define('ace/layer/text', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/lang', 'ace/lib/useragent', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/layer/text', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/lang', 'ace/lib/useragent', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -13744,7 +14229,7 @@ exports.Text = Text; }); -define('ace/layer/cursor', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { +ace.define('ace/layer/cursor', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { var dom = require("../lib/dom"); @@ -13930,14 +14415,14 @@ exports.Cursor = Cursor; }); -define('ace/scrollbar', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/event', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/scrollbar', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/dom', 'ace/lib/event', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("./lib/oop"); var dom = require("./lib/dom"); var event = require("./lib/event"); var EventEmitter = require("./lib/event_emitter").EventEmitter; -var ScrollBar = function(parent) { +var ScrollBarV = function(parent, renderer) { this.element = dom.createElement("div"); this.element.className = "ace_scrollbar"; @@ -13946,43 +14431,108 @@ var ScrollBar = function(parent) { this.element.appendChild(this.inner); parent.appendChild(this.element); + renderer.$scrollbarWidth = this.width = dom.scrollbarWidth(parent.ownerDocument); + this.fullWidth = this.width; this.element.style.width = (this.width || 15) + 5 + "px"; + this.setVisible(false); + this.element.style.overflowY = "scroll"; + + event.addListener(this.element, "scroll", this.onScrollV.bind(this)); +}; - event.addListener(this.element, "scroll", this.onScroll.bind(this)); +var ScrollBarH = function(parent, renderer) { + this.element = dom.createElement("div"); + this.element.className = "ace_scrollbar-h"; + + this.inner = dom.createElement("div"); + this.inner.className = "ace_scrollbar-inner"; + this.element.appendChild(this.inner); + + parent.appendChild(this.element); + this.height = renderer.$scrollbarWidth; + this.fullHeight = this.height; + this.element.style.height = (this.height || 15) + 5 + "px"; + this.setVisible(false); + this.element.style.overflowX = "scroll"; + + event.addListener(this.element, "scroll", this.onScrollH.bind(this)); }; (function() { oop.implement(this, EventEmitter); - this.onScroll = function() { + + this.setVisible = function(show) { + if (show) { + this.element.style.display = ""; + if (this.fullWidth) + this.width = this.fullWidth; + if (this.fullHeight) + this.height = this.fullHeight; + } else { + this.element.style.display = "none"; + this.height = this.width = 0; + } + }; + this.onScrollV = function() { if (!this.skipEvent) { this.scrollTop = this.element.scrollTop; this._emit("scroll", {data: this.scrollTop}); } this.skipEvent = false; }; + this.onScrollH = function() { + if (!this.skipEvent) { + this.scrollLeft = this.element.scrollLeft; + this._emit("scroll", {data: this.scrollLeft}); + } + this.skipEvent = false; + }; this.getWidth = function() { return this.width; }; + + this.getHeight = function() { + return this.height; + }; this.setHeight = function(height) { this.element.style.height = height + "px"; }; + + this.setWidth = function(width) { + this.element.style.width = width + "px"; + }; this.setInnerHeight = function(height) { this.inner.style.height = height + "px"; }; + + this.setInnerWidth = function(width) { + this.inner.style.width = width + "px"; + }; this.setScrollTop = function(scrollTop) { if (this.scrollTop != scrollTop) { this.skipEvent = true; this.scrollTop = this.element.scrollTop = scrollTop; } }; + this.setScrollLeft = function(scrollLeft) { + if (this.scrollLeft != scrollLeft) { + this.skipEvent = true; + this.scrollLeft = this.element.scrollLeft = scrollLeft; + } + }; -}).call(ScrollBar.prototype); +}).call(ScrollBarV.prototype); +ScrollBarH.prototype = ScrollBarV.prototype; -exports.ScrollBar = ScrollBar; + + +exports.ScrollBar = ScrollBarV; // backward compatibility +exports.ScrollBarV = ScrollBarV; +exports.ScrollBarH = ScrollBarH; }); -define('ace/renderloop', ['require', 'exports', 'module' , 'ace/lib/event'], function(require, exports, module) { +ace.define('ace/renderloop', ['require', 'exports', 'module' , 'ace/lib/event'], function(require, exports, module) { var event = require("./lib/event"); @@ -14019,7 +14569,7 @@ var RenderLoop = function(onRender, win) { exports.RenderLoop = RenderLoop; }); -define('ace/multi_select', ['require', 'exports', 'module' , 'ace/range_list', 'ace/range', 'ace/selection', 'ace/mouse/multi_select_handler', 'ace/lib/event', 'ace/lib/lang', 'ace/commands/multi_select_commands', 'ace/search', 'ace/edit_session', 'ace/editor'], function(require, exports, module) { +ace.define('ace/multi_select', ['require', 'exports', 'module' , 'ace/range_list', 'ace/range', 'ace/selection', 'ace/mouse/multi_select_handler', 'ace/lib/event', 'ace/lib/lang', 'ace/commands/multi_select_commands', 'ace/search', 'ace/edit_session', 'ace/editor', 'ace/config'], function(require, exports, module) { var RangeList = require("./range_list").RangeList; var Range = require("./range").Range; @@ -14716,13 +15266,16 @@ exports.onSessionChange = function(e) { } }; function MultiSelect(editor) { + if (editor.$multiselectOnSessionChange) + return; editor.$onAddRange = editor.$onAddRange.bind(editor); editor.$onRemoveRange = editor.$onRemoveRange.bind(editor); editor.$onMultiSelect = editor.$onMultiSelect.bind(editor); editor.$onSingleSelect = editor.$onSingleSelect.bind(editor); + editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor); - exports.onSessionChange.call(editor, editor); - editor.on("changeSession", exports.onSessionChange.bind(editor)); + editor.$multiselectOnSessionChange(editor); + editor.on("changeSession", editor.$multiselectOnSessionChange); editor.on("mousedown", onMouseDown); editor.commands.addCommands(commands.defaultCommands); @@ -14757,9 +15310,28 @@ function addAltCursorListeners(editor){ exports.MultiSelect = MultiSelect; + +require("./config").defineOptions(Editor.prototype, "editor", { + enableMultiselect: { + set: function(val) { + MultiSelect(this); + if (val) { + this.on("changeSession", this.$multiselectOnSessionChange); + this.on("mousedown", onMouseDown); + } else { + this.off("changeSession", this.$multiselectOnSessionChange); + this.off("mousedown", onMouseDown); + } + }, + value: true + } +}) + + + }); -define('ace/mouse/multi_select_handler', ['require', 'exports', 'module' , 'ace/lib/event'], function(require, exports, module) { +ace.define('ace/mouse/multi_select_handler', ['require', 'exports', 'module' , 'ace/lib/event'], function(require, exports, module) { var event = require("../lib/event"); function isSamePoint(p1, p2) { @@ -14887,7 +15459,7 @@ exports.onMouseDown = onMouseDown; }); -define('ace/commands/multi_select_commands', ['require', 'exports', 'module' , 'ace/keyboard/hash_handler'], function(require, exports, module) { +ace.define('ace/commands/multi_select_commands', ['require', 'exports', 'module' , 'ace/keyboard/hash_handler'], function(require, exports, module) { exports.defaultCommands = [{ name: "addCursorAbove", exec: function(editor) { editor.selectMoreLines(-1); }, @@ -14951,7 +15523,7 @@ exports.keyboardHandler = new HashHandler(exports.multiSelectCommands); }); -define('ace/worker/worker_client', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/config'], function(require, exports, module) { +ace.define('ace/worker/worker_client', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/config'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -15036,6 +15608,7 @@ var WorkerClient = function(topLevelNamespaces, mod, classname) { this.terminate = function() { this._emit("terminate", {}); + this.deltaQueue = null; this.$worker.terminate(); this.$worker = null; this.$doc.removeEventListener("change", this.changeListener); @@ -15141,7 +15714,7 @@ exports.UIWorkerClient = UIWorkerClient; exports.WorkerClient = WorkerClient; }); -define('ace/placeholder', ['require', 'exports', 'module' , 'ace/range', 'ace/lib/event_emitter', 'ace/lib/oop'], function(require, exports, module) { +ace.define('ace/placeholder', ['require', 'exports', 'module' , 'ace/range', 'ace/lib/event_emitter', 'ace/lib/oop'], function(require, exports, module) { var Range = require("./range").Range; @@ -15313,7 +15886,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) exports.PlaceHolder = PlaceHolder; }); -define('ace/mode/folding/fold_mode', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { +ace.define('ace/mode/folding/fold_mode', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { var Range = require("../../range").Range; @@ -15402,7 +15975,7 @@ var FoldMode = exports.FoldMode = function() {}; }); -define('ace/theme/textmate', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { +ace.define('ace/theme/textmate', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { exports.isDark = false; @@ -15488,10 +16061,10 @@ color: rgb(104, 104, 91);\ .ace-tm .ace_entity.ace_name.ace_function {\ color: #0000A2;\ }\ -.ace-tm .ace_markup.ace_heading {\ +.ace-tm .ace_heading {\ color: rgb(12, 7, 255);\ }\ -.ace-tm .ace_markup.ace_list {\ +.ace-tm .ace_list {\ color:rgb(185, 6, 144);\ }\ .ace-tm .ace_meta.ace_tag {\ @@ -15537,7 +16110,7 @@ dom.importCssString(exports.cssText, exports.cssClass); }); ; (function() { - window.require(["ace/ace"], function(a) { + ace.require(["ace/ace"], function(a) { a && a.config.init(); if (!window.ace) window.ace = {}; diff --git a/lib/client/edit/ext-searchbox.js b/lib/client/edit/ext-searchbox.js index 81c5b74f..f2990d59 100644 --- a/lib/client/edit/ext-searchbox.js +++ b/lib/client/edit/ext-searchbox.js @@ -28,7 +28,7 @@ * * ***** END LICENSE BLOCK ***** */ -define('ace/ext/searchbox', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/lang', 'ace/lib/event', 'ace/keyboard/hash_handler', 'ace/lib/keys'], function(require, exports, module) { +ace.define('ace/ext/searchbox', ['require', 'exports', 'module' , 'ace/lib/dom', 'ace/lib/lang', 'ace/lib/event', 'ace/keyboard/hash_handler', 'ace/lib/keys'], function(require, exports, module) { var dom = require("../lib/dom"); @@ -198,7 +198,7 @@ var html = '\
\ \ - \ + \ \
\
\ @@ -244,7 +244,7 @@ var SearchBox = function(editor, range, showReplaceForm) { event.stopPropagation(e); }); event.addListener(sb, "click", function(e) { - var t = e.target; + var t = e.target || e.srcElement; var action = t.getAttribute("action"); if (action && _this[action]) _this[action](); @@ -369,10 +369,18 @@ var SearchBox = function(editor, range, showReplaceForm) { this.find(true, true); }; this.replace = function() { - this.editor.replace(this.replaceInput.value); + if (!this.editor.getReadOnly()) + this.editor.replace(this.replaceInput.value); + }; + this.replaceAndFindNext = function() { + if (!this.editor.getReadOnly()) { + this.editor.replace(this.replaceInput.value); + this.findNext() + } }; this.replaceAll = function() { - this.editor.replaceAll(this.replaceInput.value); + if (!this.editor.getReadOnly()) + this.editor.replaceAll(this.replaceInput.value); }; this.hide = function() { @@ -403,45 +411,4 @@ exports.Search = function(editor, isReplace) { sb.show(editor.session.getTextRange(), isReplace); }; - -exports.ISearch = function(session, options) { - this.$changeListener = this.$changeListener.bind(this); - this.startRange = session.selection.toOrientedRange(); - this.options = options || {}; -}; - -(function(){ - this.setSession = function(session) { - if (this.session) { - this.session.removeListener(this.$changeListener); - } - this.session = session; - this.session.addListener(this.$changeListener); - }; - this.setSearchString = function() { - - }; - this.getValue = function() { - if (this.value == null) - this.value = this.session.getValue(); - return this.value; - }; - this.$changeListener = function() { - this.value = null; - }; - this.find = function() { - - }; - this.$edgeBefore = function() { - this.cursor = this.startRange[this.options.backwards ? "start" : "end"]; - }; - this.$edgeAfter = function() { - - }; - this.next = function(dir) { - - }; -}).call(exports.ISearch.prototype); - - }); diff --git a/lib/client/edit/mode-javascript.js b/lib/client/edit/mode-javascript.js index 5bfc25dd..bf541754 100644 --- a/lib/client/edit/mode-javascript.js +++ b/lib/client/edit/mode-javascript.js @@ -28,7 +28,7 @@ * * ***** END LICENSE BLOCK ***** */ -define('ace/mode/javascript', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text', 'ace/tokenizer', 'ace/mode/javascript_highlight_rules', 'ace/mode/matching_brace_outdent', 'ace/range', 'ace/worker/worker_client', 'ace/mode/behaviour/cstyle', 'ace/mode/folding/cstyle'], function(require, exports, module) { +ace.define('ace/mode/javascript', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text', 'ace/tokenizer', 'ace/mode/javascript_highlight_rules', 'ace/mode/matching_brace_outdent', 'ace/range', 'ace/worker/worker_client', 'ace/mode/behaviour/cstyle', 'ace/mode/folding/cstyle'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -42,9 +42,12 @@ var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; var CStyleFoldMode = require("./folding/cstyle").FoldMode; var Mode = function() { - this.$tokenizer = new Tokenizer(new JavaScriptHighlightRules().getRules()); + var highlighter = new JavaScriptHighlightRules(); + + this.$tokenizer = new Tokenizer(highlighter.getRules()); this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CstyleBehaviour(); + this.$keywordList = highlighter.$keywordList; this.foldingRules = new CStyleFoldMode(); }; oop.inherits(Mode, TextMode); @@ -114,7 +117,7 @@ oop.inherits(Mode, TextMode); exports.Mode = Mode; }); -define('ace/mode/javascript_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/doc_comment_highlight_rules', 'ace/mode/text_highlight_rules'], function(require, exports, module) { +ace.define('ace/mode/javascript_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/doc_comment_highlight_rules', 'ace/mode/text_highlight_rules'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -163,7 +166,8 @@ var JavaScriptHighlightRules = function() { "no_regex" : [ { token : "comment", - regex : /\/\/.*$/ + regex : "\\/\\/", + next : "line_comment" }, DocCommentHighlightRules.getStartRule("doc-start"), { @@ -238,7 +242,7 @@ var JavaScriptHighlightRules = function() { next : "start" }, { token : ["punctuation.operator", "support.function"], - regex : /(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:opzzzz|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/ + regex : /(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/ }, { token : ["punctuation.operator", "support.function.dom"], regex : /(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/ @@ -283,8 +287,8 @@ var JavaScriptHighlightRules = function() { next : "comment_regex_allowed" }, { token : "comment", - regex : "\\/\\/.*$", - next : "start" + regex : "\\/\\/", + next : "line_comment_regex_allowed" }, { token: "string.regexp", regex: "\\/", @@ -371,6 +375,14 @@ var JavaScriptHighlightRules = function() { {token : "comment", regex : "\\*\\/", next : "no_regex"}, {defaultToken : "comment"} ], + "line_comment_regex_allowed" : [ + {token : "comment", regex : "$|^", next : "start"}, + {defaultToken : "comment"} + ], + "line_comment" : [ + {token : "comment", regex : "$|^", next : "no_regex"}, + {defaultToken : "comment"} + ], "qqstring" : [ { token : "constant.language.escape", @@ -414,7 +426,7 @@ oop.inherits(JavaScriptHighlightRules, TextHighlightRules); exports.JavaScriptHighlightRules = JavaScriptHighlightRules; }); -define('ace/mode/doc_comment_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text_highlight_rules'], function(require, exports, module) { +ace.define('ace/mode/doc_comment_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text_highlight_rules'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -458,7 +470,7 @@ exports.DocCommentHighlightRules = DocCommentHighlightRules; }); -define('ace/mode/matching_brace_outdent', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { +ace.define('ace/mode/matching_brace_outdent', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { var Range = require("../range").Range; @@ -498,7 +510,7 @@ var MatchingBraceOutdent = function() {}; exports.MatchingBraceOutdent = MatchingBraceOutdent; }); -define('ace/mode/behaviour/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour', 'ace/token_iterator', 'ace/lib/lang'], function(require, exports, module) { +ace.define('ace/mode/behaviour/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour', 'ace/token_iterator', 'ace/lib/lang'], function(require, exports, module) { var oop = require("../../lib/oop"); @@ -821,7 +833,7 @@ oop.inherits(CstyleBehaviour, Behaviour); exports.CstyleBehaviour = CstyleBehaviour; }); -define('ace/mode/folding/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/range', 'ace/mode/folding/fold_mode'], function(require, exports, module) { +ace.define('ace/mode/folding/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/range', 'ace/mode/folding/fold_mode'], function(require, exports, module) { var oop = require("../../lib/oop"); @@ -873,4 +885,4 @@ oop.inherits(FoldMode, BaseFoldMode); }).call(FoldMode.prototype); -}); \ No newline at end of file +}); diff --git a/lib/client/edit/theme-tomorrow_night_blue.js b/lib/client/edit/theme-tomorrow_night_blue.js index 86c6e45f..30e1146e 100644 --- a/lib/client/edit/theme-tomorrow_night_blue.js +++ b/lib/client/edit/theme-tomorrow_night_blue.js @@ -28,7 +28,7 @@ * * ***** END LICENSE BLOCK ***** */ -define('ace/theme/tomorrow_night_blue', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { +ace.define('ace/theme/tomorrow_night_blue', ['require', 'exports', 'module' , 'ace/lib/dom'], function(require, exports, module) { exports.isDark = true; exports.cssClass = "ace-tomorrow-night-blue"; @@ -119,7 +119,7 @@ color: #BBDAFF\ .ace-tomorrow-night-blue .ace_support.ace_type {\ color: #FFEEAD\ }\ -.ace-tomorrow-night-blue .ace_markup.ace_heading,\ +.ace-tomorrow-night-blue .ace_heading,\ .ace-tomorrow-night-blue .ace_string {\ color: #D1F1A9\ }\ @@ -133,13 +133,10 @@ color: #FF9DA4\ .ace-tomorrow-night-blue .ace_comment {\ color: #7285B7\ }\ -.ace-tomorrow-night-blue .ace_markup.ace_underline {\ -text-decoration: underline\ -}\ .ace-tomorrow-night-blue .ace_indent-guide {\ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYJDzqfwPAANXAeNsiA+ZAAAAAElFTkSuQmCC) right repeat-y;\ }"; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass); -}); \ No newline at end of file +}); diff --git a/lib/client/edit/worker-javascript.js b/lib/client/edit/worker-javascript.js index 95aee706..8beac737 100644 --- a/lib/client/edit/worker-javascript.js +++ b/lib/client/edit/worker-javascript.js @@ -4,16 +4,15 @@ if (typeof window.window != "undefined" && window.document) { return; } -window.console = { - log: function() { - var msgs = Array.prototype.slice.call(arguments, 0); - postMessage({type: "log", data: msgs}); - }, - error: function() { - var msgs = Array.prototype.slice.call(arguments, 0); - postMessage({type: "log", data: msgs}); - } +window.console = function() { + var msgs = Array.prototype.slice.call(arguments, 0); + postMessage({type: "log", data: msgs}); }; +window.console.error = +window.console.warn = +window.console.log = +window.console.trace = window.console; + window.window = window; window.ace = window; @@ -86,10 +85,9 @@ window.define = function(id, deps, factory) { }; require.modules[id] = { + exports: {}, factory: function() { - var module = { - exports: {} - }; + var module = this; var returnExports = factory(req, module.exports, module); if (returnExports) module.exports = returnExports; @@ -158,7 +156,7 @@ window.onmessage = function(e) { }; })(this); -define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) { var EventEmitter = {}; @@ -283,7 +281,7 @@ exports.EventEmitter = EventEmitter; }); -define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) { exports.inherits = (function() { @@ -309,7 +307,7 @@ exports.implement = function(proto, mixin) { }); -define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) { function Empty() {} @@ -1006,7 +1004,7 @@ var toObject = function (o) { }); -define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/mode/javascript/jshint'], function(require, exports, module) { +ace.define('ace/mode/javascript_worker', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/worker/mirror', 'ace/mode/javascript/jshint'], function(require, exports, module) { var oop = require("../lib/oop"); @@ -1055,8 +1053,8 @@ oop.inherits(JavaScriptWorker, Mirror); (function() { this.setOptions = function(options) { this.options = options || { - es5: true, esnext: true, + moz: true, devel: true, browser: true, node: true, @@ -1153,7 +1151,7 @@ oop.inherits(JavaScriptWorker, Mirror); }).call(JavaScriptWorker.prototype); }); -define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) { +ace.define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) { var Document = require("../document").Document; @@ -1196,7 +1194,7 @@ var Mirror = exports.Mirror = function(sender) { }); -define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) { +ace.define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) { var oop = require("./lib/oop"); @@ -1282,7 +1280,7 @@ var Document = function(text) { }; this.getTextRange = function(range) { if (range.start.row == range.end.row) { - return this.$lines[range.start.row] + return this.getLine(range.start.row) .substring(range.start.column, range.end.column); } var lines = this.getLines(range.start.row, range.end.row); @@ -1548,7 +1546,7 @@ var Document = function(text) { exports.Document = Document; }); -define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) { var comparePoints = function(p1, p2) { return p1.row - p2.row || p1.column - p2.column; @@ -1787,36 +1785,31 @@ Range.comparePoints = function(p1, p2) { exports.Range = Range; }); -define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { +ace.define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) { var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Anchor = exports.Anchor = function(doc, row, column) { - this.document = doc; - + this.$onChange = this.onChange.bind(this); + this.attach(doc); + if (typeof column == "undefined") this.setPosition(row.row, row.column); else this.setPosition(row, column); - - this.$onChange = this.onChange.bind(this); - doc.on("change", this.$onChange); }; (function() { oop.implement(this, EventEmitter); - this.getPosition = function() { return this.$clipPositionToDocument(this.row, this.column); }; - this.getDocument = function() { return this.document; }; - this.onChange = function(e) { var delta = e.data; var range = delta.range; @@ -1878,7 +1871,6 @@ var Anchor = exports.Anchor = function(doc, row, column) { this.setPosition(row, column, true); }; - this.setPosition = function(row, column, noClip) { var pos; if (noClip) { @@ -1905,10 +1897,13 @@ var Anchor = exports.Anchor = function(doc, row, column) { value: pos }); }; - this.detach = function() { this.document.removeEventListener("change", this.$onChange); }; + this.attach = function(doc) { + this.document = doc || this.document; + this.document.on("change", this.$onChange); + }; this.$clipPositionToDocument = function(row, column) { var pos = {}; @@ -1935,7 +1930,7 @@ var Anchor = exports.Anchor = function(doc, row, column) { }); -define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) { exports.stringReverse = function(string) { @@ -2111,13 +2106,1089 @@ exports.delayedCall = function(fcn, defaultTimeout) { return _self; }; }); -define('ace/mode/javascript/jshint', ['require', 'exports', 'module' ], function(require, exports, module) { +ace.define('ace/mode/javascript/jshint', ['require', 'exports', 'module' ], function(require, exports, module) { +var require; +require=(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s 0) { + var fn = queue.shift(); + fn(); + } + } + }, true); + + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; + } + + return function nextTick(fn) { + setTimeout(fn, 0); + }; +})(); + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +} +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; + +}, +{}], +2:[function(req,module,exports){ +(function(process){if (!process.EventEmitter) process.EventEmitter = function () {}; + +var EventEmitter = exports.EventEmitter = process.EventEmitter; +var isArray = typeof Array.isArray === 'function' + ? Array.isArray + : function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]' + } +; +function indexOf (xs, x) { + if (xs.indexOf) return xs.indexOf(x); + for (var i = 0; i < xs.length; i++) { + if (x === xs[i]) return i; + } + return -1; +} +var defaultMaxListeners = 200; +EventEmitter.prototype.setMaxListeners = function(n) { + if (!this._events) this._events = {}; + this._events.maxListeners = n; +}; + + +EventEmitter.prototype.emit = function(type) { + if (type === 'error') { + if (!this._events || !this._events.error || + (isArray(this._events.error) && !this._events.error.length)) + { + if (arguments[1] instanceof Error) { + throw arguments[1]; // Unhandled 'error' event + } else { + throw new Error("Uncaught, unspecified 'error' event."); + } + return false; + } + } + + if (!this._events) return false; + var handler = this._events[type]; + if (!handler) return false; + + if (typeof handler == 'function') { + switch (arguments.length) { + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + default: + var args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + return true; + + } else if (isArray(handler)) { + var args = Array.prototype.slice.call(arguments, 1); + + var listeners = handler.slice(); + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + return true; + + } else { + return false; + } +}; +EventEmitter.prototype.addListener = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('addListener only takes instances of Function'); + } + + if (!this._events) this._events = {}; + this.emit('newListener', type, listener); + + if (!this._events[type]) { + this._events[type] = listener; + } else if (isArray(this._events[type])) { + if (!this._events[type].warned) { + var m; + if (this._events.maxListeners !== undefined) { + m = this._events.maxListeners; + } else { + m = defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + console.trace(); + } + } + this._events[type].push(listener); + } else { + this._events[type] = [this._events[type], listener]; + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + var self = this; + self.on(type, function g() { + self.removeListener(type, g); + listener.apply(this, arguments); + }); + + return this; +}; + +EventEmitter.prototype.removeListener = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('removeListener only takes instances of Function'); + } + if (!this._events || !this._events[type]) return this; + + var list = this._events[type]; + + if (isArray(list)) { + var i = indexOf(list, listener); + if (i < 0) return this; + list.splice(i, 1); + if (list.length == 0) + delete this._events[type]; + } else if (this._events[type] === listener) { + delete this._events[type]; + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + if (arguments.length === 0) { + this._events = {}; + return this; + } + if (type && this._events && this._events[type]) this._events[type] = null; + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + if (!this._events) this._events = {}; + if (!this._events[type]) this._events[type] = []; + if (!isArray(this._events[type])) { + this._events[type] = [this._events[type]]; + } + return this._events[type]; +}; + +})(req("__browserify_process")) +}, +{"__browserify_process":1}], +3:[function(req,module,exports){ +(function(){// jshint -W001 + +exports.reservedVars = { + arguments : false, + NaN : false +}; + +exports.ecmaIdentifiers = { + Array : false, + Boolean : false, + Date : false, + decodeURI : false, + decodeURIComponent : false, + encodeURI : false, + encodeURIComponent : false, + Error : false, + "eval" : false, + EvalError : false, + Function : false, + hasOwnProperty : false, + isFinite : false, + isNaN : false, + JSON : false, + Math : false, + Map : false, + Number : false, + Object : false, + parseInt : false, + parseFloat : false, + RangeError : false, + ReferenceError : false, + RegExp : false, + Set : false, + String : false, + SyntaxError : false, + TypeError : false, + URIError : false, + WeakMap : false +}; + +exports.browser = { + ArrayBuffer : false, + ArrayBufferView : false, + Audio : false, + Blob : false, + addEventListener : false, + applicationCache : false, + atob : false, + blur : false, + btoa : false, + clearInterval : false, + clearTimeout : false, + close : false, + closed : false, + DataView : false, + DOMParser : false, + defaultStatus : false, + document : false, + Element : false, + ElementTimeControl : false, + event : false, + FileReader : false, + Float32Array : false, + Float64Array : false, + FormData : false, + focus : false, + frames : false, + getComputedStyle : false, + HTMLElement : false, + HTMLAnchorElement : false, + HTMLBaseElement : false, + HTMLBlockquoteElement: false, + HTMLBodyElement : false, + HTMLBRElement : false, + HTMLButtonElement : false, + HTMLCanvasElement : false, + HTMLDirectoryElement : false, + HTMLDivElement : false, + HTMLDListElement : false, + HTMLFieldSetElement : false, + HTMLFontElement : false, + HTMLFormElement : false, + HTMLFrameElement : false, + HTMLFrameSetElement : false, + HTMLHeadElement : false, + HTMLHeadingElement : false, + HTMLHRElement : false, + HTMLHtmlElement : false, + HTMLIFrameElement : false, + HTMLImageElement : false, + HTMLInputElement : false, + HTMLIsIndexElement : false, + HTMLLabelElement : false, + HTMLLayerElement : false, + HTMLLegendElement : false, + HTMLLIElement : false, + HTMLLinkElement : false, + HTMLMapElement : false, + HTMLMenuElement : false, + HTMLMetaElement : false, + HTMLModElement : false, + HTMLObjectElement : false, + HTMLOListElement : false, + HTMLOptGroupElement : false, + HTMLOptionElement : false, + HTMLParagraphElement : false, + HTMLParamElement : false, + HTMLPreElement : false, + HTMLQuoteElement : false, + HTMLScriptElement : false, + HTMLSelectElement : false, + HTMLStyleElement : false, + HTMLTableCaptionElement: false, + HTMLTableCellElement : false, + HTMLTableColElement : false, + HTMLTableElement : false, + HTMLTableRowElement : false, + HTMLTableSectionElement: false, + HTMLTextAreaElement : false, + HTMLTitleElement : false, + HTMLUListElement : false, + HTMLVideoElement : false, + history : false, + Int16Array : false, + Int32Array : false, + Int8Array : false, + Image : false, + length : false, + localStorage : false, + location : false, + MessageChannel : false, + MessageEvent : false, + MessagePort : false, + moveBy : false, + moveTo : false, + MutationObserver : false, + name : false, + Node : false, + NodeFilter : false, + navigator : false, + onbeforeunload : true, + onblur : true, + onerror : true, + onfocus : true, + onload : true, + onresize : true, + onunload : true, + open : false, + openDatabase : false, + opener : false, + Option : false, + parent : false, + print : false, + removeEventListener : false, + resizeBy : false, + resizeTo : false, + screen : false, + scroll : false, + scrollBy : false, + scrollTo : false, + sessionStorage : false, + setInterval : false, + setTimeout : false, + SharedWorker : false, + status : false, + SVGAElement : false, + SVGAltGlyphDefElement: false, + SVGAltGlyphElement : false, + SVGAltGlyphItemElement: false, + SVGAngle : false, + SVGAnimateColorElement: false, + SVGAnimateElement : false, + SVGAnimateMotionElement: false, + SVGAnimateTransformElement: false, + SVGAnimatedAngle : false, + SVGAnimatedBoolean : false, + SVGAnimatedEnumeration: false, + SVGAnimatedInteger : false, + SVGAnimatedLength : false, + SVGAnimatedLengthList: false, + SVGAnimatedNumber : false, + SVGAnimatedNumberList: false, + SVGAnimatedPathData : false, + SVGAnimatedPoints : false, + SVGAnimatedPreserveAspectRatio: false, + SVGAnimatedRect : false, + SVGAnimatedString : false, + SVGAnimatedTransformList: false, + SVGAnimationElement : false, + SVGCSSRule : false, + SVGCircleElement : false, + SVGClipPathElement : false, + SVGColor : false, + SVGColorProfileElement: false, + SVGColorProfileRule : false, + SVGComponentTransferFunctionElement: false, + SVGCursorElement : false, + SVGDefsElement : false, + SVGDescElement : false, + SVGDocument : false, + SVGElement : false, + SVGElementInstance : false, + SVGElementInstanceList: false, + SVGEllipseElement : false, + SVGExternalResourcesRequired: false, + SVGFEBlendElement : false, + SVGFEColorMatrixElement: false, + SVGFEComponentTransferElement: false, + SVGFECompositeElement: false, + SVGFEConvolveMatrixElement: false, + SVGFEDiffuseLightingElement: false, + SVGFEDisplacementMapElement: false, + SVGFEDistantLightElement: false, + SVGFEFloodElement : false, + SVGFEFuncAElement : false, + SVGFEFuncBElement : false, + SVGFEFuncGElement : false, + SVGFEFuncRElement : false, + SVGFEGaussianBlurElement: false, + SVGFEImageElement : false, + SVGFEMergeElement : false, + SVGFEMergeNodeElement: false, + SVGFEMorphologyElement: false, + SVGFEOffsetElement : false, + SVGFEPointLightElement: false, + SVGFESpecularLightingElement: false, + SVGFESpotLightElement: false, + SVGFETileElement : false, + SVGFETurbulenceElement: false, + SVGFilterElement : false, + SVGFilterPrimitiveStandardAttributes: false, + SVGFitToViewBox : false, + SVGFontElement : false, + SVGFontFaceElement : false, + SVGFontFaceFormatElement: false, + SVGFontFaceNameElement: false, + SVGFontFaceSrcElement: false, + SVGFontFaceUriElement: false, + SVGForeignObjectElement: false, + SVGGElement : false, + SVGGlyphElement : false, + SVGGlyphRefElement : false, + SVGGradientElement : false, + SVGHKernElement : false, + SVGICCColor : false, + SVGImageElement : false, + SVGLangSpace : false, + SVGLength : false, + SVGLengthList : false, + SVGLineElement : false, + SVGLinearGradientElement: false, + SVGLocatable : false, + SVGMPathElement : false, + SVGMarkerElement : false, + SVGMaskElement : false, + SVGMatrix : false, + SVGMetadataElement : false, + SVGMissingGlyphElement: false, + SVGNumber : false, + SVGNumberList : false, + SVGPaint : false, + SVGPathElement : false, + SVGPathSeg : false, + SVGPathSegArcAbs : false, + SVGPathSegArcRel : false, + SVGPathSegClosePath : false, + SVGPathSegCurvetoCubicAbs: false, + SVGPathSegCurvetoCubicRel: false, + SVGPathSegCurvetoCubicSmoothAbs: false, + SVGPathSegCurvetoCubicSmoothRel: false, + SVGPathSegCurvetoQuadraticAbs: false, + SVGPathSegCurvetoQuadraticRel: false, + SVGPathSegCurvetoQuadraticSmoothAbs: false, + SVGPathSegCurvetoQuadraticSmoothRel: false, + SVGPathSegLinetoAbs : false, + SVGPathSegLinetoHorizontalAbs: false, + SVGPathSegLinetoHorizontalRel: false, + SVGPathSegLinetoRel : false, + SVGPathSegLinetoVerticalAbs: false, + SVGPathSegLinetoVerticalRel: false, + SVGPathSegList : false, + SVGPathSegMovetoAbs : false, + SVGPathSegMovetoRel : false, + SVGPatternElement : false, + SVGPoint : false, + SVGPointList : false, + SVGPolygonElement : false, + SVGPolylineElement : false, + SVGPreserveAspectRatio: false, + SVGRadialGradientElement: false, + SVGRect : false, + SVGRectElement : false, + SVGRenderingIntent : false, + SVGSVGElement : false, + SVGScriptElement : false, + SVGSetElement : false, + SVGStopElement : false, + SVGStringList : false, + SVGStylable : false, + SVGStyleElement : false, + SVGSwitchElement : false, + SVGSymbolElement : false, + SVGTRefElement : false, + SVGTSpanElement : false, + SVGTests : false, + SVGTextContentElement: false, + SVGTextElement : false, + SVGTextPathElement : false, + SVGTextPositioningElement: false, + SVGTitleElement : false, + SVGTransform : false, + SVGTransformList : false, + SVGTransformable : false, + SVGURIReference : false, + SVGUnitTypes : false, + SVGUseElement : false, + SVGVKernElement : false, + SVGViewElement : false, + SVGViewSpec : false, + SVGZoomAndPan : false, + TimeEvent : false, + top : false, + Uint16Array : false, + Uint32Array : false, + Uint8Array : false, + Uint8ClampedArray : false, + WebSocket : false, + window : false, + Worker : false, + XMLHttpRequest : false, + XMLSerializer : false, + XPathEvaluator : false, + XPathException : false, + XPathExpression : false, + XPathNamespace : false, + XPathNSResolver : false, + XPathResult : false +}; + +exports.devel = { + alert : false, + confirm: false, + console: false, + Debug : false, + opera : false, + prompt : false +}; + +exports.worker = { + importScripts: true, + postMessage : true, + self : true +}; +exports.nonstandard = { + escape : false, + unescape: false +}; + +exports.couch = { + "require" : false, + respond : false, + getRow : false, + emit : false, + send : false, + start : false, + sum : false, + log : false, + exports : false, + module : false, + provides : false +}; + +exports.node = { + __filename : false, + __dirname : false, + Buffer : false, + DataView : false, + console : false, + exports : true, // In Node it is ok to exports = module.exports = foo(); + GLOBAL : false, + global : false, + module : false, + process : false, + require : false, + setTimeout : false, + clearTimeout : false, + setInterval : false, + clearInterval : false, + setImmediate : false, // v0.9.1+ + clearImmediate: false // v0.9.1+ +}; + +exports.phantom = { + phantom : true, + require : true, + WebPage : true +}; + +exports.rhino = { + defineClass : false, + deserialize : false, + gc : false, + help : false, + importPackage: false, + "java" : false, + load : false, + loadClass : false, + print : false, + quit : false, + readFile : false, + readUrl : false, + runCommand : false, + seal : false, + serialize : false, + spawn : false, + sync : false, + toint32 : false, + version : false +}; + +exports.shelljs = { + target : false, + echo : false, + exit : false, + cd : false, + pwd : false, + ls : false, + find : false, + cp : false, + rm : false, + mv : false, + mkdir : false, + test : false, + cat : false, + sed : false, + grep : false, + which : false, + dirs : false, + pushd : false, + popd : false, + env : false, + exec : false, + chmod : false, + config : false, + error : false, + tempdir : false +}; + +exports.wsh = { + ActiveXObject : true, + Enumerator : true, + GetObject : true, + ScriptEngine : true, + ScriptEngineBuildVersion : true, + ScriptEngineMajorVersion : true, + ScriptEngineMinorVersion : true, + VBArray : true, + WSH : true, + WScript : true, + XDomainRequest : true +}; + +exports.dojo = { + dojo : false, + dijit : false, + dojox : false, + define : false, + "require": false +}; + +exports.jquery = { + "$" : false, + jQuery : false +}; + +exports.mootools = { + "$" : false, + "$$" : false, + Asset : false, + Browser : false, + Chain : false, + Class : false, + Color : false, + Cookie : false, + Core : false, + Document : false, + DomReady : false, + DOMEvent : false, + DOMReady : false, + Drag : false, + Element : false, + Elements : false, + Event : false, + Events : false, + Fx : false, + Group : false, + Hash : false, + HtmlTable : false, + Iframe : false, + IframeShim : false, + InputValidator: false, + instanceOf : false, + Keyboard : false, + Locale : false, + Mask : false, + MooTools : false, + Native : false, + Options : false, + OverText : false, + Request : false, + Scroller : false, + Slick : false, + Slider : false, + Sortables : false, + Spinner : false, + Swiff : false, + Tips : false, + Type : false, + typeOf : false, + URI : false, + Window : false +}; + +exports.prototypejs = { + "$" : false, + "$$" : false, + "$A" : false, + "$F" : false, + "$H" : false, + "$R" : false, + "$break" : false, + "$continue" : false, + "$w" : false, + Abstract : false, + Ajax : false, + Class : false, + Enumerable : false, + Element : false, + Event : false, + Field : false, + Form : false, + Hash : false, + Insertion : false, + ObjectRange : false, + PeriodicalExecuter: false, + Position : false, + Prototype : false, + Selector : false, + Template : false, + Toggle : false, + Try : false, + Autocompleter : false, + Builder : false, + Control : false, + Draggable : false, + Draggables : false, + Droppables : false, + Effect : false, + Sortable : false, + SortableObserver : false, + Sound : false, + Scriptaculous : false +}; + +exports.yui = { + YUI : false, + Y : false, + YUI_config: false +}; + + +})() +}, +{}], +4:[function(req,module,exports){ + +"use string"; +exports.unsafeString = + /@cc|<\/?|script|\]\s*\]|<\s*!|</i; +exports.unsafeChars = + /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; +exports.needEsc = + /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; + +exports.needEscGlobal = + /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; +exports.starSlash = /\*\//; +exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; +exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; +exports.fallsThrough = /^\s*\/\*\s*falls?\sthrough\s*\*\/\s*$/; + +}, +{}], +5:[function(req,module,exports){ + + +var state = { + syntax: {}, + + reset: function () { + this.tokens = { + prev: null, + next: null, + curr: null + }; + + this.option = {}; + this.ignored = {}; + this.directive = {}; + this.jsonMode = false; + this.jsonWarnings = []; + this.lines = []; + this.tab = ""; + this.cache = {}; // Node.JS doesn't have Map. Sniff. + } +}; + +exports.state = state; + +}, +{}], +6:[function(req,module,exports){ +(function(){ + +exports.register = function (linter) { + + linter.on("Identifier", function style_scanProto(data) { + if (linter.getOption("proto")) { + return; + } + + if (data.name === "__proto__") { + linter.warn("W103", { + line: data.line, + char: data.char, + data: [ data.name ] + }); + } + }); + + linter.on("Identifier", function style_scanIterator(data) { + if (linter.getOption("iterator")) { + return; + } + + if (data.name === "__iterator__") { + linter.warn("W104", { + line: data.line, + char: data.char, + data: [ data.name ] + }); + } + }); + + linter.on("Identifier", function style_scanDangling(data) { + if (!linter.getOption("nomen")) { + return; + } + if (data.name === "_") { + return; + } + if (linter.getOption("node")) { + if (/^(__dirname|__filename)$/.test(data.name) && !data.isProperty) { + return; + } + } + + if (/^(_+.*|.*_+)$/.test(data.name)) { + linter.warn("W105", { + line: data.line, + char: data.from, + data: [ "dangling '_'", data.name ] + }); + } + }); + + linter.on("Identifier", function style_scanCamelCase(data) { + if (!linter.getOption("camelcase")) { + return; + } + + if (data.name.replace(/^_+/, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { + linter.warn("W106", { + line: data.line, + char: data.from, + data: [ data.name ] + }); + } + }); + + linter.on("String", function style_scanQuotes(data) { + var quotmark = linter.getOption("quotmark"); + var code; + + if (!quotmark) { + return; + } + + if (quotmark === "single" && data.quote !== "'") { + code = "W109"; + } + + if (quotmark === "double" && data.quote !== "\"") { + code = "W108"; + } + + if (quotmark === true) { + if (!linter.getCache("quotmark")) { + linter.setCache("quotmark", data.quote); + } + + if (linter.getCache("quotmark") !== data.quote) { + code = "W110"; + } + } + + if (code) { + linter.warn(code, { + line: data.line, + char: data.char, + }); + } + }); + + linter.on("Number", function style_scanNumbers(data) { + if (data.value.charAt(0) === ".") { + linter.warn("W008", { + line: data.line, + char: data.char, + data: [ data.value ] + }); + } + + if (data.value.substr(data.value.length - 1) === ".") { + linter.warn("W047", { + line: data.line, + char: data.char, + data: [ data.value ] + }); + } + + if (/^00+/.test(data.value)) { + linter.warn("W046", { + line: data.line, + char: data.char, + data: [ data.value ] + }); + } + }); + + linter.on("String", function style_scanJavaScriptURLs(data) { + var re = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; + + if (linter.getOption("scripturl")) { + return; + } + + if (re.test(data.value)) { + linter.warn("W107", { + line: data.line, + char: data.char + }); + } + }); +}; +})() +}, +{}], +7:[function(req,module,exports){ +(function(global){/*global window, global*/ +var functions = [ + [log, "log"] + , [info, "info"] + , [warn, "warn"] + , [error, "error"] + , [time, "time"] + , [timeEnd, "timeEnd"] + , [trace, "trace"] + , [dir, "dir"] + , [assert, "assert"] +] + +for (var i = 0; i < functions.length; i++) { + var tuple = functions[i] + var f = tuple[0] + var name = tuple[1] + + if (!console[name]) { + console[name] = f + } +} + +module.exports = console + +function log() {} + +function info() {} + +function warn() {} + +function error() {} + +function time(label) {} + +function timeEnd(label) {} + +function trace() {} + +function dir(object) {} + +function assert(expression) {} + +})(window) +}, +{}], +"jshint":[function(req,module,exports){ +module.exports=req('E/GbHF'); +}, +{}],"E/GbHF":[function(req,module,exports){ +(function(){/*! + * JSHint, by JSHint Community. + * + * This file (and this file only) is licensed under the same slightly modified + * MIT license that JSLint is. It stops evil-doers everywhere: + * + * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * The Software shall be used for Good, not Evil. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +var _ = req("underscore"); +var events = req("events"); +var vars = req("../shared/vars.js"); +var messages = req("../shared/messages.js"); +var Lexer = req("./lex.js").Lexer; +var reg = req("./reg.js"); +var state = req("./state.js").state; +var style = req("./style.js"); +var console = req("console-browserify"); var JSHINT = (function () { - - - var anonname, // The guessed name for anonymous functions. + + var anonname, // The guessed name for anonymous functions. + api, // Extension API bang = { "<" : true, "<=" : true, @@ -2134,627 +3205,189 @@ var JSHINT = (function () { "%" : true }, boolOptions = { - asi : true, // if automatic semicolon insertion should be tolerated - bitwise : true, // if bitwise operators should not be allowed - boss : true, // if advanced usage of assignments should be allowed - browser : true, // if the standard browser globals should be predefined - camelcase : true, // if identifiers should be required in camel case - couch : true, // if CouchDB globals should be predefined - curly : true, // if curly braces around all blocks should be required - debug : true, // if debugger statements should be allowed - devel : true, // if logging globals should be predefined (console, - dojo : true, // if Dojo Toolkit globals should be predefined - eqeqeq : true, // if === should be required - eqnull : true, // if == null comparisons should be tolerated - es5 : true, // if ES5 syntax should be allowed - esnext : true, // if es.next specific syntax should be allowed - evil : true, // if eval should be allowed - expr : true, // if ExpressionStatement should be allowed as Programs - forin : true, // if for in statements must filter - funcscope : true, // if only function scope should be used for scope tests - globalstrict: true, // if global should be allowed (also - immed : true, // if immediate invocations must be wrapped in parens - iterator : true, // if the `__iterator__` property should be allowed - jquery : true, // if jQuery globals should be predefined - lastsemic : true, // if semicolons may be ommitted for the trailing - latedef : true, // if the use before definition should not be tolerated - laxbreak : true, // if line breaks should not be checked - laxcomma : true, // if line breaks should not be checked around commas - loopfunc : true, // if functions should be allowed to be defined within - mootools : true, // if MooTools globals should be predefined - multistr : true, // allow multiline strings - newcap : true, // if constructor names must be capitalized - noarg : true, // if arguments.caller and arguments.callee should be - node : true, // if the Node.js environment globals should be - noempty : true, // if empty blocks should be disallowed - nonew : true, // if using `new` for side-effects should be disallowed + asi : true, // if automatic semicolon insertion should be tolerated + bitwise : true, // if bitwise operators should not be allowed + boss : true, // if advanced usage of assignments should be allowed + browser : true, // if the standard browser globals should be predefined + camelcase : true, // if identifiers should be required in camel case + couch : true, // if CouchDB globals should be predefined + curly : true, // if curly braces around all blocks should be required + debug : true, // if debugger statements should be allowed + devel : true, // if logging globals should be predefined (console, alert, etc.) + dojo : true, // if Dojo Toolkit globals should be predefined + eqeqeq : true, // if === should be required + eqnull : true, // if == null comparisons should be tolerated + es3 : true, // if ES3 syntax should be allowed + es5 : true, // if ES5 syntax should be allowed (is now set per default) + esnext : true, // if es.next specific syntax should be allowed + moz : true, // if mozilla specific syntax should be allowed + evil : true, // if eval should be allowed + expr : true, // if ExpressionStatement should be allowed as Programs + forin : true, // if for in statements must filter + funcscope : true, // if only function scope should be used for scope tests + gcl : true, // if JSHint should be compatible with Google Closure Linter + globalstrict: true, // if global should be allowed (also enables 'strict') + immed : true, // if immediate invocations must be wrapped in parens + iterator : true, // if the `__iterator__` property should be allowed + jquery : true, // if jQuery globals should be predefined + lastsemic : true, // if semicolons may be ommitted for the trailing + laxbreak : true, // if line breaks should not be checked + laxcomma : true, // if line breaks should not be checked around commas + loopfunc : true, // if functions should be allowed to be defined within + mootools : true, // if MooTools globals should be predefined + multistr : true, // allow multiline strings + newcap : true, // if constructor names must be capitalized + noarg : true, // if arguments.caller and arguments.callee should be + node : true, // if the Node.js environment globals should be + noempty : true, // if empty blocks should be disallowed + nonew : true, // if using `new` for side-effects should be disallowed nonstandard : true, // if non-standard (but widely adopted) globals should - nomen : true, // if names should be checked - onevar : true, // if only one var statement per function should be - onecase : true, // if one case switch statements should be allowed - passfail : true, // if the scan should stop on first error - plusplus : true, // if increment/decrement should not be allowed - proto : true, // if the `__proto__` property should be allowed + nomen : true, // if names should be checked + onevar : true, // if only one var statement per function should be + passfail : true, // if the scan should stop on first error + phantom : true, // if PhantomJS symbols should be allowed + plusplus : true, // if increment/decrement should not be allowed + proto : true, // if the `__proto__` property should be allowed prototypejs : true, // if Prototype and Scriptaculous globals should be - regexdash : true, // if unescaped first/last dash (-) inside brackets - regexp : true, // if the . should not be allowed in regexp literals - rhino : true, // if the Rhino environment globals should be predefined - undef : true, // if variables should be declared before used - unused : true, // if variables should be always used - scripturl : true, // if script-targeted URLs should be tolerated - shadow : true, // if variable shadowing should be tolerated - smarttabs : true, // if smarttabs should be tolerated - strict : true, // require the pragma - sub : true, // if all forms of subscript notation are tolerated - supernew : true, // if `new function () { ... };` and `new Object;` - trailing : true, // if trailing whitespace rules apply - validthis : true, // if 'this' inside a non-constructor function is valid. - withstmt : true, // if with statements should be allowed - white : true, // if strict whitespace rules apply - worker : true, // if Web Worker script symbols should be allowed - wsh : true, // if the Windows Scripting Host environment globals - yui : true // YUI variables should be predefined + rhino : true, // if the Rhino environment globals should be predefined + shelljs : true, // if ShellJS globals should be predefined + undef : true, // if variables should be declared before used + scripturl : true, // if script-targeted URLs should be tolerated + shadow : true, // if variable shadowing should be tolerated + smarttabs : true, // if smarttabs should be tolerated + strict : true, // require the pragma + sub : true, // if all forms of subscript notation are tolerated + supernew : true, // if `new function () { ... };` and `new Object;` + trailing : true, // if trailing whitespace rules apply + validthis : true, // if 'this' inside a non-constructor function is valid. + withstmt : true, // if with statements should be allowed + white : true, // if strict whitespace rules apply + worker : true, // if Web Worker script symbols should be allowed + wsh : true, // if the Windows Scripting Host environment globals + yui : true, // YUI variables should be predefined + onecase : true, // if one case switch statements should be allowed + regexp : true, // if the . should not be allowed in regexp literals + regexdash : true // if unescaped first/last dash (-) inside brackets }, valOptions = { - maxlen : false, - indent : false, - maxerr : false, - predef : false, - quotmark : false, //'single'|'double'|true - scope : false, + maxlen : false, + indent : false, + maxerr : false, + predef : false, + quotmark : false, //'single'|'double'|true + scope : false, maxstatements: false, // {int} max statements per function - maxdepth : false, // {int} max nested block depth per function - maxparams : false, // {int} max params per function - maxcomplexity: false // {int} max cyclomatic complexity per function + maxdepth : false, // {int} max nested block depth per function + maxparams : false, // {int} max params per function + maxcomplexity: false, // {int} max cyclomatic complexity per function + unused : true, // warn if variables are unused. Available options: + latedef : false // warn if the variable is used before its definition }, invertedOptions = { - bitwise : true, - forin : true, - newcap : true, - nomen : true, - plusplus : true, - regexp : true, - undef : true, - white : true, - eqeqeq : true, - onevar : true + bitwise : true, + forin : true, + newcap : true, + nomen : true, + plusplus: true, + regexp : true, + undef : true, + white : true, + eqeqeq : true, + onevar : true, + strict : true }, renamedOptions = { - eqeq : "eqeqeq", - vars : "onevar", - windows : "wsh" - }, - browser = { - ArrayBuffer : false, - ArrayBufferView : false, - Audio : false, - Blob : false, - addEventListener : false, - applicationCache : false, - atob : false, - blur : false, - btoa : false, - clearInterval : false, - clearTimeout : false, - close : false, - closed : false, - DataView : false, - DOMParser : false, - defaultStatus : false, - document : false, - event : false, - FileReader : false, - Float32Array : false, - Float64Array : false, - FormData : false, - focus : false, - frames : false, - getComputedStyle : false, - HTMLElement : false, - HTMLAnchorElement : false, - HTMLBaseElement : false, - HTMLBlockquoteElement : false, - HTMLBodyElement : false, - HTMLBRElement : false, - HTMLButtonElement : false, - HTMLCanvasElement : false, - HTMLDirectoryElement : false, - HTMLDivElement : false, - HTMLDListElement : false, - HTMLFieldSetElement : false, - HTMLFontElement : false, - HTMLFormElement : false, - HTMLFrameElement : false, - HTMLFrameSetElement : false, - HTMLHeadElement : false, - HTMLHeadingElement : false, - HTMLHRElement : false, - HTMLHtmlElement : false, - HTMLIFrameElement : false, - HTMLImageElement : false, - HTMLInputElement : false, - HTMLIsIndexElement : false, - HTMLLabelElement : false, - HTMLLayerElement : false, - HTMLLegendElement : false, - HTMLLIElement : false, - HTMLLinkElement : false, - HTMLMapElement : false, - HTMLMenuElement : false, - HTMLMetaElement : false, - HTMLModElement : false, - HTMLObjectElement : false, - HTMLOListElement : false, - HTMLOptGroupElement : false, - HTMLOptionElement : false, - HTMLParagraphElement : false, - HTMLParamElement : false, - HTMLPreElement : false, - HTMLQuoteElement : false, - HTMLScriptElement : false, - HTMLSelectElement : false, - HTMLStyleElement : false, - HTMLTableCaptionElement : false, - HTMLTableCellElement : false, - HTMLTableColElement : false, - HTMLTableElement : false, - HTMLTableRowElement : false, - HTMLTableSectionElement : false, - HTMLTextAreaElement : false, - HTMLTitleElement : false, - HTMLUListElement : false, - HTMLVideoElement : false, - history : false, - Int16Array : false, - Int32Array : false, - Int8Array : false, - Image : false, - length : false, - localStorage : false, - location : false, - MessageChannel : false, - MessageEvent : false, - MessagePort : false, - moveBy : false, - moveTo : false, - MutationObserver : false, - name : false, - Node : false, - NodeFilter : false, - navigator : false, - onbeforeunload : true, - onblur : true, - onerror : true, - onfocus : true, - onload : true, - onresize : true, - onunload : true, - open : false, - openDatabase : false, - opener : false, - Option : false, - parent : false, - print : false, - removeEventListener : false, - resizeBy : false, - resizeTo : false, - screen : false, - scroll : false, - scrollBy : false, - scrollTo : false, - sessionStorage : false, - setInterval : false, - setTimeout : false, - SharedWorker : false, - status : false, - top : false, - Uint16Array : false, - Uint32Array : false, - Uint8Array : false, - WebSocket : false, - window : false, - Worker : false, - XMLHttpRequest : false, - XMLSerializer : false, - XPathEvaluator : false, - XPathException : false, - XPathExpression : false, - XPathNamespace : false, - XPathNSResolver : false, - XPathResult : false - }, - - couch = { - "require" : false, - respond : false, - getRow : false, - emit : false, - send : false, - start : false, - sum : false, - log : false, - exports : false, - module : false, - provides : false + eqeq : "eqeqeq", + vars : "onevar", + windows: "wsh", + sloppy : "strict" }, declared, // Globals that were declared using /*global ... */ syntax. - - devel = { - alert : false, - confirm : false, - console : false, - Debug : false, - opera : false, - prompt : false - }, - - dojo = { - dojo : false, - dijit : false, - dojox : false, - define : false, - "require" : false - }, - - funct, // The current function + exported, // Variables that are used outside of the current file. functionicity = [ "closure", "exception", "global", "label", "outer", "unused", "var" ], - functions, // All of the functions + funct, // The current function + functions, // All of the functions - global, // The global scope - implied, // Implied globals + global, // The global scope + implied, // Implied globals inblock, indent, - jsonmode, - - jquery = { - "$" : false, - jQuery : false - }, - - lines, lookahead, + lex, member, membersOnly, - - mootools = { - "$" : false, - "$$" : false, - Asset : false, - Browser : false, - Chain : false, - Class : false, - Color : false, - Cookie : false, - Core : false, - Document : false, - DomReady : false, - DOMEvent : false, - DOMReady : false, - Drag : false, - Element : false, - Elements : false, - Event : false, - Events : false, - Fx : false, - Group : false, - Hash : false, - HtmlTable : false, - Iframe : false, - IframeShim : false, - InputValidator : false, - instanceOf : false, - Keyboard : false, - Locale : false, - Mask : false, - MooTools : false, - Native : false, - Options : false, - OverText : false, - Request : false, - Scroller : false, - Slick : false, - Slider : false, - Sortables : false, - Spinner : false, - Swiff : false, - Tips : false, - Type : false, - typeOf : false, - URI : false, - Window : false - }, - - nexttoken, - - node = { - __filename : false, - __dirname : false, - Buffer : false, - console : false, - exports : true, // In Node it is ok to exports = module.exports = foo(); - GLOBAL : false, - global : false, - module : false, - process : false, - require : false, - setTimeout : false, - clearTimeout : false, - setInterval : false, - clearInterval : false - }, - noreach, - option, predefined, // Global variables defined by option - prereg, - prevtoken, - prototypejs = { - "$" : false, - "$$" : false, - "$A" : false, - "$F" : false, - "$H" : false, - "$R" : false, - "$break" : false, - "$continue" : false, - "$w" : false, - Abstract : false, - Ajax : false, - Class : false, - Enumerable : false, - Element : false, - Event : false, - Field : false, - Form : false, - Hash : false, - Insertion : false, - ObjectRange : false, - PeriodicalExecuter: false, - Position : false, - Prototype : false, - Selector : false, - Template : false, - Toggle : false, - Try : false, - Autocompleter : false, - Builder : false, - Control : false, - Draggable : false, - Draggables : false, - Droppables : false, - Effect : false, - Sortable : false, - SortableObserver : false, - Sound : false, - Scriptaculous : false - }, - - quotmark, - - rhino = { - defineClass : false, - deserialize : false, - gc : false, - help : false, - importPackage: false, - "java" : false, - load : false, - loadClass : false, - print : false, - quit : false, - readFile : false, - readUrl : false, - runCommand : false, - seal : false, - serialize : false, - spawn : false, - sync : false, - toint32 : false, - version : false - }, - - scope, // The current scope + scope, // The current scope stack, - standard = { - Array : false, - Boolean : false, - Date : false, - decodeURI : false, - decodeURIComponent : false, - encodeURI : false, - encodeURIComponent : false, - Error : false, - "eval" : false, - EvalError : false, - Function : false, - hasOwnProperty : false, - isFinite : false, - isNaN : false, - JSON : false, - Map : false, - Math : false, - NaN : false, - Number : false, - Object : false, - parseInt : false, - parseFloat : false, - RangeError : false, - ReferenceError : false, - RegExp : false, - Set : false, - String : false, - SyntaxError : false, - TypeError : false, - URIError : false, - WeakMap : false - }, - nonstandard = { - escape : false, - unescape : false - }, - - directive, - syntax = {}, - tab, - token, unuseds, urls, - useESNextSyntax, warnings, - worker = { - importScripts : true, - postMessage : true, - self : true - }, - - wsh = { - ActiveXObject : true, - Enumerator : true, - GetObject : true, - ScriptEngine : true, - ScriptEngineBuildVersion : true, - ScriptEngineMajorVersion : true, - ScriptEngineMinorVersion : true, - VBArray : true, - WSH : true, - WScript : true, - XDomainRequest : true - }, - - yui = { - YUI : false, - Y : false, - YUI_config : false - }; - var ax, cx, tx, nx, nxg, lx, ix, jx, ft; - (function () { - ax = /@cc|<\/?|script|\]\s*\]|<\s*!|</i; - cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/=(?!(\S*\/[gim]?))|\/(\*(jshint|jslint|members?|global)?|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/; - nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - lx = /\*\//; - ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; - jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; - ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/; - }()); - - function F() {} // Used by Object.create - - function is_own(object, name) { - return Object.prototype.hasOwnProperty.call(object, name); - } + extraModules = [], + emitter = new events.EventEmitter(); function checkOption(name, t) { - if (valOptions[name] === undefined && boolOptions[name] === undefined) { - warning("Bad option: '" + name + "'.", t); + name = name.trim(); + + if (/^[+-]W\d{3}$/g.test(name)) { + return true; } + + if (valOptions[name] === undefined && boolOptions[name] === undefined) { + if (t.type !== "jslint") { + error("E001", t, name); + return false; + } + } + + return true; } function isString(obj) { return Object.prototype.toString.call(obj) === "[object String]"; } - if (typeof Array.isArray !== "function") { - Array.isArray = function (o) { - return Object.prototype.toString.apply(o) === "[object Array]"; - }; - } - - if (!Array.prototype.forEach) { - Array.prototype.forEach = function (fn, scope) { - var len = this.length; - - for (var i = 0; i < len; i++) { - fn.call(scope || this, this[i], i, this); - } - }; - } - - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { - if (this === null || this === undefined) { - throw new TypeError(); - } - - var t = new Object(this); - var len = t.length >>> 0; - - if (len === 0) { - return -1; - } - - var n = 0; - if (arguments.length > 0) { - n = Number(arguments[1]); - if (n != n) { // shortcut for verifying if it's NaN - n = 0; - } else if (n !== 0 && n != Infinity && n != -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - - if (n >= len) { - return -1; - } - - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k; - } - } - - return -1; - }; - } - - if (typeof Object.create !== "function") { - Object.create = function (o) { - F.prototype = o; - return new F(); - }; - } - - if (typeof Object.keys !== "function") { - Object.keys = function (o) { - var a = [], k; - for (k in o) { - if (is_own(o, k)) { - a.push(k); - } - } - return a; - }; - } - - function isAlpha(str) { - return (str >= "a" && str <= "z\uffff") || - (str >= "A" && str <= "Z\uffff"); - } - - function isDigit(str) { - return (str >= "0" && str <= "9"); - } - - function isIdentifier(token, value) { - if (!token) + function isIdentifier(tkn, value) { + if (!tkn) return false; - if (!token.identifier || token.value !== value) + if (!tkn.identifier || tkn.value !== value) return false; return true; } + function isReserved(token) { + if (!token.reserved) { + return false; + } + + if (token.meta && token.meta.isFutureReservedWord) { + if (state.option.inES5(true) && !token.meta.es5) { + return false; + } + if (token.meta.strictOnly) { + if (!state.option.strict && !state.directive["use strict"]) { + return false; + } + } + + if (token.isProperty) { + return false; + } + } + + return true; + } + function supplant(str, data) { return str.replace(/\{([^{}]*)\}/g, function (a, b) { var r = data[b]; @@ -2765,7 +3398,7 @@ var JSHINT = (function () { function combine(t, o) { var n; for (n in o) { - if (is_own(o, n) && !is_own(JSHINT.blacklist, n)) { + if (_.has(o, n) && !_.has(JSHINT.blacklist, n)) { t[n] = o[n]; } } @@ -2778,69 +3411,92 @@ var JSHINT = (function () { } function assume() { - if (option.couch) { - combine(predefined, couch); + if (state.option.couch) { + combine(predefined, vars.couch); } - if (option.rhino) { - combine(predefined, rhino); + if (state.option.rhino) { + combine(predefined, vars.rhino); } - if (option.prototypejs) { - combine(predefined, prototypejs); + if (state.option.shelljs) { + combine(predefined, vars.shelljs); } - if (option.node) { - combine(predefined, node); - option.globalstrict = true; + if (state.option.phantom) { + combine(predefined, vars.phantom); } - if (option.devel) { - combine(predefined, devel); + if (state.option.prototypejs) { + combine(predefined, vars.prototypejs); } - if (option.dojo) { - combine(predefined, dojo); + if (state.option.node) { + combine(predefined, vars.node); } - if (option.browser) { - combine(predefined, browser); + if (state.option.devel) { + combine(predefined, vars.devel); } - if (option.nonstandard) { - combine(predefined, nonstandard); + if (state.option.dojo) { + combine(predefined, vars.dojo); } - if (option.jquery) { - combine(predefined, jquery); + if (state.option.browser) { + combine(predefined, vars.browser); } - if (option.mootools) { - combine(predefined, mootools); + if (state.option.nonstandard) { + combine(predefined, vars.nonstandard); } - if (option.worker) { - combine(predefined, worker); + if (state.option.jquery) { + combine(predefined, vars.jquery); } - if (option.wsh) { - combine(predefined, wsh); + if (state.option.mootools) { + combine(predefined, vars.mootools); } - if (option.esnext) { - useESNextSyntax(); + if (state.option.worker) { + combine(predefined, vars.worker); } - if (option.globalstrict && option.strict !== false) { - option.strict = true; + if (state.option.wsh) { + combine(predefined, vars.wsh); } - if (option.yui) { - combine(predefined, yui); + if (state.option.globalstrict && state.option.strict !== false) { + state.option.strict = true; } + + if (state.option.yui) { + combine(predefined, vars.yui); + } + + state.option.inMoz = function (strict) { + return state.option.moz; + }; + + state.option.inESNext = function (strict) { + return state.option.moz || state.option.esnext; + }; + + state.option.inES5 = function (/* strict */) { + return !state.option.es3; + }; + + state.option.inES3 = function (strict) { + if (strict) { + return !state.option.moz && !state.option.esnext && state.option.es3; + } + return state.option.es3; + }; } - function quit(message, line, chr) { - var percentage = Math.floor((line / lines.length) * 100); + function quit(code, line, chr) { + var percentage = Math.floor((line / state.lines.length) * 100); + var message = messages.errors[code].desc; throw { name: "JSHintError", @@ -2851,22 +3507,37 @@ var JSHINT = (function () { }; } - function isundef(scope, m, t, a) { - return JSHINT.undefs.push([scope, m, t, a]); + function isundef(scope, code, token, a) { + return JSHINT.undefs.push([scope, code, token, a]); } - function warning(m, t, a, b, c, d) { - var ch, l, w; - t = t || nexttoken; - if (t.id === "(end)") { // `~ - t = token; + function warning(code, t, a, b, c, d) { + var ch, l, w, msg; + + if (/^W\d{3}$/.test(code)) { + if (state.ignored[code]) + return; + + msg = messages.warnings[code]; + } else if (/E\d{3}/.test(code)) { + msg = messages.errors[code]; + } else if (/I\d{3}/.test(code)) { + msg = messages.info[code]; } + + t = t || state.tokens.next; + if (t.id === "(end)") { // `~ + t = state.tokens.curr; + } + l = t.line || 0; ch = t.from || 0; + w = { id: "(error)", - raw: m, - evidence: lines[l - 1] || "", + raw: msg.desc, + code: msg.code, + evidence: state.lines[l - 1] || "", line: l, character: ch, scope: JSHINT.scope, @@ -2875,15 +3546,19 @@ var JSHINT = (function () { c: c, d: d }; - w.reason = supplant(m, w); + + w.reason = supplant(msg.desc, w); JSHINT.errors.push(w); - if (option.passfail) { - quit("Stopping. ", l, ch); + + if (state.option.passfail) { + quit("E042", l, ch); } + warnings += 1; - if (warnings >= option.maxerr) { - quit("Too many errors.", l, ch); + if (warnings >= state.option.maxerr) { + quit("E043", l, ch); } + return w; } @@ -2915,905 +3590,258 @@ var JSHINT = (function () { return i; } - var lex = (function lex() { - var character, from, line, s; - - function nextLine() { - var at, - match, - tw; // trailing whitespace check - - if (line >= lines.length) - return false; - - character = 1; - s = lines[line]; - line += 1; - if (option.smarttabs) { - match = s.match(/(\/\/)? \t/); - at = match && !match[1] ? 0 : -1; - } else { - at = s.search(/ \t|\t [^\*]/); - } - - if (at >= 0) - warningAt("Mixed spaces and tabs.", line, at + 1); - - s = s.replace(/\t/g, tab); - at = s.search(cx); - - if (at >= 0) - warningAt("Unsafe character.", line, at); - - if (option.maxlen && option.maxlen < s.length) - warningAt("Line too long.", line, s.length); - tw = option.trailing && s.match(/^(.*?)\s+$/); - if (tw && !/^\s+$/.test(s)) { - warningAt("Trailing whitespace.", line, tw[1].length + 1); - } - return true; - } - - function it(type, value) { - var i, t; - - function checkName(name) { - if (!option.proto && name === "__proto__") { - warningAt("The '{a}' property is deprecated.", line, from, name); - return; - } - - if (!option.iterator && name === "__iterator__") { - warningAt("'{a}' is only available in JavaScript 1.7.", line, from, name); - return; - } - - var hasDangling = /^(_+.*|.*_+)$/.test(name); - - if (option.nomen && hasDangling && name !== "_") { - if (option.node && token.id !== "." && /^(__dirname|__filename)$/.test(name)) - return; - - warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", name); - return; - } - - if (option.camelcase) { - if (name.replace(/^_+/, "").indexOf("_") > -1 && !name.match(/^[A-Z0-9_]*$/)) { - warningAt("Identifier '{a}' is not in camel case.", line, from, value); - } - } - } - - if (type === "(color)" || type === "(range)") { - t = {type: type}; - } else if (type === "(punctuator)" || - (type === "(identifier)" && is_own(syntax, value))) { - t = syntax[value] || syntax["(error)"]; - } else { - t = syntax[type]; - } - - t = Object.create(t); - - if (type === "(string)" || type === "(range)") { - if (!option.scripturl && jx.test(value)) { - warningAt("Script URL.", line, from); - } - } - - if (type === "(identifier)") { - t.identifier = true; - checkName(value); - } - - t.value = value; - t.line = line; - t.character = character; - t.from = from; - i = t.id; - if (i !== "(endline)") { - prereg = i && - (("(,=:[!&|?{};".indexOf(i.charAt(i.length - 1)) >= 0) || - i === "return" || - i === "case"); - } - return t; - } - return { - init: function (source) { - if (typeof source === "string") { - lines = source - .replace(/\r\n/g, "\n") - .replace(/\r/g, "\n") - .split("\n"); - } else { - lines = source; - } - if (lines[0] && lines[0].substr(0, 2) === "#!") - lines[0] = ""; - - line = 0; - nextLine(); - from = 1; - }, - - range: function (begin, end) { - var c, value = ""; - from = character; - if (s.charAt(0) !== begin) { - errorAt("Expected '{a}' and instead saw '{b}'.", - line, character, begin, s.charAt(0)); - } - for (;;) { - s = s.slice(1); - character += 1; - c = s.charAt(0); - switch (c) { - case "": - errorAt("Missing '{a}'.", line, character, c); - break; - case end: - s = s.slice(1); - character += 1; - return it("(range)", value); - case "\\": - warningAt("Unexpected '{a}'.", line, character, c); - } - value += c; - } - - }, - token: function () { - var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n; - - function match(x) { - var r = x.exec(s), r1; - - if (r) { - l = r[0].length; - r1 = r[1]; - c = r1.charAt(0); - s = s.substr(l); - from = character + l - r1.length; - character += l; - return r1; - } - } - - function string(x) { - var c, j, r = "", allowNewLine = false; - - if (jsonmode && x !== "\"") { - warningAt("Strings must use doublequote.", - line, character); - } - - if (option.quotmark) { - if (option.quotmark === "single" && x !== "'") { - warningAt("Strings must use singlequote.", - line, character); - } else if (option.quotmark === "double" && x !== "\"") { - warningAt("Strings must use doublequote.", - line, character); - } else if (option.quotmark === true) { - quotmark = quotmark || x; - if (quotmark !== x) { - warningAt("Mixed double and single quotes.", - line, character); - } - } - } - - function esc(n) { - var i = parseInt(s.substr(j + 1, n), 16); - j += n; - if (i >= 32 && i <= 126 && - i !== 34 && i !== 92 && i !== 39) { - warningAt("Unnecessary escapement.", line, character); - } - character += n; - c = String.fromCharCode(i); - } - - j = 0; - -unclosedString: - for (;;) { - while (j >= s.length) { - j = 0; - - var cl = line, cf = from; - if (!nextLine()) { - errorAt("Unclosed string.", cl, cf); - break unclosedString; - } - - if (allowNewLine) { - allowNewLine = false; - } else { - warningAt("Unclosed string.", cl, cf); - } - } - - c = s.charAt(j); - if (c === x) { - character += 1; - s = s.substr(j + 1); - return it("(string)", r, x); - } - - if (c < " ") { - if (c === "\n" || c === "\r") { - break; - } - warningAt("Control character in string: {a}.", - line, character + j, s.slice(0, j)); - } else if (c === "\\") { - j += 1; - character += 1; - c = s.charAt(j); - n = s.charAt(j + 1); - switch (c) { - case "\\": - case "\"": - case "/": - break; - case "\'": - if (jsonmode) { - warningAt("Avoid \\'.", line, character); - } - break; - case "b": - c = "\b"; - break; - case "f": - c = "\f"; - break; - case "n": - c = "\n"; - break; - case "r": - c = "\r"; - break; - case "t": - c = "\t"; - break; - case "0": - c = "\0"; - if (n >= 0 && n <= 7 && directive["use strict"]) { - warningAt( - "Octal literals are not allowed in strict mode.", - line, character); - } - break; - case "u": - esc(4); - break; - case "v": - if (jsonmode) { - warningAt("Avoid \\v.", line, character); - } - c = "\v"; - break; - case "x": - if (jsonmode) { - warningAt("Avoid \\x-.", line, character); - } - esc(2); - break; - case "": - allowNewLine = true; - if (option.multistr) { - if (jsonmode) { - warningAt("Avoid EOL escapement.", line, character); - } - c = ""; - character -= 1; - break; - } - warningAt("Bad escapement of EOL. Use option multistr if needed.", - line, character); - break; - case "!": - if (s.charAt(j - 2) === "<") - break; - default: - warningAt("Bad escapement.", line, character); - } - } - r += c; - character += 1; - j += 1; - } - } - - for (;;) { - if (!s) { - return it(nextLine() ? "(endline)" : "(end)", ""); - } - - t = match(tx); - - if (!t) { - t = ""; - c = ""; - while (s && s < "!") { - s = s.substr(1); - } - if (s) { - errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1)); - s = ""; - } - } else { - - if (isAlpha(c) || c === "_" || c === "$") { - return it("(identifier)", t); - } - - if (isDigit(c)) { - if (!isFinite(Number(t))) { - warningAt("Bad number '{a}'.", - line, character, t); - } - if (isAlpha(s.substr(0, 1))) { - warningAt("Missing space after '{a}'.", - line, character, t); - } - if (c === "0") { - d = t.substr(1, 1); - if (isDigit(d)) { - if (token.id !== ".") { - warningAt("Don't use extra leading zeros '{a}'.", - line, character, t); - } - } else if (jsonmode && (d === "x" || d === "X")) { - warningAt("Avoid 0x-. '{a}'.", - line, character, t); - } - } - if (t.substr(t.length - 1) === ".") { - warningAt( -"A trailing decimal point can be confused with a dot '{a}'.", line, character, t); - } - return it("(number)", t); - } - switch (t) { - - case "\"": - case "'": - return string(t); - - case "//": - s = ""; - token.comment = true; - break; - - case "/*": - for (;;) { - i = s.search(lx); - if (i >= 0) { - break; - } - if (!nextLine()) { - errorAt("Unclosed comment.", line, character); - } - } - s = s.substr(i + 2); - token.comment = true; - break; - - case "/*members": - case "/*member": - case "/*jshint": - case "/*jslint": - case "/*global": - case "*/": - return { - value: t, - type: "special", - line: line, - character: character, - from: from - }; - - case "": - break; - case "/": - if (s.charAt(0) === "=") { - errorAt("A regular expression literal can be confused with '/='.", - line, from); - } - - if (prereg) { - depth = 0; - captures = 0; - l = 0; - for (;;) { - b = true; - c = s.charAt(l); - l += 1; - switch (c) { - case "": - errorAt("Unclosed regular expression.", line, from); - return quit("Stopping.", line, from); - case "/": - if (depth > 0) { - warningAt("{a} unterminated regular expression " + - "group(s).", line, from + l, depth); - } - c = s.substr(0, l - 1); - q = { - g: true, - i: true, - m: true - }; - while (q[s.charAt(l)] === true) { - q[s.charAt(l)] = false; - l += 1; - } - character += l; - s = s.substr(l); - q = s.charAt(0); - if (q === "/" || q === "*") { - errorAt("Confusing regular expression.", - line, from); - } - return it("(regexp)", c); - case "\\": - c = s.charAt(l); - if (c < " ") { - warningAt( -"Unexpected control character in regular expression.", line, from + l); - } else if (c === "<") { - warningAt( -"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); - } - l += 1; - break; - case "(": - depth += 1; - b = false; - if (s.charAt(l) === "?") { - l += 1; - switch (s.charAt(l)) { - case ":": - case "=": - case "!": - l += 1; - break; - default: - warningAt( -"Expected '{a}' and instead saw '{b}'.", line, from + l, ":", s.charAt(l)); - } - } else { - captures += 1; - } - break; - case "|": - b = false; - break; - case ")": - if (depth === 0) { - warningAt("Unescaped '{a}'.", - line, from + l, ")"); - } else { - depth -= 1; - } - break; - case " ": - q = 1; - while (s.charAt(l) === " ") { - l += 1; - q += 1; - } - if (q > 1) { - warningAt( -"Spaces are hard to count. Use {{a}}.", line, from + l, q); - } - break; - case "[": - c = s.charAt(l); - if (c === "^") { - l += 1; - if (s.charAt(l) === "]") { - errorAt("Unescaped '{a}'.", - line, from + l, "^"); - } - } - if (c === "]") { - warningAt("Empty class.", line, - from + l - 1); - } - isLiteral = false; - isInRange = false; -klass: - do { - c = s.charAt(l); - l += 1; - switch (c) { - case "[": - case "^": - warningAt("Unescaped '{a}'.", - line, from + l, c); - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - case "-": - if (isLiteral && !isInRange) { - isLiteral = false; - isInRange = true; - } else if (isInRange) { - isInRange = false; - } else if (s.charAt(l) === "]") { - isInRange = true; - } else { - if (option.regexdash !== (l === 2 || (l === 3 && - s.charAt(1) === "^"))) { - warningAt("Unescaped '{a}'.", - line, from + l - 1, "-"); - } - isLiteral = true; - } - break; - case "]": - if (isInRange && !option.regexdash) { - warningAt("Unescaped '{a}'.", - line, from + l - 1, "-"); - } - break klass; - case "\\": - c = s.charAt(l); - if (c < " ") { - warningAt( -"Unexpected control character in regular expression.", line, from + l); - } else if (c === "<") { - warningAt( -"Unexpected escaped character '{a}' in regular expression.", line, from + l, c); - } - l += 1; - if (/[wsd]/i.test(c)) { - if (isInRange) { - warningAt("Unescaped '{a}'.", - line, from + l, "-"); - isInRange = false; - } - isLiteral = false; - } else if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - case "/": - warningAt("Unescaped '{a}'.", - line, from + l - 1, "/"); - - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - case "<": - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - break; - default: - if (isInRange) { - isInRange = false; - } else { - isLiteral = true; - } - } - } while (c); - break; - case ".": - if (option.regexp) { - warningAt("Insecure '{a}'.", line, - from + l, c); - } - break; - case "]": - case "?": - case "{": - case "}": - case "+": - case "*": - warningAt("Unescaped '{a}'.", line, - from + l, c); - } - if (b) { - switch (s.charAt(l)) { - case "?": - case "+": - case "*": - l += 1; - if (s.charAt(l) === "?") { - l += 1; - } - break; - case "{": - l += 1; - c = s.charAt(l); - if (c < "0" || c > "9") { - warningAt( -"Expected a number and instead saw '{a}'.", line, from + l, c); - break; // No reason to continue checking numbers. - } - l += 1; - low = +c; - for (;;) { - c = s.charAt(l); - if (c < "0" || c > "9") { - break; - } - l += 1; - low = +c + (low * 10); - } - high = low; - if (c === ",") { - l += 1; - high = Infinity; - c = s.charAt(l); - if (c >= "0" && c <= "9") { - l += 1; - high = +c; - for (;;) { - c = s.charAt(l); - if (c < "0" || c > "9") { - break; - } - l += 1; - high = +c + (high * 10); - } - } - } - if (s.charAt(l) !== "}") { - warningAt( -"Expected '{a}' and instead saw '{b}'.", line, from + l, "}", c); - } else { - l += 1; - } - if (s.charAt(l) === "?") { - l += 1; - } - if (low > high) { - warningAt( -"'{a}' should not be greater than '{b}'.", line, from + l, low, high); - } - } - } - } - c = s.substr(0, l - 1); - character += l; - s = s.substr(l); - return it("(regexp)", c); - } - return it("(punctuator)", t); - - case "#": - return it("(punctuator)", t); - default: - return it("(punctuator)", t); - } - } - } - } - }; - }()); - - - function addlabel(t, type, token) { - if (t === "hasOwnProperty") { - warning("'hasOwnProperty' is a really bad name."); - } + function addlabel(t, type, tkn, islet) { if (type === "exception") { - if (is_own(funct["(context)"], t)) { - if (funct[t] !== true && !option.node) { - warning("Value of '{a}' may be overwritten in IE.", nexttoken, t); + if (_.has(funct["(context)"], t)) { + if (funct[t] !== true && !state.option.node) { + warning("W002", state.tokens.next, t); } } } - if (is_own(funct, t) && !funct["(global)"]) { + if (_.has(funct, t) && !funct["(global)"]) { if (funct[t] === true) { - if (option.latedef) - warning("'{a}' was used before it was defined.", nexttoken, t); + if (state.option.latedef) { + if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || + !_.contains([funct[t], type], "unction")) { + warning("W003", state.tokens.next, t); + } + } } else { - if (!option.shadow && type !== "exception") { - warning("'{a}' is already defined.", nexttoken, t); + if (!state.option.shadow && type !== "exception" || + (funct["(blockscope)"].getlabel(t))) { + warning("W004", state.tokens.next, t); } } } - - funct[t] = type; - - if (token) { - funct["(tokens)"][t] = token; + if (funct["(blockscope)"] && funct["(blockscope)"].current.has(t)) { + error("E044", state.tokens.next, t); } - - if (funct["(global)"]) { - global[t] = funct; - if (is_own(implied, t)) { - if (option.latedef) - warning("'{a}' was used before it was defined.", nexttoken, t); - delete implied[t]; - } + if (islet) { + funct["(blockscope)"].current.add(t, type, state.tokens.curr); } else { - scope[t] = funct; + + funct[t] = type; + + if (tkn) { + funct["(tokens)"][t] = tkn; + } + + if (funct["(global)"]) { + global[t] = funct; + if (_.has(implied, t)) { + if (state.option.latedef) { + if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || + !_.contains([funct[t], type], "unction")) { + warning("W003", state.tokens.next, t); + } + } + + delete implied[t]; + } + } else { + scope[t] = funct; + } } } - function doOption() { - var nt = nexttoken; - var o = nt.value; - var quotmarkValue = option.quotmark; + var nt = state.tokens.next; + var body = nt.body.split(",").map(function (s) { return s.trim(); }); var predef = {}; - var b, obj, filter, t, tn, v, minus; - switch (o) { - case "*/": - error("Unbegun comment."); - break; - case "/*members": - case "/*member": - o = "/*members"; - if (!membersOnly) { - membersOnly = {}; + if (nt.type === "globals") { + body.forEach(function (g) { + g = g.split(":"); + var key = g[0]; + var val = g[1]; + + if (key.charAt(0) === "-") { + key = key.slice(1); + val = false; + + JSHINT.blacklist[key] = key; + updatePredefined(); + } else { + predef[key] = (val === "true"); + } + }); + + combine(predefined, predef); + + for (var key in predef) { + if (_.has(predef, key)) { + declared[key] = nt; + } } - obj = membersOnly; - option.quotmark = false; - break; - case "/*jshint": - case "/*jslint": - obj = option; - filter = boolOptions; - break; - case "/*global": - obj = predef; - break; - default: - error("What?"); } - t = lex.token(); + if (nt.type === "exported") { + body.forEach(function (e) { + exported[e] = true; + }); + } - for (;;) { - minus = false; - var breakOuterLoop; - for (;;) { - if (t.type === "special" && t.value === "*/") { - breakOuterLoop = true; - break; - } - if (t.id !== "(endline)" && t.id !== ",") { - break; - } - t = lex.token(); - } - if (breakOuterLoop) - break; + if (nt.type === "members") { + membersOnly = membersOnly || {}; - if (o === "/*global" && t.value === "-") { - minus = true; - t = lex.token(); - } + body.forEach(function (m) { + var ch1 = m.charAt(0); + var ch2 = m.charAt(m.length - 1); - if (t.type !== "(string)" && t.type !== "(identifier)" && o !== "/*members") { - error("Bad option.", t); - } - - v = lex.token(); - if (v.id === ":") { - v = lex.token(); - - if (obj === membersOnly) { - error("Expected '{a}' and instead saw '{b}'.", t, "*/", ":"); + if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { + m = m + .substr(1, m.length - 2) + .replace("\\b", "\b") + .replace("\\t", "\t") + .replace("\\n", "\n") + .replace("\\v", "\v") + .replace("\\f", "\f") + .replace("\\r", "\r") + .replace("\\\\", "\\") + .replace("\\\"", "\""); } - if (o === "/*jshint") { - checkOption(t.value, t); + membersOnly[m] = false; + }); + } + + var numvals = [ + "maxstatements", + "maxparams", + "maxdepth", + "maxcomplexity", + "maxerr", + "maxlen", + "indent" + ]; + + if (nt.type === "jshint" || nt.type === "jslint") { + body.forEach(function (g) { + g = g.split(":"); + var key = (g[0] || "").trim(); + var val = (g[1] || "").trim(); + + if (!checkOption(key, nt)) { + return; } - var numericVals = [ - "maxstatements", - "maxparams", - "maxdepth", - "maxcomplexity", - "maxerr", - "maxlen", - "indent" - ]; + if (numvals.indexOf(key) >= 0) { + if (val !== "false") { + val = +val; - if (numericVals.indexOf(t.value) > -1 && (o === "/*jshint" || o === "/*jslint")) { - b = +v.value; + if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) { + error("E032", nt, g[1].trim()); + return; + } - if (typeof b !== "number" || !isFinite(b) || b <= 0 || Math.floor(b) !== b) { - error("Expected a small integer and instead saw '{a}'.", v, v.value); - } - - if (t.value === "indent") - obj.white = true; - - obj[t.value] = b; - } else if (t.value === "validthis") { - if (funct["(global)"]) { - error("Option 'validthis' can't be used in a global scope."); + if (key === "indent") { + state.option["(explicitIndent)"] = true; + } + state.option[key] = val; } else { - if (v.value === "true" || v.value === "false") - obj[t.value] = v.value === "true"; - else - error("Bad option value.", v); + if (key === "indent") { + state.option["(explicitIndent)"] = false; + } else { + state.option[key] = false; + } } - } else if (t.value === "quotmark" && (o === "/*jshint")) { - switch (v.value) { + + return; + } + + if (key === "validthis") { + if (funct["(global)"]) { + error("E009"); + } else { + if (val === "true" || val === "false") { + state.option.validthis = (val === "true"); + } else { + error("E002", nt); + } + } + return; + } + + if (key === "quotmark") { + switch (val) { case "true": - obj.quotmark = true; - break; case "false": - obj.quotmark = false; + state.option.quotmark = (val === "true"); break; case "double": case "single": - obj.quotmark = v.value; + state.option.quotmark = val; break; default: - error("Bad option value.", v); + error("E002", nt); } - } else if (v.value === "true" || v.value === "false") { - if (o === "/*jslint") { - tn = renamedOptions[t.value] || t.value; - obj[tn] = v.value === "true"; + return; + } + + if (key === "unused") { + switch (val) { + case "true": + state.option.unused = true; + break; + case "false": + state.option.unused = false; + break; + case "vars": + case "strict": + state.option.unused = val; + break; + default: + error("E002", nt); + } + return; + } + + if (key === "latedef") { + switch (val) { + case "true": + state.option.latedef = true; + break; + case "false": + state.option.latedef = false; + break; + case "nofunc": + state.option.latedef = "nofunc"; + break; + default: + error("E002", nt); + } + return; + } + + var match = /^([+-])(W\d{3})$/g.exec(key); + if (match) { + state.ignored[match[2]] = (match[1] === "-"); + return; + } + + var tn; + if (val === "true" || val === "false") { + if (nt.type === "jslint") { + tn = renamedOptions[key] || key; + state.option[tn] = (val === "true"); + if (invertedOptions[tn] !== undefined) { - obj[tn] = !obj[tn]; + state.option[tn] = !state.option[tn]; } } else { - obj[t.value] = v.value === "true"; + state.option[key] = (val === "true"); } - if (t.value === "newcap") - obj["(explicitNewcap)"] = true; - } else { - error("Bad option value.", v); - } - t = lex.token(); - } else { - if (o === "/*jshint" || o === "/*jslint") { - error("Missing option value.", t); + if (key === "newcap") { + state.option["(explicitNewcap)"] = true; + } + return; } - obj[t.value] = false; + error("E002", nt); + }); - if (o === "/*global" && minus === true) { - JSHINT.blacklist[t.value] = t.value; - updatePredefined(); - } - - t = v; - } - } - - if (o === "/*members") { - option.quotmark = quotmarkValue; - } - - combine(predefined, predef); - - for (var key in predef) { - if (is_own(predef, key)) { - declared[key] = nt; - } - } - - if (filter) { assume(); } } @@ -3832,54 +3860,61 @@ klass: } function advance(id, t) { - switch (token.id) { + switch (state.tokens.curr.id) { case "(number)": - if (nexttoken.id === ".") { - warning("A dot following a number can be confused with a decimal point.", token); + if (state.tokens.next.id === ".") { + warning("W005", state.tokens.curr); } break; case "-": - if (nexttoken.id === "-" || nexttoken.id === "--") { - warning("Confusing minusses."); + if (state.tokens.next.id === "-" || state.tokens.next.id === "--") { + warning("W006"); } break; case "+": - if (nexttoken.id === "+" || nexttoken.id === "++") { - warning("Confusing plusses."); + if (state.tokens.next.id === "+" || state.tokens.next.id === "++") { + warning("W007"); } break; } - if (token.type === "(string)" || token.identifier) { - anonname = token.value; + if (state.tokens.curr.type === "(string)" || state.tokens.curr.identifier) { + anonname = state.tokens.curr.value; } - if (id && nexttoken.id !== id) { + if (id && state.tokens.next.id !== id) { if (t) { - if (nexttoken.id === "(end)") { - warning("Unmatched '{a}'.", t, t.id); + if (state.tokens.next.id === "(end)") { + error("E019", t, t.id); } else { - warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", - nexttoken, id, t.id, t.line, nexttoken.value); + error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); } - } else if (nexttoken.type !== "(identifier)" || - nexttoken.value !== id) { - warning("Expected '{a}' and instead saw '{b}'.", - nexttoken, id, nexttoken.value); + } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { + warning("W116", state.tokens.next, id, state.tokens.next.value); } } - prevtoken = token; - token = nexttoken; + state.tokens.prev = state.tokens.curr; + state.tokens.curr = state.tokens.next; for (;;) { - nexttoken = lookahead.shift() || lex.token(); - if (nexttoken.id === "(end)" || nexttoken.id === "(error)") { + state.tokens.next = lookahead.shift() || lex.token(); + + if (!state.tokens.next) { // No more tokens left, give up + quit("E041", state.tokens.curr.line); + } + + if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { return; } - if (nexttoken.type === "special") { + + if (state.tokens.next.check) { + state.tokens.next.check(); + } + + if (state.tokens.next.isSpecial) { doOption(); } else { - if (nexttoken.id !== "(endline)") { + if (state.tokens.next.id !== "(endline)") { break; } } @@ -3887,84 +3922,100 @@ klass: } function expression(rbp, initial) { - var left, isArray = false, isObject = false; + var left, isArray = false, isObject = false, isLetExpr = false; + if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { + if (!state.option.inMoz(true)) { + warning("W118", state.tokens.next, "let expressions"); + } + isLetExpr = true; + funct["(blockscope)"].stack(); + advance("let"); + advance("("); + state.syntax["let"].fud.call(state.syntax["let"].fud, false); + advance(")"); + } - if (nexttoken.id === "(end)") - error("Unexpected early end of program.", token); + if (state.tokens.next.id === "(end)") + error("E006", state.tokens.curr); advance(); + if (initial) { anonname = "anonymous"; - funct["(verb)"] = token.value; + funct["(verb)"] = state.tokens.curr.value; } - if (initial === true && token.fud) { - left = token.fud(); + + if (initial === true && state.tokens.curr.fud) { + left = state.tokens.curr.fud(); } else { - if (token.nud) { - left = token.nud(); + if (state.tokens.curr.nud) { + left = state.tokens.curr.nud(); } else { - if (nexttoken.type === "(number)" && token.id === ".") { - warning("A leading decimal point can be confused with a dot: '.{a}'.", - token, nexttoken.value); - advance(); - return token; - } else { - error("Expected an identifier and instead saw '{a}'.", - token, token.id); - } + error("E030", state.tokens.curr, state.tokens.curr.id); } - while (rbp < nexttoken.lbp) { - isArray = token.value === "Array"; - isObject = token.value === "Object"; + + var end_of_expr = state.tokens.next.identifier && + !state.tokens.curr.led && + state.tokens.curr.line !== state.tokens.next.line; + while (rbp < state.tokens.next.lbp && !end_of_expr) { + isArray = state.tokens.curr.value === "Array"; + isObject = state.tokens.curr.value === "Object"; if (left && (left.value || (left.first && left.first.value))) { if (left.value !== "new" || (left.first && left.first.value && left.first.value === ".")) { isArray = false; - if (left.value !== token.value) { + if (left.value !== state.tokens.curr.value) { isObject = false; } } } advance(); - if (isArray && token.id === "(" && nexttoken.id === ")") - warning("Use the array literal notation [].", token); - if (isObject && token.id === "(" && nexttoken.id === ")") - warning("Use the object literal notation {}.", token); - if (token.led) { - left = token.led(left); + + if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { + warning("W009", state.tokens.curr); + } + + if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { + warning("W010", state.tokens.curr); + } + + if (left && state.tokens.curr.led) { + left = state.tokens.curr.led(left); } else { - error("Expected an operator and instead saw '{a}'.", - token, token.id); + error("E033", state.tokens.curr, state.tokens.curr.id); } } } + if (isLetExpr) { + funct["(blockscope)"].unstack(); + } return left; } function adjacent(left, right) { - left = left || token; - right = right || nexttoken; - if (option.white) { + left = left || state.tokens.curr; + right = right || state.tokens.next; + if (state.option.white) { if (left.character !== right.from && left.line === right.line) { left.from += (left.character - left.from); - warning("Unexpected space after '{a}'.", left, left.value); + warning("W011", left, left.value); } } } function nobreak(left, right) { - left = left || token; - right = right || nexttoken; - if (option.white && (left.character !== right.from || left.line !== right.line)) { - warning("Unexpected space before '{a}'.", right, right.value); + left = left || state.tokens.curr; + right = right || state.tokens.next; + if (state.option.white && (left.character !== right.from || left.line !== right.line)) { + warning("W012", right, right.value); } } function nospace(left, right) { - left = left || token; - right = right || nexttoken; - if (option.white && !left.comment) { + left = left || state.tokens.curr; + right = right || state.tokens.next; + if (state.option.white && !left.comment) { if (left.line === right.line) { adjacent(left, right); } @@ -3972,77 +4023,132 @@ klass: } function nonadjacent(left, right) { - if (option.white) { - left = left || token; - right = right || nexttoken; + if (state.option.white) { + left = left || state.tokens.curr; + right = right || state.tokens.next; + if (left.value === ";" && right.value === ";") { return; } + if (left.line === right.line && left.character === right.from) { left.from += (left.character - left.from); - warning("Missing space after '{a}'.", - left, left.value); + warning("W013", left, left.value); } } } function nobreaknonadjacent(left, right) { - left = left || token; - right = right || nexttoken; - if (!option.laxbreak && left.line !== right.line) { - warning("Bad line breaking before '{a}'.", right, right.id); - } else if (option.white) { - left = left || token; - right = right || nexttoken; + left = left || state.tokens.curr; + right = right || state.tokens.next; + if (!state.option.laxbreak && left.line !== right.line) { + warning("W014", right, right.id); + } else if (state.option.white) { + left = left || state.tokens.curr; + right = right || state.tokens.next; if (left.character === right.from) { left.from += (left.character - left.from); - warning("Missing space after '{a}'.", - left, left.value); + warning("W013", left, left.value); } } } function indentation(bias) { - var i; - if (option.white && nexttoken.id !== "(end)") { - i = indent + (bias || 0); - if (nexttoken.from !== i) { - warning( -"Expected '{a}' to have an indentation at {b} instead at {c}.", - nexttoken, nexttoken.value, i, nexttoken.from); - } + if (!state.option.white && !state.option["(explicitIndent)"]) { + return; + } + + if (state.tokens.next.id === "(end)") { + return; + } + + var i = indent + (bias || 0); + if (state.tokens.next.from !== i) { + warning("W015", state.tokens.next, state.tokens.next.value, i, state.tokens.next.from); } } function nolinebreak(t) { - t = t || token; - if (t.line !== nexttoken.line) { - warning("Line breaking error '{a}'.", t, t.value); + t = t || state.tokens.curr; + if (t.line !== state.tokens.next.line) { + warning("E022", t, t.value); } } - function comma() { - if (token.line !== nexttoken.line) { - if (!option.laxcomma) { - if (comma.first) { - warning("Comma warnings can be turned off with 'laxcomma'"); - comma.first = false; + function comma(opts) { + opts = opts || {}; + + if (!opts.peek) { + if (state.tokens.curr.line !== state.tokens.next.line) { + if (!state.option.laxcomma) { + if (comma.first) { + warning("I001"); + comma.first = false; + } + warning("W014", state.tokens.curr, state.tokens.next.value); } - warning("Bad line breaking before '{a}'.", token, nexttoken.id); + } else if (!state.tokens.curr.comment && + state.tokens.curr.character !== state.tokens.next.from && state.option.white) { + state.tokens.curr.from += (state.tokens.curr.character - state.tokens.curr.from); + warning("W011", state.tokens.curr, state.tokens.curr.value); } - } else if (!token.comment && token.character !== nexttoken.from && option.white) { - token.from += (token.character - token.from); - warning("Unexpected space after '{a}'.", token, token.value); + + advance(","); } - advance(","); - nonadjacent(token, nexttoken); + + if (state.tokens.next.value !== "]" && state.tokens.next.value !== "}") { + nonadjacent(state.tokens.curr, state.tokens.next); + } + + if (state.tokens.next.identifier && !(opts.property && state.option.inES5())) { + switch (state.tokens.next.value) { + case "break": + case "case": + case "catch": + case "continue": + case "default": + case "do": + case "else": + case "finally": + case "for": + case "if": + case "in": + case "instanceof": + case "return": + case "yield": + case "switch": + case "throw": + case "try": + case "var": + case "let": + case "while": + case "with": + error("E024", state.tokens.next, state.tokens.next.value); + return false; + } + } + + if (state.tokens.next.type === "(punctuator)") { + switch (state.tokens.next.value) { + case "}": + case "]": + case ",": + if (opts.allowTrailing) { + return true; + } + case ")": + error("E024", state.tokens.next, state.tokens.next.value); + return false; + } + } + return true; } function symbol(s, p) { - var x = syntax[s]; + var x = state.syntax[s]; if (!x || typeof x !== "object") { - syntax[s] = x = { + state.syntax[s] = x = { id: s, lbp: p, value: s @@ -4051,12 +4157,10 @@ klass: return x; } - function delim(s) { return symbol(s, 0); } - function stmt(s, f) { var x = delim(s); x.identifier = x.reserved = true; @@ -4064,14 +4168,12 @@ klass: return x; } - function blockstmt(s, f) { var x = stmt(s, f); x.block = true; return x; } - function reserveName(x) { var c = x.id.charAt(0); if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { @@ -4080,7 +4182,6 @@ klass: return x; } - function prefix(s, f) { var x = symbol(s, 150); reserveName(x); @@ -4088,11 +4189,11 @@ klass: this.right = expression(150); this.arity = "unary"; if (this.id === "++" || this.id === "--") { - if (option.plusplus) { - warning("Unexpected use of '{a}'.", this, this.id); - } else if ((!this.right.identifier || this.right.reserved) && + if (state.option.plusplus) { + warning("W016", this, this.id); + } else if ((!this.right.identifier || isReserved(this.right)) && this.right.id !== "." && this.right.id !== "[") { - warning("Bad operand.", this); + warning("W017", this); } } return this; @@ -4100,7 +4201,6 @@ klass: return x; } - function type(s, f) { var x = delim(s); x.type = s; @@ -4108,13 +4208,28 @@ klass: return x; } - - function reserve(s, f) { - var x = type(s, f); - x.identifier = x.reserved = true; + function reserve(name, func) { + var x = type(name, func); + x.identifier = true; + x.reserved = true; return x; } + function FutureReservedWord(name, meta) { + var x = type(name, (meta && meta.nud) || function () { + return this; + }); + + meta = meta || {}; + meta.isFutureReservedWord = true; + + x.value = name; + x.identifier = true; + x.reserved = true; + x.meta = meta; + + return x; + } function reservevar(s, v) { return reserve(s, function () { @@ -4125,17 +4240,16 @@ klass: }); } - function infix(s, f, p, w) { var x = symbol(s, p); reserveName(x); x.led = function (left) { if (!w) { - nobreaknonadjacent(prevtoken, token); - nonadjacent(token, nexttoken); + nobreaknonadjacent(state.tokens.prev, state.tokens.curr); + nonadjacent(state.tokens.curr, state.tokens.next); } if (s === "in" && left.id === "!") { - warning("Confusing use of '{a}'.", left, "!"); + warning("W018", left, "!"); } if (typeof f === "function") { return f(left, this); @@ -4149,24 +4263,50 @@ klass: } + function application(s) { + var x = symbol(s, 42); + + x.led = function (left) { + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "arrow function syntax (=>)"); + } + + nobreaknonadjacent(state.tokens.prev, state.tokens.curr); + nonadjacent(state.tokens.curr, state.tokens.next); + + this.left = left; + this.right = doFunction(undefined, undefined, false, left); + return this; + }; + return x; + } + function relation(s, f) { var x = symbol(s, 100); + x.led = function (left) { - nobreaknonadjacent(prevtoken, token); - nonadjacent(token, nexttoken); + nobreaknonadjacent(state.tokens.prev, state.tokens.curr); + nonadjacent(state.tokens.curr, state.tokens.next); var right = expression(100); if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { - warning("Use the isNaN function to compare with NaN.", this); + warning("W019", this); } else if (f) { f.apply(this, [left, right]); } + + if (!left || !right) { + quit("E041", state.tokens.curr.line); + } + if (left.id === "!") { - warning("Confusing use of '{a}'.", left, "!"); + warning("W018", left, "!"); } + if (right.id === "!") { - warning("Confusing use of '{a}'.", right, "!"); + warning("W018", right, "!"); } + this.left = left; this.right = right; return this; @@ -4174,58 +4314,71 @@ klass: return x; } - function isPoorRelation(node) { return node && ((node.type === "(number)" && +node.value === 0) || (node.type === "(string)" && node.value === "") || - (node.type === "null" && !option.eqnull) || + (node.type === "null" && !state.option.eqnull) || node.type === "true" || node.type === "false" || node.type === "undefined"); } - function assignop(s) { symbol(s, 20).exps = true; return infix(s, function (left, that) { that.left = left; - if (predefined[left.value] === false && - scope[left.value]["(global)"] === true) { - warning("Read only.", left); - } else if (left["function"]) { - warning("'{a}' is a function.", left, left.value); - } - if (left) { - if (option.esnext && funct[left.value] === "const") { - warning("Attempting to override '{a}' which is a constant", left, left.value); + if (predefined[left.value] === false && + scope[left.value]["(global)"] === true) { + warning("W020", left); + } else if (left["function"]) { + warning("W021", left, left.value); } - if (left.id === "." || left.id === "[") { - if (!left.left || left.left.value === "arguments") { - warning("Bad assignment.", that); + if (funct[left.value] === "const") { + error("E013", left, left.value); + } + + if (left.id === ".") { + if (!left.left) { + warning("E031", that); + } else if (left.left.value === "arguments" && !state.directive["use strict"]) { + warning("E031", that); + } + + that.right = expression(19); + return that; + } else if (left.id === "[") { + if (state.tokens.curr.left.first) { + state.tokens.curr.left.first.forEach(function (t) { + if (funct[t.value] === "const") { + error("E013", t, t.value); + } + }); + } else if (!left.left) { + warning("E031", that); + } else if (left.left.value === "arguments" && !state.directive["use strict"]) { + warning("E031", that); } that.right = expression(19); return that; - } else if (left.identifier && !left.reserved) { + } else if (left.identifier && !isReserved(left)) { if (funct[left.value] === "exception") { - warning("Do not assign to the exception parameter.", left); + warning("W022", left); } that.right = expression(19); return that; } - if (left === syntax["function"]) { - warning( -"Expected an identifier in an assignment and instead saw a function invocation.", - token); + if (left === state.syntax["function"]) { + warning("W023", state.tokens.curr); } } - error("Bad assignment.", that); + error("E031", that); }, 20); } @@ -4234,8 +4387,8 @@ klass: var x = symbol(s, p); reserveName(x); x.led = (typeof f === "function") ? f : function (left) { - if (option.bitwise) { - warning("Unexpected use of '{a}'.", this, this.id); + if (state.option.bitwise) { + warning("W016", this, this.id); } this.left = left; this.right = expression(p); @@ -4248,72 +4401,91 @@ klass: function bitwiseassignop(s) { symbol(s, 20).exps = true; return infix(s, function (left, that) { - if (option.bitwise) { - warning("Unexpected use of '{a}'.", that, that.id); + if (state.option.bitwise) { + warning("W016", that, that.id); } - nonadjacent(prevtoken, token); - nonadjacent(token, nexttoken); + nonadjacent(state.tokens.prev, state.tokens.curr); + nonadjacent(state.tokens.curr, state.tokens.next); if (left) { if (left.id === "." || left.id === "[" || - (left.identifier && !left.reserved)) { + (left.identifier && !isReserved(left))) { expression(19); return that; } - if (left === syntax["function"]) { - warning( -"Expected an identifier in an assignment, and instead saw a function invocation.", - token); + if (left === state.syntax["function"]) { + warning("W023", state.tokens.curr); } return that; } - error("Bad assignment.", that); + error("E031", that); }, 20); } function suffix(s) { var x = symbol(s, 150); + x.led = function (left) { - if (option.plusplus) { - warning("Unexpected use of '{a}'.", this, this.id); - } else if ((!left.identifier || left.reserved) && - left.id !== "." && left.id !== "[") { - warning("Bad operand.", this); + if (state.option.plusplus) { + warning("W016", this, this.id); + } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") { + warning("W017", this); } + this.left = left; return this; }; return x; } - function optionalidentifier(fnparam) { - if (nexttoken.identifier) { - advance(); - if (token.reserved && !option.es5) { - if (!fnparam || token.value !== "undefined") { - warning("Expected an identifier and instead saw '{a}' (a reserved word).", - token, token.id); - } - } - return token.value; + + function optionalidentifier(fnparam, prop) { + if (!state.tokens.next.identifier) { + return; } + + advance(); + + var curr = state.tokens.curr; + var meta = curr.meta || {}; + var val = state.tokens.curr.value; + + if (!isReserved(curr)) { + return val; + } + + if (prop) { + if (state.option.inES5() || meta.isFutureReservedWord) { + return val; + } + } + + if (fnparam && val === "undefined") { + return val; + } + if (prop && !api.getCache("displayed:I002")) { + api.setCache("displayed:I002", true); + warning("I002"); + } + + warning("W024", state.tokens.curr, state.tokens.curr.id); + return val; } - function identifier(fnparam) { - var i = optionalidentifier(fnparam); + function identifier(fnparam, prop) { + var i = optionalidentifier(fnparam, prop); if (i) { return i; } - if (token.id === "function" && nexttoken.id === "(") { - warning("Missing name in function declaration."); + if (state.tokens.curr.id === "function" && state.tokens.next.id === "(") { + warning("W025"); } else { - error("Expected an identifier and instead saw '{a}'.", - nexttoken, nexttoken.value); + error("E030", state.tokens.next, state.tokens.next.value); } } function reachable(s) { var i = 0, t; - if (nexttoken.id !== ";" || noreach) { + if (state.tokens.next.id !== ";" || noreach) { return; } for (;;) { @@ -4323,14 +4495,15 @@ klass: } if (t.id !== "(endline)") { if (t.id === "function") { - if (!option.latedef) { + if (!state.option.latedef) { break; } - warning( -"Inner functions should be listed at the top of the outer function.", t); + + warning("W026", t); break; } - warning("Unreachable '{a}' after '{b}'.", t, t.value, s); + + warning("W027", t, t.value, s); break; } i += 1; @@ -4339,29 +4512,46 @@ klass: function statement(noindent) { - var i = indent, r, s = scope, t = nexttoken; + var values; + var i = indent, r, s = scope, t = state.tokens.next; if (t.id === ";") { advance(";"); return; } + var res = isReserved(t); - if (t.identifier && !t.reserved && peek().id === ":") { + if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") { + warning("W024", t, t.id); + res = false; + } + if (_.has(["[", "{"], t.value)) { + if (lookupBlockType().isDestAssign) { + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "destructuring expression"); + } + values = destructuringExpression(); + values.forEach(function (tok) { + isundef(funct, "W117", tok.token, tok.id); + }); + advance("="); + destructuringExpressionMatch(values, expression(5, true)); + advance(";"); + return; + } + } + if (t.identifier && !res && peek().id === ":") { advance(); advance(":"); scope = Object.create(s); addlabel(t.value, "label"); - if (!nexttoken.labelled && nexttoken.value !== "{") { - warning("Label '{a}' on {b} statement.", nexttoken, t.value, nexttoken.value); + if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { + warning("W028", state.tokens.next, t.value, state.tokens.next.value); } - if (jx.test(t.value + ":")) { - warning("Label '{a}' looks like a javascript url.", t, t.value); - } - - nexttoken.label = t.value; - t = nexttoken; + state.tokens.next.label = t.value; + t = state.tokens.next; } if (t.id === "{") { @@ -4375,28 +4565,23 @@ klass: r = expression(0, true); if (!t.block) { - if (!option.expr && (!r || !r.exps)) { - warning("Expected an assignment or function call and instead saw an expression.", - token); - } else if (option.nonew && r.id === "(" && r.left.id === "new") { - warning("Do not use 'new' for side effects.", t); + if (!state.option.expr && (!r || !r.exps)) { + warning("W030", state.tokens.curr); + } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { + warning("W031", t); } - if (nexttoken.id === ",") { - return comma(); - } - - if (nexttoken.id !== ";") { - if (!option.asi) { - if (!option.lastsemic || nexttoken.id !== "}" || - nexttoken.line !== token.line) { - warningAt("Missing semicolon.", token.line, token.character); + if (state.tokens.next.id !== ";") { + if (!state.option.asi) { + if (!state.option.lastsemic || state.tokens.next.id !== "}" || + state.tokens.next.line !== state.tokens.curr.line) { + warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); } } } else { - adjacent(token, nexttoken); + adjacent(state.tokens.curr, state.tokens.next); advance(";"); - nonadjacent(token, nexttoken); + nonadjacent(state.tokens.curr, state.tokens.next); } } @@ -4409,15 +4594,17 @@ klass: function statements(startLine) { var a = [], p; - while (!nexttoken.reach && nexttoken.id !== "(end)") { - if (nexttoken.id === ";") { + while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { + if (state.tokens.next.id === ";") { p = peek(); - if (!p || p.id !== "(") { - warning("Unnecessary semicolon."); + + if (!p || (p.id !== "(" && p.id !== "[")) { + warning("W032"); } + advance(";"); } else { - a.push(statement(startLine === nexttoken.line)); + a.push(statement(startLine === state.tokens.next.line)); } } return a; @@ -4426,7 +4613,7 @@ klass: var i, p, pn; for (;;) { - if (nexttoken.id === "(string)") { + if (state.tokens.next.id === "(string)") { p = peek(0); if (p.id === "(endline)") { i = 1; @@ -4441,28 +4628,28 @@ klass: pn.id !== "}") { break; } - warning("Missing semicolon.", nexttoken); + warning("W033", state.tokens.next); } else { p = pn; } } else if (p.id === "}") { - warning("Missing semicolon.", p); + warning("W033", p); } else if (p.id !== ";") { break; } indentation(); advance(); - if (directive[token.value]) { - warning("Unnecessary directive \"{a}\".", token, token.value); + if (state.directive[state.tokens.curr.value]) { + warning("W034", state.tokens.curr, state.tokens.curr.value); } - if (token.value === "use strict") { - if (!option["(explicitNewcap)"]) - option.newcap = true; - option.undef = true; + if (state.tokens.curr.value === "use strict") { + if (!state.option["(explicitNewcap)"]) + state.option.newcap = true; + state.option.undef = true; } - directive[token.value] = true; + state.directive[state.tokens.curr.value] = true; if (p.id === ";") { advance(";"); @@ -4472,7 +4659,7 @@ klass: break; } } - function block(ordinary, stmt, isfunc) { + function block(ordinary, stmt, isfunc, isfatarrow) { var a, b = inblock, old_indent = indent, @@ -4484,37 +4671,39 @@ klass: inblock = ordinary; - if (!ordinary || !option.funcscope) + if (!ordinary || !state.option.funcscope) scope = Object.create(scope); - nonadjacent(token, nexttoken); - t = nexttoken; + nonadjacent(state.tokens.curr, state.tokens.next); + t = state.tokens.next; var metrics = funct["(metrics)"]; metrics.nestedBlockDepth += 1; metrics.verifyMaxNestedBlockDepthPerFunction(); - if (nexttoken.id === "{") { + if (state.tokens.next.id === "{") { advance("{"); - line = token.line; - if (nexttoken.id !== "}") { - indent += option.indent; - while (!ordinary && nexttoken.from > indent) { - indent += option.indent; + funct["(blockscope)"].stack(); + + line = state.tokens.curr.line; + if (state.tokens.next.id !== "}") { + indent += state.option.indent; + while (!ordinary && state.tokens.next.from > indent) { + indent += state.option.indent; } if (isfunc) { m = {}; - for (d in directive) { - if (is_own(directive, d)) { - m[d] = directive[d]; + for (d in state.directive) { + if (_.has(state.directive, d)) { + m[d] = state.directive[d]; } } directives(); - if (option.strict && funct["(context)"]["(global)"]) { - if (!m["use strict"] && !directive["use strict"]) { - warning("Missing \"use strict\" statement."); + if (state.option.strict && funct["(context)"]["(global)"]) { + if (!m["use strict"] && !state.directive["use strict"]) { + warning("E007"); } } } @@ -4524,37 +4713,65 @@ klass: metrics.statementCount += a.length; if (isfunc) { - directive = m; + state.directive = m; } - indent -= option.indent; - if (line !== nexttoken.line) { + indent -= state.option.indent; + if (line !== state.tokens.next.line) { indentation(); } - } else if (line !== nexttoken.line) { + } else if (line !== state.tokens.next.line) { indentation(); } advance("}", t); + + funct["(blockscope)"].unstack(); + indent = old_indent; } else if (!ordinary) { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, "{", nexttoken.value); + if (isfunc) { + m = {}; + if (stmt && !isfatarrow && !state.option.inMoz(true)) { + error("W118", state.tokens.curr, "function closure expressions"); + } + + if (!stmt) { + for (d in state.directive) { + if (_.has(state.directive, d)) { + m[d] = state.directive[d]; + } + } + } + expression(5); + + if (state.option.strict && funct["(context)"]["(global)"]) { + if (!m["use strict"] && !state.directive["use strict"]) { + warning("E007"); + } + } + } else { + error("E021", state.tokens.next, "{", state.tokens.next.value); + } } else { - if (!stmt || option.curly) - warning("Expected '{a}' and instead saw '{b}'.", - nexttoken, "{", nexttoken.value); + funct["(nolet)"] = true; + + if (!stmt || state.option.curly) { + warning("W116", state.tokens.next, "{", state.tokens.next.value); + } noreach = true; - indent += option.indent; - a = [statement(nexttoken.line === token.line)]; - indent -= option.indent; + indent += state.option.indent; + a = [statement(state.tokens.next.line === state.tokens.curr.line)]; + indent -= state.option.indent; noreach = false; + + delete funct["(nolet)"]; } funct["(verb)"] = null; - if (!ordinary || !option.funcscope) scope = s; + if (!ordinary || !state.option.funcscope) scope = s; inblock = b; - if (ordinary && option.noempty && (!a || a.length === 0)) { - warning("Empty block."); + if (ordinary && state.option.noempty && (!a || a.length === 0)) { + warning("W035"); } metrics.nestedBlockDepth -= 1; return a; @@ -4563,7 +4780,7 @@ klass: function countMember(m) { if (membersOnly && typeof membersOnly[m] !== "boolean") { - warning("Unexpected /*member '{a}'.", token, m); + warning("W036", state.tokens.curr, m); } if (typeof member[m] === "number") { member[m] += 1; @@ -4573,8 +4790,8 @@ klass: } - function note_implied(token) { - var name = token.value, line = token.line, a = implied[name]; + function note_implied(tkn) { + var name = tkn.value, line = tkn.line, a = implied[name]; if (typeof a === "function") { a = false; } @@ -4595,7 +4812,7 @@ klass: return this; }); - syntax["(identifier)"] = { + state.syntax["(identifier)"] = { type: "(identifier)", lbp: 0, identifier: true, @@ -4613,33 +4830,42 @@ klass: s = funct; funct = f; } - if (funct === s) { - switch (funct[v]) { + var block; + if (_.has(funct, "(blockscope)")) { + block = funct["(blockscope)"].getlabel(v); + } + if (funct === s || block) { + switch (block ? block[v]["(type)"] : funct[v]) { case "unused": - funct[v] = "var"; + if (block) block[v]["(type)"] = "var"; + else funct[v] = "var"; break; case "unction": - funct[v] = "function"; + if (block) block[v]["(type)"] = "function"; + else funct[v] = "function"; this["function"] = true; break; case "function": this["function"] = true; break; case "label": - warning("'{a}' is a statement label.", token, v); + warning("W037", state.tokens.curr, v); break; } } else if (funct["(global)"]) { - if (option.undef && typeof predefined[v] !== "boolean") { + if (typeof predefined[v] !== "boolean") { if (!(anonname === "typeof" || anonname === "delete") || - (nexttoken && (nexttoken.value === "." || nexttoken.value === "["))) { + (state.tokens.next && (state.tokens.next.value === "." || + state.tokens.next.value === "["))) { - isundef(funct, "'{a}' is not defined.", token, v); + if (!funct["(comparray)"].check(v)) { + isundef(funct, "W117", state.tokens.curr, v); + } } } - note_implied(token); + note_implied(state.tokens.curr); } else { switch (funct[v]) { @@ -4647,10 +4873,10 @@ klass: case "function": case "var": case "unused": - warning("'{a}' used out of scope.", token, v); + warning("W038", state.tokens.curr, v); break; case "label": - warning("'{a}' is a statement label.", token, v); + warning("W037", state.tokens.curr, v); break; case "outer": case "global": @@ -4659,19 +4885,17 @@ klass: if (s === true) { funct[v] = true; } else if (s === null) { - warning("'{a}' is not allowed.", token, v); - note_implied(token); + warning("W039", state.tokens.curr, v); + note_implied(state.tokens.curr); } else if (typeof s !== "object") { - if (option.undef) { - if (!(anonname === "typeof" || anonname === "delete") || - (nexttoken && - (nexttoken.value === "." || nexttoken.value === "["))) { + if (!(anonname === "typeof" || anonname === "delete") || + (state.tokens.next && + (state.tokens.next.value === "." || state.tokens.next.value === "["))) { - isundef(funct, "'{a}' is not defined.", token, v); - } + isundef(funct, "W117", state.tokens.curr, v); } funct[v] = true; - note_implied(token); + note_implied(state.tokens.curr); } else { switch (s[v]) { case "function": @@ -4689,7 +4913,7 @@ klass: funct[v] = s["(global)"] ? "global" : "outer"; break; case "label": - warning("'{a}' is a statement label.", token, v); + warning("W037", state.tokens.curr, v); } } } @@ -4697,8 +4921,7 @@ klass: return this; }, led: function () { - error("Expected an operator and instead saw '{a}'.", - nexttoken, nexttoken.value); + error("E033", state.tokens.next, state.tokens.next.value); } }; @@ -4709,10 +4932,6 @@ klass: delim("(endline)"); delim("(begin)"); delim("(end)").reach = true; - delim(""); delim("(error)").reach = true; delim("}").reach = true; delim(")"); @@ -4721,17 +4940,16 @@ klass: delim("'").reach = true; delim(";"); delim(":").reach = true; - delim(","); delim("#"); - delim("@"); + reserve("else"); reserve("case").reach = true; reserve("catch"); reserve("default").reach = true; reserve("finally"); reservevar("arguments", function (x) { - if (directive["use strict"] && funct["(global)"]) { - warning("Strict violation.", x); + if (state.directive["use strict"] && funct["(global)"]) { + warning("E008", x); } }); reservevar("eval"); @@ -4739,27 +4957,46 @@ klass: reservevar("Infinity"); reservevar("null"); reservevar("this", function (x) { - if (directive["use strict"] && !option.validthis && ((funct["(statement)"] && + if (state.directive["use strict"] && !state.option.validthis && ((funct["(statement)"] && funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { - warning("Possible strict violation.", x); + warning("W040", x); } }); reservevar("true"); reservevar("undefined"); + assignop("=", "assign", 20); assignop("+=", "assignadd", 20); assignop("-=", "assignsub", 20); assignop("*=", "assignmult", 20); assignop("/=", "assigndiv", 20).nud = function () { - error("A regular expression literal can be confused with '/='."); + error("E014"); }; assignop("%=", "assignmod", 20); + bitwiseassignop("&=", "assignbitand", 20); bitwiseassignop("|=", "assignbitor", 20); bitwiseassignop("^=", "assignbitxor", 20); bitwiseassignop("<<=", "assignshiftleft", 20); bitwiseassignop(">>=", "assignshiftright", 20); bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); + infix(",", function (left, that) { + var expr; + that.exprs = [left]; + if (!comma({peek: true})) { + return that; + } + while (true) { + if (!(expr = expression(5))) { + break; + } + that.exprs.push(expr); + if (state.tokens.next.value !== "," || !comma()) { + break; + } + } + return that; + }, 5, true); infix("?", function (left, that) { that.left = left; that.right = expression(10); @@ -4774,31 +5011,28 @@ klass: bitwise("^", "bitxor", 80); bitwise("&", "bitand", 90); relation("==", function (left, right) { - var eqnull = option.eqnull && (left.value === "null" || right.value === "null"); + var eqnull = state.option.eqnull && (left.value === "null" || right.value === "null"); - if (!eqnull && option.eqeqeq) - warning("Expected '{a}' and instead saw '{b}'.", this, "===", "=="); + if (!eqnull && state.option.eqeqeq) + warning("W116", this, "===", "=="); else if (isPoorRelation(left)) - warning("Use '{a}' to compare with '{b}'.", this, "===", left.value); + warning("W041", this, "===", left.value); else if (isPoorRelation(right)) - warning("Use '{a}' to compare with '{b}'.", this, "===", right.value); + warning("W041", this, "===", right.value); return this; }); relation("==="); relation("!=", function (left, right) { - var eqnull = option.eqnull && + var eqnull = state.option.eqnull && (left.value === "null" || right.value === "null"); - if (!eqnull && option.eqeqeq) { - warning("Expected '{a}' and instead saw '{b}'.", - this, "!==", "!="); + if (!eqnull && state.option.eqeqeq) { + warning("W116", this, "!==", "!="); } else if (isPoorRelation(left)) { - warning("Use '{a}' to compare with '{b}'.", - this, "!==", left.value); + warning("W041", this, "!==", left.value); } else if (isPoorRelation(right)) { - warning("Use '{a}' to compare with '{b}'.", - this, "!==", right.value); + warning("W041", this, "!==", right.value); } return this; }); @@ -4817,8 +5051,8 @@ klass: if (left && right && left.id === "(string)" && right.id === "(string)") { left.value += right.value; left.character = right.character; - if (!option.scripturl && jx.test(left.value)) { - warning("JavaScript URL.", left); + if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { + warning("W050", left); } return left; } @@ -4828,13 +5062,13 @@ klass: }, 130); prefix("+", "num"); prefix("+++", function () { - warning("Confusing pluses."); + warning("W007"); this.right = expression(150); this.arity = "unary"; return this; }); infix("+++", function (left) { - warning("Confusing pluses."); + warning("W007"); this.left = left; this.right = expression(130); return this; @@ -4842,13 +5076,13 @@ klass: infix("-", "sub", 130); prefix("-", "neg"); prefix("---", function () { - warning("Confusing minuses."); + warning("W006"); this.right = expression(150); this.arity = "unary"; return this; }); infix("---", function (left) { - warning("Confusing minuses."); + warning("W006"); this.left = left; this.right = expression(130); return this; @@ -4859,23 +5093,34 @@ klass: suffix("++", "postinc"); prefix("++", "preinc"); - syntax["++"].exps = true; + state.syntax["++"].exps = true; suffix("--", "postdec"); prefix("--", "predec"); - syntax["--"].exps = true; + state.syntax["--"].exps = true; prefix("delete", function () { - var p = expression(0); + var p = expression(5); if (!p || (p.id !== "." && p.id !== "[")) { - warning("Variables should not be deleted."); + warning("W051"); } this.first = p; return this; }).exps = true; prefix("~", function () { - if (option.bitwise) { - warning("Unexpected '{a}'.", this, "~"); + if (state.option.bitwise) { + warning("W052", this, "~"); + } + expression(150); + return this; + }); + + prefix("...", function () { + if (!state.option.inESNext()) { + warning("W104", this, "spread/rest operator"); + } + if (!state.tokens.next.identifier) { + error("E030", state.tokens.next, state.tokens.next.value); } expression(150); return this; @@ -4884,11 +5129,17 @@ klass: prefix("!", function () { this.right = expression(150); this.arity = "unary"; + + if (!this.right) { // '!' followed by nothing? Give up. + quit("E041", this.line || 0); + } + if (bang[this.right.id] === true) { - warning("Confusing use of '{a}'.", this, "!"); + warning("W018", this, "!"); } return this; }); + prefix("typeof", "typeof"); prefix("new", function () { var c = expression(155), i; @@ -4901,11 +5152,11 @@ klass: case "Boolean": case "Math": case "JSON": - warning("Do not use {a} as a constructor.", prevtoken, c.value); + warning("W053", state.tokens.prev, c.value); break; case "Function": - if (!option.evil) { - warning("The Function constructor is eval."); + if (!state.option.evil) { + warning("W054"); } break; case "Date": @@ -4914,102 +5165,113 @@ klass: default: if (c.id !== "function") { i = c.value.substr(0, 1); - if (option.newcap && (i < "A" || i > "Z") && !is_own(global, c.value)) { - warning("A constructor name should start with an uppercase letter.", - token); + if (state.option.newcap && (i < "A" || i > "Z") && !_.has(global, c.value)) { + warning("W055", state.tokens.curr); } } } } else { if (c.id !== "." && c.id !== "[" && c.id !== "(") { - warning("Bad constructor.", token); + warning("W056", state.tokens.curr); } } } else { - if (!option.supernew) - warning("Weird construction. Delete 'new'.", this); + if (!state.option.supernew) + warning("W057", this); } - adjacent(token, nexttoken); - if (nexttoken.id !== "(" && !option.supernew) { - warning("Missing '()' invoking a constructor.", - token, token.value); + adjacent(state.tokens.curr, state.tokens.next); + if (state.tokens.next.id !== "(" && !state.option.supernew) { + warning("W058", state.tokens.curr, state.tokens.curr.value); } this.first = c; return this; }); - syntax["new"].exps = true; + state.syntax["new"].exps = true; prefix("void").exps = true; infix(".", function (left, that) { - adjacent(prevtoken, token); + adjacent(state.tokens.prev, state.tokens.curr); nobreak(); - var m = identifier(); + var m = identifier(false, true); + if (typeof m === "string") { countMember(m); } + that.left = left; that.right = m; + + if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { + warning("W001"); + } + if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { - if (option.noarg) - warning("Avoid arguments.{a}.", left, m); - else if (directive["use strict"]) - error("Strict violation."); - } else if (!option.evil && left && left.value === "document" && + if (state.option.noarg) + warning("W059", left, m); + else if (state.directive["use strict"]) + error("E008"); + } else if (!state.option.evil && left && left.value === "document" && (m === "write" || m === "writeln")) { - warning("document.write can be a form of eval.", left); + warning("W060", left); } - if (!option.evil && (m === "eval" || m === "execScript")) { - warning("eval is evil."); + + if (!state.option.evil && (m === "eval" || m === "execScript")) { + warning("W061"); } + return that; }, 160, true); infix("(", function (left, that) { - if (prevtoken.id !== "}" && prevtoken.id !== ")") { - nobreak(prevtoken, token); + if (state.tokens.prev.id !== "}" && state.tokens.prev.id !== ")") { + nobreak(state.tokens.prev, state.tokens.curr); } + nospace(); - if (option.immed && !left.immed && left.id === "function") { - warning("Wrap an immediate function invocation in parentheses " + - "to assist the reader in understanding that the expression " + - "is the result of a function, and not the function itself."); + if (state.option.immed && left && !left.immed && left.id === "function") { + warning("W062"); } - var n = 0, - p = []; + + var n = 0; + var p = []; + if (left) { if (left.type === "(identifier)") { if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { if ("Number String Boolean Date Object".indexOf(left.value) === -1) { if (left.value === "Math") { - warning("Math is not a function.", left); - } else if (option.newcap) { - warning("Missing 'new' prefix when invoking a constructor.", left); + warning("W063", left); + } else if (state.option.newcap) { + warning("W064", left); } } } } } - if (nexttoken.id !== ")") { + + if (state.tokens.next.id !== ")") { for (;;) { p[p.length] = expression(10); n += 1; - if (nexttoken.id !== ",") { + if (state.tokens.next.id !== ",") { break; } comma(); } } + advance(")"); - nospace(prevtoken, token); + nospace(state.tokens.prev, state.tokens.curr); + if (typeof left === "object") { if (left.value === "parseInt" && n === 1) { - warning("Missing radix parameter.", token); + warning("W065", state.tokens.curr); } - if (!option.evil) { + if (!state.option.evil) { if (left.value === "eval" || left.value === "Function" || left.value === "execScript") { - warning("eval is evil.", left); + warning("W061", left); if (p[0] && [0].id === "(string)") { addInternalSrc(left, p[0].value); @@ -5017,99 +5279,188 @@ klass: } else if (p[0] && p[0].id === "(string)" && (left.value === "setTimeout" || left.value === "setInterval")) { - warning( - "Implied eval is evil. Pass a function instead of a string.", left); + warning("W066", left); addInternalSrc(left, p[0].value); } else if (p[0] && p[0].id === "(string)" && left.value === "." && left.left.value === "window" && (left.right === "setTimeout" || left.right === "setInterval")) { - warning( - "Implied eval is evil. Pass a function instead of a string.", left); + warning("W066", left); addInternalSrc(left, p[0].value); } } if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?") { - warning("Bad invocation.", left); + warning("W067", left); } } + that.left = left; return that; }, 155, true).exps = true; prefix("(", function () { nospace(); - if (nexttoken.id === "function") { - nexttoken.immed = true; + var bracket, brackets = []; + var pn, pn1, i = 0; + var ret; + + do { + pn = peek(i); + i += 1; + pn1 = peek(i); + i += 1; + } while (pn.value !== ")" && pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)"); + + if (state.tokens.next.id === "function") { + state.tokens.next.immed = true; } - var v = expression(0); - advance(")", this); - nospace(prevtoken, token); - if (option.immed && v.id === "function") { - if (nexttoken.id !== "(" && - (nexttoken.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { - warning( -"Do not wrap function literals in parens unless they are to be immediately invoked.", - this); + + var exprs = []; + + if (state.tokens.next.id !== ")") { + for (;;) { + if (pn1.value === "=>" && state.tokens.next.value === "{") { + bracket = state.tokens.next; + bracket.left = destructuringExpression(); + brackets.push(bracket); + for (var t in bracket.left) { + exprs.push(bracket.left[t].token); + } + } else { + exprs.push(expression(5)); + } + if (state.tokens.next.id !== ",") { + break; + } + comma(); } } - return v; + advance(")", this); + nospace(state.tokens.prev, state.tokens.curr); + if (state.option.immed && exprs[0] && exprs[0].id === "function") { + if (state.tokens.next.id !== "(" && + (state.tokens.next.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { + warning("W068", this); + } + } + + if (state.tokens.next.value === "=>") { + return exprs; + } + if (!exprs.length) { + return; + } + if (exprs.length > 1) { + ret = Object.create(state.syntax[","]); + ret.exprs = exprs; + } else { + ret = exprs[0]; + } + if (ret) { + ret.paren = true; + } + return ret; }); + application("=>"); + infix("[", function (left, that) { - nobreak(prevtoken, token); + nobreak(state.tokens.prev, state.tokens.curr); nospace(); - var e = expression(0), s; + var e = expression(5), s; if (e && e.type === "(string)") { - if (!option.evil && (e.value === "eval" || e.value === "execScript")) { - warning("eval is evil.", that); + if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { + warning("W061", that); } + countMember(e.value); - if (!option.sub && ix.test(e.value)) { - s = syntax[e.value]; - if (!s || !s.reserved) { - warning("['{a}'] is better written in dot notation.", - prevtoken, e.value); + if (!state.option.sub && reg.identifier.test(e.value)) { + s = state.syntax[e.value]; + if (!s || !isReserved(s)) { + warning("W069", state.tokens.prev, e.value); } } } advance("]", that); - nospace(prevtoken, token); + + if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { + warning("W001"); + } + + nospace(state.tokens.prev, state.tokens.curr); that.left = left; that.right = e; return that; }, 160, true); - prefix("[", function () { - var b = token.line !== nexttoken.line; - this.first = []; - if (b) { - indent += option.indent; - if (nexttoken.from === indent + option.indent) { - indent += option.indent; + function comprehensiveArrayExpression() { + var res = {}; + res.exps = true; + funct["(comparray)"].stack(); + + res.right = expression(5); + advance("for"); + if (state.tokens.next.value === "each") { + advance("each"); + if (!state.option.inMoz(true)) { + warning("W118", state.tokens.curr, "for each"); } } - while (nexttoken.id !== "(end)") { - while (nexttoken.id === ",") { - if (!option.es5) - warning("Extra comma."); + advance("("); + funct["(comparray)"].setState("define"); + res.left = expression(5); + advance(")"); + if (state.tokens.next.value === "if") { + advance("if"); + advance("("); + funct["(comparray)"].setState("filter"); + res.filter = expression(5); + advance(")"); + } + advance("]"); + funct["(comparray)"].unstack(); + return res; + } + + prefix("[", function () { + var blocktype = lookupBlockType(true); + if (blocktype.isCompArray) { + if (!state.option.inMoz(true)) { + warning("W118", state.tokens.curr, "array comprehension"); + } + return comprehensiveArrayExpression(); + } else if (blocktype.isDestAssign && !state.option.inESNext()) { + warning("W104", state.tokens.curr, "destructuring assignment"); + } + var b = state.tokens.curr.line !== state.tokens.next.line; + this.first = []; + if (b) { + indent += state.option.indent; + if (state.tokens.next.from === indent + state.option.indent) { + indent += state.option.indent; + } + } + while (state.tokens.next.id !== "(end)") { + while (state.tokens.next.id === ",") { + if (!state.option.inES5()) + warning("W070"); advance(","); } - if (nexttoken.id === "]") { + if (state.tokens.next.id === "]") { break; } - if (b && token.line !== nexttoken.line) { + if (b && state.tokens.curr.line !== state.tokens.next.line) { indentation(); } this.first.push(expression(10)); - if (nexttoken.id === ",") { - comma(); - if (nexttoken.id === "]" && !option.es5) { - warning("Extra comma.", token); + if (state.tokens.next.id === ",") { + comma({ allowTrailing: true }); + if (state.tokens.next.id === "]" && !state.option.inES5(true)) { + warning("W070", state.tokens.curr); break; } } else { @@ -5117,7 +5468,7 @@ klass: } } if (b) { - indent -= option.indent; + indent -= state.option.indent; indentation(); } advance("]", this); @@ -5126,71 +5477,139 @@ klass: function property_name() { - var id = optionalidentifier(true); + var id = optionalidentifier(false, true); + if (!id) { - if (nexttoken.id === "(string)") { - id = nexttoken.value; + if (state.tokens.next.id === "(string)") { + id = state.tokens.next.value; advance(); - } else if (nexttoken.id === "(number)") { - id = nexttoken.value.toString(); + } else if (state.tokens.next.id === "(number)") { + id = state.tokens.next.value.toString(); advance(); } } + + if (id === "hasOwnProperty") { + warning("W001"); + } + return id; } - function functionparams() { - var next = nexttoken; + function functionparams(parsed) { + var curr, next; var params = []; var ident; + var tokens = []; + var t; + + if (parsed) { + if (parsed instanceof Array) { + for (var i in parsed) { + curr = parsed[i]; + if (_.contains(["{", "["], curr.id)) { + for (t in curr.left) { + t = tokens[t]; + if (t.id) { + params.push(t.id); + addlabel(t.id, "unused", t.token); + } + } + } else if (curr.value === "...") { + if (!state.option.inESNext()) { + warning("W104", curr, "spread/rest operator"); + } + continue; + } else { + addlabel(curr.value, "unused", curr); + } + } + return params; + } else { + if (parsed.identifier === true) { + addlabel(parsed.value, "unused", parsed); + return [parsed]; + } + } + } + + next = state.tokens.next; advance("("); nospace(); - if (nexttoken.id === ")") { + if (state.tokens.next.id === ")") { advance(")"); return; } for (;;) { - ident = identifier(true); - params.push(ident); - addlabel(ident, "unused", token); - if (nexttoken.id === ",") { + if (_.contains(["{", "["], state.tokens.next.id)) { + tokens = destructuringExpression(); + for (t in tokens) { + t = tokens[t]; + if (t.id) { + params.push(t.id); + addlabel(t.id, "unused", t.token); + } + } + } else if (state.tokens.next.value === "...") { + if (!state.option.inESNext()) { + warning("W104", state.tokens.next, "spread/rest operator"); + } + advance("..."); + nospace(); + ident = identifier(true); + params.push(ident); + addlabel(ident, "unused", state.tokens.curr); + } else { + ident = identifier(true); + params.push(ident); + addlabel(ident, "unused", state.tokens.curr); + } + if (state.tokens.next.id === ",") { comma(); } else { advance(")", next); - nospace(prevtoken, token); + nospace(state.tokens.prev, state.tokens.curr); return params; } } } - function doFunction(name, statement) { + function doFunction(name, statement, generator, fatarrowparams) { var f; - var oldOption = option; + var oldOption = state.option; + var oldIgnored = state.ignored; var oldScope = scope; - option = Object.create(option); + state.option = Object.create(state.option); + state.ignored = Object.create(state.ignored); scope = Object.create(scope); funct = { - "(name)" : name || "\"" + anonname + "\"", - "(line)" : nexttoken.line, - "(character)": nexttoken.character, - "(context)" : funct, - "(breakage)" : 0, - "(loopage)" : 0, - "(metrics)" : createMetrics(nexttoken), - "(scope)" : scope, - "(statement)": statement, - "(tokens)" : {} + "(name)" : name || "\"" + anonname + "\"", + "(line)" : state.tokens.next.line, + "(character)" : state.tokens.next.character, + "(context)" : funct, + "(breakage)" : 0, + "(loopage)" : 0, + "(metrics)" : createMetrics(state.tokens.next), + "(scope)" : scope, + "(statement)" : statement, + "(tokens)" : {}, + "(blockscope)": funct["(blockscope)"], + "(comparray)" : funct["(comparray)"] }; + if (generator) { + funct["(generator)"] = true; + } + f = funct; - token.funct = funct; + state.tokens.curr.funct = funct; functions.push(funct); @@ -5198,18 +5617,25 @@ klass: addlabel(name, "function"); } - funct["(params)"] = functionparams(); + funct["(params)"] = functionparams(fatarrowparams); + funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]); - block(false, false, true); + block(false, true, true, fatarrowparams ? true:false); + + if (generator && funct["(generator)"] !== "yielded") { + error("E047", state.tokens.curr); + } funct["(metrics)"].verifyMaxStatementsPerFunction(); funct["(metrics)"].verifyMaxComplexityPerFunction(); + funct["(unusedOption)"] = state.option.unused; scope = oldScope; - option = oldOption; - funct["(last)"] = token.line; - funct["(lastcharacter)"] = token.character; + state.option = oldOption; + state.ignored = oldIgnored; + funct["(last)"] = state.tokens.curr.line; + funct["(lastcharacter)"] = state.tokens.curr.character; funct = funct["(context)"]; return f; @@ -5221,37 +5647,33 @@ klass: nestedBlockDepth: -1, ComplexityCount: 1, verifyMaxStatementsPerFunction: function () { - if (option.maxstatements && - this.statementCount > option.maxstatements) { - var message = "Too many statements per function (" + this.statementCount + ")."; - warning(message, functionStartToken); + if (state.option.maxstatements && + this.statementCount > state.option.maxstatements) { + warning("W071", functionStartToken, this.statementCount); } }, verifyMaxParametersPerFunction: function (params) { params = params || []; - if (option.maxparams && params.length > option.maxparams) { - var message = "Too many parameters per function (" + params.length + ")."; - warning(message, functionStartToken); + if (state.option.maxparams && params.length > state.option.maxparams) { + warning("W072", functionStartToken, params.length); } }, verifyMaxNestedBlockDepthPerFunction: function () { - if (option.maxdepth && + if (state.option.maxdepth && this.nestedBlockDepth > 0 && - this.nestedBlockDepth === option.maxdepth + 1) { - var message = "Blocks are nested too deeply (" + this.nestedBlockDepth + ")."; - warning(message); + this.nestedBlockDepth === state.option.maxdepth + 1) { + warning("W073", null, this.nestedBlockDepth); } }, verifyMaxComplexityPerFunction: function () { - var max = option.maxcomplexity; + var max = state.option.maxcomplexity; var cc = this.ComplexityCount; if (max && cc > max) { - var message = "Cyclomatic complexity is too high per function (" + cc + ")."; - warning(message, functionStartToken); + warning("W074", functionStartToken, cc); } } }; @@ -5261,236 +5683,406 @@ klass: funct["(metrics)"].ComplexityCount += 1; } + function checkCondAssignment(expr) { + var id, paren; + if (expr) { + id = expr.id; + paren = expr.paren; + if (id === "," && (expr = expr.exprs[expr.exprs.length - 1])) { + id = expr.id; + paren = paren || expr.paren; + } + } + switch (id) { + case "=": + case "+=": + case "-=": + case "*=": + case "%=": + case "&=": + case "|=": + case "^=": + case "/=": + if (!paren && !state.option.boss) { + warning("W084"); + } + } + } + (function (x) { - x.nud = function () { - var b, f, i, p, t; + x.nud = function (isclassdef) { + var b, f, i, p, t, g; var props = {}; // All properties, including accessors + var tag = ""; - function saveProperty(name, token) { - if (props[name] && is_own(props, name)) - warning("Duplicate member '{a}'.", nexttoken, i); + function saveProperty(name, tkn) { + if (props[name] && _.has(props, name)) + warning("W075", state.tokens.next, i); else props[name] = {}; props[name].basic = true; - props[name].basicToken = token; + props[name].basictkn = tkn; } - function saveSetter(name, token) { - if (props[name] && is_own(props, name)) { + function saveSetter(name, tkn) { + if (props[name] && _.has(props, name)) { if (props[name].basic || props[name].setter) - warning("Duplicate member '{a}'.", nexttoken, i); + warning("W075", state.tokens.next, i); } else { props[name] = {}; } props[name].setter = true; - props[name].setterToken = token; + props[name].setterToken = tkn; } function saveGetter(name) { - if (props[name] && is_own(props, name)) { + if (props[name] && _.has(props, name)) { if (props[name].basic || props[name].getter) - warning("Duplicate member '{a}'.", nexttoken, i); + warning("W075", state.tokens.next, i); } else { props[name] = {}; } props[name].getter = true; - props[name].getterToken = token; + props[name].getterToken = state.tokens.curr; } - b = token.line !== nexttoken.line; + b = state.tokens.curr.line !== state.tokens.next.line; if (b) { - indent += option.indent; - if (nexttoken.from === indent + option.indent) { - indent += option.indent; + indent += state.option.indent; + if (state.tokens.next.from === indent + state.option.indent) { + indent += state.option.indent; } } + for (;;) { - if (nexttoken.id === "}") { + if (state.tokens.next.id === "}") { break; } + if (b) { indentation(); } - if (nexttoken.value === "get" && peek().id !== ":") { + + if (isclassdef && state.tokens.next.value === "static") { + advance("static"); + tag = "static "; + } + + if (state.tokens.next.value === "get" && peek().id !== ":") { advance("get"); - if (!option.es5) { - error("get/set are ES5 features."); + + if (!state.option.inES5(!isclassdef)) { + error("E034"); } + i = property_name(); if (!i) { - error("Missing property name."); + error("E035"); } - saveGetter(i); - t = nexttoken; - adjacent(token, nexttoken); + if (isclassdef && i === "constructor") { + error("E049", state.tokens.next, "class getter method", i); + } + + saveGetter(tag + i); + t = state.tokens.next; + adjacent(state.tokens.curr, state.tokens.next); f = doFunction(); p = f["(params)"]; + if (p) { - warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i); + warning("W076", t, p[0], i); } - adjacent(token, nexttoken); - } else if (nexttoken.value === "set" && peek().id !== ":") { + + adjacent(state.tokens.curr, state.tokens.next); + } else if (state.tokens.next.value === "set" && peek().id !== ":") { advance("set"); - if (!option.es5) { - error("get/set are ES5 features."); + + if (!state.option.inES5(!isclassdef)) { + error("E034"); } + i = property_name(); if (!i) { - error("Missing property name."); + error("E035"); } - saveSetter(i, nexttoken); - t = nexttoken; - adjacent(token, nexttoken); + if (isclassdef && i === "constructor") { + error("E049", state.tokens.next, "class setter method", i); + } + + saveSetter(tag + i, state.tokens.next); + t = state.tokens.next; + adjacent(state.tokens.curr, state.tokens.next); f = doFunction(); p = f["(params)"]; + if (!p || p.length !== 1) { - warning("Expected a single parameter in set {a} function.", t, i); + warning("W077", t, i); } } else { + g = false; + if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { + if (!state.option.inESNext()) { + warning("W104", state.tokens.next, "generator functions"); + } + advance("*"); + g = true; + } i = property_name(); - saveProperty(i, nexttoken); + saveProperty(tag + i, state.tokens.next); + if (typeof i !== "string") { break; } - advance(":"); - nonadjacent(token, nexttoken); - expression(10); + + if (state.tokens.next.value === "(") { + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "concise methods"); + } + doFunction(i, undefined, g); + } else if (!isclassdef) { + advance(":"); + nonadjacent(state.tokens.curr, state.tokens.next); + expression(10); + } + } + if (isclassdef && i === "prototype") { + error("E049", state.tokens.next, "class method", i); } countMember(i); - if (nexttoken.id === ",") { - comma(); - if (nexttoken.id === ",") { - warning("Extra comma.", token); - } else if (nexttoken.id === "}" && !option.es5) { - warning("Extra comma.", token); + if (isclassdef) { + tag = ""; + continue; + } + if (state.tokens.next.id === ",") { + comma({ allowTrailing: true, property: true }); + if (state.tokens.next.id === ",") { + warning("W070", state.tokens.curr); + } else if (state.tokens.next.id === "}" && !state.option.inES5(true)) { + warning("W070", state.tokens.curr); } } else { break; } } if (b) { - indent -= option.indent; + indent -= state.option.indent; indentation(); } advance("}", this); - if (option.es5) { + if (state.option.inES5()) { for (var name in props) { - if (is_own(props, name) && props[name].setter && !props[name].getter) { - warning("Setter is defined without getter.", props[name].setterToken); + if (_.has(props, name) && props[name].setter && !props[name].getter) { + warning("W078", props[name].setterToken); } } } return this; }; x.fud = function () { - error("Expected to see a statement and instead saw a block.", token); + error("E036", state.tokens.curr); }; }(delim("{"))); - useESNextSyntax = function () { - var conststatement = stmt("const", function (prefix) { - var id, name, value; - - this.first = []; - for (;;) { - nonadjacent(token, nexttoken); - id = identifier(); - if (funct[id] === "const") { - warning("const '" + id + "' has already been declared"); + function destructuringExpression() { + var id, ids; + var identifiers = []; + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "destructuring expression"); + } + var nextInnerDE = function () { + var ident; + if (_.contains(["[", "{"], state.tokens.next.value)) { + ids = destructuringExpression(); + for (var id in ids) { + id = ids[id]; + identifiers.push({ id: id.id, token: id.token }); } - if (funct["(global)"] && predefined[id] === false) { - warning("Redefinition of '{a}'.", token, id); - } - addlabel(id, "const"); - if (prefix) { - break; - } - name = token; - this.first.push(token); - - if (nexttoken.id !== "=") { - warning("const " + - "'{a}' is initialized to 'undefined'.", token, id); - } - - if (nexttoken.id === "=") { - nonadjacent(token, nexttoken); - advance("="); - nonadjacent(token, nexttoken); - if (nexttoken.id === "undefined") { - warning("It is not necessary to initialize " + - "'{a}' to 'undefined'.", token, id); - } - if (peek(0).id === "=" && nexttoken.identifier) { - error("Constant {a} was not declared correctly.", - nexttoken, nexttoken.value); - } - value = expression(0); - name.first = value; - } - - if (nexttoken.id !== ",") { - break; - } - comma(); + } else if (state.tokens.next.value === ",") { + identifiers.push({ id: null, token: state.tokens.curr }); + } else { + ident = identifier(); + if (ident) + identifiers.push({ id: ident, token: state.tokens.curr }); } - return this; - }); - conststatement.exps = true; - }; + }; + if (state.tokens.next.value === "[") { + advance("["); + nextInnerDE(); + while (state.tokens.next.value !== "]") { + advance(","); + nextInnerDE(); + } + advance("]"); + } else if (state.tokens.next.value === "{") { + advance("{"); + id = identifier(); + if (state.tokens.next.value === ":") { + advance(":"); + nextInnerDE(); + } else { + identifiers.push({ id: id, token: state.tokens.curr }); + } + while (state.tokens.next.value !== "}") { + advance(","); + id = identifier(); + if (state.tokens.next.value === ":") { + advance(":"); + nextInnerDE(); + } else { + identifiers.push({ id: id, token: state.tokens.curr }); + } + } + advance("}"); + } + return identifiers; + } + function destructuringExpressionMatch(tokens, value) { + if (value.first) { + _.zip(tokens, value.first).forEach(function (val) { + var token = val[0]; + var value = val[1]; + if (token && value) { + token.first = value; + } else if (token && token.first && !value) { + warning("W080", token.first, token.first.value); + } /* else { + XXX value is discarded: wouldn't it need a warning ? + } */ + }); + } + } + var conststatement = stmt("const", function (prefix) { + var tokens, value; + var lone; + + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "const"); + } + + this.first = []; + for (;;) { + var names = []; + nonadjacent(state.tokens.curr, state.tokens.next); + if (_.contains(["{", "["], state.tokens.next.value)) { + tokens = destructuringExpression(); + lone = false; + } else { + tokens = [ { id: identifier(), token: state.tokens.curr } ]; + lone = true; + } + for (var t in tokens) { + t = tokens[t]; + if (funct[t.id] === "const") { + warning("E011", null, t.id); + } + if (funct["(global)"] && predefined[t.id] === false) { + warning("W079", t.token, t.id); + } + if (t.id) { + addlabel(t.id, "const"); + names.push(t.token); + } + } + if (prefix) { + break; + } + + this.first = this.first.concat(names); + + if (state.tokens.next.id !== "=") { + warning("E012", state.tokens.curr, state.tokens.curr.value); + } + + if (state.tokens.next.id === "=") { + nonadjacent(state.tokens.curr, state.tokens.next); + advance("="); + nonadjacent(state.tokens.curr, state.tokens.next); + if (state.tokens.next.id === "undefined") { + warning("W080", state.tokens.prev, state.tokens.prev.value); + } + if (peek(0).id === "=" && state.tokens.next.identifier) { + error("E037", state.tokens.next, state.tokens.next.value); + } + value = expression(5); + if (lone) { + tokens[0].first = value; + } else { + destructuringExpressionMatch(names, value); + } + } + + if (state.tokens.next.id !== ",") { + break; + } + comma(); + } + return this; + }); + conststatement.exps = true; var varstatement = stmt("var", function (prefix) { - var id, name, value; + var tokens, lone, value; - if (funct["(onevar)"] && option.onevar) { - warning("Too many var statements."); + if (funct["(onevar)"] && state.option.onevar) { + warning("W081"); } else if (!funct["(global)"]) { funct["(onevar)"] = true; } this.first = []; - for (;;) { - nonadjacent(token, nexttoken); - id = identifier(); - - if (option.esnext && funct[id] === "const") { - warning("const '" + id + "' has already been declared"); + var names = []; + nonadjacent(state.tokens.curr, state.tokens.next); + if (_.contains(["{", "["], state.tokens.next.value)) { + tokens = destructuringExpression(); + lone = false; + } else { + tokens = [ { id: identifier(), token: state.tokens.curr } ]; + lone = true; } - - if (funct["(global)"] && predefined[id] === false) { - warning("Redefinition of '{a}'.", token, id); + for (var t in tokens) { + t = tokens[t]; + if (state.option.inESNext() && funct[t.id] === "const") { + warning("E011", null, t.id); + } + if (funct["(global)"] && predefined[t.id] === false) { + warning("W079", t.token, t.id); + } + if (t.id) { + addlabel(t.id, "unused", t.token); + names.push(t.token); + } } - - addlabel(id, "unused", token); - if (prefix) { break; } - name = token; - this.first.push(token); + this.first = this.first.concat(names); - if (nexttoken.id === "=") { - nonadjacent(token, nexttoken); + if (state.tokens.next.id === "=") { + nonadjacent(state.tokens.curr, state.tokens.next); advance("="); - nonadjacent(token, nexttoken); - if (nexttoken.id === "undefined") { - warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id); + nonadjacent(state.tokens.curr, state.tokens.next); + if (state.tokens.next.id === "undefined") { + warning("W080", state.tokens.prev, state.tokens.prev.value); } - if (peek(0).id === "=" && nexttoken.identifier) { - error("Variable {a} was not declared correctly.", - nexttoken, nexttoken.value); + if (peek(0).id === "=" && state.tokens.next.identifier) { + error("E038", state.tokens.next, state.tokens.next.value); + } + value = expression(5); + if (lone) { + tokens[0].first = value; + } else { + destructuringExpressionMatch(names, value); } - value = expression(0); - name.first = value; } - if (nexttoken.id !== ",") { + + if (state.tokens.next.id !== ",") { break; } comma(); @@ -5498,63 +6090,190 @@ klass: return this; }); varstatement.exps = true; + var letstatement = stmt("let", function (prefix) { + var tokens, lone, value, letblock; + + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "let"); + } + + if (state.tokens.next.value === "(") { + if (!state.option.inMoz(true)) { + warning("W118", state.tokens.next, "let block"); + } + advance("("); + funct["(blockscope)"].stack(); + letblock = true; + } else if (funct["(nolet)"]) { + error("E048", state.tokens.curr); + } + + if (funct["(onevar)"] && state.option.onevar) { + warning("W081"); + } else if (!funct["(global)"]) { + funct["(onevar)"] = true; + } + + this.first = []; + for (;;) { + var names = []; + nonadjacent(state.tokens.curr, state.tokens.next); + if (_.contains(["{", "["], state.tokens.next.value)) { + tokens = destructuringExpression(); + lone = false; + } else { + tokens = [ { id: identifier(), token: state.tokens.curr.value } ]; + lone = true; + } + for (var t in tokens) { + t = tokens[t]; + if (state.option.inESNext() && funct[t.id] === "const") { + warning("E011", null, t.id); + } + if (funct["(global)"] && predefined[t.id] === false) { + warning("W079", t.token, t.id); + } + if (t.id && !funct["(nolet)"]) { + addlabel(t.id, "unused", t.token, true); + names.push(t.token); + } + } + if (prefix) { + break; + } + + this.first = this.first.concat(names); + + if (state.tokens.next.id === "=") { + nonadjacent(state.tokens.curr, state.tokens.next); + advance("="); + nonadjacent(state.tokens.curr, state.tokens.next); + if (state.tokens.next.id === "undefined") { + warning("W080", state.tokens.prev, state.tokens.prev.value); + } + if (peek(0).id === "=" && state.tokens.next.identifier) { + error("E037", state.tokens.next, state.tokens.next.value); + } + value = expression(5); + if (lone) { + tokens[0].first = value; + } else { + destructuringExpressionMatch(names, value); + } + } + + if (state.tokens.next.id !== ",") { + break; + } + comma(); + } + if (letblock) { + advance(")"); + block(true, true); + this.block = true; + funct["(blockscope)"].unstack(); + } + + return this; + }); + letstatement.exps = true; + + blockstmt("class", function () { + return classdef.call(this, true); + }); + + function classdef(stmt) { + if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "class"); + } + if (stmt) { + this.name = identifier(); + addlabel(this.name, "unused", state.tokens.curr); + } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { + this.name = identifier(); + } + classtail(this); + return this; + } + + function classtail(c) { + var strictness = state.directive["use strict"]; + if (state.tokens.next.value === "extends") { + advance("extends"); + c.heritage = expression(10); + } + state.directive["use strict"] = true; + advance("{"); + c.body = state.syntax["{"].nud(true); + state.directive["use strict"] = strictness; + } blockstmt("function", function () { + var generator = false; + if (state.tokens.next.value === "*") { + advance("*"); + if (state.option.inESNext(true)) { + generator = true; + } else { + warning("W119", state.tokens.curr, "function*"); + } + } if (inblock) { - warning("Function declarations should not be placed in blocks. " + - "Use a function expression or move the statement to the top of " + - "the outer function.", token); + warning("W082", state.tokens.curr); } var i = identifier(); - if (option.esnext && funct[i] === "const") { - warning("const '" + i + "' has already been declared"); + if (funct[i] === "const") { + warning("E011", null, i); } - adjacent(token, nexttoken); - addlabel(i, "unction", token); + adjacent(state.tokens.curr, state.tokens.next); + addlabel(i, "unction", state.tokens.curr); - doFunction(i, { statement: true }); - if (nexttoken.id === "(" && nexttoken.line === token.line) { - error( -"Function declarations are not invocable. Wrap the whole function invocation in parens."); + doFunction(i, { statement: true }, generator); + if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { + error("E039"); } return this; }); prefix("function", function () { - var i = optionalidentifier(); - if (i) { - adjacent(token, nexttoken); - } else { - nonadjacent(token, nexttoken); + var generator = false; + if (state.tokens.next.value === "*") { + if (!state.option.inESNext()) { + warning("W119", state.tokens.curr, "function*"); + } + advance("*"); + generator = true; } - doFunction(i); - if (!option.loopfunc && funct["(loopage)"]) { - warning("Don't make functions within a loop."); + var i = optionalidentifier(); + if (i || state.option.gcl) { + adjacent(state.tokens.curr, state.tokens.next); + } else { + nonadjacent(state.tokens.curr, state.tokens.next); + } + doFunction(i, undefined, generator); + if (!state.option.loopfunc && funct["(loopage)"]) { + warning("W083"); } return this; }); blockstmt("if", function () { - var t = nexttoken; + var t = state.tokens.next; increaseComplexityCount(); + state.condition = true; advance("("); nonadjacent(this, t); nospace(); - expression(20); - if (nexttoken.id === "=") { - if (!option.boss) - warning("Assignment in conditional expression"); - advance("="); - expression(20); - } + checkCondAssignment(expression(0)); advance(")", t); - nospace(prevtoken, token); + state.condition = false; + nospace(state.tokens.prev, state.tokens.curr); block(true, true); - if (nexttoken.id === "else") { - nonadjacent(token, nexttoken); + if (state.tokens.next.id === "else") { + nonadjacent(state.tokens.curr, state.tokens.next); advance("else"); - if (nexttoken.id === "if" || nexttoken.id === "switch") { + if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { statement(true); } else { block(true, true); @@ -5571,87 +6290,96 @@ klass: var e; advance("catch"); - nonadjacent(token, nexttoken); + nonadjacent(state.tokens.curr, state.tokens.next); advance("("); scope = Object.create(oldScope); - e = nexttoken.value; - if (nexttoken.type !== "(identifier)") { + e = state.tokens.next.value; + if (state.tokens.next.type !== "(identifier)") { e = null; - warning("Expected an identifier and instead saw '{a}'.", nexttoken, e); + warning("E030", state.tokens.next, e); } advance(); - advance(")"); funct = { - "(name)" : "(catch)", - "(line)" : nexttoken.line, - "(character)": nexttoken.character, + "(name)" : "(catch)", + "(line)" : state.tokens.next.line, + "(character)": state.tokens.next.character, "(context)" : funct, "(breakage)" : funct["(breakage)"], "(loopage)" : funct["(loopage)"], - "(scope)" : scope, + "(scope)" : scope, "(statement)": false, - "(metrics)" : createMetrics(nexttoken), - "(catch)" : true, - "(tokens)" : {} + "(metrics)" : createMetrics(state.tokens.next), + "(catch)" : true, + "(tokens)" : {}, + "(blockscope)": funct["(blockscope)"], + "(comparray)": funct["(comparray)"] }; if (e) { addlabel(e, "exception"); } - token.funct = funct; + if (state.tokens.next.value === "if") { + if (!state.option.inMoz(true)) { + warning("W118", state.tokens.curr, "catch filter"); + } + advance("if"); + expression(0); + } + + advance(")"); + + state.tokens.curr.funct = funct; functions.push(funct); block(false); scope = oldScope; - funct["(last)"] = token.line; - funct["(lastcharacter)"] = token.character; + funct["(last)"] = state.tokens.curr.line; + funct["(lastcharacter)"] = state.tokens.curr.character; funct = funct["(context)"]; } block(false); - if (nexttoken.id === "catch") { + while (state.tokens.next.id === "catch") { increaseComplexityCount(); + if (b && (!state.option.inMoz(true))) { + warning("W118", state.tokens.next, "multiple catch blocks"); + } doCatch(); b = true; } - if (nexttoken.id === "finally") { + if (state.tokens.next.id === "finally") { advance("finally"); block(false); return; - } else if (!b) { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, "catch", nexttoken.value); + } + + if (!b) { + error("E021", state.tokens.next, "catch", state.tokens.next.value); } return this; }); blockstmt("while", function () { - var t = nexttoken; + var t = state.tokens.next; funct["(breakage)"] += 1; funct["(loopage)"] += 1; increaseComplexityCount(); advance("("); nonadjacent(this, t); nospace(); - expression(20); - if (nexttoken.id === "=") { - if (!option.boss) - warning("Assignment in conditional expression"); - advance("="); - expression(20); - } + checkCondAssignment(expression(0)); advance(")", t); - nospace(prevtoken, token); + nospace(state.tokens.prev, state.tokens.curr); block(true, true); funct["(breakage)"] -= 1; funct["(loopage)"] -= 1; @@ -5659,11 +6387,11 @@ klass: }).labelled = true; blockstmt("with", function () { - var t = nexttoken; - if (directive["use strict"]) { - error("'with' is not allowed in strict mode.", token); - } else if (!option.withstmt) { - warning("Don't use 'with'.", token); + var t = state.tokens.next; + if (state.directive["use strict"]) { + error("E010", state.tokens.curr); + } else if (!state.option.withstmt) { + warning("W085", state.tokens.curr); } advance("("); @@ -5671,32 +6399,34 @@ klass: nospace(); expression(0); advance(")", t); - nospace(prevtoken, token); + nospace(state.tokens.prev, state.tokens.curr); block(true, true); return this; }); blockstmt("switch", function () { - var t = nexttoken, + var t = state.tokens.next, g = false; funct["(breakage)"] += 1; advance("("); nonadjacent(this, t); nospace(); - this.condition = expression(20); + checkCondAssignment(expression(0)); advance(")", t); - nospace(prevtoken, token); - nonadjacent(token, nexttoken); - t = nexttoken; + nospace(state.tokens.prev, state.tokens.curr); + nonadjacent(state.tokens.curr, state.tokens.next); + t = state.tokens.next; advance("{"); - nonadjacent(token, nexttoken); - indent += option.indent; + nonadjacent(state.tokens.curr, state.tokens.next); + indent += state.option.indent; this.cases = []; + for (;;) { - switch (nexttoken.id) { + switch (state.tokens.next.id) { case "case": switch (funct["(verb)"]) { + case "yield": case "break": case "case": case "continue": @@ -5705,13 +6435,11 @@ klass: case "throw": break; default: - if (!ft.test(lines[nexttoken.line - 2])) { - warning( - "Expected a 'break' statement before 'case'.", - token); + if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { + warning("W086", state.tokens.curr, "case"); } } - indentation(-option.indent); + indentation(-state.option.indent); advance("case"); this.cases.push(expression(20)); increaseComplexityCount(); @@ -5721,60 +6449,55 @@ klass: break; case "default": switch (funct["(verb)"]) { + case "yield": case "break": case "continue": case "return": case "throw": break; default: - if (!ft.test(lines[nexttoken.line - 2])) { - warning( - "Expected a 'break' statement before 'default'.", - token); + if (this.cases.length) { + if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { + warning("W086", state.tokens.curr, "default"); + } } } - indentation(-option.indent); + indentation(-state.option.indent); advance("default"); g = true; advance(":"); break; case "}": - indent -= option.indent; + indent -= state.option.indent; indentation(); advance("}", t); - if (this.cases.length === 1 || this.condition.id === "true" || - this.condition.id === "false") { - if (!option.onecase) - warning("This 'switch' should be an 'if'.", this); - } funct["(breakage)"] -= 1; funct["(verb)"] = undefined; return; case "(end)": - error("Missing '{a}'.", nexttoken, "}"); + error("E023", state.tokens.next, "}"); return; default: if (g) { - switch (token.id) { + switch (state.tokens.curr.id) { case ",": - error("Each value should have its own case label."); + error("E040"); return; case ":": g = false; statements(); break; default: - error("Missing ':' on a case clause.", token); + error("E025", state.tokens.curr); return; } } else { - if (token.id === ":") { + if (state.tokens.curr.id === ":") { advance(":"); - error("Unexpected '{a}'.", token, ":"); + error("E024", state.tokens.curr, ":"); statements(); } else { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, "case", nexttoken.value); + error("E021", state.tokens.next, "case", state.tokens.next.value); return; } } @@ -5783,8 +6506,8 @@ klass: }).labelled = true; stmt("debugger", function () { - if (!option.debug) { - warning("All 'debugger' statements should be removed."); + if (!state.option.debug) { + warning("W087"); } return this; }).exps = true; @@ -5795,21 +6518,15 @@ klass: funct["(loopage)"] += 1; increaseComplexityCount(); - this.first = block(true); + this.first = block(true, true); advance("while"); - var t = nexttoken; - nonadjacent(token, t); + var t = state.tokens.next; + nonadjacent(state.tokens.curr, t); advance("("); nospace(); - expression(20); - if (nexttoken.id === "=") { - if (!option.boss) - warning("Assignment in conditional expression"); - advance("="); - expression(20); - } + checkCondAssignment(expression(0)); advance(")", t); - nospace(prevtoken, token); + nospace(state.tokens.prev, state.tokens.curr); funct["(breakage)"] -= 1; funct["(loopage)"] -= 1; return this; @@ -5819,110 +6536,140 @@ klass: }()); blockstmt("for", function () { - var s, t = nexttoken; + var s, t = state.tokens.next; + var letscope = false; + var foreachtok = null; + + if (t.value === "each") { + foreachtok = t; + advance("each"); + if (!state.option.inMoz(true)) { + warning("W118", state.tokens.curr, "for each"); + } + } + funct["(breakage)"] += 1; funct["(loopage)"] += 1; increaseComplexityCount(); advance("("); nonadjacent(this, t); nospace(); - if (peek(nexttoken.id === "var" ? 1 : 0).id === "in") { - if (nexttoken.id === "var") { + var nextop; // contains the token of the "in" or "of" operator + var i = 0; + var inof = ["in", "of"]; + do { + nextop = peek(i); + ++i; + } while (!_.contains(inof, nextop.value) && nextop.value !== ";" && + nextop.type !== "(end)"); + if (_.contains(inof, nextop.value)) { + if (!state.option.inESNext() && nextop.value === "of") { + error("W104", nextop, "for of"); + } + if (state.tokens.next.id === "var") { advance("var"); - varstatement.fud.call(varstatement, true); + state.syntax["var"].fud.call(state.syntax["var"].fud, true); + } else if (state.tokens.next.id === "let") { + advance("let"); + letscope = true; + funct["(blockscope)"].stack(); + state.syntax["let"].fud.call(state.syntax["let"].fud, true); } else { - switch (funct[nexttoken.value]) { + switch (funct[state.tokens.next.value]) { case "unused": - funct[nexttoken.value] = "var"; + funct[state.tokens.next.value] = "var"; break; case "var": break; default: - warning("Bad for in variable '{a}'.", - nexttoken, nexttoken.value); + if (!funct["(blockscope)"].getlabel(state.tokens.next.value)) + warning("W088", state.tokens.next, state.tokens.next.value); } advance(); } - advance("in"); + advance(nextop.value); expression(20); advance(")", t); s = block(true, true); - if (option.forin && s && (s.length > 1 || typeof s[0] !== "object" || + if (state.option.forin && s && (s.length > 1 || typeof s[0] !== "object" || s[0].value !== "if")) { - warning("The body of a for in should be wrapped in an if statement to filter " + - "unwanted properties from the prototype.", this); + warning("W089", this); } funct["(breakage)"] -= 1; funct["(loopage)"] -= 1; - return this; } else { - if (nexttoken.id !== ";") { - if (nexttoken.id === "var") { + if (foreachtok) { + error("E045", foreachtok); + } + if (state.tokens.next.id !== ";") { + if (state.tokens.next.id === "var") { advance("var"); - varstatement.fud.call(varstatement); + state.syntax["var"].fud.call(state.syntax["var"].fud); + } else if (state.tokens.next.id === "let") { + advance("let"); + letscope = true; + funct["(blockscope)"].stack(); + state.syntax["let"].fud.call(state.syntax["let"].fud); } else { for (;;) { expression(0, "for"); - if (nexttoken.id !== ",") { + if (state.tokens.next.id !== ",") { break; } comma(); } } } - nolinebreak(token); + nolinebreak(state.tokens.curr); advance(";"); - if (nexttoken.id !== ";") { - expression(20); - if (nexttoken.id === "=") { - if (!option.boss) - warning("Assignment in conditional expression"); - advance("="); - expression(20); - } + if (state.tokens.next.id !== ";") { + checkCondAssignment(expression(0)); } - nolinebreak(token); + nolinebreak(state.tokens.curr); advance(";"); - if (nexttoken.id === ";") { - error("Expected '{a}' and instead saw '{b}'.", - nexttoken, ")", ";"); + if (state.tokens.next.id === ";") { + error("E021", state.tokens.next, ")", ";"); } - if (nexttoken.id !== ")") { + if (state.tokens.next.id !== ")") { for (;;) { expression(0, "for"); - if (nexttoken.id !== ",") { + if (state.tokens.next.id !== ",") { break; } comma(); } } advance(")", t); - nospace(prevtoken, token); + nospace(state.tokens.prev, state.tokens.curr); block(true, true); funct["(breakage)"] -= 1; funct["(loopage)"] -= 1; - return this; + } + if (letscope) { + funct["(blockscope)"].unstack(); + } + return this; }).labelled = true; stmt("break", function () { - var v = nexttoken.value; + var v = state.tokens.next.value; if (funct["(breakage)"] === 0) - warning("Unexpected '{a}'.", nexttoken, this.value); + warning("W052", state.tokens.next, this.value); - if (!option.asi) + if (!state.option.asi) nolinebreak(this); - if (nexttoken.id !== ";") { - if (token.line === nexttoken.line) { + if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { + if (state.tokens.curr.line === state.tokens.next.line) { if (funct[v] !== "label") { - warning("'{a}' is not a statement label.", nexttoken, v); + warning("W090", state.tokens.next, v); } else if (scope[v] !== funct) { - warning("'{a}' is out of scope.", nexttoken, v); + warning("W091", state.tokens.next, v); } - this.first = nexttoken; + this.first = state.tokens.next; advance(); } } @@ -5932,26 +6679,26 @@ klass: stmt("continue", function () { - var v = nexttoken.value; + var v = state.tokens.next.value; if (funct["(breakage)"] === 0) - warning("Unexpected '{a}'.", nexttoken, this.value); + warning("W052", state.tokens.next, this.value); - if (!option.asi) + if (!state.option.asi) nolinebreak(this); - if (nexttoken.id !== ";") { - if (token.line === nexttoken.line) { + if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { + if (state.tokens.curr.line === state.tokens.next.line) { if (funct[v] !== "label") { - warning("'{a}' is not a statement label.", nexttoken, v); + warning("W090", state.tokens.next, v); } else if (scope[v] !== funct) { - warning("'{a}' is out of scope.", nexttoken, v); + warning("W091", state.tokens.next, v); } - this.first = nexttoken; + this.first = state.tokens.next; advance(); } } else if (!funct["(loopage)"]) { - warning("Unexpected '{a}'.", nexttoken, this.value); + warning("W052", state.tokens.next, this.value); } reachable("continue"); return this; @@ -5959,86 +6706,248 @@ klass: stmt("return", function () { - if (this.line === nexttoken.line) { - if (nexttoken.id === "(regexp)") - warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator."); + if (this.line === state.tokens.next.line) { + if (state.tokens.next.id === "(regexp)") + warning("W092"); - if (nexttoken.id !== ";" && !nexttoken.reach) { - nonadjacent(token, nexttoken); - if (peek().value === "=" && !option.boss) { - warningAt("Did you mean to return a conditional instead of an assignment?", - token.line, token.character + 1); - } + if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { + nonadjacent(state.tokens.curr, state.tokens.next); this.first = expression(0); + + if (this.first && + this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { + warningAt("W093", this.first.line, this.first.character); + } + } + } else { + if (state.tokens.next.type === "(punctuator)" && + ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { + nolinebreak(this); // always warn (Line breaking error) } - } else if (!option.asi) { - nolinebreak(this); // always warn (Line breaking error) } reachable("return"); return this; }).exps = true; + stmt("yield", function () { + if (state.option.inESNext(true) && funct["(generator)"] !== true) { + error("E046", state.tokens.curr, "yield"); + } else if (!state.option.inESNext()) { + warning("W104", state.tokens.curr, "yield"); + } + funct["(generator)"] = "yielded"; + if (this.line === state.tokens.next.line) { + if (state.tokens.next.id === "(regexp)") + warning("W092"); + + if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { + nonadjacent(state.tokens.curr, state.tokens.next); + this.first = expression(0); + + if (this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { + warningAt("W093", this.first.line, this.first.character); + } + } + } else if (!state.option.asi) { + nolinebreak(this); // always warn (Line breaking error) + } + return this; + }).exps = true; + stmt("throw", function () { nolinebreak(this); - nonadjacent(token, nexttoken); + nonadjacent(state.tokens.curr, state.tokens.next); this.first = expression(20); reachable("throw"); return this; }).exps = true; - reserve("class"); - reserve("const"); - reserve("enum"); - reserve("export"); - reserve("extends"); - reserve("import"); - reserve("super"); + FutureReservedWord("abstract"); + FutureReservedWord("boolean"); + FutureReservedWord("byte"); + FutureReservedWord("char"); + FutureReservedWord("class", { es5: true, nud: classdef }); + FutureReservedWord("double"); + FutureReservedWord("enum", { es5: true }); + FutureReservedWord("export", { es5: true }); + FutureReservedWord("extends", { es5: true }); + FutureReservedWord("final"); + FutureReservedWord("float"); + FutureReservedWord("goto"); + FutureReservedWord("implements", { es5: true, strictOnly: true }); + FutureReservedWord("import", { es5: true }); + FutureReservedWord("int"); + FutureReservedWord("interface", { es5: true, strictOnly: true }); + FutureReservedWord("long"); + FutureReservedWord("native"); + FutureReservedWord("package", { es5: true, strictOnly: true }); + FutureReservedWord("private", { es5: true, strictOnly: true }); + FutureReservedWord("protected", { es5: true, strictOnly: true }); + FutureReservedWord("public", { es5: true, strictOnly: true }); + FutureReservedWord("short"); + FutureReservedWord("static", { es5: true, strictOnly: true }); + FutureReservedWord("super", { es5: true }); + FutureReservedWord("synchronized"); + FutureReservedWord("throws"); + FutureReservedWord("transient"); + FutureReservedWord("volatile"); - reserve("let"); - reserve("yield"); - reserve("implements"); - reserve("interface"); - reserve("package"); - reserve("private"); - reserve("protected"); - reserve("public"); - reserve("static"); + var lookupBlockType = function () { + var pn, pn1; + var i = 0; + var bracketStack = 0; + var ret = {}; + if (_.contains(["[", "{"], state.tokens.curr.value)) + bracketStack += 1; + if (_.contains(["[", "{"], state.tokens.next.value)) + bracketStack += 1; + if (_.contains(["]", "}"], state.tokens.next.value)) + bracketStack -= 1; + do { + pn = peek(i); + pn1 = peek(i + 1); + i = i + 1; + if (_.contains(["[", "{"], pn.value)) { + bracketStack += 1; + } else if (_.contains(["]", "}"], pn.value)) { + bracketStack -= 1; + } + if (pn.identifier && pn.value === "for" && bracketStack === 1) { + ret.isCompArray = true; + ret.notJson = true; + break; + } + if (_.contains(["}", "]"], pn.value) && pn1.value === "=") { + ret.isDestAssign = true; + ret.notJson = true; + break; + } + if (pn.value === ";") { + ret.isBlock = true; + ret.notJson = true; + } + } while (bracketStack > 0 && pn.id !== "(end)" && i < 15); + return ret; + }; + function destructuringAssignOrJsonValue() { + + var block = lookupBlockType(); + if (block.notJson) { + if (!state.option.inESNext() && block.isDestAssign) { + warning("W104", state.tokens.curr, "destructuring assignment"); + } + statements(); + } else { + state.option.laxbreak = true; + state.jsonMode = true; + jsonValue(); + } + } + + var arrayComprehension = function () { + var CompArray = function () { + this.mode = "use"; + this.variables = []; + }; + var _carrays = []; + var _current; + function declare(v) { + var l = _current.variables.filter(function (elt) { + if (elt.value === v) { + elt.undef = false; + return v; + } + }).length; + return l !== 0; + } + function use(v) { + var l = _current.variables.filter(function (elt) { + if (elt.value === v && !elt.undef) { + if (elt.unused === true) { + elt.unused = false; + } + return v; + } + }).length; + return (l === 0); + } + return {stack: function () { + _current = new CompArray(); + _carrays.push(_current); + }, + unstack: function () { + _current.variables.filter(function (v) { + if (v.unused) + warning("W098", v.token, v.value); + if (v.undef) + isundef(v.funct, "W117", v.token, v.value); + }); + _carrays.splice(_carrays[_carrays.length - 1], 1); + _current = _carrays[_carrays.length - 1]; + }, + setState: function (s) { + if (_.contains(["use", "define", "filter"], s)) + _current.mode = s; + }, + check: function (v) { + if (_current && _current.mode === "use") { + _current.variables.push({funct: funct, + token: state.tokens.curr, + value: v, + undef: true, + unused: false}); + return true; + } else if (_current && _current.mode === "define") { + if (!declare(v)) { + _current.variables.push({funct: funct, + token: state.tokens.curr, + value: v, + undef: false, + unused: true}); + } + return true; + } else if (_current && _current.mode === "filter") { + if (use(v)) { + isundef(funct, "W117", state.tokens.curr, v); + } + return true; + } + return false; + } + }; + }; function jsonValue() { function jsonObject() { - var o = {}, t = nexttoken; + var o = {}, t = state.tokens.next; advance("{"); - if (nexttoken.id !== "}") { + if (state.tokens.next.id !== "}") { for (;;) { - if (nexttoken.id === "(end)") { - error("Missing '}' to match '{' from line {a}.", - nexttoken, t.line); - } else if (nexttoken.id === "}") { - warning("Unexpected comma.", token); + if (state.tokens.next.id === "(end)") { + error("E026", state.tokens.next, t.line); + } else if (state.tokens.next.id === "}") { + warning("W094", state.tokens.curr); break; - } else if (nexttoken.id === ",") { - error("Unexpected comma.", nexttoken); - } else if (nexttoken.id !== "(string)") { - warning("Expected a string and instead saw {a}.", - nexttoken, nexttoken.value); + } else if (state.tokens.next.id === ",") { + error("E028", state.tokens.next); + } else if (state.tokens.next.id !== "(string)") { + warning("W095", state.tokens.next, state.tokens.next.value); } - if (o[nexttoken.value] === true) { - warning("Duplicate key '{a}'.", - nexttoken, nexttoken.value); - } else if ((nexttoken.value === "__proto__" && - !option.proto) || (nexttoken.value === "__iterator__" && - !option.iterator)) { - warning("The '{a}' key may produce unexpected results.", - nexttoken, nexttoken.value); + if (o[state.tokens.next.value] === true) { + warning("W075", state.tokens.next, state.tokens.next.value); + } else if ((state.tokens.next.value === "__proto__" && + !state.option.proto) || (state.tokens.next.value === "__iterator__" && + !state.option.iterator)) { + warning("W096", state.tokens.next, state.tokens.next.value); } else { - o[nexttoken.value] = true; + o[state.tokens.next.value] = true; } advance(); advance(":"); jsonValue(); - if (nexttoken.id !== ",") { + if (state.tokens.next.id !== ",") { break; } advance(","); @@ -6048,21 +6957,20 @@ klass: } function jsonArray() { - var t = nexttoken; + var t = state.tokens.next; advance("["); - if (nexttoken.id !== "]") { + if (state.tokens.next.id !== "]") { for (;;) { - if (nexttoken.id === "(end)") { - error("Missing ']' to match '[' from line {a}.", - nexttoken, t.line); - } else if (nexttoken.id === "]") { - warning("Unexpected comma.", token); + if (state.tokens.next.id === "(end)") { + error("E027", state.tokens.next, t.line); + } else if (state.tokens.next.id === "]") { + warning("W094", state.tokens.curr); break; - } else if (nexttoken.id === ",") { - error("Unexpected comma.", nexttoken); + } else if (state.tokens.next.id === ",") { + error("E028", state.tokens.next); } jsonValue(); - if (nexttoken.id !== ",") { + if (state.tokens.next.id !== ",") { break; } advance(","); @@ -6071,7 +6979,7 @@ klass: advance("]"); } - switch (nexttoken.id) { + switch (state.tokens.next.id) { case "{": jsonObject(); break; @@ -6087,20 +6995,72 @@ klass: break; case "-": advance("-"); - if (token.character !== nexttoken.from) { - warning("Unexpected space after '-'.", token); + if (state.tokens.curr.character !== state.tokens.next.from) { + warning("W011", state.tokens.curr); } - adjacent(token, nexttoken); + adjacent(state.tokens.curr, state.tokens.next); advance("(number)"); break; default: - error("Expected a JSON value.", nexttoken); + error("E003", state.tokens.next); } } + + var blockScope = function () { + var _current = {}; + var _variables = [_current]; + + function _checkBlockLabels() { + for (var t in _current) { + if (_current[t]["(type)"] === "unused") { + if (state.option.unused) { + var tkn = _current[t]["(token)"]; + var line = tkn.line; + var chr = tkn.character; + warningAt("W098", line, chr, t); + } + } + } + } + + return { + stack: function () { + _current = {}; + _variables.push(_current); + }, + + unstack: function () { + _checkBlockLabels(); + _variables.splice(_variables.length - 1, 1); + _current = _.last(_variables); + }, + + getlabel: function (l) { + for (var i = _variables.length - 1 ; i >= 0; --i) { + if (_.has(_variables[i], l)) { + return _variables[i]; + } + } + }, + + current: { + has: function (t) { + return _.has(_current, t); + }, + add: function (t, type, tok) { + _current[t] = { "(type)" : type, + "(token)": tok }; + } + } + }; + }; var itself = function (s, o, g) { - var a, i, k, x; + var i, k, x; var optionKeys; var newOptionObj = {}; + var newIgnoredObj = {}; + + state.reset(); if (o && o.scope) { JSHINT.scope = o.scope; @@ -6112,48 +7072,67 @@ klass: JSHINT.scope = "(main)"; } - predefined = Object.create(standard); - declared = Object.create(null); + predefined = Object.create(null); + combine(predefined, vars.ecmaIdentifiers); + combine(predefined, vars.reservedVars); + combine(predefined, g || {}); + declared = Object.create(null); + exported = Object.create(null); + + function each(obj, cb) { + if (!obj) + return; + + if (!Array.isArray(obj) && typeof obj === "object") + obj = Object.keys(obj); + + obj.forEach(cb); + } + if (o) { - a = o.predef; - if (a) { - if (!Array.isArray(a) && typeof a === "object") { - a = Object.keys(a); + each(o.predef || null, function (item) { + var slice, prop; + + if (item[0] === "-") { + slice = item.slice(1); + JSHINT.blacklist[slice] = slice; + } else { + prop = Object.getOwnPropertyDescriptor(o.predef, item); + predefined[item] = prop ? prop.value : false; } - a.forEach(function (item) { - var slice; - if (item[0] === "-") { - slice = item.slice(1); - JSHINT.blacklist[slice] = slice; - } else { - predefined[item] = true; - } - }); - } + }); + + each(o.exported || null, function (item) { + exported[item] = true; + }); + + delete o.predef; + delete o.exported; optionKeys = Object.keys(o); for (x = 0; x < optionKeys.length; x++) { - newOptionObj[optionKeys[x]] = o[optionKeys[x]]; + if (/^-W\d{3}$/g.test(optionKeys[x])) { + newIgnoredObj[optionKeys[x].slice(1)] = true; + } else { + newOptionObj[optionKeys[x]] = o[optionKeys[x]]; - if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false) - newOptionObj["(explicitNewcap)"] = true; + if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false) + newOptionObj["(explicitNewcap)"] = true; - if (optionKeys[x] === "indent") - newOptionObj.white = true; + if (optionKeys[x] === "indent") + newOptionObj["(explicitIndent)"] = o[optionKeys[x]] === false ? false : true; + } } } - option = newOptionObj; + state.option = newOptionObj; + state.ignored = newIgnoredObj; - option.indent = option.indent || 4; - option.maxerr = option.maxerr || 50; + state.option.indent = state.option.indent || 4; + state.option.maxerr = state.option.maxerr || 50; - tab = ""; - for (i = 0; i < option.indent; i += 1) { - tab += " "; - } indent = 1; global = Object.create(predefined); scope = global; @@ -6164,7 +7143,9 @@ klass: "(breakage)": 0, "(loopage)": 0, "(tokens)": {}, - "(metrics)": createMetrics(nexttoken) + "(metrics)": createMetrics(state.tokens.next), + "(blockscope)": blockScope(), + "(comparray)": arrayComprehension() }; functions = [funct]; urls = []; @@ -6174,61 +7155,106 @@ klass: implied = {}; inblock = false; lookahead = []; - jsonmode = false; warnings = 0; - lines = []; unuseds = []; if (!isString(s) && !Array.isArray(s)) { - errorAt("Input is neither a string nor an array of strings.", 0); + errorAt("E004", 0); return false; } - if (isString(s) && /^\s*$/g.test(s)) { - errorAt("Input is an empty string.", 0); - return false; - } + api = { + get isJSON() { + return state.jsonMode; + }, - if (s.length === 0) { - errorAt("Input is an empty array.", 0); - return false; - } + getOption: function (name) { + return state.option[name] || null; + }, - lex.init(s); + getCache: function (name) { + return state.cache[name]; + }, - prereg = true; - directive = {}; + setCache: function (name, value) { + state.cache[name] = value; + }, - prevtoken = token = nexttoken = syntax["(begin)"]; + warn: function (code, data) { + warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); + }, + + on: function (names, listener) { + names.split(" ").forEach(function (name) { + emitter.on(name, listener); + }.bind(this)); + } + }; + + emitter.removeAllListeners(); + (extraModules || []).forEach(function (func) { + func(api); + }); + + state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; + + lex = new Lexer(s); + + lex.on("warning", function (ev) { + warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); + }); + + lex.on("error", function (ev) { + errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); + }); + + lex.on("fatal", function (ev) { + quit("E041", ev.line, ev.from); + }); + + lex.on("Identifier", function (ev) { + emitter.emit("Identifier", ev); + }); + + lex.on("String", function (ev) { + emitter.emit("String", ev); + }); + + lex.on("Number", function (ev) { + emitter.emit("Number", ev); + }); + + lex.start(); for (var name in o) { - if (is_own(o, name)) { - checkOption(name, token); + if (_.has(o, name)) { + checkOption(name, state.tokens.curr); } } assume(); combine(predefined, g || {}); comma.first = true; - quotmark = undefined; try { advance(); - switch (nexttoken.id) { + switch (state.tokens.next.id) { case "{": case "[": - option.laxbreak = true; - jsonmode = true; - jsonValue(); + destructuringAssignOrJsonValue(); break; default: directives(); - if (directive["use strict"] && !option.globalstrict) { - warning("Use the function form of \"use strict\".", prevtoken); + + if (state.directive["use strict"]) { + if (!state.option.globalstrict && !state.option.node) { + warning("W097", state.tokens.prev); + } } statements(); } - advance((nexttoken && nexttoken.value !== ".") ? "(end)" : undefined); + advance((state.tokens.next && state.tokens.next.value !== ".") ? "(end)" : undefined); + funct["(blockscope)"].unstack(); var markDefined = function (name, context) { do { @@ -6264,12 +7290,29 @@ klass: implied[name] = newImplied; }; - var warnUnused = function (name, token) { - var line = token.line; - var chr = token.character; + var warnUnused = function (name, tkn, type, unused_opt) { + var line = tkn.line; + var chr = tkn.character; - if (option.unused) - warningAt("'{a}' is defined but never used.", line, chr, name); + if (unused_opt === undefined) { + unused_opt = state.option.unused; + } + + if (unused_opt === true) { + unused_opt = "last-param"; + } + + var warnable_types = { + "vars": ["var"], + "last-param": ["var", "param"], + "strict": ["var", "param", "last-param"] + }; + + if (unused_opt) { + if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { + warningAt("W098", line, chr, name); + } + } unuseds.push({ name: name, @@ -6280,7 +7323,7 @@ klass: var checkUnused = function (func, key) { var type = func[key]; - var token = func["(tokens)"][key]; + var tkn = func["(tokens)"][key]; if (key.charAt(0) === "(") return; @@ -6289,22 +7332,29 @@ klass: return; if (func["(params)"] && func["(params)"].indexOf(key) !== -1) return; + if (func["(global)"] && _.has(exported, key)) { + return; + } - warnUnused(key, token); + warnUnused(key, tkn, "var"); }; for (i = 0; i < JSHINT.undefs.length; i += 1) { k = JSHINT.undefs[i].slice(0); if (markDefined(k[2].value, k[0])) { clearImplied(k[2].value, k[2].line); - } else { + } else if (state.option.undef) { warning.apply(warning, k.slice(1)); } } functions.forEach(function (func) { + if (func["(unusedOption)"] === false) { + return; + } + for (var key in func) { - if (is_own(func, key)) { + if (_.has(func, key)) { checkUnused(func, key); } } @@ -6314,36 +7364,44 @@ klass: var params = func["(params)"].slice(); var param = params.pop(); - var type; + var type, unused_opt; while (param) { type = func[param]; + unused_opt = func["(unusedOption)"] || state.option.unused; + unused_opt = unused_opt === true ? "last-param" : unused_opt; if (param === "undefined") return; - if (type !== "unused" && type !== "unction") + if (type === "unused" || type === "unction") { + warnUnused(param, func["(tokens)"][param], "param", func["(unusedOption)"]); + } else if (unused_opt === "last-param") { return; + } - warnUnused(param, func["(tokens)"][param]); param = params.pop(); } }); for (var key in declared) { - if (is_own(declared, key) && !is_own(global, key)) { - warnUnused(key, declared[key]); + if (_.has(declared, key) && !_.has(global, key)) { + warnUnused(key, declared[key], "var"); } } - } catch (e) { - if (e) { - var nt = nexttoken || {}; + + } catch (err) { + if (err && err.name === "JSHintError") { + var nt = state.tokens.next || {}; JSHINT.errors.push({ - raw : e.raw, - reason : e.message, - line : e.line || nt.line, - character : e.character || nt.from + scope : "(main)", + raw : err.raw, + reason : err.message, + line : err.line || nt.line, + character : err.character || nt.from }, null); + } else { + throw err; } } @@ -6359,10 +7417,15 @@ klass: return JSHINT.errors.length === 0; }; + itself.addModule = function (func) { + extraModules.push(func); + }; + + itself.addModule(style.register); itself.data = function () { var data = { functions: [], - options: option + options: state.option }; var implieds = []; var members = []; @@ -6372,12 +7435,12 @@ klass: data.errors = itself.errors; } - if (jsonmode) { + if (state.jsonMode) { data.json = true; } for (n in implied) { - if (is_own(implied, n)) { + if (_.has(implied, n)) { implieds.push({ name: n, line: implied[n] @@ -6444,4 +7507,2474 @@ if (typeof exports === "object" && exports) { exports.JSHINT = JSHINT; } +})() +}, +{"events":2,"../shared/vars.js":3,"../shared/messages.js":10,"./lex.js":11,"./reg.js":4,"./state.js":5,"./style.js":6,"console-browserify":7,"underscore":12}], +10:[function(req,module,exports){ +(function(){ + +var _ = req("underscore"); + +var errors = { + E001: "Bad option: '{a}'.", + E002: "Bad option value.", + E003: "Expected a JSON value.", + E004: "Input is neither a string nor an array of strings.", + E005: "Input is empty.", + E006: "Unexpected early end of program.", + E007: "Missing \"use strict\" statement.", + E008: "Strict violation.", + E009: "Option 'validthis' can't be used in a global scope.", + E010: "'with' is not allowed in strict mode.", + E011: "const '{a}' has already been declared.", + E012: "const '{a}' is initialized to 'undefined'.", + E013: "Attempting to override '{a}' which is a constant.", + E014: "A regular expression literal can be confused with '/='.", + E015: "Unclosed regular expression.", + E016: "Invalid regular expression.", + E017: "Unclosed comment.", + E018: "Unbegun comment.", + E019: "Unmatched '{a}'.", + E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", + E021: "Expected '{a}' and instead saw '{b}'.", + E022: "Line breaking error '{a}'.", + E023: "Missing '{a}'.", + E024: "Unexpected '{a}'.", + E025: "Missing ':' on a case clause.", + E026: "Missing '}' to match '{' from line {a}.", + E027: "Missing ']' to match '[' form line {a}.", + E028: "Illegal comma.", + E029: "Unclosed string.", + E030: "Expected an identifier and instead saw '{a}'.", + E031: "Bad assignment.", // FIXME: Rephrase + E032: "Expected a small integer or 'false' and instead saw '{a}'.", + E033: "Expected an operator and instead saw '{a}'.", + E034: "get/set are ES5 features.", + E035: "Missing property name.", + E036: "Expected to see a statement and instead saw a block.", + E037: "Constant {a} was not declared correctly.", + E038: "Variable {a} was not declared correctly.", + E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", + E040: "Each value should have its own case label.", + E041: "Unrecoverable syntax error.", + E042: "Stopping.", + E043: "Too many errors.", + E044: "'{a}' is already defined and can't be redefined.", + E045: "Invalid for each loop.", + E046: "A yield statement shall be within a generator function (with syntax: `function*`)", + E047: "A generator function shall contain a yield statement.", + E048: "Let declaration not directly within block.", + E049: "A {a} cannot be named '{b}'." +}; + +var warnings = { + W001: "'hasOwnProperty' is a really bad name.", + W002: "Value of '{a}' may be overwritten in IE 8 and earlier.", + W003: "'{a}' was used before it was defined.", + W004: "'{a}' is already defined.", + W005: "A dot following a number can be confused with a decimal point.", + W006: "Confusing minuses.", + W007: "Confusing pluses.", + W008: "A leading decimal point can be confused with a dot: '{a}'.", + W009: "The array literal notation [] is preferrable.", + W010: "The object literal notation {} is preferrable.", + W011: "Unexpected space after '{a}'.", + W012: "Unexpected space before '{a}'.", + W013: "Missing space after '{a}'.", + W014: "Bad line breaking before '{a}'.", + W015: "Expected '{a}' to have an indentation at {b} instead at {c}.", + W016: "Unexpected use of '{a}'.", + W017: "Bad operand.", + W018: "Confusing use of '{a}'.", + W019: "Use the isNaN function to compare with NaN.", + W020: "Read only.", + W021: "'{a}' is a function.", + W022: "Do not assign to the exception parameter.", + W023: "Expected an identifier in an assignment and instead saw a function invocation.", + W024: "Expected an identifier and instead saw '{a}' (a reserved word).", + W025: "Missing name in function declaration.", + W026: "Inner functions should be listed at the top of the outer function.", + W027: "Unreachable '{a}' after '{b}'.", + W028: "Label '{a}' on {b} statement.", + W030: "Expected an assignment or function call and instead saw an expression.", + W031: "Do not use 'new' for side effects.", + W032: "Unnecessary semicolon.", + W033: "Missing semicolon.", + W034: "Unnecessary directive \"{a}\".", + W035: "Empty block.", + W036: "Unexpected /*member '{a}'.", + W037: "'{a}' is a statement label.", + W038: "'{a}' used out of scope.", + W039: "'{a}' is not allowed.", + W040: "Possible strict violation.", + W041: "Use '{a}' to compare with '{b}'.", + W042: "Avoid EOL escaping.", + W043: "Bad escaping of EOL. Use option multistr if needed.", + W044: "Bad or unnecessary escaping.", + W045: "Bad number '{a}'.", + W046: "Don't use extra leading zeros '{a}'.", + W047: "A trailing decimal point can be confused with a dot: '{a}'.", + W048: "Unexpected control character in regular expression.", + W049: "Unexpected escaped character '{a}' in regular expression.", + W050: "JavaScript URL.", + W051: "Variables should not be deleted.", + W052: "Unexpected '{a}'.", + W053: "Do not use {a} as a constructor.", + W054: "The Function constructor is a form of eval.", + W055: "A constructor name should start with an uppercase letter.", + W056: "Bad constructor.", + W057: "Weird construction. Is 'new' unnecessary?", + W058: "Missing '()' invoking a constructor.", + W059: "Avoid arguments.{a}.", + W060: "document.write can be a form of eval.", + W061: "eval can be harmful.", + W062: "Wrap an immediate function invocation in parens " + + "to assist the reader in understanding that the expression " + + "is the result of a function, and not the function itself.", + W063: "Math is not a function.", + W064: "Missing 'new' prefix when invoking a constructor.", + W065: "Missing radix parameter.", + W066: "Implied eval. Consider passing a function instead of a string.", + W067: "Bad invocation.", + W068: "Wrapping non-IIFE function literals in parens is unnecessary.", + W069: "['{a}'] is better written in dot notation.", + W070: "Extra comma. (it breaks older versions of IE)", + W071: "This function has too many statements. ({a})", + W072: "This function has too many parameters. ({a})", + W073: "Blocks are nested too deeply. ({a})", + W074: "This function's cyclomatic complexity is too high. ({a})", + W075: "Duplicate key '{a}'.", + W076: "Unexpected parameter '{a}' in get {b} function.", + W077: "Expected a single parameter in set {a} function.", + W078: "Setter is defined without getter.", + W079: "Redefinition of '{a}'.", + W080: "It's not necessary to initialize '{a}' to 'undefined'.", + W081: "Too many var statements.", + W082: "Function declarations should not be placed in blocks. " + + "Use a function expression or move the statement to the top of " + + "the outer function.", + W083: "Don't make functions within a loop.", + W084: "Assignment in conditional expression", + W085: "Don't use 'with'.", + W086: "Expected a 'break' statement before '{a}'.", + W087: "Forgotten 'debugger' statement?", + W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", + W089: "The body of a for in should be wrapped in an if statement to filter " + + "unwanted properties from the prototype.", + W090: "'{a}' is not a statement label.", + W091: "'{a}' is out of scope.", + W092: "Wrap the /regexp/ literal in parens to disambiguate the slash operator.", + W093: "Did you mean to return a conditional instead of an assignment?", + W094: "Unexpected comma.", + W095: "Expected a string and instead saw {a}.", + W096: "The '{a}' key may produce unexpected results.", + W097: "Use the function form of \"use strict\".", + W098: "'{a}' is defined but never used.", + W099: "Mixed spaces and tabs.", + W100: "This character may get silently deleted by one or more browsers.", + W101: "Line is too long.", + W102: "Trailing whitespace.", + W103: "The '{a}' property is deprecated.", + W104: "'{a}' is only available in JavaScript 1.7.", + W105: "Unexpected {a} in '{b}'.", + W106: "Identifier '{a}' is not in camel case.", + W107: "Script URL.", + W108: "Strings must use doublequote.", + W109: "Strings must use singlequote.", + W110: "Mixed double and single quotes.", + W112: "Unclosed string.", + W113: "Control character in string: {a}.", + W114: "Avoid {a}.", + W115: "Octal literals are not allowed in strict mode.", + W116: "Expected '{a}' and instead saw '{b}'.", + W117: "'{a}' is not defined.", + W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", + W119: "'{a}' is only available in ES6 (use esnext option)." +}; + +var info = { + I001: "Comma warnings can be turned off with 'laxcomma'.", + I002: "Reserved words as properties can be used under the 'es5' option.", + I003: "ES5 option is now set per default" +}; + +exports.errors = {}; +exports.warnings = {}; +exports.info = {}; + +_.each(errors, function (desc, code) { + exports.errors[code] = { code: code, desc: desc }; +}); + +_.each(warnings, function (desc, code) { + exports.warnings[code] = { code: code, desc: desc }; +}); + +_.each(info, function (desc, code) { + exports.info[code] = { code: code, desc: desc }; +}); + +})() +}, +{"underscore":12}], +11:[function(req,module,exports){ +(function(){/* + * Lexical analysis and token construction. + */ + + + +var _ = req("underscore"); +var events = req("events"); +var reg = req("./reg.js"); +var state = req("./state.js").state; + +var Token = { + Identifier: 1, + Punctuator: 2, + NumericLiteral: 3, + StringLiteral: 4, + Comment: 5, + Keyword: 6, + NullLiteral: 7, + BooleanLiteral: 8, + RegExp: 9 +}; + +var unicodeLetterTable = [ + 170, 170, 181, 181, 186, 186, 192, 214, + 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, + 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, + 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, + 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, + 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, + 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, + 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, + 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2308, 2361, + 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, + 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, + 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, + 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, + 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, + 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, + 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, + 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, + 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, + 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, + 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, + 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, + 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, + 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, + 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, + 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, + 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, + 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, + 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, + 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, + 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, + 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, + 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, + 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4304, 4346, + 4348, 4348, 4352, 4680, 4682, 4685, 4688, 4694, 4696, 4696, + 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, + 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, + 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, + 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, + 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, + 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, + 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, + 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, + 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7104, 7141, + 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, + 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, + 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, + 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, + 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, + 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, + 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, + 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, + 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, + 11360, 11492, 11499, 11502, 11520, 11557, 11568, 11621, + 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, + 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, + 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, + 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, + 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, + 12593, 12686, 12704, 12730, 12784, 12799, 13312, 13312, + 19893, 19893, 19968, 19968, 40907, 40907, 40960, 42124, + 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, + 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, + 42786, 42888, 42891, 42894, 42896, 42897, 42912, 42921, + 43002, 43009, 43011, 43013, 43015, 43018, 43020, 43042, + 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, + 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, + 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, + 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, + 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, + 43739, 43741, 43777, 43782, 43785, 43790, 43793, 43798, + 43808, 43814, 43816, 43822, 43968, 44002, 44032, 44032, + 55203, 55203, 55216, 55238, 55243, 55291, 63744, 64045, + 64048, 64109, 64112, 64217, 64256, 64262, 64275, 64279, + 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, + 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, + 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, + 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, + 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, + 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, + 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, + 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66334, + 66352, 66378, 66432, 66461, 66464, 66499, 66504, 66511, + 66513, 66517, 66560, 66717, 67584, 67589, 67592, 67592, + 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, + 67840, 67861, 67872, 67897, 68096, 68096, 68112, 68115, + 68117, 68119, 68121, 68147, 68192, 68220, 68352, 68405, + 68416, 68437, 68448, 68466, 68608, 68680, 69635, 69687, + 69763, 69807, 73728, 74606, 74752, 74850, 77824, 78894, + 92160, 92728, 110592, 110593, 119808, 119892, 119894, 119964, + 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, + 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, + 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, + 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, + 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, + 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, + 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, + 131072, 131072, 173782, 173782, 173824, 173824, 177972, 177972, + 177984, 177984, 178205, 178205, 194560, 195101 +]; + +var identifierStartTable = []; + +for (var i = 0; i < 128; i++) { + identifierStartTable[i] = + i === 36 || // $ + i >= 65 && i <= 90 || // A-Z + i === 95 || // _ + i >= 97 && i <= 122; // a-z +} + +var identifierPartTable = []; + +for (var i = 0; i < 128; i++) { + identifierPartTable[i] = + identifierStartTable[i] || // $, _, A-Z, a-z + i >= 48 && i <= 57; // 0-9 +} + +function asyncTrigger() { + var _checks = []; + + return { + push: function (fn) { + _checks.push(fn); + }, + + check: function () { + for (var check = 0; check < _checks.length; ++check) { + _checks[check](); + } + + _checks.splice(0, _checks.length); + } + }; +} +function Lexer(source) { + var lines = source; + + if (typeof lines === "string") { + lines = lines + .replace(/\r\n/g, "\n") + .replace(/\r/g, "\n") + .split("\n"); + } + + if (lines[0] && lines[0].substr(0, 2) === "#!") { + lines[0] = ""; + } + + this.emitter = new events.EventEmitter(); + this.source = source; + this.setLines(lines); + this.prereg = true; + + this.line = 0; + this.char = 1; + this.from = 1; + this.input = ""; + + for (var i = 0; i < state.option.indent; i += 1) { + state.tab += " "; + } +} + +Lexer.prototype = { + _lines: [], + + getLines: function () { + this._lines = state.lines; + return this._lines; + }, + + setLines: function (val) { + this._lines = val; + state.lines = this._lines; + }, + peek: function (i) { + return this.input.charAt(i || 0); + }, + skip: function (i) { + i = i || 1; + this.char += i; + this.input = this.input.slice(i); + }, + on: function (names, listener) { + names.split(" ").forEach(function (name) { + this.emitter.on(name, listener); + }.bind(this)); + }, + trigger: function () { + this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); + }, + triggerAsync: function (type, args, checks, fn) { + checks.push(function () { + if (fn()) { + this.trigger(type, args); + } + }.bind(this)); + }, + scanPunctuator: function () { + var ch1 = this.peek(); + var ch2, ch3, ch4; + + switch (ch1) { + case ".": + if ((/^[0-9]$/).test(this.peek(1))) { + return null; + } + if (this.peek(1) === "." && this.peek(2) === ".") { + return { + type: Token.Punctuator, + value: "..." + }; + } + case "(": + case ")": + case ";": + case ",": + case "{": + case "}": + case "[": + case "]": + case ":": + case "~": + case "?": + return { + type: Token.Punctuator, + value: ch1 + }; + case "#": + return { + type: Token.Punctuator, + value: ch1 + }; + case "": + return null; + } + + ch2 = this.peek(1); + ch3 = this.peek(2); + ch4 = this.peek(3); + + if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { + return { + type: Token.Punctuator, + value: ">>>=" + }; + } + + if (ch1 === "=" && ch2 === "=" && ch3 === "=") { + return { + type: Token.Punctuator, + value: "===" + }; + } + + if (ch1 === "!" && ch2 === "=" && ch3 === "=") { + return { + type: Token.Punctuator, + value: "!==" + }; + } + + if (ch1 === ">" && ch2 === ">" && ch3 === ">") { + return { + type: Token.Punctuator, + value: ">>>" + }; + } + + if (ch1 === "<" && ch2 === "<" && ch3 === "=") { + return { + type: Token.Punctuator, + value: "<<=" + }; + } + + if (ch1 === ">" && ch2 === ">" && ch3 === "=") { + return { + type: Token.Punctuator, + value: ">>=" + }; + } + if (ch1 === "=" && ch2 === ">") { + return { + type: Token.Punctuator, + value: ch1 + ch2 + }; + } + if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) { + return { + type: Token.Punctuator, + value: ch1 + ch2 + }; + } + + if ("<>=!+-*%&|^".indexOf(ch1) >= 0) { + if (ch2 === "=") { + return { + type: Token.Punctuator, + value: ch1 + ch2 + }; + } + + return { + type: Token.Punctuator, + value: ch1 + }; + } + + if (ch1 === "/") { + if (ch2 === "=" && /\/=(?!(\S*\/[gim]?))/.test(this.input)) { + return { + type: Token.Punctuator, + value: "/=" + }; + } + + return { + type: Token.Punctuator, + value: "/" + }; + } + + return null; + }, + scanComments: function () { + var ch1 = this.peek(); + var ch2 = this.peek(1); + var rest = this.input.substr(2); + var startLine = this.line; + var startChar = this.char; + + function commentToken(label, body, opt) { + var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"]; + var isSpecial = false; + var value = label + body; + var commentType = "plain"; + opt = opt || {}; + + if (opt.isMultiline) { + value += "*/"; + } + + special.forEach(function (str) { + if (isSpecial) { + return; + } + if (label === "//" && str !== "jshint") { + return; + } + + if (body.substr(0, str.length) === str) { + isSpecial = true; + label = label + str; + body = body.substr(str.length); + } + + if (!isSpecial && body.charAt(0) === " " && body.substr(1, str.length) === str) { + isSpecial = true; + label = label + " " + str; + body = body.substr(str.length + 1); + } + + if (!isSpecial) { + return; + } + + switch (str) { + case "member": + commentType = "members"; + break; + case "global": + commentType = "globals"; + break; + default: + commentType = str; + } + }); + + return { + type: Token.Comment, + commentType: commentType, + value: value, + body: body, + isSpecial: isSpecial, + isMultiline: opt.isMultiline || false, + isMalformed: opt.isMalformed || false + }; + } + if (ch1 === "*" && ch2 === "/") { + this.trigger("error", { + code: "E018", + line: startLine, + character: startChar + }); + + this.skip(2); + return null; + } + if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { + return null; + } + if (ch2 === "/") { + this.skip(this.input.length); // Skip to the EOL. + return commentToken("//", rest); + } + + var body = ""; + if (ch2 === "*") { + this.skip(2); + + while (this.peek() !== "*" || this.peek(1) !== "/") { + if (this.peek() === "") { // End of Line + body += "\n"; + if (!this.nextLine()) { + this.trigger("error", { + code: "E017", + line: startLine, + character: startChar + }); + + return commentToken("/*", body, { + isMultiline: true, + isMalformed: true + }); + } + } else { + body += this.peek(); + this.skip(); + } + } + + this.skip(2); + return commentToken("/*", body, { isMultiline: true }); + } + }, + scanKeyword: function () { + var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); + var keywords = [ + "if", "in", "do", "var", "for", "new", + "try", "let", "this", "else", "case", + "void", "with", "enum", "while", "break", + "catch", "throw", "const", "yield", "class", + "super", "return", "typeof", "delete", + "switch", "export", "import", "default", + "finally", "extends", "function", "continue", + "debugger", "instanceof" + ]; + + if (result && keywords.indexOf(result[0]) >= 0) { + return { + type: Token.Keyword, + value: result[0] + }; + } + + return null; + }, + scanIdentifier: function () { + var id = ""; + var index = 0; + var type, char; + + function isUnicodeLetter(code) { + for (var i = 0; i < unicodeLetterTable.length;) { + if (code < unicodeLetterTable[i++]) { + return false; + } + + if (code <= unicodeLetterTable[i++]) { + return true; + } + } + + return false; + } + + function isHexDigit(str) { + return (/^[0-9a-fA-F]$/).test(str); + } + + var readUnicodeEscapeSequence = function () { + index += 1; + + if (this.peek(index) !== "u") { + return null; + } + + var ch1 = this.peek(index + 1); + var ch2 = this.peek(index + 2); + var ch3 = this.peek(index + 3); + var ch4 = this.peek(index + 4); + var code; + + if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) { + code = parseInt(ch1 + ch2 + ch3 + ch4, 16); + + if (isUnicodeLetter(code)) { + index += 5; + return "\\u" + ch1 + ch2 + ch3 + ch4; + } + + return null; + } + + return null; + }.bind(this); + + var getIdentifierStart = function () { + var chr = this.peek(index); + var code = chr.charCodeAt(0); + + if (code === 92) { + return readUnicodeEscapeSequence(); + } + + if (code < 128) { + if (identifierStartTable[code]) { + index += 1; + return chr; + } + + return null; + } + + if (isUnicodeLetter(code)) { + index += 1; + return chr; + } + + return null; + }.bind(this); + + var getIdentifierPart = function () { + var chr = this.peek(index); + var code = chr.charCodeAt(0); + + if (code === 92) { + return readUnicodeEscapeSequence(); + } + + if (code < 128) { + if (identifierPartTable[code]) { + index += 1; + return chr; + } + + return null; + } + + if (isUnicodeLetter(code)) { + index += 1; + return chr; + } + + return null; + }.bind(this); + + char = getIdentifierStart(); + if (char === null) { + return null; + } + + id = char; + for (;;) { + char = getIdentifierPart(); + + if (char === null) { + break; + } + + id += char; + } + + switch (id) { + case "true": + case "false": + type = Token.BooleanLiteral; + break; + case "null": + type = Token.NullLiteral; + break; + default: + type = Token.Identifier; + } + + return { + type: type, + value: id + }; + }, + scanNumericLiteral: function () { + var index = 0; + var value = ""; + var length = this.input.length; + var char = this.peek(index); + var bad; + + function isDecimalDigit(str) { + return (/^[0-9]$/).test(str); + } + + function isOctalDigit(str) { + return (/^[0-7]$/).test(str); + } + + function isHexDigit(str) { + return (/^[0-9a-fA-F]$/).test(str); + } + + function isIdentifierStart(ch) { + return (ch === "$") || (ch === "_") || (ch === "\\") || + (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); + } + + if (char !== "." && !isDecimalDigit(char)) { + return null; + } + + if (char !== ".") { + value = this.peek(index); + index += 1; + char = this.peek(index); + + if (value === "0") { + if (char === "x" || char === "X") { + index += 1; + value += char; + + while (index < length) { + char = this.peek(index); + if (!isHexDigit(char)) { + break; + } + value += char; + index += 1; + } + + if (value.length <= 2) { // 0x + return { + type: Token.NumericLiteral, + value: value, + isMalformed: true + }; + } + + if (index < length) { + char = this.peek(index); + if (isIdentifierStart(char)) { + return null; + } + } + + return { + type: Token.NumericLiteral, + value: value, + base: 16, + isMalformed: false + }; + } + if (isOctalDigit(char)) { + index += 1; + value += char; + bad = false; + + while (index < length) { + char = this.peek(index); + + if (isDecimalDigit(char)) { + bad = true; + } else if (!isOctalDigit(char)) { + break; + } + value += char; + index += 1; + } + + if (index < length) { + char = this.peek(index); + if (isIdentifierStart(char)) { + return null; + } + } + + return { + type: Token.NumericLiteral, + value: value, + base: 8, + isMalformed: false + }; + } + + if (isDecimalDigit(char)) { + index += 1; + value += char; + } + } + + while (index < length) { + char = this.peek(index); + if (!isDecimalDigit(char)) { + break; + } + value += char; + index += 1; + } + } + + if (char === ".") { + value += char; + index += 1; + + while (index < length) { + char = this.peek(index); + if (!isDecimalDigit(char)) { + break; + } + value += char; + index += 1; + } + } + + if (char === "e" || char === "E") { + value += char; + index += 1; + char = this.peek(index); + + if (char === "+" || char === "-") { + value += this.peek(index); + index += 1; + } + + char = this.peek(index); + if (isDecimalDigit(char)) { + value += char; + index += 1; + + while (index < length) { + char = this.peek(index); + if (!isDecimalDigit(char)) { + break; + } + value += char; + index += 1; + } + } else { + return null; + } + } + + if (index < length) { + char = this.peek(index); + if (isIdentifierStart(char)) { + return null; + } + } + + return { + type: Token.NumericLiteral, + value: value, + base: 10, + isMalformed: !isFinite(value) + }; + }, + scanStringLiteral: function (checks) { + var quote = this.peek(); + if (quote !== "\"" && quote !== "'") { + return null; + } + this.triggerAsync("warning", { + code: "W108", + line: this.line, + character: this.char // +1? + }, checks, function () { return state.jsonMode && quote !== "\""; }); + + var value = ""; + var startLine = this.line; + var startChar = this.char; + var allowNewLine = false; + + this.skip(); + + while (this.peek() !== quote) { + while (this.peek() === "") { // End Of Line + + if (!allowNewLine) { + this.trigger("warning", { + code: "W112", + line: this.line, + character: this.char + }); + } else { + allowNewLine = false; + + this.triggerAsync("warning", { + code: "W043", + line: this.line, + character: this.char + }, checks, function () { return !state.option.multistr; }); + + this.triggerAsync("warning", { + code: "W042", + line: this.line, + character: this.char + }, checks, function () { return state.jsonMode && state.option.multistr; }); + } + + if (!this.nextLine()) { + this.trigger("error", { + code: "E029", + line: startLine, + character: startChar + }); + + return { + type: Token.StringLiteral, + value: value, + isUnclosed: true, + quote: quote + }; + } + } + + allowNewLine = false; + var char = this.peek(); + var jump = 1; // A length of a jump, after we're done + + if (char < " ") { + this.trigger("warning", { + code: "W113", + line: this.line, + character: this.char, + data: [ "" ] + }); + } + + if (char === "\\") { + this.skip(); + char = this.peek(); + + switch (char) { + case "'": + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\'" ] + }, checks, function () {return state.jsonMode; }); + break; + case "b": + char = "\b"; + break; + case "f": + char = "\f"; + break; + case "n": + char = "\n"; + break; + case "r": + char = "\r"; + break; + case "t": + char = "\t"; + break; + case "0": + char = "\0"; + var n = parseInt(this.peek(1), 10); + this.triggerAsync("warning", { + code: "W115", + line: this.line, + character: this.char + }, checks, + function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); + break; + case "u": + char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); + jump = 5; + break; + case "v": + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\v" ] + }, checks, function () { return state.jsonMode; }); + + char = "\v"; + break; + case "x": + var x = parseInt(this.input.substr(1, 2), 16); + + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "\\x-" ] + }, checks, function () { return state.jsonMode; }); + + char = String.fromCharCode(x); + jump = 3; + break; + case "\\": + case "\"": + case "/": + break; + case "": + allowNewLine = true; + char = ""; + break; + case "!": + if (value.slice(value.length - 2) === "<") { + break; + } + default: + this.trigger("warning", { + code: "W044", + line: this.line, + character: this.char + }); + } + } + + value += char; + this.skip(jump); + } + + this.skip(); + return { + type: Token.StringLiteral, + value: value, + isUnclosed: false, + quote: quote + }; + }, + scanRegExp: function () { + var index = 0; + var length = this.input.length; + var char = this.peek(); + var value = char; + var body = ""; + var flags = []; + var malformed = false; + var isCharSet = false; + var terminated; + + var scanUnexpectedChars = function () { + if (char < " ") { + malformed = true; + this.trigger("warning", { + code: "W048", + line: this.line, + character: this.char + }); + } + if (char === "<") { + malformed = true; + this.trigger("warning", { + code: "W049", + line: this.line, + character: this.char, + data: [ char ] + }); + } + }.bind(this); + if (!this.prereg || char !== "/") { + return null; + } + + index += 1; + terminated = false; + + while (index < length) { + char = this.peek(index); + value += char; + body += char; + + if (isCharSet) { + if (char === "]") { + if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { + isCharSet = false; + } + } + + if (char === "\\") { + index += 1; + char = this.peek(index); + body += char; + value += char; + + scanUnexpectedChars(); + } + + index += 1; + continue; + } + + if (char === "\\") { + index += 1; + char = this.peek(index); + body += char; + value += char; + + scanUnexpectedChars(); + + if (char === "/") { + index += 1; + continue; + } + + if (char === "[") { + index += 1; + continue; + } + } + + if (char === "[") { + isCharSet = true; + index += 1; + continue; + } + + if (char === "/") { + body = body.substr(0, body.length - 1); + terminated = true; + index += 1; + break; + } + + index += 1; + } + + if (!terminated) { + this.trigger("error", { + code: "E015", + line: this.line, + character: this.from + }); + + return void this.trigger("fatal", { + line: this.line, + from: this.from + }); + } + + while (index < length) { + char = this.peek(index); + if (!/[gim]/.test(char)) { + break; + } + flags.push(char); + value += char; + index += 1; + } + + try { + new RegExp(body, flags.join("")); + } catch (err) { + malformed = true; + this.trigger("error", { + code: "E016", + line: this.line, + character: this.char, + data: [ err.message ] // Platform dependent! + }); + } + + return { + type: Token.RegExp, + value: value, + flags: flags, + isMalformed: malformed + }; + }, + scanMixedSpacesAndTabs: function () { + var at, match; + + if (state.option.smarttabs) { + match = this.input.match(/(\/\/|^\s?\*)? \t/); + at = match && !match[1] ? 0 : -1; + } else { + at = this.input.search(/ \t|\t [^\*]/); + } + + return at; + }, + scanUnsafeChars: function () { + return this.input.search(reg.unsafeChars); + }, + next: function (checks) { + this.from = this.char; + var start; + if (/\s/.test(this.peek())) { + start = this.char; + + while (/\s/.test(this.peek())) { + this.from += 1; + this.skip(); + } + + if (this.peek() === "") { // EOL + if (!/^\s*$/.test(this.getLines()[this.line - 1]) && state.option.trailing) { + this.trigger("warning", { code: "W102", line: this.line, character: start }); + } + } + } + + var match = this.scanComments() || + this.scanStringLiteral(checks); + + if (match) { + return match; + } + + match = + this.scanRegExp() || + this.scanPunctuator() || + this.scanKeyword() || + this.scanIdentifier() || + this.scanNumericLiteral(); + + if (match) { + this.skip(match.value.length); + return match; + } + + return null; + }, + nextLine: function () { + var char; + + if (this.line >= this.getLines().length) { + return false; + } + + this.input = this.getLines()[this.line]; + this.line += 1; + this.char = 1; + this.from = 1; + + char = this.scanMixedSpacesAndTabs(); + if (char >= 0) { + this.trigger("warning", { code: "W099", line: this.line, character: char + 1 }); + } + + this.input = this.input.replace(/\t/g, state.tab); + char = this.scanUnsafeChars(); + + if (char >= 0) { + this.trigger("warning", { code: "W100", line: this.line, character: char }); + } + + if (state.option.maxlen && state.option.maxlen < this.input.length) { + this.trigger("warning", { code: "W101", line: this.line, character: this.input.length }); + } + + return true; + }, + start: function () { + this.nextLine(); + }, + token: function () { + var checks = asyncTrigger(); + var token; + + + function isReserved(token, isProperty) { + if (!token.reserved) { + return false; + } + + if (token.meta && token.meta.isFutureReservedWord) { + if (state.option.inES5(true) && !token.meta.es5) { + return false; + } + if (token.meta.strictOnly) { + if (!state.option.strict && !state.directive["use strict"]) { + return false; + } + } + + if (isProperty) { + return false; + } + } + + return true; + } + var create = function (type, value, isProperty) { + var obj; + + if (type !== "(endline)" && type !== "(end)") { + this.prereg = false; + } + + if (type === "(punctuator)") { + switch (value) { + case ".": + case ")": + case "~": + case "#": + case "]": + this.prereg = false; + break; + default: + this.prereg = true; + } + + obj = Object.create(state.syntax[value] || state.syntax["(error)"]); + } + + if (type === "(identifier)") { + if (value === "return" || value === "case" || value === "typeof") { + this.prereg = true; + } + + if (_.has(state.syntax, value)) { + obj = Object.create(state.syntax[value] || state.syntax["(error)"]); + if (!isReserved(obj, isProperty && type === "(identifier)")) { + obj = null; + } + } + } + + if (!obj) { + obj = Object.create(state.syntax[type]); + } + + obj.identifier = (type === "(identifier)"); + obj.type = obj.type || type; + obj.value = value; + obj.line = this.line; + obj.character = this.char; + obj.from = this.from; + + if (isProperty && obj.identifier) { + obj.isProperty = isProperty; + } + + obj.check = checks.check; + + return obj; + }.bind(this); + + for (;;) { + if (!this.input.length) { + return create(this.nextLine() ? "(endline)" : "(end)", ""); + } + + token = this.next(checks); + + if (!token) { + if (this.input.length) { + this.trigger("error", { + code: "E024", + line: this.line, + character: this.char, + data: [ this.peek() ] + }); + + this.input = ""; + } + + continue; + } + + switch (token.type) { + case Token.StringLiteral: + this.triggerAsync("String", { + line: this.line, + char: this.char, + from: this.from, + value: token.value, + quote: token.quote + }, checks, function () { return true; }); + + return create("(string)", token.value); + case Token.Identifier: + this.trigger("Identifier", { + line: this.line, + char: this.char, + from: this.form, + name: token.value, + isProperty: state.tokens.curr.id === "." + }); + case Token.Keyword: + case Token.NullLiteral: + case Token.BooleanLiteral: + return create("(identifier)", token.value, state.tokens.curr.id === "."); + + case Token.NumericLiteral: + if (token.isMalformed) { + this.trigger("warning", { + code: "W045", + line: this.line, + character: this.char, + data: [ token.value ] + }); + } + + this.triggerAsync("warning", { + code: "W114", + line: this.line, + character: this.char, + data: [ "0x-" ] + }, checks, function () { return token.base === 16 && state.jsonMode; }); + + this.triggerAsync("warning", { + code: "W115", + line: this.line, + character: this.char + }, checks, function () { + return state.directive["use strict"] && token.base === 8; + }); + + this.trigger("Number", { + line: this.line, + char: this.char, + from: this.from, + value: token.value, + base: token.base, + isMalformed: token.malformed + }); + + return create("(number)", token.value); + + case Token.RegExp: + return create("(regexp)", token.value); + + case Token.Comment: + state.tokens.curr.comment = true; + + if (token.isSpecial) { + return { + value: token.value, + body: token.body, + type: token.commentType, + isSpecial: token.isSpecial, + line: this.line, + character: this.char, + from: this.from + }; + } + + break; + + case "": + break; + + default: + return create("(punctuator)", token.value); + } + } + } +}; + +exports.Lexer = Lexer; + +})() +}, +{"events":2,"./reg.js":4,"./state.js":5,"underscore":12}], +12:[function(req,module,exports){ +(function(){// Underscore.js 1.4.4 + +(function() { + var root = this; + var previousUnderscore = root._; + var breaker = {}; + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + var push = ArrayProto.push, + slice = ArrayProto.slice, + concat = ArrayProto.concat, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + _.VERSION = '1.4.4'; + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + return results; + }; + + var reduceError = 'Reduce of empty array with no initial value'; + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError(reduceError); + return memo; + }; + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var length = obj.length; + if (length !== +length) { + var keys = _.keys(obj); + length = keys.length; + } + each(obj, function(value, index, list) { + index = keys ? keys[--length] : --length; + if (!initial) { + memo = obj[index]; + initial = true; + } else { + memo = iterator.call(context, memo, obj[index], index, list); + } + }); + if (!initial) throw new TypeError(reduceError); + return memo; + }; + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + _.reject = function(obj, iterator, context) { + return _.filter(obj, function(value, index, list) { + return !iterator.call(context, value, index, list); + }, context); + }; + _.every = _.all = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + _.contains = _.include = function(obj, target) { + if (obj == null) return false; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + return any(obj, function(value) { + return value === target; + }); + }; + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + return (isFunc ? method : value[method]).apply(value, args); + }); + }; + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + _.where = function(obj, attrs, first) { + if (_.isEmpty(attrs)) return first ? null : []; + return _[first ? 'find' : 'filter'](obj, function(value) { + for (var key in attrs) { + if (attrs[key] !== value[key]) return false; + } + return true; + }); + }; + _.findWhere = function(obj, attrs) { + return _.where(obj, attrs, true); + }; + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { + return Math.max.apply(Math, obj); + } + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity, value: -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { + return Math.min.apply(Math, obj); + } + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity, value: Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + _.shuffle = function(obj) { + var rand; + var index = 0; + var shuffled = []; + each(obj, function(value) { + rand = _.random(index++); + shuffled[index - 1] = shuffled[rand]; + shuffled[rand] = value; + }); + return shuffled; + }; + var lookupIterator = function(value) { + return _.isFunction(value) ? value : function(obj){ return obj[value]; }; + }; + _.sortBy = function(obj, value, context) { + var iterator = lookupIterator(value); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + index : index, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index < right.index ? -1 : 1; + }), 'value'); + }; + var group = function(obj, value, context, behavior) { + var result = {}; + var iterator = lookupIterator(value || _.identity); + each(obj, function(value, index) { + var key = iterator.call(context, value, index, obj); + behavior(result, key, value); + }); + return result; + }; + _.groupBy = function(obj, value, context) { + return group(obj, value, context, function(result, key, value) { + (_.has(result, key) ? result[key] : (result[key] = [])).push(value); + }); + }; + _.countBy = function(obj, value, context) { + return group(obj, value, context, function(result, key) { + if (!_.has(result, key)) result[key] = 0; + result[key]++; + }); + }; + _.sortedIndex = function(array, obj, iterator, context) { + iterator = iterator == null ? _.identity : lookupIterator(iterator); + var value = iterator.call(context, obj); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >>> 1; + iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; + } + return low; + }; + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (obj.length === +obj.length) return _.map(obj, _.identity); + return _.values(obj); + }; + _.size = function(obj) { + if (obj == null) return 0; + return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; + }; + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + _.last = function(array, n, guard) { + if (array == null) return void 0; + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, (n == null) || guard ? 1 : n); + }; + _.compact = function(array) { + return _.filter(array, _.identity); + }; + var flatten = function(input, shallow, output) { + each(input, function(value) { + if (_.isArray(value)) { + shallow ? push.apply(output, value) : flatten(value, shallow, output); + } else { + output.push(value); + } + }); + return output; + }; + _.flatten = function(array, shallow) { + return flatten(array, shallow, []); + }; + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + _.uniq = _.unique = function(array, isSorted, iterator, context) { + if (_.isFunction(isSorted)) { + context = iterator; + iterator = isSorted; + isSorted = false; + } + var initial = iterator ? _.map(array, iterator, context) : array; + var results = []; + var seen = []; + each(initial, function(value, index) { + if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { + seen.push(value); + results.push(array[index]); + } + }); + return results; + }; + _.union = function() { + return _.uniq(concat.apply(ArrayProto, arguments)); + }; + _.intersection = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + _.difference = function(array) { + var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.contains(rest, value); }); + }; + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) { + results[i] = _.pluck(args, "" + i); + } + return results; + }; + _.object = function(list, values) { + if (list == null) return {}; + var result = {}; + for (var i = 0, l = list.length; i < l; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i = 0, l = array.length; + if (isSorted) { + if (typeof isSorted == 'number') { + i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); + } else { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); + for (; i < l; i++) if (array[i] === item) return i; + return -1; + }; + _.lastIndexOf = function(array, item, from) { + if (array == null) return -1; + var hasIndex = from != null; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { + return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); + } + var i = (hasIndex ? from : array.length); + while (i--) if (array[i] === item) return i; + return -1; + }; + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + _.bind = function(func, context) { + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + var args = slice.call(arguments, 2); + return function() { + return func.apply(context, args.concat(slice.call(arguments))); + }; + }; + _.partial = function(func) { + var args = slice.call(arguments, 1); + return function() { + return func.apply(this, args.concat(slice.call(arguments))); + }; + }; + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length === 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(null, args); }, wait); + }; + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + _.throttle = function(func, wait) { + var context, args, timeout, result; + var previous = 0; + var later = function() { + previous = new Date; + timeout = null; + result = func.apply(context, args); + }; + return function() { + var now = new Date; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + _.debounce = function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) result = func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) result = func.apply(context, args); + return result; + }; + }; + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + memo = func.apply(this, arguments); + func = null; + return memo; + }; + }; + _.wrap = function(func, wrapper) { + return function() { + var args = [func]; + push.apply(args, arguments); + return wrapper.apply(this, args); + }; + }; + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + _.values = function(obj) { + var values = []; + for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); + return values; + }; + _.pairs = function(obj) { + var pairs = []; + for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); + return pairs; + }; + _.invert = function(obj) { + var result = {}; + for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; + return result; + }; + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + if (source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + } + }); + return obj; + }; + _.pick = function(obj) { + var copy = {}; + var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); + each(keys, function(key) { + if (key in obj) copy[key] = obj[key]; + }); + return copy; + }; + _.omit = function(obj) { + var copy = {}; + var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); + for (var key in obj) { + if (!_.contains(keys, key)) copy[key] = obj[key]; + } + return copy; + }; + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + if (source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + } + }); + return obj; + }; + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + var eq = function(a, b, aStack, bStack) { + if (a === b) return a !== 0 || 1 / a == 1 / b; + if (a == null || b == null) return a === b; + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + case '[object String]': + return a == String(b); + case '[object Number]': + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + return +a == +b; + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + var length = aStack.length; + while (length--) { + if (aStack[length] == a) return bStack[length] == b; + } + aStack.push(a); + bStack.push(b); + var size = 0, result = true; + if (className == '[object Array]') { + size = a.length; + result = size == b.length; + if (result) { + while (size--) { + if (!(result = eq(a[size], b[size], aStack, bStack))) break; + } + } + } else { + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && + _.isFunction(bCtor) && (bCtor instanceof bCtor))) { + return false; + } + for (var key in a) { + if (_.has(a, key)) { + size++; + if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; + } + } + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + aStack.pop(); + bStack.pop(); + return result; + }; + _.isEqual = function(a, b) { + return eq(a, b, [], []); + }; + _.isEmpty = function(obj) { + if (obj == null) return true; + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + _.isObject = function(obj) { + return obj === Object(obj); + }; + each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) == '[object ' + name + ']'; + }; + }); + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + if (typeof (/./) !== 'function') { + _.isFunction = function(obj) { + return typeof obj === 'function'; + }; + } + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + _.isNaN = function(obj) { + return _.isNumber(obj) && obj != +obj; + }; + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + _.isNull = function(obj) { + return obj === null; + }; + _.isUndefined = function(obj) { + return obj === void 0; + }; + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + _.identity = function(value) { + return value; + }; + _.times = function(n, iterator, context) { + var accum = Array(n); + for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); + return accum; + }; + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + var entityMap = { + escape: { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/' + } + }; + entityMap.unescape = _.invert(entityMap.escape); + var entityRegexes = { + escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), + unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') + }; + _.each(['escape', 'unescape'], function(method) { + _[method] = function(string) { + if (string == null) return ''; + return ('' + string).replace(entityRegexes[method], function(match) { + return entityMap[method][match]; + }); + }; + }); + _.result = function(object, property) { + if (object == null) return null; + var value = object[property]; + return _.isFunction(value) ? value.call(object) : value; + }; + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result.call(this, func.apply(_, args)); + }; + }); + }; + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + var noMatch = /(.)^/; + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + _.chain = function(obj) { + return _(obj).chain(); + }; + var result = function(obj) { + return this._chain ? _(obj).chain() : obj; + }; + _.mixin(_); + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; + return result.call(this, obj); + }; + }); + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result.call(this, method.apply(this._wrapped, arguments)); + }; + }); + + _.extend(_.prototype, { + chain: function() { + this._chain = true; + return this; + }, + value: function() { + return this._wrapped; + } + + }); + +}).call(this); + +})() +}, +{}] +},{},["E/GbHF"]) +; + +function req() {return require.apply(this, arguments)} +module.exports = req("jshint"); + }); \ No newline at end of file