fields.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  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, privateFieldsAsProperties, 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 (privateFieldsAsProperties) {
  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. noDocumentAll
  106. }) {
  107. const {
  108. privateNamesMap,
  109. redeclared
  110. } = this;
  111. const {
  112. node,
  113. parentPath
  114. } = path;
  115. if (!parentPath.isMemberExpression({
  116. property: node
  117. }) && !parentPath.isOptionalMemberExpression({
  118. property: node
  119. })) {
  120. return;
  121. }
  122. const {
  123. name
  124. } = node.id;
  125. if (!privateNamesMap.has(name)) return;
  126. if (redeclared && redeclared.includes(name)) return;
  127. this.handle(parentPath, noDocumentAll);
  128. }
  129. });
  130. const privateInVisitor = privateNameVisitorFactory({
  131. BinaryExpression(path) {
  132. const {
  133. operator,
  134. left,
  135. right
  136. } = path.node;
  137. if (operator !== "in") return;
  138. if (!path.get("left").isPrivateName()) return;
  139. const {
  140. privateFieldsAsProperties,
  141. privateNamesMap,
  142. redeclared
  143. } = this;
  144. const {
  145. name
  146. } = left.id;
  147. if (!privateNamesMap.has(name)) return;
  148. if (redeclared && redeclared.includes(name)) return;
  149. if (privateFieldsAsProperties) {
  150. const {
  151. id
  152. } = privateNamesMap.get(name);
  153. path.replaceWith(_core.template.expression.ast`
  154. Object.prototype.hasOwnProperty.call(${right}, ${_core.types.cloneNode(id)})
  155. `);
  156. return;
  157. }
  158. const {
  159. id,
  160. static: isStatic
  161. } = privateNamesMap.get(name);
  162. if (isStatic) {
  163. path.replaceWith(_core.template.expression.ast`${right} === ${this.classRef}`);
  164. return;
  165. }
  166. path.replaceWith(_core.template.expression.ast`${_core.types.cloneNode(id)}.has(${right})`);
  167. }
  168. });
  169. const privateNameHandlerSpec = {
  170. memoise(member, count) {
  171. const {
  172. scope
  173. } = member;
  174. const {
  175. object
  176. } = member.node;
  177. const memo = scope.maybeGenerateMemoised(object);
  178. if (!memo) {
  179. return;
  180. }
  181. this.memoiser.set(object, memo, count);
  182. },
  183. receiver(member) {
  184. const {
  185. object
  186. } = member.node;
  187. if (this.memoiser.has(object)) {
  188. return _core.types.cloneNode(this.memoiser.get(object));
  189. }
  190. return _core.types.cloneNode(object);
  191. },
  192. get(member) {
  193. const {
  194. classRef,
  195. privateNamesMap,
  196. file
  197. } = this;
  198. const {
  199. name
  200. } = member.node.property.id;
  201. const {
  202. id,
  203. static: isStatic,
  204. method: isMethod,
  205. methodId,
  206. getId,
  207. setId
  208. } = privateNamesMap.get(name);
  209. const isAccessor = getId || setId;
  210. if (isStatic) {
  211. const helperName = isMethod && !isAccessor ? "classStaticPrivateMethodGet" : "classStaticPrivateFieldSpecGet";
  212. return _core.types.callExpression(file.addHelper(helperName), [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id)]);
  213. }
  214. if (isMethod) {
  215. if (isAccessor) {
  216. if (!getId && setId) {
  217. if (file.availableHelper("writeOnlyError")) {
  218. return _core.types.sequenceExpression([this.receiver(member), _core.types.callExpression(file.addHelper("writeOnlyError"), [_core.types.stringLiteral(`#${name}`)])]);
  219. }
  220. console.warn(`@babel/helpers is outdated, update it to silence this warning.`);
  221. }
  222. return _core.types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core.types.cloneNode(id)]);
  223. }
  224. return _core.types.callExpression(file.addHelper("classPrivateMethodGet"), [this.receiver(member), _core.types.cloneNode(id), _core.types.cloneNode(methodId)]);
  225. }
  226. return _core.types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core.types.cloneNode(id)]);
  227. },
  228. boundGet(member) {
  229. this.memoise(member, 1);
  230. return _core.types.callExpression(_core.types.memberExpression(this.get(member), _core.types.identifier("bind")), [this.receiver(member)]);
  231. },
  232. set(member, value) {
  233. const {
  234. classRef,
  235. privateNamesMap,
  236. file
  237. } = this;
  238. const {
  239. name
  240. } = member.node.property.id;
  241. const {
  242. id,
  243. static: isStatic,
  244. method: isMethod,
  245. setId,
  246. getId
  247. } = privateNamesMap.get(name);
  248. const isAccessor = getId || setId;
  249. if (isStatic) {
  250. const helperName = isMethod && !isAccessor ? "classStaticPrivateMethodSet" : "classStaticPrivateFieldSpecSet";
  251. return _core.types.callExpression(file.addHelper(helperName), [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id), value]);
  252. }
  253. if (isMethod) {
  254. if (setId) {
  255. return _core.types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core.types.cloneNode(id), value]);
  256. }
  257. return _core.types.sequenceExpression([this.receiver(member), value, _core.types.callExpression(file.addHelper("readOnlyError"), [_core.types.stringLiteral(`#${name}`)])]);
  258. }
  259. return _core.types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core.types.cloneNode(id), value]);
  260. },
  261. destructureSet(member) {
  262. const {
  263. classRef,
  264. privateNamesMap,
  265. file
  266. } = this;
  267. const {
  268. name
  269. } = member.node.property.id;
  270. const {
  271. id,
  272. static: isStatic
  273. } = privateNamesMap.get(name);
  274. if (isStatic) {
  275. try {
  276. var helper = file.addHelper("classStaticPrivateFieldDestructureSet");
  277. } catch (_unused) {
  278. throw new Error("Babel can not transpile `[C.#p] = [0]` with @babel/helpers < 7.13.10, \n" + "please update @babel/helpers to the latest version.");
  279. }
  280. return _core.types.memberExpression(_core.types.callExpression(helper, [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id)]), _core.types.identifier("value"));
  281. }
  282. return _core.types.memberExpression(_core.types.callExpression(file.addHelper("classPrivateFieldDestructureSet"), [this.receiver(member), _core.types.cloneNode(id)]), _core.types.identifier("value"));
  283. },
  284. call(member, args) {
  285. this.memoise(member, 1);
  286. return (0, _helperOptimiseCallExpression.default)(this.get(member), this.receiver(member), args, false);
  287. },
  288. optionalCall(member, args) {
  289. this.memoise(member, 1);
  290. return (0, _helperOptimiseCallExpression.default)(this.get(member), this.receiver(member), args, true);
  291. }
  292. };
  293. const privateNameHandlerLoose = {
  294. get(member) {
  295. const {
  296. privateNamesMap,
  297. file
  298. } = this;
  299. const {
  300. object
  301. } = member.node;
  302. const {
  303. name
  304. } = member.node.property.id;
  305. return _core.template.expression`BASE(REF, PROP)[PROP]`({
  306. BASE: file.addHelper("classPrivateFieldLooseBase"),
  307. REF: _core.types.cloneNode(object),
  308. PROP: _core.types.cloneNode(privateNamesMap.get(name).id)
  309. });
  310. },
  311. boundGet(member) {
  312. return _core.types.callExpression(_core.types.memberExpression(this.get(member), _core.types.identifier("bind")), [_core.types.cloneNode(member.node.object)]);
  313. },
  314. simpleSet(member) {
  315. return this.get(member);
  316. },
  317. destructureSet(member) {
  318. return this.get(member);
  319. },
  320. call(member, args) {
  321. return _core.types.callExpression(this.get(member), args);
  322. },
  323. optionalCall(member, args) {
  324. return _core.types.optionalCallExpression(this.get(member), args, true);
  325. }
  326. };
  327. function transformPrivateNamesUsage(ref, path, privateNamesMap, {
  328. privateFieldsAsProperties,
  329. noDocumentAll
  330. }, state) {
  331. if (!privateNamesMap.size) return;
  332. const body = path.get("body");
  333. const handler = privateFieldsAsProperties ? privateNameHandlerLoose : privateNameHandlerSpec;
  334. (0, _helperMemberExpressionToFunctions.default)(body, privateNameVisitor, Object.assign({
  335. privateNamesMap,
  336. classRef: ref,
  337. file: state
  338. }, handler, {
  339. noDocumentAll
  340. }));
  341. body.traverse(privateInVisitor, {
  342. privateNamesMap,
  343. classRef: ref,
  344. file: state,
  345. privateFieldsAsProperties
  346. });
  347. }
  348. function buildPrivateFieldInitLoose(ref, prop, privateNamesMap) {
  349. const {
  350. id
  351. } = privateNamesMap.get(prop.node.key.id.name);
  352. const value = prop.node.value || prop.scope.buildUndefinedNode();
  353. return _core.template.statement.ast`
  354. Object.defineProperty(${ref}, ${_core.types.cloneNode(id)}, {
  355. // configurable is false by default
  356. // enumerable is false by default
  357. writable: true,
  358. value: ${value}
  359. });
  360. `;
  361. }
  362. function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) {
  363. const {
  364. id
  365. } = privateNamesMap.get(prop.node.key.id.name);
  366. const value = prop.node.value || prop.scope.buildUndefinedNode();
  367. return _core.template.statement.ast`${_core.types.cloneNode(id)}.set(${ref}, {
  368. // configurable is always false for private elements
  369. // enumerable is always false for private elements
  370. writable: true,
  371. value: ${value},
  372. })`;
  373. }
  374. function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
  375. const privateName = privateNamesMap.get(prop.node.key.id.name);
  376. const {
  377. id,
  378. getId,
  379. setId,
  380. initAdded
  381. } = privateName;
  382. const isAccessor = getId || setId;
  383. if (!prop.isProperty() && (initAdded || !isAccessor)) return;
  384. if (isAccessor) {
  385. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  386. initAdded: true
  387. }));
  388. return _core.template.statement.ast`
  389. var ${_core.types.cloneNode(id)} = {
  390. // configurable is false by default
  391. // enumerable is false by default
  392. // writable is false by default
  393. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  394. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  395. }
  396. `;
  397. }
  398. const value = prop.node.value || prop.scope.buildUndefinedNode();
  399. return _core.template.statement.ast`
  400. var ${_core.types.cloneNode(id)} = {
  401. // configurable is false by default
  402. // enumerable is false by default
  403. writable: true,
  404. value: ${value}
  405. };
  406. `;
  407. }
  408. function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
  409. const privateName = privateNamesMap.get(prop.node.key.id.name);
  410. const {
  411. methodId,
  412. id,
  413. getId,
  414. setId,
  415. initAdded
  416. } = privateName;
  417. if (initAdded) return;
  418. if (methodId) {
  419. return _core.template.statement.ast`
  420. Object.defineProperty(${ref}, ${id}, {
  421. // configurable is false by default
  422. // enumerable is false by default
  423. // writable is false by default
  424. value: ${methodId.name}
  425. });
  426. `;
  427. }
  428. const isAccessor = getId || setId;
  429. if (isAccessor) {
  430. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  431. initAdded: true
  432. }));
  433. return _core.template.statement.ast`
  434. Object.defineProperty(${ref}, ${id}, {
  435. // configurable is false by default
  436. // enumerable is false by default
  437. // writable is false by default
  438. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  439. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  440. });
  441. `;
  442. }
  443. }
  444. function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) {
  445. const privateName = privateNamesMap.get(prop.node.key.id.name);
  446. const {
  447. id,
  448. getId,
  449. setId,
  450. initAdded
  451. } = privateName;
  452. if (initAdded) return;
  453. const isAccessor = getId || setId;
  454. if (isAccessor) {
  455. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  456. initAdded: true
  457. }));
  458. return _core.template.statement.ast`
  459. ${id}.set(${ref}, {
  460. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  461. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  462. });
  463. `;
  464. }
  465. return _core.template.statement.ast`${id}.add(${ref})`;
  466. }
  467. function buildPublicFieldInitLoose(ref, prop) {
  468. const {
  469. key,
  470. computed
  471. } = prop.node;
  472. const value = prop.node.value || prop.scope.buildUndefinedNode();
  473. return _core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.memberExpression(ref, key, computed || _core.types.isLiteral(key)), value));
  474. }
  475. function buildPublicFieldInitSpec(ref, prop, state) {
  476. const {
  477. key,
  478. computed
  479. } = prop.node;
  480. const value = prop.node.value || prop.scope.buildUndefinedNode();
  481. return _core.types.expressionStatement(_core.types.callExpression(state.addHelper("defineProperty"), [ref, computed || _core.types.isLiteral(key) ? key : _core.types.stringLiteral(key.name), value]));
  482. }
  483. function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) {
  484. const privateName = privateNamesMap.get(prop.node.key.id.name);
  485. const {
  486. id,
  487. methodId,
  488. getId,
  489. setId,
  490. initAdded
  491. } = privateName;
  492. if (initAdded) return;
  493. const isAccessor = getId || setId;
  494. if (isAccessor) {
  495. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  496. initAdded: true
  497. }));
  498. return _core.template.statement.ast`
  499. Object.defineProperty(${ref}, ${id}, {
  500. // configurable is false by default
  501. // enumerable is false by default
  502. // writable is false by default
  503. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  504. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  505. })
  506. `;
  507. }
  508. return _core.template.statement.ast`
  509. Object.defineProperty(${ref}, ${id}, {
  510. // configurable is false by default
  511. // enumerable is false by default
  512. // writable is false by default
  513. value: ${methodId.name}
  514. });
  515. `;
  516. }
  517. function buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties = false) {
  518. const privateName = privateNamesMap.get(prop.node.key.id.name);
  519. const {
  520. id,
  521. methodId,
  522. getId,
  523. setId,
  524. getterDeclared,
  525. setterDeclared,
  526. static: isStatic
  527. } = privateName;
  528. const {
  529. params,
  530. body,
  531. generator,
  532. async
  533. } = prop.node;
  534. const isGetter = getId && !getterDeclared && params.length === 0;
  535. const isSetter = setId && !setterDeclared && params.length > 0;
  536. let declId = methodId;
  537. if (isGetter) {
  538. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  539. getterDeclared: true
  540. }));
  541. declId = getId;
  542. } else if (isSetter) {
  543. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  544. setterDeclared: true
  545. }));
  546. declId = setId;
  547. } else if (isStatic && !privateFieldsAsProperties) {
  548. declId = id;
  549. }
  550. return _core.types.functionDeclaration(_core.types.cloneNode(declId), params, body, generator, async);
  551. }
  552. const thisContextVisitor = _core.traverse.visitors.merge([{
  553. ThisExpression(path, state) {
  554. state.needsClassRef = true;
  555. path.replaceWith(_core.types.cloneNode(state.classRef));
  556. }
  557. }, _helperReplaceSupers.environmentVisitor]);
  558. function replaceThisContext(path, ref, superRef, file, constantSuper) {
  559. const state = {
  560. classRef: ref,
  561. needsClassRef: false
  562. };
  563. const replacer = new _helperReplaceSupers.default({
  564. methodPath: path,
  565. constantSuper,
  566. superRef,
  567. file,
  568. refToPreserve: ref,
  569. getObjectRef() {
  570. state.needsClassRef = true;
  571. return path.node.static ? ref : _core.types.memberExpression(ref, _core.types.identifier("prototype"));
  572. }
  573. });
  574. replacer.replace();
  575. if (path.isProperty()) {
  576. path.traverse(thisContextVisitor, state);
  577. }
  578. return state.needsClassRef;
  579. }
  580. function buildFieldsInitNodes(ref, superRef, props, privateNamesMap, state, setPublicClassFields, privateFieldsAsProperties, constantSuper) {
  581. let needsClassRef = false;
  582. const staticNodes = [];
  583. const instanceNodes = [];
  584. const pureStaticNodes = [];
  585. for (const prop of props) {
  586. ts.assertFieldTransformed(prop);
  587. const isStatic = prop.node.static;
  588. const isInstance = !isStatic;
  589. const isPrivate = prop.isPrivate();
  590. const isPublic = !isPrivate;
  591. const isField = prop.isProperty();
  592. const isMethod = !isField;
  593. if (isStatic || isMethod && isPrivate) {
  594. const replaced = replaceThisContext(prop, ref, superRef, state, constantSuper);
  595. needsClassRef = needsClassRef || replaced;
  596. }
  597. switch (true) {
  598. case isStatic && isPrivate && isField && privateFieldsAsProperties:
  599. needsClassRef = true;
  600. staticNodes.push(buildPrivateFieldInitLoose(_core.types.cloneNode(ref), prop, privateNamesMap));
  601. break;
  602. case isStatic && isPrivate && isField && !privateFieldsAsProperties:
  603. needsClassRef = true;
  604. staticNodes.push(buildPrivateStaticFieldInitSpec(prop, privateNamesMap));
  605. break;
  606. case isStatic && isPublic && isField && setPublicClassFields:
  607. needsClassRef = true;
  608. staticNodes.push(buildPublicFieldInitLoose(_core.types.cloneNode(ref), prop));
  609. break;
  610. case isStatic && isPublic && isField && !setPublicClassFields:
  611. needsClassRef = true;
  612. staticNodes.push(buildPublicFieldInitSpec(_core.types.cloneNode(ref), prop, state));
  613. break;
  614. case isInstance && isPrivate && isField && privateFieldsAsProperties:
  615. instanceNodes.push(buildPrivateFieldInitLoose(_core.types.thisExpression(), prop, privateNamesMap));
  616. break;
  617. case isInstance && isPrivate && isField && !privateFieldsAsProperties:
  618. instanceNodes.push(buildPrivateInstanceFieldInitSpec(_core.types.thisExpression(), prop, privateNamesMap));
  619. break;
  620. case isInstance && isPrivate && isMethod && privateFieldsAsProperties:
  621. instanceNodes.unshift(buildPrivateMethodInitLoose(_core.types.thisExpression(), prop, privateNamesMap));
  622. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  623. break;
  624. case isInstance && isPrivate && isMethod && !privateFieldsAsProperties:
  625. instanceNodes.unshift(buildPrivateInstanceMethodInitSpec(_core.types.thisExpression(), prop, privateNamesMap));
  626. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  627. break;
  628. case isStatic && isPrivate && isMethod && !privateFieldsAsProperties:
  629. needsClassRef = true;
  630. staticNodes.unshift(buildPrivateStaticFieldInitSpec(prop, privateNamesMap));
  631. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  632. break;
  633. case isStatic && isPrivate && isMethod && privateFieldsAsProperties:
  634. needsClassRef = true;
  635. staticNodes.unshift(buildPrivateStaticMethodInitLoose(_core.types.cloneNode(ref), prop, state, privateNamesMap));
  636. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  637. break;
  638. case isInstance && isPublic && isField && setPublicClassFields:
  639. instanceNodes.push(buildPublicFieldInitLoose(_core.types.thisExpression(), prop));
  640. break;
  641. case isInstance && isPublic && isField && !setPublicClassFields:
  642. instanceNodes.push(buildPublicFieldInitSpec(_core.types.thisExpression(), prop, state));
  643. break;
  644. default:
  645. throw new Error("Unreachable.");
  646. }
  647. }
  648. return {
  649. staticNodes: staticNodes.filter(Boolean),
  650. instanceNodes: instanceNodes.filter(Boolean),
  651. pureStaticNodes: pureStaticNodes.filter(Boolean),
  652. wrapClass(path) {
  653. for (const prop of props) {
  654. prop.remove();
  655. }
  656. if (!needsClassRef) return path;
  657. if (path.isClassExpression()) {
  658. path.scope.push({
  659. id: ref
  660. });
  661. path.replaceWith(_core.types.assignmentExpression("=", _core.types.cloneNode(ref), path.node));
  662. } else if (!path.node.id) {
  663. path.node.id = ref;
  664. }
  665. return path;
  666. }
  667. };
  668. }