UNPKG

44 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { equals } = require("./util/ArrayHelpers");
9const SortableSet = require("./util/SortableSet");
10const makeSerializable = require("./util/makeSerializable");
11const { forEachRuntime } = require("./util/runtime");
12
13/** @typedef {import("./Dependency").RuntimeSpec} RuntimeSpec */
14/** @typedef {import("./Module")} Module */
15/** @typedef {import("./ModuleGraph")} ModuleGraph */
16/** @typedef {import("./ModuleGraphConnection")} ModuleGraphConnection */
17/** @typedef {import("./util/Hash")} Hash */
18
19/** @typedef {typeof UsageState.OnlyPropertiesUsed | typeof UsageState.NoInfo | typeof UsageState.Unknown | typeof UsageState.Used} RuntimeUsageStateType */
20/** @typedef {typeof UsageState.Unused | RuntimeUsageStateType} UsageStateType */
21
22const UsageState = Object.freeze({
23 Unused: /** @type {0} */ (0),
24 OnlyPropertiesUsed: /** @type {1} */ (1),
25 NoInfo: /** @type {2} */ (2),
26 Unknown: /** @type {3} */ (3),
27 Used: /** @type {4} */ (4)
28});
29
30const RETURNS_TRUE = () => true;
31
32const CIRCULAR = Symbol("circular target");
33
34class RestoreProvidedData {
35 constructor(
36 exports,
37 otherProvided,
38 otherCanMangleProvide,
39 otherTerminalBinding
40 ) {
41 this.exports = exports;
42 this.otherProvided = otherProvided;
43 this.otherCanMangleProvide = otherCanMangleProvide;
44 this.otherTerminalBinding = otherTerminalBinding;
45 }
46
47 serialize({ write }) {
48 write(this.exports);
49 write(this.otherProvided);
50 write(this.otherCanMangleProvide);
51 write(this.otherTerminalBinding);
52 }
53
54 static deserialize({ read }) {
55 return new RestoreProvidedData(read(), read(), read(), read());
56 }
57}
58
59makeSerializable(
60 RestoreProvidedData,
61 "webpack/lib/ModuleGraph",
62 "RestoreProvidedData"
63);
64
65class ExportsInfo {
66 constructor() {
67 /** @type {Map<string, ExportInfo>} */
68 this._exports = new Map();
69 this._otherExportsInfo = new ExportInfo(null);
70 this._sideEffectsOnlyInfo = new ExportInfo("*side effects only*");
71 this._exportsAreOrdered = false;
72 /** @type {ExportsInfo=} */
73 this._redirectTo = undefined;
74 }
75
76 /**
77 * @returns {Iterable<ExportInfo>} all owned exports in any order
78 */
79 get ownedExports() {
80 return this._exports.values();
81 }
82
83 /**
84 * @returns {Iterable<ExportInfo>} all owned exports in order
85 */
86 get orderedOwnedExports() {
87 if (!this._exportsAreOrdered) {
88 this._sortExports();
89 }
90 return this._exports.values();
91 }
92
93 /**
94 * @returns {Iterable<ExportInfo>} all exports in any order
95 */
96 get exports() {
97 if (this._redirectTo !== undefined) {
98 const map = new Map(this._redirectTo._exports);
99 for (const [key, value] of this._exports) {
100 map.set(key, value);
101 }
102 return map.values();
103 }
104 return this._exports.values();
105 }
106
107 /**
108 * @returns {Iterable<ExportInfo>} all exports in order
109 */
110 get orderedExports() {
111 if (!this._exportsAreOrdered) {
112 this._sortExports();
113 }
114 if (this._redirectTo !== undefined) {
115 const map = new Map(
116 Array.from(this._redirectTo.orderedExports, item => [item.name, item])
117 );
118 for (const [key, value] of this._exports) {
119 map.set(key, value);
120 }
121 // sorting should be pretty fast as map contains
122 // a lot of presorted items
123 this._sortExportsMap(map);
124 return map.values();
125 }
126 return this._exports.values();
127 }
128
129 /**
130 * @returns {ExportInfo} the export info of unlisted exports
131 */
132 get otherExportsInfo() {
133 if (this._redirectTo !== undefined)
134 return this._redirectTo.otherExportsInfo;
135 return this._otherExportsInfo;
136 }
137
138 _sortExportsMap(exports) {
139 if (exports.size > 1) {
140 const namesInOrder = [];
141 for (const entry of exports.values()) {
142 namesInOrder.push(entry.name);
143 }
144 namesInOrder.sort();
145 let i = 0;
146 for (const entry of exports.values()) {
147 const name = namesInOrder[i];
148 if (entry.name !== name) break;
149 i++;
150 }
151 for (; i < namesInOrder.length; i++) {
152 const name = namesInOrder[i];
153 const correctEntry = exports.get(name);
154 exports.delete(name);
155 exports.set(name, correctEntry);
156 }
157 }
158 }
159
160 _sortExports() {
161 this._sortExportsMap(this._exports);
162 this._exportsAreOrdered = true;
163 }
164
165 setRedirectNamedTo(exportsInfo) {
166 if (this._redirectTo === exportsInfo) return false;
167 this._redirectTo = exportsInfo;
168 return true;
169 }
170
171 setHasProvideInfo() {
172 for (const exportInfo of this._exports.values()) {
173 if (exportInfo.provided === undefined) {
174 exportInfo.provided = false;
175 }
176 if (exportInfo.canMangleProvide === undefined) {
177 exportInfo.canMangleProvide = true;
178 }
179 }
180 if (this._redirectTo !== undefined) {
181 this._redirectTo.setHasProvideInfo();
182 } else {
183 if (this._otherExportsInfo.provided === undefined) {
184 this._otherExportsInfo.provided = false;
185 }
186 if (this._otherExportsInfo.canMangleProvide === undefined) {
187 this._otherExportsInfo.canMangleProvide = true;
188 }
189 }
190 }
191
192 setHasUseInfo() {
193 for (const exportInfo of this._exports.values()) {
194 exportInfo.setHasUseInfo();
195 }
196 this._sideEffectsOnlyInfo.setHasUseInfo();
197 if (this._redirectTo !== undefined) {
198 this._redirectTo.setHasUseInfo();
199 } else {
200 this._otherExportsInfo.setHasUseInfo();
201 if (this._otherExportsInfo.canMangleUse === undefined) {
202 this._otherExportsInfo.canMangleUse = true;
203 }
204 }
205 }
206
207 /**
208 * @param {string} name export name
209 * @returns {ExportInfo} export info for this name
210 */
211 getOwnExportInfo(name) {
212 const info = this._exports.get(name);
213 if (info !== undefined) return info;
214 const newInfo = new ExportInfo(name, this._otherExportsInfo);
215 this._exports.set(name, newInfo);
216 this._exportsAreOrdered = false;
217 return newInfo;
218 }
219
220 /**
221 * @param {string} name export name
222 * @returns {ExportInfo} export info for this name
223 */
224 getExportInfo(name) {
225 const info = this._exports.get(name);
226 if (info !== undefined) return info;
227 if (this._redirectTo !== undefined)
228 return this._redirectTo.getExportInfo(name);
229 const newInfo = new ExportInfo(name, this._otherExportsInfo);
230 this._exports.set(name, newInfo);
231 this._exportsAreOrdered = false;
232 return newInfo;
233 }
234
235 /**
236 * @param {string} name export name
237 * @returns {ExportInfo} export info for this name
238 */
239 getReadOnlyExportInfo(name) {
240 const info = this._exports.get(name);
241 if (info !== undefined) return info;
242 if (this._redirectTo !== undefined)
243 return this._redirectTo.getReadOnlyExportInfo(name);
244 return this._otherExportsInfo;
245 }
246
247 /**
248 * @param {string[]} name export name
249 * @returns {ExportInfo | undefined} export info for this name
250 */
251 getReadOnlyExportInfoRecursive(name) {
252 const exportInfo = this.getReadOnlyExportInfo(name[0]);
253 if (name.length === 1) return exportInfo;
254 if (!exportInfo.exportsInfo) return undefined;
255 return exportInfo.exportsInfo.getReadOnlyExportInfoRecursive(name.slice(1));
256 }
257
258 /**
259 * @param {string[]=} name the export name
260 * @returns {ExportsInfo | undefined} the nested exports info
261 */
262 getNestedExportsInfo(name) {
263 if (Array.isArray(name) && name.length > 0) {
264 const info = this.getReadOnlyExportInfo(name[0]);
265 if (!info.exportsInfo) return undefined;
266 return info.exportsInfo.getNestedExportsInfo(name.slice(1));
267 }
268 return this;
269 }
270
271 /**
272 * @param {boolean=} canMangle true, if exports can still be mangled (defaults to false)
273 * @param {Set<string>=} excludeExports list of unaffected exports
274 * @param {any=} targetKey use this as key for the target
275 * @param {ModuleGraphConnection=} targetModule set this module as target
276 * @param {number=} priority priority
277 * @returns {boolean} true, if this call changed something
278 */
279 setUnknownExportsProvided(
280 canMangle,
281 excludeExports,
282 targetKey,
283 targetModule,
284 priority
285 ) {
286 let changed = false;
287 if (excludeExports) {
288 for (const name of excludeExports) {
289 // Make sure these entries exist, so they can get different info
290 this.getExportInfo(name);
291 }
292 }
293 for (const exportInfo of this._exports.values()) {
294 if (!canMangle && exportInfo.canMangleProvide !== false) {
295 exportInfo.canMangleProvide = false;
296 changed = true;
297 }
298 if (excludeExports && excludeExports.has(exportInfo.name)) continue;
299 if (exportInfo.provided !== true && exportInfo.provided !== null) {
300 exportInfo.provided = null;
301 changed = true;
302 }
303 if (targetKey) {
304 exportInfo.setTarget(targetKey, targetModule, [exportInfo.name], -1);
305 }
306 }
307 if (this._redirectTo !== undefined) {
308 if (
309 this._redirectTo.setUnknownExportsProvided(
310 canMangle,
311 excludeExports,
312 targetKey,
313 targetModule,
314 priority
315 )
316 ) {
317 changed = true;
318 }
319 } else {
320 if (
321 this._otherExportsInfo.provided !== true &&
322 this._otherExportsInfo.provided !== null
323 ) {
324 this._otherExportsInfo.provided = null;
325 changed = true;
326 }
327 if (!canMangle && this._otherExportsInfo.canMangleProvide !== false) {
328 this._otherExportsInfo.canMangleProvide = false;
329 changed = true;
330 }
331 if (targetKey) {
332 this._otherExportsInfo.setTarget(
333 targetKey,
334 targetModule,
335 undefined,
336 priority
337 );
338 }
339 }
340 return changed;
341 }
342
343 /**
344 * @param {RuntimeSpec} runtime the runtime
345 * @returns {boolean} true, when something changed
346 */
347 setUsedInUnknownWay(runtime) {
348 let changed = false;
349 for (const exportInfo of this._exports.values()) {
350 if (exportInfo.setUsedInUnknownWay(runtime)) {
351 changed = true;
352 }
353 }
354 if (this._redirectTo !== undefined) {
355 if (this._redirectTo.setUsedInUnknownWay(runtime)) {
356 changed = true;
357 }
358 } else {
359 if (
360 this._otherExportsInfo.setUsedConditionally(
361 used => used < UsageState.Unknown,
362 UsageState.Unknown,
363 runtime
364 )
365 ) {
366 changed = true;
367 }
368 if (this._otherExportsInfo.canMangleUse !== false) {
369 this._otherExportsInfo.canMangleUse = false;
370 changed = true;
371 }
372 }
373 return changed;
374 }
375
376 /**
377 * @param {RuntimeSpec} runtime the runtime
378 * @returns {boolean} true, when something changed
379 */
380 setUsedWithoutInfo(runtime) {
381 let changed = false;
382 for (const exportInfo of this._exports.values()) {
383 if (exportInfo.setUsedWithoutInfo(runtime)) {
384 changed = true;
385 }
386 }
387 if (this._redirectTo !== undefined) {
388 if (this._redirectTo.setUsedWithoutInfo(runtime)) {
389 changed = true;
390 }
391 } else {
392 if (this._otherExportsInfo.setUsed(UsageState.NoInfo, runtime)) {
393 changed = true;
394 }
395 if (this._otherExportsInfo.canMangleUse !== false) {
396 this._otherExportsInfo.canMangleUse = false;
397 changed = true;
398 }
399 }
400 return changed;
401 }
402
403 /**
404 * @param {RuntimeSpec} runtime the runtime
405 * @returns {boolean} true, when something changed
406 */
407 setAllKnownExportsUsed(runtime) {
408 let changed = false;
409 for (const exportInfo of this._exports.values()) {
410 if (!exportInfo.provided) continue;
411 if (exportInfo.setUsed(UsageState.Used, runtime)) {
412 changed = true;
413 }
414 }
415 return changed;
416 }
417
418 /**
419 * @param {RuntimeSpec} runtime the runtime
420 * @returns {boolean} true, when something changed
421 */
422 setUsedForSideEffectsOnly(runtime) {
423 return this._sideEffectsOnlyInfo.setUsedConditionally(
424 used => used === UsageState.Unused,
425 UsageState.Used,
426 runtime
427 );
428 }
429
430 /**
431 * @param {RuntimeSpec} runtime the runtime
432 * @returns {boolean} true, when the module exports are used in any way
433 */
434 isUsed(runtime) {
435 if (this._redirectTo !== undefined) {
436 if (this._redirectTo.isUsed(runtime)) {
437 return true;
438 }
439 } else {
440 if (this._otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
441 return true;
442 }
443 }
444 for (const exportInfo of this._exports.values()) {
445 if (exportInfo.getUsed(runtime) !== UsageState.Unused) {
446 return true;
447 }
448 }
449 return false;
450 }
451
452 /**
453 * @param {RuntimeSpec} runtime the runtime
454 * @returns {boolean} true, when the module is used in any way
455 */
456 isModuleUsed(runtime) {
457 if (this.isUsed(runtime)) return true;
458 if (this._sideEffectsOnlyInfo.getUsed(runtime) !== UsageState.Unused)
459 return true;
460 return false;
461 }
462
463 /**
464 * @param {RuntimeSpec} runtime the runtime
465 * @returns {SortableSet<string> | boolean | null} set of used exports, or true (when namespace object is used), or false (when unused), or null (when unknown)
466 */
467 getUsedExports(runtime) {
468 if (!this._redirectTo !== undefined) {
469 switch (this._otherExportsInfo.getUsed(runtime)) {
470 case UsageState.NoInfo:
471 return null;
472 case UsageState.Unknown:
473 case UsageState.OnlyPropertiesUsed:
474 case UsageState.Used:
475 return true;
476 }
477 }
478 const array = [];
479 if (!this._exportsAreOrdered) this._sortExports();
480 for (const exportInfo of this._exports.values()) {
481 switch (exportInfo.getUsed(runtime)) {
482 case UsageState.NoInfo:
483 return null;
484 case UsageState.Unknown:
485 return true;
486 case UsageState.OnlyPropertiesUsed:
487 case UsageState.Used:
488 array.push(exportInfo.name);
489 }
490 }
491 if (this._redirectTo !== undefined) {
492 const inner = this._redirectTo.getUsedExports(runtime);
493 if (inner === null) return null;
494 if (inner === true) return true;
495 if (inner !== false) {
496 for (const item of inner) {
497 array.push(item);
498 }
499 }
500 }
501 if (array.length === 0) {
502 switch (this._sideEffectsOnlyInfo.getUsed(runtime)) {
503 case UsageState.NoInfo:
504 return null;
505 case UsageState.Unused:
506 return false;
507 }
508 }
509 return new SortableSet(array);
510 }
511
512 /**
513 * @returns {null | true | string[]} list of exports when known
514 */
515 getProvidedExports() {
516 if (!this._redirectTo !== undefined) {
517 switch (this._otherExportsInfo.provided) {
518 case undefined:
519 return null;
520 case null:
521 return true;
522 case true:
523 return true;
524 }
525 }
526 const array = [];
527 if (!this._exportsAreOrdered) this._sortExports();
528 for (const exportInfo of this._exports.values()) {
529 switch (exportInfo.provided) {
530 case undefined:
531 return null;
532 case null:
533 return true;
534 case true:
535 array.push(exportInfo.name);
536 }
537 }
538 if (this._redirectTo !== undefined) {
539 const inner = this._redirectTo.getProvidedExports();
540 if (inner === null) return null;
541 if (inner === true) return true;
542 for (const item of inner) {
543 if (!array.includes(item)) {
544 array.push(item);
545 }
546 }
547 }
548 return array;
549 }
550
551 /**
552 * @param {RuntimeSpec} runtime the runtime
553 * @returns {ExportInfo[]} exports that are relevant (not unused and potential provided)
554 */
555 getRelevantExports(runtime) {
556 const list = [];
557 for (const exportInfo of this._exports.values()) {
558 const used = exportInfo.getUsed(runtime);
559 if (used === UsageState.Unused) continue;
560 if (exportInfo.provided === false) continue;
561 list.push(exportInfo);
562 }
563 if (this._redirectTo !== undefined) {
564 for (const exportInfo of this._redirectTo.getRelevantExports(runtime)) {
565 if (!this._exports.has(exportInfo.name)) list.push(exportInfo);
566 }
567 }
568 if (
569 this._otherExportsInfo.provided !== false &&
570 this._otherExportsInfo.getUsed(runtime) !== UsageState.Unused
571 ) {
572 list.push(this._otherExportsInfo);
573 }
574 return list;
575 }
576
577 /**
578 * @param {string | string[]} name the name of the export
579 * @returns {boolean | undefined | null} if the export is provided
580 */
581 isExportProvided(name) {
582 if (Array.isArray(name)) {
583 const info = this.getReadOnlyExportInfo(name[0]);
584 if (info.exportsInfo && name.length > 1) {
585 return info.exportsInfo.isExportProvided(name.slice(1));
586 }
587 return info.provided ? name.length === 1 || undefined : info.provided;
588 }
589 const info = this.getReadOnlyExportInfo(name);
590 return info.provided;
591 }
592
593 /**
594 * @param {RuntimeSpec} runtime runtime
595 * @returns {string} key representing the usage
596 */
597 getUsageKey(runtime) {
598 const key = [];
599 if (this._redirectTo !== undefined) {
600 key.push(this._redirectTo.getUsageKey(runtime));
601 } else {
602 key.push(this._otherExportsInfo.getUsed(runtime));
603 }
604 key.push(this._sideEffectsOnlyInfo.getUsed(runtime));
605 for (const exportInfo of this.orderedOwnedExports) {
606 key.push(exportInfo.getUsed(runtime));
607 }
608 return key.join("|");
609 }
610
611 /**
612 * @param {RuntimeSpec} runtimeA first runtime
613 * @param {RuntimeSpec} runtimeB second runtime
614 * @returns {boolean} true, when equally used
615 */
616 isEquallyUsed(runtimeA, runtimeB) {
617 if (this._redirectTo !== undefined) {
618 if (!this._redirectTo.isEquallyUsed(runtimeA, runtimeB)) return false;
619 } else {
620 if (
621 this._otherExportsInfo.getUsed(runtimeA) !==
622 this._otherExportsInfo.getUsed(runtimeB)
623 ) {
624 return false;
625 }
626 }
627 if (
628 this._sideEffectsOnlyInfo.getUsed(runtimeA) !==
629 this._sideEffectsOnlyInfo.getUsed(runtimeB)
630 ) {
631 return false;
632 }
633 for (const exportInfo of this.ownedExports) {
634 if (exportInfo.getUsed(runtimeA) !== exportInfo.getUsed(runtimeB))
635 return false;
636 }
637 return true;
638 }
639
640 /**
641 * @param {string | string[]} name export name
642 * @param {RuntimeSpec} runtime check usage for this runtime only
643 * @returns {UsageStateType} usage status
644 */
645 getUsed(name, runtime) {
646 if (Array.isArray(name)) {
647 if (name.length === 0) return this.otherExportsInfo.getUsed(runtime);
648 let info = this.getReadOnlyExportInfo(name[0]);
649 if (info.exportsInfo && name.length > 1) {
650 return info.exportsInfo.getUsed(name.slice(1), runtime);
651 }
652 return info.getUsed(runtime);
653 }
654 let info = this.getReadOnlyExportInfo(name);
655 return info.getUsed(runtime);
656 }
657
658 /**
659 * @param {string | string[]} name the export name
660 * @param {RuntimeSpec} runtime check usage for this runtime only
661 * @returns {string | string[] | false} the used name
662 */
663 getUsedName(name, runtime) {
664 if (Array.isArray(name)) {
665 // TODO improve this
666 if (name.length === 0) {
667 if (!this.isUsed(runtime)) return false;
668 return name;
669 }
670 let info = this.getReadOnlyExportInfo(name[0]);
671 const x = info.getUsedName(name[0], runtime);
672 if (x === false) return false;
673 const arr = x === name[0] && name.length === 1 ? name : [x];
674 if (name.length === 1) {
675 return arr;
676 }
677 if (
678 info.exportsInfo &&
679 info.getUsed(runtime) === UsageState.OnlyPropertiesUsed
680 ) {
681 const nested = info.exportsInfo.getUsedName(name.slice(1), runtime);
682 if (!nested) return false;
683 return arr.concat(nested);
684 } else {
685 return arr.concat(name.slice(1));
686 }
687 } else {
688 let info = this.getReadOnlyExportInfo(name);
689 const usedName = info.getUsedName(name, runtime);
690 return usedName;
691 }
692 }
693
694 /**
695 * @param {Hash} hash the hash
696 * @param {RuntimeSpec} runtime the runtime
697 * @returns {void}
698 */
699 updateHash(hash, runtime) {
700 this._updateHash(hash, runtime, new Set());
701 }
702
703 /**
704 * @param {Hash} hash the hash
705 * @param {RuntimeSpec} runtime the runtime
706 * @param {Set<ExportsInfo>} alreadyVisitedExportsInfo for circular references
707 * @returns {void}
708 */
709 _updateHash(hash, runtime, alreadyVisitedExportsInfo) {
710 const set = new Set(alreadyVisitedExportsInfo);
711 set.add(this);
712 for (const exportInfo of this.orderedExports) {
713 if (exportInfo.hasInfo(this._otherExportsInfo, runtime)) {
714 exportInfo._updateHash(hash, runtime, set);
715 }
716 }
717 this._sideEffectsOnlyInfo._updateHash(hash, runtime, set);
718 this._otherExportsInfo._updateHash(hash, runtime, set);
719 if (this._redirectTo !== undefined) {
720 this._redirectTo._updateHash(hash, runtime, set);
721 }
722 }
723
724 getRestoreProvidedData() {
725 const otherProvided = this._otherExportsInfo.provided;
726 const otherCanMangleProvide = this._otherExportsInfo.canMangleProvide;
727 const otherTerminalBinding = this._otherExportsInfo.terminalBinding;
728 const exports = [];
729 for (const exportInfo of this.orderedExports) {
730 if (
731 exportInfo.provided !== otherProvided ||
732 exportInfo.canMangleProvide !== otherCanMangleProvide ||
733 exportInfo.terminalBinding !== otherTerminalBinding ||
734 exportInfo.exportsInfoOwned
735 ) {
736 exports.push({
737 name: exportInfo.name,
738 provided: exportInfo.provided,
739 canMangleProvide: exportInfo.canMangleProvide,
740 terminalBinding: exportInfo.terminalBinding,
741 exportsInfo: exportInfo.exportsInfoOwned
742 ? exportInfo.exportsInfo.getRestoreProvidedData()
743 : undefined
744 });
745 }
746 }
747 return new RestoreProvidedData(
748 exports,
749 otherProvided,
750 otherCanMangleProvide,
751 otherTerminalBinding
752 );
753 }
754
755 restoreProvided({
756 otherProvided,
757 otherCanMangleProvide,
758 otherTerminalBinding,
759 exports
760 }) {
761 let wasEmpty = true;
762 for (const exportInfo of this._exports.values()) {
763 wasEmpty = false;
764 exportInfo.provided = otherProvided;
765 exportInfo.canMangleProvide = otherCanMangleProvide;
766 exportInfo.terminalBinding = otherTerminalBinding;
767 }
768 this._otherExportsInfo.provided = otherProvided;
769 this._otherExportsInfo.canMangleProvide = otherCanMangleProvide;
770 this._otherExportsInfo.terminalBinding = otherTerminalBinding;
771 for (const exp of exports) {
772 const exportInfo = this.getExportInfo(exp.name);
773 exportInfo.provided = exp.provided;
774 exportInfo.canMangleProvide = exp.canMangleProvide;
775 exportInfo.terminalBinding = exp.terminalBinding;
776 if (exp.exportsInfo) {
777 const exportsInfo = exportInfo.createNestedExportsInfo();
778 exportsInfo.restoreProvided(exp.exportsInfo);
779 }
780 }
781 if (wasEmpty) this._exportsAreOrdered = true;
782 }
783}
784
785class ExportInfo {
786 /**
787 * @param {string} name the original name of the export
788 * @param {ExportInfo=} initFrom init values from this ExportInfo
789 */
790 constructor(name, initFrom) {
791 /** @type {string} */
792 this.name = name;
793 /** @private @type {string | null} */
794 this._usedName = initFrom ? initFrom._usedName : null;
795 /** @private @type {UsageStateType} */
796 this._globalUsed = initFrom ? initFrom._globalUsed : undefined;
797 /** @private @type {Map<string, RuntimeUsageStateType>} */
798 this._usedInRuntime =
799 initFrom && initFrom._usedInRuntime
800 ? new Map(initFrom._usedInRuntime)
801 : undefined;
802 /** @private @type {boolean} */
803 this._hasUseInRuntimeInfo = initFrom
804 ? initFrom._hasUseInRuntimeInfo
805 : false;
806 /**
807 * true: it is provided
808 * false: it is not provided
809 * null: only the runtime knows if it is provided
810 * undefined: it was not determined if it is provided
811 * @type {boolean | null | undefined}
812 */
813 this.provided = initFrom ? initFrom.provided : undefined;
814 /**
815 * is the export a terminal binding that should be checked for export star conflicts
816 * @type {boolean}
817 */
818 this.terminalBinding = initFrom ? initFrom.terminalBinding : false;
819 /**
820 * true: it can be mangled
821 * false: is can not be mangled
822 * undefined: it was not determined if it can be mangled
823 * @type {boolean | undefined}
824 */
825 this.canMangleProvide = initFrom ? initFrom.canMangleProvide : undefined;
826 /**
827 * true: it can be mangled
828 * false: is can not be mangled
829 * undefined: it was not determined if it can be mangled
830 * @type {boolean | undefined}
831 */
832 this.canMangleUse = initFrom ? initFrom.canMangleUse : undefined;
833 /** @type {boolean} */
834 this.exportsInfoOwned = false;
835 /** @type {ExportsInfo=} */
836 this.exportsInfo = undefined;
837 /** @type {Map<any, { connection: ModuleGraphConnection | null, export: string[], priority: number }>=} */
838 this._target = undefined;
839 if (initFrom && initFrom._target) {
840 this._target = new Map();
841 for (const [key, value] of initFrom._target) {
842 this._target.set(key, {
843 connection: value.connection,
844 export: value.export || [name],
845 priority: value.priority
846 });
847 }
848 }
849 /** @type {Map<any, { connection: ModuleGraphConnection | null, export: string[], priority: number }>=} */
850 this._maxTarget = undefined;
851 }
852
853 // TODO webpack 5 remove
854 /** @private */
855 get used() {
856 throw new Error("REMOVED");
857 }
858 /** @private */
859 get usedName() {
860 throw new Error("REMOVED");
861 }
862 /**
863 * @private
864 * @param {*} v v
865 */
866 set used(v) {
867 throw new Error("REMOVED");
868 }
869 /**
870 * @private
871 * @param {*} v v
872 */
873 set usedName(v) {
874 throw new Error("REMOVED");
875 }
876
877 get canMangle() {
878 switch (this.canMangleProvide) {
879 case undefined:
880 return this.canMangleUse === false ? false : undefined;
881 case false:
882 return false;
883 case true:
884 switch (this.canMangleUse) {
885 case undefined:
886 return undefined;
887 case false:
888 return false;
889 case true:
890 return true;
891 }
892 }
893 throw new Error(
894 `Unexpected flags for canMangle ${this.canMangleProvide} ${this.canMangleUse}`
895 );
896 }
897
898 /**
899 * @param {RuntimeSpec} runtime only apply to this runtime
900 * @returns {boolean} true, when something changed
901 */
902 setUsedInUnknownWay(runtime) {
903 let changed = false;
904 if (
905 this.setUsedConditionally(
906 used => used < UsageState.Unknown,
907 UsageState.Unknown,
908 runtime
909 )
910 ) {
911 changed = true;
912 }
913 if (this.canMangleUse !== false) {
914 this.canMangleUse = false;
915 changed = true;
916 }
917 return changed;
918 }
919
920 /**
921 * @param {RuntimeSpec} runtime only apply to this runtime
922 * @returns {boolean} true, when something changed
923 */
924 setUsedWithoutInfo(runtime) {
925 let changed = false;
926 if (this.setUsed(UsageState.NoInfo, runtime)) {
927 changed = true;
928 }
929 if (this.canMangleUse !== false) {
930 this.canMangleUse = false;
931 changed = true;
932 }
933 return changed;
934 }
935
936 setHasUseInfo() {
937 if (!this._hasUseInRuntimeInfo) {
938 this._hasUseInRuntimeInfo = true;
939 }
940 if (this.canMangleUse === undefined) {
941 this.canMangleUse = true;
942 }
943 if (this.exportsInfoOwned) {
944 this.exportsInfo.setHasUseInfo();
945 }
946 }
947
948 /**
949 * @param {function(UsageStateType): boolean} condition compare with old value
950 * @param {UsageStateType} newValue set when condition is true
951 * @param {RuntimeSpec} runtime only apply to this runtime
952 * @returns {boolean} true when something has changed
953 */
954 setUsedConditionally(condition, newValue, runtime) {
955 if (runtime === undefined) {
956 if (this._globalUsed === undefined) {
957 this._globalUsed = newValue;
958 return true;
959 } else {
960 if (this._globalUsed !== newValue && condition(this._globalUsed)) {
961 this._globalUsed = newValue;
962 return true;
963 }
964 }
965 } else if (this._usedInRuntime === undefined) {
966 if (newValue !== UsageState.Unused && condition(UsageState.Unused)) {
967 this._usedInRuntime = new Map();
968 forEachRuntime(runtime, runtime =>
969 this._usedInRuntime.set(runtime, newValue)
970 );
971 return true;
972 }
973 } else {
974 let changed = false;
975 forEachRuntime(runtime, runtime => {
976 /** @type {UsageStateType} */
977 let oldValue = this._usedInRuntime.get(runtime);
978 if (oldValue === undefined) oldValue = UsageState.Unused;
979 if (newValue !== oldValue && condition(oldValue)) {
980 if (newValue === UsageState.Unused) {
981 this._usedInRuntime.delete(runtime);
982 } else {
983 this._usedInRuntime.set(runtime, newValue);
984 }
985 changed = true;
986 }
987 });
988 if (changed) {
989 if (this._usedInRuntime.size === 0) this._usedInRuntime = undefined;
990 return true;
991 }
992 }
993 return false;
994 }
995
996 /**
997 * @param {UsageStateType} newValue new value of the used state
998 * @param {RuntimeSpec} runtime only apply to this runtime
999 * @returns {boolean} true when something has changed
1000 */
1001 setUsed(newValue, runtime) {
1002 if (runtime === undefined) {
1003 if (this._globalUsed !== newValue) {
1004 this._globalUsed = newValue;
1005 return true;
1006 }
1007 } else if (this._usedInRuntime === undefined) {
1008 if (newValue !== UsageState.Unused) {
1009 this._usedInRuntime = new Map();
1010 forEachRuntime(runtime, runtime =>
1011 this._usedInRuntime.set(runtime, newValue)
1012 );
1013 return true;
1014 }
1015 } else {
1016 let changed = false;
1017 forEachRuntime(runtime, runtime => {
1018 /** @type {UsageStateType} */
1019 let oldValue = this._usedInRuntime.get(runtime);
1020 if (oldValue === undefined) oldValue = UsageState.Unused;
1021 if (newValue !== oldValue) {
1022 if (newValue === UsageState.Unused) {
1023 this._usedInRuntime.delete(runtime);
1024 } else {
1025 this._usedInRuntime.set(runtime, newValue);
1026 }
1027 changed = true;
1028 }
1029 });
1030 if (changed) {
1031 if (this._usedInRuntime.size === 0) this._usedInRuntime = undefined;
1032 return true;
1033 }
1034 }
1035 return false;
1036 }
1037
1038 /**
1039 * @param {any} key the key
1040 * @returns {boolean} true, if something has changed
1041 */
1042 unsetTarget(key) {
1043 if (!this._target) return false;
1044 if (this._target.delete(key)) {
1045 this._maxTarget = undefined;
1046 return true;
1047 }
1048 return false;
1049 }
1050
1051 /**
1052 * @param {any} key the key
1053 * @param {ModuleGraphConnection} connection the target module if a single one
1054 * @param {string[]=} exportName the exported name
1055 * @param {number=} priority priority
1056 * @returns {boolean} true, if something has changed
1057 */
1058 setTarget(key, connection, exportName, priority = 0) {
1059 if (exportName) exportName = [...exportName];
1060 if (!this._target) {
1061 this._target = new Map();
1062 this._target.set(key, { connection, export: exportName, priority });
1063 return true;
1064 }
1065 const oldTarget = this._target.get(key);
1066 if (!oldTarget) {
1067 if (oldTarget === null && !connection) return false;
1068 this._target.set(key, { connection, export: exportName, priority });
1069 this._maxTarget = undefined;
1070 return true;
1071 }
1072 if (
1073 oldTarget.connection !== connection ||
1074 oldTarget.priority !== priority ||
1075 (exportName
1076 ? !oldTarget.export || !equals(oldTarget.export, exportName)
1077 : oldTarget.export)
1078 ) {
1079 oldTarget.connection = connection;
1080 oldTarget.export = exportName;
1081 oldTarget.priority = priority;
1082 this._maxTarget = undefined;
1083 return true;
1084 }
1085 return false;
1086 }
1087
1088 /**
1089 * @param {RuntimeSpec} runtime for this runtime
1090 * @returns {UsageStateType} usage state
1091 */
1092 getUsed(runtime) {
1093 if (!this._hasUseInRuntimeInfo) return UsageState.NoInfo;
1094 if (this._globalUsed !== undefined) return this._globalUsed;
1095 if (this._usedInRuntime === undefined) {
1096 return UsageState.Unused;
1097 } else if (typeof runtime === "string") {
1098 const value = this._usedInRuntime.get(runtime);
1099 return value === undefined ? UsageState.Unused : value;
1100 } else if (runtime === undefined) {
1101 /** @type {UsageStateType} */
1102 let max = UsageState.Unused;
1103 for (const value of this._usedInRuntime.values()) {
1104 if (value === UsageState.Used) {
1105 return UsageState.Used;
1106 }
1107 if (max < value) max = value;
1108 }
1109 return max;
1110 } else {
1111 /** @type {UsageStateType} */
1112 let max = UsageState.Unused;
1113 for (const item of runtime) {
1114 const value = this._usedInRuntime.get(item);
1115 if (value !== undefined) {
1116 if (value === UsageState.Used) {
1117 return UsageState.Used;
1118 }
1119 if (max < value) max = value;
1120 }
1121 }
1122 return max;
1123 }
1124 }
1125
1126 /**
1127 * get used name
1128 * @param {string | undefined} fallbackName fallback name for used exports with no name
1129 * @param {RuntimeSpec} runtime check usage for this runtime only
1130 * @returns {string | false} used name
1131 */
1132 getUsedName(fallbackName, runtime) {
1133 if (this._hasUseInRuntimeInfo) {
1134 if (this._globalUsed !== undefined) {
1135 if (this._globalUsed === UsageState.Unused) return false;
1136 } else {
1137 if (this._usedInRuntime === undefined) return false;
1138 if (typeof runtime === "string") {
1139 if (!this._usedInRuntime.has(runtime)) {
1140 return false;
1141 }
1142 } else if (runtime !== undefined) {
1143 if (
1144 Array.from(runtime).every(
1145 runtime => !this._usedInRuntime.has(runtime)
1146 )
1147 ) {
1148 return false;
1149 }
1150 }
1151 }
1152 }
1153 if (this._usedName !== null) return this._usedName;
1154 return this.name || fallbackName;
1155 }
1156
1157 /**
1158 * @returns {boolean} true, when a mangled name of this export is set
1159 */
1160 hasUsedName() {
1161 return this._usedName !== null;
1162 }
1163
1164 /**
1165 * Sets the mangled name of this export
1166 * @param {string} name the new name
1167 * @returns {void}
1168 */
1169 setUsedName(name) {
1170 this._usedName = name;
1171 }
1172
1173 /**
1174 * @param {ModuleGraph} moduleGraph the module graph
1175 * @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
1176 * @returns {ExportInfo | ExportsInfo | undefined} the terminal binding export(s) info if known
1177 */
1178 getTerminalBinding(moduleGraph, resolveTargetFilter = RETURNS_TRUE) {
1179 if (this.terminalBinding) return this;
1180 const target = this.getTarget(moduleGraph, resolveTargetFilter);
1181 if (!target) return undefined;
1182 const exportsInfo = moduleGraph.getExportsInfo(target.module);
1183 if (!target.export) return exportsInfo;
1184 return exportsInfo.getReadOnlyExportInfoRecursive(target.export);
1185 }
1186
1187 isReexport() {
1188 return !this.terminalBinding && this._target && this._target.size > 0;
1189 }
1190
1191 _getMaxTarget() {
1192 if (this._maxTarget !== undefined) return this._maxTarget;
1193 if (this._target.size <= 1) return (this._maxTarget = this._target);
1194 let maxPriority = -Infinity;
1195 let minPriority = Infinity;
1196 for (const { priority } of this._target.values()) {
1197 if (maxPriority < priority) maxPriority = priority;
1198 if (minPriority > priority) minPriority = priority;
1199 }
1200 // This should be very common
1201 if (maxPriority === minPriority) return (this._maxTarget = this._target);
1202
1203 // This is an edge case
1204 const map = new Map();
1205 for (const [key, value] of this._target) {
1206 if (maxPriority === value.priority) {
1207 map.set(key, value);
1208 }
1209 }
1210 this._maxTarget = map;
1211 return map;
1212 }
1213
1214 /**
1215 * @param {ModuleGraph} moduleGraph the module graph
1216 * @param {function(Module): boolean} validTargetModuleFilter a valid target module
1217 * @returns {{ module: Module, export: string[] | undefined } | undefined | false} the target, undefined when there is no target, false when no target is valid
1218 */
1219 findTarget(moduleGraph, validTargetModuleFilter) {
1220 return this._findTarget(moduleGraph, validTargetModuleFilter, new Set());
1221 }
1222
1223 /**
1224 * @param {ModuleGraph} moduleGraph the module graph
1225 * @param {function(Module): boolean} validTargetModuleFilter a valid target module
1226 * @param {Set<ExportInfo> | undefined} alreadyVisited set of already visited export info to avoid circular references
1227 * @returns {{ module: Module, export: string[] | undefined } | undefined | false} the target, undefined when there is no target, false when no target is valid
1228 */
1229 _findTarget(moduleGraph, validTargetModuleFilter, alreadyVisited) {
1230 if (!this._target || this._target.size === 0) return undefined;
1231 let rawTarget = this._getMaxTarget().values().next().value;
1232 if (!rawTarget) return undefined;
1233 /** @type {{ module: Module, export: string[] | undefined }} */
1234 let target = {
1235 module: rawTarget.connection.module,
1236 export: rawTarget.export
1237 };
1238 for (;;) {
1239 if (validTargetModuleFilter(target.module)) return target;
1240 const exportsInfo = moduleGraph.getExportsInfo(target.module);
1241 const exportInfo = exportsInfo.getExportInfo(target.export[0]);
1242 if (alreadyVisited.has(exportInfo)) return null;
1243 const newTarget = exportInfo._findTarget(
1244 moduleGraph,
1245 validTargetModuleFilter,
1246 alreadyVisited
1247 );
1248 if (!newTarget) return false;
1249 if (target.export.length === 1) {
1250 target = newTarget;
1251 } else {
1252 target = {
1253 module: newTarget.module,
1254 export: newTarget.export
1255 ? newTarget.export.concat(target.export.slice(1))
1256 : target.export.slice(1)
1257 };
1258 }
1259 }
1260 }
1261
1262 /**
1263 * @param {ModuleGraph} moduleGraph the module graph
1264 * @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
1265 * @returns {{ module: Module, export: string[] | undefined } | undefined} the target
1266 */
1267 getTarget(moduleGraph, resolveTargetFilter = RETURNS_TRUE) {
1268 const result = this._getTarget(moduleGraph, resolveTargetFilter, undefined);
1269 if (result === CIRCULAR) return undefined;
1270 return result;
1271 }
1272
1273 /**
1274 * @param {ModuleGraph} moduleGraph the module graph
1275 * @param {function({ module: Module, connection: ModuleGraphConnection, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
1276 * @param {Set<ExportInfo> | undefined} alreadyVisited set of already visited export info to avoid circular references
1277 * @returns {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined } | CIRCULAR | undefined} the target
1278 */
1279 _getTarget(moduleGraph, resolveTargetFilter, alreadyVisited) {
1280 /**
1281 * @param {{ connection: ModuleGraphConnection, export: string[] | undefined } | null} inputTarget unresolved target
1282 * @param {Set<ExportInfo>} alreadyVisited set of already visited export info to avoid circular references
1283 * @returns {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined } | CIRCULAR | null} resolved target
1284 */
1285 const resolveTarget = (inputTarget, alreadyVisited) => {
1286 if (!inputTarget) return null;
1287 if (!inputTarget.export) {
1288 return {
1289 module: inputTarget.connection.module,
1290 connection: inputTarget.connection,
1291 export: undefined
1292 };
1293 }
1294 /** @type {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined }} */
1295 let target = {
1296 module: inputTarget.connection.module,
1297 connection: inputTarget.connection,
1298 export: inputTarget.export
1299 };
1300 if (!resolveTargetFilter(target)) return target;
1301 let alreadyVisitedOwned = false;
1302 for (;;) {
1303 const exportsInfo = moduleGraph.getExportsInfo(target.module);
1304 const exportInfo = exportsInfo.getExportInfo(target.export[0]);
1305 if (!exportInfo) return target;
1306 if (alreadyVisited.has(exportInfo)) return CIRCULAR;
1307 const newTarget = exportInfo._getTarget(
1308 moduleGraph,
1309 resolveTargetFilter,
1310 alreadyVisited
1311 );
1312 if (newTarget === CIRCULAR) return CIRCULAR;
1313 if (!newTarget) return target;
1314 if (target.export.length === 1) {
1315 target = newTarget;
1316 if (!target.export) return target;
1317 } else {
1318 target = {
1319 module: newTarget.module,
1320 connection: newTarget.connection,
1321 export: newTarget.export
1322 ? newTarget.export.concat(target.export.slice(1))
1323 : target.export.slice(1)
1324 };
1325 }
1326 if (!resolveTargetFilter(target)) return target;
1327 if (!alreadyVisitedOwned) {
1328 alreadyVisited = new Set(alreadyVisited);
1329 alreadyVisitedOwned = true;
1330 }
1331 alreadyVisited.add(exportInfo);
1332 }
1333 };
1334
1335 if (!this._target || this._target.size === 0) return undefined;
1336 if (alreadyVisited && alreadyVisited.has(this)) return CIRCULAR;
1337 const newAlreadyVisited = new Set(alreadyVisited);
1338 newAlreadyVisited.add(this);
1339 const values = this._getMaxTarget().values();
1340 const target = resolveTarget(values.next().value, newAlreadyVisited);
1341 if (target === CIRCULAR) return CIRCULAR;
1342 if (target === null) return undefined;
1343 let result = values.next();
1344 while (!result.done) {
1345 const t = resolveTarget(result.value, newAlreadyVisited);
1346 if (t === CIRCULAR) return CIRCULAR;
1347 if (t === null) return undefined;
1348 if (t.module !== target.module) return undefined;
1349 if (!t.export !== !target.export) return undefined;
1350 if (target.export && !equals(t.export, target.export)) return undefined;
1351 result = values.next();
1352 }
1353 return target;
1354 }
1355
1356 /**
1357 * Move the target forward as long resolveTargetFilter is fulfilled
1358 * @param {ModuleGraph} moduleGraph the module graph
1359 * @param {function({ module: Module, export: string[] | undefined }): boolean} resolveTargetFilter filter function to further resolve target
1360 * @param {function({ module: Module, export: string[] | undefined }): ModuleGraphConnection=} updateOriginalConnection updates the original connection instead of using the target connection
1361 * @returns {{ module: Module, export: string[] | undefined } | undefined} the resolved target when moved
1362 */
1363 moveTarget(moduleGraph, resolveTargetFilter, updateOriginalConnection) {
1364 const target = this._getTarget(moduleGraph, resolveTargetFilter, undefined);
1365 if (target === CIRCULAR) return undefined;
1366 if (!target) return undefined;
1367 const originalTarget = this._getMaxTarget().values().next().value;
1368 if (
1369 originalTarget.connection === target.connection &&
1370 originalTarget.export === target.export
1371 ) {
1372 return undefined;
1373 }
1374 this._target.clear();
1375 this._target.set(undefined, {
1376 connection: updateOriginalConnection
1377 ? updateOriginalConnection(target)
1378 : target.connection,
1379 export: target.export,
1380 priority: 0
1381 });
1382 return target;
1383 }
1384
1385 createNestedExportsInfo() {
1386 if (this.exportsInfoOwned) return this.exportsInfo;
1387 this.exportsInfoOwned = true;
1388 const oldExportsInfo = this.exportsInfo;
1389 this.exportsInfo = new ExportsInfo();
1390 this.exportsInfo.setHasProvideInfo();
1391 if (oldExportsInfo) {
1392 this.exportsInfo.setRedirectNamedTo(oldExportsInfo);
1393 }
1394 return this.exportsInfo;
1395 }
1396
1397 getNestedExportsInfo() {
1398 return this.exportsInfo;
1399 }
1400
1401 hasInfo(baseInfo, runtime) {
1402 return (
1403 (this._usedName && this._usedName !== this.name) ||
1404 this.provided ||
1405 this.terminalBinding ||
1406 this.getUsed(runtime) !== baseInfo.getUsed(runtime)
1407 );
1408 }
1409
1410 updateHash(hash, runtime) {
1411 this._updateHash(hash, runtime, new Set());
1412 }
1413
1414 _updateHash(hash, runtime, alreadyVisitedExportsInfo) {
1415 hash.update(
1416 `${this._usedName || this.name}${this.getUsed(runtime)}${this.provided}${
1417 this.terminalBinding
1418 }`
1419 );
1420 if (this.exportsInfo && !alreadyVisitedExportsInfo.has(this.exportsInfo)) {
1421 this.exportsInfo._updateHash(hash, runtime, alreadyVisitedExportsInfo);
1422 }
1423 }
1424
1425 getUsedInfo() {
1426 if (this._globalUsed !== undefined) {
1427 switch (this._globalUsed) {
1428 case UsageState.Unused:
1429 return "unused";
1430 case UsageState.NoInfo:
1431 return "no usage info";
1432 case UsageState.Unknown:
1433 return "maybe used (runtime-defined)";
1434 case UsageState.Used:
1435 return "used";
1436 case UsageState.OnlyPropertiesUsed:
1437 return "only properties used";
1438 }
1439 } else if (this._usedInRuntime !== undefined) {
1440 /** @type {Map<RuntimeUsageStateType, string[]>} */
1441 const map = new Map();
1442 for (const [runtime, used] of this._usedInRuntime) {
1443 const list = map.get(used);
1444 if (list !== undefined) list.push(runtime);
1445 else map.set(used, [runtime]);
1446 }
1447 const specificInfo = Array.from(map, ([used, runtimes]) => {
1448 switch (used) {
1449 case UsageState.NoInfo:
1450 return `no usage info in ${runtimes.join(", ")}`;
1451 case UsageState.Unknown:
1452 return `maybe used in ${runtimes.join(", ")} (runtime-defined)`;
1453 case UsageState.Used:
1454 return `used in ${runtimes.join(", ")}`;
1455 case UsageState.OnlyPropertiesUsed:
1456 return `only properties used in ${runtimes.join(", ")}`;
1457 }
1458 });
1459 if (specificInfo.length > 0) {
1460 return specificInfo.join("; ");
1461 }
1462 }
1463 return this._hasUseInRuntimeInfo ? "unused" : "no usage info";
1464 }
1465
1466 getProvidedInfo() {
1467 switch (this.provided) {
1468 case undefined:
1469 return "no provided info";
1470 case null:
1471 return "maybe provided (runtime-defined)";
1472 case true:
1473 return "provided";
1474 case false:
1475 return "not provided";
1476 }
1477 }
1478
1479 getRenameInfo() {
1480 if (this._usedName !== null && this._usedName !== this.name) {
1481 return `renamed to ${JSON.stringify(this._usedName).slice(1, -1)}`;
1482 }
1483 switch (this.canMangleProvide) {
1484 case undefined:
1485 switch (this.canMangleUse) {
1486 case undefined:
1487 return "missing provision and use info prevents renaming";
1488 case false:
1489 return "usage prevents renaming (no provision info)";
1490 case true:
1491 return "missing provision info prevents renaming";
1492 }
1493 break;
1494 case true:
1495 switch (this.canMangleUse) {
1496 case undefined:
1497 return "missing usage info prevents renaming";
1498 case false:
1499 return "usage prevents renaming";
1500 case true:
1501 return "could be renamed";
1502 }
1503 break;
1504 case false:
1505 switch (this.canMangleUse) {
1506 case undefined:
1507 return "provision prevents renaming (no use info)";
1508 case false:
1509 return "usage and provision prevents renaming";
1510 case true:
1511 return "provision prevents renaming";
1512 }
1513 break;
1514 }
1515 throw new Error(
1516 `Unexpected flags for getRenameInfo ${this.canMangleProvide} ${this.canMangleUse}`
1517 );
1518 }
1519}
1520
1521module.exports = ExportsInfo;
1522module.exports.ExportInfo = ExportInfo;
1523module.exports.UsageState = UsageState;