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