fields.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.buildCheckInRHS = buildCheckInRHS;
  6. exports.buildFieldsInitNodes = buildFieldsInitNodes;
  7. exports.buildPrivateNamesMap = buildPrivateNamesMap;
  8. exports.buildPrivateNamesNodes = buildPrivateNamesNodes;
  9. exports.transformPrivateNamesUsage = transformPrivateNamesUsage;
  10. var _core = require("@babel/core");
  11. var _helperReplaceSupers = require("@babel/helper-replace-supers");
  12. var _helperEnvironmentVisitor = require("@babel/helper-environment-visitor");
  13. var _helperMemberExpressionToFunctions = require("@babel/helper-member-expression-to-functions");
  14. var _helperOptimiseCallExpression = require("@babel/helper-optimise-call-expression");
  15. var _helperAnnotateAsPure = require("@babel/helper-annotate-as-pure");
  16. var _helperSkipTransparentExpressionWrappers = require("@babel/helper-skip-transparent-expression-wrappers");
  17. var ts = require("./typescript");
  18. function buildPrivateNamesMap(props) {
  19. const privateNamesMap = new Map();
  20. for (const prop of props) {
  21. if (prop.isPrivate()) {
  22. const {
  23. name
  24. } = prop.node.key.id;
  25. const update = privateNamesMap.has(name) ? privateNamesMap.get(name) : {
  26. id: prop.scope.generateUidIdentifier(name),
  27. static: prop.node.static,
  28. method: !prop.isProperty()
  29. };
  30. if (prop.isClassPrivateMethod()) {
  31. if (prop.node.kind === "get") {
  32. update.getId = prop.scope.generateUidIdentifier(`get_${name}`);
  33. } else if (prop.node.kind === "set") {
  34. update.setId = prop.scope.generateUidIdentifier(`set_${name}`);
  35. } else if (prop.node.kind === "method") {
  36. update.methodId = prop.scope.generateUidIdentifier(name);
  37. }
  38. }
  39. privateNamesMap.set(name, update);
  40. }
  41. }
  42. return privateNamesMap;
  43. }
  44. function buildPrivateNamesNodes(privateNamesMap, privateFieldsAsProperties, privateFieldsAsSymbols, 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. let init;
  56. if (privateFieldsAsProperties) {
  57. init = _core.types.callExpression(state.addHelper("classPrivateFieldLooseKey"), [_core.types.stringLiteral(name)]);
  58. } else if (privateFieldsAsSymbols) {
  59. init = _core.types.callExpression(_core.types.identifier("Symbol"), [_core.types.stringLiteral(name)]);
  60. } else if (!isStatic) {
  61. init = _core.types.newExpression(_core.types.identifier(!isMethod || isAccessor ? "WeakMap" : "WeakSet"), []);
  62. }
  63. if (init) {
  64. (0, _helperAnnotateAsPure.default)(init);
  65. initNodes.push(_core.template.statement.ast`var ${id} = ${init}`);
  66. }
  67. }
  68. return initNodes;
  69. }
  70. function privateNameVisitorFactory(visitor) {
  71. const nestedVisitor = _core.traverse.visitors.merge([Object.assign({}, visitor), _helperEnvironmentVisitor.default]);
  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. return privateNameVisitor;
  101. }
  102. const privateNameVisitor = privateNameVisitorFactory({
  103. PrivateName(path, {
  104. noDocumentAll
  105. }) {
  106. const {
  107. privateNamesMap,
  108. redeclared
  109. } = this;
  110. const {
  111. node,
  112. parentPath
  113. } = path;
  114. if (!parentPath.isMemberExpression({
  115. property: node
  116. }) && !parentPath.isOptionalMemberExpression({
  117. property: node
  118. })) {
  119. return;
  120. }
  121. const {
  122. name
  123. } = node.id;
  124. if (!privateNamesMap.has(name)) return;
  125. if (redeclared && redeclared.includes(name)) return;
  126. this.handle(parentPath, noDocumentAll);
  127. }
  128. });
  129. function unshadow(name, scope, innerBinding) {
  130. while ((_scope = scope) != null && _scope.hasBinding(name) && !scope.bindingIdentifierEquals(name, innerBinding)) {
  131. var _scope;
  132. scope.rename(name);
  133. scope = scope.parent;
  134. }
  135. }
  136. function buildCheckInRHS(rhs, file, inRHSIsObject) {
  137. if (inRHSIsObject || !(file.availableHelper != null && file.availableHelper("checkInRHS"))) return rhs;
  138. return _core.types.callExpression(file.addHelper("checkInRHS"), [rhs]);
  139. }
  140. const privateInVisitor = privateNameVisitorFactory({
  141. BinaryExpression(path, {
  142. file
  143. }) {
  144. const {
  145. operator,
  146. left,
  147. right
  148. } = path.node;
  149. if (operator !== "in") return;
  150. if (!_core.types.isPrivateName(left)) return;
  151. const {
  152. privateFieldsAsProperties,
  153. privateNamesMap,
  154. redeclared
  155. } = this;
  156. const {
  157. name
  158. } = left.id;
  159. if (!privateNamesMap.has(name)) return;
  160. if (redeclared && redeclared.includes(name)) return;
  161. unshadow(this.classRef.name, path.scope, this.innerBinding);
  162. if (privateFieldsAsProperties) {
  163. const {
  164. id
  165. } = privateNamesMap.get(name);
  166. path.replaceWith(_core.template.expression.ast`
  167. Object.prototype.hasOwnProperty.call(${buildCheckInRHS(right, file)}, ${_core.types.cloneNode(id)})
  168. `);
  169. return;
  170. }
  171. const {
  172. id,
  173. static: isStatic
  174. } = privateNamesMap.get(name);
  175. if (isStatic) {
  176. path.replaceWith(_core.template.expression.ast`${buildCheckInRHS(right, file)} === ${_core.types.cloneNode(this.classRef)}`);
  177. return;
  178. }
  179. path.replaceWith(_core.template.expression.ast`${_core.types.cloneNode(id)}.has(${buildCheckInRHS(right, file)})`);
  180. }
  181. });
  182. const privateNameHandlerSpec = {
  183. memoise(member, count) {
  184. const {
  185. scope
  186. } = member;
  187. const {
  188. object
  189. } = member.node;
  190. const memo = scope.maybeGenerateMemoised(object);
  191. if (!memo) {
  192. return;
  193. }
  194. this.memoiser.set(object, memo, count);
  195. },
  196. receiver(member) {
  197. const {
  198. object
  199. } = member.node;
  200. if (this.memoiser.has(object)) {
  201. return _core.types.cloneNode(this.memoiser.get(object));
  202. }
  203. return _core.types.cloneNode(object);
  204. },
  205. get(member) {
  206. const {
  207. classRef,
  208. privateNamesMap,
  209. file,
  210. innerBinding
  211. } = this;
  212. const {
  213. name
  214. } = member.node.property.id;
  215. const {
  216. id,
  217. static: isStatic,
  218. method: isMethod,
  219. methodId,
  220. getId,
  221. setId
  222. } = privateNamesMap.get(name);
  223. const isAccessor = getId || setId;
  224. if (isStatic) {
  225. const helperName = isMethod && !isAccessor ? "classStaticPrivateMethodGet" : "classStaticPrivateFieldSpecGet";
  226. unshadow(classRef.name, member.scope, innerBinding);
  227. return _core.types.callExpression(file.addHelper(helperName), [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id)]);
  228. }
  229. if (isMethod) {
  230. if (isAccessor) {
  231. if (!getId && setId) {
  232. if (file.availableHelper("writeOnlyError")) {
  233. return _core.types.sequenceExpression([this.receiver(member), _core.types.callExpression(file.addHelper("writeOnlyError"), [_core.types.stringLiteral(`#${name}`)])]);
  234. }
  235. console.warn(`@babel/helpers is outdated, update it to silence this warning.`);
  236. }
  237. return _core.types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core.types.cloneNode(id)]);
  238. }
  239. return _core.types.callExpression(file.addHelper("classPrivateMethodGet"), [this.receiver(member), _core.types.cloneNode(id), _core.types.cloneNode(methodId)]);
  240. }
  241. return _core.types.callExpression(file.addHelper("classPrivateFieldGet"), [this.receiver(member), _core.types.cloneNode(id)]);
  242. },
  243. boundGet(member) {
  244. this.memoise(member, 1);
  245. return _core.types.callExpression(_core.types.memberExpression(this.get(member), _core.types.identifier("bind")), [this.receiver(member)]);
  246. },
  247. set(member, value) {
  248. const {
  249. classRef,
  250. privateNamesMap,
  251. file
  252. } = this;
  253. const {
  254. name
  255. } = member.node.property.id;
  256. const {
  257. id,
  258. static: isStatic,
  259. method: isMethod,
  260. setId,
  261. getId
  262. } = privateNamesMap.get(name);
  263. const isAccessor = getId || setId;
  264. if (isStatic) {
  265. const helperName = isMethod && !isAccessor ? "classStaticPrivateMethodSet" : "classStaticPrivateFieldSpecSet";
  266. return _core.types.callExpression(file.addHelper(helperName), [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id), value]);
  267. }
  268. if (isMethod) {
  269. if (setId) {
  270. return _core.types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core.types.cloneNode(id), value]);
  271. }
  272. return _core.types.sequenceExpression([this.receiver(member), value, _core.types.callExpression(file.addHelper("readOnlyError"), [_core.types.stringLiteral(`#${name}`)])]);
  273. }
  274. return _core.types.callExpression(file.addHelper("classPrivateFieldSet"), [this.receiver(member), _core.types.cloneNode(id), value]);
  275. },
  276. destructureSet(member) {
  277. const {
  278. classRef,
  279. privateNamesMap,
  280. file
  281. } = this;
  282. const {
  283. name
  284. } = member.node.property.id;
  285. const {
  286. id,
  287. static: isStatic
  288. } = privateNamesMap.get(name);
  289. if (isStatic) {
  290. try {
  291. var helper = file.addHelper("classStaticPrivateFieldDestructureSet");
  292. } catch (_unused) {
  293. 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.");
  294. }
  295. return _core.types.memberExpression(_core.types.callExpression(helper, [this.receiver(member), _core.types.cloneNode(classRef), _core.types.cloneNode(id)]), _core.types.identifier("value"));
  296. }
  297. return _core.types.memberExpression(_core.types.callExpression(file.addHelper("classPrivateFieldDestructureSet"), [this.receiver(member), _core.types.cloneNode(id)]), _core.types.identifier("value"));
  298. },
  299. call(member, args) {
  300. this.memoise(member, 1);
  301. return (0, _helperOptimiseCallExpression.default)(this.get(member), this.receiver(member), args, false);
  302. },
  303. optionalCall(member, args) {
  304. this.memoise(member, 1);
  305. return (0, _helperOptimiseCallExpression.default)(this.get(member), this.receiver(member), args, true);
  306. }
  307. };
  308. const privateNameHandlerLoose = {
  309. get(member) {
  310. const {
  311. privateNamesMap,
  312. file
  313. } = this;
  314. const {
  315. object
  316. } = member.node;
  317. const {
  318. name
  319. } = member.node.property.id;
  320. return _core.template.expression`BASE(REF, PROP)[PROP]`({
  321. BASE: file.addHelper("classPrivateFieldLooseBase"),
  322. REF: _core.types.cloneNode(object),
  323. PROP: _core.types.cloneNode(privateNamesMap.get(name).id)
  324. });
  325. },
  326. set() {
  327. throw new Error("private name handler with loose = true don't need set()");
  328. },
  329. boundGet(member) {
  330. return _core.types.callExpression(_core.types.memberExpression(this.get(member), _core.types.identifier("bind")), [_core.types.cloneNode(member.node.object)]);
  331. },
  332. simpleSet(member) {
  333. return this.get(member);
  334. },
  335. destructureSet(member) {
  336. return this.get(member);
  337. },
  338. call(member, args) {
  339. return _core.types.callExpression(this.get(member), args);
  340. },
  341. optionalCall(member, args) {
  342. return _core.types.optionalCallExpression(this.get(member), args, true);
  343. }
  344. };
  345. function transformPrivateNamesUsage(ref, path, privateNamesMap, {
  346. privateFieldsAsProperties,
  347. noDocumentAll,
  348. innerBinding
  349. }, state) {
  350. if (!privateNamesMap.size) return;
  351. const body = path.get("body");
  352. const handler = privateFieldsAsProperties ? privateNameHandlerLoose : privateNameHandlerSpec;
  353. (0, _helperMemberExpressionToFunctions.default)(body, privateNameVisitor, Object.assign({
  354. privateNamesMap,
  355. classRef: ref,
  356. file: state
  357. }, handler, {
  358. noDocumentAll,
  359. innerBinding
  360. }));
  361. body.traverse(privateInVisitor, {
  362. privateNamesMap,
  363. classRef: ref,
  364. file: state,
  365. privateFieldsAsProperties,
  366. innerBinding
  367. });
  368. }
  369. function buildPrivateFieldInitLoose(ref, prop, privateNamesMap) {
  370. const {
  371. id
  372. } = privateNamesMap.get(prop.node.key.id.name);
  373. const value = prop.node.value || prop.scope.buildUndefinedNode();
  374. return inheritPropComments(_core.template.statement.ast`
  375. Object.defineProperty(${ref}, ${_core.types.cloneNode(id)}, {
  376. // configurable is false by default
  377. // enumerable is false by default
  378. writable: true,
  379. value: ${value}
  380. });
  381. `, prop);
  382. }
  383. function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap, state) {
  384. const {
  385. id
  386. } = privateNamesMap.get(prop.node.key.id.name);
  387. const value = prop.node.value || prop.scope.buildUndefinedNode();
  388. {
  389. if (!state.availableHelper("classPrivateFieldInitSpec")) {
  390. return inheritPropComments(_core.template.statement.ast`${_core.types.cloneNode(id)}.set(${ref}, {
  391. // configurable is always false for private elements
  392. // enumerable is always false for private elements
  393. writable: true,
  394. value: ${value},
  395. })`, prop);
  396. }
  397. }
  398. const helper = state.addHelper("classPrivateFieldInitSpec");
  399. return inheritPropComments(_core.template.statement.ast`${helper}(
  400. ${_core.types.thisExpression()},
  401. ${_core.types.cloneNode(id)},
  402. {
  403. writable: true,
  404. value: ${value}
  405. },
  406. )`, prop);
  407. }
  408. function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
  409. const privateName = privateNamesMap.get(prop.node.key.id.name);
  410. const {
  411. id,
  412. getId,
  413. setId,
  414. initAdded
  415. } = privateName;
  416. const isAccessor = getId || setId;
  417. if (!prop.isProperty() && (initAdded || !isAccessor)) return;
  418. if (isAccessor) {
  419. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  420. initAdded: true
  421. }));
  422. return inheritPropComments(_core.template.statement.ast`
  423. var ${_core.types.cloneNode(id)} = {
  424. // configurable is false by default
  425. // enumerable is false by default
  426. // writable is false by default
  427. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  428. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  429. }
  430. `, prop);
  431. }
  432. const value = prop.node.value || prop.scope.buildUndefinedNode();
  433. return inheritPropComments(_core.template.statement.ast`
  434. var ${_core.types.cloneNode(id)} = {
  435. // configurable is false by default
  436. // enumerable is false by default
  437. writable: true,
  438. value: ${value}
  439. };
  440. `, prop);
  441. }
  442. function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
  443. const privateName = privateNamesMap.get(prop.node.key.id.name);
  444. const {
  445. methodId,
  446. id,
  447. getId,
  448. setId,
  449. initAdded
  450. } = privateName;
  451. if (initAdded) return;
  452. if (methodId) {
  453. return inheritPropComments(_core.template.statement.ast`
  454. Object.defineProperty(${ref}, ${id}, {
  455. // configurable is false by default
  456. // enumerable is false by default
  457. // writable is false by default
  458. value: ${methodId.name}
  459. });
  460. `, prop);
  461. }
  462. const isAccessor = getId || setId;
  463. if (isAccessor) {
  464. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  465. initAdded: true
  466. }));
  467. return inheritPropComments(_core.template.statement.ast`
  468. Object.defineProperty(${ref}, ${id}, {
  469. // configurable is false by default
  470. // enumerable is false by default
  471. // writable is false by default
  472. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  473. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  474. });
  475. `, prop);
  476. }
  477. }
  478. function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap, state) {
  479. const privateName = privateNamesMap.get(prop.node.key.id.name);
  480. const {
  481. getId,
  482. setId,
  483. initAdded
  484. } = privateName;
  485. if (initAdded) return;
  486. const isAccessor = getId || setId;
  487. if (isAccessor) {
  488. return buildPrivateAccessorInitialization(ref, prop, privateNamesMap, state);
  489. }
  490. return buildPrivateInstanceMethodInitialization(ref, prop, privateNamesMap, state);
  491. }
  492. function buildPrivateAccessorInitialization(ref, prop, privateNamesMap, state) {
  493. const privateName = privateNamesMap.get(prop.node.key.id.name);
  494. const {
  495. id,
  496. getId,
  497. setId
  498. } = privateName;
  499. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  500. initAdded: true
  501. }));
  502. {
  503. if (!state.availableHelper("classPrivateFieldInitSpec")) {
  504. return inheritPropComments(_core.template.statement.ast`
  505. ${id}.set(${ref}, {
  506. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  507. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  508. });
  509. `, prop);
  510. }
  511. }
  512. const helper = state.addHelper("classPrivateFieldInitSpec");
  513. return inheritPropComments(_core.template.statement.ast`${helper}(
  514. ${_core.types.thisExpression()},
  515. ${_core.types.cloneNode(id)},
  516. {
  517. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  518. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  519. },
  520. )`, prop);
  521. }
  522. function buildPrivateInstanceMethodInitialization(ref, prop, privateNamesMap, state) {
  523. const privateName = privateNamesMap.get(prop.node.key.id.name);
  524. const {
  525. id
  526. } = privateName;
  527. {
  528. if (!state.availableHelper("classPrivateMethodInitSpec")) {
  529. return inheritPropComments(_core.template.statement.ast`${id}.add(${ref})`, prop);
  530. }
  531. }
  532. const helper = state.addHelper("classPrivateMethodInitSpec");
  533. return inheritPropComments(_core.template.statement.ast`${helper}(
  534. ${_core.types.thisExpression()},
  535. ${_core.types.cloneNode(id)}
  536. )`, prop);
  537. }
  538. function buildPublicFieldInitLoose(ref, prop) {
  539. const {
  540. key,
  541. computed
  542. } = prop.node;
  543. const value = prop.node.value || prop.scope.buildUndefinedNode();
  544. return inheritPropComments(_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.memberExpression(ref, key, computed || _core.types.isLiteral(key)), value)), prop);
  545. }
  546. function buildPublicFieldInitSpec(ref, prop, state) {
  547. const {
  548. key,
  549. computed
  550. } = prop.node;
  551. const value = prop.node.value || prop.scope.buildUndefinedNode();
  552. return inheritPropComments(_core.types.expressionStatement(_core.types.callExpression(state.addHelper("defineProperty"), [ref, computed || _core.types.isLiteral(key) ? key : _core.types.stringLiteral(key.name), value])), prop);
  553. }
  554. function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) {
  555. const privateName = privateNamesMap.get(prop.node.key.id.name);
  556. const {
  557. id,
  558. methodId,
  559. getId,
  560. setId,
  561. initAdded
  562. } = privateName;
  563. if (initAdded) return;
  564. const isAccessor = getId || setId;
  565. if (isAccessor) {
  566. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  567. initAdded: true
  568. }));
  569. return inheritPropComments(_core.template.statement.ast`
  570. Object.defineProperty(${ref}, ${id}, {
  571. // configurable is false by default
  572. // enumerable is false by default
  573. // writable is false by default
  574. get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
  575. set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
  576. })
  577. `, prop);
  578. }
  579. return inheritPropComments(_core.template.statement.ast`
  580. Object.defineProperty(${ref}, ${id}, {
  581. // configurable is false by default
  582. // enumerable is false by default
  583. // writable is false by default
  584. value: ${methodId.name}
  585. });
  586. `, prop);
  587. }
  588. function buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties = false) {
  589. const privateName = privateNamesMap.get(prop.node.key.id.name);
  590. const {
  591. id,
  592. methodId,
  593. getId,
  594. setId,
  595. getterDeclared,
  596. setterDeclared,
  597. static: isStatic
  598. } = privateName;
  599. const {
  600. params,
  601. body,
  602. generator,
  603. async
  604. } = prop.node;
  605. const isGetter = getId && !getterDeclared && params.length === 0;
  606. const isSetter = setId && !setterDeclared && params.length > 0;
  607. let declId = methodId;
  608. if (isGetter) {
  609. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  610. getterDeclared: true
  611. }));
  612. declId = getId;
  613. } else if (isSetter) {
  614. privateNamesMap.set(prop.node.key.id.name, Object.assign({}, privateName, {
  615. setterDeclared: true
  616. }));
  617. declId = setId;
  618. } else if (isStatic && !privateFieldsAsProperties) {
  619. declId = id;
  620. }
  621. return inheritPropComments(_core.types.functionDeclaration(_core.types.cloneNode(declId), params, body, generator, async), prop);
  622. }
  623. const thisContextVisitor = _core.traverse.visitors.merge([{
  624. ThisExpression(path, state) {
  625. const parent = path.findParent(path => !(0, _helperSkipTransparentExpressionWrappers.isTransparentExprWrapper)(path.node));
  626. if (_core.types.isUnaryExpression(parent.node, {
  627. operator: "delete"
  628. })) {
  629. path.parentPath.replaceWith(_core.types.booleanLiteral(true));
  630. return;
  631. }
  632. state.needsClassRef = true;
  633. path.replaceWith(_core.types.cloneNode(state.classRef));
  634. },
  635. MetaProperty(path) {
  636. const meta = path.get("meta");
  637. const property = path.get("property");
  638. const {
  639. scope
  640. } = path;
  641. if (meta.isIdentifier({
  642. name: "new"
  643. }) && property.isIdentifier({
  644. name: "target"
  645. })) {
  646. path.replaceWith(scope.buildUndefinedNode());
  647. }
  648. }
  649. }, _helperEnvironmentVisitor.default]);
  650. const innerReferencesVisitor = {
  651. ReferencedIdentifier(path, state) {
  652. if (path.scope.bindingIdentifierEquals(path.node.name, state.innerBinding)) {
  653. state.needsClassRef = true;
  654. path.node.name = state.classRef.name;
  655. }
  656. }
  657. };
  658. function replaceThisContext(path, ref, getSuperRef, file, isStaticBlock, constantSuper, innerBindingRef) {
  659. var _state$classRef;
  660. const state = {
  661. classRef: ref,
  662. needsClassRef: false,
  663. innerBinding: innerBindingRef
  664. };
  665. const replacer = new _helperReplaceSupers.default({
  666. methodPath: path,
  667. constantSuper,
  668. file,
  669. refToPreserve: ref,
  670. getSuperRef,
  671. getObjectRef() {
  672. state.needsClassRef = true;
  673. return _core.types.isStaticBlock != null && _core.types.isStaticBlock(path.node) || path.node.static ? ref : _core.types.memberExpression(ref, _core.types.identifier("prototype"));
  674. }
  675. });
  676. replacer.replace();
  677. if (isStaticBlock || path.isProperty()) {
  678. path.traverse(thisContextVisitor, state);
  679. }
  680. if (innerBindingRef != null && (_state$classRef = state.classRef) != null && _state$classRef.name && state.classRef.name !== (innerBindingRef == null ? void 0 : innerBindingRef.name)) {
  681. path.traverse(innerReferencesVisitor, state);
  682. }
  683. return state.needsClassRef;
  684. }
  685. function isNameOrLength({
  686. key,
  687. computed
  688. }) {
  689. if (key.type === "Identifier") {
  690. return !computed && (key.name === "name" || key.name === "length");
  691. }
  692. if (key.type === "StringLiteral") {
  693. return key.value === "name" || key.value === "length";
  694. }
  695. return false;
  696. }
  697. function inheritPropComments(node, prop) {
  698. _core.types.inheritLeadingComments(node, prop.node);
  699. _core.types.inheritInnerComments(node, prop.node);
  700. return node;
  701. }
  702. function buildFieldsInitNodes(ref, superRef, props, privateNamesMap, state, setPublicClassFields, privateFieldsAsProperties, constantSuper, innerBindingRef) {
  703. let needsClassRef = false;
  704. let injectSuperRef;
  705. const staticNodes = [];
  706. const instanceNodes = [];
  707. const pureStaticNodes = [];
  708. const getSuperRef = _core.types.isIdentifier(superRef) ? () => superRef : () => {
  709. var _injectSuperRef;
  710. (_injectSuperRef = injectSuperRef) != null ? _injectSuperRef : injectSuperRef = props[0].scope.generateUidIdentifierBasedOnNode(superRef);
  711. return injectSuperRef;
  712. };
  713. for (const prop of props) {
  714. prop.isClassProperty() && ts.assertFieldTransformed(prop);
  715. const isStatic = !(_core.types.isStaticBlock != null && _core.types.isStaticBlock(prop.node)) && prop.node.static;
  716. const isInstance = !isStatic;
  717. const isPrivate = prop.isPrivate();
  718. const isPublic = !isPrivate;
  719. const isField = prop.isProperty();
  720. const isMethod = !isField;
  721. const isStaticBlock = prop.isStaticBlock == null ? void 0 : prop.isStaticBlock();
  722. if (isStatic || isMethod && isPrivate || isStaticBlock) {
  723. const replaced = replaceThisContext(prop, ref, getSuperRef, state, isStaticBlock, constantSuper, innerBindingRef);
  724. needsClassRef = needsClassRef || replaced;
  725. }
  726. switch (true) {
  727. case isStaticBlock:
  728. {
  729. const blockBody = prop.node.body;
  730. if (blockBody.length === 1 && _core.types.isExpressionStatement(blockBody[0])) {
  731. staticNodes.push(inheritPropComments(blockBody[0], prop));
  732. } else {
  733. staticNodes.push(_core.types.inheritsComments(_core.template.statement.ast`(() => { ${blockBody} })()`, prop.node));
  734. }
  735. break;
  736. }
  737. case isStatic && isPrivate && isField && privateFieldsAsProperties:
  738. needsClassRef = true;
  739. staticNodes.push(buildPrivateFieldInitLoose(_core.types.cloneNode(ref), prop, privateNamesMap));
  740. break;
  741. case isStatic && isPrivate && isField && !privateFieldsAsProperties:
  742. needsClassRef = true;
  743. staticNodes.push(buildPrivateStaticFieldInitSpec(prop, privateNamesMap));
  744. break;
  745. case isStatic && isPublic && isField && setPublicClassFields:
  746. if (!isNameOrLength(prop.node)) {
  747. needsClassRef = true;
  748. staticNodes.push(buildPublicFieldInitLoose(_core.types.cloneNode(ref), prop));
  749. break;
  750. }
  751. case isStatic && isPublic && isField && !setPublicClassFields:
  752. needsClassRef = true;
  753. staticNodes.push(buildPublicFieldInitSpec(_core.types.cloneNode(ref), prop, state));
  754. break;
  755. case isInstance && isPrivate && isField && privateFieldsAsProperties:
  756. instanceNodes.push(buildPrivateFieldInitLoose(_core.types.thisExpression(), prop, privateNamesMap));
  757. break;
  758. case isInstance && isPrivate && isField && !privateFieldsAsProperties:
  759. instanceNodes.push(buildPrivateInstanceFieldInitSpec(_core.types.thisExpression(), prop, privateNamesMap, state));
  760. break;
  761. case isInstance && isPrivate && isMethod && privateFieldsAsProperties:
  762. instanceNodes.unshift(buildPrivateMethodInitLoose(_core.types.thisExpression(), prop, privateNamesMap));
  763. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  764. break;
  765. case isInstance && isPrivate && isMethod && !privateFieldsAsProperties:
  766. instanceNodes.unshift(buildPrivateInstanceMethodInitSpec(_core.types.thisExpression(), prop, privateNamesMap, state));
  767. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  768. break;
  769. case isStatic && isPrivate && isMethod && !privateFieldsAsProperties:
  770. needsClassRef = true;
  771. staticNodes.unshift(buildPrivateStaticFieldInitSpec(prop, privateNamesMap));
  772. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  773. break;
  774. case isStatic && isPrivate && isMethod && privateFieldsAsProperties:
  775. needsClassRef = true;
  776. staticNodes.unshift(buildPrivateStaticMethodInitLoose(_core.types.cloneNode(ref), prop, state, privateNamesMap));
  777. pureStaticNodes.push(buildPrivateMethodDeclaration(prop, privateNamesMap, privateFieldsAsProperties));
  778. break;
  779. case isInstance && isPublic && isField && setPublicClassFields:
  780. instanceNodes.push(buildPublicFieldInitLoose(_core.types.thisExpression(), prop));
  781. break;
  782. case isInstance && isPublic && isField && !setPublicClassFields:
  783. instanceNodes.push(buildPublicFieldInitSpec(_core.types.thisExpression(), prop, state));
  784. break;
  785. default:
  786. throw new Error("Unreachable.");
  787. }
  788. }
  789. return {
  790. staticNodes: staticNodes.filter(Boolean),
  791. instanceNodes: instanceNodes.filter(Boolean),
  792. pureStaticNodes: pureStaticNodes.filter(Boolean),
  793. wrapClass(path) {
  794. for (const prop of props) {
  795. prop.remove();
  796. }
  797. if (injectSuperRef) {
  798. path.scope.push({
  799. id: _core.types.cloneNode(injectSuperRef)
  800. });
  801. path.set("superClass", _core.types.assignmentExpression("=", injectSuperRef, path.node.superClass));
  802. }
  803. if (!needsClassRef) return path;
  804. if (path.isClassExpression()) {
  805. path.scope.push({
  806. id: ref
  807. });
  808. path.replaceWith(_core.types.assignmentExpression("=", _core.types.cloneNode(ref), path.node));
  809. } else if (!path.node.id) {
  810. path.node.id = ref;
  811. }
  812. return path;
  813. }
  814. };
  815. }
  816. //# sourceMappingURL=fields.js.map