source: imaps-frontend/node_modules/webpack/lib/ExportsInfo.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

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