]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
1 | //2.1.8 |
2 | var JSHINT; | |
3 | (function () { | |
4 | var require; | |
5 | 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<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){ | |
6 | // shim for using process in browser | |
7 | ||
8 | var process = module.exports = {}; | |
9 | ||
10 | process.nextTick = (function () { | |
11 | var canSetImmediate = typeof window !== 'undefined' | |
12 | && window.setImmediate; | |
13 | var canPost = typeof window !== 'undefined' | |
14 | && window.postMessage && window.addEventListener | |
15 | ; | |
16 | ||
17 | if (canSetImmediate) { | |
18 | return function (f) { return window.setImmediate(f) }; | |
19 | } | |
20 | ||
21 | if (canPost) { | |
22 | var queue = []; | |
23 | window.addEventListener('message', function (ev) { | |
24 | if (ev.source === window && ev.data === 'process-tick') { | |
25 | ev.stopPropagation(); | |
26 | if (queue.length > 0) { | |
27 | var fn = queue.shift(); | |
28 | fn(); | |
29 | } | |
30 | } | |
31 | }, true); | |
32 | ||
33 | return function nextTick(fn) { | |
34 | queue.push(fn); | |
35 | window.postMessage('process-tick', '*'); | |
36 | }; | |
37 | } | |
38 | ||
39 | return function nextTick(fn) { | |
40 | setTimeout(fn, 0); | |
41 | }; | |
42 | })(); | |
43 | ||
44 | process.title = 'browser'; | |
45 | process.browser = true; | |
46 | process.env = {}; | |
47 | process.argv = []; | |
48 | ||
49 | process.binding = function (name) { | |
50 | throw new Error('process.binding is not supported'); | |
51 | } | |
52 | ||
53 | // TODO(shtylman) | |
54 | process.cwd = function () { return '/' }; | |
55 | process.chdir = function (dir) { | |
56 | throw new Error('process.chdir is not supported'); | |
57 | }; | |
58 | ||
59 | },{}],2:[function(require,module,exports){ | |
60 | (function(process){if (!process.EventEmitter) process.EventEmitter = function () {}; | |
61 | ||
62 | var EventEmitter = exports.EventEmitter = process.EventEmitter; | |
63 | var isArray = typeof Array.isArray === 'function' | |
64 | ? Array.isArray | |
65 | : function (xs) { | |
66 | return Object.prototype.toString.call(xs) === '[object Array]' | |
67 | } | |
68 | ; | |
69 | function indexOf (xs, x) { | |
70 | if (xs.indexOf) return xs.indexOf(x); | |
71 | for (var i = 0; i < xs.length; i++) { | |
72 | if (x === xs[i]) return i; | |
73 | } | |
74 | return -1; | |
75 | } | |
76 | ||
77 | // By default EventEmitters will print a warning if more than | |
78 | // 10 listeners are added to it. This is a useful default which | |
79 | // helps finding memory leaks. | |
80 | // | |
81 | // Obviously not all Emitters should be limited to 10. This function allows | |
82 | // that to be increased. Set to zero for unlimited. | |
83 | var defaultMaxListeners = 10; | |
84 | EventEmitter.prototype.setMaxListeners = function(n) { | |
85 | if (!this._events) this._events = {}; | |
86 | this._events.maxListeners = n; | |
87 | }; | |
88 | ||
89 | ||
90 | EventEmitter.prototype.emit = function(type) { | |
91 | // If there is no 'error' event listener then throw. | |
92 | if (type === 'error') { | |
93 | if (!this._events || !this._events.error || | |
94 | (isArray(this._events.error) && !this._events.error.length)) | |
95 | { | |
96 | if (arguments[1] instanceof Error) { | |
97 | throw arguments[1]; // Unhandled 'error' event | |
98 | } else { | |
99 | throw new Error("Uncaught, unspecified 'error' event."); | |
100 | } | |
101 | return false; | |
102 | } | |
103 | } | |
104 | ||
105 | if (!this._events) return false; | |
106 | var handler = this._events[type]; | |
107 | if (!handler) return false; | |
108 | ||
109 | if (typeof handler == 'function') { | |
110 | switch (arguments.length) { | |
111 | // fast cases | |
112 | case 1: | |
113 | handler.call(this); | |
114 | break; | |
115 | case 2: | |
116 | handler.call(this, arguments[1]); | |
117 | break; | |
118 | case 3: | |
119 | handler.call(this, arguments[1], arguments[2]); | |
120 | break; | |
121 | // slower | |
122 | default: | |
123 | var args = Array.prototype.slice.call(arguments, 1); | |
124 | handler.apply(this, args); | |
125 | } | |
126 | return true; | |
127 | ||
128 | } else if (isArray(handler)) { | |
129 | var args = Array.prototype.slice.call(arguments, 1); | |
130 | ||
131 | var listeners = handler.slice(); | |
132 | for (var i = 0, l = listeners.length; i < l; i++) { | |
133 | listeners[i].apply(this, args); | |
134 | } | |
135 | return true; | |
136 | ||
137 | } else { | |
138 | return false; | |
139 | } | |
140 | }; | |
141 | ||
142 | // EventEmitter is defined in src/node_events.cc | |
143 | // EventEmitter.prototype.emit() is also defined there. | |
144 | EventEmitter.prototype.addListener = function(type, listener) { | |
145 | if ('function' !== typeof listener) { | |
146 | throw new Error('addListener only takes instances of Function'); | |
147 | } | |
148 | ||
149 | if (!this._events) this._events = {}; | |
150 | ||
151 | // To avoid recursion in the case that type == "newListeners"! Before | |
152 | // adding it to the listeners, first emit "newListeners". | |
153 | this.emit('newListener', type, listener); | |
154 | ||
155 | if (!this._events[type]) { | |
156 | // Optimize the case of one listener. Don't need the extra array object. | |
157 | this._events[type] = listener; | |
158 | } else if (isArray(this._events[type])) { | |
159 | ||
160 | // Check for listener leak | |
161 | if (!this._events[type].warned) { | |
162 | var m; | |
163 | if (this._events.maxListeners !== undefined) { | |
164 | m = this._events.maxListeners; | |
165 | } else { | |
166 | m = defaultMaxListeners; | |
167 | } | |
168 | ||
169 | if (m && m > 0 && this._events[type].length > m) { | |
170 | this._events[type].warned = true; | |
171 | console.error('(node) warning: possible EventEmitter memory ' + | |
172 | 'leak detected. %d listeners added. ' + | |
173 | 'Use emitter.setMaxListeners() to increase limit.', | |
174 | this._events[type].length); | |
175 | console.trace(); | |
176 | } | |
177 | } | |
178 | ||
179 | // If we've already got an array, just append. | |
180 | this._events[type].push(listener); | |
181 | } else { | |
182 | // Adding the second element, need to change to array. | |
183 | this._events[type] = [this._events[type], listener]; | |
184 | } | |
185 | ||
186 | return this; | |
187 | }; | |
188 | ||
189 | EventEmitter.prototype.on = EventEmitter.prototype.addListener; | |
190 | ||
191 | EventEmitter.prototype.once = function(type, listener) { | |
192 | var self = this; | |
193 | self.on(type, function g() { | |
194 | self.removeListener(type, g); | |
195 | listener.apply(this, arguments); | |
196 | }); | |
197 | ||
198 | return this; | |
199 | }; | |
200 | ||
201 | EventEmitter.prototype.removeListener = function(type, listener) { | |
202 | if ('function' !== typeof listener) { | |
203 | throw new Error('removeListener only takes instances of Function'); | |
204 | } | |
205 | ||
206 | // does not use listeners(), so no side effect of creating _events[type] | |
207 | if (!this._events || !this._events[type]) return this; | |
208 | ||
209 | var list = this._events[type]; | |
210 | ||
211 | if (isArray(list)) { | |
212 | var i = indexOf(list, listener); | |
213 | if (i < 0) return this; | |
214 | list.splice(i, 1); | |
215 | if (list.length == 0) | |
216 | delete this._events[type]; | |
217 | } else if (this._events[type] === listener) { | |
218 | delete this._events[type]; | |
219 | } | |
220 | ||
221 | return this; | |
222 | }; | |
223 | ||
224 | EventEmitter.prototype.removeAllListeners = function(type) { | |
225 | if (arguments.length === 0) { | |
226 | this._events = {}; | |
227 | return this; | |
228 | } | |
229 | ||
230 | // does not use listeners(), so no side effect of creating _events[type] | |
231 | if (type && this._events && this._events[type]) this._events[type] = null; | |
232 | return this; | |
233 | }; | |
234 | ||
235 | EventEmitter.prototype.listeners = function(type) { | |
236 | if (!this._events) this._events = {}; | |
237 | if (!this._events[type]) this._events[type] = []; | |
238 | if (!isArray(this._events[type])) { | |
239 | this._events[type] = [this._events[type]]; | |
240 | } | |
241 | return this._events[type]; | |
242 | }; | |
243 | ||
244 | })(require("__browserify_process")) | |
245 | },{"__browserify_process":1}],3:[function(require,module,exports){ | |
246 | (function(){// jshint -W001 | |
247 | ||
248 | "use strict"; | |
249 | ||
250 | // Identifiers provided by the ECMAScript standard. | |
251 | ||
252 | exports.reservedVars = { | |
253 | arguments : false, | |
254 | NaN : false | |
255 | }; | |
256 | ||
257 | exports.ecmaIdentifiers = { | |
258 | Array : false, | |
259 | Boolean : false, | |
260 | Date : false, | |
261 | decodeURI : false, | |
262 | decodeURIComponent : false, | |
263 | encodeURI : false, | |
264 | encodeURIComponent : false, | |
265 | Error : false, | |
266 | "eval" : false, | |
267 | EvalError : false, | |
268 | Function : false, | |
269 | hasOwnProperty : false, | |
270 | isFinite : false, | |
271 | isNaN : false, | |
272 | JSON : false, | |
273 | Math : false, | |
274 | Map : false, | |
275 | Number : false, | |
276 | Object : false, | |
277 | parseInt : false, | |
278 | parseFloat : false, | |
279 | RangeError : false, | |
280 | ReferenceError : false, | |
281 | RegExp : false, | |
282 | Set : false, | |
283 | String : false, | |
284 | SyntaxError : false, | |
285 | TypeError : false, | |
286 | URIError : false, | |
287 | WeakMap : false | |
288 | }; | |
289 | ||
290 | // Global variables commonly provided by a web browser environment. | |
291 | ||
292 | exports.browser = { | |
293 | ArrayBuffer : false, | |
294 | ArrayBufferView : false, | |
295 | Audio : false, | |
296 | Blob : false, | |
297 | addEventListener : false, | |
298 | applicationCache : false, | |
299 | atob : false, | |
300 | blur : false, | |
301 | btoa : false, | |
302 | clearInterval : false, | |
303 | clearTimeout : false, | |
304 | close : false, | |
305 | closed : false, | |
306 | CustomEvent : false, | |
307 | DataView : false, | |
308 | DOMParser : false, | |
309 | defaultStatus : false, | |
310 | document : false, | |
311 | Element : false, | |
312 | ElementTimeControl : false, | |
313 | event : false, | |
314 | FileReader : false, | |
315 | Float32Array : false, | |
316 | Float64Array : false, | |
317 | FormData : false, | |
318 | focus : false, | |
319 | frames : false, | |
320 | getComputedStyle : false, | |
321 | HTMLElement : false, | |
322 | HTMLAnchorElement : false, | |
323 | HTMLBaseElement : false, | |
324 | HTMLBlockquoteElement: false, | |
325 | HTMLBodyElement : false, | |
326 | HTMLBRElement : false, | |
327 | HTMLButtonElement : false, | |
328 | HTMLCanvasElement : false, | |
329 | HTMLDirectoryElement : false, | |
330 | HTMLDivElement : false, | |
331 | HTMLDListElement : false, | |
332 | HTMLFieldSetElement : false, | |
333 | HTMLFontElement : false, | |
334 | HTMLFormElement : false, | |
335 | HTMLFrameElement : false, | |
336 | HTMLFrameSetElement : false, | |
337 | HTMLHeadElement : false, | |
338 | HTMLHeadingElement : false, | |
339 | HTMLHRElement : false, | |
340 | HTMLHtmlElement : false, | |
341 | HTMLIFrameElement : false, | |
342 | HTMLImageElement : false, | |
343 | HTMLInputElement : false, | |
344 | HTMLIsIndexElement : false, | |
345 | HTMLLabelElement : false, | |
346 | HTMLLayerElement : false, | |
347 | HTMLLegendElement : false, | |
348 | HTMLLIElement : false, | |
349 | HTMLLinkElement : false, | |
350 | HTMLMapElement : false, | |
351 | HTMLMenuElement : false, | |
352 | HTMLMetaElement : false, | |
353 | HTMLModElement : false, | |
354 | HTMLObjectElement : false, | |
355 | HTMLOListElement : false, | |
356 | HTMLOptGroupElement : false, | |
357 | HTMLOptionElement : false, | |
358 | HTMLParagraphElement : false, | |
359 | HTMLParamElement : false, | |
360 | HTMLPreElement : false, | |
361 | HTMLQuoteElement : false, | |
362 | HTMLScriptElement : false, | |
363 | HTMLSelectElement : false, | |
364 | HTMLStyleElement : false, | |
365 | HTMLTableCaptionElement: false, | |
366 | HTMLTableCellElement : false, | |
367 | HTMLTableColElement : false, | |
368 | HTMLTableElement : false, | |
369 | HTMLTableRowElement : false, | |
370 | HTMLTableSectionElement: false, | |
371 | HTMLTextAreaElement : false, | |
372 | HTMLTitleElement : false, | |
373 | HTMLUListElement : false, | |
374 | HTMLVideoElement : false, | |
375 | history : false, | |
376 | Int16Array : false, | |
377 | Int32Array : false, | |
378 | Int8Array : false, | |
379 | Image : false, | |
380 | length : false, | |
381 | localStorage : false, | |
382 | location : false, | |
383 | MessageChannel : false, | |
384 | MessageEvent : false, | |
385 | MessagePort : false, | |
386 | MouseEvent : false, | |
387 | moveBy : false, | |
388 | moveTo : false, | |
389 | MutationObserver : false, | |
390 | name : false, | |
391 | Node : false, | |
392 | NodeFilter : false, | |
393 | navigator : false, | |
394 | onbeforeunload : true, | |
395 | onblur : true, | |
396 | onerror : true, | |
397 | onfocus : true, | |
398 | onload : true, | |
399 | onresize : true, | |
400 | onunload : true, | |
401 | open : false, | |
402 | openDatabase : false, | |
403 | opener : false, | |
404 | Option : false, | |
405 | parent : false, | |
406 | print : false, | |
407 | removeEventListener : false, | |
408 | resizeBy : false, | |
409 | resizeTo : false, | |
410 | screen : false, | |
411 | scroll : false, | |
412 | scrollBy : false, | |
413 | scrollTo : false, | |
414 | sessionStorage : false, | |
415 | setInterval : false, | |
416 | setTimeout : false, | |
417 | SharedWorker : false, | |
418 | status : false, | |
419 | SVGAElement : false, | |
420 | SVGAltGlyphDefElement: false, | |
421 | SVGAltGlyphElement : false, | |
422 | SVGAltGlyphItemElement: false, | |
423 | SVGAngle : false, | |
424 | SVGAnimateColorElement: false, | |
425 | SVGAnimateElement : false, | |
426 | SVGAnimateMotionElement: false, | |
427 | SVGAnimateTransformElement: false, | |
428 | SVGAnimatedAngle : false, | |
429 | SVGAnimatedBoolean : false, | |
430 | SVGAnimatedEnumeration: false, | |
431 | SVGAnimatedInteger : false, | |
432 | SVGAnimatedLength : false, | |
433 | SVGAnimatedLengthList: false, | |
434 | SVGAnimatedNumber : false, | |
435 | SVGAnimatedNumberList: false, | |
436 | SVGAnimatedPathData : false, | |
437 | SVGAnimatedPoints : false, | |
438 | SVGAnimatedPreserveAspectRatio: false, | |
439 | SVGAnimatedRect : false, | |
440 | SVGAnimatedString : false, | |
441 | SVGAnimatedTransformList: false, | |
442 | SVGAnimationElement : false, | |
443 | SVGCSSRule : false, | |
444 | SVGCircleElement : false, | |
445 | SVGClipPathElement : false, | |
446 | SVGColor : false, | |
447 | SVGColorProfileElement: false, | |
448 | SVGColorProfileRule : false, | |
449 | SVGComponentTransferFunctionElement: false, | |
450 | SVGCursorElement : false, | |
451 | SVGDefsElement : false, | |
452 | SVGDescElement : false, | |
453 | SVGDocument : false, | |
454 | SVGElement : false, | |
455 | SVGElementInstance : false, | |
456 | SVGElementInstanceList: false, | |
457 | SVGEllipseElement : false, | |
458 | SVGExternalResourcesRequired: false, | |
459 | SVGFEBlendElement : false, | |
460 | SVGFEColorMatrixElement: false, | |
461 | SVGFEComponentTransferElement: false, | |
462 | SVGFECompositeElement: false, | |
463 | SVGFEConvolveMatrixElement: false, | |
464 | SVGFEDiffuseLightingElement: false, | |
465 | SVGFEDisplacementMapElement: false, | |
466 | SVGFEDistantLightElement: false, | |
467 | SVGFEFloodElement : false, | |
468 | SVGFEFuncAElement : false, | |
469 | SVGFEFuncBElement : false, | |
470 | SVGFEFuncGElement : false, | |
471 | SVGFEFuncRElement : false, | |
472 | SVGFEGaussianBlurElement: false, | |
473 | SVGFEImageElement : false, | |
474 | SVGFEMergeElement : false, | |
475 | SVGFEMergeNodeElement: false, | |
476 | SVGFEMorphologyElement: false, | |
477 | SVGFEOffsetElement : false, | |
478 | SVGFEPointLightElement: false, | |
479 | SVGFESpecularLightingElement: false, | |
480 | SVGFESpotLightElement: false, | |
481 | SVGFETileElement : false, | |
482 | SVGFETurbulenceElement: false, | |
483 | SVGFilterElement : false, | |
484 | SVGFilterPrimitiveStandardAttributes: false, | |
485 | SVGFitToViewBox : false, | |
486 | SVGFontElement : false, | |
487 | SVGFontFaceElement : false, | |
488 | SVGFontFaceFormatElement: false, | |
489 | SVGFontFaceNameElement: false, | |
490 | SVGFontFaceSrcElement: false, | |
491 | SVGFontFaceUriElement: false, | |
492 | SVGForeignObjectElement: false, | |
493 | SVGGElement : false, | |
494 | SVGGlyphElement : false, | |
495 | SVGGlyphRefElement : false, | |
496 | SVGGradientElement : false, | |
497 | SVGHKernElement : false, | |
498 | SVGICCColor : false, | |
499 | SVGImageElement : false, | |
500 | SVGLangSpace : false, | |
501 | SVGLength : false, | |
502 | SVGLengthList : false, | |
503 | SVGLineElement : false, | |
504 | SVGLinearGradientElement: false, | |
505 | SVGLocatable : false, | |
506 | SVGMPathElement : false, | |
507 | SVGMarkerElement : false, | |
508 | SVGMaskElement : false, | |
509 | SVGMatrix : false, | |
510 | SVGMetadataElement : false, | |
511 | SVGMissingGlyphElement: false, | |
512 | SVGNumber : false, | |
513 | SVGNumberList : false, | |
514 | SVGPaint : false, | |
515 | SVGPathElement : false, | |
516 | SVGPathSeg : false, | |
517 | SVGPathSegArcAbs : false, | |
518 | SVGPathSegArcRel : false, | |
519 | SVGPathSegClosePath : false, | |
520 | SVGPathSegCurvetoCubicAbs: false, | |
521 | SVGPathSegCurvetoCubicRel: false, | |
522 | SVGPathSegCurvetoCubicSmoothAbs: false, | |
523 | SVGPathSegCurvetoCubicSmoothRel: false, | |
524 | SVGPathSegCurvetoQuadraticAbs: false, | |
525 | SVGPathSegCurvetoQuadraticRel: false, | |
526 | SVGPathSegCurvetoQuadraticSmoothAbs: false, | |
527 | SVGPathSegCurvetoQuadraticSmoothRel: false, | |
528 | SVGPathSegLinetoAbs : false, | |
529 | SVGPathSegLinetoHorizontalAbs: false, | |
530 | SVGPathSegLinetoHorizontalRel: false, | |
531 | SVGPathSegLinetoRel : false, | |
532 | SVGPathSegLinetoVerticalAbs: false, | |
533 | SVGPathSegLinetoVerticalRel: false, | |
534 | SVGPathSegList : false, | |
535 | SVGPathSegMovetoAbs : false, | |
536 | SVGPathSegMovetoRel : false, | |
537 | SVGPatternElement : false, | |
538 | SVGPoint : false, | |
539 | SVGPointList : false, | |
540 | SVGPolygonElement : false, | |
541 | SVGPolylineElement : false, | |
542 | SVGPreserveAspectRatio: false, | |
543 | SVGRadialGradientElement: false, | |
544 | SVGRect : false, | |
545 | SVGRectElement : false, | |
546 | SVGRenderingIntent : false, | |
547 | SVGSVGElement : false, | |
548 | SVGScriptElement : false, | |
549 | SVGSetElement : false, | |
550 | SVGStopElement : false, | |
551 | SVGStringList : false, | |
552 | SVGStylable : false, | |
553 | SVGStyleElement : false, | |
554 | SVGSwitchElement : false, | |
555 | SVGSymbolElement : false, | |
556 | SVGTRefElement : false, | |
557 | SVGTSpanElement : false, | |
558 | SVGTests : false, | |
559 | SVGTextContentElement: false, | |
560 | SVGTextElement : false, | |
561 | SVGTextPathElement : false, | |
562 | SVGTextPositioningElement: false, | |
563 | SVGTitleElement : false, | |
564 | SVGTransform : false, | |
565 | SVGTransformList : false, | |
566 | SVGTransformable : false, | |
567 | SVGURIReference : false, | |
568 | SVGUnitTypes : false, | |
569 | SVGUseElement : false, | |
570 | SVGVKernElement : false, | |
571 | SVGViewElement : false, | |
572 | SVGViewSpec : false, | |
573 | SVGZoomAndPan : false, | |
574 | TimeEvent : false, | |
575 | top : false, | |
576 | Uint16Array : false, | |
577 | Uint32Array : false, | |
578 | Uint8Array : false, | |
579 | Uint8ClampedArray : false, | |
580 | WebSocket : false, | |
581 | window : false, | |
582 | Worker : false, | |
583 | XMLHttpRequest : false, | |
584 | XMLSerializer : false, | |
585 | XPathEvaluator : false, | |
586 | XPathException : false, | |
587 | XPathExpression : false, | |
588 | XPathNamespace : false, | |
589 | XPathNSResolver : false, | |
590 | XPathResult : false | |
591 | }; | |
592 | ||
593 | exports.devel = { | |
594 | alert : false, | |
595 | confirm: false, | |
596 | console: false, | |
597 | Debug : false, | |
598 | opera : false, | |
599 | prompt : false | |
600 | }; | |
601 | ||
602 | exports.worker = { | |
603 | importScripts: true, | |
604 | postMessage : true, | |
605 | self : true | |
606 | }; | |
607 | ||
608 | // Widely adopted global names that are not part of ECMAScript standard | |
609 | exports.nonstandard = { | |
610 | escape : false, | |
611 | unescape: false | |
612 | }; | |
613 | ||
614 | // Globals provided by popular JavaScript environments. | |
615 | ||
616 | exports.couch = { | |
617 | "require" : false, | |
618 | respond : false, | |
619 | getRow : false, | |
620 | emit : false, | |
621 | send : false, | |
622 | start : false, | |
623 | sum : false, | |
624 | log : false, | |
625 | exports : false, | |
626 | module : false, | |
627 | provides : false | |
628 | }; | |
629 | ||
630 | exports.node = { | |
631 | __filename : false, | |
632 | __dirname : false, | |
633 | Buffer : false, | |
634 | DataView : false, | |
635 | console : false, | |
636 | exports : true, // In Node it is ok to exports = module.exports = foo(); | |
637 | GLOBAL : false, | |
638 | global : false, | |
639 | module : false, | |
640 | process : false, | |
641 | require : false, | |
642 | setTimeout : false, | |
643 | clearTimeout : false, | |
644 | setInterval : false, | |
645 | clearInterval : false, | |
646 | setImmediate : false, // v0.9.1+ | |
647 | clearImmediate: false // v0.9.1+ | |
648 | }; | |
649 | ||
650 | exports.phantom = { | |
651 | phantom : true, | |
652 | require : true, | |
653 | WebPage : true | |
654 | }; | |
655 | ||
656 | exports.rhino = { | |
657 | defineClass : false, | |
658 | deserialize : false, | |
659 | gc : false, | |
660 | help : false, | |
661 | importPackage: false, | |
662 | "java" : false, | |
663 | load : false, | |
664 | loadClass : false, | |
665 | print : false, | |
666 | quit : false, | |
667 | readFile : false, | |
668 | readUrl : false, | |
669 | runCommand : false, | |
670 | seal : false, | |
671 | serialize : false, | |
672 | spawn : false, | |
673 | sync : false, | |
674 | toint32 : false, | |
675 | version : false | |
676 | }; | |
677 | ||
678 | exports.shelljs = { | |
679 | target : false, | |
680 | echo : false, | |
681 | exit : false, | |
682 | cd : false, | |
683 | pwd : false, | |
684 | ls : false, | |
685 | find : false, | |
686 | cp : false, | |
687 | rm : false, | |
688 | mv : false, | |
689 | mkdir : false, | |
690 | test : false, | |
691 | cat : false, | |
692 | sed : false, | |
693 | grep : false, | |
694 | which : false, | |
695 | dirs : false, | |
696 | pushd : false, | |
697 | popd : false, | |
698 | env : false, | |
699 | exec : false, | |
700 | chmod : false, | |
701 | config : false, | |
702 | error : false, | |
703 | tempdir : false | |
704 | }; | |
705 | ||
706 | exports.wsh = { | |
707 | ActiveXObject : true, | |
708 | Enumerator : true, | |
709 | GetObject : true, | |
710 | ScriptEngine : true, | |
711 | ScriptEngineBuildVersion : true, | |
712 | ScriptEngineMajorVersion : true, | |
713 | ScriptEngineMinorVersion : true, | |
714 | VBArray : true, | |
715 | WSH : true, | |
716 | WScript : true, | |
717 | XDomainRequest : true | |
718 | }; | |
719 | ||
720 | // Globals provided by popular JavaScript libraries. | |
721 | ||
722 | exports.dojo = { | |
723 | dojo : false, | |
724 | dijit : false, | |
725 | dojox : false, | |
726 | define : false, | |
727 | "require": false | |
728 | }; | |
729 | ||
730 | exports.jquery = { | |
731 | "$" : false, | |
732 | jQuery : false | |
733 | }; | |
734 | ||
735 | exports.mootools = { | |
736 | "$" : false, | |
737 | "$$" : false, | |
738 | Asset : false, | |
739 | Browser : false, | |
740 | Chain : false, | |
741 | Class : false, | |
742 | Color : false, | |
743 | Cookie : false, | |
744 | Core : false, | |
745 | Document : false, | |
746 | DomReady : false, | |
747 | DOMEvent : false, | |
748 | DOMReady : false, | |
749 | Drag : false, | |
750 | Element : false, | |
751 | Elements : false, | |
752 | Event : false, | |
753 | Events : false, | |
754 | Fx : false, | |
755 | Group : false, | |
756 | Hash : false, | |
757 | HtmlTable : false, | |
758 | Iframe : false, | |
759 | IframeShim : false, | |
760 | InputValidator: false, | |
761 | instanceOf : false, | |
762 | Keyboard : false, | |
763 | Locale : false, | |
764 | Mask : false, | |
765 | MooTools : false, | |
766 | Native : false, | |
767 | Options : false, | |
768 | OverText : false, | |
769 | Request : false, | |
770 | Scroller : false, | |
771 | Slick : false, | |
772 | Slider : false, | |
773 | Sortables : false, | |
774 | Spinner : false, | |
775 | Swiff : false, | |
776 | Tips : false, | |
777 | Type : false, | |
778 | typeOf : false, | |
779 | URI : false, | |
780 | Window : false | |
781 | }; | |
782 | ||
783 | exports.prototypejs = { | |
784 | "$" : false, | |
785 | "$$" : false, | |
786 | "$A" : false, | |
787 | "$F" : false, | |
788 | "$H" : false, | |
789 | "$R" : false, | |
790 | "$break" : false, | |
791 | "$continue" : false, | |
792 | "$w" : false, | |
793 | Abstract : false, | |
794 | Ajax : false, | |
795 | Class : false, | |
796 | Enumerable : false, | |
797 | Element : false, | |
798 | Event : false, | |
799 | Field : false, | |
800 | Form : false, | |
801 | Hash : false, | |
802 | Insertion : false, | |
803 | ObjectRange : false, | |
804 | PeriodicalExecuter: false, | |
805 | Position : false, | |
806 | Prototype : false, | |
807 | Selector : false, | |
808 | Template : false, | |
809 | Toggle : false, | |
810 | Try : false, | |
811 | Autocompleter : false, | |
812 | Builder : false, | |
813 | Control : false, | |
814 | Draggable : false, | |
815 | Draggables : false, | |
816 | Droppables : false, | |
817 | Effect : false, | |
818 | Sortable : false, | |
819 | SortableObserver : false, | |
820 | Sound : false, | |
821 | Scriptaculous : false | |
822 | }; | |
823 | ||
824 | exports.yui = { | |
825 | YUI : false, | |
826 | Y : false, | |
827 | YUI_config: false | |
828 | }; | |
829 | ||
830 | ||
831 | })() | |
832 | },{}],4:[function(require,module,exports){ | |
833 | /* | |
834 | * Regular expressions. Some of these are stupidly long. | |
835 | */ | |
836 | ||
837 | /*jshint maxlen:1000 */ | |
838 | ||
839 | "use string"; | |
840 | ||
841 | // Unsafe comment or string (ax) | |
842 | exports.unsafeString = | |
843 | /@cc|<\/?|script|\]\s*\]|<\s*!|</i; | |
844 | ||
845 | // Unsafe characters that are silently deleted by one or more browsers (cx) | |
846 | exports.unsafeChars = | |
847 | /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; | |
848 | ||
849 | // Characters in strings that need escaping (nx and nxg) | |
850 | exports.needEsc = | |
851 | /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; | |
852 | ||
853 | exports.needEscGlobal = | |
854 | /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | |
855 | ||
856 | // Star slash (lx) | |
857 | exports.starSlash = /\*\//; | |
858 | ||
859 | // Identifier (ix) | |
860 | exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; | |
861 | ||
862 | // JavaScript URL (jx) | |
863 | exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; | |
864 | ||
865 | // Catches /* falls through */ comments (ft) | |
866 | exports.fallsThrough = /^\s*\/\*\s*falls?\sthrough\s*\*\/\s*$/; | |
867 | ||
868 | },{}],5:[function(require,module,exports){ | |
869 | (function(){"use strict"; | |
870 | ||
871 | exports.register = function (linter) { | |
872 | // Check for properties named __proto__. This special property was | |
873 | // deprecated and then re-introduced for ES6. | |
874 | ||
875 | linter.on("Identifier", function style_scanProto(data) { | |
876 | if (linter.getOption("proto")) { | |
877 | return; | |
878 | } | |
879 | ||
880 | if (data.name === "__proto__") { | |
881 | linter.warn("W103", { | |
882 | line: data.line, | |
883 | char: data.char, | |
884 | data: [ data.name ] | |
885 | }); | |
886 | } | |
887 | }); | |
888 | ||
889 | // Check for properties named __iterator__. This is a special property | |
890 | // available only in browsers with JavaScript 1.7 implementation. | |
891 | ||
892 | linter.on("Identifier", function style_scanIterator(data) { | |
893 | if (linter.getOption("iterator")) { | |
894 | return; | |
895 | } | |
896 | ||
897 | if (data.name === "__iterator__") { | |
898 | linter.warn("W104", { | |
899 | line: data.line, | |
900 | char: data.char, | |
901 | data: [ data.name ] | |
902 | }); | |
903 | } | |
904 | }); | |
905 | ||
906 | // Check for dangling underscores. | |
907 | ||
908 | linter.on("Identifier", function style_scanDangling(data) { | |
909 | if (!linter.getOption("nomen")) { | |
910 | return; | |
911 | } | |
912 | ||
913 | // Underscore.js | |
914 | if (data.name === "_") { | |
915 | return; | |
916 | } | |
917 | ||
918 | // In Node, __dirname and __filename should be ignored. | |
919 | if (linter.getOption("node")) { | |
920 | if (/^(__dirname|__filename)$/.test(data.name) && !data.isProperty) { | |
921 | return; | |
922 | } | |
923 | } | |
924 | ||
925 | if (/^(_+.*|.*_+)$/.test(data.name)) { | |
926 | linter.warn("W105", { | |
927 | line: data.line, | |
928 | char: data.from, | |
929 | data: [ "dangling '_'", data.name ] | |
930 | }); | |
931 | } | |
932 | }); | |
933 | ||
934 | // Check that all identifiers are using camelCase notation. | |
935 | // Exceptions: names like MY_VAR and _myVar. | |
936 | ||
937 | linter.on("Identifier", function style_scanCamelCase(data) { | |
938 | if (!linter.getOption("camelcase")) { | |
939 | return; | |
940 | } | |
941 | ||
942 | if (data.name.replace(/^_+/, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { | |
943 | linter.warn("W106", { | |
944 | line: data.line, | |
945 | char: data.from, | |
946 | data: [ data.name ] | |
947 | }); | |
948 | } | |
949 | }); | |
950 | ||
951 | // Enforce consistency in style of quoting. | |
952 | ||
953 | linter.on("String", function style_scanQuotes(data) { | |
954 | var quotmark = linter.getOption("quotmark"); | |
955 | var code; | |
956 | ||
957 | if (!quotmark) { | |
958 | return; | |
959 | } | |
960 | ||
961 | // If quotmark is set to 'single' warn about all double-quotes. | |
962 | ||
963 | if (quotmark === "single" && data.quote !== "'") { | |
964 | code = "W109"; | |
965 | } | |
966 | ||
967 | // If quotmark is set to 'double' warn about all single-quotes. | |
968 | ||
969 | if (quotmark === "double" && data.quote !== "\"") { | |
970 | code = "W108"; | |
971 | } | |
972 | ||
973 | // If quotmark is set to true, remember the first quotation style | |
974 | // and then warn about all others. | |
975 | ||
976 | if (quotmark === true) { | |
977 | if (!linter.getCache("quotmark")) { | |
978 | linter.setCache("quotmark", data.quote); | |
979 | } | |
980 | ||
981 | if (linter.getCache("quotmark") !== data.quote) { | |
982 | code = "W110"; | |
983 | } | |
984 | } | |
985 | ||
986 | if (code) { | |
987 | linter.warn(code, { | |
988 | line: data.line, | |
989 | char: data.char, | |
990 | }); | |
991 | } | |
992 | }); | |
993 | ||
994 | linter.on("Number", function style_scanNumbers(data) { | |
995 | if (data.value.charAt(0) === ".") { | |
996 | // Warn about a leading decimal point. | |
997 | linter.warn("W008", { | |
998 | line: data.line, | |
999 | char: data.char, | |
1000 | data: [ data.value ] | |
1001 | }); | |
1002 | } | |
1003 | ||
1004 | if (data.value.substr(data.value.length - 1) === ".") { | |
1005 | // Warn about a trailing decimal point. | |
1006 | linter.warn("W047", { | |
1007 | line: data.line, | |
1008 | char: data.char, | |
1009 | data: [ data.value ] | |
1010 | }); | |
1011 | } | |
1012 | ||
1013 | if (/^00+/.test(data.value)) { | |
1014 | // Multiple leading zeroes. | |
1015 | linter.warn("W046", { | |
1016 | line: data.line, | |
1017 | char: data.char, | |
1018 | data: [ data.value ] | |
1019 | }); | |
1020 | } | |
1021 | }); | |
1022 | ||
1023 | // Warn about script URLs. | |
1024 | ||
1025 | linter.on("String", function style_scanJavaScriptURLs(data) { | |
1026 | var re = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; | |
1027 | ||
1028 | if (linter.getOption("scripturl")) { | |
1029 | return; | |
1030 | } | |
1031 | ||
1032 | if (re.test(data.value)) { | |
1033 | linter.warn("W107", { | |
1034 | line: data.line, | |
1035 | char: data.char | |
1036 | }); | |
1037 | } | |
1038 | }); | |
1039 | }; | |
1040 | })() | |
1041 | },{}],6:[function(require,module,exports){ | |
1042 | "use strict"; | |
1043 | ||
1044 | var state = { | |
1045 | syntax: {}, | |
1046 | ||
1047 | reset: function () { | |
1048 | this.tokens = { | |
1049 | prev: null, | |
1050 | next: null, | |
1051 | curr: null | |
1052 | }; | |
1053 | ||
1054 | this.option = {}; | |
1055 | this.ignored = {}; | |
1056 | this.directive = {}; | |
1057 | this.jsonMode = false; | |
1058 | this.jsonWarnings = []; | |
1059 | this.lines = []; | |
1060 | this.tab = ""; | |
1061 | this.cache = {}; // Node.JS doesn't have Map. Sniff. | |
1062 | } | |
1063 | }; | |
1064 | ||
1065 | exports.state = state; | |
1066 | ||
1067 | },{}],"jshint":[function(require,module,exports){ | |
1068 | module.exports=require('E/GbHF'); | |
1069 | },{}],"E/GbHF":[function(require,module,exports){ | |
1070 | (function(){/*! | |
1071 | * JSHint, by JSHint Community. | |
1072 | * | |
f2a92ac6 DC |
1073 | * This file (and this file only) was licensed under the same slightly modified |
1074 | * MIT license that JSLint is. After a relicensing in 2020 this is now MIT License (Expat). | |
1075 | * Relicensing: https://jshint.com/relicensing-2020/ | |
1076 | * License-Url: https://github.com/jshint/jshint/blob/main/LICENSE | |
eb39fafa | 1077 | * |
f2a92ac6 | 1078 | * Copyright 2012 Anton Kovalyov (http://jshint.com) |
eb39fafa DC |
1079 | * |
1080 | * Permission is hereby granted, free of charge, to any person obtaining | |
1081 | * a copy of this software and associated documentation files (the "Software"), | |
1082 | * to deal in the Software without restriction, including without limitation | |
1083 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
1084 | * and/or sell copies of the Software, and to permit persons to whom | |
1085 | * the Software is furnished to do so, subject to the following conditions: | |
1086 | * | |
1087 | * The above copyright notice and this permission notice shall be included | |
1088 | * in all copies or substantial portions of the Software. | |
1089 | * | |
eb39fafa DC |
1090 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1091 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
1092 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
1093 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
1094 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
1095 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
1096 | * DEALINGS IN THE SOFTWARE. | |
1097 | * | |
1098 | */ | |
1099 | ||
1100 | /*jshint quotmark:double */ | |
1101 | /*global console:true */ | |
1102 | /*exported console */ | |
1103 | ||
1104 | var _ = require("underscore"); | |
1105 | var events = require("events"); | |
1106 | var vars = require("../shared/vars.js"); | |
1107 | var messages = require("../shared/messages.js"); | |
1108 | var Lexer = require("./lex.js").Lexer; | |
1109 | var reg = require("./reg.js"); | |
1110 | var state = require("./state.js").state; | |
1111 | var style = require("./style.js"); | |
1112 | ||
1113 | // We need this module here because environments such as IE and Rhino | |
56c4a2cb | 1114 | // don't necessarily expose the 'console' API and browserify uses |
eb39fafa DC |
1115 | // it to log things. It's a sad state of affair, really. |
1116 | var console = require("console-browserify"); | |
1117 | ||
1118 | // We build the application inside a function so that we produce only a singleton | |
1119 | // variable. That function will be invoked immediately, and its return value is | |
1120 | // the JSHINT function itself. | |
1121 | ||
1122 | var JSHINT = (function () { | |
1123 | "use strict"; | |
1124 | ||
1125 | var anonname, // The guessed name for anonymous functions. | |
1126 | api, // Extension API | |
1127 | ||
1128 | // These are operators that should not be used with the ! operator. | |
1129 | bang = { | |
1130 | "<" : true, | |
1131 | "<=" : true, | |
1132 | "==" : true, | |
1133 | "===": true, | |
1134 | "!==": true, | |
1135 | "!=" : true, | |
1136 | ">" : true, | |
1137 | ">=" : true, | |
1138 | "+" : true, | |
1139 | "-" : true, | |
1140 | "*" : true, | |
1141 | "/" : true, | |
1142 | "%" : true | |
1143 | }, | |
1144 | ||
1145 | // These are the JSHint boolean options. | |
1146 | boolOptions = { | |
1147 | asi : true, // if automatic semicolon insertion should be tolerated | |
1148 | bitwise : true, // if bitwise operators should not be allowed | |
1149 | boss : true, // if advanced usage of assignments should be allowed | |
1150 | browser : true, // if the standard browser globals should be predefined | |
1151 | camelcase : true, // if identifiers should be required in camel case | |
1152 | couch : true, // if CouchDB globals should be predefined | |
1153 | curly : true, // if curly braces around all blocks should be required | |
1154 | debug : true, // if debugger statements should be allowed | |
1155 | devel : true, // if logging globals should be predefined (console, alert, etc.) | |
1156 | dojo : true, // if Dojo Toolkit globals should be predefined | |
1157 | eqeqeq : true, // if === should be required | |
1158 | eqnull : true, // if == null comparisons should be tolerated | |
1159 | es3 : true, // if ES3 syntax should be allowed | |
1160 | es5 : true, // if ES5 syntax should be allowed (is now set per default) | |
1161 | esnext : true, // if es.next specific syntax should be allowed | |
1162 | moz : true, // if mozilla specific syntax should be allowed | |
1163 | evil : true, // if eval should be allowed | |
1164 | expr : true, // if ExpressionStatement should be allowed as Programs | |
1165 | forin : true, // if for in statements must filter | |
1166 | funcscope : true, // if only function scope should be used for scope tests | |
1167 | gcl : true, // if JSHint should be compatible with Google Closure Linter | |
1168 | globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') | |
1169 | immed : true, // if immediate invocations must be wrapped in parens | |
1170 | iterator : true, // if the `__iterator__` property should be allowed | |
1171 | jquery : true, // if jQuery globals should be predefined | |
56c4a2cb | 1172 | lastsemic : true, // if semicolons may be omitted for the trailing |
eb39fafa DC |
1173 | // statements inside of a one-line blocks. |
1174 | laxbreak : true, // if line breaks should not be checked | |
1175 | laxcomma : true, // if line breaks should not be checked around commas | |
1176 | loopfunc : true, // if functions should be allowed to be defined within | |
1177 | // loops | |
1178 | mootools : true, // if MooTools globals should be predefined | |
1179 | multistr : true, // allow multiline strings | |
1180 | newcap : true, // if constructor names must be capitalized | |
1181 | noarg : true, // if arguments.caller and arguments.callee should be | |
1182 | // disallowed | |
1183 | node : true, // if the Node.js environment globals should be | |
1184 | // predefined | |
1185 | noempty : true, // if empty blocks should be disallowed | |
1186 | nonew : true, // if using `new` for side-effects should be disallowed | |
1187 | nonstandard : true, // if non-standard (but widely adopted) globals should | |
1188 | // be predefined | |
1189 | nomen : true, // if names should be checked | |
1190 | onevar : true, // if only one var statement per function should be | |
1191 | // allowed | |
1192 | passfail : true, // if the scan should stop on first error | |
1193 | phantom : true, // if PhantomJS symbols should be allowed | |
1194 | plusplus : true, // if increment/decrement should not be allowed | |
1195 | proto : true, // if the `__proto__` property should be allowed | |
1196 | prototypejs : true, // if Prototype and Scriptaculous globals should be | |
1197 | // predefined | |
1198 | rhino : true, // if the Rhino environment globals should be predefined | |
1199 | shelljs : true, // if ShellJS globals should be predefined | |
1200 | undef : true, // if variables should be declared before used | |
1201 | scripturl : true, // if script-targeted URLs should be tolerated | |
1202 | shadow : true, // if variable shadowing should be tolerated | |
1203 | smarttabs : true, // if smarttabs should be tolerated | |
1204 | // (http://www.emacswiki.org/emacs/SmartTabs) | |
1205 | strict : true, // require the "use strict"; pragma | |
1206 | sub : true, // if all forms of subscript notation are tolerated | |
1207 | supernew : true, // if `new function () { ... };` and `new Object;` | |
1208 | // should be tolerated | |
1209 | trailing : true, // if trailing whitespace rules apply | |
1210 | validthis : true, // if 'this' inside a non-constructor function is valid. | |
1211 | // This is a function scoped option only. | |
1212 | withstmt : true, // if with statements should be allowed | |
1213 | white : true, // if strict whitespace rules apply | |
1214 | worker : true, // if Web Worker script symbols should be allowed | |
1215 | wsh : true, // if the Windows Scripting Host environment globals | |
1216 | // should be predefined | |
1217 | yui : true, // YUI variables should be predefined | |
1218 | ||
1219 | // Obsolete options | |
1220 | onecase : true, // if one case switch statements should be allowed | |
1221 | regexp : true, // if the . should not be allowed in regexp literals | |
1222 | regexdash : true // if unescaped first/last dash (-) inside brackets | |
1223 | // should be tolerated | |
1224 | }, | |
1225 | ||
1226 | // These are the JSHint options that can take any value | |
1227 | // (we use this object to detect invalid options) | |
1228 | valOptions = { | |
1229 | maxlen : false, | |
1230 | indent : false, | |
1231 | maxerr : false, | |
1232 | predef : false, | |
1233 | quotmark : false, //'single'|'double'|true | |
1234 | scope : false, | |
1235 | maxstatements: false, // {int} max statements per function | |
1236 | maxdepth : false, // {int} max nested block depth per function | |
1237 | maxparams : false, // {int} max params per function | |
1238 | maxcomplexity: false, // {int} max cyclomatic complexity per function | |
1239 | unused : true, // warn if variables are unused. Available options: | |
1240 | // false - don't check for unused variables | |
1241 | // true - "vars" + check last function param | |
1242 | // "vars" - skip checking unused function params | |
1243 | // "strict" - "vars" + check all function params | |
1244 | latedef : false // warn if the variable is used before its definition | |
1245 | // false - don't emit any warnings | |
1246 | // true - warn if any variable is used before its definition | |
1247 | // "nofunc" - warn for any variable but function declarations | |
1248 | }, | |
1249 | ||
1250 | // These are JSHint boolean options which are shared with JSLint | |
1251 | // where the definition in JSHint is opposite JSLint | |
1252 | invertedOptions = { | |
1253 | bitwise : true, | |
1254 | forin : true, | |
1255 | newcap : true, | |
1256 | nomen : true, | |
1257 | plusplus: true, | |
1258 | regexp : true, | |
1259 | undef : true, | |
1260 | white : true, | |
1261 | ||
1262 | // Inverted and renamed, use JSHint name here | |
1263 | eqeqeq : true, | |
1264 | onevar : true, | |
1265 | strict : true | |
1266 | }, | |
1267 | ||
1268 | // These are JSHint boolean options which are shared with JSLint | |
1269 | // where the name has been changed but the effect is unchanged | |
1270 | renamedOptions = { | |
1271 | eqeq : "eqeqeq", | |
1272 | vars : "onevar", | |
1273 | windows: "wsh", | |
1274 | sloppy : "strict" | |
1275 | }, | |
1276 | ||
1277 | declared, // Globals that were declared using /*global ... */ syntax. | |
1278 | exported, // Variables that are used outside of the current file. | |
1279 | ||
1280 | functionicity = [ | |
1281 | "closure", "exception", "global", "label", | |
1282 | "outer", "unused", "var" | |
1283 | ], | |
1284 | ||
1285 | funct, // The current function | |
1286 | functions, // All of the functions | |
1287 | ||
1288 | global, // The global scope | |
1289 | implied, // Implied globals | |
1290 | inblock, | |
1291 | indent, | |
1292 | lookahead, | |
1293 | lex, | |
1294 | member, | |
1295 | membersOnly, | |
1296 | noreach, | |
1297 | predefined, // Global variables defined by option | |
1298 | ||
1299 | scope, // The current scope | |
1300 | stack, | |
1301 | unuseds, | |
1302 | urls, | |
1303 | warnings, | |
1304 | ||
1305 | extraModules = [], | |
1306 | emitter = new events.EventEmitter(); | |
1307 | ||
1308 | function checkOption(name, t) { | |
1309 | name = name.trim(); | |
1310 | ||
1311 | if (/^[+-]W\d{3}$/g.test(name)) { | |
1312 | return true; | |
1313 | } | |
1314 | ||
1315 | if (valOptions[name] === undefined && boolOptions[name] === undefined) { | |
1316 | if (t.type !== "jslint") { | |
1317 | error("E001", t, name); | |
1318 | return false; | |
1319 | } | |
1320 | } | |
1321 | ||
1322 | return true; | |
1323 | } | |
1324 | ||
1325 | function isString(obj) { | |
1326 | return Object.prototype.toString.call(obj) === "[object String]"; | |
1327 | } | |
1328 | ||
1329 | function isIdentifier(tkn, value) { | |
1330 | if (!tkn) | |
1331 | return false; | |
1332 | ||
1333 | if (!tkn.identifier || tkn.value !== value) | |
1334 | return false; | |
1335 | ||
1336 | return true; | |
1337 | } | |
1338 | ||
1339 | function isReserved(token) { | |
1340 | if (!token.reserved) { | |
1341 | return false; | |
1342 | } | |
1343 | var meta = token.meta; | |
1344 | ||
1345 | if (meta && meta.isFutureReservedWord && state.option.inES5()) { | |
1346 | // ES3 FutureReservedWord in an ES5 environment. | |
1347 | if (!meta.es5) { | |
1348 | return false; | |
1349 | } | |
1350 | ||
1351 | // Some ES5 FutureReservedWord identifiers are active only | |
1352 | // within a strict mode environment. | |
1353 | if (meta.strictOnly) { | |
1354 | if (!state.option.strict && !state.directive["use strict"]) { | |
1355 | return false; | |
1356 | } | |
1357 | } | |
1358 | ||
1359 | if (token.isProperty) { | |
1360 | return false; | |
1361 | } | |
1362 | } | |
1363 | ||
1364 | return true; | |
1365 | } | |
1366 | ||
1367 | function supplant(str, data) { | |
1368 | return str.replace(/\{([^{}]*)\}/g, function (a, b) { | |
1369 | var r = data[b]; | |
1370 | return typeof r === "string" || typeof r === "number" ? r : a; | |
1371 | }); | |
1372 | } | |
1373 | ||
1374 | function combine(t, o) { | |
1375 | var n; | |
1376 | for (n in o) { | |
1377 | if (_.has(o, n) && !_.has(JSHINT.blacklist, n)) { | |
1378 | t[n] = o[n]; | |
1379 | } | |
1380 | } | |
1381 | } | |
1382 | ||
1383 | function updatePredefined() { | |
1384 | Object.keys(JSHINT.blacklist).forEach(function (key) { | |
1385 | delete predefined[key]; | |
1386 | }); | |
1387 | } | |
1388 | ||
1389 | function assume() { | |
1390 | if (state.option.es5) { | |
1391 | warning("I003"); | |
1392 | } | |
1393 | if (state.option.couch) { | |
1394 | combine(predefined, vars.couch); | |
1395 | } | |
1396 | ||
1397 | if (state.option.rhino) { | |
1398 | combine(predefined, vars.rhino); | |
1399 | } | |
1400 | ||
1401 | if (state.option.shelljs) { | |
1402 | combine(predefined, vars.shelljs); | |
1403 | combine(predefined, vars.node); | |
1404 | } | |
1405 | ||
1406 | if (state.option.phantom) { | |
1407 | combine(predefined, vars.phantom); | |
1408 | } | |
1409 | ||
1410 | if (state.option.prototypejs) { | |
1411 | combine(predefined, vars.prototypejs); | |
1412 | } | |
1413 | ||
1414 | if (state.option.node) { | |
1415 | combine(predefined, vars.node); | |
1416 | } | |
1417 | ||
1418 | if (state.option.devel) { | |
1419 | combine(predefined, vars.devel); | |
1420 | } | |
1421 | ||
1422 | if (state.option.dojo) { | |
1423 | combine(predefined, vars.dojo); | |
1424 | } | |
1425 | ||
1426 | if (state.option.browser) { | |
1427 | combine(predefined, vars.browser); | |
1428 | } | |
1429 | ||
1430 | if (state.option.nonstandard) { | |
1431 | combine(predefined, vars.nonstandard); | |
1432 | } | |
1433 | ||
1434 | if (state.option.jquery) { | |
1435 | combine(predefined, vars.jquery); | |
1436 | } | |
1437 | ||
1438 | if (state.option.mootools) { | |
1439 | combine(predefined, vars.mootools); | |
1440 | } | |
1441 | ||
1442 | if (state.option.worker) { | |
1443 | combine(predefined, vars.worker); | |
1444 | } | |
1445 | ||
1446 | if (state.option.wsh) { | |
1447 | combine(predefined, vars.wsh); | |
1448 | } | |
1449 | ||
1450 | if (state.option.globalstrict && state.option.strict !== false) { | |
1451 | state.option.strict = true; | |
1452 | } | |
1453 | ||
1454 | if (state.option.yui) { | |
1455 | combine(predefined, vars.yui); | |
1456 | } | |
1457 | ||
1458 | // Let's assume that chronologically ES3 < ES5 < ES6/ESNext < Moz | |
1459 | ||
1460 | state.option.inMoz = function (strict) { | |
1461 | if (strict) { | |
1462 | return state.option.moz && !state.option.esnext; | |
1463 | } | |
1464 | return state.option.moz; | |
1465 | }; | |
1466 | ||
1467 | state.option.inESNext = function (strict) { | |
1468 | if (strict) { | |
1469 | return !state.option.moz && state.option.esnext; | |
1470 | } | |
1471 | return state.option.moz || state.option.esnext; | |
1472 | }; | |
1473 | ||
1474 | state.option.inES5 = function (/* strict */) { | |
1475 | return !state.option.es3; | |
1476 | }; | |
1477 | ||
1478 | state.option.inES3 = function (strict) { | |
1479 | if (strict) { | |
1480 | return !state.option.moz && !state.option.esnext && state.option.es3; | |
1481 | } | |
1482 | return state.option.es3; | |
1483 | }; | |
1484 | } | |
1485 | ||
1486 | // Produce an error warning. | |
1487 | function quit(code, line, chr) { | |
1488 | var percentage = Math.floor((line / state.lines.length) * 100); | |
1489 | var message = messages.errors[code].desc; | |
1490 | ||
1491 | throw { | |
1492 | name: "JSHintError", | |
1493 | line: line, | |
1494 | character: chr, | |
1495 | message: message + " (" + percentage + "% scanned).", | |
1496 | raw: message, | |
1497 | code: code | |
1498 | }; | |
1499 | } | |
1500 | ||
1501 | function isundef(scope, code, token, a) { | |
1502 | return JSHINT.undefs.push([scope, code, token, a]); | |
1503 | } | |
1504 | ||
1505 | function warning(code, t, a, b, c, d) { | |
1506 | var ch, l, w, msg; | |
1507 | ||
1508 | if (/^W\d{3}$/.test(code)) { | |
1509 | if (state.ignored[code]) | |
1510 | return; | |
1511 | ||
1512 | msg = messages.warnings[code]; | |
1513 | } else if (/E\d{3}/.test(code)) { | |
1514 | msg = messages.errors[code]; | |
1515 | } else if (/I\d{3}/.test(code)) { | |
1516 | msg = messages.info[code]; | |
1517 | } | |
1518 | ||
1519 | t = t || state.tokens.next; | |
1520 | if (t.id === "(end)") { // `~ | |
1521 | t = state.tokens.curr; | |
1522 | } | |
1523 | ||
1524 | l = t.line || 0; | |
1525 | ch = t.from || 0; | |
1526 | ||
1527 | w = { | |
1528 | id: "(error)", | |
1529 | raw: msg.desc, | |
1530 | code: msg.code, | |
1531 | evidence: state.lines[l - 1] || "", | |
1532 | line: l, | |
1533 | character: ch, | |
1534 | scope: JSHINT.scope, | |
1535 | a: a, | |
1536 | b: b, | |
1537 | c: c, | |
1538 | d: d | |
1539 | }; | |
1540 | ||
1541 | w.reason = supplant(msg.desc, w); | |
1542 | JSHINT.errors.push(w); | |
1543 | ||
1544 | if (state.option.passfail) { | |
1545 | quit("E042", l, ch); | |
1546 | } | |
1547 | ||
1548 | warnings += 1; | |
1549 | if (warnings >= state.option.maxerr) { | |
1550 | quit("E043", l, ch); | |
1551 | } | |
1552 | ||
1553 | return w; | |
1554 | } | |
1555 | ||
1556 | function warningAt(m, l, ch, a, b, c, d) { | |
1557 | return warning(m, { | |
1558 | line: l, | |
1559 | from: ch | |
1560 | }, a, b, c, d); | |
1561 | } | |
1562 | ||
1563 | function error(m, t, a, b, c, d) { | |
1564 | warning(m, t, a, b, c, d); | |
1565 | } | |
1566 | ||
1567 | function errorAt(m, l, ch, a, b, c, d) { | |
1568 | return error(m, { | |
1569 | line: l, | |
1570 | from: ch | |
1571 | }, a, b, c, d); | |
1572 | } | |
1573 | ||
1574 | // Tracking of "internal" scripts, like eval containing a static string | |
1575 | function addInternalSrc(elem, src) { | |
1576 | var i; | |
1577 | i = { | |
1578 | id: "(internal)", | |
1579 | elem: elem, | |
1580 | value: src | |
1581 | }; | |
1582 | JSHINT.internals.push(i); | |
1583 | return i; | |
1584 | } | |
1585 | ||
1586 | function addlabel(t, type, tkn, islet) { | |
1587 | // Define t in the current function in the current scope. | |
1588 | if (type === "exception") { | |
1589 | if (_.has(funct["(context)"], t)) { | |
1590 | if (funct[t] !== true && !state.option.node) { | |
1591 | warning("W002", state.tokens.next, t); | |
1592 | } | |
1593 | } | |
1594 | } | |
1595 | ||
1596 | if (_.has(funct, t) && !funct["(global)"]) { | |
1597 | if (funct[t] === true) { | |
1598 | if (state.option.latedef) { | |
1599 | if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || | |
1600 | !_.contains([funct[t], type], "unction")) { | |
1601 | warning("W003", state.tokens.next, t); | |
1602 | } | |
1603 | } | |
1604 | } else { | |
1605 | if (!state.option.shadow && type !== "exception" || | |
1606 | (funct["(blockscope)"].getlabel(t))) { | |
1607 | warning("W004", state.tokens.next, t); | |
1608 | } | |
1609 | } | |
1610 | } | |
1611 | ||
1612 | // a double definition of a let variable in same block throws a TypeError | |
1613 | if (funct["(blockscope)"] && funct["(blockscope)"].current.has(t)) { | |
1614 | error("E044", state.tokens.next, t); | |
1615 | } | |
1616 | ||
1617 | // if the identifier is from a let, adds it only to the current blockscope | |
1618 | if (islet) { | |
1619 | funct["(blockscope)"].current.add(t, type, state.tokens.curr); | |
1620 | } else { | |
1621 | ||
1622 | funct[t] = type; | |
1623 | ||
1624 | if (tkn) { | |
1625 | funct["(tokens)"][t] = tkn; | |
1626 | } | |
1627 | ||
1628 | if (funct["(global)"]) { | |
1629 | global[t] = funct; | |
1630 | if (_.has(implied, t)) { | |
1631 | if (state.option.latedef) { | |
1632 | if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || | |
1633 | !_.contains([funct[t], type], "unction")) { | |
1634 | warning("W003", state.tokens.next, t); | |
1635 | } | |
1636 | } | |
1637 | ||
1638 | delete implied[t]; | |
1639 | } | |
1640 | } else { | |
1641 | scope[t] = funct; | |
1642 | } | |
1643 | } | |
1644 | } | |
1645 | ||
1646 | function doOption() { | |
1647 | var nt = state.tokens.next; | |
1648 | var body = nt.body.split(",").map(function (s) { return s.trim(); }); | |
1649 | var predef = {}; | |
1650 | ||
1651 | if (nt.type === "globals") { | |
1652 | body.forEach(function (g) { | |
1653 | g = g.split(":"); | |
1654 | var key = g[0]; | |
1655 | var val = g[1]; | |
1656 | ||
1657 | if (key.charAt(0) === "-") { | |
1658 | key = key.slice(1); | |
1659 | val = false; | |
1660 | ||
1661 | JSHINT.blacklist[key] = key; | |
1662 | updatePredefined(); | |
1663 | } else { | |
1664 | predef[key] = (val === "true"); | |
1665 | } | |
1666 | }); | |
1667 | ||
1668 | combine(predefined, predef); | |
1669 | ||
1670 | for (var key in predef) { | |
1671 | if (_.has(predef, key)) { | |
1672 | declared[key] = nt; | |
1673 | } | |
1674 | } | |
1675 | } | |
1676 | ||
1677 | if (nt.type === "exported") { | |
1678 | body.forEach(function (e) { | |
1679 | exported[e] = true; | |
1680 | }); | |
1681 | } | |
1682 | ||
1683 | if (nt.type === "members") { | |
1684 | membersOnly = membersOnly || {}; | |
1685 | ||
1686 | body.forEach(function (m) { | |
1687 | var ch1 = m.charAt(0); | |
1688 | var ch2 = m.charAt(m.length - 1); | |
1689 | ||
1690 | if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { | |
1691 | m = m | |
1692 | .substr(1, m.length - 2) | |
1693 | .replace("\\b", "\b") | |
1694 | .replace("\\t", "\t") | |
1695 | .replace("\\n", "\n") | |
1696 | .replace("\\v", "\v") | |
1697 | .replace("\\f", "\f") | |
1698 | .replace("\\r", "\r") | |
1699 | .replace("\\\\", "\\") | |
1700 | .replace("\\\"", "\""); | |
1701 | } | |
1702 | ||
1703 | membersOnly[m] = false; | |
1704 | }); | |
1705 | } | |
1706 | ||
1707 | var numvals = [ | |
1708 | "maxstatements", | |
1709 | "maxparams", | |
1710 | "maxdepth", | |
1711 | "maxcomplexity", | |
1712 | "maxerr", | |
1713 | "maxlen", | |
1714 | "indent" | |
1715 | ]; | |
1716 | ||
1717 | if (nt.type === "jshint" || nt.type === "jslint") { | |
1718 | body.forEach(function (g) { | |
1719 | g = g.split(":"); | |
1720 | var key = (g[0] || "").trim(); | |
1721 | var val = (g[1] || "").trim(); | |
1722 | ||
1723 | if (!checkOption(key, nt)) { | |
1724 | return; | |
1725 | } | |
1726 | ||
1727 | if (numvals.indexOf(key) >= 0) { | |
1728 | ||
1729 | // GH988 - numeric options can be disabled by setting them to `false` | |
1730 | if (val !== "false") { | |
1731 | val = +val; | |
1732 | ||
1733 | if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) { | |
1734 | error("E032", nt, g[1].trim()); | |
1735 | return; | |
1736 | } | |
1737 | ||
1738 | if (key === "indent") { | |
1739 | state.option["(explicitIndent)"] = true; | |
1740 | } | |
1741 | state.option[key] = val; | |
1742 | } else { | |
1743 | if (key === "indent") { | |
1744 | state.option["(explicitIndent)"] = false; | |
1745 | } else { | |
1746 | state.option[key] = false; | |
1747 | } | |
1748 | } | |
1749 | ||
1750 | return; | |
1751 | } | |
1752 | ||
1753 | if (key === "validthis") { | |
1754 | // `validthis` is valid only within a function scope. | |
1755 | if (funct["(global)"]) { | |
1756 | error("E009"); | |
1757 | } else { | |
1758 | if (val === "true" || val === "false") { | |
1759 | state.option.validthis = (val === "true"); | |
1760 | } else { | |
1761 | error("E002", nt); | |
1762 | } | |
1763 | } | |
1764 | return; | |
1765 | } | |
1766 | ||
1767 | if (key === "quotmark") { | |
1768 | switch (val) { | |
1769 | case "true": | |
1770 | case "false": | |
1771 | state.option.quotmark = (val === "true"); | |
1772 | break; | |
1773 | case "double": | |
1774 | case "single": | |
1775 | state.option.quotmark = val; | |
1776 | break; | |
1777 | default: | |
1778 | error("E002", nt); | |
1779 | } | |
1780 | return; | |
1781 | } | |
1782 | ||
1783 | if (key === "unused") { | |
1784 | switch (val) { | |
1785 | case "true": | |
1786 | state.option.unused = true; | |
1787 | break; | |
1788 | case "false": | |
1789 | state.option.unused = false; | |
1790 | break; | |
1791 | case "vars": | |
1792 | case "strict": | |
1793 | state.option.unused = val; | |
1794 | break; | |
1795 | default: | |
1796 | error("E002", nt); | |
1797 | } | |
1798 | return; | |
1799 | } | |
1800 | ||
1801 | if (key === "latedef") { | |
1802 | switch (val) { | |
1803 | case "true": | |
1804 | state.option.latedef = true; | |
1805 | break; | |
1806 | case "false": | |
1807 | state.option.latedef = false; | |
1808 | break; | |
1809 | case "nofunc": | |
1810 | state.option.latedef = "nofunc"; | |
1811 | break; | |
1812 | default: | |
1813 | error("E002", nt); | |
1814 | } | |
1815 | return; | |
1816 | } | |
1817 | ||
1818 | var match = /^([+-])(W\d{3})$/g.exec(key); | |
1819 | if (match) { | |
1820 | // ignore for -W..., unignore for +W... | |
1821 | state.ignored[match[2]] = (match[1] === "-"); | |
1822 | return; | |
1823 | } | |
1824 | ||
1825 | var tn; | |
1826 | if (val === "true" || val === "false") { | |
1827 | if (nt.type === "jslint") { | |
1828 | tn = renamedOptions[key] || key; | |
1829 | state.option[tn] = (val === "true"); | |
1830 | ||
1831 | if (invertedOptions[tn] !== undefined) { | |
1832 | state.option[tn] = !state.option[tn]; | |
1833 | } | |
1834 | } else { | |
1835 | state.option[key] = (val === "true"); | |
1836 | } | |
1837 | ||
1838 | if (key === "newcap") { | |
1839 | state.option["(explicitNewcap)"] = true; | |
1840 | } | |
1841 | return; | |
1842 | } | |
1843 | ||
1844 | error("E002", nt); | |
1845 | }); | |
1846 | ||
1847 | assume(); | |
1848 | } | |
1849 | } | |
1850 | ||
1851 | // We need a peek function. If it has an argument, it peeks that much farther | |
1852 | // ahead. It is used to distinguish | |
1853 | // for ( var i in ... | |
1854 | // from | |
1855 | // for ( var i = ... | |
1856 | ||
1857 | function peek(p) { | |
1858 | var i = p || 0, j = 0, t; | |
1859 | ||
1860 | while (j <= i) { | |
1861 | t = lookahead[j]; | |
1862 | if (!t) { | |
1863 | t = lookahead[j] = lex.token(); | |
1864 | } | |
1865 | j += 1; | |
1866 | } | |
1867 | return t; | |
1868 | } | |
1869 | ||
1870 | // Produce the next token. It looks for programming errors. | |
1871 | ||
1872 | function advance(id, t) { | |
1873 | switch (state.tokens.curr.id) { | |
1874 | case "(number)": | |
1875 | if (state.tokens.next.id === ".") { | |
1876 | warning("W005", state.tokens.curr); | |
1877 | } | |
1878 | break; | |
1879 | case "-": | |
1880 | if (state.tokens.next.id === "-" || state.tokens.next.id === "--") { | |
1881 | warning("W006"); | |
1882 | } | |
1883 | break; | |
1884 | case "+": | |
1885 | if (state.tokens.next.id === "+" || state.tokens.next.id === "++") { | |
1886 | warning("W007"); | |
1887 | } | |
1888 | break; | |
1889 | } | |
1890 | ||
1891 | if (state.tokens.curr.type === "(string)" || state.tokens.curr.identifier) { | |
1892 | anonname = state.tokens.curr.value; | |
1893 | } | |
1894 | ||
1895 | if (id && state.tokens.next.id !== id) { | |
1896 | if (t) { | |
1897 | if (state.tokens.next.id === "(end)") { | |
1898 | error("E019", t, t.id); | |
1899 | } else { | |
1900 | error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); | |
1901 | } | |
1902 | } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { | |
1903 | warning("W116", state.tokens.next, id, state.tokens.next.value); | |
1904 | } | |
1905 | } | |
1906 | ||
1907 | state.tokens.prev = state.tokens.curr; | |
1908 | state.tokens.curr = state.tokens.next; | |
1909 | for (;;) { | |
1910 | state.tokens.next = lookahead.shift() || lex.token(); | |
1911 | ||
1912 | if (!state.tokens.next) { // No more tokens left, give up | |
1913 | quit("E041", state.tokens.curr.line); | |
1914 | } | |
1915 | ||
1916 | if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { | |
1917 | return; | |
1918 | } | |
1919 | ||
1920 | if (state.tokens.next.check) { | |
1921 | state.tokens.next.check(); | |
1922 | } | |
1923 | ||
1924 | if (state.tokens.next.isSpecial) { | |
1925 | doOption(); | |
1926 | } else { | |
1927 | if (state.tokens.next.id !== "(endline)") { | |
1928 | break; | |
1929 | } | |
1930 | } | |
1931 | } | |
1932 | } | |
1933 | ||
1934 | function isInfix(token) { | |
1935 | return token.infix || (!token.identifier && !!token.led); | |
1936 | } | |
1937 | ||
1938 | function isEndOfExpr() { | |
1939 | var curr = state.tokens.curr; | |
1940 | var next = state.tokens.next; | |
1941 | if (next.id === ";" || next.id === "}" || next.id === ":") { | |
1942 | return true; | |
1943 | } | |
1944 | if (isInfix(next) === isInfix(curr) || (curr.id === "yield" && state.option.inMoz(true))) { | |
1945 | return curr.line !== next.line; | |
1946 | } | |
1947 | return false; | |
1948 | } | |
1949 | ||
1950 | // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it | |
1951 | // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is | |
1952 | // like .nud except that it is only used on the first token of a statement. | |
1953 | // Having .fud makes it much easier to define statement-oriented languages like | |
1954 | // JavaScript. I retained Pratt's nomenclature. | |
1955 | ||
1956 | // .nud Null denotation | |
1957 | // .fud First null denotation | |
1958 | // .led Left denotation | |
1959 | // lbp Left binding power | |
1960 | // rbp Right binding power | |
1961 | ||
1962 | // They are elements of the parsing method called Top Down Operator Precedence. | |
1963 | ||
1964 | function expression(rbp, initial) { | |
1965 | var left, isArray = false, isObject = false, isLetExpr = false; | |
1966 | ||
1967 | // if current expression is a let expression | |
1968 | if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { | |
1969 | if (!state.option.inMoz(true)) { | |
1970 | warning("W118", state.tokens.next, "let expressions"); | |
1971 | } | |
1972 | isLetExpr = true; | |
1973 | // create a new block scope we use only for the current expression | |
1974 | funct["(blockscope)"].stack(); | |
1975 | advance("let"); | |
1976 | advance("("); | |
1977 | state.syntax["let"].fud.call(state.syntax["let"].fud, false); | |
1978 | advance(")"); | |
1979 | } | |
1980 | ||
1981 | if (state.tokens.next.id === "(end)") | |
1982 | error("E006", state.tokens.curr); | |
1983 | ||
1984 | advance(); | |
1985 | ||
1986 | if (initial) { | |
1987 | anonname = "anonymous"; | |
1988 | funct["(verb)"] = state.tokens.curr.value; | |
1989 | } | |
1990 | ||
1991 | if (initial === true && state.tokens.curr.fud) { | |
1992 | left = state.tokens.curr.fud(); | |
1993 | } else { | |
1994 | if (state.tokens.curr.nud) { | |
1995 | left = state.tokens.curr.nud(); | |
1996 | } else { | |
1997 | error("E030", state.tokens.curr, state.tokens.curr.id); | |
1998 | } | |
1999 | ||
2000 | while (rbp < state.tokens.next.lbp && !isEndOfExpr()) { | |
2001 | isArray = state.tokens.curr.value === "Array"; | |
2002 | isObject = state.tokens.curr.value === "Object"; | |
2003 | ||
2004 | // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() | |
2005 | // Line breaks in IfStatement heads exist to satisfy the checkJSHint | |
2006 | // "Line too long." error. | |
2007 | if (left && (left.value || (left.first && left.first.value))) { | |
2008 | // If the left.value is not "new", or the left.first.value is a "." | |
2009 | // then safely assume that this is not "new Array()" and possibly | |
2010 | // not "new Object()"... | |
2011 | if (left.value !== "new" || | |
2012 | (left.first && left.first.value && left.first.value === ".")) { | |
2013 | isArray = false; | |
2014 | // ...In the case of Object, if the left.value and state.tokens.curr.value | |
2015 | // are not equal, then safely assume that this not "new Object()" | |
2016 | if (left.value !== state.tokens.curr.value) { | |
2017 | isObject = false; | |
2018 | } | |
2019 | } | |
2020 | } | |
2021 | ||
2022 | advance(); | |
2023 | ||
2024 | if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { | |
2025 | warning("W009", state.tokens.curr); | |
2026 | } | |
2027 | ||
2028 | if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { | |
2029 | warning("W010", state.tokens.curr); | |
2030 | } | |
2031 | ||
2032 | if (left && state.tokens.curr.led) { | |
2033 | left = state.tokens.curr.led(left); | |
2034 | } else { | |
2035 | error("E033", state.tokens.curr, state.tokens.curr.id); | |
2036 | } | |
2037 | } | |
2038 | } | |
2039 | if (isLetExpr) { | |
2040 | funct["(blockscope)"].unstack(); | |
2041 | } | |
2042 | return left; | |
2043 | } | |
2044 | ||
2045 | ||
2046 | // Functions for conformance of style. | |
2047 | ||
2048 | function adjacent(left, right) { | |
2049 | left = left || state.tokens.curr; | |
2050 | right = right || state.tokens.next; | |
2051 | if (state.option.white) { | |
2052 | if (left.character !== right.from && left.line === right.line) { | |
2053 | left.from += (left.character - left.from); | |
2054 | warning("W011", left, left.value); | |
2055 | } | |
2056 | } | |
2057 | } | |
2058 | ||
2059 | function nobreak(left, right) { | |
2060 | left = left || state.tokens.curr; | |
2061 | right = right || state.tokens.next; | |
2062 | if (state.option.white && (left.character !== right.from || left.line !== right.line)) { | |
2063 | warning("W012", right, right.value); | |
2064 | } | |
2065 | } | |
2066 | ||
2067 | function nospace(left, right) { | |
2068 | left = left || state.tokens.curr; | |
2069 | right = right || state.tokens.next; | |
2070 | if (state.option.white && !left.comment) { | |
2071 | if (left.line === right.line) { | |
2072 | adjacent(left, right); | |
2073 | } | |
2074 | } | |
2075 | } | |
2076 | ||
2077 | function nonadjacent(left, right) { | |
2078 | if (state.option.white) { | |
2079 | left = left || state.tokens.curr; | |
2080 | right = right || state.tokens.next; | |
2081 | ||
2082 | if (left.value === ";" && right.value === ";") { | |
2083 | return; | |
2084 | } | |
2085 | ||
2086 | if (left.line === right.line && left.character === right.from) { | |
2087 | left.from += (left.character - left.from); | |
2088 | warning("W013", left, left.value); | |
2089 | } | |
2090 | } | |
2091 | } | |
2092 | ||
2093 | function nobreaknonadjacent(left, right) { | |
2094 | left = left || state.tokens.curr; | |
2095 | right = right || state.tokens.next; | |
2096 | if (!state.option.laxbreak && left.line !== right.line) { | |
2097 | warning("W014", right, right.value); | |
2098 | } else if (state.option.white) { | |
2099 | left = left || state.tokens.curr; | |
2100 | right = right || state.tokens.next; | |
2101 | if (left.character === right.from) { | |
2102 | left.from += (left.character - left.from); | |
2103 | warning("W013", left, left.value); | |
2104 | } | |
2105 | } | |
2106 | } | |
2107 | ||
2108 | function indentation(bias) { | |
2109 | if (!state.option.white && !state.option["(explicitIndent)"]) { | |
2110 | return; | |
2111 | } | |
2112 | ||
2113 | if (state.tokens.next.id === "(end)") { | |
2114 | return; | |
2115 | } | |
2116 | ||
2117 | var i = indent + (bias || 0); | |
2118 | if (state.tokens.next.from !== i) { | |
2119 | warning("W015", state.tokens.next, state.tokens.next.value, i, state.tokens.next.from); | |
2120 | } | |
2121 | } | |
2122 | ||
2123 | function nolinebreak(t) { | |
2124 | t = t || state.tokens.curr; | |
2125 | if (t.line !== state.tokens.next.line) { | |
2126 | warning("E022", t, t.value); | |
2127 | } | |
2128 | } | |
2129 | ||
2130 | function nobreakcomma(left, right) { | |
2131 | if (left.line !== right.line) { | |
2132 | if (!state.option.laxcomma) { | |
2133 | if (comma.first) { | |
2134 | warning("I001"); | |
2135 | comma.first = false; | |
2136 | } | |
2137 | warning("W014", left, right.value); | |
2138 | } | |
2139 | } else if (!left.comment && left.character !== right.from && state.option.white) { | |
2140 | left.from += (left.character - left.from); | |
2141 | warning("W011", left, left.value); | |
2142 | } | |
2143 | } | |
2144 | ||
2145 | function comma(opts) { | |
2146 | opts = opts || {}; | |
2147 | ||
2148 | if (!opts.peek) { | |
2149 | nobreakcomma(state.tokens.curr, state.tokens.next); | |
2150 | advance(","); | |
2151 | } else { | |
2152 | nobreakcomma(state.tokens.prev, state.tokens.curr); | |
2153 | } | |
2154 | ||
2155 | // TODO: This is a temporary solution to fight against false-positives in | |
2156 | // arrays and objects with trailing commas (see GH-363). The best solution | |
2157 | // would be to extract all whitespace rules out of parser. | |
2158 | ||
2159 | if (state.tokens.next.value !== "]" && state.tokens.next.value !== "}") { | |
2160 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2161 | } | |
2162 | ||
2163 | if (state.tokens.next.identifier && !(opts.property && state.option.inES5())) { | |
2164 | // Keywords that cannot follow a comma operator. | |
2165 | switch (state.tokens.next.value) { | |
2166 | case "break": | |
2167 | case "case": | |
2168 | case "catch": | |
2169 | case "continue": | |
2170 | case "default": | |
2171 | case "do": | |
2172 | case "else": | |
2173 | case "finally": | |
2174 | case "for": | |
2175 | case "if": | |
2176 | case "in": | |
2177 | case "instanceof": | |
2178 | case "return": | |
2179 | case "switch": | |
2180 | case "throw": | |
2181 | case "try": | |
2182 | case "var": | |
2183 | case "let": | |
2184 | case "while": | |
2185 | case "with": | |
2186 | error("E024", state.tokens.next, state.tokens.next.value); | |
2187 | return false; | |
2188 | } | |
2189 | } | |
2190 | ||
2191 | if (state.tokens.next.type === "(punctuator)") { | |
2192 | switch (state.tokens.next.value) { | |
2193 | case "}": | |
2194 | case "]": | |
2195 | case ",": | |
2196 | if (opts.allowTrailing) { | |
2197 | return true; | |
2198 | } | |
2199 | ||
2200 | /* falls through */ | |
2201 | case ")": | |
2202 | error("E024", state.tokens.next, state.tokens.next.value); | |
2203 | return false; | |
2204 | } | |
2205 | } | |
2206 | return true; | |
2207 | } | |
2208 | ||
2209 | // Functional constructors for making the symbols that will be inherited by | |
2210 | // tokens. | |
2211 | ||
2212 | function symbol(s, p) { | |
2213 | var x = state.syntax[s]; | |
2214 | if (!x || typeof x !== "object") { | |
2215 | state.syntax[s] = x = { | |
2216 | id: s, | |
2217 | lbp: p, | |
2218 | value: s | |
2219 | }; | |
2220 | } | |
2221 | return x; | |
2222 | } | |
2223 | ||
2224 | function delim(s) { | |
2225 | return symbol(s, 0); | |
2226 | } | |
2227 | ||
2228 | function stmt(s, f) { | |
2229 | var x = delim(s); | |
2230 | x.identifier = x.reserved = true; | |
2231 | x.fud = f; | |
2232 | return x; | |
2233 | } | |
2234 | ||
2235 | function blockstmt(s, f) { | |
2236 | var x = stmt(s, f); | |
2237 | x.block = true; | |
2238 | return x; | |
2239 | } | |
2240 | ||
2241 | function reserveName(x) { | |
2242 | var c = x.id.charAt(0); | |
2243 | if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { | |
2244 | x.identifier = x.reserved = true; | |
2245 | } | |
2246 | return x; | |
2247 | } | |
2248 | ||
2249 | function prefix(s, f) { | |
2250 | var x = symbol(s, 150); | |
2251 | reserveName(x); | |
2252 | x.nud = (typeof f === "function") ? f : function () { | |
2253 | this.right = expression(150); | |
2254 | this.arity = "unary"; | |
2255 | if (this.id === "++" || this.id === "--") { | |
2256 | if (state.option.plusplus) { | |
2257 | warning("W016", this, this.id); | |
2258 | } else if ((!this.right.identifier || isReserved(this.right)) && | |
2259 | this.right.id !== "." && this.right.id !== "[") { | |
2260 | warning("W017", this); | |
2261 | } | |
2262 | } | |
2263 | return this; | |
2264 | }; | |
2265 | return x; | |
2266 | } | |
2267 | ||
2268 | function type(s, f) { | |
2269 | var x = delim(s); | |
2270 | x.type = s; | |
2271 | x.nud = f; | |
2272 | return x; | |
2273 | } | |
2274 | ||
2275 | function reserve(name, func) { | |
2276 | var x = type(name, func); | |
2277 | x.identifier = true; | |
2278 | x.reserved = true; | |
2279 | return x; | |
2280 | } | |
2281 | ||
2282 | function FutureReservedWord(name, meta) { | |
2283 | var x = type(name, (meta && meta.nud) || function () { | |
2284 | return this; | |
2285 | }); | |
2286 | ||
2287 | meta = meta || {}; | |
2288 | meta.isFutureReservedWord = true; | |
2289 | ||
2290 | x.value = name; | |
2291 | x.identifier = true; | |
2292 | x.reserved = true; | |
2293 | x.meta = meta; | |
2294 | ||
2295 | return x; | |
2296 | } | |
2297 | ||
2298 | function reservevar(s, v) { | |
2299 | return reserve(s, function () { | |
2300 | if (typeof v === "function") { | |
2301 | v(this); | |
2302 | } | |
2303 | return this; | |
2304 | }); | |
2305 | } | |
2306 | ||
2307 | function infix(s, f, p, w) { | |
2308 | var x = symbol(s, p); | |
2309 | reserveName(x); | |
2310 | x.infix = true; | |
2311 | x.led = function (left) { | |
2312 | if (!w) { | |
2313 | nobreaknonadjacent(state.tokens.prev, state.tokens.curr); | |
2314 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2315 | } | |
2316 | if (s === "in" && left.id === "!") { | |
2317 | warning("W018", left, "!"); | |
2318 | } | |
2319 | if (typeof f === "function") { | |
2320 | return f(left, this); | |
2321 | } else { | |
2322 | this.left = left; | |
2323 | this.right = expression(p); | |
2324 | return this; | |
2325 | } | |
2326 | }; | |
2327 | return x; | |
2328 | } | |
2329 | ||
2330 | ||
2331 | function application(s) { | |
2332 | var x = symbol(s, 42); | |
2333 | ||
2334 | x.led = function (left) { | |
2335 | if (!state.option.inESNext()) { | |
2336 | warning("W104", state.tokens.curr, "arrow function syntax (=>)"); | |
2337 | } | |
2338 | ||
2339 | nobreaknonadjacent(state.tokens.prev, state.tokens.curr); | |
2340 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2341 | ||
2342 | this.left = left; | |
2343 | this.right = doFunction(undefined, undefined, false, left); | |
2344 | return this; | |
2345 | }; | |
2346 | return x; | |
2347 | } | |
2348 | ||
2349 | function relation(s, f) { | |
2350 | var x = symbol(s, 100); | |
2351 | ||
2352 | x.led = function (left) { | |
2353 | nobreaknonadjacent(state.tokens.prev, state.tokens.curr); | |
2354 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2355 | var right = expression(100); | |
2356 | ||
2357 | if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { | |
2358 | warning("W019", this); | |
2359 | } else if (f) { | |
2360 | f.apply(this, [left, right]); | |
2361 | } | |
2362 | ||
2363 | if (!left || !right) { | |
2364 | quit("E041", state.tokens.curr.line); | |
2365 | } | |
2366 | ||
2367 | if (left.id === "!") { | |
2368 | warning("W018", left, "!"); | |
2369 | } | |
2370 | ||
2371 | if (right.id === "!") { | |
2372 | warning("W018", right, "!"); | |
2373 | } | |
2374 | ||
2375 | this.left = left; | |
2376 | this.right = right; | |
2377 | return this; | |
2378 | }; | |
2379 | return x; | |
2380 | } | |
2381 | ||
2382 | function isPoorRelation(node) { | |
2383 | return node && | |
2384 | ((node.type === "(number)" && +node.value === 0) || | |
2385 | (node.type === "(string)" && node.value === "") || | |
2386 | (node.type === "null" && !state.option.eqnull) || | |
2387 | node.type === "true" || | |
2388 | node.type === "false" || | |
2389 | node.type === "undefined"); | |
2390 | } | |
2391 | ||
2392 | function assignop(s, f, p) { | |
2393 | var x = infix(s, typeof f === "function" ? f : function (left, that) { | |
2394 | that.left = left; | |
2395 | ||
2396 | if (left) { | |
2397 | if (predefined[left.value] === false && | |
2398 | scope[left.value]["(global)"] === true) { | |
2399 | warning("W020", left); | |
2400 | } else if (left["function"]) { | |
2401 | warning("W021", left, left.value); | |
2402 | } | |
2403 | ||
2404 | if (funct[left.value] === "const") { | |
2405 | error("E013", left, left.value); | |
2406 | } | |
2407 | ||
2408 | if (left.id === ".") { | |
2409 | if (!left.left) { | |
2410 | warning("E031", that); | |
2411 | } else if (left.left.value === "arguments" && !state.directive["use strict"]) { | |
2412 | warning("E031", that); | |
2413 | } | |
2414 | ||
2415 | that.right = expression(10); | |
2416 | return that; | |
2417 | } else if (left.id === "[") { | |
2418 | if (state.tokens.curr.left.first) { | |
2419 | state.tokens.curr.left.first.forEach(function (t) { | |
2420 | if (funct[t.value] === "const") { | |
2421 | error("E013", t, t.value); | |
2422 | } | |
2423 | }); | |
2424 | } else if (!left.left) { | |
2425 | warning("E031", that); | |
2426 | } else if (left.left.value === "arguments" && !state.directive["use strict"]) { | |
2427 | warning("E031", that); | |
2428 | } | |
2429 | that.right = expression(10); | |
2430 | return that; | |
2431 | } else if (left.identifier && !isReserved(left)) { | |
2432 | if (funct[left.value] === "exception") { | |
2433 | warning("W022", left); | |
2434 | } | |
2435 | that.right = expression(10); | |
2436 | return that; | |
2437 | } | |
2438 | ||
2439 | if (left === state.syntax["function"]) { | |
2440 | warning("W023", state.tokens.curr); | |
2441 | } | |
2442 | } | |
2443 | ||
2444 | error("E031", that); | |
2445 | }, p); | |
2446 | ||
2447 | x.exps = true; | |
2448 | x.assign = true; | |
2449 | return x; | |
2450 | } | |
2451 | ||
2452 | ||
2453 | function bitwise(s, f, p) { | |
2454 | var x = symbol(s, p); | |
2455 | reserveName(x); | |
2456 | x.led = (typeof f === "function") ? f : function (left) { | |
2457 | if (state.option.bitwise) { | |
2458 | warning("W016", this, this.id); | |
2459 | } | |
2460 | this.left = left; | |
2461 | this.right = expression(p); | |
2462 | return this; | |
2463 | }; | |
2464 | return x; | |
2465 | } | |
2466 | ||
2467 | ||
2468 | function bitwiseassignop(s) { | |
2469 | return assignop(s, function (left, that) { | |
2470 | if (state.option.bitwise) { | |
2471 | warning("W016", that, that.id); | |
2472 | } | |
2473 | nonadjacent(state.tokens.prev, state.tokens.curr); | |
2474 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2475 | if (left) { | |
2476 | if (left.id === "." || left.id === "[" || | |
2477 | (left.identifier && !isReserved(left))) { | |
2478 | expression(10); | |
2479 | return that; | |
2480 | } | |
2481 | if (left === state.syntax["function"]) { | |
2482 | warning("W023", state.tokens.curr); | |
2483 | } | |
2484 | return that; | |
2485 | } | |
2486 | error("E031", that); | |
2487 | }, 20); | |
2488 | } | |
2489 | ||
2490 | ||
2491 | function suffix(s) { | |
2492 | var x = symbol(s, 150); | |
2493 | ||
2494 | x.led = function (left) { | |
2495 | if (state.option.plusplus) { | |
2496 | warning("W016", this, this.id); | |
2497 | } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") { | |
2498 | warning("W017", this); | |
2499 | } | |
2500 | ||
2501 | this.left = left; | |
2502 | return this; | |
2503 | }; | |
2504 | return x; | |
2505 | } | |
2506 | ||
2507 | // fnparam means that this identifier is being defined as a function | |
2508 | // argument (see identifier()) | |
2509 | // prop means that this identifier is that of an object property | |
2510 | ||
2511 | function optionalidentifier(fnparam, prop) { | |
2512 | if (!state.tokens.next.identifier) { | |
2513 | return; | |
2514 | } | |
2515 | ||
2516 | advance(); | |
2517 | ||
2518 | var curr = state.tokens.curr; | |
2519 | var val = state.tokens.curr.value; | |
2520 | ||
2521 | if (!isReserved(curr)) { | |
2522 | return val; | |
2523 | } | |
2524 | ||
2525 | if (prop) { | |
2526 | if (state.option.inES5()) { | |
2527 | return val; | |
2528 | } | |
2529 | } | |
2530 | ||
2531 | if (fnparam && val === "undefined") { | |
2532 | return val; | |
2533 | } | |
2534 | ||
2535 | // Display an info message about reserved words as properties | |
2536 | // and ES5 but do it only once. | |
2537 | if (prop && !api.getCache("displayed:I002")) { | |
2538 | api.setCache("displayed:I002", true); | |
2539 | warning("I002"); | |
2540 | } | |
2541 | ||
2542 | warning("W024", state.tokens.curr, state.tokens.curr.id); | |
2543 | return val; | |
2544 | } | |
2545 | ||
2546 | // fnparam means that this identifier is being defined as a function | |
2547 | // argument | |
2548 | // prop means that this identifier is that of an object property | |
2549 | function identifier(fnparam, prop) { | |
2550 | var i = optionalidentifier(fnparam, prop); | |
2551 | if (i) { | |
2552 | return i; | |
2553 | } | |
2554 | if (state.tokens.curr.id === "function" && state.tokens.next.id === "(") { | |
2555 | warning("W025"); | |
2556 | } else { | |
2557 | error("E030", state.tokens.next, state.tokens.next.value); | |
2558 | } | |
2559 | } | |
2560 | ||
2561 | ||
2562 | function reachable(s) { | |
2563 | var i = 0, t; | |
2564 | if (state.tokens.next.id !== ";" || noreach) { | |
2565 | return; | |
2566 | } | |
2567 | for (;;) { | |
2568 | t = peek(i); | |
2569 | if (t.reach) { | |
2570 | return; | |
2571 | } | |
2572 | if (t.id !== "(endline)") { | |
2573 | if (t.id === "function") { | |
2574 | if (!state.option.latedef) { | |
2575 | break; | |
2576 | } | |
2577 | ||
2578 | warning("W026", t); | |
2579 | break; | |
2580 | } | |
2581 | ||
2582 | warning("W027", t, t.value, s); | |
2583 | break; | |
2584 | } | |
2585 | i += 1; | |
2586 | } | |
2587 | } | |
2588 | ||
2589 | ||
2590 | function statement(noindent) { | |
2591 | var values; | |
2592 | var i = indent, r, s = scope, t = state.tokens.next; | |
2593 | ||
2594 | if (t.id === ";") { | |
2595 | advance(";"); | |
2596 | return; | |
2597 | } | |
2598 | ||
2599 | // Is this a labelled statement? | |
2600 | var res = isReserved(t); | |
2601 | ||
2602 | // We're being more tolerant here: if someone uses | |
2603 | // a FutureReservedWord as a label, we warn but proceed | |
2604 | // anyway. | |
2605 | ||
2606 | if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") { | |
2607 | warning("W024", t, t.id); | |
2608 | res = false; | |
2609 | } | |
2610 | ||
2611 | // detect a destructuring assignment | |
2612 | if (_.has(["[", "{"], t.value)) { | |
2613 | if (lookupBlockType().isDestAssign) { | |
2614 | if (!state.option.inESNext()) { | |
2615 | warning("W104", state.tokens.curr, "destructuring expression"); | |
2616 | } | |
2617 | values = destructuringExpression(); | |
2618 | values.forEach(function (tok) { | |
2619 | isundef(funct, "W117", tok.token, tok.id); | |
2620 | }); | |
2621 | advance("="); | |
2622 | destructuringExpressionMatch(values, expression(10, true)); | |
2623 | advance(";"); | |
2624 | return; | |
2625 | } | |
2626 | } | |
2627 | if (t.identifier && !res && peek().id === ":") { | |
2628 | advance(); | |
2629 | advance(":"); | |
2630 | scope = Object.create(s); | |
2631 | addlabel(t.value, "label"); | |
2632 | ||
2633 | if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { | |
2634 | warning("W028", state.tokens.next, t.value, state.tokens.next.value); | |
2635 | } | |
2636 | ||
2637 | state.tokens.next.label = t.value; | |
2638 | t = state.tokens.next; | |
2639 | } | |
2640 | ||
2641 | // Is it a lonely block? | |
2642 | ||
2643 | if (t.id === "{") { | |
2644 | block(true, true); | |
2645 | return; | |
2646 | } | |
2647 | ||
2648 | // Parse the statement. | |
2649 | ||
2650 | if (!noindent) { | |
2651 | indentation(); | |
2652 | } | |
2653 | r = expression(0, true); | |
2654 | ||
2655 | // Look for the final semicolon. | |
2656 | ||
2657 | if (!t.block) { | |
2658 | if (!state.option.expr && (!r || !r.exps)) { | |
2659 | warning("W030", state.tokens.curr); | |
2660 | } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { | |
2661 | warning("W031", t); | |
2662 | } | |
2663 | ||
2664 | if (state.tokens.next.id !== ";") { | |
2665 | if (!state.option.asi) { | |
2666 | // If this is the last statement in a block that ends on | |
2667 | // the same line *and* option lastsemic is on, ignore the warning. | |
2668 | // Otherwise, complain about missing semicolon. | |
2669 | if (!state.option.lastsemic || state.tokens.next.id !== "}" || | |
2670 | state.tokens.next.line !== state.tokens.curr.line) { | |
2671 | warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); | |
2672 | } | |
2673 | } | |
2674 | } else { | |
2675 | adjacent(state.tokens.curr, state.tokens.next); | |
2676 | advance(";"); | |
2677 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2678 | } | |
2679 | } | |
2680 | ||
2681 | // Restore the indentation. | |
2682 | ||
2683 | indent = i; | |
2684 | scope = s; | |
2685 | return r; | |
2686 | } | |
2687 | ||
2688 | ||
2689 | function statements(startLine) { | |
2690 | var a = [], p; | |
2691 | ||
2692 | while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { | |
2693 | if (state.tokens.next.id === ";") { | |
2694 | p = peek(); | |
2695 | ||
2696 | if (!p || (p.id !== "(" && p.id !== "[")) { | |
2697 | warning("W032"); | |
2698 | } | |
2699 | ||
2700 | advance(";"); | |
2701 | } else { | |
2702 | a.push(statement(startLine === state.tokens.next.line)); | |
2703 | } | |
2704 | } | |
2705 | return a; | |
2706 | } | |
2707 | ||
2708 | ||
2709 | /* | |
2710 | * read all directives | |
2711 | * recognizes a simple form of asi, but always | |
2712 | * warns, if it is used | |
2713 | */ | |
2714 | function directives() { | |
2715 | var i, p, pn; | |
2716 | ||
2717 | for (;;) { | |
2718 | if (state.tokens.next.id === "(string)") { | |
2719 | p = peek(0); | |
2720 | if (p.id === "(endline)") { | |
2721 | i = 1; | |
2722 | do { | |
2723 | pn = peek(i); | |
2724 | i = i + 1; | |
2725 | } while (pn.id === "(endline)"); | |
2726 | ||
2727 | if (pn.id !== ";") { | |
2728 | if (pn.id !== "(string)" && pn.id !== "(number)" && | |
2729 | pn.id !== "(regexp)" && pn.identifier !== true && | |
2730 | pn.id !== "}") { | |
2731 | break; | |
2732 | } | |
2733 | warning("W033", state.tokens.next); | |
2734 | } else { | |
2735 | p = pn; | |
2736 | } | |
2737 | } else if (p.id === "}") { | |
2738 | // Directive with no other statements, warn about missing semicolon | |
2739 | warning("W033", p); | |
2740 | } else if (p.id !== ";") { | |
2741 | break; | |
2742 | } | |
2743 | ||
2744 | indentation(); | |
2745 | advance(); | |
2746 | if (state.directive[state.tokens.curr.value]) { | |
2747 | warning("W034", state.tokens.curr, state.tokens.curr.value); | |
2748 | } | |
2749 | ||
2750 | if (state.tokens.curr.value === "use strict") { | |
2751 | if (!state.option["(explicitNewcap)"]) | |
2752 | state.option.newcap = true; | |
2753 | state.option.undef = true; | |
2754 | } | |
2755 | ||
2756 | // there's no directive negation, so always set to true | |
2757 | state.directive[state.tokens.curr.value] = true; | |
2758 | ||
2759 | if (p.id === ";") { | |
2760 | advance(";"); | |
2761 | } | |
2762 | continue; | |
2763 | } | |
2764 | break; | |
2765 | } | |
2766 | } | |
2767 | ||
2768 | ||
2769 | /* | |
2770 | * Parses a single block. A block is a sequence of statements wrapped in | |
2771 | * braces. | |
2772 | * | |
2773 | * ordinary - true for everything but function bodies and try blocks. | |
2774 | * stmt - true if block can be a single statement (e.g. in if/for/while). | |
2775 | * isfunc - true if block is a function body | |
2776 | */ | |
2777 | function block(ordinary, stmt, isfunc, isfatarrow) { | |
2778 | var a, | |
2779 | b = inblock, | |
2780 | old_indent = indent, | |
2781 | m, | |
2782 | s = scope, | |
2783 | t, | |
2784 | line, | |
2785 | d; | |
2786 | ||
2787 | inblock = ordinary; | |
2788 | ||
2789 | if (!ordinary || !state.option.funcscope) | |
2790 | scope = Object.create(scope); | |
2791 | ||
2792 | nonadjacent(state.tokens.curr, state.tokens.next); | |
2793 | t = state.tokens.next; | |
2794 | ||
2795 | var metrics = funct["(metrics)"]; | |
2796 | metrics.nestedBlockDepth += 1; | |
2797 | metrics.verifyMaxNestedBlockDepthPerFunction(); | |
2798 | ||
2799 | if (state.tokens.next.id === "{") { | |
2800 | advance("{"); | |
2801 | ||
2802 | // create a new block scope | |
2803 | funct["(blockscope)"].stack(); | |
2804 | ||
2805 | line = state.tokens.curr.line; | |
2806 | if (state.tokens.next.id !== "}") { | |
2807 | indent += state.option.indent; | |
2808 | while (!ordinary && state.tokens.next.from > indent) { | |
2809 | indent += state.option.indent; | |
2810 | } | |
2811 | ||
2812 | if (isfunc) { | |
2813 | m = {}; | |
2814 | for (d in state.directive) { | |
2815 | if (_.has(state.directive, d)) { | |
2816 | m[d] = state.directive[d]; | |
2817 | } | |
2818 | } | |
2819 | directives(); | |
2820 | ||
2821 | if (state.option.strict && funct["(context)"]["(global)"]) { | |
2822 | if (!m["use strict"] && !state.directive["use strict"]) { | |
2823 | warning("E007"); | |
2824 | } | |
2825 | } | |
2826 | } | |
2827 | ||
2828 | a = statements(line); | |
2829 | ||
2830 | metrics.statementCount += a.length; | |
2831 | ||
2832 | if (isfunc) { | |
2833 | state.directive = m; | |
2834 | } | |
2835 | ||
2836 | indent -= state.option.indent; | |
2837 | if (line !== state.tokens.next.line) { | |
2838 | indentation(); | |
2839 | } | |
2840 | } else if (line !== state.tokens.next.line) { | |
2841 | indentation(); | |
2842 | } | |
2843 | advance("}", t); | |
2844 | ||
2845 | funct["(blockscope)"].unstack(); | |
2846 | ||
2847 | indent = old_indent; | |
2848 | } else if (!ordinary) { | |
2849 | if (isfunc) { | |
2850 | m = {}; | |
2851 | if (stmt && !isfatarrow && !state.option.inMoz(true)) { | |
2852 | error("W118", state.tokens.curr, "function closure expressions"); | |
2853 | } | |
2854 | ||
2855 | if (!stmt) { | |
2856 | for (d in state.directive) { | |
2857 | if (_.has(state.directive, d)) { | |
2858 | m[d] = state.directive[d]; | |
2859 | } | |
2860 | } | |
2861 | } | |
2862 | expression(10); | |
2863 | ||
2864 | if (state.option.strict && funct["(context)"]["(global)"]) { | |
2865 | if (!m["use strict"] && !state.directive["use strict"]) { | |
2866 | warning("E007"); | |
2867 | } | |
2868 | } | |
2869 | } else { | |
2870 | error("E021", state.tokens.next, "{", state.tokens.next.value); | |
2871 | } | |
2872 | } else { | |
2873 | ||
2874 | // check to avoid let declaration not within a block | |
2875 | funct["(nolet)"] = true; | |
2876 | ||
2877 | if (!stmt || state.option.curly) { | |
2878 | warning("W116", state.tokens.next, "{", state.tokens.next.value); | |
2879 | } | |
2880 | ||
2881 | noreach = true; | |
2882 | indent += state.option.indent; | |
2883 | // test indentation only if statement is in new line | |
2884 | a = [statement(state.tokens.next.line === state.tokens.curr.line)]; | |
2885 | indent -= state.option.indent; | |
2886 | noreach = false; | |
2887 | ||
2888 | delete funct["(nolet)"]; | |
2889 | } | |
2890 | funct["(verb)"] = null; | |
2891 | if (!ordinary || !state.option.funcscope) scope = s; | |
2892 | inblock = b; | |
2893 | if (ordinary && state.option.noempty && (!a || a.length === 0)) { | |
2894 | warning("W035"); | |
2895 | } | |
2896 | metrics.nestedBlockDepth -= 1; | |
2897 | return a; | |
2898 | } | |
2899 | ||
2900 | ||
2901 | function countMember(m) { | |
2902 | if (membersOnly && typeof membersOnly[m] !== "boolean") { | |
2903 | warning("W036", state.tokens.curr, m); | |
2904 | } | |
2905 | if (typeof member[m] === "number") { | |
2906 | member[m] += 1; | |
2907 | } else { | |
2908 | member[m] = 1; | |
2909 | } | |
2910 | } | |
2911 | ||
2912 | ||
2913 | function note_implied(tkn) { | |
2914 | var name = tkn.value, line = tkn.line, a = implied[name]; | |
2915 | if (typeof a === "function") { | |
2916 | a = false; | |
2917 | } | |
2918 | ||
2919 | if (!a) { | |
2920 | a = [line]; | |
2921 | implied[name] = a; | |
2922 | } else if (a[a.length - 1] !== line) { | |
2923 | a.push(line); | |
2924 | } | |
2925 | } | |
2926 | ||
2927 | ||
2928 | // Build the syntax table by declaring the syntactic elements of the language. | |
2929 | ||
2930 | type("(number)", function () { | |
2931 | return this; | |
2932 | }); | |
2933 | ||
2934 | type("(string)", function () { | |
2935 | return this; | |
2936 | }); | |
2937 | ||
2938 | state.syntax["(identifier)"] = { | |
2939 | type: "(identifier)", | |
2940 | lbp: 0, | |
2941 | identifier: true, | |
2942 | nud: function () { | |
2943 | var v = this.value, | |
2944 | s = scope[v], | |
2945 | f; | |
2946 | ||
2947 | if (typeof s === "function") { | |
2948 | // Protection against accidental inheritance. | |
2949 | s = undefined; | |
2950 | } else if (typeof s === "boolean") { | |
2951 | f = funct; | |
2952 | funct = functions[0]; | |
2953 | addlabel(v, "var"); | |
2954 | s = funct; | |
2955 | funct = f; | |
2956 | } | |
2957 | var block; | |
2958 | if (_.has(funct, "(blockscope)")) { | |
2959 | block = funct["(blockscope)"].getlabel(v); | |
2960 | } | |
2961 | ||
2962 | // The name is in scope and defined in the current function. | |
2963 | if (funct === s || block) { | |
2964 | // Change 'unused' to 'var', and reject labels. | |
2965 | // the name is in a block scope | |
2966 | switch (block ? block[v]["(type)"] : funct[v]) { | |
2967 | case "unused": | |
2968 | if (block) block[v]["(type)"] = "var"; | |
2969 | else funct[v] = "var"; | |
2970 | break; | |
2971 | case "unction": | |
2972 | if (block) block[v]["(type)"] = "function"; | |
2973 | else funct[v] = "function"; | |
2974 | this["function"] = true; | |
2975 | break; | |
2976 | case "function": | |
2977 | this["function"] = true; | |
2978 | break; | |
2979 | case "label": | |
2980 | warning("W037", state.tokens.curr, v); | |
2981 | break; | |
2982 | } | |
2983 | } else if (funct["(global)"]) { | |
2984 | // The name is not defined in the function. If we are in the global | |
2985 | // scope, then we have an undefined variable. | |
2986 | // | |
2987 | // Operators typeof and delete do not raise runtime errors even if | |
2988 | // the base object of a reference is null so no need to display warning | |
2989 | // if we're inside of typeof or delete. | |
2990 | ||
2991 | if (typeof predefined[v] !== "boolean") { | |
2992 | // Attempting to subscript a null reference will throw an | |
2993 | // error, even within the typeof and delete operators | |
2994 | if (!(anonname === "typeof" || anonname === "delete") || | |
2995 | (state.tokens.next && (state.tokens.next.value === "." || | |
2996 | state.tokens.next.value === "["))) { | |
2997 | ||
2998 | // if we're in a list comprehension, variables are declared | |
2999 | // locally and used before being defined. So we check | |
3000 | // the presence of the given variable in the comp array | |
3001 | // before declaring it undefined. | |
3002 | ||
3003 | if (!funct["(comparray)"].check(v)) { | |
3004 | isundef(funct, "W117", state.tokens.curr, v); | |
3005 | } | |
3006 | } | |
3007 | } | |
3008 | ||
3009 | note_implied(state.tokens.curr); | |
3010 | } else { | |
3011 | // If the name is already defined in the current | |
3012 | // function, but not as outer, then there is a scope error. | |
3013 | ||
3014 | switch (funct[v]) { | |
3015 | case "closure": | |
3016 | case "function": | |
3017 | case "var": | |
3018 | case "unused": | |
3019 | warning("W038", state.tokens.curr, v); | |
3020 | break; | |
3021 | case "label": | |
3022 | warning("W037", state.tokens.curr, v); | |
3023 | break; | |
3024 | case "outer": | |
3025 | case "global": | |
3026 | break; | |
3027 | default: | |
3028 | // If the name is defined in an outer function, make an outer entry, | |
3029 | // and if it was unused, make it var. | |
3030 | if (s === true) { | |
3031 | funct[v] = true; | |
3032 | } else if (s === null) { | |
3033 | warning("W039", state.tokens.curr, v); | |
3034 | note_implied(state.tokens.curr); | |
3035 | } else if (typeof s !== "object") { | |
3036 | // Operators typeof and delete do not raise runtime errors even | |
3037 | // if the base object of a reference is null so no need to | |
3038 | // | |
3039 | // display warning if we're inside of typeof or delete. | |
3040 | // Attempting to subscript a null reference will throw an | |
3041 | // error, even within the typeof and delete operators | |
3042 | if (!(anonname === "typeof" || anonname === "delete") || | |
3043 | (state.tokens.next && | |
3044 | (state.tokens.next.value === "." || state.tokens.next.value === "["))) { | |
3045 | ||
3046 | isundef(funct, "W117", state.tokens.curr, v); | |
3047 | } | |
3048 | funct[v] = true; | |
3049 | note_implied(state.tokens.curr); | |
3050 | } else { | |
3051 | switch (s[v]) { | |
3052 | case "function": | |
3053 | case "unction": | |
3054 | this["function"] = true; | |
3055 | s[v] = "closure"; | |
3056 | funct[v] = s["(global)"] ? "global" : "outer"; | |
3057 | break; | |
3058 | case "var": | |
3059 | case "unused": | |
3060 | s[v] = "closure"; | |
3061 | funct[v] = s["(global)"] ? "global" : "outer"; | |
3062 | break; | |
3063 | case "closure": | |
3064 | funct[v] = s["(global)"] ? "global" : "outer"; | |
3065 | break; | |
3066 | case "label": | |
3067 | warning("W037", state.tokens.curr, v); | |
3068 | } | |
3069 | } | |
3070 | } | |
3071 | } | |
3072 | return this; | |
3073 | }, | |
3074 | led: function () { | |
3075 | error("E033", state.tokens.next, state.tokens.next.value); | |
3076 | } | |
3077 | }; | |
3078 | ||
3079 | type("(regexp)", function () { | |
3080 | return this; | |
3081 | }); | |
3082 | ||
3083 | // ECMAScript parser | |
3084 | ||
3085 | delim("(endline)"); | |
3086 | delim("(begin)"); | |
3087 | delim("(end)").reach = true; | |
3088 | delim("(error)").reach = true; | |
3089 | delim("}").reach = true; | |
3090 | delim(")"); | |
3091 | delim("]"); | |
3092 | delim("\"").reach = true; | |
3093 | delim("'").reach = true; | |
3094 | delim(";"); | |
3095 | delim(":").reach = true; | |
3096 | delim("#"); | |
3097 | ||
3098 | reserve("else"); | |
3099 | reserve("case").reach = true; | |
3100 | reserve("catch"); | |
3101 | reserve("default").reach = true; | |
3102 | reserve("finally"); | |
3103 | reservevar("arguments", function (x) { | |
3104 | if (state.directive["use strict"] && funct["(global)"]) { | |
3105 | warning("E008", x); | |
3106 | } | |
3107 | }); | |
3108 | reservevar("eval"); | |
3109 | reservevar("false"); | |
3110 | reservevar("Infinity"); | |
3111 | reservevar("null"); | |
3112 | reservevar("this", function (x) { | |
3113 | if (state.directive["use strict"] && !state.option.validthis && ((funct["(statement)"] && | |
3114 | funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { | |
3115 | warning("W040", x); | |
3116 | } | |
3117 | }); | |
3118 | reservevar("true"); | |
3119 | reservevar("undefined"); | |
3120 | ||
3121 | assignop("=", "assign", 20); | |
3122 | assignop("+=", "assignadd", 20); | |
3123 | assignop("-=", "assignsub", 20); | |
3124 | assignop("*=", "assignmult", 20); | |
3125 | assignop("/=", "assigndiv", 20).nud = function () { | |
3126 | error("E014"); | |
3127 | }; | |
3128 | assignop("%=", "assignmod", 20); | |
3129 | ||
3130 | bitwiseassignop("&=", "assignbitand", 20); | |
3131 | bitwiseassignop("|=", "assignbitor", 20); | |
3132 | bitwiseassignop("^=", "assignbitxor", 20); | |
3133 | bitwiseassignop("<<=", "assignshiftleft", 20); | |
3134 | bitwiseassignop(">>=", "assignshiftright", 20); | |
3135 | bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); | |
3136 | infix(",", function (left, that) { | |
3137 | var expr; | |
3138 | that.exprs = [left]; | |
3139 | if (!comma({peek: true})) { | |
3140 | return that; | |
3141 | } | |
3142 | while (true) { | |
3143 | if (!(expr = expression(10))) { | |
3144 | break; | |
3145 | } | |
3146 | that.exprs.push(expr); | |
3147 | if (state.tokens.next.value !== "," || !comma()) { | |
3148 | break; | |
3149 | } | |
3150 | } | |
3151 | return that; | |
3152 | }, 10, true); | |
3153 | ||
3154 | infix("?", function (left, that) { | |
3155 | increaseComplexityCount(); | |
3156 | that.left = left; | |
3157 | that.right = expression(10); | |
3158 | advance(":"); | |
3159 | that["else"] = expression(10); | |
3160 | return that; | |
3161 | }, 30); | |
3162 | ||
3163 | var orPrecendence = 40; | |
3164 | infix("||", function (left, that) { | |
3165 | increaseComplexityCount(); | |
3166 | that.left = left; | |
3167 | that.right = expression(orPrecendence); | |
3168 | return that; | |
3169 | }, orPrecendence); | |
3170 | infix("&&", "and", 50); | |
3171 | bitwise("|", "bitor", 70); | |
3172 | bitwise("^", "bitxor", 80); | |
3173 | bitwise("&", "bitand", 90); | |
3174 | relation("==", function (left, right) { | |
3175 | var eqnull = state.option.eqnull && (left.value === "null" || right.value === "null"); | |
3176 | ||
3177 | if (!eqnull && state.option.eqeqeq) | |
3178 | warning("W116", this, "===", "=="); | |
3179 | else if (isPoorRelation(left)) | |
3180 | warning("W041", this, "===", left.value); | |
3181 | else if (isPoorRelation(right)) | |
3182 | warning("W041", this, "===", right.value); | |
3183 | ||
3184 | return this; | |
3185 | }); | |
3186 | relation("==="); | |
3187 | relation("!=", function (left, right) { | |
3188 | var eqnull = state.option.eqnull && | |
3189 | (left.value === "null" || right.value === "null"); | |
3190 | ||
3191 | if (!eqnull && state.option.eqeqeq) { | |
3192 | warning("W116", this, "!==", "!="); | |
3193 | } else if (isPoorRelation(left)) { | |
3194 | warning("W041", this, "!==", left.value); | |
3195 | } else if (isPoorRelation(right)) { | |
3196 | warning("W041", this, "!==", right.value); | |
3197 | } | |
3198 | return this; | |
3199 | }); | |
3200 | relation("!=="); | |
3201 | relation("<"); | |
3202 | relation(">"); | |
3203 | relation("<="); | |
3204 | relation(">="); | |
3205 | bitwise("<<", "shiftleft", 120); | |
3206 | bitwise(">>", "shiftright", 120); | |
3207 | bitwise(">>>", "shiftrightunsigned", 120); | |
3208 | infix("in", "in", 120); | |
3209 | infix("instanceof", "instanceof", 120); | |
3210 | infix("+", function (left, that) { | |
3211 | var right = expression(130); | |
3212 | if (left && right && left.id === "(string)" && right.id === "(string)") { | |
3213 | left.value += right.value; | |
3214 | left.character = right.character; | |
3215 | if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { | |
3216 | warning("W050", left); | |
3217 | } | |
3218 | return left; | |
3219 | } | |
3220 | that.left = left; | |
3221 | that.right = right; | |
3222 | return that; | |
3223 | }, 130); | |
3224 | prefix("+", "num"); | |
3225 | prefix("+++", function () { | |
3226 | warning("W007"); | |
3227 | this.right = expression(150); | |
3228 | this.arity = "unary"; | |
3229 | return this; | |
3230 | }); | |
3231 | infix("+++", function (left) { | |
3232 | warning("W007"); | |
3233 | this.left = left; | |
3234 | this.right = expression(130); | |
3235 | return this; | |
3236 | }, 130); | |
3237 | infix("-", "sub", 130); | |
3238 | prefix("-", "neg"); | |
3239 | prefix("---", function () { | |
3240 | warning("W006"); | |
3241 | this.right = expression(150); | |
3242 | this.arity = "unary"; | |
3243 | return this; | |
3244 | }); | |
3245 | infix("---", function (left) { | |
3246 | warning("W006"); | |
3247 | this.left = left; | |
3248 | this.right = expression(130); | |
3249 | return this; | |
3250 | }, 130); | |
3251 | infix("*", "mult", 140); | |
3252 | infix("/", "div", 140); | |
3253 | infix("%", "mod", 140); | |
3254 | ||
3255 | suffix("++", "postinc"); | |
3256 | prefix("++", "preinc"); | |
3257 | state.syntax["++"].exps = true; | |
3258 | ||
3259 | suffix("--", "postdec"); | |
3260 | prefix("--", "predec"); | |
3261 | state.syntax["--"].exps = true; | |
3262 | prefix("delete", function () { | |
3263 | var p = expression(10); | |
3264 | if (!p || (p.id !== "." && p.id !== "[")) { | |
3265 | warning("W051"); | |
3266 | } | |
3267 | this.first = p; | |
3268 | return this; | |
3269 | }).exps = true; | |
3270 | ||
3271 | prefix("~", function () { | |
3272 | if (state.option.bitwise) { | |
3273 | warning("W052", this, "~"); | |
3274 | } | |
3275 | expression(150); | |
3276 | return this; | |
3277 | }); | |
3278 | ||
3279 | prefix("...", function () { | |
3280 | if (!state.option.inESNext()) { | |
3281 | warning("W104", this, "spread/rest operator"); | |
3282 | } | |
3283 | if (!state.tokens.next.identifier) { | |
3284 | error("E030", state.tokens.next, state.tokens.next.value); | |
3285 | } | |
3286 | expression(150); | |
3287 | return this; | |
3288 | }); | |
3289 | ||
3290 | prefix("!", function () { | |
3291 | this.right = expression(150); | |
3292 | this.arity = "unary"; | |
3293 | ||
3294 | if (!this.right) { // '!' followed by nothing? Give up. | |
3295 | quit("E041", this.line || 0); | |
3296 | } | |
3297 | ||
3298 | if (bang[this.right.id] === true) { | |
3299 | warning("W018", this, "!"); | |
3300 | } | |
3301 | return this; | |
3302 | }); | |
3303 | ||
3304 | prefix("typeof", "typeof"); | |
3305 | prefix("new", function () { | |
3306 | var c = expression(155), i; | |
3307 | if (c && c.id !== "function") { | |
3308 | if (c.identifier) { | |
3309 | c["new"] = true; | |
3310 | switch (c.value) { | |
3311 | case "Number": | |
3312 | case "String": | |
3313 | case "Boolean": | |
3314 | case "Math": | |
3315 | case "JSON": | |
3316 | warning("W053", state.tokens.prev, c.value); | |
3317 | break; | |
3318 | case "Function": | |
3319 | if (!state.option.evil) { | |
3320 | warning("W054"); | |
3321 | } | |
3322 | break; | |
3323 | case "Date": | |
3324 | case "RegExp": | |
3325 | break; | |
3326 | default: | |
3327 | if (c.id !== "function") { | |
3328 | i = c.value.substr(0, 1); | |
3329 | if (state.option.newcap && (i < "A" || i > "Z") && !_.has(global, c.value)) { | |
3330 | warning("W055", state.tokens.curr); | |
3331 | } | |
3332 | } | |
3333 | } | |
3334 | } else { | |
3335 | if (c.id !== "." && c.id !== "[" && c.id !== "(") { | |
3336 | warning("W056", state.tokens.curr); | |
3337 | } | |
3338 | } | |
3339 | } else { | |
3340 | if (!state.option.supernew) | |
3341 | warning("W057", this); | |
3342 | } | |
3343 | adjacent(state.tokens.curr, state.tokens.next); | |
3344 | if (state.tokens.next.id !== "(" && !state.option.supernew) { | |
3345 | warning("W058", state.tokens.curr, state.tokens.curr.value); | |
3346 | } | |
3347 | this.first = c; | |
3348 | return this; | |
3349 | }); | |
3350 | state.syntax["new"].exps = true; | |
3351 | ||
3352 | prefix("void").exps = true; | |
3353 | ||
3354 | infix(".", function (left, that) { | |
3355 | adjacent(state.tokens.prev, state.tokens.curr); | |
3356 | nobreak(); | |
3357 | var m = identifier(false, true); | |
3358 | ||
3359 | if (typeof m === "string") { | |
3360 | countMember(m); | |
3361 | } | |
3362 | ||
3363 | that.left = left; | |
3364 | that.right = m; | |
3365 | ||
3366 | if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { | |
3367 | warning("W001"); | |
3368 | } | |
3369 | ||
3370 | if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { | |
3371 | if (state.option.noarg) | |
3372 | warning("W059", left, m); | |
3373 | else if (state.directive["use strict"]) | |
3374 | error("E008"); | |
3375 | } else if (!state.option.evil && left && left.value === "document" && | |
3376 | (m === "write" || m === "writeln")) { | |
3377 | warning("W060", left); | |
3378 | } | |
3379 | ||
3380 | if (!state.option.evil && (m === "eval" || m === "execScript")) { | |
3381 | warning("W061"); | |
3382 | } | |
3383 | ||
3384 | return that; | |
3385 | }, 160, true); | |
3386 | ||
3387 | infix("(", function (left, that) { | |
3388 | if (state.tokens.prev.id !== "}" && state.tokens.prev.id !== ")") { | |
3389 | nobreak(state.tokens.prev, state.tokens.curr); | |
3390 | } | |
3391 | ||
3392 | nospace(); | |
3393 | if (state.option.immed && left && !left.immed && left.id === "function") { | |
3394 | warning("W062"); | |
3395 | } | |
3396 | ||
3397 | var n = 0; | |
3398 | var p = []; | |
3399 | ||
3400 | if (left) { | |
3401 | if (left.type === "(identifier)") { | |
3402 | if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { | |
3403 | if ("Number String Boolean Date Object".indexOf(left.value) === -1) { | |
3404 | if (left.value === "Math") { | |
3405 | warning("W063", left); | |
3406 | } else if (state.option.newcap) { | |
3407 | warning("W064", left); | |
3408 | } | |
3409 | } | |
3410 | } | |
3411 | } | |
3412 | } | |
3413 | ||
3414 | if (state.tokens.next.id !== ")") { | |
3415 | for (;;) { | |
3416 | p[p.length] = expression(10); | |
3417 | n += 1; | |
3418 | if (state.tokens.next.id !== ",") { | |
3419 | break; | |
3420 | } | |
3421 | comma(); | |
3422 | } | |
3423 | } | |
3424 | ||
3425 | advance(")"); | |
3426 | nospace(state.tokens.prev, state.tokens.curr); | |
3427 | ||
3428 | if (typeof left === "object") { | |
3429 | if (left.value === "parseInt" && n === 1) { | |
3430 | warning("W065", state.tokens.curr); | |
3431 | } | |
3432 | if (!state.option.evil) { | |
3433 | if (left.value === "eval" || left.value === "Function" || | |
3434 | left.value === "execScript") { | |
3435 | warning("W061", left); | |
3436 | ||
3437 | if (p[0] && [0].id === "(string)") { | |
3438 | addInternalSrc(left, p[0].value); | |
3439 | } | |
3440 | } else if (p[0] && p[0].id === "(string)" && | |
3441 | (left.value === "setTimeout" || | |
3442 | left.value === "setInterval")) { | |
3443 | warning("W066", left); | |
3444 | addInternalSrc(left, p[0].value); | |
3445 | ||
3446 | // window.setTimeout/setInterval | |
3447 | } else if (p[0] && p[0].id === "(string)" && | |
3448 | left.value === "." && | |
3449 | left.left.value === "window" && | |
3450 | (left.right === "setTimeout" || | |
3451 | left.right === "setInterval")) { | |
3452 | warning("W066", left); | |
3453 | addInternalSrc(left, p[0].value); | |
3454 | } | |
3455 | } | |
3456 | if (!left.identifier && left.id !== "." && left.id !== "[" && | |
3457 | left.id !== "(" && left.id !== "&&" && left.id !== "||" && | |
3458 | left.id !== "?") { | |
3459 | warning("W067", left); | |
3460 | } | |
3461 | } | |
3462 | ||
3463 | that.left = left; | |
3464 | return that; | |
3465 | }, 155, true).exps = true; | |
3466 | ||
3467 | prefix("(", function () { | |
3468 | nospace(); | |
3469 | var bracket, brackets = []; | |
3470 | var pn, pn1, i = 0; | |
3471 | var ret; | |
3472 | ||
3473 | do { | |
3474 | pn = peek(i); | |
3475 | i += 1; | |
3476 | pn1 = peek(i); | |
3477 | i += 1; | |
3478 | } while (pn.value !== ")" && pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)"); | |
3479 | ||
3480 | if (state.tokens.next.id === "function") { | |
3481 | state.tokens.next.immed = true; | |
3482 | } | |
3483 | ||
3484 | var exprs = []; | |
3485 | ||
3486 | if (state.tokens.next.id !== ")") { | |
3487 | for (;;) { | |
3488 | if (pn1.value === "=>" && state.tokens.next.value === "{") { | |
3489 | bracket = state.tokens.next; | |
3490 | bracket.left = destructuringExpression(); | |
3491 | brackets.push(bracket); | |
3492 | for (var t in bracket.left) { | |
3493 | exprs.push(bracket.left[t].token); | |
3494 | } | |
3495 | } else { | |
3496 | exprs.push(expression(10)); | |
3497 | } | |
3498 | if (state.tokens.next.id !== ",") { | |
3499 | break; | |
3500 | } | |
3501 | comma(); | |
3502 | } | |
3503 | } | |
3504 | ||
3505 | advance(")", this); | |
3506 | nospace(state.tokens.prev, state.tokens.curr); | |
3507 | if (state.option.immed && exprs[0] && exprs[0].id === "function") { | |
3508 | if (state.tokens.next.id !== "(" && | |
3509 | (state.tokens.next.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { | |
3510 | warning("W068", this); | |
3511 | } | |
3512 | } | |
3513 | ||
3514 | if (state.tokens.next.value === "=>") { | |
3515 | return exprs; | |
3516 | } | |
3517 | if (!exprs.length) { | |
3518 | return; | |
3519 | } | |
3520 | if (exprs.length > 1) { | |
3521 | ret = Object.create(state.syntax[","]); | |
3522 | ret.exprs = exprs; | |
3523 | } else { | |
3524 | ret = exprs[0]; | |
3525 | } | |
3526 | if (ret) { | |
3527 | ret.paren = true; | |
3528 | } | |
3529 | return ret; | |
3530 | }); | |
3531 | ||
3532 | application("=>"); | |
3533 | ||
3534 | infix("[", function (left, that) { | |
3535 | nobreak(state.tokens.prev, state.tokens.curr); | |
3536 | nospace(); | |
3537 | var e = expression(10), s; | |
3538 | if (e && e.type === "(string)") { | |
3539 | if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { | |
3540 | warning("W061", that); | |
3541 | } | |
3542 | ||
3543 | countMember(e.value); | |
3544 | if (!state.option.sub && reg.identifier.test(e.value)) { | |
3545 | s = state.syntax[e.value]; | |
3546 | if (!s || !isReserved(s)) { | |
3547 | warning("W069", state.tokens.prev, e.value); | |
3548 | } | |
3549 | } | |
3550 | } | |
3551 | advance("]", that); | |
3552 | ||
3553 | if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { | |
3554 | warning("W001"); | |
3555 | } | |
3556 | ||
3557 | nospace(state.tokens.prev, state.tokens.curr); | |
3558 | that.left = left; | |
3559 | that.right = e; | |
3560 | return that; | |
3561 | }, 160, true); | |
3562 | ||
3563 | function comprehensiveArrayExpression() { | |
3564 | var res = {}; | |
3565 | res.exps = true; | |
3566 | funct["(comparray)"].stack(); | |
3567 | ||
3568 | res.right = expression(10); | |
3569 | advance("for"); | |
3570 | if (state.tokens.next.value === "each") { | |
3571 | advance("each"); | |
3572 | if (!state.option.inMoz(true)) { | |
3573 | warning("W118", state.tokens.curr, "for each"); | |
3574 | } | |
3575 | } | |
3576 | advance("("); | |
3577 | funct["(comparray)"].setState("define"); | |
3578 | res.left = expression(10); | |
3579 | advance(")"); | |
3580 | if (state.tokens.next.value === "if") { | |
3581 | advance("if"); | |
3582 | advance("("); | |
3583 | funct["(comparray)"].setState("filter"); | |
3584 | res.filter = expression(10); | |
3585 | advance(")"); | |
3586 | } | |
3587 | advance("]"); | |
3588 | funct["(comparray)"].unstack(); | |
3589 | return res; | |
3590 | } | |
3591 | ||
3592 | prefix("[", function () { | |
3593 | var blocktype = lookupBlockType(true); | |
3594 | if (blocktype.isCompArray) { | |
3595 | if (!state.option.inMoz(true)) { | |
3596 | warning("W118", state.tokens.curr, "array comprehension"); | |
3597 | } | |
3598 | return comprehensiveArrayExpression(); | |
3599 | } else if (blocktype.isDestAssign && !state.option.inESNext()) { | |
3600 | warning("W104", state.tokens.curr, "destructuring assignment"); | |
3601 | } | |
3602 | var b = state.tokens.curr.line !== state.tokens.next.line; | |
3603 | this.first = []; | |
3604 | if (b) { | |
3605 | indent += state.option.indent; | |
3606 | if (state.tokens.next.from === indent + state.option.indent) { | |
3607 | indent += state.option.indent; | |
3608 | } | |
3609 | } | |
3610 | while (state.tokens.next.id !== "(end)") { | |
3611 | while (state.tokens.next.id === ",") { | |
3612 | if (!state.option.inES5()) | |
3613 | warning("W070"); | |
3614 | advance(","); | |
3615 | } | |
3616 | if (state.tokens.next.id === "]") { | |
3617 | break; | |
3618 | } | |
3619 | if (b && state.tokens.curr.line !== state.tokens.next.line) { | |
3620 | indentation(); | |
3621 | } | |
3622 | this.first.push(expression(10)); | |
3623 | if (state.tokens.next.id === ",") { | |
3624 | comma({ allowTrailing: true }); | |
3625 | if (state.tokens.next.id === "]" && !state.option.inES5(true)) { | |
3626 | warning("W070", state.tokens.curr); | |
3627 | break; | |
3628 | } | |
3629 | } else { | |
3630 | break; | |
3631 | } | |
3632 | } | |
3633 | if (b) { | |
3634 | indent -= state.option.indent; | |
3635 | indentation(); | |
3636 | } | |
3637 | advance("]", this); | |
3638 | return this; | |
3639 | }, 160); | |
3640 | ||
3641 | ||
3642 | function property_name() { | |
3643 | var id = optionalidentifier(false, true); | |
3644 | ||
3645 | if (!id) { | |
3646 | if (state.tokens.next.id === "(string)") { | |
3647 | id = state.tokens.next.value; | |
3648 | advance(); | |
3649 | } else if (state.tokens.next.id === "(number)") { | |
3650 | id = state.tokens.next.value.toString(); | |
3651 | advance(); | |
3652 | } | |
3653 | } | |
3654 | ||
3655 | if (id === "hasOwnProperty") { | |
3656 | warning("W001"); | |
3657 | } | |
3658 | ||
3659 | return id; | |
3660 | } | |
3661 | ||
3662 | ||
3663 | function functionparams(parsed) { | |
3664 | var curr, next; | |
3665 | var params = []; | |
3666 | var ident; | |
3667 | var tokens = []; | |
3668 | var t; | |
3669 | var pastDefault = false; | |
3670 | ||
3671 | if (parsed) { | |
3672 | if (parsed instanceof Array) { | |
3673 | for (var i in parsed) { | |
3674 | curr = parsed[i]; | |
3675 | if (_.contains(["{", "["], curr.id)) { | |
3676 | for (t in curr.left) { | |
3677 | t = tokens[t]; | |
3678 | if (t.id) { | |
3679 | params.push(t.id); | |
3680 | addlabel(t.id, "unused", t.token); | |
3681 | } | |
3682 | } | |
3683 | } else if (curr.value === "...") { | |
3684 | if (!state.option.inESNext()) { | |
3685 | warning("W104", curr, "spread/rest operator"); | |
3686 | } | |
3687 | continue; | |
3688 | } else { | |
3689 | addlabel(curr.value, "unused", curr); | |
3690 | } | |
3691 | } | |
3692 | return params; | |
3693 | } else { | |
3694 | if (parsed.identifier === true) { | |
3695 | addlabel(parsed.value, "unused", parsed); | |
3696 | return [parsed]; | |
3697 | } | |
3698 | } | |
3699 | } | |
3700 | ||
3701 | next = state.tokens.next; | |
3702 | ||
3703 | advance("("); | |
3704 | nospace(); | |
3705 | ||
3706 | if (state.tokens.next.id === ")") { | |
3707 | advance(")"); | |
3708 | return; | |
3709 | } | |
3710 | ||
3711 | for (;;) { | |
3712 | if (_.contains(["{", "["], state.tokens.next.id)) { | |
3713 | tokens = destructuringExpression(); | |
3714 | for (t in tokens) { | |
3715 | t = tokens[t]; | |
3716 | if (t.id) { | |
3717 | params.push(t.id); | |
3718 | addlabel(t.id, "unused", t.token); | |
3719 | } | |
3720 | } | |
3721 | } else if (state.tokens.next.value === "...") { | |
3722 | if (!state.option.inESNext()) { | |
3723 | warning("W104", state.tokens.next, "spread/rest operator"); | |
3724 | } | |
3725 | advance("..."); | |
3726 | nospace(); | |
3727 | ident = identifier(true); | |
3728 | params.push(ident); | |
3729 | addlabel(ident, "unused", state.tokens.curr); | |
3730 | } else { | |
3731 | ident = identifier(true); | |
3732 | params.push(ident); | |
3733 | addlabel(ident, "unused", state.tokens.curr); | |
3734 | } | |
3735 | ||
3736 | // it is a syntax error to have a regular argument after a default argument | |
3737 | if (pastDefault) { | |
3738 | if (state.tokens.next.id !== "=") { | |
3739 | error("E051", state.tokens.current); | |
3740 | } | |
3741 | } | |
3742 | if (state.tokens.next.id === "=") { | |
3743 | if (!state.option.inESNext()) { | |
3744 | warning("W119", state.tokens.next, "default parameters"); | |
3745 | } | |
3746 | advance("="); | |
3747 | pastDefault = true; | |
3748 | expression(10); | |
3749 | } | |
3750 | if (state.tokens.next.id === ",") { | |
3751 | comma(); | |
3752 | } else { | |
3753 | advance(")", next); | |
3754 | nospace(state.tokens.prev, state.tokens.curr); | |
3755 | return params; | |
3756 | } | |
3757 | } | |
3758 | } | |
3759 | ||
3760 | ||
3761 | function doFunction(name, statement, generator, fatarrowparams) { | |
3762 | var f; | |
3763 | var oldOption = state.option; | |
3764 | var oldIgnored = state.ignored; | |
3765 | var oldScope = scope; | |
3766 | ||
3767 | state.option = Object.create(state.option); | |
3768 | state.ignored = Object.create(state.ignored); | |
3769 | scope = Object.create(scope); | |
3770 | ||
3771 | funct = { | |
3772 | "(name)" : name || "\"" + anonname + "\"", | |
3773 | "(line)" : state.tokens.next.line, | |
3774 | "(character)" : state.tokens.next.character, | |
3775 | "(context)" : funct, | |
3776 | "(breakage)" : 0, | |
3777 | "(loopage)" : 0, | |
3778 | "(metrics)" : createMetrics(state.tokens.next), | |
3779 | "(scope)" : scope, | |
3780 | "(statement)" : statement, | |
3781 | "(tokens)" : {}, | |
3782 | "(blockscope)": funct["(blockscope)"], | |
3783 | "(comparray)" : funct["(comparray)"] | |
3784 | }; | |
3785 | ||
3786 | if (generator) { | |
3787 | funct["(generator)"] = true; | |
3788 | } | |
3789 | ||
3790 | f = funct; | |
3791 | state.tokens.curr.funct = funct; | |
3792 | ||
3793 | functions.push(funct); | |
3794 | ||
3795 | if (name) { | |
3796 | addlabel(name, "function"); | |
3797 | } | |
3798 | ||
3799 | funct["(params)"] = functionparams(fatarrowparams); | |
3800 | ||
3801 | funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]); | |
3802 | ||
3803 | block(false, true, true, fatarrowparams ? true:false); | |
3804 | ||
3805 | if (generator && funct["(generator)"] !== "yielded") { | |
3806 | error("E047", state.tokens.curr); | |
3807 | } | |
3808 | ||
3809 | funct["(metrics)"].verifyMaxStatementsPerFunction(); | |
3810 | funct["(metrics)"].verifyMaxComplexityPerFunction(); | |
3811 | funct["(unusedOption)"] = state.option.unused; | |
3812 | ||
3813 | scope = oldScope; | |
3814 | state.option = oldOption; | |
3815 | state.ignored = oldIgnored; | |
3816 | funct["(last)"] = state.tokens.curr.line; | |
3817 | funct["(lastcharacter)"] = state.tokens.curr.character; | |
3818 | funct = funct["(context)"]; | |
3819 | ||
3820 | return f; | |
3821 | } | |
3822 | ||
3823 | function createMetrics(functionStartToken) { | |
3824 | return { | |
3825 | statementCount: 0, | |
3826 | nestedBlockDepth: -1, | |
3827 | ComplexityCount: 1, | |
3828 | verifyMaxStatementsPerFunction: function () { | |
3829 | if (state.option.maxstatements && | |
3830 | this.statementCount > state.option.maxstatements) { | |
3831 | warning("W071", functionStartToken, this.statementCount); | |
3832 | } | |
3833 | }, | |
3834 | ||
3835 | verifyMaxParametersPerFunction: function (params) { | |
3836 | params = params || []; | |
3837 | ||
3838 | if (state.option.maxparams && params.length > state.option.maxparams) { | |
3839 | warning("W072", functionStartToken, params.length); | |
3840 | } | |
3841 | }, | |
3842 | ||
3843 | verifyMaxNestedBlockDepthPerFunction: function () { | |
3844 | if (state.option.maxdepth && | |
3845 | this.nestedBlockDepth > 0 && | |
3846 | this.nestedBlockDepth === state.option.maxdepth + 1) { | |
3847 | warning("W073", null, this.nestedBlockDepth); | |
3848 | } | |
3849 | }, | |
3850 | ||
3851 | verifyMaxComplexityPerFunction: function () { | |
3852 | var max = state.option.maxcomplexity; | |
3853 | var cc = this.ComplexityCount; | |
3854 | if (max && cc > max) { | |
3855 | warning("W074", functionStartToken, cc); | |
3856 | } | |
3857 | } | |
3858 | }; | |
3859 | } | |
3860 | ||
3861 | function increaseComplexityCount() { | |
3862 | funct["(metrics)"].ComplexityCount += 1; | |
3863 | } | |
3864 | ||
3865 | // Parse assignments that were found instead of conditionals. | |
3866 | // For example: if (a = 1) { ... } | |
3867 | ||
3868 | function checkCondAssignment(expr) { | |
3869 | var id, paren; | |
3870 | if (expr) { | |
3871 | id = expr.id; | |
3872 | paren = expr.paren; | |
3873 | if (id === "," && (expr = expr.exprs[expr.exprs.length - 1])) { | |
3874 | id = expr.id; | |
3875 | paren = paren || expr.paren; | |
3876 | } | |
3877 | } | |
3878 | switch (id) { | |
3879 | case "=": | |
3880 | case "+=": | |
3881 | case "-=": | |
3882 | case "*=": | |
3883 | case "%=": | |
3884 | case "&=": | |
3885 | case "|=": | |
3886 | case "^=": | |
3887 | case "/=": | |
3888 | if (!paren && !state.option.boss) { | |
3889 | warning("W084"); | |
3890 | } | |
3891 | } | |
3892 | } | |
3893 | ||
3894 | ||
3895 | (function (x) { | |
3896 | x.nud = function (isclassdef) { | |
3897 | var b, f, i, p, t, g; | |
3898 | var props = {}; // All properties, including accessors | |
3899 | var tag = ""; | |
3900 | ||
3901 | function saveProperty(name, tkn) { | |
3902 | if (props[name] && _.has(props, name)) | |
3903 | warning("W075", state.tokens.next, i); | |
3904 | else | |
3905 | props[name] = {}; | |
3906 | ||
3907 | props[name].basic = true; | |
3908 | props[name].basictkn = tkn; | |
3909 | } | |
3910 | ||
3911 | function saveSetter(name, tkn) { | |
3912 | if (props[name] && _.has(props, name)) { | |
3913 | if (props[name].basic || props[name].setter) | |
3914 | warning("W075", state.tokens.next, i); | |
3915 | } else { | |
3916 | props[name] = {}; | |
3917 | } | |
3918 | ||
3919 | props[name].setter = true; | |
3920 | props[name].setterToken = tkn; | |
3921 | } | |
3922 | ||
3923 | function saveGetter(name) { | |
3924 | if (props[name] && _.has(props, name)) { | |
3925 | if (props[name].basic || props[name].getter) | |
3926 | warning("W075", state.tokens.next, i); | |
3927 | } else { | |
3928 | props[name] = {}; | |
3929 | } | |
3930 | ||
3931 | props[name].getter = true; | |
3932 | props[name].getterToken = state.tokens.curr; | |
3933 | } | |
3934 | ||
3935 | b = state.tokens.curr.line !== state.tokens.next.line; | |
3936 | if (b) { | |
3937 | indent += state.option.indent; | |
3938 | if (state.tokens.next.from === indent + state.option.indent) { | |
3939 | indent += state.option.indent; | |
3940 | } | |
3941 | } | |
3942 | ||
3943 | for (;;) { | |
3944 | if (state.tokens.next.id === "}") { | |
3945 | break; | |
3946 | } | |
3947 | ||
3948 | if (b) { | |
3949 | indentation(); | |
3950 | } | |
3951 | ||
3952 | if (isclassdef && state.tokens.next.value === "static") { | |
3953 | advance("static"); | |
3954 | tag = "static "; | |
3955 | } | |
3956 | ||
3957 | if (state.tokens.next.value === "get" && peek().id !== ":") { | |
3958 | advance("get"); | |
3959 | ||
3960 | if (!state.option.inES5(!isclassdef)) { | |
3961 | error("E034"); | |
3962 | } | |
3963 | ||
3964 | i = property_name(); | |
3965 | if (!i) { | |
3966 | error("E035"); | |
3967 | } | |
3968 | ||
3969 | // It is a Syntax Error if PropName of MethodDefinition is | |
3970 | // "constructor" and SpecialMethod of MethodDefinition is true. | |
3971 | if (isclassdef && i === "constructor") { | |
3972 | error("E049", state.tokens.next, "class getter method", i); | |
3973 | } | |
3974 | ||
3975 | saveGetter(tag + i); | |
3976 | t = state.tokens.next; | |
3977 | adjacent(state.tokens.curr, state.tokens.next); | |
3978 | f = doFunction(); | |
3979 | p = f["(params)"]; | |
3980 | ||
3981 | if (p) { | |
3982 | warning("W076", t, p[0], i); | |
3983 | } | |
3984 | ||
3985 | adjacent(state.tokens.curr, state.tokens.next); | |
3986 | } else if (state.tokens.next.value === "set" && peek().id !== ":") { | |
3987 | advance("set"); | |
3988 | ||
3989 | if (!state.option.inES5(!isclassdef)) { | |
3990 | error("E034"); | |
3991 | } | |
3992 | ||
3993 | i = property_name(); | |
3994 | if (!i) { | |
3995 | error("E035"); | |
3996 | } | |
3997 | ||
3998 | // It is a Syntax Error if PropName of MethodDefinition is | |
3999 | // "constructor" and SpecialMethod of MethodDefinition is true. | |
4000 | if (isclassdef && i === "constructor") { | |
4001 | error("E049", state.tokens.next, "class setter method", i); | |
4002 | } | |
4003 | ||
4004 | saveSetter(tag + i, state.tokens.next); | |
4005 | t = state.tokens.next; | |
4006 | adjacent(state.tokens.curr, state.tokens.next); | |
4007 | f = doFunction(); | |
4008 | p = f["(params)"]; | |
4009 | ||
4010 | if (!p || p.length !== 1) { | |
4011 | warning("W077", t, i); | |
4012 | } | |
4013 | } else { | |
4014 | g = false; | |
4015 | if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { | |
4016 | if (!state.option.inESNext()) { | |
4017 | warning("W104", state.tokens.next, "generator functions"); | |
4018 | } | |
4019 | advance("*"); | |
4020 | g = true; | |
4021 | } | |
4022 | i = property_name(); | |
4023 | saveProperty(tag + i, state.tokens.next); | |
4024 | ||
4025 | if (typeof i !== "string") { | |
4026 | break; | |
4027 | } | |
4028 | ||
4029 | if (state.tokens.next.value === "(") { | |
4030 | if (!state.option.inESNext()) { | |
4031 | warning("W104", state.tokens.curr, "concise methods"); | |
4032 | } | |
4033 | doFunction(i, undefined, g); | |
4034 | } else if (!isclassdef) { | |
4035 | advance(":"); | |
4036 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4037 | expression(10); | |
4038 | } | |
4039 | } | |
4040 | // It is a Syntax Error if PropName of MethodDefinition is "prototype". | |
4041 | if (isclassdef && i === "prototype") { | |
4042 | error("E049", state.tokens.next, "class method", i); | |
4043 | } | |
4044 | ||
4045 | countMember(i); | |
4046 | if (isclassdef) { | |
4047 | tag = ""; | |
4048 | continue; | |
4049 | } | |
4050 | if (state.tokens.next.id === ",") { | |
4051 | comma({ allowTrailing: true, property: true }); | |
4052 | if (state.tokens.next.id === ",") { | |
4053 | warning("W070", state.tokens.curr); | |
4054 | } else if (state.tokens.next.id === "}" && !state.option.inES5(true)) { | |
4055 | warning("W070", state.tokens.curr); | |
4056 | } | |
4057 | } else { | |
4058 | break; | |
4059 | } | |
4060 | } | |
4061 | if (b) { | |
4062 | indent -= state.option.indent; | |
4063 | indentation(); | |
4064 | } | |
4065 | advance("}", this); | |
4066 | ||
4067 | // Check for lonely setters if in the ES5 mode. | |
4068 | if (state.option.inES5()) { | |
4069 | for (var name in props) { | |
4070 | if (_.has(props, name) && props[name].setter && !props[name].getter) { | |
4071 | warning("W078", props[name].setterToken); | |
4072 | } | |
4073 | } | |
4074 | } | |
4075 | return this; | |
4076 | }; | |
4077 | x.fud = function () { | |
4078 | error("E036", state.tokens.curr); | |
4079 | }; | |
4080 | }(delim("{"))); | |
4081 | ||
4082 | function destructuringExpression() { | |
4083 | var id, ids; | |
4084 | var identifiers = []; | |
4085 | if (!state.option.inESNext()) { | |
4086 | warning("W104", state.tokens.curr, "destructuring expression"); | |
4087 | } | |
4088 | var nextInnerDE = function () { | |
4089 | var ident; | |
4090 | if (_.contains(["[", "{"], state.tokens.next.value)) { | |
4091 | ids = destructuringExpression(); | |
4092 | for (var id in ids) { | |
4093 | id = ids[id]; | |
4094 | identifiers.push({ id: id.id, token: id.token }); | |
4095 | } | |
4096 | } else if (state.tokens.next.value === ",") { | |
4097 | identifiers.push({ id: null, token: state.tokens.curr }); | |
4098 | } else { | |
4099 | ident = identifier(); | |
4100 | if (ident) | |
4101 | identifiers.push({ id: ident, token: state.tokens.curr }); | |
4102 | } | |
4103 | }; | |
4104 | if (state.tokens.next.value === "[") { | |
4105 | advance("["); | |
4106 | nextInnerDE(); | |
4107 | while (state.tokens.next.value !== "]") { | |
4108 | advance(","); | |
4109 | nextInnerDE(); | |
4110 | } | |
4111 | advance("]"); | |
4112 | } else if (state.tokens.next.value === "{") { | |
4113 | advance("{"); | |
4114 | id = identifier(); | |
4115 | if (state.tokens.next.value === ":") { | |
4116 | advance(":"); | |
4117 | nextInnerDE(); | |
4118 | } else { | |
4119 | identifiers.push({ id: id, token: state.tokens.curr }); | |
4120 | } | |
4121 | while (state.tokens.next.value !== "}") { | |
4122 | advance(","); | |
4123 | id = identifier(); | |
4124 | if (state.tokens.next.value === ":") { | |
4125 | advance(":"); | |
4126 | nextInnerDE(); | |
4127 | } else { | |
4128 | identifiers.push({ id: id, token: state.tokens.curr }); | |
4129 | } | |
4130 | } | |
4131 | advance("}"); | |
4132 | } | |
4133 | return identifiers; | |
4134 | } | |
4135 | function destructuringExpressionMatch(tokens, value) { | |
4136 | if (value.first) { | |
4137 | _.zip(tokens, value.first).forEach(function (val) { | |
4138 | var token = val[0]; | |
4139 | var value = val[1]; | |
4140 | if (token && value) { | |
4141 | token.first = value; | |
4142 | } else if (token && token.first && !value) { | |
4143 | warning("W080", token.first, token.first.value); | |
4144 | } /* else { | |
4145 | XXX value is discarded: wouldn't it need a warning ? | |
4146 | } */ | |
4147 | }); | |
4148 | } | |
4149 | } | |
4150 | ||
4151 | var conststatement = stmt("const", function (prefix) { | |
4152 | var tokens, value; | |
4153 | // state variable to know if it is a lone identifier, or a destructuring statement. | |
4154 | var lone; | |
4155 | ||
4156 | if (!state.option.inESNext()) { | |
4157 | warning("W104", state.tokens.curr, "const"); | |
4158 | } | |
4159 | ||
4160 | this.first = []; | |
4161 | for (;;) { | |
4162 | var names = []; | |
4163 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4164 | if (_.contains(["{", "["], state.tokens.next.value)) { | |
4165 | tokens = destructuringExpression(); | |
4166 | lone = false; | |
4167 | } else { | |
4168 | tokens = [ { id: identifier(), token: state.tokens.curr } ]; | |
4169 | lone = true; | |
4170 | } | |
4171 | for (var t in tokens) { | |
4172 | t = tokens[t]; | |
4173 | if (funct[t.id] === "const") { | |
4174 | warning("E011", null, t.id); | |
4175 | } | |
4176 | if (funct["(global)"] && predefined[t.id] === false) { | |
4177 | warning("W079", t.token, t.id); | |
4178 | } | |
4179 | if (t.id) { | |
4180 | addlabel(t.id, "const"); | |
4181 | names.push(t.token); | |
4182 | } | |
4183 | } | |
4184 | if (prefix) { | |
4185 | break; | |
4186 | } | |
4187 | ||
4188 | this.first = this.first.concat(names); | |
4189 | ||
4190 | if (state.tokens.next.id !== "=") { | |
4191 | warning("E012", state.tokens.curr, state.tokens.curr.value); | |
4192 | } | |
4193 | ||
4194 | if (state.tokens.next.id === "=") { | |
4195 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4196 | advance("="); | |
4197 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4198 | if (state.tokens.next.id === "undefined") { | |
4199 | warning("W080", state.tokens.prev, state.tokens.prev.value); | |
4200 | } | |
4201 | if (peek(0).id === "=" && state.tokens.next.identifier) { | |
4202 | warning("W120", state.tokens.next, state.tokens.next.value); | |
4203 | } | |
4204 | value = expression(10); | |
4205 | if (lone) { | |
4206 | tokens[0].first = value; | |
4207 | } else { | |
4208 | destructuringExpressionMatch(names, value); | |
4209 | } | |
4210 | } | |
4211 | ||
4212 | if (state.tokens.next.id !== ",") { | |
4213 | break; | |
4214 | } | |
4215 | comma(); | |
4216 | } | |
4217 | return this; | |
4218 | }); | |
4219 | conststatement.exps = true; | |
4220 | var varstatement = stmt("var", function (prefix) { | |
4221 | // JavaScript does not have block scope. It only has function scope. So, | |
4222 | // declaring a variable in a block can have unexpected consequences. | |
4223 | var tokens, lone, value; | |
4224 | ||
4225 | if (funct["(onevar)"] && state.option.onevar) { | |
4226 | warning("W081"); | |
4227 | } else if (!funct["(global)"]) { | |
4228 | funct["(onevar)"] = true; | |
4229 | } | |
4230 | ||
4231 | this.first = []; | |
4232 | for (;;) { | |
4233 | var names = []; | |
4234 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4235 | if (_.contains(["{", "["], state.tokens.next.value)) { | |
4236 | tokens = destructuringExpression(); | |
4237 | lone = false; | |
4238 | } else { | |
4239 | tokens = [ { id: identifier(), token: state.tokens.curr } ]; | |
4240 | lone = true; | |
4241 | } | |
4242 | for (var t in tokens) { | |
4243 | t = tokens[t]; | |
4244 | if (state.option.inESNext() && funct[t.id] === "const") { | |
4245 | warning("E011", null, t.id); | |
4246 | } | |
4247 | if (funct["(global)"] && predefined[t.id] === false) { | |
4248 | warning("W079", t.token, t.id); | |
4249 | } | |
4250 | if (t.id) { | |
4251 | addlabel(t.id, "unused", t.token); | |
4252 | names.push(t.token); | |
4253 | } | |
4254 | } | |
4255 | if (prefix) { | |
4256 | break; | |
4257 | } | |
4258 | ||
4259 | this.first = this.first.concat(names); | |
4260 | ||
4261 | if (state.tokens.next.id === "=") { | |
4262 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4263 | advance("="); | |
4264 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4265 | if (state.tokens.next.id === "undefined") { | |
4266 | warning("W080", state.tokens.prev, state.tokens.prev.value); | |
4267 | } | |
4268 | if (peek(0).id === "=" && state.tokens.next.identifier) { | |
4269 | warning("W120", state.tokens.next, state.tokens.next.value); | |
4270 | } | |
4271 | value = expression(10); | |
4272 | if (lone) { | |
4273 | tokens[0].first = value; | |
4274 | } else { | |
4275 | destructuringExpressionMatch(names, value); | |
4276 | } | |
4277 | } | |
4278 | ||
4279 | if (state.tokens.next.id !== ",") { | |
4280 | break; | |
4281 | } | |
4282 | comma(); | |
4283 | } | |
4284 | return this; | |
4285 | }); | |
4286 | varstatement.exps = true; | |
4287 | var letstatement = stmt("let", function (prefix) { | |
4288 | var tokens, lone, value, letblock; | |
4289 | ||
4290 | if (!state.option.inESNext()) { | |
4291 | warning("W104", state.tokens.curr, "let"); | |
4292 | } | |
4293 | ||
4294 | if (state.tokens.next.value === "(") { | |
4295 | if (!state.option.inMoz(true)) { | |
4296 | warning("W118", state.tokens.next, "let block"); | |
4297 | } | |
4298 | advance("("); | |
4299 | funct["(blockscope)"].stack(); | |
4300 | letblock = true; | |
4301 | } else if (funct["(nolet)"]) { | |
4302 | error("E048", state.tokens.curr); | |
4303 | } | |
4304 | ||
4305 | if (funct["(onevar)"] && state.option.onevar) { | |
4306 | warning("W081"); | |
4307 | } else if (!funct["(global)"]) { | |
4308 | funct["(onevar)"] = true; | |
4309 | } | |
4310 | ||
4311 | this.first = []; | |
4312 | for (;;) { | |
4313 | var names = []; | |
4314 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4315 | if (_.contains(["{", "["], state.tokens.next.value)) { | |
4316 | tokens = destructuringExpression(); | |
4317 | lone = false; | |
4318 | } else { | |
4319 | tokens = [ { id: identifier(), token: state.tokens.curr.value } ]; | |
4320 | lone = true; | |
4321 | } | |
4322 | for (var t in tokens) { | |
4323 | t = tokens[t]; | |
4324 | if (state.option.inESNext() && funct[t.id] === "const") { | |
4325 | warning("E011", null, t.id); | |
4326 | } | |
4327 | if (funct["(global)"] && predefined[t.id] === false) { | |
4328 | warning("W079", t.token, t.id); | |
4329 | } | |
4330 | if (t.id && !funct["(nolet)"]) { | |
4331 | addlabel(t.id, "unused", t.token, true); | |
4332 | names.push(t.token); | |
4333 | } | |
4334 | } | |
4335 | if (prefix) { | |
4336 | break; | |
4337 | } | |
4338 | ||
4339 | this.first = this.first.concat(names); | |
4340 | ||
4341 | if (state.tokens.next.id === "=") { | |
4342 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4343 | advance("="); | |
4344 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4345 | if (state.tokens.next.id === "undefined") { | |
4346 | warning("W080", state.tokens.prev, state.tokens.prev.value); | |
4347 | } | |
4348 | if (peek(0).id === "=" && state.tokens.next.identifier) { | |
4349 | warning("W120", state.tokens.next, state.tokens.next.value); | |
4350 | } | |
4351 | value = expression(10); | |
4352 | if (lone) { | |
4353 | tokens[0].first = value; | |
4354 | } else { | |
4355 | destructuringExpressionMatch(names, value); | |
4356 | } | |
4357 | } | |
4358 | ||
4359 | if (state.tokens.next.id !== ",") { | |
4360 | break; | |
4361 | } | |
4362 | comma(); | |
4363 | } | |
4364 | if (letblock) { | |
4365 | advance(")"); | |
4366 | block(true, true); | |
4367 | this.block = true; | |
4368 | funct["(blockscope)"].unstack(); | |
4369 | } | |
4370 | ||
4371 | return this; | |
4372 | }); | |
4373 | letstatement.exps = true; | |
4374 | ||
4375 | blockstmt("class", function () { | |
4376 | return classdef.call(this, true); | |
4377 | }); | |
4378 | ||
4379 | function classdef(stmt) { | |
4380 | /*jshint validthis:true */ | |
4381 | if (!state.option.inESNext()) { | |
4382 | warning("W104", state.tokens.curr, "class"); | |
4383 | } | |
4384 | if (stmt) { | |
4385 | // BindingIdentifier | |
4386 | this.name = identifier(); | |
4387 | addlabel(this.name, "unused", state.tokens.curr); | |
4388 | } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { | |
4389 | // BindingIdentifier(opt) | |
4390 | this.name = identifier(); | |
4391 | } | |
4392 | classtail(this); | |
4393 | return this; | |
4394 | } | |
4395 | ||
4396 | function classtail(c) { | |
4397 | var strictness = state.directive["use strict"]; | |
4398 | ||
4399 | // ClassHeritage(opt) | |
4400 | if (state.tokens.next.value === "extends") { | |
4401 | advance("extends"); | |
4402 | c.heritage = expression(10); | |
4403 | } | |
4404 | ||
4405 | // A ClassBody is always strict code. | |
4406 | state.directive["use strict"] = true; | |
4407 | advance("{"); | |
4408 | // ClassBody(opt) | |
4409 | c.body = state.syntax["{"].nud(true); | |
4410 | state.directive["use strict"] = strictness; | |
4411 | } | |
4412 | ||
4413 | blockstmt("function", function () { | |
4414 | var generator = false; | |
4415 | if (state.tokens.next.value === "*") { | |
4416 | advance("*"); | |
4417 | if (state.option.inESNext(true)) { | |
4418 | generator = true; | |
4419 | } else { | |
4420 | warning("W119", state.tokens.curr, "function*"); | |
4421 | } | |
4422 | } | |
4423 | if (inblock) { | |
4424 | warning("W082", state.tokens.curr); | |
4425 | ||
4426 | } | |
4427 | var i = identifier(); | |
4428 | if (funct[i] === "const") { | |
4429 | warning("E011", null, i); | |
4430 | } | |
4431 | adjacent(state.tokens.curr, state.tokens.next); | |
4432 | addlabel(i, "unction", state.tokens.curr); | |
4433 | ||
4434 | doFunction(i, { statement: true }, generator); | |
4435 | if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { | |
4436 | error("E039"); | |
4437 | } | |
4438 | return this; | |
4439 | }); | |
4440 | ||
4441 | prefix("function", function () { | |
4442 | var generator = false; | |
4443 | if (state.tokens.next.value === "*") { | |
4444 | if (!state.option.inESNext()) { | |
4445 | warning("W119", state.tokens.curr, "function*"); | |
4446 | } | |
4447 | advance("*"); | |
4448 | generator = true; | |
4449 | } | |
4450 | var i = optionalidentifier(); | |
4451 | if (i || state.option.gcl) { | |
4452 | adjacent(state.tokens.curr, state.tokens.next); | |
4453 | } else { | |
4454 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4455 | } | |
4456 | doFunction(i, undefined, generator); | |
4457 | if (!state.option.loopfunc && funct["(loopage)"]) { | |
4458 | warning("W083"); | |
4459 | } | |
4460 | return this; | |
4461 | }); | |
4462 | ||
4463 | blockstmt("if", function () { | |
4464 | var t = state.tokens.next; | |
4465 | increaseComplexityCount(); | |
4466 | state.condition = true; | |
4467 | advance("("); | |
4468 | nonadjacent(this, t); | |
4469 | nospace(); | |
4470 | checkCondAssignment(expression(0)); | |
4471 | advance(")", t); | |
4472 | state.condition = false; | |
4473 | nospace(state.tokens.prev, state.tokens.curr); | |
4474 | block(true, true); | |
4475 | if (state.tokens.next.id === "else") { | |
4476 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4477 | advance("else"); | |
4478 | if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { | |
4479 | statement(true); | |
4480 | } else { | |
4481 | block(true, true); | |
4482 | } | |
4483 | } | |
4484 | return this; | |
4485 | }); | |
4486 | ||
4487 | blockstmt("try", function () { | |
4488 | var b; | |
4489 | ||
4490 | function doCatch() { | |
4491 | var oldScope = scope; | |
4492 | var e; | |
4493 | ||
4494 | advance("catch"); | |
4495 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4496 | advance("("); | |
4497 | ||
4498 | scope = Object.create(oldScope); | |
4499 | ||
4500 | e = state.tokens.next.value; | |
4501 | if (state.tokens.next.type !== "(identifier)") { | |
4502 | e = null; | |
4503 | warning("E030", state.tokens.next, e); | |
4504 | } | |
4505 | ||
4506 | advance(); | |
4507 | ||
4508 | funct = { | |
4509 | "(name)" : "(catch)", | |
4510 | "(line)" : state.tokens.next.line, | |
4511 | "(character)": state.tokens.next.character, | |
4512 | "(context)" : funct, | |
4513 | "(breakage)" : funct["(breakage)"], | |
4514 | "(loopage)" : funct["(loopage)"], | |
4515 | "(scope)" : scope, | |
4516 | "(statement)": false, | |
4517 | "(metrics)" : createMetrics(state.tokens.next), | |
4518 | "(catch)" : true, | |
4519 | "(tokens)" : {}, | |
4520 | "(blockscope)": funct["(blockscope)"], | |
4521 | "(comparray)": funct["(comparray)"] | |
4522 | }; | |
4523 | ||
4524 | if (e) { | |
4525 | addlabel(e, "exception"); | |
4526 | } | |
4527 | ||
4528 | if (state.tokens.next.value === "if") { | |
4529 | if (!state.option.inMoz(true)) { | |
4530 | warning("W118", state.tokens.curr, "catch filter"); | |
4531 | } | |
4532 | advance("if"); | |
4533 | expression(0); | |
4534 | } | |
4535 | ||
4536 | advance(")"); | |
4537 | ||
4538 | state.tokens.curr.funct = funct; | |
4539 | functions.push(funct); | |
4540 | ||
4541 | block(false); | |
4542 | ||
4543 | scope = oldScope; | |
4544 | ||
4545 | funct["(last)"] = state.tokens.curr.line; | |
4546 | funct["(lastcharacter)"] = state.tokens.curr.character; | |
4547 | funct = funct["(context)"]; | |
4548 | } | |
4549 | ||
4550 | block(false); | |
4551 | ||
4552 | while (state.tokens.next.id === "catch") { | |
4553 | increaseComplexityCount(); | |
4554 | if (b && (!state.option.inMoz(true))) { | |
4555 | warning("W118", state.tokens.next, "multiple catch blocks"); | |
4556 | } | |
4557 | doCatch(); | |
4558 | b = true; | |
4559 | } | |
4560 | ||
4561 | if (state.tokens.next.id === "finally") { | |
4562 | advance("finally"); | |
4563 | block(false); | |
4564 | return; | |
4565 | } | |
4566 | ||
4567 | if (!b) { | |
4568 | error("E021", state.tokens.next, "catch", state.tokens.next.value); | |
4569 | } | |
4570 | ||
4571 | return this; | |
4572 | }); | |
4573 | ||
4574 | blockstmt("while", function () { | |
4575 | var t = state.tokens.next; | |
4576 | funct["(breakage)"] += 1; | |
4577 | funct["(loopage)"] += 1; | |
4578 | increaseComplexityCount(); | |
4579 | advance("("); | |
4580 | nonadjacent(this, t); | |
4581 | nospace(); | |
4582 | checkCondAssignment(expression(0)); | |
4583 | advance(")", t); | |
4584 | nospace(state.tokens.prev, state.tokens.curr); | |
4585 | block(true, true); | |
4586 | funct["(breakage)"] -= 1; | |
4587 | funct["(loopage)"] -= 1; | |
4588 | return this; | |
4589 | }).labelled = true; | |
4590 | ||
4591 | blockstmt("with", function () { | |
4592 | var t = state.tokens.next; | |
4593 | if (state.directive["use strict"]) { | |
4594 | error("E010", state.tokens.curr); | |
4595 | } else if (!state.option.withstmt) { | |
4596 | warning("W085", state.tokens.curr); | |
4597 | } | |
4598 | ||
4599 | advance("("); | |
4600 | nonadjacent(this, t); | |
4601 | nospace(); | |
4602 | expression(0); | |
4603 | advance(")", t); | |
4604 | nospace(state.tokens.prev, state.tokens.curr); | |
4605 | block(true, true); | |
4606 | ||
4607 | return this; | |
4608 | }); | |
4609 | ||
4610 | blockstmt("switch", function () { | |
4611 | var t = state.tokens.next, | |
4612 | g = false; | |
4613 | funct["(breakage)"] += 1; | |
4614 | advance("("); | |
4615 | nonadjacent(this, t); | |
4616 | nospace(); | |
4617 | checkCondAssignment(expression(0)); | |
4618 | advance(")", t); | |
4619 | nospace(state.tokens.prev, state.tokens.curr); | |
4620 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4621 | t = state.tokens.next; | |
4622 | advance("{"); | |
4623 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4624 | indent += state.option.indent; | |
4625 | this.cases = []; | |
4626 | ||
4627 | for (;;) { | |
4628 | switch (state.tokens.next.id) { | |
4629 | case "case": | |
4630 | switch (funct["(verb)"]) { | |
4631 | case "yield": | |
4632 | case "break": | |
4633 | case "case": | |
4634 | case "continue": | |
4635 | case "return": | |
4636 | case "switch": | |
4637 | case "throw": | |
4638 | break; | |
4639 | default: | |
4640 | // You can tell JSHint that you don't use break intentionally by | |
4641 | // adding a comment /* falls through */ on a line just before | |
4642 | // the next `case`. | |
4643 | if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { | |
4644 | warning("W086", state.tokens.curr, "case"); | |
4645 | } | |
4646 | } | |
4647 | indentation(-state.option.indent); | |
4648 | advance("case"); | |
4649 | this.cases.push(expression(20)); | |
4650 | increaseComplexityCount(); | |
4651 | g = true; | |
4652 | advance(":"); | |
4653 | funct["(verb)"] = "case"; | |
4654 | break; | |
4655 | case "default": | |
4656 | switch (funct["(verb)"]) { | |
4657 | case "yield": | |
4658 | case "break": | |
4659 | case "continue": | |
4660 | case "return": | |
4661 | case "throw": | |
4662 | break; | |
4663 | default: | |
4664 | // Do not display a warning if 'default' is the first statement or if | |
4665 | // there is a special /* falls through */ comment. | |
4666 | if (this.cases.length) { | |
4667 | if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { | |
4668 | warning("W086", state.tokens.curr, "default"); | |
4669 | } | |
4670 | } | |
4671 | } | |
4672 | indentation(-state.option.indent); | |
4673 | advance("default"); | |
4674 | g = true; | |
4675 | advance(":"); | |
4676 | break; | |
4677 | case "}": | |
4678 | indent -= state.option.indent; | |
4679 | indentation(); | |
4680 | advance("}", t); | |
4681 | funct["(breakage)"] -= 1; | |
4682 | funct["(verb)"] = undefined; | |
4683 | return; | |
4684 | case "(end)": | |
4685 | error("E023", state.tokens.next, "}"); | |
4686 | return; | |
4687 | default: | |
4688 | if (g) { | |
4689 | switch (state.tokens.curr.id) { | |
4690 | case ",": | |
4691 | error("E040"); | |
4692 | return; | |
4693 | case ":": | |
4694 | g = false; | |
4695 | statements(); | |
4696 | break; | |
4697 | default: | |
4698 | error("E025", state.tokens.curr); | |
4699 | return; | |
4700 | } | |
4701 | } else { | |
4702 | if (state.tokens.curr.id === ":") { | |
4703 | advance(":"); | |
4704 | error("E024", state.tokens.curr, ":"); | |
4705 | statements(); | |
4706 | } else { | |
4707 | error("E021", state.tokens.next, "case", state.tokens.next.value); | |
4708 | return; | |
4709 | } | |
4710 | } | |
4711 | } | |
4712 | } | |
4713 | }).labelled = true; | |
4714 | ||
4715 | stmt("debugger", function () { | |
4716 | if (!state.option.debug) { | |
4717 | warning("W087"); | |
4718 | } | |
4719 | return this; | |
4720 | }).exps = true; | |
4721 | ||
4722 | (function () { | |
4723 | var x = stmt("do", function () { | |
4724 | funct["(breakage)"] += 1; | |
4725 | funct["(loopage)"] += 1; | |
4726 | increaseComplexityCount(); | |
4727 | ||
4728 | this.first = block(true, true); | |
4729 | advance("while"); | |
4730 | var t = state.tokens.next; | |
4731 | nonadjacent(state.tokens.curr, t); | |
4732 | advance("("); | |
4733 | nospace(); | |
4734 | checkCondAssignment(expression(0)); | |
4735 | advance(")", t); | |
4736 | nospace(state.tokens.prev, state.tokens.curr); | |
4737 | funct["(breakage)"] -= 1; | |
4738 | funct["(loopage)"] -= 1; | |
4739 | return this; | |
4740 | }); | |
4741 | x.labelled = true; | |
4742 | x.exps = true; | |
4743 | }()); | |
4744 | ||
4745 | blockstmt("for", function () { | |
4746 | var s, t = state.tokens.next; | |
4747 | var letscope = false; | |
4748 | var foreachtok = null; | |
4749 | ||
4750 | if (t.value === "each") { | |
4751 | foreachtok = t; | |
4752 | advance("each"); | |
4753 | if (!state.option.inMoz(true)) { | |
4754 | warning("W118", state.tokens.curr, "for each"); | |
4755 | } | |
4756 | } | |
4757 | ||
4758 | funct["(breakage)"] += 1; | |
4759 | funct["(loopage)"] += 1; | |
4760 | increaseComplexityCount(); | |
4761 | advance("("); | |
4762 | nonadjacent(this, t); | |
4763 | nospace(); | |
4764 | ||
4765 | // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? | |
4766 | var nextop; // contains the token of the "in" or "of" operator | |
4767 | var i = 0; | |
4768 | var inof = ["in", "of"]; | |
4769 | do { | |
4770 | nextop = peek(i); | |
4771 | ++i; | |
4772 | } while (!_.contains(inof, nextop.value) && nextop.value !== ";" && | |
4773 | nextop.type !== "(end)"); | |
4774 | ||
4775 | // if we're in a for (… in|of …) statement | |
4776 | if (_.contains(inof, nextop.value)) { | |
4777 | if (!state.option.inESNext() && nextop.value === "of") { | |
4778 | error("W104", nextop, "for of"); | |
4779 | } | |
4780 | if (state.tokens.next.id === "var") { | |
4781 | advance("var"); | |
4782 | state.syntax["var"].fud.call(state.syntax["var"].fud, true); | |
4783 | } else if (state.tokens.next.id === "let") { | |
4784 | advance("let"); | |
4785 | // create a new block scope | |
4786 | letscope = true; | |
4787 | funct["(blockscope)"].stack(); | |
4788 | state.syntax["let"].fud.call(state.syntax["let"].fud, true); | |
4789 | } else { | |
4790 | switch (funct[state.tokens.next.value]) { | |
4791 | case "unused": | |
4792 | funct[state.tokens.next.value] = "var"; | |
4793 | break; | |
4794 | case "var": | |
4795 | break; | |
4796 | default: | |
4797 | if (!funct["(blockscope)"].getlabel(state.tokens.next.value)) | |
4798 | warning("W088", state.tokens.next, state.tokens.next.value); | |
4799 | } | |
4800 | advance(); | |
4801 | } | |
4802 | advance(nextop.value); | |
4803 | expression(20); | |
4804 | advance(")", t); | |
4805 | s = block(true, true); | |
4806 | if (state.option.forin && s && (s.length > 1 || typeof s[0] !== "object" || | |
4807 | s[0].value !== "if")) { | |
4808 | warning("W089", this); | |
4809 | } | |
4810 | funct["(breakage)"] -= 1; | |
4811 | funct["(loopage)"] -= 1; | |
4812 | } else { | |
4813 | if (foreachtok) { | |
4814 | error("E045", foreachtok); | |
4815 | } | |
4816 | if (state.tokens.next.id !== ";") { | |
4817 | if (state.tokens.next.id === "var") { | |
4818 | advance("var"); | |
4819 | state.syntax["var"].fud.call(state.syntax["var"].fud); | |
4820 | } else if (state.tokens.next.id === "let") { | |
4821 | advance("let"); | |
4822 | // create a new block scope | |
4823 | letscope = true; | |
4824 | funct["(blockscope)"].stack(); | |
4825 | state.syntax["let"].fud.call(state.syntax["let"].fud); | |
4826 | } else { | |
4827 | for (;;) { | |
4828 | expression(0, "for"); | |
4829 | if (state.tokens.next.id !== ",") { | |
4830 | break; | |
4831 | } | |
4832 | comma(); | |
4833 | } | |
4834 | } | |
4835 | } | |
4836 | nolinebreak(state.tokens.curr); | |
4837 | advance(";"); | |
4838 | if (state.tokens.next.id !== ";") { | |
4839 | checkCondAssignment(expression(0)); | |
4840 | } | |
4841 | nolinebreak(state.tokens.curr); | |
4842 | advance(";"); | |
4843 | if (state.tokens.next.id === ";") { | |
4844 | error("E021", state.tokens.next, ")", ";"); | |
4845 | } | |
4846 | if (state.tokens.next.id !== ")") { | |
4847 | for (;;) { | |
4848 | expression(0, "for"); | |
4849 | if (state.tokens.next.id !== ",") { | |
4850 | break; | |
4851 | } | |
4852 | comma(); | |
4853 | } | |
4854 | } | |
4855 | advance(")", t); | |
4856 | nospace(state.tokens.prev, state.tokens.curr); | |
4857 | block(true, true); | |
4858 | funct["(breakage)"] -= 1; | |
4859 | funct["(loopage)"] -= 1; | |
4860 | ||
4861 | } | |
4862 | // unstack loop blockscope | |
4863 | if (letscope) { | |
4864 | funct["(blockscope)"].unstack(); | |
4865 | } | |
4866 | return this; | |
4867 | }).labelled = true; | |
4868 | ||
4869 | ||
4870 | stmt("break", function () { | |
4871 | var v = state.tokens.next.value; | |
4872 | ||
4873 | if (funct["(breakage)"] === 0) | |
4874 | warning("W052", state.tokens.next, this.value); | |
4875 | ||
4876 | if (!state.option.asi) | |
4877 | nolinebreak(this); | |
4878 | ||
4879 | if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { | |
4880 | if (state.tokens.curr.line === state.tokens.next.line) { | |
4881 | if (funct[v] !== "label") { | |
4882 | warning("W090", state.tokens.next, v); | |
4883 | } else if (scope[v] !== funct) { | |
4884 | warning("W091", state.tokens.next, v); | |
4885 | } | |
4886 | this.first = state.tokens.next; | |
4887 | advance(); | |
4888 | } | |
4889 | } | |
4890 | reachable("break"); | |
4891 | return this; | |
4892 | }).exps = true; | |
4893 | ||
4894 | ||
4895 | stmt("continue", function () { | |
4896 | var v = state.tokens.next.value; | |
4897 | ||
4898 | if (funct["(breakage)"] === 0) | |
4899 | warning("W052", state.tokens.next, this.value); | |
4900 | ||
4901 | if (!state.option.asi) | |
4902 | nolinebreak(this); | |
4903 | ||
4904 | if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { | |
4905 | if (state.tokens.curr.line === state.tokens.next.line) { | |
4906 | if (funct[v] !== "label") { | |
4907 | warning("W090", state.tokens.next, v); | |
4908 | } else if (scope[v] !== funct) { | |
4909 | warning("W091", state.tokens.next, v); | |
4910 | } | |
4911 | this.first = state.tokens.next; | |
4912 | advance(); | |
4913 | } | |
4914 | } else if (!funct["(loopage)"]) { | |
4915 | warning("W052", state.tokens.next, this.value); | |
4916 | } | |
4917 | reachable("continue"); | |
4918 | return this; | |
4919 | }).exps = true; | |
4920 | ||
4921 | ||
4922 | stmt("return", function () { | |
4923 | if (this.line === state.tokens.next.line) { | |
4924 | if (state.tokens.next.id === "(regexp)") | |
4925 | warning("W092"); | |
4926 | ||
4927 | if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { | |
4928 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4929 | this.first = expression(0); | |
4930 | ||
4931 | if (this.first && | |
4932 | this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { | |
4933 | warningAt("W093", this.first.line, this.first.character); | |
4934 | } | |
4935 | } | |
4936 | } else { | |
4937 | if (state.tokens.next.type === "(punctuator)" && | |
4938 | ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { | |
4939 | nolinebreak(this); // always warn (Line breaking error) | |
4940 | } | |
4941 | } | |
4942 | reachable("return"); | |
4943 | return this; | |
4944 | }).exps = true; | |
4945 | ||
4946 | (function (x) { | |
4947 | x.exps = true; | |
4948 | x.lbp = 25; | |
4949 | }(prefix("yield", function () { | |
4950 | var prev = state.tokens.prev; | |
4951 | if (state.option.inESNext(true) && !funct["(generator)"]) { | |
4952 | error("E046", state.tokens.curr, "yield"); | |
4953 | } else if (!state.option.inESNext()) { | |
4954 | warning("W104", state.tokens.curr, "yield"); | |
4955 | } | |
4956 | funct["(generator)"] = "yielded"; | |
4957 | if (this.line === state.tokens.next.line || !state.option.inMoz(true)) { | |
4958 | if (state.tokens.next.id === "(regexp)") | |
4959 | warning("W092"); | |
4960 | ||
4961 | if (state.tokens.next.id !== ";" && !state.tokens.next.reach && state.tokens.next.nud) { | |
4962 | nobreaknonadjacent(state.tokens.curr, state.tokens.next); | |
4963 | this.first = expression(10); | |
4964 | ||
4965 | if (this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { | |
4966 | warningAt("W093", this.first.line, this.first.character); | |
4967 | } | |
4968 | } | |
4969 | ||
4970 | if (state.option.inMoz(true) && state.tokens.next.id !== ")" && | |
4971 | (prev.lbp > 30 || (!prev.assign && !isEndOfExpr()) || prev.id === "yield")) { | |
4972 | error("E050", this); | |
4973 | } | |
4974 | } else if (!state.option.asi) { | |
4975 | nolinebreak(this); // always warn (Line breaking error) | |
4976 | } | |
4977 | return this; | |
4978 | }))); | |
4979 | ||
4980 | ||
4981 | stmt("throw", function () { | |
4982 | nolinebreak(this); | |
4983 | nonadjacent(state.tokens.curr, state.tokens.next); | |
4984 | this.first = expression(20); | |
4985 | reachable("throw"); | |
4986 | return this; | |
4987 | }).exps = true; | |
4988 | ||
4989 | stmt("import", function () { | |
4990 | if (!state.option.inESNext()) { | |
4991 | warning("W119", state.tokens.curr, "import"); | |
4992 | } | |
4993 | ||
4994 | if (state.tokens.next.identifier) { | |
4995 | this.name = identifier(); | |
4996 | addlabel(this.name, "unused", state.tokens.curr); | |
4997 | } else { | |
4998 | advance("{"); | |
4999 | for (;;) { | |
5000 | var importName; | |
5001 | if (state.tokens.next.type === "default") { | |
5002 | importName = "default"; | |
5003 | advance("default"); | |
5004 | } else { | |
5005 | importName = identifier(); | |
5006 | } | |
5007 | if (state.tokens.next.value === "as") { | |
5008 | advance("as"); | |
5009 | importName = identifier(); | |
5010 | } | |
5011 | addlabel(importName, "unused", state.tokens.curr); | |
5012 | ||
5013 | if (state.tokens.next.value === ",") { | |
5014 | advance(","); | |
5015 | } else if (state.tokens.next.value === "}") { | |
5016 | advance("}"); | |
5017 | break; | |
5018 | } else { | |
5019 | error("E024", state.tokens.next, state.tokens.next.value); | |
5020 | break; | |
5021 | } | |
5022 | } | |
5023 | } | |
5024 | ||
5025 | advance("from"); | |
5026 | advance("(string)"); | |
5027 | return this; | |
5028 | }).exps = true; | |
5029 | ||
5030 | stmt("export", function () { | |
5031 | if (!state.option.inESNext()) { | |
5032 | warning("W119", state.tokens.curr, "export"); | |
5033 | } | |
5034 | ||
5035 | if (state.tokens.next.type === "default") { | |
5036 | advance("default"); | |
5037 | if (state.tokens.next.id === "function" || state.tokens.next.id === "class") { | |
5038 | this.block = true; | |
5039 | } | |
5040 | this.exportee = expression(10); | |
5041 | ||
5042 | return this; | |
5043 | } | |
5044 | ||
5045 | if (state.tokens.next.value === "{") { | |
5046 | advance("{"); | |
5047 | for (;;) { | |
5048 | identifier(); | |
5049 | ||
5050 | if (state.tokens.next.value === ",") { | |
5051 | advance(","); | |
5052 | } else if (state.tokens.next.value === "}") { | |
5053 | advance("}"); | |
5054 | break; | |
5055 | } else { | |
5056 | error("E024", state.tokens.next, state.tokens.next.value); | |
5057 | break; | |
5058 | } | |
5059 | } | |
5060 | return this; | |
5061 | } | |
5062 | ||
5063 | if (state.tokens.next.id === "var") { | |
5064 | advance("var"); | |
5065 | state.syntax["var"].fud.call(state.syntax["var"].fud); | |
5066 | } else if (state.tokens.next.id === "let") { | |
5067 | advance("let"); | |
5068 | state.syntax["let"].fud.call(state.syntax["let"].fud); | |
5069 | } else if (state.tokens.next.id === "const") { | |
5070 | advance("const"); | |
5071 | state.syntax["const"].fud.call(state.syntax["const"].fud); | |
5072 | } else if (state.tokens.next.id === "function") { | |
5073 | this.block = true; | |
5074 | advance("function"); | |
5075 | state.syntax["function"].fud(); | |
5076 | } else if (state.tokens.next.id === "class") { | |
5077 | this.block = true; | |
5078 | advance("class"); | |
5079 | state.syntax["class"].fud(); | |
5080 | } else { | |
5081 | error("E024", state.tokens.next, state.tokens.next.value); | |
5082 | } | |
5083 | ||
5084 | return this; | |
5085 | }).exps = true; | |
5086 | ||
5087 | // Future Reserved Words | |
5088 | ||
5089 | FutureReservedWord("abstract"); | |
5090 | FutureReservedWord("boolean"); | |
5091 | FutureReservedWord("byte"); | |
5092 | FutureReservedWord("char"); | |
5093 | FutureReservedWord("class", { es5: true, nud: classdef }); | |
5094 | FutureReservedWord("double"); | |
5095 | FutureReservedWord("enum", { es5: true }); | |
5096 | FutureReservedWord("export", { es5: true }); | |
5097 | FutureReservedWord("extends", { es5: true }); | |
5098 | FutureReservedWord("final"); | |
5099 | FutureReservedWord("float"); | |
5100 | FutureReservedWord("goto"); | |
5101 | FutureReservedWord("implements", { es5: true, strictOnly: true }); | |
5102 | FutureReservedWord("import", { es5: true }); | |
5103 | FutureReservedWord("int"); | |
5104 | FutureReservedWord("interface", { es5: true, strictOnly: true }); | |
5105 | FutureReservedWord("long"); | |
5106 | FutureReservedWord("native"); | |
5107 | FutureReservedWord("package", { es5: true, strictOnly: true }); | |
5108 | FutureReservedWord("private", { es5: true, strictOnly: true }); | |
5109 | FutureReservedWord("protected", { es5: true, strictOnly: true }); | |
5110 | FutureReservedWord("public", { es5: true, strictOnly: true }); | |
5111 | FutureReservedWord("short"); | |
5112 | FutureReservedWord("static", { es5: true, strictOnly: true }); | |
5113 | FutureReservedWord("super", { es5: true }); | |
5114 | FutureReservedWord("synchronized"); | |
5115 | FutureReservedWord("throws"); | |
5116 | FutureReservedWord("transient"); | |
5117 | FutureReservedWord("volatile"); | |
5118 | ||
5119 | // this function is used to determine wether a squarebracket or a curlybracket | |
5120 | // expression is a comprehension array, destructuring assignment or a json value. | |
5121 | ||
5122 | var lookupBlockType = function () { | |
5123 | var pn, pn1; | |
5124 | var i = 0; | |
5125 | var bracketStack = 0; | |
5126 | var ret = {}; | |
5127 | if (_.contains(["[", "{"], state.tokens.curr.value)) | |
5128 | bracketStack += 1; | |
5129 | if (_.contains(["[", "{"], state.tokens.next.value)) | |
5130 | bracketStack += 1; | |
5131 | if (_.contains(["]", "}"], state.tokens.next.value)) | |
5132 | bracketStack -= 1; | |
5133 | do { | |
5134 | pn = peek(i); | |
5135 | pn1 = peek(i + 1); | |
5136 | i = i + 1; | |
5137 | if (_.contains(["[", "{"], pn.value)) { | |
5138 | bracketStack += 1; | |
5139 | } else if (_.contains(["]", "}"], pn.value)) { | |
5140 | bracketStack -= 1; | |
5141 | } | |
5142 | if (pn.identifier && pn.value === "for" && bracketStack === 1) { | |
5143 | ret.isCompArray = true; | |
5144 | ret.notJson = true; | |
5145 | break; | |
5146 | } | |
5147 | if (_.contains(["}", "]"], pn.value) && pn1.value === "=") { | |
5148 | ret.isDestAssign = true; | |
5149 | ret.notJson = true; | |
5150 | break; | |
5151 | } | |
5152 | if (pn.value === ";") { | |
5153 | ret.isBlock = true; | |
5154 | ret.notJson = true; | |
5155 | } | |
5156 | } while (bracketStack > 0 && pn.id !== "(end)" && i < 15); | |
5157 | return ret; | |
5158 | }; | |
5159 | ||
5160 | // Check whether this function has been reached for a destructuring assign with undeclared values | |
5161 | function destructuringAssignOrJsonValue() { | |
5162 | // lookup for the assignment (esnext only) | |
5163 | // if it has semicolons, it is a block, so go parse it as a block | |
5164 | // or it's not a block, but there are assignments, check for undeclared variables | |
5165 | ||
5166 | var block = lookupBlockType(); | |
5167 | if (block.notJson) { | |
5168 | if (!state.option.inESNext() && block.isDestAssign) { | |
5169 | warning("W104", state.tokens.curr, "destructuring assignment"); | |
5170 | } | |
5171 | statements(); | |
5172 | // otherwise parse json value | |
5173 | } else { | |
5174 | state.option.laxbreak = true; | |
5175 | state.jsonMode = true; | |
5176 | jsonValue(); | |
5177 | } | |
5178 | } | |
5179 | ||
5180 | // array comprehension parsing function | |
5181 | // parses and defines the three states of the list comprehension in order | |
5182 | // to avoid defining global variables, but keeping them to the list comprehension scope | |
5183 | // only. The order of the states are as follows: | |
5184 | // * "use" which will be the returned iterative part of the list comprehension | |
5185 | // * "define" which will define the variables local to the list comprehension | |
5186 | // * "filter" which will help filter out values | |
5187 | ||
5188 | var arrayComprehension = function () { | |
5189 | var CompArray = function () { | |
5190 | this.mode = "use"; | |
5191 | this.variables = []; | |
5192 | }; | |
5193 | var _carrays = []; | |
5194 | var _current; | |
5195 | function declare(v) { | |
5196 | var l = _current.variables.filter(function (elt) { | |
5197 | // if it has, change its undef state | |
5198 | if (elt.value === v) { | |
5199 | elt.undef = false; | |
5200 | return v; | |
5201 | } | |
5202 | }).length; | |
5203 | return l !== 0; | |
5204 | } | |
5205 | function use(v) { | |
5206 | var l = _current.variables.filter(function (elt) { | |
5207 | // and if it has been defined | |
5208 | if (elt.value === v && !elt.undef) { | |
5209 | if (elt.unused === true) { | |
5210 | elt.unused = false; | |
5211 | } | |
5212 | return v; | |
5213 | } | |
5214 | }).length; | |
5215 | // otherwise we warn about it | |
5216 | return (l === 0); | |
5217 | } | |
5218 | return {stack: function () { | |
5219 | _current = new CompArray(); | |
5220 | _carrays.push(_current); | |
5221 | }, | |
5222 | unstack: function () { | |
5223 | _current.variables.filter(function (v) { | |
5224 | if (v.unused) | |
5225 | warning("W098", v.token, v.value); | |
5226 | if (v.undef) | |
5227 | isundef(v.funct, "W117", v.token, v.value); | |
5228 | }); | |
5229 | _carrays.splice(_carrays[_carrays.length - 1], 1); | |
5230 | _current = _carrays[_carrays.length - 1]; | |
5231 | }, | |
5232 | setState: function (s) { | |
5233 | if (_.contains(["use", "define", "filter"], s)) | |
5234 | _current.mode = s; | |
5235 | }, | |
5236 | check: function (v) { | |
5237 | // When we are in "use" state of the list comp, we enqueue that var | |
5238 | if (_current && _current.mode === "use") { | |
5239 | _current.variables.push({funct: funct, | |
5240 | token: state.tokens.curr, | |
5241 | value: v, | |
5242 | undef: true, | |
5243 | unused: false}); | |
5244 | return true; | |
5245 | // When we are in "define" state of the list comp, | |
5246 | } else if (_current && _current.mode === "define") { | |
5247 | // check if the variable has been used previously | |
5248 | if (!declare(v)) { | |
5249 | _current.variables.push({funct: funct, | |
5250 | token: state.tokens.curr, | |
5251 | value: v, | |
5252 | undef: false, | |
5253 | unused: true}); | |
5254 | } | |
5255 | return true; | |
5256 | // When we are in "filter" state, | |
5257 | } else if (_current && _current.mode === "filter") { | |
5258 | // we check whether current variable has been declared | |
5259 | if (use(v)) { | |
5260 | // if not we warn about it | |
5261 | isundef(funct, "W117", state.tokens.curr, v); | |
5262 | } | |
5263 | return true; | |
5264 | } | |
5265 | return false; | |
5266 | } | |
5267 | }; | |
5268 | }; | |
5269 | ||
5270 | ||
5271 | // Parse JSON | |
5272 | ||
5273 | function jsonValue() { | |
5274 | ||
5275 | function jsonObject() { | |
5276 | var o = {}, t = state.tokens.next; | |
5277 | advance("{"); | |
5278 | if (state.tokens.next.id !== "}") { | |
5279 | for (;;) { | |
5280 | if (state.tokens.next.id === "(end)") { | |
5281 | error("E026", state.tokens.next, t.line); | |
5282 | } else if (state.tokens.next.id === "}") { | |
5283 | warning("W094", state.tokens.curr); | |
5284 | break; | |
5285 | } else if (state.tokens.next.id === ",") { | |
5286 | error("E028", state.tokens.next); | |
5287 | } else if (state.tokens.next.id !== "(string)") { | |
5288 | warning("W095", state.tokens.next, state.tokens.next.value); | |
5289 | } | |
5290 | if (o[state.tokens.next.value] === true) { | |
5291 | warning("W075", state.tokens.next, state.tokens.next.value); | |
5292 | } else if ((state.tokens.next.value === "__proto__" && | |
5293 | !state.option.proto) || (state.tokens.next.value === "__iterator__" && | |
5294 | !state.option.iterator)) { | |
5295 | warning("W096", state.tokens.next, state.tokens.next.value); | |
5296 | } else { | |
5297 | o[state.tokens.next.value] = true; | |
5298 | } | |
5299 | advance(); | |
5300 | advance(":"); | |
5301 | jsonValue(); | |
5302 | if (state.tokens.next.id !== ",") { | |
5303 | break; | |
5304 | } | |
5305 | advance(","); | |
5306 | } | |
5307 | } | |
5308 | advance("}"); | |
5309 | } | |
5310 | ||
5311 | function jsonArray() { | |
5312 | var t = state.tokens.next; | |
5313 | advance("["); | |
5314 | if (state.tokens.next.id !== "]") { | |
5315 | for (;;) { | |
5316 | if (state.tokens.next.id === "(end)") { | |
5317 | error("E027", state.tokens.next, t.line); | |
5318 | } else if (state.tokens.next.id === "]") { | |
5319 | warning("W094", state.tokens.curr); | |
5320 | break; | |
5321 | } else if (state.tokens.next.id === ",") { | |
5322 | error("E028", state.tokens.next); | |
5323 | } | |
5324 | jsonValue(); | |
5325 | if (state.tokens.next.id !== ",") { | |
5326 | break; | |
5327 | } | |
5328 | advance(","); | |
5329 | } | |
5330 | } | |
5331 | advance("]"); | |
5332 | } | |
5333 | ||
5334 | switch (state.tokens.next.id) { | |
5335 | case "{": | |
5336 | jsonObject(); | |
5337 | break; | |
5338 | case "[": | |
5339 | jsonArray(); | |
5340 | break; | |
5341 | case "true": | |
5342 | case "false": | |
5343 | case "null": | |
5344 | case "(number)": | |
5345 | case "(string)": | |
5346 | advance(); | |
5347 | break; | |
5348 | case "-": | |
5349 | advance("-"); | |
5350 | if (state.tokens.curr.character !== state.tokens.next.from) { | |
5351 | warning("W011", state.tokens.curr); | |
5352 | } | |
5353 | adjacent(state.tokens.curr, state.tokens.next); | |
5354 | advance("(number)"); | |
5355 | break; | |
5356 | default: | |
5357 | error("E003", state.tokens.next); | |
5358 | } | |
5359 | } | |
5360 | ||
5361 | var blockScope = function () { | |
5362 | var _current = {}; | |
5363 | var _variables = [_current]; | |
5364 | ||
5365 | function _checkBlockLabels() { | |
5366 | for (var t in _current) { | |
5367 | if (_current[t]["(type)"] === "unused") { | |
5368 | if (state.option.unused) { | |
5369 | var tkn = _current[t]["(token)"]; | |
5370 | var line = tkn.line; | |
5371 | var chr = tkn.character; | |
5372 | warningAt("W098", line, chr, t); | |
5373 | } | |
5374 | } | |
5375 | } | |
5376 | } | |
5377 | ||
5378 | return { | |
5379 | stack: function () { | |
5380 | _current = {}; | |
5381 | _variables.push(_current); | |
5382 | }, | |
5383 | ||
5384 | unstack: function () { | |
5385 | _checkBlockLabels(); | |
5386 | _variables.splice(_variables.length - 1, 1); | |
5387 | _current = _.last(_variables); | |
5388 | }, | |
5389 | ||
5390 | getlabel: function (l) { | |
5391 | for (var i = _variables.length - 1 ; i >= 0; --i) { | |
5392 | if (_.has(_variables[i], l)) { | |
5393 | return _variables[i]; | |
5394 | } | |
5395 | } | |
5396 | }, | |
5397 | ||
5398 | current: { | |
5399 | has: function (t) { | |
5400 | return _.has(_current, t); | |
5401 | }, | |
5402 | add: function (t, type, tok) { | |
5403 | _current[t] = { "(type)" : type, | |
5404 | "(token)": tok }; | |
5405 | } | |
5406 | } | |
5407 | }; | |
5408 | }; | |
5409 | ||
5410 | // The actual JSHINT function itself. | |
5411 | var itself = function (s, o, g) { | |
5412 | var i, k, x; | |
5413 | var optionKeys; | |
5414 | var newOptionObj = {}; | |
5415 | var newIgnoredObj = {}; | |
5416 | ||
5417 | state.reset(); | |
5418 | ||
5419 | if (o && o.scope) { | |
5420 | JSHINT.scope = o.scope; | |
5421 | } else { | |
5422 | JSHINT.errors = []; | |
5423 | JSHINT.undefs = []; | |
5424 | JSHINT.internals = []; | |
5425 | JSHINT.blacklist = {}; | |
5426 | JSHINT.scope = "(main)"; | |
5427 | } | |
5428 | ||
5429 | predefined = Object.create(null); | |
5430 | combine(predefined, vars.ecmaIdentifiers); | |
5431 | combine(predefined, vars.reservedVars); | |
5432 | ||
5433 | combine(predefined, g || {}); | |
5434 | ||
5435 | declared = Object.create(null); | |
5436 | exported = Object.create(null); | |
5437 | ||
5438 | function each(obj, cb) { | |
5439 | if (!obj) | |
5440 | return; | |
5441 | ||
5442 | if (!Array.isArray(obj) && typeof obj === "object") | |
5443 | obj = Object.keys(obj); | |
5444 | ||
5445 | obj.forEach(cb); | |
5446 | } | |
5447 | ||
5448 | if (o) { | |
5449 | each(o.predef || null, function (item) { | |
5450 | var slice, prop; | |
5451 | ||
5452 | if (item[0] === "-") { | |
5453 | slice = item.slice(1); | |
5454 | JSHINT.blacklist[slice] = slice; | |
5455 | } else { | |
5456 | prop = Object.getOwnPropertyDescriptor(o.predef, item); | |
5457 | predefined[item] = prop ? prop.value : false; | |
5458 | } | |
5459 | }); | |
5460 | ||
5461 | each(o.exported || null, function (item) { | |
5462 | exported[item] = true; | |
5463 | }); | |
5464 | ||
5465 | delete o.predef; | |
5466 | delete o.exported; | |
5467 | ||
5468 | optionKeys = Object.keys(o); | |
5469 | for (x = 0; x < optionKeys.length; x++) { | |
5470 | if (/^-W\d{3}$/g.test(optionKeys[x])) { | |
5471 | newIgnoredObj[optionKeys[x].slice(1)] = true; | |
5472 | } else { | |
5473 | newOptionObj[optionKeys[x]] = o[optionKeys[x]]; | |
5474 | ||
5475 | if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false) | |
5476 | newOptionObj["(explicitNewcap)"] = true; | |
5477 | ||
5478 | if (optionKeys[x] === "indent") | |
5479 | newOptionObj["(explicitIndent)"] = o[optionKeys[x]] === false ? false : true; | |
5480 | } | |
5481 | } | |
5482 | } | |
5483 | ||
5484 | state.option = newOptionObj; | |
5485 | state.ignored = newIgnoredObj; | |
5486 | ||
5487 | state.option.indent = state.option.indent || 4; | |
5488 | state.option.maxerr = state.option.maxerr || 50; | |
5489 | ||
5490 | indent = 1; | |
5491 | global = Object.create(predefined); | |
5492 | scope = global; | |
5493 | funct = { | |
5494 | "(global)": true, | |
5495 | "(name)": "(global)", | |
5496 | "(scope)": scope, | |
5497 | "(breakage)": 0, | |
5498 | "(loopage)": 0, | |
5499 | "(tokens)": {}, | |
5500 | "(metrics)": createMetrics(state.tokens.next), | |
5501 | "(blockscope)": blockScope(), | |
5502 | "(comparray)": arrayComprehension() | |
5503 | }; | |
5504 | functions = [funct]; | |
5505 | urls = []; | |
5506 | stack = null; | |
5507 | member = {}; | |
5508 | membersOnly = null; | |
5509 | implied = {}; | |
5510 | inblock = false; | |
5511 | lookahead = []; | |
5512 | warnings = 0; | |
5513 | unuseds = []; | |
5514 | ||
5515 | if (!isString(s) && !Array.isArray(s)) { | |
5516 | errorAt("E004", 0); | |
5517 | return false; | |
5518 | } | |
5519 | ||
5520 | api = { | |
5521 | get isJSON() { | |
5522 | return state.jsonMode; | |
5523 | }, | |
5524 | ||
5525 | getOption: function (name) { | |
5526 | return state.option[name] || null; | |
5527 | }, | |
5528 | ||
5529 | getCache: function (name) { | |
5530 | return state.cache[name]; | |
5531 | }, | |
5532 | ||
5533 | setCache: function (name, value) { | |
5534 | state.cache[name] = value; | |
5535 | }, | |
5536 | ||
5537 | warn: function (code, data) { | |
5538 | warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); | |
5539 | }, | |
5540 | ||
5541 | on: function (names, listener) { | |
5542 | names.split(" ").forEach(function (name) { | |
5543 | emitter.on(name, listener); | |
5544 | }.bind(this)); | |
5545 | } | |
5546 | }; | |
5547 | ||
5548 | emitter.removeAllListeners(); | |
5549 | (extraModules || []).forEach(function (func) { | |
5550 | func(api); | |
5551 | }); | |
5552 | ||
5553 | state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; | |
5554 | ||
5555 | lex = new Lexer(s); | |
5556 | ||
5557 | lex.on("warning", function (ev) { | |
5558 | warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); | |
5559 | }); | |
5560 | ||
5561 | lex.on("error", function (ev) { | |
5562 | errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); | |
5563 | }); | |
5564 | ||
5565 | lex.on("fatal", function (ev) { | |
5566 | quit("E041", ev.line, ev.from); | |
5567 | }); | |
5568 | ||
5569 | lex.on("Identifier", function (ev) { | |
5570 | emitter.emit("Identifier", ev); | |
5571 | }); | |
5572 | ||
5573 | lex.on("String", function (ev) { | |
5574 | emitter.emit("String", ev); | |
5575 | }); | |
5576 | ||
5577 | lex.on("Number", function (ev) { | |
5578 | emitter.emit("Number", ev); | |
5579 | }); | |
5580 | ||
5581 | lex.start(); | |
5582 | ||
5583 | // Check options | |
5584 | for (var name in o) { | |
5585 | if (_.has(o, name)) { | |
5586 | checkOption(name, state.tokens.curr); | |
5587 | } | |
5588 | } | |
5589 | ||
5590 | assume(); | |
5591 | ||
5592 | // combine the passed globals after we've assumed all our options | |
5593 | combine(predefined, g || {}); | |
5594 | ||
5595 | //reset values | |
5596 | comma.first = true; | |
5597 | ||
5598 | try { | |
5599 | advance(); | |
5600 | switch (state.tokens.next.id) { | |
5601 | case "{": | |
5602 | case "[": | |
5603 | destructuringAssignOrJsonValue(); | |
5604 | break; | |
5605 | default: | |
5606 | directives(); | |
5607 | ||
5608 | if (state.directive["use strict"]) { | |
5609 | if (!state.option.globalstrict && !state.option.node) { | |
5610 | warning("W097", state.tokens.prev); | |
5611 | } | |
5612 | } | |
5613 | ||
5614 | statements(); | |
5615 | } | |
5616 | advance((state.tokens.next && state.tokens.next.value !== ".") ? "(end)" : undefined); | |
5617 | funct["(blockscope)"].unstack(); | |
5618 | ||
5619 | var markDefined = function (name, context) { | |
5620 | do { | |
5621 | if (typeof context[name] === "string") { | |
5622 | // JSHINT marks unused variables as 'unused' and | |
5623 | // unused function declaration as 'unction'. This | |
5624 | // code changes such instances back 'var' and | |
5625 | // 'closure' so that the code in JSHINT.data() | |
5626 | // doesn't think they're unused. | |
5627 | ||
5628 | if (context[name] === "unused") | |
5629 | context[name] = "var"; | |
5630 | else if (context[name] === "unction") | |
5631 | context[name] = "closure"; | |
5632 | ||
5633 | return true; | |
5634 | } | |
5635 | ||
5636 | context = context["(context)"]; | |
5637 | } while (context); | |
5638 | ||
5639 | return false; | |
5640 | }; | |
5641 | ||
5642 | var clearImplied = function (name, line) { | |
5643 | if (!implied[name]) | |
5644 | return; | |
5645 | ||
5646 | var newImplied = []; | |
5647 | for (var i = 0; i < implied[name].length; i += 1) { | |
5648 | if (implied[name][i] !== line) | |
5649 | newImplied.push(implied[name][i]); | |
5650 | } | |
5651 | ||
5652 | if (newImplied.length === 0) | |
5653 | delete implied[name]; | |
5654 | else | |
5655 | implied[name] = newImplied; | |
5656 | }; | |
5657 | ||
5658 | var warnUnused = function (name, tkn, type, unused_opt) { | |
5659 | var line = tkn.line; | |
5660 | var chr = tkn.character; | |
5661 | ||
5662 | if (unused_opt === undefined) { | |
5663 | unused_opt = state.option.unused; | |
5664 | } | |
5665 | ||
5666 | if (unused_opt === true) { | |
5667 | unused_opt = "last-param"; | |
5668 | } | |
5669 | ||
5670 | var warnable_types = { | |
5671 | "vars": ["var"], | |
5672 | "last-param": ["var", "param"], | |
5673 | "strict": ["var", "param", "last-param"] | |
5674 | }; | |
5675 | ||
5676 | if (unused_opt) { | |
5677 | if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { | |
5678 | warningAt("W098", line, chr, name); | |
5679 | } | |
5680 | } | |
5681 | ||
5682 | unuseds.push({ | |
5683 | name: name, | |
5684 | line: line, | |
5685 | character: chr | |
5686 | }); | |
5687 | }; | |
5688 | ||
5689 | var checkUnused = function (func, key) { | |
5690 | var type = func[key]; | |
5691 | var tkn = func["(tokens)"][key]; | |
5692 | ||
5693 | if (key.charAt(0) === "(") | |
5694 | return; | |
5695 | ||
5696 | if (type !== "unused" && type !== "unction") | |
5697 | return; | |
5698 | ||
5699 | // Params are checked separately from other variables. | |
5700 | if (func["(params)"] && func["(params)"].indexOf(key) !== -1) | |
5701 | return; | |
5702 | ||
5703 | // Variable is in global scope and defined as exported. | |
5704 | if (func["(global)"] && _.has(exported, key)) { | |
5705 | return; | |
5706 | } | |
5707 | ||
5708 | warnUnused(key, tkn, "var"); | |
5709 | }; | |
5710 | ||
5711 | // Check queued 'x is not defined' instances to see if they're still undefined. | |
5712 | for (i = 0; i < JSHINT.undefs.length; i += 1) { | |
5713 | k = JSHINT.undefs[i].slice(0); | |
5714 | ||
5715 | if (markDefined(k[2].value, k[0])) { | |
5716 | clearImplied(k[2].value, k[2].line); | |
5717 | } else if (state.option.undef) { | |
5718 | warning.apply(warning, k.slice(1)); | |
5719 | } | |
5720 | } | |
5721 | ||
5722 | functions.forEach(function (func) { | |
5723 | if (func["(unusedOption)"] === false) { | |
5724 | return; | |
5725 | } | |
5726 | ||
5727 | for (var key in func) { | |
5728 | if (_.has(func, key)) { | |
5729 | checkUnused(func, key); | |
5730 | } | |
5731 | } | |
5732 | ||
5733 | if (!func["(params)"]) | |
5734 | return; | |
5735 | ||
5736 | var params = func["(params)"].slice(); | |
5737 | var param = params.pop(); | |
5738 | var type, unused_opt; | |
5739 | ||
5740 | while (param) { | |
5741 | type = func[param]; | |
5742 | unused_opt = func["(unusedOption)"] || state.option.unused; | |
5743 | unused_opt = unused_opt === true ? "last-param" : unused_opt; | |
5744 | ||
5745 | // 'undefined' is a special case for (function (window, undefined) { ... })(); | |
5746 | // patterns. | |
5747 | ||
5748 | if (param === "undefined") | |
5749 | return; | |
5750 | ||
5751 | if (type === "unused" || type === "unction") { | |
5752 | warnUnused(param, func["(tokens)"][param], "param", func["(unusedOption)"]); | |
5753 | } else if (unused_opt === "last-param") { | |
5754 | return; | |
5755 | } | |
5756 | ||
5757 | param = params.pop(); | |
5758 | } | |
5759 | }); | |
5760 | ||
5761 | for (var key in declared) { | |
5762 | if (_.has(declared, key) && !_.has(global, key)) { | |
5763 | warnUnused(key, declared[key], "var"); | |
5764 | } | |
5765 | } | |
5766 | ||
5767 | } catch (err) { | |
5768 | if (err && err.name === "JSHintError") { | |
5769 | var nt = state.tokens.next || {}; | |
5770 | JSHINT.errors.push({ | |
5771 | scope : "(main)", | |
5772 | raw : err.raw, | |
5773 | code : err.code, | |
5774 | reason : err.message, | |
5775 | line : err.line || nt.line, | |
5776 | character : err.character || nt.from | |
5777 | }, null); | |
5778 | } else { | |
5779 | throw err; | |
5780 | } | |
5781 | } | |
5782 | ||
5783 | // Loop over the listed "internals", and check them as well. | |
5784 | ||
5785 | if (JSHINT.scope === "(main)") { | |
5786 | o = o || {}; | |
5787 | ||
5788 | for (i = 0; i < JSHINT.internals.length; i += 1) { | |
5789 | k = JSHINT.internals[i]; | |
5790 | o.scope = k.elem; | |
5791 | itself(k.value, o, g); | |
5792 | } | |
5793 | } | |
5794 | ||
5795 | return JSHINT.errors.length === 0; | |
5796 | }; | |
5797 | ||
5798 | // Modules. | |
5799 | itself.addModule = function (func) { | |
5800 | extraModules.push(func); | |
5801 | }; | |
5802 | ||
5803 | itself.addModule(style.register); | |
5804 | ||
5805 | // Data summary. | |
5806 | itself.data = function () { | |
5807 | var data = { | |
5808 | functions: [], | |
5809 | options: state.option | |
5810 | }; | |
5811 | var implieds = []; | |
5812 | var members = []; | |
5813 | var fu, f, i, j, n, globals; | |
5814 | ||
5815 | if (itself.errors.length) { | |
5816 | data.errors = itself.errors; | |
5817 | } | |
5818 | ||
5819 | if (state.jsonMode) { | |
5820 | data.json = true; | |
5821 | } | |
5822 | ||
5823 | for (n in implied) { | |
5824 | if (_.has(implied, n)) { | |
5825 | implieds.push({ | |
5826 | name: n, | |
5827 | line: implied[n] | |
5828 | }); | |
5829 | } | |
5830 | } | |
5831 | ||
5832 | if (implieds.length > 0) { | |
5833 | data.implieds = implieds; | |
5834 | } | |
5835 | ||
5836 | if (urls.length > 0) { | |
5837 | data.urls = urls; | |
5838 | } | |
5839 | ||
5840 | globals = Object.keys(scope); | |
5841 | if (globals.length > 0) { | |
5842 | data.globals = globals; | |
5843 | } | |
5844 | ||
5845 | for (i = 1; i < functions.length; i += 1) { | |
5846 | f = functions[i]; | |
5847 | fu = {}; | |
5848 | ||
5849 | for (j = 0; j < functionicity.length; j += 1) { | |
5850 | fu[functionicity[j]] = []; | |
5851 | } | |
5852 | ||
5853 | for (j = 0; j < functionicity.length; j += 1) { | |
5854 | if (fu[functionicity[j]].length === 0) { | |
5855 | delete fu[functionicity[j]]; | |
5856 | } | |
5857 | } | |
5858 | ||
5859 | fu.name = f["(name)"]; | |
5860 | fu.param = f["(params)"]; | |
5861 | fu.line = f["(line)"]; | |
5862 | fu.character = f["(character)"]; | |
5863 | fu.last = f["(last)"]; | |
5864 | fu.lastcharacter = f["(lastcharacter)"]; | |
5865 | data.functions.push(fu); | |
5866 | } | |
5867 | ||
5868 | if (unuseds.length > 0) { | |
5869 | data.unused = unuseds; | |
5870 | } | |
5871 | ||
5872 | members = []; | |
5873 | for (n in member) { | |
5874 | if (typeof member[n] === "number") { | |
5875 | data.member = member; | |
5876 | break; | |
5877 | } | |
5878 | } | |
5879 | ||
5880 | return data; | |
5881 | }; | |
5882 | ||
5883 | itself.jshint = itself; | |
5884 | ||
5885 | return itself; | |
5886 | }()); | |
5887 | ||
5888 | // Make JSHINT a Node module, if possible. | |
5889 | if (typeof exports === "object" && exports) { | |
5890 | exports.JSHINT = JSHINT; | |
5891 | } | |
5892 | ||
5893 | })() | |
5894 | },{"events":2,"../shared/vars.js":3,"../shared/messages.js":7,"./reg.js":4,"./state.js":6,"./style.js":5,"./lex.js":8,"console-browserify":9,"underscore":10}],7:[function(require,module,exports){ | |
5895 | (function(){"use strict"; | |
5896 | ||
5897 | var _ = require("underscore"); | |
5898 | ||
5899 | var errors = { | |
5900 | // JSHint options | |
5901 | E001: "Bad option: '{a}'.", | |
5902 | E002: "Bad option value.", | |
5903 | ||
5904 | // JSHint input | |
5905 | E003: "Expected a JSON value.", | |
5906 | E004: "Input is neither a string nor an array of strings.", | |
5907 | E005: "Input is empty.", | |
5908 | E006: "Unexpected early end of program.", | |
5909 | ||
5910 | // Strict mode | |
5911 | E007: "Missing \"use strict\" statement.", | |
5912 | E008: "Strict violation.", | |
5913 | E009: "Option 'validthis' can't be used in a global scope.", | |
5914 | E010: "'with' is not allowed in strict mode.", | |
5915 | ||
5916 | // Constants | |
5917 | E011: "const '{a}' has already been declared.", | |
5918 | E012: "const '{a}' is initialized to 'undefined'.", | |
5919 | E013: "Attempting to override '{a}' which is a constant.", | |
5920 | ||
5921 | // Regular expressions | |
5922 | E014: "A regular expression literal can be confused with '/='.", | |
5923 | E015: "Unclosed regular expression.", | |
5924 | E016: "Invalid regular expression.", | |
5925 | ||
5926 | // Tokens | |
5927 | E017: "Unclosed comment.", | |
5928 | E018: "Unbegun comment.", | |
5929 | E019: "Unmatched '{a}'.", | |
5930 | E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", | |
5931 | E021: "Expected '{a}' and instead saw '{b}'.", | |
5932 | E022: "Line breaking error '{a}'.", | |
5933 | E023: "Missing '{a}'.", | |
5934 | E024: "Unexpected '{a}'.", | |
5935 | E025: "Missing ':' on a case clause.", | |
5936 | E026: "Missing '}' to match '{' from line {a}.", | |
5937 | E027: "Missing ']' to match '[' form line {a}.", | |
5938 | E028: "Illegal comma.", | |
5939 | E029: "Unclosed string.", | |
5940 | ||
5941 | // Everything else | |
5942 | E030: "Expected an identifier and instead saw '{a}'.", | |
5943 | E031: "Bad assignment.", // FIXME: Rephrase | |
5944 | E032: "Expected a small integer or 'false' and instead saw '{a}'.", | |
5945 | E033: "Expected an operator and instead saw '{a}'.", | |
5946 | E034: "get/set are ES5 features.", | |
5947 | E035: "Missing property name.", | |
5948 | E036: "Expected to see a statement and instead saw a block.", | |
5949 | E037: null, // Vacant | |
5950 | E038: null, // Vacant | |
5951 | E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", | |
5952 | E040: "Each value should have its own case label.", | |
5953 | E041: "Unrecoverable syntax error.", | |
5954 | E042: "Stopping.", | |
5955 | E043: "Too many errors.", | |
5956 | E044: "'{a}' is already defined and can't be redefined.", | |
5957 | E045: "Invalid for each loop.", | |
5958 | E046: "A yield statement shall be within a generator function (with syntax: `function*`)", | |
5959 | E047: "A generator function shall contain a yield statement.", | |
5960 | E048: "Let declaration not directly within block.", | |
5961 | E049: "A {a} cannot be named '{b}'.", | |
5962 | E050: "Mozilla requires the yield expression to be parenthesized here.", | |
5963 | E051: "Regular parameters cannot come after default parameters." | |
5964 | }; | |
5965 | ||
5966 | var warnings = { | |
5967 | W001: "'hasOwnProperty' is a really bad name.", | |
5968 | W002: "Value of '{a}' may be overwritten in IE 8 and earlier.", | |
5969 | W003: "'{a}' was used before it was defined.", | |
5970 | W004: "'{a}' is already defined.", | |
5971 | W005: "A dot following a number can be confused with a decimal point.", | |
5972 | W006: "Confusing minuses.", | |
5973 | W007: "Confusing pluses.", | |
5974 | W008: "A leading decimal point can be confused with a dot: '{a}'.", | |
5975 | W009: "The array literal notation [] is preferrable.", | |
5976 | W010: "The object literal notation {} is preferrable.", | |
5977 | W011: "Unexpected space after '{a}'.", | |
5978 | W012: "Unexpected space before '{a}'.", | |
5979 | W013: "Missing space after '{a}'.", | |
5980 | W014: "Bad line breaking before '{a}'.", | |
5981 | W015: "Expected '{a}' to have an indentation at {b} instead at {c}.", | |
5982 | W016: "Unexpected use of '{a}'.", | |
5983 | W017: "Bad operand.", | |
5984 | W018: "Confusing use of '{a}'.", | |
5985 | W019: "Use the isNaN function to compare with NaN.", | |
5986 | W020: "Read only.", | |
5987 | W021: "'{a}' is a function.", | |
5988 | W022: "Do not assign to the exception parameter.", | |
5989 | W023: "Expected an identifier in an assignment and instead saw a function invocation.", | |
5990 | W024: "Expected an identifier and instead saw '{a}' (a reserved word).", | |
5991 | W025: "Missing name in function declaration.", | |
5992 | W026: "Inner functions should be listed at the top of the outer function.", | |
5993 | W027: "Unreachable '{a}' after '{b}'.", | |
5994 | W028: "Label '{a}' on {b} statement.", | |
5995 | W030: "Expected an assignment or function call and instead saw an expression.", | |
5996 | W031: "Do not use 'new' for side effects.", | |
5997 | W032: "Unnecessary semicolon.", | |
5998 | W033: "Missing semicolon.", | |
5999 | W034: "Unnecessary directive \"{a}\".", | |
6000 | W035: "Empty block.", | |
6001 | W036: "Unexpected /*member '{a}'.", | |
6002 | W037: "'{a}' is a statement label.", | |
6003 | W038: "'{a}' used out of scope.", | |
6004 | W039: "'{a}' is not allowed.", | |
6005 | W040: "Possible strict violation.", | |
6006 | W041: "Use '{a}' to compare with '{b}'.", | |
6007 | W042: "Avoid EOL escaping.", | |
6008 | W043: "Bad escaping of EOL. Use option multistr if needed.", | |
6009 | W044: "Bad or unnecessary escaping.", | |
6010 | W045: "Bad number '{a}'.", | |
6011 | W046: "Don't use extra leading zeros '{a}'.", | |
6012 | W047: "A trailing decimal point can be confused with a dot: '{a}'.", | |
6013 | W048: "Unexpected control character in regular expression.", | |
6014 | W049: "Unexpected escaped character '{a}' in regular expression.", | |
6015 | W050: "JavaScript URL.", | |
6016 | W051: "Variables should not be deleted.", | |
6017 | W052: "Unexpected '{a}'.", | |
6018 | W053: "Do not use {a} as a constructor.", | |
6019 | W054: "The Function constructor is a form of eval.", | |
6020 | W055: "A constructor name should start with an uppercase letter.", | |
6021 | W056: "Bad constructor.", | |
6022 | W057: "Weird construction. Is 'new' unnecessary?", | |
6023 | W058: "Missing '()' invoking a constructor.", | |
6024 | W059: "Avoid arguments.{a}.", | |
6025 | W060: "document.write can be a form of eval.", | |
6026 | W061: "eval can be harmful.", | |
6027 | W062: "Wrap an immediate function invocation in parens " + | |
6028 | "to assist the reader in understanding that the expression " + | |
6029 | "is the result of a function, and not the function itself.", | |
6030 | W063: "Math is not a function.", | |
6031 | W064: "Missing 'new' prefix when invoking a constructor.", | |
6032 | W065: "Missing radix parameter.", | |
6033 | W066: "Implied eval. Consider passing a function instead of a string.", | |
6034 | W067: "Bad invocation.", | |
6035 | W068: "Wrapping non-IIFE function literals in parens is unnecessary.", | |
6036 | W069: "['{a}'] is better written in dot notation.", | |
6037 | W070: "Extra comma. (it breaks older versions of IE)", | |
6038 | W071: "This function has too many statements. ({a})", | |
6039 | W072: "This function has too many parameters. ({a})", | |
6040 | W073: "Blocks are nested too deeply. ({a})", | |
6041 | W074: "This function's cyclomatic complexity is too high. ({a})", | |
6042 | W075: "Duplicate key '{a}'.", | |
6043 | W076: "Unexpected parameter '{a}' in get {b} function.", | |
6044 | W077: "Expected a single parameter in set {a} function.", | |
6045 | W078: "Setter is defined without getter.", | |
6046 | W079: "Redefinition of '{a}'.", | |
6047 | W080: "It's not necessary to initialize '{a}' to 'undefined'.", | |
6048 | W081: "Too many var statements.", | |
6049 | W082: "Function declarations should not be placed in blocks. " + | |
6050 | "Use a function expression or move the statement to the top of " + | |
6051 | "the outer function.", | |
6052 | W083: "Don't make functions within a loop.", | |
6053 | W084: "Expected a conditional expression and instead saw an assignment.", | |
6054 | W085: "Don't use 'with'.", | |
6055 | W086: "Expected a 'break' statement before '{a}'.", | |
6056 | W087: "Forgotten 'debugger' statement?", | |
6057 | W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", | |
6058 | W089: "The body of a for in should be wrapped in an if statement to filter " + | |
6059 | "unwanted properties from the prototype.", | |
6060 | W090: "'{a}' is not a statement label.", | |
6061 | W091: "'{a}' is out of scope.", | |
6062 | W092: "Wrap the /regexp/ literal in parens to disambiguate the slash operator.", | |
6063 | W093: "Did you mean to return a conditional instead of an assignment?", | |
6064 | W094: "Unexpected comma.", | |
6065 | W095: "Expected a string and instead saw {a}.", | |
6066 | W096: "The '{a}' key may produce unexpected results.", | |
6067 | W097: "Use the function form of \"use strict\".", | |
6068 | W098: "'{a}' is defined but never used.", | |
6069 | W099: "Mixed spaces and tabs.", | |
6070 | W100: "This character may get silently deleted by one or more browsers.", | |
6071 | W101: "Line is too long.", | |
6072 | W102: "Trailing whitespace.", | |
6073 | W103: "The '{a}' property is deprecated.", | |
6074 | W104: "'{a}' is only available in JavaScript 1.7.", | |
6075 | W105: "Unexpected {a} in '{b}'.", | |
6076 | W106: "Identifier '{a}' is not in camel case.", | |
6077 | W107: "Script URL.", | |
6078 | W108: "Strings must use doublequote.", | |
6079 | W109: "Strings must use singlequote.", | |
6080 | W110: "Mixed double and single quotes.", | |
6081 | W112: "Unclosed string.", | |
6082 | W113: "Control character in string: {a}.", | |
6083 | W114: "Avoid {a}.", | |
6084 | W115: "Octal literals are not allowed in strict mode.", | |
6085 | W116: "Expected '{a}' and instead saw '{b}'.", | |
6086 | W117: "'{a}' is not defined.", | |
6087 | W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", | |
6088 | W119: "'{a}' is only available in ES6 (use esnext option).", | |
6089 | W120: "You might be leaking a variable ({a}) here." | |
6090 | }; | |
6091 | ||
6092 | var info = { | |
6093 | I001: "Comma warnings can be turned off with 'laxcomma'.", | |
6094 | I002: "Reserved words as properties can be used under the 'es5' option.", | |
6095 | I003: "ES5 option is now set per default" | |
6096 | }; | |
6097 | ||
6098 | exports.errors = {}; | |
6099 | exports.warnings = {}; | |
6100 | exports.info = {}; | |
6101 | ||
6102 | _.each(errors, function (desc, code) { | |
6103 | exports.errors[code] = { code: code, desc: desc }; | |
6104 | }); | |
6105 | ||
6106 | _.each(warnings, function (desc, code) { | |
6107 | exports.warnings[code] = { code: code, desc: desc }; | |
6108 | }); | |
6109 | ||
6110 | _.each(info, function (desc, code) { | |
6111 | exports.info[code] = { code: code, desc: desc }; | |
6112 | }); | |
6113 | ||
6114 | })() | |
6115 | },{"underscore":10}],8:[function(require,module,exports){ | |
6116 | (function(){/* | |
6117 | * Lexical analysis and token construction. | |
6118 | */ | |
6119 | ||
6120 | "use strict"; | |
6121 | ||
6122 | var _ = require("underscore"); | |
6123 | var events = require("events"); | |
6124 | var reg = require("./reg.js"); | |
6125 | var state = require("./state.js").state; | |
6126 | ||
6127 | // Some of these token types are from JavaScript Parser API | |
6128 | // while others are specific to JSHint parser. | |
6129 | // JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API | |
6130 | ||
6131 | var Token = { | |
6132 | Identifier: 1, | |
6133 | Punctuator: 2, | |
6134 | NumericLiteral: 3, | |
6135 | StringLiteral: 4, | |
6136 | Comment: 5, | |
6137 | Keyword: 6, | |
6138 | NullLiteral: 7, | |
6139 | BooleanLiteral: 8, | |
6140 | RegExp: 9 | |
6141 | }; | |
6142 | ||
6143 | // This is auto generated from the unicode tables. | |
6144 | // The tables are at: | |
6145 | // http://www.fileformat.info/info/unicode/category/Lu/list.htm | |
6146 | // http://www.fileformat.info/info/unicode/category/Ll/list.htm | |
6147 | // http://www.fileformat.info/info/unicode/category/Lt/list.htm | |
6148 | // http://www.fileformat.info/info/unicode/category/Lm/list.htm | |
6149 | // http://www.fileformat.info/info/unicode/category/Lo/list.htm | |
6150 | // http://www.fileformat.info/info/unicode/category/Nl/list.htm | |
6151 | ||
6152 | var unicodeLetterTable = [ | |
6153 | 170, 170, 181, 181, 186, 186, 192, 214, | |
6154 | 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, | |
6155 | 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, | |
6156 | 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, | |
6157 | 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, | |
6158 | 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, | |
6159 | 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, | |
6160 | 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, | |
6161 | 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2308, 2361, | |
6162 | 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, | |
6163 | 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, | |
6164 | 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, | |
6165 | 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, | |
6166 | 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, | |
6167 | 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, | |
6168 | 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, | |
6169 | 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, | |
6170 | 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, | |
6171 | 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, | |
6172 | 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, | |
6173 | 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, | |
6174 | 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, | |
6175 | 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, | |
6176 | 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, | |
6177 | 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, | |
6178 | 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, | |
6179 | 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, | |
6180 | 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, | |
6181 | 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, | |
6182 | 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, | |
6183 | 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, | |
6184 | 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, | |
6185 | 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4304, 4346, | |
6186 | 4348, 4348, 4352, 4680, 4682, 4685, 4688, 4694, 4696, 4696, | |
6187 | 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, | |
6188 | 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, | |
6189 | 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, | |
6190 | 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, | |
6191 | 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, | |
6192 | 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, | |
6193 | 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, | |
6194 | 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, | |
6195 | 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7104, 7141, | |
6196 | 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, | |
6197 | 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, | |
6198 | 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, | |
6199 | 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, | |
6200 | 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, | |
6201 | 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, | |
6202 | 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, | |
6203 | 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, | |
6204 | 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, | |
6205 | 11360, 11492, 11499, 11502, 11520, 11557, 11568, 11621, | |
6206 | 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, | |
6207 | 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, | |
6208 | 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, | |
6209 | 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, | |
6210 | 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, | |
6211 | 12593, 12686, 12704, 12730, 12784, 12799, 13312, 13312, | |
6212 | 19893, 19893, 19968, 19968, 40907, 40907, 40960, 42124, | |
6213 | 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, | |
6214 | 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, | |
6215 | 42786, 42888, 42891, 42894, 42896, 42897, 42912, 42921, | |
6216 | 43002, 43009, 43011, 43013, 43015, 43018, 43020, 43042, | |
6217 | 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, | |
6218 | 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, | |
6219 | 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, | |
6220 | 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, | |
6221 | 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, | |
6222 | 43739, 43741, 43777, 43782, 43785, 43790, 43793, 43798, | |
6223 | 43808, 43814, 43816, 43822, 43968, 44002, 44032, 44032, | |
6224 | 55203, 55203, 55216, 55238, 55243, 55291, 63744, 64045, | |
6225 | 64048, 64109, 64112, 64217, 64256, 64262, 64275, 64279, | |
6226 | 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, | |
6227 | 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, | |
6228 | 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, | |
6229 | 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, | |
6230 | 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, | |
6231 | 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, | |
6232 | 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, | |
6233 | 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66334, | |
6234 | 66352, 66378, 66432, 66461, 66464, 66499, 66504, 66511, | |
6235 | 66513, 66517, 66560, 66717, 67584, 67589, 67592, 67592, | |
6236 | 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, | |
6237 | 67840, 67861, 67872, 67897, 68096, 68096, 68112, 68115, | |
6238 | 68117, 68119, 68121, 68147, 68192, 68220, 68352, 68405, | |
6239 | 68416, 68437, 68448, 68466, 68608, 68680, 69635, 69687, | |
6240 | 69763, 69807, 73728, 74606, 74752, 74850, 77824, 78894, | |
6241 | 92160, 92728, 110592, 110593, 119808, 119892, 119894, 119964, | |
6242 | 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, | |
6243 | 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, | |
6244 | 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, | |
6245 | 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, | |
6246 | 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, | |
6247 | 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, | |
6248 | 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, | |
6249 | 131072, 131072, 173782, 173782, 173824, 173824, 177972, 177972, | |
6250 | 177984, 177984, 178205, 178205, 194560, 195101 | |
6251 | ]; | |
6252 | ||
6253 | var identifierStartTable = []; | |
6254 | ||
6255 | for (var i = 0; i < 128; i++) { | |
6256 | identifierStartTable[i] = | |
6257 | i === 36 || // $ | |
6258 | i >= 65 && i <= 90 || // A-Z | |
6259 | i === 95 || // _ | |
6260 | i >= 97 && i <= 122; // a-z | |
6261 | } | |
6262 | ||
6263 | var identifierPartTable = []; | |
6264 | ||
6265 | for (var i = 0; i < 128; i++) { | |
6266 | identifierPartTable[i] = | |
6267 | identifierStartTable[i] || // $, _, A-Z, a-z | |
6268 | i >= 48 && i <= 57; // 0-9 | |
6269 | } | |
6270 | ||
6271 | // Object that handles postponed lexing verifications that checks the parsed | |
6272 | // environment state. | |
6273 | ||
6274 | function asyncTrigger() { | |
6275 | var _checks = []; | |
6276 | ||
6277 | return { | |
6278 | push: function (fn) { | |
6279 | _checks.push(fn); | |
6280 | }, | |
6281 | ||
6282 | check: function () { | |
6283 | for (var check = 0; check < _checks.length; ++check) { | |
6284 | _checks[check](); | |
6285 | } | |
6286 | ||
6287 | _checks.splice(0, _checks.length); | |
6288 | } | |
6289 | }; | |
6290 | } | |
6291 | ||
6292 | /* | |
6293 | * Lexer for JSHint. | |
6294 | * | |
6295 | * This object does a char-by-char scan of the provided source code | |
6296 | * and produces a sequence of tokens. | |
6297 | * | |
6298 | * var lex = new Lexer("var i = 0;"); | |
6299 | * lex.start(); | |
6300 | * lex.token(); // returns the next token | |
6301 | * | |
6302 | * You have to use the token() method to move the lexer forward | |
6303 | * but you don't have to use its return value to get tokens. In addition | |
6304 | * to token() method returning the next token, the Lexer object also | |
6305 | * emits events. | |
6306 | * | |
6307 | * lex.on("Identifier", function (data) { | |
6308 | * if (data.name.indexOf("_") >= 0) { | |
6309 | * // Produce a warning. | |
6310 | * } | |
6311 | * }); | |
6312 | * | |
6313 | * Note that the token() method returns tokens in a JSLint-compatible | |
6314 | * format while the event emitter uses a slightly modified version of | |
6315 | * Mozilla's JavaScript Parser API. Eventually, we will move away from | |
6316 | * JSLint format. | |
6317 | */ | |
6318 | function Lexer(source) { | |
6319 | var lines = source; | |
6320 | ||
6321 | if (typeof lines === "string") { | |
6322 | lines = lines | |
6323 | .replace(/\r\n/g, "\n") | |
6324 | .replace(/\r/g, "\n") | |
6325 | .split("\n"); | |
6326 | } | |
6327 | ||
6328 | // If the first line is a shebang (#!), make it a blank and move on. | |
6329 | // Shebangs are used by Node scripts. | |
6330 | ||
6331 | if (lines[0] && lines[0].substr(0, 2) === "#!") { | |
6332 | lines[0] = ""; | |
6333 | } | |
6334 | ||
6335 | this.emitter = new events.EventEmitter(); | |
6336 | this.source = source; | |
6337 | this.setLines(lines); | |
6338 | this.prereg = true; | |
6339 | ||
6340 | this.line = 0; | |
6341 | this.char = 1; | |
6342 | this.from = 1; | |
6343 | this.input = ""; | |
6344 | ||
6345 | for (var i = 0; i < state.option.indent; i += 1) { | |
6346 | state.tab += " "; | |
6347 | } | |
6348 | } | |
6349 | ||
6350 | Lexer.prototype = { | |
6351 | _lines: [], | |
6352 | ||
6353 | getLines: function () { | |
6354 | this._lines = state.lines; | |
6355 | return this._lines; | |
6356 | }, | |
6357 | ||
6358 | setLines: function (val) { | |
6359 | this._lines = val; | |
6360 | state.lines = this._lines; | |
6361 | }, | |
6362 | ||
6363 | /* | |
6364 | * Return the next i character without actually moving the | |
6365 | * char pointer. | |
6366 | */ | |
6367 | peek: function (i) { | |
6368 | return this.input.charAt(i || 0); | |
6369 | }, | |
6370 | ||
6371 | /* | |
6372 | * Move the char pointer forward i times. | |
6373 | */ | |
6374 | skip: function (i) { | |
6375 | i = i || 1; | |
6376 | this.char += i; | |
6377 | this.input = this.input.slice(i); | |
6378 | }, | |
6379 | ||
6380 | /* | |
6381 | * Subscribe to a token event. The API for this method is similar | |
6382 | * Underscore.js i.e. you can subscribe to multiple events with | |
6383 | * one call: | |
6384 | * | |
6385 | * lex.on("Identifier Number", function (data) { | |
6386 | * // ... | |
6387 | * }); | |
6388 | */ | |
6389 | on: function (names, listener) { | |
6390 | names.split(" ").forEach(function (name) { | |
6391 | this.emitter.on(name, listener); | |
6392 | }.bind(this)); | |
6393 | }, | |
6394 | ||
6395 | /* | |
6396 | * Trigger a token event. All arguments will be passed to each | |
6397 | * listener. | |
6398 | */ | |
6399 | trigger: function () { | |
6400 | this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); | |
6401 | }, | |
6402 | ||
6403 | /* | |
6404 | * Postpone a token event. the checking condition is set as | |
6405 | * last parameter, and the trigger function is called in a | |
6406 | * stored callback. To be later called using the check() function | |
6407 | * by the parser. This avoids parser's peek() to give the lexer | |
6408 | * a false context. | |
6409 | */ | |
6410 | triggerAsync: function (type, args, checks, fn) { | |
6411 | checks.push(function () { | |
6412 | if (fn()) { | |
6413 | this.trigger(type, args); | |
6414 | } | |
6415 | }.bind(this)); | |
6416 | }, | |
6417 | ||
6418 | /* | |
6419 | * Extract a punctuator out of the next sequence of characters | |
6420 | * or return 'null' if its not possible. | |
6421 | * | |
6422 | * This method's implementation was heavily influenced by the | |
6423 | * scanPunctuator function in the Esprima parser's source code. | |
6424 | */ | |
6425 | scanPunctuator: function () { | |
6426 | var ch1 = this.peek(); | |
6427 | var ch2, ch3, ch4; | |
6428 | ||
6429 | switch (ch1) { | |
6430 | // Most common single-character punctuators | |
6431 | case ".": | |
6432 | if ((/^[0-9]$/).test(this.peek(1))) { | |
6433 | return null; | |
6434 | } | |
6435 | if (this.peek(1) === "." && this.peek(2) === ".") { | |
6436 | return { | |
6437 | type: Token.Punctuator, | |
6438 | value: "..." | |
6439 | }; | |
6440 | } | |
6441 | /* falls through */ | |
6442 | case "(": | |
6443 | case ")": | |
6444 | case ";": | |
6445 | case ",": | |
6446 | case "{": | |
6447 | case "}": | |
6448 | case "[": | |
6449 | case "]": | |
6450 | case ":": | |
6451 | case "~": | |
6452 | case "?": | |
6453 | return { | |
6454 | type: Token.Punctuator, | |
6455 | value: ch1 | |
6456 | }; | |
6457 | ||
6458 | // A pound sign (for Node shebangs) | |
6459 | case "#": | |
6460 | return { | |
6461 | type: Token.Punctuator, | |
6462 | value: ch1 | |
6463 | }; | |
6464 | ||
6465 | // We're at the end of input | |
6466 | case "": | |
6467 | return null; | |
6468 | } | |
6469 | ||
6470 | // Peek more characters | |
6471 | ||
6472 | ch2 = this.peek(1); | |
6473 | ch3 = this.peek(2); | |
6474 | ch4 = this.peek(3); | |
6475 | ||
6476 | // 4-character punctuator: >>>= | |
6477 | ||
6478 | if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { | |
6479 | return { | |
6480 | type: Token.Punctuator, | |
6481 | value: ">>>=" | |
6482 | }; | |
6483 | } | |
6484 | ||
6485 | // 3-character punctuators: === !== >>> <<= >>= | |
6486 | ||
6487 | if (ch1 === "=" && ch2 === "=" && ch3 === "=") { | |
6488 | return { | |
6489 | type: Token.Punctuator, | |
6490 | value: "===" | |
6491 | }; | |
6492 | } | |
6493 | ||
6494 | if (ch1 === "!" && ch2 === "=" && ch3 === "=") { | |
6495 | return { | |
6496 | type: Token.Punctuator, | |
6497 | value: "!==" | |
6498 | }; | |
6499 | } | |
6500 | ||
6501 | if (ch1 === ">" && ch2 === ">" && ch3 === ">") { | |
6502 | return { | |
6503 | type: Token.Punctuator, | |
6504 | value: ">>>" | |
6505 | }; | |
6506 | } | |
6507 | ||
6508 | if (ch1 === "<" && ch2 === "<" && ch3 === "=") { | |
6509 | return { | |
6510 | type: Token.Punctuator, | |
6511 | value: "<<=" | |
6512 | }; | |
6513 | } | |
6514 | ||
6515 | if (ch1 === ">" && ch2 === ">" && ch3 === "=") { | |
6516 | return { | |
6517 | type: Token.Punctuator, | |
6518 | value: ">>=" | |
6519 | }; | |
6520 | } | |
6521 | ||
6522 | // Fat arrow punctuator | |
6523 | if (ch1 === "=" && ch2 === ">") { | |
6524 | return { | |
6525 | type: Token.Punctuator, | |
6526 | value: ch1 + ch2 | |
6527 | }; | |
6528 | } | |
6529 | ||
6530 | // 2-character punctuators: <= >= == != ++ -- << >> && || | |
6531 | // += -= *= %= &= |= ^= (but not /=, see below) | |
6532 | if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) { | |
6533 | return { | |
6534 | type: Token.Punctuator, | |
6535 | value: ch1 + ch2 | |
6536 | }; | |
6537 | } | |
6538 | ||
6539 | if ("<>=!+-*%&|^".indexOf(ch1) >= 0) { | |
6540 | if (ch2 === "=") { | |
6541 | return { | |
6542 | type: Token.Punctuator, | |
6543 | value: ch1 + ch2 | |
6544 | }; | |
6545 | } | |
6546 | ||
6547 | return { | |
6548 | type: Token.Punctuator, | |
6549 | value: ch1 | |
6550 | }; | |
6551 | } | |
6552 | ||
6553 | // Special case: /=. We need to make sure that this is an | |
6554 | // operator and not a regular expression. | |
6555 | ||
6556 | if (ch1 === "/") { | |
6557 | if (ch2 === "=" && /\/=(?!(\S*\/[gim]?))/.test(this.input)) { | |
6558 | // /= is not a part of a regular expression, return it as a | |
6559 | // punctuator. | |
6560 | return { | |
6561 | type: Token.Punctuator, | |
6562 | value: "/=" | |
6563 | }; | |
6564 | } | |
6565 | ||
6566 | return { | |
6567 | type: Token.Punctuator, | |
6568 | value: "/" | |
6569 | }; | |
6570 | } | |
6571 | ||
6572 | return null; | |
6573 | }, | |
6574 | ||
6575 | /* | |
6576 | * Extract a comment out of the next sequence of characters and/or | |
6577 | * lines or return 'null' if its not possible. Since comments can | |
6578 | * span across multiple lines this method has to move the char | |
6579 | * pointer. | |
6580 | * | |
6581 | * In addition to normal JavaScript comments (// and /*) this method | |
6582 | * also recognizes JSHint- and JSLint-specific comments such as | |
6583 | * /*jshint, /*jslint, /*globals and so on. | |
6584 | */ | |
6585 | scanComments: function () { | |
6586 | var ch1 = this.peek(); | |
6587 | var ch2 = this.peek(1); | |
6588 | var rest = this.input.substr(2); | |
6589 | var startLine = this.line; | |
6590 | var startChar = this.char; | |
6591 | ||
6592 | // Create a comment token object and make sure it | |
6593 | // has all the data JSHint needs to work with special | |
6594 | // comments. | |
6595 | ||
6596 | function commentToken(label, body, opt) { | |
6597 | var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"]; | |
6598 | var isSpecial = false; | |
6599 | var value = label + body; | |
6600 | var commentType = "plain"; | |
6601 | opt = opt || {}; | |
6602 | ||
6603 | if (opt.isMultiline) { | |
6604 | value += "*/"; | |
6605 | } | |
6606 | ||
6607 | special.forEach(function (str) { | |
6608 | if (isSpecial) { | |
6609 | return; | |
6610 | } | |
6611 | ||
6612 | // Don't recognize any special comments other than jshint for single-line | |
6613 | // comments. This introduced many problems with legit comments. | |
6614 | if (label === "//" && str !== "jshint") { | |
6615 | return; | |
6616 | } | |
6617 | ||
6618 | if (body.substr(0, str.length) === str) { | |
6619 | isSpecial = true; | |
6620 | label = label + str; | |
6621 | body = body.substr(str.length); | |
6622 | } | |
6623 | ||
6624 | if (!isSpecial && body.charAt(0) === " " && body.substr(1, str.length) === str) { | |
6625 | isSpecial = true; | |
6626 | label = label + " " + str; | |
6627 | body = body.substr(str.length + 1); | |
6628 | } | |
6629 | ||
6630 | if (!isSpecial) { | |
6631 | return; | |
6632 | } | |
6633 | ||
6634 | switch (str) { | |
6635 | case "member": | |
6636 | commentType = "members"; | |
6637 | break; | |
6638 | case "global": | |
6639 | commentType = "globals"; | |
6640 | break; | |
6641 | default: | |
6642 | commentType = str; | |
6643 | } | |
6644 | }); | |
6645 | ||
6646 | return { | |
6647 | type: Token.Comment, | |
6648 | commentType: commentType, | |
6649 | value: value, | |
6650 | body: body, | |
6651 | isSpecial: isSpecial, | |
6652 | isMultiline: opt.isMultiline || false, | |
6653 | isMalformed: opt.isMalformed || false | |
6654 | }; | |
6655 | } | |
6656 | ||
6657 | // End of unbegun comment. Raise an error and skip that input. | |
6658 | if (ch1 === "*" && ch2 === "/") { | |
6659 | this.trigger("error", { | |
6660 | code: "E018", | |
6661 | line: startLine, | |
6662 | character: startChar | |
6663 | }); | |
6664 | ||
6665 | this.skip(2); | |
6666 | return null; | |
6667 | } | |
6668 | ||
6669 | // Comments must start either with // or /* | |
6670 | if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { | |
6671 | return null; | |
6672 | } | |
6673 | ||
6674 | // One-line comment | |
6675 | if (ch2 === "/") { | |
6676 | this.skip(this.input.length); // Skip to the EOL. | |
6677 | return commentToken("//", rest); | |
6678 | } | |
6679 | ||
6680 | var body = ""; | |
6681 | ||
6682 | /* Multi-line comment */ | |
6683 | if (ch2 === "*") { | |
6684 | this.skip(2); | |
6685 | ||
6686 | while (this.peek() !== "*" || this.peek(1) !== "/") { | |
6687 | if (this.peek() === "") { // End of Line | |
6688 | body += "\n"; | |
6689 | ||
6690 | // If we hit EOF and our comment is still unclosed, | |
6691 | // trigger an error and end the comment implicitly. | |
6692 | if (!this.nextLine()) { | |
6693 | this.trigger("error", { | |
6694 | code: "E017", | |
6695 | line: startLine, | |
6696 | character: startChar | |
6697 | }); | |
6698 | ||
6699 | return commentToken("/*", body, { | |
6700 | isMultiline: true, | |
6701 | isMalformed: true | |
6702 | }); | |
6703 | } | |
6704 | } else { | |
6705 | body += this.peek(); | |
6706 | this.skip(); | |
6707 | } | |
6708 | } | |
6709 | ||
6710 | this.skip(2); | |
6711 | return commentToken("/*", body, { isMultiline: true }); | |
6712 | } | |
6713 | }, | |
6714 | ||
6715 | /* | |
6716 | * Extract a keyword out of the next sequence of characters or | |
6717 | * return 'null' if its not possible. | |
6718 | */ | |
6719 | scanKeyword: function () { | |
6720 | var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); | |
6721 | var keywords = [ | |
6722 | "if", "in", "do", "var", "for", "new", | |
6723 | "try", "let", "this", "else", "case", | |
6724 | "void", "with", "enum", "while", "break", | |
6725 | "catch", "throw", "const", "yield", "class", | |
6726 | "super", "return", "typeof", "delete", | |
6727 | "switch", "export", "import", "default", | |
6728 | "finally", "extends", "function", "continue", | |
6729 | "debugger", "instanceof" | |
6730 | ]; | |
6731 | ||
6732 | if (result && keywords.indexOf(result[0]) >= 0) { | |
6733 | return { | |
6734 | type: Token.Keyword, | |
6735 | value: result[0] | |
6736 | }; | |
6737 | } | |
6738 | ||
6739 | return null; | |
6740 | }, | |
6741 | ||
6742 | /* | |
6743 | * Extract a JavaScript identifier out of the next sequence of | |
6744 | * characters or return 'null' if its not possible. In addition, | |
6745 | * to Identifier this method can also produce BooleanLiteral | |
6746 | * (true/false) and NullLiteral (null). | |
6747 | */ | |
6748 | scanIdentifier: function () { | |
6749 | var id = ""; | |
6750 | var index = 0; | |
6751 | var type, char; | |
6752 | ||
6753 | // Detects any character in the Unicode categories "Uppercase | |
6754 | // letter (Lu)", "Lowercase letter (Ll)", "Titlecase letter | |
6755 | // (Lt)", "Modifier letter (Lm)", "Other letter (Lo)", or | |
6756 | // "Letter number (Nl)". | |
6757 | // | |
6758 | // Both approach and unicodeLetterTable were borrowed from | |
6759 | // Google's Traceur. | |
6760 | ||
6761 | function isUnicodeLetter(code) { | |
6762 | for (var i = 0; i < unicodeLetterTable.length;) { | |
6763 | if (code < unicodeLetterTable[i++]) { | |
6764 | return false; | |
6765 | } | |
6766 | ||
6767 | if (code <= unicodeLetterTable[i++]) { | |
6768 | return true; | |
6769 | } | |
6770 | } | |
6771 | ||
6772 | return false; | |
6773 | } | |
6774 | ||
6775 | function isHexDigit(str) { | |
6776 | return (/^[0-9a-fA-F]$/).test(str); | |
6777 | } | |
6778 | ||
6779 | var readUnicodeEscapeSequence = function () { | |
6780 | /*jshint validthis:true */ | |
6781 | index += 1; | |
6782 | ||
6783 | if (this.peek(index) !== "u") { | |
6784 | return null; | |
6785 | } | |
6786 | ||
6787 | var ch1 = this.peek(index + 1); | |
6788 | var ch2 = this.peek(index + 2); | |
6789 | var ch3 = this.peek(index + 3); | |
6790 | var ch4 = this.peek(index + 4); | |
6791 | var code; | |
6792 | ||
6793 | if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) { | |
6794 | code = parseInt(ch1 + ch2 + ch3 + ch4, 16); | |
6795 | ||
6796 | if (isUnicodeLetter(code)) { | |
6797 | index += 5; | |
6798 | return "\\u" + ch1 + ch2 + ch3 + ch4; | |
6799 | } | |
6800 | ||
6801 | return null; | |
6802 | } | |
6803 | ||
6804 | return null; | |
6805 | }.bind(this); | |
6806 | ||
6807 | var getIdentifierStart = function () { | |
6808 | /*jshint validthis:true */ | |
6809 | var chr = this.peek(index); | |
6810 | var code = chr.charCodeAt(0); | |
6811 | ||
6812 | if (code === 92) { | |
6813 | return readUnicodeEscapeSequence(); | |
6814 | } | |
6815 | ||
6816 | if (code < 128) { | |
6817 | if (identifierStartTable[code]) { | |
6818 | index += 1; | |
6819 | return chr; | |
6820 | } | |
6821 | ||
6822 | return null; | |
6823 | } | |
6824 | ||
6825 | if (isUnicodeLetter(code)) { | |
6826 | index += 1; | |
6827 | return chr; | |
6828 | } | |
6829 | ||
6830 | return null; | |
6831 | }.bind(this); | |
6832 | ||
6833 | var getIdentifierPart = function () { | |
6834 | /*jshint validthis:true */ | |
6835 | var chr = this.peek(index); | |
6836 | var code = chr.charCodeAt(0); | |
6837 | ||
6838 | if (code === 92) { | |
6839 | return readUnicodeEscapeSequence(); | |
6840 | } | |
6841 | ||
6842 | if (code < 128) { | |
6843 | if (identifierPartTable[code]) { | |
6844 | index += 1; | |
6845 | return chr; | |
6846 | } | |
6847 | ||
6848 | return null; | |
6849 | } | |
6850 | ||
6851 | if (isUnicodeLetter(code)) { | |
6852 | index += 1; | |
6853 | return chr; | |
6854 | } | |
6855 | ||
6856 | return null; | |
6857 | }.bind(this); | |
6858 | ||
6859 | char = getIdentifierStart(); | |
6860 | if (char === null) { | |
6861 | return null; | |
6862 | } | |
6863 | ||
6864 | id = char; | |
6865 | for (;;) { | |
6866 | char = getIdentifierPart(); | |
6867 | ||
6868 | if (char === null) { | |
6869 | break; | |
6870 | } | |
6871 | ||
6872 | id += char; | |
6873 | } | |
6874 | ||
6875 | switch (id) { | |
6876 | case "true": | |
6877 | case "false": | |
6878 | type = Token.BooleanLiteral; | |
6879 | break; | |
6880 | case "null": | |
6881 | type = Token.NullLiteral; | |
6882 | break; | |
6883 | default: | |
6884 | type = Token.Identifier; | |
6885 | } | |
6886 | ||
6887 | return { | |
6888 | type: type, | |
6889 | value: id | |
6890 | }; | |
6891 | }, | |
6892 | ||
6893 | /* | |
6894 | * Extract a numeric literal out of the next sequence of | |
6895 | * characters or return 'null' if its not possible. This method | |
6896 | * supports all numeric literals described in section 7.8.3 | |
6897 | * of the EcmaScript 5 specification. | |
6898 | * | |
6899 | * This method's implementation was heavily influenced by the | |
6900 | * scanNumericLiteral function in the Esprima parser's source code. | |
6901 | */ | |
6902 | scanNumericLiteral: function () { | |
6903 | var index = 0; | |
6904 | var value = ""; | |
6905 | var length = this.input.length; | |
6906 | var char = this.peek(index); | |
6907 | var bad; | |
6908 | ||
6909 | function isDecimalDigit(str) { | |
6910 | return (/^[0-9]$/).test(str); | |
6911 | } | |
6912 | ||
6913 | function isOctalDigit(str) { | |
6914 | return (/^[0-7]$/).test(str); | |
6915 | } | |
6916 | ||
6917 | function isHexDigit(str) { | |
6918 | return (/^[0-9a-fA-F]$/).test(str); | |
6919 | } | |
6920 | ||
6921 | function isIdentifierStart(ch) { | |
6922 | return (ch === "$") || (ch === "_") || (ch === "\\") || | |
6923 | (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); | |
6924 | } | |
6925 | ||
6926 | // Numbers must start either with a decimal digit or a point. | |
6927 | ||
6928 | if (char !== "." && !isDecimalDigit(char)) { | |
6929 | return null; | |
6930 | } | |
6931 | ||
6932 | if (char !== ".") { | |
6933 | value = this.peek(index); | |
6934 | index += 1; | |
6935 | char = this.peek(index); | |
6936 | ||
6937 | if (value === "0") { | |
6938 | // Base-16 numbers. | |
6939 | if (char === "x" || char === "X") { | |
6940 | index += 1; | |
6941 | value += char; | |
6942 | ||
6943 | while (index < length) { | |
6944 | char = this.peek(index); | |
6945 | if (!isHexDigit(char)) { | |
6946 | break; | |
6947 | } | |
6948 | value += char; | |
6949 | index += 1; | |
6950 | } | |
6951 | ||
6952 | if (value.length <= 2) { // 0x | |
6953 | return { | |
6954 | type: Token.NumericLiteral, | |
6955 | value: value, | |
6956 | isMalformed: true | |
6957 | }; | |
6958 | } | |
6959 | ||
6960 | if (index < length) { | |
6961 | char = this.peek(index); | |
6962 | if (isIdentifierStart(char)) { | |
6963 | return null; | |
6964 | } | |
6965 | } | |
6966 | ||
6967 | return { | |
6968 | type: Token.NumericLiteral, | |
6969 | value: value, | |
6970 | base: 16, | |
6971 | isMalformed: false | |
6972 | }; | |
6973 | } | |
6974 | ||
6975 | // Base-8 numbers. | |
6976 | if (isOctalDigit(char)) { | |
6977 | index += 1; | |
6978 | value += char; | |
6979 | bad = false; | |
6980 | ||
6981 | while (index < length) { | |
6982 | char = this.peek(index); | |
6983 | ||
6984 | // Numbers like '019' (note the 9) are not valid octals | |
6985 | // but we still parse them and mark as malformed. | |
6986 | ||
6987 | if (isDecimalDigit(char)) { | |
6988 | bad = true; | |
6989 | } else if (!isOctalDigit(char)) { | |
6990 | break; | |
6991 | } | |
6992 | value += char; | |
6993 | index += 1; | |
6994 | } | |
6995 | ||
6996 | if (index < length) { | |
6997 | char = this.peek(index); | |
6998 | if (isIdentifierStart(char)) { | |
6999 | return null; | |
7000 | } | |
7001 | } | |
7002 | ||
7003 | return { | |
7004 | type: Token.NumericLiteral, | |
7005 | value: value, | |
7006 | base: 8, | |
7007 | isMalformed: false | |
7008 | }; | |
7009 | } | |
7010 | ||
7011 | // Decimal numbers that start with '0' such as '09' are illegal | |
7012 | // but we still parse them and return as malformed. | |
7013 | ||
7014 | if (isDecimalDigit(char)) { | |
7015 | index += 1; | |
7016 | value += char; | |
7017 | } | |
7018 | } | |
7019 | ||
7020 | while (index < length) { | |
7021 | char = this.peek(index); | |
7022 | if (!isDecimalDigit(char)) { | |
7023 | break; | |
7024 | } | |
7025 | value += char; | |
7026 | index += 1; | |
7027 | } | |
7028 | } | |
7029 | ||
7030 | // Decimal digits. | |
7031 | ||
7032 | if (char === ".") { | |
7033 | value += char; | |
7034 | index += 1; | |
7035 | ||
7036 | while (index < length) { | |
7037 | char = this.peek(index); | |
7038 | if (!isDecimalDigit(char)) { | |
7039 | break; | |
7040 | } | |
7041 | value += char; | |
7042 | index += 1; | |
7043 | } | |
7044 | } | |
7045 | ||
7046 | // Exponent part. | |
7047 | ||
7048 | if (char === "e" || char === "E") { | |
7049 | value += char; | |
7050 | index += 1; | |
7051 | char = this.peek(index); | |
7052 | ||
7053 | if (char === "+" || char === "-") { | |
7054 | value += this.peek(index); | |
7055 | index += 1; | |
7056 | } | |
7057 | ||
7058 | char = this.peek(index); | |
7059 | if (isDecimalDigit(char)) { | |
7060 | value += char; | |
7061 | index += 1; | |
7062 | ||
7063 | while (index < length) { | |
7064 | char = this.peek(index); | |
7065 | if (!isDecimalDigit(char)) { | |
7066 | break; | |
7067 | } | |
7068 | value += char; | |
7069 | index += 1; | |
7070 | } | |
7071 | } else { | |
7072 | return null; | |
7073 | } | |
7074 | } | |
7075 | ||
7076 | if (index < length) { | |
7077 | char = this.peek(index); | |
7078 | if (isIdentifierStart(char)) { | |
7079 | return null; | |
7080 | } | |
7081 | } | |
7082 | ||
7083 | return { | |
7084 | type: Token.NumericLiteral, | |
7085 | value: value, | |
7086 | base: 10, | |
7087 | isMalformed: !isFinite(value) | |
7088 | }; | |
7089 | }, | |
7090 | ||
7091 | /* | |
7092 | * Extract a string out of the next sequence of characters and/or | |
7093 | * lines or return 'null' if its not possible. Since strings can | |
7094 | * span across multiple lines this method has to move the char | |
7095 | * pointer. | |
7096 | * | |
7097 | * This method recognizes pseudo-multiline JavaScript strings: | |
7098 | * | |
7099 | * var str = "hello\ | |
7100 | * world"; | |
7101 | */ | |
7102 | scanStringLiteral: function (checks) { | |
7103 | /*jshint loopfunc:true */ | |
7104 | var quote = this.peek(); | |
7105 | ||
7106 | // String must start with a quote. | |
7107 | if (quote !== "\"" && quote !== "'") { | |
7108 | return null; | |
7109 | } | |
7110 | ||
7111 | // In JSON strings must always use double quotes. | |
7112 | this.triggerAsync("warning", { | |
7113 | code: "W108", | |
7114 | line: this.line, | |
7115 | character: this.char // +1? | |
7116 | }, checks, function () { return state.jsonMode && quote !== "\""; }); | |
7117 | ||
7118 | var value = ""; | |
7119 | var startLine = this.line; | |
7120 | var startChar = this.char; | |
7121 | var allowNewLine = false; | |
7122 | ||
7123 | this.skip(); | |
7124 | ||
7125 | while (this.peek() !== quote) { | |
7126 | while (this.peek() === "") { // End Of Line | |
7127 | ||
7128 | // If an EOL is not preceded by a backslash, show a warning | |
7129 | // and proceed like it was a legit multi-line string where | |
7130 | // author simply forgot to escape the newline symbol. | |
7131 | // | |
7132 | // Another approach is to implicitly close a string on EOL | |
7133 | // but it generates too many false positives. | |
7134 | ||
7135 | if (!allowNewLine) { | |
7136 | this.trigger("warning", { | |
7137 | code: "W112", | |
7138 | line: this.line, | |
7139 | character: this.char | |
7140 | }); | |
7141 | } else { | |
7142 | allowNewLine = false; | |
7143 | ||
7144 | // Otherwise show a warning if multistr option was not set. | |
7145 | // For JSON, show warning no matter what. | |
7146 | ||
7147 | this.triggerAsync("warning", { | |
7148 | code: "W043", | |
7149 | line: this.line, | |
7150 | character: this.char | |
7151 | }, checks, function () { return !state.option.multistr; }); | |
7152 | ||
7153 | this.triggerAsync("warning", { | |
7154 | code: "W042", | |
7155 | line: this.line, | |
7156 | character: this.char | |
7157 | }, checks, function () { return state.jsonMode && state.option.multistr; }); | |
7158 | } | |
7159 | ||
7160 | // If we get an EOF inside of an unclosed string, show an | |
7161 | // error and implicitly close it at the EOF point. | |
7162 | ||
7163 | if (!this.nextLine()) { | |
7164 | this.trigger("error", { | |
7165 | code: "E029", | |
7166 | line: startLine, | |
7167 | character: startChar | |
7168 | }); | |
7169 | ||
7170 | return { | |
7171 | type: Token.StringLiteral, | |
7172 | value: value, | |
7173 | isUnclosed: true, | |
7174 | quote: quote | |
7175 | }; | |
7176 | } | |
7177 | } | |
7178 | ||
7179 | allowNewLine = false; | |
7180 | var char = this.peek(); | |
7181 | var jump = 1; // A length of a jump, after we're done | |
7182 | // parsing this character. | |
7183 | ||
7184 | if (char < " ") { | |
7185 | // Warn about a control character in a string. | |
7186 | this.trigger("warning", { | |
7187 | code: "W113", | |
7188 | line: this.line, | |
7189 | character: this.char, | |
7190 | data: [ "<non-printable>" ] | |
7191 | }); | |
7192 | } | |
7193 | ||
7194 | // Special treatment for some escaped characters. | |
7195 | ||
7196 | if (char === "\\") { | |
7197 | this.skip(); | |
7198 | char = this.peek(); | |
7199 | ||
7200 | switch (char) { | |
7201 | case "'": | |
7202 | this.triggerAsync("warning", { | |
7203 | code: "W114", | |
7204 | line: this.line, | |
7205 | character: this.char, | |
7206 | data: [ "\\'" ] | |
7207 | }, checks, function () {return state.jsonMode; }); | |
7208 | break; | |
7209 | case "b": | |
7210 | char = "\b"; | |
7211 | break; | |
7212 | case "f": | |
7213 | char = "\f"; | |
7214 | break; | |
7215 | case "n": | |
7216 | char = "\n"; | |
7217 | break; | |
7218 | case "r": | |
7219 | char = "\r"; | |
7220 | break; | |
7221 | case "t": | |
7222 | char = "\t"; | |
7223 | break; | |
7224 | case "0": | |
7225 | char = "\0"; | |
7226 | ||
7227 | // Octal literals fail in strict mode. | |
7228 | // Check if the number is between 00 and 07. | |
7229 | var n = parseInt(this.peek(1), 10); | |
7230 | this.triggerAsync("warning", { | |
7231 | code: "W115", | |
7232 | line: this.line, | |
7233 | character: this.char | |
7234 | }, checks, | |
7235 | function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); | |
7236 | break; | |
7237 | case "u": | |
7238 | char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); | |
7239 | jump = 5; | |
7240 | break; | |
7241 | case "v": | |
7242 | this.triggerAsync("warning", { | |
7243 | code: "W114", | |
7244 | line: this.line, | |
7245 | character: this.char, | |
7246 | data: [ "\\v" ] | |
7247 | }, checks, function () { return state.jsonMode; }); | |
7248 | ||
7249 | char = "\v"; | |
7250 | break; | |
7251 | case "x": | |
7252 | var x = parseInt(this.input.substr(1, 2), 16); | |
7253 | ||
7254 | this.triggerAsync("warning", { | |
7255 | code: "W114", | |
7256 | line: this.line, | |
7257 | character: this.char, | |
7258 | data: [ "\\x-" ] | |
7259 | }, checks, function () { return state.jsonMode; }); | |
7260 | ||
7261 | char = String.fromCharCode(x); | |
7262 | jump = 3; | |
7263 | break; | |
7264 | case "\\": | |
7265 | case "\"": | |
7266 | case "/": | |
7267 | break; | |
7268 | case "": | |
7269 | allowNewLine = true; | |
7270 | char = ""; | |
7271 | break; | |
7272 | case "!": | |
7273 | if (value.slice(value.length - 2) === "<") { | |
7274 | break; | |
7275 | } | |
7276 | ||
7277 | /*falls through */ | |
7278 | default: | |
7279 | // Weird escaping. | |
7280 | this.trigger("warning", { | |
7281 | code: "W044", | |
7282 | line: this.line, | |
7283 | character: this.char | |
7284 | }); | |
7285 | } | |
7286 | } | |
7287 | ||
7288 | value += char; | |
7289 | this.skip(jump); | |
7290 | } | |
7291 | ||
7292 | this.skip(); | |
7293 | return { | |
7294 | type: Token.StringLiteral, | |
7295 | value: value, | |
7296 | isUnclosed: false, | |
7297 | quote: quote | |
7298 | }; | |
7299 | }, | |
7300 | ||
7301 | /* | |
7302 | * Extract a regular expression out of the next sequence of | |
7303 | * characters and/or lines or return 'null' if its not possible. | |
7304 | * | |
7305 | * This method is platform dependent: it accepts almost any | |
7306 | * regular expression values but then tries to compile and run | |
7307 | * them using system's RegExp object. This means that there are | |
7308 | * rare edge cases where one JavaScript engine complains about | |
7309 | * your regular expression while others don't. | |
7310 | */ | |
7311 | scanRegExp: function () { | |
7312 | var index = 0; | |
7313 | var length = this.input.length; | |
7314 | var char = this.peek(); | |
7315 | var value = char; | |
7316 | var body = ""; | |
7317 | var flags = []; | |
7318 | var malformed = false; | |
7319 | var isCharSet = false; | |
7320 | var terminated; | |
7321 | ||
7322 | var scanUnexpectedChars = function () { | |
7323 | // Unexpected control character | |
7324 | if (char < " ") { | |
7325 | malformed = true; | |
7326 | this.trigger("warning", { | |
7327 | code: "W048", | |
7328 | line: this.line, | |
7329 | character: this.char | |
7330 | }); | |
7331 | } | |
7332 | ||
7333 | // Unexpected escaped character | |
7334 | if (char === "<") { | |
7335 | malformed = true; | |
7336 | this.trigger("warning", { | |
7337 | code: "W049", | |
7338 | line: this.line, | |
7339 | character: this.char, | |
7340 | data: [ char ] | |
7341 | }); | |
7342 | } | |
7343 | }.bind(this); | |
7344 | ||
7345 | // Regular expressions must start with '/' | |
7346 | if (!this.prereg || char !== "/") { | |
7347 | return null; | |
7348 | } | |
7349 | ||
7350 | index += 1; | |
7351 | terminated = false; | |
7352 | ||
7353 | // Try to get everything in between slashes. A couple of | |
7354 | // cases aside (see scanUnexpectedChars) we don't really | |
7355 | // care whether the resulting expression is valid or not. | |
7356 | // We will check that later using the RegExp object. | |
7357 | ||
7358 | while (index < length) { | |
7359 | char = this.peek(index); | |
7360 | value += char; | |
7361 | body += char; | |
7362 | ||
7363 | if (isCharSet) { | |
7364 | if (char === "]") { | |
7365 | if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { | |
7366 | isCharSet = false; | |
7367 | } | |
7368 | } | |
7369 | ||
7370 | if (char === "\\") { | |
7371 | index += 1; | |
7372 | char = this.peek(index); | |
7373 | body += char; | |
7374 | value += char; | |
7375 | ||
7376 | scanUnexpectedChars(); | |
7377 | } | |
7378 | ||
7379 | index += 1; | |
7380 | continue; | |
7381 | } | |
7382 | ||
7383 | if (char === "\\") { | |
7384 | index += 1; | |
7385 | char = this.peek(index); | |
7386 | body += char; | |
7387 | value += char; | |
7388 | ||
7389 | scanUnexpectedChars(); | |
7390 | ||
7391 | if (char === "/") { | |
7392 | index += 1; | |
7393 | continue; | |
7394 | } | |
7395 | ||
7396 | if (char === "[") { | |
7397 | index += 1; | |
7398 | continue; | |
7399 | } | |
7400 | } | |
7401 | ||
7402 | if (char === "[") { | |
7403 | isCharSet = true; | |
7404 | index += 1; | |
7405 | continue; | |
7406 | } | |
7407 | ||
7408 | if (char === "/") { | |
7409 | body = body.substr(0, body.length - 1); | |
7410 | terminated = true; | |
7411 | index += 1; | |
7412 | break; | |
7413 | } | |
7414 | ||
7415 | index += 1; | |
7416 | } | |
7417 | ||
7418 | // A regular expression that was never closed is an | |
7419 | // error from which we cannot recover. | |
7420 | ||
7421 | if (!terminated) { | |
7422 | this.trigger("error", { | |
7423 | code: "E015", | |
7424 | line: this.line, | |
7425 | character: this.from | |
7426 | }); | |
7427 | ||
7428 | return void this.trigger("fatal", { | |
7429 | line: this.line, | |
7430 | from: this.from | |
7431 | }); | |
7432 | } | |
7433 | ||
7434 | // Parse flags (if any). | |
7435 | ||
7436 | while (index < length) { | |
7437 | char = this.peek(index); | |
7438 | if (!/[gim]/.test(char)) { | |
7439 | break; | |
7440 | } | |
7441 | flags.push(char); | |
7442 | value += char; | |
7443 | index += 1; | |
7444 | } | |
7445 | ||
7446 | // Check regular expression for correctness. | |
7447 | ||
7448 | try { | |
7449 | new RegExp(body, flags.join("")); | |
7450 | } catch (err) { | |
7451 | malformed = true; | |
7452 | this.trigger("error", { | |
7453 | code: "E016", | |
7454 | line: this.line, | |
7455 | character: this.char, | |
7456 | data: [ err.message ] // Platform dependent! | |
7457 | }); | |
7458 | } | |
7459 | ||
7460 | return { | |
7461 | type: Token.RegExp, | |
7462 | value: value, | |
7463 | flags: flags, | |
7464 | isMalformed: malformed | |
7465 | }; | |
7466 | }, | |
7467 | ||
7468 | /* | |
56c4a2cb | 7469 | * Scan for any occurrence of mixed tabs and spaces. If smarttabs option |
eb39fafa DC |
7470 | * is on, ignore tabs followed by spaces. |
7471 | * | |
7472 | * Tabs followed by one space followed by a block comment are allowed. | |
7473 | */ | |
7474 | scanMixedSpacesAndTabs: function () { | |
7475 | var at, match; | |
7476 | ||
7477 | if (state.option.smarttabs) { | |
7478 | // Negative look-behind for "//" | |
7479 | match = this.input.match(/(\/\/|^\s?\*)? \t/); | |
7480 | at = match && !match[1] ? 0 : -1; | |
7481 | } else { | |
7482 | at = this.input.search(/ \t|\t [^\*]/); | |
7483 | } | |
7484 | ||
7485 | return at; | |
7486 | }, | |
7487 | ||
7488 | /* | |
7489 | * Scan for characters that get silently deleted by one or more browsers. | |
7490 | */ | |
7491 | scanUnsafeChars: function () { | |
7492 | return this.input.search(reg.unsafeChars); | |
7493 | }, | |
7494 | ||
7495 | /* | |
7496 | * Produce the next raw token or return 'null' if no tokens can be matched. | |
7497 | * This method skips over all space characters. | |
7498 | */ | |
7499 | next: function (checks) { | |
7500 | this.from = this.char; | |
7501 | ||
7502 | // Move to the next non-space character. | |
7503 | var start; | |
7504 | if (/\s/.test(this.peek())) { | |
7505 | start = this.char; | |
7506 | ||
7507 | while (/\s/.test(this.peek())) { | |
7508 | this.from += 1; | |
7509 | this.skip(); | |
7510 | } | |
7511 | ||
7512 | if (this.peek() === "") { // EOL | |
7513 | if (!/^\s*$/.test(this.getLines()[this.line - 1]) && state.option.trailing) { | |
7514 | this.trigger("warning", { code: "W102", line: this.line, character: start }); | |
7515 | } | |
7516 | } | |
7517 | } | |
7518 | ||
7519 | // Methods that work with multi-line structures and move the | |
7520 | // character pointer. | |
7521 | ||
7522 | var match = this.scanComments() || | |
7523 | this.scanStringLiteral(checks); | |
7524 | ||
7525 | if (match) { | |
7526 | return match; | |
7527 | } | |
7528 | ||
7529 | // Methods that don't move the character pointer. | |
7530 | ||
7531 | match = | |
7532 | this.scanRegExp() || | |
7533 | this.scanPunctuator() || | |
7534 | this.scanKeyword() || | |
7535 | this.scanIdentifier() || | |
7536 | this.scanNumericLiteral(); | |
7537 | ||
7538 | if (match) { | |
7539 | this.skip(match.value.length); | |
7540 | return match; | |
7541 | } | |
7542 | ||
7543 | // No token could be matched, give up. | |
7544 | ||
7545 | return null; | |
7546 | }, | |
7547 | ||
7548 | /* | |
7549 | * Switch to the next line and reset all char pointers. Once | |
7550 | * switched, this method also checks for mixed spaces and tabs | |
7551 | * and other minor warnings. | |
7552 | */ | |
7553 | nextLine: function () { | |
7554 | var char; | |
7555 | ||
7556 | if (this.line >= this.getLines().length) { | |
7557 | return false; | |
7558 | } | |
7559 | ||
7560 | this.input = this.getLines()[this.line]; | |
7561 | this.line += 1; | |
7562 | this.char = 1; | |
7563 | this.from = 1; | |
7564 | ||
7565 | char = this.scanMixedSpacesAndTabs(); | |
7566 | if (char >= 0) { | |
7567 | this.trigger("warning", { code: "W099", line: this.line, character: char + 1 }); | |
7568 | } | |
7569 | ||
7570 | this.input = this.input.replace(/\t/g, state.tab); | |
7571 | char = this.scanUnsafeChars(); | |
7572 | ||
7573 | if (char >= 0) { | |
7574 | this.trigger("warning", { code: "W100", line: this.line, character: char }); | |
7575 | } | |
7576 | ||
7577 | // If there is a limit on line length, warn when lines get too | |
7578 | // long. | |
7579 | ||
7580 | if (state.option.maxlen && state.option.maxlen < this.input.length) { | |
7581 | this.trigger("warning", { code: "W101", line: this.line, character: this.input.length }); | |
7582 | } | |
7583 | ||
7584 | return true; | |
7585 | }, | |
7586 | ||
7587 | /* | |
7588 | * This is simply a synonym for nextLine() method with a friendlier | |
7589 | * public name. | |
7590 | */ | |
7591 | start: function () { | |
7592 | this.nextLine(); | |
7593 | }, | |
7594 | ||
7595 | /* | |
7596 | * Produce the next token. This function is called by advance() to get | |
56c4a2cb | 7597 | * the next token. It returns a token in a JSLint-compatible format. |
eb39fafa DC |
7598 | */ |
7599 | token: function () { | |
7600 | /*jshint loopfunc:true */ | |
7601 | var checks = asyncTrigger(); | |
7602 | var token; | |
7603 | ||
7604 | ||
7605 | function isReserved(token, isProperty) { | |
7606 | if (!token.reserved) { | |
7607 | return false; | |
7608 | } | |
7609 | var meta = token.meta; | |
7610 | ||
7611 | if (meta && meta.isFutureReservedWord && state.option.inES5()) { | |
7612 | // ES3 FutureReservedWord in an ES5 environment. | |
7613 | if (!meta.es5) { | |
7614 | return false; | |
7615 | } | |
7616 | ||
7617 | // Some ES5 FutureReservedWord identifiers are active only | |
7618 | // within a strict mode environment. | |
7619 | if (meta.strictOnly) { | |
7620 | if (!state.option.strict && !state.directive["use strict"]) { | |
7621 | return false; | |
7622 | } | |
7623 | } | |
7624 | ||
7625 | if (isProperty) { | |
7626 | return false; | |
7627 | } | |
7628 | } | |
7629 | ||
7630 | return true; | |
7631 | } | |
7632 | ||
7633 | // Produce a token object. | |
7634 | var create = function (type, value, isProperty) { | |
7635 | /*jshint validthis:true */ | |
7636 | var obj; | |
7637 | ||
7638 | if (type !== "(endline)" && type !== "(end)") { | |
7639 | this.prereg = false; | |
7640 | } | |
7641 | ||
7642 | if (type === "(punctuator)") { | |
7643 | switch (value) { | |
7644 | case ".": | |
7645 | case ")": | |
7646 | case "~": | |
7647 | case "#": | |
7648 | case "]": | |
7649 | this.prereg = false; | |
7650 | break; | |
7651 | default: | |
7652 | this.prereg = true; | |
7653 | } | |
7654 | ||
7655 | obj = Object.create(state.syntax[value] || state.syntax["(error)"]); | |
7656 | } | |
7657 | ||
7658 | if (type === "(identifier)") { | |
7659 | if (value === "return" || value === "case" || value === "typeof") { | |
7660 | this.prereg = true; | |
7661 | } | |
7662 | ||
7663 | if (_.has(state.syntax, value)) { | |
7664 | obj = Object.create(state.syntax[value] || state.syntax["(error)"]); | |
7665 | ||
7666 | // If this can't be a reserved keyword, reset the object. | |
7667 | if (!isReserved(obj, isProperty && type === "(identifier)")) { | |
7668 | obj = null; | |
7669 | } | |
7670 | } | |
7671 | } | |
7672 | ||
7673 | if (!obj) { | |
7674 | obj = Object.create(state.syntax[type]); | |
7675 | } | |
7676 | ||
7677 | obj.identifier = (type === "(identifier)"); | |
7678 | obj.type = obj.type || type; | |
7679 | obj.value = value; | |
7680 | obj.line = this.line; | |
7681 | obj.character = this.char; | |
7682 | obj.from = this.from; | |
7683 | ||
7684 | if (isProperty && obj.identifier) { | |
7685 | obj.isProperty = isProperty; | |
7686 | } | |
7687 | ||
7688 | obj.check = checks.check; | |
7689 | ||
7690 | return obj; | |
7691 | }.bind(this); | |
7692 | ||
7693 | for (;;) { | |
7694 | if (!this.input.length) { | |
7695 | return create(this.nextLine() ? "(endline)" : "(end)", ""); | |
7696 | } | |
7697 | ||
7698 | token = this.next(checks); | |
7699 | ||
7700 | if (!token) { | |
7701 | if (this.input.length) { | |
7702 | // Unexpected character. | |
7703 | this.trigger("error", { | |
7704 | code: "E024", | |
7705 | line: this.line, | |
7706 | character: this.char, | |
7707 | data: [ this.peek() ] | |
7708 | }); | |
7709 | ||
7710 | this.input = ""; | |
7711 | } | |
7712 | ||
7713 | continue; | |
7714 | } | |
7715 | ||
7716 | switch (token.type) { | |
7717 | case Token.StringLiteral: | |
7718 | this.triggerAsync("String", { | |
7719 | line: this.line, | |
7720 | char: this.char, | |
7721 | from: this.from, | |
7722 | value: token.value, | |
7723 | quote: token.quote | |
7724 | }, checks, function () { return true; }); | |
7725 | ||
7726 | return create("(string)", token.value); | |
7727 | case Token.Identifier: | |
7728 | this.trigger("Identifier", { | |
7729 | line: this.line, | |
7730 | char: this.char, | |
7731 | from: this.form, | |
7732 | name: token.value, | |
7733 | isProperty: state.tokens.curr.id === "." | |
7734 | }); | |
7735 | ||
7736 | /* falls through */ | |
7737 | case Token.Keyword: | |
7738 | case Token.NullLiteral: | |
7739 | case Token.BooleanLiteral: | |
7740 | return create("(identifier)", token.value, state.tokens.curr.id === "."); | |
7741 | ||
7742 | case Token.NumericLiteral: | |
7743 | if (token.isMalformed) { | |
7744 | this.trigger("warning", { | |
7745 | code: "W045", | |
7746 | line: this.line, | |
7747 | character: this.char, | |
7748 | data: [ token.value ] | |
7749 | }); | |
7750 | } | |
7751 | ||
7752 | this.triggerAsync("warning", { | |
7753 | code: "W114", | |
7754 | line: this.line, | |
7755 | character: this.char, | |
7756 | data: [ "0x-" ] | |
7757 | }, checks, function () { return token.base === 16 && state.jsonMode; }); | |
7758 | ||
7759 | this.triggerAsync("warning", { | |
7760 | code: "W115", | |
7761 | line: this.line, | |
7762 | character: this.char | |
7763 | }, checks, function () { | |
7764 | return state.directive["use strict"] && token.base === 8; | |
7765 | }); | |
7766 | ||
7767 | this.trigger("Number", { | |
7768 | line: this.line, | |
7769 | char: this.char, | |
7770 | from: this.from, | |
7771 | value: token.value, | |
7772 | base: token.base, | |
7773 | isMalformed: token.malformed | |
7774 | }); | |
7775 | ||
7776 | return create("(number)", token.value); | |
7777 | ||
7778 | case Token.RegExp: | |
7779 | return create("(regexp)", token.value); | |
7780 | ||
7781 | case Token.Comment: | |
7782 | state.tokens.curr.comment = true; | |
7783 | ||
7784 | if (token.isSpecial) { | |
7785 | return { | |
7786 | value: token.value, | |
7787 | body: token.body, | |
7788 | type: token.commentType, | |
7789 | isSpecial: token.isSpecial, | |
7790 | line: this.line, | |
7791 | character: this.char, | |
7792 | from: this.from | |
7793 | }; | |
7794 | } | |
7795 | ||
7796 | break; | |
7797 | ||
7798 | case "": | |
7799 | break; | |
7800 | ||
7801 | default: | |
7802 | return create("(punctuator)", token.value); | |
7803 | } | |
7804 | } | |
7805 | } | |
7806 | }; | |
7807 | ||
7808 | exports.Lexer = Lexer; | |
7809 | ||
7810 | })() | |
7811 | },{"events":2,"./state.js":6,"./reg.js":4,"underscore":10}],9:[function(require,module,exports){ | |
7812 | (function(global){/*global window, global*/ | |
7813 | var util = require("util") | |
7814 | var assert = require("assert") | |
7815 | ||
7816 | var slice = Array.prototype.slice | |
7817 | var console | |
7818 | var times = {} | |
7819 | ||
7820 | if (typeof global !== "undefined" && global.console) { | |
7821 | console = global.console | |
7822 | } else if (typeof window !== "undefined" && window.console) { | |
7823 | console = window.console | |
7824 | } else { | |
7825 | console = window.console = {} | |
7826 | } | |
7827 | ||
7828 | var functions = [ | |
7829 | [log, "log"] | |
7830 | , [info, "info"] | |
7831 | , [warn, "warn"] | |
7832 | , [error, "error"] | |
7833 | , [time, "time"] | |
7834 | , [timeEnd, "timeEnd"] | |
7835 | , [trace, "trace"] | |
7836 | , [dir, "dir"] | |
7837 | , [assert, "assert"] | |
7838 | ] | |
7839 | ||
7840 | for (var i = 0; i < functions.length; i++) { | |
7841 | var tuple = functions[i] | |
7842 | var f = tuple[0] | |
7843 | var name = tuple[1] | |
7844 | ||
7845 | if (!console[name]) { | |
7846 | console[name] = f | |
7847 | } | |
7848 | } | |
7849 | ||
7850 | module.exports = console | |
7851 | ||
7852 | function log() {} | |
7853 | ||
7854 | function info() { | |
7855 | console.log.apply(console, arguments) | |
7856 | } | |
7857 | ||
7858 | function warn() { | |
7859 | console.log.apply(console, arguments) | |
7860 | } | |
7861 | ||
7862 | function error() { | |
7863 | console.warn.apply(console, arguments) | |
7864 | } | |
7865 | ||
7866 | function time(label) { | |
7867 | times[label] = Date.now() | |
7868 | } | |
7869 | ||
7870 | function timeEnd(label) { | |
7871 | var time = times[label] | |
7872 | if (!time) { | |
7873 | throw new Error("No such label: " + label) | |
7874 | } | |
7875 | ||
7876 | var duration = Date.now() - time | |
7877 | console.log(label + ": " + duration + "ms") | |
7878 | } | |
7879 | ||
7880 | function trace() { | |
7881 | var err = new Error() | |
7882 | err.name = "Trace" | |
7883 | err.message = util.format.apply(null, arguments) | |
7884 | console.error(err.stack) | |
7885 | } | |
7886 | ||
7887 | function dir(object) { | |
7888 | console.log(util.inspect(object) + "\n") | |
7889 | } | |
7890 | ||
7891 | function assert(expression) { | |
7892 | if (!expression) { | |
7893 | var arr = slice.call(arguments, 1) | |
7894 | assert.ok(false, util.format.apply(null, arr)) | |
7895 | } | |
7896 | } | |
7897 | ||
7898 | })(window) | |
7899 | },{"util":11,"assert":12}],10:[function(require,module,exports){ | |
7900 | (function(){// Underscore.js 1.4.4 | |
7901 | // http://underscorejs.org | |
7902 | // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. | |
7903 | // Underscore may be freely distributed under the MIT license. | |
7904 | ||
7905 | (function() { | |
7906 | ||
7907 | // Baseline setup | |
7908 | // -------------- | |
7909 | ||
7910 | // Establish the root object, `window` in the browser, or `global` on the server. | |
7911 | var root = this; | |
7912 | ||
7913 | // Save the previous value of the `_` variable. | |
7914 | var previousUnderscore = root._; | |
7915 | ||
7916 | // Establish the object that gets returned to break out of a loop iteration. | |
7917 | var breaker = {}; | |
7918 | ||
7919 | // Save bytes in the minified (but not gzipped) version: | |
7920 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; | |
7921 | ||
7922 | // Create quick reference variables for speed access to core prototypes. | |
7923 | var push = ArrayProto.push, | |
7924 | slice = ArrayProto.slice, | |
7925 | concat = ArrayProto.concat, | |
7926 | toString = ObjProto.toString, | |
7927 | hasOwnProperty = ObjProto.hasOwnProperty; | |
7928 | ||
7929 | // All **ECMAScript 5** native function implementations that we hope to use | |
7930 | // are declared here. | |
7931 | var | |
7932 | nativeForEach = ArrayProto.forEach, | |
7933 | nativeMap = ArrayProto.map, | |
7934 | nativeReduce = ArrayProto.reduce, | |
7935 | nativeReduceRight = ArrayProto.reduceRight, | |
7936 | nativeFilter = ArrayProto.filter, | |
7937 | nativeEvery = ArrayProto.every, | |
7938 | nativeSome = ArrayProto.some, | |
7939 | nativeIndexOf = ArrayProto.indexOf, | |
7940 | nativeLastIndexOf = ArrayProto.lastIndexOf, | |
7941 | nativeIsArray = Array.isArray, | |
7942 | nativeKeys = Object.keys, | |
7943 | nativeBind = FuncProto.bind; | |
7944 | ||
7945 | // Create a safe reference to the Underscore object for use below. | |
7946 | var _ = function(obj) { | |
7947 | if (obj instanceof _) return obj; | |
7948 | if (!(this instanceof _)) return new _(obj); | |
7949 | this._wrapped = obj; | |
7950 | }; | |
7951 | ||
7952 | // Export the Underscore object for **Node.js**, with | |
7953 | // backwards-compatibility for the old `require()` API. If we're in | |
7954 | // the browser, add `_` as a global object via a string identifier, | |
7955 | // for Closure Compiler "advanced" mode. | |
7956 | if (typeof exports !== 'undefined') { | |
7957 | if (typeof module !== 'undefined' && module.exports) { | |
7958 | exports = module.exports = _; | |
7959 | } | |
7960 | exports._ = _; | |
7961 | } else { | |
7962 | root._ = _; | |
7963 | } | |
7964 | ||
7965 | // Current version. | |
7966 | _.VERSION = '1.4.4'; | |
7967 | ||
7968 | // Collection Functions | |
7969 | // -------------------- | |
7970 | ||
7971 | // The cornerstone, an `each` implementation, aka `forEach`. | |
7972 | // Handles objects with the built-in `forEach`, arrays, and raw objects. | |
7973 | // Delegates to **ECMAScript 5**'s native `forEach` if available. | |
7974 | var each = _.each = _.forEach = function(obj, iterator, context) { | |
7975 | if (obj == null) return; | |
7976 | if (nativeForEach && obj.forEach === nativeForEach) { | |
7977 | obj.forEach(iterator, context); | |
7978 | } else if (obj.length === +obj.length) { | |
7979 | for (var i = 0, l = obj.length; i < l; i++) { | |
7980 | if (iterator.call(context, obj[i], i, obj) === breaker) return; | |
7981 | } | |
7982 | } else { | |
7983 | for (var key in obj) { | |
7984 | if (_.has(obj, key)) { | |
7985 | if (iterator.call(context, obj[key], key, obj) === breaker) return; | |
7986 | } | |
7987 | } | |
7988 | } | |
7989 | }; | |
7990 | ||
7991 | // Return the results of applying the iterator to each element. | |
7992 | // Delegates to **ECMAScript 5**'s native `map` if available. | |
7993 | _.map = _.collect = function(obj, iterator, context) { | |
7994 | var results = []; | |
7995 | if (obj == null) return results; | |
7996 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); | |
7997 | each(obj, function(value, index, list) { | |
7998 | results[results.length] = iterator.call(context, value, index, list); | |
7999 | }); | |
8000 | return results; | |
8001 | }; | |
8002 | ||
8003 | var reduceError = 'Reduce of empty array with no initial value'; | |
8004 | ||
8005 | // **Reduce** builds up a single result from a list of values, aka `inject`, | |
8006 | // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. | |
8007 | _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { | |
8008 | var initial = arguments.length > 2; | |
8009 | if (obj == null) obj = []; | |
8010 | if (nativeReduce && obj.reduce === nativeReduce) { | |
8011 | if (context) iterator = _.bind(iterator, context); | |
8012 | return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); | |
8013 | } | |
8014 | each(obj, function(value, index, list) { | |
8015 | if (!initial) { | |
8016 | memo = value; | |
8017 | initial = true; | |
8018 | } else { | |
8019 | memo = iterator.call(context, memo, value, index, list); | |
8020 | } | |
8021 | }); | |
8022 | if (!initial) throw new TypeError(reduceError); | |
8023 | return memo; | |
8024 | }; | |
8025 | ||
8026 | // The right-associative version of reduce, also known as `foldr`. | |
8027 | // Delegates to **ECMAScript 5**'s native `reduceRight` if available. | |
8028 | _.reduceRight = _.foldr = function(obj, iterator, memo, context) { | |
8029 | var initial = arguments.length > 2; | |
8030 | if (obj == null) obj = []; | |
8031 | if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { | |
8032 | if (context) iterator = _.bind(iterator, context); | |
8033 | return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); | |
8034 | } | |
8035 | var length = obj.length; | |
8036 | if (length !== +length) { | |
8037 | var keys = _.keys(obj); | |
8038 | length = keys.length; | |
8039 | } | |
8040 | each(obj, function(value, index, list) { | |
8041 | index = keys ? keys[--length] : --length; | |
8042 | if (!initial) { | |
8043 | memo = obj[index]; | |
8044 | initial = true; | |
8045 | } else { | |
8046 | memo = iterator.call(context, memo, obj[index], index, list); | |
8047 | } | |
8048 | }); | |
8049 | if (!initial) throw new TypeError(reduceError); | |
8050 | return memo; | |
8051 | }; | |
8052 | ||
8053 | // Return the first value which passes a truth test. Aliased as `detect`. | |
8054 | _.find = _.detect = function(obj, iterator, context) { | |
8055 | var result; | |
8056 | any(obj, function(value, index, list) { | |
8057 | if (iterator.call(context, value, index, list)) { | |
8058 | result = value; | |
8059 | return true; | |
8060 | } | |
8061 | }); | |
8062 | return result; | |
8063 | }; | |
8064 | ||
8065 | // Return all the elements that pass a truth test. | |
8066 | // Delegates to **ECMAScript 5**'s native `filter` if available. | |
8067 | // Aliased as `select`. | |
8068 | _.filter = _.select = function(obj, iterator, context) { | |
8069 | var results = []; | |
8070 | if (obj == null) return results; | |
8071 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); | |
8072 | each(obj, function(value, index, list) { | |
8073 | if (iterator.call(context, value, index, list)) results[results.length] = value; | |
8074 | }); | |
8075 | return results; | |
8076 | }; | |
8077 | ||
8078 | // Return all the elements for which a truth test fails. | |
8079 | _.reject = function(obj, iterator, context) { | |
8080 | return _.filter(obj, function(value, index, list) { | |
8081 | return !iterator.call(context, value, index, list); | |
8082 | }, context); | |
8083 | }; | |
8084 | ||
8085 | // Determine whether all of the elements match a truth test. | |
8086 | // Delegates to **ECMAScript 5**'s native `every` if available. | |
8087 | // Aliased as `all`. | |
8088 | _.every = _.all = function(obj, iterator, context) { | |
8089 | iterator || (iterator = _.identity); | |
8090 | var result = true; | |
8091 | if (obj == null) return result; | |
8092 | if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); | |
8093 | each(obj, function(value, index, list) { | |
8094 | if (!(result = result && iterator.call(context, value, index, list))) return breaker; | |
8095 | }); | |
8096 | return !!result; | |
8097 | }; | |
8098 | ||
8099 | // Determine if at least one element in the object matches a truth test. | |
8100 | // Delegates to **ECMAScript 5**'s native `some` if available. | |
8101 | // Aliased as `any`. | |
8102 | var any = _.some = _.any = function(obj, iterator, context) { | |
8103 | iterator || (iterator = _.identity); | |
8104 | var result = false; | |
8105 | if (obj == null) return result; | |
8106 | if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); | |
8107 | each(obj, function(value, index, list) { | |
8108 | if (result || (result = iterator.call(context, value, index, list))) return breaker; | |
8109 | }); | |
8110 | return !!result; | |
8111 | }; | |
8112 | ||
8113 | // Determine if the array or object contains a given value (using `===`). | |
8114 | // Aliased as `include`. | |
8115 | _.contains = _.include = function(obj, target) { | |
8116 | if (obj == null) return false; | |
8117 | if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; | |
8118 | return any(obj, function(value) { | |
8119 | return value === target; | |
8120 | }); | |
8121 | }; | |
8122 | ||
8123 | // Invoke a method (with arguments) on every item in a collection. | |
8124 | _.invoke = function(obj, method) { | |
8125 | var args = slice.call(arguments, 2); | |
8126 | var isFunc = _.isFunction(method); | |
8127 | return _.map(obj, function(value) { | |
8128 | return (isFunc ? method : value[method]).apply(value, args); | |
8129 | }); | |
8130 | }; | |
8131 | ||
8132 | // Convenience version of a common use case of `map`: fetching a property. | |
8133 | _.pluck = function(obj, key) { | |
8134 | return _.map(obj, function(value){ return value[key]; }); | |
8135 | }; | |
8136 | ||
8137 | // Convenience version of a common use case of `filter`: selecting only objects | |
8138 | // containing specific `key:value` pairs. | |
8139 | _.where = function(obj, attrs, first) { | |
8140 | if (_.isEmpty(attrs)) return first ? null : []; | |
8141 | return _[first ? 'find' : 'filter'](obj, function(value) { | |
8142 | for (var key in attrs) { | |
8143 | if (attrs[key] !== value[key]) return false; | |
8144 | } | |
8145 | return true; | |
8146 | }); | |
8147 | }; | |
8148 | ||
8149 | // Convenience version of a common use case of `find`: getting the first object | |
8150 | // containing specific `key:value` pairs. | |
8151 | _.findWhere = function(obj, attrs) { | |
8152 | return _.where(obj, attrs, true); | |
8153 | }; | |
8154 | ||
8155 | // Return the maximum element or (element-based computation). | |
8156 | // Can't optimize arrays of integers longer than 65,535 elements. | |
8157 | // See: https://bugs.webkit.org/show_bug.cgi?id=80797 | |
8158 | _.max = function(obj, iterator, context) { | |
8159 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { | |
8160 | return Math.max.apply(Math, obj); | |
8161 | } | |
8162 | if (!iterator && _.isEmpty(obj)) return -Infinity; | |
8163 | var result = {computed : -Infinity, value: -Infinity}; | |
8164 | each(obj, function(value, index, list) { | |
8165 | var computed = iterator ? iterator.call(context, value, index, list) : value; | |
8166 | computed >= result.computed && (result = {value : value, computed : computed}); | |
8167 | }); | |
8168 | return result.value; | |
8169 | }; | |
8170 | ||
8171 | // Return the minimum element (or element-based computation). | |
8172 | _.min = function(obj, iterator, context) { | |
8173 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { | |
8174 | return Math.min.apply(Math, obj); | |
8175 | } | |
8176 | if (!iterator && _.isEmpty(obj)) return Infinity; | |
8177 | var result = {computed : Infinity, value: Infinity}; | |
8178 | each(obj, function(value, index, list) { | |
8179 | var computed = iterator ? iterator.call(context, value, index, list) : value; | |
8180 | computed < result.computed && (result = {value : value, computed : computed}); | |
8181 | }); | |
8182 | return result.value; | |
8183 | }; | |
8184 | ||
8185 | // Shuffle an array. | |
8186 | _.shuffle = function(obj) { | |
8187 | var rand; | |
8188 | var index = 0; | |
8189 | var shuffled = []; | |
8190 | each(obj, function(value) { | |
8191 | rand = _.random(index++); | |
8192 | shuffled[index - 1] = shuffled[rand]; | |
8193 | shuffled[rand] = value; | |
8194 | }); | |
8195 | return shuffled; | |
8196 | }; | |
8197 | ||
8198 | // An internal function to generate lookup iterators. | |
8199 | var lookupIterator = function(value) { | |
8200 | return _.isFunction(value) ? value : function(obj){ return obj[value]; }; | |
8201 | }; | |
8202 | ||
8203 | // Sort the object's values by a criterion produced by an iterator. | |
8204 | _.sortBy = function(obj, value, context) { | |
8205 | var iterator = lookupIterator(value); | |
8206 | return _.pluck(_.map(obj, function(value, index, list) { | |
8207 | return { | |
8208 | value : value, | |
8209 | index : index, | |
8210 | criteria : iterator.call(context, value, index, list) | |
8211 | }; | |
8212 | }).sort(function(left, right) { | |
8213 | var a = left.criteria; | |
8214 | var b = right.criteria; | |
8215 | if (a !== b) { | |
8216 | if (a > b || a === void 0) return 1; | |
8217 | if (a < b || b === void 0) return -1; | |
8218 | } | |
8219 | return left.index < right.index ? -1 : 1; | |
8220 | }), 'value'); | |
8221 | }; | |
8222 | ||
8223 | // An internal function used for aggregate "group by" operations. | |
8224 | var group = function(obj, value, context, behavior) { | |
8225 | var result = {}; | |
8226 | var iterator = lookupIterator(value || _.identity); | |
8227 | each(obj, function(value, index) { | |
8228 | var key = iterator.call(context, value, index, obj); | |
8229 | behavior(result, key, value); | |
8230 | }); | |
8231 | return result; | |
8232 | }; | |
8233 | ||
8234 | // Groups the object's values by a criterion. Pass either a string attribute | |
8235 | // to group by, or a function that returns the criterion. | |
8236 | _.groupBy = function(obj, value, context) { | |
8237 | return group(obj, value, context, function(result, key, value) { | |
8238 | (_.has(result, key) ? result[key] : (result[key] = [])).push(value); | |
8239 | }); | |
8240 | }; | |
8241 | ||
8242 | // Counts instances of an object that group by a certain criterion. Pass | |
8243 | // either a string attribute to count by, or a function that returns the | |
8244 | // criterion. | |
8245 | _.countBy = function(obj, value, context) { | |
8246 | return group(obj, value, context, function(result, key) { | |
8247 | if (!_.has(result, key)) result[key] = 0; | |
8248 | result[key]++; | |
8249 | }); | |
8250 | }; | |
8251 | ||
8252 | // Use a comparator function to figure out the smallest index at which | |
8253 | // an object should be inserted so as to maintain order. Uses binary search. | |
8254 | _.sortedIndex = function(array, obj, iterator, context) { | |
8255 | iterator = iterator == null ? _.identity : lookupIterator(iterator); | |
8256 | var value = iterator.call(context, obj); | |
8257 | var low = 0, high = array.length; | |
8258 | while (low < high) { | |
8259 | var mid = (low + high) >>> 1; | |
8260 | iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; | |
8261 | } | |
8262 | return low; | |
8263 | }; | |
8264 | ||
8265 | // Safely convert anything iterable into a real, live array. | |
8266 | _.toArray = function(obj) { | |
8267 | if (!obj) return []; | |
8268 | if (_.isArray(obj)) return slice.call(obj); | |
8269 | if (obj.length === +obj.length) return _.map(obj, _.identity); | |
8270 | return _.values(obj); | |
8271 | }; | |
8272 | ||
8273 | // Return the number of elements in an object. | |
8274 | _.size = function(obj) { | |
8275 | if (obj == null) return 0; | |
8276 | return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; | |
8277 | }; | |
8278 | ||
8279 | // Array Functions | |
8280 | // --------------- | |
8281 | ||
8282 | // Get the first element of an array. Passing **n** will return the first N | |
8283 | // values in the array. Aliased as `head` and `take`. The **guard** check | |
8284 | // allows it to work with `_.map`. | |
8285 | _.first = _.head = _.take = function(array, n, guard) { | |
8286 | if (array == null) return void 0; | |
8287 | return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; | |
8288 | }; | |
8289 | ||
8290 | // Returns everything but the last entry of the array. Especially useful on | |
8291 | // the arguments object. Passing **n** will return all the values in | |
8292 | // the array, excluding the last N. The **guard** check allows it to work with | |
8293 | // `_.map`. | |
8294 | _.initial = function(array, n, guard) { | |
8295 | return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); | |
8296 | }; | |
8297 | ||
8298 | // Get the last element of an array. Passing **n** will return the last N | |
8299 | // values in the array. The **guard** check allows it to work with `_.map`. | |
8300 | _.last = function(array, n, guard) { | |
8301 | if (array == null) return void 0; | |
8302 | if ((n != null) && !guard) { | |
8303 | return slice.call(array, Math.max(array.length - n, 0)); | |
8304 | } else { | |
8305 | return array[array.length - 1]; | |
8306 | } | |
8307 | }; | |
8308 | ||
8309 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. | |
8310 | // Especially useful on the arguments object. Passing an **n** will return | |
8311 | // the rest N values in the array. The **guard** | |
8312 | // check allows it to work with `_.map`. | |
8313 | _.rest = _.tail = _.drop = function(array, n, guard) { | |
8314 | return slice.call(array, (n == null) || guard ? 1 : n); | |
8315 | }; | |
8316 | ||
8317 | // Trim out all falsy values from an array. | |
8318 | _.compact = function(array) { | |
8319 | return _.filter(array, _.identity); | |
8320 | }; | |
8321 | ||
8322 | // Internal implementation of a recursive `flatten` function. | |
8323 | var flatten = function(input, shallow, output) { | |
8324 | each(input, function(value) { | |
8325 | if (_.isArray(value)) { | |
8326 | shallow ? push.apply(output, value) : flatten(value, shallow, output); | |
8327 | } else { | |
8328 | output.push(value); | |
8329 | } | |
8330 | }); | |
8331 | return output; | |
8332 | }; | |
8333 | ||
8334 | // Return a completely flattened version of an array. | |
8335 | _.flatten = function(array, shallow) { | |
8336 | return flatten(array, shallow, []); | |
8337 | }; | |
8338 | ||
8339 | // Return a version of the array that does not contain the specified value(s). | |
8340 | _.without = function(array) { | |
8341 | return _.difference(array, slice.call(arguments, 1)); | |
8342 | }; | |
8343 | ||
8344 | // Produce a duplicate-free version of the array. If the array has already | |
8345 | // been sorted, you have the option of using a faster algorithm. | |
8346 | // Aliased as `unique`. | |
8347 | _.uniq = _.unique = function(array, isSorted, iterator, context) { | |
8348 | if (_.isFunction(isSorted)) { | |
8349 | context = iterator; | |
8350 | iterator = isSorted; | |
8351 | isSorted = false; | |
8352 | } | |
8353 | var initial = iterator ? _.map(array, iterator, context) : array; | |
8354 | var results = []; | |
8355 | var seen = []; | |
8356 | each(initial, function(value, index) { | |
8357 | if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { | |
8358 | seen.push(value); | |
8359 | results.push(array[index]); | |
8360 | } | |
8361 | }); | |
8362 | return results; | |
8363 | }; | |
8364 | ||
8365 | // Produce an array that contains the union: each distinct element from all of | |
8366 | // the passed-in arrays. | |
8367 | _.union = function() { | |
8368 | return _.uniq(concat.apply(ArrayProto, arguments)); | |
8369 | }; | |
8370 | ||
8371 | // Produce an array that contains every item shared between all the | |
8372 | // passed-in arrays. | |
8373 | _.intersection = function(array) { | |
8374 | var rest = slice.call(arguments, 1); | |
8375 | return _.filter(_.uniq(array), function(item) { | |
8376 | return _.every(rest, function(other) { | |
8377 | return _.indexOf(other, item) >= 0; | |
8378 | }); | |
8379 | }); | |
8380 | }; | |
8381 | ||
8382 | // Take the difference between one array and a number of other arrays. | |
8383 | // Only the elements present in just the first array will remain. | |
8384 | _.difference = function(array) { | |
8385 | var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); | |
8386 | return _.filter(array, function(value){ return !_.contains(rest, value); }); | |
8387 | }; | |
8388 | ||
8389 | // Zip together multiple lists into a single array -- elements that share | |
8390 | // an index go together. | |
8391 | _.zip = function() { | |
8392 | var args = slice.call(arguments); | |
8393 | var length = _.max(_.pluck(args, 'length')); | |
8394 | var results = new Array(length); | |
8395 | for (var i = 0; i < length; i++) { | |
8396 | results[i] = _.pluck(args, "" + i); | |
8397 | } | |
8398 | return results; | |
8399 | }; | |
8400 | ||
8401 | // Converts lists into objects. Pass either a single array of `[key, value]` | |
8402 | // pairs, or two parallel arrays of the same length -- one of keys, and one of | |
8403 | // the corresponding values. | |
8404 | _.object = function(list, values) { | |
8405 | if (list == null) return {}; | |
8406 | var result = {}; | |
8407 | for (var i = 0, l = list.length; i < l; i++) { | |
8408 | if (values) { | |
8409 | result[list[i]] = values[i]; | |
8410 | } else { | |
8411 | result[list[i][0]] = list[i][1]; | |
8412 | } | |
8413 | } | |
8414 | return result; | |
8415 | }; | |
8416 | ||
8417 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), | |
8418 | // we need this function. Return the position of the first occurrence of an | |
8419 | // item in an array, or -1 if the item is not included in the array. | |
8420 | // Delegates to **ECMAScript 5**'s native `indexOf` if available. | |
8421 | // If the array is large and already in sort order, pass `true` | |
8422 | // for **isSorted** to use binary search. | |
8423 | _.indexOf = function(array, item, isSorted) { | |
8424 | if (array == null) return -1; | |
8425 | var i = 0, l = array.length; | |
8426 | if (isSorted) { | |
8427 | if (typeof isSorted == 'number') { | |
8428 | i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); | |
8429 | } else { | |
8430 | i = _.sortedIndex(array, item); | |
8431 | return array[i] === item ? i : -1; | |
8432 | } | |
8433 | } | |
8434 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); | |
8435 | for (; i < l; i++) if (array[i] === item) return i; | |
8436 | return -1; | |
8437 | }; | |
8438 | ||
8439 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. | |
8440 | _.lastIndexOf = function(array, item, from) { | |
8441 | if (array == null) return -1; | |
8442 | var hasIndex = from != null; | |
8443 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { | |
8444 | return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); | |
8445 | } | |
8446 | var i = (hasIndex ? from : array.length); | |
8447 | while (i--) if (array[i] === item) return i; | |
8448 | return -1; | |
8449 | }; | |
8450 | ||
8451 | // Generate an integer Array containing an arithmetic progression. A port of | |
8452 | // the native Python `range()` function. See | |
8453 | // [the Python documentation](http://docs.python.org/library/functions.html#range). | |
8454 | _.range = function(start, stop, step) { | |
8455 | if (arguments.length <= 1) { | |
8456 | stop = start || 0; | |
8457 | start = 0; | |
8458 | } | |
8459 | step = arguments[2] || 1; | |
8460 | ||
8461 | var len = Math.max(Math.ceil((stop - start) / step), 0); | |
8462 | var idx = 0; | |
8463 | var range = new Array(len); | |
8464 | ||
8465 | while(idx < len) { | |
8466 | range[idx++] = start; | |
8467 | start += step; | |
8468 | } | |
8469 | ||
8470 | return range; | |
8471 | }; | |
8472 | ||
8473 | // Function (ahem) Functions | |
8474 | // ------------------ | |
8475 | ||
8476 | // Create a function bound to a given object (assigning `this`, and arguments, | |
8477 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if | |
8478 | // available. | |
8479 | _.bind = function(func, context) { | |
8480 | if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); | |
8481 | var args = slice.call(arguments, 2); | |
8482 | return function() { | |
8483 | return func.apply(context, args.concat(slice.call(arguments))); | |
8484 | }; | |
8485 | }; | |
8486 | ||
8487 | // Partially apply a function by creating a version that has had some of its | |
8488 | // arguments pre-filled, without changing its dynamic `this` context. | |
8489 | _.partial = function(func) { | |
8490 | var args = slice.call(arguments, 1); | |
8491 | return function() { | |
8492 | return func.apply(this, args.concat(slice.call(arguments))); | |
8493 | }; | |
8494 | }; | |
8495 | ||
8496 | // Bind all of an object's methods to that object. Useful for ensuring that | |
8497 | // all callbacks defined on an object belong to it. | |
8498 | _.bindAll = function(obj) { | |
8499 | var funcs = slice.call(arguments, 1); | |
8500 | if (funcs.length === 0) funcs = _.functions(obj); | |
8501 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); | |
8502 | return obj; | |
8503 | }; | |
8504 | ||
8505 | // Memoize an expensive function by storing its results. | |
8506 | _.memoize = function(func, hasher) { | |
8507 | var memo = {}; | |
8508 | hasher || (hasher = _.identity); | |
8509 | return function() { | |
8510 | var key = hasher.apply(this, arguments); | |
8511 | return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); | |
8512 | }; | |
8513 | }; | |
8514 | ||
8515 | // Delays a function for the given number of milliseconds, and then calls | |
8516 | // it with the arguments supplied. | |
8517 | _.delay = function(func, wait) { | |
8518 | var args = slice.call(arguments, 2); | |
8519 | return setTimeout(function(){ return func.apply(null, args); }, wait); | |
8520 | }; | |
8521 | ||
8522 | // Defers a function, scheduling it to run after the current call stack has | |
8523 | // cleared. | |
8524 | _.defer = function(func) { | |
8525 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); | |
8526 | }; | |
8527 | ||
8528 | // Returns a function, that, when invoked, will only be triggered at most once | |
8529 | // during a given window of time. | |
8530 | _.throttle = function(func, wait) { | |
8531 | var context, args, timeout, result; | |
8532 | var previous = 0; | |
8533 | var later = function() { | |
8534 | previous = new Date; | |
8535 | timeout = null; | |
8536 | result = func.apply(context, args); | |
8537 | }; | |
8538 | return function() { | |
8539 | var now = new Date; | |
8540 | var remaining = wait - (now - previous); | |
8541 | context = this; | |
8542 | args = arguments; | |
8543 | if (remaining <= 0) { | |
8544 | clearTimeout(timeout); | |
8545 | timeout = null; | |
8546 | previous = now; | |
8547 | result = func.apply(context, args); | |
8548 | } else if (!timeout) { | |
8549 | timeout = setTimeout(later, remaining); | |
8550 | } | |
8551 | return result; | |
8552 | }; | |
8553 | }; | |
8554 | ||
8555 | // Returns a function, that, as long as it continues to be invoked, will not | |
8556 | // be triggered. The function will be called after it stops being called for | |
8557 | // N milliseconds. If `immediate` is passed, trigger the function on the | |
8558 | // leading edge, instead of the trailing. | |
8559 | _.debounce = function(func, wait, immediate) { | |
8560 | var timeout, result; | |
8561 | return function() { | |
8562 | var context = this, args = arguments; | |
8563 | var later = function() { | |
8564 | timeout = null; | |
8565 | if (!immediate) result = func.apply(context, args); | |
8566 | }; | |
8567 | var callNow = immediate && !timeout; | |
8568 | clearTimeout(timeout); | |
8569 | timeout = setTimeout(later, wait); | |
8570 | if (callNow) result = func.apply(context, args); | |
8571 | return result; | |
8572 | }; | |
8573 | }; | |
8574 | ||
8575 | // Returns a function that will be executed at most one time, no matter how | |
8576 | // often you call it. Useful for lazy initialization. | |
8577 | _.once = function(func) { | |
8578 | var ran = false, memo; | |
8579 | return function() { | |
8580 | if (ran) return memo; | |
8581 | ran = true; | |
8582 | memo = func.apply(this, arguments); | |
8583 | func = null; | |
8584 | return memo; | |
8585 | }; | |
8586 | }; | |
8587 | ||
8588 | // Returns the first function passed as an argument to the second, | |
8589 | // allowing you to adjust arguments, run code before and after, and | |
8590 | // conditionally execute the original function. | |
8591 | _.wrap = function(func, wrapper) { | |
8592 | return function() { | |
8593 | var args = [func]; | |
8594 | push.apply(args, arguments); | |
8595 | return wrapper.apply(this, args); | |
8596 | }; | |
8597 | }; | |
8598 | ||
8599 | // Returns a function that is the composition of a list of functions, each | |
8600 | // consuming the return value of the function that follows. | |
8601 | _.compose = function() { | |
8602 | var funcs = arguments; | |
8603 | return function() { | |
8604 | var args = arguments; | |
8605 | for (var i = funcs.length - 1; i >= 0; i--) { | |
8606 | args = [funcs[i].apply(this, args)]; | |
8607 | } | |
8608 | return args[0]; | |
8609 | }; | |
8610 | }; | |
8611 | ||
8612 | // Returns a function that will only be executed after being called N times. | |
8613 | _.after = function(times, func) { | |
8614 | if (times <= 0) return func(); | |
8615 | return function() { | |
8616 | if (--times < 1) { | |
8617 | return func.apply(this, arguments); | |
8618 | } | |
8619 | }; | |
8620 | }; | |
8621 | ||
8622 | // Object Functions | |
8623 | // ---------------- | |
8624 | ||
8625 | // Retrieve the names of an object's properties. | |
8626 | // Delegates to **ECMAScript 5**'s native `Object.keys` | |
8627 | _.keys = nativeKeys || function(obj) { | |
8628 | if (obj !== Object(obj)) throw new TypeError('Invalid object'); | |
8629 | var keys = []; | |
8630 | for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; | |
8631 | return keys; | |
8632 | }; | |
8633 | ||
8634 | // Retrieve the values of an object's properties. | |
8635 | _.values = function(obj) { | |
8636 | var values = []; | |
8637 | for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); | |
8638 | return values; | |
8639 | }; | |
8640 | ||
8641 | // Convert an object into a list of `[key, value]` pairs. | |
8642 | _.pairs = function(obj) { | |
8643 | var pairs = []; | |
8644 | for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); | |
8645 | return pairs; | |
8646 | }; | |
8647 | ||
8648 | // Invert the keys and values of an object. The values must be serializable. | |
8649 | _.invert = function(obj) { | |
8650 | var result = {}; | |
8651 | for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; | |
8652 | return result; | |
8653 | }; | |
8654 | ||
8655 | // Return a sorted list of the function names available on the object. | |
8656 | // Aliased as `methods` | |
8657 | _.functions = _.methods = function(obj) { | |
8658 | var names = []; | |
8659 | for (var key in obj) { | |
8660 | if (_.isFunction(obj[key])) names.push(key); | |
8661 | } | |
8662 | return names.sort(); | |
8663 | }; | |
8664 | ||
8665 | // Extend a given object with all the properties in passed-in object(s). | |
8666 | _.extend = function(obj) { | |
8667 | each(slice.call(arguments, 1), function(source) { | |
8668 | if (source) { | |
8669 | for (var prop in source) { | |
8670 | obj[prop] = source[prop]; | |
8671 | } | |
8672 | } | |
8673 | }); | |
8674 | return obj; | |
8675 | }; | |
8676 | ||
8677 | // Return a copy of the object only containing the whitelisted properties. | |
8678 | _.pick = function(obj) { | |
8679 | var copy = {}; | |
8680 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); | |
8681 | each(keys, function(key) { | |
8682 | if (key in obj) copy[key] = obj[key]; | |
8683 | }); | |
8684 | return copy; | |
8685 | }; | |
8686 | ||
8687 | // Return a copy of the object without the blacklisted properties. | |
8688 | _.omit = function(obj) { | |
8689 | var copy = {}; | |
8690 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); | |
8691 | for (var key in obj) { | |
8692 | if (!_.contains(keys, key)) copy[key] = obj[key]; | |
8693 | } | |
8694 | return copy; | |
8695 | }; | |
8696 | ||
8697 | // Fill in a given object with default properties. | |
8698 | _.defaults = function(obj) { | |
8699 | each(slice.call(arguments, 1), function(source) { | |
8700 | if (source) { | |
8701 | for (var prop in source) { | |
8702 | if (obj[prop] == null) obj[prop] = source[prop]; | |
8703 | } | |
8704 | } | |
8705 | }); | |
8706 | return obj; | |
8707 | }; | |
8708 | ||
8709 | // Create a (shallow-cloned) duplicate of an object. | |
8710 | _.clone = function(obj) { | |
8711 | if (!_.isObject(obj)) return obj; | |
8712 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj); | |
8713 | }; | |
8714 | ||
8715 | // Invokes interceptor with the obj, and then returns obj. | |
8716 | // The primary purpose of this method is to "tap into" a method chain, in | |
8717 | // order to perform operations on intermediate results within the chain. | |
8718 | _.tap = function(obj, interceptor) { | |
8719 | interceptor(obj); | |
8720 | return obj; | |
8721 | }; | |
8722 | ||
8723 | // Internal recursive comparison function for `isEqual`. | |
8724 | var eq = function(a, b, aStack, bStack) { | |
8725 | // Identical objects are equal. `0 === -0`, but they aren't identical. | |
8726 | // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. | |
8727 | if (a === b) return a !== 0 || 1 / a == 1 / b; | |
8728 | // A strict comparison is necessary because `null == undefined`. | |
8729 | if (a == null || b == null) return a === b; | |
8730 | // Unwrap any wrapped objects. | |
8731 | if (a instanceof _) a = a._wrapped; | |
8732 | if (b instanceof _) b = b._wrapped; | |
8733 | // Compare `[[Class]]` names. | |
8734 | var className = toString.call(a); | |
8735 | if (className != toString.call(b)) return false; | |
8736 | switch (className) { | |
8737 | // Strings, numbers, dates, and booleans are compared by value. | |
8738 | case '[object String]': | |
8739 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is | |
8740 | // equivalent to `new String("5")`. | |
8741 | return a == String(b); | |
8742 | case '[object Number]': | |
8743 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for | |
8744 | // other numeric values. | |
8745 | return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); | |
8746 | case '[object Date]': | |
8747 | case '[object Boolean]': | |
8748 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their | |
8749 | // millisecond representations. Note that invalid dates with millisecond representations | |
8750 | // of `NaN` are not equivalent. | |
8751 | return +a == +b; | |
8752 | // RegExps are compared by their source patterns and flags. | |
8753 | case '[object RegExp]': | |
8754 | return a.source == b.source && | |
8755 | a.global == b.global && | |
8756 | a.multiline == b.multiline && | |
8757 | a.ignoreCase == b.ignoreCase; | |
8758 | } | |
8759 | if (typeof a != 'object' || typeof b != 'object') return false; | |
8760 | // Assume equality for cyclic structures. The algorithm for detecting cyclic | |
8761 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. | |
8762 | var length = aStack.length; | |
8763 | while (length--) { | |
8764 | // Linear search. Performance is inversely proportional to the number of | |
8765 | // unique nested structures. | |
8766 | if (aStack[length] == a) return bStack[length] == b; | |
8767 | } | |
8768 | // Add the first object to the stack of traversed objects. | |
8769 | aStack.push(a); | |
8770 | bStack.push(b); | |
8771 | var size = 0, result = true; | |
8772 | // Recursively compare objects and arrays. | |
8773 | if (className == '[object Array]') { | |
8774 | // Compare array lengths to determine if a deep comparison is necessary. | |
8775 | size = a.length; | |
8776 | result = size == b.length; | |
8777 | if (result) { | |
8778 | // Deep compare the contents, ignoring non-numeric properties. | |
8779 | while (size--) { | |
8780 | if (!(result = eq(a[size], b[size], aStack, bStack))) break; | |
8781 | } | |
8782 | } | |
8783 | } else { | |
8784 | // Objects with different constructors are not equivalent, but `Object`s | |
8785 | // from different frames are. | |
8786 | var aCtor = a.constructor, bCtor = b.constructor; | |
8787 | if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && | |
8788 | _.isFunction(bCtor) && (bCtor instanceof bCtor))) { | |
8789 | return false; | |
8790 | } | |
8791 | // Deep compare objects. | |
8792 | for (var key in a) { | |
8793 | if (_.has(a, key)) { | |
8794 | // Count the expected number of properties. | |
8795 | size++; | |
8796 | // Deep compare each member. | |
8797 | if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; | |
8798 | } | |
8799 | } | |
8800 | // Ensure that both objects contain the same number of properties. | |
8801 | if (result) { | |
8802 | for (key in b) { | |
8803 | if (_.has(b, key) && !(size--)) break; | |
8804 | } | |
8805 | result = !size; | |
8806 | } | |
8807 | } | |
8808 | // Remove the first object from the stack of traversed objects. | |
8809 | aStack.pop(); | |
8810 | bStack.pop(); | |
8811 | return result; | |
8812 | }; | |
8813 | ||
8814 | // Perform a deep comparison to check if two objects are equal. | |
8815 | _.isEqual = function(a, b) { | |
8816 | return eq(a, b, [], []); | |
8817 | }; | |
8818 | ||
8819 | // Is a given array, string, or object empty? | |
8820 | // An "empty" object has no enumerable own-properties. | |
8821 | _.isEmpty = function(obj) { | |
8822 | if (obj == null) return true; | |
8823 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; | |
8824 | for (var key in obj) if (_.has(obj, key)) return false; | |
8825 | return true; | |
8826 | }; | |
8827 | ||
8828 | // Is a given value a DOM element? | |
8829 | _.isElement = function(obj) { | |
8830 | return !!(obj && obj.nodeType === 1); | |
8831 | }; | |
8832 | ||
8833 | // Is a given value an array? | |
8834 | // Delegates to ECMA5's native Array.isArray | |
8835 | _.isArray = nativeIsArray || function(obj) { | |
8836 | return toString.call(obj) == '[object Array]'; | |
8837 | }; | |
8838 | ||
8839 | // Is a given variable an object? | |
8840 | _.isObject = function(obj) { | |
8841 | return obj === Object(obj); | |
8842 | }; | |
8843 | ||
8844 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. | |
8845 | each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { | |
8846 | _['is' + name] = function(obj) { | |
8847 | return toString.call(obj) == '[object ' + name + ']'; | |
8848 | }; | |
8849 | }); | |
8850 | ||
8851 | // Define a fallback version of the method in browsers (ahem, IE), where | |
8852 | // there isn't any inspectable "Arguments" type. | |
8853 | if (!_.isArguments(arguments)) { | |
8854 | _.isArguments = function(obj) { | |
8855 | return !!(obj && _.has(obj, 'callee')); | |
8856 | }; | |
8857 | } | |
8858 | ||
8859 | // Optimize `isFunction` if appropriate. | |
8860 | if (typeof (/./) !== 'function') { | |
8861 | _.isFunction = function(obj) { | |
8862 | return typeof obj === 'function'; | |
8863 | }; | |
8864 | } | |
8865 | ||
8866 | // Is a given object a finite number? | |
8867 | _.isFinite = function(obj) { | |
8868 | return isFinite(obj) && !isNaN(parseFloat(obj)); | |
8869 | }; | |
8870 | ||
8871 | // Is the given value `NaN`? (NaN is the only number which does not equal itself). | |
8872 | _.isNaN = function(obj) { | |
8873 | return _.isNumber(obj) && obj != +obj; | |
8874 | }; | |
8875 | ||
8876 | // Is a given value a boolean? | |
8877 | _.isBoolean = function(obj) { | |
8878 | return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; | |
8879 | }; | |
8880 | ||
8881 | // Is a given value equal to null? | |
8882 | _.isNull = function(obj) { | |
8883 | return obj === null; | |
8884 | }; | |
8885 | ||
8886 | // Is a given variable undefined? | |
8887 | _.isUndefined = function(obj) { | |
8888 | return obj === void 0; | |
8889 | }; | |
8890 | ||
8891 | // Shortcut function for checking if an object has a given property directly | |
8892 | // on itself (in other words, not on a prototype). | |
8893 | _.has = function(obj, key) { | |
8894 | return hasOwnProperty.call(obj, key); | |
8895 | }; | |
8896 | ||
8897 | // Utility Functions | |
8898 | // ----------------- | |
8899 | ||
8900 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its | |
8901 | // previous owner. Returns a reference to the Underscore object. | |
8902 | _.noConflict = function() { | |
8903 | root._ = previousUnderscore; | |
8904 | return this; | |
8905 | }; | |
8906 | ||
8907 | // Keep the identity function around for default iterators. | |
8908 | _.identity = function(value) { | |
8909 | return value; | |
8910 | }; | |
8911 | ||
8912 | // Run a function **n** times. | |
8913 | _.times = function(n, iterator, context) { | |
8914 | var accum = Array(n); | |
8915 | for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); | |
8916 | return accum; | |
8917 | }; | |
8918 | ||
8919 | // Return a random integer between min and max (inclusive). | |
8920 | _.random = function(min, max) { | |
8921 | if (max == null) { | |
8922 | max = min; | |
8923 | min = 0; | |
8924 | } | |
8925 | return min + Math.floor(Math.random() * (max - min + 1)); | |
8926 | }; | |
8927 | ||
8928 | // List of HTML entities for escaping. | |
8929 | var entityMap = { | |
8930 | escape: { | |
8931 | '&': '&', | |
8932 | '<': '<', | |
8933 | '>': '>', | |
8934 | '"': '"', | |
8935 | "'": ''', | |
8936 | '/': '/' | |
8937 | } | |
8938 | }; | |
8939 | entityMap.unescape = _.invert(entityMap.escape); | |
8940 | ||
8941 | // Regexes containing the keys and values listed immediately above. | |
8942 | var entityRegexes = { | |
8943 | escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), | |
8944 | unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') | |
8945 | }; | |
8946 | ||
8947 | // Functions for escaping and unescaping strings to/from HTML interpolation. | |
8948 | _.each(['escape', 'unescape'], function(method) { | |
8949 | _[method] = function(string) { | |
8950 | if (string == null) return ''; | |
8951 | return ('' + string).replace(entityRegexes[method], function(match) { | |
8952 | return entityMap[method][match]; | |
8953 | }); | |
8954 | }; | |
8955 | }); | |
8956 | ||
8957 | // If the value of the named property is a function then invoke it; | |
8958 | // otherwise, return it. | |
8959 | _.result = function(object, property) { | |
8960 | if (object == null) return null; | |
8961 | var value = object[property]; | |
8962 | return _.isFunction(value) ? value.call(object) : value; | |
8963 | }; | |
8964 | ||
8965 | // Add your own custom functions to the Underscore object. | |
8966 | _.mixin = function(obj) { | |
8967 | each(_.functions(obj), function(name){ | |
8968 | var func = _[name] = obj[name]; | |
8969 | _.prototype[name] = function() { | |
8970 | var args = [this._wrapped]; | |
8971 | push.apply(args, arguments); | |
8972 | return result.call(this, func.apply(_, args)); | |
8973 | }; | |
8974 | }); | |
8975 | }; | |
8976 | ||
8977 | // Generate a unique integer id (unique within the entire client session). | |
8978 | // Useful for temporary DOM ids. | |
8979 | var idCounter = 0; | |
8980 | _.uniqueId = function(prefix) { | |
8981 | var id = ++idCounter + ''; | |
8982 | return prefix ? prefix + id : id; | |
8983 | }; | |
8984 | ||
8985 | // By default, Underscore uses ERB-style template delimiters, change the | |
8986 | // following template settings to use alternative delimiters. | |
8987 | _.templateSettings = { | |
8988 | evaluate : /<%([\s\S]+?)%>/g, | |
8989 | interpolate : /<%=([\s\S]+?)%>/g, | |
8990 | escape : /<%-([\s\S]+?)%>/g | |
8991 | }; | |
8992 | ||
8993 | // When customizing `templateSettings`, if you don't want to define an | |
8994 | // interpolation, evaluation or escaping regex, we need one that is | |
8995 | // guaranteed not to match. | |
8996 | var noMatch = /(.)^/; | |
8997 | ||
8998 | // Certain characters need to be escaped so that they can be put into a | |
8999 | // string literal. | |
9000 | var escapes = { | |
9001 | "'": "'", | |
9002 | '\\': '\\', | |
9003 | '\r': 'r', | |
9004 | '\n': 'n', | |
9005 | '\t': 't', | |
9006 | '\u2028': 'u2028', | |
9007 | '\u2029': 'u2029' | |
9008 | }; | |
9009 | ||
9010 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; | |
9011 | ||
9012 | // JavaScript micro-templating, similar to John Resig's implementation. | |
9013 | // Underscore templating handles arbitrary delimiters, preserves whitespace, | |
9014 | // and correctly escapes quotes within interpolated code. | |
9015 | _.template = function(text, data, settings) { | |
9016 | var render; | |
9017 | settings = _.defaults({}, settings, _.templateSettings); | |
9018 | ||
9019 | // Combine delimiters into one regular expression via alternation. | |
9020 | var matcher = new RegExp([ | |
9021 | (settings.escape || noMatch).source, | |
9022 | (settings.interpolate || noMatch).source, | |
9023 | (settings.evaluate || noMatch).source | |
9024 | ].join('|') + '|$', 'g'); | |
9025 | ||
9026 | // Compile the template source, escaping string literals appropriately. | |
9027 | var index = 0; | |
9028 | var source = "__p+='"; | |
9029 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { | |
9030 | source += text.slice(index, offset) | |
9031 | .replace(escaper, function(match) { return '\\' + escapes[match]; }); | |
9032 | ||
9033 | if (escape) { | |
9034 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; | |
9035 | } | |
9036 | if (interpolate) { | |
9037 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; | |
9038 | } | |
9039 | if (evaluate) { | |
9040 | source += "';\n" + evaluate + "\n__p+='"; | |
9041 | } | |
9042 | index = offset + match.length; | |
9043 | return match; | |
9044 | }); | |
9045 | source += "';\n"; | |
9046 | ||
9047 | // If a variable is not specified, place data values in local scope. | |
9048 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; | |
9049 | ||
9050 | source = "var __t,__p='',__j=Array.prototype.join," + | |
9051 | "print=function(){__p+=__j.call(arguments,'');};\n" + | |
9052 | source + "return __p;\n"; | |
9053 | ||
9054 | try { | |
9055 | render = new Function(settings.variable || 'obj', '_', source); | |
9056 | } catch (e) { | |
9057 | e.source = source; | |
9058 | throw e; | |
9059 | } | |
9060 | ||
9061 | if (data) return render(data, _); | |
9062 | var template = function(data) { | |
9063 | return render.call(this, data, _); | |
9064 | }; | |
9065 | ||
9066 | // Provide the compiled function source as a convenience for precompilation. | |
9067 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; | |
9068 | ||
9069 | return template; | |
9070 | }; | |
9071 | ||
9072 | // Add a "chain" function, which will delegate to the wrapper. | |
9073 | _.chain = function(obj) { | |
9074 | return _(obj).chain(); | |
9075 | }; | |
9076 | ||
9077 | // OOP | |
9078 | // --------------- | |
9079 | // If Underscore is called as a function, it returns a wrapped object that | |
9080 | // can be used OO-style. This wrapper holds altered versions of all the | |
9081 | // underscore functions. Wrapped objects may be chained. | |
9082 | ||
9083 | // Helper function to continue chaining intermediate results. | |
9084 | var result = function(obj) { | |
9085 | return this._chain ? _(obj).chain() : obj; | |
9086 | }; | |
9087 | ||
9088 | // Add all of the Underscore functions to the wrapper object. | |
9089 | _.mixin(_); | |
9090 | ||
9091 | // Add all mutator Array functions to the wrapper. | |
9092 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { | |
9093 | var method = ArrayProto[name]; | |
9094 | _.prototype[name] = function() { | |
9095 | var obj = this._wrapped; | |
9096 | method.apply(obj, arguments); | |
9097 | if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; | |
9098 | return result.call(this, obj); | |
9099 | }; | |
9100 | }); | |
9101 | ||
9102 | // Add all accessor Array functions to the wrapper. | |
9103 | each(['concat', 'join', 'slice'], function(name) { | |
9104 | var method = ArrayProto[name]; | |
9105 | _.prototype[name] = function() { | |
9106 | return result.call(this, method.apply(this._wrapped, arguments)); | |
9107 | }; | |
9108 | }); | |
9109 | ||
9110 | _.extend(_.prototype, { | |
9111 | ||
9112 | // Start chaining a wrapped Underscore object. | |
9113 | chain: function() { | |
9114 | this._chain = true; | |
9115 | return this; | |
9116 | }, | |
9117 | ||
9118 | // Extracts the result from a wrapped and chained object. | |
9119 | value: function() { | |
9120 | return this._wrapped; | |
9121 | } | |
9122 | ||
9123 | }); | |
9124 | ||
9125 | }).call(this); | |
9126 | ||
9127 | })() | |
9128 | },{}],11:[function(require,module,exports){ | |
9129 | var events = require('events'); | |
9130 | ||
9131 | exports.isArray = isArray; | |
9132 | exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'}; | |
9133 | exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'}; | |
9134 | ||
9135 | ||
9136 | exports.print = function () {}; | |
9137 | exports.puts = function () {}; | |
9138 | exports.debug = function() {}; | |
9139 | ||
9140 | exports.inspect = function(obj, showHidden, depth, colors) { | |
9141 | var seen = []; | |
9142 | ||
9143 | var stylize = function(str, styleType) { | |
9144 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics | |
9145 | var styles = | |
9146 | { 'bold' : [1, 22], | |
9147 | 'italic' : [3, 23], | |
9148 | 'underline' : [4, 24], | |
9149 | 'inverse' : [7, 27], | |
9150 | 'white' : [37, 39], | |
9151 | 'grey' : [90, 39], | |
9152 | 'black' : [30, 39], | |
9153 | 'blue' : [34, 39], | |
9154 | 'cyan' : [36, 39], | |
9155 | 'green' : [32, 39], | |
9156 | 'magenta' : [35, 39], | |
9157 | 'red' : [31, 39], | |
9158 | 'yellow' : [33, 39] }; | |
9159 | ||
9160 | var style = | |
9161 | { 'special': 'cyan', | |
9162 | 'number': 'blue', | |
9163 | 'boolean': 'yellow', | |
9164 | 'undefined': 'grey', | |
9165 | 'null': 'bold', | |
9166 | 'string': 'green', | |
9167 | 'date': 'magenta', | |
9168 | // "name": intentionally not styling | |
9169 | 'regexp': 'red' }[styleType]; | |
9170 | ||
9171 | if (style) { | |
9172 | return '\033[' + styles[style][0] + 'm' + str + | |
9173 | '\033[' + styles[style][1] + 'm'; | |
9174 | } else { | |
9175 | return str; | |
9176 | } | |
9177 | }; | |
9178 | if (! colors) { | |
9179 | stylize = function(str, styleType) { return str; }; | |
9180 | } | |
9181 | ||
9182 | function format(value, recurseTimes) { | |
9183 | // Provide a hook for user-specified inspect functions. | |
9184 | // Check that value is an object with an inspect function on it | |
9185 | if (value && typeof value.inspect === 'function' && | |
9186 | // Filter out the util module, it's inspect function is special | |
9187 | value !== exports && | |
9188 | // Also filter out any prototype objects using the circular check. | |
9189 | !(value.constructor && value.constructor.prototype === value)) { | |
9190 | return value.inspect(recurseTimes); | |
9191 | } | |
9192 | ||
9193 | // Primitive types cannot have properties | |
9194 | switch (typeof value) { | |
9195 | case 'undefined': | |
9196 | return stylize('undefined', 'undefined'); | |
9197 | ||
9198 | case 'string': | |
9199 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | |
9200 | .replace(/'/g, "\\'") | |
9201 | .replace(/\\"/g, '"') + '\''; | |
9202 | return stylize(simple, 'string'); | |
9203 | ||
9204 | case 'number': | |
9205 | return stylize('' + value, 'number'); | |
9206 | ||
9207 | case 'boolean': | |
9208 | return stylize('' + value, 'boolean'); | |
9209 | } | |
9210 | // For some reason typeof null is "object", so special case here. | |
9211 | if (value === null) { | |
9212 | return stylize('null', 'null'); | |
9213 | } | |
9214 | ||
9215 | // Look up the keys of the object. | |
9216 | var visible_keys = Object_keys(value); | |
9217 | var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys; | |
9218 | ||
9219 | // Functions without properties can be shortcutted. | |
9220 | if (typeof value === 'function' && keys.length === 0) { | |
9221 | if (isRegExp(value)) { | |
9222 | return stylize('' + value, 'regexp'); | |
9223 | } else { | |
9224 | var name = value.name ? ': ' + value.name : ''; | |
9225 | return stylize('[Function' + name + ']', 'special'); | |
9226 | } | |
9227 | } | |
9228 | ||
9229 | // Dates without properties can be shortcutted | |
9230 | if (isDate(value) && keys.length === 0) { | |
9231 | return stylize(value.toUTCString(), 'date'); | |
9232 | } | |
9233 | ||
9234 | var base, type, braces; | |
9235 | // Determine the object type | |
9236 | if (isArray(value)) { | |
9237 | type = 'Array'; | |
9238 | braces = ['[', ']']; | |
9239 | } else { | |
9240 | type = 'Object'; | |
9241 | braces = ['{', '}']; | |
9242 | } | |
9243 | ||
9244 | // Make functions say that they are functions | |
9245 | if (typeof value === 'function') { | |
9246 | var n = value.name ? ': ' + value.name : ''; | |
9247 | base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; | |
9248 | } else { | |
9249 | base = ''; | |
9250 | } | |
9251 | ||
9252 | // Make dates with properties first say the date | |
9253 | if (isDate(value)) { | |
9254 | base = ' ' + value.toUTCString(); | |
9255 | } | |
9256 | ||
9257 | if (keys.length === 0) { | |
9258 | return braces[0] + base + braces[1]; | |
9259 | } | |
9260 | ||
9261 | if (recurseTimes < 0) { | |
9262 | if (isRegExp(value)) { | |
9263 | return stylize('' + value, 'regexp'); | |
9264 | } else { | |
9265 | return stylize('[Object]', 'special'); | |
9266 | } | |
9267 | } | |
9268 | ||
9269 | seen.push(value); | |
9270 | ||
9271 | var output = keys.map(function(key) { | |
9272 | var name, str; | |
9273 | if (value.__lookupGetter__) { | |
9274 | if (value.__lookupGetter__(key)) { | |
9275 | if (value.__lookupSetter__(key)) { | |
9276 | str = stylize('[Getter/Setter]', 'special'); | |
9277 | } else { | |
9278 | str = stylize('[Getter]', 'special'); | |
9279 | } | |
9280 | } else { | |
9281 | if (value.__lookupSetter__(key)) { | |
9282 | str = stylize('[Setter]', 'special'); | |
9283 | } | |
9284 | } | |
9285 | } | |
9286 | if (visible_keys.indexOf(key) < 0) { | |
9287 | name = '[' + key + ']'; | |
9288 | } | |
9289 | if (!str) { | |
9290 | if (seen.indexOf(value[key]) < 0) { | |
9291 | if (recurseTimes === null) { | |
9292 | str = format(value[key]); | |
9293 | } else { | |
9294 | str = format(value[key], recurseTimes - 1); | |
9295 | } | |
9296 | if (str.indexOf('\n') > -1) { | |
9297 | if (isArray(value)) { | |
9298 | str = str.split('\n').map(function(line) { | |
9299 | return ' ' + line; | |
9300 | }).join('\n').substr(2); | |
9301 | } else { | |
9302 | str = '\n' + str.split('\n').map(function(line) { | |
9303 | return ' ' + line; | |
9304 | }).join('\n'); | |
9305 | } | |
9306 | } | |
9307 | } else { | |
9308 | str = stylize('[Circular]', 'special'); | |
9309 | } | |
9310 | } | |
9311 | if (typeof name === 'undefined') { | |
9312 | if (type === 'Array' && key.match(/^\d+$/)) { | |
9313 | return str; | |
9314 | } | |
9315 | name = JSON.stringify('' + key); | |
9316 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { | |
9317 | name = name.substr(1, name.length - 2); | |
9318 | name = stylize(name, 'name'); | |
9319 | } else { | |
9320 | name = name.replace(/'/g, "\\'") | |
9321 | .replace(/\\"/g, '"') | |
9322 | .replace(/(^"|"$)/g, "'"); | |
9323 | name = stylize(name, 'string'); | |
9324 | } | |
9325 | } | |
9326 | ||
9327 | return name + ': ' + str; | |
9328 | }); | |
9329 | ||
9330 | seen.pop(); | |
9331 | ||
9332 | var numLinesEst = 0; | |
9333 | var length = output.reduce(function(prev, cur) { | |
9334 | numLinesEst++; | |
9335 | if (cur.indexOf('\n') >= 0) numLinesEst++; | |
9336 | return prev + cur.length + 1; | |
9337 | }, 0); | |
9338 | ||
9339 | if (length > 50) { | |
9340 | output = braces[0] + | |
9341 | (base === '' ? '' : base + '\n ') + | |
9342 | ' ' + | |
9343 | output.join(',\n ') + | |
9344 | ' ' + | |
9345 | braces[1]; | |
9346 | ||
9347 | } else { | |
9348 | output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; | |
9349 | } | |
9350 | ||
9351 | return output; | |
9352 | } | |
9353 | return format(obj, (typeof depth === 'undefined' ? 2 : depth)); | |
9354 | }; | |
9355 | ||
9356 | ||
9357 | function isArray(ar) { | |
9358 | return ar instanceof Array || | |
9359 | Array.isArray(ar) || | |
9360 | (ar && ar !== Object.prototype && isArray(ar.__proto__)); | |
9361 | } | |
9362 | ||
9363 | ||
9364 | function isRegExp(re) { | |
9365 | return re instanceof RegExp || | |
9366 | (typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]'); | |
9367 | } | |
9368 | ||
9369 | ||
9370 | function isDate(d) { | |
9371 | if (d instanceof Date) return true; | |
9372 | if (typeof d !== 'object') return false; | |
9373 | var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype); | |
9374 | var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__); | |
9375 | return JSON.stringify(proto) === JSON.stringify(properties); | |
9376 | } | |
9377 | ||
9378 | function pad(n) { | |
9379 | return n < 10 ? '0' + n.toString(10) : n.toString(10); | |
9380 | } | |
9381 | ||
9382 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', | |
9383 | 'Oct', 'Nov', 'Dec']; | |
9384 | ||
9385 | // 26 Feb 16:19:34 | |
9386 | function timestamp() { | |
9387 | var d = new Date(); | |
9388 | var time = [pad(d.getHours()), | |
9389 | pad(d.getMinutes()), | |
9390 | pad(d.getSeconds())].join(':'); | |
9391 | return [d.getDate(), months[d.getMonth()], time].join(' '); | |
9392 | } | |
9393 | ||
9394 | exports.log = function (msg) {}; | |
9395 | ||
9396 | exports.pump = null; | |
9397 | ||
9398 | var Object_keys = Object.keys || function (obj) { | |
9399 | var res = []; | |
9400 | for (var key in obj) res.push(key); | |
9401 | return res; | |
9402 | }; | |
9403 | ||
9404 | var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) { | |
9405 | var res = []; | |
9406 | for (var key in obj) { | |
9407 | if (Object.hasOwnProperty.call(obj, key)) res.push(key); | |
9408 | } | |
9409 | return res; | |
9410 | }; | |
9411 | ||
9412 | var Object_create = Object.create || function (prototype, properties) { | |
9413 | // from es5-shim | |
9414 | var object; | |
9415 | if (prototype === null) { | |
9416 | object = { '__proto__' : null }; | |
9417 | } | |
9418 | else { | |
9419 | if (typeof prototype !== 'object') { | |
9420 | throw new TypeError( | |
9421 | 'typeof prototype[' + (typeof prototype) + '] != \'object\'' | |
9422 | ); | |
9423 | } | |
9424 | var Type = function () {}; | |
9425 | Type.prototype = prototype; | |
9426 | object = new Type(); | |
9427 | object.__proto__ = prototype; | |
9428 | } | |
9429 | if (typeof properties !== 'undefined' && Object.defineProperties) { | |
9430 | Object.defineProperties(object, properties); | |
9431 | } | |
9432 | return object; | |
9433 | }; | |
9434 | ||
9435 | exports.inherits = function(ctor, superCtor) { | |
9436 | ctor.super_ = superCtor; | |
9437 | ctor.prototype = Object_create(superCtor.prototype, { | |
9438 | constructor: { | |
9439 | value: ctor, | |
9440 | enumerable: false, | |
9441 | writable: true, | |
9442 | configurable: true | |
9443 | } | |
9444 | }); | |
9445 | }; | |
9446 | ||
9447 | var formatRegExp = /%[sdj%]/g; | |
9448 | exports.format = function(f) { | |
9449 | if (typeof f !== 'string') { | |
9450 | var objects = []; | |
9451 | for (var i = 0; i < arguments.length; i++) { | |
9452 | objects.push(exports.inspect(arguments[i])); | |
9453 | } | |
9454 | return objects.join(' '); | |
9455 | } | |
9456 | ||
9457 | var i = 1; | |
9458 | var args = arguments; | |
9459 | var len = args.length; | |
9460 | var str = String(f).replace(formatRegExp, function(x) { | |
9461 | if (x === '%%') return '%'; | |
9462 | if (i >= len) return x; | |
9463 | switch (x) { | |
9464 | case '%s': return String(args[i++]); | |
9465 | case '%d': return Number(args[i++]); | |
9466 | case '%j': return JSON.stringify(args[i++]); | |
9467 | default: | |
9468 | return x; | |
9469 | } | |
9470 | }); | |
9471 | for(var x = args[i]; i < len; x = args[++i]){ | |
9472 | if (x === null || typeof x !== 'object') { | |
9473 | str += ' ' + x; | |
9474 | } else { | |
9475 | str += ' ' + exports.inspect(x); | |
9476 | } | |
9477 | } | |
9478 | return str; | |
9479 | }; | |
9480 | ||
9481 | },{"events":2}],12:[function(require,module,exports){ | |
9482 | (function(){// UTILITY | |
9483 | var util = require('util'); | |
9484 | var Buffer = require("buffer").Buffer; | |
9485 | var pSlice = Array.prototype.slice; | |
9486 | ||
9487 | function objectKeys(object) { | |
9488 | if (Object.keys) return Object.keys(object); | |
9489 | var result = []; | |
9490 | for (var name in object) { | |
9491 | if (Object.prototype.hasOwnProperty.call(object, name)) { | |
9492 | result.push(name); | |
9493 | } | |
9494 | } | |
9495 | return result; | |
9496 | } | |
9497 | ||
9498 | // 1. The assert module provides functions that throw | |
9499 | // AssertionError's when particular conditions are not met. The | |
9500 | // assert module must conform to the following interface. | |
9501 | ||
9502 | var assert = module.exports = ok; | |
9503 | ||
9504 | // 2. The AssertionError is defined in assert. | |
9505 | // new assert.AssertionError({ message: message, | |
9506 | // actual: actual, | |
9507 | // expected: expected }) | |
9508 | ||
9509 | assert.AssertionError = function AssertionError(options) { | |
9510 | this.name = 'AssertionError'; | |
9511 | this.message = options.message; | |
9512 | this.actual = options.actual; | |
9513 | this.expected = options.expected; | |
9514 | this.operator = options.operator; | |
9515 | var stackStartFunction = options.stackStartFunction || fail; | |
9516 | ||
9517 | if (Error.captureStackTrace) { | |
9518 | Error.captureStackTrace(this, stackStartFunction); | |
9519 | } | |
9520 | }; | |
9521 | util.inherits(assert.AssertionError, Error); | |
9522 | ||
9523 | function replacer(key, value) { | |
9524 | if (value === undefined) { | |
9525 | return '' + value; | |
9526 | } | |
9527 | if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) { | |
9528 | return value.toString(); | |
9529 | } | |
9530 | if (typeof value === 'function' || value instanceof RegExp) { | |
9531 | return value.toString(); | |
9532 | } | |
9533 | return value; | |
9534 | } | |
9535 | ||
9536 | function truncate(s, n) { | |
9537 | if (typeof s == 'string') { | |
9538 | return s.length < n ? s : s.slice(0, n); | |
9539 | } else { | |
9540 | return s; | |
9541 | } | |
9542 | } | |
9543 | ||
9544 | assert.AssertionError.prototype.toString = function() { | |
9545 | if (this.message) { | |
9546 | return [this.name + ':', this.message].join(' '); | |
9547 | } else { | |
9548 | return [ | |
9549 | this.name + ':', | |
9550 | truncate(JSON.stringify(this.actual, replacer), 128), | |
9551 | this.operator, | |
9552 | truncate(JSON.stringify(this.expected, replacer), 128) | |
9553 | ].join(' '); | |
9554 | } | |
9555 | }; | |
9556 | ||
9557 | // assert.AssertionError instanceof Error | |
9558 | ||
9559 | assert.AssertionError.__proto__ = Error.prototype; | |
9560 | ||
9561 | // At present only the three keys mentioned above are used and | |
9562 | // understood by the spec. Implementations or sub modules can pass | |
9563 | // other keys to the AssertionError's constructor - they will be | |
9564 | // ignored. | |
9565 | ||
9566 | // 3. All of the following functions must throw an AssertionError | |
9567 | // when a corresponding condition is not met, with a message that | |
9568 | // may be undefined if not provided. All assertion methods provide | |
9569 | // both the actual and expected values to the assertion error for | |
9570 | // display purposes. | |
9571 | ||
9572 | function fail(actual, expected, message, operator, stackStartFunction) { | |
9573 | throw new assert.AssertionError({ | |
9574 | message: message, | |
9575 | actual: actual, | |
9576 | expected: expected, | |
9577 | operator: operator, | |
9578 | stackStartFunction: stackStartFunction | |
9579 | }); | |
9580 | } | |
9581 | ||
9582 | // EXTENSION! allows for well behaved errors defined elsewhere. | |
9583 | assert.fail = fail; | |
9584 | ||
9585 | // 4. Pure assertion tests whether a value is truthy, as determined | |
9586 | // by !!guard. | |
9587 | // assert.ok(guard, message_opt); | |
9588 | // This statement is equivalent to assert.equal(true, guard, | |
9589 | // message_opt);. To test strictly for the value true, use | |
9590 | // assert.strictEqual(true, guard, message_opt);. | |
9591 | ||
9592 | function ok(value, message) { | |
9593 | if (!!!value) fail(value, true, message, '==', assert.ok); | |
9594 | } | |
9595 | assert.ok = ok; | |
9596 | ||
9597 | // 5. The equality assertion tests shallow, coercive equality with | |
9598 | // ==. | |
9599 | // assert.equal(actual, expected, message_opt); | |
9600 | ||
9601 | assert.equal = function equal(actual, expected, message) { | |
9602 | if (actual != expected) fail(actual, expected, message, '==', assert.equal); | |
9603 | }; | |
9604 | ||
9605 | // 6. The non-equality assertion tests for whether two objects are not equal | |
9606 | // with != assert.notEqual(actual, expected, message_opt); | |
9607 | ||
9608 | assert.notEqual = function notEqual(actual, expected, message) { | |
9609 | if (actual == expected) { | |
9610 | fail(actual, expected, message, '!=', assert.notEqual); | |
9611 | } | |
9612 | }; | |
9613 | ||
9614 | // 7. The equivalence assertion tests a deep equality relation. | |
9615 | // assert.deepEqual(actual, expected, message_opt); | |
9616 | ||
9617 | assert.deepEqual = function deepEqual(actual, expected, message) { | |
9618 | if (!_deepEqual(actual, expected)) { | |
9619 | fail(actual, expected, message, 'deepEqual', assert.deepEqual); | |
9620 | } | |
9621 | }; | |
9622 | ||
9623 | function _deepEqual(actual, expected) { | |
9624 | // 7.1. All identical values are equivalent, as determined by ===. | |
9625 | if (actual === expected) { | |
9626 | return true; | |
9627 | ||
9628 | } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { | |
9629 | if (actual.length != expected.length) return false; | |
9630 | ||
9631 | for (var i = 0; i < actual.length; i++) { | |
9632 | if (actual[i] !== expected[i]) return false; | |
9633 | } | |
9634 | ||
9635 | return true; | |
9636 | ||
9637 | // 7.2. If the expected value is a Date object, the actual value is | |
9638 | // equivalent if it is also a Date object that refers to the same time. | |
9639 | } else if (actual instanceof Date && expected instanceof Date) { | |
9640 | return actual.getTime() === expected.getTime(); | |
9641 | ||
9642 | // 7.3. Other pairs that do not both pass typeof value == 'object', | |
9643 | // equivalence is determined by ==. | |
9644 | } else if (typeof actual != 'object' && typeof expected != 'object') { | |
9645 | return actual == expected; | |
9646 | ||
9647 | // 7.4. For all other Object pairs, including Array objects, equivalence is | |
9648 | // determined by having the same number of owned properties (as verified | |
9649 | // with Object.prototype.hasOwnProperty.call), the same set of keys | |
9650 | // (although not necessarily the same order), equivalent values for every | |
9651 | // corresponding key, and an identical 'prototype' property. Note: this | |
9652 | // accounts for both named and indexed properties on Arrays. | |
9653 | } else { | |
9654 | return objEquiv(actual, expected); | |
9655 | } | |
9656 | } | |
9657 | ||
9658 | function isUndefinedOrNull(value) { | |
9659 | return value === null || value === undefined; | |
9660 | } | |
9661 | ||
9662 | function isArguments(object) { | |
9663 | return Object.prototype.toString.call(object) == '[object Arguments]'; | |
9664 | } | |
9665 | ||
9666 | function objEquiv(a, b) { | |
9667 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) | |
9668 | return false; | |
9669 | // an identical 'prototype' property. | |
9670 | if (a.prototype !== b.prototype) return false; | |
9671 | //~~~I've managed to break Object.keys through screwy arguments passing. | |
9672 | // Converting to array solves the problem. | |
9673 | if (isArguments(a)) { | |
9674 | if (!isArguments(b)) { | |
9675 | return false; | |
9676 | } | |
9677 | a = pSlice.call(a); | |
9678 | b = pSlice.call(b); | |
9679 | return _deepEqual(a, b); | |
9680 | } | |
9681 | try { | |
9682 | var ka = objectKeys(a), | |
9683 | kb = objectKeys(b), | |
9684 | key, i; | |
9685 | } catch (e) {//happens when one is a string literal and the other isn't | |
9686 | return false; | |
9687 | } | |
9688 | // having the same number of owned properties (keys incorporates | |
9689 | // hasOwnProperty) | |
9690 | if (ka.length != kb.length) | |
9691 | return false; | |
9692 | //the same set of keys (although not necessarily the same order), | |
9693 | ka.sort(); | |
9694 | kb.sort(); | |
9695 | //~~~cheap key test | |
9696 | for (i = ka.length - 1; i >= 0; i--) { | |
9697 | if (ka[i] != kb[i]) | |
9698 | return false; | |
9699 | } | |
9700 | //equivalent values for every corresponding key, and | |
9701 | //~~~possibly expensive deep test | |
9702 | for (i = ka.length - 1; i >= 0; i--) { | |
9703 | key = ka[i]; | |
9704 | if (!_deepEqual(a[key], b[key])) return false; | |
9705 | } | |
9706 | return true; | |
9707 | } | |
9708 | ||
9709 | // 8. The non-equivalence assertion tests for any deep inequality. | |
9710 | // assert.notDeepEqual(actual, expected, message_opt); | |
9711 | ||
9712 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) { | |
9713 | if (_deepEqual(actual, expected)) { | |
9714 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); | |
9715 | } | |
9716 | }; | |
9717 | ||
9718 | // 9. The strict equality assertion tests strict equality, as determined by ===. | |
9719 | // assert.strictEqual(actual, expected, message_opt); | |
9720 | ||
9721 | assert.strictEqual = function strictEqual(actual, expected, message) { | |
9722 | if (actual !== expected) { | |
9723 | fail(actual, expected, message, '===', assert.strictEqual); | |
9724 | } | |
9725 | }; | |
9726 | ||
9727 | // 10. The strict non-equality assertion tests for strict inequality, as | |
9728 | // determined by !==. assert.notStrictEqual(actual, expected, message_opt); | |
9729 | ||
9730 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) { | |
9731 | if (actual === expected) { | |
9732 | fail(actual, expected, message, '!==', assert.notStrictEqual); | |
9733 | } | |
9734 | }; | |
9735 | ||
9736 | function expectedException(actual, expected) { | |
9737 | if (!actual || !expected) { | |
9738 | return false; | |
9739 | } | |
9740 | ||
9741 | if (expected instanceof RegExp) { | |
9742 | return expected.test(actual); | |
9743 | } else if (actual instanceof expected) { | |
9744 | return true; | |
9745 | } else if (expected.call({}, actual) === true) { | |
9746 | return true; | |
9747 | } | |
9748 | ||
9749 | return false; | |
9750 | } | |
9751 | ||
9752 | function _throws(shouldThrow, block, expected, message) { | |
9753 | var actual; | |
9754 | ||
9755 | if (typeof expected === 'string') { | |
9756 | message = expected; | |
9757 | expected = null; | |
9758 | } | |
9759 | ||
9760 | try { | |
9761 | block(); | |
9762 | } catch (e) { | |
9763 | actual = e; | |
9764 | } | |
9765 | ||
9766 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + | |
9767 | (message ? ' ' + message : '.'); | |
9768 | ||
9769 | if (shouldThrow && !actual) { | |
9770 | fail('Missing expected exception' + message); | |
9771 | } | |
9772 | ||
9773 | if (!shouldThrow && expectedException(actual, expected)) { | |
9774 | fail('Got unwanted exception' + message); | |
9775 | } | |
9776 | ||
9777 | if ((shouldThrow && actual && expected && | |
9778 | !expectedException(actual, expected)) || (!shouldThrow && actual)) { | |
9779 | throw actual; | |
9780 | } | |
9781 | } | |
9782 | ||
9783 | // 11. Expected to throw an error: | |
9784 | // assert.throws(block, Error_opt, message_opt); | |
9785 | ||
9786 | assert.throws = function(block, /*optional*/error, /*optional*/message) { | |
9787 | _throws.apply(this, [true].concat(pSlice.call(arguments))); | |
9788 | }; | |
9789 | ||
9790 | // EXTENSION! This is annoying to write outside this module. | |
9791 | assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { | |
9792 | _throws.apply(this, [false].concat(pSlice.call(arguments))); | |
9793 | }; | |
9794 | ||
9795 | assert.ifError = function(err) { if (err) {throw err;}}; | |
9796 | ||
9797 | })() | |
9798 | },{"util":11,"buffer":13}],14:[function(require,module,exports){ | |
9799 | exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) { | |
9800 | var e, m, | |
9801 | eLen = nBytes * 8 - mLen - 1, | |
9802 | eMax = (1 << eLen) - 1, | |
9803 | eBias = eMax >> 1, | |
9804 | nBits = -7, | |
9805 | i = isBE ? 0 : (nBytes - 1), | |
9806 | d = isBE ? 1 : -1, | |
9807 | s = buffer[offset + i]; | |
9808 | ||
9809 | i += d; | |
9810 | ||
9811 | e = s & ((1 << (-nBits)) - 1); | |
9812 | s >>= (-nBits); | |
9813 | nBits += eLen; | |
9814 | for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); | |
9815 | ||
9816 | m = e & ((1 << (-nBits)) - 1); | |
9817 | e >>= (-nBits); | |
9818 | nBits += mLen; | |
9819 | for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); | |
9820 | ||
9821 | if (e === 0) { | |
9822 | e = 1 - eBias; | |
9823 | } else if (e === eMax) { | |
9824 | return m ? NaN : ((s ? -1 : 1) * Infinity); | |
9825 | } else { | |
9826 | m = m + Math.pow(2, mLen); | |
9827 | e = e - eBias; | |
9828 | } | |
9829 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen); | |
9830 | }; | |
9831 | ||
9832 | exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) { | |
9833 | var e, m, c, | |
9834 | eLen = nBytes * 8 - mLen - 1, | |
9835 | eMax = (1 << eLen) - 1, | |
9836 | eBias = eMax >> 1, | |
9837 | rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), | |
9838 | i = isBE ? (nBytes - 1) : 0, | |
9839 | d = isBE ? -1 : 1, | |
9840 | s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; | |
9841 | ||
9842 | value = Math.abs(value); | |
9843 | ||
9844 | if (isNaN(value) || value === Infinity) { | |
9845 | m = isNaN(value) ? 1 : 0; | |
9846 | e = eMax; | |
9847 | } else { | |
9848 | e = Math.floor(Math.log(value) / Math.LN2); | |
9849 | if (value * (c = Math.pow(2, -e)) < 1) { | |
9850 | e--; | |
9851 | c *= 2; | |
9852 | } | |
9853 | if (e + eBias >= 1) { | |
9854 | value += rt / c; | |
9855 | } else { | |
9856 | value += rt * Math.pow(2, 1 - eBias); | |
9857 | } | |
9858 | if (value * c >= 2) { | |
9859 | e++; | |
9860 | c /= 2; | |
9861 | } | |
9862 | ||
9863 | if (e + eBias >= eMax) { | |
9864 | m = 0; | |
9865 | e = eMax; | |
9866 | } else if (e + eBias >= 1) { | |
9867 | m = (value * c - 1) * Math.pow(2, mLen); | |
9868 | e = e + eBias; | |
9869 | } else { | |
9870 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); | |
9871 | e = 0; | |
9872 | } | |
9873 | } | |
9874 | ||
9875 | for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); | |
9876 | ||
9877 | e = (e << mLen) | m; | |
9878 | eLen += mLen; | |
9879 | for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); | |
9880 | ||
9881 | buffer[offset + i - d] |= s * 128; | |
9882 | }; | |
9883 | ||
9884 | },{}],13:[function(require,module,exports){ | |
9885 | (function(){function SlowBuffer (size) { | |
9886 | this.length = size; | |
9887 | }; | |
9888 | ||
9889 | var assert = require('assert'); | |
9890 | ||
9891 | exports.INSPECT_MAX_BYTES = 50; | |
9892 | ||
9893 | ||
9894 | function toHex(n) { | |
9895 | if (n < 16) return '0' + n.toString(16); | |
9896 | return n.toString(16); | |
9897 | } | |
9898 | ||
9899 | function utf8ToBytes(str) { | |
9900 | var byteArray = []; | |
9901 | for (var i = 0; i < str.length; i++) | |
9902 | if (str.charCodeAt(i) <= 0x7F) | |
9903 | byteArray.push(str.charCodeAt(i)); | |
9904 | else { | |
9905 | var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); | |
9906 | for (var j = 0; j < h.length; j++) | |
9907 | byteArray.push(parseInt(h[j], 16)); | |
9908 | } | |
9909 | ||
9910 | return byteArray; | |
9911 | } | |
9912 | ||
9913 | function asciiToBytes(str) { | |
9914 | var byteArray = [] | |
9915 | for (var i = 0; i < str.length; i++ ) | |
9916 | // Node's code seems to be doing this and not & 0x7F.. | |
9917 | byteArray.push( str.charCodeAt(i) & 0xFF ); | |
9918 | ||
9919 | return byteArray; | |
9920 | } | |
9921 | ||
9922 | function base64ToBytes(str) { | |
9923 | return require("base64-js").toByteArray(str); | |
9924 | } | |
9925 | ||
9926 | SlowBuffer.byteLength = function (str, encoding) { | |
9927 | switch (encoding || "utf8") { | |
9928 | case 'hex': | |
9929 | return str.length / 2; | |
9930 | ||
9931 | case 'utf8': | |
9932 | case 'utf-8': | |
9933 | return utf8ToBytes(str).length; | |
9934 | ||
9935 | case 'ascii': | |
9936 | case 'binary': | |
9937 | return str.length; | |
9938 | ||
9939 | case 'base64': | |
9940 | return base64ToBytes(str).length; | |
9941 | ||
9942 | default: | |
9943 | throw new Error('Unknown encoding'); | |
9944 | } | |
9945 | }; | |
9946 | ||
9947 | function blitBuffer(src, dst, offset, length) { | |
9948 | var pos, i = 0; | |
9949 | while (i < length) { | |
9950 | if ((i+offset >= dst.length) || (i >= src.length)) | |
9951 | break; | |
9952 | ||
9953 | dst[i + offset] = src[i]; | |
9954 | i++; | |
9955 | } | |
9956 | return i; | |
9957 | } | |
9958 | ||
9959 | SlowBuffer.prototype.utf8Write = function (string, offset, length) { | |
9960 | var bytes, pos; | |
9961 | return SlowBuffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length); | |
9962 | }; | |
9963 | ||
9964 | SlowBuffer.prototype.asciiWrite = function (string, offset, length) { | |
9965 | var bytes, pos; | |
9966 | return SlowBuffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length); | |
9967 | }; | |
9968 | ||
9969 | SlowBuffer.prototype.binaryWrite = SlowBuffer.prototype.asciiWrite; | |
9970 | ||
9971 | SlowBuffer.prototype.base64Write = function (string, offset, length) { | |
9972 | var bytes, pos; | |
9973 | return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length); | |
9974 | }; | |
9975 | ||
9976 | SlowBuffer.prototype.base64Slice = function (start, end) { | |
9977 | var bytes = Array.prototype.slice.apply(this, arguments) | |
9978 | return require("base64-js").fromByteArray(bytes); | |
9979 | } | |
9980 | ||
9981 | function decodeUtf8Char(str) { | |
9982 | try { | |
9983 | return decodeURIComponent(str); | |
9984 | } catch (err) { | |
9985 | return String.fromCharCode(0xFFFD); // UTF 8 invalid char | |
9986 | } | |
9987 | } | |
9988 | ||
9989 | SlowBuffer.prototype.utf8Slice = function () { | |
9990 | var bytes = Array.prototype.slice.apply(this, arguments); | |
9991 | var res = ""; | |
9992 | var tmp = ""; | |
9993 | var i = 0; | |
9994 | while (i < bytes.length) { | |
9995 | if (bytes[i] <= 0x7F) { | |
9996 | res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]); | |
9997 | tmp = ""; | |
9998 | } else | |
9999 | tmp += "%" + bytes[i].toString(16); | |
10000 | ||
10001 | i++; | |
10002 | } | |
10003 | ||
10004 | return res + decodeUtf8Char(tmp); | |
10005 | } | |
10006 | ||
10007 | SlowBuffer.prototype.asciiSlice = function () { | |
10008 | var bytes = Array.prototype.slice.apply(this, arguments); | |
10009 | var ret = ""; | |
10010 | for (var i = 0; i < bytes.length; i++) | |
10011 | ret += String.fromCharCode(bytes[i]); | |
10012 | return ret; | |
10013 | } | |
10014 | ||
10015 | SlowBuffer.prototype.binarySlice = SlowBuffer.prototype.asciiSlice; | |
10016 | ||
10017 | SlowBuffer.prototype.inspect = function() { | |
10018 | var out = [], | |
10019 | len = this.length; | |
10020 | for (var i = 0; i < len; i++) { | |
10021 | out[i] = toHex(this[i]); | |
10022 | if (i == exports.INSPECT_MAX_BYTES) { | |
10023 | out[i + 1] = '...'; | |
10024 | break; | |
10025 | } | |
10026 | } | |
10027 | return '<SlowBuffer ' + out.join(' ') + '>'; | |
10028 | }; | |
10029 | ||
10030 | ||
10031 | SlowBuffer.prototype.hexSlice = function(start, end) { | |
10032 | var len = this.length; | |
10033 | ||
10034 | if (!start || start < 0) start = 0; | |
10035 | if (!end || end < 0 || end > len) end = len; | |
10036 | ||
10037 | var out = ''; | |
10038 | for (var i = start; i < end; i++) { | |
10039 | out += toHex(this[i]); | |
10040 | } | |
10041 | return out; | |
10042 | }; | |
10043 | ||
10044 | ||
10045 | SlowBuffer.prototype.toString = function(encoding, start, end) { | |
10046 | encoding = String(encoding || 'utf8').toLowerCase(); | |
10047 | start = +start || 0; | |
10048 | if (typeof end == 'undefined') end = this.length; | |
10049 | ||
10050 | // Fastpath empty strings | |
10051 | if (+end == start) { | |
10052 | return ''; | |
10053 | } | |
10054 | ||
10055 | switch (encoding) { | |
10056 | case 'hex': | |
10057 | return this.hexSlice(start, end); | |
10058 | ||
10059 | case 'utf8': | |
10060 | case 'utf-8': | |
10061 | return this.utf8Slice(start, end); | |
10062 | ||
10063 | case 'ascii': | |
10064 | return this.asciiSlice(start, end); | |
10065 | ||
10066 | case 'binary': | |
10067 | return this.binarySlice(start, end); | |
10068 | ||
10069 | case 'base64': | |
10070 | return this.base64Slice(start, end); | |
10071 | ||
10072 | case 'ucs2': | |
10073 | case 'ucs-2': | |
10074 | return this.ucs2Slice(start, end); | |
10075 | ||
10076 | default: | |
10077 | throw new Error('Unknown encoding'); | |
10078 | } | |
10079 | }; | |
10080 | ||
10081 | ||
10082 | SlowBuffer.prototype.hexWrite = function(string, offset, length) { | |
10083 | offset = +offset || 0; | |
10084 | var remaining = this.length - offset; | |
10085 | if (!length) { | |
10086 | length = remaining; | |
10087 | } else { | |
10088 | length = +length; | |
10089 | if (length > remaining) { | |
10090 | length = remaining; | |
10091 | } | |
10092 | } | |
10093 | ||
10094 | // must be an even number of digits | |
10095 | var strLen = string.length; | |
10096 | if (strLen % 2) { | |
10097 | throw new Error('Invalid hex string'); | |
10098 | } | |
10099 | if (length > strLen / 2) { | |
10100 | length = strLen / 2; | |
10101 | } | |
10102 | for (var i = 0; i < length; i++) { | |
10103 | var byte = parseInt(string.substr(i * 2, 2), 16); | |
10104 | if (isNaN(byte)) throw new Error('Invalid hex string'); | |
10105 | this[offset + i] = byte; | |
10106 | } | |
10107 | SlowBuffer._charsWritten = i * 2; | |
10108 | return i; | |
10109 | }; | |
10110 | ||
10111 | ||
10112 | SlowBuffer.prototype.write = function(string, offset, length, encoding) { | |
10113 | // Support both (string, offset, length, encoding) | |
10114 | // and the legacy (string, encoding, offset, length) | |
10115 | if (isFinite(offset)) { | |
10116 | if (!isFinite(length)) { | |
10117 | encoding = length; | |
10118 | length = undefined; | |
10119 | } | |
10120 | } else { // legacy | |
10121 | var swap = encoding; | |
10122 | encoding = offset; | |
10123 | offset = length; | |
10124 | length = swap; | |
10125 | } | |
10126 | ||
10127 | offset = +offset || 0; | |
10128 | var remaining = this.length - offset; | |
10129 | if (!length) { | |
10130 | length = remaining; | |
10131 | } else { | |
10132 | length = +length; | |
10133 | if (length > remaining) { | |
10134 | length = remaining; | |
10135 | } | |
10136 | } | |
10137 | encoding = String(encoding || 'utf8').toLowerCase(); | |
10138 | ||
10139 | switch (encoding) { | |
10140 | case 'hex': | |
10141 | return this.hexWrite(string, offset, length); | |
10142 | ||
10143 | case 'utf8': | |
10144 | case 'utf-8': | |
10145 | return this.utf8Write(string, offset, length); | |
10146 | ||
10147 | case 'ascii': | |
10148 | return this.asciiWrite(string, offset, length); | |
10149 | ||
10150 | case 'binary': | |
10151 | return this.binaryWrite(string, offset, length); | |
10152 | ||
10153 | case 'base64': | |
10154 | return this.base64Write(string, offset, length); | |
10155 | ||
10156 | case 'ucs2': | |
10157 | case 'ucs-2': | |
10158 | return this.ucs2Write(string, offset, length); | |
10159 | ||
10160 | default: | |
10161 | throw new Error('Unknown encoding'); | |
10162 | } | |
10163 | }; | |
10164 | ||
10165 | ||
10166 | // slice(start, end) | |
10167 | SlowBuffer.prototype.slice = function(start, end) { | |
10168 | if (end === undefined) end = this.length; | |
10169 | ||
10170 | if (end > this.length) { | |
10171 | throw new Error('oob'); | |
10172 | } | |
10173 | if (start > end) { | |
10174 | throw new Error('oob'); | |
10175 | } | |
10176 | ||
10177 | return new Buffer(this, end - start, +start); | |
10178 | }; | |
10179 | ||
10180 | SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) { | |
10181 | var temp = []; | |
10182 | for (var i=sourcestart; i<sourceend; i++) { | |
10183 | assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!"); | |
10184 | temp.push(this[i]); | |
10185 | } | |
10186 | ||
10187 | for (var i=targetstart; i<targetstart+temp.length; i++) { | |
10188 | target[i] = temp[i-targetstart]; | |
10189 | } | |
10190 | }; | |
10191 | ||
10192 | SlowBuffer.prototype.fill = function(value, start, end) { | |
10193 | if (end > this.length) { | |
10194 | throw new Error('oob'); | |
10195 | } | |
10196 | if (start > end) { | |
10197 | throw new Error('oob'); | |
10198 | } | |
10199 | ||
10200 | for (var i = start; i < end; i++) { | |
10201 | this[i] = value; | |
10202 | } | |
10203 | } | |
10204 | ||
10205 | function coerce(length) { | |
10206 | // Coerce length to a number (possibly NaN), round up | |
10207 | // in case it's fractional (e.g. 123.456) then do a | |
10208 | // double negate to coerce a NaN to 0. Easy, right? | |
10209 | length = ~~Math.ceil(+length); | |
10210 | return length < 0 ? 0 : length; | |
10211 | } | |
10212 | ||
10213 | ||
10214 | // Buffer | |
10215 | ||
10216 | function Buffer(subject, encoding, offset) { | |
10217 | if (!(this instanceof Buffer)) { | |
10218 | return new Buffer(subject, encoding, offset); | |
10219 | } | |
10220 | ||
10221 | var type; | |
10222 | ||
10223 | // Are we slicing? | |
10224 | if (typeof offset === 'number') { | |
10225 | this.length = coerce(encoding); | |
10226 | this.parent = subject; | |
10227 | this.offset = offset; | |
10228 | } else { | |
10229 | // Find the length | |
10230 | switch (type = typeof subject) { | |
10231 | case 'number': | |
10232 | this.length = coerce(subject); | |
10233 | break; | |
10234 | ||
10235 | case 'string': | |
10236 | this.length = Buffer.byteLength(subject, encoding); | |
10237 | break; | |
10238 | ||
10239 | case 'object': // Assume object is an array | |
10240 | this.length = coerce(subject.length); | |
10241 | break; | |
10242 | ||
10243 | default: | |
10244 | throw new Error('First argument needs to be a number, ' + | |
10245 | 'array or string.'); | |
10246 | } | |
10247 | ||
10248 | if (this.length > Buffer.poolSize) { | |
10249 | // Big buffer, just alloc one. | |
10250 | this.parent = new SlowBuffer(this.length); | |
10251 | this.offset = 0; | |
10252 | ||
10253 | } else { | |
10254 | // Small buffer. | |
10255 | if (!pool || pool.length - pool.used < this.length) allocPool(); | |
10256 | this.parent = pool; | |
10257 | this.offset = pool.used; | |
10258 | pool.used += this.length; | |
10259 | } | |
10260 | ||
10261 | // Treat array-ish objects as a byte array. | |
10262 | if (isArrayIsh(subject)) { | |
10263 | for (var i = 0; i < this.length; i++) { | |
10264 | if (subject instanceof Buffer) { | |
10265 | this.parent[i + this.offset] = subject.readUInt8(i); | |
10266 | } | |
10267 | else { | |
10268 | this.parent[i + this.offset] = subject[i]; | |
10269 | } | |
10270 | } | |
10271 | } else if (type == 'string') { | |
10272 | // We are a string | |
10273 | this.length = this.write(subject, 0, encoding); | |
10274 | } | |
10275 | } | |
10276 | ||
10277 | } | |
10278 | ||
10279 | function isArrayIsh(subject) { | |
10280 | return Array.isArray(subject) || Buffer.isBuffer(subject) || | |
10281 | subject && typeof subject === 'object' && | |
10282 | typeof subject.length === 'number'; | |
10283 | } | |
10284 | ||
10285 | exports.SlowBuffer = SlowBuffer; | |
10286 | exports.Buffer = Buffer; | |
10287 | ||
10288 | Buffer.poolSize = 8 * 1024; | |
10289 | var pool; | |
10290 | ||
10291 | function allocPool() { | |
10292 | pool = new SlowBuffer(Buffer.poolSize); | |
10293 | pool.used = 0; | |
10294 | } | |
10295 | ||
10296 | ||
10297 | // Static methods | |
10298 | Buffer.isBuffer = function isBuffer(b) { | |
10299 | return b instanceof Buffer || b instanceof SlowBuffer; | |
10300 | }; | |
10301 | ||
10302 | Buffer.concat = function (list, totalLength) { | |
10303 | if (!Array.isArray(list)) { | |
10304 | throw new Error("Usage: Buffer.concat(list, [totalLength])\n \ | |
10305 | list should be an Array."); | |
10306 | } | |
10307 | ||
10308 | if (list.length === 0) { | |
10309 | return new Buffer(0); | |
10310 | } else if (list.length === 1) { | |
10311 | return list[0]; | |
10312 | } | |
10313 | ||
10314 | if (typeof totalLength !== 'number') { | |
10315 | totalLength = 0; | |
10316 | for (var i = 0; i < list.length; i++) { | |
10317 | var buf = list[i]; | |
10318 | totalLength += buf.length; | |
10319 | } | |
10320 | } | |
10321 | ||
10322 | var buffer = new Buffer(totalLength); | |
10323 | var pos = 0; | |
10324 | for (var i = 0; i < list.length; i++) { | |
10325 | var buf = list[i]; | |
10326 | buf.copy(buffer, pos); | |
10327 | pos += buf.length; | |
10328 | } | |
10329 | return buffer; | |
10330 | }; | |
10331 | ||
10332 | // Inspect | |
10333 | Buffer.prototype.inspect = function inspect() { | |
10334 | var out = [], | |
10335 | len = this.length; | |
10336 | ||
10337 | for (var i = 0; i < len; i++) { | |
10338 | out[i] = toHex(this.parent[i + this.offset]); | |
10339 | if (i == exports.INSPECT_MAX_BYTES) { | |
10340 | out[i + 1] = '...'; | |
10341 | break; | |
10342 | } | |
10343 | } | |
10344 | ||
10345 | return '<Buffer ' + out.join(' ') + '>'; | |
10346 | }; | |
10347 | ||
10348 | ||
10349 | Buffer.prototype.get = function get(i) { | |
10350 | if (i < 0 || i >= this.length) throw new Error('oob'); | |
10351 | return this.parent[this.offset + i]; | |
10352 | }; | |
10353 | ||
10354 | ||
10355 | Buffer.prototype.set = function set(i, v) { | |
10356 | if (i < 0 || i >= this.length) throw new Error('oob'); | |
10357 | return this.parent[this.offset + i] = v; | |
10358 | }; | |
10359 | ||
10360 | ||
10361 | // write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8') | |
10362 | Buffer.prototype.write = function(string, offset, length, encoding) { | |
10363 | // Support both (string, offset, length, encoding) | |
10364 | // and the legacy (string, encoding, offset, length) | |
10365 | if (isFinite(offset)) { | |
10366 | if (!isFinite(length)) { | |
10367 | encoding = length; | |
10368 | length = undefined; | |
10369 | } | |
10370 | } else { // legacy | |
10371 | var swap = encoding; | |
10372 | encoding = offset; | |
10373 | offset = length; | |
10374 | length = swap; | |
10375 | } | |
10376 | ||
10377 | offset = +offset || 0; | |
10378 | var remaining = this.length - offset; | |
10379 | if (!length) { | |
10380 | length = remaining; | |
10381 | } else { | |
10382 | length = +length; | |
10383 | if (length > remaining) { | |
10384 | length = remaining; | |
10385 | } | |
10386 | } | |
10387 | encoding = String(encoding || 'utf8').toLowerCase(); | |
10388 | ||
10389 | var ret; | |
10390 | switch (encoding) { | |
10391 | case 'hex': | |
10392 | ret = this.parent.hexWrite(string, this.offset + offset, length); | |
10393 | break; | |
10394 | ||
10395 | case 'utf8': | |
10396 | case 'utf-8': | |
10397 | ret = this.parent.utf8Write(string, this.offset + offset, length); | |
10398 | break; | |
10399 | ||
10400 | case 'ascii': | |
10401 | ret = this.parent.asciiWrite(string, this.offset + offset, length); | |
10402 | break; | |
10403 | ||
10404 | case 'binary': | |
10405 | ret = this.parent.binaryWrite(string, this.offset + offset, length); | |
10406 | break; | |
10407 | ||
10408 | case 'base64': | |
10409 | // Warning: maxLength not taken into account in base64Write | |
10410 | ret = this.parent.base64Write(string, this.offset + offset, length); | |
10411 | break; | |
10412 | ||
10413 | case 'ucs2': | |
10414 | case 'ucs-2': | |
10415 | ret = this.parent.ucs2Write(string, this.offset + offset, length); | |
10416 | break; | |
10417 | ||
10418 | default: | |
10419 | throw new Error('Unknown encoding'); | |
10420 | } | |
10421 | ||
10422 | Buffer._charsWritten = SlowBuffer._charsWritten; | |
10423 | ||
10424 | return ret; | |
10425 | }; | |
10426 | ||
10427 | ||
10428 | // toString(encoding, start=0, end=buffer.length) | |
10429 | Buffer.prototype.toString = function(encoding, start, end) { | |
10430 | encoding = String(encoding || 'utf8').toLowerCase(); | |
10431 | ||
10432 | if (typeof start == 'undefined' || start < 0) { | |
10433 | start = 0; | |
10434 | } else if (start > this.length) { | |
10435 | start = this.length; | |
10436 | } | |
10437 | ||
10438 | if (typeof end == 'undefined' || end > this.length) { | |
10439 | end = this.length; | |
10440 | } else if (end < 0) { | |
10441 | end = 0; | |
10442 | } | |
10443 | ||
10444 | start = start + this.offset; | |
10445 | end = end + this.offset; | |
10446 | ||
10447 | switch (encoding) { | |
10448 | case 'hex': | |
10449 | return this.parent.hexSlice(start, end); | |
10450 | ||
10451 | case 'utf8': | |
10452 | case 'utf-8': | |
10453 | return this.parent.utf8Slice(start, end); | |
10454 | ||
10455 | case 'ascii': | |
10456 | return this.parent.asciiSlice(start, end); | |
10457 | ||
10458 | case 'binary': | |
10459 | return this.parent.binarySlice(start, end); | |
10460 | ||
10461 | case 'base64': | |
10462 | return this.parent.base64Slice(start, end); | |
10463 | ||
10464 | case 'ucs2': | |
10465 | case 'ucs-2': | |
10466 | return this.parent.ucs2Slice(start, end); | |
10467 | ||
10468 | default: | |
10469 | throw new Error('Unknown encoding'); | |
10470 | } | |
10471 | }; | |
10472 | ||
10473 | ||
10474 | // byteLength | |
10475 | Buffer.byteLength = SlowBuffer.byteLength; | |
10476 | ||
10477 | ||
10478 | // fill(value, start=0, end=buffer.length) | |
10479 | Buffer.prototype.fill = function fill(value, start, end) { | |
10480 | value || (value = 0); | |
10481 | start || (start = 0); | |
10482 | end || (end = this.length); | |
10483 | ||
10484 | if (typeof value === 'string') { | |
10485 | value = value.charCodeAt(0); | |
10486 | } | |
10487 | if (!(typeof value === 'number') || isNaN(value)) { | |
10488 | throw new Error('value is not a number'); | |
10489 | } | |
10490 | ||
10491 | if (end < start) throw new Error('end < start'); | |
10492 | ||
10493 | // Fill 0 bytes; we're done | |
10494 | if (end === start) return 0; | |
10495 | if (this.length == 0) return 0; | |
10496 | ||
10497 | if (start < 0 || start >= this.length) { | |
10498 | throw new Error('start out of bounds'); | |
10499 | } | |
10500 | ||
10501 | if (end < 0 || end > this.length) { | |
10502 | throw new Error('end out of bounds'); | |
10503 | } | |
10504 | ||
10505 | return this.parent.fill(value, | |
10506 | start + this.offset, | |
10507 | end + this.offset); | |
10508 | }; | |
10509 | ||
10510 | ||
10511 | // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) | |
10512 | Buffer.prototype.copy = function(target, target_start, start, end) { | |
10513 | var source = this; | |
10514 | start || (start = 0); | |
10515 | end || (end = this.length); | |
10516 | target_start || (target_start = 0); | |
10517 | ||
10518 | if (end < start) throw new Error('sourceEnd < sourceStart'); | |
10519 | ||
10520 | // Copy 0 bytes; we're done | |
10521 | if (end === start) return 0; | |
10522 | if (target.length == 0 || source.length == 0) return 0; | |
10523 | ||
10524 | if (target_start < 0 || target_start >= target.length) { | |
10525 | throw new Error('targetStart out of bounds'); | |
10526 | } | |
10527 | ||
10528 | if (start < 0 || start >= source.length) { | |
10529 | throw new Error('sourceStart out of bounds'); | |
10530 | } | |
10531 | ||
10532 | if (end < 0 || end > source.length) { | |
10533 | throw new Error('sourceEnd out of bounds'); | |
10534 | } | |
10535 | ||
10536 | // Are we oob? | |
10537 | if (end > this.length) { | |
10538 | end = this.length; | |
10539 | } | |
10540 | ||
10541 | if (target.length - target_start < end - start) { | |
10542 | end = target.length - target_start + start; | |
10543 | } | |
10544 | ||
10545 | return this.parent.copy(target.parent, | |
10546 | target_start + target.offset, | |
10547 | start + this.offset, | |
10548 | end + this.offset); | |
10549 | }; | |
10550 | ||
10551 | ||
10552 | // slice(start, end) | |
10553 | Buffer.prototype.slice = function(start, end) { | |
10554 | if (end === undefined) end = this.length; | |
10555 | if (end > this.length) throw new Error('oob'); | |
10556 | if (start > end) throw new Error('oob'); | |
10557 | ||
10558 | return new Buffer(this.parent, end - start, +start + this.offset); | |
10559 | }; | |
10560 | ||
10561 | ||
10562 | // Legacy methods for backwards compatibility. | |
10563 | ||
10564 | Buffer.prototype.utf8Slice = function(start, end) { | |
10565 | return this.toString('utf8', start, end); | |
10566 | }; | |
10567 | ||
10568 | Buffer.prototype.binarySlice = function(start, end) { | |
10569 | return this.toString('binary', start, end); | |
10570 | }; | |
10571 | ||
10572 | Buffer.prototype.asciiSlice = function(start, end) { | |
10573 | return this.toString('ascii', start, end); | |
10574 | }; | |
10575 | ||
10576 | Buffer.prototype.utf8Write = function(string, offset) { | |
10577 | return this.write(string, offset, 'utf8'); | |
10578 | }; | |
10579 | ||
10580 | Buffer.prototype.binaryWrite = function(string, offset) { | |
10581 | return this.write(string, offset, 'binary'); | |
10582 | }; | |
10583 | ||
10584 | Buffer.prototype.asciiWrite = function(string, offset) { | |
10585 | return this.write(string, offset, 'ascii'); | |
10586 | }; | |
10587 | ||
10588 | Buffer.prototype.readUInt8 = function(offset, noAssert) { | |
10589 | var buffer = this; | |
10590 | ||
10591 | if (!noAssert) { | |
10592 | assert.ok(offset !== undefined && offset !== null, | |
10593 | 'missing offset'); | |
10594 | ||
10595 | assert.ok(offset < buffer.length, | |
10596 | 'Trying to read beyond buffer length'); | |
10597 | } | |
10598 | ||
10599 | if (offset >= buffer.length) return; | |
10600 | ||
10601 | return buffer.parent[buffer.offset + offset]; | |
10602 | }; | |
10603 | ||
10604 | function readUInt16(buffer, offset, isBigEndian, noAssert) { | |
10605 | var val = 0; | |
10606 | ||
10607 | ||
10608 | if (!noAssert) { | |
10609 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10610 | 'missing or invalid endian'); | |
10611 | ||
10612 | assert.ok(offset !== undefined && offset !== null, | |
10613 | 'missing offset'); | |
10614 | ||
10615 | assert.ok(offset + 1 < buffer.length, | |
10616 | 'Trying to read beyond buffer length'); | |
10617 | } | |
10618 | ||
10619 | if (offset >= buffer.length) return 0; | |
10620 | ||
10621 | if (isBigEndian) { | |
10622 | val = buffer.parent[buffer.offset + offset] << 8; | |
10623 | if (offset + 1 < buffer.length) { | |
10624 | val |= buffer.parent[buffer.offset + offset + 1]; | |
10625 | } | |
10626 | } else { | |
10627 | val = buffer.parent[buffer.offset + offset]; | |
10628 | if (offset + 1 < buffer.length) { | |
10629 | val |= buffer.parent[buffer.offset + offset + 1] << 8; | |
10630 | } | |
10631 | } | |
10632 | ||
10633 | return val; | |
10634 | } | |
10635 | ||
10636 | Buffer.prototype.readUInt16LE = function(offset, noAssert) { | |
10637 | return readUInt16(this, offset, false, noAssert); | |
10638 | }; | |
10639 | ||
10640 | Buffer.prototype.readUInt16BE = function(offset, noAssert) { | |
10641 | return readUInt16(this, offset, true, noAssert); | |
10642 | }; | |
10643 | ||
10644 | function readUInt32(buffer, offset, isBigEndian, noAssert) { | |
10645 | var val = 0; | |
10646 | ||
10647 | if (!noAssert) { | |
10648 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10649 | 'missing or invalid endian'); | |
10650 | ||
10651 | assert.ok(offset !== undefined && offset !== null, | |
10652 | 'missing offset'); | |
10653 | ||
10654 | assert.ok(offset + 3 < buffer.length, | |
10655 | 'Trying to read beyond buffer length'); | |
10656 | } | |
10657 | ||
10658 | if (offset >= buffer.length) return 0; | |
10659 | ||
10660 | if (isBigEndian) { | |
10661 | if (offset + 1 < buffer.length) | |
10662 | val = buffer.parent[buffer.offset + offset + 1] << 16; | |
10663 | if (offset + 2 < buffer.length) | |
10664 | val |= buffer.parent[buffer.offset + offset + 2] << 8; | |
10665 | if (offset + 3 < buffer.length) | |
10666 | val |= buffer.parent[buffer.offset + offset + 3]; | |
10667 | val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0); | |
10668 | } else { | |
10669 | if (offset + 2 < buffer.length) | |
10670 | val = buffer.parent[buffer.offset + offset + 2] << 16; | |
10671 | if (offset + 1 < buffer.length) | |
10672 | val |= buffer.parent[buffer.offset + offset + 1] << 8; | |
10673 | val |= buffer.parent[buffer.offset + offset]; | |
10674 | if (offset + 3 < buffer.length) | |
10675 | val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0); | |
10676 | } | |
10677 | ||
10678 | return val; | |
10679 | } | |
10680 | ||
10681 | Buffer.prototype.readUInt32LE = function(offset, noAssert) { | |
10682 | return readUInt32(this, offset, false, noAssert); | |
10683 | }; | |
10684 | ||
10685 | Buffer.prototype.readUInt32BE = function(offset, noAssert) { | |
10686 | return readUInt32(this, offset, true, noAssert); | |
10687 | }; | |
10688 | ||
10689 | ||
10690 | /* | |
10691 | * Signed integer types, yay team! A reminder on how two's complement actually | |
10692 | * works. The first bit is the signed bit, i.e. tells us whether or not the | |
10693 | * number should be positive or negative. If the two's complement value is | |
10694 | * positive, then we're done, as it's equivalent to the unsigned representation. | |
10695 | * | |
10696 | * Now if the number is positive, you're pretty much done, you can just leverage | |
10697 | * the unsigned translations and return those. Unfortunately, negative numbers | |
10698 | * aren't quite that straightforward. | |
10699 | * | |
10700 | * At first glance, one might be inclined to use the traditional formula to | |
10701 | * translate binary numbers between the positive and negative values in two's | |
10702 | * complement. (Though it doesn't quite work for the most negative value) | |
10703 | * Mainly: | |
10704 | * - invert all the bits | |
10705 | * - add one to the result | |
10706 | * | |
10707 | * Of course, this doesn't quite work in Javascript. Take for example the value | |
10708 | * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of | |
10709 | * course, Javascript will do the following: | |
10710 | * | |
10711 | * > ~0xff80 | |
10712 | * -65409 | |
10713 | * | |
10714 | * Whoh there, Javascript, that's not quite right. But wait, according to | |
10715 | * Javascript that's perfectly correct. When Javascript ends up seeing the | |
10716 | * constant 0xff80, it has no notion that it is actually a signed number. It | |
10717 | * assumes that we've input the unsigned value 0xff80. Thus, when it does the | |
10718 | * binary negation, it casts it into a signed value, (positive 0xff80). Then | |
10719 | * when you perform binary negation on that, it turns it into a negative number. | |
10720 | * | |
10721 | * Instead, we're going to have to use the following general formula, that works | |
10722 | * in a rather Javascript friendly way. I'm glad we don't support this kind of | |
10723 | * weird numbering scheme in the kernel. | |
10724 | * | |
10725 | * (BIT-MAX - (unsigned)val + 1) * -1 | |
10726 | * | |
10727 | * The astute observer, may think that this doesn't make sense for 8-bit numbers | |
10728 | * (really it isn't necessary for them). However, when you get 16-bit numbers, | |
10729 | * you do. Let's go back to our prior example and see how this will look: | |
10730 | * | |
10731 | * (0xffff - 0xff80 + 1) * -1 | |
10732 | * (0x007f + 1) * -1 | |
10733 | * (0x0080) * -1 | |
10734 | */ | |
10735 | Buffer.prototype.readInt8 = function(offset, noAssert) { | |
10736 | var buffer = this; | |
10737 | var neg; | |
10738 | ||
10739 | if (!noAssert) { | |
10740 | assert.ok(offset !== undefined && offset !== null, | |
10741 | 'missing offset'); | |
10742 | ||
10743 | assert.ok(offset < buffer.length, | |
10744 | 'Trying to read beyond buffer length'); | |
10745 | } | |
10746 | ||
10747 | if (offset >= buffer.length) return; | |
10748 | ||
10749 | neg = buffer.parent[buffer.offset + offset] & 0x80; | |
10750 | if (!neg) { | |
10751 | return (buffer.parent[buffer.offset + offset]); | |
10752 | } | |
10753 | ||
10754 | return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1); | |
10755 | }; | |
10756 | ||
10757 | function readInt16(buffer, offset, isBigEndian, noAssert) { | |
10758 | var neg, val; | |
10759 | ||
10760 | if (!noAssert) { | |
10761 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10762 | 'missing or invalid endian'); | |
10763 | ||
10764 | assert.ok(offset !== undefined && offset !== null, | |
10765 | 'missing offset'); | |
10766 | ||
10767 | assert.ok(offset + 1 < buffer.length, | |
10768 | 'Trying to read beyond buffer length'); | |
10769 | } | |
10770 | ||
10771 | val = readUInt16(buffer, offset, isBigEndian, noAssert); | |
10772 | neg = val & 0x8000; | |
10773 | if (!neg) { | |
10774 | return val; | |
10775 | } | |
10776 | ||
10777 | return (0xffff - val + 1) * -1; | |
10778 | } | |
10779 | ||
10780 | Buffer.prototype.readInt16LE = function(offset, noAssert) { | |
10781 | return readInt16(this, offset, false, noAssert); | |
10782 | }; | |
10783 | ||
10784 | Buffer.prototype.readInt16BE = function(offset, noAssert) { | |
10785 | return readInt16(this, offset, true, noAssert); | |
10786 | }; | |
10787 | ||
10788 | function readInt32(buffer, offset, isBigEndian, noAssert) { | |
10789 | var neg, val; | |
10790 | ||
10791 | if (!noAssert) { | |
10792 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10793 | 'missing or invalid endian'); | |
10794 | ||
10795 | assert.ok(offset !== undefined && offset !== null, | |
10796 | 'missing offset'); | |
10797 | ||
10798 | assert.ok(offset + 3 < buffer.length, | |
10799 | 'Trying to read beyond buffer length'); | |
10800 | } | |
10801 | ||
10802 | val = readUInt32(buffer, offset, isBigEndian, noAssert); | |
10803 | neg = val & 0x80000000; | |
10804 | if (!neg) { | |
10805 | return (val); | |
10806 | } | |
10807 | ||
10808 | return (0xffffffff - val + 1) * -1; | |
10809 | } | |
10810 | ||
10811 | Buffer.prototype.readInt32LE = function(offset, noAssert) { | |
10812 | return readInt32(this, offset, false, noAssert); | |
10813 | }; | |
10814 | ||
10815 | Buffer.prototype.readInt32BE = function(offset, noAssert) { | |
10816 | return readInt32(this, offset, true, noAssert); | |
10817 | }; | |
10818 | ||
10819 | function readFloat(buffer, offset, isBigEndian, noAssert) { | |
10820 | if (!noAssert) { | |
10821 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10822 | 'missing or invalid endian'); | |
10823 | ||
10824 | assert.ok(offset + 3 < buffer.length, | |
10825 | 'Trying to read beyond buffer length'); | |
10826 | } | |
10827 | ||
10828 | return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, | |
10829 | 23, 4); | |
10830 | } | |
10831 | ||
10832 | Buffer.prototype.readFloatLE = function(offset, noAssert) { | |
10833 | return readFloat(this, offset, false, noAssert); | |
10834 | }; | |
10835 | ||
10836 | Buffer.prototype.readFloatBE = function(offset, noAssert) { | |
10837 | return readFloat(this, offset, true, noAssert); | |
10838 | }; | |
10839 | ||
10840 | function readDouble(buffer, offset, isBigEndian, noAssert) { | |
10841 | if (!noAssert) { | |
10842 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10843 | 'missing or invalid endian'); | |
10844 | ||
10845 | assert.ok(offset + 7 < buffer.length, | |
10846 | 'Trying to read beyond buffer length'); | |
10847 | } | |
10848 | ||
10849 | return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, | |
10850 | 52, 8); | |
10851 | } | |
10852 | ||
10853 | Buffer.prototype.readDoubleLE = function(offset, noAssert) { | |
10854 | return readDouble(this, offset, false, noAssert); | |
10855 | }; | |
10856 | ||
10857 | Buffer.prototype.readDoubleBE = function(offset, noAssert) { | |
10858 | return readDouble(this, offset, true, noAssert); | |
10859 | }; | |
10860 | ||
10861 | ||
10862 | /* | |
10863 | * We have to make sure that the value is a valid integer. This means that it is | |
10864 | * non-negative. It has no fractional component and that it does not exceed the | |
10865 | * maximum allowed value. | |
10866 | * | |
10867 | * value The number to check for validity | |
10868 | * | |
10869 | * max The maximum value | |
10870 | */ | |
10871 | function verifuint(value, max) { | |
10872 | assert.ok(typeof (value) == 'number', | |
10873 | 'cannot write a non-number as a number'); | |
10874 | ||
10875 | assert.ok(value >= 0, | |
10876 | 'specified a negative value for writing an unsigned value'); | |
10877 | ||
10878 | assert.ok(value <= max, 'value is larger than maximum value for type'); | |
10879 | ||
10880 | assert.ok(Math.floor(value) === value, 'value has a fractional component'); | |
10881 | } | |
10882 | ||
10883 | Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { | |
10884 | var buffer = this; | |
10885 | ||
10886 | if (!noAssert) { | |
10887 | assert.ok(value !== undefined && value !== null, | |
10888 | 'missing value'); | |
10889 | ||
10890 | assert.ok(offset !== undefined && offset !== null, | |
10891 | 'missing offset'); | |
10892 | ||
10893 | assert.ok(offset < buffer.length, | |
10894 | 'trying to write beyond buffer length'); | |
10895 | ||
10896 | verifuint(value, 0xff); | |
10897 | } | |
10898 | ||
10899 | if (offset < buffer.length) { | |
10900 | buffer.parent[buffer.offset + offset] = value; | |
10901 | } | |
10902 | }; | |
10903 | ||
10904 | function writeUInt16(buffer, value, offset, isBigEndian, noAssert) { | |
10905 | if (!noAssert) { | |
10906 | assert.ok(value !== undefined && value !== null, | |
10907 | 'missing value'); | |
10908 | ||
10909 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10910 | 'missing or invalid endian'); | |
10911 | ||
10912 | assert.ok(offset !== undefined && offset !== null, | |
10913 | 'missing offset'); | |
10914 | ||
10915 | assert.ok(offset + 1 < buffer.length, | |
10916 | 'trying to write beyond buffer length'); | |
10917 | ||
10918 | verifuint(value, 0xffff); | |
10919 | } | |
10920 | ||
10921 | for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) { | |
10922 | buffer.parent[buffer.offset + offset + i] = | |
10923 | (value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>> | |
10924 | (isBigEndian ? 1 - i : i) * 8; | |
10925 | } | |
10926 | ||
10927 | } | |
10928 | ||
10929 | Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { | |
10930 | writeUInt16(this, value, offset, false, noAssert); | |
10931 | }; | |
10932 | ||
10933 | Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) { | |
10934 | writeUInt16(this, value, offset, true, noAssert); | |
10935 | }; | |
10936 | ||
10937 | function writeUInt32(buffer, value, offset, isBigEndian, noAssert) { | |
10938 | if (!noAssert) { | |
10939 | assert.ok(value !== undefined && value !== null, | |
10940 | 'missing value'); | |
10941 | ||
10942 | assert.ok(typeof (isBigEndian) === 'boolean', | |
10943 | 'missing or invalid endian'); | |
10944 | ||
10945 | assert.ok(offset !== undefined && offset !== null, | |
10946 | 'missing offset'); | |
10947 | ||
10948 | assert.ok(offset + 3 < buffer.length, | |
10949 | 'trying to write beyond buffer length'); | |
10950 | ||
10951 | verifuint(value, 0xffffffff); | |
10952 | } | |
10953 | ||
10954 | for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) { | |
10955 | buffer.parent[buffer.offset + offset + i] = | |
10956 | (value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff; | |
10957 | } | |
10958 | } | |
10959 | ||
10960 | Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { | |
10961 | writeUInt32(this, value, offset, false, noAssert); | |
10962 | }; | |
10963 | ||
10964 | Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { | |
10965 | writeUInt32(this, value, offset, true, noAssert); | |
10966 | }; | |
10967 | ||
10968 | ||
10969 | /* | |
10970 | * We now move onto our friends in the signed number category. Unlike unsigned | |
10971 | * numbers, we're going to have to worry a bit more about how we put values into | |
10972 | * arrays. Since we are only worrying about signed 32-bit values, we're in | |
10973 | * slightly better shape. Unfortunately, we really can't do our favorite binary | |
10974 | * & in this system. It really seems to do the wrong thing. For example: | |
10975 | * | |
10976 | * > -32 & 0xff | |
10977 | * 224 | |
10978 | * | |
10979 | * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of | |
10980 | * this aren't treated as a signed number. Ultimately a bad thing. | |
10981 | * | |
10982 | * What we're going to want to do is basically create the unsigned equivalent of | |
10983 | * our representation and pass that off to the wuint* functions. To do that | |
10984 | * we're going to do the following: | |
10985 | * | |
10986 | * - if the value is positive | |
10987 | * we can pass it directly off to the equivalent wuint | |
10988 | * - if the value is negative | |
10989 | * we do the following computation: | |
10990 | * mb + val + 1, where | |
10991 | * mb is the maximum unsigned value in that byte size | |
10992 | * val is the Javascript negative integer | |
10993 | * | |
10994 | * | |
10995 | * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If | |
10996 | * you do out the computations: | |
10997 | * | |
10998 | * 0xffff - 128 + 1 | |
10999 | * 0xffff - 127 | |
11000 | * 0xff80 | |
11001 | * | |
11002 | * You can then encode this value as the signed version. This is really rather | |
11003 | * hacky, but it should work and get the job done which is our goal here. | |
11004 | */ | |
11005 | ||
11006 | /* | |
11007 | * A series of checks to make sure we actually have a signed 32-bit number | |
11008 | */ | |
11009 | function verifsint(value, max, min) { | |
11010 | assert.ok(typeof (value) == 'number', | |
11011 | 'cannot write a non-number as a number'); | |
11012 | ||
11013 | assert.ok(value <= max, 'value larger than maximum allowed value'); | |
11014 | ||
11015 | assert.ok(value >= min, 'value smaller than minimum allowed value'); | |
11016 | ||
11017 | assert.ok(Math.floor(value) === value, 'value has a fractional component'); | |
11018 | } | |
11019 | ||
11020 | function verifIEEE754(value, max, min) { | |
11021 | assert.ok(typeof (value) == 'number', | |
11022 | 'cannot write a non-number as a number'); | |
11023 | ||
11024 | assert.ok(value <= max, 'value larger than maximum allowed value'); | |
11025 | ||
11026 | assert.ok(value >= min, 'value smaller than minimum allowed value'); | |
11027 | } | |
11028 | ||
11029 | Buffer.prototype.writeInt8 = function(value, offset, noAssert) { | |
11030 | var buffer = this; | |
11031 | ||
11032 | if (!noAssert) { | |
11033 | assert.ok(value !== undefined && value !== null, | |
11034 | 'missing value'); | |
11035 | ||
11036 | assert.ok(offset !== undefined && offset !== null, | |
11037 | 'missing offset'); | |
11038 | ||
11039 | assert.ok(offset < buffer.length, | |
11040 | 'Trying to write beyond buffer length'); | |
11041 | ||
11042 | verifsint(value, 0x7f, -0x80); | |
11043 | } | |
11044 | ||
11045 | if (value >= 0) { | |
11046 | buffer.writeUInt8(value, offset, noAssert); | |
11047 | } else { | |
11048 | buffer.writeUInt8(0xff + value + 1, offset, noAssert); | |
11049 | } | |
11050 | }; | |
11051 | ||
11052 | function writeInt16(buffer, value, offset, isBigEndian, noAssert) { | |
11053 | if (!noAssert) { | |
11054 | assert.ok(value !== undefined && value !== null, | |
11055 | 'missing value'); | |
11056 | ||
11057 | assert.ok(typeof (isBigEndian) === 'boolean', | |
11058 | 'missing or invalid endian'); | |
11059 | ||
11060 | assert.ok(offset !== undefined && offset !== null, | |
11061 | 'missing offset'); | |
11062 | ||
11063 | assert.ok(offset + 1 < buffer.length, | |
11064 | 'Trying to write beyond buffer length'); | |
11065 | ||
11066 | verifsint(value, 0x7fff, -0x8000); | |
11067 | } | |
11068 | ||
11069 | if (value >= 0) { | |
11070 | writeUInt16(buffer, value, offset, isBigEndian, noAssert); | |
11071 | } else { | |
11072 | writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert); | |
11073 | } | |
11074 | } | |
11075 | ||
11076 | Buffer.prototype.writeInt16LE = function(value, offset, noAssert) { | |
11077 | writeInt16(this, value, offset, false, noAssert); | |
11078 | }; | |
11079 | ||
11080 | Buffer.prototype.writeInt16BE = function(value, offset, noAssert) { | |
11081 | writeInt16(this, value, offset, true, noAssert); | |
11082 | }; | |
11083 | ||
11084 | function writeInt32(buffer, value, offset, isBigEndian, noAssert) { | |
11085 | if (!noAssert) { | |
11086 | assert.ok(value !== undefined && value !== null, | |
11087 | 'missing value'); | |
11088 | ||
11089 | assert.ok(typeof (isBigEndian) === 'boolean', | |
11090 | 'missing or invalid endian'); | |
11091 | ||
11092 | assert.ok(offset !== undefined && offset !== null, | |
11093 | 'missing offset'); | |
11094 | ||
11095 | assert.ok(offset + 3 < buffer.length, | |
11096 | 'Trying to write beyond buffer length'); | |
11097 | ||
11098 | verifsint(value, 0x7fffffff, -0x80000000); | |
11099 | } | |
11100 | ||
11101 | if (value >= 0) { | |
11102 | writeUInt32(buffer, value, offset, isBigEndian, noAssert); | |
11103 | } else { | |
11104 | writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert); | |
11105 | } | |
11106 | } | |
11107 | ||
11108 | Buffer.prototype.writeInt32LE = function(value, offset, noAssert) { | |
11109 | writeInt32(this, value, offset, false, noAssert); | |
11110 | }; | |
11111 | ||
11112 | Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { | |
11113 | writeInt32(this, value, offset, true, noAssert); | |
11114 | }; | |
11115 | ||
11116 | function writeFloat(buffer, value, offset, isBigEndian, noAssert) { | |
11117 | if (!noAssert) { | |
11118 | assert.ok(value !== undefined && value !== null, | |
11119 | 'missing value'); | |
11120 | ||
11121 | assert.ok(typeof (isBigEndian) === 'boolean', | |
11122 | 'missing or invalid endian'); | |
11123 | ||
11124 | assert.ok(offset !== undefined && offset !== null, | |
11125 | 'missing offset'); | |
11126 | ||
11127 | assert.ok(offset + 3 < buffer.length, | |
11128 | 'Trying to write beyond buffer length'); | |
11129 | ||
11130 | verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38); | |
11131 | } | |
11132 | ||
11133 | require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, | |
11134 | 23, 4); | |
11135 | } | |
11136 | ||
11137 | Buffer.prototype.writeFloatLE = function(value, offset, noAssert) { | |
11138 | writeFloat(this, value, offset, false, noAssert); | |
11139 | }; | |
11140 | ||
11141 | Buffer.prototype.writeFloatBE = function(value, offset, noAssert) { | |
11142 | writeFloat(this, value, offset, true, noAssert); | |
11143 | }; | |
11144 | ||
11145 | function writeDouble(buffer, value, offset, isBigEndian, noAssert) { | |
11146 | if (!noAssert) { | |
11147 | assert.ok(value !== undefined && value !== null, | |
11148 | 'missing value'); | |
11149 | ||
11150 | assert.ok(typeof (isBigEndian) === 'boolean', | |
11151 | 'missing or invalid endian'); | |
11152 | ||
11153 | assert.ok(offset !== undefined && offset !== null, | |
11154 | 'missing offset'); | |
11155 | ||
11156 | assert.ok(offset + 7 < buffer.length, | |
11157 | 'Trying to write beyond buffer length'); | |
11158 | ||
11159 | verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308); | |
11160 | } | |
11161 | ||
11162 | require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, | |
11163 | 52, 8); | |
11164 | } | |
11165 | ||
11166 | Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) { | |
11167 | writeDouble(this, value, offset, false, noAssert); | |
11168 | }; | |
11169 | ||
11170 | Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { | |
11171 | writeDouble(this, value, offset, true, noAssert); | |
11172 | }; | |
11173 | ||
11174 | SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8; | |
11175 | SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE; | |
11176 | SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE; | |
11177 | SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE; | |
11178 | SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE; | |
11179 | SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8; | |
11180 | SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE; | |
11181 | SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE; | |
11182 | SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE; | |
11183 | SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE; | |
11184 | SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE; | |
11185 | SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE; | |
11186 | SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE; | |
11187 | SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE; | |
11188 | SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8; | |
11189 | SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE; | |
11190 | SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE; | |
11191 | SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE; | |
11192 | SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE; | |
11193 | SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8; | |
11194 | SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE; | |
11195 | SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE; | |
11196 | SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE; | |
11197 | SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE; | |
11198 | SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE; | |
11199 | SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE; | |
11200 | SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE; | |
11201 | SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE; | |
11202 | ||
11203 | })() | |
11204 | },{"assert":12,"./buffer_ieee754":14,"base64-js":15}],15:[function(require,module,exports){ | |
11205 | (function (exports) { | |
11206 | 'use strict'; | |
11207 | ||
11208 | var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; | |
11209 | ||
11210 | function b64ToByteArray(b64) { | |
11211 | var i, j, l, tmp, placeHolders, arr; | |
11212 | ||
11213 | if (b64.length % 4 > 0) { | |
11214 | throw 'Invalid string. Length must be a multiple of 4'; | |
11215 | } | |
11216 | ||
11217 | // the number of equal signs (place holders) | |
11218 | // if there are two placeholders, than the two characters before it | |
11219 | // represent one byte | |
11220 | // if there is only one, then the three characters before it represent 2 bytes | |
11221 | // this is just a cheap hack to not do indexOf twice | |
11222 | placeHolders = b64.indexOf('='); | |
11223 | placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0; | |
11224 | ||
11225 | // base64 is 4/3 + up to two characters of the original data | |
11226 | arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders); | |
11227 | ||
11228 | // if there are placeholders, only get up to the last complete 4 chars | |
11229 | l = placeHolders > 0 ? b64.length - 4 : b64.length; | |
11230 | ||
11231 | for (i = 0, j = 0; i < l; i += 4, j += 3) { | |
11232 | tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]); | |
11233 | arr.push((tmp & 0xFF0000) >> 16); | |
11234 | arr.push((tmp & 0xFF00) >> 8); | |
11235 | arr.push(tmp & 0xFF); | |
11236 | } | |
11237 | ||
11238 | if (placeHolders === 2) { | |
11239 | tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4); | |
11240 | arr.push(tmp & 0xFF); | |
11241 | } else if (placeHolders === 1) { | |
11242 | tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2); | |
11243 | arr.push((tmp >> 8) & 0xFF); | |
11244 | arr.push(tmp & 0xFF); | |
11245 | } | |
11246 | ||
11247 | return arr; | |
11248 | } | |
11249 | ||
11250 | function uint8ToBase64(uint8) { | |
11251 | var i, | |
11252 | extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes | |
11253 | output = "", | |
11254 | temp, length; | |
11255 | ||
11256 | function tripletToBase64 (num) { | |
11257 | return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; | |
11258 | }; | |
11259 | ||
11260 | // go through the array every three bytes, we'll deal with trailing stuff later | |
11261 | for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { | |
11262 | temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); | |
11263 | output += tripletToBase64(temp); | |
11264 | } | |
11265 | ||
11266 | // pad the end with zeros, but make sure to not forget the extra bytes | |
11267 | switch (extraBytes) { | |
11268 | case 1: | |
11269 | temp = uint8[uint8.length - 1]; | |
11270 | output += lookup[temp >> 2]; | |
11271 | output += lookup[(temp << 4) & 0x3F]; | |
11272 | output += '=='; | |
11273 | break; | |
11274 | case 2: | |
11275 | temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]); | |
11276 | output += lookup[temp >> 10]; | |
11277 | output += lookup[(temp >> 4) & 0x3F]; | |
11278 | output += lookup[(temp << 2) & 0x3F]; | |
11279 | output += '='; | |
11280 | break; | |
11281 | } | |
11282 | ||
11283 | return output; | |
11284 | } | |
11285 | ||
11286 | module.exports.toByteArray = b64ToByteArray; | |
11287 | module.exports.fromByteArray = uint8ToBase64; | |
11288 | }()); | |
11289 | ||
11290 | },{}]},{},["E/GbHF"]) | |
11291 | ; | |
11292 | JSHINT = require('jshint').JSHINT; | |
f2a92ac6 | 11293 | }()); |