webpack 5.99.6 → 5.99.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/lib/AutomaticPrefetchPlugin.js +21 -22
  2. package/lib/BannerPlugin.js +31 -35
  3. package/lib/CleanPlugin.js +5 -3
  4. package/lib/Compilation.js +9 -8
  5. package/lib/Compiler.js +2 -1
  6. package/lib/ContextExclusionPlugin.js +4 -2
  7. package/lib/ContextReplacementPlugin.js +5 -3
  8. package/lib/DelegatedPlugin.js +4 -2
  9. package/lib/DllEntryPlugin.js +4 -2
  10. package/lib/DllPlugin.js +5 -3
  11. package/lib/DllReferencePlugin.js +56 -60
  12. package/lib/DynamicEntryPlugin.js +4 -2
  13. package/lib/EntryOptionPlugin.js +3 -1
  14. package/lib/EntryPlugin.js +4 -2
  15. package/lib/EnvironmentPlugin.js +4 -2
  16. package/lib/EvalDevToolModulePlugin.js +9 -7
  17. package/lib/EvalSourceMapDevToolPlugin.js +137 -138
  18. package/lib/ExternalsPlugin.js +3 -1
  19. package/lib/FlagDependencyExportsPlugin.js +2 -1
  20. package/lib/IgnorePlugin.js +6 -4
  21. package/lib/IgnoreWarningsPlugin.js +4 -2
  22. package/lib/LibManifestPlugin.js +3 -4
  23. package/lib/LoaderOptionsPlugin.js +4 -2
  24. package/lib/LoaderTargetPlugin.js +4 -2
  25. package/lib/Module.js +19 -12
  26. package/lib/ModuleInfoHeaderPlugin.js +11 -12
  27. package/lib/MultiCompiler.js +5 -3
  28. package/lib/NoEmitOnErrorsPlugin.js +5 -3
  29. package/lib/NormalModule.js +5 -1
  30. package/lib/NormalModuleReplacementPlugin.js +33 -36
  31. package/lib/PlatformPlugin.js +3 -1
  32. package/lib/PrefetchPlugin.js +4 -2
  33. package/lib/ProgressPlugin.js +23 -26
  34. package/lib/RecordIdsPlugin.js +72 -102
  35. package/lib/RuntimePlugin.js +34 -32
  36. package/lib/SourceMapDevToolPlugin.js +7 -5
  37. package/lib/WarnCaseSensitiveModulesPlugin.js +36 -37
  38. package/lib/WarnNoModeSetPlugin.js +3 -1
  39. package/lib/WatchIgnorePlugin.js +3 -1
  40. package/lib/WebpackError.js +11 -3
  41. package/lib/WebpackOptionsApply.js +5 -3
  42. package/lib/async-modules/InferAsyncModulesPlugin.js +25 -26
  43. package/lib/cache/IdleFileCachePlugin.js +11 -12
  44. package/lib/cache/MemoryWithGcCachePlugin.js +7 -5
  45. package/lib/cache/ResolverCachePlugin.js +8 -6
  46. package/lib/cli.js +5 -1
  47. package/lib/config/normalization.js +9 -3
  48. package/lib/container/ContainerReferencePlugin.js +24 -26
  49. package/lib/container/ModuleFederationPlugin.js +2 -1
  50. package/lib/css/CssGenerator.js +1 -1
  51. package/lib/css/CssModulesPlugin.js +6 -4
  52. package/lib/dependencies/HarmonyDetectionParserPlugin.js +9 -15
  53. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +15 -15
  54. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +4 -2
  55. package/lib/dependencies/LoaderPlugin.js +5 -3
  56. package/lib/dependencies/RequireContextDependencyParserPlugin.js +46 -46
  57. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +94 -100
  58. package/lib/esm/ModuleChunkLoadingPlugin.js +72 -73
  59. package/lib/hmr/HotModuleReplacement.runtime.js +0 -1
  60. package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +0 -1
  61. package/lib/hmr/LazyCompilationPlugin.js +17 -18
  62. package/lib/ids/ChunkModuleIdRangePlugin.js +6 -6
  63. package/lib/ids/DeterministicModuleIdsPlugin.js +47 -48
  64. package/lib/ids/HashedModuleIdsPlugin.js +4 -2
  65. package/lib/ids/NamedChunkIdsPlugin.js +4 -2
  66. package/lib/ids/NamedModuleIdsPlugin.js +4 -2
  67. package/lib/ids/NaturalChunkIdsPlugin.js +4 -2
  68. package/lib/ids/NaturalModuleIdsPlugin.js +4 -2
  69. package/lib/ids/OccurrenceChunkIdsPlugin.js +4 -2
  70. package/lib/ids/OccurrenceModuleIdsPlugin.js +4 -2
  71. package/lib/javascript/JavascriptParser.js +634 -656
  72. package/lib/library/ModuleLibraryPlugin.js +60 -42
  73. package/lib/node/CommonJsChunkLoadingPlugin.js +69 -73
  74. package/lib/node/NodeEnvironmentPlugin.js +3 -1
  75. package/lib/optimize/AggressiveSplittingPlugin.js +224 -232
  76. package/lib/optimize/ConcatenatedModule.js +12 -15
  77. package/lib/optimize/FlagIncludedChunksPlugin.js +92 -97
  78. package/lib/optimize/LimitChunkCountPlugin.js +4 -2
  79. package/lib/optimize/MangleExportsPlugin.js +15 -16
  80. package/lib/optimize/MinChunkSizePlugin.js +4 -2
  81. package/lib/optimize/ModuleConcatenationPlugin.js +4 -2
  82. package/lib/optimize/RealContentHashPlugin.js +4 -2
  83. package/lib/optimize/RemoveEmptyChunksPlugin.js +5 -3
  84. package/lib/optimize/RemoveParentModulesPlugin.js +4 -2
  85. package/lib/optimize/RuntimeChunkPlugin.js +17 -18
  86. package/lib/optimize/SplitChunksPlugin.js +7 -5
  87. package/lib/performance/SizeLimitsPlugin.js +3 -1
  88. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +61 -62
  89. package/lib/runtime/StartupChunkDependenciesPlugin.js +39 -42
  90. package/lib/schemes/DataUriPlugin.js +5 -3
  91. package/lib/schemes/FileUriPlugin.js +5 -3
  92. package/lib/schemes/HttpUriPlugin.js +32 -39
  93. package/lib/serialization/AggregateErrorSerializer.js +42 -0
  94. package/lib/serialization/ErrorObjectSerializer.js +7 -2
  95. package/lib/serialization/ObjectMiddleware.js +13 -0
  96. package/lib/sharing/ProvideSharedPlugin.js +6 -4
  97. package/lib/stats/DefaultStatsFactoryPlugin.js +89 -33
  98. package/lib/stats/DefaultStatsPresetPlugin.js +25 -20
  99. package/lib/stats/DefaultStatsPrinterPlugin.js +306 -341
  100. package/lib/util/concatenate.js +4 -2
  101. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +55 -57
  102. package/lib/web/JsonpChunkLoadingPlugin.js +73 -74
  103. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +77 -78
  104. package/package.json +4 -3
  105. package/schemas/WebpackOptions.check.js +1 -1
  106. package/schemas/WebpackOptions.json +24 -2
  107. package/types.d.ts +148 -55
@@ -389,6 +389,8 @@ const EMPTY_COMMENT_OPTIONS = {
389
389
  errors: null
390
390
  };
391
391
 
392
+ const CLASS_NAME = "JavascriptParser";
393
+
392
394
  class JavascriptParser extends Parser {
393
395
  /**
394
396
  * @param {"module" | "script" | "auto"} sourceType default source type
@@ -600,7 +602,7 @@ class JavascriptParser extends Parser {
600
602
  }
601
603
 
602
604
  _initializeEvaluating() {
603
- this.hooks.evaluate.for("Literal").tap("JavascriptParser", _expr => {
605
+ this.hooks.evaluate.for("Literal").tap(CLASS_NAME, _expr => {
604
606
  const expr = /** @type {Literal} */ (_expr);
605
607
 
606
608
  switch (typeof expr.value) {
@@ -632,7 +634,7 @@ class JavascriptParser extends Parser {
632
634
  .setRange(/** @type {Range} */ (expr.range));
633
635
  }
634
636
  });
635
- this.hooks.evaluate.for("NewExpression").tap("JavascriptParser", _expr => {
637
+ this.hooks.evaluate.for("NewExpression").tap(CLASS_NAME, _expr => {
636
638
  const expr = /** @type {NewExpression} */ (_expr);
637
639
  const callee = expr.callee;
638
640
  if (callee.type !== "Identifier") return;
@@ -695,52 +697,50 @@ class JavascriptParser extends Parser {
695
697
  .setRegExp(flags ? new RegExp(regExp, flags) : new RegExp(regExp))
696
698
  .setRange(/** @type {Range} */ (expr.range));
697
699
  });
698
- this.hooks.evaluate
699
- .for("LogicalExpression")
700
- .tap("JavascriptParser", _expr => {
701
- const expr = /** @type {LogicalExpression} */ (_expr);
702
-
703
- const left = this.evaluateExpression(expr.left);
704
- let returnRight = false;
705
- /** @type {boolean | undefined} */
706
- let allowedRight;
707
- if (expr.operator === "&&") {
708
- const leftAsBool = left.asBool();
709
- if (leftAsBool === false)
710
- return left.setRange(/** @type {Range} */ (expr.range));
711
- returnRight = leftAsBool === true;
712
- allowedRight = false;
713
- } else if (expr.operator === "||") {
714
- const leftAsBool = left.asBool();
715
- if (leftAsBool === true)
716
- return left.setRange(/** @type {Range} */ (expr.range));
717
- returnRight = leftAsBool === false;
718
- allowedRight = true;
719
- } else if (expr.operator === "??") {
720
- const leftAsNullish = left.asNullish();
721
- if (leftAsNullish === false)
722
- return left.setRange(/** @type {Range} */ (expr.range));
723
- if (leftAsNullish !== true) return;
724
- returnRight = true;
725
- } else return;
726
- const right = this.evaluateExpression(expr.right);
727
- if (returnRight) {
728
- if (left.couldHaveSideEffects()) right.setSideEffects();
729
- return right.setRange(/** @type {Range} */ (expr.range));
730
- }
700
+ this.hooks.evaluate.for("LogicalExpression").tap(CLASS_NAME, _expr => {
701
+ const expr = /** @type {LogicalExpression} */ (_expr);
702
+
703
+ const left = this.evaluateExpression(expr.left);
704
+ let returnRight = false;
705
+ /** @type {boolean | undefined} */
706
+ let allowedRight;
707
+ if (expr.operator === "&&") {
708
+ const leftAsBool = left.asBool();
709
+ if (leftAsBool === false)
710
+ return left.setRange(/** @type {Range} */ (expr.range));
711
+ returnRight = leftAsBool === true;
712
+ allowedRight = false;
713
+ } else if (expr.operator === "||") {
714
+ const leftAsBool = left.asBool();
715
+ if (leftAsBool === true)
716
+ return left.setRange(/** @type {Range} */ (expr.range));
717
+ returnRight = leftAsBool === false;
718
+ allowedRight = true;
719
+ } else if (expr.operator === "??") {
720
+ const leftAsNullish = left.asNullish();
721
+ if (leftAsNullish === false)
722
+ return left.setRange(/** @type {Range} */ (expr.range));
723
+ if (leftAsNullish !== true) return;
724
+ returnRight = true;
725
+ } else return;
726
+ const right = this.evaluateExpression(expr.right);
727
+ if (returnRight) {
728
+ if (left.couldHaveSideEffects()) right.setSideEffects();
729
+ return right.setRange(/** @type {Range} */ (expr.range));
730
+ }
731
731
 
732
- const asBool = right.asBool();
732
+ const asBool = right.asBool();
733
733
 
734
- if (allowedRight === true && asBool === true) {
735
- return new BasicEvaluatedExpression()
736
- .setRange(/** @type {Range} */ (expr.range))
737
- .setTruthy();
738
- } else if (allowedRight === false && asBool === false) {
739
- return new BasicEvaluatedExpression()
740
- .setRange(/** @type {Range} */ (expr.range))
741
- .setFalsy();
742
- }
743
- });
734
+ if (allowedRight === true && asBool === true) {
735
+ return new BasicEvaluatedExpression()
736
+ .setRange(/** @type {Range} */ (expr.range))
737
+ .setTruthy();
738
+ } else if (allowedRight === false && asBool === false) {
739
+ return new BasicEvaluatedExpression()
740
+ .setRange(/** @type {Range} */ (expr.range))
741
+ .setFalsy();
742
+ }
743
+ });
744
744
 
745
745
  /**
746
746
  * In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on
@@ -810,553 +810,539 @@ class JavascriptParser extends Parser {
810
810
  }
811
811
  };
812
812
 
813
- this.hooks.evaluate
814
- .for("BinaryExpression")
815
- .tap("JavascriptParser", _expr => {
816
- const expr = /** @type {BinaryExpression} */ (_expr);
813
+ this.hooks.evaluate.for("BinaryExpression").tap(CLASS_NAME, _expr => {
814
+ const expr = /** @type {BinaryExpression} */ (_expr);
817
815
 
818
- /**
819
- * Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
820
- * @template T
821
- * @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
822
- * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
823
- */
824
- const handleConstOperation = operandHandler => {
825
- const left = this.evaluateExpression(expr.left);
826
- if (!left.isCompileTimeValue()) return;
827
-
828
- const right = this.evaluateExpression(expr.right);
829
- if (!right.isCompileTimeValue()) return;
816
+ /**
817
+ * Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
818
+ * @template T
819
+ * @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
820
+ * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
821
+ */
822
+ const handleConstOperation = operandHandler => {
823
+ const left = this.evaluateExpression(expr.left);
824
+ if (!left.isCompileTimeValue()) return;
830
825
 
831
- const result = operandHandler(
832
- /** @type {T} */ (left.asCompileTimeValue()),
833
- /** @type {T} */ (right.asCompileTimeValue())
834
- );
835
- return valueAsExpression(
836
- result,
837
- expr,
838
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
839
- );
840
- };
826
+ const right = this.evaluateExpression(expr.right);
827
+ if (!right.isCompileTimeValue()) return;
841
828
 
842
- /**
843
- * Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
844
- * to determine if an expressions boolean or nullish conversion is equal or not.
845
- * @param {boolean} a first boolean to compare
846
- * @param {boolean} b second boolean to compare
847
- * @returns {boolean} true if the two booleans are always different, false otherwise
848
- */
849
- const isAlwaysDifferent = (a, b) =>
850
- (a === true && b === false) || (a === false && b === true);
829
+ const result = operandHandler(
830
+ /** @type {T} */ (left.asCompileTimeValue()),
831
+ /** @type {T} */ (right.asCompileTimeValue())
832
+ );
833
+ return valueAsExpression(
834
+ result,
835
+ expr,
836
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
837
+ );
838
+ };
851
839
 
840
+ /**
841
+ * Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
842
+ * to determine if an expressions boolean or nullish conversion is equal or not.
843
+ * @param {boolean} a first boolean to compare
844
+ * @param {boolean} b second boolean to compare
845
+ * @returns {boolean} true if the two booleans are always different, false otherwise
846
+ */
847
+ const isAlwaysDifferent = (a, b) =>
848
+ (a === true && b === false) || (a === false && b === true);
849
+
850
+ /**
851
+ * @param {BasicEvaluatedExpression} left left
852
+ * @param {BasicEvaluatedExpression} right right
853
+ * @param {BasicEvaluatedExpression} res res
854
+ * @param {boolean} eql true for "===" and false for "!=="
855
+ * @returns {BasicEvaluatedExpression | undefined} result
856
+ */
857
+ const handleTemplateStringCompare = (left, right, res, eql) => {
852
858
  /**
853
- * @param {BasicEvaluatedExpression} left left
854
- * @param {BasicEvaluatedExpression} right right
855
- * @param {BasicEvaluatedExpression} res res
856
- * @param {boolean} eql true for "===" and false for "!=="
857
- * @returns {BasicEvaluatedExpression | undefined} result
859
+ * @param {BasicEvaluatedExpression[]} parts parts
860
+ * @returns {string} value
858
861
  */
859
- const handleTemplateStringCompare = (left, right, res, eql) => {
860
- /**
861
- * @param {BasicEvaluatedExpression[]} parts parts
862
- * @returns {string} value
863
- */
864
- const getPrefix = parts => {
865
- let value = "";
866
- for (const p of parts) {
867
- const v = p.asString();
868
- if (v !== undefined) value += v;
869
- else break;
870
- }
871
- return value;
872
- };
873
- /**
874
- * @param {BasicEvaluatedExpression[]} parts parts
875
- * @returns {string} value
876
- */
877
- const getSuffix = parts => {
878
- let value = "";
879
- for (let i = parts.length - 1; i >= 0; i--) {
880
- const v = parts[i].asString();
881
- if (v !== undefined) value = v + value;
882
- else break;
883
- }
884
- return value;
885
- };
886
- const leftPrefix = getPrefix(
887
- /** @type {BasicEvaluatedExpression[]} */ (left.parts)
888
- );
889
- const rightPrefix = getPrefix(
890
- /** @type {BasicEvaluatedExpression[]} */ (right.parts)
891
- );
892
- const leftSuffix = getSuffix(
893
- /** @type {BasicEvaluatedExpression[]} */ (left.parts)
894
- );
895
- const rightSuffix = getSuffix(
896
- /** @type {BasicEvaluatedExpression[]} */ (right.parts)
897
- );
898
- const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
899
- const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
900
- const prefixMismatch =
901
- lenPrefix > 0 &&
902
- leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
903
- const suffixMismatch =
904
- lenSuffix > 0 &&
905
- leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
906
- if (prefixMismatch || suffixMismatch) {
907
- return res
908
- .setBoolean(!eql)
909
- .setSideEffects(
910
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
911
- );
862
+ const getPrefix = parts => {
863
+ let value = "";
864
+ for (const p of parts) {
865
+ const v = p.asString();
866
+ if (v !== undefined) value += v;
867
+ else break;
912
868
  }
869
+ return value;
913
870
  };
914
-
915
871
  /**
916
- * Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
917
- * @param {boolean} eql true for "===" and false for "!=="
918
- * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
872
+ * @param {BasicEvaluatedExpression[]} parts parts
873
+ * @returns {string} value
919
874
  */
920
- const handleStrictEqualityComparison = eql => {
921
- const left = this.evaluateExpression(expr.left);
922
- const right = this.evaluateExpression(expr.right);
923
- const res = new BasicEvaluatedExpression();
924
- res.setRange(/** @type {Range} */ (expr.range));
925
-
926
- const leftConst = left.isCompileTimeValue();
927
- const rightConst = right.isCompileTimeValue();
928
-
929
- if (leftConst && rightConst) {
930
- return res
931
- .setBoolean(
932
- eql ===
933
- (left.asCompileTimeValue() === right.asCompileTimeValue())
934
- )
935
- .setSideEffects(
936
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
937
- );
875
+ const getSuffix = parts => {
876
+ let value = "";
877
+ for (let i = parts.length - 1; i >= 0; i--) {
878
+ const v = parts[i].asString();
879
+ if (v !== undefined) value = v + value;
880
+ else break;
938
881
  }
882
+ return value;
883
+ };
884
+ const leftPrefix = getPrefix(
885
+ /** @type {BasicEvaluatedExpression[]} */ (left.parts)
886
+ );
887
+ const rightPrefix = getPrefix(
888
+ /** @type {BasicEvaluatedExpression[]} */ (right.parts)
889
+ );
890
+ const leftSuffix = getSuffix(
891
+ /** @type {BasicEvaluatedExpression[]} */ (left.parts)
892
+ );
893
+ const rightSuffix = getSuffix(
894
+ /** @type {BasicEvaluatedExpression[]} */ (right.parts)
895
+ );
896
+ const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
897
+ const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
898
+ const prefixMismatch =
899
+ lenPrefix > 0 &&
900
+ leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
901
+ const suffixMismatch =
902
+ lenSuffix > 0 &&
903
+ leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
904
+ if (prefixMismatch || suffixMismatch) {
905
+ return res
906
+ .setBoolean(!eql)
907
+ .setSideEffects(
908
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
909
+ );
910
+ }
911
+ };
939
912
 
940
- if (left.isArray() && right.isArray()) {
941
- return res
942
- .setBoolean(!eql)
943
- .setSideEffects(
944
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
945
- );
946
- }
947
- if (left.isTemplateString() && right.isTemplateString()) {
948
- return handleTemplateStringCompare(left, right, res, eql);
949
- }
913
+ /**
914
+ * Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
915
+ * @param {boolean} eql true for "===" and false for "!=="
916
+ * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
917
+ */
918
+ const handleStrictEqualityComparison = eql => {
919
+ const left = this.evaluateExpression(expr.left);
920
+ const right = this.evaluateExpression(expr.right);
921
+ const res = new BasicEvaluatedExpression();
922
+ res.setRange(/** @type {Range} */ (expr.range));
950
923
 
951
- const leftPrimitive = left.isPrimitiveType();
952
- const rightPrimitive = right.isPrimitiveType();
924
+ const leftConst = left.isCompileTimeValue();
925
+ const rightConst = right.isCompileTimeValue();
953
926
 
954
- if (
955
- // Primitive !== Object or
956
- // compile-time object types are never equal to something at runtime
957
- (leftPrimitive === false &&
958
- (leftConst || rightPrimitive === true)) ||
959
- (rightPrimitive === false &&
960
- (rightConst || leftPrimitive === true)) ||
961
- // Different nullish or boolish status also means not equal
962
- isAlwaysDifferent(
963
- /** @type {boolean} */ (left.asBool()),
964
- /** @type {boolean} */ (right.asBool())
965
- ) ||
966
- isAlwaysDifferent(
967
- /** @type {boolean} */ (left.asNullish()),
968
- /** @type {boolean} */ (right.asNullish())
927
+ if (leftConst && rightConst) {
928
+ return res
929
+ .setBoolean(
930
+ eql === (left.asCompileTimeValue() === right.asCompileTimeValue())
969
931
  )
970
- ) {
971
- return res
972
- .setBoolean(!eql)
973
- .setSideEffects(
974
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
975
- );
976
- }
977
- };
932
+ .setSideEffects(
933
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
934
+ );
935
+ }
978
936
 
979
- /**
980
- * Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
981
- * @param {boolean} eql true for "==" and false for "!="
982
- * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
983
- */
984
- const handleAbstractEqualityComparison = eql => {
985
- const left = this.evaluateExpression(expr.left);
986
- const right = this.evaluateExpression(expr.right);
987
- const res = new BasicEvaluatedExpression();
988
- res.setRange(/** @type {Range} */ (expr.range));
989
-
990
- const leftConst = left.isCompileTimeValue();
991
- const rightConst = right.isCompileTimeValue();
992
-
993
- if (leftConst && rightConst) {
994
- return res
995
- .setBoolean(
996
- eql ===
997
- // eslint-disable-next-line eqeqeq
998
- (left.asCompileTimeValue() == right.asCompileTimeValue())
999
- )
1000
- .setSideEffects(
1001
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
1002
- );
1003
- }
937
+ if (left.isArray() && right.isArray()) {
938
+ return res
939
+ .setBoolean(!eql)
940
+ .setSideEffects(
941
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
942
+ );
943
+ }
944
+ if (left.isTemplateString() && right.isTemplateString()) {
945
+ return handleTemplateStringCompare(left, right, res, eql);
946
+ }
1004
947
 
1005
- if (left.isArray() && right.isArray()) {
1006
- return res
1007
- .setBoolean(!eql)
1008
- .setSideEffects(
1009
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
1010
- );
1011
- }
1012
- if (left.isTemplateString() && right.isTemplateString()) {
1013
- return handleTemplateStringCompare(left, right, res, eql);
1014
- }
1015
- };
948
+ const leftPrimitive = left.isPrimitiveType();
949
+ const rightPrimitive = right.isPrimitiveType();
1016
950
 
1017
- if (expr.operator === "+") {
1018
- const left = this.evaluateExpression(expr.left);
1019
- const right = this.evaluateExpression(expr.right);
1020
- const res = new BasicEvaluatedExpression();
1021
- if (left.isString()) {
1022
- if (right.isString()) {
1023
- res.setString(
1024
- /** @type {string} */ (left.string) +
1025
- /** @type {string} */ (right.string)
1026
- );
1027
- } else if (right.isNumber()) {
1028
- res.setString(/** @type {string} */ (left.string) + right.number);
1029
- } else if (
1030
- right.isWrapped() &&
1031
- right.prefix &&
1032
- right.prefix.isString()
1033
- ) {
1034
- // "left" + ("prefix" + inner + "postfix")
1035
- // => ("leftPrefix" + inner + "postfix")
1036
- res.setWrapped(
1037
- new BasicEvaluatedExpression()
1038
- .setString(
1039
- /** @type {string} */ (left.string) +
1040
- /** @type {string} */ (right.prefix.string)
1041
- )
1042
- .setRange(
1043
- joinRanges(
1044
- /** @type {Range} */ (left.range),
1045
- /** @type {Range} */ (right.prefix.range)
1046
- )
1047
- ),
1048
- right.postfix,
1049
- right.wrappedInnerExpressions
1050
- );
1051
- } else if (right.isWrapped()) {
1052
- // "left" + ([null] + inner + "postfix")
1053
- // => ("left" + inner + "postfix")
1054
- res.setWrapped(
1055
- left,
1056
- right.postfix,
1057
- right.wrappedInnerExpressions
1058
- );
1059
- } else {
1060
- // "left" + expr
1061
- // => ("left" + expr + "")
1062
- res.setWrapped(left, null, [right]);
1063
- }
1064
- } else if (left.isNumber()) {
1065
- if (right.isString()) {
1066
- res.setString(left.number + /** @type {string} */ (right.string));
1067
- } else if (right.isNumber()) {
1068
- res.setNumber(
1069
- /** @type {number} */ (left.number) +
1070
- /** @type {number} */ (right.number)
1071
- );
1072
- } else {
1073
- return;
1074
- }
1075
- } else if (left.isBigInt()) {
1076
- if (right.isBigInt()) {
1077
- res.setBigInt(
1078
- /** @type {bigint} */ (left.bigint) +
1079
- /** @type {bigint} */ (right.bigint)
1080
- );
1081
- }
1082
- } else if (left.isWrapped()) {
1083
- if (left.postfix && left.postfix.isString() && right.isString()) {
1084
- // ("prefix" + inner + "postfix") + "right"
1085
- // => ("prefix" + inner + "postfixRight")
1086
- res.setWrapped(
1087
- left.prefix,
1088
- new BasicEvaluatedExpression()
1089
- .setString(
1090
- /** @type {string} */ (left.postfix.string) +
1091
- /** @type {string} */ (right.string)
951
+ if (
952
+ // Primitive !== Object or
953
+ // compile-time object types are never equal to something at runtime
954
+ (leftPrimitive === false && (leftConst || rightPrimitive === true)) ||
955
+ (rightPrimitive === false &&
956
+ (rightConst || leftPrimitive === true)) ||
957
+ // Different nullish or boolish status also means not equal
958
+ isAlwaysDifferent(
959
+ /** @type {boolean} */ (left.asBool()),
960
+ /** @type {boolean} */ (right.asBool())
961
+ ) ||
962
+ isAlwaysDifferent(
963
+ /** @type {boolean} */ (left.asNullish()),
964
+ /** @type {boolean} */ (right.asNullish())
965
+ )
966
+ ) {
967
+ return res
968
+ .setBoolean(!eql)
969
+ .setSideEffects(
970
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
971
+ );
972
+ }
973
+ };
974
+
975
+ /**
976
+ * Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
977
+ * @param {boolean} eql true for "==" and false for "!="
978
+ * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
979
+ */
980
+ const handleAbstractEqualityComparison = eql => {
981
+ const left = this.evaluateExpression(expr.left);
982
+ const right = this.evaluateExpression(expr.right);
983
+ const res = new BasicEvaluatedExpression();
984
+ res.setRange(/** @type {Range} */ (expr.range));
985
+
986
+ const leftConst = left.isCompileTimeValue();
987
+ const rightConst = right.isCompileTimeValue();
988
+
989
+ if (leftConst && rightConst) {
990
+ return res
991
+ .setBoolean(
992
+ eql ===
993
+ // eslint-disable-next-line eqeqeq
994
+ (left.asCompileTimeValue() == right.asCompileTimeValue())
995
+ )
996
+ .setSideEffects(
997
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
998
+ );
999
+ }
1000
+
1001
+ if (left.isArray() && right.isArray()) {
1002
+ return res
1003
+ .setBoolean(!eql)
1004
+ .setSideEffects(
1005
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1006
+ );
1007
+ }
1008
+ if (left.isTemplateString() && right.isTemplateString()) {
1009
+ return handleTemplateStringCompare(left, right, res, eql);
1010
+ }
1011
+ };
1012
+
1013
+ if (expr.operator === "+") {
1014
+ const left = this.evaluateExpression(expr.left);
1015
+ const right = this.evaluateExpression(expr.right);
1016
+ const res = new BasicEvaluatedExpression();
1017
+ if (left.isString()) {
1018
+ if (right.isString()) {
1019
+ res.setString(
1020
+ /** @type {string} */ (left.string) +
1021
+ /** @type {string} */ (right.string)
1022
+ );
1023
+ } else if (right.isNumber()) {
1024
+ res.setString(/** @type {string} */ (left.string) + right.number);
1025
+ } else if (
1026
+ right.isWrapped() &&
1027
+ right.prefix &&
1028
+ right.prefix.isString()
1029
+ ) {
1030
+ // "left" + ("prefix" + inner + "postfix")
1031
+ // => ("leftPrefix" + inner + "postfix")
1032
+ res.setWrapped(
1033
+ new BasicEvaluatedExpression()
1034
+ .setString(
1035
+ /** @type {string} */ (left.string) +
1036
+ /** @type {string} */ (right.prefix.string)
1037
+ )
1038
+ .setRange(
1039
+ joinRanges(
1040
+ /** @type {Range} */ (left.range),
1041
+ /** @type {Range} */ (right.prefix.range)
1092
1042
  )
1093
- .setRange(
1094
- joinRanges(
1095
- /** @type {Range} */ (left.postfix.range),
1096
- /** @type {Range} */ (right.range)
1097
- )
1098
- ),
1099
- left.wrappedInnerExpressions
1100
- );
1101
- } else if (
1102
- left.postfix &&
1103
- left.postfix.isString() &&
1104
- right.isNumber()
1105
- ) {
1106
- // ("prefix" + inner + "postfix") + 123
1107
- // => ("prefix" + inner + "postfix123")
1108
- res.setWrapped(
1109
- left.prefix,
1110
- new BasicEvaluatedExpression()
1111
- .setString(
1112
- /** @type {string} */ (left.postfix.string) +
1113
- /** @type {number} */ (right.number)
1043
+ ),
1044
+ right.postfix,
1045
+ right.wrappedInnerExpressions
1046
+ );
1047
+ } else if (right.isWrapped()) {
1048
+ // "left" + ([null] + inner + "postfix")
1049
+ // => ("left" + inner + "postfix")
1050
+ res.setWrapped(left, right.postfix, right.wrappedInnerExpressions);
1051
+ } else {
1052
+ // "left" + expr
1053
+ // => ("left" + expr + "")
1054
+ res.setWrapped(left, null, [right]);
1055
+ }
1056
+ } else if (left.isNumber()) {
1057
+ if (right.isString()) {
1058
+ res.setString(left.number + /** @type {string} */ (right.string));
1059
+ } else if (right.isNumber()) {
1060
+ res.setNumber(
1061
+ /** @type {number} */ (left.number) +
1062
+ /** @type {number} */ (right.number)
1063
+ );
1064
+ } else {
1065
+ return;
1066
+ }
1067
+ } else if (left.isBigInt()) {
1068
+ if (right.isBigInt()) {
1069
+ res.setBigInt(
1070
+ /** @type {bigint} */ (left.bigint) +
1071
+ /** @type {bigint} */ (right.bigint)
1072
+ );
1073
+ }
1074
+ } else if (left.isWrapped()) {
1075
+ if (left.postfix && left.postfix.isString() && right.isString()) {
1076
+ // ("prefix" + inner + "postfix") + "right"
1077
+ // => ("prefix" + inner + "postfixRight")
1078
+ res.setWrapped(
1079
+ left.prefix,
1080
+ new BasicEvaluatedExpression()
1081
+ .setString(
1082
+ /** @type {string} */ (left.postfix.string) +
1083
+ /** @type {string} */ (right.string)
1084
+ )
1085
+ .setRange(
1086
+ joinRanges(
1087
+ /** @type {Range} */ (left.postfix.range),
1088
+ /** @type {Range} */ (right.range)
1114
1089
  )
1115
- .setRange(
1116
- joinRanges(
1117
- /** @type {Range} */ (left.postfix.range),
1118
- /** @type {Range} */ (right.range)
1119
- )
1120
- ),
1121
- left.wrappedInnerExpressions
1122
- );
1123
- } else if (right.isString()) {
1124
- // ("prefix" + inner + [null]) + "right"
1125
- // => ("prefix" + inner + "right")
1126
- res.setWrapped(left.prefix, right, left.wrappedInnerExpressions);
1127
- } else if (right.isNumber()) {
1128
- // ("prefix" + inner + [null]) + 123
1129
- // => ("prefix" + inner + "123")
1130
- res.setWrapped(
1131
- left.prefix,
1132
- new BasicEvaluatedExpression()
1133
- .setString(String(right.number))
1134
- .setRange(/** @type {Range} */ (right.range)),
1135
- left.wrappedInnerExpressions
1136
- );
1137
- } else if (right.isWrapped()) {
1138
- // ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")
1139
- // ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")
1140
- res.setWrapped(
1141
- left.prefix,
1142
- right.postfix,
1143
- left.wrappedInnerExpressions &&
1144
- right.wrappedInnerExpressions &&
1145
- left.wrappedInnerExpressions
1146
- .concat(left.postfix ? [left.postfix] : [])
1147
- .concat(right.prefix ? [right.prefix] : [])
1148
- .concat(right.wrappedInnerExpressions)
1149
- );
1150
- } else {
1151
- // ("prefix" + inner + postfix) + expr
1152
- // => ("prefix" + inner + postfix + expr + [null])
1153
- res.setWrapped(
1154
- left.prefix,
1155
- null,
1156
- left.wrappedInnerExpressions &&
1157
- left.wrappedInnerExpressions.concat(
1158
- left.postfix ? [left.postfix, right] : [right]
1090
+ ),
1091
+ left.wrappedInnerExpressions
1092
+ );
1093
+ } else if (
1094
+ left.postfix &&
1095
+ left.postfix.isString() &&
1096
+ right.isNumber()
1097
+ ) {
1098
+ // ("prefix" + inner + "postfix") + 123
1099
+ // => ("prefix" + inner + "postfix123")
1100
+ res.setWrapped(
1101
+ left.prefix,
1102
+ new BasicEvaluatedExpression()
1103
+ .setString(
1104
+ /** @type {string} */ (left.postfix.string) +
1105
+ /** @type {number} */ (right.number)
1106
+ )
1107
+ .setRange(
1108
+ joinRanges(
1109
+ /** @type {Range} */ (left.postfix.range),
1110
+ /** @type {Range} */ (right.range)
1159
1111
  )
1160
- );
1161
- }
1112
+ ),
1113
+ left.wrappedInnerExpressions
1114
+ );
1162
1115
  } else if (right.isString()) {
1163
- // left + "right"
1164
- // => ([null] + left + "right")
1165
- res.setWrapped(null, right, [left]);
1116
+ // ("prefix" + inner + [null]) + "right"
1117
+ // => ("prefix" + inner + "right")
1118
+ res.setWrapped(left.prefix, right, left.wrappedInnerExpressions);
1119
+ } else if (right.isNumber()) {
1120
+ // ("prefix" + inner + [null]) + 123
1121
+ // => ("prefix" + inner + "123")
1122
+ res.setWrapped(
1123
+ left.prefix,
1124
+ new BasicEvaluatedExpression()
1125
+ .setString(String(right.number))
1126
+ .setRange(/** @type {Range} */ (right.range)),
1127
+ left.wrappedInnerExpressions
1128
+ );
1166
1129
  } else if (right.isWrapped()) {
1167
- // left + (prefix + inner + "postfix")
1168
- // => ([null] + left + prefix + inner + "postfix")
1130
+ // ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")
1131
+ // ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")
1169
1132
  res.setWrapped(
1170
- null,
1133
+ left.prefix,
1171
1134
  right.postfix,
1172
- right.wrappedInnerExpressions &&
1173
- (right.prefix ? [left, right.prefix] : [left]).concat(
1174
- right.wrappedInnerExpressions
1175
- )
1135
+ left.wrappedInnerExpressions &&
1136
+ right.wrappedInnerExpressions &&
1137
+ left.wrappedInnerExpressions
1138
+ .concat(left.postfix ? [left.postfix] : [])
1139
+ .concat(right.prefix ? [right.prefix] : [])
1140
+ .concat(right.wrappedInnerExpressions)
1176
1141
  );
1177
1142
  } else {
1178
- return;
1143
+ // ("prefix" + inner + postfix) + expr
1144
+ // => ("prefix" + inner + postfix + expr + [null])
1145
+ res.setWrapped(
1146
+ left.prefix,
1147
+ null,
1148
+ left.wrappedInnerExpressions &&
1149
+ left.wrappedInnerExpressions.concat(
1150
+ left.postfix ? [left.postfix, right] : [right]
1151
+ )
1152
+ );
1179
1153
  }
1180
- if (left.couldHaveSideEffects() || right.couldHaveSideEffects())
1181
- res.setSideEffects();
1182
- res.setRange(/** @type {Range} */ (expr.range));
1183
- return res;
1184
- } else if (expr.operator === "-") {
1185
- return handleConstOperation((l, r) => l - r);
1186
- } else if (expr.operator === "*") {
1187
- return handleConstOperation((l, r) => l * r);
1188
- } else if (expr.operator === "/") {
1189
- return handleConstOperation((l, r) => l / r);
1190
- } else if (expr.operator === "**") {
1191
- return handleConstOperation((l, r) => l ** r);
1192
- } else if (expr.operator === "===") {
1193
- return handleStrictEqualityComparison(true);
1194
- } else if (expr.operator === "==") {
1195
- return handleAbstractEqualityComparison(true);
1196
- } else if (expr.operator === "!==") {
1197
- return handleStrictEqualityComparison(false);
1198
- } else if (expr.operator === "!=") {
1199
- return handleAbstractEqualityComparison(false);
1200
- } else if (expr.operator === "&") {
1201
- return handleConstOperation((l, r) => l & r);
1202
- } else if (expr.operator === "|") {
1203
- return handleConstOperation((l, r) => l | r);
1204
- } else if (expr.operator === "^") {
1205
- return handleConstOperation((l, r) => l ^ r);
1206
- } else if (expr.operator === ">>>") {
1207
- return handleConstOperation((l, r) => l >>> r);
1208
- } else if (expr.operator === ">>") {
1209
- return handleConstOperation((l, r) => l >> r);
1210
- } else if (expr.operator === "<<") {
1211
- return handleConstOperation((l, r) => l << r);
1212
- } else if (expr.operator === "<") {
1213
- return handleConstOperation((l, r) => l < r);
1214
- } else if (expr.operator === ">") {
1215
- return handleConstOperation((l, r) => l > r);
1216
- } else if (expr.operator === "<=") {
1217
- return handleConstOperation((l, r) => l <= r);
1218
- } else if (expr.operator === ">=") {
1219
- return handleConstOperation((l, r) => l >= r);
1220
- }
1221
- });
1222
- this.hooks.evaluate
1223
- .for("UnaryExpression")
1224
- .tap("JavascriptParser", _expr => {
1225
- const expr = /** @type {UnaryExpression} */ (_expr);
1226
-
1227
- /**
1228
- * Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
1229
- * @template T
1230
- * @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
1231
- * @returns {BasicEvaluatedExpression | undefined} evaluated expression
1232
- */
1233
- const handleConstOperation = operandHandler => {
1234
- const argument = this.evaluateExpression(expr.argument);
1235
- if (!argument.isCompileTimeValue()) return;
1236
- const result = operandHandler(
1237
- /** @type {T} */ (argument.asCompileTimeValue())
1238
- );
1239
- return valueAsExpression(
1240
- result,
1241
- expr,
1242
- argument.couldHaveSideEffects()
1154
+ } else if (right.isString()) {
1155
+ // left + "right"
1156
+ // => ([null] + left + "right")
1157
+ res.setWrapped(null, right, [left]);
1158
+ } else if (right.isWrapped()) {
1159
+ // left + (prefix + inner + "postfix")
1160
+ // => ([null] + left + prefix + inner + "postfix")
1161
+ res.setWrapped(
1162
+ null,
1163
+ right.postfix,
1164
+ right.wrappedInnerExpressions &&
1165
+ (right.prefix ? [left, right.prefix] : [left]).concat(
1166
+ right.wrappedInnerExpressions
1167
+ )
1243
1168
  );
1244
- };
1169
+ } else {
1170
+ return;
1171
+ }
1172
+ if (left.couldHaveSideEffects() || right.couldHaveSideEffects())
1173
+ res.setSideEffects();
1174
+ res.setRange(/** @type {Range} */ (expr.range));
1175
+ return res;
1176
+ } else if (expr.operator === "-") {
1177
+ return handleConstOperation((l, r) => l - r);
1178
+ } else if (expr.operator === "*") {
1179
+ return handleConstOperation((l, r) => l * r);
1180
+ } else if (expr.operator === "/") {
1181
+ return handleConstOperation((l, r) => l / r);
1182
+ } else if (expr.operator === "**") {
1183
+ return handleConstOperation((l, r) => l ** r);
1184
+ } else if (expr.operator === "===") {
1185
+ return handleStrictEqualityComparison(true);
1186
+ } else if (expr.operator === "==") {
1187
+ return handleAbstractEqualityComparison(true);
1188
+ } else if (expr.operator === "!==") {
1189
+ return handleStrictEqualityComparison(false);
1190
+ } else if (expr.operator === "!=") {
1191
+ return handleAbstractEqualityComparison(false);
1192
+ } else if (expr.operator === "&") {
1193
+ return handleConstOperation((l, r) => l & r);
1194
+ } else if (expr.operator === "|") {
1195
+ return handleConstOperation((l, r) => l | r);
1196
+ } else if (expr.operator === "^") {
1197
+ return handleConstOperation((l, r) => l ^ r);
1198
+ } else if (expr.operator === ">>>") {
1199
+ return handleConstOperation((l, r) => l >>> r);
1200
+ } else if (expr.operator === ">>") {
1201
+ return handleConstOperation((l, r) => l >> r);
1202
+ } else if (expr.operator === "<<") {
1203
+ return handleConstOperation((l, r) => l << r);
1204
+ } else if (expr.operator === "<") {
1205
+ return handleConstOperation((l, r) => l < r);
1206
+ } else if (expr.operator === ">") {
1207
+ return handleConstOperation((l, r) => l > r);
1208
+ } else if (expr.operator === "<=") {
1209
+ return handleConstOperation((l, r) => l <= r);
1210
+ } else if (expr.operator === ">=") {
1211
+ return handleConstOperation((l, r) => l >= r);
1212
+ }
1213
+ });
1214
+ this.hooks.evaluate.for("UnaryExpression").tap(CLASS_NAME, _expr => {
1215
+ const expr = /** @type {UnaryExpression} */ (_expr);
1216
+
1217
+ /**
1218
+ * Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
1219
+ * @template T
1220
+ * @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
1221
+ * @returns {BasicEvaluatedExpression | undefined} evaluated expression
1222
+ */
1223
+ const handleConstOperation = operandHandler => {
1224
+ const argument = this.evaluateExpression(expr.argument);
1225
+ if (!argument.isCompileTimeValue()) return;
1226
+ const result = operandHandler(
1227
+ /** @type {T} */ (argument.asCompileTimeValue())
1228
+ );
1229
+ return valueAsExpression(result, expr, argument.couldHaveSideEffects());
1230
+ };
1245
1231
 
1246
- if (expr.operator === "typeof") {
1247
- switch (expr.argument.type) {
1248
- case "Identifier": {
1249
- const res = this.callHooksForName(
1250
- this.hooks.evaluateTypeof,
1251
- expr.argument.name,
1252
- expr
1253
- );
1254
- if (res !== undefined) return res;
1255
- break;
1256
- }
1257
- case "MetaProperty": {
1258
- const res = this.callHooksForName(
1259
- this.hooks.evaluateTypeof,
1260
- /** @type {string} */
1261
- (getRootName(expr.argument)),
1262
- expr
1263
- );
1264
- if (res !== undefined) return res;
1265
- break;
1266
- }
1267
- case "MemberExpression": {
1268
- const res = this.callHooksForExpression(
1269
- this.hooks.evaluateTypeof,
1270
- expr.argument,
1271
- expr
1272
- );
1273
- if (res !== undefined) return res;
1274
- break;
1275
- }
1276
- case "ChainExpression": {
1277
- const res = this.callHooksForExpression(
1278
- this.hooks.evaluateTypeof,
1279
- expr.argument.expression,
1280
- expr
1281
- );
1282
- if (res !== undefined) return res;
1283
- break;
1284
- }
1285
- case "FunctionExpression": {
1286
- return new BasicEvaluatedExpression()
1287
- .setString("function")
1288
- .setRange(/** @type {Range} */ (expr.range));
1289
- }
1290
- }
1291
- const arg = this.evaluateExpression(expr.argument);
1292
- if (arg.isUnknown()) return;
1293
- if (arg.isString()) {
1294
- return new BasicEvaluatedExpression()
1295
- .setString("string")
1296
- .setRange(/** @type {Range} */ (expr.range));
1297
- }
1298
- if (arg.isWrapped()) {
1299
- return new BasicEvaluatedExpression()
1300
- .setString("string")
1301
- .setSideEffects()
1302
- .setRange(/** @type {Range} */ (expr.range));
1303
- }
1304
- if (arg.isUndefined()) {
1305
- return new BasicEvaluatedExpression()
1306
- .setString("undefined")
1307
- .setRange(/** @type {Range} */ (expr.range));
1308
- }
1309
- if (arg.isNumber()) {
1310
- return new BasicEvaluatedExpression()
1311
- .setString("number")
1312
- .setRange(/** @type {Range} */ (expr.range));
1232
+ if (expr.operator === "typeof") {
1233
+ switch (expr.argument.type) {
1234
+ case "Identifier": {
1235
+ const res = this.callHooksForName(
1236
+ this.hooks.evaluateTypeof,
1237
+ expr.argument.name,
1238
+ expr
1239
+ );
1240
+ if (res !== undefined) return res;
1241
+ break;
1313
1242
  }
1314
- if (arg.isBigInt()) {
1315
- return new BasicEvaluatedExpression()
1316
- .setString("bigint")
1317
- .setRange(/** @type {Range} */ (expr.range));
1243
+ case "MetaProperty": {
1244
+ const res = this.callHooksForName(
1245
+ this.hooks.evaluateTypeof,
1246
+ /** @type {string} */
1247
+ (getRootName(expr.argument)),
1248
+ expr
1249
+ );
1250
+ if (res !== undefined) return res;
1251
+ break;
1318
1252
  }
1319
- if (arg.isBoolean()) {
1320
- return new BasicEvaluatedExpression()
1321
- .setString("boolean")
1322
- .setRange(/** @type {Range} */ (expr.range));
1253
+ case "MemberExpression": {
1254
+ const res = this.callHooksForExpression(
1255
+ this.hooks.evaluateTypeof,
1256
+ expr.argument,
1257
+ expr
1258
+ );
1259
+ if (res !== undefined) return res;
1260
+ break;
1323
1261
  }
1324
- if (arg.isConstArray() || arg.isRegExp() || arg.isNull()) {
1325
- return new BasicEvaluatedExpression()
1326
- .setString("object")
1327
- .setRange(/** @type {Range} */ (expr.range));
1262
+ case "ChainExpression": {
1263
+ const res = this.callHooksForExpression(
1264
+ this.hooks.evaluateTypeof,
1265
+ expr.argument.expression,
1266
+ expr
1267
+ );
1268
+ if (res !== undefined) return res;
1269
+ break;
1328
1270
  }
1329
- if (arg.isArray()) {
1271
+ case "FunctionExpression": {
1330
1272
  return new BasicEvaluatedExpression()
1331
- .setString("object")
1332
- .setSideEffects(arg.couldHaveSideEffects())
1273
+ .setString("function")
1333
1274
  .setRange(/** @type {Range} */ (expr.range));
1334
1275
  }
1335
- } else if (expr.operator === "!") {
1336
- const argument = this.evaluateExpression(expr.argument);
1337
- const bool = argument.asBool();
1338
- if (typeof bool !== "boolean") return;
1276
+ }
1277
+ const arg = this.evaluateExpression(expr.argument);
1278
+ if (arg.isUnknown()) return;
1279
+ if (arg.isString()) {
1339
1280
  return new BasicEvaluatedExpression()
1340
- .setBoolean(!bool)
1341
- .setSideEffects(argument.couldHaveSideEffects())
1281
+ .setString("string")
1342
1282
  .setRange(/** @type {Range} */ (expr.range));
1343
- } else if (expr.operator === "~") {
1344
- return handleConstOperation(v => ~v);
1345
- } else if (expr.operator === "+") {
1346
- // eslint-disable-next-line no-implicit-coercion
1347
- return handleConstOperation(v => +v);
1348
- } else if (expr.operator === "-") {
1349
- return handleConstOperation(v => -v);
1350
1283
  }
1351
- });
1284
+ if (arg.isWrapped()) {
1285
+ return new BasicEvaluatedExpression()
1286
+ .setString("string")
1287
+ .setSideEffects()
1288
+ .setRange(/** @type {Range} */ (expr.range));
1289
+ }
1290
+ if (arg.isUndefined()) {
1291
+ return new BasicEvaluatedExpression()
1292
+ .setString("undefined")
1293
+ .setRange(/** @type {Range} */ (expr.range));
1294
+ }
1295
+ if (arg.isNumber()) {
1296
+ return new BasicEvaluatedExpression()
1297
+ .setString("number")
1298
+ .setRange(/** @type {Range} */ (expr.range));
1299
+ }
1300
+ if (arg.isBigInt()) {
1301
+ return new BasicEvaluatedExpression()
1302
+ .setString("bigint")
1303
+ .setRange(/** @type {Range} */ (expr.range));
1304
+ }
1305
+ if (arg.isBoolean()) {
1306
+ return new BasicEvaluatedExpression()
1307
+ .setString("boolean")
1308
+ .setRange(/** @type {Range} */ (expr.range));
1309
+ }
1310
+ if (arg.isConstArray() || arg.isRegExp() || arg.isNull()) {
1311
+ return new BasicEvaluatedExpression()
1312
+ .setString("object")
1313
+ .setRange(/** @type {Range} */ (expr.range));
1314
+ }
1315
+ if (arg.isArray()) {
1316
+ return new BasicEvaluatedExpression()
1317
+ .setString("object")
1318
+ .setSideEffects(arg.couldHaveSideEffects())
1319
+ .setRange(/** @type {Range} */ (expr.range));
1320
+ }
1321
+ } else if (expr.operator === "!") {
1322
+ const argument = this.evaluateExpression(expr.argument);
1323
+ const bool = argument.asBool();
1324
+ if (typeof bool !== "boolean") return;
1325
+ return new BasicEvaluatedExpression()
1326
+ .setBoolean(!bool)
1327
+ .setSideEffects(argument.couldHaveSideEffects())
1328
+ .setRange(/** @type {Range} */ (expr.range));
1329
+ } else if (expr.operator === "~") {
1330
+ return handleConstOperation(v => ~v);
1331
+ } else if (expr.operator === "+") {
1332
+ // eslint-disable-next-line no-implicit-coercion
1333
+ return handleConstOperation(v => +v);
1334
+ } else if (expr.operator === "-") {
1335
+ return handleConstOperation(v => -v);
1336
+ }
1337
+ });
1352
1338
  this.hooks.evaluateTypeof
1353
1339
  .for("undefined")
1354
- .tap("JavascriptParser", expr =>
1340
+ .tap(CLASS_NAME, expr =>
1355
1341
  new BasicEvaluatedExpression()
1356
1342
  .setString("undefined")
1357
1343
  .setRange(/** @type {Range} */ (expr.range))
1358
1344
  );
1359
- this.hooks.evaluate.for("Identifier").tap("JavascriptParser", expr => {
1345
+ this.hooks.evaluate.for("Identifier").tap(CLASS_NAME, expr => {
1360
1346
  if (/** @type {Identifier} */ (expr).name === "undefined") {
1361
1347
  return new BasicEvaluatedExpression()
1362
1348
  .setUndefined()
@@ -1373,7 +1359,7 @@ class JavascriptParser extends Parser {
1373
1359
  let cachedExpression;
1374
1360
  /** @type {GetInfoResult | undefined} */
1375
1361
  let cachedInfo;
1376
- this.hooks.evaluate.for(exprType).tap("JavascriptParser", expr => {
1362
+ this.hooks.evaluate.for(exprType).tap(CLASS_NAME, expr => {
1377
1363
  const expression =
1378
1364
  /** @type {Identifier | ThisExpression | MemberExpression} */ (expr);
1379
1365
 
@@ -1398,7 +1384,7 @@ class JavascriptParser extends Parser {
1398
1384
  });
1399
1385
  this.hooks.evaluate
1400
1386
  .for(exprType)
1401
- .tap({ name: "JavascriptParser", stage: 100 }, expr => {
1387
+ .tap({ name: CLASS_NAME, stage: 100 }, expr => {
1402
1388
  const expression =
1403
1389
  /** @type {Identifier | ThisExpression | MemberExpression} */
1404
1390
  (expr);
@@ -1416,7 +1402,7 @@ class JavascriptParser extends Parser {
1416
1402
  .setRange(/** @type {Range} */ (expression.range));
1417
1403
  }
1418
1404
  });
1419
- this.hooks.finish.tap("JavascriptParser", () => {
1405
+ this.hooks.finish.tap(CLASS_NAME, () => {
1420
1406
  // Cleanup for GC
1421
1407
  cachedExpression = cachedInfo = undefined;
1422
1408
  });
@@ -1451,7 +1437,7 @@ class JavascriptParser extends Parser {
1451
1437
  };
1452
1438
  }
1453
1439
  });
1454
- this.hooks.evaluate.for("MetaProperty").tap("JavascriptParser", expr => {
1440
+ this.hooks.evaluate.for("MetaProperty").tap(CLASS_NAME, expr => {
1455
1441
  const metaProperty = /** @type {MetaProperty} */ (expr);
1456
1442
 
1457
1443
  return this.callHooksForName(
@@ -1468,7 +1454,7 @@ class JavascriptParser extends Parser {
1468
1454
  )
1469
1455
  );
1470
1456
 
1471
- this.hooks.evaluate.for("CallExpression").tap("JavascriptParser", _expr => {
1457
+ this.hooks.evaluate.for("CallExpression").tap(CLASS_NAME, _expr => {
1472
1458
  const expr = /** @type {CallExpression} */ (_expr);
1473
1459
  if (
1474
1460
  expr.callee.type === "MemberExpression" &&
@@ -1497,7 +1483,7 @@ class JavascriptParser extends Parser {
1497
1483
  });
1498
1484
  this.hooks.evaluateCallExpressionMember
1499
1485
  .for("indexOf")
1500
- .tap("JavascriptParser", (expr, param) => {
1486
+ .tap(CLASS_NAME, (expr, param) => {
1501
1487
  if (!param.isString()) return;
1502
1488
  if (expr.arguments.length === 0) return;
1503
1489
  const [arg1, arg2] = expr.arguments;
@@ -1525,7 +1511,7 @@ class JavascriptParser extends Parser {
1525
1511
  });
1526
1512
  this.hooks.evaluateCallExpressionMember
1527
1513
  .for("replace")
1528
- .tap("JavascriptParser", (expr, param) => {
1514
+ .tap(CLASS_NAME, (expr, param) => {
1529
1515
  if (!param.isString()) return;
1530
1516
  if (expr.arguments.length !== 2) return;
1531
1517
  if (expr.arguments[0].type === "SpreadElement") return;
@@ -1548,7 +1534,7 @@ class JavascriptParser extends Parser {
1548
1534
  for (const fn of ["substr", "substring", "slice"]) {
1549
1535
  this.hooks.evaluateCallExpressionMember
1550
1536
  .for(fn)
1551
- .tap("JavascriptParser", (expr, param) => {
1537
+ .tap(CLASS_NAME, (expr, param) => {
1552
1538
  if (!param.isString()) return;
1553
1539
  let arg1;
1554
1540
  let result;
@@ -1640,22 +1626,20 @@ class JavascriptParser extends Parser {
1640
1626
  };
1641
1627
  };
1642
1628
 
1643
- this.hooks.evaluate
1644
- .for("TemplateLiteral")
1645
- .tap("JavascriptParser", _node => {
1646
- const node = /** @type {TemplateLiteral} */ (_node);
1629
+ this.hooks.evaluate.for("TemplateLiteral").tap(CLASS_NAME, _node => {
1630
+ const node = /** @type {TemplateLiteral} */ (_node);
1647
1631
 
1648
- const { quasis, parts } = getSimplifiedTemplateResult("cooked", node);
1649
- if (parts.length === 1) {
1650
- return parts[0].setRange(/** @type {Range} */ (node.range));
1651
- }
1652
- return new BasicEvaluatedExpression()
1653
- .setTemplateString(quasis, parts, "cooked")
1654
- .setRange(/** @type {Range} */ (node.range));
1655
- });
1632
+ const { quasis, parts } = getSimplifiedTemplateResult("cooked", node);
1633
+ if (parts.length === 1) {
1634
+ return parts[0].setRange(/** @type {Range} */ (node.range));
1635
+ }
1636
+ return new BasicEvaluatedExpression()
1637
+ .setTemplateString(quasis, parts, "cooked")
1638
+ .setRange(/** @type {Range} */ (node.range));
1639
+ });
1656
1640
  this.hooks.evaluate
1657
1641
  .for("TaggedTemplateExpression")
1658
- .tap("JavascriptParser", _node => {
1642
+ .tap(CLASS_NAME, _node => {
1659
1643
  const node = /** @type {TaggedTemplateExpression} */ (_node);
1660
1644
  const tag = this.evaluateExpression(node.tag);
1661
1645
 
@@ -1672,7 +1656,7 @@ class JavascriptParser extends Parser {
1672
1656
 
1673
1657
  this.hooks.evaluateCallExpressionMember
1674
1658
  .for("concat")
1675
- .tap("JavascriptParser", (expr, param) => {
1659
+ .tap(CLASS_NAME, (expr, param) => {
1676
1660
  if (!param.isString() && !param.isWrapped()) return;
1677
1661
  let stringSuffix = null;
1678
1662
  let hasUnknownParams = false;
@@ -1742,7 +1726,7 @@ class JavascriptParser extends Parser {
1742
1726
  });
1743
1727
  this.hooks.evaluateCallExpressionMember
1744
1728
  .for("split")
1745
- .tap("JavascriptParser", (expr, param) => {
1729
+ .tap(CLASS_NAME, (expr, param) => {
1746
1730
  if (!param.isString()) return;
1747
1731
  if (expr.arguments.length !== 1) return;
1748
1732
  if (expr.arguments[0].type === "SpreadElement") return;
@@ -1764,101 +1748,95 @@ class JavascriptParser extends Parser {
1764
1748
  .setSideEffects(param.couldHaveSideEffects())
1765
1749
  .setRange(/** @type {Range} */ (expr.range));
1766
1750
  });
1767
- this.hooks.evaluate
1768
- .for("ConditionalExpression")
1769
- .tap("JavascriptParser", _expr => {
1770
- const expr = /** @type {ConditionalExpression} */ (_expr);
1771
-
1772
- const condition = this.evaluateExpression(expr.test);
1773
- const conditionValue = condition.asBool();
1774
- let res;
1775
- if (conditionValue === undefined) {
1776
- const consequent = this.evaluateExpression(expr.consequent);
1777
- const alternate = this.evaluateExpression(expr.alternate);
1778
- res = new BasicEvaluatedExpression();
1779
- if (consequent.isConditional()) {
1780
- res.setOptions(
1781
- /** @type {BasicEvaluatedExpression[]} */ (consequent.options)
1782
- );
1783
- } else {
1784
- res.setOptions([consequent]);
1785
- }
1786
- if (alternate.isConditional()) {
1787
- res.addOptions(
1788
- /** @type {BasicEvaluatedExpression[]} */ (alternate.options)
1789
- );
1790
- } else {
1791
- res.addOptions([alternate]);
1792
- }
1751
+ this.hooks.evaluate.for("ConditionalExpression").tap(CLASS_NAME, _expr => {
1752
+ const expr = /** @type {ConditionalExpression} */ (_expr);
1753
+
1754
+ const condition = this.evaluateExpression(expr.test);
1755
+ const conditionValue = condition.asBool();
1756
+ let res;
1757
+ if (conditionValue === undefined) {
1758
+ const consequent = this.evaluateExpression(expr.consequent);
1759
+ const alternate = this.evaluateExpression(expr.alternate);
1760
+ res = new BasicEvaluatedExpression();
1761
+ if (consequent.isConditional()) {
1762
+ res.setOptions(
1763
+ /** @type {BasicEvaluatedExpression[]} */ (consequent.options)
1764
+ );
1793
1765
  } else {
1794
- res = this.evaluateExpression(
1795
- conditionValue ? expr.consequent : expr.alternate
1766
+ res.setOptions([consequent]);
1767
+ }
1768
+ if (alternate.isConditional()) {
1769
+ res.addOptions(
1770
+ /** @type {BasicEvaluatedExpression[]} */ (alternate.options)
1796
1771
  );
1797
- if (condition.couldHaveSideEffects()) res.setSideEffects();
1772
+ } else {
1773
+ res.addOptions([alternate]);
1798
1774
  }
1799
- res.setRange(/** @type {Range} */ (expr.range));
1800
- return res;
1801
- });
1802
- this.hooks.evaluate
1803
- .for("ArrayExpression")
1804
- .tap("JavascriptParser", _expr => {
1805
- const expr = /** @type {ArrayExpression} */ (_expr);
1806
-
1807
- const items = expr.elements.map(
1808
- element =>
1809
- element !== null &&
1810
- element.type !== "SpreadElement" &&
1811
- this.evaluateExpression(element)
1775
+ } else {
1776
+ res = this.evaluateExpression(
1777
+ conditionValue ? expr.consequent : expr.alternate
1812
1778
  );
1813
- if (!items.every(Boolean)) return;
1814
- return new BasicEvaluatedExpression()
1815
- .setItems(/** @type {BasicEvaluatedExpression[]} */ (items))
1816
- .setRange(/** @type {Range} */ (expr.range));
1817
- });
1818
- this.hooks.evaluate
1819
- .for("ChainExpression")
1820
- .tap("JavascriptParser", _expr => {
1821
- const expr = /** @type {ChainExpression} */ (_expr);
1822
- /** @type {Expression[]} */
1823
- const optionalExpressionsStack = [];
1824
- /** @type {Expression|Super} */
1825
- let next = expr.expression;
1826
-
1827
- while (
1828
- next.type === "MemberExpression" ||
1829
- next.type === "CallExpression"
1830
- ) {
1831
- if (next.type === "MemberExpression") {
1832
- if (next.optional) {
1833
- // SuperNode can not be optional
1834
- optionalExpressionsStack.push(
1835
- /** @type {Expression} */ (next.object)
1836
- );
1837
- }
1838
- next = next.object;
1839
- } else {
1840
- if (next.optional) {
1841
- // SuperNode can not be optional
1842
- optionalExpressionsStack.push(
1843
- /** @type {Expression} */ (next.callee)
1844
- );
1845
- }
1846
- next = next.callee;
1779
+ if (condition.couldHaveSideEffects()) res.setSideEffects();
1780
+ }
1781
+ res.setRange(/** @type {Range} */ (expr.range));
1782
+ return res;
1783
+ });
1784
+ this.hooks.evaluate.for("ArrayExpression").tap(CLASS_NAME, _expr => {
1785
+ const expr = /** @type {ArrayExpression} */ (_expr);
1786
+
1787
+ const items = expr.elements.map(
1788
+ element =>
1789
+ element !== null &&
1790
+ element.type !== "SpreadElement" &&
1791
+ this.evaluateExpression(element)
1792
+ );
1793
+ if (!items.every(Boolean)) return;
1794
+ return new BasicEvaluatedExpression()
1795
+ .setItems(/** @type {BasicEvaluatedExpression[]} */ (items))
1796
+ .setRange(/** @type {Range} */ (expr.range));
1797
+ });
1798
+ this.hooks.evaluate.for("ChainExpression").tap(CLASS_NAME, _expr => {
1799
+ const expr = /** @type {ChainExpression} */ (_expr);
1800
+ /** @type {Expression[]} */
1801
+ const optionalExpressionsStack = [];
1802
+ /** @type {Expression|Super} */
1803
+ let next = expr.expression;
1804
+
1805
+ while (
1806
+ next.type === "MemberExpression" ||
1807
+ next.type === "CallExpression"
1808
+ ) {
1809
+ if (next.type === "MemberExpression") {
1810
+ if (next.optional) {
1811
+ // SuperNode can not be optional
1812
+ optionalExpressionsStack.push(
1813
+ /** @type {Expression} */ (next.object)
1814
+ );
1815
+ }
1816
+ next = next.object;
1817
+ } else {
1818
+ if (next.optional) {
1819
+ // SuperNode can not be optional
1820
+ optionalExpressionsStack.push(
1821
+ /** @type {Expression} */ (next.callee)
1822
+ );
1847
1823
  }
1824
+ next = next.callee;
1848
1825
  }
1826
+ }
1849
1827
 
1850
- while (optionalExpressionsStack.length > 0) {
1851
- const expression =
1852
- /** @type {Expression} */
1853
- (optionalExpressionsStack.pop());
1854
- const evaluated = this.evaluateExpression(expression);
1828
+ while (optionalExpressionsStack.length > 0) {
1829
+ const expression =
1830
+ /** @type {Expression} */
1831
+ (optionalExpressionsStack.pop());
1832
+ const evaluated = this.evaluateExpression(expression);
1855
1833
 
1856
- if (evaluated.asNullish()) {
1857
- return evaluated.setRange(/** @type {Range} */ (_expr.range));
1858
- }
1834
+ if (evaluated.asNullish()) {
1835
+ return evaluated.setRange(/** @type {Range} */ (_expr.range));
1859
1836
  }
1860
- return this.evaluateExpression(expr.expression);
1861
- });
1837
+ }
1838
+ return this.evaluateExpression(expr.expression);
1839
+ });
1862
1840
  }
1863
1841
 
1864
1842
  /**