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