PageRenderTime 87ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 1ms

/ajax/libs/blanket.js/1.1.4/blanket.js

https://bitbucket.org/kolbyjAFK/cdnjs
JavaScript | 7280 lines | 6371 code | 701 blank | 208 comment | 796 complexity | 857bfaf7873960b2529b544b28661f14 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*! blanket - v1.1.3 */
  2. if (typeof QUnit !== 'undefined'){ QUnit.config.autostart = false; }
  3. (function(define){
  4. /*
  5. Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
  6. Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
  7. Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
  8. Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
  9. Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
  10. Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
  11. Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
  12. Redistribution and use in source and binary forms, with or without
  13. modification, are permitted provided that the following conditions are met:
  14. * Redistributions of source code must retain the above copyright
  15. notice, this list of conditions and the following disclaimer.
  16. * Redistributions in binary form must reproduce the above copyright
  17. notice, this list of conditions and the following disclaimer in the
  18. documentation and/or other materials provided with the distribution.
  19. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  23. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /*jslint bitwise:true plusplus:true */
  31. /*global esprima:true, define:true, exports:true, window: true,
  32. throwError: true, createLiteral: true, generateStatement: true,
  33. parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
  34. parseFunctionDeclaration: true, parseFunctionExpression: true,
  35. parseFunctionSourceElements: true, parseVariableIdentifier: true,
  36. parseLeftHandSideExpression: true,
  37. parseStatement: true, parseSourceElement: true */
  38. (function (root, factory) {
  39. 'use strict';
  40. // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
  41. // Rhino, and plain browser loading.
  42. if (typeof define === 'function' && define.amd) {
  43. define(['exports'], factory);
  44. } else if (typeof exports !== 'undefined') {
  45. factory(exports);
  46. } else {
  47. factory((root.esprima = {}));
  48. }
  49. }(this, function (exports) {
  50. 'use strict';
  51. var Token,
  52. TokenName,
  53. Syntax,
  54. PropertyKind,
  55. Messages,
  56. Regex,
  57. source,
  58. strict,
  59. index,
  60. lineNumber,
  61. lineStart,
  62. length,
  63. buffer,
  64. state,
  65. extra;
  66. Token = {
  67. BooleanLiteral: 1,
  68. EOF: 2,
  69. Identifier: 3,
  70. Keyword: 4,
  71. NullLiteral: 5,
  72. NumericLiteral: 6,
  73. Punctuator: 7,
  74. StringLiteral: 8
  75. };
  76. TokenName = {};
  77. TokenName[Token.BooleanLiteral] = 'Boolean';
  78. TokenName[Token.EOF] = '<end>';
  79. TokenName[Token.Identifier] = 'Identifier';
  80. TokenName[Token.Keyword] = 'Keyword';
  81. TokenName[Token.NullLiteral] = 'Null';
  82. TokenName[Token.NumericLiteral] = 'Numeric';
  83. TokenName[Token.Punctuator] = 'Punctuator';
  84. TokenName[Token.StringLiteral] = 'String';
  85. Syntax = {
  86. AssignmentExpression: 'AssignmentExpression',
  87. ArrayExpression: 'ArrayExpression',
  88. BlockStatement: 'BlockStatement',
  89. BinaryExpression: 'BinaryExpression',
  90. BreakStatement: 'BreakStatement',
  91. CallExpression: 'CallExpression',
  92. CatchClause: 'CatchClause',
  93. ConditionalExpression: 'ConditionalExpression',
  94. ContinueStatement: 'ContinueStatement',
  95. DoWhileStatement: 'DoWhileStatement',
  96. DebuggerStatement: 'DebuggerStatement',
  97. EmptyStatement: 'EmptyStatement',
  98. ExpressionStatement: 'ExpressionStatement',
  99. ForStatement: 'ForStatement',
  100. ForInStatement: 'ForInStatement',
  101. FunctionDeclaration: 'FunctionDeclaration',
  102. FunctionExpression: 'FunctionExpression',
  103. Identifier: 'Identifier',
  104. IfStatement: 'IfStatement',
  105. Literal: 'Literal',
  106. LabeledStatement: 'LabeledStatement',
  107. LogicalExpression: 'LogicalExpression',
  108. MemberExpression: 'MemberExpression',
  109. NewExpression: 'NewExpression',
  110. ObjectExpression: 'ObjectExpression',
  111. Program: 'Program',
  112. Property: 'Property',
  113. ReturnStatement: 'ReturnStatement',
  114. SequenceExpression: 'SequenceExpression',
  115. SwitchStatement: 'SwitchStatement',
  116. SwitchCase: 'SwitchCase',
  117. ThisExpression: 'ThisExpression',
  118. ThrowStatement: 'ThrowStatement',
  119. TryStatement: 'TryStatement',
  120. UnaryExpression: 'UnaryExpression',
  121. UpdateExpression: 'UpdateExpression',
  122. VariableDeclaration: 'VariableDeclaration',
  123. VariableDeclarator: 'VariableDeclarator',
  124. WhileStatement: 'WhileStatement',
  125. WithStatement: 'WithStatement'
  126. };
  127. PropertyKind = {
  128. Data: 1,
  129. Get: 2,
  130. Set: 4
  131. };
  132. // Error messages should be identical to V8.
  133. Messages = {
  134. UnexpectedToken: 'Unexpected token %0',
  135. UnexpectedNumber: 'Unexpected number',
  136. UnexpectedString: 'Unexpected string',
  137. UnexpectedIdentifier: 'Unexpected identifier',
  138. UnexpectedReserved: 'Unexpected reserved word',
  139. UnexpectedEOS: 'Unexpected end of input',
  140. NewlineAfterThrow: 'Illegal newline after throw',
  141. InvalidRegExp: 'Invalid regular expression',
  142. UnterminatedRegExp: 'Invalid regular expression: missing /',
  143. InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
  144. InvalidLHSInForIn: 'Invalid left-hand side in for-in',
  145. MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
  146. NoCatchOrFinally: 'Missing catch or finally after try',
  147. UnknownLabel: 'Undefined label \'%0\'',
  148. Redeclaration: '%0 \'%1\' has already been declared',
  149. IllegalContinue: 'Illegal continue statement',
  150. IllegalBreak: 'Illegal break statement',
  151. IllegalReturn: 'Illegal return statement',
  152. StrictModeWith: 'Strict mode code may not include a with statement',
  153. StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
  154. StrictVarName: 'Variable name may not be eval or arguments in strict mode',
  155. StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
  156. StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
  157. StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
  158. StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
  159. StrictDelete: 'Delete of an unqualified identifier in strict mode.',
  160. StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
  161. AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
  162. AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
  163. StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
  164. StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
  165. StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
  166. StrictReservedWord: 'Use of future reserved word in strict mode'
  167. };
  168. // See also tools/generate-unicode-regex.py.
  169. Regex = {
  170. NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
  171. NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
  172. };
  173. // Ensure the condition is true, otherwise throw an error.
  174. // This is only to have a better contract semantic, i.e. another safety net
  175. // to catch a logic error. The condition shall be fulfilled in normal case.
  176. // Do NOT use this to enforce a certain condition on any user input.
  177. function assert(condition, message) {
  178. if (!condition) {
  179. throw new Error('ASSERT: ' + message);
  180. }
  181. }
  182. function sliceSource(from, to) {
  183. return source.slice(from, to);
  184. }
  185. if (typeof 'esprima'[0] === 'undefined') {
  186. sliceSource = function sliceArraySource(from, to) {
  187. return source.slice(from, to).join('');
  188. };
  189. }
  190. function isDecimalDigit(ch) {
  191. return '0123456789'.indexOf(ch) >= 0;
  192. }
  193. function isHexDigit(ch) {
  194. return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
  195. }
  196. function isOctalDigit(ch) {
  197. return '01234567'.indexOf(ch) >= 0;
  198. }
  199. // 7.2 White Space
  200. function isWhiteSpace(ch) {
  201. return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
  202. (ch === '\u000C') || (ch === '\u00A0') ||
  203. (ch.charCodeAt(0) >= 0x1680 &&
  204. '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
  205. }
  206. // 7.3 Line Terminators
  207. function isLineTerminator(ch) {
  208. return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
  209. }
  210. // 7.6 Identifier Names and Identifiers
  211. function isIdentifierStart(ch) {
  212. return (ch === '$') || (ch === '_') || (ch === '\\') ||
  213. (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
  214. ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
  215. }
  216. function isIdentifierPart(ch) {
  217. return (ch === '$') || (ch === '_') || (ch === '\\') ||
  218. (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
  219. ((ch >= '0') && (ch <= '9')) ||
  220. ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
  221. }
  222. // 7.6.1.2 Future Reserved Words
  223. function isFutureReservedWord(id) {
  224. switch (id) {
  225. // Future reserved words.
  226. case 'class':
  227. case 'enum':
  228. case 'export':
  229. case 'extends':
  230. case 'import':
  231. case 'super':
  232. return true;
  233. }
  234. return false;
  235. }
  236. function isStrictModeReservedWord(id) {
  237. switch (id) {
  238. // Strict Mode reserved words.
  239. case 'implements':
  240. case 'interface':
  241. case 'package':
  242. case 'private':
  243. case 'protected':
  244. case 'public':
  245. case 'static':
  246. case 'yield':
  247. case 'let':
  248. return true;
  249. }
  250. return false;
  251. }
  252. function isRestrictedWord(id) {
  253. return id === 'eval' || id === 'arguments';
  254. }
  255. // 7.6.1.1 Keywords
  256. function isKeyword(id) {
  257. var keyword = false;
  258. switch (id.length) {
  259. case 2:
  260. keyword = (id === 'if') || (id === 'in') || (id === 'do');
  261. break;
  262. case 3:
  263. keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
  264. break;
  265. case 4:
  266. keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
  267. break;
  268. case 5:
  269. keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
  270. break;
  271. case 6:
  272. keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
  273. break;
  274. case 7:
  275. keyword = (id === 'default') || (id === 'finally');
  276. break;
  277. case 8:
  278. keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
  279. break;
  280. case 10:
  281. keyword = (id === 'instanceof');
  282. break;
  283. }
  284. if (keyword) {
  285. return true;
  286. }
  287. switch (id) {
  288. // Future reserved words.
  289. // 'const' is specialized as Keyword in V8.
  290. case 'const':
  291. return true;
  292. // For compatiblity to SpiderMonkey and ES.next
  293. case 'yield':
  294. case 'let':
  295. return true;
  296. }
  297. if (strict && isStrictModeReservedWord(id)) {
  298. return true;
  299. }
  300. return isFutureReservedWord(id);
  301. }
  302. // 7.4 Comments
  303. function skipComment() {
  304. var ch, blockComment, lineComment;
  305. blockComment = false;
  306. lineComment = false;
  307. while (index < length) {
  308. ch = source[index];
  309. if (lineComment) {
  310. ch = source[index++];
  311. if (isLineTerminator(ch)) {
  312. lineComment = false;
  313. if (ch === '\r' && source[index] === '\n') {
  314. ++index;
  315. }
  316. ++lineNumber;
  317. lineStart = index;
  318. }
  319. } else if (blockComment) {
  320. if (isLineTerminator(ch)) {
  321. if (ch === '\r' && source[index + 1] === '\n') {
  322. ++index;
  323. }
  324. ++lineNumber;
  325. ++index;
  326. lineStart = index;
  327. if (index >= length) {
  328. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  329. }
  330. } else {
  331. ch = source[index++];
  332. if (index >= length) {
  333. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  334. }
  335. if (ch === '*') {
  336. ch = source[index];
  337. if (ch === '/') {
  338. ++index;
  339. blockComment = false;
  340. }
  341. }
  342. }
  343. } else if (ch === '/') {
  344. ch = source[index + 1];
  345. if (ch === '/') {
  346. index += 2;
  347. lineComment = true;
  348. } else if (ch === '*') {
  349. index += 2;
  350. blockComment = true;
  351. if (index >= length) {
  352. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  353. }
  354. } else {
  355. break;
  356. }
  357. } else if (isWhiteSpace(ch)) {
  358. ++index;
  359. } else if (isLineTerminator(ch)) {
  360. ++index;
  361. if (ch === '\r' && source[index] === '\n') {
  362. ++index;
  363. }
  364. ++lineNumber;
  365. lineStart = index;
  366. } else {
  367. break;
  368. }
  369. }
  370. }
  371. function scanHexEscape(prefix) {
  372. var i, len, ch, code = 0;
  373. len = (prefix === 'u') ? 4 : 2;
  374. for (i = 0; i < len; ++i) {
  375. if (index < length && isHexDigit(source[index])) {
  376. ch = source[index++];
  377. code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
  378. } else {
  379. return '';
  380. }
  381. }
  382. return String.fromCharCode(code);
  383. }
  384. function scanIdentifier() {
  385. var ch, start, id, restore;
  386. ch = source[index];
  387. if (!isIdentifierStart(ch)) {
  388. return;
  389. }
  390. start = index;
  391. if (ch === '\\') {
  392. ++index;
  393. if (source[index] !== 'u') {
  394. return;
  395. }
  396. ++index;
  397. restore = index;
  398. ch = scanHexEscape('u');
  399. if (ch) {
  400. if (ch === '\\' || !isIdentifierStart(ch)) {
  401. return;
  402. }
  403. id = ch;
  404. } else {
  405. index = restore;
  406. id = 'u';
  407. }
  408. } else {
  409. id = source[index++];
  410. }
  411. while (index < length) {
  412. ch = source[index];
  413. if (!isIdentifierPart(ch)) {
  414. break;
  415. }
  416. if (ch === '\\') {
  417. ++index;
  418. if (source[index] !== 'u') {
  419. return;
  420. }
  421. ++index;
  422. restore = index;
  423. ch = scanHexEscape('u');
  424. if (ch) {
  425. if (ch === '\\' || !isIdentifierPart(ch)) {
  426. return;
  427. }
  428. id += ch;
  429. } else {
  430. index = restore;
  431. id += 'u';
  432. }
  433. } else {
  434. id += source[index++];
  435. }
  436. }
  437. // There is no keyword or literal with only one character.
  438. // Thus, it must be an identifier.
  439. if (id.length === 1) {
  440. return {
  441. type: Token.Identifier,
  442. value: id,
  443. lineNumber: lineNumber,
  444. lineStart: lineStart,
  445. range: [start, index]
  446. };
  447. }
  448. if (isKeyword(id)) {
  449. return {
  450. type: Token.Keyword,
  451. value: id,
  452. lineNumber: lineNumber,
  453. lineStart: lineStart,
  454. range: [start, index]
  455. };
  456. }
  457. // 7.8.1 Null Literals
  458. if (id === 'null') {
  459. return {
  460. type: Token.NullLiteral,
  461. value: id,
  462. lineNumber: lineNumber,
  463. lineStart: lineStart,
  464. range: [start, index]
  465. };
  466. }
  467. // 7.8.2 Boolean Literals
  468. if (id === 'true' || id === 'false') {
  469. return {
  470. type: Token.BooleanLiteral,
  471. value: id,
  472. lineNumber: lineNumber,
  473. lineStart: lineStart,
  474. range: [start, index]
  475. };
  476. }
  477. return {
  478. type: Token.Identifier,
  479. value: id,
  480. lineNumber: lineNumber,
  481. lineStart: lineStart,
  482. range: [start, index]
  483. };
  484. }
  485. // 7.7 Punctuators
  486. function scanPunctuator() {
  487. var start = index,
  488. ch1 = source[index],
  489. ch2,
  490. ch3,
  491. ch4;
  492. // Check for most common single-character punctuators.
  493. if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
  494. ++index;
  495. return {
  496. type: Token.Punctuator,
  497. value: ch1,
  498. lineNumber: lineNumber,
  499. lineStart: lineStart,
  500. range: [start, index]
  501. };
  502. }
  503. if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
  504. ++index;
  505. return {
  506. type: Token.Punctuator,
  507. value: ch1,
  508. lineNumber: lineNumber,
  509. lineStart: lineStart,
  510. range: [start, index]
  511. };
  512. }
  513. // Dot (.) can also start a floating-point number, hence the need
  514. // to check the next character.
  515. ch2 = source[index + 1];
  516. if (ch1 === '.' && !isDecimalDigit(ch2)) {
  517. return {
  518. type: Token.Punctuator,
  519. value: source[index++],
  520. lineNumber: lineNumber,
  521. lineStart: lineStart,
  522. range: [start, index]
  523. };
  524. }
  525. // Peek more characters.
  526. ch3 = source[index + 2];
  527. ch4 = source[index + 3];
  528. // 4-character punctuator: >>>=
  529. if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
  530. if (ch4 === '=') {
  531. index += 4;
  532. return {
  533. type: Token.Punctuator,
  534. value: '>>>=',
  535. lineNumber: lineNumber,
  536. lineStart: lineStart,
  537. range: [start, index]
  538. };
  539. }
  540. }
  541. // 3-character punctuators: === !== >>> <<= >>=
  542. if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
  543. index += 3;
  544. return {
  545. type: Token.Punctuator,
  546. value: '===',
  547. lineNumber: lineNumber,
  548. lineStart: lineStart,
  549. range: [start, index]
  550. };
  551. }
  552. if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
  553. index += 3;
  554. return {
  555. type: Token.Punctuator,
  556. value: '!==',
  557. lineNumber: lineNumber,
  558. lineStart: lineStart,
  559. range: [start, index]
  560. };
  561. }
  562. if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
  563. index += 3;
  564. return {
  565. type: Token.Punctuator,
  566. value: '>>>',
  567. lineNumber: lineNumber,
  568. lineStart: lineStart,
  569. range: [start, index]
  570. };
  571. }
  572. if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
  573. index += 3;
  574. return {
  575. type: Token.Punctuator,
  576. value: '<<=',
  577. lineNumber: lineNumber,
  578. lineStart: lineStart,
  579. range: [start, index]
  580. };
  581. }
  582. if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
  583. index += 3;
  584. return {
  585. type: Token.Punctuator,
  586. value: '>>=',
  587. lineNumber: lineNumber,
  588. lineStart: lineStart,
  589. range: [start, index]
  590. };
  591. }
  592. // 2-character punctuators: <= >= == != ++ -- << >> && ||
  593. // += -= *= %= &= |= ^= /=
  594. if (ch2 === '=') {
  595. if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
  596. index += 2;
  597. return {
  598. type: Token.Punctuator,
  599. value: ch1 + ch2,
  600. lineNumber: lineNumber,
  601. lineStart: lineStart,
  602. range: [start, index]
  603. };
  604. }
  605. }
  606. if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
  607. if ('+-<>&|'.indexOf(ch2) >= 0) {
  608. index += 2;
  609. return {
  610. type: Token.Punctuator,
  611. value: ch1 + ch2,
  612. lineNumber: lineNumber,
  613. lineStart: lineStart,
  614. range: [start, index]
  615. };
  616. }
  617. }
  618. // The remaining 1-character punctuators.
  619. if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
  620. return {
  621. type: Token.Punctuator,
  622. value: source[index++],
  623. lineNumber: lineNumber,
  624. lineStart: lineStart,
  625. range: [start, index]
  626. };
  627. }
  628. }
  629. // 7.8.3 Numeric Literals
  630. function scanNumericLiteral() {
  631. var number, start, ch;
  632. ch = source[index];
  633. assert(isDecimalDigit(ch) || (ch === '.'),
  634. 'Numeric literal must start with a decimal digit or a decimal point');
  635. start = index;
  636. number = '';
  637. if (ch !== '.') {
  638. number = source[index++];
  639. ch = source[index];
  640. // Hex number starts with '0x'.
  641. // Octal number starts with '0'.
  642. if (number === '0') {
  643. if (ch === 'x' || ch === 'X') {
  644. number += source[index++];
  645. while (index < length) {
  646. ch = source[index];
  647. if (!isHexDigit(ch)) {
  648. break;
  649. }
  650. number += source[index++];
  651. }
  652. if (number.length <= 2) {
  653. // only 0x
  654. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  655. }
  656. if (index < length) {
  657. ch = source[index];
  658. if (isIdentifierStart(ch)) {
  659. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  660. }
  661. }
  662. return {
  663. type: Token.NumericLiteral,
  664. value: parseInt(number, 16),
  665. lineNumber: lineNumber,
  666. lineStart: lineStart,
  667. range: [start, index]
  668. };
  669. } else if (isOctalDigit(ch)) {
  670. number += source[index++];
  671. while (index < length) {
  672. ch = source[index];
  673. if (!isOctalDigit(ch)) {
  674. break;
  675. }
  676. number += source[index++];
  677. }
  678. if (index < length) {
  679. ch = source[index];
  680. if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
  681. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  682. }
  683. }
  684. return {
  685. type: Token.NumericLiteral,
  686. value: parseInt(number, 8),
  687. octal: true,
  688. lineNumber: lineNumber,
  689. lineStart: lineStart,
  690. range: [start, index]
  691. };
  692. }
  693. // decimal number starts with '0' such as '09' is illegal.
  694. if (isDecimalDigit(ch)) {
  695. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  696. }
  697. }
  698. while (index < length) {
  699. ch = source[index];
  700. if (!isDecimalDigit(ch)) {
  701. break;
  702. }
  703. number += source[index++];
  704. }
  705. }
  706. if (ch === '.') {
  707. number += source[index++];
  708. while (index < length) {
  709. ch = source[index];
  710. if (!isDecimalDigit(ch)) {
  711. break;
  712. }
  713. number += source[index++];
  714. }
  715. }
  716. if (ch === 'e' || ch === 'E') {
  717. number += source[index++];
  718. ch = source[index];
  719. if (ch === '+' || ch === '-') {
  720. number += source[index++];
  721. }
  722. ch = source[index];
  723. if (isDecimalDigit(ch)) {
  724. number += source[index++];
  725. while (index < length) {
  726. ch = source[index];
  727. if (!isDecimalDigit(ch)) {
  728. break;
  729. }
  730. number += source[index++];
  731. }
  732. } else {
  733. ch = 'character ' + ch;
  734. if (index >= length) {
  735. ch = '<end>';
  736. }
  737. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  738. }
  739. }
  740. if (index < length) {
  741. ch = source[index];
  742. if (isIdentifierStart(ch)) {
  743. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  744. }
  745. }
  746. return {
  747. type: Token.NumericLiteral,
  748. value: parseFloat(number),
  749. lineNumber: lineNumber,
  750. lineStart: lineStart,
  751. range: [start, index]
  752. };
  753. }
  754. // 7.8.4 String Literals
  755. function scanStringLiteral() {
  756. var str = '', quote, start, ch, code, unescaped, restore, octal = false;
  757. quote = source[index];
  758. assert((quote === '\'' || quote === '"'),
  759. 'String literal must starts with a quote');
  760. start = index;
  761. ++index;
  762. while (index < length) {
  763. ch = source[index++];
  764. if (ch === quote) {
  765. quote = '';
  766. break;
  767. } else if (ch === '\\') {
  768. ch = source[index++];
  769. if (!isLineTerminator(ch)) {
  770. switch (ch) {
  771. case 'n':
  772. str += '\n';
  773. break;
  774. case 'r':
  775. str += '\r';
  776. break;
  777. case 't':
  778. str += '\t';
  779. break;
  780. case 'u':
  781. case 'x':
  782. restore = index;
  783. unescaped = scanHexEscape(ch);
  784. if (unescaped) {
  785. str += unescaped;
  786. } else {
  787. index = restore;
  788. str += ch;
  789. }
  790. break;
  791. case 'b':
  792. str += '\b';
  793. break;
  794. case 'f':
  795. str += '\f';
  796. break;
  797. case 'v':
  798. str += '\v';
  799. break;
  800. default:
  801. if (isOctalDigit(ch)) {
  802. code = '01234567'.indexOf(ch);
  803. // \0 is not octal escape sequence
  804. if (code !== 0) {
  805. octal = true;
  806. }
  807. if (index < length && isOctalDigit(source[index])) {
  808. octal = true;
  809. code = code * 8 + '01234567'.indexOf(source[index++]);
  810. // 3 digits are only allowed when string starts
  811. // with 0, 1, 2, 3
  812. if ('0123'.indexOf(ch) >= 0 &&
  813. index < length &&
  814. isOctalDigit(source[index])) {
  815. code = code * 8 + '01234567'.indexOf(source[index++]);
  816. }
  817. }
  818. str += String.fromCharCode(code);
  819. } else {
  820. str += ch;
  821. }
  822. break;
  823. }
  824. } else {
  825. ++lineNumber;
  826. if (ch === '\r' && source[index] === '\n') {
  827. ++index;
  828. }
  829. }
  830. } else if (isLineTerminator(ch)) {
  831. break;
  832. } else {
  833. str += ch;
  834. }
  835. }
  836. if (quote !== '') {
  837. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  838. }
  839. return {
  840. type: Token.StringLiteral,
  841. value: str,
  842. octal: octal,
  843. lineNumber: lineNumber,
  844. lineStart: lineStart,
  845. range: [start, index]
  846. };
  847. }
  848. function scanRegExp() {
  849. var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
  850. buffer = null;
  851. skipComment();
  852. start = index;
  853. ch = source[index];
  854. assert(ch === '/', 'Regular expression literal must start with a slash');
  855. str = source[index++];
  856. while (index < length) {
  857. ch = source[index++];
  858. str += ch;
  859. if (classMarker) {
  860. if (ch === ']') {
  861. classMarker = false;
  862. }
  863. } else {
  864. if (ch === '\\') {
  865. ch = source[index++];
  866. // ECMA-262 7.8.5
  867. if (isLineTerminator(ch)) {
  868. throwError({}, Messages.UnterminatedRegExp);
  869. }
  870. str += ch;
  871. } else if (ch === '/') {
  872. terminated = true;
  873. break;
  874. } else if (ch === '[') {
  875. classMarker = true;
  876. } else if (isLineTerminator(ch)) {
  877. throwError({}, Messages.UnterminatedRegExp);
  878. }
  879. }
  880. }
  881. if (!terminated) {
  882. throwError({}, Messages.UnterminatedRegExp);
  883. }
  884. // Exclude leading and trailing slash.
  885. pattern = str.substr(1, str.length - 2);
  886. flags = '';
  887. while (index < length) {
  888. ch = source[index];
  889. if (!isIdentifierPart(ch)) {
  890. break;
  891. }
  892. ++index;
  893. if (ch === '\\' && index < length) {
  894. ch = source[index];
  895. if (ch === 'u') {
  896. ++index;
  897. restore = index;
  898. ch = scanHexEscape('u');
  899. if (ch) {
  900. flags += ch;
  901. str += '\\u';
  902. for (; restore < index; ++restore) {
  903. str += source[restore];
  904. }
  905. } else {
  906. index = restore;
  907. flags += 'u';
  908. str += '\\u';
  909. }
  910. } else {
  911. str += '\\';
  912. }
  913. } else {
  914. flags += ch;
  915. str += ch;
  916. }
  917. }
  918. try {
  919. value = new RegExp(pattern, flags);
  920. } catch (e) {
  921. throwError({}, Messages.InvalidRegExp);
  922. }
  923. return {
  924. literal: str,
  925. value: value,
  926. range: [start, index]
  927. };
  928. }
  929. function isIdentifierName(token) {
  930. return token.type === Token.Identifier ||
  931. token.type === Token.Keyword ||
  932. token.type === Token.BooleanLiteral ||
  933. token.type === Token.NullLiteral;
  934. }
  935. function advance() {
  936. var ch, token;
  937. skipComment();
  938. if (index >= length) {
  939. return {
  940. type: Token.EOF,
  941. lineNumber: lineNumber,
  942. lineStart: lineStart,
  943. range: [index, index]
  944. };
  945. }
  946. token = scanPunctuator();
  947. if (typeof token !== 'undefined') {
  948. return token;
  949. }
  950. ch = source[index];
  951. if (ch === '\'' || ch === '"') {
  952. return scanStringLiteral();
  953. }
  954. if (ch === '.' || isDecimalDigit(ch)) {
  955. return scanNumericLiteral();
  956. }
  957. token = scanIdentifier();
  958. if (typeof token !== 'undefined') {
  959. return token;
  960. }
  961. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  962. }
  963. function lex() {
  964. var token;
  965. if (buffer) {
  966. index = buffer.range[1];
  967. lineNumber = buffer.lineNumber;
  968. lineStart = buffer.lineStart;
  969. token = buffer;
  970. buffer = null;
  971. return token;
  972. }
  973. buffer = null;
  974. return advance();
  975. }
  976. function lookahead() {
  977. var pos, line, start;
  978. if (buffer !== null) {
  979. return buffer;
  980. }
  981. pos = index;
  982. line = lineNumber;
  983. start = lineStart;
  984. buffer = advance();
  985. index = pos;
  986. lineNumber = line;
  987. lineStart = start;
  988. return buffer;
  989. }
  990. // Return true if there is a line terminator before the next token.
  991. function peekLineTerminator() {
  992. var pos, line, start, found;
  993. pos = index;
  994. line = lineNumber;
  995. start = lineStart;
  996. skipComment();
  997. found = lineNumber !== line;
  998. index = pos;
  999. lineNumber = line;
  1000. lineStart = start;
  1001. return found;
  1002. }
  1003. // Throw an exception
  1004. function throwError(token, messageFormat) {
  1005. var error,
  1006. args = Array.prototype.slice.call(arguments, 2),
  1007. msg = messageFormat.replace(
  1008. /%(\d)/g,
  1009. function (whole, index) {
  1010. return args[index] || '';
  1011. }
  1012. );
  1013. if (typeof token.lineNumber === 'number') {
  1014. error = new Error('Line ' + token.lineNumber + ': ' + msg);
  1015. error.index = token.range[0];
  1016. error.lineNumber = token.lineNumber;
  1017. error.column = token.range[0] - lineStart + 1;
  1018. } else {
  1019. error = new Error('Line ' + lineNumber + ': ' + msg);
  1020. error.index = index;
  1021. error.lineNumber = lineNumber;
  1022. error.column = index - lineStart + 1;
  1023. }
  1024. throw error;
  1025. }
  1026. function throwErrorTolerant() {
  1027. try {
  1028. throwError.apply(null, arguments);
  1029. } catch (e) {
  1030. if (extra.errors) {
  1031. extra.errors.push(e);
  1032. } else {
  1033. throw e;
  1034. }
  1035. }
  1036. }
  1037. // Throw an exception because of the token.
  1038. function throwUnexpected(token) {
  1039. if (token.type === Token.EOF) {
  1040. throwError(token, Messages.UnexpectedEOS);
  1041. }
  1042. if (token.type === Token.NumericLiteral) {
  1043. throwError(token, Messages.UnexpectedNumber);
  1044. }
  1045. if (token.type === Token.StringLiteral) {
  1046. throwError(token, Messages.UnexpectedString);
  1047. }
  1048. if (token.type === Token.Identifier) {
  1049. throwError(token, Messages.UnexpectedIdentifier);
  1050. }
  1051. if (token.type === Token.Keyword) {
  1052. if (isFutureReservedWord(token.value)) {
  1053. throwError(token, Messages.UnexpectedReserved);
  1054. } else if (strict && isStrictModeReservedWord(token.value)) {
  1055. throwErrorTolerant(token, Messages.StrictReservedWord);
  1056. return;
  1057. }
  1058. throwError(token, Messages.UnexpectedToken, token.value);
  1059. }
  1060. // BooleanLiteral, NullLiteral, or Punctuator.
  1061. throwError(token, Messages.UnexpectedToken, token.value);
  1062. }
  1063. // Expect the next token to match the specified punctuator.
  1064. // If not, an exception will be thrown.
  1065. function expect(value) {
  1066. var token = lex();
  1067. if (token.type !== Token.Punctuator || token.value !== value) {
  1068. throwUnexpected(token);
  1069. }
  1070. }
  1071. // Expect the next token to match the specified keyword.
  1072. // If not, an exception will be thrown.
  1073. function expectKeyword(keyword) {
  1074. var token = lex();
  1075. if (token.type !== Token.Keyword || token.value !== keyword) {
  1076. throwUnexpected(token);
  1077. }
  1078. }
  1079. // Return true if the next token matches the specified punctuator.
  1080. function match(value) {
  1081. var token = lookahead();
  1082. return token.type === Token.Punctuator && token.value === value;
  1083. }
  1084. // Return true if the next token matches the specified keyword
  1085. function matchKeyword(keyword) {
  1086. var token = lookahead();
  1087. return token.type === Token.Keyword && token.value === keyword;
  1088. }
  1089. // Return true if the next token is an assignment operator
  1090. function matchAssign() {
  1091. var token = lookahead(),
  1092. op = token.value;
  1093. if (token.type !== Token.Punctuator) {
  1094. return false;
  1095. }
  1096. return op === '=' ||
  1097. op === '*=' ||
  1098. op === '/=' ||
  1099. op === '%=' ||
  1100. op === '+=' ||
  1101. op === '-=' ||
  1102. op === '<<=' ||
  1103. op === '>>=' ||
  1104. op === '>>>=' ||
  1105. op === '&=' ||
  1106. op === '^=' ||
  1107. op === '|=';
  1108. }
  1109. function consumeSemicolon() {
  1110. var token, line;
  1111. // Catch the very common case first.
  1112. if (source[index] === ';') {
  1113. lex();
  1114. return;
  1115. }
  1116. line = lineNumber;
  1117. skipComment();
  1118. if (lineNumber !== line) {
  1119. return;
  1120. }
  1121. if (match(';')) {
  1122. lex();
  1123. return;
  1124. }
  1125. token = lookahead();
  1126. if (token.type !== Token.EOF && !match('}')) {
  1127. throwUnexpected(token);
  1128. }
  1129. }
  1130. // Return true if provided expression is LeftHandSideExpression
  1131. function isLeftHandSide(expr) {
  1132. return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
  1133. }
  1134. // 11.1.4 Array Initialiser
  1135. function parseArrayInitialiser() {
  1136. var elements = [];
  1137. expect('[');
  1138. while (!match(']')) {
  1139. if (match(',')) {
  1140. lex();
  1141. elements.push(null);
  1142. } else {
  1143. elements.push(parseAssignmentExpression());
  1144. if (!match(']')) {
  1145. expect(',');
  1146. }
  1147. }
  1148. }
  1149. expect(']');
  1150. return {
  1151. type: Syntax.ArrayExpression,
  1152. elements: elements
  1153. };
  1154. }
  1155. // 11.1.5 Object Initialiser
  1156. function parsePropertyFunction(param, first) {
  1157. var previousStrict, body;
  1158. previousStrict = strict;
  1159. body = parseFunctionSourceElements();
  1160. if (first && strict && isRestrictedWord(param[0].name)) {
  1161. throwErrorTolerant(first, Messages.StrictParamName);
  1162. }
  1163. strict = previousStrict;
  1164. return {
  1165. type: Syntax.FunctionExpression,
  1166. id: null,
  1167. params: param,
  1168. defaults: [],
  1169. body: body,
  1170. rest: null,
  1171. generator: false,
  1172. expression: false
  1173. };
  1174. }
  1175. function parseObjectPropertyKey() {
  1176. var token = lex();
  1177. // Note: This function is called only from parseObjectProperty(), where
  1178. // EOF and Punctuator tokens are already filtered out.
  1179. if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
  1180. if (strict && token.octal) {
  1181. throwErrorTolerant(token, Messages.StrictOctalLiteral);
  1182. }
  1183. return createLiteral(token);
  1184. }
  1185. return {
  1186. type: Syntax.Identifier,
  1187. name: token.value
  1188. };
  1189. }
  1190. function parseObjectProperty() {
  1191. var token, key, id, param;
  1192. token = lookahead();
  1193. if (token.type === Token.Identifier) {
  1194. id = parseObjectPropertyKey();
  1195. // Property Assignment: Getter and Setter.
  1196. if (token.value === 'get' && !match(':')) {
  1197. key = parseObjectPropertyKey();
  1198. expect('(');
  1199. expect(')');
  1200. return {
  1201. type: Syntax.Property,
  1202. key: key,
  1203. value: parsePropertyFunction([]),
  1204. kind: 'get'
  1205. };
  1206. } else if (token.value === 'set' && !match(':')) {
  1207. key = parseObjectPropertyKey();
  1208. expect('(');
  1209. token = lookahead();
  1210. if (token.type !== Token.Identifier) {
  1211. throwUnexpected(lex());
  1212. }
  1213. param = [ parseVariableIdentifier() ];
  1214. expect(')');
  1215. return {
  1216. type: Syntax.Property,
  1217. key: key,
  1218. value: parsePropertyFunction(param, token),
  1219. kind: 'set'
  1220. };
  1221. } else {
  1222. expect(':');
  1223. return {
  1224. type: Syntax.Property,
  1225. key: id,
  1226. value: parseAssignmentExpression(),
  1227. kind: 'init'
  1228. };
  1229. }
  1230. } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
  1231. throwUnexpected(token);
  1232. } else {
  1233. key = parseObjectPropertyKey();
  1234. expect(':');
  1235. return {
  1236. type: Syntax.Property,
  1237. key: key,
  1238. value: parseAssignmentExpression(),
  1239. kind: 'init'
  1240. };
  1241. }
  1242. }
  1243. function parseObjectInitialiser() {
  1244. var properties = [], property, name, kind, map = {}, toString = String;
  1245. expect('{');
  1246. while (!match('}')) {
  1247. property = parseObjectProperty();
  1248. if (property.key.type === Syntax.Identifier) {
  1249. name = property.key.name;
  1250. } else {
  1251. name = toString(property.key.value);
  1252. }
  1253. kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
  1254. if (Object.prototype.hasOwnProperty.call(map, name)) {
  1255. if (map[name] === PropertyKind.Data) {
  1256. if (strict && kind === PropertyKind.Data) {
  1257. throwErrorTolerant({}, Messages.StrictDuplicateProperty);
  1258. } else if (kind !== PropertyKind.Data) {
  1259. throwErrorTolerant({}, Messages.AccessorDataProperty);
  1260. }
  1261. } else {
  1262. if (kind === PropertyKind.Data) {
  1263. throwErrorTolerant({}, Messages.AccessorDataProperty);
  1264. } else if (map[name] & kind) {
  1265. throwErrorTolerant({}, Messages.AccessorGetSet);
  1266. }
  1267. }
  1268. map[name] |= kind;
  1269. } else {
  1270. map[name] = kind;
  1271. }
  1272. properties.push(property);
  1273. if (!match('}')) {
  1274. expect(',');
  1275. }
  1276. }
  1277. expect('}');
  1278. return {
  1279. type: Syntax.ObjectExpression,
  1280. properties: properties
  1281. };
  1282. }
  1283. // 11.1.6 The Grouping Operator
  1284. function parseGroupExpression() {
  1285. var expr;
  1286. expect('(');
  1287. expr = parseExpression();
  1288. expect(')');
  1289. return expr;
  1290. }
  1291. // 11.1 Primary Expressions
  1292. function parsePrimaryExpression() {
  1293. var token = lookahead(),
  1294. type = token.type;
  1295. if (type === Token.Identifier) {
  1296. return {
  1297. type: Syntax.Identifier,
  1298. name: lex().value
  1299. };
  1300. }
  1301. if (type === Token.StringLiteral || type === Token.NumericLiteral) {
  1302. if (strict && token.octal) {
  1303. throwErrorTolerant(token, Messages.StrictOctalLiteral);
  1304. }
  1305. return createLiteral(lex());
  1306. }
  1307. if (type === Token.Keyword) {
  1308. if (matchKeyword('this')) {
  1309. lex();
  1310. return {
  1311. type: Syntax.ThisExpression
  1312. };
  1313. }
  1314. if (matchKeyword('function')) {
  1315. return parseFunctionExpression();
  1316. }
  1317. }
  1318. if (type === Token.BooleanLiteral) {
  1319. lex();
  1320. token.value = (token.value === 'true');
  1321. return createLiteral(token);
  1322. }
  1323. if (type === Token.NullLiteral) {
  1324. lex();
  1325. token.value = null;
  1326. return createLiteral(token);
  1327. }
  1328. if (match('[')) {
  1329. return parseArrayInitialiser();
  1330. }
  1331. if (match('{')) {
  1332. return parseObjectInitialiser();
  1333. }
  1334. if (match('(')) {
  1335. return parseGroupExpression();
  1336. }
  1337. if (match('/') || match('/=')) {
  1338. return createLiteral(scanRegExp());
  1339. }
  1340. return throwUnexpected(lex());
  1341. }
  1342. // 11.2 Left-Hand-Side Expressions
  1343. function parseArguments() {
  1344. var args = [];
  1345. expect('(');
  1346. if (!match(')')) {
  1347. while (index < length) {
  1348. args.push(parseAssignmentExpression());
  1349. if (match(')')) {
  1350. break;
  1351. }
  1352. expect(',');
  1353. }
  1354. }
  1355. expect(')');
  1356. return args;
  1357. }
  1358. function parseNonComputedProperty() {
  1359. var token = lex();
  1360. if (!isIdentifierName(token)) {
  1361. throwUnexpected(token);
  1362. }
  1363. return {
  1364. type: Syntax.Identifier,
  1365. name: token.value
  1366. };
  1367. }
  1368. function parseNonComputedMember() {
  1369. expect('.');
  1370. return parseNonComputedProperty();
  1371. }
  1372. function parseComputedMember() {
  1373. var expr;
  1374. expect('[');
  1375. expr = parseExpression();
  1376. expect(']');
  1377. return expr;
  1378. }
  1379. function parseNewExpression() {
  1380. var expr;
  1381. expectKeyword('new');
  1382. expr = {
  1383. type: Syntax.NewExpression,
  1384. callee: parseLeftHandSideExpression(),
  1385. 'arguments': []
  1386. };
  1387. if (match('(')) {
  1388. expr['arguments'] = parseArguments();
  1389. }
  1390. return expr;
  1391. }
  1392. function parseLeftHandSideExpressionAllowCall() {
  1393. var expr;
  1394. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  1395. while (match('.') || match('[') || match('(')) {
  1396. if (match('(')) {
  1397. expr = {
  1398. type: Syntax.CallExpression,
  1399. callee: expr,
  1400. 'arguments': parseArguments()
  1401. };
  1402. } else if (match('[')) {
  1403. expr = {
  1404. type: Syntax.MemberExpression,
  1405. computed: true,
  1406. object: expr,
  1407. property: parseComputedMember()
  1408. };
  1409. } else {
  1410. expr = {
  1411. type: Syntax.MemberExpression,
  1412. computed: false,
  1413. object: expr,
  1414. property: parseNonComputedMember()
  1415. };
  1416. }
  1417. }
  1418. return expr;
  1419. }
  1420. function parseLeftHandSideExpression() {
  1421. var expr;
  1422. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  1423. while (match('.') || match('[')) {
  1424. if (match('[')) {
  1425. expr = {
  1426. type: Syntax.MemberExpression,
  1427. computed: true,
  1428. object: expr,
  1429. property: parseComputedMember()
  1430. };
  1431. } else {
  1432. expr = {
  1433. type: Syntax.MemberExpression,
  1434. computed: false,
  1435. object: expr,
  1436. property: parseNonComputedMember()
  1437. };
  1438. }
  1439. }
  1440. return expr;
  1441. }
  1442. // 11.3 Postfix Expressions
  1443. function parsePostfixExpression() {
  1444. var expr = parseLeftHandSideExpressionAllowCall(), token;
  1445. token = lookahead();
  1446. if (token.type !== Token.Punctuator) {
  1447. return expr;
  1448. }
  1449. if ((match('++') || match('--')) && !peekLineTerminator()) {
  1450. // 11.3.1, 11.3.2
  1451. if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
  1452. throwErrorTolerant({}, Messages.StrictLHSPostfix);
  1453. }
  1454. if (!isLeftHandSide(expr)) {
  1455. throwError({}, Messages.InvalidLHSInAssignment);
  1456. }
  1457. expr = {
  1458. type: Syntax.UpdateExpression,
  1459. operator: lex().value,
  1460. argument: expr,
  1461. prefix: false
  1462. };
  1463. }
  1464. return expr;
  1465. }
  1466. // 11.4 Unary Operators
  1467. function parseUnaryExpression() {
  1468. var token, expr;
  1469. token = lookahead();
  1470. if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
  1471. return parsePostfixExpression();
  1472. }
  1473. if (match('++') || match('--')) {
  1474. token = lex();
  1475. expr = parseUnaryExpression();
  1476. // 11.4.4, 11.4.5
  1477. if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
  1478. throwErrorTolerant({}, Messages.StrictLHSPrefix);
  1479. }
  1480. if (!isLeftHandSide(expr)) {
  1481. throwError({}, Messages.InvalidLHSInAssignment);
  1482. }
  1483. expr = {
  1484. type: Syntax.UpdateExpression,
  1485. operator: token.value,
  1486. argument: expr,
  1487. prefix: true
  1488. };
  1489. return expr;
  1490. }
  1491. if (match('+') || match('-') || match('~') || match('!')) {
  1492. expr = {
  1493. type: Syntax.UnaryExpression,
  1494. operator: lex().value,
  1495. argument: parseUnaryExpression()
  1496. };
  1497. return expr;
  1498. }
  1499. if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
  1500. expr = {
  1501. type: Syntax.UnaryExpression,
  1502. operator: lex().value,
  1503. argument: parseUnaryExpression()
  1504. };
  1505. if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
  1506. throwErrorTolerant({}, Messages.StrictDelete);
  1507. }
  1508. return expr;
  1509. }
  1510. return parsePostfixExpression();
  1511. }
  1512. // 11.5 Multiplicative Operators
  1513. function parseMultiplicativeExpression() {
  1514. var expr = parseUnaryExpression();
  1515. while (match('*') || match('/') || match('%')) {
  1516. expr = {
  1517. type: Syntax.BinaryExpression,
  1518. operator: lex().value,
  1519. left: expr,
  1520. right: parseUnaryExpression()
  1521. };
  1522. }
  1523. return expr;
  1524. }
  1525. // 11.6 Additive Operators
  1526. function parseAdditiveExpression() {
  1527. var expr = parseMultiplicativeExpression();
  1528. while (match('+') || match('-')) {
  1529. expr = {
  1530. type: Syntax.BinaryExpression,
  1531. operator: lex().value,
  1532. left: expr,
  1533. right: parseMultiplicativeExpression()
  1534. };
  1535. }
  1536. return expr;
  1537. }
  1538. // 11.7 Bitwise Shift Operators
  1539. function parseShiftExpression() {
  1540. var expr = parseAdditiveExpression();
  1541. while (match('<<') || match('>>') || match('>>>')) {
  1542. expr = {
  1543. type: Syntax.BinaryExpression,
  1544. operator: lex().value,
  1545. left: expr,
  1546. right: parseAdditiveExpression()
  1547. };
  1548. }
  1549. return expr;
  1550. }
  1551. // 11.8 Relational Operators
  1552. function parseRelationalExpression() {
  1553. var expr, previousAllowIn;
  1554. previousAllowIn = state.allowIn;
  1555. state.allowIn = true;
  1556. expr = parseShiftExpression();
  1557. while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
  1558. expr = {
  1559. type: Syntax.BinaryExpression,
  1560. operator: lex().value,
  1561. left: expr,
  1562. right: parseShiftExpression()
  1563. };
  1564. }
  1565. state.allowIn = previousAllowIn;
  1566. return expr;
  1567. }
  1568. // 11.9 Equality Operators
  1569. function parseEqualityExpression() {
  1570. var expr = parseRelationalExpression();
  1571. while (match('==') || match('!=') || match('===') || match('!==')) {
  1572. expr = {
  1573. type: Syntax.BinaryExpression,
  1574. operator: lex().value,
  1575. left: expr,
  1576. right: parseRelationalExpression()
  1577. };
  1578. }
  1579. return expr;
  1580. }
  1581. // 11.10 Binary Bitwise Operators
  1582. function parseBitwiseANDExpression() {
  1583. var expr = parseEqualityExpression();
  1584. while (match('&')) {
  1585. lex();
  1586. expr = {
  1587. type: Syntax.BinaryExpression,
  1588. operator: '&',
  1589. left: expr,
  1590. right: parseEqualityExpression()
  1591. };
  1592. }
  1593. return expr;
  1594. }
  1595. function parseBitwiseXORExpression() {
  1596. var expr = parseBitwiseANDExpression();
  1597. while (match('^')) {
  1598. lex();
  1599. expr = {
  1600. type: Syntax.BinaryExpression,
  1601. operator: '^',
  1602. left: expr,
  1603. right: parseBitwiseANDExpression()
  1604. };
  1605. }
  1606. return expr;
  1607. }
  1608. function parseBitwiseORExpression() {
  1609. var expr = parseBitwiseXORExpression();
  1610. while (match('|')) {
  1611. lex();
  1612. expr = {
  1613. type: Syntax.BinaryExpression,
  1614. operator: '|',
  1615. left: expr,
  1616. right: parseBitwiseXORExpression()
  1617. };
  1618. }
  1619. return expr;
  1620. }
  1621. // 11.11 Binary Logical Operators
  1622. function parseLogicalANDExpression() {
  1623. var expr = parseBitwiseORExpression();
  1624. while (match('&&')) {
  1625. lex();
  1626. expr = {
  1627. type: Syntax.LogicalExpression,
  1628. operator: '&&',
  1629. left: expr,
  1630. right: parseBitwiseORExpression()
  1631. };
  1632. }
  1633. return expr;
  1634. }
  1635. function parseLogicalORExpression() {
  1636. var expr = parseLogicalANDExpression();
  1637. while (match('||')) {
  1638. lex();
  1639. expr = {
  1640. type: Syntax.LogicalExpression,
  1641. operator: '||',
  1642. left: expr,
  1643. right: parseLogicalANDExpression()
  1644. };
  1645. }
  1646. return expr;
  1647. }
  1648. // 11.12 Conditional Operator
  1649. function parseConditionalExpression() {
  1650. var expr, previousAllowIn, consequent;
  1651. expr = parseLogicalORExpression();
  1652. if (match('?')) {
  1653. lex();
  1654. previousAllowIn = state.allowIn;
  1655. state.allowIn = true;
  1656. consequent = parseAssignmentExpression();
  1657. state.allowIn = previousAllowIn;
  1658. expect(':');
  1659. expr = {
  1660. type: Syntax.ConditionalExpression,
  1661. test: expr,
  1662. consequent: consequent,
  1663. alternate: parseAssignmentExpression()
  1664. };
  1665. }
  1666. return expr;
  1667. }
  1668. // 11.13 Assignment Operators
  1669. function parseAssignmentExpression() {
  1670. var token, expr;
  1671. token = lookahead();
  1672. expr = parseConditionalExpression();
  1673. if (matchAssign()) {
  1674. // LeftHandSideExpression
  1675. if (!isLeftHandSide(expr)) {
  1676. throwError({}, Messages.InvalidLHSInAssignment);
  1677. }
  1678. // 11.13.1
  1679. if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
  1680. throwErrorTolerant(token, Messages.StrictLHSAssignment);
  1681. }
  1682. expr = {
  1683. type: Syntax.AssignmentExpression,
  1684. operator: lex().value,
  1685. left: expr,
  1686. right: parseAssignmentExpression()
  1687. };
  1688. }
  1689. return expr;
  1690. }
  1691. // 11.14 Comma Operator
  1692. function parseExpression() {
  1693. var expr = parseAssignmentExpression();
  1694. if (match(',')) {
  1695. expr = {
  1696. type: Syntax.SequenceExpression,
  1697. expressions: [ expr ]
  1698. };
  1699. while (index < length) {
  1700. if (!match(',')) {
  1701. break;
  1702. }
  1703. lex();
  1704. expr.expressions.push(parseAssignmentExpression());
  1705. }
  1706. }
  1707. return expr;
  1708. }
  1709. // 12.1 Block
  1710. function parseStatementList() {
  1711. var list = [],
  1712. statement;
  1713. while (index < length) {
  1714. if (match('}')) {
  1715. break;
  1716. }
  1717. statement = parseSourceElement();
  1718. if (typeof statement === 'undefined') {
  1719. break;
  1720. }
  1721. list.push(statement);
  1722. }
  1723. return list;
  1724. }
  1725. function parseBlock() {
  1726. var block;
  1727. expect('{');
  1728. block = parseStatementList();
  1729. expect('}');
  1730. return {
  1731. type: Syntax.BlockStatement,
  1732. body: block
  1733. };
  1734. }
  1735. // 12.2 Variable Statement
  1736. function parseVariableIdentifier() {
  1737. var token = lex();
  1738. if (token.type !== Token.Identifier) {
  1739. throwUnexpected(token);
  1740. }
  1741. return {
  1742. type: Syntax.Identifier,
  1743. name: token.value
  1744. };
  1745. }
  1746. function parseVariableDeclaration(kind) {
  1747. var id = parseVariableIdentifier(),
  1748. init = null;
  1749. // 12.2.1
  1750. if (strict && isRestrictedWord(id.name)) {
  1751. throwErrorTolerant({}, Messages.StrictVarName);
  1752. }
  1753. if (kind === 'const') {
  1754. expect('=');
  1755. init = parseAssignmentExpression();
  1756. } else if (match('=')) {
  1757. lex();
  1758. init = parseAssignmentExpression();
  1759. }
  1760. return {
  1761. type: Syntax.VariableDeclarator,
  1762. id: id,
  1763. init: init
  1764. };
  1765. }
  1766. function parseVariableDeclarationList(kind) {
  1767. var list = [];
  1768. while (index < length) {
  1769. list.push(parseVariableDeclaration(kind));
  1770. if (!match(',')) {
  1771. break;
  1772. }
  1773. lex();
  1774. }
  1775. return list;
  1776. }
  1777. function parseVariableStatement() {
  1778. var declarations;
  1779. expectKeyword('var');
  1780. declarations = parseVariableDeclarationList();
  1781. consumeSemicolon();
  1782. return {
  1783. type: Syntax.VariableDeclaration,
  1784. declarations: declarations,
  1785. kind: 'var'
  1786. };
  1787. }
  1788. // kind may be `const` or `let`
  1789. // Both are experimental and not in the specification yet.
  1790. // see http://wiki.ecmascript.org/doku.php?id=harmony:const
  1791. // and http://wiki.ecmascript.org/doku.php?id=harmony:let
  1792. function parseConstLetDeclaration(kind) {
  1793. var declarations;
  1794. expectKeyword(kind);
  1795. declarations = parseVariableDeclarationList(kind);
  1796. consumeSemicolon();
  1797. return {
  1798. type: Syntax.VariableDeclaration,
  1799. declarations: declarations,
  1800. kind: kind
  1801. };
  1802. }
  1803. // 12.3 Empty Statement
  1804. function parseEmptyStatement() {
  1805. expect(';');
  1806. return {
  1807. type: Syntax.EmptyStatement
  1808. };
  1809. }
  1810. // 12.4 Expression Statement
  1811. function parseExpressionStatement() {
  1812. var expr = parseExpression();
  1813. consumeSemicolon();
  1814. return {
  1815. type: Syntax.ExpressionStatement,
  1816. expression: expr
  1817. };
  1818. }
  1819. // 12.5 If statement
  1820. function parseIfStatement() {
  1821. var test, consequent, alternate;
  1822. expectKeyword('if');
  1823. expect('(');
  1824. test = parseExpression();
  1825. expect(')');
  1826. consequent = parseStatement();
  1827. if (matchKeyword('else')) {
  1828. lex();
  1829. alternate = parseStatement();
  1830. } else {
  1831. alternate = null;
  1832. }
  1833. return {
  1834. type: Syntax.IfStatement,
  1835. test: test,
  1836. consequent: consequent,
  1837. alternate: alternate
  1838. };
  1839. }
  1840. // 12.6 Iteration Statements
  1841. function parseDoWhileStatement() {
  1842. var body, test, oldInIteration;
  1843. expectKeyword('do');
  1844. oldInIteration = state.inIteration;
  1845. state.inIteration = true;
  1846. body = parseStatement();
  1847. state.inIteration = oldInIteration;
  1848. expectKeyword('while');
  1849. expect('(');
  1850. test = parseExpression();
  1851. expect(')');
  1852. if (match(';')) {
  1853. lex();
  1854. }
  1855. return {
  1856. type: Syntax.DoWhileStatement,
  1857. body: body,
  1858. test: test
  1859. };
  1860. }
  1861. function parseWhileStatement() {
  1862. var test, body, oldInIteration;
  1863. expectKeyword('while');
  1864. expect('(');
  1865. test = parseExpression();
  1866. expect(')');
  1867. oldInIteration = state.inIteration;
  1868. state.inIteration = true;
  1869. body = parseStatement();
  1870. state.inIteration = oldInIteration;
  1871. return {
  1872. type: Syntax.WhileStatement,
  1873. test: test,
  1874. body: body
  1875. };
  1876. }
  1877. function parseForVariableDeclaration() {
  1878. var token = lex();
  1879. return {
  1880. type: Syntax.VariableDeclaration,
  1881. declarations: parseVariableDeclarationList(),
  1882. kind: token.value
  1883. };
  1884. }
  1885. function parseForStatement() {
  1886. var init, test, update, left, right, body, oldInIteration;
  1887. init = test = update = null;
  1888. expectKeyword('for');
  1889. expect('(');
  1890. if (match(';')) {
  1891. lex();
  1892. } else {
  1893. if (matchKeyword('var') || matchKeyword('let')) {
  1894. state.allowIn = false;
  1895. init = parseForVariableDeclaration();
  1896. state.allowIn = true;
  1897. if (init.declarations.length === 1 && matchKeyword('in')) {
  1898. lex();
  1899. left = init;
  1900. right = parseExpression();
  1901. init = null;
  1902. }
  1903. } else {
  1904. state.allowIn = false;
  1905. init = parseExpression();
  1906. state.allowIn = true;
  1907. if (matchKeyword('in')) {
  1908. // LeftHandSideExpression
  1909. if (!isLeftHandSide(init)) {
  1910. throwError({}, Messages.InvalidLHSInForIn);
  1911. }
  1912. lex();
  1913. left = init;
  1914. right = parseExpression();
  1915. init = null;
  1916. }
  1917. }
  1918. if (typeof left === 'undefined') {
  1919. expect(';');
  1920. }
  1921. }
  1922. if (typeof left === 'undefined') {
  1923. if (!match(';')) {
  1924. test = parseExpression();
  1925. }
  1926. expect(';');
  1927. if (!match(')')) {
  1928. update = parseExpression();
  1929. }
  1930. }
  1931. expect(')');
  1932. oldInIteration = state.inIteration;
  1933. state.inIteration = true;
  1934. body = parseStatement();
  1935. state.inIteration = oldInIteration;
  1936. if (typeof left === 'undefined') {
  1937. return {
  1938. type: Syntax.ForStatement,
  1939. init: init,
  1940. test: test,
  1941. update: update,
  1942. body: body
  1943. };
  1944. }
  1945. return {
  1946. type: Syntax.ForInStatement,
  1947. left: left,
  1948. right: right,
  1949. body: body,
  1950. each: false
  1951. };
  1952. }
  1953. // 12.7 The continue statement
  1954. function parseContinueStatement() {
  1955. var token, label = null;
  1956. expectKeyword('continue');
  1957. // Optimize the most common form: 'continue;'.
  1958. if (source[index] === ';') {
  1959. lex();
  1960. if (!state.inIteration) {
  1961. throwError({}, Messages.IllegalContinue);
  1962. }
  1963. return {
  1964. type: Syntax.ContinueStatement,
  1965. label: null
  1966. };
  1967. }
  1968. if (peekLineTerminator()) {
  1969. if (!state.inIteration) {
  1970. throwError({}, Messages.IllegalContinue);
  1971. }
  1972. return {
  1973. type: Syntax.ContinueStatement,
  1974. label: null
  1975. };
  1976. }
  1977. token = lookahead();
  1978. if (token.type === Token.Identifier) {
  1979. label = parseVariableIdentifier();
  1980. if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
  1981. throwError({}, Messages.UnknownLabel, label.name);
  1982. }
  1983. }
  1984. consumeSemicolon();
  1985. if (label === null && !state.inIteration) {
  1986. throwError({}, Messages.IllegalContinue);
  1987. }
  1988. return {
  1989. type: Syntax.ContinueStatement,
  1990. label: label
  1991. };
  1992. }
  1993. // 12.8 The break statement
  1994. function parseBreakStatement() {
  1995. var token, label = null;
  1996. expectKeyword('break');
  1997. // Optimize the most common form: 'break;'.
  1998. if (source[index] === ';') {
  1999. lex();
  2000. if (!(state.inIteration || state.inSwitch)) {
  2001. throwError({}, Messages.IllegalBreak);
  2002. }
  2003. return {
  2004. type: Syntax.BreakStatement,
  2005. label: null
  2006. };
  2007. }
  2008. if (peekLineTerminator()) {
  2009. if (!(state.inIteration || state.inSwitch)) {
  2010. throwError({}, Messages.IllegalBreak);
  2011. }
  2012. return {
  2013. type: Syntax.BreakStatement,
  2014. label: null
  2015. };
  2016. }
  2017. token = lookahead();
  2018. if (token.type === Token.Identifier) {
  2019. label = parseVariableIdentifier();
  2020. if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
  2021. throwError({}, Messages.UnknownLabel, label.name);
  2022. }
  2023. }
  2024. consumeSemicolon();
  2025. if (label === null && !(state.inIteration || state.inSwitch)) {
  2026. throwError({}, Messages.IllegalBreak);
  2027. }
  2028. return {
  2029. type: Syntax.BreakStatement,
  2030. label: label
  2031. };
  2032. }
  2033. // 12.9 The return statement
  2034. function parseReturnStatement() {
  2035. var token, argument = null;
  2036. expectKeyword('return');
  2037. if (!state.inFunctionBody) {
  2038. throwErrorTolerant({}, Messages.IllegalReturn);
  2039. }
  2040. // 'return' followed by a space and an identifier is very common.
  2041. if (source[index] === ' ') {
  2042. if (isIdentifierStart(source[index + 1])) {
  2043. argument = parseExpression();
  2044. consumeSemicolon();
  2045. return {
  2046. type: Syntax.ReturnStatement,
  2047. argument: argument
  2048. };
  2049. }
  2050. }
  2051. if (peekLineTerminator()) {
  2052. return {
  2053. type: Syntax.ReturnStatement,
  2054. argument: null
  2055. };
  2056. }
  2057. if (!match(';')) {
  2058. token = lookahead();
  2059. if (!match('}') && token.type !== Token.EOF) {
  2060. argument = parseExpression();
  2061. }
  2062. }
  2063. consumeSemicolon();
  2064. return {
  2065. type: Syntax.ReturnStatement,
  2066. argument: argument
  2067. };
  2068. }
  2069. // 12.10 The with statement
  2070. function parseWithStatement() {
  2071. var object, body;
  2072. if (strict) {
  2073. throwErrorTolerant({}, Messages.StrictModeWith);
  2074. }
  2075. expectKeyword('with');
  2076. expect('(');
  2077. object = parseExpression();
  2078. expect(')');
  2079. body = parseStatement();
  2080. return {
  2081. type: Syntax.WithStatement,
  2082. object: object,
  2083. body: body
  2084. };
  2085. }
  2086. // 12.10 The swith statement
  2087. function parseSwitchCase() {
  2088. var test,
  2089. consequent = [],
  2090. statement;
  2091. if (matchKeyword('default')) {
  2092. lex();
  2093. test = null;
  2094. } else {
  2095. expectKeyword('case');
  2096. test = parseExpression();
  2097. }
  2098. expect(':');
  2099. while (index < length) {
  2100. if (match('}') || matchKeyword('default') || matchKeyword('case')) {
  2101. break;
  2102. }
  2103. statement = parseStatement();
  2104. if (typeof statement === 'undefined') {
  2105. break;
  2106. }
  2107. consequent.push(statement);
  2108. }
  2109. return {
  2110. type: Syntax.SwitchCase,
  2111. test: test,
  2112. consequent: consequent
  2113. };
  2114. }
  2115. function parseSwitchStatement() {
  2116. var discriminant, cases, clause, oldInSwitch, defaultFound;
  2117. expectKeyword('switch');
  2118. expect('(');
  2119. discriminant = parseExpression();
  2120. expect(')');
  2121. expect('{');
  2122. if (match('}')) {
  2123. lex();
  2124. return {
  2125. type: Syntax.SwitchStatement,
  2126. discriminant: discriminant
  2127. };
  2128. }
  2129. cases = [];
  2130. oldInSwitch = state.inSwitch;
  2131. state.inSwitch = true;
  2132. defaultFound = false;
  2133. while (index < length) {
  2134. if (match('}')) {
  2135. break;
  2136. }
  2137. clause = parseSwitchCase();
  2138. if (clause.test === null) {
  2139. if (defaultFound) {
  2140. throwError({}, Messages.MultipleDefaultsInSwitch);
  2141. }
  2142. defaultFound = true;
  2143. }
  2144. cases.push(clause);
  2145. }
  2146. state.inSwitch = oldInSwitch;
  2147. expect('}');
  2148. return {
  2149. type: Syntax.SwitchStatement,
  2150. discriminant: discriminant,
  2151. cases: cases
  2152. };
  2153. }
  2154. // 12.13 The throw statement
  2155. function parseThrowStatement() {
  2156. var argument;
  2157. expectKeyword('throw');
  2158. if (peekLineTerminator()) {
  2159. throwError({}, Messages.NewlineAfterThrow);
  2160. }
  2161. argument = parseExpression();
  2162. consumeSemicolon();
  2163. return {
  2164. type: Syntax.ThrowStatement,
  2165. argument: argument
  2166. };
  2167. }
  2168. // 12.14 The try statement
  2169. function parseCatchClause() {
  2170. var param;
  2171. expectKeyword('catch');
  2172. expect('(');
  2173. if (!match(')')) {
  2174. param = parseExpression();
  2175. // 12.14.1
  2176. if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
  2177. throwErrorTolerant({}, Messages.StrictCatchVariable);
  2178. }
  2179. }
  2180. expect(')');
  2181. return {
  2182. type: Syntax.CatchClause,
  2183. param: param,
  2184. body: parseBlock()
  2185. };
  2186. }
  2187. function parseTryStatement() {
  2188. var block, handlers = [], finalizer = null;
  2189. expectKeyword('try');
  2190. block = parseBlock();
  2191. if (matchKeyword('catch')) {
  2192. handlers.push(parseCatchClause());
  2193. }
  2194. if (matchKeyword('finally')) {
  2195. lex();
  2196. finalizer = parseBlock();
  2197. }
  2198. if (handlers.length === 0 && !finalizer) {
  2199. throwError({}, Messages.NoCatchOrFinally);
  2200. }
  2201. return {
  2202. type: Syntax.TryStatement,
  2203. block: block,
  2204. guardedHandlers: [],
  2205. handlers: handlers,
  2206. finalizer: finalizer
  2207. };
  2208. }
  2209. // 12.15 The debugger statement
  2210. function parseDebuggerStatement() {
  2211. expectKeyword('debugger');
  2212. consumeSemicolon();
  2213. return {
  2214. type: Syntax.DebuggerStatement
  2215. };
  2216. }
  2217. // 12 Statements
  2218. function parseStatement() {
  2219. var token = lookahead(),
  2220. expr,
  2221. labeledBody;
  2222. if (token.type === Token.EOF) {
  2223. throwUnexpected(token);
  2224. }
  2225. if (token.type === Token.Punctuator) {
  2226. switch (token.value) {
  2227. case ';':
  2228. return parseEmptyStatement();
  2229. case '{':
  2230. return parseBlock();
  2231. case '(':
  2232. return parseExpressionStatement();
  2233. default:
  2234. break;
  2235. }
  2236. }
  2237. if (token.type === Token.Keyword) {
  2238. switch (token.value) {
  2239. case 'break':
  2240. return parseBreakStatement();
  2241. case 'continue':
  2242. return parseContinueStatement();
  2243. case 'debugger':
  2244. return parseDebuggerStatement();
  2245. case 'do':
  2246. return parseDoWhileStatement();
  2247. case 'for':
  2248. return parseForStatement();
  2249. case 'function':
  2250. return parseFunctionDeclaration();
  2251. case 'if':
  2252. return parseIfStatement();
  2253. case 'return':
  2254. return parseReturnStatement();
  2255. case 'switch':
  2256. return parseSwitchStatement();
  2257. case 'throw':
  2258. return parseThrowStatement();
  2259. case 'try':
  2260. return parseTryStatement();
  2261. case 'var':
  2262. return parseVariableStatement();
  2263. case 'while':
  2264. return parseWhileStatement();
  2265. case 'with':
  2266. return parseWithStatement();
  2267. default:
  2268. break;
  2269. }
  2270. }
  2271. expr = parseExpression();
  2272. // 12.12 Labelled Statements
  2273. if ((expr.type === Syntax.Identifier) && match(':')) {
  2274. lex();
  2275. if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
  2276. throwError({}, Messages.Redeclaration, 'Label', expr.name);
  2277. }
  2278. state.labelSet[expr.name] = true;
  2279. labeledBody = parseStatement();
  2280. delete state.labelSet[expr.name];
  2281. return {
  2282. type: Syntax.LabeledStatement,
  2283. label: expr,
  2284. body: labeledBody
  2285. };
  2286. }
  2287. consumeSemicolon();
  2288. return {
  2289. type: Syntax.ExpressionStatement,
  2290. expression: expr
  2291. };
  2292. }
  2293. // 13 Function Definition
  2294. function parseFunctionSourceElements() {
  2295. var sourceElement, sourceElements = [], token, directive, firstRestricted,
  2296. oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
  2297. expect('{');
  2298. while (index < length) {
  2299. token = lookahead();
  2300. if (token.type !== Token.StringLiteral) {
  2301. break;
  2302. }
  2303. sourceElement = parseSourceElement();
  2304. sourceElements.push(sourceElement);
  2305. if (sourceElement.expression.type !== Syntax.Literal) {
  2306. // this is not directive
  2307. break;
  2308. }
  2309. directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
  2310. if (directive === 'use strict') {
  2311. strict = true;
  2312. if (firstRestricted) {
  2313. throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
  2314. }
  2315. } else {
  2316. if (!firstRestricted && token.octal) {
  2317. firstRestricted = token;
  2318. }
  2319. }
  2320. }
  2321. oldLabelSet = state.labelSet;
  2322. oldInIteration = state.inIteration;
  2323. oldInSwitch = state.inSwitch;
  2324. oldInFunctionBody = state.inFunctionBody;
  2325. state.labelSet = {};
  2326. state.inIteration = false;
  2327. state.inSwitch = false;
  2328. state.inFunctionBody = true;
  2329. while (index < length) {
  2330. if (match('}')) {
  2331. break;
  2332. }
  2333. sourceElement = parseSourceElement();
  2334. if (typeof sourceElement === 'undefined') {
  2335. break;
  2336. }
  2337. sourceElements.push(sourceElement);
  2338. }
  2339. expect('}');
  2340. state.labelSet = oldLabelSet;
  2341. state.inIteration = oldInIteration;
  2342. state.inSwitch = oldInSwitch;
  2343. state.inFunctionBody = oldInFunctionBody;
  2344. return {
  2345. type: Syntax.BlockStatement,
  2346. body: sourceElements
  2347. };
  2348. }
  2349. function parseFunctionDeclaration() {
  2350. var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet;
  2351. expectKeyword('function');
  2352. token = lookahead();
  2353. id = parseVariableIdentifier();
  2354. if (strict) {
  2355. if (isRestrictedWord(token.value)) {
  2356. throwErrorTolerant(token, Messages.StrictFunctionName);
  2357. }
  2358. } else {
  2359. if (isRestrictedWord(token.value)) {
  2360. firstRestricted = token;
  2361. message = Messages.StrictFunctionName;
  2362. } else if (isStrictModeReservedWord(token.value)) {
  2363. firstRestricted = token;
  2364. message = Messages.StrictReservedWord;
  2365. }
  2366. }
  2367. expect('(');
  2368. if (!match(')')) {
  2369. paramSet = {};
  2370. while (index < length) {
  2371. token = lookahead();
  2372. param = parseVariableIdentifier();
  2373. if (strict) {
  2374. if (isRestrictedWord(token.value)) {
  2375. stricted = token;
  2376. message = Messages.StrictParamName;
  2377. }
  2378. if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2379. stricted = token;
  2380. message = Messages.StrictParamDupe;
  2381. }
  2382. } else if (!firstRestricted) {
  2383. if (isRestrictedWord(token.value)) {
  2384. firstRestricted = token;
  2385. message = Messages.StrictParamName;
  2386. } else if (isStrictModeReservedWord(token.value)) {
  2387. firstRestricted = token;
  2388. message = Messages.StrictReservedWord;
  2389. } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2390. firstRestricted = token;
  2391. message = Messages.StrictParamDupe;
  2392. }
  2393. }
  2394. params.push(param);
  2395. paramSet[param.name] = true;
  2396. if (match(')')) {
  2397. break;
  2398. }
  2399. expect(',');
  2400. }
  2401. }
  2402. expect(')');
  2403. previousStrict = strict;
  2404. body = parseFunctionSourceElements();
  2405. if (strict && firstRestricted) {
  2406. throwError(firstRestricted, message);
  2407. }
  2408. if (strict && stricted) {
  2409. throwErrorTolerant(stricted, message);
  2410. }
  2411. strict = previousStrict;
  2412. return {
  2413. type: Syntax.FunctionDeclaration,
  2414. id: id,
  2415. params: params,
  2416. defaults: [],
  2417. body: body,
  2418. rest: null,
  2419. generator: false,
  2420. expression: false
  2421. };
  2422. }
  2423. function parseFunctionExpression() {
  2424. var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet;
  2425. expectKeyword('function');
  2426. if (!match('(')) {
  2427. token = lookahead();
  2428. id = parseVariableIdentifier();
  2429. if (strict) {
  2430. if (isRestrictedWord(token.value)) {
  2431. throwErrorTolerant(token, Messages.StrictFunctionName);
  2432. }
  2433. } else {
  2434. if (isRestrictedWord(token.value)) {
  2435. firstRestricted = token;
  2436. message = Messages.StrictFunctionName;
  2437. } else if (isStrictModeReservedWord(token.value)) {
  2438. firstRestricted = token;
  2439. message = Messages.StrictReservedWord;
  2440. }
  2441. }
  2442. }
  2443. expect('(');
  2444. if (!match(')')) {
  2445. paramSet = {};
  2446. while (index < length) {
  2447. token = lookahead();
  2448. param = parseVariableIdentifier();
  2449. if (strict) {
  2450. if (isRestrictedWord(token.value)) {
  2451. stricted = token;
  2452. message = Messages.StrictParamName;
  2453. }
  2454. if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2455. stricted = token;
  2456. message = Messages.StrictParamDupe;
  2457. }
  2458. } else if (!firstRestricted) {
  2459. if (isRestrictedWord(token.value)) {
  2460. firstRestricted = token;
  2461. message = Messages.StrictParamName;
  2462. } else if (isStrictModeReservedWord(token.value)) {
  2463. firstRestricted = token;
  2464. message = Messages.StrictReservedWord;
  2465. } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2466. firstRestricted = token;
  2467. message = Messages.StrictParamDupe;
  2468. }
  2469. }
  2470. params.push(param);
  2471. paramSet[param.name] = true;
  2472. if (match(')')) {
  2473. break;
  2474. }
  2475. expect(',');
  2476. }
  2477. }
  2478. expect(')');
  2479. previousStrict = strict;
  2480. body = parseFunctionSourceElements();
  2481. if (strict && firstRestricted) {
  2482. throwError(firstRestricted, message);
  2483. }
  2484. if (strict && stricted) {
  2485. throwErrorTolerant(stricted, message);
  2486. }
  2487. strict = previousStrict;
  2488. return {
  2489. type: Syntax.FunctionExpression,
  2490. id: id,
  2491. params: params,
  2492. defaults: [],
  2493. body: body,
  2494. rest: null,
  2495. generator: false,
  2496. expression: false
  2497. };
  2498. }
  2499. // 14 Program
  2500. function parseSourceElement() {
  2501. var token = lookahead();
  2502. if (token.type === Token.Keyword) {
  2503. switch (token.value) {
  2504. case 'const':
  2505. case 'let':
  2506. return parseConstLetDeclaration(token.value);
  2507. case 'function':
  2508. return parseFunctionDeclaration();
  2509. default:
  2510. return parseStatement();
  2511. }
  2512. }
  2513. if (token.type !== Token.EOF) {
  2514. return parseStatement();
  2515. }
  2516. }
  2517. function parseSourceElements() {
  2518. var sourceElement, sourceElements = [], token, directive, firstRestricted;
  2519. while (index < length) {
  2520. token = lookahead();
  2521. if (token.type !== Token.StringLiteral) {
  2522. break;
  2523. }
  2524. sourceElement = parseSourceElement();
  2525. sourceElements.push(sourceElement);
  2526. if (sourceElement.expression.type !== Syntax.Literal) {
  2527. // this is not directive
  2528. break;
  2529. }
  2530. directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
  2531. if (directive === 'use strict') {
  2532. strict = true;
  2533. if (firstRestricted) {
  2534. throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
  2535. }
  2536. } else {
  2537. if (!firstRestricted && token.octal) {
  2538. firstRestricted = token;
  2539. }
  2540. }
  2541. }
  2542. while (index < length) {
  2543. sourceElement = parseSourceElement();
  2544. if (typeof sourceElement === 'undefined') {
  2545. break;
  2546. }
  2547. sourceElements.push(sourceElement);
  2548. }
  2549. return sourceElements;
  2550. }
  2551. function parseProgram() {
  2552. var program;
  2553. strict = false;
  2554. program = {
  2555. type: Syntax.Program,
  2556. body: parseSourceElements()
  2557. };
  2558. return program;
  2559. }
  2560. // The following functions are needed only when the option to preserve
  2561. // the comments is active.
  2562. function addComment(type, value, start, end, loc) {
  2563. assert(typeof start === 'number', 'Comment must have valid position');
  2564. // Because the way the actual token is scanned, often the comments
  2565. // (if any) are skipped twice during the lexical analysis.
  2566. // Thus, we need to skip adding a comment if the comment array already
  2567. // handled it.
  2568. if (extra.comments.length > 0) {
  2569. if (extra.comments[extra.comments.length - 1].range[1] > start) {
  2570. return;
  2571. }
  2572. }
  2573. extra.comments.push({
  2574. type: type,
  2575. value: value,
  2576. range: [start, end],
  2577. loc: loc
  2578. });
  2579. }
  2580. function scanComment() {
  2581. var comment, ch, loc, start, blockComment, lineComment;
  2582. comment = '';
  2583. blockComment = false;
  2584. lineComment = false;
  2585. while (index < length) {
  2586. ch = source[index];
  2587. if (lineComment) {
  2588. ch = source[index++];
  2589. if (isLineTerminator(ch)) {
  2590. loc.end = {
  2591. line: lineNumber,
  2592. column: index - lineStart - 1
  2593. };
  2594. lineComment = false;
  2595. addComment('Line', comment, start, index - 1, loc);
  2596. if (ch === '\r' && source[index] === '\n') {
  2597. ++index;
  2598. }
  2599. ++lineNumber;
  2600. lineStart = index;
  2601. comment = '';
  2602. } else if (index >= length) {
  2603. lineComment = false;
  2604. comment += ch;
  2605. loc.end = {
  2606. line: lineNumber,
  2607. column: length - lineStart
  2608. };
  2609. addComment('Line', comment, start, length, loc);
  2610. } else {
  2611. comment += ch;
  2612. }
  2613. } else if (blockComment) {
  2614. if (isLineTerminator(ch)) {
  2615. if (ch === '\r' && source[index + 1] === '\n') {
  2616. ++index;
  2617. comment += '\r\n';
  2618. } else {
  2619. comment += ch;
  2620. }
  2621. ++lineNumber;
  2622. ++index;
  2623. lineStart = index;
  2624. if (index >= length) {
  2625. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2626. }
  2627. } else {
  2628. ch = source[index++];
  2629. if (index >= length) {
  2630. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2631. }
  2632. comment += ch;
  2633. if (ch === '*') {
  2634. ch = source[index];
  2635. if (ch === '/') {
  2636. comment = comment.substr(0, comment.length - 1);
  2637. blockComment = false;
  2638. ++index;
  2639. loc.end = {
  2640. line: lineNumber,
  2641. column: index - lineStart
  2642. };
  2643. addComment('Block', comment, start, index, loc);
  2644. comment = '';
  2645. }
  2646. }
  2647. }
  2648. } else if (ch === '/') {
  2649. ch = source[index + 1];
  2650. if (ch === '/') {
  2651. loc = {
  2652. start: {
  2653. line: lineNumber,
  2654. column: index - lineStart
  2655. }
  2656. };
  2657. start = index;
  2658. index += 2;
  2659. lineComment = true;
  2660. if (index >= length) {
  2661. loc.end = {
  2662. line: lineNumber,
  2663. column: index - lineStart
  2664. };
  2665. lineComment = false;
  2666. addComment('Line', comment, start, index, loc);
  2667. }
  2668. } else if (ch === '*') {
  2669. start = index;
  2670. index += 2;
  2671. blockComment = true;
  2672. loc = {
  2673. start: {
  2674. line: lineNumber,
  2675. column: index - lineStart - 2
  2676. }
  2677. };
  2678. if (index >= length) {
  2679. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2680. }
  2681. } else {
  2682. break;
  2683. }
  2684. } else if (isWhiteSpace(ch)) {
  2685. ++index;
  2686. } else if (isLineTerminator(ch)) {
  2687. ++index;
  2688. if (ch === '\r' && source[index] === '\n') {
  2689. ++index;
  2690. }
  2691. ++lineNumber;
  2692. lineStart = index;
  2693. } else {
  2694. break;
  2695. }
  2696. }
  2697. }
  2698. function filterCommentLocation() {
  2699. var i, entry, comment, comments = [];
  2700. for (i = 0; i < extra.comments.length; ++i) {
  2701. entry = extra.comments[i];
  2702. comment = {
  2703. type: entry.type,
  2704. value: entry.value
  2705. };
  2706. if (extra.range) {
  2707. comment.range = entry.range;
  2708. }
  2709. if (extra.loc) {
  2710. comment.loc = entry.loc;
  2711. }
  2712. comments.push(comment);
  2713. }
  2714. extra.comments = comments;
  2715. }
  2716. function collectToken() {
  2717. var start, loc, token, range, value;
  2718. skipComment();
  2719. start = index;
  2720. loc = {
  2721. start: {
  2722. line: lineNumber,
  2723. column: index - lineStart
  2724. }
  2725. };
  2726. token = extra.advance();
  2727. loc.end = {
  2728. line: lineNumber,
  2729. column: index - lineStart
  2730. };
  2731. if (token.type !== Token.EOF) {
  2732. range = [token.range[0], token.range[1]];
  2733. value = sliceSource(token.range[0], token.range[1]);
  2734. extra.tokens.push({
  2735. type: TokenName[token.type],
  2736. value: value,
  2737. range: range,
  2738. loc: loc
  2739. });
  2740. }
  2741. return token;
  2742. }
  2743. function collectRegex() {
  2744. var pos, loc, regex, token;
  2745. skipComment();
  2746. pos = index;
  2747. loc = {
  2748. start: {
  2749. line: lineNumber,
  2750. column: index - lineStart
  2751. }
  2752. };
  2753. regex = extra.scanRegExp();
  2754. loc.end = {
  2755. line: lineNumber,
  2756. column: index - lineStart
  2757. };
  2758. // Pop the previous token, which is likely '/' or '/='
  2759. if (extra.tokens.length > 0) {
  2760. token = extra.tokens[extra.tokens.length - 1];
  2761. if (token.range[0] === pos && token.type === 'Punctuator') {
  2762. if (token.value === '/' || token.value === '/=') {
  2763. extra.tokens.pop();
  2764. }
  2765. }
  2766. }
  2767. extra.tokens.push({
  2768. type: 'RegularExpression',
  2769. value: regex.literal,
  2770. range: [pos, index],
  2771. loc: loc
  2772. });
  2773. return regex;
  2774. }
  2775. function filterTokenLocation() {
  2776. var i, entry, token, tokens = [];
  2777. for (i = 0; i < extra.tokens.length; ++i) {
  2778. entry = extra.tokens[i];
  2779. token = {
  2780. type: entry.type,
  2781. value: entry.value
  2782. };
  2783. if (extra.range) {
  2784. token.range = entry.range;
  2785. }
  2786. if (extra.loc) {
  2787. token.loc = entry.loc;
  2788. }
  2789. tokens.push(token);
  2790. }
  2791. extra.tokens = tokens;
  2792. }
  2793. function createLiteral(token) {
  2794. return {
  2795. type: Syntax.Literal,
  2796. value: token.value
  2797. };
  2798. }
  2799. function createRawLiteral(token) {
  2800. return {
  2801. type: Syntax.Literal,
  2802. value: token.value,
  2803. raw: sliceSource(token.range[0], token.range[1])
  2804. };
  2805. }
  2806. function createLocationMarker() {
  2807. var marker = {};
  2808. marker.range = [index, index];
  2809. marker.loc = {
  2810. start: {
  2811. line: lineNumber,
  2812. column: index - lineStart
  2813. },
  2814. end: {
  2815. line: lineNumber,
  2816. column: index - lineStart
  2817. }
  2818. };
  2819. marker.end = function () {
  2820. this.range[1] = index;
  2821. this.loc.end.line = lineNumber;
  2822. this.loc.end.column = index - lineStart;
  2823. };
  2824. marker.applyGroup = function (node) {
  2825. if (extra.range) {
  2826. node.groupRange = [this.range[0], this.range[1]];
  2827. }
  2828. if (extra.loc) {
  2829. node.groupLoc = {
  2830. start: {
  2831. line: this.loc.start.line,
  2832. column: this.loc.start.column
  2833. },
  2834. end: {
  2835. line: this.loc.end.line,
  2836. column: this.loc.end.column
  2837. }
  2838. };
  2839. }
  2840. };
  2841. marker.apply = function (node) {
  2842. if (extra.range) {
  2843. node.range = [this.range[0], this.range[1]];
  2844. }
  2845. if (extra.loc) {
  2846. node.loc = {
  2847. start: {
  2848. line: this.loc.start.line,
  2849. column: this.loc.start.column
  2850. },
  2851. end: {
  2852. line: this.loc.end.line,
  2853. column: this.loc.end.column
  2854. }
  2855. };
  2856. }
  2857. };
  2858. return marker;
  2859. }
  2860. function trackGroupExpression() {
  2861. var marker, expr;
  2862. skipComment();
  2863. marker = createLocationMarker();
  2864. expect('(');
  2865. expr = parseExpression();
  2866. expect(')');
  2867. marker.end();
  2868. marker.applyGroup(expr);
  2869. return expr;
  2870. }
  2871. function trackLeftHandSideExpression() {
  2872. var marker, expr;
  2873. skipComment();
  2874. marker = createLocationMarker();
  2875. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  2876. while (match('.') || match('[')) {
  2877. if (match('[')) {
  2878. expr = {
  2879. type: Syntax.MemberExpression,
  2880. computed: true,
  2881. object: expr,
  2882. property: parseComputedMember()
  2883. };
  2884. marker.end();
  2885. marker.apply(expr);
  2886. } else {
  2887. expr = {
  2888. type: Syntax.MemberExpression,
  2889. computed: false,
  2890. object: expr,
  2891. property: parseNonComputedMember()
  2892. };
  2893. marker.end();
  2894. marker.apply(expr);
  2895. }
  2896. }
  2897. return expr;
  2898. }
  2899. function trackLeftHandSideExpressionAllowCall() {
  2900. var marker, expr;
  2901. skipComment();
  2902. marker = createLocationMarker();
  2903. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  2904. while (match('.') || match('[') || match('(')) {
  2905. if (match('(')) {
  2906. expr = {
  2907. type: Syntax.CallExpression,
  2908. callee: expr,
  2909. 'arguments': parseArguments()
  2910. };
  2911. marker.end();
  2912. marker.apply(expr);
  2913. } else if (match('[')) {
  2914. expr = {
  2915. type: Syntax.MemberExpression,
  2916. computed: true,
  2917. object: expr,
  2918. property: parseComputedMember()
  2919. };
  2920. marker.end();
  2921. marker.apply(expr);
  2922. } else {
  2923. expr = {
  2924. type: Syntax.MemberExpression,
  2925. computed: false,
  2926. object: expr,
  2927. property: parseNonComputedMember()
  2928. };
  2929. marker.end();
  2930. marker.apply(expr);
  2931. }
  2932. }
  2933. return expr;
  2934. }
  2935. function filterGroup(node) {
  2936. var n, i, entry;
  2937. n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {};
  2938. for (i in node) {
  2939. if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') {
  2940. entry = node[i];
  2941. if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) {
  2942. n[i] = entry;
  2943. } else {
  2944. n[i] = filterGroup(entry);
  2945. }
  2946. }
  2947. }
  2948. return n;
  2949. }
  2950. function wrapTrackingFunction(range, loc) {
  2951. return function (parseFunction) {
  2952. function isBinary(node) {
  2953. return node.type === Syntax.LogicalExpression ||
  2954. node.type === Syntax.BinaryExpression;
  2955. }
  2956. function visit(node) {
  2957. var start, end;
  2958. if (isBinary(node.left)) {
  2959. visit(node.left);
  2960. }
  2961. if (isBinary(node.right)) {
  2962. visit(node.right);
  2963. }
  2964. if (range) {
  2965. if (node.left.groupRange || node.right.groupRange) {
  2966. start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0];
  2967. end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1];
  2968. node.range = [start, end];
  2969. } else if (typeof node.range === 'undefined') {
  2970. start = node.left.range[0];
  2971. end = node.right.range[1];
  2972. node.range = [start, end];
  2973. }
  2974. }
  2975. if (loc) {
  2976. if (node.left.groupLoc || node.right.groupLoc) {
  2977. start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start;
  2978. end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end;
  2979. node.loc = {
  2980. start: start,
  2981. end: end
  2982. };
  2983. } else if (typeof node.loc === 'undefined') {
  2984. node.loc = {
  2985. start: node.left.loc.start,
  2986. end: node.right.loc.end
  2987. };
  2988. }
  2989. }
  2990. }
  2991. return function () {
  2992. var marker, node;
  2993. skipComment();
  2994. marker = createLocationMarker();
  2995. node = parseFunction.apply(null, arguments);
  2996. marker.end();
  2997. if (range && typeof node.range === 'undefined') {
  2998. marker.apply(node);
  2999. }
  3000. if (loc && typeof node.loc === 'undefined') {
  3001. marker.apply(node);
  3002. }
  3003. if (isBinary(node)) {
  3004. visit(node);
  3005. }
  3006. return node;
  3007. };
  3008. };
  3009. }
  3010. function patch() {
  3011. var wrapTracking;
  3012. if (extra.comments) {
  3013. extra.skipComment = skipComment;
  3014. skipComment = scanComment;
  3015. }
  3016. if (extra.raw) {
  3017. extra.createLiteral = createLiteral;
  3018. createLiteral = createRawLiteral;
  3019. }
  3020. if (extra.range || extra.loc) {
  3021. extra.parseGroupExpression = parseGroupExpression;
  3022. extra.parseLeftHandSideExpression = parseLeftHandSideExpression;
  3023. extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall;
  3024. parseGroupExpression = trackGroupExpression;
  3025. parseLeftHandSideExpression = trackLeftHandSideExpression;
  3026. parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall;
  3027. wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
  3028. extra.parseAdditiveExpression = parseAdditiveExpression;
  3029. extra.parseAssignmentExpression = parseAssignmentExpression;
  3030. extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
  3031. extra.parseBitwiseORExpression = parseBitwiseORExpression;
  3032. extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
  3033. extra.parseBlock = parseBlock;
  3034. extra.parseFunctionSourceElements = parseFunctionSourceElements;
  3035. extra.parseCatchClause = parseCatchClause;
  3036. extra.parseComputedMember = parseComputedMember;
  3037. extra.parseConditionalExpression = parseConditionalExpression;
  3038. extra.parseConstLetDeclaration = parseConstLetDeclaration;
  3039. extra.parseEqualityExpression = parseEqualityExpression;
  3040. extra.parseExpression = parseExpression;
  3041. extra.parseForVariableDeclaration = parseForVariableDeclaration;
  3042. extra.parseFunctionDeclaration = parseFunctionDeclaration;
  3043. extra.parseFunctionExpression = parseFunctionExpression;
  3044. extra.parseLogicalANDExpression = parseLogicalANDExpression;
  3045. extra.parseLogicalORExpression = parseLogicalORExpression;
  3046. extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
  3047. extra.parseNewExpression = parseNewExpression;
  3048. extra.parseNonComputedProperty = parseNonComputedProperty;
  3049. extra.parseObjectProperty = parseObjectProperty;
  3050. extra.parseObjectPropertyKey = parseObjectPropertyKey;
  3051. extra.parsePostfixExpression = parsePostfixExpression;
  3052. extra.parsePrimaryExpression = parsePrimaryExpression;
  3053. extra.parseProgram = parseProgram;
  3054. extra.parsePropertyFunction = parsePropertyFunction;
  3055. extra.parseRelationalExpression = parseRelationalExpression;
  3056. extra.parseStatement = parseStatement;
  3057. extra.parseShiftExpression = parseShiftExpression;
  3058. extra.parseSwitchCase = parseSwitchCase;
  3059. extra.parseUnaryExpression = parseUnaryExpression;
  3060. extra.parseVariableDeclaration = parseVariableDeclaration;
  3061. extra.parseVariableIdentifier = parseVariableIdentifier;
  3062. parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
  3063. parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
  3064. parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
  3065. parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
  3066. parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
  3067. parseBlock = wrapTracking(extra.parseBlock);
  3068. parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
  3069. parseCatchClause = wrapTracking(extra.parseCatchClause);
  3070. parseComputedMember = wrapTracking(extra.parseComputedMember);
  3071. parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
  3072. parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
  3073. parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
  3074. parseExpression = wrapTracking(extra.parseExpression);
  3075. parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
  3076. parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
  3077. parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
  3078. parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression);
  3079. parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
  3080. parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
  3081. parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
  3082. parseNewExpression = wrapTracking(extra.parseNewExpression);
  3083. parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
  3084. parseObjectProperty = wrapTracking(extra.parseObjectProperty);
  3085. parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
  3086. parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
  3087. parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
  3088. parseProgram = wrapTracking(extra.parseProgram);
  3089. parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
  3090. parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
  3091. parseStatement = wrapTracking(extra.parseStatement);
  3092. parseShiftExpression = wrapTracking(extra.parseShiftExpression);
  3093. parseSwitchCase = wrapTracking(extra.parseSwitchCase);
  3094. parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
  3095. parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
  3096. parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
  3097. }
  3098. if (typeof extra.tokens !== 'undefined') {
  3099. extra.advance = advance;
  3100. extra.scanRegExp = scanRegExp;
  3101. advance = collectToken;
  3102. scanRegExp = collectRegex;
  3103. }
  3104. }
  3105. function unpatch() {
  3106. if (typeof extra.skipComment === 'function') {
  3107. skipComment = extra.skipComment;
  3108. }
  3109. if (extra.raw) {
  3110. createLiteral = extra.createLiteral;
  3111. }
  3112. if (extra.range || extra.loc) {
  3113. parseAdditiveExpression = extra.parseAdditiveExpression;
  3114. parseAssignmentExpression = extra.parseAssignmentExpression;
  3115. parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
  3116. parseBitwiseORExpression = extra.parseBitwiseORExpression;
  3117. parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
  3118. parseBlock = extra.parseBlock;
  3119. parseFunctionSourceElements = extra.parseFunctionSourceElements;
  3120. parseCatchClause = extra.parseCatchClause;
  3121. parseComputedMember = extra.parseComputedMember;
  3122. parseConditionalExpression = extra.parseConditionalExpression;
  3123. parseConstLetDeclaration = extra.parseConstLetDeclaration;
  3124. parseEqualityExpression = extra.parseEqualityExpression;
  3125. parseExpression = extra.parseExpression;
  3126. parseForVariableDeclaration = extra.parseForVariableDeclaration;
  3127. parseFunctionDeclaration = extra.parseFunctionDeclaration;
  3128. parseFunctionExpression = extra.parseFunctionExpression;
  3129. parseGroupExpression = extra.parseGroupExpression;
  3130. parseLeftHandSideExpression = extra.parseLeftHandSideExpression;
  3131. parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall;
  3132. parseLogicalANDExpression = extra.parseLogicalANDExpression;
  3133. parseLogicalORExpression = extra.parseLogicalORExpression;
  3134. parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
  3135. parseNewExpression = extra.parseNewExpression;
  3136. parseNonComputedProperty = extra.parseNonComputedProperty;
  3137. parseObjectProperty = extra.parseObjectProperty;
  3138. parseObjectPropertyKey = extra.parseObjectPropertyKey;
  3139. parsePrimaryExpression = extra.parsePrimaryExpression;
  3140. parsePostfixExpression = extra.parsePostfixExpression;
  3141. parseProgram = extra.parseProgram;
  3142. parsePropertyFunction = extra.parsePropertyFunction;
  3143. parseRelationalExpression = extra.parseRelationalExpression;
  3144. parseStatement = extra.parseStatement;
  3145. parseShiftExpression = extra.parseShiftExpression;
  3146. parseSwitchCase = extra.parseSwitchCase;
  3147. parseUnaryExpression = extra.parseUnaryExpression;
  3148. parseVariableDeclaration = extra.parseVariableDeclaration;
  3149. parseVariableIdentifier = extra.parseVariableIdentifier;
  3150. }
  3151. if (typeof extra.scanRegExp === 'function') {
  3152. advance = extra.advance;
  3153. scanRegExp = extra.scanRegExp;
  3154. }
  3155. }
  3156. function stringToArray(str) {
  3157. var length = str.length,
  3158. result = [],
  3159. i;
  3160. for (i = 0; i < length; ++i) {
  3161. result[i] = str.charAt(i);
  3162. }
  3163. return result;
  3164. }
  3165. function parse(code, options) {
  3166. var program, toString;
  3167. toString = String;
  3168. if (typeof code !== 'string' && !(code instanceof String)) {
  3169. code = toString(code);
  3170. }
  3171. source = code;
  3172. index = 0;
  3173. lineNumber = (source.length > 0) ? 1 : 0;
  3174. lineStart = 0;
  3175. length = source.length;
  3176. buffer = null;
  3177. state = {
  3178. allowIn: true,
  3179. labelSet: {},
  3180. inFunctionBody: false,
  3181. inIteration: false,
  3182. inSwitch: false
  3183. };
  3184. extra = {};
  3185. if (typeof options !== 'undefined') {
  3186. extra.range = (typeof options.range === 'boolean') && options.range;
  3187. extra.loc = (typeof options.loc === 'boolean') && options.loc;
  3188. extra.raw = (typeof options.raw === 'boolean') && options.raw;
  3189. if (typeof options.tokens === 'boolean' && options.tokens) {
  3190. extra.tokens = [];
  3191. }
  3192. if (typeof options.comment === 'boolean' && options.comment) {
  3193. extra.comments = [];
  3194. }
  3195. if (typeof options.tolerant === 'boolean' && options.tolerant) {
  3196. extra.errors = [];
  3197. }
  3198. }
  3199. if (length > 0) {
  3200. if (typeof source[0] === 'undefined') {
  3201. // Try first to convert to a string. This is good as fast path
  3202. // for old IE which understands string indexing for string
  3203. // literals only and not for string object.
  3204. if (code instanceof String) {
  3205. source = code.valueOf();
  3206. }
  3207. // Force accessing the characters via an array.
  3208. if (typeof source[0] === 'undefined') {
  3209. source = stringToArray(code);
  3210. }
  3211. }
  3212. }
  3213. patch();
  3214. try {
  3215. program = parseProgram();
  3216. if (typeof extra.comments !== 'undefined') {
  3217. filterCommentLocation();
  3218. program.comments = extra.comments;
  3219. }
  3220. if (typeof extra.tokens !== 'undefined') {
  3221. filterTokenLocation();
  3222. program.tokens = extra.tokens;
  3223. }
  3224. if (typeof extra.errors !== 'undefined') {
  3225. program.errors = extra.errors;
  3226. }
  3227. if (extra.range || extra.loc) {
  3228. program.body = filterGroup(program.body);
  3229. }
  3230. } catch (e) {
  3231. throw e;
  3232. } finally {
  3233. unpatch();
  3234. extra = {};
  3235. }
  3236. return program;
  3237. }
  3238. // Sync with package.json.
  3239. exports.version = '1.0.2';
  3240. exports.parse = parse;
  3241. // Deep copy.
  3242. exports.Syntax = (function () {
  3243. var name, types = {};
  3244. if (typeof Object.create === 'function') {
  3245. types = Object.create(null);
  3246. }
  3247. for (name in Syntax) {
  3248. if (Syntax.hasOwnProperty(name)) {
  3249. types[name] = Syntax[name];
  3250. }
  3251. }
  3252. if (typeof Object.freeze === 'function') {
  3253. Object.freeze(types);
  3254. }
  3255. return types;
  3256. }());
  3257. }));
  3258. /* vim: set sw=4 ts=4 et tw=80 : */
  3259. })(null);
  3260. (function(require,module){
  3261. var parse = require('esprima').parse;
  3262. var objectKeys = Object.keys || function (obj) {
  3263. var keys = [];
  3264. for (var key in obj) keys.push(key);
  3265. return keys;
  3266. };
  3267. var forEach = function (xs, fn) {
  3268. if (xs.forEach) return xs.forEach(fn);
  3269. for (var i = 0; i < xs.length; i++) {
  3270. fn.call(xs, xs[i], i, xs);
  3271. }
  3272. };
  3273. var isArray = Array.isArray || function (xs) {
  3274. return Object.prototype.toString.call(xs) === '[object Array]';
  3275. };
  3276. module.exports = function (src, opts, fn) {
  3277. if (typeof opts === 'function') {
  3278. fn = opts;
  3279. opts = {};
  3280. }
  3281. if (typeof src === 'object') {
  3282. opts = src;
  3283. src = opts.source;
  3284. delete opts.source;
  3285. }
  3286. src = src === undefined ? opts.source : src;
  3287. opts.range = true;
  3288. if (typeof src !== 'string') src = String(src);
  3289. var ast = parse(src, opts);
  3290. var result = {
  3291. chunks : src.split(''),
  3292. toString : function () { return result.chunks.join('') },
  3293. inspect : function () { return result.toString() }
  3294. };
  3295. var index = 0;
  3296. (function walk (node, parent) {
  3297. insertHelpers(node, parent, result.chunks);
  3298. forEach(objectKeys(node), function (key) {
  3299. if (key === 'parent') return;
  3300. var child = node[key];
  3301. if (isArray(child)) {
  3302. forEach(child, function (c) {
  3303. if (c && typeof c.type === 'string') {
  3304. walk(c, node);
  3305. }
  3306. });
  3307. }
  3308. else if (child && typeof child.type === 'string') {
  3309. insertHelpers(child, node, result.chunks);
  3310. walk(child, node);
  3311. }
  3312. });
  3313. fn(node);
  3314. })(ast, undefined);
  3315. return result;
  3316. };
  3317. function insertHelpers (node, parent, chunks) {
  3318. if (!node.range) return;
  3319. node.parent = parent;
  3320. node.source = function () {
  3321. return chunks.slice(
  3322. node.range[0], node.range[1]
  3323. ).join('');
  3324. };
  3325. if (node.update && typeof node.update === 'object') {
  3326. var prev = node.update;
  3327. forEach(objectKeys(prev), function (key) {
  3328. update[key] = prev[key];
  3329. });
  3330. node.update = update;
  3331. }
  3332. else {
  3333. node.update = update;
  3334. }
  3335. function update (s) {
  3336. chunks[node.range[0]] = s;
  3337. for (var i = node.range[0] + 1; i < node.range[1]; i++) {
  3338. chunks[i] = '';
  3339. }
  3340. };
  3341. }
  3342. window.falafel = module.exports;})(function(){return {parse: esprima.parse};},{exports: {}});
  3343. var inBrowser = typeof window !== 'undefined' && this === window;
  3344. var parseAndModify = (inBrowser ? window.falafel : require("falafel"));
  3345. (inBrowser ? window : exports).blanket = (function(){
  3346. var linesToAddTracking = [
  3347. "ExpressionStatement",
  3348. "BreakStatement" ,
  3349. "ContinueStatement" ,
  3350. "VariableDeclaration",
  3351. "ReturnStatement" ,
  3352. "ThrowStatement" ,
  3353. "TryStatement" ,
  3354. "FunctionDeclaration" ,
  3355. "IfStatement" ,
  3356. "WhileStatement" ,
  3357. "DoWhileStatement" ,
  3358. "ForStatement" ,
  3359. "ForInStatement" ,
  3360. "SwitchStatement" ,
  3361. "WithStatement"
  3362. ],
  3363. linesToAddBrackets = [
  3364. "IfStatement" ,
  3365. "WhileStatement" ,
  3366. "DoWhileStatement" ,
  3367. "ForStatement" ,
  3368. "ForInStatement" ,
  3369. "WithStatement"
  3370. ],
  3371. __blanket,
  3372. copynumber = Math.floor(Math.random()*1000),
  3373. coverageInfo = {},options = {
  3374. reporter: null,
  3375. adapter:null,
  3376. filter: null,
  3377. customVariable: null,
  3378. orderedLoading: true,
  3379. loader: null,
  3380. ignoreScriptError: false,
  3381. existingRequireJS:false,
  3382. autoStart: false,
  3383. timeout: 180,
  3384. ignoreCors: false,
  3385. branchTracking: false,
  3386. sourceURL: false,
  3387. debug:false,
  3388. engineOnly:false,
  3389. testReadyCallback:null,
  3390. commonJS:false,
  3391. instrumentCache:false
  3392. };
  3393. if (inBrowser && typeof window.blanket !== 'undefined'){
  3394. __blanket = window.blanket.noConflict();
  3395. }
  3396. _blanket = {
  3397. noConflict: function(){
  3398. if (__blanket){
  3399. return __blanket;
  3400. }
  3401. return _blanket;
  3402. },
  3403. _getCopyNumber: function(){
  3404. //internal method
  3405. //for differentiating between instances
  3406. return copynumber;
  3407. },
  3408. extend: function(obj) {
  3409. //borrowed from underscore
  3410. _blanket._extend(_blanket,obj);
  3411. },
  3412. _extend: function(dest,source){
  3413. if (source) {
  3414. for (var prop in source) {
  3415. if ( dest[prop] instanceof Object && typeof dest[prop] !== "function"){
  3416. _blanket._extend(dest[prop],source[prop]);
  3417. }else{
  3418. dest[prop] = source[prop];
  3419. }
  3420. }
  3421. }
  3422. },
  3423. getCovVar: function(){
  3424. var opt = _blanket.options("customVariable");
  3425. if (opt){
  3426. if (_blanket.options("debug")) {console.log("BLANKET-Using custom tracking variable:",opt);}
  3427. return inBrowser ? "window."+opt : opt;
  3428. }
  3429. return inBrowser ? "window._$blanket" : "_$jscoverage";
  3430. },
  3431. options: function(key,value){
  3432. if (typeof key !== "string"){
  3433. _blanket._extend(options,key);
  3434. }else if (typeof value === 'undefined'){
  3435. return options[key];
  3436. }else{
  3437. options[key]=value;
  3438. }
  3439. },
  3440. instrument: function(config, next){
  3441. //check instrumented hash table,
  3442. //return instrumented code if available.
  3443. var inFile = config.inputFile,
  3444. inFileName = config.inputFileName;
  3445. //check instrument cache
  3446. if (_blanket.options("instrumentCache") && sessionStorage && sessionStorage.getItem("blanket_instrument_store-"+inFileName)){
  3447. if (_blanket.options("debug")) {console.log("BLANKET-Reading instrumentation from cache: ",inFileName);}
  3448. next(sessionStorage.getItem("blanket_instrument_store-"+inFileName));
  3449. }else{
  3450. var sourceArray = _blanket._prepareSource(inFile);
  3451. _blanket._trackingArraySetup=[];
  3452. var instrumented = parseAndModify(inFile,{loc:true,comment:true}, _blanket._addTracking(inFileName));
  3453. instrumented = _blanket._trackingSetup(inFileName,sourceArray)+instrumented;
  3454. if (_blanket.options("sourceURL")){
  3455. instrumented += "\n//@ sourceURL="+inFileName.replace("http://","");
  3456. }
  3457. if (_blanket.options("debug")) {console.log("BLANKET-Instrumented file: ",inFileName);}
  3458. if (_blanket.options("instrumentCache") && sessionStorage){
  3459. if (_blanket.options("debug")) {console.log("BLANKET-Saving instrumentation to cache: ",inFileName);}
  3460. sessionStorage.setItem("blanket_instrument_store-"+inFileName,instrumented);
  3461. }
  3462. next(instrumented);
  3463. }
  3464. },
  3465. _trackingArraySetup: [],
  3466. _branchingArraySetup: [],
  3467. _prepareSource: function(source){
  3468. return source.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/(\r\n|\n|\r)/gm,"\n").split('\n');
  3469. },
  3470. _trackingSetup: function(filename,sourceArray){
  3471. var branches = _blanket.options("branchTracking");
  3472. var sourceString = sourceArray.join("',\n'");
  3473. var intro = "";
  3474. var covVar = _blanket.getCovVar();
  3475. intro += "if (typeof "+covVar+" === 'undefined') "+covVar+" = {};\n";
  3476. if (branches){
  3477. intro += "var _$branchFcn=function(f,l,c,r){ ";
  3478. intro += "if (!!r) { ";
  3479. intro += covVar+"[f].branchData[l][c][0] = "+covVar+"[f].branchData[l][c][0] || [];";
  3480. intro += covVar+"[f].branchData[l][c][0].push(r); }";
  3481. intro += "else { ";
  3482. intro += covVar+"[f].branchData[l][c][1] = "+covVar+"[f].branchData[l][c][1] || [];";
  3483. intro += covVar+"[f].branchData[l][c][1].push(r); }";
  3484. intro += "return r;};\n";
  3485. }
  3486. intro += "if (typeof "+covVar+"['"+filename+"'] === 'undefined'){";
  3487. intro += covVar+"['"+filename+"']=[];\n";
  3488. if (branches){
  3489. intro += covVar+"['"+filename+"'].branchData=[];\n";
  3490. }
  3491. intro += covVar+"['"+filename+"'].source=['"+sourceString+"'];\n";
  3492. //initialize array values
  3493. _blanket._trackingArraySetup.sort(function(a,b){
  3494. return parseInt(a,10) > parseInt(b,10);
  3495. }).forEach(function(item){
  3496. intro += covVar+"['"+filename+"']["+item+"]=0;\n";
  3497. });
  3498. if (branches){
  3499. _blanket._branchingArraySetup.sort(function(a,b){
  3500. return a.line > b.line;
  3501. }).sort(function(a,b){
  3502. return a.column > b.column;
  3503. }).forEach(function(item){
  3504. if (item.file === filename){
  3505. intro += "if (typeof "+ covVar+"['"+filename+"'].branchData["+item.line+"] === 'undefined'){\n";
  3506. intro += covVar+"['"+filename+"'].branchData["+item.line+"]=[];\n";
  3507. intro += "}";
  3508. intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"] = [];\n";
  3509. intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"].consequent = "+JSON.stringify(item.consequent)+";\n";
  3510. intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"].alternate = "+JSON.stringify(item.alternate)+";\n";
  3511. }
  3512. });
  3513. }
  3514. intro += "}";
  3515. return intro;
  3516. },
  3517. _blockifyIf: function(node){
  3518. if (linesToAddBrackets.indexOf(node.type) > -1){
  3519. var bracketsExistObject = node.consequent || node.body;
  3520. var bracketsExistAlt = node.alternate;
  3521. if( bracketsExistAlt && bracketsExistAlt.type !== "BlockStatement") {
  3522. bracketsExistAlt.update("{\n"+bracketsExistAlt.source()+"}\n");
  3523. }
  3524. if( bracketsExistObject && bracketsExistObject.type !== "BlockStatement") {
  3525. bracketsExistObject.update("{\n"+bracketsExistObject.source()+"}\n");
  3526. }
  3527. }
  3528. },
  3529. _trackBranch: function(node,filename){
  3530. //recursive on consequent and alternative
  3531. var line = node.loc.start.line;
  3532. var col = node.loc.start.column;
  3533. _blanket._branchingArraySetup.push({
  3534. line: line,
  3535. column: col,
  3536. file:filename,
  3537. consequent: node.consequent.loc,
  3538. alternate: node.alternate.loc
  3539. });
  3540. var source = node.source();
  3541. var updated = "_$branchFcn"+
  3542. "('"+filename+"',"+line+","+col+","+source.slice(0,source.indexOf("?"))+
  3543. ")"+source.slice(source.indexOf("?"));
  3544. node.update(updated);
  3545. },
  3546. _addTracking: function (filename) {
  3547. //falafel doesn't take a file name
  3548. //so we include the filename in a closure
  3549. //and return the function to falafel
  3550. var covVar = _blanket.getCovVar();
  3551. return function(node){
  3552. _blanket._blockifyIf(node);
  3553. if (linesToAddTracking.indexOf(node.type) > -1 && node.parent.type !== "LabeledStatement") {
  3554. _blanket._checkDefs(node,filename);
  3555. if (node.type === "VariableDeclaration" &&
  3556. (node.parent.type === "ForStatement" || node.parent.type === "ForInStatement")){
  3557. return;
  3558. }
  3559. if (node.loc && node.loc.start){
  3560. node.update(covVar+"['"+filename+"']["+node.loc.start.line+"]++;\n"+node.source());
  3561. _blanket._trackingArraySetup.push(node.loc.start.line);
  3562. }else{
  3563. //I don't think we can handle a node with no location
  3564. throw new Error("The instrumenter encountered a node with no location: "+Object.keys(node));
  3565. }
  3566. }else if (_blanket.options("branchTracking") && node.type === "ConditionalExpression"){
  3567. _blanket._trackBranch(node,filename);
  3568. }
  3569. };
  3570. },
  3571. _checkDefs: function(node,filename){
  3572. // Make sure developers don't redefine window. if they do, inform them it is wrong.
  3573. if (inBrowser){
  3574. if (node.type === "VariableDeclaration" && node.declarations) {
  3575. node.declarations.forEach(function(declaration) {
  3576. if (declaration.id.name === "window") {
  3577. throw new Error("Instrumentation error, you cannot redefine the 'window' variable in " + filename + ":" + node.loc.start.line);
  3578. }
  3579. });
  3580. }
  3581. if (node.type === "FunctionDeclaration" && node.params) {
  3582. node.params.forEach(function(param) {
  3583. if (param.name === "window") {
  3584. throw new Error("Instrumentation error, you cannot redefine the 'window' variable in " + filename + ":" + node.loc.start.line);
  3585. }
  3586. });
  3587. }
  3588. //Make sure developers don't redefine the coverage variable
  3589. if (node.type === "ExpressionStatement" &&
  3590. node.expression && node.expression.left &&
  3591. node.expression.left.object && node.expression.left.property &&
  3592. node.expression.left.object.name +
  3593. "." + node.expression.left.property.name === _blanket.getCovVar()) {
  3594. throw new Error("Instrumentation error, you cannot redefine the coverage variable in " + filename + ":" + node.loc.start.line);
  3595. }
  3596. }else{
  3597. //Make sure developers don't redefine the coverage variable in node
  3598. if (node.type === "ExpressionStatement" &&
  3599. node.expression && node.expression.left &&
  3600. !node.expression.left.object && !node.expression.left.property &&
  3601. node.expression.left.name === _blanket.getCovVar()) {
  3602. throw new Error("Instrumentation error, you cannot redefine the coverage variable in " + filename + ":" + node.loc.start.line);
  3603. }
  3604. }
  3605. },
  3606. setupCoverage: function(){
  3607. coverageInfo.instrumentation = "blanket";
  3608. coverageInfo.stats = {
  3609. "suites": 0,
  3610. "tests": 0,
  3611. "passes": 0,
  3612. "pending": 0,
  3613. "failures": 0,
  3614. "start": new Date()
  3615. };
  3616. },
  3617. _checkIfSetup: function(){
  3618. if (!coverageInfo.stats){
  3619. throw new Error("You must call blanket.setupCoverage() first.");
  3620. }
  3621. },
  3622. onTestStart: function(){
  3623. if (_blanket.options("debug")) {console.log("BLANKET-Test event started");}
  3624. this._checkIfSetup();
  3625. coverageInfo.stats.tests++;
  3626. coverageInfo.stats.pending++;
  3627. },
  3628. onTestDone: function(total,passed){
  3629. this._checkIfSetup();
  3630. if(passed === total){
  3631. coverageInfo.stats.passes++;
  3632. }else{
  3633. coverageInfo.stats.failures++;
  3634. }
  3635. coverageInfo.stats.pending--;
  3636. },
  3637. onModuleStart: function(){
  3638. this._checkIfSetup();
  3639. coverageInfo.stats.suites++;
  3640. },
  3641. onTestsDone: function(){
  3642. if (_blanket.options("debug")) {console.log("BLANKET-Test event done");}
  3643. this._checkIfSetup();
  3644. coverageInfo.stats.end = new Date();
  3645. if (inBrowser){
  3646. this.report(coverageInfo);
  3647. }else{
  3648. if (!_blanket.options("branchTracking")){
  3649. delete (inBrowser ? window : global)[_blanket.getCovVar()].branchFcn;
  3650. }
  3651. this.options("reporter").call(this,coverageInfo);
  3652. }
  3653. }
  3654. };
  3655. return _blanket;
  3656. })();
  3657. (function(_blanket){
  3658. var oldOptions = _blanket.options;
  3659. _blanket.extend({
  3660. outstandingRequireFiles:[],
  3661. options: function(key,value){
  3662. var newVal={};
  3663. if (typeof key !== "string"){
  3664. //key is key/value map
  3665. oldOptions(key);
  3666. newVal = key;
  3667. }else if (typeof value === 'undefined'){
  3668. //accessor
  3669. return oldOptions(key);
  3670. }else{
  3671. //setter
  3672. oldOptions(key,value);
  3673. newVal[key] = value;
  3674. }
  3675. if (newVal.adapter){
  3676. _blanket._loadFile(newVal.adapter);
  3677. }
  3678. if (newVal.loader){
  3679. _blanket._loadFile(newVal.loader);
  3680. }
  3681. },
  3682. requiringFile: function(filename,done){
  3683. if (typeof filename === "undefined"){
  3684. _blanket.outstandingRequireFiles=[];
  3685. }else if (typeof done === "undefined"){
  3686. _blanket.outstandingRequireFiles.push(filename);
  3687. }else{
  3688. _blanket.outstandingRequireFiles.splice(_blanket.outstandingRequireFiles.indexOf(filename),1);
  3689. }
  3690. },
  3691. requireFilesLoaded: function(){
  3692. return _blanket.outstandingRequireFiles.length === 0;
  3693. },
  3694. showManualLoader: function(){
  3695. if (document.getElementById("blanketLoaderDialog")){
  3696. return;
  3697. }
  3698. //copied from http://blog.avtex.com/2012/01/26/cross-browser-css-only-modal-box/
  3699. var loader = "<div class='blanketDialogOverlay'>";
  3700. loader += "&nbsp;</div>";
  3701. loader += "<div class='blanketDialogVerticalOffset'>";
  3702. loader += "<div class='blanketDialogBox'>";
  3703. loader += "<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files. ";
  3704. loader += "<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). ";
  3705. loader += "<br><br>Some solutions include <a href='http://askubuntu.com/questions/160245/making-google-chrome-option-allow-file-access-from-files-permanent' target='_blank'>starting Chrome with special flags</a>, <a target='_blank' href='https://github.com/remy/servedir'>running a server locally</a>, or using a browser without these CORS restrictions (Safari).";
  3706. loader += "<br>";
  3707. if (typeof FileReader !== "undefined"){
  3708. loader += "<br>Or, try the experimental loader. When prompted, simply click on the directory containing all the source files you want covered.";
  3709. loader += "<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>";
  3710. loader += "<input type='file' type='application/x-javascript' accept='application/x-javascript' webkitdirectory id='fileInput' multiple onchange='window.blanket.manualFileLoader(this.files)' style='visibility:hidden;position:absolute;top:-50;left:-50'/>";
  3711. }
  3712. loader += "<br><span style='float:right;cursor:pointer;' onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>";
  3713. loader += "<div style='clear:both'></div>";
  3714. loader += "</div></div>";
  3715. var css = ".blanketDialogWrapper {";
  3716. css += "display:block;";
  3717. css += "position:fixed;";
  3718. css += "z-index:40001; }";
  3719. css += ".blanketDialogOverlay {";
  3720. css += "position:fixed;";
  3721. css += "width:100%;";
  3722. css += "height:100%;";
  3723. css += "background-color:black;";
  3724. css += "opacity:.5; ";
  3725. css += "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ";
  3726. css += "filter:alpha(opacity=50); ";
  3727. css += "z-index:40001; }";
  3728. css += ".blanketDialogVerticalOffset { ";
  3729. css += "position:fixed;";
  3730. css += "top:30%;";
  3731. css += "width:100%;";
  3732. css += "z-index:40002; }";
  3733. css += ".blanketDialogBox { ";
  3734. css += "width:405px; ";
  3735. css += "position:relative;";
  3736. css += "margin:0 auto;";
  3737. css += "background-color:white;";
  3738. css += "padding:10px;";
  3739. css += "border:1px solid black; }";
  3740. var dom = document.createElement("style");
  3741. dom.innerHTML = css;
  3742. document.head.appendChild(dom);
  3743. var div = document.createElement("div");
  3744. div.id = "blanketLoaderDialog";
  3745. div.className = "blanketDialogWrapper";
  3746. div.innerHTML = loader;
  3747. document.body.insertBefore(div,document.body.firstChild);
  3748. },
  3749. manualFileLoader: function(files){
  3750. var toArray =Array.prototype.slice;
  3751. files = toArray.call(files).filter(function(item){
  3752. return item.type !== "";
  3753. });
  3754. var sessionLength = files.length-1;
  3755. var sessionIndx=0;
  3756. var sessionArray = {};
  3757. if (sessionStorage["blanketSessionLoader"]){
  3758. sessionArray = JSON.parse(sessionStorage["blanketSessionLoader"]);
  3759. }
  3760. var fileLoader = function(event){
  3761. var fileContent = event.currentTarget.result;
  3762. var file = files[sessionIndx];
  3763. var filename = file.webkitRelativePath && file.webkitRelativePath !== '' ? file.webkitRelativePath : file.name;
  3764. sessionArray[filename] = fileContent;
  3765. sessionIndx++;
  3766. if (sessionIndx === sessionLength){
  3767. sessionStorage.setItem("blanketSessionLoader", JSON.stringify(sessionArray));
  3768. document.location.reload();
  3769. }else{
  3770. readFile(files[sessionIndx]);
  3771. }
  3772. };
  3773. function readFile(file){
  3774. var reader = new FileReader();
  3775. reader.onload = fileLoader;
  3776. reader.readAsText(file);
  3777. }
  3778. readFile(files[sessionIndx]);
  3779. },
  3780. _loadFile: function(path){
  3781. if (typeof path !== "undefined"){
  3782. var request = new XMLHttpRequest();
  3783. request.open('GET', path, false);
  3784. request.send();
  3785. var script = document.createElement("script");
  3786. script.type = "text/javascript";
  3787. script.text = request.responseText;
  3788. (document.body || document.getElementsByTagName('head')[0]).appendChild(script);
  3789. }
  3790. },
  3791. hasAdapter: function(callback){
  3792. return _blanket.options("adapter") !== null;
  3793. },
  3794. report: function(coverage_data){
  3795. if (!document.getElementById("blanketLoaderDialog")){
  3796. //all found, clear it
  3797. _blanket.blanketSession = null;
  3798. }
  3799. coverage_data.files = window._$blanket;
  3800. var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
  3801. // Check if we have any covered files that requires reporting
  3802. // otherwise just exit gracefully.
  3803. if (!coverage_data.files || !Object.keys(coverage_data.files).length) {
  3804. if (_blanket.options("debug")) {console.log("BLANKET-Reporting No files were instrumented.");}
  3805. return;
  3806. }
  3807. if (typeof coverage_data.files.branchFcn !== "undefined"){
  3808. delete coverage_data.files.branchFcn;
  3809. }
  3810. if (typeof _blanket.options("reporter") === "string"){
  3811. require([_blanket.options("reporter").replace(".js","")],function(r){
  3812. r(coverage_data,_blanket.options("reporter_options"));
  3813. });
  3814. }else if (typeof _blanket.options("reporter") === "function"){
  3815. _blanket.options("reporter")(coverage_data);
  3816. }else if (typeof _blanket.defaultReporter === 'function'){
  3817. _blanket.defaultReporter(coverage_data);
  3818. }else{
  3819. throw new Error("no reporter defined.");
  3820. }
  3821. },
  3822. _bindStartTestRunner: function(bindEvent,startEvent){
  3823. if (bindEvent){
  3824. bindEvent(startEvent);
  3825. }else{
  3826. window.addEventListener("load",startEvent,false);
  3827. }
  3828. },
  3829. _loadSourceFiles: function(callback){
  3830. console.log("ls1:"+new Date().getTime());
  3831. var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
  3832. function copy(o){
  3833. var _copy = Object.create( Object.getPrototypeOf(o) );
  3834. var propNames = Object.getOwnPropertyNames(o);
  3835. propNames.forEach(function(name){
  3836. var desc = Object.getOwnPropertyDescriptor(o, name);
  3837. Object.defineProperty(_copy, name, desc);
  3838. });
  3839. return _copy;
  3840. }
  3841. if (_blanket.options("debug")) {console.log("BLANKET-Collecting page scripts");}
  3842. var scripts = _blanket.utils.collectPageScripts();
  3843. //_blanket.options("filter",scripts);
  3844. if (scripts.length === 0){
  3845. callback();
  3846. }else{
  3847. //check session state
  3848. if (sessionStorage["blanketSessionLoader"]){
  3849. _blanket.blanketSession = JSON.parse(sessionStorage["blanketSessionLoader"]);
  3850. }
  3851. var requireConfig = {
  3852. paths: {},
  3853. shim: {},
  3854. waitSeconds: _blanket.options("timeout")
  3855. };
  3856. var lastDep = {
  3857. deps: []
  3858. };
  3859. var isOrdered = _blanket.options("orderedLoading");
  3860. var initialGet=[];
  3861. scripts.forEach(function(file,indx){
  3862. //for whatever reason requirejs
  3863. //prefers when we don't use the full path
  3864. //so we just use a custom name
  3865. var requireKey = "blanket_"+indx;
  3866. initialGet.push(requireKey);
  3867. requireConfig.paths[requireKey] = file;
  3868. if (isOrdered){
  3869. if (indx > 0){
  3870. requireConfig.shim[requireKey] = copy(lastDep);
  3871. }
  3872. lastDep.deps = [requireKey];
  3873. }
  3874. });
  3875. require.config(requireConfig);
  3876. var filt = initialGet;
  3877. require(filt, function(){
  3878. callback();
  3879. });
  3880. }
  3881. console.log("ls2:"+new Date().getTime());
  3882. },
  3883. beforeStartTestRunner: function(opts){
  3884. opts = opts || {};
  3885. opts.checkRequirejs = typeof opts.checkRequirejs === "undefined" ? true : opts.checkRequirejs;
  3886. opts.callback = opts.callback || function() { };
  3887. opts.coverage = typeof opts.coverage === "undefined" ? true : opts.coverage;
  3888. if (opts.coverage) {
  3889. _blanket._bindStartTestRunner(opts.bindEvent,
  3890. function(){
  3891. _blanket._loadSourceFiles(function() {
  3892. var allLoaded = function(){
  3893. return opts.condition ? opts.condition() : _blanket.requireFilesLoaded();
  3894. };
  3895. var check = function() {
  3896. if (allLoaded()) {
  3897. if (_blanket.options("debug")) {console.log("BLANKET-All files loaded, init start test runner callback.");}
  3898. var cb = _blanket.options("testReadyCallback");
  3899. if (cb){
  3900. if (typeof cb === "function"){
  3901. cb(opts.callback);
  3902. }else if (typeof cb === "string"){
  3903. eval(cb);
  3904. opts.callback();
  3905. }
  3906. }else{
  3907. opts.callback();
  3908. }
  3909. } else {
  3910. setTimeout(check, 13);
  3911. }
  3912. };
  3913. check();
  3914. });
  3915. });
  3916. }else{
  3917. opts.callback();
  3918. }
  3919. },
  3920. utils: {
  3921. qualifyURL: function (url) {
  3922. //http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
  3923. var a = document.createElement('a');
  3924. a.href = url;
  3925. return a.href;
  3926. }
  3927. }
  3928. });
  3929. })(blanket);
  3930. blanket.setupRequireJS=function(context){
  3931. /** vim: et:ts=4:sw=4:sts=4
  3932. * @license RequireJS 2.1.4 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
  3933. * Available via the MIT or new BSD license.
  3934. * see: http://github.com/jrburke/requirejs for details
  3935. */
  3936. //Not using strict: uneven strict support in browsers, #392, and causes
  3937. //problems with requirejs.exec()/transpiler plugins that may not be strict.
  3938. /*jslint regexp: true, nomen: true, sloppy: true */
  3939. /*global window, navigator, document, importScripts, setTimeout, opera */
  3940. var requirejs, require, define;
  3941. (function (global) {
  3942. var req, s, head, baseElement, dataMain, src,
  3943. interactiveScript, currentlyAddingScript, mainScript, subPath,
  3944. version = '2.1.4',
  3945. commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
  3946. cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
  3947. jsSuffixRegExp = /\.js$/,
  3948. currDirRegExp = /^\.\//,
  3949. op = Object.prototype,
  3950. ostring = op.toString,
  3951. hasOwn = op.hasOwnProperty,
  3952. ap = Array.prototype,
  3953. apsp = ap.splice,
  3954. isBrowser = !!(typeof window !== 'undefined' && navigator && document),
  3955. isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
  3956. //PS3 indicates loaded and complete, but need to wait for complete
  3957. //specifically. Sequence is 'loading', 'loaded', execution,
  3958. // then 'complete'. The UA check is unfortunate, but not sure how
  3959. //to feature test w/o causing perf issues.
  3960. readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
  3961. /^complete$/ : /^(complete|loaded)$/,
  3962. defContextName = '_',
  3963. //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
  3964. isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
  3965. contexts = {},
  3966. cfg = {},
  3967. globalDefQueue = [],
  3968. useInteractive = false;
  3969. function isFunction(it) {
  3970. return ostring.call(it) === '[object Function]';
  3971. }
  3972. function isArray(it) {
  3973. return ostring.call(it) === '[object Array]';
  3974. }
  3975. /**
  3976. * Helper function for iterating over an array. If the func returns
  3977. * a true value, it will break out of the loop.
  3978. */
  3979. function each(ary, func) {
  3980. if (ary) {
  3981. var i;
  3982. for (i = 0; i < ary.length; i += 1) {
  3983. if (ary[i] && func(ary[i], i, ary)) {
  3984. break;
  3985. }
  3986. }
  3987. }
  3988. }
  3989. /**
  3990. * Helper function for iterating over an array backwards. If the func
  3991. * returns a true value, it will break out of the loop.
  3992. */
  3993. function eachReverse(ary, func) {
  3994. if (ary) {
  3995. var i;
  3996. for (i = ary.length - 1; i > -1; i -= 1) {
  3997. if (ary[i] && func(ary[i], i, ary)) {
  3998. break;
  3999. }
  4000. }
  4001. }
  4002. }
  4003. function hasProp(obj, prop) {
  4004. return hasOwn.call(obj, prop);
  4005. }
  4006. function getOwn(obj, prop) {
  4007. return hasProp(obj, prop) && obj[prop];
  4008. }
  4009. /**
  4010. * Cycles over properties in an object and calls a function for each
  4011. * property value. If the function returns a truthy value, then the
  4012. * iteration is stopped.
  4013. */
  4014. function eachProp(obj, func) {
  4015. var prop;
  4016. for (prop in obj) {
  4017. if (hasProp(obj, prop)) {
  4018. if (func(obj[prop], prop)) {
  4019. break;
  4020. }
  4021. }
  4022. }
  4023. }
  4024. /**
  4025. * Simple function to mix in properties from source into target,
  4026. * but only if target does not already have a property of the same name.
  4027. */
  4028. function mixin(target, source, force, deepStringMixin) {
  4029. if (source) {
  4030. eachProp(source, function (value, prop) {
  4031. if (force || !hasProp(target, prop)) {
  4032. if (deepStringMixin && typeof value !== 'string') {
  4033. if (!target[prop]) {
  4034. target[prop] = {};
  4035. }
  4036. mixin(target[prop], value, force, deepStringMixin);
  4037. } else {
  4038. target[prop] = value;
  4039. }
  4040. }
  4041. });
  4042. }
  4043. return target;
  4044. }
  4045. //Similar to Function.prototype.bind, but the 'this' object is specified
  4046. //first, since it is easier to read/figure out what 'this' will be.
  4047. function bind(obj, fn) {
  4048. return function () {
  4049. return fn.apply(obj, arguments);
  4050. };
  4051. }
  4052. function scripts() {
  4053. return document.getElementsByTagName('script');
  4054. }
  4055. //Allow getting a global that expressed in
  4056. //dot notation, like 'a.b.c'.
  4057. function getGlobal(value) {
  4058. if (!value) {
  4059. return value;
  4060. }
  4061. var g = global;
  4062. each(value.split('.'), function (part) {
  4063. g = g[part];
  4064. });
  4065. return g;
  4066. }
  4067. /**
  4068. * Constructs an error with a pointer to an URL with more information.
  4069. * @param {String} id the error ID that maps to an ID on a web page.
  4070. * @param {String} message human readable error.
  4071. * @param {Error} [err] the original error, if there is one.
  4072. *
  4073. * @returns {Error}
  4074. */
  4075. function makeError(id, msg, err, requireModules) {
  4076. var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
  4077. e.requireType = id;
  4078. e.requireModules = requireModules;
  4079. if (err) {
  4080. e.originalError = err;
  4081. }
  4082. return e;
  4083. }
  4084. if (typeof define !== 'undefined') {
  4085. //If a define is already in play via another AMD loader,
  4086. //do not overwrite.
  4087. return;
  4088. }
  4089. if (typeof requirejs !== 'undefined') {
  4090. if (isFunction(requirejs)) {
  4091. //Do not overwrite and existing requirejs instance.
  4092. return;
  4093. }
  4094. cfg = requirejs;
  4095. requirejs = undefined;
  4096. }
  4097. //Allow for a require config object
  4098. if (typeof require !== 'undefined' && !isFunction(require)) {
  4099. //assume it is a config object.
  4100. cfg = require;
  4101. require = undefined;
  4102. }
  4103. function newContext(contextName) {
  4104. var inCheckLoaded, Module, context, handlers,
  4105. checkLoadedTimeoutId,
  4106. config = {
  4107. waitSeconds: 7,
  4108. baseUrl: './',
  4109. paths: {},
  4110. pkgs: {},
  4111. shim: {},
  4112. map: {},
  4113. config: {}
  4114. },
  4115. registry = {},
  4116. undefEvents = {},
  4117. defQueue = [],
  4118. defined = {},
  4119. urlFetched = {},
  4120. requireCounter = 1,
  4121. unnormalizedCounter = 1;
  4122. /**
  4123. * Trims the . and .. from an array of path segments.
  4124. * It will keep a leading path segment if a .. will become
  4125. * the first path segment, to help with module name lookups,
  4126. * which act like paths, but can be remapped. But the end result,
  4127. * all paths that use this function should look normalized.
  4128. * NOTE: this method MODIFIES the input array.
  4129. * @param {Array} ary the array of path segments.
  4130. */
  4131. function trimDots(ary) {
  4132. var i, part;
  4133. for (i = 0; ary[i]; i += 1) {
  4134. part = ary[i];
  4135. if (part === '.') {
  4136. ary.splice(i, 1);
  4137. i -= 1;
  4138. } else if (part === '..') {
  4139. if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
  4140. //End of the line. Keep at least one non-dot
  4141. //path segment at the front so it can be mapped
  4142. //correctly to disk. Otherwise, there is likely
  4143. //no path mapping for a path starting with '..'.
  4144. //This can still fail, but catches the most reasonable
  4145. //uses of ..
  4146. break;
  4147. } else if (i > 0) {
  4148. ary.splice(i - 1, 2);
  4149. i -= 2;
  4150. }
  4151. }
  4152. }
  4153. }
  4154. /**
  4155. * Given a relative module name, like ./something, normalize it to
  4156. * a real name that can be mapped to a path.
  4157. * @param {String} name the relative name
  4158. * @param {String} baseName a real name that the name arg is relative
  4159. * to.
  4160. * @param {Boolean} applyMap apply the map config to the value. Should
  4161. * only be done if this normalization is for a dependency ID.
  4162. * @returns {String} normalized name
  4163. */
  4164. function normalize(name, baseName, applyMap) {
  4165. var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
  4166. foundMap, foundI, foundStarMap, starI,
  4167. baseParts = baseName && baseName.split('/'),
  4168. normalizedBaseParts = baseParts,
  4169. map = config.map,
  4170. starMap = map && map['*'];
  4171. //Adjust any relative paths.
  4172. if (name && name.charAt(0) === '.') {
  4173. //If have a base name, try to normalize against it,
  4174. //otherwise, assume it is a top-level require that will
  4175. //be relative to baseUrl in the end.
  4176. if (baseName) {
  4177. if (getOwn(config.pkgs, baseName)) {
  4178. //If the baseName is a package name, then just treat it as one
  4179. //name to concat the name with.
  4180. normalizedBaseParts = baseParts = [baseName];
  4181. } else {
  4182. //Convert baseName to array, and lop off the last part,
  4183. //so that . matches that 'directory' and not name of the baseName's
  4184. //module. For instance, baseName of 'one/two/three', maps to
  4185. //'one/two/three.js', but we want the directory, 'one/two' for
  4186. //this normalization.
  4187. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
  4188. }
  4189. name = normalizedBaseParts.concat(name.split('/'));
  4190. trimDots(name);
  4191. //Some use of packages may use a . path to reference the
  4192. //'main' module name, so normalize for that.
  4193. pkgConfig = getOwn(config.pkgs, (pkgName = name[0]));
  4194. name = name.join('/');
  4195. if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
  4196. name = pkgName;
  4197. }
  4198. } else if (name.indexOf('./') === 0) {
  4199. // No baseName, so this is ID is resolved relative
  4200. // to baseUrl, pull off the leading dot.
  4201. name = name.substring(2);
  4202. }
  4203. }
  4204. //Apply map config if available.
  4205. if (applyMap && (baseParts || starMap) && map) {
  4206. nameParts = name.split('/');
  4207. for (i = nameParts.length; i > 0; i -= 1) {
  4208. nameSegment = nameParts.slice(0, i).join('/');
  4209. if (baseParts) {
  4210. //Find the longest baseName segment match in the config.
  4211. //So, do joins on the biggest to smallest lengths of baseParts.
  4212. for (j = baseParts.length; j > 0; j -= 1) {
  4213. mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
  4214. //baseName segment has config, find if it has one for
  4215. //this name.
  4216. if (mapValue) {
  4217. mapValue = getOwn(mapValue, nameSegment);
  4218. if (mapValue) {
  4219. //Match, update name to the new value.
  4220. foundMap = mapValue;
  4221. foundI = i;
  4222. break;
  4223. }
  4224. }
  4225. }
  4226. }
  4227. if (foundMap) {
  4228. break;
  4229. }
  4230. //Check for a star map match, but just hold on to it,
  4231. //if there is a shorter segment match later in a matching
  4232. //config, then favor over this star map.
  4233. if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
  4234. foundStarMap = getOwn(starMap, nameSegment);
  4235. starI = i;
  4236. }
  4237. }
  4238. if (!foundMap && foundStarMap) {
  4239. foundMap = foundStarMap;
  4240. foundI = starI;
  4241. }
  4242. if (foundMap) {
  4243. nameParts.splice(0, foundI, foundMap);
  4244. name = nameParts.join('/');
  4245. }
  4246. }
  4247. return name;
  4248. }
  4249. function removeScript(name) {
  4250. if (isBrowser) {
  4251. each(scripts(), function (scriptNode) {
  4252. if (scriptNode.getAttribute('data-requiremodule') === name &&
  4253. scriptNode.getAttribute('data-requirecontext') === context.contextName) {
  4254. scriptNode.parentNode.removeChild(scriptNode);
  4255. return true;
  4256. }
  4257. });
  4258. }
  4259. }
  4260. function hasPathFallback(id) {
  4261. var pathConfig = getOwn(config.paths, id);
  4262. if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
  4263. removeScript(id);
  4264. //Pop off the first array value, since it failed, and
  4265. //retry
  4266. pathConfig.shift();
  4267. context.require.undef(id);
  4268. context.require([id]);
  4269. return true;
  4270. }
  4271. }
  4272. //Turns a plugin!resource to [plugin, resource]
  4273. //with the plugin being undefined if the name
  4274. //did not have a plugin prefix.
  4275. function splitPrefix(name) {
  4276. var prefix,
  4277. index = name ? name.indexOf('!') : -1;
  4278. if (index > -1) {
  4279. prefix = name.substring(0, index);
  4280. name = name.substring(index + 1, name.length);
  4281. }
  4282. return [prefix, name];
  4283. }
  4284. /**
  4285. * Creates a module mapping that includes plugin prefix, module
  4286. * name, and path. If parentModuleMap is provided it will
  4287. * also normalize the name via require.normalize()
  4288. *
  4289. * @param {String} name the module name
  4290. * @param {String} [parentModuleMap] parent module map
  4291. * for the module name, used to resolve relative names.
  4292. * @param {Boolean} isNormalized: is the ID already normalized.
  4293. * This is true if this call is done for a define() module ID.
  4294. * @param {Boolean} applyMap: apply the map config to the ID.
  4295. * Should only be true if this map is for a dependency.
  4296. *
  4297. * @returns {Object}
  4298. */
  4299. function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
  4300. var url, pluginModule, suffix, nameParts,
  4301. prefix = null,
  4302. parentName = parentModuleMap ? parentModuleMap.name : null,
  4303. originalName = name,
  4304. isDefine = true,
  4305. normalizedName = '';
  4306. //If no name, then it means it is a require call, generate an
  4307. //internal name.
  4308. if (!name) {
  4309. isDefine = false;
  4310. name = '_@r' + (requireCounter += 1);
  4311. }
  4312. nameParts = splitPrefix(name);
  4313. prefix = nameParts[0];
  4314. name = nameParts[1];
  4315. if (prefix) {
  4316. prefix = normalize(prefix, parentName, applyMap);
  4317. pluginModule = getOwn(defined, prefix);
  4318. }
  4319. //Account for relative paths if there is a base name.
  4320. if (name) {
  4321. if (prefix) {
  4322. if (pluginModule && pluginModule.normalize) {
  4323. //Plugin is loaded, use its normalize method.
  4324. normalizedName = pluginModule.normalize(name, function (name) {
  4325. return normalize(name, parentName, applyMap);
  4326. });
  4327. } else {
  4328. normalizedName = normalize(name, parentName, applyMap);
  4329. }
  4330. } else {
  4331. //A regular module.
  4332. normalizedName = normalize(name, parentName, applyMap);
  4333. //Normalized name may be a plugin ID due to map config
  4334. //application in normalize. The map config values must
  4335. //already be normalized, so do not need to redo that part.
  4336. nameParts = splitPrefix(normalizedName);
  4337. prefix = nameParts[0];
  4338. normalizedName = nameParts[1];
  4339. isNormalized = true;
  4340. url = context.nameToUrl(normalizedName);
  4341. }
  4342. }
  4343. //If the id is a plugin id that cannot be determined if it needs
  4344. //normalization, stamp it with a unique ID so two matching relative
  4345. //ids that may conflict can be separate.
  4346. suffix = prefix && !pluginModule && !isNormalized ?
  4347. '_unnormalized' + (unnormalizedCounter += 1) :
  4348. '';
  4349. return {
  4350. prefix: prefix,
  4351. name: normalizedName,
  4352. parentMap: parentModuleMap,
  4353. unnormalized: !!suffix,
  4354. url: url,
  4355. originalName: originalName,
  4356. isDefine: isDefine,
  4357. id: (prefix ?
  4358. prefix + '!' + normalizedName :
  4359. normalizedName) + suffix
  4360. };
  4361. }
  4362. function getModule(depMap) {
  4363. var id = depMap.id,
  4364. mod = getOwn(registry, id);
  4365. if (!mod) {
  4366. mod = registry[id] = new context.Module(depMap);
  4367. }
  4368. return mod;
  4369. }
  4370. function on(depMap, name, fn) {
  4371. var id = depMap.id,
  4372. mod = getOwn(registry, id);
  4373. if (hasProp(defined, id) &&
  4374. (!mod || mod.defineEmitComplete)) {
  4375. if (name === 'defined') {
  4376. fn(defined[id]);
  4377. }
  4378. } else {
  4379. getModule(depMap).on(name, fn);
  4380. }
  4381. }
  4382. function onError(err, errback) {
  4383. var ids = err.requireModules,
  4384. notified = false;
  4385. if (errback) {
  4386. errback(err);
  4387. } else {
  4388. each(ids, function (id) {
  4389. var mod = getOwn(registry, id);
  4390. if (mod) {
  4391. //Set error on module, so it skips timeout checks.
  4392. mod.error = err;
  4393. if (mod.events.error) {
  4394. notified = true;
  4395. mod.emit('error', err);
  4396. }
  4397. }
  4398. });
  4399. if (!notified) {
  4400. req.onError(err);
  4401. }
  4402. }
  4403. }
  4404. /**
  4405. * Internal method to transfer globalQueue items to this context's
  4406. * defQueue.
  4407. */
  4408. function takeGlobalQueue() {
  4409. //Push all the globalDefQueue items into the context's defQueue
  4410. if (globalDefQueue.length) {
  4411. //Array splice in the values since the context code has a
  4412. //local var ref to defQueue, so cannot just reassign the one
  4413. //on context.
  4414. apsp.apply(defQueue,
  4415. [defQueue.length - 1, 0].concat(globalDefQueue));
  4416. globalDefQueue = [];
  4417. }
  4418. }
  4419. handlers = {
  4420. 'require': function (mod) {
  4421. if (mod.require) {
  4422. return mod.require;
  4423. } else {
  4424. return (mod.require = context.makeRequire(mod.map));
  4425. }
  4426. },
  4427. 'exports': function (mod) {
  4428. mod.usingExports = true;
  4429. if (mod.map.isDefine) {
  4430. if (mod.exports) {
  4431. return mod.exports;
  4432. } else {
  4433. return (mod.exports = defined[mod.map.id] = {});
  4434. }
  4435. }
  4436. },
  4437. 'module': function (mod) {
  4438. if (mod.module) {
  4439. return mod.module;
  4440. } else {
  4441. return (mod.module = {
  4442. id: mod.map.id,
  4443. uri: mod.map.url,
  4444. config: function () {
  4445. return (config.config && getOwn(config.config, mod.map.id)) || {};
  4446. },
  4447. exports: defined[mod.map.id]
  4448. });
  4449. }
  4450. }
  4451. };
  4452. function cleanRegistry(id) {
  4453. //Clean up machinery used for waiting modules.
  4454. delete registry[id];
  4455. }
  4456. function breakCycle(mod, traced, processed) {
  4457. var id = mod.map.id;
  4458. if (mod.error) {
  4459. mod.emit('error', mod.error);
  4460. } else {
  4461. traced[id] = true;
  4462. each(mod.depMaps, function (depMap, i) {
  4463. var depId = depMap.id,
  4464. dep = getOwn(registry, depId);
  4465. //Only force things that have not completed
  4466. //being defined, so still in the registry,
  4467. //and only if it has not been matched up
  4468. //in the module already.
  4469. if (dep && !mod.depMatched[i] && !processed[depId]) {
  4470. if (getOwn(traced, depId)) {
  4471. mod.defineDep(i, defined[depId]);
  4472. mod.check(); //pass false?
  4473. } else {
  4474. breakCycle(dep, traced, processed);
  4475. }
  4476. }
  4477. });
  4478. processed[id] = true;
  4479. }
  4480. }
  4481. function checkLoaded() {
  4482. var map, modId, err, usingPathFallback,
  4483. waitInterval = config.waitSeconds * 1000,
  4484. //It is possible to disable the wait interval by using waitSeconds of 0.
  4485. expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
  4486. noLoads = [],
  4487. reqCalls = [],
  4488. stillLoading = false,
  4489. needCycleCheck = true;
  4490. //Do not bother if this call was a result of a cycle break.
  4491. if (inCheckLoaded) {
  4492. return;
  4493. }
  4494. inCheckLoaded = true;
  4495. //Figure out the state of all the modules.
  4496. eachProp(registry, function (mod) {
  4497. map = mod.map;
  4498. modId = map.id;
  4499. //Skip things that are not enabled or in error state.
  4500. if (!mod.enabled) {
  4501. return;
  4502. }
  4503. if (!map.isDefine) {
  4504. reqCalls.push(mod);
  4505. }
  4506. if (!mod.error) {
  4507. //If the module should be executed, and it has not
  4508. //been inited and time is up, remember it.
  4509. if (!mod.inited && expired) {
  4510. if (hasPathFallback(modId)) {
  4511. usingPathFallback = true;
  4512. stillLoading = true;
  4513. } else {
  4514. noLoads.push(modId);
  4515. removeScript(modId);
  4516. }
  4517. } else if (!mod.inited && mod.fetched && map.isDefine) {
  4518. stillLoading = true;
  4519. if (!map.prefix) {
  4520. //No reason to keep looking for unfinished
  4521. //loading. If the only stillLoading is a
  4522. //plugin resource though, keep going,
  4523. //because it may be that a plugin resource
  4524. //is waiting on a non-plugin cycle.
  4525. return (needCycleCheck = false);
  4526. }
  4527. }
  4528. }
  4529. });
  4530. if (expired && noLoads.length) {
  4531. //If wait time expired, throw error of unloaded modules.
  4532. err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
  4533. err.contextName = context.contextName;
  4534. return onError(err);
  4535. }
  4536. //Not expired, check for a cycle.
  4537. if (needCycleCheck) {
  4538. each(reqCalls, function (mod) {
  4539. breakCycle(mod, {}, {});
  4540. });
  4541. }
  4542. //If still waiting on loads, and the waiting load is something
  4543. //other than a plugin resource, or there are still outstanding
  4544. //scripts, then just try back later.
  4545. if ((!expired || usingPathFallback) && stillLoading) {
  4546. //Something is still waiting to load. Wait for it, but only
  4547. //if a timeout is not already in effect.
  4548. if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
  4549. checkLoadedTimeoutId = setTimeout(function () {
  4550. checkLoadedTimeoutId = 0;
  4551. checkLoaded();
  4552. }, 50);
  4553. }
  4554. }
  4555. inCheckLoaded = false;
  4556. }
  4557. Module = function (map) {
  4558. this.events = getOwn(undefEvents, map.id) || {};
  4559. this.map = map;
  4560. this.shim = getOwn(config.shim, map.id);
  4561. this.depExports = [];
  4562. this.depMaps = [];
  4563. this.depMatched = [];
  4564. this.pluginMaps = {};
  4565. this.depCount = 0;
  4566. /* this.exports this.factory
  4567. this.depMaps = [],
  4568. this.enabled, this.fetched
  4569. */
  4570. };
  4571. Module.prototype = {
  4572. init: function (depMaps, factory, errback, options) {
  4573. options = options || {};
  4574. //Do not do more inits if already done. Can happen if there
  4575. //are multiple define calls for the same module. That is not
  4576. //a normal, common case, but it is also not unexpected.
  4577. if (this.inited) {
  4578. return;
  4579. }
  4580. this.factory = factory;
  4581. if (errback) {
  4582. //Register for errors on this module.
  4583. this.on('error', errback);
  4584. } else if (this.events.error) {
  4585. //If no errback already, but there are error listeners
  4586. //on this module, set up an errback to pass to the deps.
  4587. errback = bind(this, function (err) {
  4588. this.emit('error', err);
  4589. });
  4590. }
  4591. //Do a copy of the dependency array, so that
  4592. //source inputs are not modified. For example
  4593. //"shim" deps are passed in here directly, and
  4594. //doing a direct modification of the depMaps array
  4595. //would affect that config.
  4596. this.depMaps = depMaps && depMaps.slice(0);
  4597. this.errback = errback;
  4598. //Indicate this module has be initialized
  4599. this.inited = true;
  4600. this.ignore = options.ignore;
  4601. //Could have option to init this module in enabled mode,
  4602. //or could have been previously marked as enabled. However,
  4603. //the dependencies are not known until init is called. So
  4604. //if enabled previously, now trigger dependencies as enabled.
  4605. if (options.enabled || this.enabled) {
  4606. //Enable this module and dependencies.
  4607. //Will call this.check()
  4608. this.enable();
  4609. } else {
  4610. this.check();
  4611. }
  4612. },
  4613. defineDep: function (i, depExports) {
  4614. //Because of cycles, defined callback for a given
  4615. //export can be called more than once.
  4616. if (!this.depMatched[i]) {
  4617. this.depMatched[i] = true;
  4618. this.depCount -= 1;
  4619. this.depExports[i] = depExports;
  4620. }
  4621. },
  4622. fetch: function () {
  4623. if (this.fetched) {
  4624. return;
  4625. }
  4626. this.fetched = true;
  4627. context.startTime = (new Date()).getTime();
  4628. var map = this.map;
  4629. //If the manager is for a plugin managed resource,
  4630. //ask the plugin to load it now.
  4631. if (this.shim) {
  4632. context.makeRequire(this.map, {
  4633. enableBuildCallback: true
  4634. })(this.shim.deps || [], bind(this, function () {
  4635. return map.prefix ? this.callPlugin() : this.load();
  4636. }));
  4637. } else {
  4638. //Regular dependency.
  4639. return map.prefix ? this.callPlugin() : this.load();
  4640. }
  4641. },
  4642. load: function () {
  4643. var url = this.map.url;
  4644. //Regular dependency.
  4645. if (!urlFetched[url]) {
  4646. urlFetched[url] = true;
  4647. context.load(this.map.id, url);
  4648. }
  4649. },
  4650. /**
  4651. * Checks is the module is ready to define itself, and if so,
  4652. * define it.
  4653. */
  4654. check: function () {
  4655. if (!this.enabled || this.enabling) {
  4656. return;
  4657. }
  4658. var err, cjsModule,
  4659. id = this.map.id,
  4660. depExports = this.depExports,
  4661. exports = this.exports,
  4662. factory = this.factory;
  4663. if (!this.inited) {
  4664. this.fetch();
  4665. } else if (this.error) {
  4666. this.emit('error', this.error);
  4667. } else if (!this.defining) {
  4668. //The factory could trigger another require call
  4669. //that would result in checking this module to
  4670. //define itself again. If already in the process
  4671. //of doing that, skip this work.
  4672. this.defining = true;
  4673. if (this.depCount < 1 && !this.defined) {
  4674. if (isFunction(factory)) {
  4675. //If there is an error listener, favor passing
  4676. //to that instead of throwing an error.
  4677. if (this.events.error) {
  4678. try {
  4679. exports = context.execCb(id, factory, depExports, exports);
  4680. } catch (e) {
  4681. err = e;
  4682. }
  4683. } else {
  4684. exports = context.execCb(id, factory, depExports, exports);
  4685. }
  4686. if (this.map.isDefine) {
  4687. //If setting exports via 'module' is in play,
  4688. //favor that over return value and exports. After that,
  4689. //favor a non-undefined return value over exports use.
  4690. cjsModule = this.module;
  4691. if (cjsModule &&
  4692. cjsModule.exports !== undefined &&
  4693. //Make sure it is not already the exports value
  4694. cjsModule.exports !== this.exports) {
  4695. exports = cjsModule.exports;
  4696. } else if (exports === undefined && this.usingExports) {
  4697. //exports already set the defined value.
  4698. exports = this.exports;
  4699. }
  4700. }
  4701. if (err) {
  4702. err.requireMap = this.map;
  4703. err.requireModules = [this.map.id];
  4704. err.requireType = 'define';
  4705. return onError((this.error = err));
  4706. }
  4707. } else {
  4708. //Just a literal value
  4709. exports = factory;
  4710. }
  4711. this.exports = exports;
  4712. if (this.map.isDefine && !this.ignore) {
  4713. defined[id] = exports;
  4714. if (req.onResourceLoad) {
  4715. req.onResourceLoad(context, this.map, this.depMaps);
  4716. }
  4717. }
  4718. //Clean up
  4719. delete registry[id];
  4720. this.defined = true;
  4721. }
  4722. //Finished the define stage. Allow calling check again
  4723. //to allow define notifications below in the case of a
  4724. //cycle.
  4725. this.defining = false;
  4726. if (this.defined && !this.defineEmitted) {
  4727. this.defineEmitted = true;
  4728. this.emit('defined', this.exports);
  4729. this.defineEmitComplete = true;
  4730. }
  4731. }
  4732. },
  4733. callPlugin: function () {
  4734. var map = this.map,
  4735. id = map.id,
  4736. //Map already normalized the prefix.
  4737. pluginMap = makeModuleMap(map.prefix);
  4738. //Mark this as a dependency for this plugin, so it
  4739. //can be traced for cycles.
  4740. this.depMaps.push(pluginMap);
  4741. on(pluginMap, 'defined', bind(this, function (plugin) {
  4742. var load, normalizedMap, normalizedMod,
  4743. name = this.map.name,
  4744. parentName = this.map.parentMap ? this.map.parentMap.name : null,
  4745. localRequire = context.makeRequire(map.parentMap, {
  4746. enableBuildCallback: true
  4747. });
  4748. //If current map is not normalized, wait for that
  4749. //normalized name to load instead of continuing.
  4750. if (this.map.unnormalized) {
  4751. //Normalize the ID if the plugin allows it.
  4752. if (plugin.normalize) {
  4753. name = plugin.normalize(name, function (name) {
  4754. return normalize(name, parentName, true);
  4755. }) || '';
  4756. }
  4757. //prefix and name should already be normalized, no need
  4758. //for applying map config again either.
  4759. normalizedMap = makeModuleMap(map.prefix + '!' + name,
  4760. this.map.parentMap);
  4761. on(normalizedMap,
  4762. 'defined', bind(this, function (value) {
  4763. this.init([], function () { return value; }, null, {
  4764. enabled: true,
  4765. ignore: true
  4766. });
  4767. }));
  4768. normalizedMod = getOwn(registry, normalizedMap.id);
  4769. if (normalizedMod) {
  4770. //Mark this as a dependency for this plugin, so it
  4771. //can be traced for cycles.
  4772. this.depMaps.push(normalizedMap);
  4773. if (this.events.error) {
  4774. normalizedMod.on('error', bind(this, function (err) {
  4775. this.emit('error', err);
  4776. }));
  4777. }
  4778. normalizedMod.enable();
  4779. }
  4780. return;
  4781. }
  4782. load = bind(this, function (value) {
  4783. this.init([], function () { return value; }, null, {
  4784. enabled: true
  4785. });
  4786. });
  4787. load.error = bind(this, function (err) {
  4788. this.inited = true;
  4789. this.error = err;
  4790. err.requireModules = [id];
  4791. //Remove temp unnormalized modules for this module,
  4792. //since they will never be resolved otherwise now.
  4793. eachProp(registry, function (mod) {
  4794. if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
  4795. cleanRegistry(mod.map.id);
  4796. }
  4797. });
  4798. onError(err);
  4799. });
  4800. //Allow plugins to load other code without having to know the
  4801. //context or how to 'complete' the load.
  4802. load.fromText = bind(this, function (text, textAlt) {
  4803. /*jslint evil: true */
  4804. var moduleName = map.name,
  4805. moduleMap = makeModuleMap(moduleName),
  4806. hasInteractive = useInteractive;
  4807. //As of 2.1.0, support just passing the text, to reinforce
  4808. //fromText only being called once per resource. Still
  4809. //support old style of passing moduleName but discard
  4810. //that moduleName in favor of the internal ref.
  4811. if (textAlt) {
  4812. text = textAlt;
  4813. }
  4814. //Turn off interactive script matching for IE for any define
  4815. //calls in the text, then turn it back on at the end.
  4816. if (hasInteractive) {
  4817. useInteractive = false;
  4818. }
  4819. //Prime the system by creating a module instance for
  4820. //it.
  4821. getModule(moduleMap);
  4822. //Transfer any config to this other module.
  4823. if (hasProp(config.config, id)) {
  4824. config.config[moduleName] = config.config[id];
  4825. }
  4826. try {
  4827. req.exec(text);
  4828. } catch (e) {
  4829. return onError(makeError('fromtexteval',
  4830. 'fromText eval for ' + id +
  4831. ' failed: ' + e,
  4832. e,
  4833. [id]));
  4834. }
  4835. if (hasInteractive) {
  4836. useInteractive = true;
  4837. }
  4838. //Mark this as a dependency for the plugin
  4839. //resource
  4840. this.depMaps.push(moduleMap);
  4841. //Support anonymous modules.
  4842. context.completeLoad(moduleName);
  4843. //Bind the value of that module to the value for this
  4844. //resource ID.
  4845. localRequire([moduleName], load);
  4846. });
  4847. //Use parentName here since the plugin's name is not reliable,
  4848. //could be some weird string with no path that actually wants to
  4849. //reference the parentName's path.
  4850. plugin.load(map.name, localRequire, load, config);
  4851. }));
  4852. context.enable(pluginMap, this);
  4853. this.pluginMaps[pluginMap.id] = pluginMap;
  4854. },
  4855. enable: function () {
  4856. this.enabled = true;
  4857. //Set flag mentioning that the module is enabling,
  4858. //so that immediate calls to the defined callbacks
  4859. //for dependencies do not trigger inadvertent load
  4860. //with the depCount still being zero.
  4861. this.enabling = true;
  4862. //Enable each dependency
  4863. each(this.depMaps, bind(this, function (depMap, i) {
  4864. var id, mod, handler;
  4865. if (typeof depMap === 'string') {
  4866. //Dependency needs to be converted to a depMap
  4867. //and wired up to this module.
  4868. depMap = makeModuleMap(depMap,
  4869. (this.map.isDefine ? this.map : this.map.parentMap),
  4870. false,
  4871. !this.skipMap);
  4872. this.depMaps[i] = depMap;
  4873. handler = getOwn(handlers, depMap.id);
  4874. if (handler) {
  4875. this.depExports[i] = handler(this);
  4876. return;
  4877. }
  4878. this.depCount += 1;
  4879. on(depMap, 'defined', bind(this, function (depExports) {
  4880. this.defineDep(i, depExports);
  4881. this.check();
  4882. }));
  4883. if (this.errback) {
  4884. on(depMap, 'error', this.errback);
  4885. }
  4886. }
  4887. id = depMap.id;
  4888. mod = registry[id];
  4889. //Skip special modules like 'require', 'exports', 'module'
  4890. //Also, don't call enable if it is already enabled,
  4891. //important in circular dependency cases.
  4892. if (!hasProp(handlers, id) && mod && !mod.enabled) {
  4893. context.enable(depMap, this);
  4894. }
  4895. }));
  4896. //Enable each plugin that is used in
  4897. //a dependency
  4898. eachProp(this.pluginMaps, bind(this, function (pluginMap) {
  4899. var mod = getOwn(registry, pluginMap.id);
  4900. if (mod && !mod.enabled) {
  4901. context.enable(pluginMap, this);
  4902. }
  4903. }));
  4904. this.enabling = false;
  4905. this.check();
  4906. },
  4907. on: function (name, cb) {
  4908. var cbs = this.events[name];
  4909. if (!cbs) {
  4910. cbs = this.events[name] = [];
  4911. }
  4912. cbs.push(cb);
  4913. },
  4914. emit: function (name, evt) {
  4915. each(this.events[name], function (cb) {
  4916. cb(evt);
  4917. });
  4918. if (name === 'error') {
  4919. //Now that the error handler was triggered, remove
  4920. //the listeners, since this broken Module instance
  4921. //can stay around for a while in the registry.
  4922. delete this.events[name];
  4923. }
  4924. }
  4925. };
  4926. function callGetModule(args) {
  4927. //Skip modules already defined.
  4928. if (!hasProp(defined, args[0])) {
  4929. getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
  4930. }
  4931. }
  4932. function removeListener(node, func, name, ieName) {
  4933. //Favor detachEvent because of IE9
  4934. //issue, see attachEvent/addEventListener comment elsewhere
  4935. //in this file.
  4936. if (node.detachEvent && !isOpera) {
  4937. //Probably IE. If not it will throw an error, which will be
  4938. //useful to know.
  4939. if (ieName) {
  4940. node.detachEvent(ieName, func);
  4941. }
  4942. } else {
  4943. node.removeEventListener(name, func, false);
  4944. }
  4945. }
  4946. /**
  4947. * Given an event from a script node, get the requirejs info from it,
  4948. * and then removes the event listeners on the node.
  4949. * @param {Event} evt
  4950. * @returns {Object}
  4951. */
  4952. function getScriptData(evt) {
  4953. //Using currentTarget instead of target for Firefox 2.0's sake. Not
  4954. //all old browsers will be supported, but this one was easy enough
  4955. //to support and still makes sense.
  4956. var node = evt.currentTarget || evt.srcElement;
  4957. //Remove the listeners once here.
  4958. removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
  4959. removeListener(node, context.onScriptError, 'error');
  4960. return {
  4961. node: node,
  4962. id: node && node.getAttribute('data-requiremodule')
  4963. };
  4964. }
  4965. function intakeDefines() {
  4966. var args;
  4967. //Any defined modules in the global queue, intake them now.
  4968. takeGlobalQueue();
  4969. //Make sure any remaining defQueue items get properly processed.
  4970. while (defQueue.length) {
  4971. args = defQueue.shift();
  4972. if (args[0] === null) {
  4973. return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
  4974. } else {
  4975. //args are id, deps, factory. Should be normalized by the
  4976. //define() function.
  4977. callGetModule(args);
  4978. }
  4979. }
  4980. }
  4981. context = {
  4982. config: config,
  4983. contextName: contextName,
  4984. registry: registry,
  4985. defined: defined,
  4986. urlFetched: urlFetched,
  4987. defQueue: defQueue,
  4988. Module: Module,
  4989. makeModuleMap: makeModuleMap,
  4990. nextTick: req.nextTick,
  4991. /**
  4992. * Set a configuration for the context.
  4993. * @param {Object} cfg config object to integrate.
  4994. */
  4995. configure: function (cfg) {
  4996. //Make sure the baseUrl ends in a slash.
  4997. if (cfg.baseUrl) {
  4998. if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
  4999. cfg.baseUrl += '/';
  5000. }
  5001. }
  5002. //Save off the paths and packages since they require special processing,
  5003. //they are additive.
  5004. var pkgs = config.pkgs,
  5005. shim = config.shim,
  5006. objs = {
  5007. paths: true,
  5008. config: true,
  5009. map: true
  5010. };
  5011. eachProp(cfg, function (value, prop) {
  5012. if (objs[prop]) {
  5013. if (prop === 'map') {
  5014. mixin(config[prop], value, true, true);
  5015. } else {
  5016. mixin(config[prop], value, true);
  5017. }
  5018. } else {
  5019. config[prop] = value;
  5020. }
  5021. });
  5022. //Merge shim
  5023. if (cfg.shim) {
  5024. eachProp(cfg.shim, function (value, id) {
  5025. //Normalize the structure
  5026. if (isArray(value)) {
  5027. value = {
  5028. deps: value
  5029. };
  5030. }
  5031. if ((value.exports || value.init) && !value.exportsFn) {
  5032. value.exportsFn = context.makeShimExports(value);
  5033. }
  5034. shim[id] = value;
  5035. });
  5036. config.shim = shim;
  5037. }
  5038. //Adjust packages if necessary.
  5039. if (cfg.packages) {
  5040. each(cfg.packages, function (pkgObj) {
  5041. var location;
  5042. pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
  5043. location = pkgObj.location;
  5044. //Create a brand new object on pkgs, since currentPackages can
  5045. //be passed in again, and config.pkgs is the internal transformed
  5046. //state for all package configs.
  5047. pkgs[pkgObj.name] = {
  5048. name: pkgObj.name,
  5049. location: location || pkgObj.name,
  5050. //Remove leading dot in main, so main paths are normalized,
  5051. //and remove any trailing .js, since different package
  5052. //envs have different conventions: some use a module name,
  5053. //some use a file name.
  5054. main: (pkgObj.main || 'main')
  5055. .replace(currDirRegExp, '')
  5056. .replace(jsSuffixRegExp, '')
  5057. };
  5058. });
  5059. //Done with modifications, assing packages back to context config
  5060. config.pkgs = pkgs;
  5061. }
  5062. //If there are any "waiting to execute" modules in the registry,
  5063. //update the maps for them, since their info, like URLs to load,
  5064. //may have changed.
  5065. eachProp(registry, function (mod, id) {
  5066. //If module already has init called, since it is too
  5067. //late to modify them, and ignore unnormalized ones
  5068. //since they are transient.
  5069. if (!mod.inited && !mod.map.unnormalized) {
  5070. mod.map = makeModuleMap(id);
  5071. }
  5072. });
  5073. //If a deps array or a config callback is specified, then call
  5074. //require with those args. This is useful when require is defined as a
  5075. //config object before require.js is loaded.
  5076. if (cfg.deps || cfg.callback) {
  5077. context.require(cfg.deps || [], cfg.callback);
  5078. }
  5079. },
  5080. makeShimExports: function (value) {
  5081. function fn() {
  5082. var ret;
  5083. if (value.init) {
  5084. ret = value.init.apply(global, arguments);
  5085. }
  5086. return ret || (value.exports && getGlobal(value.exports));
  5087. }
  5088. return fn;
  5089. },
  5090. makeRequire: function (relMap, options) {
  5091. options = options || {};
  5092. function localRequire(deps, callback, errback) {
  5093. var id, map, requireMod;
  5094. if (options.enableBuildCallback && callback && isFunction(callback)) {
  5095. callback.__requireJsBuild = true;
  5096. }
  5097. if (typeof deps === 'string') {
  5098. if (isFunction(callback)) {
  5099. //Invalid call
  5100. return onError(makeError('requireargs', 'Invalid require call'), errback);
  5101. }
  5102. //If require|exports|module are requested, get the
  5103. //value for them from the special handlers. Caveat:
  5104. //this only works while module is being defined.
  5105. if (relMap && hasProp(handlers, deps)) {
  5106. return handlers[deps](registry[relMap.id]);
  5107. }
  5108. //Synchronous access to one module. If require.get is
  5109. //available (as in the Node adapter), prefer that.
  5110. if (req.get) {
  5111. return req.get(context, deps, relMap);
  5112. }
  5113. //Normalize module name, if it contains . or ..
  5114. map = makeModuleMap(deps, relMap, false, true);
  5115. id = map.id;
  5116. if (!hasProp(defined, id)) {
  5117. return onError(makeError('notloaded', 'Module name "' +
  5118. id +
  5119. '" has not been loaded yet for context: ' +
  5120. contextName +
  5121. (relMap ? '' : '. Use require([])')));
  5122. }
  5123. return defined[id];
  5124. }
  5125. //Grab defines waiting in the global queue.
  5126. intakeDefines();
  5127. //Mark all the dependencies as needing to be loaded.
  5128. context.nextTick(function () {
  5129. //Some defines could have been added since the
  5130. //require call, collect them.
  5131. intakeDefines();
  5132. requireMod = getModule(makeModuleMap(null, relMap));
  5133. //Store if map config should be applied to this require
  5134. //call for dependencies.
  5135. requireMod.skipMap = options.skipMap;
  5136. requireMod.init(deps, callback, errback, {
  5137. enabled: true
  5138. });
  5139. checkLoaded();
  5140. });
  5141. return localRequire;
  5142. }
  5143. mixin(localRequire, {
  5144. isBrowser: isBrowser,
  5145. /**
  5146. * Converts a module name + .extension into an URL path.
  5147. * *Requires* the use of a module name. It does not support using
  5148. * plain URLs like nameToUrl.
  5149. */
  5150. toUrl: function (moduleNamePlusExt) {
  5151. var ext, url,
  5152. index = moduleNamePlusExt.lastIndexOf('.'),
  5153. segment = moduleNamePlusExt.split('/')[0],
  5154. isRelative = segment === '.' || segment === '..';
  5155. //Have a file extension alias, and it is not the
  5156. //dots from a relative path.
  5157. if (index !== -1 && (!isRelative || index > 1)) {
  5158. ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
  5159. moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
  5160. }
  5161. url = context.nameToUrl(normalize(moduleNamePlusExt,
  5162. relMap && relMap.id, true), ext || '.fake');
  5163. return ext ? url : url.substring(0, url.length - 5);
  5164. },
  5165. defined: function (id) {
  5166. return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
  5167. },
  5168. specified: function (id) {
  5169. id = makeModuleMap(id, relMap, false, true).id;
  5170. return hasProp(defined, id) || hasProp(registry, id);
  5171. }
  5172. });
  5173. //Only allow undef on top level require calls
  5174. if (!relMap) {
  5175. localRequire.undef = function (id) {
  5176. //Bind any waiting define() calls to this context,
  5177. //fix for #408
  5178. takeGlobalQueue();
  5179. var map = makeModuleMap(id, relMap, true),
  5180. mod = getOwn(registry, id);
  5181. delete defined[id];
  5182. delete urlFetched[map.url];
  5183. delete undefEvents[id];
  5184. if (mod) {
  5185. //Hold on to listeners in case the
  5186. //module will be attempted to be reloaded
  5187. //using a different config.
  5188. if (mod.events.defined) {
  5189. undefEvents[id] = mod.events;
  5190. }
  5191. cleanRegistry(id);
  5192. }
  5193. };
  5194. }
  5195. return localRequire;
  5196. },
  5197. /**
  5198. * Called to enable a module if it is still in the registry
  5199. * awaiting enablement. A second arg, parent, the parent module,
  5200. * is passed in for context, when this method is overriden by
  5201. * the optimizer. Not shown here to keep code compact.
  5202. */
  5203. enable: function (depMap) {
  5204. var mod = getOwn(registry, depMap.id);
  5205. if (mod) {
  5206. getModule(depMap).enable();
  5207. }
  5208. },
  5209. /**
  5210. * Internal method used by environment adapters to complete a load event.
  5211. * A load event could be a script load or just a load pass from a synchronous
  5212. * load call.
  5213. * @param {String} moduleName the name of the module to potentially complete.
  5214. */
  5215. completeLoad: function (moduleName) {
  5216. var found, args, mod,
  5217. shim = getOwn(config.shim, moduleName) || {},
  5218. shExports = shim.exports;
  5219. takeGlobalQueue();
  5220. while (defQueue.length) {
  5221. args = defQueue.shift();
  5222. if (args[0] === null) {
  5223. args[0] = moduleName;
  5224. //If already found an anonymous module and bound it
  5225. //to this name, then this is some other anon module
  5226. //waiting for its completeLoad to fire.
  5227. if (found) {
  5228. break;
  5229. }
  5230. found = true;
  5231. } else if (args[0] === moduleName) {
  5232. //Found matching define call for this script!
  5233. found = true;
  5234. }
  5235. callGetModule(args);
  5236. }
  5237. //Do this after the cycle of callGetModule in case the result
  5238. //of those calls/init calls changes the registry.
  5239. mod = getOwn(registry, moduleName);
  5240. if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
  5241. if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
  5242. if (hasPathFallback(moduleName)) {
  5243. return;
  5244. } else {
  5245. return onError(makeError('nodefine',
  5246. 'No define call for ' + moduleName,
  5247. null,
  5248. [moduleName]));
  5249. }
  5250. } else {
  5251. //A script that does not call define(), so just simulate
  5252. //the call for it.
  5253. callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
  5254. }
  5255. }
  5256. checkLoaded();
  5257. },
  5258. /**
  5259. * Converts a module name to a file path. Supports cases where
  5260. * moduleName may actually be just an URL.
  5261. * Note that it **does not** call normalize on the moduleName,
  5262. * it is assumed to have already been normalized. This is an
  5263. * internal API, not a public one. Use toUrl for the public API.
  5264. */
  5265. nameToUrl: function (moduleName, ext) {
  5266. var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
  5267. parentPath;
  5268. //If a colon is in the URL, it indicates a protocol is used and it is just
  5269. //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
  5270. //or ends with .js, then assume the user meant to use an url and not a module id.
  5271. //The slash is important for protocol-less URLs as well as full paths.
  5272. if (req.jsExtRegExp.test(moduleName)) {
  5273. //Just a plain path, not module name lookup, so just return it.
  5274. //Add extension if it is included. This is a bit wonky, only non-.js things pass
  5275. //an extension, this method probably needs to be reworked.
  5276. url = moduleName + (ext || '');
  5277. } else {
  5278. //A module that needs to be converted to a path.
  5279. paths = config.paths;
  5280. pkgs = config.pkgs;
  5281. syms = moduleName.split('/');
  5282. //For each module name segment, see if there is a path
  5283. //registered for it. Start with most specific name
  5284. //and work up from it.
  5285. for (i = syms.length; i > 0; i -= 1) {
  5286. parentModule = syms.slice(0, i).join('/');
  5287. pkg = getOwn(pkgs, parentModule);
  5288. parentPath = getOwn(paths, parentModule);
  5289. if (parentPath) {
  5290. //If an array, it means there are a few choices,
  5291. //Choose the one that is desired
  5292. if (isArray(parentPath)) {
  5293. parentPath = parentPath[0];
  5294. }
  5295. syms.splice(0, i, parentPath);
  5296. break;
  5297. } else if (pkg) {
  5298. //If module name is just the package name, then looking
  5299. //for the main module.
  5300. if (moduleName === pkg.name) {
  5301. pkgPath = pkg.location + '/' + pkg.main;
  5302. } else {
  5303. pkgPath = pkg.location;
  5304. }
  5305. syms.splice(0, i, pkgPath);
  5306. break;
  5307. }
  5308. }
  5309. //Join the path parts together, then figure out if baseUrl is needed.
  5310. url = syms.join('/');
  5311. url += (ext || (/\?/.test(url) ? '' : '.js'));
  5312. url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
  5313. }
  5314. return config.urlArgs ? url +
  5315. ((url.indexOf('?') === -1 ? '?' : '&') +
  5316. config.urlArgs) : url;
  5317. },
  5318. //Delegates to req.load. Broken out as a separate function to
  5319. //allow overriding in the optimizer.
  5320. load: function (id, url) {
  5321. req.load(context, id, url);
  5322. },
  5323. /**
  5324. * Executes a module callack function. Broken out as a separate function
  5325. * solely to allow the build system to sequence the files in the built
  5326. * layer in the right sequence.
  5327. *
  5328. * @private
  5329. */
  5330. execCb: function (name, callback, args, exports) {
  5331. return callback.apply(exports, args);
  5332. },
  5333. /**
  5334. * callback for script loads, used to check status of loading.
  5335. *
  5336. * @param {Event} evt the event from the browser for the script
  5337. * that was loaded.
  5338. */
  5339. onScriptLoad: function (evt) {
  5340. //Using currentTarget instead of target for Firefox 2.0's sake. Not
  5341. //all old browsers will be supported, but this one was easy enough
  5342. //to support and still makes sense.
  5343. if (evt.type === 'load' ||
  5344. (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
  5345. //Reset interactive script so a script node is not held onto for
  5346. //to long.
  5347. interactiveScript = null;
  5348. //Pull out the name of the module and the context.
  5349. var data = getScriptData(evt);
  5350. context.completeLoad(data.id);
  5351. }
  5352. },
  5353. /**
  5354. * Callback for script errors.
  5355. */
  5356. onScriptError: function (evt) {
  5357. var data = getScriptData(evt);
  5358. if (!hasPathFallback(data.id)) {
  5359. return onError(makeError('scripterror', 'Script error', evt, [data.id]));
  5360. }
  5361. }
  5362. };
  5363. context.require = context.makeRequire();
  5364. return context;
  5365. }
  5366. /**
  5367. * Main entry point.
  5368. *
  5369. * If the only argument to require is a string, then the module that
  5370. * is represented by that string is fetched for the appropriate context.
  5371. *
  5372. * If the first argument is an array, then it will be treated as an array
  5373. * of dependency string names to fetch. An optional function callback can
  5374. * be specified to execute when all of those dependencies are available.
  5375. *
  5376. * Make a local req variable to help Caja compliance (it assumes things
  5377. * on a require that are not standardized), and to give a short
  5378. * name for minification/local scope use.
  5379. */
  5380. req = requirejs = function (deps, callback, errback, optional) {
  5381. //Find the right context, use default
  5382. var context, config,
  5383. contextName = defContextName;
  5384. // Determine if have config object in the call.
  5385. if (!isArray(deps) && typeof deps !== 'string') {
  5386. // deps is a config object
  5387. config = deps;
  5388. if (isArray(callback)) {
  5389. // Adjust args if there are dependencies
  5390. deps = callback;
  5391. callback = errback;
  5392. errback = optional;
  5393. } else {
  5394. deps = [];
  5395. }
  5396. }
  5397. if (config && config.context) {
  5398. contextName = config.context;
  5399. }
  5400. context = getOwn(contexts, contextName);
  5401. if (!context) {
  5402. context = contexts[contextName] = req.s.newContext(contextName);
  5403. }
  5404. if (config) {
  5405. context.configure(config);
  5406. }
  5407. return context.require(deps, callback, errback);
  5408. };
  5409. /**
  5410. * Support require.config() to make it easier to cooperate with other
  5411. * AMD loaders on globally agreed names.
  5412. */
  5413. req.config = function (config) {
  5414. return req(config);
  5415. };
  5416. /**
  5417. * Execute something after the current tick
  5418. * of the event loop. Override for other envs
  5419. * that have a better solution than setTimeout.
  5420. * @param {Function} fn function to execute later.
  5421. */
  5422. req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
  5423. setTimeout(fn, 4);
  5424. } : function (fn) { fn(); };
  5425. /**
  5426. * Export require as a global, but only if it does not already exist.
  5427. */
  5428. if (!require) {
  5429. require = req;
  5430. }
  5431. req.version = version;
  5432. //Used to filter out dependencies that are already paths.
  5433. req.jsExtRegExp = /^\/|:|\?|\.js$/;
  5434. req.isBrowser = isBrowser;
  5435. s = req.s = {
  5436. contexts: contexts,
  5437. newContext: newContext
  5438. };
  5439. //Create default context.
  5440. req({});
  5441. //Exports some context-sensitive methods on global require.
  5442. each([
  5443. 'toUrl',
  5444. 'undef',
  5445. 'defined',
  5446. 'specified'
  5447. ], function (prop) {
  5448. //Reference from contexts instead of early binding to default context,
  5449. //so that during builds, the latest instance of the default context
  5450. //with its config gets used.
  5451. req[prop] = function () {
  5452. var ctx = contexts[defContextName];
  5453. return ctx.require[prop].apply(ctx, arguments);
  5454. };
  5455. });
  5456. if (isBrowser) {
  5457. head = s.head = document.getElementsByTagName('head')[0];
  5458. //If BASE tag is in play, using appendChild is a problem for IE6.
  5459. //When that browser dies, this can be removed. Details in this jQuery bug:
  5460. //http://dev.jquery.com/ticket/2709
  5461. baseElement = document.getElementsByTagName('base')[0];
  5462. if (baseElement) {
  5463. head = s.head = baseElement.parentNode;
  5464. }
  5465. }
  5466. /**
  5467. * Any errors that require explicitly generates will be passed to this
  5468. * function. Intercept/override it if you want custom error handling.
  5469. * @param {Error} err the error object.
  5470. */
  5471. req.onError = function (err) {
  5472. throw err;
  5473. };
  5474. /**
  5475. * Does the request to load a module for the browser case.
  5476. * Make this a separate function to allow other environments
  5477. * to override it.
  5478. *
  5479. * @param {Object} context the require context to find state.
  5480. * @param {String} moduleName the name of the module.
  5481. * @param {Object} url the URL to the module.
  5482. */
  5483. req.load = function (context, moduleName, url) {
  5484. var config = (context && context.config) || {},
  5485. node;
  5486. if (isBrowser) {
  5487. //In the browser so use a script tag
  5488. node = config.xhtml ?
  5489. document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
  5490. document.createElement('script');
  5491. node.type = config.scriptType || 'text/javascript';
  5492. node.charset = 'utf-8';
  5493. node.async = true;
  5494. node.setAttribute('data-requirecontext', context.contextName);
  5495. node.setAttribute('data-requiremodule', moduleName);
  5496. //Set up load listener. Test attachEvent first because IE9 has
  5497. //a subtle issue in its addEventListener and script onload firings
  5498. //that do not match the behavior of all other browsers with
  5499. //addEventListener support, which fire the onload event for a
  5500. //script right after the script execution. See:
  5501. //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
  5502. //UNFORTUNATELY Opera implements attachEvent but does not follow the script
  5503. //script execution mode.
  5504. if (node.attachEvent &&
  5505. //Check if node.attachEvent is artificially added by custom script or
  5506. //natively supported by browser
  5507. //read https://github.com/jrburke/requirejs/issues/187
  5508. //if we can NOT find [native code] then it must NOT natively supported.
  5509. //in IE8, node.attachEvent does not have toString()
  5510. //Note the test for "[native code" with no closing brace, see:
  5511. //https://github.com/jrburke/requirejs/issues/273
  5512. !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
  5513. !isOpera) {
  5514. //Probably IE. IE (at least 6-8) do not fire
  5515. //script onload right after executing the script, so
  5516. //we cannot tie the anonymous define call to a name.
  5517. //However, IE reports the script as being in 'interactive'
  5518. //readyState at the time of the define call.
  5519. useInteractive = true;
  5520. node.attachEvent('onreadystatechange', context.onScriptLoad);
  5521. //It would be great to add an error handler here to catch
  5522. //404s in IE9+. However, onreadystatechange will fire before
  5523. //the error handler, so that does not help. If addEvenListener
  5524. //is used, then IE will fire error before load, but we cannot
  5525. //use that pathway given the connect.microsoft.com issue
  5526. //mentioned above about not doing the 'script execute,
  5527. //then fire the script load event listener before execute
  5528. //next script' that other browsers do.
  5529. //Best hope: IE10 fixes the issues,
  5530. //and then destroys all installs of IE 6-9.
  5531. //node.attachEvent('onerror', context.onScriptError);
  5532. } else {
  5533. node.addEventListener('load', context.onScriptLoad, false);
  5534. node.addEventListener('error', context.onScriptError, false);
  5535. }
  5536. node.src = url;
  5537. //For some cache cases in IE 6-8, the script executes before the end
  5538. //of the appendChild execution, so to tie an anonymous define
  5539. //call to the module name (which is stored on the node), hold on
  5540. //to a reference to this node, but clear after the DOM insertion.
  5541. currentlyAddingScript = node;
  5542. if (baseElement) {
  5543. head.insertBefore(node, baseElement);
  5544. } else {
  5545. head.appendChild(node);
  5546. }
  5547. currentlyAddingScript = null;
  5548. return node;
  5549. } else if (isWebWorker) {
  5550. //In a web worker, use importScripts. This is not a very
  5551. //efficient use of importScripts, importScripts will block until
  5552. //its script is downloaded and evaluated. However, if web workers
  5553. //are in play, the expectation that a build has been done so that
  5554. //only one script needs to be loaded anyway. This may need to be
  5555. //reevaluated if other use cases become common.
  5556. importScripts(url);
  5557. //Account for anonymous modules
  5558. context.completeLoad(moduleName);
  5559. }
  5560. };
  5561. function getInteractiveScript() {
  5562. if (interactiveScript && interactiveScript.readyState === 'interactive') {
  5563. return interactiveScript;
  5564. }
  5565. eachReverse(scripts(), function (script) {
  5566. if (script.readyState === 'interactive') {
  5567. return (interactiveScript = script);
  5568. }
  5569. });
  5570. return interactiveScript;
  5571. }
  5572. //Look for a data-main script attribute, which could also adjust the baseUrl.
  5573. if (isBrowser) {
  5574. //Figure out baseUrl. Get it from the script tag with require.js in it.
  5575. eachReverse(scripts(), function (script) {
  5576. //Set the 'head' where we can append children by
  5577. //using the script's parent.
  5578. if (!head) {
  5579. head = script.parentNode;
  5580. }
  5581. //Look for a data-main attribute to set main script for the page
  5582. //to load. If it is there, the path to data main becomes the
  5583. //baseUrl, if it is not already set.
  5584. dataMain = script.getAttribute('data-main');
  5585. if (dataMain) {
  5586. //Set final baseUrl if there is not already an explicit one.
  5587. if (!cfg.baseUrl) {
  5588. //Pull off the directory of data-main for use as the
  5589. //baseUrl.
  5590. src = dataMain.split('/');
  5591. mainScript = src.pop();
  5592. subPath = src.length ? src.join('/') + '/' : './';
  5593. cfg.baseUrl = subPath;
  5594. dataMain = mainScript;
  5595. }
  5596. //Strip off any trailing .js since dataMain is now
  5597. //like a module name.
  5598. dataMain = dataMain.replace(jsSuffixRegExp, '');
  5599. //Put the data-main script in the files to load.
  5600. cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
  5601. return true;
  5602. }
  5603. });
  5604. }
  5605. /**
  5606. * The function that handles definitions of modules. Differs from
  5607. * require() in that a string for the module should be the first argument,
  5608. * and the function to execute after dependencies are loaded should
  5609. * return a value to define the module corresponding to the first argument's
  5610. * name.
  5611. */
  5612. define = function (name, deps, callback) {
  5613. var node, context;
  5614. //Allow for anonymous modules
  5615. if (typeof name !== 'string') {
  5616. //Adjust args appropriately
  5617. callback = deps;
  5618. deps = name;
  5619. name = null;
  5620. }
  5621. //This module may not have dependencies
  5622. if (!isArray(deps)) {
  5623. callback = deps;
  5624. deps = [];
  5625. }
  5626. //If no name, and callback is a function, then figure out if it a
  5627. //CommonJS thing with dependencies.
  5628. if (!deps.length && isFunction(callback)) {
  5629. //Remove comments from the callback string,
  5630. //look for require calls, and pull them into the dependencies,
  5631. //but only if there are function args.
  5632. if (callback.length) {
  5633. callback
  5634. .toString()
  5635. .replace(commentRegExp, '')
  5636. .replace(cjsRequireRegExp, function (match, dep) {
  5637. deps.push(dep);
  5638. });
  5639. //May be a CommonJS thing even without require calls, but still
  5640. //could use exports, and module. Avoid doing exports and module
  5641. //work though if it just needs require.
  5642. //REQUIRES the function to expect the CommonJS variables in the
  5643. //order listed below.
  5644. deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
  5645. }
  5646. }
  5647. //If in IE 6-8 and hit an anonymous define() call, do the interactive
  5648. //work.
  5649. if (useInteractive) {
  5650. node = currentlyAddingScript || getInteractiveScript();
  5651. if (node) {
  5652. if (!name) {
  5653. name = node.getAttribute('data-requiremodule');
  5654. }
  5655. context = contexts[node.getAttribute('data-requirecontext')];
  5656. }
  5657. }
  5658. //Always save off evaluating the def call until the script onload handler.
  5659. //This allows multiple modules to be in a file without prematurely
  5660. //tracing dependencies, and allows for anonymous module support,
  5661. //where the module name is not known until the script onload event
  5662. //occurs. If no context, use the global queue, and get it processed
  5663. //in the onscript load callback.
  5664. (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
  5665. };
  5666. define.amd = {
  5667. jQuery: true
  5668. };
  5669. /**
  5670. * Executes the text. Normally just uses eval, but can be modified
  5671. * to use a better, environment-specific call. Only used for transpiling
  5672. * loader plugins, not for plain JS modules.
  5673. * @param {String} text the text to execute/evaluate.
  5674. */
  5675. req.exec = function (text) {
  5676. /*jslint evil: true */
  5677. return eval(text);
  5678. };
  5679. //Set up with config info.
  5680. req(cfg);
  5681. }(this));
  5682. context.require=require; context.define=define; context.requirejs=requirejs; };
  5683. blanket.defaultReporter = function(coverage){
  5684. var cssSytle = "#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;} #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:yellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}",
  5685. successRate = 60,
  5686. head = document.head,
  5687. fileNumber = 0,
  5688. body = document.body,
  5689. headerContent,
  5690. hasBranchTracking = Object.keys(coverage.files).some(function(elem){
  5691. return typeof coverage.files[elem].branchData !== 'undefined';
  5692. }),
  5693. bodyContent = "<div id='blanket-main'><div class='blanket bl-title'><div class='bl-cl bl-file'><a href='http://alex-seville.github.com/blanket/' target='_blank' class='bl-logo'>Blanket.js</a> results</div><div class='bl-cl rs'>Coverage (%)</div><div class='bl-cl rs'>Covered/Total Smts.</div>"+(hasBranchTracking ? "<div class='bl-cl rs'>Covered/Total Branches</div>":"")+"<div style='clear:both;'></div></div>",
  5694. fileTemplate = "<div class='blanket {{statusclass}}'><div class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a href='javascript:blanket_toggleSource(\"file-{{fileNumber}}\")'>{{file}}</a></div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" )+"<div id='file-{{fileNumber}}' class='bl-source' style='display:none;'>{{source}}</div><div style='clear:both;'></div></div>";
  5695. grandTotalTemplate = "<div class='blanket grand-total {{statusclass}}'><div class='bl-cl'>Totals</div><div class='bl-cl rs'>{{percentage}} %</div>"+( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" )+"<div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div><div style='clear:both;'></div></div>";
  5696. function blanket_toggleSource(id) {
  5697. var element = document.getElementById(id);
  5698. if(element.style.display === 'block') {
  5699. element.style.display = 'none';
  5700. } else {
  5701. element.style.display = 'block';
  5702. }
  5703. }
  5704. var script = document.createElement("script");
  5705. script.type = "text/javascript";
  5706. script.text = blanket_toggleSource.toString().replace('function ' + blanket_toggleSource.name, 'function blanket_toggleSource');
  5707. body.appendChild(script);
  5708. var percentage = function(number, total) {
  5709. return (Math.round(((number/total) * 100)*100)/100);
  5710. };
  5711. var appendTag = function (type, el, str) {
  5712. var dom = document.createElement(type);
  5713. dom.innerHTML = str;
  5714. el.appendChild(dom);
  5715. };
  5716. function escapeInvalidXmlChars(str) {
  5717. return str.replace(/\&/g, "&amp;")
  5718. .replace(/</g, "&lt;")
  5719. .replace(/\>/g, "&gt;")
  5720. .replace(/\"/g, "&quot;")
  5721. .replace(/\'/g, "&apos;");
  5722. }
  5723. function isBranchFollowed(data,bool){
  5724. var mode = bool ? 0 : 1;
  5725. if (typeof data === 'undefined' ||
  5726. typeof data === null ||
  5727. typeof data[mode] === 'undefined'){
  5728. return false;
  5729. }
  5730. return data[mode].length > 0;
  5731. }
  5732. var branchStack = [];
  5733. function branchReport(colsIndex,src,cols,offset,lineNum){
  5734. var newsrc="";
  5735. var postfix="";
  5736. if (branchStack.length > 0){
  5737. newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],branchStack[0][1].consequent === branchStack[0][0]) ? 'branchOkay' : 'branchWarning') + "'>";
  5738. if (branchStack[0][0].end.line === lineNum){
  5739. newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
  5740. src = src.slice(branchStack[0][0].end.column);
  5741. branchStack.shift();
  5742. if (branchStack.length > 0){
  5743. newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],false) ? 'branchOkay' : 'branchWarning') + "'>";
  5744. if (branchStack[0][0].end.line === lineNum){
  5745. newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
  5746. src = src.slice(branchStack[0][0].end.column);
  5747. branchStack.shift();
  5748. if (!cols){
  5749. return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
  5750. }
  5751. }
  5752. else if (!cols){
  5753. return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
  5754. }
  5755. else{
  5756. postfix = "</span>";
  5757. }
  5758. }else if (!cols){
  5759. return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
  5760. }
  5761. }else if(!cols){
  5762. return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
  5763. }else{
  5764. postfix = "</span>";
  5765. }
  5766. }
  5767. var thisline = cols[colsIndex];
  5768. //consequent
  5769. var cons = thisline.consequent;
  5770. if (cons.start.line > lineNum){
  5771. branchStack.unshift([thisline.alternate,thisline]);
  5772. branchStack.unshift([cons,thisline]);
  5773. src = escapeInvalidXmlChars(src);
  5774. }else{
  5775. var style = "<span class='" + (isBranchFollowed(thisline,true) ? 'branchOkay' : 'branchWarning') + "'>";
  5776. newsrc += escapeInvalidXmlChars(src.slice(0,cons.start.column-offset)) + style;
  5777. if (cols.length > colsIndex+1 &&
  5778. cols[colsIndex+1].consequent.start.line === lineNum &&
  5779. cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].consequent.end.column-offset)
  5780. {
  5781. var res = branchReport(colsIndex+1,src.slice(cons.start.column-offset,cons.end.column-offset),cols,cons.start.column-offset,lineNum);
  5782. newsrc += res.src;
  5783. cols = res.cols;
  5784. cols[colsIndex+1] = cols[colsIndex+2];
  5785. cols.length--;
  5786. }else{
  5787. newsrc += escapeInvalidXmlChars(src.slice(cons.start.column-offset,cons.end.column-offset));
  5788. }
  5789. newsrc += "</span>";
  5790. var alt = thisline.alternate;
  5791. if (alt.start.line > lineNum){
  5792. newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset));
  5793. branchStack.unshift([alt,thisline]);
  5794. }else{
  5795. newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset,alt.start.column-offset));
  5796. style = "<span class='" + (isBranchFollowed(thisline,false) ? 'branchOkay' : 'branchWarning') + "'>";
  5797. newsrc += style;
  5798. if (cols.length > colsIndex+1 &&
  5799. cols[colsIndex+1].consequent.start.line === lineNum &&
  5800. cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].alternate.end.column-offset)
  5801. {
  5802. var res2 = branchReport(colsIndex+1,src.slice(alt.start.column-offset,alt.end.column-offset),cols,alt.start.column-offset,lineNum);
  5803. newsrc += res2.src;
  5804. cols = res2.cols;
  5805. cols[colsIndex+1] = cols[colsIndex+2];
  5806. cols.length--;
  5807. }else{
  5808. newsrc += escapeInvalidXmlChars(src.slice(alt.start.column-offset,alt.end.column-offset));
  5809. }
  5810. newsrc += "</span>";
  5811. newsrc += escapeInvalidXmlChars(src.slice(alt.end.column-offset));
  5812. src = newsrc;
  5813. }
  5814. }
  5815. return {src:src+postfix, cols:cols};
  5816. }
  5817. var isUndefined = function(item){
  5818. return typeof item !== 'undefined';
  5819. };
  5820. var files = coverage.files;
  5821. var totals = {
  5822. totalSmts: 0,
  5823. numberOfFilesCovered: 0
  5824. };
  5825. for(var file in files)
  5826. {
  5827. fileNumber++;
  5828. var statsForFile = files[file],
  5829. totalSmts = 0,
  5830. numberOfFilesCovered = 0,
  5831. code = [],
  5832. i;
  5833. var end = [];
  5834. for(i = 0; i < statsForFile.source.length; i +=1){
  5835. var src = statsForFile.source[i];
  5836. if (branchStack.length > 0 ||
  5837. typeof statsForFile.branchData !== 'undefined')
  5838. {
  5839. if (typeof statsForFile.branchData[i+1] !== 'undefined')
  5840. {
  5841. var cols = statsForFile.branchData[i+1].filter(isUndefined);
  5842. var colsIndex=0;
  5843. src = branchReport(colsIndex,src,cols,0,i+1).src;
  5844. }else if (branchStack.length){
  5845. src = branchReport(0,src,null,0,i+1).src;
  5846. }else{
  5847. src = escapeInvalidXmlChars(src);
  5848. }
  5849. }else{
  5850. src = escapeInvalidXmlChars(src);
  5851. }
  5852. var lineClass="";
  5853. if(statsForFile[i+1]) {
  5854. numberOfFilesCovered += 1;
  5855. totalSmts += 1;
  5856. lineClass = 'hit';
  5857. }else{
  5858. if(statsForFile[i+1] === 0){
  5859. totalSmts++;
  5860. lineClass = 'miss';
  5861. }
  5862. }
  5863. code[i + 1] = "<div class='"+lineClass+"'><span class=''>"+(i + 1)+"</span>"+src+"</div>";
  5864. totals.totalSmts += totalSmts;
  5865. totals.numberOfFilesCovered += numberOfFilesCovered;
  5866. }
  5867. var totalBranches=0;
  5868. var passedBranches=0;
  5869. if (typeof statsForFile.branchData !== 'undefined'){
  5870. for(var j=0;j<statsForFile.branchData.length;j++){
  5871. if (typeof statsForFile.branchData[j] !== 'undefined'){
  5872. for(var k=0;k<statsForFile.branchData[j].length;k++){
  5873. if (typeof statsForFile.branchData[j][k] !== 'undefined'){
  5874. totalBranches++;
  5875. if (typeof statsForFile.branchData[j][k][0] !== 'undefined' &&
  5876. statsForFile.branchData[j][k][0].length > 0 &&
  5877. typeof statsForFile.branchData[j][k][1] !== 'undefined' &&
  5878. statsForFile.branchData[j][k][1].length > 0){
  5879. passedBranches++;
  5880. }
  5881. }
  5882. }
  5883. }
  5884. }
  5885. }
  5886. var result = percentage(numberOfFilesCovered, totalSmts);
  5887. var output = fileTemplate.replace("{{file}}", file)
  5888. .replace("{{percentage}}",result)
  5889. .replace("{{numberCovered}}", numberOfFilesCovered)
  5890. .replace(/\{\{fileNumber\}\}/g, fileNumber)
  5891. .replace("{{totalSmts}}", totalSmts)
  5892. .replace("{{totalBranches}}", totalBranches)
  5893. .replace("{{passedBranches}}", passedBranches)
  5894. .replace("{{source}}", code.join(" "));
  5895. if(result < successRate)
  5896. {
  5897. output = output.replace("{{statusclass}}", "bl-error");
  5898. } else {
  5899. output = output.replace("{{statusclass}}", "bl-success");
  5900. }
  5901. bodyContent += output;
  5902. }
  5903. var totalPercent = percentage(totals.numberOfFilesCovered, totals.totalSmts);
  5904. var statusClass = totalPercent < successRate ? "bl-error" : "bl-success";
  5905. var totalsOutput = grandTotalTemplate.replace("{{percentage}}", totalPercent)
  5906. .replace("{{numberCovered}}", totals.numberOfFilesCovered)
  5907. .replace("{{totalSmts}}", totals.totalSmts)
  5908. .replace("{{statusclass}}", statusClass);
  5909. bodyContent += totalsOutput;
  5910. bodyContent += "</div>"; //closing main
  5911. appendTag('style', head, cssSytle);
  5912. //appendStyle(body, headerContent);
  5913. if (document.getElementById("blanket-main")){
  5914. document.getElementById("blanket-main").innerHTML=
  5915. bodyContent.slice(23,-6);
  5916. }else{
  5917. appendTag('div', body, bodyContent);
  5918. }
  5919. //appendHtml(body, '</div>');
  5920. };
  5921. (function(){
  5922. var newOptions={};
  5923. //http://stackoverflow.com/a/2954896
  5924. var toArray =Array.prototype.slice;
  5925. var scripts = toArray.call(document.scripts);
  5926. toArray.call(scripts[scripts.length - 1].attributes)
  5927. .forEach(function(es){
  5928. if(es.nodeName === "data-cover-only"){
  5929. newOptions.filter = es.nodeValue;
  5930. }
  5931. if(es.nodeName === "data-cover-never"){
  5932. newOptions.antifilter = es.nodeValue;
  5933. }
  5934. if(es.nodeName === "data-cover-reporter"){
  5935. newOptions.reporter = es.nodeValue;
  5936. }
  5937. if (es.nodeName === "data-cover-adapter"){
  5938. newOptions.adapter = es.nodeValue;
  5939. }
  5940. if (es.nodeName === "data-cover-loader"){
  5941. newOptions.loader = es.nodeValue;
  5942. }
  5943. if (es.nodeName === "data-cover-timeout"){
  5944. newOptions.timeout = es.nodeValue;
  5945. }
  5946. if (es.nodeName === "data-cover-reporter-options"){
  5947. try{
  5948. newOptions.reporter_options = JSON.parse(es.nodeValue);
  5949. }catch(e){
  5950. if (blanket.options("debug")){
  5951. throw new Error("Invalid reporter options. Must be a valid stringified JSON object.");
  5952. }
  5953. }
  5954. }
  5955. if (es.nodeName === "data-cover-testReadyCallback"){
  5956. newOptions.testReadyCallback = es.nodeValue;
  5957. }
  5958. if (es.nodeName === "data-cover-customVariable"){
  5959. newOptions.customVariable = es.nodeValue;
  5960. }
  5961. if (es.nodeName === "data-cover-flags"){
  5962. var flags = " "+es.nodeValue+" ";
  5963. if (flags.indexOf(" unordered ") > -1){
  5964. newOptions.order = false;
  5965. }
  5966. if (flags.indexOf(" ignoreError ") > -1){
  5967. newOptions.ignoreScriptError = true;
  5968. }
  5969. if (flags.indexOf(" autoStart ") > -1){
  5970. newOptions.autoStart = true;
  5971. }
  5972. if (flags.indexOf(" ignoreCors ") > -1){
  5973. newOptions.ignoreCors = true;
  5974. }
  5975. if (flags.indexOf(" branchTracking ") > -1){
  5976. newOptions.branchTracking = true;
  5977. }
  5978. if (flags.indexOf(" sourceURL ") > -1){
  5979. newOptions.sourceURL = true;
  5980. }
  5981. if (flags.indexOf(" debug ") > -1){
  5982. newOptions.debug = true;
  5983. }
  5984. if (flags.indexOf(" engineOnly ") > -1){
  5985. newOptions.engineOnly = true;
  5986. }
  5987. if (flags.indexOf(" commonJS ") > -1){
  5988. newOptions.commonJS = true;
  5989. }
  5990. if (flags.indexOf(" instrumentCache ") > -1){
  5991. newOptions.instrumentCache = true;
  5992. }
  5993. }
  5994. });
  5995. blanket.options(newOptions);
  5996. if (typeof requirejs !== 'undefined'){
  5997. blanket.options("existingRequireJS",true);
  5998. }
  5999. /* setup requirejs loader, if needed */
  6000. if (!blanket.options("existingRequireJS") ){
  6001. if (typeof window["define"] !== "undefined"){
  6002. window["__blanket_old_define"]=window["define"];
  6003. window["define"]=void 0;
  6004. }
  6005. if (blanket.options("commonJS")){
  6006. blanket._commonjs = {};
  6007. blanket.setupRequireJS(blanket._commonjs);
  6008. }else{
  6009. blanket.setupRequireJS(window);
  6010. }
  6011. if (typeof window["__blanket_old_define"] !== "undefined"){
  6012. window["define"] = window["__blanket_old_define"];
  6013. }
  6014. }
  6015. })();
  6016. (function(_blanket){
  6017. _blanket.extend({
  6018. utils: {
  6019. normalizeBackslashes: function(str) {
  6020. return str.replace(/\\/g, '/');
  6021. },
  6022. matchPatternAttribute: function(filename,pattern){
  6023. if (typeof pattern === 'string'){
  6024. if (pattern.indexOf("[") === 0){
  6025. //treat as array
  6026. var pattenArr = pattern.slice(1,pattern.length-1).split(",");
  6027. return pattenArr.some(function(elem){
  6028. return _blanket.utils.matchPatternAttribute(filename,_blanket.utils.normalizeBackslashes(elem.slice(1,-1)));
  6029. //return filename.indexOf(_blanket.utils.normalizeBackslashes(elem.slice(1,-1))) > -1;
  6030. });
  6031. }else if ( pattern.indexOf("//") === 0){
  6032. var ex = pattern.slice(2,pattern.lastIndexOf('/'));
  6033. var mods = pattern.slice(pattern.lastIndexOf('/')+1);
  6034. var regex = new RegExp(ex,mods);
  6035. return regex.test(filename);
  6036. }else if (pattern.indexOf("#") === 0){
  6037. return window[pattern.slice(1)].call(window,filename);
  6038. }else{
  6039. return filename.indexOf(_blanket.utils.normalizeBackslashes(pattern)) > -1;
  6040. }
  6041. }else if ( pattern instanceof Array ){
  6042. return pattern.some(function(elem){
  6043. return _blanket.utils.matchPatternAttribute(filename,elem);
  6044. });
  6045. }else if (pattern instanceof RegExp){
  6046. return pattern.test(filename);
  6047. }else if (typeof pattern === "function"){
  6048. return pattern.call(window,filename);
  6049. }
  6050. },
  6051. blanketEval: function(data){
  6052. return ( window.execScript || function( data ) {
  6053. //borrowed from jquery
  6054. window[ "eval" ].call( window, data );
  6055. } )( data );
  6056. },
  6057. collectPageScripts: function(){
  6058. console.log("cps1:"+new Date().getTime());
  6059. var toArray = Array.prototype.slice;
  6060. var scripts = toArray.call(document.scripts);
  6061. var selectedScripts=[],scriptNames=[];
  6062. var filter = _blanket.options("filter");
  6063. if(filter != null){
  6064. //global filter in place, data-cover-only
  6065. var antimatch = _blanket.options("antifilter");
  6066. selectedScripts = toArray.call(document.scripts)
  6067. .filter(function(s){
  6068. return toArray.call(s.attributes).filter(function(sn){
  6069. return sn.nodeName === "src" && _blanket.utils.matchPatternAttribute(sn.nodeValue,filter) &&
  6070. (typeof antimatch === "undefined" || !_blanket.utils.matchPatternAttribute(sn.nodeValue,antimatch));
  6071. }).length === 1;
  6072. });
  6073. }else{
  6074. selectedScripts = toArray.call(document.querySelectorAll("script[data-cover]"));
  6075. }
  6076. scriptNames = selectedScripts.map(function(s){
  6077. return _blanket.utils.qualifyURL(
  6078. toArray.call(s.attributes).filter(
  6079. function(sn){
  6080. return sn.nodeName === "src";
  6081. })[0].nodeValue).replace(".js","");
  6082. });
  6083. if (!filter){
  6084. _blanket.options("filter","['"+scriptNames.join("','")+"']");
  6085. }
  6086. return scriptNames;
  6087. }
  6088. }
  6089. });
  6090. (function(){
  6091. var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
  6092. var requirejs = blanket.options("commonJS") ? blanket._commonjs.requirejs : window.requirejs;
  6093. if (!_blanket.options("engineOnly")){
  6094. _blanket.utils.oldloader = requirejs.load;
  6095. console.log("cps2:"+new Date().getTime());
  6096. requirejs.load = function (context, moduleName, url) {
  6097. _blanket.requiringFile(url);
  6098. requirejs.cget(url, function (content) {
  6099. var match = _blanket.options("filter");
  6100. //we check the never matches first
  6101. var antimatch = _blanket.options("antifilter");
  6102. if (typeof antimatch !== "undefined" &&
  6103. _blanket.utils.matchPatternAttribute(url.replace(".js",""),antimatch)
  6104. ){
  6105. _blanket.utils.oldloader(context, moduleName, url);
  6106. if (_blanket.options("debug")) {console.log("BLANKET-File will never be instrumented:"+url);}
  6107. _blanket.requiringFile(url,true);
  6108. }else if (_blanket.utils.matchPatternAttribute(url.replace(".js",""),match)){
  6109. if (_blanket.options("debug")) {console.log("BLANKET-Attempting instrument of:"+url);}
  6110. _blanket.instrument({
  6111. inputFile: content,
  6112. inputFileName: url
  6113. },function(instrumented){
  6114. try{
  6115. _blanket.utils.blanketEval(instrumented);
  6116. context.completeLoad(moduleName);
  6117. _blanket.requiringFile(url,true);
  6118. }
  6119. catch(err){
  6120. if (_blanket.options("ignoreScriptError")){
  6121. //we can continue like normal if
  6122. //we're ignoring script errors,
  6123. //but otherwise we don't want
  6124. //to completeLoad or the error might be
  6125. //missed.
  6126. if (_blanket.options("debug")) { console.log("BLANKET-There was an error loading the file:"+url); }
  6127. context.completeLoad(moduleName);
  6128. _blanket.requiringFile(url,true);
  6129. }else{
  6130. throw new Error("Error parsing instrumented code: "+err);
  6131. }
  6132. }
  6133. });
  6134. }else{
  6135. if (_blanket.options("debug")) { console.log("BLANKET-Loading (without instrumenting) the file:"+url);}
  6136. _blanket.utils.oldloader(context, moduleName, url);
  6137. _blanket.requiringFile(url,true);
  6138. }
  6139. }, function (err) {
  6140. _blanket.requiringFile();
  6141. throw err;
  6142. });
  6143. };
  6144. requirejs.createXhr = function () {
  6145. //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
  6146. var xhr, i, progId;
  6147. if (typeof XMLHttpRequest !== "undefined") {
  6148. return new XMLHttpRequest();
  6149. } else if (typeof ActiveXObject !== "undefined") {
  6150. for (i = 0; i < 3; i += 1) {
  6151. progId = progIds[i];
  6152. try {
  6153. xhr = new ActiveXObject(progId);
  6154. } catch (e) {}
  6155. if (xhr) {
  6156. progIds = [progId]; // so faster next time
  6157. break;
  6158. }
  6159. }
  6160. }
  6161. return xhr;
  6162. };
  6163. requirejs.cget = function (url, callback, errback, onXhr) {
  6164. var foundInSession = false;
  6165. if (_blanket.blanketSession){
  6166. var files = Object.keys(_blanket.blanketSession);
  6167. for (var i=0; i<files.length;i++ ){
  6168. var key = files[i];
  6169. if (url.indexOf(key) > -1){
  6170. callback(_blanket.blanketSession[key]);
  6171. foundInSession=true;
  6172. return;
  6173. }
  6174. }
  6175. }
  6176. if (!foundInSession){
  6177. var xhr = requirejs.createXhr();
  6178. xhr.open('GET', url, true);
  6179. //Allow overrides specified in config
  6180. if (onXhr) {
  6181. onXhr(xhr, url);
  6182. }
  6183. xhr.onreadystatechange = function (evt) {
  6184. var status, err;
  6185. //Do not explicitly handle errors, those should be
  6186. //visible via console output in the browser.
  6187. if (xhr.readyState === 4) {
  6188. status = xhr.status;
  6189. if ((status > 399 && status < 600) /*||
  6190. (status === 0 &&
  6191. navigator.userAgent.toLowerCase().indexOf('firefox') > -1)
  6192. */ ) {
  6193. //An http 4xx or 5xx error. Signal an error.
  6194. err = new Error(url + ' HTTP status: ' + status);
  6195. err.xhr = xhr;
  6196. errback(err);
  6197. } else {
  6198. callback(xhr.responseText);
  6199. }
  6200. }
  6201. };
  6202. try{
  6203. xhr.send(null);
  6204. }catch(e){
  6205. if (e.code && (e.code === 101 || e.code === 1012) && _blanket.options("ignoreCors") === false){
  6206. //running locally and getting error from browser
  6207. _blanket.showManualLoader();
  6208. } else {
  6209. throw e;
  6210. }
  6211. }
  6212. }
  6213. };
  6214. }
  6215. })();
  6216. })(blanket);
  6217. (function(){
  6218. if (typeof QUnit !== 'undefined'){
  6219. //check to make sure requirejs is completed before we start the test runner
  6220. var allLoaded = function() {
  6221. return window.QUnit.config.queue.length > 0 && blanket.noConflict().requireFilesLoaded();
  6222. };
  6223. if (!QUnit.config.urlConfig[0].tooltip){
  6224. //older versions we run coverage automatically
  6225. //and we change how events are binded
  6226. QUnit.begin=function(){
  6227. blanket.noConflict().setupCoverage();
  6228. };
  6229. QUnit.done=function(failures, total) {
  6230. blanket.noConflict().onTestsDone();
  6231. };
  6232. QUnit.moduleStart=function( details ) {
  6233. blanket.noConflict().onModuleStart();
  6234. };
  6235. QUnit.testStart=function( details ) {
  6236. blanket.noConflict().onTestStart();
  6237. };
  6238. QUnit.testDone=function( details ) {
  6239. blanket.noConflict().onTestDone(details.total,details.passed);
  6240. };
  6241. blanket.beforeStartTestRunner({
  6242. condition: allLoaded,
  6243. callback: QUnit.start
  6244. });
  6245. }else{
  6246. QUnit.config.urlConfig.push({
  6247. id: "coverage",
  6248. label: "Enable coverage",
  6249. tooltip: "Enable code coverage."
  6250. });
  6251. if ( QUnit.urlParams.coverage || blanket.options("autoStart") ) {
  6252. QUnit.begin(function(){
  6253. blanket.noConflict().setupCoverage();
  6254. });
  6255. QUnit.done(function(failures, total) {
  6256. blanket.noConflict().onTestsDone();
  6257. });
  6258. QUnit.moduleStart(function( details ) {
  6259. blanket.noConflict().onModuleStart();
  6260. });
  6261. QUnit.testStart(function( details ) {
  6262. blanket.noConflict().onTestStart();
  6263. });
  6264. QUnit.testDone(function( details ) {
  6265. blanket.noConflict().onTestDone(details.total,details.passed);
  6266. });
  6267. blanket.noConflict().beforeStartTestRunner({
  6268. condition: allLoaded,
  6269. callback: function(){
  6270. if (!(blanket.options("existingRequireJS") && !blanket.options("autoStart"))){
  6271. QUnit.start();
  6272. }
  6273. }
  6274. });
  6275. }else{
  6276. requirejs.load = _blanket.utils.oldloader;
  6277. blanket.noConflict().beforeStartTestRunner({
  6278. condition: allLoaded,
  6279. callback: function(){
  6280. if (!(blanket.options("existingRequireJS") && !blanket.options("autoStart"))){
  6281. QUnit.start();
  6282. }
  6283. },
  6284. coverage:false
  6285. });
  6286. }
  6287. }
  6288. }
  6289. })();