vanilla.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. "use strict";
  2. exports.__esModule = true;
  3. var _getIterator2 = require("babel-runtime/core-js/get-iterator");
  4. var _getIterator3 = _interopRequireDefault(_getIterator2);
  5. var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
  6. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  7. var _babelTraverse = require("babel-traverse");
  8. var _babelHelperReplaceSupers = require("babel-helper-replace-supers");
  9. var _babelHelperReplaceSupers2 = _interopRequireDefault(_babelHelperReplaceSupers);
  10. var _babelHelperOptimiseCallExpression = require("babel-helper-optimise-call-expression");
  11. var _babelHelperOptimiseCallExpression2 = _interopRequireDefault(_babelHelperOptimiseCallExpression);
  12. var _babelHelperDefineMap = require("babel-helper-define-map");
  13. var defineMap = _interopRequireWildcard(_babelHelperDefineMap);
  14. var _babelTemplate = require("babel-template");
  15. var _babelTemplate2 = _interopRequireDefault(_babelTemplate);
  16. var _babelTypes = require("babel-types");
  17. var t = _interopRequireWildcard(_babelTypes);
  18. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
  19. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  20. var buildDerivedConstructor = (0, _babelTemplate2.default)("\n (function () {\n super(...arguments);\n })\n");
  21. var noMethodVisitor = {
  22. "FunctionExpression|FunctionDeclaration": function FunctionExpressionFunctionDeclaration(path) {
  23. if (!path.is("shadow")) {
  24. path.skip();
  25. }
  26. },
  27. Method: function Method(path) {
  28. path.skip();
  29. }
  30. };
  31. var verifyConstructorVisitor = _babelTraverse.visitors.merge([noMethodVisitor, {
  32. Super: function Super(path) {
  33. if (this.isDerived && !this.hasBareSuper && !path.parentPath.isCallExpression({ callee: path.node })) {
  34. throw path.buildCodeFrameError("'super.*' is not allowed before super()");
  35. }
  36. },
  37. CallExpression: {
  38. exit: function exit(path) {
  39. if (path.get("callee").isSuper()) {
  40. this.hasBareSuper = true;
  41. if (!this.isDerived) {
  42. throw path.buildCodeFrameError("super() is only allowed in a derived constructor");
  43. }
  44. }
  45. }
  46. },
  47. ThisExpression: function ThisExpression(path) {
  48. if (this.isDerived && !this.hasBareSuper) {
  49. if (!path.inShadow("this")) {
  50. throw path.buildCodeFrameError("'this' is not allowed before super()");
  51. }
  52. }
  53. }
  54. }]);
  55. var findThisesVisitor = _babelTraverse.visitors.merge([noMethodVisitor, {
  56. ThisExpression: function ThisExpression(path) {
  57. this.superThises.push(path);
  58. }
  59. }]);
  60. var ClassTransformer = function () {
  61. function ClassTransformer(path, file) {
  62. (0, _classCallCheck3.default)(this, ClassTransformer);
  63. this.parent = path.parent;
  64. this.scope = path.scope;
  65. this.node = path.node;
  66. this.path = path;
  67. this.file = file;
  68. this.clearDescriptors();
  69. this.instancePropBody = [];
  70. this.instancePropRefs = {};
  71. this.staticPropBody = [];
  72. this.body = [];
  73. this.bareSuperAfter = [];
  74. this.bareSupers = [];
  75. this.pushedConstructor = false;
  76. this.pushedInherits = false;
  77. this.isLoose = false;
  78. this.superThises = [];
  79. this.classId = this.node.id;
  80. this.classRef = this.node.id ? t.identifier(this.node.id.name) : this.scope.generateUidIdentifier("class");
  81. this.superName = this.node.superClass || t.identifier("Function");
  82. this.isDerived = !!this.node.superClass;
  83. }
  84. ClassTransformer.prototype.run = function run() {
  85. var _this = this;
  86. var superName = this.superName;
  87. var file = this.file;
  88. var body = this.body;
  89. var constructorBody = this.constructorBody = t.blockStatement([]);
  90. this.constructor = this.buildConstructor();
  91. var closureParams = [];
  92. var closureArgs = [];
  93. if (this.isDerived) {
  94. closureArgs.push(superName);
  95. superName = this.scope.generateUidIdentifierBasedOnNode(superName);
  96. closureParams.push(superName);
  97. this.superName = superName;
  98. }
  99. this.buildBody();
  100. constructorBody.body.unshift(t.expressionStatement(t.callExpression(file.addHelper("classCallCheck"), [t.thisExpression(), this.classRef])));
  101. body = body.concat(this.staticPropBody.map(function (fn) {
  102. return fn(_this.classRef);
  103. }));
  104. if (this.classId) {
  105. if (body.length === 1) return t.toExpression(body[0]);
  106. }
  107. body.push(t.returnStatement(this.classRef));
  108. var container = t.functionExpression(null, closureParams, t.blockStatement(body));
  109. container.shadow = true;
  110. return t.callExpression(container, closureArgs);
  111. };
  112. ClassTransformer.prototype.buildConstructor = function buildConstructor() {
  113. var func = t.functionDeclaration(this.classRef, [], this.constructorBody);
  114. t.inherits(func, this.node);
  115. return func;
  116. };
  117. ClassTransformer.prototype.pushToMap = function pushToMap(node, enumerable) {
  118. var kind = arguments.length <= 2 || arguments[2] === undefined ? "value" : arguments[2];
  119. var scope = arguments[3];
  120. var mutatorMap = void 0;
  121. if (node.static) {
  122. this.hasStaticDescriptors = true;
  123. mutatorMap = this.staticMutatorMap;
  124. } else {
  125. this.hasInstanceDescriptors = true;
  126. mutatorMap = this.instanceMutatorMap;
  127. }
  128. var map = defineMap.push(mutatorMap, node, kind, this.file, scope);
  129. if (enumerable) {
  130. map.enumerable = t.booleanLiteral(true);
  131. }
  132. return map;
  133. };
  134. ClassTransformer.prototype.constructorMeMaybe = function constructorMeMaybe() {
  135. var hasConstructor = false;
  136. var paths = this.path.get("body.body");
  137. for (var _iterator = paths, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) {
  138. var _ref;
  139. if (_isArray) {
  140. if (_i >= _iterator.length) break;
  141. _ref = _iterator[_i++];
  142. } else {
  143. _i = _iterator.next();
  144. if (_i.done) break;
  145. _ref = _i.value;
  146. }
  147. var path = _ref;
  148. hasConstructor = path.equals("kind", "constructor");
  149. if (hasConstructor) break;
  150. }
  151. if (hasConstructor) return;
  152. var params = void 0,
  153. body = void 0;
  154. if (this.isDerived) {
  155. var _constructor = buildDerivedConstructor().expression;
  156. params = _constructor.params;
  157. body = _constructor.body;
  158. } else {
  159. params = [];
  160. body = t.blockStatement([]);
  161. }
  162. this.path.get("body").unshiftContainer("body", t.classMethod("constructor", t.identifier("constructor"), params, body));
  163. };
  164. ClassTransformer.prototype.buildBody = function buildBody() {
  165. this.constructorMeMaybe();
  166. this.pushBody();
  167. this.verifyConstructor();
  168. if (this.userConstructor) {
  169. var constructorBody = this.constructorBody;
  170. constructorBody.body = constructorBody.body.concat(this.userConstructor.body.body);
  171. t.inherits(this.constructor, this.userConstructor);
  172. t.inherits(constructorBody, this.userConstructor.body);
  173. }
  174. this.pushDescriptors();
  175. };
  176. ClassTransformer.prototype.pushBody = function pushBody() {
  177. var classBodyPaths = this.path.get("body.body");
  178. for (var _iterator2 = classBodyPaths, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) {
  179. var _ref2;
  180. if (_isArray2) {
  181. if (_i2 >= _iterator2.length) break;
  182. _ref2 = _iterator2[_i2++];
  183. } else {
  184. _i2 = _iterator2.next();
  185. if (_i2.done) break;
  186. _ref2 = _i2.value;
  187. }
  188. var path = _ref2;
  189. var node = path.node;
  190. if (path.isClassProperty()) {
  191. throw path.buildCodeFrameError("Missing class properties transform.");
  192. }
  193. if (node.decorators) {
  194. throw path.buildCodeFrameError("Method has decorators, put the decorator plugin before the classes one.");
  195. }
  196. if (t.isClassMethod(node)) {
  197. var isConstructor = node.kind === "constructor";
  198. if (isConstructor) {
  199. path.traverse(verifyConstructorVisitor, this);
  200. if (!this.hasBareSuper && this.isDerived) {
  201. throw path.buildCodeFrameError("missing super() call in constructor");
  202. }
  203. }
  204. var replaceSupers = new _babelHelperReplaceSupers2.default({
  205. forceSuperMemoisation: isConstructor,
  206. methodPath: path,
  207. methodNode: node,
  208. objectRef: this.classRef,
  209. superRef: this.superName,
  210. isStatic: node.static,
  211. isLoose: this.isLoose,
  212. scope: this.scope,
  213. file: this.file
  214. }, true);
  215. replaceSupers.replace();
  216. if (isConstructor) {
  217. this.pushConstructor(replaceSupers, node, path);
  218. } else {
  219. this.pushMethod(node, path);
  220. }
  221. }
  222. }
  223. };
  224. ClassTransformer.prototype.clearDescriptors = function clearDescriptors() {
  225. this.hasInstanceDescriptors = false;
  226. this.hasStaticDescriptors = false;
  227. this.instanceMutatorMap = {};
  228. this.staticMutatorMap = {};
  229. };
  230. ClassTransformer.prototype.pushDescriptors = function pushDescriptors() {
  231. this.pushInherits();
  232. var body = this.body;
  233. var instanceProps = void 0;
  234. var staticProps = void 0;
  235. if (this.hasInstanceDescriptors) {
  236. instanceProps = defineMap.toClassObject(this.instanceMutatorMap);
  237. }
  238. if (this.hasStaticDescriptors) {
  239. staticProps = defineMap.toClassObject(this.staticMutatorMap);
  240. }
  241. if (instanceProps || staticProps) {
  242. if (instanceProps) instanceProps = defineMap.toComputedObjectFromClass(instanceProps);
  243. if (staticProps) staticProps = defineMap.toComputedObjectFromClass(staticProps);
  244. var nullNode = t.nullLiteral();
  245. var args = [this.classRef, nullNode, nullNode, nullNode, nullNode];
  246. if (instanceProps) args[1] = instanceProps;
  247. if (staticProps) args[2] = staticProps;
  248. if (this.instanceInitializersId) {
  249. args[3] = this.instanceInitializersId;
  250. body.unshift(this.buildObjectAssignment(this.instanceInitializersId));
  251. }
  252. if (this.staticInitializersId) {
  253. args[4] = this.staticInitializersId;
  254. body.unshift(this.buildObjectAssignment(this.staticInitializersId));
  255. }
  256. var lastNonNullIndex = 0;
  257. for (var i = 0; i < args.length; i++) {
  258. if (args[i] !== nullNode) lastNonNullIndex = i;
  259. }
  260. args = args.slice(0, lastNonNullIndex + 1);
  261. body.push(t.expressionStatement(t.callExpression(this.file.addHelper("createClass"), args)));
  262. }
  263. this.clearDescriptors();
  264. };
  265. ClassTransformer.prototype.buildObjectAssignment = function buildObjectAssignment(id) {
  266. return t.variableDeclaration("var", [t.variableDeclarator(id, t.objectExpression([]))]);
  267. };
  268. ClassTransformer.prototype.wrapSuperCall = function wrapSuperCall(bareSuper, superRef, thisRef, body) {
  269. var bareSuperNode = bareSuper.node;
  270. if (this.isLoose) {
  271. bareSuperNode.arguments.unshift(t.thisExpression());
  272. if (bareSuperNode.arguments.length === 2 && t.isSpreadElement(bareSuperNode.arguments[1]) && t.isIdentifier(bareSuperNode.arguments[1].argument, { name: "arguments" })) {
  273. bareSuperNode.arguments[1] = bareSuperNode.arguments[1].argument;
  274. bareSuperNode.callee = t.memberExpression(superRef, t.identifier("apply"));
  275. } else {
  276. bareSuperNode.callee = t.memberExpression(superRef, t.identifier("call"));
  277. }
  278. } else {
  279. bareSuperNode = (0, _babelHelperOptimiseCallExpression2.default)(t.logicalExpression("||", t.memberExpression(this.classRef, t.identifier("__proto__")), t.callExpression(t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")), [this.classRef])), t.thisExpression(), bareSuperNode.arguments);
  280. }
  281. var call = t.callExpression(this.file.addHelper("possibleConstructorReturn"), [t.thisExpression(), bareSuperNode]);
  282. var bareSuperAfter = this.bareSuperAfter.map(function (fn) {
  283. return fn(thisRef);
  284. });
  285. if (bareSuper.parentPath.isExpressionStatement() && bareSuper.parentPath.container === body.node.body && body.node.body.length - 1 === bareSuper.parentPath.key) {
  286. if (this.superThises.length || bareSuperAfter.length) {
  287. bareSuper.scope.push({ id: thisRef });
  288. call = t.assignmentExpression("=", thisRef, call);
  289. }
  290. if (bareSuperAfter.length) {
  291. call = t.toSequenceExpression([call].concat(bareSuperAfter, [thisRef]));
  292. }
  293. bareSuper.parentPath.replaceWith(t.returnStatement(call));
  294. } else {
  295. bareSuper.replaceWithMultiple([t.variableDeclaration("var", [t.variableDeclarator(thisRef, call)])].concat(bareSuperAfter, [t.expressionStatement(thisRef)]));
  296. }
  297. };
  298. ClassTransformer.prototype.verifyConstructor = function verifyConstructor() {
  299. var _this2 = this;
  300. if (!this.isDerived) return;
  301. var path = this.userConstructorPath;
  302. var body = path.get("body");
  303. path.traverse(findThisesVisitor, this);
  304. var guaranteedSuperBeforeFinish = !!this.bareSupers.length;
  305. var superRef = this.superName || t.identifier("Function");
  306. var thisRef = path.scope.generateUidIdentifier("this");
  307. for (var _iterator3 = this.bareSupers, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) {
  308. var _ref3;
  309. if (_isArray3) {
  310. if (_i3 >= _iterator3.length) break;
  311. _ref3 = _iterator3[_i3++];
  312. } else {
  313. _i3 = _iterator3.next();
  314. if (_i3.done) break;
  315. _ref3 = _i3.value;
  316. }
  317. var bareSuper = _ref3;
  318. this.wrapSuperCall(bareSuper, superRef, thisRef, body);
  319. if (guaranteedSuperBeforeFinish) {
  320. bareSuper.find(function (parentPath) {
  321. if (parentPath === path) {
  322. return true;
  323. }
  324. if (parentPath.isLoop() || parentPath.isConditional()) {
  325. guaranteedSuperBeforeFinish = false;
  326. return true;
  327. }
  328. });
  329. }
  330. }
  331. for (var _iterator4 = this.superThises, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : (0, _getIterator3.default)(_iterator4);;) {
  332. var _ref4;
  333. if (_isArray4) {
  334. if (_i4 >= _iterator4.length) break;
  335. _ref4 = _iterator4[_i4++];
  336. } else {
  337. _i4 = _iterator4.next();
  338. if (_i4.done) break;
  339. _ref4 = _i4.value;
  340. }
  341. var thisPath = _ref4;
  342. thisPath.replaceWith(thisRef);
  343. }
  344. var wrapReturn = function wrapReturn(returnArg) {
  345. return t.callExpression(_this2.file.addHelper("possibleConstructorReturn"), [thisRef].concat(returnArg || []));
  346. };
  347. var bodyPaths = body.get("body");
  348. if (bodyPaths.length && !bodyPaths.pop().isReturnStatement()) {
  349. body.pushContainer("body", t.returnStatement(guaranteedSuperBeforeFinish ? thisRef : wrapReturn()));
  350. }
  351. for (var _iterator5 = this.superReturns, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : (0, _getIterator3.default)(_iterator5);;) {
  352. var _ref5;
  353. if (_isArray5) {
  354. if (_i5 >= _iterator5.length) break;
  355. _ref5 = _iterator5[_i5++];
  356. } else {
  357. _i5 = _iterator5.next();
  358. if (_i5.done) break;
  359. _ref5 = _i5.value;
  360. }
  361. var returnPath = _ref5;
  362. if (returnPath.node.argument) {
  363. var ref = returnPath.scope.generateDeclaredUidIdentifier("ret");
  364. returnPath.get("argument").replaceWithMultiple([t.assignmentExpression("=", ref, returnPath.node.argument), wrapReturn(ref)]);
  365. } else {
  366. returnPath.get("argument").replaceWith(wrapReturn());
  367. }
  368. }
  369. };
  370. ClassTransformer.prototype.pushMethod = function pushMethod(node, path) {
  371. var scope = path ? path.scope : this.scope;
  372. if (node.kind === "method") {
  373. if (this._processMethod(node, scope)) return;
  374. }
  375. this.pushToMap(node, false, null, scope);
  376. };
  377. ClassTransformer.prototype._processMethod = function _processMethod() {
  378. return false;
  379. };
  380. ClassTransformer.prototype.pushConstructor = function pushConstructor(replaceSupers, method, path) {
  381. this.bareSupers = replaceSupers.bareSupers;
  382. this.superReturns = replaceSupers.returns;
  383. if (path.scope.hasOwnBinding(this.classRef.name)) {
  384. path.scope.rename(this.classRef.name);
  385. }
  386. var construct = this.constructor;
  387. this.userConstructorPath = path;
  388. this.userConstructor = method;
  389. this.hasConstructor = true;
  390. t.inheritsComments(construct, method);
  391. construct._ignoreUserWhitespace = true;
  392. construct.params = method.params;
  393. t.inherits(construct.body, method.body);
  394. construct.body.directives = method.body.directives;
  395. this._pushConstructor();
  396. };
  397. ClassTransformer.prototype._pushConstructor = function _pushConstructor() {
  398. if (this.pushedConstructor) return;
  399. this.pushedConstructor = true;
  400. if (this.hasInstanceDescriptors || this.hasStaticDescriptors) {
  401. this.pushDescriptors();
  402. }
  403. this.body.push(this.constructor);
  404. this.pushInherits();
  405. };
  406. ClassTransformer.prototype.pushInherits = function pushInherits() {
  407. if (!this.isDerived || this.pushedInherits) return;
  408. this.pushedInherits = true;
  409. this.body.unshift(t.expressionStatement(t.callExpression(this.file.addHelper("inherits"), [this.classRef, this.superName])));
  410. };
  411. return ClassTransformer;
  412. }();
  413. exports.default = ClassTransformer;
  414. module.exports = exports["default"];