|
1 //2.1.3 |
|
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 DataView : false, |
|
307 DOMParser : false, |
|
308 defaultStatus : false, |
|
309 document : false, |
|
310 Element : false, |
|
311 ElementTimeControl : false, |
|
312 event : false, |
|
313 FileReader : false, |
|
314 Float32Array : false, |
|
315 Float64Array : false, |
|
316 FormData : false, |
|
317 focus : false, |
|
318 frames : false, |
|
319 getComputedStyle : false, |
|
320 HTMLElement : false, |
|
321 HTMLAnchorElement : false, |
|
322 HTMLBaseElement : false, |
|
323 HTMLBlockquoteElement: false, |
|
324 HTMLBodyElement : false, |
|
325 HTMLBRElement : false, |
|
326 HTMLButtonElement : false, |
|
327 HTMLCanvasElement : false, |
|
328 HTMLDirectoryElement : false, |
|
329 HTMLDivElement : false, |
|
330 HTMLDListElement : false, |
|
331 HTMLFieldSetElement : false, |
|
332 HTMLFontElement : false, |
|
333 HTMLFormElement : false, |
|
334 HTMLFrameElement : false, |
|
335 HTMLFrameSetElement : false, |
|
336 HTMLHeadElement : false, |
|
337 HTMLHeadingElement : false, |
|
338 HTMLHRElement : false, |
|
339 HTMLHtmlElement : false, |
|
340 HTMLIFrameElement : false, |
|
341 HTMLImageElement : false, |
|
342 HTMLInputElement : false, |
|
343 HTMLIsIndexElement : false, |
|
344 HTMLLabelElement : false, |
|
345 HTMLLayerElement : false, |
|
346 HTMLLegendElement : false, |
|
347 HTMLLIElement : false, |
|
348 HTMLLinkElement : false, |
|
349 HTMLMapElement : false, |
|
350 HTMLMenuElement : false, |
|
351 HTMLMetaElement : false, |
|
352 HTMLModElement : false, |
|
353 HTMLObjectElement : false, |
|
354 HTMLOListElement : false, |
|
355 HTMLOptGroupElement : false, |
|
356 HTMLOptionElement : false, |
|
357 HTMLParagraphElement : false, |
|
358 HTMLParamElement : false, |
|
359 HTMLPreElement : false, |
|
360 HTMLQuoteElement : false, |
|
361 HTMLScriptElement : false, |
|
362 HTMLSelectElement : false, |
|
363 HTMLStyleElement : false, |
|
364 HTMLTableCaptionElement: false, |
|
365 HTMLTableCellElement : false, |
|
366 HTMLTableColElement : false, |
|
367 HTMLTableElement : false, |
|
368 HTMLTableRowElement : false, |
|
369 HTMLTableSectionElement: false, |
|
370 HTMLTextAreaElement : false, |
|
371 HTMLTitleElement : false, |
|
372 HTMLUListElement : false, |
|
373 HTMLVideoElement : false, |
|
374 history : false, |
|
375 Int16Array : false, |
|
376 Int32Array : false, |
|
377 Int8Array : false, |
|
378 Image : false, |
|
379 length : false, |
|
380 localStorage : false, |
|
381 location : false, |
|
382 MessageChannel : false, |
|
383 MessageEvent : false, |
|
384 MessagePort : false, |
|
385 moveBy : false, |
|
386 moveTo : false, |
|
387 MutationObserver : false, |
|
388 name : false, |
|
389 Node : false, |
|
390 NodeFilter : false, |
|
391 navigator : false, |
|
392 onbeforeunload : true, |
|
393 onblur : true, |
|
394 onerror : true, |
|
395 onfocus : true, |
|
396 onload : true, |
|
397 onresize : true, |
|
398 onunload : true, |
|
399 open : false, |
|
400 openDatabase : false, |
|
401 opener : false, |
|
402 Option : false, |
|
403 parent : false, |
|
404 print : false, |
|
405 removeEventListener : false, |
|
406 resizeBy : false, |
|
407 resizeTo : false, |
|
408 screen : false, |
|
409 scroll : false, |
|
410 scrollBy : false, |
|
411 scrollTo : false, |
|
412 sessionStorage : false, |
|
413 setInterval : false, |
|
414 setTimeout : false, |
|
415 SharedWorker : false, |
|
416 status : false, |
|
417 SVGAElement : false, |
|
418 SVGAltGlyphDefElement: false, |
|
419 SVGAltGlyphElement : false, |
|
420 SVGAltGlyphItemElement: false, |
|
421 SVGAngle : false, |
|
422 SVGAnimateColorElement: false, |
|
423 SVGAnimateElement : false, |
|
424 SVGAnimateMotionElement: false, |
|
425 SVGAnimateTransformElement: false, |
|
426 SVGAnimatedAngle : false, |
|
427 SVGAnimatedBoolean : false, |
|
428 SVGAnimatedEnumeration: false, |
|
429 SVGAnimatedInteger : false, |
|
430 SVGAnimatedLength : false, |
|
431 SVGAnimatedLengthList: false, |
|
432 SVGAnimatedNumber : false, |
|
433 SVGAnimatedNumberList: false, |
|
434 SVGAnimatedPathData : false, |
|
435 SVGAnimatedPoints : false, |
|
436 SVGAnimatedPreserveAspectRatio: false, |
|
437 SVGAnimatedRect : false, |
|
438 SVGAnimatedString : false, |
|
439 SVGAnimatedTransformList: false, |
|
440 SVGAnimationElement : false, |
|
441 SVGCSSRule : false, |
|
442 SVGCircleElement : false, |
|
443 SVGClipPathElement : false, |
|
444 SVGColor : false, |
|
445 SVGColorProfileElement: false, |
|
446 SVGColorProfileRule : false, |
|
447 SVGComponentTransferFunctionElement: false, |
|
448 SVGCursorElement : false, |
|
449 SVGDefsElement : false, |
|
450 SVGDescElement : false, |
|
451 SVGDocument : false, |
|
452 SVGElement : false, |
|
453 SVGElementInstance : false, |
|
454 SVGElementInstanceList: false, |
|
455 SVGEllipseElement : false, |
|
456 SVGExternalResourcesRequired: false, |
|
457 SVGFEBlendElement : false, |
|
458 SVGFEColorMatrixElement: false, |
|
459 SVGFEComponentTransferElement: false, |
|
460 SVGFECompositeElement: false, |
|
461 SVGFEConvolveMatrixElement: false, |
|
462 SVGFEDiffuseLightingElement: false, |
|
463 SVGFEDisplacementMapElement: false, |
|
464 SVGFEDistantLightElement: false, |
|
465 SVGFEDropShadowElement: false, |
|
466 SVGFEFloodElement : false, |
|
467 SVGFEFuncAElement : false, |
|
468 SVGFEFuncBElement : false, |
|
469 SVGFEFuncGElement : false, |
|
470 SVGFEFuncRElement : false, |
|
471 SVGFEGaussianBlurElement: false, |
|
472 SVGFEImageElement : false, |
|
473 SVGFEMergeElement : false, |
|
474 SVGFEMergeNodeElement: false, |
|
475 SVGFEMorphologyElement: false, |
|
476 SVGFEOffsetElement : false, |
|
477 SVGFEPointLightElement: false, |
|
478 SVGFESpecularLightingElement: false, |
|
479 SVGFESpotLightElement: false, |
|
480 SVGFETileElement : false, |
|
481 SVGFETurbulenceElement: false, |
|
482 SVGFilterElement : false, |
|
483 SVGFilterPrimitiveStandardAttributes: false, |
|
484 SVGFitToViewBox : false, |
|
485 SVGFontElement : false, |
|
486 SVGFontFaceElement : false, |
|
487 SVGFontFaceFormatElement: false, |
|
488 SVGFontFaceNameElement: false, |
|
489 SVGFontFaceSrcElement: false, |
|
490 SVGFontFaceUriElement: false, |
|
491 SVGForeignObjectElement: false, |
|
492 SVGGElement : false, |
|
493 SVGGlyphElement : false, |
|
494 SVGGlyphRefElement : false, |
|
495 SVGGradientElement : false, |
|
496 SVGHKernElement : false, |
|
497 SVGICCColor : false, |
|
498 SVGImageElement : false, |
|
499 SVGLangSpace : false, |
|
500 SVGLength : false, |
|
501 SVGLengthList : false, |
|
502 SVGLineElement : false, |
|
503 SVGLinearGradientElement: false, |
|
504 SVGLocatable : false, |
|
505 SVGMPathElement : false, |
|
506 SVGMarkerElement : false, |
|
507 SVGMaskElement : false, |
|
508 SVGMatrix : false, |
|
509 SVGMetadataElement : false, |
|
510 SVGMissingGlyphElement: false, |
|
511 SVGNumber : false, |
|
512 SVGNumberList : false, |
|
513 SVGPaint : false, |
|
514 SVGPathElement : false, |
|
515 SVGPathSeg : false, |
|
516 SVGPathSegArcAbs : false, |
|
517 SVGPathSegArcRel : false, |
|
518 SVGPathSegClosePath : false, |
|
519 SVGPathSegCurvetoCubicAbs: false, |
|
520 SVGPathSegCurvetoCubicRel: false, |
|
521 SVGPathSegCurvetoCubicSmoothAbs: false, |
|
522 SVGPathSegCurvetoCubicSmoothRel: false, |
|
523 SVGPathSegCurvetoQuadraticAbs: false, |
|
524 SVGPathSegCurvetoQuadraticRel: false, |
|
525 SVGPathSegCurvetoQuadraticSmoothAbs: false, |
|
526 SVGPathSegCurvetoQuadraticSmoothRel: false, |
|
527 SVGPathSegLinetoAbs : false, |
|
528 SVGPathSegLinetoHorizontalAbs: false, |
|
529 SVGPathSegLinetoHorizontalRel: false, |
|
530 SVGPathSegLinetoRel : false, |
|
531 SVGPathSegLinetoVerticalAbs: false, |
|
532 SVGPathSegLinetoVerticalRel: false, |
|
533 SVGPathSegList : false, |
|
534 SVGPathSegMovetoAbs : false, |
|
535 SVGPathSegMovetoRel : false, |
|
536 SVGPatternElement : false, |
|
537 SVGPoint : false, |
|
538 SVGPointList : false, |
|
539 SVGPolygonElement : false, |
|
540 SVGPolylineElement : false, |
|
541 SVGPreserveAspectRatio: false, |
|
542 SVGRadialGradientElement: false, |
|
543 SVGRect : false, |
|
544 SVGRectElement : false, |
|
545 SVGRenderingIntent : false, |
|
546 SVGSVGElement : false, |
|
547 SVGScriptElement : false, |
|
548 SVGSetElement : false, |
|
549 SVGStopElement : false, |
|
550 SVGStringList : false, |
|
551 SVGStylable : false, |
|
552 SVGStyleElement : false, |
|
553 SVGSwitchElement : false, |
|
554 SVGSymbolElement : false, |
|
555 SVGTRefElement : false, |
|
556 SVGTSpanElement : false, |
|
557 SVGTests : false, |
|
558 SVGTextContentElement: false, |
|
559 SVGTextElement : false, |
|
560 SVGTextPathElement : false, |
|
561 SVGTextPositioningElement: false, |
|
562 SVGTitleElement : false, |
|
563 SVGTransform : false, |
|
564 SVGTransformList : false, |
|
565 SVGTransformable : false, |
|
566 SVGURIReference : false, |
|
567 SVGUnitTypes : false, |
|
568 SVGUseElement : false, |
|
569 SVGVKernElement : false, |
|
570 SVGViewElement : false, |
|
571 SVGViewSpec : false, |
|
572 SVGZoomAndPan : false, |
|
573 TimeEvent : false, |
|
574 top : false, |
|
575 Uint16Array : false, |
|
576 Uint32Array : false, |
|
577 Uint8Array : false, |
|
578 Uint8ClampedArray : false, |
|
579 WebSocket : false, |
|
580 window : false, |
|
581 Worker : false, |
|
582 XMLHttpRequest : false, |
|
583 XMLSerializer : false, |
|
584 XPathEvaluator : false, |
|
585 XPathException : false, |
|
586 XPathExpression : false, |
|
587 XPathNSResolver : false, |
|
588 XPathResult : false |
|
589 }; |
|
590 |
|
591 exports.devel = { |
|
592 alert : false, |
|
593 confirm: false, |
|
594 console: false, |
|
595 Debug : false, |
|
596 opera : false, |
|
597 prompt : false |
|
598 }; |
|
599 |
|
600 exports.worker = { |
|
601 importScripts: true, |
|
602 postMessage : true, |
|
603 self : true |
|
604 }; |
|
605 |
|
606 // Widely adopted global names that are not part of ECMAScript standard |
|
607 exports.nonstandard = { |
|
608 escape : false, |
|
609 unescape: false |
|
610 }; |
|
611 |
|
612 // Globals provided by popular JavaScript environments. |
|
613 |
|
614 exports.couch = { |
|
615 "require" : false, |
|
616 respond : false, |
|
617 getRow : false, |
|
618 emit : false, |
|
619 send : false, |
|
620 start : false, |
|
621 sum : false, |
|
622 log : false, |
|
623 exports : false, |
|
624 module : false, |
|
625 provides : false |
|
626 }; |
|
627 |
|
628 exports.node = { |
|
629 __filename : false, |
|
630 __dirname : false, |
|
631 Buffer : false, |
|
632 DataView : false, |
|
633 console : false, |
|
634 exports : true, // In Node it is ok to exports = module.exports = foo(); |
|
635 GLOBAL : false, |
|
636 global : false, |
|
637 module : false, |
|
638 process : false, |
|
639 require : false, |
|
640 setTimeout : false, |
|
641 clearTimeout : false, |
|
642 setInterval : false, |
|
643 clearInterval : false, |
|
644 setImmediate : false, // v0.9.1+ |
|
645 clearImmediate: false // v0.9.1+ |
|
646 }; |
|
647 |
|
648 exports.phantom = { |
|
649 phantom : true, |
|
650 require : true, |
|
651 WebPage : true |
|
652 }; |
|
653 |
|
654 exports.rhino = { |
|
655 defineClass : false, |
|
656 deserialize : false, |
|
657 gc : false, |
|
658 help : false, |
|
659 importPackage: false, |
|
660 "java" : false, |
|
661 load : false, |
|
662 loadClass : false, |
|
663 print : false, |
|
664 quit : false, |
|
665 readFile : false, |
|
666 readUrl : false, |
|
667 runCommand : false, |
|
668 seal : false, |
|
669 serialize : false, |
|
670 spawn : false, |
|
671 sync : false, |
|
672 toint32 : false, |
|
673 version : false |
|
674 }; |
|
675 |
|
676 exports.wsh = { |
|
677 ActiveXObject : true, |
|
678 Enumerator : true, |
|
679 GetObject : true, |
|
680 ScriptEngine : true, |
|
681 ScriptEngineBuildVersion : true, |
|
682 ScriptEngineMajorVersion : true, |
|
683 ScriptEngineMinorVersion : true, |
|
684 VBArray : true, |
|
685 WSH : true, |
|
686 WScript : true, |
|
687 XDomainRequest : true |
|
688 }; |
|
689 |
|
690 // Globals provided by popular JavaScript libraries. |
|
691 |
|
692 exports.dojo = { |
|
693 dojo : false, |
|
694 dijit : false, |
|
695 dojox : false, |
|
696 define : false, |
|
697 "require": false |
|
698 }; |
|
699 |
|
700 exports.jquery = { |
|
701 "$" : false, |
|
702 jQuery : false |
|
703 }; |
|
704 |
|
705 exports.mootools = { |
|
706 "$" : false, |
|
707 "$$" : false, |
|
708 Asset : false, |
|
709 Browser : false, |
|
710 Chain : false, |
|
711 Class : false, |
|
712 Color : false, |
|
713 Cookie : false, |
|
714 Core : false, |
|
715 Document : false, |
|
716 DomReady : false, |
|
717 DOMEvent : false, |
|
718 DOMReady : false, |
|
719 Drag : false, |
|
720 Element : false, |
|
721 Elements : false, |
|
722 Event : false, |
|
723 Events : false, |
|
724 Fx : false, |
|
725 Group : false, |
|
726 Hash : false, |
|
727 HtmlTable : false, |
|
728 Iframe : false, |
|
729 IframeShim : false, |
|
730 InputValidator: false, |
|
731 instanceOf : false, |
|
732 Keyboard : false, |
|
733 Locale : false, |
|
734 Mask : false, |
|
735 MooTools : false, |
|
736 Native : false, |
|
737 Options : false, |
|
738 OverText : false, |
|
739 Request : false, |
|
740 Scroller : false, |
|
741 Slick : false, |
|
742 Slider : false, |
|
743 Sortables : false, |
|
744 Spinner : false, |
|
745 Swiff : false, |
|
746 Tips : false, |
|
747 Type : false, |
|
748 typeOf : false, |
|
749 URI : false, |
|
750 Window : false |
|
751 }; |
|
752 |
|
753 exports.prototypejs = { |
|
754 "$" : false, |
|
755 "$$" : false, |
|
756 "$A" : false, |
|
757 "$F" : false, |
|
758 "$H" : false, |
|
759 "$R" : false, |
|
760 "$break" : false, |
|
761 "$continue" : false, |
|
762 "$w" : false, |
|
763 Abstract : false, |
|
764 Ajax : false, |
|
765 Class : false, |
|
766 Enumerable : false, |
|
767 Element : false, |
|
768 Event : false, |
|
769 Field : false, |
|
770 Form : false, |
|
771 Hash : false, |
|
772 Insertion : false, |
|
773 ObjectRange : false, |
|
774 PeriodicalExecuter: false, |
|
775 Position : false, |
|
776 Prototype : false, |
|
777 Selector : false, |
|
778 Template : false, |
|
779 Toggle : false, |
|
780 Try : false, |
|
781 Autocompleter : false, |
|
782 Builder : false, |
|
783 Control : false, |
|
784 Draggable : false, |
|
785 Draggables : false, |
|
786 Droppables : false, |
|
787 Effect : false, |
|
788 Sortable : false, |
|
789 SortableObserver : false, |
|
790 Sound : false, |
|
791 Scriptaculous : false |
|
792 }; |
|
793 |
|
794 exports.yui = { |
|
795 YUI : false, |
|
796 Y : false, |
|
797 YUI_config: false |
|
798 }; |
|
799 |
|
800 |
|
801 })() |
|
802 },{}],4:[function(require,module,exports){ |
|
803 "use strict"; |
|
804 |
|
805 var state = { |
|
806 syntax: {}, |
|
807 |
|
808 reset: function () { |
|
809 this.tokens = { |
|
810 prev: null, |
|
811 next: null, |
|
812 curr: null |
|
813 }; |
|
814 |
|
815 this.option = {}; |
|
816 this.ignored = {}; |
|
817 this.directive = {}; |
|
818 this.jsonMode = false; |
|
819 this.jsonWarnings = []; |
|
820 this.lines = []; |
|
821 this.tab = ""; |
|
822 this.cache = {}; // Node.JS doesn't have Map. Sniff. |
|
823 } |
|
824 }; |
|
825 |
|
826 exports.state = state; |
|
827 |
|
828 },{}],5:[function(require,module,exports){ |
|
829 (function(){"use strict"; |
|
830 |
|
831 exports.register = function (linter) { |
|
832 // Check for properties named __proto__. This special property was |
|
833 // deprecated and then re-introduced for ES6. |
|
834 |
|
835 linter.on("Identifier", function style_scanProto(data) { |
|
836 if (linter.getOption("proto")) { |
|
837 return; |
|
838 } |
|
839 |
|
840 if (data.name === "__proto__") { |
|
841 linter.warn("W103", { |
|
842 line: data.line, |
|
843 char: data.char, |
|
844 data: [ data.name ] |
|
845 }); |
|
846 } |
|
847 }); |
|
848 |
|
849 // Check for properties named __iterator__. This is a special property |
|
850 // available only in browsers with JavaScript 1.7 implementation. |
|
851 |
|
852 linter.on("Identifier", function style_scanIterator(data) { |
|
853 if (linter.getOption("iterator")) { |
|
854 return; |
|
855 } |
|
856 |
|
857 if (data.name === "__iterator__") { |
|
858 linter.warn("W104", { |
|
859 line: data.line, |
|
860 char: data.char, |
|
861 data: [ data.name ] |
|
862 }); |
|
863 } |
|
864 }); |
|
865 |
|
866 // Check for dangling underscores. |
|
867 |
|
868 linter.on("Identifier", function style_scanDangling(data) { |
|
869 if (!linter.getOption("nomen")) { |
|
870 return; |
|
871 } |
|
872 |
|
873 // Underscore.js |
|
874 if (data.name === "_") { |
|
875 return; |
|
876 } |
|
877 |
|
878 // In Node, __dirname and __filename should be ignored. |
|
879 if (linter.getOption("node")) { |
|
880 if (/^(__dirname|__filename)$/.test(data.name) && !data.isProperty) { |
|
881 return; |
|
882 } |
|
883 } |
|
884 |
|
885 if (/^(_+.*|.*_+)$/.test(data.name)) { |
|
886 linter.warn("W105", { |
|
887 line: data.line, |
|
888 char: data.from, |
|
889 data: [ "dangling '_'", data.name ] |
|
890 }); |
|
891 } |
|
892 }); |
|
893 |
|
894 // Check that all identifiers are using camelCase notation. |
|
895 // Exceptions: names like MY_VAR and _myVar. |
|
896 |
|
897 linter.on("Identifier", function style_scanCamelCase(data) { |
|
898 if (!linter.getOption("camelcase")) { |
|
899 return; |
|
900 } |
|
901 |
|
902 if (data.name.replace(/^_+/, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { |
|
903 linter.warn("W106", { |
|
904 line: data.line, |
|
905 char: data.from, |
|
906 data: [ data.name ] |
|
907 }); |
|
908 } |
|
909 }); |
|
910 |
|
911 // Enforce consistency in style of quoting. |
|
912 |
|
913 linter.on("String", function style_scanQuotes(data) { |
|
914 var quotmark = linter.getOption("quotmark"); |
|
915 var code; |
|
916 |
|
917 if (!quotmark) { |
|
918 return; |
|
919 } |
|
920 |
|
921 // If quotmark is set to 'single' warn about all double-quotes. |
|
922 |
|
923 if (quotmark === "single" && data.quote !== "'") { |
|
924 code = "W109"; |
|
925 } |
|
926 |
|
927 // If quotmark is set to 'double' warn about all single-quotes. |
|
928 |
|
929 if (quotmark === "double" && data.quote !== "\"") { |
|
930 code = "W108"; |
|
931 } |
|
932 |
|
933 // If quotmark is set to true, remember the first quotation style |
|
934 // and then warn about all others. |
|
935 |
|
936 if (quotmark === true) { |
|
937 if (!linter.getCache("quotmark")) { |
|
938 linter.setCache("quotmark", data.quote); |
|
939 } |
|
940 |
|
941 if (linter.getCache("quotmark") !== data.quote) { |
|
942 code = "W110"; |
|
943 } |
|
944 } |
|
945 |
|
946 if (code) { |
|
947 linter.warn(code, { |
|
948 line: data.line, |
|
949 char: data.char, |
|
950 }); |
|
951 } |
|
952 }); |
|
953 |
|
954 linter.on("Number", function style_scanNumbers(data) { |
|
955 if (data.value.charAt(0) === ".") { |
|
956 // Warn about a leading decimal point. |
|
957 linter.warn("W008", { |
|
958 line: data.line, |
|
959 char: data.char, |
|
960 data: [ data.value ] |
|
961 }); |
|
962 } |
|
963 |
|
964 if (data.value.substr(data.value.length - 1) === ".") { |
|
965 // Warn about a trailing decimal point. |
|
966 linter.warn("W047", { |
|
967 line: data.line, |
|
968 char: data.char, |
|
969 data: [ data.value ] |
|
970 }); |
|
971 } |
|
972 |
|
973 if (/^00+/.test(data.value)) { |
|
974 // Multiple leading zeroes. |
|
975 linter.warn("W046", { |
|
976 line: data.line, |
|
977 char: data.char, |
|
978 data: [ data.value ] |
|
979 }); |
|
980 } |
|
981 }); |
|
982 |
|
983 // Warn about script URLs. |
|
984 |
|
985 linter.on("String", function style_scanJavaScriptURLs(data) { |
|
986 var re = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; |
|
987 |
|
988 if (linter.getOption("scripturl")) { |
|
989 return; |
|
990 } |
|
991 |
|
992 if (re.test(data.value)) { |
|
993 linter.warn("W107", { |
|
994 line: data.line, |
|
995 char: data.char |
|
996 }); |
|
997 } |
|
998 }); |
|
999 }; |
|
1000 })() |
|
1001 },{}],6:[function(require,module,exports){ |
|
1002 /* |
|
1003 * Regular expressions. Some of these are stupidly long. |
|
1004 */ |
|
1005 |
|
1006 /*jshint maxlen:1000 */ |
|
1007 |
|
1008 "use string"; |
|
1009 |
|
1010 // Unsafe comment or string (ax) |
|
1011 exports.unsafeString = |
|
1012 /@cc|<\/?|script|\]\s*\]|<\s*!|</i; |
|
1013 |
|
1014 // Unsafe characters that are silently deleted by one or more browsers (cx) |
|
1015 exports.unsafeChars = |
|
1016 /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; |
|
1017 |
|
1018 // Characters in strings that need escaping (nx and nxg) |
|
1019 exports.needEsc = |
|
1020 /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; |
|
1021 |
|
1022 exports.needEscGlobal = |
|
1023 /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; |
|
1024 |
|
1025 // Star slash (lx) |
|
1026 exports.starSlash = /\*\//; |
|
1027 |
|
1028 // Identifier (ix) |
|
1029 exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; |
|
1030 |
|
1031 // JavaScript URL (jx) |
|
1032 exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; |
|
1033 |
|
1034 // Catches /* falls through */ comments (ft) |
|
1035 //exports.fallsThrough = /^\s*\/\*\s*falls?\sthrough\s*\*\/\s*$/; |
|
1036 exports.fallsThrough = /^\s*\/\/\s*Falls?\sthrough.*\s*$/; |
|
1037 |
|
1038 },{}],7:[function(require,module,exports){ |
|
1039 (function(global){/*global window, global*/ |
|
1040 var util = require("util") |
|
1041 var assert = require("assert") |
|
1042 |
|
1043 var slice = Array.prototype.slice |
|
1044 var console |
|
1045 var times = {} |
|
1046 |
|
1047 if (typeof global !== "undefined" && global.console) { |
|
1048 console = global.console |
|
1049 } else if (typeof window !== "undefined" && window.console) { |
|
1050 console = window.console |
|
1051 } else { |
|
1052 console = window.console = {} |
|
1053 } |
|
1054 |
|
1055 var functions = [ |
|
1056 [log, "log"] |
|
1057 , [info, "info"] |
|
1058 , [warn, "warn"] |
|
1059 , [error, "error"] |
|
1060 , [time, "time"] |
|
1061 , [timeEnd, "timeEnd"] |
|
1062 , [trace, "trace"] |
|
1063 , [dir, "dir"] |
|
1064 , [assert, "assert"] |
|
1065 ] |
|
1066 |
|
1067 for (var i = 0; i < functions.length; i++) { |
|
1068 var tuple = functions[i] |
|
1069 var f = tuple[0] |
|
1070 var name = tuple[1] |
|
1071 |
|
1072 if (!console[name]) { |
|
1073 console[name] = f |
|
1074 } |
|
1075 } |
|
1076 |
|
1077 module.exports = console |
|
1078 |
|
1079 function log() {} |
|
1080 |
|
1081 function info() { |
|
1082 console.log.apply(console, arguments) |
|
1083 } |
|
1084 |
|
1085 function warn() { |
|
1086 console.log.apply(console, arguments) |
|
1087 } |
|
1088 |
|
1089 function error() { |
|
1090 console.warn.apply(console, arguments) |
|
1091 } |
|
1092 |
|
1093 function time(label) { |
|
1094 times[label] = Date.now() |
|
1095 } |
|
1096 |
|
1097 function timeEnd(label) { |
|
1098 var time = times[label] |
|
1099 if (!time) { |
|
1100 throw new Error("No such label: " + label) |
|
1101 } |
|
1102 |
|
1103 var duration = Date.now() - time |
|
1104 console.log(label + ": " + duration + "ms") |
|
1105 } |
|
1106 |
|
1107 function trace() { |
|
1108 var err = new Error() |
|
1109 err.name = "Trace" |
|
1110 err.message = util.format.apply(null, arguments) |
|
1111 console.error(err.stack) |
|
1112 } |
|
1113 |
|
1114 function dir(object) { |
|
1115 console.log(util.inspect(object) + "\n") |
|
1116 } |
|
1117 |
|
1118 function assert(expression) { |
|
1119 if (!expression) { |
|
1120 var arr = slice.call(arguments, 1) |
|
1121 assert.ok(false, util.format.apply(null, arr)) |
|
1122 } |
|
1123 } |
|
1124 |
|
1125 })(window) |
|
1126 },{"util":8,"assert":9}],10:[function(require,module,exports){ |
|
1127 (function(){/* |
|
1128 * Lexical analysis and token construction. |
|
1129 */ |
|
1130 |
|
1131 "use strict"; |
|
1132 |
|
1133 var _ = require("underscore"); |
|
1134 var events = require("events"); |
|
1135 var reg = require("./reg.js"); |
|
1136 var state = require("./state.js").state; |
|
1137 |
|
1138 // Some of these token types are from JavaScript Parser API |
|
1139 // while others are specific to JSHint parser. |
|
1140 // JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API |
|
1141 |
|
1142 var Token = { |
|
1143 Identifier: 1, |
|
1144 Punctuator: 2, |
|
1145 NumericLiteral: 3, |
|
1146 StringLiteral: 4, |
|
1147 Comment: 5, |
|
1148 Keyword: 6, |
|
1149 NullLiteral: 7, |
|
1150 BooleanLiteral: 8, |
|
1151 RegExp: 9 |
|
1152 }; |
|
1153 |
|
1154 // This is auto generated from the unicode tables. |
|
1155 // The tables are at: |
|
1156 // http://www.fileformat.info/info/unicode/category/Lu/list.htm |
|
1157 // http://www.fileformat.info/info/unicode/category/Ll/list.htm |
|
1158 // http://www.fileformat.info/info/unicode/category/Lt/list.htm |
|
1159 // http://www.fileformat.info/info/unicode/category/Lm/list.htm |
|
1160 // http://www.fileformat.info/info/unicode/category/Lo/list.htm |
|
1161 // http://www.fileformat.info/info/unicode/category/Nl/list.htm |
|
1162 |
|
1163 var unicodeLetterTable = [ |
|
1164 170, 170, 181, 181, 186, 186, 192, 214, |
|
1165 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, |
|
1166 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, |
|
1167 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, |
|
1168 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, |
|
1169 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, |
|
1170 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, |
|
1171 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, |
|
1172 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2308, 2361, |
|
1173 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, |
|
1174 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, |
|
1175 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, |
|
1176 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, |
|
1177 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, |
|
1178 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, |
|
1179 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, |
|
1180 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, |
|
1181 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, |
|
1182 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, |
|
1183 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, |
|
1184 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, |
|
1185 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, |
|
1186 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, |
|
1187 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, |
|
1188 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, |
|
1189 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, |
|
1190 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, |
|
1191 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, |
|
1192 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, |
|
1193 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, |
|
1194 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, |
|
1195 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, |
|
1196 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4304, 4346, |
|
1197 4348, 4348, 4352, 4680, 4682, 4685, 4688, 4694, 4696, 4696, |
|
1198 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, |
|
1199 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, |
|
1200 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, |
|
1201 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, |
|
1202 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, |
|
1203 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, |
|
1204 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, |
|
1205 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, |
|
1206 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7104, 7141, |
|
1207 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, |
|
1208 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, |
|
1209 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, |
|
1210 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, |
|
1211 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, |
|
1212 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, |
|
1213 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, |
|
1214 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, |
|
1215 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, |
|
1216 11360, 11492, 11499, 11502, 11520, 11557, 11568, 11621, |
|
1217 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, |
|
1218 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, |
|
1219 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, |
|
1220 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, |
|
1221 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, |
|
1222 12593, 12686, 12704, 12730, 12784, 12799, 13312, 13312, |
|
1223 19893, 19893, 19968, 19968, 40907, 40907, 40960, 42124, |
|
1224 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, |
|
1225 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, |
|
1226 42786, 42888, 42891, 42894, 42896, 42897, 42912, 42921, |
|
1227 43002, 43009, 43011, 43013, 43015, 43018, 43020, 43042, |
|
1228 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, |
|
1229 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, |
|
1230 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, |
|
1231 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, |
|
1232 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, |
|
1233 43739, 43741, 43777, 43782, 43785, 43790, 43793, 43798, |
|
1234 43808, 43814, 43816, 43822, 43968, 44002, 44032, 44032, |
|
1235 55203, 55203, 55216, 55238, 55243, 55291, 63744, 64045, |
|
1236 64048, 64109, 64112, 64217, 64256, 64262, 64275, 64279, |
|
1237 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, |
|
1238 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, |
|
1239 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, |
|
1240 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, |
|
1241 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, |
|
1242 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, |
|
1243 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, |
|
1244 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66334, |
|
1245 66352, 66378, 66432, 66461, 66464, 66499, 66504, 66511, |
|
1246 66513, 66517, 66560, 66717, 67584, 67589, 67592, 67592, |
|
1247 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, |
|
1248 67840, 67861, 67872, 67897, 68096, 68096, 68112, 68115, |
|
1249 68117, 68119, 68121, 68147, 68192, 68220, 68352, 68405, |
|
1250 68416, 68437, 68448, 68466, 68608, 68680, 69635, 69687, |
|
1251 69763, 69807, 73728, 74606, 74752, 74850, 77824, 78894, |
|
1252 92160, 92728, 110592, 110593, 119808, 119892, 119894, 119964, |
|
1253 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, |
|
1254 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, |
|
1255 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, |
|
1256 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, |
|
1257 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, |
|
1258 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, |
|
1259 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, |
|
1260 131072, 131072, 173782, 173782, 173824, 173824, 177972, 177972, |
|
1261 177984, 177984, 178205, 178205, 194560, 195101 |
|
1262 ]; |
|
1263 |
|
1264 var identifierStartTable = []; |
|
1265 |
|
1266 for (var i = 0; i < 128; i++) { |
|
1267 identifierStartTable[i] = |
|
1268 i === 36 || // $ |
|
1269 i >= 65 && i <= 90 || // A-Z |
|
1270 i === 95 || // _ |
|
1271 i >= 97 && i <= 122; // a-z |
|
1272 } |
|
1273 |
|
1274 var identifierPartTable = []; |
|
1275 |
|
1276 for (var i = 0; i < 128; i++) { |
|
1277 identifierPartTable[i] = |
|
1278 identifierStartTable[i] || // $, _, A-Z, a-z |
|
1279 i >= 48 && i <= 57; // 0-9 |
|
1280 } |
|
1281 |
|
1282 // Object that handles postponed lexing verifications that checks the parsed |
|
1283 // environment state. |
|
1284 |
|
1285 function asyncTrigger() { |
|
1286 var _checks = []; |
|
1287 |
|
1288 return { |
|
1289 push: function (fn) { |
|
1290 _checks.push(fn); |
|
1291 }, |
|
1292 |
|
1293 check: function () { |
|
1294 for (var check in _checks) { |
|
1295 _checks[check](); |
|
1296 } |
|
1297 |
|
1298 _checks.splice(0, _checks.length); |
|
1299 } |
|
1300 }; |
|
1301 } |
|
1302 |
|
1303 /* |
|
1304 * Lexer for JSHint. |
|
1305 * |
|
1306 * This object does a char-by-char scan of the provided source code |
|
1307 * and produces a sequence of tokens. |
|
1308 * |
|
1309 * var lex = new Lexer("var i = 0;"); |
|
1310 * lex.start(); |
|
1311 * lex.token(); // returns the next token |
|
1312 * |
|
1313 * You have to use the token() method to move the lexer forward |
|
1314 * but you don't have to use its return value to get tokens. In addition |
|
1315 * to token() method returning the next token, the Lexer object also |
|
1316 * emits events. |
|
1317 * |
|
1318 * lex.on("Identifier", function (data) { |
|
1319 * if (data.name.indexOf("_") >= 0) { |
|
1320 * // Produce a warning. |
|
1321 * } |
|
1322 * }); |
|
1323 * |
|
1324 * Note that the token() method returns tokens in a JSLint-compatible |
|
1325 * format while the event emitter uses a slightly modified version of |
|
1326 * Mozilla's JavaScript Parser API. Eventually, we will move away from |
|
1327 * JSLint format. |
|
1328 */ |
|
1329 function Lexer(source) { |
|
1330 var lines = source; |
|
1331 |
|
1332 if (typeof lines === "string") { |
|
1333 lines = lines |
|
1334 .replace(/\r\n/g, "\n") |
|
1335 .replace(/\r/g, "\n") |
|
1336 .split("\n"); |
|
1337 } |
|
1338 |
|
1339 // If the first line is a shebang (#!), make it a blank and move on. |
|
1340 // Shebangs are used by Node scripts. |
|
1341 |
|
1342 if (lines[0] && lines[0].substr(0, 2) === "#!") { |
|
1343 lines[0] = ""; |
|
1344 } |
|
1345 |
|
1346 this.emitter = new events.EventEmitter(); |
|
1347 this.source = source; |
|
1348 this.lines = lines; |
|
1349 this.prereg = true; |
|
1350 |
|
1351 this.line = 0; |
|
1352 this.char = 1; |
|
1353 this.from = 1; |
|
1354 this.input = ""; |
|
1355 |
|
1356 for (var i = 0; i < state.option.indent; i += 1) { |
|
1357 state.tab += " "; |
|
1358 } |
|
1359 } |
|
1360 |
|
1361 Lexer.prototype = { |
|
1362 _lines: [], |
|
1363 |
|
1364 get lines() { |
|
1365 this._lines = state.lines; |
|
1366 return this._lines; |
|
1367 }, |
|
1368 |
|
1369 set lines(val) { |
|
1370 this._lines = val; |
|
1371 state.lines = this._lines; |
|
1372 }, |
|
1373 |
|
1374 /* |
|
1375 * Return the next i character without actually moving the |
|
1376 * char pointer. |
|
1377 */ |
|
1378 peek: function (i) { |
|
1379 return this.input.charAt(i || 0); |
|
1380 }, |
|
1381 |
|
1382 /* |
|
1383 * Move the char pointer forward i times. |
|
1384 */ |
|
1385 skip: function (i) { |
|
1386 i = i || 1; |
|
1387 this.char += i; |
|
1388 this.input = this.input.slice(i); |
|
1389 }, |
|
1390 |
|
1391 /* |
|
1392 * Subscribe to a token event. The API for this method is similar |
|
1393 * Underscore.js i.e. you can subscribe to multiple events with |
|
1394 * one call: |
|
1395 * |
|
1396 * lex.on("Identifier Number", function (data) { |
|
1397 * // ... |
|
1398 * }); |
|
1399 */ |
|
1400 on: function (names, listener) { |
|
1401 names.split(" ").forEach(function (name) { |
|
1402 this.emitter.on(name, listener); |
|
1403 }.bind(this)); |
|
1404 }, |
|
1405 |
|
1406 /* |
|
1407 * Trigger a token event. All arguments will be passed to each |
|
1408 * listener. |
|
1409 */ |
|
1410 trigger: function () { |
|
1411 this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); |
|
1412 }, |
|
1413 |
|
1414 /* |
|
1415 * Postpone a token event. the checking condition is set as |
|
1416 * last parameter, and the trigger function is called in a |
|
1417 * stored callback. To be later called using the check() function |
|
1418 * by the parser. This avoids parser's peek() to give the lexer |
|
1419 * a false context. |
|
1420 */ |
|
1421 triggerAsync: function (type, args, checks, fn) { |
|
1422 checks.push(function () { |
|
1423 if (fn()) { |
|
1424 this.trigger(type, args); |
|
1425 } |
|
1426 }.bind(this)); |
|
1427 }, |
|
1428 |
|
1429 /* |
|
1430 * Extract a punctuator out of the next sequence of characters |
|
1431 * or return 'null' if its not possible. |
|
1432 * |
|
1433 * This method's implementation was heavily influenced by the |
|
1434 * scanPunctuator function in the Esprima parser's source code. |
|
1435 */ |
|
1436 scanPunctuator: function () { |
|
1437 var ch1 = this.peek(); |
|
1438 var ch2, ch3, ch4; |
|
1439 |
|
1440 switch (ch1) { |
|
1441 // Most common single-character punctuators |
|
1442 case ".": |
|
1443 if ((/^[0-9]$/).test(this.peek(1))) { |
|
1444 return null; |
|
1445 } |
|
1446 if (this.peek(1) === "." && this.peek(2) === ".") { |
|
1447 return { |
|
1448 type: Token.Punctuator, |
|
1449 value: "..." |
|
1450 }; |
|
1451 } |
|
1452 /* falls through */ |
|
1453 case "(": |
|
1454 case ")": |
|
1455 case ";": |
|
1456 case ",": |
|
1457 case "{": |
|
1458 case "}": |
|
1459 case "[": |
|
1460 case "]": |
|
1461 case ":": |
|
1462 case "~": |
|
1463 case "?": |
|
1464 return { |
|
1465 type: Token.Punctuator, |
|
1466 value: ch1 |
|
1467 }; |
|
1468 |
|
1469 // A pound sign (for Node shebangs) |
|
1470 case "#": |
|
1471 return { |
|
1472 type: Token.Punctuator, |
|
1473 value: ch1 |
|
1474 }; |
|
1475 |
|
1476 // We're at the end of input |
|
1477 case "": |
|
1478 return null; |
|
1479 } |
|
1480 |
|
1481 // Peek more characters |
|
1482 |
|
1483 ch2 = this.peek(1); |
|
1484 ch3 = this.peek(2); |
|
1485 ch4 = this.peek(3); |
|
1486 |
|
1487 // 4-character punctuator: >>>= |
|
1488 |
|
1489 if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { |
|
1490 return { |
|
1491 type: Token.Punctuator, |
|
1492 value: ">>>=" |
|
1493 }; |
|
1494 } |
|
1495 |
|
1496 // 3-character punctuators: === !== >>> <<= >>= |
|
1497 |
|
1498 if (ch1 === "=" && ch2 === "=" && ch3 === "=") { |
|
1499 return { |
|
1500 type: Token.Punctuator, |
|
1501 value: "===" |
|
1502 }; |
|
1503 } |
|
1504 |
|
1505 if (ch1 === "!" && ch2 === "=" && ch3 === "=") { |
|
1506 return { |
|
1507 type: Token.Punctuator, |
|
1508 value: "!==" |
|
1509 }; |
|
1510 } |
|
1511 |
|
1512 if (ch1 === ">" && ch2 === ">" && ch3 === ">") { |
|
1513 return { |
|
1514 type: Token.Punctuator, |
|
1515 value: ">>>" |
|
1516 }; |
|
1517 } |
|
1518 |
|
1519 if (ch1 === "<" && ch2 === "<" && ch3 === "=") { |
|
1520 return { |
|
1521 type: Token.Punctuator, |
|
1522 value: "<<=" |
|
1523 }; |
|
1524 } |
|
1525 |
|
1526 if (ch1 === ">" && ch2 === ">" && ch3 === "=") { |
|
1527 return { |
|
1528 type: Token.Punctuator, |
|
1529 value: ">>=" |
|
1530 }; |
|
1531 } |
|
1532 |
|
1533 // Fat arrow punctuator |
|
1534 if (ch1 === "=" && ch2 === ">") { |
|
1535 return { |
|
1536 type: Token.Punctuator, |
|
1537 value: ch1 + ch2 |
|
1538 }; |
|
1539 } |
|
1540 |
|
1541 // 2-character punctuators: <= >= == != ++ -- << >> && || |
|
1542 // += -= *= %= &= |= ^= (but not /=, see below) |
|
1543 if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) { |
|
1544 return { |
|
1545 type: Token.Punctuator, |
|
1546 value: ch1 + ch2 |
|
1547 }; |
|
1548 } |
|
1549 |
|
1550 if ("<>=!+-*%&|^".indexOf(ch1) >= 0) { |
|
1551 if (ch2 === "=") { |
|
1552 return { |
|
1553 type: Token.Punctuator, |
|
1554 value: ch1 + ch2 |
|
1555 }; |
|
1556 } |
|
1557 |
|
1558 return { |
|
1559 type: Token.Punctuator, |
|
1560 value: ch1 |
|
1561 }; |
|
1562 } |
|
1563 |
|
1564 // Special case: /=. We need to make sure that this is an |
|
1565 // operator and not a regular expression. |
|
1566 |
|
1567 if (ch1 === "/") { |
|
1568 if (ch2 === "=" && /\/=(?!(\S*\/[gim]?))/.test(this.input)) { |
|
1569 // /= is not a part of a regular expression, return it as a |
|
1570 // punctuator. |
|
1571 return { |
|
1572 type: Token.Punctuator, |
|
1573 value: "/=" |
|
1574 }; |
|
1575 } |
|
1576 |
|
1577 return { |
|
1578 type: Token.Punctuator, |
|
1579 value: "/" |
|
1580 }; |
|
1581 } |
|
1582 |
|
1583 return null; |
|
1584 }, |
|
1585 |
|
1586 /* |
|
1587 * Extract a comment out of the next sequence of characters and/or |
|
1588 * lines or return 'null' if its not possible. Since comments can |
|
1589 * span across multiple lines this method has to move the char |
|
1590 * pointer. |
|
1591 * |
|
1592 * In addition to normal JavaScript comments (// and /*) this method |
|
1593 * also recognizes JSHint- and JSLint-specific comments such as |
|
1594 * /*jshint, /*jslint, /*globals and so on. |
|
1595 */ |
|
1596 scanComments: function () { |
|
1597 var ch1 = this.peek(); |
|
1598 var ch2 = this.peek(1); |
|
1599 var rest = this.input.substr(2); |
|
1600 var startLine = this.line; |
|
1601 var startChar = this.char; |
|
1602 |
|
1603 // Create a comment token object and make sure it |
|
1604 // has all the data JSHint needs to work with special |
|
1605 // comments. |
|
1606 |
|
1607 function commentToken(label, body, opt) { |
|
1608 var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"]; |
|
1609 var isSpecial = false; |
|
1610 var value = label + body; |
|
1611 var commentType = "plain"; |
|
1612 opt = opt || {}; |
|
1613 |
|
1614 if (opt.isMultiline) { |
|
1615 value += "*/"; |
|
1616 } |
|
1617 |
|
1618 special.forEach(function (str) { |
|
1619 if (isSpecial) { |
|
1620 return; |
|
1621 } |
|
1622 |
|
1623 // Don't recognize any special comments other than jshint for single-line |
|
1624 // comments. This introduced many problems with legit comments. |
|
1625 if (label === "//" && str !== "jshint") { |
|
1626 return; |
|
1627 } |
|
1628 |
|
1629 if (body.substr(0, str.length) === str) { |
|
1630 isSpecial = true; |
|
1631 label = label + str; |
|
1632 body = body.substr(str.length); |
|
1633 } |
|
1634 |
|
1635 if (!isSpecial && body.charAt(0) === " " && body.substr(1, str.length) === str) { |
|
1636 isSpecial = true; |
|
1637 label = label + " " + str; |
|
1638 body = body.substr(str.length + 1); |
|
1639 } |
|
1640 |
|
1641 if (!isSpecial) { |
|
1642 return; |
|
1643 } |
|
1644 |
|
1645 switch (str) { |
|
1646 case "member": |
|
1647 commentType = "members"; |
|
1648 break; |
|
1649 case "global": |
|
1650 commentType = "globals"; |
|
1651 break; |
|
1652 default: |
|
1653 commentType = str; |
|
1654 } |
|
1655 }); |
|
1656 |
|
1657 return { |
|
1658 type: Token.Comment, |
|
1659 commentType: commentType, |
|
1660 value: value, |
|
1661 body: body, |
|
1662 isSpecial: isSpecial, |
|
1663 isMultiline: opt.isMultiline || false, |
|
1664 isMalformed: opt.isMalformed || false |
|
1665 }; |
|
1666 } |
|
1667 |
|
1668 // End of unbegun comment. Raise an error and skip that input. |
|
1669 if (ch1 === "*" && ch2 === "/") { |
|
1670 this.trigger("error", { |
|
1671 code: "E018", |
|
1672 line: startLine, |
|
1673 character: startChar |
|
1674 }); |
|
1675 |
|
1676 this.skip(2); |
|
1677 return null; |
|
1678 } |
|
1679 |
|
1680 // Comments must start either with // or /* |
|
1681 if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { |
|
1682 return null; |
|
1683 } |
|
1684 |
|
1685 // One-line comment |
|
1686 if (ch2 === "/") { |
|
1687 this.skip(this.input.length); // Skip to the EOL. |
|
1688 return commentToken("//", rest); |
|
1689 } |
|
1690 |
|
1691 var body = ""; |
|
1692 |
|
1693 /* Multi-line comment */ |
|
1694 if (ch2 === "*") { |
|
1695 this.skip(2); |
|
1696 |
|
1697 while (this.peek() !== "*" || this.peek(1) !== "/") { |
|
1698 if (this.peek() === "") { // End of Line |
|
1699 body += "\n"; |
|
1700 |
|
1701 // If we hit EOF and our comment is still unclosed, |
|
1702 // trigger an error and end the comment implicitly. |
|
1703 if (!this.nextLine()) { |
|
1704 this.trigger("error", { |
|
1705 code: "E017", |
|
1706 line: startLine, |
|
1707 character: startChar |
|
1708 }); |
|
1709 |
|
1710 return commentToken("/*", body, { |
|
1711 isMultiline: true, |
|
1712 isMalformed: true |
|
1713 }); |
|
1714 } |
|
1715 } else { |
|
1716 body += this.peek(); |
|
1717 this.skip(); |
|
1718 } |
|
1719 } |
|
1720 |
|
1721 this.skip(2); |
|
1722 return commentToken("/*", body, { isMultiline: true }); |
|
1723 } |
|
1724 }, |
|
1725 |
|
1726 /* |
|
1727 * Extract a keyword out of the next sequence of characters or |
|
1728 * return 'null' if its not possible. |
|
1729 */ |
|
1730 scanKeyword: function () { |
|
1731 var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); |
|
1732 var keywords = [ |
|
1733 "if", "in", "do", "var", "for", "new", |
|
1734 "try", "let", "this", "else", "case", |
|
1735 "void", "with", "enum", "while", "break", |
|
1736 "catch", "throw", "const", "yield", "class", |
|
1737 "super", "return", "typeof", "delete", |
|
1738 "switch", "export", "import", "default", |
|
1739 "finally", "extends", "function", "continue", |
|
1740 "debugger", "instanceof" |
|
1741 ]; |
|
1742 |
|
1743 if (result && keywords.indexOf(result[0]) >= 0) { |
|
1744 return { |
|
1745 type: Token.Keyword, |
|
1746 value: result[0] |
|
1747 }; |
|
1748 } |
|
1749 |
|
1750 return null; |
|
1751 }, |
|
1752 |
|
1753 /* |
|
1754 * Extract a JavaScript identifier out of the next sequence of |
|
1755 * characters or return 'null' if its not possible. In addition, |
|
1756 * to Identifier this method can also produce BooleanLiteral |
|
1757 * (true/false) and NullLiteral (null). |
|
1758 */ |
|
1759 scanIdentifier: function () { |
|
1760 var id = ""; |
|
1761 var index = 0; |
|
1762 var type, char; |
|
1763 |
|
1764 // Detects any character in the Unicode categories "Uppercase |
|
1765 // letter (Lu)", "Lowercase letter (Ll)", "Titlecase letter |
|
1766 // (Lt)", "Modifier letter (Lm)", "Other letter (Lo)", or |
|
1767 // "Letter number (Nl)". |
|
1768 // |
|
1769 // Both approach and unicodeLetterTable were borrowed from |
|
1770 // Google's Traceur. |
|
1771 |
|
1772 function isUnicodeLetter(code) { |
|
1773 for (var i = 0; i < unicodeLetterTable.length;) { |
|
1774 if (code < unicodeLetterTable[i++]) { |
|
1775 return false; |
|
1776 } |
|
1777 |
|
1778 if (code <= unicodeLetterTable[i++]) { |
|
1779 return true; |
|
1780 } |
|
1781 } |
|
1782 |
|
1783 return false; |
|
1784 } |
|
1785 |
|
1786 function isHexDigit(str) { |
|
1787 return (/^[0-9a-fA-F]$/).test(str); |
|
1788 } |
|
1789 |
|
1790 var readUnicodeEscapeSequence = function () { |
|
1791 /*jshint validthis:true */ |
|
1792 index += 1; |
|
1793 |
|
1794 if (this.peek(index) !== "u") { |
|
1795 return null; |
|
1796 } |
|
1797 |
|
1798 var ch1 = this.peek(index + 1); |
|
1799 var ch2 = this.peek(index + 2); |
|
1800 var ch3 = this.peek(index + 3); |
|
1801 var ch4 = this.peek(index + 4); |
|
1802 var code; |
|
1803 |
|
1804 if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) { |
|
1805 code = parseInt(ch1 + ch2 + ch3 + ch4, 16); |
|
1806 |
|
1807 if (isUnicodeLetter(code)) { |
|
1808 index += 5; |
|
1809 return "\\u" + ch1 + ch2 + ch3 + ch4; |
|
1810 } |
|
1811 |
|
1812 return null; |
|
1813 } |
|
1814 |
|
1815 return null; |
|
1816 }.bind(this); |
|
1817 |
|
1818 var getIdentifierStart = function () { |
|
1819 /*jshint validthis:true */ |
|
1820 var chr = this.peek(index); |
|
1821 var code = chr.charCodeAt(0); |
|
1822 |
|
1823 if (code === 92) { |
|
1824 return readUnicodeEscapeSequence(); |
|
1825 } |
|
1826 |
|
1827 if (code < 128) { |
|
1828 if (identifierStartTable[code]) { |
|
1829 index += 1; |
|
1830 return chr; |
|
1831 } |
|
1832 |
|
1833 return null; |
|
1834 } |
|
1835 |
|
1836 if (isUnicodeLetter(code)) { |
|
1837 index += 1; |
|
1838 return chr; |
|
1839 } |
|
1840 |
|
1841 return null; |
|
1842 }.bind(this); |
|
1843 |
|
1844 var getIdentifierPart = function () { |
|
1845 /*jshint validthis:true */ |
|
1846 var chr = this.peek(index); |
|
1847 var code = chr.charCodeAt(0); |
|
1848 |
|
1849 if (code === 92) { |
|
1850 return readUnicodeEscapeSequence(); |
|
1851 } |
|
1852 |
|
1853 if (code < 128) { |
|
1854 if (identifierPartTable[code]) { |
|
1855 index += 1; |
|
1856 return chr; |
|
1857 } |
|
1858 |
|
1859 return null; |
|
1860 } |
|
1861 |
|
1862 if (isUnicodeLetter(code)) { |
|
1863 index += 1; |
|
1864 return chr; |
|
1865 } |
|
1866 |
|
1867 return null; |
|
1868 }.bind(this); |
|
1869 |
|
1870 char = getIdentifierStart(); |
|
1871 if (char === null) { |
|
1872 return null; |
|
1873 } |
|
1874 |
|
1875 id = char; |
|
1876 for (;;) { |
|
1877 char = getIdentifierPart(); |
|
1878 |
|
1879 if (char === null) { |
|
1880 break; |
|
1881 } |
|
1882 |
|
1883 id += char; |
|
1884 } |
|
1885 |
|
1886 switch (id) { |
|
1887 case "true": |
|
1888 case "false": |
|
1889 type = Token.BooleanLiteral; |
|
1890 break; |
|
1891 case "null": |
|
1892 type = Token.NullLiteral; |
|
1893 break; |
|
1894 default: |
|
1895 type = Token.Identifier; |
|
1896 } |
|
1897 |
|
1898 return { |
|
1899 type: type, |
|
1900 value: id |
|
1901 }; |
|
1902 }, |
|
1903 |
|
1904 /* |
|
1905 * Extract a numeric literal out of the next sequence of |
|
1906 * characters or return 'null' if its not possible. This method |
|
1907 * supports all numeric literals described in section 7.8.3 |
|
1908 * of the EcmaScript 5 specification. |
|
1909 * |
|
1910 * This method's implementation was heavily influenced by the |
|
1911 * scanNumericLiteral function in the Esprima parser's source code. |
|
1912 */ |
|
1913 scanNumericLiteral: function () { |
|
1914 var index = 0; |
|
1915 var value = ""; |
|
1916 var length = this.input.length; |
|
1917 var char = this.peek(index); |
|
1918 var bad; |
|
1919 |
|
1920 function isDecimalDigit(str) { |
|
1921 return (/^[0-9]$/).test(str); |
|
1922 } |
|
1923 |
|
1924 function isOctalDigit(str) { |
|
1925 return (/^[0-7]$/).test(str); |
|
1926 } |
|
1927 |
|
1928 function isHexDigit(str) { |
|
1929 return (/^[0-9a-fA-F]$/).test(str); |
|
1930 } |
|
1931 |
|
1932 function isIdentifierStart(ch) { |
|
1933 return (ch === "$") || (ch === "_") || (ch === "\\") || |
|
1934 (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); |
|
1935 } |
|
1936 |
|
1937 // Numbers must start either with a decimal digit or a point. |
|
1938 |
|
1939 if (char !== "." && !isDecimalDigit(char)) { |
|
1940 return null; |
|
1941 } |
|
1942 |
|
1943 if (char !== ".") { |
|
1944 value = this.peek(index); |
|
1945 index += 1; |
|
1946 char = this.peek(index); |
|
1947 |
|
1948 if (value === "0") { |
|
1949 // Base-16 numbers. |
|
1950 if (char === "x" || char === "X") { |
|
1951 index += 1; |
|
1952 value += char; |
|
1953 |
|
1954 while (index < length) { |
|
1955 char = this.peek(index); |
|
1956 if (!isHexDigit(char)) { |
|
1957 break; |
|
1958 } |
|
1959 value += char; |
|
1960 index += 1; |
|
1961 } |
|
1962 |
|
1963 if (value.length <= 2) { // 0x |
|
1964 return { |
|
1965 type: Token.NumericLiteral, |
|
1966 value: value, |
|
1967 isMalformed: true |
|
1968 }; |
|
1969 } |
|
1970 |
|
1971 if (index < length) { |
|
1972 char = this.peek(index); |
|
1973 if (isIdentifierStart(char)) { |
|
1974 return null; |
|
1975 } |
|
1976 } |
|
1977 |
|
1978 return { |
|
1979 type: Token.NumericLiteral, |
|
1980 value: value, |
|
1981 base: 16, |
|
1982 isMalformed: false |
|
1983 }; |
|
1984 } |
|
1985 |
|
1986 // Base-8 numbers. |
|
1987 if (isOctalDigit(char)) { |
|
1988 index += 1; |
|
1989 value += char; |
|
1990 bad = false; |
|
1991 |
|
1992 while (index < length) { |
|
1993 char = this.peek(index); |
|
1994 |
|
1995 // Numbers like '019' (note the 9) are not valid octals |
|
1996 // but we still parse them and mark as malformed. |
|
1997 |
|
1998 if (isDecimalDigit(char)) { |
|
1999 bad = true; |
|
2000 } else if (!isOctalDigit(char)) { |
|
2001 break; |
|
2002 } |
|
2003 value += char; |
|
2004 index += 1; |
|
2005 } |
|
2006 |
|
2007 if (index < length) { |
|
2008 char = this.peek(index); |
|
2009 if (isIdentifierStart(char)) { |
|
2010 return null; |
|
2011 } |
|
2012 } |
|
2013 |
|
2014 return { |
|
2015 type: Token.NumericLiteral, |
|
2016 value: value, |
|
2017 base: 8, |
|
2018 isMalformed: false |
|
2019 }; |
|
2020 } |
|
2021 |
|
2022 // Decimal numbers that start with '0' such as '09' are illegal |
|
2023 // but we still parse them and return as malformed. |
|
2024 |
|
2025 if (isDecimalDigit(char)) { |
|
2026 index += 1; |
|
2027 value += char; |
|
2028 } |
|
2029 } |
|
2030 |
|
2031 while (index < length) { |
|
2032 char = this.peek(index); |
|
2033 if (!isDecimalDigit(char)) { |
|
2034 break; |
|
2035 } |
|
2036 value += char; |
|
2037 index += 1; |
|
2038 } |
|
2039 } |
|
2040 |
|
2041 // Decimal digits. |
|
2042 |
|
2043 if (char === ".") { |
|
2044 value += char; |
|
2045 index += 1; |
|
2046 |
|
2047 while (index < length) { |
|
2048 char = this.peek(index); |
|
2049 if (!isDecimalDigit(char)) { |
|
2050 break; |
|
2051 } |
|
2052 value += char; |
|
2053 index += 1; |
|
2054 } |
|
2055 } |
|
2056 |
|
2057 // Exponent part. |
|
2058 |
|
2059 if (char === "e" || char === "E") { |
|
2060 value += char; |
|
2061 index += 1; |
|
2062 char = this.peek(index); |
|
2063 |
|
2064 if (char === "+" || char === "-") { |
|
2065 value += this.peek(index); |
|
2066 index += 1; |
|
2067 } |
|
2068 |
|
2069 char = this.peek(index); |
|
2070 if (isDecimalDigit(char)) { |
|
2071 value += char; |
|
2072 index += 1; |
|
2073 |
|
2074 while (index < length) { |
|
2075 char = this.peek(index); |
|
2076 if (!isDecimalDigit(char)) { |
|
2077 break; |
|
2078 } |
|
2079 value += char; |
|
2080 index += 1; |
|
2081 } |
|
2082 } else { |
|
2083 return null; |
|
2084 } |
|
2085 } |
|
2086 |
|
2087 if (index < length) { |
|
2088 char = this.peek(index); |
|
2089 if (isIdentifierStart(char)) { |
|
2090 return null; |
|
2091 } |
|
2092 } |
|
2093 |
|
2094 return { |
|
2095 type: Token.NumericLiteral, |
|
2096 value: value, |
|
2097 base: 10, |
|
2098 isMalformed: !isFinite(value) |
|
2099 }; |
|
2100 }, |
|
2101 |
|
2102 /* |
|
2103 * Extract a string out of the next sequence of characters and/or |
|
2104 * lines or return 'null' if its not possible. Since strings can |
|
2105 * span across multiple lines this method has to move the char |
|
2106 * pointer. |
|
2107 * |
|
2108 * This method recognizes pseudo-multiline JavaScript strings: |
|
2109 * |
|
2110 * var str = "hello\ |
|
2111 * world"; |
|
2112 */ |
|
2113 scanStringLiteral: function (checks) { |
|
2114 /*jshint loopfunc:true */ |
|
2115 var quote = this.peek(); |
|
2116 |
|
2117 // String must start with a quote. |
|
2118 if (quote !== "\"" && quote !== "'") { |
|
2119 return null; |
|
2120 } |
|
2121 |
|
2122 // In JSON strings must always use double quotes. |
|
2123 this.triggerAsync("warning", { |
|
2124 code: "W108", |
|
2125 line: this.line, |
|
2126 character: this.char // +1? |
|
2127 }, checks, function () { return state.jsonMode && quote !== "\""; }); |
|
2128 |
|
2129 var value = ""; |
|
2130 var startLine = this.line; |
|
2131 var startChar = this.char; |
|
2132 var allowNewLine = false; |
|
2133 |
|
2134 this.skip(); |
|
2135 |
|
2136 while (this.peek() !== quote) { |
|
2137 while (this.peek() === "") { // End Of Line |
|
2138 |
|
2139 // If an EOL is not preceded by a backslash, show a warning |
|
2140 // and proceed like it was a legit multi-line string where |
|
2141 // author simply forgot to escape the newline symbol. |
|
2142 // |
|
2143 // Another approach is to implicitly close a string on EOL |
|
2144 // but it generates too many false positives. |
|
2145 |
|
2146 if (!allowNewLine) { |
|
2147 this.trigger("warning", { |
|
2148 code: "W112", |
|
2149 line: this.line, |
|
2150 character: this.char |
|
2151 }); |
|
2152 } else { |
|
2153 allowNewLine = false; |
|
2154 |
|
2155 // Otherwise show a warning if multistr option was not set. |
|
2156 // For JSON, show warning no matter what. |
|
2157 |
|
2158 this.triggerAsync("warning", { |
|
2159 code: "W043", |
|
2160 line: this.line, |
|
2161 character: this.char |
|
2162 }, checks, function () { return !state.option.multistr; }); |
|
2163 |
|
2164 this.triggerAsync("warning", { |
|
2165 code: "W042", |
|
2166 line: this.line, |
|
2167 character: this.char |
|
2168 }, checks, function () { return state.jsonMode && state.option.multistr; }); |
|
2169 } |
|
2170 |
|
2171 // If we get an EOF inside of an unclosed string, show an |
|
2172 // error and implicitly close it at the EOF point. |
|
2173 |
|
2174 if (!this.nextLine()) { |
|
2175 this.trigger("error", { |
|
2176 code: "E029", |
|
2177 line: startLine, |
|
2178 character: startChar |
|
2179 }); |
|
2180 |
|
2181 return { |
|
2182 type: Token.StringLiteral, |
|
2183 value: value, |
|
2184 isUnclosed: true, |
|
2185 quote: quote |
|
2186 }; |
|
2187 } |
|
2188 } |
|
2189 |
|
2190 allowNewLine = false; |
|
2191 var char = this.peek(); |
|
2192 var jump = 1; // A length of a jump, after we're done |
|
2193 // parsing this character. |
|
2194 |
|
2195 if (char < " ") { |
|
2196 // Warn about a control character in a string. |
|
2197 this.trigger("warning", { |
|
2198 code: "W113", |
|
2199 line: this.line, |
|
2200 character: this.char, |
|
2201 data: [ "<non-printable>" ] |
|
2202 }); |
|
2203 } |
|
2204 |
|
2205 // Special treatment for some escaped characters. |
|
2206 |
|
2207 if (char === "\\") { |
|
2208 this.skip(); |
|
2209 char = this.peek(); |
|
2210 |
|
2211 switch (char) { |
|
2212 case "'": |
|
2213 this.triggerAsync("warning", { |
|
2214 code: "W114", |
|
2215 line: this.line, |
|
2216 character: this.char, |
|
2217 data: [ "\\'" ] |
|
2218 }, checks, function () {return state.jsonMode; }); |
|
2219 break; |
|
2220 case "b": |
|
2221 char = "\b"; |
|
2222 break; |
|
2223 case "f": |
|
2224 char = "\f"; |
|
2225 break; |
|
2226 case "n": |
|
2227 char = "\n"; |
|
2228 break; |
|
2229 case "r": |
|
2230 char = "\r"; |
|
2231 break; |
|
2232 case "t": |
|
2233 char = "\t"; |
|
2234 break; |
|
2235 case "0": |
|
2236 char = "\0"; |
|
2237 |
|
2238 // Octal literals fail in strict mode. |
|
2239 // Check if the number is between 00 and 07. |
|
2240 var n = parseInt(this.peek(1), 10); |
|
2241 this.triggerAsync("warning", { |
|
2242 code: "W115", |
|
2243 line: this.line, |
|
2244 character: this.char |
|
2245 }, checks, |
|
2246 function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); |
|
2247 break; |
|
2248 case "u": |
|
2249 char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); |
|
2250 jump = 5; |
|
2251 break; |
|
2252 case "v": |
|
2253 this.triggerAsync("warning", { |
|
2254 code: "W114", |
|
2255 line: this.line, |
|
2256 character: this.char, |
|
2257 data: [ "\\v" ] |
|
2258 }, checks, function () { return state.jsonMode; }); |
|
2259 |
|
2260 char = "\v"; |
|
2261 break; |
|
2262 case "x": |
|
2263 var x = parseInt(this.input.substr(1, 2), 16); |
|
2264 |
|
2265 this.triggerAsync("warning", { |
|
2266 code: "W114", |
|
2267 line: this.line, |
|
2268 character: this.char, |
|
2269 data: [ "\\x-" ] |
|
2270 }, checks, function () { return state.jsonMode; }); |
|
2271 |
|
2272 char = String.fromCharCode(x); |
|
2273 jump = 3; |
|
2274 break; |
|
2275 case "\\": |
|
2276 case "\"": |
|
2277 case "/": |
|
2278 break; |
|
2279 case "": |
|
2280 allowNewLine = true; |
|
2281 char = ""; |
|
2282 break; |
|
2283 case "!": |
|
2284 if (value.slice(value.length - 2) === "<") { |
|
2285 break; |
|
2286 } |
|
2287 |
|
2288 /*falls through */ |
|
2289 default: |
|
2290 // Weird escaping. |
|
2291 this.trigger("warning", { |
|
2292 code: "W044", |
|
2293 line: this.line, |
|
2294 character: this.char |
|
2295 }); |
|
2296 } |
|
2297 } |
|
2298 |
|
2299 value += char; |
|
2300 this.skip(jump); |
|
2301 } |
|
2302 |
|
2303 this.skip(); |
|
2304 return { |
|
2305 type: Token.StringLiteral, |
|
2306 value: value, |
|
2307 isUnclosed: false, |
|
2308 quote: quote |
|
2309 }; |
|
2310 }, |
|
2311 |
|
2312 /* |
|
2313 * Extract a regular expression out of the next sequence of |
|
2314 * characters and/or lines or return 'null' if its not possible. |
|
2315 * |
|
2316 * This method is platform dependent: it accepts almost any |
|
2317 * regular expression values but then tries to compile and run |
|
2318 * them using system's RegExp object. This means that there are |
|
2319 * rare edge cases where one JavaScript engine complains about |
|
2320 * your regular expression while others don't. |
|
2321 */ |
|
2322 scanRegExp: function () { |
|
2323 var index = 0; |
|
2324 var length = this.input.length; |
|
2325 var char = this.peek(); |
|
2326 var value = char; |
|
2327 var body = ""; |
|
2328 var flags = []; |
|
2329 var malformed = false; |
|
2330 var isCharSet = false; |
|
2331 var terminated; |
|
2332 |
|
2333 var scanUnexpectedChars = function () { |
|
2334 // Unexpected control character |
|
2335 if (char < " ") { |
|
2336 malformed = true; |
|
2337 this.trigger("warning", { |
|
2338 code: "W048", |
|
2339 line: this.line, |
|
2340 character: this.char |
|
2341 }); |
|
2342 } |
|
2343 |
|
2344 // Unexpected escaped character |
|
2345 if (char === "<") { |
|
2346 malformed = true; |
|
2347 this.trigger("warning", { |
|
2348 code: "W049", |
|
2349 line: this.line, |
|
2350 character: this.char, |
|
2351 data: [ char ] |
|
2352 }); |
|
2353 } |
|
2354 }.bind(this); |
|
2355 |
|
2356 // Regular expressions must start with '/' |
|
2357 if (!this.prereg || char !== "/") { |
|
2358 return null; |
|
2359 } |
|
2360 |
|
2361 index += 1; |
|
2362 terminated = false; |
|
2363 |
|
2364 // Try to get everything in between slashes. A couple of |
|
2365 // cases aside (see scanUnexpectedChars) we don't really |
|
2366 // care whether the resulting expression is valid or not. |
|
2367 // We will check that later using the RegExp object. |
|
2368 |
|
2369 while (index < length) { |
|
2370 char = this.peek(index); |
|
2371 value += char; |
|
2372 body += char; |
|
2373 |
|
2374 if (isCharSet) { |
|
2375 if (char === "]") { |
|
2376 if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { |
|
2377 isCharSet = false; |
|
2378 } |
|
2379 } |
|
2380 |
|
2381 if (char === "\\") { |
|
2382 index += 1; |
|
2383 char = this.peek(index); |
|
2384 body += char; |
|
2385 value += char; |
|
2386 |
|
2387 scanUnexpectedChars(); |
|
2388 } |
|
2389 |
|
2390 index += 1; |
|
2391 continue; |
|
2392 } |
|
2393 |
|
2394 if (char === "\\") { |
|
2395 index += 1; |
|
2396 char = this.peek(index); |
|
2397 body += char; |
|
2398 value += char; |
|
2399 |
|
2400 scanUnexpectedChars(); |
|
2401 |
|
2402 if (char === "/") { |
|
2403 index += 1; |
|
2404 continue; |
|
2405 } |
|
2406 |
|
2407 if (char === "[") { |
|
2408 index += 1; |
|
2409 continue; |
|
2410 } |
|
2411 } |
|
2412 |
|
2413 if (char === "[") { |
|
2414 isCharSet = true; |
|
2415 index += 1; |
|
2416 continue; |
|
2417 } |
|
2418 |
|
2419 if (char === "/") { |
|
2420 body = body.substr(0, body.length - 1); |
|
2421 terminated = true; |
|
2422 index += 1; |
|
2423 break; |
|
2424 } |
|
2425 |
|
2426 index += 1; |
|
2427 } |
|
2428 |
|
2429 // A regular expression that was never closed is an |
|
2430 // error from which we cannot recover. |
|
2431 |
|
2432 if (!terminated) { |
|
2433 this.trigger("error", { |
|
2434 code: "E015", |
|
2435 line: this.line, |
|
2436 character: this.from |
|
2437 }); |
|
2438 |
|
2439 return void this.trigger("fatal", { |
|
2440 line: this.line, |
|
2441 from: this.from |
|
2442 }); |
|
2443 } |
|
2444 |
|
2445 // Parse flags (if any). |
|
2446 |
|
2447 while (index < length) { |
|
2448 char = this.peek(index); |
|
2449 if (!/[gim]/.test(char)) { |
|
2450 break; |
|
2451 } |
|
2452 flags.push(char); |
|
2453 value += char; |
|
2454 index += 1; |
|
2455 } |
|
2456 |
|
2457 // Check regular expression for correctness. |
|
2458 |
|
2459 try { |
|
2460 new RegExp(body, flags.join("")); |
|
2461 } catch (err) { |
|
2462 malformed = true; |
|
2463 this.trigger("error", { |
|
2464 code: "E016", |
|
2465 line: this.line, |
|
2466 character: this.char, |
|
2467 data: [ err.message ] // Platform dependent! |
|
2468 }); |
|
2469 } |
|
2470 |
|
2471 return { |
|
2472 type: Token.RegExp, |
|
2473 value: value, |
|
2474 flags: flags, |
|
2475 isMalformed: malformed |
|
2476 }; |
|
2477 }, |
|
2478 |
|
2479 /* |
|
2480 * Scan for any occurence of mixed tabs and spaces. If smarttabs option |
|
2481 * is on, ignore tabs followed by spaces. |
|
2482 * |
|
2483 * Tabs followed by one space followed by a block comment are allowed. |
|
2484 */ |
|
2485 scanMixedSpacesAndTabs: function () { |
|
2486 var at, match; |
|
2487 |
|
2488 if (state.option.smarttabs) { |
|
2489 // Negative look-behind for "//" |
|
2490 match = this.input.match(/(\/\/|^\s?\*)? \t/); |
|
2491 at = match && !match[1] ? 0 : -1; |
|
2492 } else { |
|
2493 at = this.input.search(/ \t|\t [^\*]/); |
|
2494 } |
|
2495 |
|
2496 return at; |
|
2497 }, |
|
2498 |
|
2499 /* |
|
2500 * Scan for characters that get silently deleted by one or more browsers. |
|
2501 */ |
|
2502 scanUnsafeChars: function () { |
|
2503 return this.input.search(reg.unsafeChars); |
|
2504 }, |
|
2505 |
|
2506 /* |
|
2507 * Produce the next raw token or return 'null' if no tokens can be matched. |
|
2508 * This method skips over all space characters. |
|
2509 */ |
|
2510 next: function (checks) { |
|
2511 this.from = this.char; |
|
2512 |
|
2513 // Move to the next non-space character. |
|
2514 var start; |
|
2515 if (/\s/.test(this.peek())) { |
|
2516 start = this.char; |
|
2517 |
|
2518 while (/\s/.test(this.peek())) { |
|
2519 this.from += 1; |
|
2520 this.skip(); |
|
2521 } |
|
2522 |
|
2523 if (this.peek() === "") { // EOL |
|
2524 if (!/^\s*$/.test(this.lines[this.line - 1]) && state.option.trailing) { |
|
2525 this.trigger("warning", { code: "W102", line: this.line, character: start }); |
|
2526 } |
|
2527 } |
|
2528 } |
|
2529 |
|
2530 // Methods that work with multi-line structures and move the |
|
2531 // character pointer. |
|
2532 |
|
2533 var match = this.scanComments() || |
|
2534 this.scanStringLiteral(checks); |
|
2535 |
|
2536 if (match) { |
|
2537 return match; |
|
2538 } |
|
2539 |
|
2540 // Methods that don't move the character pointer. |
|
2541 |
|
2542 match = |
|
2543 this.scanRegExp() || |
|
2544 this.scanPunctuator() || |
|
2545 this.scanKeyword() || |
|
2546 this.scanIdentifier() || |
|
2547 this.scanNumericLiteral(); |
|
2548 |
|
2549 if (match) { |
|
2550 this.skip(match.value.length); |
|
2551 return match; |
|
2552 } |
|
2553 |
|
2554 // No token could be matched, give up. |
|
2555 |
|
2556 return null; |
|
2557 }, |
|
2558 |
|
2559 /* |
|
2560 * Switch to the next line and reset all char pointers. Once |
|
2561 * switched, this method also checks for mixed spaces and tabs |
|
2562 * and other minor warnings. |
|
2563 */ |
|
2564 nextLine: function () { |
|
2565 var char; |
|
2566 |
|
2567 if (this.line >= this.lines.length) { |
|
2568 return false; |
|
2569 } |
|
2570 |
|
2571 this.input = this.lines[this.line]; |
|
2572 this.line += 1; |
|
2573 this.char = 1; |
|
2574 this.from = 1; |
|
2575 |
|
2576 char = this.scanMixedSpacesAndTabs(); |
|
2577 if (char >= 0) { |
|
2578 this.trigger("warning", { code: "W099", line: this.line, character: char + 1 }); |
|
2579 } |
|
2580 |
|
2581 this.input = this.input.replace(/\t/g, state.tab); |
|
2582 char = this.scanUnsafeChars(); |
|
2583 |
|
2584 if (char >= 0) { |
|
2585 this.trigger("warning", { code: "W100", line: this.line, character: char }); |
|
2586 } |
|
2587 |
|
2588 // If there is a limit on line length, warn when lines get too |
|
2589 // long. |
|
2590 |
|
2591 if (state.option.maxlen && state.option.maxlen < this.input.length) { |
|
2592 this.trigger("warning", { code: "W101", line: this.line, character: this.input.length }); |
|
2593 } |
|
2594 |
|
2595 return true; |
|
2596 }, |
|
2597 |
|
2598 /* |
|
2599 * This is simply a synonym for nextLine() method with a friendlier |
|
2600 * public name. |
|
2601 */ |
|
2602 start: function () { |
|
2603 this.nextLine(); |
|
2604 }, |
|
2605 |
|
2606 /* |
|
2607 * Produce the next token. This function is called by advance() to get |
|
2608 * the next token. It retuns a token in a JSLint-compatible format. |
|
2609 */ |
|
2610 token: function () { |
|
2611 /*jshint loopfunc:true */ |
|
2612 var checks = asyncTrigger(); |
|
2613 var token; |
|
2614 |
|
2615 |
|
2616 function isReserved(token, isProperty) { |
|
2617 if (!token.reserved) { |
|
2618 return false; |
|
2619 } |
|
2620 |
|
2621 if (token.meta && token.meta.isFutureReservedWord) { |
|
2622 // ES3 FutureReservedWord in an ES5 environment. |
|
2623 if (state.option.inES5(true) && !token.meta.es5) { |
|
2624 return false; |
|
2625 } |
|
2626 |
|
2627 // Some ES5 FutureReservedWord identifiers are active only |
|
2628 // within a strict mode environment. |
|
2629 if (token.meta.strictOnly) { |
|
2630 if (!state.option.strict && !state.directive["use strict"]) { |
|
2631 return false; |
|
2632 } |
|
2633 } |
|
2634 |
|
2635 if (isProperty) { |
|
2636 return false; |
|
2637 } |
|
2638 } |
|
2639 |
|
2640 return true; |
|
2641 } |
|
2642 |
|
2643 // Produce a token object. |
|
2644 var create = function (type, value, isProperty) { |
|
2645 /*jshint validthis:true */ |
|
2646 var obj; |
|
2647 |
|
2648 if (type !== "(endline)" && type !== "(end)") { |
|
2649 this.prereg = false; |
|
2650 } |
|
2651 |
|
2652 if (type === "(punctuator)") { |
|
2653 switch (value) { |
|
2654 case ".": |
|
2655 case ")": |
|
2656 case "~": |
|
2657 case "#": |
|
2658 case "]": |
|
2659 this.prereg = false; |
|
2660 break; |
|
2661 default: |
|
2662 this.prereg = true; |
|
2663 } |
|
2664 |
|
2665 obj = Object.create(state.syntax[value] || state.syntax["(error)"]); |
|
2666 } |
|
2667 |
|
2668 if (type === "(identifier)") { |
|
2669 if (value === "return" || value === "case" || value === "typeof") { |
|
2670 this.prereg = true; |
|
2671 } |
|
2672 |
|
2673 if (_.has(state.syntax, value)) { |
|
2674 obj = Object.create(state.syntax[value] || state.syntax["(error)"]); |
|
2675 |
|
2676 // If this can't be a reserved keyword, reset the object. |
|
2677 if (!isReserved(obj, isProperty && type === "(identifier)")) { |
|
2678 obj = null; |
|
2679 } |
|
2680 } |
|
2681 } |
|
2682 |
|
2683 if (!obj) { |
|
2684 obj = Object.create(state.syntax[type]); |
|
2685 } |
|
2686 |
|
2687 obj.identifier = (type === "(identifier)"); |
|
2688 obj.type = obj.type || type; |
|
2689 obj.value = value; |
|
2690 obj.line = this.line; |
|
2691 obj.character = this.char; |
|
2692 obj.from = this.from; |
|
2693 |
|
2694 if (isProperty && obj.identifier) { |
|
2695 obj.isProperty = isProperty; |
|
2696 } |
|
2697 |
|
2698 obj.check = checks.check; |
|
2699 |
|
2700 return obj; |
|
2701 }.bind(this); |
|
2702 |
|
2703 for (;;) { |
|
2704 if (!this.input.length) { |
|
2705 return create(this.nextLine() ? "(endline)" : "(end)", ""); |
|
2706 } |
|
2707 |
|
2708 token = this.next(checks); |
|
2709 |
|
2710 if (!token) { |
|
2711 if (this.input.length) { |
|
2712 // Unexpected character. |
|
2713 this.trigger("error", { |
|
2714 code: "E024", |
|
2715 line: this.line, |
|
2716 character: this.char, |
|
2717 data: [ this.peek() ] |
|
2718 }); |
|
2719 |
|
2720 this.input = ""; |
|
2721 } |
|
2722 |
|
2723 continue; |
|
2724 } |
|
2725 |
|
2726 switch (token.type) { |
|
2727 case Token.StringLiteral: |
|
2728 this.triggerAsync("String", { |
|
2729 line: this.line, |
|
2730 char: this.char, |
|
2731 from: this.from, |
|
2732 value: token.value, |
|
2733 quote: token.quote |
|
2734 }, checks, function () { return true; }); |
|
2735 |
|
2736 return create("(string)", token.value); |
|
2737 case Token.Identifier: |
|
2738 this.trigger("Identifier", { |
|
2739 line: this.line, |
|
2740 char: this.char, |
|
2741 from: this.form, |
|
2742 name: token.value, |
|
2743 isProperty: state.tokens.curr.id === "." |
|
2744 }); |
|
2745 |
|
2746 /* falls through */ |
|
2747 case Token.Keyword: |
|
2748 case Token.NullLiteral: |
|
2749 case Token.BooleanLiteral: |
|
2750 return create("(identifier)", token.value, state.tokens.curr.id === "."); |
|
2751 |
|
2752 case Token.NumericLiteral: |
|
2753 if (token.isMalformed) { |
|
2754 this.trigger("warning", { |
|
2755 code: "W045", |
|
2756 line: this.line, |
|
2757 character: this.char, |
|
2758 data: [ token.value ] |
|
2759 }); |
|
2760 } |
|
2761 |
|
2762 this.triggerAsync("warning", { |
|
2763 code: "W114", |
|
2764 line: this.line, |
|
2765 character: this.char, |
|
2766 data: [ "0x-" ] |
|
2767 }, checks, function () { return token.base === 16 && state.jsonMode; }); |
|
2768 |
|
2769 this.triggerAsync("warning", { |
|
2770 code: "W115", |
|
2771 line: this.line, |
|
2772 character: this.char |
|
2773 }, checks, function () { |
|
2774 return state.directive["use strict"] && token.base === 8; |
|
2775 }); |
|
2776 |
|
2777 this.trigger("Number", { |
|
2778 line: this.line, |
|
2779 char: this.char, |
|
2780 from: this.from, |
|
2781 value: token.value, |
|
2782 base: token.base, |
|
2783 isMalformed: token.malformed |
|
2784 }); |
|
2785 |
|
2786 return create("(number)", token.value); |
|
2787 |
|
2788 case Token.RegExp: |
|
2789 return create("(regexp)", token.value); |
|
2790 |
|
2791 case Token.Comment: |
|
2792 state.tokens.curr.comment = true; |
|
2793 |
|
2794 if (token.isSpecial) { |
|
2795 return { |
|
2796 value: token.value, |
|
2797 body: token.body, |
|
2798 type: token.commentType, |
|
2799 isSpecial: token.isSpecial, |
|
2800 line: this.line, |
|
2801 character: this.char, |
|
2802 from: this.from |
|
2803 }; |
|
2804 } |
|
2805 |
|
2806 break; |
|
2807 |
|
2808 case "": |
|
2809 break; |
|
2810 |
|
2811 default: |
|
2812 return create("(punctuator)", token.value); |
|
2813 } |
|
2814 } |
|
2815 } |
|
2816 }; |
|
2817 |
|
2818 exports.Lexer = Lexer; |
|
2819 |
|
2820 })() |
|
2821 },{"events":2,"./reg.js":6,"./state.js":4,"underscore":11}],"jshint":[function(require,module,exports){ |
|
2822 module.exports=require('E/GbHF'); |
|
2823 },{}],"E/GbHF":[function(require,module,exports){ |
|
2824 (function(){/*! |
|
2825 * JSHint, by JSHint Community. |
|
2826 * |
|
2827 * This file (and this file only) is licensed under the same slightly modified |
|
2828 * MIT license that JSLint is. It stops evil-doers everywhere: |
|
2829 * |
|
2830 * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) |
|
2831 * |
|
2832 * Permission is hereby granted, free of charge, to any person obtaining |
|
2833 * a copy of this software and associated documentation files (the "Software"), |
|
2834 * to deal in the Software without restriction, including without limitation |
|
2835 * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
2836 * and/or sell copies of the Software, and to permit persons to whom |
|
2837 * the Software is furnished to do so, subject to the following conditions: |
|
2838 * |
|
2839 * The above copyright notice and this permission notice shall be included |
|
2840 * in all copies or substantial portions of the Software. |
|
2841 * |
|
2842 * The Software shall be used for Good, not Evil. |
|
2843 * |
|
2844 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
2845 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
2846 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
2847 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
2848 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
2849 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
2850 * DEALINGS IN THE SOFTWARE. |
|
2851 * |
|
2852 */ |
|
2853 |
|
2854 /*jshint quotmark:double */ |
|
2855 /*global console:true */ |
|
2856 /*exported console */ |
|
2857 |
|
2858 var _ = require("underscore"); |
|
2859 var events = require("events"); |
|
2860 var vars = require("../shared/vars.js"); |
|
2861 var messages = require("../shared/messages.js"); |
|
2862 var Lexer = require("./lex.js").Lexer; |
|
2863 var reg = require("./reg.js"); |
|
2864 var state = require("./state.js").state; |
|
2865 var style = require("./style.js"); |
|
2866 |
|
2867 // We need this module here because environments such as IE and Rhino |
|
2868 // don't necessarilly expose the 'console' API and browserify uses |
|
2869 // it to log things. It's a sad state of affair, really. |
|
2870 var console = require("console-browserify"); |
|
2871 |
|
2872 // We build the application inside a function so that we produce only a singleton |
|
2873 // variable. That function will be invoked immediately, and its return value is |
|
2874 // the JSHINT function itself. |
|
2875 |
|
2876 var JSHINT = (function () { |
|
2877 "use strict"; |
|
2878 |
|
2879 var anonname, // The guessed name for anonymous functions. |
|
2880 api, // Extension API |
|
2881 |
|
2882 // These are operators that should not be used with the ! operator. |
|
2883 bang = { |
|
2884 "<" : true, |
|
2885 "<=" : true, |
|
2886 "==" : true, |
|
2887 "===": true, |
|
2888 "!==": true, |
|
2889 "!=" : true, |
|
2890 ">" : true, |
|
2891 ">=" : true, |
|
2892 "+" : true, |
|
2893 "-" : true, |
|
2894 "*" : true, |
|
2895 "/" : true, |
|
2896 "%" : true |
|
2897 }, |
|
2898 |
|
2899 // These are the JSHint boolean options. |
|
2900 boolOptions = { |
|
2901 asi : true, // if automatic semicolon insertion should be tolerated |
|
2902 bitwise : true, // if bitwise operators should not be allowed |
|
2903 boss : true, // if advanced usage of assignments should be allowed |
|
2904 browser : true, // if the standard browser globals should be predefined |
|
2905 camelcase : true, // if identifiers should be required in camel case |
|
2906 couch : true, // if CouchDB globals should be predefined |
|
2907 curly : true, // if curly braces around all blocks should be required |
|
2908 debug : true, // if debugger statements should be allowed |
|
2909 devel : true, // if logging globals should be predefined (console, alert, etc.) |
|
2910 dojo : true, // if Dojo Toolkit globals should be predefined |
|
2911 eqeqeq : true, // if === should be required |
|
2912 eqnull : true, // if == null comparisons should be tolerated |
|
2913 es3 : true, // if ES3 syntax should be allowed |
|
2914 es5 : true, // if ES5 syntax should be allowed (is now set per default) |
|
2915 esnext : true, // if es.next specific syntax should be allowed |
|
2916 moz : true, // if mozilla specific syntax should be allowed |
|
2917 evil : true, // if eval should be allowed |
|
2918 expr : true, // if ExpressionStatement should be allowed as Programs |
|
2919 forin : true, // if for in statements must filter |
|
2920 funcscope : true, // if only function scope should be used for scope tests |
|
2921 gcl : true, // if JSHint should be compatible with Google Closure Linter |
|
2922 globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') |
|
2923 immed : true, // if immediate invocations must be wrapped in parens |
|
2924 iterator : true, // if the `__iterator__` property should be allowed |
|
2925 jquery : true, // if jQuery globals should be predefined |
|
2926 lastsemic : true, // if semicolons may be ommitted for the trailing |
|
2927 // statements inside of a one-line blocks. |
|
2928 laxbreak : true, // if line breaks should not be checked |
|
2929 laxcomma : true, // if line breaks should not be checked around commas |
|
2930 loopfunc : true, // if functions should be allowed to be defined within |
|
2931 // loops |
|
2932 mootools : true, // if MooTools globals should be predefined |
|
2933 multistr : true, // allow multiline strings |
|
2934 newcap : true, // if constructor names must be capitalized |
|
2935 noarg : true, // if arguments.caller and arguments.callee should be |
|
2936 // disallowed |
|
2937 node : true, // if the Node.js environment globals should be |
|
2938 // predefined |
|
2939 noempty : true, // if empty blocks should be disallowed |
|
2940 nonew : true, // if using `new` for side-effects should be disallowed |
|
2941 nonstandard : true, // if non-standard (but widely adopted) globals should |
|
2942 // be predefined |
|
2943 nomen : true, // if names should be checked |
|
2944 onevar : true, // if only one var statement per function should be |
|
2945 // allowed |
|
2946 passfail : true, // if the scan should stop on first error |
|
2947 phantom : true, // if PhantomJS symbols should be allowed |
|
2948 plusplus : true, // if increment/decrement should not be allowed |
|
2949 proto : true, // if the `__proto__` property should be allowed |
|
2950 prototypejs : true, // if Prototype and Scriptaculous globals should be |
|
2951 // predefined |
|
2952 rhino : true, // if the Rhino environment globals should be predefined |
|
2953 undef : true, // if variables should be declared before used |
|
2954 scripturl : true, // if script-targeted URLs should be tolerated |
|
2955 shadow : true, // if variable shadowing should be tolerated |
|
2956 smarttabs : true, // if smarttabs should be tolerated |
|
2957 // (http://www.emacswiki.org/emacs/SmartTabs) |
|
2958 strict : true, // require the "use strict"; pragma |
|
2959 sub : true, // if all forms of subscript notation are tolerated |
|
2960 supernew : true, // if `new function () { ... };` and `new Object;` |
|
2961 // should be tolerated |
|
2962 trailing : true, // if trailing whitespace rules apply |
|
2963 validthis : true, // if 'this' inside a non-constructor function is valid. |
|
2964 // This is a function scoped option only. |
|
2965 withstmt : true, // if with statements should be allowed |
|
2966 white : true, // if strict whitespace rules apply |
|
2967 worker : true, // if Web Worker script symbols should be allowed |
|
2968 wsh : true, // if the Windows Scripting Host environment globals |
|
2969 // should be predefined |
|
2970 yui : true, // YUI variables should be predefined |
|
2971 |
|
2972 // Obsolete options |
|
2973 onecase : true, // if one case switch statements should be allowed |
|
2974 regexp : true, // if the . should not be allowed in regexp literals |
|
2975 regexdash : true // if unescaped first/last dash (-) inside brackets |
|
2976 // should be tolerated |
|
2977 }, |
|
2978 |
|
2979 // These are the JSHint options that can take any value |
|
2980 // (we use this object to detect invalid options) |
|
2981 valOptions = { |
|
2982 maxlen : false, |
|
2983 indent : false, |
|
2984 maxerr : false, |
|
2985 predef : false, |
|
2986 quotmark : false, //'single'|'double'|true |
|
2987 scope : false, |
|
2988 maxstatements: false, // {int} max statements per function |
|
2989 maxdepth : false, // {int} max nested block depth per function |
|
2990 maxparams : false, // {int} max params per function |
|
2991 maxcomplexity: false, // {int} max cyclomatic complexity per function |
|
2992 unused : true, // warn if variables are unused. Available options: |
|
2993 // false - don't check for unused variables |
|
2994 // true - "vars" + check last function param |
|
2995 // "vars" - skip checking unused function params |
|
2996 // "strict" - "vars" + check all function params |
|
2997 latedef : false // warn if the variable is used before its definition |
|
2998 // false - don't emit any warnings |
|
2999 // true - warn if any variable is used before its definition |
|
3000 // "nofunc" - warn for any variable but function declarations |
|
3001 }, |
|
3002 |
|
3003 // These are JSHint boolean options which are shared with JSLint |
|
3004 // where the definition in JSHint is opposite JSLint |
|
3005 invertedOptions = { |
|
3006 bitwise : true, |
|
3007 forin : true, |
|
3008 newcap : true, |
|
3009 nomen : true, |
|
3010 plusplus: true, |
|
3011 regexp : true, |
|
3012 undef : true, |
|
3013 white : true, |
|
3014 |
|
3015 // Inverted and renamed, use JSHint name here |
|
3016 eqeqeq : true, |
|
3017 onevar : true, |
|
3018 strict : true |
|
3019 }, |
|
3020 |
|
3021 // These are JSHint boolean options which are shared with JSLint |
|
3022 // where the name has been changed but the effect is unchanged |
|
3023 renamedOptions = { |
|
3024 eqeq : "eqeqeq", |
|
3025 vars : "onevar", |
|
3026 windows: "wsh", |
|
3027 sloppy : "strict" |
|
3028 }, |
|
3029 |
|
3030 declared, // Globals that were declared using /*global ... */ syntax. |
|
3031 exported, // Variables that are used outside of the current file. |
|
3032 |
|
3033 functionicity = [ |
|
3034 "closure", "exception", "global", "label", |
|
3035 "outer", "unused", "var" |
|
3036 ], |
|
3037 |
|
3038 funct, // The current function |
|
3039 functions, // All of the functions |
|
3040 |
|
3041 global, // The global scope |
|
3042 implied, // Implied globals |
|
3043 inblock, |
|
3044 indent, |
|
3045 lookahead, |
|
3046 lex, |
|
3047 member, |
|
3048 membersOnly, |
|
3049 noreach, |
|
3050 predefined, // Global variables defined by option |
|
3051 |
|
3052 scope, // The current scope |
|
3053 stack, |
|
3054 unuseds, |
|
3055 urls, |
|
3056 warnings, |
|
3057 |
|
3058 extraModules = [], |
|
3059 emitter = new events.EventEmitter(); |
|
3060 |
|
3061 function checkOption(name, t) { |
|
3062 name = name.trim(); |
|
3063 |
|
3064 if (/^[+-]W\d{3}$/g.test(name)) { |
|
3065 return true; |
|
3066 } |
|
3067 |
|
3068 if (valOptions[name] === undefined && boolOptions[name] === undefined) { |
|
3069 if (t.type !== "jslint") { |
|
3070 error("E001", t, name); |
|
3071 return false; |
|
3072 } |
|
3073 } |
|
3074 |
|
3075 return true; |
|
3076 } |
|
3077 |
|
3078 function isString(obj) { |
|
3079 return Object.prototype.toString.call(obj) === "[object String]"; |
|
3080 } |
|
3081 |
|
3082 function isIdentifier(tkn, value) { |
|
3083 if (!tkn) |
|
3084 return false; |
|
3085 |
|
3086 if (!tkn.identifier || tkn.value !== value) |
|
3087 return false; |
|
3088 |
|
3089 return true; |
|
3090 } |
|
3091 |
|
3092 function isReserved(token) { |
|
3093 if (!token.reserved) { |
|
3094 return false; |
|
3095 } |
|
3096 |
|
3097 if (token.meta && token.meta.isFutureReservedWord) { |
|
3098 // ES3 FutureReservedWord in an ES5 environment. |
|
3099 if (state.option.inES5(true) && !token.meta.es5) { |
|
3100 return false; |
|
3101 } |
|
3102 |
|
3103 // Some ES5 FutureReservedWord identifiers are active only |
|
3104 // within a strict mode environment. |
|
3105 if (token.meta.strictOnly) { |
|
3106 if (!state.option.strict && !state.directive["use strict"]) { |
|
3107 return false; |
|
3108 } |
|
3109 } |
|
3110 |
|
3111 if (token.isProperty) { |
|
3112 return false; |
|
3113 } |
|
3114 } |
|
3115 |
|
3116 return true; |
|
3117 } |
|
3118 |
|
3119 function supplant(str, data) { |
|
3120 return str.replace(/\{([^{}]*)\}/g, function (a, b) { |
|
3121 var r = data[b]; |
|
3122 return typeof r === "string" || typeof r === "number" ? r : a; |
|
3123 }); |
|
3124 } |
|
3125 |
|
3126 function combine(t, o) { |
|
3127 var n; |
|
3128 for (n in o) { |
|
3129 if (_.has(o, n) && !_.has(JSHINT.blacklist, n)) { |
|
3130 t[n] = o[n]; |
|
3131 } |
|
3132 } |
|
3133 } |
|
3134 |
|
3135 function updatePredefined() { |
|
3136 Object.keys(JSHINT.blacklist).forEach(function (key) { |
|
3137 delete predefined[key]; |
|
3138 }); |
|
3139 } |
|
3140 |
|
3141 function assume() { |
|
3142 if (state.option.es5) { |
|
3143 warning("I003"); |
|
3144 } |
|
3145 if (state.option.couch) { |
|
3146 combine(predefined, vars.couch); |
|
3147 } |
|
3148 |
|
3149 if (state.option.rhino) { |
|
3150 combine(predefined, vars.rhino); |
|
3151 } |
|
3152 |
|
3153 if (state.option.phantom) { |
|
3154 combine(predefined, vars.phantom); |
|
3155 } |
|
3156 |
|
3157 if (state.option.prototypejs) { |
|
3158 combine(predefined, vars.prototypejs); |
|
3159 } |
|
3160 |
|
3161 if (state.option.node) { |
|
3162 combine(predefined, vars.node); |
|
3163 } |
|
3164 |
|
3165 if (state.option.devel) { |
|
3166 combine(predefined, vars.devel); |
|
3167 } |
|
3168 |
|
3169 if (state.option.dojo) { |
|
3170 combine(predefined, vars.dojo); |
|
3171 } |
|
3172 |
|
3173 if (state.option.browser) { |
|
3174 combine(predefined, vars.browser); |
|
3175 } |
|
3176 |
|
3177 if (state.option.nonstandard) { |
|
3178 combine(predefined, vars.nonstandard); |
|
3179 } |
|
3180 |
|
3181 if (state.option.jquery) { |
|
3182 combine(predefined, vars.jquery); |
|
3183 } |
|
3184 |
|
3185 if (state.option.mootools) { |
|
3186 combine(predefined, vars.mootools); |
|
3187 } |
|
3188 |
|
3189 if (state.option.worker) { |
|
3190 combine(predefined, vars.worker); |
|
3191 } |
|
3192 |
|
3193 if (state.option.wsh) { |
|
3194 combine(predefined, vars.wsh); |
|
3195 } |
|
3196 |
|
3197 if (state.option.globalstrict && state.option.strict !== false) { |
|
3198 state.option.strict = true; |
|
3199 } |
|
3200 |
|
3201 if (state.option.yui) { |
|
3202 combine(predefined, vars.yui); |
|
3203 } |
|
3204 |
|
3205 // Let's assume that chronologically ES3 < ES5 < ES6/ESNext < Moz |
|
3206 |
|
3207 state.option.inMoz = function (strict) { |
|
3208 if (strict) { |
|
3209 return state.option.moz && !state.option.esnext; |
|
3210 } |
|
3211 return state.option.moz; |
|
3212 }; |
|
3213 |
|
3214 state.option.inESNext = function (strict) { |
|
3215 if (strict) { |
|
3216 return !state.option.moz && state.option.esnext; |
|
3217 } |
|
3218 return state.option.moz || state.option.esnext; |
|
3219 }; |
|
3220 |
|
3221 state.option.inES5 = function (/* strict */) { |
|
3222 return !state.option.es3; |
|
3223 }; |
|
3224 |
|
3225 state.option.inES3 = function (strict) { |
|
3226 if (strict) { |
|
3227 return !state.option.moz && !state.option.esnext && state.option.es3; |
|
3228 } |
|
3229 return state.option.es3; |
|
3230 }; |
|
3231 } |
|
3232 |
|
3233 // Produce an error warning. |
|
3234 function quit(code, line, chr) { |
|
3235 var percentage = Math.floor((line / state.lines.length) * 100); |
|
3236 var message = messages.errors[code].desc; |
|
3237 |
|
3238 throw { |
|
3239 name: "JSHintError", |
|
3240 line: line, |
|
3241 character: chr, |
|
3242 message: message + " (" + percentage + "% scanned).", |
|
3243 raw: message |
|
3244 }; |
|
3245 } |
|
3246 |
|
3247 function isundef(scope, code, token, a) { |
|
3248 return JSHINT.undefs.push([scope, code, token, a]); |
|
3249 } |
|
3250 |
|
3251 function warning(code, t, a, b, c, d) { |
|
3252 var ch, l, w, msg; |
|
3253 |
|
3254 if (/^W\d{3}$/.test(code)) { |
|
3255 if (state.ignored[code]) |
|
3256 return; |
|
3257 |
|
3258 msg = messages.warnings[code]; |
|
3259 } else if (/E\d{3}/.test(code)) { |
|
3260 msg = messages.errors[code]; |
|
3261 } else if (/I\d{3}/.test(code)) { |
|
3262 msg = messages.info[code]; |
|
3263 } |
|
3264 |
|
3265 t = t || state.tokens.next; |
|
3266 if (t.id === "(end)") { // `~ |
|
3267 t = state.tokens.curr; |
|
3268 } |
|
3269 |
|
3270 l = t.line || 0; |
|
3271 ch = t.from || 0; |
|
3272 |
|
3273 w = { |
|
3274 id: "(error)", |
|
3275 raw: msg.desc, |
|
3276 code: msg.code, |
|
3277 evidence: state.lines[l - 1] || "", |
|
3278 line: l, |
|
3279 character: ch, |
|
3280 scope: JSHINT.scope, |
|
3281 a: a, |
|
3282 b: b, |
|
3283 c: c, |
|
3284 d: d |
|
3285 }; |
|
3286 |
|
3287 w.reason = supplant(msg.desc, w); |
|
3288 JSHINT.errors.push(w); |
|
3289 |
|
3290 if (state.option.passfail) { |
|
3291 quit("E042", l, ch); |
|
3292 } |
|
3293 |
|
3294 warnings += 1; |
|
3295 if (warnings >= state.option.maxerr) { |
|
3296 quit("E043", l, ch); |
|
3297 } |
|
3298 |
|
3299 return w; |
|
3300 } |
|
3301 |
|
3302 function warningAt(m, l, ch, a, b, c, d) { |
|
3303 return warning(m, { |
|
3304 line: l, |
|
3305 from: ch |
|
3306 }, a, b, c, d); |
|
3307 } |
|
3308 |
|
3309 function error(m, t, a, b, c, d) { |
|
3310 warning(m, t, a, b, c, d); |
|
3311 } |
|
3312 |
|
3313 function errorAt(m, l, ch, a, b, c, d) { |
|
3314 return error(m, { |
|
3315 line: l, |
|
3316 from: ch |
|
3317 }, a, b, c, d); |
|
3318 } |
|
3319 |
|
3320 // Tracking of "internal" scripts, like eval containing a static string |
|
3321 function addInternalSrc(elem, src) { |
|
3322 var i; |
|
3323 i = { |
|
3324 id: "(internal)", |
|
3325 elem: elem, |
|
3326 value: src |
|
3327 }; |
|
3328 JSHINT.internals.push(i); |
|
3329 return i; |
|
3330 } |
|
3331 |
|
3332 function addlabel(t, type, tkn, islet) { |
|
3333 // Define t in the current function in the current scope. |
|
3334 if (type === "exception") { |
|
3335 if (_.has(funct["(context)"], t)) { |
|
3336 if (funct[t] !== true && !state.option.node) { |
|
3337 warning("W002", state.tokens.next, t); |
|
3338 } |
|
3339 } |
|
3340 } |
|
3341 |
|
3342 if (_.has(funct, t) && !funct["(global)"]) { |
|
3343 if (funct[t] === true) { |
|
3344 if (state.option.latedef) { |
|
3345 if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || |
|
3346 !_.contains([funct[t], type], "unction")) { |
|
3347 warning("W003", state.tokens.next, t); |
|
3348 } |
|
3349 } |
|
3350 } else { |
|
3351 if (!state.option.shadow && type !== "exception" || |
|
3352 (funct["(blockscope)"].getlabel(t))) { |
|
3353 warning("W004", state.tokens.next, t); |
|
3354 } |
|
3355 } |
|
3356 } |
|
3357 |
|
3358 // a double definition of a let variable in same block throws a TypeError |
|
3359 //if (funct["(blockscope)"] && funct["(blockscope)"].current.has(t)) { |
|
3360 // error("E044", state.tokens.next, t); |
|
3361 //} |
|
3362 |
|
3363 // if the identifier is from a let, adds it only to the current blockscope |
|
3364 if (islet) { |
|
3365 funct["(blockscope)"].current.add(t, type, state.tokens.curr); |
|
3366 } else { |
|
3367 |
|
3368 funct[t] = type; |
|
3369 |
|
3370 if (tkn) { |
|
3371 funct["(tokens)"][t] = tkn; |
|
3372 } |
|
3373 |
|
3374 if (funct["(global)"]) { |
|
3375 global[t] = funct; |
|
3376 if (_.has(implied, t)) { |
|
3377 if (state.option.latedef) { |
|
3378 if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || |
|
3379 !_.contains([funct[t], type], "unction")) { |
|
3380 warning("W003", state.tokens.next, t); |
|
3381 } |
|
3382 } |
|
3383 |
|
3384 delete implied[t]; |
|
3385 } |
|
3386 } else { |
|
3387 scope[t] = funct; |
|
3388 } |
|
3389 } |
|
3390 } |
|
3391 |
|
3392 function doOption() { |
|
3393 var nt = state.tokens.next; |
|
3394 var body = nt.body.split(",").map(function (s) { return s.trim(); }); |
|
3395 var predef = {}; |
|
3396 |
|
3397 if (nt.type === "globals") { |
|
3398 body.forEach(function (g) { |
|
3399 g = g.split(":"); |
|
3400 var key = g[0]; |
|
3401 var val = g[1]; |
|
3402 |
|
3403 if (key.charAt(0) === "-") { |
|
3404 key = key.slice(1); |
|
3405 val = false; |
|
3406 |
|
3407 JSHINT.blacklist[key] = key; |
|
3408 updatePredefined(); |
|
3409 } else { |
|
3410 predef[key] = (val === "true"); |
|
3411 } |
|
3412 }); |
|
3413 |
|
3414 combine(predefined, predef); |
|
3415 |
|
3416 for (var key in predef) { |
|
3417 if (_.has(predef, key)) { |
|
3418 declared[key] = nt; |
|
3419 } |
|
3420 } |
|
3421 } |
|
3422 |
|
3423 if (nt.type === "exported") { |
|
3424 body.forEach(function (e) { |
|
3425 exported[e] = true; |
|
3426 }); |
|
3427 } |
|
3428 |
|
3429 if (nt.type === "members") { |
|
3430 membersOnly = membersOnly || {}; |
|
3431 |
|
3432 body.forEach(function (m) { |
|
3433 var ch1 = m.charAt(0); |
|
3434 var ch2 = m.charAt(m.length - 1); |
|
3435 |
|
3436 if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { |
|
3437 m = m |
|
3438 .substr(1, m.length - 2) |
|
3439 .replace("\\b", "\b") |
|
3440 .replace("\\t", "\t") |
|
3441 .replace("\\n", "\n") |
|
3442 .replace("\\v", "\v") |
|
3443 .replace("\\f", "\f") |
|
3444 .replace("\\r", "\r") |
|
3445 .replace("\\\\", "\\") |
|
3446 .replace("\\\"", "\""); |
|
3447 } |
|
3448 |
|
3449 membersOnly[m] = false; |
|
3450 }); |
|
3451 } |
|
3452 |
|
3453 var numvals = [ |
|
3454 "maxstatements", |
|
3455 "maxparams", |
|
3456 "maxdepth", |
|
3457 "maxcomplexity", |
|
3458 "maxerr", |
|
3459 "maxlen", |
|
3460 "indent" |
|
3461 ]; |
|
3462 |
|
3463 if (nt.type === "jshint" || nt.type === "jslint") { |
|
3464 body.forEach(function (g) { |
|
3465 g = g.split(":"); |
|
3466 var key = (g[0] || "").trim(); |
|
3467 var val = (g[1] || "").trim(); |
|
3468 |
|
3469 if (!checkOption(key, nt)) { |
|
3470 return; |
|
3471 } |
|
3472 |
|
3473 if (numvals.indexOf(key) >= 0) { |
|
3474 |
|
3475 // GH988 - numeric options can be disabled by setting them to `false` |
|
3476 if (val !== "false") { |
|
3477 val = +val; |
|
3478 |
|
3479 if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) { |
|
3480 error("E032", nt, g[1].trim()); |
|
3481 return; |
|
3482 } |
|
3483 |
|
3484 if (key === "indent") { |
|
3485 state.option["(explicitIndent)"] = true; |
|
3486 } |
|
3487 state.option[key] = val; |
|
3488 } else { |
|
3489 if (key === "indent") { |
|
3490 state.option["(explicitIndent)"] = false; |
|
3491 } else { |
|
3492 state.option[key] = false; |
|
3493 } |
|
3494 } |
|
3495 |
|
3496 return; |
|
3497 } |
|
3498 |
|
3499 if (key === "validthis") { |
|
3500 // `validthis` is valid only within a function scope. |
|
3501 if (funct["(global)"]) { |
|
3502 error("E009"); |
|
3503 } else { |
|
3504 if (val === "true" || val === "false") { |
|
3505 state.option.validthis = (val === "true"); |
|
3506 } else { |
|
3507 error("E002", nt); |
|
3508 } |
|
3509 } |
|
3510 return; |
|
3511 } |
|
3512 |
|
3513 if (key === "quotmark") { |
|
3514 switch (val) { |
|
3515 case "true": |
|
3516 case "false": |
|
3517 state.option.quotmark = (val === "true"); |
|
3518 break; |
|
3519 case "double": |
|
3520 case "single": |
|
3521 state.option.quotmark = val; |
|
3522 break; |
|
3523 default: |
|
3524 error("E002", nt); |
|
3525 } |
|
3526 return; |
|
3527 } |
|
3528 |
|
3529 if (key === "unused") { |
|
3530 switch (val) { |
|
3531 case "true": |
|
3532 state.option.unused = true; |
|
3533 break; |
|
3534 case "false": |
|
3535 state.option.unused = false; |
|
3536 break; |
|
3537 case "vars": |
|
3538 case "strict": |
|
3539 state.option.unused = val; |
|
3540 break; |
|
3541 default: |
|
3542 error("E002", nt); |
|
3543 } |
|
3544 return; |
|
3545 } |
|
3546 |
|
3547 if (key === "latedef") { |
|
3548 switch (val) { |
|
3549 case "true": |
|
3550 state.option.latedef = true; |
|
3551 break; |
|
3552 case "false": |
|
3553 state.option.latedef = false; |
|
3554 break; |
|
3555 case "nofunc": |
|
3556 state.option.latedef = "nofunc"; |
|
3557 break; |
|
3558 default: |
|
3559 error("E002", nt); |
|
3560 } |
|
3561 return; |
|
3562 } |
|
3563 |
|
3564 var match = /^([+-])(W\d{3})$/g.exec(key); |
|
3565 if (match) { |
|
3566 // ignore for -W..., unignore for +W... |
|
3567 state.ignored[match[2]] = (match[1] === "-"); |
|
3568 return; |
|
3569 } |
|
3570 |
|
3571 var tn; |
|
3572 if (val === "true" || val === "false") { |
|
3573 if (nt.type === "jslint") { |
|
3574 tn = renamedOptions[key] || key; |
|
3575 state.option[tn] = (val === "true"); |
|
3576 |
|
3577 if (invertedOptions[tn] !== undefined) { |
|
3578 state.option[tn] = !state.option[tn]; |
|
3579 } |
|
3580 } else { |
|
3581 state.option[key] = (val === "true"); |
|
3582 } |
|
3583 |
|
3584 if (key === "newcap") { |
|
3585 state.option["(explicitNewcap)"] = true; |
|
3586 } |
|
3587 return; |
|
3588 } |
|
3589 |
|
3590 error("E002", nt); |
|
3591 }); |
|
3592 |
|
3593 assume(); |
|
3594 } |
|
3595 } |
|
3596 |
|
3597 // We need a peek function. If it has an argument, it peeks that much farther |
|
3598 // ahead. It is used to distinguish |
|
3599 // for ( var i in ... |
|
3600 // from |
|
3601 // for ( var i = ... |
|
3602 |
|
3603 function peek(p) { |
|
3604 var i = p || 0, j = 0, t; |
|
3605 |
|
3606 while (j <= i) { |
|
3607 t = lookahead[j]; |
|
3608 if (!t) { |
|
3609 t = lookahead[j] = lex.token(); |
|
3610 } |
|
3611 j += 1; |
|
3612 } |
|
3613 return t; |
|
3614 } |
|
3615 |
|
3616 // Produce the next token. It looks for programming errors. |
|
3617 |
|
3618 function advance(id, t) { |
|
3619 switch (state.tokens.curr.id) { |
|
3620 case "(number)": |
|
3621 if (state.tokens.next.id === ".") { |
|
3622 warning("W005", state.tokens.curr); |
|
3623 } |
|
3624 break; |
|
3625 case "-": |
|
3626 if (state.tokens.next.id === "-" || state.tokens.next.id === "--") { |
|
3627 warning("W006"); |
|
3628 } |
|
3629 break; |
|
3630 case "+": |
|
3631 if (state.tokens.next.id === "+" || state.tokens.next.id === "++") { |
|
3632 warning("W007"); |
|
3633 } |
|
3634 break; |
|
3635 } |
|
3636 |
|
3637 if (state.tokens.curr.type === "(string)" || state.tokens.curr.identifier) { |
|
3638 anonname = state.tokens.curr.value; |
|
3639 } |
|
3640 |
|
3641 if (id && state.tokens.next.id !== id) { |
|
3642 if (t) { |
|
3643 if (state.tokens.next.id === "(end)") { |
|
3644 error("E019", t, t.id); |
|
3645 } else { |
|
3646 error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); |
|
3647 } |
|
3648 } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { |
|
3649 warning("W116", state.tokens.next, id, state.tokens.next.value); |
|
3650 } |
|
3651 } |
|
3652 |
|
3653 state.tokens.prev = state.tokens.curr; |
|
3654 state.tokens.curr = state.tokens.next; |
|
3655 for (;;) { |
|
3656 state.tokens.next = lookahead.shift() || lex.token(); |
|
3657 |
|
3658 if (!state.tokens.next) { // No more tokens left, give up |
|
3659 quit("E041", state.tokens.curr.line); |
|
3660 } |
|
3661 |
|
3662 if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { |
|
3663 return; |
|
3664 } |
|
3665 |
|
3666 if (state.tokens.next.check) { |
|
3667 state.tokens.next.check(); |
|
3668 } |
|
3669 |
|
3670 if (state.tokens.next.isSpecial) { |
|
3671 doOption(); |
|
3672 } else { |
|
3673 if (state.tokens.next.id !== "(endline)") { |
|
3674 break; |
|
3675 } |
|
3676 } |
|
3677 } |
|
3678 } |
|
3679 |
|
3680 // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it |
|
3681 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is |
|
3682 // like .nud except that it is only used on the first token of a statement. |
|
3683 // Having .fud makes it much easier to define statement-oriented languages like |
|
3684 // JavaScript. I retained Pratt's nomenclature. |
|
3685 |
|
3686 // .nud Null denotation |
|
3687 // .fud First null denotation |
|
3688 // .led Left denotation |
|
3689 // lbp Left binding power |
|
3690 // rbp Right binding power |
|
3691 |
|
3692 // They are elements of the parsing method called Top Down Operator Precedence. |
|
3693 |
|
3694 function expression(rbp, initial) { |
|
3695 var left, isArray = false, isObject = false, isLetExpr = false; |
|
3696 |
|
3697 // if current expression is a let expression |
|
3698 if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { |
|
3699 if (!state.option.inMoz(true)) { |
|
3700 warning("W118", state.tokens.next, "let expressions"); |
|
3701 } |
|
3702 isLetExpr = true; |
|
3703 // create a new block scope we use only for the current expression |
|
3704 funct["(blockscope)"].stack(); |
|
3705 advance("let"); |
|
3706 advance("("); |
|
3707 state.syntax["let"].fud.call(state.syntax["let"].fud, false); |
|
3708 advance(")"); |
|
3709 } |
|
3710 |
|
3711 if (state.tokens.next.id === "(end)") |
|
3712 error("E006", state.tokens.curr); |
|
3713 |
|
3714 advance(); |
|
3715 |
|
3716 if (initial) { |
|
3717 anonname = "anonymous"; |
|
3718 funct["(verb)"] = state.tokens.curr.value; |
|
3719 } |
|
3720 |
|
3721 if (initial === true && state.tokens.curr.fud) { |
|
3722 left = state.tokens.curr.fud(); |
|
3723 } else { |
|
3724 if (state.tokens.curr.nud) { |
|
3725 left = state.tokens.curr.nud(); |
|
3726 } else { |
|
3727 error("E030", state.tokens.curr, state.tokens.curr.id); |
|
3728 } |
|
3729 |
|
3730 var end_of_expr = state.tokens.next.identifier && |
|
3731 !state.tokens.curr.led && |
|
3732 state.tokens.curr.line !== state.tokens.next.line; |
|
3733 while (rbp < state.tokens.next.lbp && !end_of_expr) { |
|
3734 isArray = state.tokens.curr.value === "Array"; |
|
3735 isObject = state.tokens.curr.value === "Object"; |
|
3736 |
|
3737 // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() |
|
3738 // Line breaks in IfStatement heads exist to satisfy the checkJSHint |
|
3739 // "Line too long." error. |
|
3740 if (left && (left.value || (left.first && left.first.value))) { |
|
3741 // If the left.value is not "new", or the left.first.value is a "." |
|
3742 // then safely assume that this is not "new Array()" and possibly |
|
3743 // not "new Object()"... |
|
3744 if (left.value !== "new" || |
|
3745 (left.first && left.first.value && left.first.value === ".")) { |
|
3746 isArray = false; |
|
3747 // ...In the case of Object, if the left.value and state.tokens.curr.value |
|
3748 // are not equal, then safely assume that this not "new Object()" |
|
3749 if (left.value !== state.tokens.curr.value) { |
|
3750 isObject = false; |
|
3751 } |
|
3752 } |
|
3753 } |
|
3754 |
|
3755 advance(); |
|
3756 |
|
3757 if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { |
|
3758 warning("W009", state.tokens.curr); |
|
3759 } |
|
3760 |
|
3761 if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { |
|
3762 warning("W010", state.tokens.curr); |
|
3763 } |
|
3764 |
|
3765 if (left && state.tokens.curr.led) { |
|
3766 left = state.tokens.curr.led(left); |
|
3767 } else { |
|
3768 error("E033", state.tokens.curr, state.tokens.curr.id); |
|
3769 } |
|
3770 } |
|
3771 } |
|
3772 if (isLetExpr) { |
|
3773 funct["(blockscope)"].unstack(); |
|
3774 } |
|
3775 return left; |
|
3776 } |
|
3777 |
|
3778 |
|
3779 // Functions for conformance of style. |
|
3780 |
|
3781 function adjacent(left, right) { |
|
3782 left = left || state.tokens.curr; |
|
3783 right = right || state.tokens.next; |
|
3784 if (state.option.white) { |
|
3785 if (left.character !== right.from && left.line === right.line) { |
|
3786 left.from += (left.character - left.from); |
|
3787 warning("W011", left, left.value); |
|
3788 } |
|
3789 } |
|
3790 } |
|
3791 |
|
3792 function nobreak(left, right) { |
|
3793 left = left || state.tokens.curr; |
|
3794 right = right || state.tokens.next; |
|
3795 if (state.option.white && (left.character !== right.from || left.line !== right.line)) { |
|
3796 warning("W012", right, right.value); |
|
3797 } |
|
3798 } |
|
3799 |
|
3800 function nospace(left, right) { |
|
3801 left = left || state.tokens.curr; |
|
3802 right = right || state.tokens.next; |
|
3803 if (state.option.white && !left.comment) { |
|
3804 if (left.line === right.line) { |
|
3805 adjacent(left, right); |
|
3806 } |
|
3807 } |
|
3808 } |
|
3809 |
|
3810 function nonadjacent(left, right) { |
|
3811 if (state.option.white) { |
|
3812 left = left || state.tokens.curr; |
|
3813 right = right || state.tokens.next; |
|
3814 |
|
3815 if (left.value === ";" && right.value === ";") { |
|
3816 return; |
|
3817 } |
|
3818 |
|
3819 if (left.line === right.line && left.character === right.from) { |
|
3820 left.from += (left.character - left.from); |
|
3821 warning("W013", left, left.value); |
|
3822 } |
|
3823 } |
|
3824 } |
|
3825 |
|
3826 function nobreaknonadjacent(left, right) { |
|
3827 left = left || state.tokens.curr; |
|
3828 right = right || state.tokens.next; |
|
3829 if (!state.option.laxbreak && left.line !== right.line) { |
|
3830 warning("W014", right, right.id); |
|
3831 } else if (state.option.white) { |
|
3832 left = left || state.tokens.curr; |
|
3833 right = right || state.tokens.next; |
|
3834 if (left.character === right.from) { |
|
3835 left.from += (left.character - left.from); |
|
3836 warning("W013", left, left.value); |
|
3837 } |
|
3838 } |
|
3839 } |
|
3840 |
|
3841 function indentation(bias) { |
|
3842 if (!state.option.white && !state.option["(explicitIndent)"]) { |
|
3843 return; |
|
3844 } |
|
3845 |
|
3846 if (state.tokens.next.id === "(end)") { |
|
3847 return; |
|
3848 } |
|
3849 |
|
3850 var i = indent + (bias || 0); |
|
3851 if (state.tokens.next.from !== i) { |
|
3852 warning("W015", state.tokens.next, state.tokens.next.value, i, state.tokens.next.from); |
|
3853 } |
|
3854 } |
|
3855 |
|
3856 function nolinebreak(t) { |
|
3857 t = t || state.tokens.curr; |
|
3858 if (t.line !== state.tokens.next.line) { |
|
3859 warning("E022", t, t.value); |
|
3860 } |
|
3861 } |
|
3862 |
|
3863 |
|
3864 function comma(opts) { |
|
3865 opts = opts || {}; |
|
3866 |
|
3867 if (!opts.peek) { |
|
3868 if (state.tokens.curr.line !== state.tokens.next.line) { |
|
3869 if (!state.option.laxcomma) { |
|
3870 if (comma.first) { |
|
3871 warning("I001"); |
|
3872 comma.first = false; |
|
3873 } |
|
3874 warning("W014", state.tokens.curr, state.tokens.next.value); |
|
3875 } |
|
3876 } else if (!state.tokens.curr.comment && |
|
3877 state.tokens.curr.character !== state.tokens.next.from && state.option.white) { |
|
3878 state.tokens.curr.from += (state.tokens.curr.character - state.tokens.curr.from); |
|
3879 warning("W011", state.tokens.curr, state.tokens.curr.value); |
|
3880 } |
|
3881 |
|
3882 advance(","); |
|
3883 } |
|
3884 |
|
3885 // TODO: This is a temporary solution to fight against false-positives in |
|
3886 // arrays and objects with trailing commas (see GH-363). The best solution |
|
3887 // would be to extract all whitespace rules out of parser. |
|
3888 |
|
3889 if (state.tokens.next.value !== "]" && state.tokens.next.value !== "}") { |
|
3890 nonadjacent(state.tokens.curr, state.tokens.next); |
|
3891 } |
|
3892 |
|
3893 if (state.tokens.next.identifier && !(opts.property && state.option.inES5())) { |
|
3894 // Keywords that cannot follow a comma operator. |
|
3895 switch (state.tokens.next.value) { |
|
3896 case "break": |
|
3897 case "case": |
|
3898 case "catch": |
|
3899 case "continue": |
|
3900 case "default": |
|
3901 case "do": |
|
3902 case "else": |
|
3903 case "finally": |
|
3904 case "for": |
|
3905 case "if": |
|
3906 case "in": |
|
3907 case "instanceof": |
|
3908 case "return": |
|
3909 case "yield": |
|
3910 case "switch": |
|
3911 case "throw": |
|
3912 case "try": |
|
3913 case "var": |
|
3914 case "let": |
|
3915 case "while": |
|
3916 case "with": |
|
3917 error("E024", state.tokens.next, state.tokens.next.value); |
|
3918 return false; |
|
3919 } |
|
3920 } |
|
3921 |
|
3922 if (state.tokens.next.type === "(punctuator)") { |
|
3923 switch (state.tokens.next.value) { |
|
3924 case "}": |
|
3925 case "]": |
|
3926 case ",": |
|
3927 if (opts.allowTrailing) { |
|
3928 return true; |
|
3929 } |
|
3930 |
|
3931 /* falls through */ |
|
3932 case ")": |
|
3933 error("E024", state.tokens.next, state.tokens.next.value); |
|
3934 return false; |
|
3935 } |
|
3936 } |
|
3937 return true; |
|
3938 } |
|
3939 |
|
3940 // Functional constructors for making the symbols that will be inherited by |
|
3941 // tokens. |
|
3942 |
|
3943 function symbol(s, p) { |
|
3944 var x = state.syntax[s]; |
|
3945 if (!x || typeof x !== "object") { |
|
3946 state.syntax[s] = x = { |
|
3947 id: s, |
|
3948 lbp: p, |
|
3949 value: s |
|
3950 }; |
|
3951 } |
|
3952 return x; |
|
3953 } |
|
3954 |
|
3955 function delim(s) { |
|
3956 return symbol(s, 0); |
|
3957 } |
|
3958 |
|
3959 function stmt(s, f) { |
|
3960 var x = delim(s); |
|
3961 x.identifier = x.reserved = true; |
|
3962 x.fud = f; |
|
3963 return x; |
|
3964 } |
|
3965 |
|
3966 function blockstmt(s, f) { |
|
3967 var x = stmt(s, f); |
|
3968 x.block = true; |
|
3969 return x; |
|
3970 } |
|
3971 |
|
3972 function reserveName(x) { |
|
3973 var c = x.id.charAt(0); |
|
3974 if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { |
|
3975 x.identifier = x.reserved = true; |
|
3976 } |
|
3977 return x; |
|
3978 } |
|
3979 |
|
3980 function prefix(s, f) { |
|
3981 var x = symbol(s, 150); |
|
3982 reserveName(x); |
|
3983 x.nud = (typeof f === "function") ? f : function () { |
|
3984 this.right = expression(150); |
|
3985 this.arity = "unary"; |
|
3986 if (this.id === "++" || this.id === "--") { |
|
3987 if (state.option.plusplus) { |
|
3988 warning("W016", this, this.id); |
|
3989 } else if ((!this.right.identifier || isReserved(this.right)) && |
|
3990 this.right.id !== "." && this.right.id !== "[") { |
|
3991 warning("W017", this); |
|
3992 } |
|
3993 } |
|
3994 return this; |
|
3995 }; |
|
3996 return x; |
|
3997 } |
|
3998 |
|
3999 function type(s, f) { |
|
4000 var x = delim(s); |
|
4001 x.type = s; |
|
4002 x.nud = f; |
|
4003 return x; |
|
4004 } |
|
4005 |
|
4006 function reserve(name, func) { |
|
4007 var x = type(name, func); |
|
4008 x.identifier = true; |
|
4009 x.reserved = true; |
|
4010 return x; |
|
4011 } |
|
4012 |
|
4013 function FutureReservedWord(name, meta) { |
|
4014 var x = type(name, (meta && meta.nud) || function () { |
|
4015 return this; |
|
4016 }); |
|
4017 |
|
4018 meta = meta || {}; |
|
4019 meta.isFutureReservedWord = true; |
|
4020 |
|
4021 x.value = name; |
|
4022 x.identifier = true; |
|
4023 x.reserved = true; |
|
4024 x.meta = meta; |
|
4025 |
|
4026 return x; |
|
4027 } |
|
4028 |
|
4029 function reservevar(s, v) { |
|
4030 return reserve(s, function () { |
|
4031 if (typeof v === "function") { |
|
4032 v(this); |
|
4033 } |
|
4034 return this; |
|
4035 }); |
|
4036 } |
|
4037 |
|
4038 function infix(s, f, p, w) { |
|
4039 var x = symbol(s, p); |
|
4040 reserveName(x); |
|
4041 x.led = function (left) { |
|
4042 if (!w) { |
|
4043 nobreaknonadjacent(state.tokens.prev, state.tokens.curr); |
|
4044 nonadjacent(state.tokens.curr, state.tokens.next); |
|
4045 } |
|
4046 if (s === "in" && left.id === "!") { |
|
4047 warning("W018", left, "!"); |
|
4048 } |
|
4049 if (typeof f === "function") { |
|
4050 return f(left, this); |
|
4051 } else { |
|
4052 this.left = left; |
|
4053 this.right = expression(p); |
|
4054 return this; |
|
4055 } |
|
4056 }; |
|
4057 return x; |
|
4058 } |
|
4059 |
|
4060 |
|
4061 function application(s) { |
|
4062 var x = symbol(s, 42); |
|
4063 |
|
4064 x.led = function (left) { |
|
4065 if (!state.option.inESNext()) { |
|
4066 warning("W104", state.tokens.curr, "arrow function syntax (=>)"); |
|
4067 } |
|
4068 |
|
4069 nobreaknonadjacent(state.tokens.prev, state.tokens.curr); |
|
4070 nonadjacent(state.tokens.curr, state.tokens.next); |
|
4071 |
|
4072 this.left = left; |
|
4073 this.right = doFunction(undefined, undefined, false, left); |
|
4074 return this; |
|
4075 }; |
|
4076 return x; |
|
4077 } |
|
4078 |
|
4079 function relation(s, f) { |
|
4080 var x = symbol(s, 100); |
|
4081 |
|
4082 x.led = function (left) { |
|
4083 nobreaknonadjacent(state.tokens.prev, state.tokens.curr); |
|
4084 nonadjacent(state.tokens.curr, state.tokens.next); |
|
4085 var right = expression(100); |
|
4086 |
|
4087 if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { |
|
4088 warning("W019", this); |
|
4089 } else if (f) { |
|
4090 f.apply(this, [left, right]); |
|
4091 } |
|
4092 |
|
4093 if (!left || !right) { |
|
4094 quit("E041", state.tokens.curr.line); |
|
4095 } |
|
4096 |
|
4097 if (left.id === "!") { |
|
4098 warning("W018", left, "!"); |
|
4099 } |
|
4100 |
|
4101 if (right.id === "!") { |
|
4102 warning("W018", right, "!"); |
|
4103 } |
|
4104 |
|
4105 this.left = left; |
|
4106 this.right = right; |
|
4107 return this; |
|
4108 }; |
|
4109 return x; |
|
4110 } |
|
4111 |
|
4112 function isPoorRelation(node) { |
|
4113 return node && |
|
4114 ((node.type === "(number)" && +node.value === 0) || |
|
4115 (node.type === "(string)" && node.value === "") || |
|
4116 (node.type === "null" && !state.option.eqnull) || |
|
4117 node.type === "true" || |
|
4118 node.type === "false" || |
|
4119 node.type === "undefined"); |
|
4120 } |
|
4121 |
|
4122 function assignop(s) { |
|
4123 symbol(s, 20).exps = true; |
|
4124 |
|
4125 return infix(s, function (left, that) { |
|
4126 that.left = left; |
|
4127 |
|
4128 if (left) { |
|
4129 if (predefined[left.value] === false && |
|
4130 scope[left.value]["(global)"] === true) { |
|
4131 warning("W020", left); |
|
4132 } else if (left["function"]) { |
|
4133 warning("W021", left, left.value); |
|
4134 } |
|
4135 |
|
4136 if (funct[left.value] === "const") { |
|
4137 error("E013", left, left.value); |
|
4138 } |
|
4139 |
|
4140 if (left.id === ".") { |
|
4141 if (!left.left) { |
|
4142 warning("E031", that); |
|
4143 } else if (left.left.value === "arguments" && !state.directive["use strict"]) { |
|
4144 warning("E031", that); |
|
4145 } |
|
4146 |
|
4147 that.right = expression(19); |
|
4148 return that; |
|
4149 } else if (left.id === "[") { |
|
4150 if (state.tokens.curr.left.first) { |
|
4151 state.tokens.curr.left.first.forEach(function (t) { |
|
4152 if (funct[t.value] === "const") { |
|
4153 error("E013", t, t.value); |
|
4154 } |
|
4155 }); |
|
4156 } else if (!left.left) { |
|
4157 warning("E031", that); |
|
4158 } else if (left.left.value === "arguments" && !state.directive["use strict"]) { |
|
4159 warning("E031", that); |
|
4160 } |
|
4161 that.right = expression(19); |
|
4162 return that; |
|
4163 } else if (left.identifier && !isReserved(left)) { |
|
4164 if (funct[left.value] === "exception") { |
|
4165 warning("W022", left); |
|
4166 } |
|
4167 that.right = expression(19); |
|
4168 return that; |
|
4169 } |
|
4170 |
|
4171 if (left === state.syntax["function"]) { |
|
4172 warning("W023", state.tokens.curr); |
|
4173 } |
|
4174 } |
|
4175 |
|
4176 error("E031", that); |
|
4177 }, 20); |
|
4178 } |
|
4179 |
|
4180 |
|
4181 function bitwise(s, f, p) { |
|
4182 var x = symbol(s, p); |
|
4183 reserveName(x); |
|
4184 x.led = (typeof f === "function") ? f : function (left) { |
|
4185 if (state.option.bitwise) { |
|
4186 warning("W016", this, this.id); |
|
4187 } |
|
4188 this.left = left; |
|
4189 this.right = expression(p); |
|
4190 return this; |
|
4191 }; |
|
4192 return x; |
|
4193 } |
|
4194 |
|
4195 |
|
4196 function bitwiseassignop(s) { |
|
4197 symbol(s, 20).exps = true; |
|
4198 return infix(s, function (left, that) { |
|
4199 if (state.option.bitwise) { |
|
4200 warning("W016", that, that.id); |
|
4201 } |
|
4202 nonadjacent(state.tokens.prev, state.tokens.curr); |
|
4203 nonadjacent(state.tokens.curr, state.tokens.next); |
|
4204 if (left) { |
|
4205 if (left.id === "." || left.id === "[" || |
|
4206 (left.identifier && !isReserved(left))) { |
|
4207 expression(19); |
|
4208 return that; |
|
4209 } |
|
4210 if (left === state.syntax["function"]) { |
|
4211 warning("W023", state.tokens.curr); |
|
4212 } |
|
4213 return that; |
|
4214 } |
|
4215 error("E031", that); |
|
4216 }, 20); |
|
4217 } |
|
4218 |
|
4219 |
|
4220 function suffix(s) { |
|
4221 var x = symbol(s, 150); |
|
4222 |
|
4223 x.led = function (left) { |
|
4224 if (state.option.plusplus) { |
|
4225 warning("W016", this, this.id); |
|
4226 } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") { |
|
4227 warning("W017", this); |
|
4228 } |
|
4229 |
|
4230 this.left = left; |
|
4231 return this; |
|
4232 }; |
|
4233 return x; |
|
4234 } |
|
4235 |
|
4236 // fnparam means that this identifier is being defined as a function |
|
4237 // argument (see identifier()) |
|
4238 // prop means that this identifier is that of an object property |
|
4239 |
|
4240 function optionalidentifier(fnparam, prop) { |
|
4241 if (!state.tokens.next.identifier) { |
|
4242 return; |
|
4243 } |
|
4244 |
|
4245 advance(); |
|
4246 |
|
4247 var curr = state.tokens.curr; |
|
4248 var meta = curr.meta || {}; |
|
4249 var val = state.tokens.curr.value; |
|
4250 |
|
4251 if (!isReserved(curr)) { |
|
4252 return val; |
|
4253 } |
|
4254 |
|
4255 if (prop) { |
|
4256 if (state.option.inES5() || meta.isFutureReservedWord) { |
|
4257 return val; |
|
4258 } |
|
4259 } |
|
4260 |
|
4261 if (fnparam && val === "undefined") { |
|
4262 return val; |
|
4263 } |
|
4264 |
|
4265 // Display an info message about reserved words as properties |
|
4266 // and ES5 but do it only once. |
|
4267 if (prop && !api.getCache("displayed:I002")) { |
|
4268 api.setCache("displayed:I002", true); |
|
4269 warning("I002"); |
|
4270 } |
|
4271 |
|
4272 warning("W024", state.tokens.curr, state.tokens.curr.id); |
|
4273 return val; |
|
4274 } |
|
4275 |
|
4276 // fnparam means that this identifier is being defined as a function |
|
4277 // argument |
|
4278 // prop means that this identifier is that of an object property |
|
4279 function identifier(fnparam, prop) { |
|
4280 var i = optionalidentifier(fnparam, prop); |
|
4281 if (i) { |
|
4282 return i; |
|
4283 } |
|
4284 if (state.tokens.curr.id === "function" && state.tokens.next.id === "(") { |
|
4285 warning("W025"); |
|
4286 } else { |
|
4287 error("E030", state.tokens.next, state.tokens.next.value); |
|
4288 } |
|
4289 } |
|
4290 |
|
4291 |
|
4292 function reachable(s) { |
|
4293 var i = 0, t; |
|
4294 if (state.tokens.next.id !== ";" || noreach) { |
|
4295 return; |
|
4296 } |
|
4297 for (;;) { |
|
4298 t = peek(i); |
|
4299 if (t.reach) { |
|
4300 return; |
|
4301 } |
|
4302 if (t.id !== "(endline)") { |
|
4303 if (t.id === "function") { |
|
4304 if (!state.option.latedef) { |
|
4305 break; |
|
4306 } |
|
4307 |
|
4308 warning("W026", t); |
|
4309 break; |
|
4310 } |
|
4311 |
|
4312 warning("W027", t, t.value, s); |
|
4313 break; |
|
4314 } |
|
4315 i += 1; |
|
4316 } |
|
4317 } |
|
4318 |
|
4319 |
|
4320 function statement(noindent) { |
|
4321 var values; |
|
4322 var i = indent, r, s = scope, t = state.tokens.next; |
|
4323 |
|
4324 if (t.id === ";") { |
|
4325 advance(";"); |
|
4326 return; |
|
4327 } |
|
4328 |
|
4329 // Is this a labelled statement? |
|
4330 var res = isReserved(t); |
|
4331 |
|
4332 // We're being more tolerant here: if someone uses |
|
4333 // a FutureReservedWord as a label, we warn but proceed |
|
4334 // anyway. |
|
4335 |
|
4336 if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") { |
|
4337 warning("W024", t, t.id); |
|
4338 res = false; |
|
4339 } |
|
4340 |
|
4341 // detect a destructuring assignment |
|
4342 if (_.has(["[", "{"], t.value)) { |
|
4343 if (lookupBlockType().isDestAssign) { |
|
4344 if (!state.option.inESNext()) { |
|
4345 warning("W104", state.tokens.curr, "destructuring expression"); |
|
4346 } |
|
4347 values = destructuringExpression(); |
|
4348 values.forEach(function (tok) { |
|
4349 isundef(funct, "W117", tok.token, tok.id); |
|
4350 }); |
|
4351 advance("="); |
|
4352 destructuringExpressionMatch(values, expression(5, true)); |
|
4353 advance(";"); |
|
4354 return; |
|
4355 } |
|
4356 } |
|
4357 if (t.identifier && !res && peek().id === ":") { |
|
4358 advance(); |
|
4359 advance(":"); |
|
4360 scope = Object.create(s); |
|
4361 addlabel(t.value, "label"); |
|
4362 |
|
4363 if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { |
|
4364 warning("W028", state.tokens.next, t.value, state.tokens.next.value); |
|
4365 } |
|
4366 |
|
4367 state.tokens.next.label = t.value; |
|
4368 t = state.tokens.next; |
|
4369 } |
|
4370 |
|
4371 // Is it a lonely block? |
|
4372 |
|
4373 if (t.id === "{") { |
|
4374 // Is it a switch case block? |
|
4375 // |
|
4376 // switch (foo) { |
|
4377 // case bar: { <= here. |
|
4378 // ... |
|
4379 // } |
|
4380 // } |
|
4381 var iscase = (funct["(verb)"] === "case" && state.tokens.curr.value === ":"); |
|
4382 block(true, true, false, false, iscase); |
|
4383 return; |
|
4384 } |
|
4385 |
|
4386 // Parse the statement. |
|
4387 |
|
4388 if (!noindent) { |
|
4389 indentation(); |
|
4390 } |
|
4391 r = expression(0, true); |
|
4392 |
|
4393 // Look for the final semicolon. |
|
4394 |
|
4395 if (!t.block) { |
|
4396 if (!state.option.expr && (!r || !r.exps)) { |
|
4397 warning("W030", state.tokens.curr); |
|
4398 } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { |
|
4399 warning("W031", t); |
|
4400 } |
|
4401 |
|
4402 if (state.tokens.next.id !== ";") { |
|
4403 if (!state.option.asi) { |
|
4404 // If this is the last statement in a block that ends on |
|
4405 // the same line *and* option lastsemic is on, ignore the warning. |
|
4406 // Otherwise, complain about missing semicolon. |
|
4407 if (!state.option.lastsemic || state.tokens.next.id !== "}" || |
|
4408 state.tokens.next.line !== state.tokens.curr.line) { |
|
4409 warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); |
|
4410 } |
|
4411 } |
|
4412 } else { |
|
4413 adjacent(state.tokens.curr, state.tokens.next); |
|
4414 advance(";"); |
|
4415 nonadjacent(state.tokens.curr, state.tokens.next); |
|
4416 } |
|
4417 } |
|
4418 |
|
4419 // Restore the indentation. |
|
4420 |
|
4421 indent = i; |
|
4422 scope = s; |
|
4423 return r; |
|
4424 } |
|
4425 |
|
4426 |
|
4427 function statements(startLine) { |
|
4428 var a = [], p; |
|
4429 |
|
4430 while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { |
|
4431 if (state.tokens.next.id === ";") { |
|
4432 p = peek(); |
|
4433 |
|
4434 if (!p || (p.id !== "(" && p.id !== "[")) { |
|
4435 warning("W032"); |
|
4436 } |
|
4437 |
|
4438 advance(";"); |
|
4439 } else { |
|
4440 a.push(statement(startLine === state.tokens.next.line)); |
|
4441 } |
|
4442 } |
|
4443 return a; |
|
4444 } |
|
4445 |
|
4446 |
|
4447 /* |
|
4448 * read all directives |
|
4449 * recognizes a simple form of asi, but always |
|
4450 * warns, if it is used |
|
4451 */ |
|
4452 function directives() { |
|
4453 var i, p, pn; |
|
4454 |
|
4455 for (;;) { |
|
4456 if (state.tokens.next.id === "(string)") { |
|
4457 p = peek(0); |
|
4458 if (p.id === "(endline)") { |
|
4459 i = 1; |
|
4460 do { |
|
4461 pn = peek(i); |
|
4462 i = i + 1; |
|
4463 } while (pn.id === "(endline)"); |
|
4464 |
|
4465 if (pn.id !== ";") { |
|
4466 if (pn.id !== "(string)" && pn.id !== "(number)" && |
|
4467 pn.id !== "(regexp)" && pn.identifier !== true && |
|
4468 pn.id !== "}") { |
|
4469 break; |
|
4470 } |
|
4471 warning("W033", state.tokens.next); |
|
4472 } else { |
|
4473 p = pn; |
|
4474 } |
|
4475 } else if (p.id === "}") { |
|
4476 // Directive with no other statements, warn about missing semicolon |
|
4477 warning("W033", p); |
|
4478 } else if (p.id !== ";") { |
|
4479 break; |
|
4480 } |
|
4481 |
|
4482 indentation(); |
|
4483 advance(); |
|
4484 if (state.directive[state.tokens.curr.value]) { |
|
4485 warning("W034", state.tokens.curr, state.tokens.curr.value); |
|
4486 } |
|
4487 |
|
4488 if (state.tokens.curr.value === "use strict") { |
|
4489 if (!state.option["(explicitNewcap)"]) |
|
4490 state.option.newcap = true; |
|
4491 state.option.undef = true; |
|
4492 } |
|
4493 |
|
4494 // there's no directive negation, so always set to true |
|
4495 state.directive[state.tokens.curr.value] = true; |
|
4496 |
|
4497 if (p.id === ";") { |
|
4498 advance(";"); |
|
4499 } |
|
4500 continue; |
|
4501 } |
|
4502 break; |
|
4503 } |
|
4504 } |
|
4505 |
|
4506 |
|
4507 /* |
|
4508 * Parses a single block. A block is a sequence of statements wrapped in |
|
4509 * braces. |
|
4510 * |
|
4511 * ordinary - true for everything but function bodies and try blocks. |
|
4512 * stmt - true if block can be a single statement (e.g. in if/for/while). |
|
4513 * isfunc - true if block is a function body |
|
4514 * isfatarrow - |
|
4515 * iscase - true if block is a switch case block |
|
4516 */ |
|
4517 function block(ordinary, stmt, isfunc, isfatarrow, iscase) { |
|
4518 var a, |
|
4519 b = inblock, |
|
4520 old_indent = indent, |
|
4521 m, |
|
4522 s = scope, |
|
4523 t, |
|
4524 line, |
|
4525 d; |
|
4526 |
|
4527 inblock = ordinary; |
|
4528 |
|
4529 if (!ordinary || !state.option.funcscope) |
|
4530 scope = Object.create(scope); |
|
4531 |
|
4532 nonadjacent(state.tokens.curr, state.tokens.next); |
|
4533 t = state.tokens.next; |
|
4534 |
|
4535 var metrics = funct["(metrics)"]; |
|
4536 metrics.nestedBlockDepth += 1; |
|
4537 metrics.verifyMaxNestedBlockDepthPerFunction(); |
|
4538 |
|
4539 if (state.tokens.next.id === "{") { |
|
4540 advance("{"); |
|
4541 |
|
4542 // create a new block scope |
|
4543 funct["(blockscope)"].stack(); |
|
4544 |
|
4545 line = state.tokens.curr.line; |
|
4546 if (state.tokens.next.id !== "}") { |
|
4547 indent += state.option.indent; |
|
4548 while (!ordinary && state.tokens.next.from > indent) { |
|
4549 indent += state.option.indent; |
|
4550 } |
|
4551 |
|
4552 if (isfunc) { |
|
4553 m = {}; |
|
4554 for (d in state.directive) { |
|
4555 if (_.has(state.directive, d)) { |
|
4556 m[d] = state.directive[d]; |
|
4557 } |
|
4558 } |
|
4559 directives(); |
|
4560 |
|
4561 if (state.option.strict && funct["(context)"]["(global)"]) { |
|
4562 if (!m["use strict"] && !state.directive["use strict"]) { |
|
4563 warning("E007"); |
|
4564 } |
|
4565 } |
|
4566 } |
|
4567 |
|
4568 a = statements(line); |
|
4569 |
|
4570 metrics.statementCount += a.length; |
|
4571 |
|
4572 if (isfunc) { |
|
4573 state.directive = m; |
|
4574 } |
|
4575 |
|
4576 indent -= state.option.indent; |
|
4577 if (line !== state.tokens.next.line) { |
|
4578 indentation(); |
|
4579 } |
|
4580 } else if (line !== state.tokens.next.line) { |
|
4581 indentation(); |
|
4582 } |
|
4583 advance("}", t); |
|
4584 |
|
4585 funct["(blockscope)"].unstack(); |
|
4586 |
|
4587 indent = old_indent; |
|
4588 } else if (!ordinary) { |
|
4589 if (isfunc) { |
|
4590 m = {}; |
|
4591 if (stmt && !isfatarrow && !state.option.inMoz(true)) { |
|
4592 error("W118", state.tokens.curr, "function closure expressions"); |
|
4593 } |
|
4594 |
|
4595 if (!stmt) { |
|
4596 for (d in state.directive) { |
|
4597 if (_.has(state.directive, d)) { |
|
4598 m[d] = state.directive[d]; |
|
4599 } |
|
4600 } |
|
4601 } |
|
4602 expression(5); |
|
4603 |
|
4604 if (state.option.strict && funct["(context)"]["(global)"]) { |
|
4605 if (!m["use strict"] && !state.directive["use strict"]) { |
|
4606 warning("E007"); |
|
4607 } |
|
4608 } |
|
4609 } else { |
|
4610 error("E021", state.tokens.next, "{", state.tokens.next.value); |
|
4611 } |
|
4612 } else { |
|
4613 |
|
4614 // check to avoid let declaration not within a block |
|
4615 funct["(nolet)"] = true; |
|
4616 |
|
4617 if (!stmt || state.option.curly) { |
|
4618 warning("W116", state.tokens.next, "{", state.tokens.next.value); |
|
4619 } |
|
4620 |
|
4621 noreach = true; |
|
4622 indent += state.option.indent; |
|
4623 // test indentation only if statement is in new line |
|
4624 a = [statement(state.tokens.next.line === state.tokens.curr.line)]; |
|
4625 indent -= state.option.indent; |
|
4626 noreach = false; |
|
4627 |
|
4628 delete funct["(nolet)"]; |
|
4629 } |
|
4630 // If it is a "break" in switch case, don't clear and let it propagate out. |
|
4631 if (!(iscase && funct["(verb)"] === "break")) funct["(verb)"] = null; |
|
4632 |
|
4633 if (!ordinary || !state.option.funcscope) scope = s; |
|
4634 inblock = b; |
|
4635 if (ordinary && state.option.noempty && (!a || a.length === 0)) { |
|
4636 warning("W035"); |
|
4637 } |
|
4638 metrics.nestedBlockDepth -= 1; |
|
4639 return a; |
|
4640 } |
|
4641 |
|
4642 |
|
4643 function countMember(m) { |
|
4644 if (membersOnly && typeof membersOnly[m] !== "boolean") { |
|
4645 warning("W036", state.tokens.curr, m); |
|
4646 } |
|
4647 if (typeof member[m] === "number") { |
|
4648 member[m] += 1; |
|
4649 } else { |
|
4650 member[m] = 1; |
|
4651 } |
|
4652 } |
|
4653 |
|
4654 |
|
4655 function note_implied(tkn) { |
|
4656 var name = tkn.value, line = tkn.line, a = implied[name]; |
|
4657 if (typeof a === "function") { |
|
4658 a = false; |
|
4659 } |
|
4660 |
|
4661 if (!a) { |
|
4662 a = [line]; |
|
4663 implied[name] = a; |
|
4664 } else if (a[a.length - 1] !== line) { |
|
4665 a.push(line); |
|
4666 } |
|
4667 } |
|
4668 |
|
4669 |
|
4670 // Build the syntax table by declaring the syntactic elements of the language. |
|
4671 |
|
4672 type("(number)", function () { |
|
4673 return this; |
|
4674 }); |
|
4675 |
|
4676 type("(string)", function () { |
|
4677 return this; |
|
4678 }); |
|
4679 |
|
4680 state.syntax["(identifier)"] = { |
|
4681 type: "(identifier)", |
|
4682 lbp: 0, |
|
4683 identifier: true, |
|
4684 nud: function () { |
|
4685 var v = this.value, |
|
4686 s = scope[v], |
|
4687 f; |
|
4688 |
|
4689 if (typeof s === "function") { |
|
4690 // Protection against accidental inheritance. |
|
4691 s = undefined; |
|
4692 } else if (typeof s === "boolean") { |
|
4693 f = funct; |
|
4694 funct = functions[0]; |
|
4695 addlabel(v, "var"); |
|
4696 s = funct; |
|
4697 funct = f; |
|
4698 } |
|
4699 var block; |
|
4700 if (_.has(funct, "(blockscope)")) { |
|
4701 block = funct["(blockscope)"].getlabel(v); |
|
4702 } |
|
4703 |
|
4704 // The name is in scope and defined in the current function. |
|
4705 if (funct === s || block) { |
|
4706 // Change 'unused' to 'var', and reject labels. |
|
4707 // the name is in a block scope |
|
4708 switch (block ? block[v]["(type)"] : funct[v]) { |
|
4709 case "unused": |
|
4710 if (block) block[v]["(type)"] = "var"; |
|
4711 else funct[v] = "var"; |
|
4712 break; |
|
4713 case "unction": |
|
4714 if (block) block[v]["(type)"] = "function"; |
|
4715 else funct[v] = "function"; |
|
4716 this["function"] = true; |
|
4717 break; |
|
4718 case "function": |
|
4719 this["function"] = true; |
|
4720 break; |
|
4721 case "label": |
|
4722 warning("W037", state.tokens.curr, v); |
|
4723 break; |
|
4724 } |
|
4725 } else if (funct["(global)"]) { |
|
4726 // The name is not defined in the function. If we are in the global |
|
4727 // scope, then we have an undefined variable. |
|
4728 // |
|
4729 // Operators typeof and delete do not raise runtime errors even if |
|
4730 // the base object of a reference is null so no need to display warning |
|
4731 // if we're inside of typeof or delete. |
|
4732 |
|
4733 if (typeof predefined[v] !== "boolean") { |
|
4734 // Attempting to subscript a null reference will throw an |
|
4735 // error, even within the typeof and delete operators |
|
4736 if (!(anonname === "typeof" || anonname === "delete") || |
|
4737 (state.tokens.next && (state.tokens.next.value === "." || |
|
4738 state.tokens.next.value === "["))) { |
|
4739 |
|
4740 // if we're in a list comprehension, variables are declared |
|
4741 // locally and used before being defined. So we check |
|
4742 // the presence of the given variable in the comp array |
|
4743 // before declaring it undefined. |
|
4744 |
|
4745 if (!funct["(comparray)"].check(v)) { |
|
4746 isundef(funct, "W117", state.tokens.curr, v); |
|
4747 } |
|
4748 } |
|
4749 } |
|
4750 |
|
4751 note_implied(state.tokens.curr); |
|
4752 } else { |
|
4753 // If the name is already defined in the current |
|
4754 // function, but not as outer, then there is a scope error. |
|
4755 |
|
4756 switch (funct[v]) { |
|
4757 case "closure": |
|
4758 case "function": |
|
4759 case "var": |
|
4760 case "unused": |
|
4761 warning("W038", state.tokens.curr, v); |
|
4762 break; |
|
4763 case "label": |
|
4764 warning("W037", state.tokens.curr, v); |
|
4765 break; |
|
4766 case "outer": |
|
4767 case "global": |
|
4768 break; |
|
4769 default: |
|
4770 // If the name is defined in an outer function, make an outer entry, |
|
4771 // and if it was unused, make it var. |
|
4772 if (s === true) { |
|
4773 funct[v] = true; |
|
4774 } else if (s === null) { |
|
4775 warning("W039", state.tokens.curr, v); |
|
4776 note_implied(state.tokens.curr); |
|
4777 } else if (typeof s !== "object") { |
|
4778 // Operators typeof and delete do not raise runtime errors even |
|
4779 // if the base object of a reference is null so no need to |
|
4780 // |
|
4781 // display warning if we're inside of typeof or delete. |
|
4782 // Attempting to subscript a null reference will throw an |
|
4783 // error, even within the typeof and delete operators |
|
4784 if (!(anonname === "typeof" || anonname === "delete") || |
|
4785 (state.tokens.next && |
|
4786 (state.tokens.next.value === "." || state.tokens.next.value === "["))) { |
|
4787 |
|
4788 isundef(funct, "W117", state.tokens.curr, v); |
|
4789 } |
|
4790 funct[v] = true; |
|
4791 note_implied(state.tokens.curr); |
|
4792 } else { |
|
4793 switch (s[v]) { |
|
4794 case "function": |
|
4795 case "unction": |
|
4796 this["function"] = true; |
|
4797 s[v] = "closure"; |
|
4798 funct[v] = s["(global)"] ? "global" : "outer"; |
|
4799 break; |
|
4800 case "var": |
|
4801 case "unused": |
|
4802 s[v] = "closure"; |
|
4803 funct[v] = s["(global)"] ? "global" : "outer"; |
|
4804 break; |
|
4805 case "closure": |
|
4806 funct[v] = s["(global)"] ? "global" : "outer"; |
|
4807 break; |
|
4808 case "label": |
|
4809 warning("W037", state.tokens.curr, v); |
|
4810 } |
|
4811 } |
|
4812 } |
|
4813 } |
|
4814 return this; |
|
4815 }, |
|
4816 led: function () { |
|
4817 error("E033", state.tokens.next, state.tokens.next.value); |
|
4818 } |
|
4819 }; |
|
4820 |
|
4821 type("(regexp)", function () { |
|
4822 return this; |
|
4823 }); |
|
4824 |
|
4825 // ECMAScript parser |
|
4826 |
|
4827 delim("(endline)"); |
|
4828 delim("(begin)"); |
|
4829 delim("(end)").reach = true; |
|
4830 delim("(error)").reach = true; |
|
4831 delim("}").reach = true; |
|
4832 delim(")"); |
|
4833 delim("]"); |
|
4834 delim("\"").reach = true; |
|
4835 delim("'").reach = true; |
|
4836 delim(";"); |
|
4837 delim(":").reach = true; |
|
4838 delim("#"); |
|
4839 |
|
4840 reserve("else"); |
|
4841 reserve("case").reach = true; |
|
4842 reserve("catch"); |
|
4843 reserve("default").reach = true; |
|
4844 reserve("finally"); |
|
4845 reservevar("arguments", function (x) { |
|
4846 if (state.directive["use strict"] && funct["(global)"]) { |
|
4847 warning("E008", x); |
|
4848 } |
|
4849 }); |
|
4850 reservevar("eval"); |
|
4851 reservevar("false"); |
|
4852 reservevar("Infinity"); |
|
4853 reservevar("null"); |
|
4854 reservevar("this", function (x) { |
|
4855 if (state.directive["use strict"] && !state.option.validthis && ((funct["(statement)"] && |
|
4856 funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { |
|
4857 warning("W040", x); |
|
4858 } |
|
4859 }); |
|
4860 reservevar("true"); |
|
4861 reservevar("undefined"); |
|
4862 |
|
4863 assignop("=", "assign", 20); |
|
4864 assignop("+=", "assignadd", 20); |
|
4865 assignop("-=", "assignsub", 20); |
|
4866 assignop("*=", "assignmult", 20); |
|
4867 assignop("/=", "assigndiv", 20).nud = function () { |
|
4868 error("E014"); |
|
4869 }; |
|
4870 assignop("%=", "assignmod", 20); |
|
4871 |
|
4872 bitwiseassignop("&=", "assignbitand", 20); |
|
4873 bitwiseassignop("|=", "assignbitor", 20); |
|
4874 bitwiseassignop("^=", "assignbitxor", 20); |
|
4875 bitwiseassignop("<<=", "assignshiftleft", 20); |
|
4876 bitwiseassignop(">>=", "assignshiftright", 20); |
|
4877 bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); |
|
4878 infix(",", function (left, that) { |
|
4879 var expr; |
|
4880 that.exprs = [left]; |
|
4881 if (!comma({peek: true})) { |
|
4882 return that; |
|
4883 } |
|
4884 while (true) { |
|
4885 if (!(expr = expression(5))) { |
|
4886 break; |
|
4887 } |
|
4888 that.exprs.push(expr); |
|
4889 if (state.tokens.next.value !== "," || !comma()) { |
|
4890 break; |
|
4891 } |
|
4892 } |
|
4893 return that; |
|
4894 }, 5, true); |
|
4895 infix("?", function (left, that) { |
|
4896 that.left = left; |
|
4897 that.right = expression(10); |
|
4898 advance(":"); |
|
4899 that["else"] = expression(10); |
|
4900 return that; |
|
4901 }, 30); |
|
4902 |
|
4903 infix("||", "or", 40); |
|
4904 infix("&&", "and", 50); |
|
4905 bitwise("|", "bitor", 70); |
|
4906 bitwise("^", "bitxor", 80); |
|
4907 bitwise("&", "bitand", 90); |
|
4908 relation("==", function (left, right) { |
|
4909 var eqnull = state.option.eqnull && (left.value === "null" || right.value === "null"); |
|
4910 |
|
4911 if (!eqnull && state.option.eqeqeq) |
|
4912 warning("W116", this, "===", "=="); |
|
4913 else if (isPoorRelation(left)) |
|
4914 warning("W041", this, "===", left.value); |
|
4915 else if (isPoorRelation(right)) |
|
4916 warning("W041", this, "===", right.value); |
|
4917 |
|
4918 return this; |
|
4919 }); |
|
4920 relation("==="); |
|
4921 relation("!=", function (left, right) { |
|
4922 var eqnull = state.option.eqnull && |
|
4923 (left.value === "null" || right.value === "null"); |
|
4924 |
|
4925 if (!eqnull && state.option.eqeqeq) { |
|
4926 warning("W116", this, "!==", "!="); |
|
4927 } else if (isPoorRelation(left)) { |
|
4928 warning("W041", this, "!==", left.value); |
|
4929 } else if (isPoorRelation(right)) { |
|
4930 warning("W041", this, "!==", right.value); |
|
4931 } |
|
4932 return this; |
|
4933 }); |
|
4934 relation("!=="); |
|
4935 relation("<"); |
|
4936 relation(">"); |
|
4937 relation("<="); |
|
4938 relation(">="); |
|
4939 bitwise("<<", "shiftleft", 120); |
|
4940 bitwise(">>", "shiftright", 120); |
|
4941 bitwise(">>>", "shiftrightunsigned", 120); |
|
4942 infix("in", "in", 120); |
|
4943 infix("instanceof", "instanceof", 120); |
|
4944 infix("+", function (left, that) { |
|
4945 var right = expression(130); |
|
4946 if (left && right && left.id === "(string)" && right.id === "(string)") { |
|
4947 left.value += right.value; |
|
4948 left.character = right.character; |
|
4949 if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { |
|
4950 warning("W050", left); |
|
4951 } |
|
4952 return left; |
|
4953 } |
|
4954 that.left = left; |
|
4955 that.right = right; |
|
4956 return that; |
|
4957 }, 130); |
|
4958 prefix("+", "num"); |
|
4959 prefix("+++", function () { |
|
4960 warning("W007"); |
|
4961 this.right = expression(150); |
|
4962 this.arity = "unary"; |
|
4963 return this; |
|
4964 }); |
|
4965 infix("+++", function (left) { |
|
4966 warning("W007"); |
|
4967 this.left = left; |
|
4968 this.right = expression(130); |
|
4969 return this; |
|
4970 }, 130); |
|
4971 infix("-", "sub", 130); |
|
4972 prefix("-", "neg"); |
|
4973 prefix("---", function () { |
|
4974 warning("W006"); |
|
4975 this.right = expression(150); |
|
4976 this.arity = "unary"; |
|
4977 return this; |
|
4978 }); |
|
4979 infix("---", function (left) { |
|
4980 warning("W006"); |
|
4981 this.left = left; |
|
4982 this.right = expression(130); |
|
4983 return this; |
|
4984 }, 130); |
|
4985 infix("*", "mult", 140); |
|
4986 infix("/", "div", 140); |
|
4987 infix("%", "mod", 140); |
|
4988 |
|
4989 suffix("++", "postinc"); |
|
4990 prefix("++", "preinc"); |
|
4991 state.syntax["++"].exps = true; |
|
4992 |
|
4993 suffix("--", "postdec"); |
|
4994 prefix("--", "predec"); |
|
4995 state.syntax["--"].exps = true; |
|
4996 prefix("delete", function () { |
|
4997 var p = expression(5); |
|
4998 if (!p || (p.id !== "." && p.id !== "[")) { |
|
4999 warning("W051"); |
|
5000 } |
|
5001 this.first = p; |
|
5002 return this; |
|
5003 }).exps = true; |
|
5004 |
|
5005 prefix("~", function () { |
|
5006 if (state.option.bitwise) { |
|
5007 warning("W052", this, "~"); |
|
5008 } |
|
5009 expression(150); |
|
5010 return this; |
|
5011 }); |
|
5012 |
|
5013 prefix("...", function () { |
|
5014 if (!state.option.inESNext()) { |
|
5015 warning("W104", this, "spread/rest operator"); |
|
5016 } |
|
5017 if (!state.tokens.next.identifier) { |
|
5018 error("E030", state.tokens.next, state.tokens.next.value); |
|
5019 } |
|
5020 expression(150); |
|
5021 return this; |
|
5022 }); |
|
5023 |
|
5024 prefix("!", function () { |
|
5025 this.right = expression(150); |
|
5026 this.arity = "unary"; |
|
5027 |
|
5028 if (!this.right) { // '!' followed by nothing? Give up. |
|
5029 quit("E041", this.line || 0); |
|
5030 } |
|
5031 |
|
5032 if (bang[this.right.id] === true) { |
|
5033 warning("W018", this, "!"); |
|
5034 } |
|
5035 return this; |
|
5036 }); |
|
5037 |
|
5038 prefix("typeof", "typeof"); |
|
5039 prefix("new", function () { |
|
5040 var c = expression(155), i; |
|
5041 if (c && c.id !== "function") { |
|
5042 if (c.identifier) { |
|
5043 c["new"] = true; |
|
5044 switch (c.value) { |
|
5045 case "Number": |
|
5046 case "String": |
|
5047 case "Boolean": |
|
5048 case "Math": |
|
5049 case "JSON": |
|
5050 warning("W053", state.tokens.prev, c.value); |
|
5051 break; |
|
5052 case "Function": |
|
5053 if (!state.option.evil) { |
|
5054 warning("W054"); |
|
5055 } |
|
5056 break; |
|
5057 case "Date": |
|
5058 case "RegExp": |
|
5059 break; |
|
5060 default: |
|
5061 if (c.id !== "function") { |
|
5062 i = c.value.substr(0, 1); |
|
5063 if (state.option.newcap && (i < "A" || i > "Z") && !_.has(global, c.value)) { |
|
5064 warning("W055", state.tokens.curr); |
|
5065 } |
|
5066 } |
|
5067 } |
|
5068 } else { |
|
5069 if (c.id !== "." && c.id !== "[" && c.id !== "(") { |
|
5070 warning("W056", state.tokens.curr); |
|
5071 } |
|
5072 } |
|
5073 } else { |
|
5074 if (!state.option.supernew) |
|
5075 warning("W057", this); |
|
5076 } |
|
5077 adjacent(state.tokens.curr, state.tokens.next); |
|
5078 if (state.tokens.next.id !== "(" && !state.option.supernew) { |
|
5079 warning("W058", state.tokens.curr, state.tokens.curr.value); |
|
5080 } |
|
5081 this.first = c; |
|
5082 return this; |
|
5083 }); |
|
5084 state.syntax["new"].exps = true; |
|
5085 |
|
5086 prefix("void").exps = true; |
|
5087 |
|
5088 infix(".", function (left, that) { |
|
5089 adjacent(state.tokens.prev, state.tokens.curr); |
|
5090 nobreak(); |
|
5091 var m = identifier(false, true); |
|
5092 |
|
5093 if (typeof m === "string") { |
|
5094 countMember(m); |
|
5095 } |
|
5096 |
|
5097 that.left = left; |
|
5098 that.right = m; |
|
5099 |
|
5100 if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { |
|
5101 warning("W001"); |
|
5102 } |
|
5103 |
|
5104 if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { |
|
5105 if (state.option.noarg) |
|
5106 warning("W059", left, m); |
|
5107 else if (state.directive["use strict"]) |
|
5108 error("E008"); |
|
5109 } else if (!state.option.evil && left && left.value === "document" && |
|
5110 (m === "write" || m === "writeln")) { |
|
5111 warning("W060", left); |
|
5112 } |
|
5113 |
|
5114 if (!state.option.evil && (m === "eval" || m === "execScript")) { |
|
5115 warning("W061"); |
|
5116 } |
|
5117 |
|
5118 return that; |
|
5119 }, 160, true); |
|
5120 |
|
5121 infix("(", function (left, that) { |
|
5122 if (state.tokens.prev.id !== "}" && state.tokens.prev.id !== ")") { |
|
5123 nobreak(state.tokens.prev, state.tokens.curr); |
|
5124 } |
|
5125 |
|
5126 nospace(); |
|
5127 if (state.option.immed && left && !left.immed && left.id === "function") { |
|
5128 warning("W062"); |
|
5129 } |
|
5130 |
|
5131 var n = 0; |
|
5132 var p = []; |
|
5133 |
|
5134 if (left) { |
|
5135 if (left.type === "(identifier)") { |
|
5136 if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { |
|
5137 if ("Number String Boolean Date Object".indexOf(left.value) === -1) { |
|
5138 if (left.value === "Math") { |
|
5139 warning("W063", left); |
|
5140 } else if (state.option.newcap) { |
|
5141 warning("W064", left); |
|
5142 } |
|
5143 } |
|
5144 } |
|
5145 } |
|
5146 } |
|
5147 |
|
5148 if (state.tokens.next.id !== ")") { |
|
5149 for (;;) { |
|
5150 p[p.length] = expression(10); |
|
5151 n += 1; |
|
5152 if (state.tokens.next.id !== ",") { |
|
5153 break; |
|
5154 } |
|
5155 comma(); |
|
5156 } |
|
5157 } |
|
5158 |
|
5159 advance(")"); |
|
5160 nospace(state.tokens.prev, state.tokens.curr); |
|
5161 |
|
5162 if (typeof left === "object") { |
|
5163 if (left.value === "parseInt" && n === 1) { |
|
5164 warning("W065", state.tokens.curr); |
|
5165 } |
|
5166 if (!state.option.evil) { |
|
5167 if (left.value === "eval" || left.value === "Function" || |
|
5168 left.value === "execScript") { |
|
5169 warning("W061", left); |
|
5170 |
|
5171 if (p[0] && [0].id === "(string)") { |
|
5172 addInternalSrc(left, p[0].value); |
|
5173 } |
|
5174 } else if (p[0] && p[0].id === "(string)" && |
|
5175 (left.value === "setTimeout" || |
|
5176 left.value === "setInterval")) { |
|
5177 warning("W066", left); |
|
5178 addInternalSrc(left, p[0].value); |
|
5179 |
|
5180 // window.setTimeout/setInterval |
|
5181 } else if (p[0] && p[0].id === "(string)" && |
|
5182 left.value === "." && |
|
5183 left.left.value === "window" && |
|
5184 (left.right === "setTimeout" || |
|
5185 left.right === "setInterval")) { |
|
5186 warning("W066", left); |
|
5187 addInternalSrc(left, p[0].value); |
|
5188 } |
|
5189 } |
|
5190 if (!left.identifier && left.id !== "." && left.id !== "[" && |
|
5191 left.id !== "(" && left.id !== "&&" && left.id !== "||" && |
|
5192 left.id !== "?") { |
|
5193 warning("W067", left); |
|
5194 } |
|
5195 } |
|
5196 |
|
5197 that.left = left; |
|
5198 return that; |
|
5199 }, 155, true).exps = true; |
|
5200 |
|
5201 prefix("(", function () { |
|
5202 nospace(); |
|
5203 var bracket, brackets = []; |
|
5204 var pn, pn1, i = 0; |
|
5205 |
|
5206 do { |
|
5207 pn = peek(i); |
|
5208 i += 1; |
|
5209 pn1 = peek(i); |
|
5210 i += 1; |
|
5211 } while (pn.value !== ")" && pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)"); |
|
5212 |
|
5213 if (state.tokens.next.id === "function") { |
|
5214 state.tokens.next.immed = true; |
|
5215 } |
|
5216 |
|
5217 var exprs = []; |
|
5218 |
|
5219 if (state.tokens.next.id !== ")") { |
|
5220 for (;;) { |
|
5221 if (pn1.value === "=>" && state.tokens.next.value === "{") { |
|
5222 bracket = state.tokens.next; |
|
5223 bracket.left = destructuringExpression(); |
|
5224 brackets.push(bracket); |
|
5225 for (var t in bracket.left) { |
|
5226 exprs.push(bracket.left[t].token); |
|
5227 } |
|
5228 } else { |
|
5229 exprs.push(expression(5)); |
|
5230 } |
|
5231 if (state.tokens.next.id !== ",") { |
|
5232 break; |
|
5233 } |
|
5234 comma(); |
|
5235 } |
|
5236 } |
|
5237 |
|
5238 advance(")", this); |
|
5239 nospace(state.tokens.prev, state.tokens.curr); |
|
5240 if (state.option.immed && exprs[0] && exprs[0].id === "function") { |
|
5241 if (state.tokens.next.id !== "(" && |
|
5242 (state.tokens.next.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { |
|
5243 warning("W068", this); |
|
5244 } |
|
5245 } |
|
5246 |
|
5247 if (state.tokens.next.value === "=>") { |
|
5248 return exprs; |
|
5249 } |
|
5250 if (!exprs.length) { |
|
5251 return; |
|
5252 } |
|
5253 exprs[exprs.length - 1].paren = true; |
|
5254 if (exprs.length > 1) { |
|
5255 return Object.create(state.syntax[","], { exprs: { value: exprs } }); |
|
5256 } |
|
5257 return exprs[0]; |
|
5258 }); |
|
5259 |
|
5260 application("=>"); |
|
5261 |
|
5262 infix("[", function (left, that) { |
|
5263 nobreak(state.tokens.prev, state.tokens.curr); |
|
5264 nospace(); |
|
5265 var e = expression(5), s; |
|
5266 if (e && e.type === "(string)") { |
|
5267 if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { |
|
5268 warning("W061", that); |
|
5269 } |
|
5270 |
|
5271 countMember(e.value); |
|
5272 if (!state.option.sub && reg.identifier.test(e.value)) { |
|
5273 s = state.syntax[e.value]; |
|
5274 if (!s || !isReserved(s)) { |
|
5275 warning("W069", state.tokens.prev, e.value); |
|
5276 } |
|
5277 } |
|
5278 } |
|
5279 advance("]", that); |
|
5280 |
|
5281 if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { |
|
5282 warning("W001"); |
|
5283 } |
|
5284 |
|
5285 nospace(state.tokens.prev, state.tokens.curr); |
|
5286 that.left = left; |
|
5287 that.right = e; |
|
5288 return that; |
|
5289 }, 160, true); |
|
5290 |
|
5291 function comprehensiveArrayExpression() { |
|
5292 var res = {}; |
|
5293 res.exps = true; |
|
5294 funct["(comparray)"].stack(); |
|
5295 |
|
5296 res.right = expression(5); |
|
5297 advance("for"); |
|
5298 if (state.tokens.next.value === "each") { |
|
5299 advance("each"); |
|
5300 if (!state.option.inMoz(true)) { |
|
5301 warning("W118", state.tokens.curr, "for each"); |
|
5302 } |
|
5303 } |
|
5304 advance("("); |
|
5305 funct["(comparray)"].setState("define"); |
|
5306 res.left = expression(5); |
|
5307 advance(")"); |
|
5308 if (state.tokens.next.value === "if") { |
|
5309 advance("if"); |
|
5310 advance("("); |
|
5311 funct["(comparray)"].setState("filter"); |
|
5312 res.filter = expression(5); |
|
5313 advance(")"); |
|
5314 } |
|
5315 advance("]"); |
|
5316 funct["(comparray)"].unstack(); |
|
5317 return res; |
|
5318 } |
|
5319 |
|
5320 prefix("[", function () { |
|
5321 var blocktype = lookupBlockType(true); |
|
5322 if (blocktype.isCompArray) { |
|
5323 if (!state.option.inMoz(true)) { |
|
5324 warning("W118", state.tokens.curr, "array comprehension"); |
|
5325 } |
|
5326 return comprehensiveArrayExpression(); |
|
5327 } else if (blocktype.isDestAssign && !state.option.inESNext()) { |
|
5328 warning("W104", state.tokens.curr, "destructuring assignment"); |
|
5329 } |
|
5330 var b = state.tokens.curr.line !== state.tokens.next.line; |
|
5331 this.first = []; |
|
5332 if (b) { |
|
5333 indent += state.option.indent; |
|
5334 if (state.tokens.next.from === indent + state.option.indent) { |
|
5335 indent += state.option.indent; |
|
5336 } |
|
5337 } |
|
5338 while (state.tokens.next.id !== "(end)") { |
|
5339 while (state.tokens.next.id === ",") { |
|
5340 if (!state.option.inES5()) |
|
5341 warning("W070"); |
|
5342 advance(","); |
|
5343 } |
|
5344 if (state.tokens.next.id === "]") { |
|
5345 break; |
|
5346 } |
|
5347 if (b && state.tokens.curr.line !== state.tokens.next.line) { |
|
5348 indentation(); |
|
5349 } |
|
5350 this.first.push(expression(10)); |
|
5351 if (state.tokens.next.id === ",") { |
|
5352 comma({ allowTrailing: true }); |
|
5353 if (state.tokens.next.id === "]" && !state.option.inES5(true)) { |
|
5354 warning("W070", state.tokens.curr); |
|
5355 break; |
|
5356 } |
|
5357 } else { |
|
5358 break; |
|
5359 } |
|
5360 } |
|
5361 if (b) { |
|
5362 indent -= state.option.indent; |
|
5363 indentation(); |
|
5364 } |
|
5365 advance("]", this); |
|
5366 return this; |
|
5367 }, 160); |
|
5368 |
|
5369 |
|
5370 function property_name() { |
|
5371 var id = optionalidentifier(false, true); |
|
5372 |
|
5373 if (!id) { |
|
5374 if (state.tokens.next.id === "(string)") { |
|
5375 id = state.tokens.next.value; |
|
5376 advance(); |
|
5377 } else if (state.tokens.next.id === "(number)") { |
|
5378 id = state.tokens.next.value.toString(); |
|
5379 advance(); |
|
5380 } |
|
5381 } |
|
5382 |
|
5383 if (id === "hasOwnProperty") { |
|
5384 warning("W001"); |
|
5385 } |
|
5386 |
|
5387 return id; |
|
5388 } |
|
5389 |
|
5390 |
|
5391 function functionparams(parsed) { |
|
5392 var curr, next; |
|
5393 var params = []; |
|
5394 var ident; |
|
5395 var tokens = []; |
|
5396 var t; |
|
5397 |
|
5398 if (parsed) { |
|
5399 if (parsed instanceof Array) { |
|
5400 for (var i in parsed) { |
|
5401 curr = parsed[i]; |
|
5402 if (_.contains(["{", "["], curr.id)) { |
|
5403 for (t in curr.left) { |
|
5404 t = tokens[t]; |
|
5405 if (t.id) { |
|
5406 params.push(t.id); |
|
5407 addlabel(t.id, "unused", t.token); |
|
5408 } |
|
5409 } |
|
5410 } else if (curr.value === "...") { |
|
5411 if (!state.option.inESNext()) { |
|
5412 warning("W104", curr, "spread/rest operator"); |
|
5413 } |
|
5414 continue; |
|
5415 } else { |
|
5416 addlabel(curr.value, "unused", curr); |
|
5417 } |
|
5418 } |
|
5419 return params; |
|
5420 } else { |
|
5421 if (parsed.identifier === true) { |
|
5422 addlabel(parsed.value, "unused", parsed); |
|
5423 return [parsed]; |
|
5424 } |
|
5425 } |
|
5426 } |
|
5427 |
|
5428 next = state.tokens.next; |
|
5429 |
|
5430 advance("("); |
|
5431 nospace(); |
|
5432 |
|
5433 if (state.tokens.next.id === ")") { |
|
5434 advance(")"); |
|
5435 return; |
|
5436 } |
|
5437 |
|
5438 for (;;) { |
|
5439 if (_.contains(["{", "["], state.tokens.next.id)) { |
|
5440 tokens = destructuringExpression(); |
|
5441 for (t in tokens) { |
|
5442 t = tokens[t]; |
|
5443 if (t.id) { |
|
5444 params.push(t.id); |
|
5445 addlabel(t.id, "unused", t.token); |
|
5446 } |
|
5447 } |
|
5448 } else if (state.tokens.next.value === "...") { |
|
5449 if (!state.option.inESNext()) { |
|
5450 warning("W104", state.tokens.next, "spread/rest operator"); |
|
5451 } |
|
5452 advance("..."); |
|
5453 nospace(); |
|
5454 ident = identifier(true); |
|
5455 params.push(ident); |
|
5456 addlabel(ident, "unused", state.tokens.curr); |
|
5457 } else { |
|
5458 ident = identifier(true); |
|
5459 params.push(ident); |
|
5460 addlabel(ident, "unused", state.tokens.curr); |
|
5461 } |
|
5462 if (state.tokens.next.id === ",") { |
|
5463 comma(); |
|
5464 } else { |
|
5465 advance(")", next); |
|
5466 nospace(state.tokens.prev, state.tokens.curr); |
|
5467 return params; |
|
5468 } |
|
5469 } |
|
5470 } |
|
5471 |
|
5472 |
|
5473 function doFunction(name, statement, generator, fatarrowparams) { |
|
5474 var f; |
|
5475 var oldOption = state.option; |
|
5476 var oldIgnored = state.ignored; |
|
5477 var oldScope = scope; |
|
5478 |
|
5479 state.option = Object.create(state.option); |
|
5480 state.ignored = Object.create(state.ignored); |
|
5481 scope = Object.create(scope); |
|
5482 |
|
5483 funct = { |
|
5484 "(name)" : name || "\"" + anonname + "\"", |
|
5485 "(line)" : state.tokens.next.line, |
|
5486 "(character)" : state.tokens.next.character, |
|
5487 "(context)" : funct, |
|
5488 "(breakage)" : 0, |
|
5489 "(loopage)" : 0, |
|
5490 "(metrics)" : createMetrics(state.tokens.next), |
|
5491 "(scope)" : scope, |
|
5492 "(statement)" : statement, |
|
5493 "(tokens)" : {}, |
|
5494 "(blockscope)": funct["(blockscope)"], |
|
5495 "(comparray)" : funct["(comparray)"] |
|
5496 }; |
|
5497 |
|
5498 if (generator) { |
|
5499 funct["(generator)"] = true; |
|
5500 } |
|
5501 |
|
5502 f = funct; |
|
5503 state.tokens.curr.funct = funct; |
|
5504 |
|
5505 functions.push(funct); |
|
5506 |
|
5507 if (name) { |
|
5508 addlabel(name, "function"); |
|
5509 } |
|
5510 |
|
5511 funct["(params)"] = functionparams(fatarrowparams); |
|
5512 |
|
5513 funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]); |
|
5514 |
|
5515 block(false, true, true, fatarrowparams ? true:false); |
|
5516 |
|
5517 if (generator && funct["(generator)"] !== "yielded") { |
|
5518 error("E047", state.tokens.curr); |
|
5519 } |
|
5520 |
|
5521 funct["(metrics)"].verifyMaxStatementsPerFunction(); |
|
5522 funct["(metrics)"].verifyMaxComplexityPerFunction(); |
|
5523 funct["(unusedOption)"] = state.option.unused; |
|
5524 |
|
5525 scope = oldScope; |
|
5526 state.option = oldOption; |
|
5527 state.ignored = oldIgnored; |
|
5528 funct["(last)"] = state.tokens.curr.line; |
|
5529 funct["(lastcharacter)"] = state.tokens.curr.character; |
|
5530 funct = funct["(context)"]; |
|
5531 |
|
5532 return f; |
|
5533 } |
|
5534 |
|
5535 function createMetrics(functionStartToken) { |
|
5536 return { |
|
5537 statementCount: 0, |
|
5538 nestedBlockDepth: -1, |
|
5539 ComplexityCount: 1, |
|
5540 verifyMaxStatementsPerFunction: function () { |
|
5541 if (state.option.maxstatements && |
|
5542 this.statementCount > state.option.maxstatements) { |
|
5543 warning("W071", functionStartToken, this.statementCount); |
|
5544 } |
|
5545 }, |
|
5546 |
|
5547 verifyMaxParametersPerFunction: function (params) { |
|
5548 params = params || []; |
|
5549 |
|
5550 if (state.option.maxparams && params.length > state.option.maxparams) { |
|
5551 warning("W072", functionStartToken, params.length); |
|
5552 } |
|
5553 }, |
|
5554 |
|
5555 verifyMaxNestedBlockDepthPerFunction: function () { |
|
5556 if (state.option.maxdepth && |
|
5557 this.nestedBlockDepth > 0 && |
|
5558 this.nestedBlockDepth === state.option.maxdepth + 1) { |
|
5559 warning("W073", null, this.nestedBlockDepth); |
|
5560 } |
|
5561 }, |
|
5562 |
|
5563 verifyMaxComplexityPerFunction: function () { |
|
5564 var max = state.option.maxcomplexity; |
|
5565 var cc = this.ComplexityCount; |
|
5566 if (max && cc > max) { |
|
5567 warning("W074", functionStartToken, cc); |
|
5568 } |
|
5569 } |
|
5570 }; |
|
5571 } |
|
5572 |
|
5573 function increaseComplexityCount() { |
|
5574 funct["(metrics)"].ComplexityCount += 1; |
|
5575 } |
|
5576 |
|
5577 // Parse assignments that were found instead of conditionals. |
|
5578 // For example: if (a = 1) { ... } |
|
5579 |
|
5580 function checkCondAssignment(expr) { |
|
5581 var id = expr.id; |
|
5582 if (id === ",") { |
|
5583 expr = expr.exprs[expr.exprs.length - 1]; |
|
5584 id = expr.id; |
|
5585 } |
|
5586 switch (id) { |
|
5587 case "=": |
|
5588 case "+=": |
|
5589 case "-=": |
|
5590 case "*=": |
|
5591 case "%=": |
|
5592 case "&=": |
|
5593 case "|=": |
|
5594 case "^=": |
|
5595 case "/=": |
|
5596 if (!expr.paren && !state.option.boss) { |
|
5597 warning("W084"); |
|
5598 } |
|
5599 } |
|
5600 } |
|
5601 |
|
5602 |
|
5603 (function (x) { |
|
5604 x.nud = function (isclassdef) { |
|
5605 var b, f, i, p, t, g; |
|
5606 var props = {}; // All properties, including accessors |
|
5607 var tag = ""; |
|
5608 |
|
5609 function saveProperty(name, tkn) { |
|
5610 if (props[name] && _.has(props, name)) |
|
5611 warning("W075", state.tokens.next, i); |
|
5612 else |
|
5613 props[name] = {}; |
|
5614 |
|
5615 props[name].basic = true; |
|
5616 props[name].basictkn = tkn; |
|
5617 } |
|
5618 |
|
5619 function saveSetter(name, tkn) { |
|
5620 if (props[name] && _.has(props, name)) { |
|
5621 if (props[name].basic || props[name].setter) |
|
5622 warning("W075", state.tokens.next, i); |
|
5623 } else { |
|
5624 props[name] = {}; |
|
5625 } |
|
5626 |
|
5627 props[name].setter = true; |
|
5628 props[name].setterToken = tkn; |
|
5629 } |
|
5630 |
|
5631 function saveGetter(name) { |
|
5632 if (props[name] && _.has(props, name)) { |
|
5633 if (props[name].basic || props[name].getter) |
|
5634 warning("W075", state.tokens.next, i); |
|
5635 } else { |
|
5636 props[name] = {}; |
|
5637 } |
|
5638 |
|
5639 props[name].getter = true; |
|
5640 props[name].getterToken = state.tokens.curr; |
|
5641 } |
|
5642 |
|
5643 b = state.tokens.curr.line !== state.tokens.next.line; |
|
5644 if (b) { |
|
5645 indent += state.option.indent; |
|
5646 if (state.tokens.next.from === indent + state.option.indent) { |
|
5647 indent += state.option.indent; |
|
5648 } |
|
5649 } |
|
5650 |
|
5651 for (;;) { |
|
5652 if (state.tokens.next.id === "}") { |
|
5653 break; |
|
5654 } |
|
5655 |
|
5656 if (b) { |
|
5657 indentation(); |
|
5658 } |
|
5659 |
|
5660 if (isclassdef && state.tokens.next.value === "static") { |
|
5661 advance("static"); |
|
5662 tag = "static "; |
|
5663 } |
|
5664 |
|
5665 if (state.tokens.next.value === "get" && peek().id !== ":") { |
|
5666 advance("get"); |
|
5667 |
|
5668 if (!state.option.inES5(!isclassdef)) { |
|
5669 error("E034"); |
|
5670 } |
|
5671 |
|
5672 i = property_name(); |
|
5673 if (!i) { |
|
5674 error("E035"); |
|
5675 } |
|
5676 |
|
5677 // It is a Syntax Error if PropName of MethodDefinition is |
|
5678 // "constructor" and SpecialMethod of MethodDefinition is true. |
|
5679 if (isclassdef && i === "constructor") { |
|
5680 error("E049", state.tokens.next, "class getter method", i); |
|
5681 } |
|
5682 |
|
5683 saveGetter(tag + i); |
|
5684 t = state.tokens.next; |
|
5685 adjacent(state.tokens.curr, state.tokens.next); |
|
5686 f = doFunction(); |
|
5687 p = f["(params)"]; |
|
5688 |
|
5689 if (p) { |
|
5690 warning("W076", t, p[0], i); |
|
5691 } |
|
5692 |
|
5693 adjacent(state.tokens.curr, state.tokens.next); |
|
5694 } else if (state.tokens.next.value === "set" && peek().id !== ":") { |
|
5695 advance("set"); |
|
5696 |
|
5697 if (!state.option.inES5(!isclassdef)) { |
|
5698 error("E034"); |
|
5699 } |
|
5700 |
|
5701 i = property_name(); |
|
5702 if (!i) { |
|
5703 error("E035"); |
|
5704 } |
|
5705 |
|
5706 // It is a Syntax Error if PropName of MethodDefinition is |
|
5707 // "constructor" and SpecialMethod of MethodDefinition is true. |
|
5708 if (isclassdef && i === "constructor") { |
|
5709 error("E049", state.tokens.next, "class setter method", i); |
|
5710 } |
|
5711 |
|
5712 saveSetter(tag + i, state.tokens.next); |
|
5713 t = state.tokens.next; |
|
5714 adjacent(state.tokens.curr, state.tokens.next); |
|
5715 f = doFunction(); |
|
5716 p = f["(params)"]; |
|
5717 |
|
5718 if (!p || p.length !== 1) { |
|
5719 warning("W077", t, i); |
|
5720 } |
|
5721 } else { |
|
5722 g = false; |
|
5723 if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { |
|
5724 if (!state.option.inESNext()) { |
|
5725 warning("W104", state.tokens.next, "generator functions"); |
|
5726 } |
|
5727 advance("*"); |
|
5728 g = true; |
|
5729 } |
|
5730 i = property_name(); |
|
5731 saveProperty(tag + i, state.tokens.next); |
|
5732 |
|
5733 if (typeof i !== "string") { |
|
5734 break; |
|
5735 } |
|
5736 |
|
5737 if (state.tokens.next.value === "(") { |
|
5738 if (!state.option.inESNext()) { |
|
5739 warning("W104", state.tokens.curr, "concise methods"); |
|
5740 } |
|
5741 doFunction(i, undefined, g); |
|
5742 } else if (!isclassdef) { |
|
5743 advance(":"); |
|
5744 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5745 expression(10); |
|
5746 } |
|
5747 } |
|
5748 // It is a Syntax Error if PropName of MethodDefinition is "prototype". |
|
5749 if (isclassdef && i === "prototype") { |
|
5750 error("E049", state.tokens.next, "class method", i); |
|
5751 } |
|
5752 |
|
5753 countMember(i); |
|
5754 if (isclassdef) { |
|
5755 tag = ""; |
|
5756 continue; |
|
5757 } |
|
5758 if (state.tokens.next.id === ",") { |
|
5759 comma({ allowTrailing: true, property: true }); |
|
5760 if (state.tokens.next.id === ",") { |
|
5761 warning("W070", state.tokens.curr); |
|
5762 } else if (state.tokens.next.id === "}" && !state.option.inES5(true)) { |
|
5763 warning("W070", state.tokens.curr); |
|
5764 } |
|
5765 } else { |
|
5766 break; |
|
5767 } |
|
5768 } |
|
5769 if (b) { |
|
5770 indent -= state.option.indent; |
|
5771 indentation(); |
|
5772 } |
|
5773 advance("}", this); |
|
5774 |
|
5775 // Check for lonely setters if in the ES5 mode. |
|
5776 if (state.option.inES5()) { |
|
5777 for (var name in props) { |
|
5778 if (_.has(props, name) && props[name].setter && !props[name].getter) { |
|
5779 warning("W078", props[name].setterToken); |
|
5780 } |
|
5781 } |
|
5782 } |
|
5783 return this; |
|
5784 }; |
|
5785 x.fud = function () { |
|
5786 error("E036", state.tokens.curr); |
|
5787 }; |
|
5788 }(delim("{"))); |
|
5789 |
|
5790 function destructuringExpression() { |
|
5791 var id, ids; |
|
5792 var identifiers = []; |
|
5793 if (!state.option.inESNext()) { |
|
5794 warning("W104", state.tokens.curr, "destructuring expression"); |
|
5795 } |
|
5796 var nextInnerDE = function () { |
|
5797 var ident; |
|
5798 if (_.contains(["[", "{"], state.tokens.next.value)) { |
|
5799 ids = destructuringExpression(); |
|
5800 for (var id in ids) { |
|
5801 id = ids[id]; |
|
5802 identifiers.push({ id: id.id, token: id.token }); |
|
5803 } |
|
5804 } else if (state.tokens.next.value === ",") { |
|
5805 identifiers.push({ id: null, token: state.tokens.curr }); |
|
5806 } else { |
|
5807 ident = identifier(); |
|
5808 if (ident) |
|
5809 identifiers.push({ id: ident, token: state.tokens.curr }); |
|
5810 } |
|
5811 }; |
|
5812 if (state.tokens.next.value === "[") { |
|
5813 advance("["); |
|
5814 nextInnerDE(); |
|
5815 while (state.tokens.next.value !== "]") { |
|
5816 advance(","); |
|
5817 nextInnerDE(); |
|
5818 } |
|
5819 advance("]"); |
|
5820 } else if (state.tokens.next.value === "{") { |
|
5821 advance("{"); |
|
5822 id = identifier(); |
|
5823 if (state.tokens.next.value === ":") { |
|
5824 advance(":"); |
|
5825 nextInnerDE(); |
|
5826 } else { |
|
5827 identifiers.push({ id: id, token: state.tokens.curr }); |
|
5828 } |
|
5829 while (state.tokens.next.value !== "}") { |
|
5830 advance(","); |
|
5831 id = identifier(); |
|
5832 if (state.tokens.next.value === ":") { |
|
5833 advance(":"); |
|
5834 nextInnerDE(); |
|
5835 } else { |
|
5836 identifiers.push({ id: id, token: state.tokens.curr }); |
|
5837 } |
|
5838 } |
|
5839 advance("}"); |
|
5840 } |
|
5841 return identifiers; |
|
5842 } |
|
5843 function destructuringExpressionMatch(tokens, value) { |
|
5844 if (value.first) { |
|
5845 _.zip(tokens, value.first).forEach(function (val) { |
|
5846 var token = val[0]; |
|
5847 var value = val[1]; |
|
5848 if (token && value) { |
|
5849 token.first = value; |
|
5850 } else if (token && token.first && !value) { |
|
5851 warning("W080", token.first, token.first.value); |
|
5852 } /* else { |
|
5853 XXX value is discarded: wouldn't it need a warning ? |
|
5854 } */ |
|
5855 }); |
|
5856 } |
|
5857 } |
|
5858 |
|
5859 var conststatement = stmt("const", function (prefix) { |
|
5860 var tokens, value; |
|
5861 // state variable to know if it is a lone identifier, or a destructuring statement. |
|
5862 var lone; |
|
5863 |
|
5864 if (!state.option.inESNext()) { |
|
5865 warning("W104", state.tokens.curr, "const"); |
|
5866 } |
|
5867 |
|
5868 this.first = []; |
|
5869 for (;;) { |
|
5870 var names = []; |
|
5871 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5872 if (_.contains(["{", "["], state.tokens.next.value)) { |
|
5873 tokens = destructuringExpression(); |
|
5874 lone = false; |
|
5875 } else { |
|
5876 tokens = [ { id: identifier(), token: state.tokens.curr } ]; |
|
5877 lone = true; |
|
5878 } |
|
5879 for (var t in tokens) { |
|
5880 t = tokens[t]; |
|
5881 if (funct[t.id] === "const") { |
|
5882 warning("E011", null, t.id); |
|
5883 } |
|
5884 if (funct["(global)"] && predefined[t.id] === false) { |
|
5885 warning("W079", t.token, t.id); |
|
5886 } |
|
5887 if (t.id) { |
|
5888 addlabel(t.id, "const"); |
|
5889 names.push(t.token); |
|
5890 } |
|
5891 } |
|
5892 if (prefix) { |
|
5893 break; |
|
5894 } |
|
5895 |
|
5896 this.first = this.first.concat(names); |
|
5897 |
|
5898 if (state.tokens.next.id !== "=") { |
|
5899 warning("E012", state.tokens.curr, state.tokens.curr.value); |
|
5900 } |
|
5901 |
|
5902 if (state.tokens.next.id === "=") { |
|
5903 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5904 advance("="); |
|
5905 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5906 if (state.tokens.next.id === "undefined") { |
|
5907 warning("W080", state.tokens.prev, state.tokens.prev.value); |
|
5908 } |
|
5909 if (peek(0).id === "=" && state.tokens.next.identifier) { |
|
5910 error("E037", state.tokens.next, state.tokens.next.value); |
|
5911 } |
|
5912 value = expression(5); |
|
5913 if (lone) { |
|
5914 tokens[0].first = value; |
|
5915 } else { |
|
5916 destructuringExpressionMatch(names, value); |
|
5917 } |
|
5918 } |
|
5919 |
|
5920 if (state.tokens.next.id !== ",") { |
|
5921 break; |
|
5922 } |
|
5923 comma(); |
|
5924 } |
|
5925 return this; |
|
5926 }); |
|
5927 conststatement.exps = true; |
|
5928 var varstatement = stmt("var", function (prefix) { |
|
5929 // JavaScript does not have block scope. It only has function scope. So, |
|
5930 // declaring a variable in a block can have unexpected consequences. |
|
5931 var tokens, lone, value; |
|
5932 |
|
5933 if (funct["(onevar)"] && state.option.onevar) { |
|
5934 warning("W081"); |
|
5935 } else if (!funct["(global)"]) { |
|
5936 funct["(onevar)"] = true; |
|
5937 } |
|
5938 |
|
5939 this.first = []; |
|
5940 for (;;) { |
|
5941 var names = []; |
|
5942 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5943 if (_.contains(["{", "["], state.tokens.next.value)) { |
|
5944 tokens = destructuringExpression(); |
|
5945 lone = false; |
|
5946 } else { |
|
5947 tokens = [ { id: identifier(), token: state.tokens.curr } ]; |
|
5948 lone = true; |
|
5949 } |
|
5950 for (var t in tokens) { |
|
5951 t = tokens[t]; |
|
5952 if (state.option.inESNext() && funct[t.id] === "const") { |
|
5953 warning("E011", null, t.id); |
|
5954 } |
|
5955 if (funct["(global)"] && predefined[t.id] === false) { |
|
5956 warning("W079", t.token, t.id); |
|
5957 } |
|
5958 if (t.id) { |
|
5959 addlabel(t.id, "unused", t.token); |
|
5960 names.push(t.token); |
|
5961 } |
|
5962 } |
|
5963 if (prefix) { |
|
5964 break; |
|
5965 } |
|
5966 |
|
5967 this.first = this.first.concat(names); |
|
5968 |
|
5969 if (state.tokens.next.id === "=") { |
|
5970 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5971 advance("="); |
|
5972 nonadjacent(state.tokens.curr, state.tokens.next); |
|
5973 if (state.tokens.next.id === "undefined") { |
|
5974 warning("W080", state.tokens.prev, state.tokens.prev.value); |
|
5975 } |
|
5976 if (peek(0).id === "=" && state.tokens.next.identifier) { |
|
5977 error("E038", state.tokens.next, state.tokens.next.value); |
|
5978 } |
|
5979 value = expression(5); |
|
5980 if (lone) { |
|
5981 tokens[0].first = value; |
|
5982 } else { |
|
5983 destructuringExpressionMatch(names, value); |
|
5984 } |
|
5985 } |
|
5986 |
|
5987 if (state.tokens.next.id !== ",") { |
|
5988 break; |
|
5989 } |
|
5990 comma(); |
|
5991 } |
|
5992 return this; |
|
5993 }); |
|
5994 varstatement.exps = true; |
|
5995 var letstatement = stmt("let", function (prefix) { |
|
5996 var tokens, lone, value, letblock; |
|
5997 |
|
5998 if (!state.option.inESNext()) { |
|
5999 warning("W104", state.tokens.curr, "let"); |
|
6000 } |
|
6001 |
|
6002 if (state.tokens.next.value === "(") { |
|
6003 if (!state.option.inMoz(true)) { |
|
6004 warning("W118", state.tokens.next, "let block"); |
|
6005 } |
|
6006 advance("("); |
|
6007 funct["(blockscope)"].stack(); |
|
6008 letblock = true; |
|
6009 } else if (funct["(nolet)"]) { |
|
6010 error("E048", state.tokens.curr); |
|
6011 } |
|
6012 |
|
6013 if (funct["(onevar)"] && state.option.onevar) { |
|
6014 warning("W081"); |
|
6015 } else if (!funct["(global)"]) { |
|
6016 funct["(onevar)"] = true; |
|
6017 } |
|
6018 |
|
6019 this.first = []; |
|
6020 for (;;) { |
|
6021 var names = []; |
|
6022 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6023 if (_.contains(["{", "["], state.tokens.next.value)) { |
|
6024 tokens = destructuringExpression(); |
|
6025 lone = false; |
|
6026 } else { |
|
6027 tokens = [ { id: identifier(), token: state.tokens.curr.value } ]; |
|
6028 lone = true; |
|
6029 } |
|
6030 for (var t in tokens) { |
|
6031 t = tokens[t]; |
|
6032 if (state.option.inESNext() && funct[t.id] === "const") { |
|
6033 warning("E011", null, t.id); |
|
6034 } |
|
6035 if (funct["(global)"] && predefined[t.id] === false) { |
|
6036 warning("W079", t.token, t.id); |
|
6037 } |
|
6038 if (t.id && !funct["(nolet)"]) { |
|
6039 addlabel(t.id, "unused", t.token, true); |
|
6040 names.push(t.token); |
|
6041 } |
|
6042 } |
|
6043 if (prefix) { |
|
6044 break; |
|
6045 } |
|
6046 |
|
6047 this.first = this.first.concat(names); |
|
6048 |
|
6049 if (state.tokens.next.id === "=") { |
|
6050 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6051 advance("="); |
|
6052 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6053 if (state.tokens.next.id === "undefined") { |
|
6054 warning("W080", state.tokens.prev, state.tokens.prev.value); |
|
6055 } |
|
6056 if (peek(0).id === "=" && state.tokens.next.identifier) { |
|
6057 error("E037", state.tokens.next, state.tokens.next.value); |
|
6058 } |
|
6059 value = expression(5); |
|
6060 if (lone) { |
|
6061 tokens[0].first = value; |
|
6062 } else { |
|
6063 destructuringExpressionMatch(names, value); |
|
6064 } |
|
6065 } |
|
6066 |
|
6067 if (state.tokens.next.id !== ",") { |
|
6068 break; |
|
6069 } |
|
6070 comma(); |
|
6071 } |
|
6072 if (letblock) { |
|
6073 advance(")"); |
|
6074 block(true, true); |
|
6075 this.block = true; |
|
6076 funct["(blockscope)"].unstack(); |
|
6077 } |
|
6078 |
|
6079 return this; |
|
6080 }); |
|
6081 letstatement.exps = true; |
|
6082 |
|
6083 blockstmt("class", function () { |
|
6084 return classdef.call(this, true); |
|
6085 }); |
|
6086 |
|
6087 function classdef(stmt) { |
|
6088 /*jshint validthis:true */ |
|
6089 if (!state.option.inESNext()) { |
|
6090 warning("W104", state.tokens.curr, "class"); |
|
6091 } |
|
6092 if (stmt) { |
|
6093 // BindingIdentifier |
|
6094 this.name = identifier(); |
|
6095 addlabel(this.name, "unused", state.tokens.curr); |
|
6096 } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { |
|
6097 // BindingIdentifier(opt) |
|
6098 this.name = identifier(); |
|
6099 } |
|
6100 classtail(this); |
|
6101 return this; |
|
6102 } |
|
6103 |
|
6104 function classtail(c) { |
|
6105 var strictness = state.directive["use strict"]; |
|
6106 |
|
6107 // ClassHeritage(opt) |
|
6108 if (state.tokens.next.value === "extends") { |
|
6109 advance("extends"); |
|
6110 c.heritage = expression(10); |
|
6111 } |
|
6112 |
|
6113 // A ClassBody is always strict code. |
|
6114 state.directive["use strict"] = true; |
|
6115 advance("{"); |
|
6116 // ClassBody(opt) |
|
6117 c.body = state.syntax["{"].nud(true); |
|
6118 state.directive["use strict"] = strictness; |
|
6119 } |
|
6120 |
|
6121 blockstmt("function", function () { |
|
6122 var generator = false; |
|
6123 if (state.tokens.next.value === "*") { |
|
6124 advance("*"); |
|
6125 if (state.option.inESNext(true)) { |
|
6126 generator = true; |
|
6127 } else { |
|
6128 warning("W119", state.tokens.curr, "function*"); |
|
6129 } |
|
6130 } |
|
6131 if (inblock) { |
|
6132 warning("W082", state.tokens.curr); |
|
6133 |
|
6134 } |
|
6135 var i = identifier(); |
|
6136 if (funct[i] === "const") { |
|
6137 warning("E011", null, i); |
|
6138 } |
|
6139 adjacent(state.tokens.curr, state.tokens.next); |
|
6140 addlabel(i, "unction", state.tokens.curr); |
|
6141 |
|
6142 doFunction(i, { statement: true }, generator); |
|
6143 if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { |
|
6144 error("E039"); |
|
6145 } |
|
6146 return this; |
|
6147 }); |
|
6148 |
|
6149 prefix("function", function () { |
|
6150 var generator = false; |
|
6151 if (state.tokens.next.value === "*") { |
|
6152 if (!state.option.inESNext()) { |
|
6153 warning("W119", state.tokens.curr, "function*"); |
|
6154 } |
|
6155 advance("*"); |
|
6156 generator = true; |
|
6157 } |
|
6158 var i = optionalidentifier(); |
|
6159 if (i || state.option.gcl) { |
|
6160 adjacent(state.tokens.curr, state.tokens.next); |
|
6161 } else { |
|
6162 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6163 } |
|
6164 doFunction(i, undefined, generator); |
|
6165 if (!state.option.loopfunc && funct["(loopage)"]) { |
|
6166 warning("W083"); |
|
6167 } |
|
6168 return this; |
|
6169 }); |
|
6170 |
|
6171 blockstmt("if", function () { |
|
6172 var t = state.tokens.next; |
|
6173 increaseComplexityCount(); |
|
6174 state.condition = true; |
|
6175 advance("("); |
|
6176 nonadjacent(this, t); |
|
6177 nospace(); |
|
6178 checkCondAssignment(expression(0)); |
|
6179 advance(")", t); |
|
6180 state.condition = false; |
|
6181 nospace(state.tokens.prev, state.tokens.curr); |
|
6182 block(true, true); |
|
6183 if (state.tokens.next.id === "else") { |
|
6184 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6185 advance("else"); |
|
6186 if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { |
|
6187 statement(true); |
|
6188 } else { |
|
6189 block(true, true); |
|
6190 } |
|
6191 } |
|
6192 return this; |
|
6193 }); |
|
6194 |
|
6195 blockstmt("try", function () { |
|
6196 var b; |
|
6197 |
|
6198 function doCatch() { |
|
6199 var oldScope = scope; |
|
6200 var e; |
|
6201 |
|
6202 advance("catch"); |
|
6203 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6204 advance("("); |
|
6205 |
|
6206 scope = Object.create(oldScope); |
|
6207 |
|
6208 e = state.tokens.next.value; |
|
6209 if (state.tokens.next.type !== "(identifier)") { |
|
6210 e = null; |
|
6211 warning("E030", state.tokens.next, e); |
|
6212 } |
|
6213 |
|
6214 advance(); |
|
6215 |
|
6216 funct = { |
|
6217 "(name)" : "(catch)", |
|
6218 "(line)" : state.tokens.next.line, |
|
6219 "(character)": state.tokens.next.character, |
|
6220 "(context)" : funct, |
|
6221 "(breakage)" : funct["(breakage)"], |
|
6222 "(loopage)" : funct["(loopage)"], |
|
6223 "(scope)" : scope, |
|
6224 "(statement)": false, |
|
6225 "(metrics)" : createMetrics(state.tokens.next), |
|
6226 "(catch)" : true, |
|
6227 "(tokens)" : {}, |
|
6228 "(blockscope)": funct["(blockscope)"], |
|
6229 "(comparray)": funct["(comparray)"] |
|
6230 }; |
|
6231 |
|
6232 if (e) { |
|
6233 addlabel(e, "exception"); |
|
6234 } |
|
6235 |
|
6236 if (state.tokens.next.value === "if") { |
|
6237 if (!state.option.inMoz(true)) { |
|
6238 warning("W118", state.tokens.curr, "catch filter"); |
|
6239 } |
|
6240 advance("if"); |
|
6241 expression(0); |
|
6242 } |
|
6243 |
|
6244 advance(")"); |
|
6245 |
|
6246 state.tokens.curr.funct = funct; |
|
6247 functions.push(funct); |
|
6248 |
|
6249 block(false); |
|
6250 |
|
6251 scope = oldScope; |
|
6252 |
|
6253 funct["(last)"] = state.tokens.curr.line; |
|
6254 funct["(lastcharacter)"] = state.tokens.curr.character; |
|
6255 funct = funct["(context)"]; |
|
6256 } |
|
6257 |
|
6258 block(false); |
|
6259 |
|
6260 while (state.tokens.next.id === "catch") { |
|
6261 increaseComplexityCount(); |
|
6262 if (b && (!state.option.inMoz(true))) { |
|
6263 warning("W118", state.tokens.next, "multiple catch blocks"); |
|
6264 } |
|
6265 doCatch(); |
|
6266 b = true; |
|
6267 } |
|
6268 |
|
6269 if (state.tokens.next.id === "finally") { |
|
6270 advance("finally"); |
|
6271 block(false); |
|
6272 return; |
|
6273 } |
|
6274 |
|
6275 if (!b) { |
|
6276 error("E021", state.tokens.next, "catch", state.tokens.next.value); |
|
6277 } |
|
6278 |
|
6279 return this; |
|
6280 }); |
|
6281 |
|
6282 blockstmt("while", function () { |
|
6283 var t = state.tokens.next; |
|
6284 funct["(breakage)"] += 1; |
|
6285 funct["(loopage)"] += 1; |
|
6286 increaseComplexityCount(); |
|
6287 advance("("); |
|
6288 nonadjacent(this, t); |
|
6289 nospace(); |
|
6290 checkCondAssignment(expression(0)); |
|
6291 advance(")", t); |
|
6292 nospace(state.tokens.prev, state.tokens.curr); |
|
6293 block(true, true); |
|
6294 funct["(breakage)"] -= 1; |
|
6295 funct["(loopage)"] -= 1; |
|
6296 return this; |
|
6297 }).labelled = true; |
|
6298 |
|
6299 blockstmt("with", function () { |
|
6300 var t = state.tokens.next; |
|
6301 if (state.directive["use strict"]) { |
|
6302 error("E010", state.tokens.curr); |
|
6303 } else if (!state.option.withstmt) { |
|
6304 warning("W085", state.tokens.curr); |
|
6305 } |
|
6306 |
|
6307 advance("("); |
|
6308 nonadjacent(this, t); |
|
6309 nospace(); |
|
6310 expression(0); |
|
6311 advance(")", t); |
|
6312 nospace(state.tokens.prev, state.tokens.curr); |
|
6313 block(true, true); |
|
6314 |
|
6315 return this; |
|
6316 }); |
|
6317 |
|
6318 blockstmt("switch", function () { |
|
6319 var t = state.tokens.next, |
|
6320 g = false; |
|
6321 funct["(breakage)"] += 1; |
|
6322 advance("("); |
|
6323 nonadjacent(this, t); |
|
6324 nospace(); |
|
6325 checkCondAssignment(expression(0)); |
|
6326 advance(")", t); |
|
6327 nospace(state.tokens.prev, state.tokens.curr); |
|
6328 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6329 t = state.tokens.next; |
|
6330 advance("{"); |
|
6331 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6332 indent += state.option.indent; |
|
6333 this.cases = []; |
|
6334 |
|
6335 for (;;) { |
|
6336 switch (state.tokens.next.id) { |
|
6337 case "case": |
|
6338 switch (funct["(verb)"]) { |
|
6339 case "yield": |
|
6340 case "break": |
|
6341 case "case": |
|
6342 case "continue": |
|
6343 case "return": |
|
6344 case "switch": |
|
6345 case "throw": |
|
6346 break; |
|
6347 default: |
|
6348 // You can tell JSHint that you don't use break intentionally by |
|
6349 // adding a comment /* falls through */ on a line just before |
|
6350 // the next `case`. |
|
6351 if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { |
|
6352 warning("W086", state.tokens.curr, "case"); |
|
6353 } |
|
6354 } |
|
6355 indentation(-state.option.indent); |
|
6356 advance("case"); |
|
6357 this.cases.push(expression(20)); |
|
6358 increaseComplexityCount(); |
|
6359 g = true; |
|
6360 advance(":"); |
|
6361 funct["(verb)"] = "case"; |
|
6362 break; |
|
6363 case "default": |
|
6364 switch (funct["(verb)"]) { |
|
6365 case "yield": |
|
6366 case "break": |
|
6367 case "continue": |
|
6368 case "return": |
|
6369 case "throw": |
|
6370 break; |
|
6371 default: |
|
6372 // Do not display a warning if 'default' is the first statement or if |
|
6373 // there is a special /* falls through */ comment. |
|
6374 if (this.cases.length) { |
|
6375 if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { |
|
6376 warning("W086", state.tokens.curr, "default"); |
|
6377 } |
|
6378 } |
|
6379 } |
|
6380 indentation(-state.option.indent); |
|
6381 advance("default"); |
|
6382 g = true; |
|
6383 advance(":"); |
|
6384 break; |
|
6385 case "}": |
|
6386 indent -= state.option.indent; |
|
6387 indentation(); |
|
6388 advance("}", t); |
|
6389 funct["(breakage)"] -= 1; |
|
6390 funct["(verb)"] = undefined; |
|
6391 return; |
|
6392 case "(end)": |
|
6393 error("E023", state.tokens.next, "}"); |
|
6394 return; |
|
6395 default: |
|
6396 if (g) { |
|
6397 switch (state.tokens.curr.id) { |
|
6398 case ",": |
|
6399 error("E040"); |
|
6400 return; |
|
6401 case ":": |
|
6402 g = false; |
|
6403 statements(); |
|
6404 break; |
|
6405 default: |
|
6406 error("E025", state.tokens.curr); |
|
6407 return; |
|
6408 } |
|
6409 } else { |
|
6410 if (state.tokens.curr.id === ":") { |
|
6411 advance(":"); |
|
6412 error("E024", state.tokens.curr, ":"); |
|
6413 statements(); |
|
6414 } else { |
|
6415 error("E021", state.tokens.next, "case", state.tokens.next.value); |
|
6416 return; |
|
6417 } |
|
6418 } |
|
6419 } |
|
6420 } |
|
6421 }).labelled = true; |
|
6422 |
|
6423 stmt("debugger", function () { |
|
6424 if (!state.option.debug) { |
|
6425 warning("W087"); |
|
6426 } |
|
6427 return this; |
|
6428 }).exps = true; |
|
6429 |
|
6430 (function () { |
|
6431 var x = stmt("do", function () { |
|
6432 funct["(breakage)"] += 1; |
|
6433 funct["(loopage)"] += 1; |
|
6434 increaseComplexityCount(); |
|
6435 |
|
6436 this.first = block(true, true); |
|
6437 advance("while"); |
|
6438 var t = state.tokens.next; |
|
6439 nonadjacent(state.tokens.curr, t); |
|
6440 advance("("); |
|
6441 nospace(); |
|
6442 checkCondAssignment(expression(0)); |
|
6443 advance(")", t); |
|
6444 nospace(state.tokens.prev, state.tokens.curr); |
|
6445 funct["(breakage)"] -= 1; |
|
6446 funct["(loopage)"] -= 1; |
|
6447 return this; |
|
6448 }); |
|
6449 x.labelled = true; |
|
6450 x.exps = true; |
|
6451 }()); |
|
6452 |
|
6453 blockstmt("for", function () { |
|
6454 var s, t = state.tokens.next; |
|
6455 var letscope = false; |
|
6456 var foreachtok = null; |
|
6457 |
|
6458 if (t.value === "each") { |
|
6459 foreachtok = t; |
|
6460 advance("each"); |
|
6461 if (!state.option.inMoz(true)) { |
|
6462 warning("W118", state.tokens.curr, "for each"); |
|
6463 } |
|
6464 } |
|
6465 |
|
6466 funct["(breakage)"] += 1; |
|
6467 funct["(loopage)"] += 1; |
|
6468 increaseComplexityCount(); |
|
6469 advance("("); |
|
6470 nonadjacent(this, t); |
|
6471 nospace(); |
|
6472 |
|
6473 // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? |
|
6474 var nextop; // contains the token of the "in" or "of" operator |
|
6475 var i = 0; |
|
6476 var inof = ["in", "of"]; |
|
6477 do { |
|
6478 nextop = peek(i); |
|
6479 ++i; |
|
6480 } while (!_.contains(inof, nextop.value) && nextop.value !== ";" && |
|
6481 nextop.type !== "(end)"); |
|
6482 |
|
6483 // if we're in a for (… in|of …) statement |
|
6484 if (_.contains(inof, nextop.value)) { |
|
6485 if (!state.option.inESNext() && nextop.value === "of") { |
|
6486 error("W104", nextop, "for of"); |
|
6487 } |
|
6488 if (state.tokens.next.id === "var") { |
|
6489 advance("var"); |
|
6490 state.syntax["var"].fud.call(state.syntax["var"].fud, true); |
|
6491 } else if (state.tokens.next.id === "let") { |
|
6492 advance("let"); |
|
6493 // create a new block scope |
|
6494 letscope = true; |
|
6495 funct["(blockscope)"].stack(); |
|
6496 state.syntax["let"].fud.call(state.syntax["let"].fud, true); |
|
6497 } else { |
|
6498 switch (funct[state.tokens.next.value]) { |
|
6499 case "unused": |
|
6500 funct[state.tokens.next.value] = "var"; |
|
6501 break; |
|
6502 case "var": |
|
6503 break; |
|
6504 default: |
|
6505 if (!funct["(blockscope)"].getlabel(state.tokens.next.value)) |
|
6506 warning("W088", state.tokens.next, state.tokens.next.value); |
|
6507 } |
|
6508 advance(); |
|
6509 } |
|
6510 advance(nextop.value); |
|
6511 expression(20); |
|
6512 advance(")", t); |
|
6513 s = block(true, true); |
|
6514 if (state.option.forin && s && (s.length > 1 || typeof s[0] !== "object" || |
|
6515 s[0].value !== "if")) { |
|
6516 warning("W089", this); |
|
6517 } |
|
6518 funct["(breakage)"] -= 1; |
|
6519 funct["(loopage)"] -= 1; |
|
6520 } else { |
|
6521 if (foreachtok) { |
|
6522 error("E045", foreachtok); |
|
6523 } |
|
6524 if (state.tokens.next.id !== ";") { |
|
6525 if (state.tokens.next.id === "var") { |
|
6526 advance("var"); |
|
6527 state.syntax["var"].fud.call(state.syntax["var"].fud); |
|
6528 } else if (state.tokens.next.id === "let") { |
|
6529 advance("let"); |
|
6530 // create a new block scope |
|
6531 letscope = true; |
|
6532 funct["(blockscope)"].stack(); |
|
6533 state.syntax["let"].fud.call(state.syntax["let"].fud); |
|
6534 } else { |
|
6535 for (;;) { |
|
6536 expression(0, "for"); |
|
6537 if (state.tokens.next.id !== ",") { |
|
6538 break; |
|
6539 } |
|
6540 comma(); |
|
6541 } |
|
6542 } |
|
6543 } |
|
6544 nolinebreak(state.tokens.curr); |
|
6545 advance(";"); |
|
6546 if (state.tokens.next.id !== ";") { |
|
6547 checkCondAssignment(expression(0)); |
|
6548 } |
|
6549 nolinebreak(state.tokens.curr); |
|
6550 advance(";"); |
|
6551 if (state.tokens.next.id === ";") { |
|
6552 error("E021", state.tokens.next, ")", ";"); |
|
6553 } |
|
6554 if (state.tokens.next.id !== ")") { |
|
6555 for (;;) { |
|
6556 expression(0, "for"); |
|
6557 if (state.tokens.next.id !== ",") { |
|
6558 break; |
|
6559 } |
|
6560 comma(); |
|
6561 } |
|
6562 } |
|
6563 advance(")", t); |
|
6564 nospace(state.tokens.prev, state.tokens.curr); |
|
6565 block(true, true); |
|
6566 funct["(breakage)"] -= 1; |
|
6567 funct["(loopage)"] -= 1; |
|
6568 |
|
6569 } |
|
6570 // unstack loop blockscope |
|
6571 if (letscope) { |
|
6572 funct["(blockscope)"].unstack(); |
|
6573 } |
|
6574 return this; |
|
6575 }).labelled = true; |
|
6576 |
|
6577 |
|
6578 stmt("break", function () { |
|
6579 var v = state.tokens.next.value; |
|
6580 |
|
6581 if (funct["(breakage)"] === 0) |
|
6582 warning("W052", state.tokens.next, this.value); |
|
6583 |
|
6584 if (!state.option.asi) |
|
6585 nolinebreak(this); |
|
6586 |
|
6587 if (state.tokens.next.id !== ";") { |
|
6588 if (state.tokens.curr.line === state.tokens.next.line) { |
|
6589 if (funct[v] !== "label") { |
|
6590 warning("W090", state.tokens.next, v); |
|
6591 } else if (scope[v] !== funct) { |
|
6592 warning("W091", state.tokens.next, v); |
|
6593 } |
|
6594 this.first = state.tokens.next; |
|
6595 advance(); |
|
6596 } |
|
6597 } |
|
6598 reachable("break"); |
|
6599 return this; |
|
6600 }).exps = true; |
|
6601 |
|
6602 |
|
6603 stmt("continue", function () { |
|
6604 var v = state.tokens.next.value; |
|
6605 |
|
6606 if (funct["(breakage)"] === 0) |
|
6607 warning("W052", state.tokens.next, this.value); |
|
6608 |
|
6609 if (!state.option.asi) |
|
6610 nolinebreak(this); |
|
6611 |
|
6612 if (state.tokens.next.id !== ";") { |
|
6613 if (state.tokens.curr.line === state.tokens.next.line) { |
|
6614 if (funct[v] !== "label") { |
|
6615 warning("W090", state.tokens.next, v); |
|
6616 } else if (scope[v] !== funct) { |
|
6617 warning("W091", state.tokens.next, v); |
|
6618 } |
|
6619 this.first = state.tokens.next; |
|
6620 advance(); |
|
6621 } |
|
6622 } else if (!funct["(loopage)"]) { |
|
6623 warning("W052", state.tokens.next, this.value); |
|
6624 } |
|
6625 reachable("continue"); |
|
6626 return this; |
|
6627 }).exps = true; |
|
6628 |
|
6629 |
|
6630 stmt("return", function () { |
|
6631 if (this.line === state.tokens.next.line) { |
|
6632 if (state.tokens.next.id === "(regexp)") |
|
6633 warning("W092"); |
|
6634 |
|
6635 if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { |
|
6636 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6637 this.first = expression(0); |
|
6638 |
|
6639 if (this.first && |
|
6640 this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { |
|
6641 warningAt("W093", this.first.line, this.first.character); |
|
6642 } |
|
6643 } |
|
6644 } else { |
|
6645 if (state.tokens.next.type === "(punctuator)" && |
|
6646 ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { |
|
6647 nolinebreak(this); // always warn (Line breaking error) |
|
6648 } |
|
6649 } |
|
6650 reachable("return"); |
|
6651 return this; |
|
6652 }).exps = true; |
|
6653 |
|
6654 stmt("yield", function () { |
|
6655 if (state.option.inESNext(true) && funct["(generator)"] !== true) { |
|
6656 error("E046", state.tokens.curr, "yield"); |
|
6657 } else if (!state.option.inESNext()) { |
|
6658 warning("W104", state.tokens.curr, "yield"); |
|
6659 } |
|
6660 funct["(generator)"] = "yielded"; |
|
6661 if (this.line === state.tokens.next.line) { |
|
6662 if (state.tokens.next.id === "(regexp)") |
|
6663 warning("W092"); |
|
6664 |
|
6665 if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { |
|
6666 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6667 this.first = expression(0); |
|
6668 |
|
6669 if (this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { |
|
6670 warningAt("W093", this.first.line, this.first.character); |
|
6671 } |
|
6672 } |
|
6673 } else if (!state.option.asi) { |
|
6674 nolinebreak(this); // always warn (Line breaking error) |
|
6675 } |
|
6676 return this; |
|
6677 }).exps = true; |
|
6678 |
|
6679 |
|
6680 stmt("throw", function () { |
|
6681 nolinebreak(this); |
|
6682 nonadjacent(state.tokens.curr, state.tokens.next); |
|
6683 this.first = expression(20); |
|
6684 reachable("throw"); |
|
6685 return this; |
|
6686 }).exps = true; |
|
6687 |
|
6688 // Future Reserved Words |
|
6689 |
|
6690 FutureReservedWord("abstract"); |
|
6691 FutureReservedWord("boolean"); |
|
6692 FutureReservedWord("byte"); |
|
6693 FutureReservedWord("char"); |
|
6694 FutureReservedWord("class", { es5: true, nud: classdef }); |
|
6695 FutureReservedWord("double"); |
|
6696 FutureReservedWord("enum", { es5: true }); |
|
6697 FutureReservedWord("export", { es5: true }); |
|
6698 FutureReservedWord("extends", { es5: true }); |
|
6699 FutureReservedWord("final"); |
|
6700 FutureReservedWord("float"); |
|
6701 FutureReservedWord("goto"); |
|
6702 FutureReservedWord("implements", { es5: true, strictOnly: true }); |
|
6703 FutureReservedWord("import", { es5: true }); |
|
6704 FutureReservedWord("int"); |
|
6705 FutureReservedWord("interface", { es5: true, strictOnly: true }); |
|
6706 FutureReservedWord("long"); |
|
6707 FutureReservedWord("native"); |
|
6708 FutureReservedWord("package", { es5: true, strictOnly: true }); |
|
6709 FutureReservedWord("private", { es5: true, strictOnly: true }); |
|
6710 FutureReservedWord("protected", { es5: true, strictOnly: true }); |
|
6711 FutureReservedWord("public", { es5: true, strictOnly: true }); |
|
6712 FutureReservedWord("short"); |
|
6713 FutureReservedWord("static", { es5: true, strictOnly: true }); |
|
6714 FutureReservedWord("super", { es5: true }); |
|
6715 FutureReservedWord("synchronized"); |
|
6716 FutureReservedWord("throws"); |
|
6717 FutureReservedWord("transient"); |
|
6718 FutureReservedWord("volatile"); |
|
6719 |
|
6720 // this function is used to determine wether a squarebracket or a curlybracket |
|
6721 // expression is a comprehension array, destructuring assignment or a json value. |
|
6722 |
|
6723 var lookupBlockType = function () { |
|
6724 var pn, pn1; |
|
6725 var i = 0; |
|
6726 var bracketStack = 0; |
|
6727 var ret = {}; |
|
6728 if (_.contains(["[", "{"], state.tokens.curr.value)) |
|
6729 bracketStack += 1; |
|
6730 if (_.contains(["[", "{"], state.tokens.next.value)) |
|
6731 bracketStack += 1; |
|
6732 if (_.contains(["]", "}"], state.tokens.next.value)) |
|
6733 bracketStack -= 1; |
|
6734 do { |
|
6735 pn = peek(i); |
|
6736 pn1 = peek(i + 1); |
|
6737 i = i + 1; |
|
6738 if (_.contains(["[", "{"], pn.value)) { |
|
6739 bracketStack += 1; |
|
6740 } else if (_.contains(["]", "}"], pn.value)) { |
|
6741 bracketStack -= 1; |
|
6742 } |
|
6743 if (pn.identifier && pn.value === "for" && bracketStack === 1) { |
|
6744 ret.isCompArray = true; |
|
6745 ret.notJson = true; |
|
6746 break; |
|
6747 } |
|
6748 if (_.contains(["}", "]"], pn.value) && pn1.value === "=") { |
|
6749 ret.isDestAssign = true; |
|
6750 ret.notJson = true; |
|
6751 break; |
|
6752 } |
|
6753 if (pn.value === ";") { |
|
6754 ret.isBlock = true; |
|
6755 ret.notJson = true; |
|
6756 } |
|
6757 } while (bracketStack > 0 && pn.id !== "(end)" && i < 15); |
|
6758 return ret; |
|
6759 }; |
|
6760 |
|
6761 // Check whether this function has been reached for a destructuring assign with undeclared values |
|
6762 function destructuringAssignOrJsonValue() { |
|
6763 // lookup for the assignment (esnext only) |
|
6764 // if it has semicolons, it is a block, so go parse it as a block |
|
6765 // or it's not a block, but there are assignments, check for undeclared variables |
|
6766 |
|
6767 var block = lookupBlockType(); |
|
6768 if (block.notJson) { |
|
6769 if (!state.option.inESNext() && block.isDestAssign) { |
|
6770 warning("W104", state.tokens.curr, "destructuring assignment"); |
|
6771 } |
|
6772 statements(); |
|
6773 // otherwise parse json value |
|
6774 } else { |
|
6775 state.option.laxbreak = true; |
|
6776 state.jsonMode = true; |
|
6777 jsonValue(); |
|
6778 } |
|
6779 } |
|
6780 |
|
6781 // array comprehension parsing function |
|
6782 // parses and defines the three states of the list comprehension in order |
|
6783 // to avoid defining global variables, but keeping them to the list comprehension scope |
|
6784 // only. The order of the states are as follows: |
|
6785 // * "use" which will be the returned iterative part of the list comprehension |
|
6786 // * "define" which will define the variables local to the list comprehension |
|
6787 // * "filter" which will help filter out values |
|
6788 |
|
6789 var arrayComprehension = function () { |
|
6790 var CompArray = function () { |
|
6791 this.mode = "use"; |
|
6792 this.variables = []; |
|
6793 }; |
|
6794 var _carrays = []; |
|
6795 var _current; |
|
6796 function declare(v) { |
|
6797 var l = _current.variables.filter(function (elt) { |
|
6798 // if it has, change its undef state |
|
6799 if (elt.value === v) { |
|
6800 elt.undef = false; |
|
6801 return v; |
|
6802 } |
|
6803 }).length; |
|
6804 return l !== 0; |
|
6805 } |
|
6806 function use(v) { |
|
6807 var l = _current.variables.filter(function (elt) { |
|
6808 // and if it has been defined |
|
6809 if (elt.value === v && !elt.undef) { |
|
6810 if (elt.unused === true) { |
|
6811 elt.unused = false; |
|
6812 } |
|
6813 return v; |
|
6814 } |
|
6815 }).length; |
|
6816 // otherwise we warn about it |
|
6817 return (l === 0); |
|
6818 } |
|
6819 return {stack: function () { |
|
6820 _current = new CompArray(); |
|
6821 _carrays.push(_current); |
|
6822 }, |
|
6823 unstack: function () { |
|
6824 _current.variables.filter(function (v) { |
|
6825 if (v.unused) |
|
6826 warning("W098", v.token, v.value); |
|
6827 if (v.undef) |
|
6828 isundef(v.funct, "W117", v.token, v.value); |
|
6829 }); |
|
6830 _carrays.splice(_carrays[_carrays.length - 1], 1); |
|
6831 _current = _carrays[_carrays.length - 1]; |
|
6832 }, |
|
6833 setState: function (s) { |
|
6834 if (_.contains(["use", "define", "filter"], s)) |
|
6835 _current.mode = s; |
|
6836 }, |
|
6837 check: function (v) { |
|
6838 // When we are in "use" state of the list comp, we enqueue that var |
|
6839 if (_current && _current.mode === "use") { |
|
6840 _current.variables.push({funct: funct, |
|
6841 token: state.tokens.curr, |
|
6842 value: v, |
|
6843 undef: true, |
|
6844 unused: false}); |
|
6845 return true; |
|
6846 // When we are in "define" state of the list comp, |
|
6847 } else if (_current && _current.mode === "define") { |
|
6848 // check if the variable has been used previously |
|
6849 if (!declare(v)) { |
|
6850 _current.variables.push({funct: funct, |
|
6851 token: state.tokens.curr, |
|
6852 value: v, |
|
6853 undef: false, |
|
6854 unused: true}); |
|
6855 } |
|
6856 return true; |
|
6857 // When we are in "filter" state, |
|
6858 } else if (_current && _current.mode === "filter") { |
|
6859 // we check whether current variable has been declared |
|
6860 if (use(v)) { |
|
6861 // if not we warn about it |
|
6862 isundef(funct, "W117", state.tokens.curr, v); |
|
6863 } |
|
6864 return true; |
|
6865 } |
|
6866 return false; |
|
6867 } |
|
6868 }; |
|
6869 }; |
|
6870 |
|
6871 |
|
6872 // Parse JSON |
|
6873 |
|
6874 function jsonValue() { |
|
6875 |
|
6876 function jsonObject() { |
|
6877 var o = {}, t = state.tokens.next; |
|
6878 advance("{"); |
|
6879 if (state.tokens.next.id !== "}") { |
|
6880 for (;;) { |
|
6881 if (state.tokens.next.id === "(end)") { |
|
6882 error("E026", state.tokens.next, t.line); |
|
6883 } else if (state.tokens.next.id === "}") { |
|
6884 warning("W094", state.tokens.curr); |
|
6885 break; |
|
6886 } else if (state.tokens.next.id === ",") { |
|
6887 error("E028", state.tokens.next); |
|
6888 } else if (state.tokens.next.id !== "(string)") { |
|
6889 warning("W095", state.tokens.next, state.tokens.next.value); |
|
6890 } |
|
6891 if (o[state.tokens.next.value] === true) { |
|
6892 warning("W075", state.tokens.next, state.tokens.next.value); |
|
6893 } else if ((state.tokens.next.value === "__proto__" && |
|
6894 !state.option.proto) || (state.tokens.next.value === "__iterator__" && |
|
6895 !state.option.iterator)) { |
|
6896 warning("W096", state.tokens.next, state.tokens.next.value); |
|
6897 } else { |
|
6898 o[state.tokens.next.value] = true; |
|
6899 } |
|
6900 advance(); |
|
6901 advance(":"); |
|
6902 jsonValue(); |
|
6903 if (state.tokens.next.id !== ",") { |
|
6904 break; |
|
6905 } |
|
6906 advance(","); |
|
6907 } |
|
6908 } |
|
6909 advance("}"); |
|
6910 } |
|
6911 |
|
6912 function jsonArray() { |
|
6913 var t = state.tokens.next; |
|
6914 advance("["); |
|
6915 if (state.tokens.next.id !== "]") { |
|
6916 for (;;) { |
|
6917 if (state.tokens.next.id === "(end)") { |
|
6918 error("E027", state.tokens.next, t.line); |
|
6919 } else if (state.tokens.next.id === "]") { |
|
6920 warning("W094", state.tokens.curr); |
|
6921 break; |
|
6922 } else if (state.tokens.next.id === ",") { |
|
6923 error("E028", state.tokens.next); |
|
6924 } |
|
6925 jsonValue(); |
|
6926 if (state.tokens.next.id !== ",") { |
|
6927 break; |
|
6928 } |
|
6929 advance(","); |
|
6930 } |
|
6931 } |
|
6932 advance("]"); |
|
6933 } |
|
6934 |
|
6935 switch (state.tokens.next.id) { |
|
6936 case "{": |
|
6937 jsonObject(); |
|
6938 break; |
|
6939 case "[": |
|
6940 jsonArray(); |
|
6941 break; |
|
6942 case "true": |
|
6943 case "false": |
|
6944 case "null": |
|
6945 case "(number)": |
|
6946 case "(string)": |
|
6947 advance(); |
|
6948 break; |
|
6949 case "-": |
|
6950 advance("-"); |
|
6951 if (state.tokens.curr.character !== state.tokens.next.from) { |
|
6952 warning("W011", state.tokens.curr); |
|
6953 } |
|
6954 adjacent(state.tokens.curr, state.tokens.next); |
|
6955 advance("(number)"); |
|
6956 break; |
|
6957 default: |
|
6958 error("E003", state.tokens.next); |
|
6959 } |
|
6960 } |
|
6961 |
|
6962 var blockScope = function () { |
|
6963 var _current = {}; |
|
6964 var _variables = [_current]; |
|
6965 |
|
6966 function _checkBlockLabels() { |
|
6967 for (var t in _current) { |
|
6968 if (_current[t]["(type)"] === "unused") { |
|
6969 if (state.option.unused) { |
|
6970 var tkn = _current[t]["(token)"]; |
|
6971 var line = tkn.line; |
|
6972 var chr = tkn.character; |
|
6973 warningAt("W098", line, chr, t); |
|
6974 } |
|
6975 } |
|
6976 } |
|
6977 } |
|
6978 |
|
6979 return { |
|
6980 stack: function () { |
|
6981 _current = {}; |
|
6982 _variables.push(_current); |
|
6983 }, |
|
6984 |
|
6985 unstack: function () { |
|
6986 _checkBlockLabels(); |
|
6987 _variables.splice(_variables.length - 1, 1); |
|
6988 _current = _.last(_variables); |
|
6989 }, |
|
6990 |
|
6991 getlabel: function (l) { |
|
6992 for (var i = _variables.length - 1 ; i >= 0; --i) { |
|
6993 if (_.has(_variables[i], l)) { |
|
6994 return _variables[i]; |
|
6995 } |
|
6996 } |
|
6997 }, |
|
6998 |
|
6999 current: { |
|
7000 has: function (t) { |
|
7001 return _.has(_current, t); |
|
7002 }, |
|
7003 add: function (t, type, tok) { |
|
7004 _current[t] = { "(type)" : type, |
|
7005 "(token)": tok }; |
|
7006 } |
|
7007 } |
|
7008 }; |
|
7009 }; |
|
7010 |
|
7011 // The actual JSHINT function itself. |
|
7012 var itself = function (s, o, g) { |
|
7013 var a, i, k, x; |
|
7014 var optionKeys; |
|
7015 var newOptionObj = {}; |
|
7016 var newIgnoredObj = {}; |
|
7017 |
|
7018 state.reset(); |
|
7019 |
|
7020 if (o && o.scope) { |
|
7021 JSHINT.scope = o.scope; |
|
7022 } else { |
|
7023 JSHINT.errors = []; |
|
7024 JSHINT.undefs = []; |
|
7025 JSHINT.internals = []; |
|
7026 JSHINT.blacklist = {}; |
|
7027 JSHINT.scope = "(main)"; |
|
7028 } |
|
7029 |
|
7030 predefined = Object.create(null); |
|
7031 combine(predefined, vars.ecmaIdentifiers); |
|
7032 combine(predefined, vars.reservedVars); |
|
7033 |
|
7034 combine(predefined, g || {}); |
|
7035 |
|
7036 declared = Object.create(null); |
|
7037 exported = Object.create(null); |
|
7038 |
|
7039 if (o) { |
|
7040 a = o.predef; |
|
7041 if (a) { |
|
7042 if (!Array.isArray(a) && typeof a === "object") { |
|
7043 a = Object.keys(a); |
|
7044 } |
|
7045 |
|
7046 a.forEach(function (item) { |
|
7047 var slice, prop; |
|
7048 |
|
7049 if (item[0] === "-") { |
|
7050 slice = item.slice(1); |
|
7051 JSHINT.blacklist[slice] = slice; |
|
7052 } else { |
|
7053 prop = Object.getOwnPropertyDescriptor(o.predef, item); |
|
7054 predefined[item] = prop ? prop.value : false; |
|
7055 } |
|
7056 }); |
|
7057 } |
|
7058 |
|
7059 optionKeys = Object.keys(o); |
|
7060 for (x = 0; x < optionKeys.length; x++) { |
|
7061 if (/^-W\d{3}$/g.test(optionKeys[x])) { |
|
7062 newIgnoredObj[optionKeys[x].slice(1)] = true; |
|
7063 } else { |
|
7064 newOptionObj[optionKeys[x]] = o[optionKeys[x]]; |
|
7065 |
|
7066 if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false) |
|
7067 newOptionObj["(explicitNewcap)"] = true; |
|
7068 |
|
7069 if (optionKeys[x] === "indent") |
|
7070 newOptionObj["(explicitIndent)"] = o[optionKeys[x]] === false ? false : true; |
|
7071 } |
|
7072 } |
|
7073 } |
|
7074 |
|
7075 state.option = newOptionObj; |
|
7076 state.ignored = newIgnoredObj; |
|
7077 |
|
7078 state.option.indent = state.option.indent || 4; |
|
7079 state.option.maxerr = state.option.maxerr || 50; |
|
7080 |
|
7081 indent = 1; |
|
7082 global = Object.create(predefined); |
|
7083 scope = global; |
|
7084 funct = { |
|
7085 "(global)": true, |
|
7086 "(name)": "(global)", |
|
7087 "(scope)": scope, |
|
7088 "(breakage)": 0, |
|
7089 "(loopage)": 0, |
|
7090 "(tokens)": {}, |
|
7091 "(metrics)": createMetrics(state.tokens.next), |
|
7092 "(blockscope)": blockScope(), |
|
7093 "(comparray)": arrayComprehension() |
|
7094 }; |
|
7095 functions = [funct]; |
|
7096 urls = []; |
|
7097 stack = null; |
|
7098 member = {}; |
|
7099 membersOnly = null; |
|
7100 implied = {}; |
|
7101 inblock = false; |
|
7102 lookahead = []; |
|
7103 warnings = 0; |
|
7104 unuseds = []; |
|
7105 |
|
7106 if (!isString(s) && !Array.isArray(s)) { |
|
7107 errorAt("E004", 0); |
|
7108 return false; |
|
7109 } |
|
7110 |
|
7111 api = { |
|
7112 get isJSON() { |
|
7113 return state.jsonMode; |
|
7114 }, |
|
7115 |
|
7116 getOption: function (name) { |
|
7117 return state.option[name] || null; |
|
7118 }, |
|
7119 |
|
7120 getCache: function (name) { |
|
7121 return state.cache[name]; |
|
7122 }, |
|
7123 |
|
7124 setCache: function (name, value) { |
|
7125 state.cache[name] = value; |
|
7126 }, |
|
7127 |
|
7128 warn: function (code, data) { |
|
7129 warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); |
|
7130 }, |
|
7131 |
|
7132 on: function (names, listener) { |
|
7133 names.split(" ").forEach(function (name) { |
|
7134 emitter.on(name, listener); |
|
7135 }.bind(this)); |
|
7136 } |
|
7137 }; |
|
7138 |
|
7139 emitter.removeAllListeners(); |
|
7140 (extraModules || []).forEach(function (func) { |
|
7141 func(api); |
|
7142 }); |
|
7143 |
|
7144 state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; |
|
7145 |
|
7146 lex = new Lexer(s); |
|
7147 |
|
7148 lex.on("warning", function (ev) { |
|
7149 warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); |
|
7150 }); |
|
7151 |
|
7152 lex.on("error", function (ev) { |
|
7153 errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); |
|
7154 }); |
|
7155 |
|
7156 lex.on("fatal", function (ev) { |
|
7157 quit("E041", ev.line, ev.from); |
|
7158 }); |
|
7159 |
|
7160 lex.on("Identifier", function (ev) { |
|
7161 emitter.emit("Identifier", ev); |
|
7162 }); |
|
7163 |
|
7164 lex.on("String", function (ev) { |
|
7165 emitter.emit("String", ev); |
|
7166 }); |
|
7167 |
|
7168 lex.on("Number", function (ev) { |
|
7169 emitter.emit("Number", ev); |
|
7170 }); |
|
7171 |
|
7172 lex.start(); |
|
7173 |
|
7174 // Check options |
|
7175 for (var name in o) { |
|
7176 if (_.has(o, name)) { |
|
7177 checkOption(name, state.tokens.curr); |
|
7178 } |
|
7179 } |
|
7180 |
|
7181 assume(); |
|
7182 |
|
7183 // combine the passed globals after we've assumed all our options |
|
7184 combine(predefined, g || {}); |
|
7185 |
|
7186 //reset values |
|
7187 comma.first = true; |
|
7188 |
|
7189 try { |
|
7190 advance(); |
|
7191 switch (state.tokens.next.id) { |
|
7192 case "{": |
|
7193 case "[": |
|
7194 destructuringAssignOrJsonValue(); |
|
7195 break; |
|
7196 default: |
|
7197 directives(); |
|
7198 |
|
7199 if (state.directive["use strict"]) { |
|
7200 if (!state.option.globalstrict && !state.option.node) { |
|
7201 warning("W097", state.tokens.prev); |
|
7202 } |
|
7203 } |
|
7204 |
|
7205 statements(); |
|
7206 } |
|
7207 advance((state.tokens.next && state.tokens.next.value !== ".") ? "(end)" : undefined); |
|
7208 funct["(blockscope)"].unstack(); |
|
7209 |
|
7210 var markDefined = function (name, context) { |
|
7211 do { |
|
7212 if (typeof context[name] === "string") { |
|
7213 // JSHINT marks unused variables as 'unused' and |
|
7214 // unused function declaration as 'unction'. This |
|
7215 // code changes such instances back 'var' and |
|
7216 // 'closure' so that the code in JSHINT.data() |
|
7217 // doesn't think they're unused. |
|
7218 |
|
7219 if (context[name] === "unused") |
|
7220 context[name] = "var"; |
|
7221 else if (context[name] === "unction") |
|
7222 context[name] = "closure"; |
|
7223 |
|
7224 return true; |
|
7225 } |
|
7226 |
|
7227 context = context["(context)"]; |
|
7228 } while (context); |
|
7229 |
|
7230 return false; |
|
7231 }; |
|
7232 |
|
7233 var clearImplied = function (name, line) { |
|
7234 if (!implied[name]) |
|
7235 return; |
|
7236 |
|
7237 var newImplied = []; |
|
7238 for (var i = 0; i < implied[name].length; i += 1) { |
|
7239 if (implied[name][i] !== line) |
|
7240 newImplied.push(implied[name][i]); |
|
7241 } |
|
7242 |
|
7243 if (newImplied.length === 0) |
|
7244 delete implied[name]; |
|
7245 else |
|
7246 implied[name] = newImplied; |
|
7247 }; |
|
7248 |
|
7249 var warnUnused = function (name, tkn, type, unused_opt) { |
|
7250 var line = tkn.line; |
|
7251 var chr = tkn.character; |
|
7252 |
|
7253 if (unused_opt === undefined) { |
|
7254 unused_opt = state.option.unused; |
|
7255 } |
|
7256 |
|
7257 if (unused_opt === true) { |
|
7258 unused_opt = "last-param"; |
|
7259 } |
|
7260 |
|
7261 var warnable_types = { |
|
7262 "vars": ["var"], |
|
7263 "last-param": ["var", "param"], |
|
7264 "strict": ["var", "param", "last-param"] |
|
7265 }; |
|
7266 |
|
7267 if (unused_opt) { |
|
7268 if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { |
|
7269 warningAt("W098", line, chr, name); |
|
7270 } |
|
7271 } |
|
7272 |
|
7273 unuseds.push({ |
|
7274 name: name, |
|
7275 line: line, |
|
7276 character: chr |
|
7277 }); |
|
7278 }; |
|
7279 |
|
7280 var checkUnused = function (func, key) { |
|
7281 var type = func[key]; |
|
7282 var tkn = func["(tokens)"][key]; |
|
7283 |
|
7284 if (key.charAt(0) === "(") |
|
7285 return; |
|
7286 |
|
7287 if (type !== "unused" && type !== "unction") |
|
7288 return; |
|
7289 |
|
7290 // Params are checked separately from other variables. |
|
7291 if (func["(params)"] && func["(params)"].indexOf(key) !== -1) |
|
7292 return; |
|
7293 |
|
7294 // Variable is in global scope and defined as exported. |
|
7295 if (func["(global)"] && _.has(exported, key)) { |
|
7296 return; |
|
7297 } |
|
7298 |
|
7299 warnUnused(key, tkn, "var"); |
|
7300 }; |
|
7301 |
|
7302 // Check queued 'x is not defined' instances to see if they're still undefined. |
|
7303 for (i = 0; i < JSHINT.undefs.length; i += 1) { |
|
7304 k = JSHINT.undefs[i].slice(0); |
|
7305 |
|
7306 if (markDefined(k[2].value, k[0])) { |
|
7307 clearImplied(k[2].value, k[2].line); |
|
7308 } else if (state.option.undef) { |
|
7309 warning.apply(warning, k.slice(1)); |
|
7310 } |
|
7311 } |
|
7312 |
|
7313 functions.forEach(function (func) { |
|
7314 if (func["(unusedOption)"] === false) { |
|
7315 return; |
|
7316 } |
|
7317 |
|
7318 for (var key in func) { |
|
7319 if (_.has(func, key)) { |
|
7320 checkUnused(func, key); |
|
7321 } |
|
7322 } |
|
7323 |
|
7324 if (!func["(params)"]) |
|
7325 return; |
|
7326 |
|
7327 var params = func["(params)"].slice(); |
|
7328 var param = params.pop(); |
|
7329 var type, unused_opt; |
|
7330 |
|
7331 while (param) { |
|
7332 type = func[param]; |
|
7333 unused_opt = func["(unusedOption)"] || state.option.unused; |
|
7334 unused_opt = unused_opt === true ? "last-param" : unused_opt; |
|
7335 |
|
7336 // 'undefined' is a special case for (function (window, undefined) { ... })(); |
|
7337 // patterns. |
|
7338 |
|
7339 if (param === "undefined") |
|
7340 return; |
|
7341 |
|
7342 if (type === "unused" || type === "unction") { |
|
7343 warnUnused(param, func["(tokens)"][param], "param", func["(unusedOption)"]); |
|
7344 } else if (unused_opt === "last-param") { |
|
7345 return; |
|
7346 } |
|
7347 |
|
7348 param = params.pop(); |
|
7349 } |
|
7350 }); |
|
7351 |
|
7352 for (var key in declared) { |
|
7353 if (_.has(declared, key) && !_.has(global, key)) { |
|
7354 warnUnused(key, declared[key], "var"); |
|
7355 } |
|
7356 } |
|
7357 |
|
7358 } catch (err) { |
|
7359 if (err && err.name === "JSHintError") { |
|
7360 var nt = state.tokens.next || {}; |
|
7361 JSHINT.errors.push({ |
|
7362 scope : "(main)", |
|
7363 raw : err.raw, |
|
7364 reason : err.message, |
|
7365 line : err.line || nt.line, |
|
7366 character : err.character || nt.from |
|
7367 }, null); |
|
7368 } else { |
|
7369 throw err; |
|
7370 } |
|
7371 } |
|
7372 |
|
7373 // Loop over the listed "internals", and check them as well. |
|
7374 |
|
7375 if (JSHINT.scope === "(main)") { |
|
7376 o = o || {}; |
|
7377 |
|
7378 for (i = 0; i < JSHINT.internals.length; i += 1) { |
|
7379 k = JSHINT.internals[i]; |
|
7380 o.scope = k.elem; |
|
7381 itself(k.value, o, g); |
|
7382 } |
|
7383 } |
|
7384 |
|
7385 return JSHINT.errors.length === 0; |
|
7386 }; |
|
7387 |
|
7388 // Modules. |
|
7389 itself.addModule = function (func) { |
|
7390 extraModules.push(func); |
|
7391 }; |
|
7392 |
|
7393 itself.addModule(style.register); |
|
7394 |
|
7395 // Data summary. |
|
7396 itself.data = function () { |
|
7397 var data = { |
|
7398 functions: [], |
|
7399 options: state.option |
|
7400 }; |
|
7401 var implieds = []; |
|
7402 var members = []; |
|
7403 var fu, f, i, j, n, globals; |
|
7404 |
|
7405 if (itself.errors.length) { |
|
7406 data.errors = itself.errors; |
|
7407 } |
|
7408 |
|
7409 if (state.jsonMode) { |
|
7410 data.json = true; |
|
7411 } |
|
7412 |
|
7413 for (n in implied) { |
|
7414 if (_.has(implied, n)) { |
|
7415 implieds.push({ |
|
7416 name: n, |
|
7417 line: implied[n] |
|
7418 }); |
|
7419 } |
|
7420 } |
|
7421 |
|
7422 if (implieds.length > 0) { |
|
7423 data.implieds = implieds; |
|
7424 } |
|
7425 |
|
7426 if (urls.length > 0) { |
|
7427 data.urls = urls; |
|
7428 } |
|
7429 |
|
7430 globals = Object.keys(scope); |
|
7431 if (globals.length > 0) { |
|
7432 data.globals = globals; |
|
7433 } |
|
7434 |
|
7435 for (i = 1; i < functions.length; i += 1) { |
|
7436 f = functions[i]; |
|
7437 fu = {}; |
|
7438 |
|
7439 for (j = 0; j < functionicity.length; j += 1) { |
|
7440 fu[functionicity[j]] = []; |
|
7441 } |
|
7442 |
|
7443 for (j = 0; j < functionicity.length; j += 1) { |
|
7444 if (fu[functionicity[j]].length === 0) { |
|
7445 delete fu[functionicity[j]]; |
|
7446 } |
|
7447 } |
|
7448 |
|
7449 fu.name = f["(name)"]; |
|
7450 fu.param = f["(params)"]; |
|
7451 fu.line = f["(line)"]; |
|
7452 fu.character = f["(character)"]; |
|
7453 fu.last = f["(last)"]; |
|
7454 fu.lastcharacter = f["(lastcharacter)"]; |
|
7455 data.functions.push(fu); |
|
7456 } |
|
7457 |
|
7458 if (unuseds.length > 0) { |
|
7459 data.unused = unuseds; |
|
7460 } |
|
7461 |
|
7462 members = []; |
|
7463 for (n in member) { |
|
7464 if (typeof member[n] === "number") { |
|
7465 data.member = member; |
|
7466 break; |
|
7467 } |
|
7468 } |
|
7469 |
|
7470 return data; |
|
7471 }; |
|
7472 |
|
7473 itself.jshint = itself; |
|
7474 |
|
7475 return itself; |
|
7476 }()); |
|
7477 |
|
7478 // Make JSHINT a Node module, if possible. |
|
7479 if (typeof exports === "object" && exports) { |
|
7480 exports.JSHINT = JSHINT; |
|
7481 } |
|
7482 |
|
7483 })() |
|
7484 },{"events":2,"../shared/vars.js":3,"./lex.js":10,"./reg.js":6,"./state.js":4,"../shared/messages.js":12,"./style.js":5,"console-browserify":7,"underscore":11}],12:[function(require,module,exports){ |
|
7485 (function(){"use strict"; |
|
7486 |
|
7487 var _ = require("underscore"); |
|
7488 |
|
7489 var errors = { |
|
7490 // JSHint options |
|
7491 E001: "Bad option: '{a}'.", |
|
7492 E002: "Bad option value.", |
|
7493 |
|
7494 // JSHint input |
|
7495 E003: "Expected a JSON value.", |
|
7496 E004: "Input is neither a string nor an array of strings.", |
|
7497 E005: "Input is empty.", |
|
7498 E006: "Unexpected early end of program.", |
|
7499 |
|
7500 // Strict mode |
|
7501 E007: "Missing \"use strict\" statement.", |
|
7502 E008: "Strict violation.", |
|
7503 E009: "Option 'validthis' can't be used in a global scope.", |
|
7504 E010: "'with' is not allowed in strict mode.", |
|
7505 |
|
7506 // Constants |
|
7507 E011: "const '{a}' has already been declared.", |
|
7508 E012: "const '{a}' is initialized to 'undefined'.", |
|
7509 E013: "Attempting to override '{a}' which is a constant.", |
|
7510 |
|
7511 // Regular expressions |
|
7512 E014: "A regular expression literal can be confused with '/='.", |
|
7513 E015: "Unclosed regular expression.", |
|
7514 E016: "Invalid regular expression.", |
|
7515 |
|
7516 // Tokens |
|
7517 E017: "Unclosed comment.", |
|
7518 E018: "Unbegun comment.", |
|
7519 E019: "Unmatched '{a}'.", |
|
7520 E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", |
|
7521 E021: "Expected '{a}' and instead saw '{b}'.", |
|
7522 E022: "Line breaking error '{a}'.", |
|
7523 E023: "Missing '{a}'.", |
|
7524 E024: "Unexpected '{a}'.", |
|
7525 E025: "Missing ':' on a case clause.", |
|
7526 E026: "Missing '}' to match '{' from line {a}.", |
|
7527 E027: "Missing ']' to match '[' form line {a}.", |
|
7528 E028: "Illegal comma.", |
|
7529 E029: "Unclosed string.", |
|
7530 |
|
7531 // Everything else |
|
7532 E030: "Expected an identifier and instead saw '{a}'.", |
|
7533 E031: "Bad assignment.", // FIXME: Rephrase |
|
7534 E032: "Expected a small integer or 'false' and instead saw '{a}'.", |
|
7535 E033: "Expected an operator and instead saw '{a}'.", |
|
7536 E034: "get/set are ES5 features.", |
|
7537 E035: "Missing property name.", |
|
7538 E036: "Expected to see a statement and instead saw a block.", |
|
7539 E037: "Constant {a} was not declared correctly.", |
|
7540 E038: "Variable {a} was not declared correctly.", |
|
7541 E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", |
|
7542 E040: "Each value should have its own case label.", |
|
7543 E041: "Unrecoverable syntax error.", |
|
7544 E042: "Stopping.", |
|
7545 E043: "Too many errors.", |
|
7546 E044: "'{a}' is already defined and can't be redefined.", |
|
7547 E045: "Invalid for each loop.", |
|
7548 E046: "A yield statement shall be within a generator function (with syntax: `function*`)", |
|
7549 E047: "A generator function shall contain a yield statement.", |
|
7550 E048: "Let declaration not directly within block.", |
|
7551 E049: "A {a} cannot be named '{b}'." |
|
7552 }; |
|
7553 |
|
7554 var warnings = { |
|
7555 W001: "'hasOwnProperty' is a really bad name.", |
|
7556 W002: "Value of '{a}' may be overwritten in IE.", |
|
7557 W003: "'{a}' was used before it was defined.", |
|
7558 W004: "'{a}' is already defined.", |
|
7559 W005: "A dot following a number can be confused with a decimal point.", |
|
7560 W006: "Confusing minuses.", |
|
7561 W007: "Confusing pluses.", |
|
7562 W008: "A leading decimal point can be confused with a dot: '{a}'.", |
|
7563 W009: "The array literal notation [] is preferrable.", |
|
7564 W010: "The object literal notation {} is preferrable.", |
|
7565 W011: "Unexpected space after '{a}'.", |
|
7566 W012: "Unexpected space before '{a}'.", |
|
7567 W013: "Missing space after '{a}'.", |
|
7568 W014: "Bad line breaking before '{a}'.", |
|
7569 W015: "Expected '{a}' to have an indentation at {b} instead at {c}.", |
|
7570 W016: "Unexpected use of '{a}'.", |
|
7571 W017: "Bad operand.", |
|
7572 W018: "Confusing use of '{a}'.", |
|
7573 W019: "Use the isNaN function to compare with NaN.", |
|
7574 W020: "Read only.", |
|
7575 W021: "'{a}' is a function.", |
|
7576 W022: "Do not assign to the exception parameter.", |
|
7577 W023: "Expected an identifier in an assignment and instead saw a function invocation.", |
|
7578 W024: "Expected an identifier and instead saw '{a}' (a reserved word).", |
|
7579 W025: "Missing name in function declaration.", |
|
7580 W026: "Inner functions should be listed at the top of the outer function.", |
|
7581 W027: "Unreachable '{a}' after '{b}'.", |
|
7582 W028: "Label '{a}' on {b} statement.", |
|
7583 W030: "Expected an assignment or function call and instead saw an expression.", |
|
7584 W031: "Do not use 'new' for side effects.", |
|
7585 W032: "Unnecessary semicolon.", |
|
7586 W033: "Missing semicolon.", |
|
7587 W034: "Unnecessary directive \"{a}\".", |
|
7588 W035: "Empty block.", |
|
7589 W036: "Unexpected /*member '{a}'.", |
|
7590 W037: "'{a}' is a statement label.", |
|
7591 W038: "'{a}' used out of scope.", |
|
7592 W039: "'{a}' is not allowed.", |
|
7593 W040: "Possible strict violation.", |
|
7594 W041: "Use '{a}' to compare with '{b}'.", |
|
7595 W042: "Avoid EOL escaping.", |
|
7596 W043: "Bad escaping of EOL. Use option multistr if needed.", |
|
7597 W044: "Bad or unnecessary escaping.", |
|
7598 W045: "Bad number '{a}'.", |
|
7599 W046: "Don't use extra leading zeros '{a}'.", |
|
7600 W047: "A trailing decimal point can be confused with a dot: '{a}'.", |
|
7601 W048: "Unexpected control character in regular expression.", |
|
7602 W049: "Unexpected escaped character '{a}' in regular expression.", |
|
7603 W050: "JavaScript URL.", |
|
7604 W051: "Variables should not be deleted.", |
|
7605 W052: "Unexpected '{a}'.", |
|
7606 W053: "Do not use {a} as a constructor.", |
|
7607 W054: "The Function constructor is a form of eval.", |
|
7608 W055: "A constructor name should start with an uppercase letter.", |
|
7609 W056: "Bad constructor.", |
|
7610 W057: "Weird construction. Is 'new' unnecessary?", |
|
7611 W058: "Missing '()' invoking a constructor.", |
|
7612 W059: "Avoid arguments.{a}.", |
|
7613 W060: "document.write can be a form of eval.", |
|
7614 W061: "eval can be harmful.", |
|
7615 W062: "Wrap an immediate function invocation in parens " + |
|
7616 "to assist the reader in understanding that the expression " + |
|
7617 "is the result of a function, and not the function itself.", |
|
7618 W063: "Math is not a function.", |
|
7619 W064: "Missing 'new' prefix when invoking a constructor.", |
|
7620 W065: "Missing radix parameter.", |
|
7621 W066: "Implied eval. Consider passing a function instead of a string.", |
|
7622 W067: "Bad invocation.", |
|
7623 W068: "Wrapping non-IIFE function literals in parens is unnecessary.", |
|
7624 W069: "['{a}'] is better written in dot notation.", |
|
7625 W070: "Extra comma. (it breaks older versions of IE)", |
|
7626 W071: "This function has too many statements. ({a})", |
|
7627 W072: "This function has too many parameters. ({a})", |
|
7628 W073: "Blocks are nested too deeply. ({a})", |
|
7629 W074: "This function's cyclomatic complexity is too high. ({a})", |
|
7630 W075: "Duplicate key '{a}'.", |
|
7631 W076: "Unexpected parameter '{a}' in get {b} function.", |
|
7632 W077: "Expected a single parameter in set {a} function.", |
|
7633 W078: "Setter is defined without getter.", |
|
7634 W079: "Redefinition of '{a}'.", |
|
7635 W080: "It's not necessary to initialize '{a}' to 'undefined'.", |
|
7636 W081: "Too many var statements.", |
|
7637 W082: "Function declarations should not be placed in blocks. " + |
|
7638 "Use a function expression or move the statement to the top of " + |
|
7639 "the outer function.", |
|
7640 W083: "Don't make functions within a loop.", |
|
7641 W084: "Expected a conditional expression and instead saw an assignment.", |
|
7642 W085: "Don't use 'with'.", |
|
7643 W086: "Expected a 'break' statement before '{a}'.", |
|
7644 W087: "Forgotten 'debugger' statement?", |
|
7645 W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", |
|
7646 W089: "The body of a for in should be wrapped in an if statement to filter " + |
|
7647 "unwanted properties from the prototype.", |
|
7648 W090: "'{a}' is not a statement label.", |
|
7649 W091: "'{a}' is out of scope.", |
|
7650 W092: "Wrap the /regexp/ literal in parens to disambiguate the slash operator.", |
|
7651 W093: "Did you mean to return a conditional instead of an assignment?", |
|
7652 W094: "Unexpected comma.", |
|
7653 W095: "Expected a string and instead saw {a}.", |
|
7654 W096: "The '{a}' key may produce unexpected results.", |
|
7655 W097: "Use the function form of \"use strict\".", |
|
7656 W098: "'{a}' is defined but never used.", |
|
7657 W099: "Mixed spaces and tabs.", |
|
7658 W100: "This character may get silently deleted by one or more browsers.", |
|
7659 W101: "Line is too long.", |
|
7660 W102: "Trailing whitespace.", |
|
7661 W103: "The '{a}' property is deprecated.", |
|
7662 W104: "'{a}' is only available in JavaScript 1.7.", |
|
7663 W105: "Unexpected {a} in '{b}'.", |
|
7664 W106: "Identifier '{a}' is not in camel case.", |
|
7665 W107: "Script URL.", |
|
7666 W108: "Strings must use doublequote.", |
|
7667 W109: "Strings must use singlequote.", |
|
7668 W110: "Mixed double and single quotes.", |
|
7669 W112: "Unclosed string.", |
|
7670 W113: "Control character in string: {a}.", |
|
7671 W114: "Avoid {a}.", |
|
7672 W115: "Octal literals are not allowed in strict mode.", |
|
7673 W116: "Expected '{a}' and instead saw '{b}'.", |
|
7674 W117: "'{a}' is not defined.", |
|
7675 W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", |
|
7676 W119: "'{a}' is only available in ES6 (use esnext option)." |
|
7677 }; |
|
7678 |
|
7679 var info = { |
|
7680 I001: "Comma warnings can be turned off with 'laxcomma'.", |
|
7681 I002: "Reserved words as properties can be used under the 'es5' option.", |
|
7682 I003: "ES5 option is now set per default" |
|
7683 }; |
|
7684 |
|
7685 exports.errors = {}; |
|
7686 exports.warnings = {}; |
|
7687 exports.info = {}; |
|
7688 |
|
7689 _.each(errors, function (desc, code) { |
|
7690 exports.errors[code] = { code: code, desc: desc }; |
|
7691 }); |
|
7692 |
|
7693 _.each(warnings, function (desc, code) { |
|
7694 exports.warnings[code] = { code: code, desc: desc }; |
|
7695 }); |
|
7696 |
|
7697 _.each(info, function (desc, code) { |
|
7698 exports.info[code] = { code: code, desc: desc }; |
|
7699 }); |
|
7700 |
|
7701 })() |
|
7702 },{"underscore":11}],8:[function(require,module,exports){ |
|
7703 var events = require('events'); |
|
7704 |
|
7705 exports.isArray = isArray; |
|
7706 exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'}; |
|
7707 exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'}; |
|
7708 |
|
7709 |
|
7710 exports.print = function () {}; |
|
7711 exports.puts = function () {}; |
|
7712 exports.debug = function() {}; |
|
7713 |
|
7714 exports.inspect = function(obj, showHidden, depth, colors) { |
|
7715 var seen = []; |
|
7716 |
|
7717 var stylize = function(str, styleType) { |
|
7718 // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics |
|
7719 var styles = |
|
7720 { 'bold' : [1, 22], |
|
7721 'italic' : [3, 23], |
|
7722 'underline' : [4, 24], |
|
7723 'inverse' : [7, 27], |
|
7724 'white' : [37, 39], |
|
7725 'grey' : [90, 39], |
|
7726 'black' : [30, 39], |
|
7727 'blue' : [34, 39], |
|
7728 'cyan' : [36, 39], |
|
7729 'green' : [32, 39], |
|
7730 'magenta' : [35, 39], |
|
7731 'red' : [31, 39], |
|
7732 'yellow' : [33, 39] }; |
|
7733 |
|
7734 var style = |
|
7735 { 'special': 'cyan', |
|
7736 'number': 'blue', |
|
7737 'boolean': 'yellow', |
|
7738 'undefined': 'grey', |
|
7739 'null': 'bold', |
|
7740 'string': 'green', |
|
7741 'date': 'magenta', |
|
7742 // "name": intentionally not styling |
|
7743 'regexp': 'red' }[styleType]; |
|
7744 |
|
7745 if (style) { |
|
7746 return '\033[' + styles[style][0] + 'm' + str + |
|
7747 '\033[' + styles[style][1] + 'm'; |
|
7748 } else { |
|
7749 return str; |
|
7750 } |
|
7751 }; |
|
7752 if (! colors) { |
|
7753 stylize = function(str, styleType) { return str; }; |
|
7754 } |
|
7755 |
|
7756 function format(value, recurseTimes) { |
|
7757 // Provide a hook for user-specified inspect functions. |
|
7758 // Check that value is an object with an inspect function on it |
|
7759 if (value && typeof value.inspect === 'function' && |
|
7760 // Filter out the util module, it's inspect function is special |
|
7761 value !== exports && |
|
7762 // Also filter out any prototype objects using the circular check. |
|
7763 !(value.constructor && value.constructor.prototype === value)) { |
|
7764 return value.inspect(recurseTimes); |
|
7765 } |
|
7766 |
|
7767 // Primitive types cannot have properties |
|
7768 switch (typeof value) { |
|
7769 case 'undefined': |
|
7770 return stylize('undefined', 'undefined'); |
|
7771 |
|
7772 case 'string': |
|
7773 var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') |
|
7774 .replace(/'/g, "\\'") |
|
7775 .replace(/\\"/g, '"') + '\''; |
|
7776 return stylize(simple, 'string'); |
|
7777 |
|
7778 case 'number': |
|
7779 return stylize('' + value, 'number'); |
|
7780 |
|
7781 case 'boolean': |
|
7782 return stylize('' + value, 'boolean'); |
|
7783 } |
|
7784 // For some reason typeof null is "object", so special case here. |
|
7785 if (value === null) { |
|
7786 return stylize('null', 'null'); |
|
7787 } |
|
7788 |
|
7789 // Look up the keys of the object. |
|
7790 var visible_keys = Object_keys(value); |
|
7791 var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys; |
|
7792 |
|
7793 // Functions without properties can be shortcutted. |
|
7794 if (typeof value === 'function' && keys.length === 0) { |
|
7795 if (isRegExp(value)) { |
|
7796 return stylize('' + value, 'regexp'); |
|
7797 } else { |
|
7798 var name = value.name ? ': ' + value.name : ''; |
|
7799 return stylize('[Function' + name + ']', 'special'); |
|
7800 } |
|
7801 } |
|
7802 |
|
7803 // Dates without properties can be shortcutted |
|
7804 if (isDate(value) && keys.length === 0) { |
|
7805 return stylize(value.toUTCString(), 'date'); |
|
7806 } |
|
7807 |
|
7808 var base, type, braces; |
|
7809 // Determine the object type |
|
7810 if (isArray(value)) { |
|
7811 type = 'Array'; |
|
7812 braces = ['[', ']']; |
|
7813 } else { |
|
7814 type = 'Object'; |
|
7815 braces = ['{', '}']; |
|
7816 } |
|
7817 |
|
7818 // Make functions say that they are functions |
|
7819 if (typeof value === 'function') { |
|
7820 var n = value.name ? ': ' + value.name : ''; |
|
7821 base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; |
|
7822 } else { |
|
7823 base = ''; |
|
7824 } |
|
7825 |
|
7826 // Make dates with properties first say the date |
|
7827 if (isDate(value)) { |
|
7828 base = ' ' + value.toUTCString(); |
|
7829 } |
|
7830 |
|
7831 if (keys.length === 0) { |
|
7832 return braces[0] + base + braces[1]; |
|
7833 } |
|
7834 |
|
7835 if (recurseTimes < 0) { |
|
7836 if (isRegExp(value)) { |
|
7837 return stylize('' + value, 'regexp'); |
|
7838 } else { |
|
7839 return stylize('[Object]', 'special'); |
|
7840 } |
|
7841 } |
|
7842 |
|
7843 seen.push(value); |
|
7844 |
|
7845 var output = keys.map(function(key) { |
|
7846 var name, str; |
|
7847 if (value.__lookupGetter__) { |
|
7848 if (value.__lookupGetter__(key)) { |
|
7849 if (value.__lookupSetter__(key)) { |
|
7850 str = stylize('[Getter/Setter]', 'special'); |
|
7851 } else { |
|
7852 str = stylize('[Getter]', 'special'); |
|
7853 } |
|
7854 } else { |
|
7855 if (value.__lookupSetter__(key)) { |
|
7856 str = stylize('[Setter]', 'special'); |
|
7857 } |
|
7858 } |
|
7859 } |
|
7860 if (visible_keys.indexOf(key) < 0) { |
|
7861 name = '[' + key + ']'; |
|
7862 } |
|
7863 if (!str) { |
|
7864 if (seen.indexOf(value[key]) < 0) { |
|
7865 if (recurseTimes === null) { |
|
7866 str = format(value[key]); |
|
7867 } else { |
|
7868 str = format(value[key], recurseTimes - 1); |
|
7869 } |
|
7870 if (str.indexOf('\n') > -1) { |
|
7871 if (isArray(value)) { |
|
7872 str = str.split('\n').map(function(line) { |
|
7873 return ' ' + line; |
|
7874 }).join('\n').substr(2); |
|
7875 } else { |
|
7876 str = '\n' + str.split('\n').map(function(line) { |
|
7877 return ' ' + line; |
|
7878 }).join('\n'); |
|
7879 } |
|
7880 } |
|
7881 } else { |
|
7882 str = stylize('[Circular]', 'special'); |
|
7883 } |
|
7884 } |
|
7885 if (typeof name === 'undefined') { |
|
7886 if (type === 'Array' && key.match(/^\d+$/)) { |
|
7887 return str; |
|
7888 } |
|
7889 name = JSON.stringify('' + key); |
|
7890 if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { |
|
7891 name = name.substr(1, name.length - 2); |
|
7892 name = stylize(name, 'name'); |
|
7893 } else { |
|
7894 name = name.replace(/'/g, "\\'") |
|
7895 .replace(/\\"/g, '"') |
|
7896 .replace(/(^"|"$)/g, "'"); |
|
7897 name = stylize(name, 'string'); |
|
7898 } |
|
7899 } |
|
7900 |
|
7901 return name + ': ' + str; |
|
7902 }); |
|
7903 |
|
7904 seen.pop(); |
|
7905 |
|
7906 var numLinesEst = 0; |
|
7907 var length = output.reduce(function(prev, cur) { |
|
7908 numLinesEst++; |
|
7909 if (cur.indexOf('\n') >= 0) numLinesEst++; |
|
7910 return prev + cur.length + 1; |
|
7911 }, 0); |
|
7912 |
|
7913 if (length > 50) { |
|
7914 output = braces[0] + |
|
7915 (base === '' ? '' : base + '\n ') + |
|
7916 ' ' + |
|
7917 output.join(',\n ') + |
|
7918 ' ' + |
|
7919 braces[1]; |
|
7920 |
|
7921 } else { |
|
7922 output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; |
|
7923 } |
|
7924 |
|
7925 return output; |
|
7926 } |
|
7927 return format(obj, (typeof depth === 'undefined' ? 2 : depth)); |
|
7928 }; |
|
7929 |
|
7930 |
|
7931 function isArray(ar) { |
|
7932 return ar instanceof Array || |
|
7933 Array.isArray(ar) || |
|
7934 (ar && ar !== Object.prototype && isArray(ar.__proto__)); |
|
7935 } |
|
7936 |
|
7937 |
|
7938 function isRegExp(re) { |
|
7939 return re instanceof RegExp || |
|
7940 (typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]'); |
|
7941 } |
|
7942 |
|
7943 |
|
7944 function isDate(d) { |
|
7945 if (d instanceof Date) return true; |
|
7946 if (typeof d !== 'object') return false; |
|
7947 var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype); |
|
7948 var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__); |
|
7949 return JSON.stringify(proto) === JSON.stringify(properties); |
|
7950 } |
|
7951 |
|
7952 function pad(n) { |
|
7953 return n < 10 ? '0' + n.toString(10) : n.toString(10); |
|
7954 } |
|
7955 |
|
7956 var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', |
|
7957 'Oct', 'Nov', 'Dec']; |
|
7958 |
|
7959 // 26 Feb 16:19:34 |
|
7960 function timestamp() { |
|
7961 var d = new Date(); |
|
7962 var time = [pad(d.getHours()), |
|
7963 pad(d.getMinutes()), |
|
7964 pad(d.getSeconds())].join(':'); |
|
7965 return [d.getDate(), months[d.getMonth()], time].join(' '); |
|
7966 } |
|
7967 |
|
7968 exports.log = function (msg) {}; |
|
7969 |
|
7970 exports.pump = null; |
|
7971 |
|
7972 var Object_keys = Object.keys || function (obj) { |
|
7973 var res = []; |
|
7974 for (var key in obj) res.push(key); |
|
7975 return res; |
|
7976 }; |
|
7977 |
|
7978 var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) { |
|
7979 var res = []; |
|
7980 for (var key in obj) { |
|
7981 if (Object.hasOwnProperty.call(obj, key)) res.push(key); |
|
7982 } |
|
7983 return res; |
|
7984 }; |
|
7985 |
|
7986 var Object_create = Object.create || function (prototype, properties) { |
|
7987 // from es5-shim |
|
7988 var object; |
|
7989 if (prototype === null) { |
|
7990 object = { '__proto__' : null }; |
|
7991 } |
|
7992 else { |
|
7993 if (typeof prototype !== 'object') { |
|
7994 throw new TypeError( |
|
7995 'typeof prototype[' + (typeof prototype) + '] != \'object\'' |
|
7996 ); |
|
7997 } |
|
7998 var Type = function () {}; |
|
7999 Type.prototype = prototype; |
|
8000 object = new Type(); |
|
8001 object.__proto__ = prototype; |
|
8002 } |
|
8003 if (typeof properties !== 'undefined' && Object.defineProperties) { |
|
8004 Object.defineProperties(object, properties); |
|
8005 } |
|
8006 return object; |
|
8007 }; |
|
8008 |
|
8009 exports.inherits = function(ctor, superCtor) { |
|
8010 ctor.super_ = superCtor; |
|
8011 ctor.prototype = Object_create(superCtor.prototype, { |
|
8012 constructor: { |
|
8013 value: ctor, |
|
8014 enumerable: false, |
|
8015 writable: true, |
|
8016 configurable: true |
|
8017 } |
|
8018 }); |
|
8019 }; |
|
8020 |
|
8021 var formatRegExp = /%[sdj%]/g; |
|
8022 exports.format = function(f) { |
|
8023 if (typeof f !== 'string') { |
|
8024 var objects = []; |
|
8025 for (var i = 0; i < arguments.length; i++) { |
|
8026 objects.push(exports.inspect(arguments[i])); |
|
8027 } |
|
8028 return objects.join(' '); |
|
8029 } |
|
8030 |
|
8031 var i = 1; |
|
8032 var args = arguments; |
|
8033 var len = args.length; |
|
8034 var str = String(f).replace(formatRegExp, function(x) { |
|
8035 if (x === '%%') return '%'; |
|
8036 if (i >= len) return x; |
|
8037 switch (x) { |
|
8038 case '%s': return String(args[i++]); |
|
8039 case '%d': return Number(args[i++]); |
|
8040 case '%j': return JSON.stringify(args[i++]); |
|
8041 default: |
|
8042 return x; |
|
8043 } |
|
8044 }); |
|
8045 for(var x = args[i]; i < len; x = args[++i]){ |
|
8046 if (x === null || typeof x !== 'object') { |
|
8047 str += ' ' + x; |
|
8048 } else { |
|
8049 str += ' ' + exports.inspect(x); |
|
8050 } |
|
8051 } |
|
8052 return str; |
|
8053 }; |
|
8054 |
|
8055 },{"events":2}],9:[function(require,module,exports){ |
|
8056 (function(){// UTILITY |
|
8057 var util = require('util'); |
|
8058 var Buffer = require("buffer").Buffer; |
|
8059 var pSlice = Array.prototype.slice; |
|
8060 |
|
8061 function objectKeys(object) { |
|
8062 if (Object.keys) return Object.keys(object); |
|
8063 var result = []; |
|
8064 for (var name in object) { |
|
8065 if (Object.prototype.hasOwnProperty.call(object, name)) { |
|
8066 result.push(name); |
|
8067 } |
|
8068 } |
|
8069 return result; |
|
8070 } |
|
8071 |
|
8072 // 1. The assert module provides functions that throw |
|
8073 // AssertionError's when particular conditions are not met. The |
|
8074 // assert module must conform to the following interface. |
|
8075 |
|
8076 var assert = module.exports = ok; |
|
8077 |
|
8078 // 2. The AssertionError is defined in assert. |
|
8079 // new assert.AssertionError({ message: message, |
|
8080 // actual: actual, |
|
8081 // expected: expected }) |
|
8082 |
|
8083 assert.AssertionError = function AssertionError(options) { |
|
8084 this.name = 'AssertionError'; |
|
8085 this.message = options.message; |
|
8086 this.actual = options.actual; |
|
8087 this.expected = options.expected; |
|
8088 this.operator = options.operator; |
|
8089 var stackStartFunction = options.stackStartFunction || fail; |
|
8090 |
|
8091 if (Error.captureStackTrace) { |
|
8092 Error.captureStackTrace(this, stackStartFunction); |
|
8093 } |
|
8094 }; |
|
8095 util.inherits(assert.AssertionError, Error); |
|
8096 |
|
8097 function replacer(key, value) { |
|
8098 if (value === undefined) { |
|
8099 return '' + value; |
|
8100 } |
|
8101 if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) { |
|
8102 return value.toString(); |
|
8103 } |
|
8104 if (typeof value === 'function' || value instanceof RegExp) { |
|
8105 return value.toString(); |
|
8106 } |
|
8107 return value; |
|
8108 } |
|
8109 |
|
8110 function truncate(s, n) { |
|
8111 if (typeof s == 'string') { |
|
8112 return s.length < n ? s : s.slice(0, n); |
|
8113 } else { |
|
8114 return s; |
|
8115 } |
|
8116 } |
|
8117 |
|
8118 assert.AssertionError.prototype.toString = function() { |
|
8119 if (this.message) { |
|
8120 return [this.name + ':', this.message].join(' '); |
|
8121 } else { |
|
8122 return [ |
|
8123 this.name + ':', |
|
8124 truncate(JSON.stringify(this.actual, replacer), 128), |
|
8125 this.operator, |
|
8126 truncate(JSON.stringify(this.expected, replacer), 128) |
|
8127 ].join(' '); |
|
8128 } |
|
8129 }; |
|
8130 |
|
8131 // assert.AssertionError instanceof Error |
|
8132 |
|
8133 assert.AssertionError.__proto__ = Error.prototype; |
|
8134 |
|
8135 // At present only the three keys mentioned above are used and |
|
8136 // understood by the spec. Implementations or sub modules can pass |
|
8137 // other keys to the AssertionError's constructor - they will be |
|
8138 // ignored. |
|
8139 |
|
8140 // 3. All of the following functions must throw an AssertionError |
|
8141 // when a corresponding condition is not met, with a message that |
|
8142 // may be undefined if not provided. All assertion methods provide |
|
8143 // both the actual and expected values to the assertion error for |
|
8144 // display purposes. |
|
8145 |
|
8146 function fail(actual, expected, message, operator, stackStartFunction) { |
|
8147 throw new assert.AssertionError({ |
|
8148 message: message, |
|
8149 actual: actual, |
|
8150 expected: expected, |
|
8151 operator: operator, |
|
8152 stackStartFunction: stackStartFunction |
|
8153 }); |
|
8154 } |
|
8155 |
|
8156 // EXTENSION! allows for well behaved errors defined elsewhere. |
|
8157 assert.fail = fail; |
|
8158 |
|
8159 // 4. Pure assertion tests whether a value is truthy, as determined |
|
8160 // by !!guard. |
|
8161 // assert.ok(guard, message_opt); |
|
8162 // This statement is equivalent to assert.equal(true, guard, |
|
8163 // message_opt);. To test strictly for the value true, use |
|
8164 // assert.strictEqual(true, guard, message_opt);. |
|
8165 |
|
8166 function ok(value, message) { |
|
8167 if (!!!value) fail(value, true, message, '==', assert.ok); |
|
8168 } |
|
8169 assert.ok = ok; |
|
8170 |
|
8171 // 5. The equality assertion tests shallow, coercive equality with |
|
8172 // ==. |
|
8173 // assert.equal(actual, expected, message_opt); |
|
8174 |
|
8175 assert.equal = function equal(actual, expected, message) { |
|
8176 if (actual != expected) fail(actual, expected, message, '==', assert.equal); |
|
8177 }; |
|
8178 |
|
8179 // 6. The non-equality assertion tests for whether two objects are not equal |
|
8180 // with != assert.notEqual(actual, expected, message_opt); |
|
8181 |
|
8182 assert.notEqual = function notEqual(actual, expected, message) { |
|
8183 if (actual == expected) { |
|
8184 fail(actual, expected, message, '!=', assert.notEqual); |
|
8185 } |
|
8186 }; |
|
8187 |
|
8188 // 7. The equivalence assertion tests a deep equality relation. |
|
8189 // assert.deepEqual(actual, expected, message_opt); |
|
8190 |
|
8191 assert.deepEqual = function deepEqual(actual, expected, message) { |
|
8192 if (!_deepEqual(actual, expected)) { |
|
8193 fail(actual, expected, message, 'deepEqual', assert.deepEqual); |
|
8194 } |
|
8195 }; |
|
8196 |
|
8197 function _deepEqual(actual, expected) { |
|
8198 // 7.1. All identical values are equivalent, as determined by ===. |
|
8199 if (actual === expected) { |
|
8200 return true; |
|
8201 |
|
8202 } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { |
|
8203 if (actual.length != expected.length) return false; |
|
8204 |
|
8205 for (var i = 0; i < actual.length; i++) { |
|
8206 if (actual[i] !== expected[i]) return false; |
|
8207 } |
|
8208 |
|
8209 return true; |
|
8210 |
|
8211 // 7.2. If the expected value is a Date object, the actual value is |
|
8212 // equivalent if it is also a Date object that refers to the same time. |
|
8213 } else if (actual instanceof Date && expected instanceof Date) { |
|
8214 return actual.getTime() === expected.getTime(); |
|
8215 |
|
8216 // 7.3. Other pairs that do not both pass typeof value == 'object', |
|
8217 // equivalence is determined by ==. |
|
8218 } else if (typeof actual != 'object' && typeof expected != 'object') { |
|
8219 return actual == expected; |
|
8220 |
|
8221 // 7.4. For all other Object pairs, including Array objects, equivalence is |
|
8222 // determined by having the same number of owned properties (as verified |
|
8223 // with Object.prototype.hasOwnProperty.call), the same set of keys |
|
8224 // (although not necessarily the same order), equivalent values for every |
|
8225 // corresponding key, and an identical 'prototype' property. Note: this |
|
8226 // accounts for both named and indexed properties on Arrays. |
|
8227 } else { |
|
8228 return objEquiv(actual, expected); |
|
8229 } |
|
8230 } |
|
8231 |
|
8232 function isUndefinedOrNull(value) { |
|
8233 return value === null || value === undefined; |
|
8234 } |
|
8235 |
|
8236 function isArguments(object) { |
|
8237 return Object.prototype.toString.call(object) == '[object Arguments]'; |
|
8238 } |
|
8239 |
|
8240 function objEquiv(a, b) { |
|
8241 if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) |
|
8242 return false; |
|
8243 // an identical 'prototype' property. |
|
8244 if (a.prototype !== b.prototype) return false; |
|
8245 //~~~I've managed to break Object.keys through screwy arguments passing. |
|
8246 // Converting to array solves the problem. |
|
8247 if (isArguments(a)) { |
|
8248 if (!isArguments(b)) { |
|
8249 return false; |
|
8250 } |
|
8251 a = pSlice.call(a); |
|
8252 b = pSlice.call(b); |
|
8253 return _deepEqual(a, b); |
|
8254 } |
|
8255 try { |
|
8256 var ka = objectKeys(a), |
|
8257 kb = objectKeys(b), |
|
8258 key, i; |
|
8259 } catch (e) {//happens when one is a string literal and the other isn't |
|
8260 return false; |
|
8261 } |
|
8262 // having the same number of owned properties (keys incorporates |
|
8263 // hasOwnProperty) |
|
8264 if (ka.length != kb.length) |
|
8265 return false; |
|
8266 //the same set of keys (although not necessarily the same order), |
|
8267 ka.sort(); |
|
8268 kb.sort(); |
|
8269 //~~~cheap key test |
|
8270 for (i = ka.length - 1; i >= 0; i--) { |
|
8271 if (ka[i] != kb[i]) |
|
8272 return false; |
|
8273 } |
|
8274 //equivalent values for every corresponding key, and |
|
8275 //~~~possibly expensive deep test |
|
8276 for (i = ka.length - 1; i >= 0; i--) { |
|
8277 key = ka[i]; |
|
8278 if (!_deepEqual(a[key], b[key])) return false; |
|
8279 } |
|
8280 return true; |
|
8281 } |
|
8282 |
|
8283 // 8. The non-equivalence assertion tests for any deep inequality. |
|
8284 // assert.notDeepEqual(actual, expected, message_opt); |
|
8285 |
|
8286 assert.notDeepEqual = function notDeepEqual(actual, expected, message) { |
|
8287 if (_deepEqual(actual, expected)) { |
|
8288 fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); |
|
8289 } |
|
8290 }; |
|
8291 |
|
8292 // 9. The strict equality assertion tests strict equality, as determined by ===. |
|
8293 // assert.strictEqual(actual, expected, message_opt); |
|
8294 |
|
8295 assert.strictEqual = function strictEqual(actual, expected, message) { |
|
8296 if (actual !== expected) { |
|
8297 fail(actual, expected, message, '===', assert.strictEqual); |
|
8298 } |
|
8299 }; |
|
8300 |
|
8301 // 10. The strict non-equality assertion tests for strict inequality, as |
|
8302 // determined by !==. assert.notStrictEqual(actual, expected, message_opt); |
|
8303 |
|
8304 assert.notStrictEqual = function notStrictEqual(actual, expected, message) { |
|
8305 if (actual === expected) { |
|
8306 fail(actual, expected, message, '!==', assert.notStrictEqual); |
|
8307 } |
|
8308 }; |
|
8309 |
|
8310 function expectedException(actual, expected) { |
|
8311 if (!actual || !expected) { |
|
8312 return false; |
|
8313 } |
|
8314 |
|
8315 if (expected instanceof RegExp) { |
|
8316 return expected.test(actual); |
|
8317 } else if (actual instanceof expected) { |
|
8318 return true; |
|
8319 } else if (expected.call({}, actual) === true) { |
|
8320 return true; |
|
8321 } |
|
8322 |
|
8323 return false; |
|
8324 } |
|
8325 |
|
8326 function _throws(shouldThrow, block, expected, message) { |
|
8327 var actual; |
|
8328 |
|
8329 if (typeof expected === 'string') { |
|
8330 message = expected; |
|
8331 expected = null; |
|
8332 } |
|
8333 |
|
8334 try { |
|
8335 block(); |
|
8336 } catch (e) { |
|
8337 actual = e; |
|
8338 } |
|
8339 |
|
8340 message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + |
|
8341 (message ? ' ' + message : '.'); |
|
8342 |
|
8343 if (shouldThrow && !actual) { |
|
8344 fail('Missing expected exception' + message); |
|
8345 } |
|
8346 |
|
8347 if (!shouldThrow && expectedException(actual, expected)) { |
|
8348 fail('Got unwanted exception' + message); |
|
8349 } |
|
8350 |
|
8351 if ((shouldThrow && actual && expected && |
|
8352 !expectedException(actual, expected)) || (!shouldThrow && actual)) { |
|
8353 throw actual; |
|
8354 } |
|
8355 } |
|
8356 |
|
8357 // 11. Expected to throw an error: |
|
8358 // assert.throws(block, Error_opt, message_opt); |
|
8359 |
|
8360 assert.throws = function(block, /*optional*/error, /*optional*/message) { |
|
8361 _throws.apply(this, [true].concat(pSlice.call(arguments))); |
|
8362 }; |
|
8363 |
|
8364 // EXTENSION! This is annoying to write outside this module. |
|
8365 assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { |
|
8366 _throws.apply(this, [false].concat(pSlice.call(arguments))); |
|
8367 }; |
|
8368 |
|
8369 assert.ifError = function(err) { if (err) {throw err;}}; |
|
8370 |
|
8371 })() |
|
8372 },{"util":8,"buffer":13}],11:[function(require,module,exports){ |
|
8373 (function(){// Underscore.js 1.4.4 |
|
8374 // http://underscorejs.org |
|
8375 // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. |
|
8376 // Underscore may be freely distributed under the MIT license. |
|
8377 |
|
8378 (function() { |
|
8379 |
|
8380 // Baseline setup |
|
8381 // -------------- |
|
8382 |
|
8383 // Establish the root object, `window` in the browser, or `global` on the server. |
|
8384 var root = this; |
|
8385 |
|
8386 // Save the previous value of the `_` variable. |
|
8387 var previousUnderscore = root._; |
|
8388 |
|
8389 // Establish the object that gets returned to break out of a loop iteration. |
|
8390 var breaker = {}; |
|
8391 |
|
8392 // Save bytes in the minified (but not gzipped) version: |
|
8393 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; |
|
8394 |
|
8395 // Create quick reference variables for speed access to core prototypes. |
|
8396 var push = ArrayProto.push, |
|
8397 slice = ArrayProto.slice, |
|
8398 concat = ArrayProto.concat, |
|
8399 toString = ObjProto.toString, |
|
8400 hasOwnProperty = ObjProto.hasOwnProperty; |
|
8401 |
|
8402 // All **ECMAScript 5** native function implementations that we hope to use |
|
8403 // are declared here. |
|
8404 var |
|
8405 nativeForEach = ArrayProto.forEach, |
|
8406 nativeMap = ArrayProto.map, |
|
8407 nativeReduce = ArrayProto.reduce, |
|
8408 nativeReduceRight = ArrayProto.reduceRight, |
|
8409 nativeFilter = ArrayProto.filter, |
|
8410 nativeEvery = ArrayProto.every, |
|
8411 nativeSome = ArrayProto.some, |
|
8412 nativeIndexOf = ArrayProto.indexOf, |
|
8413 nativeLastIndexOf = ArrayProto.lastIndexOf, |
|
8414 nativeIsArray = Array.isArray, |
|
8415 nativeKeys = Object.keys, |
|
8416 nativeBind = FuncProto.bind; |
|
8417 |
|
8418 // Create a safe reference to the Underscore object for use below. |
|
8419 var _ = function(obj) { |
|
8420 if (obj instanceof _) return obj; |
|
8421 if (!(this instanceof _)) return new _(obj); |
|
8422 this._wrapped = obj; |
|
8423 }; |
|
8424 |
|
8425 // Export the Underscore object for **Node.js**, with |
|
8426 // backwards-compatibility for the old `require()` API. If we're in |
|
8427 // the browser, add `_` as a global object via a string identifier, |
|
8428 // for Closure Compiler "advanced" mode. |
|
8429 if (typeof exports !== 'undefined') { |
|
8430 if (typeof module !== 'undefined' && module.exports) { |
|
8431 exports = module.exports = _; |
|
8432 } |
|
8433 exports._ = _; |
|
8434 } else { |
|
8435 root._ = _; |
|
8436 } |
|
8437 |
|
8438 // Current version. |
|
8439 _.VERSION = '1.4.4'; |
|
8440 |
|
8441 // Collection Functions |
|
8442 // -------------------- |
|
8443 |
|
8444 // The cornerstone, an `each` implementation, aka `forEach`. |
|
8445 // Handles objects with the built-in `forEach`, arrays, and raw objects. |
|
8446 // Delegates to **ECMAScript 5**'s native `forEach` if available. |
|
8447 var each = _.each = _.forEach = function(obj, iterator, context) { |
|
8448 if (obj == null) return; |
|
8449 if (nativeForEach && obj.forEach === nativeForEach) { |
|
8450 obj.forEach(iterator, context); |
|
8451 } else if (obj.length === +obj.length) { |
|
8452 for (var i = 0, l = obj.length; i < l; i++) { |
|
8453 if (iterator.call(context, obj[i], i, obj) === breaker) return; |
|
8454 } |
|
8455 } else { |
|
8456 for (var key in obj) { |
|
8457 if (_.has(obj, key)) { |
|
8458 if (iterator.call(context, obj[key], key, obj) === breaker) return; |
|
8459 } |
|
8460 } |
|
8461 } |
|
8462 }; |
|
8463 |
|
8464 // Return the results of applying the iterator to each element. |
|
8465 // Delegates to **ECMAScript 5**'s native `map` if available. |
|
8466 _.map = _.collect = function(obj, iterator, context) { |
|
8467 var results = []; |
|
8468 if (obj == null) return results; |
|
8469 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); |
|
8470 each(obj, function(value, index, list) { |
|
8471 results[results.length] = iterator.call(context, value, index, list); |
|
8472 }); |
|
8473 return results; |
|
8474 }; |
|
8475 |
|
8476 var reduceError = 'Reduce of empty array with no initial value'; |
|
8477 |
|
8478 // **Reduce** builds up a single result from a list of values, aka `inject`, |
|
8479 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. |
|
8480 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { |
|
8481 var initial = arguments.length > 2; |
|
8482 if (obj == null) obj = []; |
|
8483 if (nativeReduce && obj.reduce === nativeReduce) { |
|
8484 if (context) iterator = _.bind(iterator, context); |
|
8485 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); |
|
8486 } |
|
8487 each(obj, function(value, index, list) { |
|
8488 if (!initial) { |
|
8489 memo = value; |
|
8490 initial = true; |
|
8491 } else { |
|
8492 memo = iterator.call(context, memo, value, index, list); |
|
8493 } |
|
8494 }); |
|
8495 if (!initial) throw new TypeError(reduceError); |
|
8496 return memo; |
|
8497 }; |
|
8498 |
|
8499 // The right-associative version of reduce, also known as `foldr`. |
|
8500 // Delegates to **ECMAScript 5**'s native `reduceRight` if available. |
|
8501 _.reduceRight = _.foldr = function(obj, iterator, memo, context) { |
|
8502 var initial = arguments.length > 2; |
|
8503 if (obj == null) obj = []; |
|
8504 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { |
|
8505 if (context) iterator = _.bind(iterator, context); |
|
8506 return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); |
|
8507 } |
|
8508 var length = obj.length; |
|
8509 if (length !== +length) { |
|
8510 var keys = _.keys(obj); |
|
8511 length = keys.length; |
|
8512 } |
|
8513 each(obj, function(value, index, list) { |
|
8514 index = keys ? keys[--length] : --length; |
|
8515 if (!initial) { |
|
8516 memo = obj[index]; |
|
8517 initial = true; |
|
8518 } else { |
|
8519 memo = iterator.call(context, memo, obj[index], index, list); |
|
8520 } |
|
8521 }); |
|
8522 if (!initial) throw new TypeError(reduceError); |
|
8523 return memo; |
|
8524 }; |
|
8525 |
|
8526 // Return the first value which passes a truth test. Aliased as `detect`. |
|
8527 _.find = _.detect = function(obj, iterator, context) { |
|
8528 var result; |
|
8529 any(obj, function(value, index, list) { |
|
8530 if (iterator.call(context, value, index, list)) { |
|
8531 result = value; |
|
8532 return true; |
|
8533 } |
|
8534 }); |
|
8535 return result; |
|
8536 }; |
|
8537 |
|
8538 // Return all the elements that pass a truth test. |
|
8539 // Delegates to **ECMAScript 5**'s native `filter` if available. |
|
8540 // Aliased as `select`. |
|
8541 _.filter = _.select = function(obj, iterator, context) { |
|
8542 var results = []; |
|
8543 if (obj == null) return results; |
|
8544 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); |
|
8545 each(obj, function(value, index, list) { |
|
8546 if (iterator.call(context, value, index, list)) results[results.length] = value; |
|
8547 }); |
|
8548 return results; |
|
8549 }; |
|
8550 |
|
8551 // Return all the elements for which a truth test fails. |
|
8552 _.reject = function(obj, iterator, context) { |
|
8553 return _.filter(obj, function(value, index, list) { |
|
8554 return !iterator.call(context, value, index, list); |
|
8555 }, context); |
|
8556 }; |
|
8557 |
|
8558 // Determine whether all of the elements match a truth test. |
|
8559 // Delegates to **ECMAScript 5**'s native `every` if available. |
|
8560 // Aliased as `all`. |
|
8561 _.every = _.all = function(obj, iterator, context) { |
|
8562 iterator || (iterator = _.identity); |
|
8563 var result = true; |
|
8564 if (obj == null) return result; |
|
8565 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); |
|
8566 each(obj, function(value, index, list) { |
|
8567 if (!(result = result && iterator.call(context, value, index, list))) return breaker; |
|
8568 }); |
|
8569 return !!result; |
|
8570 }; |
|
8571 |
|
8572 // Determine if at least one element in the object matches a truth test. |
|
8573 // Delegates to **ECMAScript 5**'s native `some` if available. |
|
8574 // Aliased as `any`. |
|
8575 var any = _.some = _.any = function(obj, iterator, context) { |
|
8576 iterator || (iterator = _.identity); |
|
8577 var result = false; |
|
8578 if (obj == null) return result; |
|
8579 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); |
|
8580 each(obj, function(value, index, list) { |
|
8581 if (result || (result = iterator.call(context, value, index, list))) return breaker; |
|
8582 }); |
|
8583 return !!result; |
|
8584 }; |
|
8585 |
|
8586 // Determine if the array or object contains a given value (using `===`). |
|
8587 // Aliased as `include`. |
|
8588 _.contains = _.include = function(obj, target) { |
|
8589 if (obj == null) return false; |
|
8590 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; |
|
8591 return any(obj, function(value) { |
|
8592 return value === target; |
|
8593 }); |
|
8594 }; |
|
8595 |
|
8596 // Invoke a method (with arguments) on every item in a collection. |
|
8597 _.invoke = function(obj, method) { |
|
8598 var args = slice.call(arguments, 2); |
|
8599 var isFunc = _.isFunction(method); |
|
8600 return _.map(obj, function(value) { |
|
8601 return (isFunc ? method : value[method]).apply(value, args); |
|
8602 }); |
|
8603 }; |
|
8604 |
|
8605 // Convenience version of a common use case of `map`: fetching a property. |
|
8606 _.pluck = function(obj, key) { |
|
8607 return _.map(obj, function(value){ return value[key]; }); |
|
8608 }; |
|
8609 |
|
8610 // Convenience version of a common use case of `filter`: selecting only objects |
|
8611 // containing specific `key:value` pairs. |
|
8612 _.where = function(obj, attrs, first) { |
|
8613 if (_.isEmpty(attrs)) return first ? null : []; |
|
8614 return _[first ? 'find' : 'filter'](obj, function(value) { |
|
8615 for (var key in attrs) { |
|
8616 if (attrs[key] !== value[key]) return false; |
|
8617 } |
|
8618 return true; |
|
8619 }); |
|
8620 }; |
|
8621 |
|
8622 // Convenience version of a common use case of `find`: getting the first object |
|
8623 // containing specific `key:value` pairs. |
|
8624 _.findWhere = function(obj, attrs) { |
|
8625 return _.where(obj, attrs, true); |
|
8626 }; |
|
8627 |
|
8628 // Return the maximum element or (element-based computation). |
|
8629 // Can't optimize arrays of integers longer than 65,535 elements. |
|
8630 // See: https://bugs.webkit.org/show_bug.cgi?id=80797 |
|
8631 _.max = function(obj, iterator, context) { |
|
8632 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { |
|
8633 return Math.max.apply(Math, obj); |
|
8634 } |
|
8635 if (!iterator && _.isEmpty(obj)) return -Infinity; |
|
8636 var result = {computed : -Infinity, value: -Infinity}; |
|
8637 each(obj, function(value, index, list) { |
|
8638 var computed = iterator ? iterator.call(context, value, index, list) : value; |
|
8639 computed >= result.computed && (result = {value : value, computed : computed}); |
|
8640 }); |
|
8641 return result.value; |
|
8642 }; |
|
8643 |
|
8644 // Return the minimum element (or element-based computation). |
|
8645 _.min = function(obj, iterator, context) { |
|
8646 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { |
|
8647 return Math.min.apply(Math, obj); |
|
8648 } |
|
8649 if (!iterator && _.isEmpty(obj)) return Infinity; |
|
8650 var result = {computed : Infinity, value: Infinity}; |
|
8651 each(obj, function(value, index, list) { |
|
8652 var computed = iterator ? iterator.call(context, value, index, list) : value; |
|
8653 computed < result.computed && (result = {value : value, computed : computed}); |
|
8654 }); |
|
8655 return result.value; |
|
8656 }; |
|
8657 |
|
8658 // Shuffle an array. |
|
8659 _.shuffle = function(obj) { |
|
8660 var rand; |
|
8661 var index = 0; |
|
8662 var shuffled = []; |
|
8663 each(obj, function(value) { |
|
8664 rand = _.random(index++); |
|
8665 shuffled[index - 1] = shuffled[rand]; |
|
8666 shuffled[rand] = value; |
|
8667 }); |
|
8668 return shuffled; |
|
8669 }; |
|
8670 |
|
8671 // An internal function to generate lookup iterators. |
|
8672 var lookupIterator = function(value) { |
|
8673 return _.isFunction(value) ? value : function(obj){ return obj[value]; }; |
|
8674 }; |
|
8675 |
|
8676 // Sort the object's values by a criterion produced by an iterator. |
|
8677 _.sortBy = function(obj, value, context) { |
|
8678 var iterator = lookupIterator(value); |
|
8679 return _.pluck(_.map(obj, function(value, index, list) { |
|
8680 return { |
|
8681 value : value, |
|
8682 index : index, |
|
8683 criteria : iterator.call(context, value, index, list) |
|
8684 }; |
|
8685 }).sort(function(left, right) { |
|
8686 var a = left.criteria; |
|
8687 var b = right.criteria; |
|
8688 if (a !== b) { |
|
8689 if (a > b || a === void 0) return 1; |
|
8690 if (a < b || b === void 0) return -1; |
|
8691 } |
|
8692 return left.index < right.index ? -1 : 1; |
|
8693 }), 'value'); |
|
8694 }; |
|
8695 |
|
8696 // An internal function used for aggregate "group by" operations. |
|
8697 var group = function(obj, value, context, behavior) { |
|
8698 var result = {}; |
|
8699 var iterator = lookupIterator(value || _.identity); |
|
8700 each(obj, function(value, index) { |
|
8701 var key = iterator.call(context, value, index, obj); |
|
8702 behavior(result, key, value); |
|
8703 }); |
|
8704 return result; |
|
8705 }; |
|
8706 |
|
8707 // Groups the object's values by a criterion. Pass either a string attribute |
|
8708 // to group by, or a function that returns the criterion. |
|
8709 _.groupBy = function(obj, value, context) { |
|
8710 return group(obj, value, context, function(result, key, value) { |
|
8711 (_.has(result, key) ? result[key] : (result[key] = [])).push(value); |
|
8712 }); |
|
8713 }; |
|
8714 |
|
8715 // Counts instances of an object that group by a certain criterion. Pass |
|
8716 // either a string attribute to count by, or a function that returns the |
|
8717 // criterion. |
|
8718 _.countBy = function(obj, value, context) { |
|
8719 return group(obj, value, context, function(result, key) { |
|
8720 if (!_.has(result, key)) result[key] = 0; |
|
8721 result[key]++; |
|
8722 }); |
|
8723 }; |
|
8724 |
|
8725 // Use a comparator function to figure out the smallest index at which |
|
8726 // an object should be inserted so as to maintain order. Uses binary search. |
|
8727 _.sortedIndex = function(array, obj, iterator, context) { |
|
8728 iterator = iterator == null ? _.identity : lookupIterator(iterator); |
|
8729 var value = iterator.call(context, obj); |
|
8730 var low = 0, high = array.length; |
|
8731 while (low < high) { |
|
8732 var mid = (low + high) >>> 1; |
|
8733 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; |
|
8734 } |
|
8735 return low; |
|
8736 }; |
|
8737 |
|
8738 // Safely convert anything iterable into a real, live array. |
|
8739 _.toArray = function(obj) { |
|
8740 if (!obj) return []; |
|
8741 if (_.isArray(obj)) return slice.call(obj); |
|
8742 if (obj.length === +obj.length) return _.map(obj, _.identity); |
|
8743 return _.values(obj); |
|
8744 }; |
|
8745 |
|
8746 // Return the number of elements in an object. |
|
8747 _.size = function(obj) { |
|
8748 if (obj == null) return 0; |
|
8749 return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; |
|
8750 }; |
|
8751 |
|
8752 // Array Functions |
|
8753 // --------------- |
|
8754 |
|
8755 // Get the first element of an array. Passing **n** will return the first N |
|
8756 // values in the array. Aliased as `head` and `take`. The **guard** check |
|
8757 // allows it to work with `_.map`. |
|
8758 _.first = _.head = _.take = function(array, n, guard) { |
|
8759 if (array == null) return void 0; |
|
8760 return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; |
|
8761 }; |
|
8762 |
|
8763 // Returns everything but the last entry of the array. Especially useful on |
|
8764 // the arguments object. Passing **n** will return all the values in |
|
8765 // the array, excluding the last N. The **guard** check allows it to work with |
|
8766 // `_.map`. |
|
8767 _.initial = function(array, n, guard) { |
|
8768 return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); |
|
8769 }; |
|
8770 |
|
8771 // Get the last element of an array. Passing **n** will return the last N |
|
8772 // values in the array. The **guard** check allows it to work with `_.map`. |
|
8773 _.last = function(array, n, guard) { |
|
8774 if (array == null) return void 0; |
|
8775 if ((n != null) && !guard) { |
|
8776 return slice.call(array, Math.max(array.length - n, 0)); |
|
8777 } else { |
|
8778 return array[array.length - 1]; |
|
8779 } |
|
8780 }; |
|
8781 |
|
8782 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. |
|
8783 // Especially useful on the arguments object. Passing an **n** will return |
|
8784 // the rest N values in the array. The **guard** |
|
8785 // check allows it to work with `_.map`. |
|
8786 _.rest = _.tail = _.drop = function(array, n, guard) { |
|
8787 return slice.call(array, (n == null) || guard ? 1 : n); |
|
8788 }; |
|
8789 |
|
8790 // Trim out all falsy values from an array. |
|
8791 _.compact = function(array) { |
|
8792 return _.filter(array, _.identity); |
|
8793 }; |
|
8794 |
|
8795 // Internal implementation of a recursive `flatten` function. |
|
8796 var flatten = function(input, shallow, output) { |
|
8797 each(input, function(value) { |
|
8798 if (_.isArray(value)) { |
|
8799 shallow ? push.apply(output, value) : flatten(value, shallow, output); |
|
8800 } else { |
|
8801 output.push(value); |
|
8802 } |
|
8803 }); |
|
8804 return output; |
|
8805 }; |
|
8806 |
|
8807 // Return a completely flattened version of an array. |
|
8808 _.flatten = function(array, shallow) { |
|
8809 return flatten(array, shallow, []); |
|
8810 }; |
|
8811 |
|
8812 // Return a version of the array that does not contain the specified value(s). |
|
8813 _.without = function(array) { |
|
8814 return _.difference(array, slice.call(arguments, 1)); |
|
8815 }; |
|
8816 |
|
8817 // Produce a duplicate-free version of the array. If the array has already |
|
8818 // been sorted, you have the option of using a faster algorithm. |
|
8819 // Aliased as `unique`. |
|
8820 _.uniq = _.unique = function(array, isSorted, iterator, context) { |
|
8821 if (_.isFunction(isSorted)) { |
|
8822 context = iterator; |
|
8823 iterator = isSorted; |
|
8824 isSorted = false; |
|
8825 } |
|
8826 var initial = iterator ? _.map(array, iterator, context) : array; |
|
8827 var results = []; |
|
8828 var seen = []; |
|
8829 each(initial, function(value, index) { |
|
8830 if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { |
|
8831 seen.push(value); |
|
8832 results.push(array[index]); |
|
8833 } |
|
8834 }); |
|
8835 return results; |
|
8836 }; |
|
8837 |
|
8838 // Produce an array that contains the union: each distinct element from all of |
|
8839 // the passed-in arrays. |
|
8840 _.union = function() { |
|
8841 return _.uniq(concat.apply(ArrayProto, arguments)); |
|
8842 }; |
|
8843 |
|
8844 // Produce an array that contains every item shared between all the |
|
8845 // passed-in arrays. |
|
8846 _.intersection = function(array) { |
|
8847 var rest = slice.call(arguments, 1); |
|
8848 return _.filter(_.uniq(array), function(item) { |
|
8849 return _.every(rest, function(other) { |
|
8850 return _.indexOf(other, item) >= 0; |
|
8851 }); |
|
8852 }); |
|
8853 }; |
|
8854 |
|
8855 // Take the difference between one array and a number of other arrays. |
|
8856 // Only the elements present in just the first array will remain. |
|
8857 _.difference = function(array) { |
|
8858 var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); |
|
8859 return _.filter(array, function(value){ return !_.contains(rest, value); }); |
|
8860 }; |
|
8861 |
|
8862 // Zip together multiple lists into a single array -- elements that share |
|
8863 // an index go together. |
|
8864 _.zip = function() { |
|
8865 var args = slice.call(arguments); |
|
8866 var length = _.max(_.pluck(args, 'length')); |
|
8867 var results = new Array(length); |
|
8868 for (var i = 0; i < length; i++) { |
|
8869 results[i] = _.pluck(args, "" + i); |
|
8870 } |
|
8871 return results; |
|
8872 }; |
|
8873 |
|
8874 // Converts lists into objects. Pass either a single array of `[key, value]` |
|
8875 // pairs, or two parallel arrays of the same length -- one of keys, and one of |
|
8876 // the corresponding values. |
|
8877 _.object = function(list, values) { |
|
8878 if (list == null) return {}; |
|
8879 var result = {}; |
|
8880 for (var i = 0, l = list.length; i < l; i++) { |
|
8881 if (values) { |
|
8882 result[list[i]] = values[i]; |
|
8883 } else { |
|
8884 result[list[i][0]] = list[i][1]; |
|
8885 } |
|
8886 } |
|
8887 return result; |
|
8888 }; |
|
8889 |
|
8890 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), |
|
8891 // we need this function. Return the position of the first occurrence of an |
|
8892 // item in an array, or -1 if the item is not included in the array. |
|
8893 // Delegates to **ECMAScript 5**'s native `indexOf` if available. |
|
8894 // If the array is large and already in sort order, pass `true` |
|
8895 // for **isSorted** to use binary search. |
|
8896 _.indexOf = function(array, item, isSorted) { |
|
8897 if (array == null) return -1; |
|
8898 var i = 0, l = array.length; |
|
8899 if (isSorted) { |
|
8900 if (typeof isSorted == 'number') { |
|
8901 i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); |
|
8902 } else { |
|
8903 i = _.sortedIndex(array, item); |
|
8904 return array[i] === item ? i : -1; |
|
8905 } |
|
8906 } |
|
8907 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); |
|
8908 for (; i < l; i++) if (array[i] === item) return i; |
|
8909 return -1; |
|
8910 }; |
|
8911 |
|
8912 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. |
|
8913 _.lastIndexOf = function(array, item, from) { |
|
8914 if (array == null) return -1; |
|
8915 var hasIndex = from != null; |
|
8916 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { |
|
8917 return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); |
|
8918 } |
|
8919 var i = (hasIndex ? from : array.length); |
|
8920 while (i--) if (array[i] === item) return i; |
|
8921 return -1; |
|
8922 }; |
|
8923 |
|
8924 // Generate an integer Array containing an arithmetic progression. A port of |
|
8925 // the native Python `range()` function. See |
|
8926 // [the Python documentation](http://docs.python.org/library/functions.html#range). |
|
8927 _.range = function(start, stop, step) { |
|
8928 if (arguments.length <= 1) { |
|
8929 stop = start || 0; |
|
8930 start = 0; |
|
8931 } |
|
8932 step = arguments[2] || 1; |
|
8933 |
|
8934 var len = Math.max(Math.ceil((stop - start) / step), 0); |
|
8935 var idx = 0; |
|
8936 var range = new Array(len); |
|
8937 |
|
8938 while(idx < len) { |
|
8939 range[idx++] = start; |
|
8940 start += step; |
|
8941 } |
|
8942 |
|
8943 return range; |
|
8944 }; |
|
8945 |
|
8946 // Function (ahem) Functions |
|
8947 // ------------------ |
|
8948 |
|
8949 // Create a function bound to a given object (assigning `this`, and arguments, |
|
8950 // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if |
|
8951 // available. |
|
8952 _.bind = function(func, context) { |
|
8953 if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); |
|
8954 var args = slice.call(arguments, 2); |
|
8955 return function() { |
|
8956 return func.apply(context, args.concat(slice.call(arguments))); |
|
8957 }; |
|
8958 }; |
|
8959 |
|
8960 // Partially apply a function by creating a version that has had some of its |
|
8961 // arguments pre-filled, without changing its dynamic `this` context. |
|
8962 _.partial = function(func) { |
|
8963 var args = slice.call(arguments, 1); |
|
8964 return function() { |
|
8965 return func.apply(this, args.concat(slice.call(arguments))); |
|
8966 }; |
|
8967 }; |
|
8968 |
|
8969 // Bind all of an object's methods to that object. Useful for ensuring that |
|
8970 // all callbacks defined on an object belong to it. |
|
8971 _.bindAll = function(obj) { |
|
8972 var funcs = slice.call(arguments, 1); |
|
8973 if (funcs.length === 0) funcs = _.functions(obj); |
|
8974 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); |
|
8975 return obj; |
|
8976 }; |
|
8977 |
|
8978 // Memoize an expensive function by storing its results. |
|
8979 _.memoize = function(func, hasher) { |
|
8980 var memo = {}; |
|
8981 hasher || (hasher = _.identity); |
|
8982 return function() { |
|
8983 var key = hasher.apply(this, arguments); |
|
8984 return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); |
|
8985 }; |
|
8986 }; |
|
8987 |
|
8988 // Delays a function for the given number of milliseconds, and then calls |
|
8989 // it with the arguments supplied. |
|
8990 _.delay = function(func, wait) { |
|
8991 var args = slice.call(arguments, 2); |
|
8992 return setTimeout(function(){ return func.apply(null, args); }, wait); |
|
8993 }; |
|
8994 |
|
8995 // Defers a function, scheduling it to run after the current call stack has |
|
8996 // cleared. |
|
8997 _.defer = function(func) { |
|
8998 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); |
|
8999 }; |
|
9000 |
|
9001 // Returns a function, that, when invoked, will only be triggered at most once |
|
9002 // during a given window of time. |
|
9003 _.throttle = function(func, wait) { |
|
9004 var context, args, timeout, result; |
|
9005 var previous = 0; |
|
9006 var later = function() { |
|
9007 previous = new Date; |
|
9008 timeout = null; |
|
9009 result = func.apply(context, args); |
|
9010 }; |
|
9011 return function() { |
|
9012 var now = new Date; |
|
9013 var remaining = wait - (now - previous); |
|
9014 context = this; |
|
9015 args = arguments; |
|
9016 if (remaining <= 0) { |
|
9017 clearTimeout(timeout); |
|
9018 timeout = null; |
|
9019 previous = now; |
|
9020 result = func.apply(context, args); |
|
9021 } else if (!timeout) { |
|
9022 timeout = setTimeout(later, remaining); |
|
9023 } |
|
9024 return result; |
|
9025 }; |
|
9026 }; |
|
9027 |
|
9028 // Returns a function, that, as long as it continues to be invoked, will not |
|
9029 // be triggered. The function will be called after it stops being called for |
|
9030 // N milliseconds. If `immediate` is passed, trigger the function on the |
|
9031 // leading edge, instead of the trailing. |
|
9032 _.debounce = function(func, wait, immediate) { |
|
9033 var timeout, result; |
|
9034 return function() { |
|
9035 var context = this, args = arguments; |
|
9036 var later = function() { |
|
9037 timeout = null; |
|
9038 if (!immediate) result = func.apply(context, args); |
|
9039 }; |
|
9040 var callNow = immediate && !timeout; |
|
9041 clearTimeout(timeout); |
|
9042 timeout = setTimeout(later, wait); |
|
9043 if (callNow) result = func.apply(context, args); |
|
9044 return result; |
|
9045 }; |
|
9046 }; |
|
9047 |
|
9048 // Returns a function that will be executed at most one time, no matter how |
|
9049 // often you call it. Useful for lazy initialization. |
|
9050 _.once = function(func) { |
|
9051 var ran = false, memo; |
|
9052 return function() { |
|
9053 if (ran) return memo; |
|
9054 ran = true; |
|
9055 memo = func.apply(this, arguments); |
|
9056 func = null; |
|
9057 return memo; |
|
9058 }; |
|
9059 }; |
|
9060 |
|
9061 // Returns the first function passed as an argument to the second, |
|
9062 // allowing you to adjust arguments, run code before and after, and |
|
9063 // conditionally execute the original function. |
|
9064 _.wrap = function(func, wrapper) { |
|
9065 return function() { |
|
9066 var args = [func]; |
|
9067 push.apply(args, arguments); |
|
9068 return wrapper.apply(this, args); |
|
9069 }; |
|
9070 }; |
|
9071 |
|
9072 // Returns a function that is the composition of a list of functions, each |
|
9073 // consuming the return value of the function that follows. |
|
9074 _.compose = function() { |
|
9075 var funcs = arguments; |
|
9076 return function() { |
|
9077 var args = arguments; |
|
9078 for (var i = funcs.length - 1; i >= 0; i--) { |
|
9079 args = [funcs[i].apply(this, args)]; |
|
9080 } |
|
9081 return args[0]; |
|
9082 }; |
|
9083 }; |
|
9084 |
|
9085 // Returns a function that will only be executed after being called N times. |
|
9086 _.after = function(times, func) { |
|
9087 if (times <= 0) return func(); |
|
9088 return function() { |
|
9089 if (--times < 1) { |
|
9090 return func.apply(this, arguments); |
|
9091 } |
|
9092 }; |
|
9093 }; |
|
9094 |
|
9095 // Object Functions |
|
9096 // ---------------- |
|
9097 |
|
9098 // Retrieve the names of an object's properties. |
|
9099 // Delegates to **ECMAScript 5**'s native `Object.keys` |
|
9100 _.keys = nativeKeys || function(obj) { |
|
9101 if (obj !== Object(obj)) throw new TypeError('Invalid object'); |
|
9102 var keys = []; |
|
9103 for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; |
|
9104 return keys; |
|
9105 }; |
|
9106 |
|
9107 // Retrieve the values of an object's properties. |
|
9108 _.values = function(obj) { |
|
9109 var values = []; |
|
9110 for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); |
|
9111 return values; |
|
9112 }; |
|
9113 |
|
9114 // Convert an object into a list of `[key, value]` pairs. |
|
9115 _.pairs = function(obj) { |
|
9116 var pairs = []; |
|
9117 for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); |
|
9118 return pairs; |
|
9119 }; |
|
9120 |
|
9121 // Invert the keys and values of an object. The values must be serializable. |
|
9122 _.invert = function(obj) { |
|
9123 var result = {}; |
|
9124 for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; |
|
9125 return result; |
|
9126 }; |
|
9127 |
|
9128 // Return a sorted list of the function names available on the object. |
|
9129 // Aliased as `methods` |
|
9130 _.functions = _.methods = function(obj) { |
|
9131 var names = []; |
|
9132 for (var key in obj) { |
|
9133 if (_.isFunction(obj[key])) names.push(key); |
|
9134 } |
|
9135 return names.sort(); |
|
9136 }; |
|
9137 |
|
9138 // Extend a given object with all the properties in passed-in object(s). |
|
9139 _.extend = function(obj) { |
|
9140 each(slice.call(arguments, 1), function(source) { |
|
9141 if (source) { |
|
9142 for (var prop in source) { |
|
9143 obj[prop] = source[prop]; |
|
9144 } |
|
9145 } |
|
9146 }); |
|
9147 return obj; |
|
9148 }; |
|
9149 |
|
9150 // Return a copy of the object only containing the whitelisted properties. |
|
9151 _.pick = function(obj) { |
|
9152 var copy = {}; |
|
9153 var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); |
|
9154 each(keys, function(key) { |
|
9155 if (key in obj) copy[key] = obj[key]; |
|
9156 }); |
|
9157 return copy; |
|
9158 }; |
|
9159 |
|
9160 // Return a copy of the object without the blacklisted properties. |
|
9161 _.omit = function(obj) { |
|
9162 var copy = {}; |
|
9163 var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); |
|
9164 for (var key in obj) { |
|
9165 if (!_.contains(keys, key)) copy[key] = obj[key]; |
|
9166 } |
|
9167 return copy; |
|
9168 }; |
|
9169 |
|
9170 // Fill in a given object with default properties. |
|
9171 _.defaults = function(obj) { |
|
9172 each(slice.call(arguments, 1), function(source) { |
|
9173 if (source) { |
|
9174 for (var prop in source) { |
|
9175 if (obj[prop] == null) obj[prop] = source[prop]; |
|
9176 } |
|
9177 } |
|
9178 }); |
|
9179 return obj; |
|
9180 }; |
|
9181 |
|
9182 // Create a (shallow-cloned) duplicate of an object. |
|
9183 _.clone = function(obj) { |
|
9184 if (!_.isObject(obj)) return obj; |
|
9185 return _.isArray(obj) ? obj.slice() : _.extend({}, obj); |
|
9186 }; |
|
9187 |
|
9188 // Invokes interceptor with the obj, and then returns obj. |
|
9189 // The primary purpose of this method is to "tap into" a method chain, in |
|
9190 // order to perform operations on intermediate results within the chain. |
|
9191 _.tap = function(obj, interceptor) { |
|
9192 interceptor(obj); |
|
9193 return obj; |
|
9194 }; |
|
9195 |
|
9196 // Internal recursive comparison function for `isEqual`. |
|
9197 var eq = function(a, b, aStack, bStack) { |
|
9198 // Identical objects are equal. `0 === -0`, but they aren't identical. |
|
9199 // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. |
|
9200 if (a === b) return a !== 0 || 1 / a == 1 / b; |
|
9201 // A strict comparison is necessary because `null == undefined`. |
|
9202 if (a == null || b == null) return a === b; |
|
9203 // Unwrap any wrapped objects. |
|
9204 if (a instanceof _) a = a._wrapped; |
|
9205 if (b instanceof _) b = b._wrapped; |
|
9206 // Compare `[[Class]]` names. |
|
9207 var className = toString.call(a); |
|
9208 if (className != toString.call(b)) return false; |
|
9209 switch (className) { |
|
9210 // Strings, numbers, dates, and booleans are compared by value. |
|
9211 case '[object String]': |
|
9212 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is |
|
9213 // equivalent to `new String("5")`. |
|
9214 return a == String(b); |
|
9215 case '[object Number]': |
|
9216 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for |
|
9217 // other numeric values. |
|
9218 return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); |
|
9219 case '[object Date]': |
|
9220 case '[object Boolean]': |
|
9221 // Coerce dates and booleans to numeric primitive values. Dates are compared by their |
|
9222 // millisecond representations. Note that invalid dates with millisecond representations |
|
9223 // of `NaN` are not equivalent. |
|
9224 return +a == +b; |
|
9225 // RegExps are compared by their source patterns and flags. |
|
9226 case '[object RegExp]': |
|
9227 return a.source == b.source && |
|
9228 a.global == b.global && |
|
9229 a.multiline == b.multiline && |
|
9230 a.ignoreCase == b.ignoreCase; |
|
9231 } |
|
9232 if (typeof a != 'object' || typeof b != 'object') return false; |
|
9233 // Assume equality for cyclic structures. The algorithm for detecting cyclic |
|
9234 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. |
|
9235 var length = aStack.length; |
|
9236 while (length--) { |
|
9237 // Linear search. Performance is inversely proportional to the number of |
|
9238 // unique nested structures. |
|
9239 if (aStack[length] == a) return bStack[length] == b; |
|
9240 } |
|
9241 // Add the first object to the stack of traversed objects. |
|
9242 aStack.push(a); |
|
9243 bStack.push(b); |
|
9244 var size = 0, result = true; |
|
9245 // Recursively compare objects and arrays. |
|
9246 if (className == '[object Array]') { |
|
9247 // Compare array lengths to determine if a deep comparison is necessary. |
|
9248 size = a.length; |
|
9249 result = size == b.length; |
|
9250 if (result) { |
|
9251 // Deep compare the contents, ignoring non-numeric properties. |
|
9252 while (size--) { |
|
9253 if (!(result = eq(a[size], b[size], aStack, bStack))) break; |
|
9254 } |
|
9255 } |
|
9256 } else { |
|
9257 // Objects with different constructors are not equivalent, but `Object`s |
|
9258 // from different frames are. |
|
9259 var aCtor = a.constructor, bCtor = b.constructor; |
|
9260 if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && |
|
9261 _.isFunction(bCtor) && (bCtor instanceof bCtor))) { |
|
9262 return false; |
|
9263 } |
|
9264 // Deep compare objects. |
|
9265 for (var key in a) { |
|
9266 if (_.has(a, key)) { |
|
9267 // Count the expected number of properties. |
|
9268 size++; |
|
9269 // Deep compare each member. |
|
9270 if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; |
|
9271 } |
|
9272 } |
|
9273 // Ensure that both objects contain the same number of properties. |
|
9274 if (result) { |
|
9275 for (key in b) { |
|
9276 if (_.has(b, key) && !(size--)) break; |
|
9277 } |
|
9278 result = !size; |
|
9279 } |
|
9280 } |
|
9281 // Remove the first object from the stack of traversed objects. |
|
9282 aStack.pop(); |
|
9283 bStack.pop(); |
|
9284 return result; |
|
9285 }; |
|
9286 |
|
9287 // Perform a deep comparison to check if two objects are equal. |
|
9288 _.isEqual = function(a, b) { |
|
9289 return eq(a, b, [], []); |
|
9290 }; |
|
9291 |
|
9292 // Is a given array, string, or object empty? |
|
9293 // An "empty" object has no enumerable own-properties. |
|
9294 _.isEmpty = function(obj) { |
|
9295 if (obj == null) return true; |
|
9296 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; |
|
9297 for (var key in obj) if (_.has(obj, key)) return false; |
|
9298 return true; |
|
9299 }; |
|
9300 |
|
9301 // Is a given value a DOM element? |
|
9302 _.isElement = function(obj) { |
|
9303 return !!(obj && obj.nodeType === 1); |
|
9304 }; |
|
9305 |
|
9306 // Is a given value an array? |
|
9307 // Delegates to ECMA5's native Array.isArray |
|
9308 _.isArray = nativeIsArray || function(obj) { |
|
9309 return toString.call(obj) == '[object Array]'; |
|
9310 }; |
|
9311 |
|
9312 // Is a given variable an object? |
|
9313 _.isObject = function(obj) { |
|
9314 return obj === Object(obj); |
|
9315 }; |
|
9316 |
|
9317 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. |
|
9318 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { |
|
9319 _['is' + name] = function(obj) { |
|
9320 return toString.call(obj) == '[object ' + name + ']'; |
|
9321 }; |
|
9322 }); |
|
9323 |
|
9324 // Define a fallback version of the method in browsers (ahem, IE), where |
|
9325 // there isn't any inspectable "Arguments" type. |
|
9326 if (!_.isArguments(arguments)) { |
|
9327 _.isArguments = function(obj) { |
|
9328 return !!(obj && _.has(obj, 'callee')); |
|
9329 }; |
|
9330 } |
|
9331 |
|
9332 // Optimize `isFunction` if appropriate. |
|
9333 if (typeof (/./) !== 'function') { |
|
9334 _.isFunction = function(obj) { |
|
9335 return typeof obj === 'function'; |
|
9336 }; |
|
9337 } |
|
9338 |
|
9339 // Is a given object a finite number? |
|
9340 _.isFinite = function(obj) { |
|
9341 return isFinite(obj) && !isNaN(parseFloat(obj)); |
|
9342 }; |
|
9343 |
|
9344 // Is the given value `NaN`? (NaN is the only number which does not equal itself). |
|
9345 _.isNaN = function(obj) { |
|
9346 return _.isNumber(obj) && obj != +obj; |
|
9347 }; |
|
9348 |
|
9349 // Is a given value a boolean? |
|
9350 _.isBoolean = function(obj) { |
|
9351 return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; |
|
9352 }; |
|
9353 |
|
9354 // Is a given value equal to null? |
|
9355 _.isNull = function(obj) { |
|
9356 return obj === null; |
|
9357 }; |
|
9358 |
|
9359 // Is a given variable undefined? |
|
9360 _.isUndefined = function(obj) { |
|
9361 return obj === void 0; |
|
9362 }; |
|
9363 |
|
9364 // Shortcut function for checking if an object has a given property directly |
|
9365 // on itself (in other words, not on a prototype). |
|
9366 _.has = function(obj, key) { |
|
9367 return hasOwnProperty.call(obj, key); |
|
9368 }; |
|
9369 |
|
9370 // Utility Functions |
|
9371 // ----------------- |
|
9372 |
|
9373 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its |
|
9374 // previous owner. Returns a reference to the Underscore object. |
|
9375 _.noConflict = function() { |
|
9376 root._ = previousUnderscore; |
|
9377 return this; |
|
9378 }; |
|
9379 |
|
9380 // Keep the identity function around for default iterators. |
|
9381 _.identity = function(value) { |
|
9382 return value; |
|
9383 }; |
|
9384 |
|
9385 // Run a function **n** times. |
|
9386 _.times = function(n, iterator, context) { |
|
9387 var accum = Array(n); |
|
9388 for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); |
|
9389 return accum; |
|
9390 }; |
|
9391 |
|
9392 // Return a random integer between min and max (inclusive). |
|
9393 _.random = function(min, max) { |
|
9394 if (max == null) { |
|
9395 max = min; |
|
9396 min = 0; |
|
9397 } |
|
9398 return min + Math.floor(Math.random() * (max - min + 1)); |
|
9399 }; |
|
9400 |
|
9401 // List of HTML entities for escaping. |
|
9402 var entityMap = { |
|
9403 escape: { |
|
9404 '&': '&', |
|
9405 '<': '<', |
|
9406 '>': '>', |
|
9407 '"': '"', |
|
9408 "'": ''', |
|
9409 '/': '/' |
|
9410 } |
|
9411 }; |
|
9412 entityMap.unescape = _.invert(entityMap.escape); |
|
9413 |
|
9414 // Regexes containing the keys and values listed immediately above. |
|
9415 var entityRegexes = { |
|
9416 escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), |
|
9417 unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') |
|
9418 }; |
|
9419 |
|
9420 // Functions for escaping and unescaping strings to/from HTML interpolation. |
|
9421 _.each(['escape', 'unescape'], function(method) { |
|
9422 _[method] = function(string) { |
|
9423 if (string == null) return ''; |
|
9424 return ('' + string).replace(entityRegexes[method], function(match) { |
|
9425 return entityMap[method][match]; |
|
9426 }); |
|
9427 }; |
|
9428 }); |
|
9429 |
|
9430 // If the value of the named property is a function then invoke it; |
|
9431 // otherwise, return it. |
|
9432 _.result = function(object, property) { |
|
9433 if (object == null) return null; |
|
9434 var value = object[property]; |
|
9435 return _.isFunction(value) ? value.call(object) : value; |
|
9436 }; |
|
9437 |
|
9438 // Add your own custom functions to the Underscore object. |
|
9439 _.mixin = function(obj) { |
|
9440 each(_.functions(obj), function(name){ |
|
9441 var func = _[name] = obj[name]; |
|
9442 _.prototype[name] = function() { |
|
9443 var args = [this._wrapped]; |
|
9444 push.apply(args, arguments); |
|
9445 return result.call(this, func.apply(_, args)); |
|
9446 }; |
|
9447 }); |
|
9448 }; |
|
9449 |
|
9450 // Generate a unique integer id (unique within the entire client session). |
|
9451 // Useful for temporary DOM ids. |
|
9452 var idCounter = 0; |
|
9453 _.uniqueId = function(prefix) { |
|
9454 var id = ++idCounter + ''; |
|
9455 return prefix ? prefix + id : id; |
|
9456 }; |
|
9457 |
|
9458 // By default, Underscore uses ERB-style template delimiters, change the |
|
9459 // following template settings to use alternative delimiters. |
|
9460 _.templateSettings = { |
|
9461 evaluate : /<%([\s\S]+?)%>/g, |
|
9462 interpolate : /<%=([\s\S]+?)%>/g, |
|
9463 escape : /<%-([\s\S]+?)%>/g |
|
9464 }; |
|
9465 |
|
9466 // When customizing `templateSettings`, if you don't want to define an |
|
9467 // interpolation, evaluation or escaping regex, we need one that is |
|
9468 // guaranteed not to match. |
|
9469 var noMatch = /(.)^/; |
|
9470 |
|
9471 // Certain characters need to be escaped so that they can be put into a |
|
9472 // string literal. |
|
9473 var escapes = { |
|
9474 "'": "'", |
|
9475 '\\': '\\', |
|
9476 '\r': 'r', |
|
9477 '\n': 'n', |
|
9478 '\t': 't', |
|
9479 '\u2028': 'u2028', |
|
9480 '\u2029': 'u2029' |
|
9481 }; |
|
9482 |
|
9483 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; |
|
9484 |
|
9485 // JavaScript micro-templating, similar to John Resig's implementation. |
|
9486 // Underscore templating handles arbitrary delimiters, preserves whitespace, |
|
9487 // and correctly escapes quotes within interpolated code. |
|
9488 _.template = function(text, data, settings) { |
|
9489 var render; |
|
9490 settings = _.defaults({}, settings, _.templateSettings); |
|
9491 |
|
9492 // Combine delimiters into one regular expression via alternation. |
|
9493 var matcher = new RegExp([ |
|
9494 (settings.escape || noMatch).source, |
|
9495 (settings.interpolate || noMatch).source, |
|
9496 (settings.evaluate || noMatch).source |
|
9497 ].join('|') + '|$', 'g'); |
|
9498 |
|
9499 // Compile the template source, escaping string literals appropriately. |
|
9500 var index = 0; |
|
9501 var source = "__p+='"; |
|
9502 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { |
|
9503 source += text.slice(index, offset) |
|
9504 .replace(escaper, function(match) { return '\\' + escapes[match]; }); |
|
9505 |
|
9506 if (escape) { |
|
9507 source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; |
|
9508 } |
|
9509 if (interpolate) { |
|
9510 source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; |
|
9511 } |
|
9512 if (evaluate) { |
|
9513 source += "';\n" + evaluate + "\n__p+='"; |
|
9514 } |
|
9515 index = offset + match.length; |
|
9516 return match; |
|
9517 }); |
|
9518 source += "';\n"; |
|
9519 |
|
9520 // If a variable is not specified, place data values in local scope. |
|
9521 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; |
|
9522 |
|
9523 source = "var __t,__p='',__j=Array.prototype.join," + |
|
9524 "print=function(){__p+=__j.call(arguments,'');};\n" + |
|
9525 source + "return __p;\n"; |
|
9526 |
|
9527 try { |
|
9528 render = new Function(settings.variable || 'obj', '_', source); |
|
9529 } catch (e) { |
|
9530 e.source = source; |
|
9531 throw e; |
|
9532 } |
|
9533 |
|
9534 if (data) return render(data, _); |
|
9535 var template = function(data) { |
|
9536 return render.call(this, data, _); |
|
9537 }; |
|
9538 |
|
9539 // Provide the compiled function source as a convenience for precompilation. |
|
9540 template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; |
|
9541 |
|
9542 return template; |
|
9543 }; |
|
9544 |
|
9545 // Add a "chain" function, which will delegate to the wrapper. |
|
9546 _.chain = function(obj) { |
|
9547 return _(obj).chain(); |
|
9548 }; |
|
9549 |
|
9550 // OOP |
|
9551 // --------------- |
|
9552 // If Underscore is called as a function, it returns a wrapped object that |
|
9553 // can be used OO-style. This wrapper holds altered versions of all the |
|
9554 // underscore functions. Wrapped objects may be chained. |
|
9555 |
|
9556 // Helper function to continue chaining intermediate results. |
|
9557 var result = function(obj) { |
|
9558 return this._chain ? _(obj).chain() : obj; |
|
9559 }; |
|
9560 |
|
9561 // Add all of the Underscore functions to the wrapper object. |
|
9562 _.mixin(_); |
|
9563 |
|
9564 // Add all mutator Array functions to the wrapper. |
|
9565 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { |
|
9566 var method = ArrayProto[name]; |
|
9567 _.prototype[name] = function() { |
|
9568 var obj = this._wrapped; |
|
9569 method.apply(obj, arguments); |
|
9570 if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; |
|
9571 return result.call(this, obj); |
|
9572 }; |
|
9573 }); |
|
9574 |
|
9575 // Add all accessor Array functions to the wrapper. |
|
9576 each(['concat', 'join', 'slice'], function(name) { |
|
9577 var method = ArrayProto[name]; |
|
9578 _.prototype[name] = function() { |
|
9579 return result.call(this, method.apply(this._wrapped, arguments)); |
|
9580 }; |
|
9581 }); |
|
9582 |
|
9583 _.extend(_.prototype, { |
|
9584 |
|
9585 // Start chaining a wrapped Underscore object. |
|
9586 chain: function() { |
|
9587 this._chain = true; |
|
9588 return this; |
|
9589 }, |
|
9590 |
|
9591 // Extracts the result from a wrapped and chained object. |
|
9592 value: function() { |
|
9593 return this._wrapped; |
|
9594 } |
|
9595 |
|
9596 }); |
|
9597 |
|
9598 }).call(this); |
|
9599 |
|
9600 })() |
|
9601 },{}],14:[function(require,module,exports){ |
|
9602 exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) { |
|
9603 var e, m, |
|
9604 eLen = nBytes * 8 - mLen - 1, |
|
9605 eMax = (1 << eLen) - 1, |
|
9606 eBias = eMax >> 1, |
|
9607 nBits = -7, |
|
9608 i = isBE ? 0 : (nBytes - 1), |
|
9609 d = isBE ? 1 : -1, |
|
9610 s = buffer[offset + i]; |
|
9611 |
|
9612 i += d; |
|
9613 |
|
9614 e = s & ((1 << (-nBits)) - 1); |
|
9615 s >>= (-nBits); |
|
9616 nBits += eLen; |
|
9617 for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); |
|
9618 |
|
9619 m = e & ((1 << (-nBits)) - 1); |
|
9620 e >>= (-nBits); |
|
9621 nBits += mLen; |
|
9622 for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); |
|
9623 |
|
9624 if (e === 0) { |
|
9625 e = 1 - eBias; |
|
9626 } else if (e === eMax) { |
|
9627 return m ? NaN : ((s ? -1 : 1) * Infinity); |
|
9628 } else { |
|
9629 m = m + Math.pow(2, mLen); |
|
9630 e = e - eBias; |
|
9631 } |
|
9632 return (s ? -1 : 1) * m * Math.pow(2, e - mLen); |
|
9633 }; |
|
9634 |
|
9635 exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) { |
|
9636 var e, m, c, |
|
9637 eLen = nBytes * 8 - mLen - 1, |
|
9638 eMax = (1 << eLen) - 1, |
|
9639 eBias = eMax >> 1, |
|
9640 rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), |
|
9641 i = isBE ? (nBytes - 1) : 0, |
|
9642 d = isBE ? -1 : 1, |
|
9643 s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; |
|
9644 |
|
9645 value = Math.abs(value); |
|
9646 |
|
9647 if (isNaN(value) || value === Infinity) { |
|
9648 m = isNaN(value) ? 1 : 0; |
|
9649 e = eMax; |
|
9650 } else { |
|
9651 e = Math.floor(Math.log(value) / Math.LN2); |
|
9652 if (value * (c = Math.pow(2, -e)) < 1) { |
|
9653 e--; |
|
9654 c *= 2; |
|
9655 } |
|
9656 if (e + eBias >= 1) { |
|
9657 value += rt / c; |
|
9658 } else { |
|
9659 value += rt * Math.pow(2, 1 - eBias); |
|
9660 } |
|
9661 if (value * c >= 2) { |
|
9662 e++; |
|
9663 c /= 2; |
|
9664 } |
|
9665 |
|
9666 if (e + eBias >= eMax) { |
|
9667 m = 0; |
|
9668 e = eMax; |
|
9669 } else if (e + eBias >= 1) { |
|
9670 m = (value * c - 1) * Math.pow(2, mLen); |
|
9671 e = e + eBias; |
|
9672 } else { |
|
9673 m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); |
|
9674 e = 0; |
|
9675 } |
|
9676 } |
|
9677 |
|
9678 for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); |
|
9679 |
|
9680 e = (e << mLen) | m; |
|
9681 eLen += mLen; |
|
9682 for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); |
|
9683 |
|
9684 buffer[offset + i - d] |= s * 128; |
|
9685 }; |
|
9686 |
|
9687 },{}],13:[function(require,module,exports){ |
|
9688 (function(){function SlowBuffer (size) { |
|
9689 this.length = size; |
|
9690 }; |
|
9691 |
|
9692 var assert = require('assert'); |
|
9693 |
|
9694 exports.INSPECT_MAX_BYTES = 50; |
|
9695 |
|
9696 |
|
9697 function toHex(n) { |
|
9698 if (n < 16) return '0' + n.toString(16); |
|
9699 return n.toString(16); |
|
9700 } |
|
9701 |
|
9702 function utf8ToBytes(str) { |
|
9703 var byteArray = []; |
|
9704 for (var i = 0; i < str.length; i++) |
|
9705 if (str.charCodeAt(i) <= 0x7F) |
|
9706 byteArray.push(str.charCodeAt(i)); |
|
9707 else { |
|
9708 var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); |
|
9709 for (var j = 0; j < h.length; j++) |
|
9710 byteArray.push(parseInt(h[j], 16)); |
|
9711 } |
|
9712 |
|
9713 return byteArray; |
|
9714 } |
|
9715 |
|
9716 function asciiToBytes(str) { |
|
9717 var byteArray = [] |
|
9718 for (var i = 0; i < str.length; i++ ) |
|
9719 // Node's code seems to be doing this and not & 0x7F.. |
|
9720 byteArray.push( str.charCodeAt(i) & 0xFF ); |
|
9721 |
|
9722 return byteArray; |
|
9723 } |
|
9724 |
|
9725 function base64ToBytes(str) { |
|
9726 return require("base64-js").toByteArray(str); |
|
9727 } |
|
9728 |
|
9729 SlowBuffer.byteLength = function (str, encoding) { |
|
9730 switch (encoding || "utf8") { |
|
9731 case 'hex': |
|
9732 return str.length / 2; |
|
9733 |
|
9734 case 'utf8': |
|
9735 case 'utf-8': |
|
9736 return utf8ToBytes(str).length; |
|
9737 |
|
9738 case 'ascii': |
|
9739 case 'binary': |
|
9740 return str.length; |
|
9741 |
|
9742 case 'base64': |
|
9743 return base64ToBytes(str).length; |
|
9744 |
|
9745 default: |
|
9746 throw new Error('Unknown encoding'); |
|
9747 } |
|
9748 }; |
|
9749 |
|
9750 function blitBuffer(src, dst, offset, length) { |
|
9751 var pos, i = 0; |
|
9752 while (i < length) { |
|
9753 if ((i+offset >= dst.length) || (i >= src.length)) |
|
9754 break; |
|
9755 |
|
9756 dst[i + offset] = src[i]; |
|
9757 i++; |
|
9758 } |
|
9759 return i; |
|
9760 } |
|
9761 |
|
9762 SlowBuffer.prototype.utf8Write = function (string, offset, length) { |
|
9763 var bytes, pos; |
|
9764 return SlowBuffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length); |
|
9765 }; |
|
9766 |
|
9767 SlowBuffer.prototype.asciiWrite = function (string, offset, length) { |
|
9768 var bytes, pos; |
|
9769 return SlowBuffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length); |
|
9770 }; |
|
9771 |
|
9772 SlowBuffer.prototype.binaryWrite = SlowBuffer.prototype.asciiWrite; |
|
9773 |
|
9774 SlowBuffer.prototype.base64Write = function (string, offset, length) { |
|
9775 var bytes, pos; |
|
9776 return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length); |
|
9777 }; |
|
9778 |
|
9779 SlowBuffer.prototype.base64Slice = function (start, end) { |
|
9780 var bytes = Array.prototype.slice.apply(this, arguments) |
|
9781 return require("base64-js").fromByteArray(bytes); |
|
9782 } |
|
9783 |
|
9784 function decodeUtf8Char(str) { |
|
9785 try { |
|
9786 return decodeURIComponent(str); |
|
9787 } catch (err) { |
|
9788 return String.fromCharCode(0xFFFD); // UTF 8 invalid char |
|
9789 } |
|
9790 } |
|
9791 |
|
9792 SlowBuffer.prototype.utf8Slice = function () { |
|
9793 var bytes = Array.prototype.slice.apply(this, arguments); |
|
9794 var res = ""; |
|
9795 var tmp = ""; |
|
9796 var i = 0; |
|
9797 while (i < bytes.length) { |
|
9798 if (bytes[i] <= 0x7F) { |
|
9799 res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]); |
|
9800 tmp = ""; |
|
9801 } else |
|
9802 tmp += "%" + bytes[i].toString(16); |
|
9803 |
|
9804 i++; |
|
9805 } |
|
9806 |
|
9807 return res + decodeUtf8Char(tmp); |
|
9808 } |
|
9809 |
|
9810 SlowBuffer.prototype.asciiSlice = function () { |
|
9811 var bytes = Array.prototype.slice.apply(this, arguments); |
|
9812 var ret = ""; |
|
9813 for (var i = 0; i < bytes.length; i++) |
|
9814 ret += String.fromCharCode(bytes[i]); |
|
9815 return ret; |
|
9816 } |
|
9817 |
|
9818 SlowBuffer.prototype.binarySlice = SlowBuffer.prototype.asciiSlice; |
|
9819 |
|
9820 SlowBuffer.prototype.inspect = function() { |
|
9821 var out = [], |
|
9822 len = this.length; |
|
9823 for (var i = 0; i < len; i++) { |
|
9824 out[i] = toHex(this[i]); |
|
9825 if (i == exports.INSPECT_MAX_BYTES) { |
|
9826 out[i + 1] = '...'; |
|
9827 break; |
|
9828 } |
|
9829 } |
|
9830 return '<SlowBuffer ' + out.join(' ') + '>'; |
|
9831 }; |
|
9832 |
|
9833 |
|
9834 SlowBuffer.prototype.hexSlice = function(start, end) { |
|
9835 var len = this.length; |
|
9836 |
|
9837 if (!start || start < 0) start = 0; |
|
9838 if (!end || end < 0 || end > len) end = len; |
|
9839 |
|
9840 var out = ''; |
|
9841 for (var i = start; i < end; i++) { |
|
9842 out += toHex(this[i]); |
|
9843 } |
|
9844 return out; |
|
9845 }; |
|
9846 |
|
9847 |
|
9848 SlowBuffer.prototype.toString = function(encoding, start, end) { |
|
9849 encoding = String(encoding || 'utf8').toLowerCase(); |
|
9850 start = +start || 0; |
|
9851 if (typeof end == 'undefined') end = this.length; |
|
9852 |
|
9853 // Fastpath empty strings |
|
9854 if (+end == start) { |
|
9855 return ''; |
|
9856 } |
|
9857 |
|
9858 switch (encoding) { |
|
9859 case 'hex': |
|
9860 return this.hexSlice(start, end); |
|
9861 |
|
9862 case 'utf8': |
|
9863 case 'utf-8': |
|
9864 return this.utf8Slice(start, end); |
|
9865 |
|
9866 case 'ascii': |
|
9867 return this.asciiSlice(start, end); |
|
9868 |
|
9869 case 'binary': |
|
9870 return this.binarySlice(start, end); |
|
9871 |
|
9872 case 'base64': |
|
9873 return this.base64Slice(start, end); |
|
9874 |
|
9875 case 'ucs2': |
|
9876 case 'ucs-2': |
|
9877 return this.ucs2Slice(start, end); |
|
9878 |
|
9879 default: |
|
9880 throw new Error('Unknown encoding'); |
|
9881 } |
|
9882 }; |
|
9883 |
|
9884 |
|
9885 SlowBuffer.prototype.hexWrite = function(string, offset, length) { |
|
9886 offset = +offset || 0; |
|
9887 var remaining = this.length - offset; |
|
9888 if (!length) { |
|
9889 length = remaining; |
|
9890 } else { |
|
9891 length = +length; |
|
9892 if (length > remaining) { |
|
9893 length = remaining; |
|
9894 } |
|
9895 } |
|
9896 |
|
9897 // must be an even number of digits |
|
9898 var strLen = string.length; |
|
9899 if (strLen % 2) { |
|
9900 throw new Error('Invalid hex string'); |
|
9901 } |
|
9902 if (length > strLen / 2) { |
|
9903 length = strLen / 2; |
|
9904 } |
|
9905 for (var i = 0; i < length; i++) { |
|
9906 var byte = parseInt(string.substr(i * 2, 2), 16); |
|
9907 if (isNaN(byte)) throw new Error('Invalid hex string'); |
|
9908 this[offset + i] = byte; |
|
9909 } |
|
9910 SlowBuffer._charsWritten = i * 2; |
|
9911 return i; |
|
9912 }; |
|
9913 |
|
9914 |
|
9915 SlowBuffer.prototype.write = function(string, offset, length, encoding) { |
|
9916 // Support both (string, offset, length, encoding) |
|
9917 // and the legacy (string, encoding, offset, length) |
|
9918 if (isFinite(offset)) { |
|
9919 if (!isFinite(length)) { |
|
9920 encoding = length; |
|
9921 length = undefined; |
|
9922 } |
|
9923 } else { // legacy |
|
9924 var swap = encoding; |
|
9925 encoding = offset; |
|
9926 offset = length; |
|
9927 length = swap; |
|
9928 } |
|
9929 |
|
9930 offset = +offset || 0; |
|
9931 var remaining = this.length - offset; |
|
9932 if (!length) { |
|
9933 length = remaining; |
|
9934 } else { |
|
9935 length = +length; |
|
9936 if (length > remaining) { |
|
9937 length = remaining; |
|
9938 } |
|
9939 } |
|
9940 encoding = String(encoding || 'utf8').toLowerCase(); |
|
9941 |
|
9942 switch (encoding) { |
|
9943 case 'hex': |
|
9944 return this.hexWrite(string, offset, length); |
|
9945 |
|
9946 case 'utf8': |
|
9947 case 'utf-8': |
|
9948 return this.utf8Write(string, offset, length); |
|
9949 |
|
9950 case 'ascii': |
|
9951 return this.asciiWrite(string, offset, length); |
|
9952 |
|
9953 case 'binary': |
|
9954 return this.binaryWrite(string, offset, length); |
|
9955 |
|
9956 case 'base64': |
|
9957 return this.base64Write(string, offset, length); |
|
9958 |
|
9959 case 'ucs2': |
|
9960 case 'ucs-2': |
|
9961 return this.ucs2Write(string, offset, length); |
|
9962 |
|
9963 default: |
|
9964 throw new Error('Unknown encoding'); |
|
9965 } |
|
9966 }; |
|
9967 |
|
9968 |
|
9969 // slice(start, end) |
|
9970 SlowBuffer.prototype.slice = function(start, end) { |
|
9971 if (end === undefined) end = this.length; |
|
9972 |
|
9973 if (end > this.length) { |
|
9974 throw new Error('oob'); |
|
9975 } |
|
9976 if (start > end) { |
|
9977 throw new Error('oob'); |
|
9978 } |
|
9979 |
|
9980 return new Buffer(this, end - start, +start); |
|
9981 }; |
|
9982 |
|
9983 SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) { |
|
9984 var temp = []; |
|
9985 for (var i=sourcestart; i<sourceend; i++) { |
|
9986 assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!"); |
|
9987 temp.push(this[i]); |
|
9988 } |
|
9989 |
|
9990 for (var i=targetstart; i<targetstart+temp.length; i++) { |
|
9991 target[i] = temp[i-targetstart]; |
|
9992 } |
|
9993 }; |
|
9994 |
|
9995 SlowBuffer.prototype.fill = function(value, start, end) { |
|
9996 if (end > this.length) { |
|
9997 throw new Error('oob'); |
|
9998 } |
|
9999 if (start > end) { |
|
10000 throw new Error('oob'); |
|
10001 } |
|
10002 |
|
10003 for (var i = start; i < end; i++) { |
|
10004 this[i] = value; |
|
10005 } |
|
10006 } |
|
10007 |
|
10008 function coerce(length) { |
|
10009 // Coerce length to a number (possibly NaN), round up |
|
10010 // in case it's fractional (e.g. 123.456) then do a |
|
10011 // double negate to coerce a NaN to 0. Easy, right? |
|
10012 length = ~~Math.ceil(+length); |
|
10013 return length < 0 ? 0 : length; |
|
10014 } |
|
10015 |
|
10016 |
|
10017 // Buffer |
|
10018 |
|
10019 function Buffer(subject, encoding, offset) { |
|
10020 if (!(this instanceof Buffer)) { |
|
10021 return new Buffer(subject, encoding, offset); |
|
10022 } |
|
10023 |
|
10024 var type; |
|
10025 |
|
10026 // Are we slicing? |
|
10027 if (typeof offset === 'number') { |
|
10028 this.length = coerce(encoding); |
|
10029 this.parent = subject; |
|
10030 this.offset = offset; |
|
10031 } else { |
|
10032 // Find the length |
|
10033 switch (type = typeof subject) { |
|
10034 case 'number': |
|
10035 this.length = coerce(subject); |
|
10036 break; |
|
10037 |
|
10038 case 'string': |
|
10039 this.length = Buffer.byteLength(subject, encoding); |
|
10040 break; |
|
10041 |
|
10042 case 'object': // Assume object is an array |
|
10043 this.length = coerce(subject.length); |
|
10044 break; |
|
10045 |
|
10046 default: |
|
10047 throw new Error('First argument needs to be a number, ' + |
|
10048 'array or string.'); |
|
10049 } |
|
10050 |
|
10051 if (this.length > Buffer.poolSize) { |
|
10052 // Big buffer, just alloc one. |
|
10053 this.parent = new SlowBuffer(this.length); |
|
10054 this.offset = 0; |
|
10055 |
|
10056 } else { |
|
10057 // Small buffer. |
|
10058 if (!pool || pool.length - pool.used < this.length) allocPool(); |
|
10059 this.parent = pool; |
|
10060 this.offset = pool.used; |
|
10061 pool.used += this.length; |
|
10062 } |
|
10063 |
|
10064 // Treat array-ish objects as a byte array. |
|
10065 if (isArrayIsh(subject)) { |
|
10066 for (var i = 0; i < this.length; i++) { |
|
10067 if (subject instanceof Buffer) { |
|
10068 this.parent[i + this.offset] = subject.readUInt8(i); |
|
10069 } |
|
10070 else { |
|
10071 this.parent[i + this.offset] = subject[i]; |
|
10072 } |
|
10073 } |
|
10074 } else if (type == 'string') { |
|
10075 // We are a string |
|
10076 this.length = this.write(subject, 0, encoding); |
|
10077 } |
|
10078 } |
|
10079 |
|
10080 } |
|
10081 |
|
10082 function isArrayIsh(subject) { |
|
10083 return Array.isArray(subject) || Buffer.isBuffer(subject) || |
|
10084 subject && typeof subject === 'object' && |
|
10085 typeof subject.length === 'number'; |
|
10086 } |
|
10087 |
|
10088 exports.SlowBuffer = SlowBuffer; |
|
10089 exports.Buffer = Buffer; |
|
10090 |
|
10091 Buffer.poolSize = 8 * 1024; |
|
10092 var pool; |
|
10093 |
|
10094 function allocPool() { |
|
10095 pool = new SlowBuffer(Buffer.poolSize); |
|
10096 pool.used = 0; |
|
10097 } |
|
10098 |
|
10099 |
|
10100 // Static methods |
|
10101 Buffer.isBuffer = function isBuffer(b) { |
|
10102 return b instanceof Buffer || b instanceof SlowBuffer; |
|
10103 }; |
|
10104 |
|
10105 Buffer.concat = function (list, totalLength) { |
|
10106 if (!Array.isArray(list)) { |
|
10107 throw new Error("Usage: Buffer.concat(list, [totalLength])\n \ |
|
10108 list should be an Array."); |
|
10109 } |
|
10110 |
|
10111 if (list.length === 0) { |
|
10112 return new Buffer(0); |
|
10113 } else if (list.length === 1) { |
|
10114 return list[0]; |
|
10115 } |
|
10116 |
|
10117 if (typeof totalLength !== 'number') { |
|
10118 totalLength = 0; |
|
10119 for (var i = 0; i < list.length; i++) { |
|
10120 var buf = list[i]; |
|
10121 totalLength += buf.length; |
|
10122 } |
|
10123 } |
|
10124 |
|
10125 var buffer = new Buffer(totalLength); |
|
10126 var pos = 0; |
|
10127 for (var i = 0; i < list.length; i++) { |
|
10128 var buf = list[i]; |
|
10129 buf.copy(buffer, pos); |
|
10130 pos += buf.length; |
|
10131 } |
|
10132 return buffer; |
|
10133 }; |
|
10134 |
|
10135 // Inspect |
|
10136 Buffer.prototype.inspect = function inspect() { |
|
10137 var out = [], |
|
10138 len = this.length; |
|
10139 |
|
10140 for (var i = 0; i < len; i++) { |
|
10141 out[i] = toHex(this.parent[i + this.offset]); |
|
10142 if (i == exports.INSPECT_MAX_BYTES) { |
|
10143 out[i + 1] = '...'; |
|
10144 break; |
|
10145 } |
|
10146 } |
|
10147 |
|
10148 return '<Buffer ' + out.join(' ') + '>'; |
|
10149 }; |
|
10150 |
|
10151 |
|
10152 Buffer.prototype.get = function get(i) { |
|
10153 if (i < 0 || i >= this.length) throw new Error('oob'); |
|
10154 return this.parent[this.offset + i]; |
|
10155 }; |
|
10156 |
|
10157 |
|
10158 Buffer.prototype.set = function set(i, v) { |
|
10159 if (i < 0 || i >= this.length) throw new Error('oob'); |
|
10160 return this.parent[this.offset + i] = v; |
|
10161 }; |
|
10162 |
|
10163 |
|
10164 // write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8') |
|
10165 Buffer.prototype.write = function(string, offset, length, encoding) { |
|
10166 // Support both (string, offset, length, encoding) |
|
10167 // and the legacy (string, encoding, offset, length) |
|
10168 if (isFinite(offset)) { |
|
10169 if (!isFinite(length)) { |
|
10170 encoding = length; |
|
10171 length = undefined; |
|
10172 } |
|
10173 } else { // legacy |
|
10174 var swap = encoding; |
|
10175 encoding = offset; |
|
10176 offset = length; |
|
10177 length = swap; |
|
10178 } |
|
10179 |
|
10180 offset = +offset || 0; |
|
10181 var remaining = this.length - offset; |
|
10182 if (!length) { |
|
10183 length = remaining; |
|
10184 } else { |
|
10185 length = +length; |
|
10186 if (length > remaining) { |
|
10187 length = remaining; |
|
10188 } |
|
10189 } |
|
10190 encoding = String(encoding || 'utf8').toLowerCase(); |
|
10191 |
|
10192 var ret; |
|
10193 switch (encoding) { |
|
10194 case 'hex': |
|
10195 ret = this.parent.hexWrite(string, this.offset + offset, length); |
|
10196 break; |
|
10197 |
|
10198 case 'utf8': |
|
10199 case 'utf-8': |
|
10200 ret = this.parent.utf8Write(string, this.offset + offset, length); |
|
10201 break; |
|
10202 |
|
10203 case 'ascii': |
|
10204 ret = this.parent.asciiWrite(string, this.offset + offset, length); |
|
10205 break; |
|
10206 |
|
10207 case 'binary': |
|
10208 ret = this.parent.binaryWrite(string, this.offset + offset, length); |
|
10209 break; |
|
10210 |
|
10211 case 'base64': |
|
10212 // Warning: maxLength not taken into account in base64Write |
|
10213 ret = this.parent.base64Write(string, this.offset + offset, length); |
|
10214 break; |
|
10215 |
|
10216 case 'ucs2': |
|
10217 case 'ucs-2': |
|
10218 ret = this.parent.ucs2Write(string, this.offset + offset, length); |
|
10219 break; |
|
10220 |
|
10221 default: |
|
10222 throw new Error('Unknown encoding'); |
|
10223 } |
|
10224 |
|
10225 Buffer._charsWritten = SlowBuffer._charsWritten; |
|
10226 |
|
10227 return ret; |
|
10228 }; |
|
10229 |
|
10230 |
|
10231 // toString(encoding, start=0, end=buffer.length) |
|
10232 Buffer.prototype.toString = function(encoding, start, end) { |
|
10233 encoding = String(encoding || 'utf8').toLowerCase(); |
|
10234 |
|
10235 if (typeof start == 'undefined' || start < 0) { |
|
10236 start = 0; |
|
10237 } else if (start > this.length) { |
|
10238 start = this.length; |
|
10239 } |
|
10240 |
|
10241 if (typeof end == 'undefined' || end > this.length) { |
|
10242 end = this.length; |
|
10243 } else if (end < 0) { |
|
10244 end = 0; |
|
10245 } |
|
10246 |
|
10247 start = start + this.offset; |
|
10248 end = end + this.offset; |
|
10249 |
|
10250 switch (encoding) { |
|
10251 case 'hex': |
|
10252 return this.parent.hexSlice(start, end); |
|
10253 |
|
10254 case 'utf8': |
|
10255 case 'utf-8': |
|
10256 return this.parent.utf8Slice(start, end); |
|
10257 |
|
10258 case 'ascii': |
|
10259 return this.parent.asciiSlice(start, end); |
|
10260 |
|
10261 case 'binary': |
|
10262 return this.parent.binarySlice(start, end); |
|
10263 |
|
10264 case 'base64': |
|
10265 return this.parent.base64Slice(start, end); |
|
10266 |
|
10267 case 'ucs2': |
|
10268 case 'ucs-2': |
|
10269 return this.parent.ucs2Slice(start, end); |
|
10270 |
|
10271 default: |
|
10272 throw new Error('Unknown encoding'); |
|
10273 } |
|
10274 }; |
|
10275 |
|
10276 |
|
10277 // byteLength |
|
10278 Buffer.byteLength = SlowBuffer.byteLength; |
|
10279 |
|
10280 |
|
10281 // fill(value, start=0, end=buffer.length) |
|
10282 Buffer.prototype.fill = function fill(value, start, end) { |
|
10283 value || (value = 0); |
|
10284 start || (start = 0); |
|
10285 end || (end = this.length); |
|
10286 |
|
10287 if (typeof value === 'string') { |
|
10288 value = value.charCodeAt(0); |
|
10289 } |
|
10290 if (!(typeof value === 'number') || isNaN(value)) { |
|
10291 throw new Error('value is not a number'); |
|
10292 } |
|
10293 |
|
10294 if (end < start) throw new Error('end < start'); |
|
10295 |
|
10296 // Fill 0 bytes; we're done |
|
10297 if (end === start) return 0; |
|
10298 if (this.length == 0) return 0; |
|
10299 |
|
10300 if (start < 0 || start >= this.length) { |
|
10301 throw new Error('start out of bounds'); |
|
10302 } |
|
10303 |
|
10304 if (end < 0 || end > this.length) { |
|
10305 throw new Error('end out of bounds'); |
|
10306 } |
|
10307 |
|
10308 return this.parent.fill(value, |
|
10309 start + this.offset, |
|
10310 end + this.offset); |
|
10311 }; |
|
10312 |
|
10313 |
|
10314 // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) |
|
10315 Buffer.prototype.copy = function(target, target_start, start, end) { |
|
10316 var source = this; |
|
10317 start || (start = 0); |
|
10318 end || (end = this.length); |
|
10319 target_start || (target_start = 0); |
|
10320 |
|
10321 if (end < start) throw new Error('sourceEnd < sourceStart'); |
|
10322 |
|
10323 // Copy 0 bytes; we're done |
|
10324 if (end === start) return 0; |
|
10325 if (target.length == 0 || source.length == 0) return 0; |
|
10326 |
|
10327 if (target_start < 0 || target_start >= target.length) { |
|
10328 throw new Error('targetStart out of bounds'); |
|
10329 } |
|
10330 |
|
10331 if (start < 0 || start >= source.length) { |
|
10332 throw new Error('sourceStart out of bounds'); |
|
10333 } |
|
10334 |
|
10335 if (end < 0 || end > source.length) { |
|
10336 throw new Error('sourceEnd out of bounds'); |
|
10337 } |
|
10338 |
|
10339 // Are we oob? |
|
10340 if (end > this.length) { |
|
10341 end = this.length; |
|
10342 } |
|
10343 |
|
10344 if (target.length - target_start < end - start) { |
|
10345 end = target.length - target_start + start; |
|
10346 } |
|
10347 |
|
10348 return this.parent.copy(target.parent, |
|
10349 target_start + target.offset, |
|
10350 start + this.offset, |
|
10351 end + this.offset); |
|
10352 }; |
|
10353 |
|
10354 |
|
10355 // slice(start, end) |
|
10356 Buffer.prototype.slice = function(start, end) { |
|
10357 if (end === undefined) end = this.length; |
|
10358 if (end > this.length) throw new Error('oob'); |
|
10359 if (start > end) throw new Error('oob'); |
|
10360 |
|
10361 return new Buffer(this.parent, end - start, +start + this.offset); |
|
10362 }; |
|
10363 |
|
10364 |
|
10365 // Legacy methods for backwards compatibility. |
|
10366 |
|
10367 Buffer.prototype.utf8Slice = function(start, end) { |
|
10368 return this.toString('utf8', start, end); |
|
10369 }; |
|
10370 |
|
10371 Buffer.prototype.binarySlice = function(start, end) { |
|
10372 return this.toString('binary', start, end); |
|
10373 }; |
|
10374 |
|
10375 Buffer.prototype.asciiSlice = function(start, end) { |
|
10376 return this.toString('ascii', start, end); |
|
10377 }; |
|
10378 |
|
10379 Buffer.prototype.utf8Write = function(string, offset) { |
|
10380 return this.write(string, offset, 'utf8'); |
|
10381 }; |
|
10382 |
|
10383 Buffer.prototype.binaryWrite = function(string, offset) { |
|
10384 return this.write(string, offset, 'binary'); |
|
10385 }; |
|
10386 |
|
10387 Buffer.prototype.asciiWrite = function(string, offset) { |
|
10388 return this.write(string, offset, 'ascii'); |
|
10389 }; |
|
10390 |
|
10391 Buffer.prototype.readUInt8 = function(offset, noAssert) { |
|
10392 var buffer = this; |
|
10393 |
|
10394 if (!noAssert) { |
|
10395 assert.ok(offset !== undefined && offset !== null, |
|
10396 'missing offset'); |
|
10397 |
|
10398 assert.ok(offset < buffer.length, |
|
10399 'Trying to read beyond buffer length'); |
|
10400 } |
|
10401 |
|
10402 if (offset >= buffer.length) return; |
|
10403 |
|
10404 return buffer.parent[buffer.offset + offset]; |
|
10405 }; |
|
10406 |
|
10407 function readUInt16(buffer, offset, isBigEndian, noAssert) { |
|
10408 var val = 0; |
|
10409 |
|
10410 |
|
10411 if (!noAssert) { |
|
10412 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10413 'missing or invalid endian'); |
|
10414 |
|
10415 assert.ok(offset !== undefined && offset !== null, |
|
10416 'missing offset'); |
|
10417 |
|
10418 assert.ok(offset + 1 < buffer.length, |
|
10419 'Trying to read beyond buffer length'); |
|
10420 } |
|
10421 |
|
10422 if (offset >= buffer.length) return 0; |
|
10423 |
|
10424 if (isBigEndian) { |
|
10425 val = buffer.parent[buffer.offset + offset] << 8; |
|
10426 if (offset + 1 < buffer.length) { |
|
10427 val |= buffer.parent[buffer.offset + offset + 1]; |
|
10428 } |
|
10429 } else { |
|
10430 val = buffer.parent[buffer.offset + offset]; |
|
10431 if (offset + 1 < buffer.length) { |
|
10432 val |= buffer.parent[buffer.offset + offset + 1] << 8; |
|
10433 } |
|
10434 } |
|
10435 |
|
10436 return val; |
|
10437 } |
|
10438 |
|
10439 Buffer.prototype.readUInt16LE = function(offset, noAssert) { |
|
10440 return readUInt16(this, offset, false, noAssert); |
|
10441 }; |
|
10442 |
|
10443 Buffer.prototype.readUInt16BE = function(offset, noAssert) { |
|
10444 return readUInt16(this, offset, true, noAssert); |
|
10445 }; |
|
10446 |
|
10447 function readUInt32(buffer, offset, isBigEndian, noAssert) { |
|
10448 var val = 0; |
|
10449 |
|
10450 if (!noAssert) { |
|
10451 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10452 'missing or invalid endian'); |
|
10453 |
|
10454 assert.ok(offset !== undefined && offset !== null, |
|
10455 'missing offset'); |
|
10456 |
|
10457 assert.ok(offset + 3 < buffer.length, |
|
10458 'Trying to read beyond buffer length'); |
|
10459 } |
|
10460 |
|
10461 if (offset >= buffer.length) return 0; |
|
10462 |
|
10463 if (isBigEndian) { |
|
10464 if (offset + 1 < buffer.length) |
|
10465 val = buffer.parent[buffer.offset + offset + 1] << 16; |
|
10466 if (offset + 2 < buffer.length) |
|
10467 val |= buffer.parent[buffer.offset + offset + 2] << 8; |
|
10468 if (offset + 3 < buffer.length) |
|
10469 val |= buffer.parent[buffer.offset + offset + 3]; |
|
10470 val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0); |
|
10471 } else { |
|
10472 if (offset + 2 < buffer.length) |
|
10473 val = buffer.parent[buffer.offset + offset + 2] << 16; |
|
10474 if (offset + 1 < buffer.length) |
|
10475 val |= buffer.parent[buffer.offset + offset + 1] << 8; |
|
10476 val |= buffer.parent[buffer.offset + offset]; |
|
10477 if (offset + 3 < buffer.length) |
|
10478 val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0); |
|
10479 } |
|
10480 |
|
10481 return val; |
|
10482 } |
|
10483 |
|
10484 Buffer.prototype.readUInt32LE = function(offset, noAssert) { |
|
10485 return readUInt32(this, offset, false, noAssert); |
|
10486 }; |
|
10487 |
|
10488 Buffer.prototype.readUInt32BE = function(offset, noAssert) { |
|
10489 return readUInt32(this, offset, true, noAssert); |
|
10490 }; |
|
10491 |
|
10492 |
|
10493 /* |
|
10494 * Signed integer types, yay team! A reminder on how two's complement actually |
|
10495 * works. The first bit is the signed bit, i.e. tells us whether or not the |
|
10496 * number should be positive or negative. If the two's complement value is |
|
10497 * positive, then we're done, as it's equivalent to the unsigned representation. |
|
10498 * |
|
10499 * Now if the number is positive, you're pretty much done, you can just leverage |
|
10500 * the unsigned translations and return those. Unfortunately, negative numbers |
|
10501 * aren't quite that straightforward. |
|
10502 * |
|
10503 * At first glance, one might be inclined to use the traditional formula to |
|
10504 * translate binary numbers between the positive and negative values in two's |
|
10505 * complement. (Though it doesn't quite work for the most negative value) |
|
10506 * Mainly: |
|
10507 * - invert all the bits |
|
10508 * - add one to the result |
|
10509 * |
|
10510 * Of course, this doesn't quite work in Javascript. Take for example the value |
|
10511 * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of |
|
10512 * course, Javascript will do the following: |
|
10513 * |
|
10514 * > ~0xff80 |
|
10515 * -65409 |
|
10516 * |
|
10517 * Whoh there, Javascript, that's not quite right. But wait, according to |
|
10518 * Javascript that's perfectly correct. When Javascript ends up seeing the |
|
10519 * constant 0xff80, it has no notion that it is actually a signed number. It |
|
10520 * assumes that we've input the unsigned value 0xff80. Thus, when it does the |
|
10521 * binary negation, it casts it into a signed value, (positive 0xff80). Then |
|
10522 * when you perform binary negation on that, it turns it into a negative number. |
|
10523 * |
|
10524 * Instead, we're going to have to use the following general formula, that works |
|
10525 * in a rather Javascript friendly way. I'm glad we don't support this kind of |
|
10526 * weird numbering scheme in the kernel. |
|
10527 * |
|
10528 * (BIT-MAX - (unsigned)val + 1) * -1 |
|
10529 * |
|
10530 * The astute observer, may think that this doesn't make sense for 8-bit numbers |
|
10531 * (really it isn't necessary for them). However, when you get 16-bit numbers, |
|
10532 * you do. Let's go back to our prior example and see how this will look: |
|
10533 * |
|
10534 * (0xffff - 0xff80 + 1) * -1 |
|
10535 * (0x007f + 1) * -1 |
|
10536 * (0x0080) * -1 |
|
10537 */ |
|
10538 Buffer.prototype.readInt8 = function(offset, noAssert) { |
|
10539 var buffer = this; |
|
10540 var neg; |
|
10541 |
|
10542 if (!noAssert) { |
|
10543 assert.ok(offset !== undefined && offset !== null, |
|
10544 'missing offset'); |
|
10545 |
|
10546 assert.ok(offset < buffer.length, |
|
10547 'Trying to read beyond buffer length'); |
|
10548 } |
|
10549 |
|
10550 if (offset >= buffer.length) return; |
|
10551 |
|
10552 neg = buffer.parent[buffer.offset + offset] & 0x80; |
|
10553 if (!neg) { |
|
10554 return (buffer.parent[buffer.offset + offset]); |
|
10555 } |
|
10556 |
|
10557 return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1); |
|
10558 }; |
|
10559 |
|
10560 function readInt16(buffer, offset, isBigEndian, noAssert) { |
|
10561 var neg, val; |
|
10562 |
|
10563 if (!noAssert) { |
|
10564 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10565 'missing or invalid endian'); |
|
10566 |
|
10567 assert.ok(offset !== undefined && offset !== null, |
|
10568 'missing offset'); |
|
10569 |
|
10570 assert.ok(offset + 1 < buffer.length, |
|
10571 'Trying to read beyond buffer length'); |
|
10572 } |
|
10573 |
|
10574 val = readUInt16(buffer, offset, isBigEndian, noAssert); |
|
10575 neg = val & 0x8000; |
|
10576 if (!neg) { |
|
10577 return val; |
|
10578 } |
|
10579 |
|
10580 return (0xffff - val + 1) * -1; |
|
10581 } |
|
10582 |
|
10583 Buffer.prototype.readInt16LE = function(offset, noAssert) { |
|
10584 return readInt16(this, offset, false, noAssert); |
|
10585 }; |
|
10586 |
|
10587 Buffer.prototype.readInt16BE = function(offset, noAssert) { |
|
10588 return readInt16(this, offset, true, noAssert); |
|
10589 }; |
|
10590 |
|
10591 function readInt32(buffer, offset, isBigEndian, noAssert) { |
|
10592 var neg, val; |
|
10593 |
|
10594 if (!noAssert) { |
|
10595 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10596 'missing or invalid endian'); |
|
10597 |
|
10598 assert.ok(offset !== undefined && offset !== null, |
|
10599 'missing offset'); |
|
10600 |
|
10601 assert.ok(offset + 3 < buffer.length, |
|
10602 'Trying to read beyond buffer length'); |
|
10603 } |
|
10604 |
|
10605 val = readUInt32(buffer, offset, isBigEndian, noAssert); |
|
10606 neg = val & 0x80000000; |
|
10607 if (!neg) { |
|
10608 return (val); |
|
10609 } |
|
10610 |
|
10611 return (0xffffffff - val + 1) * -1; |
|
10612 } |
|
10613 |
|
10614 Buffer.prototype.readInt32LE = function(offset, noAssert) { |
|
10615 return readInt32(this, offset, false, noAssert); |
|
10616 }; |
|
10617 |
|
10618 Buffer.prototype.readInt32BE = function(offset, noAssert) { |
|
10619 return readInt32(this, offset, true, noAssert); |
|
10620 }; |
|
10621 |
|
10622 function readFloat(buffer, offset, isBigEndian, noAssert) { |
|
10623 if (!noAssert) { |
|
10624 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10625 'missing or invalid endian'); |
|
10626 |
|
10627 assert.ok(offset + 3 < buffer.length, |
|
10628 'Trying to read beyond buffer length'); |
|
10629 } |
|
10630 |
|
10631 return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, |
|
10632 23, 4); |
|
10633 } |
|
10634 |
|
10635 Buffer.prototype.readFloatLE = function(offset, noAssert) { |
|
10636 return readFloat(this, offset, false, noAssert); |
|
10637 }; |
|
10638 |
|
10639 Buffer.prototype.readFloatBE = function(offset, noAssert) { |
|
10640 return readFloat(this, offset, true, noAssert); |
|
10641 }; |
|
10642 |
|
10643 function readDouble(buffer, offset, isBigEndian, noAssert) { |
|
10644 if (!noAssert) { |
|
10645 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10646 'missing or invalid endian'); |
|
10647 |
|
10648 assert.ok(offset + 7 < buffer.length, |
|
10649 'Trying to read beyond buffer length'); |
|
10650 } |
|
10651 |
|
10652 return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, |
|
10653 52, 8); |
|
10654 } |
|
10655 |
|
10656 Buffer.prototype.readDoubleLE = function(offset, noAssert) { |
|
10657 return readDouble(this, offset, false, noAssert); |
|
10658 }; |
|
10659 |
|
10660 Buffer.prototype.readDoubleBE = function(offset, noAssert) { |
|
10661 return readDouble(this, offset, true, noAssert); |
|
10662 }; |
|
10663 |
|
10664 |
|
10665 /* |
|
10666 * We have to make sure that the value is a valid integer. This means that it is |
|
10667 * non-negative. It has no fractional component and that it does not exceed the |
|
10668 * maximum allowed value. |
|
10669 * |
|
10670 * value The number to check for validity |
|
10671 * |
|
10672 * max The maximum value |
|
10673 */ |
|
10674 function verifuint(value, max) { |
|
10675 assert.ok(typeof (value) == 'number', |
|
10676 'cannot write a non-number as a number'); |
|
10677 |
|
10678 assert.ok(value >= 0, |
|
10679 'specified a negative value for writing an unsigned value'); |
|
10680 |
|
10681 assert.ok(value <= max, 'value is larger than maximum value for type'); |
|
10682 |
|
10683 assert.ok(Math.floor(value) === value, 'value has a fractional component'); |
|
10684 } |
|
10685 |
|
10686 Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { |
|
10687 var buffer = this; |
|
10688 |
|
10689 if (!noAssert) { |
|
10690 assert.ok(value !== undefined && value !== null, |
|
10691 'missing value'); |
|
10692 |
|
10693 assert.ok(offset !== undefined && offset !== null, |
|
10694 'missing offset'); |
|
10695 |
|
10696 assert.ok(offset < buffer.length, |
|
10697 'trying to write beyond buffer length'); |
|
10698 |
|
10699 verifuint(value, 0xff); |
|
10700 } |
|
10701 |
|
10702 if (offset < buffer.length) { |
|
10703 buffer.parent[buffer.offset + offset] = value; |
|
10704 } |
|
10705 }; |
|
10706 |
|
10707 function writeUInt16(buffer, value, offset, isBigEndian, noAssert) { |
|
10708 if (!noAssert) { |
|
10709 assert.ok(value !== undefined && value !== null, |
|
10710 'missing value'); |
|
10711 |
|
10712 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10713 'missing or invalid endian'); |
|
10714 |
|
10715 assert.ok(offset !== undefined && offset !== null, |
|
10716 'missing offset'); |
|
10717 |
|
10718 assert.ok(offset + 1 < buffer.length, |
|
10719 'trying to write beyond buffer length'); |
|
10720 |
|
10721 verifuint(value, 0xffff); |
|
10722 } |
|
10723 |
|
10724 for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) { |
|
10725 buffer.parent[buffer.offset + offset + i] = |
|
10726 (value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>> |
|
10727 (isBigEndian ? 1 - i : i) * 8; |
|
10728 } |
|
10729 |
|
10730 } |
|
10731 |
|
10732 Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { |
|
10733 writeUInt16(this, value, offset, false, noAssert); |
|
10734 }; |
|
10735 |
|
10736 Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) { |
|
10737 writeUInt16(this, value, offset, true, noAssert); |
|
10738 }; |
|
10739 |
|
10740 function writeUInt32(buffer, value, offset, isBigEndian, noAssert) { |
|
10741 if (!noAssert) { |
|
10742 assert.ok(value !== undefined && value !== null, |
|
10743 'missing value'); |
|
10744 |
|
10745 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10746 'missing or invalid endian'); |
|
10747 |
|
10748 assert.ok(offset !== undefined && offset !== null, |
|
10749 'missing offset'); |
|
10750 |
|
10751 assert.ok(offset + 3 < buffer.length, |
|
10752 'trying to write beyond buffer length'); |
|
10753 |
|
10754 verifuint(value, 0xffffffff); |
|
10755 } |
|
10756 |
|
10757 for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) { |
|
10758 buffer.parent[buffer.offset + offset + i] = |
|
10759 (value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff; |
|
10760 } |
|
10761 } |
|
10762 |
|
10763 Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { |
|
10764 writeUInt32(this, value, offset, false, noAssert); |
|
10765 }; |
|
10766 |
|
10767 Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { |
|
10768 writeUInt32(this, value, offset, true, noAssert); |
|
10769 }; |
|
10770 |
|
10771 |
|
10772 /* |
|
10773 * We now move onto our friends in the signed number category. Unlike unsigned |
|
10774 * numbers, we're going to have to worry a bit more about how we put values into |
|
10775 * arrays. Since we are only worrying about signed 32-bit values, we're in |
|
10776 * slightly better shape. Unfortunately, we really can't do our favorite binary |
|
10777 * & in this system. It really seems to do the wrong thing. For example: |
|
10778 * |
|
10779 * > -32 & 0xff |
|
10780 * 224 |
|
10781 * |
|
10782 * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of |
|
10783 * this aren't treated as a signed number. Ultimately a bad thing. |
|
10784 * |
|
10785 * What we're going to want to do is basically create the unsigned equivalent of |
|
10786 * our representation and pass that off to the wuint* functions. To do that |
|
10787 * we're going to do the following: |
|
10788 * |
|
10789 * - if the value is positive |
|
10790 * we can pass it directly off to the equivalent wuint |
|
10791 * - if the value is negative |
|
10792 * we do the following computation: |
|
10793 * mb + val + 1, where |
|
10794 * mb is the maximum unsigned value in that byte size |
|
10795 * val is the Javascript negative integer |
|
10796 * |
|
10797 * |
|
10798 * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If |
|
10799 * you do out the computations: |
|
10800 * |
|
10801 * 0xffff - 128 + 1 |
|
10802 * 0xffff - 127 |
|
10803 * 0xff80 |
|
10804 * |
|
10805 * You can then encode this value as the signed version. This is really rather |
|
10806 * hacky, but it should work and get the job done which is our goal here. |
|
10807 */ |
|
10808 |
|
10809 /* |
|
10810 * A series of checks to make sure we actually have a signed 32-bit number |
|
10811 */ |
|
10812 function verifsint(value, max, min) { |
|
10813 assert.ok(typeof (value) == 'number', |
|
10814 'cannot write a non-number as a number'); |
|
10815 |
|
10816 assert.ok(value <= max, 'value larger than maximum allowed value'); |
|
10817 |
|
10818 assert.ok(value >= min, 'value smaller than minimum allowed value'); |
|
10819 |
|
10820 assert.ok(Math.floor(value) === value, 'value has a fractional component'); |
|
10821 } |
|
10822 |
|
10823 function verifIEEE754(value, max, min) { |
|
10824 assert.ok(typeof (value) == 'number', |
|
10825 'cannot write a non-number as a number'); |
|
10826 |
|
10827 assert.ok(value <= max, 'value larger than maximum allowed value'); |
|
10828 |
|
10829 assert.ok(value >= min, 'value smaller than minimum allowed value'); |
|
10830 } |
|
10831 |
|
10832 Buffer.prototype.writeInt8 = function(value, offset, noAssert) { |
|
10833 var buffer = this; |
|
10834 |
|
10835 if (!noAssert) { |
|
10836 assert.ok(value !== undefined && value !== null, |
|
10837 'missing value'); |
|
10838 |
|
10839 assert.ok(offset !== undefined && offset !== null, |
|
10840 'missing offset'); |
|
10841 |
|
10842 assert.ok(offset < buffer.length, |
|
10843 'Trying to write beyond buffer length'); |
|
10844 |
|
10845 verifsint(value, 0x7f, -0x80); |
|
10846 } |
|
10847 |
|
10848 if (value >= 0) { |
|
10849 buffer.writeUInt8(value, offset, noAssert); |
|
10850 } else { |
|
10851 buffer.writeUInt8(0xff + value + 1, offset, noAssert); |
|
10852 } |
|
10853 }; |
|
10854 |
|
10855 function writeInt16(buffer, value, offset, isBigEndian, noAssert) { |
|
10856 if (!noAssert) { |
|
10857 assert.ok(value !== undefined && value !== null, |
|
10858 'missing value'); |
|
10859 |
|
10860 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10861 'missing or invalid endian'); |
|
10862 |
|
10863 assert.ok(offset !== undefined && offset !== null, |
|
10864 'missing offset'); |
|
10865 |
|
10866 assert.ok(offset + 1 < buffer.length, |
|
10867 'Trying to write beyond buffer length'); |
|
10868 |
|
10869 verifsint(value, 0x7fff, -0x8000); |
|
10870 } |
|
10871 |
|
10872 if (value >= 0) { |
|
10873 writeUInt16(buffer, value, offset, isBigEndian, noAssert); |
|
10874 } else { |
|
10875 writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert); |
|
10876 } |
|
10877 } |
|
10878 |
|
10879 Buffer.prototype.writeInt16LE = function(value, offset, noAssert) { |
|
10880 writeInt16(this, value, offset, false, noAssert); |
|
10881 }; |
|
10882 |
|
10883 Buffer.prototype.writeInt16BE = function(value, offset, noAssert) { |
|
10884 writeInt16(this, value, offset, true, noAssert); |
|
10885 }; |
|
10886 |
|
10887 function writeInt32(buffer, value, offset, isBigEndian, noAssert) { |
|
10888 if (!noAssert) { |
|
10889 assert.ok(value !== undefined && value !== null, |
|
10890 'missing value'); |
|
10891 |
|
10892 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10893 'missing or invalid endian'); |
|
10894 |
|
10895 assert.ok(offset !== undefined && offset !== null, |
|
10896 'missing offset'); |
|
10897 |
|
10898 assert.ok(offset + 3 < buffer.length, |
|
10899 'Trying to write beyond buffer length'); |
|
10900 |
|
10901 verifsint(value, 0x7fffffff, -0x80000000); |
|
10902 } |
|
10903 |
|
10904 if (value >= 0) { |
|
10905 writeUInt32(buffer, value, offset, isBigEndian, noAssert); |
|
10906 } else { |
|
10907 writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert); |
|
10908 } |
|
10909 } |
|
10910 |
|
10911 Buffer.prototype.writeInt32LE = function(value, offset, noAssert) { |
|
10912 writeInt32(this, value, offset, false, noAssert); |
|
10913 }; |
|
10914 |
|
10915 Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { |
|
10916 writeInt32(this, value, offset, true, noAssert); |
|
10917 }; |
|
10918 |
|
10919 function writeFloat(buffer, value, offset, isBigEndian, noAssert) { |
|
10920 if (!noAssert) { |
|
10921 assert.ok(value !== undefined && value !== null, |
|
10922 'missing value'); |
|
10923 |
|
10924 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10925 'missing or invalid endian'); |
|
10926 |
|
10927 assert.ok(offset !== undefined && offset !== null, |
|
10928 'missing offset'); |
|
10929 |
|
10930 assert.ok(offset + 3 < buffer.length, |
|
10931 'Trying to write beyond buffer length'); |
|
10932 |
|
10933 verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38); |
|
10934 } |
|
10935 |
|
10936 require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, |
|
10937 23, 4); |
|
10938 } |
|
10939 |
|
10940 Buffer.prototype.writeFloatLE = function(value, offset, noAssert) { |
|
10941 writeFloat(this, value, offset, false, noAssert); |
|
10942 }; |
|
10943 |
|
10944 Buffer.prototype.writeFloatBE = function(value, offset, noAssert) { |
|
10945 writeFloat(this, value, offset, true, noAssert); |
|
10946 }; |
|
10947 |
|
10948 function writeDouble(buffer, value, offset, isBigEndian, noAssert) { |
|
10949 if (!noAssert) { |
|
10950 assert.ok(value !== undefined && value !== null, |
|
10951 'missing value'); |
|
10952 |
|
10953 assert.ok(typeof (isBigEndian) === 'boolean', |
|
10954 'missing or invalid endian'); |
|
10955 |
|
10956 assert.ok(offset !== undefined && offset !== null, |
|
10957 'missing offset'); |
|
10958 |
|
10959 assert.ok(offset + 7 < buffer.length, |
|
10960 'Trying to write beyond buffer length'); |
|
10961 |
|
10962 verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308); |
|
10963 } |
|
10964 |
|
10965 require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, |
|
10966 52, 8); |
|
10967 } |
|
10968 |
|
10969 Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) { |
|
10970 writeDouble(this, value, offset, false, noAssert); |
|
10971 }; |
|
10972 |
|
10973 Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { |
|
10974 writeDouble(this, value, offset, true, noAssert); |
|
10975 }; |
|
10976 |
|
10977 SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8; |
|
10978 SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE; |
|
10979 SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE; |
|
10980 SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE; |
|
10981 SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE; |
|
10982 SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8; |
|
10983 SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE; |
|
10984 SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE; |
|
10985 SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE; |
|
10986 SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE; |
|
10987 SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE; |
|
10988 SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE; |
|
10989 SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE; |
|
10990 SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE; |
|
10991 SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8; |
|
10992 SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE; |
|
10993 SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE; |
|
10994 SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE; |
|
10995 SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE; |
|
10996 SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8; |
|
10997 SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE; |
|
10998 SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE; |
|
10999 SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE; |
|
11000 SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE; |
|
11001 SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE; |
|
11002 SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE; |
|
11003 SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE; |
|
11004 SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE; |
|
11005 |
|
11006 })() |
|
11007 },{"assert":9,"./buffer_ieee754":14,"base64-js":15}],15:[function(require,module,exports){ |
|
11008 (function (exports) { |
|
11009 'use strict'; |
|
11010 |
|
11011 var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; |
|
11012 |
|
11013 function b64ToByteArray(b64) { |
|
11014 var i, j, l, tmp, placeHolders, arr; |
|
11015 |
|
11016 if (b64.length % 4 > 0) { |
|
11017 throw 'Invalid string. Length must be a multiple of 4'; |
|
11018 } |
|
11019 |
|
11020 // the number of equal signs (place holders) |
|
11021 // if there are two placeholders, than the two characters before it |
|
11022 // represent one byte |
|
11023 // if there is only one, then the three characters before it represent 2 bytes |
|
11024 // this is just a cheap hack to not do indexOf twice |
|
11025 placeHolders = b64.indexOf('='); |
|
11026 placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0; |
|
11027 |
|
11028 // base64 is 4/3 + up to two characters of the original data |
|
11029 arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders); |
|
11030 |
|
11031 // if there are placeholders, only get up to the last complete 4 chars |
|
11032 l = placeHolders > 0 ? b64.length - 4 : b64.length; |
|
11033 |
|
11034 for (i = 0, j = 0; i < l; i += 4, j += 3) { |
|
11035 tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]); |
|
11036 arr.push((tmp & 0xFF0000) >> 16); |
|
11037 arr.push((tmp & 0xFF00) >> 8); |
|
11038 arr.push(tmp & 0xFF); |
|
11039 } |
|
11040 |
|
11041 if (placeHolders === 2) { |
|
11042 tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4); |
|
11043 arr.push(tmp & 0xFF); |
|
11044 } else if (placeHolders === 1) { |
|
11045 tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2); |
|
11046 arr.push((tmp >> 8) & 0xFF); |
|
11047 arr.push(tmp & 0xFF); |
|
11048 } |
|
11049 |
|
11050 return arr; |
|
11051 } |
|
11052 |
|
11053 function uint8ToBase64(uint8) { |
|
11054 var i, |
|
11055 extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes |
|
11056 output = "", |
|
11057 temp, length; |
|
11058 |
|
11059 function tripletToBase64 (num) { |
|
11060 return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; |
|
11061 }; |
|
11062 |
|
11063 // go through the array every three bytes, we'll deal with trailing stuff later |
|
11064 for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { |
|
11065 temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); |
|
11066 output += tripletToBase64(temp); |
|
11067 } |
|
11068 |
|
11069 // pad the end with zeros, but make sure to not forget the extra bytes |
|
11070 switch (extraBytes) { |
|
11071 case 1: |
|
11072 temp = uint8[uint8.length - 1]; |
|
11073 output += lookup[temp >> 2]; |
|
11074 output += lookup[(temp << 4) & 0x3F]; |
|
11075 output += '=='; |
|
11076 break; |
|
11077 case 2: |
|
11078 temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]); |
|
11079 output += lookup[temp >> 10]; |
|
11080 output += lookup[(temp >> 4) & 0x3F]; |
|
11081 output += lookup[(temp << 2) & 0x3F]; |
|
11082 output += '='; |
|
11083 break; |
|
11084 } |
|
11085 |
|
11086 return output; |
|
11087 } |
|
11088 |
|
11089 module.exports.toByteArray = b64ToByteArray; |
|
11090 module.exports.fromByteArray = uint8ToBase64; |
|
11091 }()); |
|
11092 |
|
11093 },{}]},{},["E/GbHF"]) |
|
11094 ; |
|
11095 JSHINT = require('jshint').JSHINT; |
|
11096 }()); |