fields.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.buildPrivateNamesMap = buildPrivateNamesMap;
  6. exports.buildPrivateNamesNodes = buildPrivateNamesNodes;
  7. exports.transformPrivateNamesUsage = transformPrivateNamesUsage;
  8. exports.buildFieldsInitNodes = buildFieldsInitNodes;
  9. var _core = require("@babel/core");
  10. var _helperReplaceSupers = _interopRequireWildcard(require("@babel/helper-replace-supers"));
  11. var _helperMemberExpressionToFunctions = _interopRequireDefault(require("@babel/helper-member-expression-to-functions"));
  12. var _helperOptimiseCallExpression = _interopRequireDefault(require("@babel/helper-optimise-call-expression"));
  13. var ts = _interopRequireWildcard(require("./typescript"));
  14. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  15. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
  16. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  17. function buildPrivateNamesMap(props) {
  18. const privateNamesMap = new Map();
  19. for (const prop of props) {
  20. const isPrivate = prop.isPrivate();
  21. const isMethod = !prop.isProperty();
  22. const isInstance = !prop.node.static;
  23. if (isPrivate) {
  24. const {
  25. name
  26. } = prop.node.key.id;
  27. const update = privateNamesMap.has(name) ? privateNamesMap.get(name) : {
  28. id: prop.scope.generateUidIdentifier(name),
  29. static: !isInstance,
  30. method: isMethod
  31. };
  32. if (prop.node.kind === "get") {
  33. update.getId = prop.scope.generateUidIdentifier(`get_${name}`);
  34. } else if (prop.node.kind === "set") {
  35. update.setId = prop.scope.generateUidIdentifier(`set_${name}`);
  36. } else if (prop.node.kind === "method") {
  37. update.methodId = prop.scope.generateUidIdentifier(name);
  38. }
  39. privateNamesMap.set(name, update);
  40. }
  41. }
  42. return privateNamesMap;
  43. }
  44. function buildPrivateNamesNodes(privateNamesMap, loose, state) {
  45. const initNodes = [];
  46. for (const [name, value] of privateNamesMap) {
  47. const {
  48. static: isStatic,
  49. method: isMethod,
  50. getId,
  51. setId
  52. } = value;
  53. const isAccessor = getId || setId;
  54. const id = _core.types.cloneNode(value.id);
  55. if (loose) {
  56. initNodes.push(_core.template.statement.ast`
  57. var ${id} = ${state.addHelper("classPrivateFieldLooseKey")}("${name}")
  58. `);
  59. } else if (isMethod && !isStatic) {
  60. if (isAccessor) {
  61. initNodes.push(_core.template.statement.ast`var ${id} = new WeakMap();`);
  62. } else {
  63. initNodes.push(_core.template.statement.ast`var ${id} = new WeakSet();`);
  64. }
  65. } else if (!isStatic) {
  66. initNodes.push(_core.template.statement.ast`var ${id} = new WeakMap();`);
  67. }
  68. }
  69. return initNodes;
  70. }
  71. function privateNameVisitorFactory(visitor) {
  72. const privateNameVisitor = Object.assign({}, visitor, {
  73. Class(path) {
  74. const {
  75. privateNamesMap
  76. } = this;
  77. const body = path.get("body.body");
  78. const visiblePrivateNames = new Map(privateNamesMap);
  79. const redeclared = [];
  80. for (const prop of body) {
  81. if (!prop.isPrivate()) continue;
  82. const {
  83. name
  84. } = prop.node.key.id;
  85. visiblePrivateNames.delete(name);
  86. redeclared.push(name);
  87. }
  88. if (!redeclared.length) {
  89. return;
  90. }
  91. path.get("body").traverse(nestedVisitor, Object.assign({}, this, {
  92. redeclared
  93. }));
  94. path.traverse(privateNameVisitor, Object.assign({}, this, {
  95. privateNamesMap: visiblePrivateNames
  96. }));
  97. path.skipKey("body");
  98. }
  99. });
  100. const nestedVisitor = _core.traverse.visitors.merge([Object.assign({}, visitor), _helperReplaceSupers.environmentVisitor]);
  101. return privateNameVisitor;
  102. }
  103. const privateNameVisitor = privateNameVisitorFactory({
  104. PrivateName(path) {
  105. const {
  106. privateNamesMap,
  107. redeclared
  108. } = this;
  109. const {
  110. node,
  111. parentPath
  112. } = path;
  113. if (!parentPath.isMemberExpression({
  114. property: node
  115. }) && !parentPath.isOptionalMemberExpression({
  116. property: node
  117. })) {
  118. return;
  119. }
  120. const {
  121. name
  122. } = node.id;
  123. if (!privateNamesMap.has(name)) return;
  124. if (redeclared && redeclared.includes(name)) return;
  125. this.handle(parentPath);
  126. }
  127. });
  128. const privateInVisitor = privateNameVisitorFactory({
  129. BinaryExpression(path) {
  130. const {
  131. operator,
  132. left,
  133. right
  134. } = path.node;
  135. if (operator !== "in") return;
  136. if (!path.get("left").isPrivateName()) return;
  137. const {
  138. loose,
  139. privateNamesMap,
  140. redeclared
  141. } = this;
  142. const {
  143. name
  144. } = left.id;
  145. if (!privateNamesMap.has(name)) return;
  146. if (redeclared && redeclared.includes(name)) return;
  147. if (loose) {
  148. const {
  149. id
  150. } = privateNamesMap.get(name);
  151. path.replaceWith(_core.template.expression.ast`
  152. Object.prototype.hasOwnProperty.call(${right}, ${_core.types.cloneNode(id)})
  153. `);
  154. return;
  155. }
  156. const {
  157. id,
  158. static: isStatic
  159. } = privateNamesMap.get(name);
  160. if (isStatic) {
  161. path.replaceWith(_core.template.expression.ast`${right} === ${this.classRef}`);
  162. return;
  163. }
  164. path.replaceWith(_core.template.expression.ast`${_core.types.cloneNode(id)}.has(${right})`);
  165. }
  166. });
  167. const privateNameHandlerSpec = {
  168. memoise(member, count) {
  169. const {
  170. scope
  171. } = member;
  172. const {
  173. object
  174. } = member.node;
  175. const memo = scope.maybeGenerateMemoised(object);
  176. if (!memo) {
  177. return;
  178. }
  179. this.memoiser.set(object, memo, count);
  180. },
  181. receiver(member) {
  182. const {
  183. object
  184. } = member.node;
  185. if (this.memoiser.has(object)) {
  186. return _core.types.cloneNode(this.memoiser.get(object));
  187. }
  188. return _core.types.cloneNode(object);
  189. },
  190. get(member) {
  191. const {
  192. classRef,
  193. privateNamesMap,
  194. file
  195. } = this;
  196. const {
  197. name
  198. } = member.node.property.id;
  199. const {
  200. id,
  201. static: isStatic,
  202. method: isMethod,
  203. methodId,
  204. getId,
  205. setId
  206. } = privateNamesMap.get(name);
  207. const isAccessor = getId || setId;
  208. if (isStatic) {
  209. const helperName = isMethod && !isAccessor ? "classStaticPrivateMethodGet" : "classStaticPrivateFieldSpecGet";
  210. return _core.types.callExpression(file.addHelper(helperName), [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id)]);
  211. }
  212. if (isMethod) {
  213. if (isAccessor) {
  214. return _core.types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core.types.cloneNode(id)]);
  215. }
  216. return _core.types.callExpression(file.addHelper("classPrivateMethodGet"), [this.receiver(member), _core.types.cloneNode(id), _core.types.cloneNode(methodId)]);
  217. }
  218. return _core.types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core.types.cloneNode(id)]);
  219. },
  220. boundGet(member) {
  221. this.memoise(member, 1);
  222. return _core.types.callExpression(_core.types.memberExpression(this.get(member), _core.types.identifier("bind")), [this.receiver(member)]);
  223. },
  224. set(member, value) {
  225. const {
  226. classRef,
  227. privateNamesMap,
  228. file
  229. } = this;
  230. const {
  231. name
  232. } = member.node.property.id;
  233. const {
  234. id,
  235. static: isStatic,
  236. method: isMethod,
  237. setId,
  238. getId
  239. } = privateNamesMap.get(name);
  240. const isAccessor = getId || setId;
  241. if (isStatic) {
  242. const helperName = isMethod && !isAccessor ? "classStaticPrivateMethodSet" : "classStaticPrivateFieldSpecSet";
  243. return _core.types.callExpression(file.addHelper(helperName), [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id), value]);
  244. }
  245. if (isMethod) {
  246. if (setId) {
  247. return _core.types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core.types.cloneNode(id), value]);
  248. }
  249. return _core.types.callExpression(file.addHelper("classPrivateMethodSet"), []);
  250. }
  251. return _core.types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core.types.cloneNode(id), value]);
  252. },
  253. destructureSet(member) {
  254. const {
  255. privateNamesMap,
  256. file
  257. } = this;
  258. const {
  259. name
  260. } = member.node.property.id;
  261. const {
  262. id
  263. } = privateNamesMap.get(name);
  264. return _core.types.memberExpression(_core.types.callExpression(file.addHelper("classPrivateFieldDestructureSet"), [this.receiver(member), _core.types.cloneNode(id)]), _core.types.identifier("value"));
  265. },
  266. call(member, args) {
  267. this.memoise(member, 1);
  268. return (0, _helperOptimiseCallExpression.default)(this.get(member), this.receiver(member), args, false);
  269. },
  270. optionalCall(member, args) {
  271. this.memoise(member, 1);
  272. return (0, _helperOptimiseCallExpression.default)(this.get(member), this.receiver(member), args, true);
  273. }
  274. };
  275. const privateNameHandlerLoose = {
  276. get(member) {
  277. const {
  278. privateNamesMap,
  279. file
  280. } = this;
  281. const {
  282. object
  283. } = member.node;
  284. const {
  285. name
  286. } = member.node.property.id;
  287. return _core.template.expression`BASE(REF, PROP)[PROP]`({
  288. BASE: file.addHelper("classPrivateFieldLooseBase"),
  289. REF: _core.types.cloneNode(object),
  290. PROP: _core.types.cloneNode(privateNamesMap.get(name).id)
  291. });
  292. },
  293. boundGet(member) {
  294. return _core.types.callExpression(_core.types.memberExpression(this.get(member), _core.types.identifier("bind")), [_core.types.cloneNode(member.node.object)]);
  295. },
  296. simpleSet(member) {
  297. return this.get(member);
  298. },
  299. destructureSet(member) {
  300. return this.get(member);
  301. },
  302. call(member, args) {
  303. return _core.types.callExpression(this.get(member), args);
  304. },
  305. optionalCall(member, args) {
  306. return _core.types.optionalCallExpression(this.get(member), args, true);
  307. }
  308. };
  309. function transformPrivateNamesUsage(ref, path, privateNamesMap, loose, state) {
  310. if (!privateNamesMap.size) return;
  311. const body = path.get("body");
  312. const handler = loose ? privateNameHandlerLoose : privateNameHandlerSpec;
  313. (0, _helperMemberExpressionToFunctions.default)(body, privateNameVisitor, Object.assign({
  314. privateNamesMap,
  315. classRef: ref,
  316. file: state
  317. }, handler));
  318. body.traverse(privateInVisitor, {
  319. privateNamesMap,
  320. classRef: ref,
  321. file: state,
  322. loose
  323. });
  324. }
  325. function buildPrivateFieldInitLoose(ref, prop, privateNamesMap) {
  326. const {
  327. id
  328. } = privateNamesMap.get(prop.node.key.id.name);
  329. const value = prop.node.value || prop.scope.buildUndefinedNode();
  330. return _core.template.statement.ast`
  331. Object.defineProperty(${ref}, ${_core.types.cloneNode(id)}, {
  332. // configurable is false by default
  333. // enumerable is false by default
  334. writable: true,
  335. value: ${value}
  336. });
  337. `;
  338. }
  339. function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) {
  340. const {
  341. id
  342. } = privateNamesMap.get(prop.node.key.id.name);
  343. const value = prop.node.value || prop.scope.buildUndefinedNode();
  344. return _core.template.statement.ast`${_core.types.cloneNode(id)}.set(${ref}, {
  345. // configurable is always false for private elements
  346. // enumerable is always false for private elements
  347. writable: true,
  348. value: ${value},
  349. })`;
  350. }
  351. function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
  352. const privateName = privateNamesMap.get(prop.node.key.id.name);
  353. const {
  354. id,
  355. getId,
  356. setId,
  357. initAdded
  358. } = privateName;
  359. const isAccessor = getId || setId;
  360. if (!prop.isProperty() && (initAdded || !isAccessor)) return;
  361. if (isAccessor) {
  362. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  363. initAdded: true
  364. }));
  365. return _core.template.statement.ast`
  366. var ${_core.types.cloneNode(id)} = {
  367. // configurable is false by default
  368. // enumerable is false by default
  369. // writable is false by default
  370. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  371. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  372. }
  373. `;
  374. }
  375. const value = prop.node.value || prop.scope.buildUndefinedNode();
  376. return _core.template.statement.ast`
  377. var ${_core.types.cloneNode(id)} = {
  378. // configurable is false by default
  379. // enumerable is false by default
  380. writable: true,
  381. value: ${value}
  382. };
  383. `;
  384. }
  385. function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
  386. const privateName = privateNamesMap.get(prop.node.key.id.name);
  387. const {
  388. methodId,
  389. id,
  390. getId,
  391. setId,
  392. initAdded
  393. } = privateName;
  394. if (initAdded) return;
  395. if (methodId) {
  396. return _core.template.statement.ast`
  397. Object.defineProperty(${ref}, ${id}, {
  398. // configurable is false by default
  399. // enumerable is false by default
  400. // writable is false by default
  401. value: ${methodId.name}
  402. });
  403. `;
  404. }
  405. const isAccessor = getId || setId;
  406. if (isAccessor) {
  407. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  408. initAdded: true
  409. }));
  410. return _core.template.statement.ast`
  411. Object.defineProperty(${ref}, ${id}, {
  412. // configurable is false by default
  413. // enumerable is false by default
  414. // writable is false by default
  415. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  416. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  417. });
  418. `;
  419. }
  420. }
  421. function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) {
  422. const privateName = privateNamesMap.get(prop.node.key.id.name);
  423. const {
  424. id,
  425. getId,
  426. setId,
  427. initAdded
  428. } = privateName;
  429. if (initAdded) return;
  430. const isAccessor = getId || setId;
  431. if (isAccessor) {
  432. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  433. initAdded: true
  434. }));
  435. return _core.template.statement.ast`
  436. ${id}.set(${ref}, {
  437. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  438. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  439. });
  440. `;
  441. }
  442. return _core.template.statement.ast`${id}.add(${ref})`;
  443. }
  444. function buildPublicFieldInitLoose(ref, prop) {
  445. const {
  446. key,
  447. computed
  448. } = prop.node;
  449. const value = prop.node.value || prop.scope.buildUndefinedNode();
  450. return _core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.memberExpression(ref, key, computed || _core.types.isLiteral(key)), value));
  451. }
  452. function buildPublicFieldInitSpec(ref, prop, state) {
  453. const {
  454. key,
  455. computed
  456. } = prop.node;
  457. const value = prop.node.value || prop.scope.buildUndefinedNode();
  458. return _core.types.expressionStatement(_core.types.callExpression(state.addHelper("defineProperty"), [ref, computed || _core.types.isLiteral(key) ? key : _core.types.stringLiteral(key.name), value]));
  459. }
  460. function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) {
  461. const privateName = privateNamesMap.get(prop.node.key.id.name);
  462. const {
  463. id,
  464. methodId,
  465. getId,
  466. setId,
  467. initAdded
  468. } = privateName;
  469. if (initAdded) return;
  470. const isAccessor = getId || setId;
  471. if (isAccessor) {
  472. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  473. initAdded: true
  474. }));
  475. return _core.template.statement.ast`
  476. Object.defineProperty(${ref}, ${id}, {
  477. // configurable is false by default
  478. // enumerable is false by default
  479. // writable is false by default
  480. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  481. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  482. })
  483. `;
  484. }
  485. return _core.template.statement.ast`
  486. Object.defineProperty(${ref}, ${id}, {
  487. // configurable is false by default
  488. // enumerable is false by default
  489. // writable is false by default
  490. value: ${methodId.name}
  491. });
  492. `;
  493. }
  494. function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) {
  495. const privateName = privateNamesMap.get(prop.node.key.id.name);
  496. const {
  497. id,
  498. methodId,
  499. getId,
  500. setId,
  501. getterDeclared,
  502. setterDeclared,
  503. static: isStatic
  504. } = privateName;
  505. const {
  506. params,
  507. body,
  508. generator,
  509. async
  510. } = prop.node;
  511. const methodValue = _core.types.functionExpression(methodId, params, body, generator, async);
  512. const isGetter = getId && !getterDeclared && params.length === 0;
  513. const isSetter = setId && !setterDeclared && params.length > 0;
  514. if (isGetter) {
  515. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  516. getterDeclared: true
  517. }));
  518. return _core.types.variableDeclaration("var", [_core.types.variableDeclarator(getId, methodValue)]);
  519. }
  520. if (isSetter) {
  521. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  522. setterDeclared: true
  523. }));
  524. return _core.types.variableDeclaration("var", [_core.types.variableDeclarator(setId, methodValue)]);
  525. }
  526. if (isStatic && !loose) {
  527. return _core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.cloneNode(id), _core.types.functionExpression(id, params, body, generator, async))]);
  528. }
  529. return _core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.cloneNode(methodId), methodValue)]);
  530. }
  531. const thisContextVisitor = _core.traverse.visitors.merge([{
  532. ThisExpression(path, state) {
  533. state.needsClassRef = true;
  534. path.replaceWith(_core.types.cloneNode(state.classRef));
  535. }
  536. }, _helperReplaceSupers.environmentVisitor]);
  537. function replaceThisContext(path, ref, superRef, file, loose) {
  538. const state = {
  539. classRef: ref,
  540. needsClassRef: false
  541. };
  542. const replacer = new _helperReplaceSupers.default({
  543. methodPath: path,
  544. isLoose: loose,
  545. superRef,
  546. file,
  547. getObjectRef() {
  548. state.needsClassRef = true;
  549. return path.node.static ? ref : _core.types.memberExpression(ref, _core.types.identifier("prototype"));
  550. }
  551. });
  552. replacer.replace();
  553. if (path.isProperty()) {
  554. path.traverse(thisContextVisitor, state);
  555. }
  556. return state.needsClassRef;
  557. }
  558. function buildFieldsInitNodes(ref, superRef, props, privateNamesMap, state, loose) {
  559. const staticNodes = [];
  560. const instanceNodes = [];
  561. let needsClassRef = false;
  562. for (const prop of props) {
  563. ts.assertFieldTransformed(prop);
  564. const isStatic = prop.node.static;
  565. const isInstance = !isStatic;
  566. const isPrivate = prop.isPrivate();
  567. const isPublic = !isPrivate;
  568. const isField = prop.isProperty();
  569. const isMethod = !isField;
  570. if (isStatic || isMethod && isPrivate) {
  571. const replaced = replaceThisContext(prop, ref, superRef, state, loose);
  572. needsClassRef = needsClassRef || replaced;
  573. }
  574. switch (true) {
  575. case isStatic && isPrivate && isField && loose:
  576. needsClassRef = true;
  577. staticNodes.push(buildPrivateFieldInitLoose(_core.types.cloneNode(ref), prop, privateNamesMap));
  578. break;
  579. case isStatic && isPrivate && isField && !loose:
  580. needsClassRef = true;
  581. staticNodes.push(buildPrivateStaticFieldInitSpec(prop, privateNamesMap));
  582. break;
  583. case isStatic && isPublic && isField && loose:
  584. needsClassRef = true;
  585. staticNodes.push(buildPublicFieldInitLoose(_core.types.cloneNode(ref), prop));
  586. break;
  587. case isStatic && isPublic && isField && !loose:
  588. needsClassRef = true;
  589. staticNodes.push(buildPublicFieldInitSpec(_core.types.cloneNode(ref), prop, state));
  590. break;
  591. case isInstance && isPrivate && isField && loose:
  592. instanceNodes.push(buildPrivateFieldInitLoose(_core.types.thisExpression(), prop, privateNamesMap));
  593. break;
  594. case isInstance && isPrivate && isField && !loose:
  595. instanceNodes.push(buildPrivateInstanceFieldInitSpec(_core.types.thisExpression(), prop, privateNamesMap));
  596. break;
  597. case isInstance && isPrivate && isMethod && loose:
  598. instanceNodes.unshift(buildPrivateMethodInitLoose(_core.types.thisExpression(), prop, privateNamesMap));
  599. staticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, loose));
  600. break;
  601. case isInstance && isPrivate && isMethod && !loose:
  602. instanceNodes.unshift(buildPrivateInstanceMethodInitSpec(_core.types.thisExpression(), prop, privateNamesMap));
  603. staticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, loose));
  604. break;
  605. case isStatic && isPrivate && isMethod && !loose:
  606. needsClassRef = true;
  607. staticNodes.push(buildPrivateStaticFieldInitSpec(prop, privateNamesMap));
  608. staticNodes.unshift(buildPrivateMethodDeclaration(prop, privateNamesMap, loose));
  609. break;
  610. case isStatic && isPrivate && isMethod && loose:
  611. needsClassRef = true;
  612. staticNodes.push(buildPrivateStaticMethodInitLoose(_core.types.cloneNode(ref), prop, state, privateNamesMap));
  613. staticNodes.unshift(buildPrivateMethodDeclaration(prop, privateNamesMap, loose));
  614. break;
  615. case isInstance && isPublic && isField && loose:
  616. instanceNodes.push(buildPublicFieldInitLoose(_core.types.thisExpression(), prop));
  617. break;
  618. case isInstance && isPublic && isField && !loose:
  619. instanceNodes.push(buildPublicFieldInitSpec(_core.types.thisExpression(), prop, state));
  620. break;
  621. default:
  622. throw new Error("Unreachable.");
  623. }
  624. }
  625. return {
  626. staticNodes: staticNodes.filter(Boolean),
  627. instanceNodes: instanceNodes.filter(Boolean),
  628. wrapClass(path) {
  629. for (const prop of props) {
  630. prop.remove();
  631. }
  632. if (!needsClassRef) return path;
  633. if (path.isClassExpression()) {
  634. path.scope.push({
  635. id: ref
  636. });
  637. path.replaceWith(_core.types.assignmentExpression("=", _core.types.cloneNode(ref), path.node));
  638. } else if (!path.node.id) {
  639. path.node.id = ref;
  640. }
  641. return path;
  642. }
  643. };
  644. }