UNPKG

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