webpack 5.99.5 → 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.
- package/README.md +1 -1
- package/lib/APIPlugin.js +2 -2
- package/lib/AutomaticPrefetchPlugin.js +21 -22
- package/lib/BannerPlugin.js +31 -35
- package/lib/Cache.js +1 -1
- package/lib/Chunk.js +12 -9
- package/lib/CleanPlugin.js +5 -3
- package/lib/Compilation.js +45 -35
- package/lib/Compiler.js +6 -4
- package/lib/ContextExclusionPlugin.js +4 -2
- package/lib/ContextModule.js +2 -1
- package/lib/ContextReplacementPlugin.js +5 -3
- package/lib/DelegatedPlugin.js +4 -2
- package/lib/DllEntryPlugin.js +4 -2
- package/lib/DllPlugin.js +5 -3
- package/lib/DllReferencePlugin.js +56 -60
- package/lib/DynamicEntryPlugin.js +4 -2
- package/lib/EntryOptionPlugin.js +3 -1
- package/lib/EntryPlugin.js +4 -2
- package/lib/EnvironmentPlugin.js +4 -2
- package/lib/EvalDevToolModulePlugin.js +9 -7
- package/lib/EvalSourceMapDevToolPlugin.js +137 -138
- package/lib/ExternalsPlugin.js +3 -1
- package/lib/FlagDependencyExportsPlugin.js +2 -1
- package/lib/HotModuleReplacementPlugin.js +3 -3
- package/lib/IgnorePlugin.js +6 -4
- package/lib/IgnoreWarningsPlugin.js +4 -2
- package/lib/LibManifestPlugin.js +3 -4
- package/lib/LoaderOptionsPlugin.js +4 -2
- package/lib/LoaderTargetPlugin.js +4 -2
- package/lib/Module.js +29 -14
- package/lib/ModuleFilenameHelpers.js +1 -1
- package/lib/ModuleGraph.js +15 -10
- package/lib/ModuleInfoHeaderPlugin.js +11 -12
- package/lib/MultiCompiler.js +5 -3
- package/lib/NoEmitOnErrorsPlugin.js +5 -3
- package/lib/NormalModule.js +6 -2
- package/lib/NormalModuleReplacementPlugin.js +33 -36
- package/lib/PlatformPlugin.js +3 -1
- package/lib/PrefetchPlugin.js +5 -3
- package/lib/ProgressPlugin.js +23 -26
- package/lib/RecordIdsPlugin.js +73 -103
- package/lib/RuntimePlugin.js +34 -32
- package/lib/SourceMapDevToolPlugin.js +8 -6
- package/lib/Template.js +1 -1
- package/lib/WarnCaseSensitiveModulesPlugin.js +36 -37
- package/lib/WarnNoModeSetPlugin.js +3 -1
- package/lib/WatchIgnorePlugin.js +3 -1
- package/lib/WebpackError.js +11 -3
- package/lib/WebpackOptionsApply.js +22 -5
- package/lib/async-modules/InferAsyncModulesPlugin.js +25 -26
- package/lib/buildChunkGraph.js +7 -2
- package/lib/cache/IdleFileCachePlugin.js +12 -13
- package/lib/cache/MemoryCachePlugin.js +2 -1
- package/lib/cache/MemoryWithGcCachePlugin.js +10 -7
- package/lib/cache/PackFileCacheStrategy.js +13 -21
- package/lib/cache/ResolverCachePlugin.js +22 -22
- package/lib/cli.js +8 -4
- package/lib/config/defaults.js +2 -2
- package/lib/config/normalization.js +9 -3
- package/lib/config/target.js +6 -6
- package/lib/container/ContainerReferencePlugin.js +24 -26
- package/lib/container/ModuleFederationPlugin.js +2 -1
- package/lib/css/CssGenerator.js +1 -1
- package/lib/css/CssModulesPlugin.js +6 -4
- package/lib/css/CssParser.js +1 -1
- package/lib/debug/ProfilingPlugin.js +1 -1
- package/lib/dependencies/ContextDependencyHelpers.js +1 -1
- package/lib/dependencies/CssIcssImportDependency.js +3 -2
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +9 -15
- package/lib/dependencies/HarmonyExportExpressionDependency.js +1 -1
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +2 -1
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +1 -1
- package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +15 -15
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +4 -2
- package/lib/dependencies/JsonExportsDependency.js +1 -1
- package/lib/dependencies/LoaderPlugin.js +5 -3
- package/lib/dependencies/LocalModulesHelpers.js +1 -1
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +46 -46
- package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +94 -100
- package/lib/dependencies/RequireResolveDependency.js +1 -1
- package/lib/dependencies/WorkerPlugin.js +2 -2
- package/lib/esm/ModuleChunkLoadingPlugin.js +76 -57
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +11 -9
- package/lib/hmr/HotModuleReplacement.runtime.js +0 -1
- package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +0 -1
- package/lib/hmr/LazyCompilationPlugin.js +17 -18
- package/lib/ids/ChunkModuleIdRangePlugin.js +6 -6
- package/lib/ids/DeterministicChunkIdsPlugin.js +1 -1
- package/lib/ids/DeterministicModuleIdsPlugin.js +48 -49
- package/lib/ids/HashedModuleIdsPlugin.js +4 -2
- package/lib/ids/NamedChunkIdsPlugin.js +6 -4
- package/lib/ids/NamedModuleIdsPlugin.js +6 -4
- package/lib/ids/NaturalChunkIdsPlugin.js +4 -2
- package/lib/ids/NaturalModuleIdsPlugin.js +4 -2
- package/lib/ids/OccurrenceChunkIdsPlugin.js +4 -2
- package/lib/ids/OccurrenceModuleIdsPlugin.js +4 -2
- package/lib/index.js +1 -1
- package/lib/javascript/BasicEvaluatedExpression.js +2 -2
- package/lib/javascript/JavascriptParser.js +670 -688
- package/lib/library/EnableLibraryPlugin.js +15 -2
- package/lib/library/ModuleLibraryPlugin.js +66 -43
- package/lib/logging/createConsoleLogger.js +0 -1
- package/lib/node/CommonJsChunkLoadingPlugin.js +71 -75
- package/lib/node/NodeEnvironmentPlugin.js +3 -1
- package/lib/node/NodeTemplatePlugin.js +2 -2
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +2 -2
- package/lib/node/ReadFileCompileWasmPlugin.js +3 -3
- package/lib/optimize/AggressiveMergingPlugin.js +1 -1
- package/lib/optimize/AggressiveSplittingPlugin.js +224 -232
- package/lib/optimize/ConcatenatedModule.js +12 -15
- package/lib/optimize/FlagIncludedChunksPlugin.js +92 -97
- package/lib/optimize/LimitChunkCountPlugin.js +4 -2
- package/lib/optimize/MangleExportsPlugin.js +15 -16
- package/lib/optimize/MinChunkSizePlugin.js +4 -2
- package/lib/optimize/ModuleConcatenationPlugin.js +4 -2
- package/lib/optimize/RealContentHashPlugin.js +4 -2
- package/lib/optimize/RemoveEmptyChunksPlugin.js +5 -3
- package/lib/optimize/RemoveParentModulesPlugin.js +4 -2
- package/lib/optimize/RuntimeChunkPlugin.js +17 -18
- package/lib/optimize/SplitChunksPlugin.js +9 -6
- package/lib/performance/SizeLimitsPlugin.js +3 -1
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +61 -62
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +3 -4
- package/lib/runtime/StartupChunkDependenciesPlugin.js +39 -42
- package/lib/schemes/DataUriPlugin.js +5 -3
- package/lib/schemes/FileUriPlugin.js +5 -3
- package/lib/schemes/HttpUriPlugin.js +32 -39
- package/lib/serialization/AggregateErrorSerializer.js +42 -0
- package/lib/serialization/BinaryMiddleware.js +22 -38
- package/lib/serialization/ErrorObjectSerializer.js +7 -2
- package/lib/serialization/FileMiddleware.js +29 -33
- package/lib/serialization/ObjectMiddleware.js +42 -30
- package/lib/serialization/Serializer.js +29 -18
- package/lib/serialization/SerializerMiddleware.js +105 -72
- package/lib/serialization/SingleItemMiddleware.js +4 -5
- package/lib/sharing/ProvideSharedPlugin.js +6 -4
- package/lib/stats/DefaultStatsFactoryPlugin.js +128 -57
- package/lib/stats/DefaultStatsPresetPlugin.js +25 -20
- package/lib/stats/DefaultStatsPrinterPlugin.js +486 -334
- package/lib/stats/StatsFactory.js +47 -10
- package/lib/stats/StatsPrinter.js +52 -31
- package/lib/util/ArrayQueue.js +1 -1
- package/lib/util/AsyncQueue.js +1 -1
- package/lib/util/TupleQueue.js +9 -7
- package/lib/util/TupleSet.js +37 -18
- package/lib/util/WeakTupleMap.js +50 -37
- package/lib/util/cleverMerge.js +2 -2
- package/lib/util/comparators.js +1 -1
- package/lib/util/concatenate.js +4 -2
- package/lib/util/createHash.js +1 -1
- package/lib/util/fs.js +1 -1
- package/lib/util/makeSerializable.js +1 -1
- package/lib/util/runtime.js +1 -0
- package/lib/util/serialization.js +50 -42
- package/lib/wasm-async/AsyncWebAssemblyGenerator.js +1 -1
- package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +1 -1
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +2 -2
- package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +55 -57
- package/lib/wasm-sync/WebAssemblyGenerator.js +1 -1
- package/lib/wasm-sync/WebAssemblyModulesPlugin.js +1 -1
- package/lib/web/FetchCompileWasmPlugin.js +2 -2
- package/lib/web/JsonpChunkLoadingPlugin.js +73 -74
- package/lib/webpack.js +1 -1
- package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +77 -78
- package/package.json +4 -3
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +24 -2
- package/types.d.ts +273 -128
@@ -280,10 +280,13 @@ class VariableInfo {
|
|
280
280
|
/**
|
281
281
|
* @typedef {object} TagInfo
|
282
282
|
* @property {Tag} tag
|
283
|
-
* @property {TagData}
|
283
|
+
* @property {TagData=} data
|
284
284
|
* @property {TagInfo | undefined} next
|
285
285
|
*/
|
286
286
|
|
287
|
+
const SCOPE_INFO_TERMINATED_RETURN = 1;
|
288
|
+
const SCOPE_INFO_TERMINATED_THROW = 2;
|
289
|
+
|
287
290
|
/**
|
288
291
|
* @typedef {object} ScopeInfo
|
289
292
|
* @property {StackedMap<string, VariableInfo | ScopeInfo>} definitions
|
@@ -293,8 +296,7 @@ class VariableInfo {
|
|
293
296
|
* @property {boolean} inTry
|
294
297
|
* @property {boolean} isStrict
|
295
298
|
* @property {boolean} isAsmJs
|
296
|
-
* @property {
|
297
|
-
* @property {undefined|"return"|"throw"} terminated
|
299
|
+
* @property {undefined | 1 | 2} terminated
|
298
300
|
*/
|
299
301
|
|
300
302
|
/** @typedef {[number, number]} Range */
|
@@ -310,9 +312,9 @@ class VariableInfo {
|
|
310
312
|
* Helper function for joining two ranges into a single range. This is useful
|
311
313
|
* when working with AST nodes, as it allows you to combine the ranges of child nodes
|
312
314
|
* to create the range of the _parent node_.
|
313
|
-
* @param {
|
314
|
-
* @param {
|
315
|
-
* @returns {
|
315
|
+
* @param {Range} startRange start range to join
|
316
|
+
* @param {Range} endRange end range to join
|
317
|
+
* @returns {Range} joined range
|
316
318
|
* @example
|
317
319
|
* ```js
|
318
320
|
* const startRange = [0, 5];
|
@@ -387,6 +389,8 @@ const EMPTY_COMMENT_OPTIONS = {
|
|
387
389
|
errors: null
|
388
390
|
};
|
389
391
|
|
392
|
+
const CLASS_NAME = "JavascriptParser";
|
393
|
+
|
390
394
|
class JavascriptParser extends Parser {
|
391
395
|
/**
|
392
396
|
* @param {"module" | "script" | "auto"} sourceType default source type
|
@@ -598,7 +602,7 @@ class JavascriptParser extends Parser {
|
|
598
602
|
}
|
599
603
|
|
600
604
|
_initializeEvaluating() {
|
601
|
-
this.hooks.evaluate.for("Literal").tap(
|
605
|
+
this.hooks.evaluate.for("Literal").tap(CLASS_NAME, _expr => {
|
602
606
|
const expr = /** @type {Literal} */ (_expr);
|
603
607
|
|
604
608
|
switch (typeof expr.value) {
|
@@ -630,7 +634,7 @@ class JavascriptParser extends Parser {
|
|
630
634
|
.setRange(/** @type {Range} */ (expr.range));
|
631
635
|
}
|
632
636
|
});
|
633
|
-
this.hooks.evaluate.for("NewExpression").tap(
|
637
|
+
this.hooks.evaluate.for("NewExpression").tap(CLASS_NAME, _expr => {
|
634
638
|
const expr = /** @type {NewExpression} */ (_expr);
|
635
639
|
const callee = expr.callee;
|
636
640
|
if (callee.type !== "Identifier") return;
|
@@ -693,52 +697,50 @@ class JavascriptParser extends Parser {
|
|
693
697
|
.setRegExp(flags ? new RegExp(regExp, flags) : new RegExp(regExp))
|
694
698
|
.setRange(/** @type {Range} */ (expr.range));
|
695
699
|
});
|
696
|
-
this.hooks.evaluate
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
if (
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
return right.setRange(/** @type {Range} */ (expr.range));
|
728
|
-
}
|
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
|
+
}
|
729
731
|
|
730
|
-
|
732
|
+
const asBool = right.asBool();
|
731
733
|
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
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
|
+
});
|
742
744
|
|
743
745
|
/**
|
744
746
|
* In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on
|
@@ -808,551 +810,539 @@ class JavascriptParser extends Parser {
|
|
808
810
|
}
|
809
811
|
};
|
810
812
|
|
811
|
-
this.hooks.evaluate
|
812
|
-
|
813
|
-
.tap("JavascriptParser", _expr => {
|
814
|
-
const expr = /** @type {BinaryExpression} */ (_expr);
|
815
|
-
|
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;
|
813
|
+
this.hooks.evaluate.for("BinaryExpression").tap(CLASS_NAME, _expr => {
|
814
|
+
const expr = /** @type {BinaryExpression} */ (_expr);
|
825
815
|
|
826
|
-
|
827
|
-
|
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;
|
828
825
|
|
829
|
-
|
830
|
-
|
831
|
-
right.asCompileTimeValue()
|
832
|
-
);
|
833
|
-
return valueAsExpression(
|
834
|
-
result,
|
835
|
-
expr,
|
836
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
837
|
-
);
|
838
|
-
};
|
826
|
+
const right = this.evaluateExpression(expr.right);
|
827
|
+
if (!right.isCompileTimeValue()) return;
|
839
828
|
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
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
|
+
};
|
849
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) => {
|
850
858
|
/**
|
851
|
-
* @param {BasicEvaluatedExpression}
|
852
|
-
* @
|
853
|
-
* @param {BasicEvaluatedExpression} res res
|
854
|
-
* @param {boolean} eql true for "===" and false for "!=="
|
855
|
-
* @returns {BasicEvaluatedExpression | undefined} result
|
859
|
+
* @param {BasicEvaluatedExpression[]} parts parts
|
860
|
+
* @returns {string} value
|
856
861
|
*/
|
857
|
-
const
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
let value = "";
|
864
|
-
for (const p of parts) {
|
865
|
-
const v = p.asString();
|
866
|
-
if (v !== undefined) value += v;
|
867
|
-
else break;
|
868
|
-
}
|
869
|
-
return value;
|
870
|
-
};
|
871
|
-
/**
|
872
|
-
* @param {BasicEvaluatedExpression[]} parts parts
|
873
|
-
* @returns {string} value
|
874
|
-
*/
|
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;
|
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
|
-
);
|
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;
|
910
868
|
}
|
869
|
+
return value;
|
911
870
|
};
|
912
|
-
|
913
871
|
/**
|
914
|
-
*
|
915
|
-
* @
|
916
|
-
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
872
|
+
* @param {BasicEvaluatedExpression[]} parts parts
|
873
|
+
* @returns {string} value
|
917
874
|
*/
|
918
|
-
const
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
const leftConst = left.isCompileTimeValue();
|
925
|
-
const rightConst = right.isCompileTimeValue();
|
926
|
-
|
927
|
-
if (leftConst && rightConst) {
|
928
|
-
return res
|
929
|
-
.setBoolean(
|
930
|
-
eql ===
|
931
|
-
(left.asCompileTimeValue() === right.asCompileTimeValue())
|
932
|
-
)
|
933
|
-
.setSideEffects(
|
934
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
935
|
-
);
|
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;
|
936
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
|
+
};
|
937
912
|
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
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));
|
948
923
|
|
949
|
-
|
950
|
-
|
924
|
+
const leftConst = left.isCompileTimeValue();
|
925
|
+
const rightConst = right.isCompileTimeValue();
|
951
926
|
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
(leftConst || rightPrimitive === true)) ||
|
957
|
-
(rightPrimitive === false &&
|
958
|
-
(rightConst || leftPrimitive === true)) ||
|
959
|
-
// Different nullish or boolish status also means not equal
|
960
|
-
isAlwaysDifferent(
|
961
|
-
/** @type {boolean} */ (left.asBool()),
|
962
|
-
/** @type {boolean} */ (right.asBool())
|
963
|
-
) ||
|
964
|
-
isAlwaysDifferent(
|
965
|
-
/** @type {boolean} */ (left.asNullish()),
|
966
|
-
/** @type {boolean} */ (right.asNullish())
|
927
|
+
if (leftConst && rightConst) {
|
928
|
+
return res
|
929
|
+
.setBoolean(
|
930
|
+
eql === (left.asCompileTimeValue() === right.asCompileTimeValue())
|
967
931
|
)
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
973
|
-
);
|
974
|
-
}
|
975
|
-
};
|
932
|
+
.setSideEffects(
|
933
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
934
|
+
);
|
935
|
+
}
|
976
936
|
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
const leftConst = left.isCompileTimeValue();
|
989
|
-
const rightConst = right.isCompileTimeValue();
|
990
|
-
|
991
|
-
if (leftConst && rightConst) {
|
992
|
-
return res
|
993
|
-
.setBoolean(
|
994
|
-
eql ===
|
995
|
-
// eslint-disable-next-line eqeqeq
|
996
|
-
(left.asCompileTimeValue() == right.asCompileTimeValue())
|
997
|
-
)
|
998
|
-
.setSideEffects(
|
999
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
1000
|
-
);
|
1001
|
-
}
|
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
|
+
}
|
1002
947
|
|
1003
|
-
|
1004
|
-
|
1005
|
-
.setBoolean(!eql)
|
1006
|
-
.setSideEffects(
|
1007
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
1008
|
-
);
|
1009
|
-
}
|
1010
|
-
if (left.isTemplateString() && right.isTemplateString()) {
|
1011
|
-
return handleTemplateStringCompare(left, right, res, eql);
|
1012
|
-
}
|
1013
|
-
};
|
948
|
+
const leftPrimitive = left.isPrimitiveType();
|
949
|
+
const rightPrimitive = right.isPrimitiveType();
|
1014
950
|
|
1015
|
-
if (
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
}
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
)
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
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)
|
1090
1042
|
)
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
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)
|
1112
1089
|
)
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
);
|
1135
|
-
} else if (right.isWrapped()) {
|
1136
|
-
// ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")
|
1137
|
-
// ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")
|
1138
|
-
res.setWrapped(
|
1139
|
-
left.prefix,
|
1140
|
-
right.postfix,
|
1141
|
-
left.wrappedInnerExpressions &&
|
1142
|
-
right.wrappedInnerExpressions &&
|
1143
|
-
left.wrappedInnerExpressions
|
1144
|
-
.concat(left.postfix ? [left.postfix] : [])
|
1145
|
-
.concat(right.prefix ? [right.prefix] : [])
|
1146
|
-
.concat(right.wrappedInnerExpressions)
|
1147
|
-
);
|
1148
|
-
} else {
|
1149
|
-
// ("prefix" + inner + postfix) + expr
|
1150
|
-
// => ("prefix" + inner + postfix + expr + [null])
|
1151
|
-
res.setWrapped(
|
1152
|
-
left.prefix,
|
1153
|
-
null,
|
1154
|
-
left.wrappedInnerExpressions &&
|
1155
|
-
left.wrappedInnerExpressions.concat(
|
1156
|
-
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)
|
1157
1111
|
)
|
1158
|
-
|
1159
|
-
|
1112
|
+
),
|
1113
|
+
left.wrappedInnerExpressions
|
1114
|
+
);
|
1160
1115
|
} else if (right.isString()) {
|
1161
|
-
//
|
1162
|
-
// => (
|
1163
|
-
res.setWrapped(
|
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
|
+
);
|
1164
1129
|
} else if (right.isWrapped()) {
|
1165
|
-
//
|
1166
|
-
//
|
1130
|
+
// ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")
|
1131
|
+
// ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")
|
1167
1132
|
res.setWrapped(
|
1168
|
-
|
1133
|
+
left.prefix,
|
1169
1134
|
right.postfix,
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
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)
|
1174
1141
|
);
|
1175
1142
|
} else {
|
1176
|
-
|
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
|
+
);
|
1177
1153
|
}
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
} else if (
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
} else if (expr.operator === "==") {
|
1193
|
-
return handleAbstractEqualityComparison(true);
|
1194
|
-
} else if (expr.operator === "!==") {
|
1195
|
-
return handleStrictEqualityComparison(false);
|
1196
|
-
} else if (expr.operator === "!=") {
|
1197
|
-
return handleAbstractEqualityComparison(false);
|
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
|
-
} 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
|
-
}
|
1219
|
-
});
|
1220
|
-
this.hooks.evaluate
|
1221
|
-
.for("UnaryExpression")
|
1222
|
-
.tap("JavascriptParser", _expr => {
|
1223
|
-
const expr = /** @type {UnaryExpression} */ (_expr);
|
1224
|
-
|
1225
|
-
/**
|
1226
|
-
* Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
|
1227
|
-
* @template T
|
1228
|
-
* @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
|
1229
|
-
* @returns {BasicEvaluatedExpression | undefined} evaluated expression
|
1230
|
-
*/
|
1231
|
-
const handleConstOperation = operandHandler => {
|
1232
|
-
const argument = this.evaluateExpression(expr.argument);
|
1233
|
-
if (!argument.isCompileTimeValue()) return;
|
1234
|
-
const result = operandHandler(argument.asCompileTimeValue());
|
1235
|
-
return valueAsExpression(
|
1236
|
-
result,
|
1237
|
-
expr,
|
1238
|
-
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
|
+
)
|
1239
1168
|
);
|
1240
|
-
}
|
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
|
+
};
|
1241
1231
|
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
}
|
1253
|
-
case "MetaProperty": {
|
1254
|
-
const res = this.callHooksForName(
|
1255
|
-
this.hooks.evaluateTypeof,
|
1256
|
-
/** @type {string} */
|
1257
|
-
(getRootName(expr.argument)),
|
1258
|
-
expr
|
1259
|
-
);
|
1260
|
-
if (res !== undefined) return res;
|
1261
|
-
break;
|
1262
|
-
}
|
1263
|
-
case "MemberExpression": {
|
1264
|
-
const res = this.callHooksForExpression(
|
1265
|
-
this.hooks.evaluateTypeof,
|
1266
|
-
expr.argument,
|
1267
|
-
expr
|
1268
|
-
);
|
1269
|
-
if (res !== undefined) return res;
|
1270
|
-
break;
|
1271
|
-
}
|
1272
|
-
case "ChainExpression": {
|
1273
|
-
const res = this.callHooksForExpression(
|
1274
|
-
this.hooks.evaluateTypeof,
|
1275
|
-
expr.argument.expression,
|
1276
|
-
expr
|
1277
|
-
);
|
1278
|
-
if (res !== undefined) return res;
|
1279
|
-
break;
|
1280
|
-
}
|
1281
|
-
case "FunctionExpression": {
|
1282
|
-
return new BasicEvaluatedExpression()
|
1283
|
-
.setString("function")
|
1284
|
-
.setRange(/** @type {Range} */ (expr.range));
|
1285
|
-
}
|
1286
|
-
}
|
1287
|
-
const arg = this.evaluateExpression(expr.argument);
|
1288
|
-
if (arg.isUnknown()) return;
|
1289
|
-
if (arg.isString()) {
|
1290
|
-
return new BasicEvaluatedExpression()
|
1291
|
-
.setString("string")
|
1292
|
-
.setRange(/** @type {Range} */ (expr.range));
|
1293
|
-
}
|
1294
|
-
if (arg.isWrapped()) {
|
1295
|
-
return new BasicEvaluatedExpression()
|
1296
|
-
.setString("string")
|
1297
|
-
.setSideEffects()
|
1298
|
-
.setRange(/** @type {Range} */ (expr.range));
|
1299
|
-
}
|
1300
|
-
if (arg.isUndefined()) {
|
1301
|
-
return new BasicEvaluatedExpression()
|
1302
|
-
.setString("undefined")
|
1303
|
-
.setRange(/** @type {Range} */ (expr.range));
|
1304
|
-
}
|
1305
|
-
if (arg.isNumber()) {
|
1306
|
-
return new BasicEvaluatedExpression()
|
1307
|
-
.setString("number")
|
1308
|
-
.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;
|
1309
1242
|
}
|
1310
|
-
|
1311
|
-
|
1312
|
-
.
|
1313
|
-
|
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;
|
1314
1252
|
}
|
1315
|
-
|
1316
|
-
|
1317
|
-
.
|
1318
|
-
|
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;
|
1319
1261
|
}
|
1320
|
-
|
1321
|
-
|
1322
|
-
.
|
1323
|
-
|
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;
|
1324
1270
|
}
|
1325
|
-
|
1271
|
+
case "FunctionExpression": {
|
1326
1272
|
return new BasicEvaluatedExpression()
|
1327
|
-
.setString("
|
1328
|
-
.setSideEffects(arg.couldHaveSideEffects())
|
1273
|
+
.setString("function")
|
1329
1274
|
.setRange(/** @type {Range} */ (expr.range));
|
1330
1275
|
}
|
1331
|
-
}
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1276
|
+
}
|
1277
|
+
const arg = this.evaluateExpression(expr.argument);
|
1278
|
+
if (arg.isUnknown()) return;
|
1279
|
+
if (arg.isString()) {
|
1335
1280
|
return new BasicEvaluatedExpression()
|
1336
|
-
.
|
1337
|
-
.setSideEffects(argument.couldHaveSideEffects())
|
1281
|
+
.setString("string")
|
1338
1282
|
.setRange(/** @type {Range} */ (expr.range));
|
1339
|
-
} else if (expr.operator === "~") {
|
1340
|
-
return handleConstOperation(v => ~v);
|
1341
|
-
} else if (expr.operator === "+") {
|
1342
|
-
// eslint-disable-next-line no-implicit-coercion
|
1343
|
-
return handleConstOperation(v => +v);
|
1344
|
-
} else if (expr.operator === "-") {
|
1345
|
-
return handleConstOperation(v => -v);
|
1346
1283
|
}
|
1347
|
-
|
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
|
+
});
|
1348
1338
|
this.hooks.evaluateTypeof
|
1349
1339
|
.for("undefined")
|
1350
|
-
.tap(
|
1340
|
+
.tap(CLASS_NAME, expr =>
|
1351
1341
|
new BasicEvaluatedExpression()
|
1352
1342
|
.setString("undefined")
|
1353
1343
|
.setRange(/** @type {Range} */ (expr.range))
|
1354
1344
|
);
|
1355
|
-
this.hooks.evaluate.for("Identifier").tap(
|
1345
|
+
this.hooks.evaluate.for("Identifier").tap(CLASS_NAME, expr => {
|
1356
1346
|
if (/** @type {Identifier} */ (expr).name === "undefined") {
|
1357
1347
|
return new BasicEvaluatedExpression()
|
1358
1348
|
.setUndefined()
|
@@ -1369,7 +1359,7 @@ class JavascriptParser extends Parser {
|
|
1369
1359
|
let cachedExpression;
|
1370
1360
|
/** @type {GetInfoResult | undefined} */
|
1371
1361
|
let cachedInfo;
|
1372
|
-
this.hooks.evaluate.for(exprType).tap(
|
1362
|
+
this.hooks.evaluate.for(exprType).tap(CLASS_NAME, expr => {
|
1373
1363
|
const expression =
|
1374
1364
|
/** @type {Identifier | ThisExpression | MemberExpression} */ (expr);
|
1375
1365
|
|
@@ -1394,7 +1384,7 @@ class JavascriptParser extends Parser {
|
|
1394
1384
|
});
|
1395
1385
|
this.hooks.evaluate
|
1396
1386
|
.for(exprType)
|
1397
|
-
.tap({ name:
|
1387
|
+
.tap({ name: CLASS_NAME, stage: 100 }, expr => {
|
1398
1388
|
const expression =
|
1399
1389
|
/** @type {Identifier | ThisExpression | MemberExpression} */
|
1400
1390
|
(expr);
|
@@ -1412,7 +1402,7 @@ class JavascriptParser extends Parser {
|
|
1412
1402
|
.setRange(/** @type {Range} */ (expression.range));
|
1413
1403
|
}
|
1414
1404
|
});
|
1415
|
-
this.hooks.finish.tap(
|
1405
|
+
this.hooks.finish.tap(CLASS_NAME, () => {
|
1416
1406
|
// Cleanup for GC
|
1417
1407
|
cachedExpression = cachedInfo = undefined;
|
1418
1408
|
});
|
@@ -1447,7 +1437,7 @@ class JavascriptParser extends Parser {
|
|
1447
1437
|
};
|
1448
1438
|
}
|
1449
1439
|
});
|
1450
|
-
this.hooks.evaluate.for("MetaProperty").tap(
|
1440
|
+
this.hooks.evaluate.for("MetaProperty").tap(CLASS_NAME, expr => {
|
1451
1441
|
const metaProperty = /** @type {MetaProperty} */ (expr);
|
1452
1442
|
|
1453
1443
|
return this.callHooksForName(
|
@@ -1464,7 +1454,7 @@ class JavascriptParser extends Parser {
|
|
1464
1454
|
)
|
1465
1455
|
);
|
1466
1456
|
|
1467
|
-
this.hooks.evaluate.for("CallExpression").tap(
|
1457
|
+
this.hooks.evaluate.for("CallExpression").tap(CLASS_NAME, _expr => {
|
1468
1458
|
const expr = /** @type {CallExpression} */ (_expr);
|
1469
1459
|
if (
|
1470
1460
|
expr.callee.type === "MemberExpression" &&
|
@@ -1493,7 +1483,7 @@ class JavascriptParser extends Parser {
|
|
1493
1483
|
});
|
1494
1484
|
this.hooks.evaluateCallExpressionMember
|
1495
1485
|
.for("indexOf")
|
1496
|
-
.tap(
|
1486
|
+
.tap(CLASS_NAME, (expr, param) => {
|
1497
1487
|
if (!param.isString()) return;
|
1498
1488
|
if (expr.arguments.length === 0) return;
|
1499
1489
|
const [arg1, arg2] = expr.arguments;
|
@@ -1521,7 +1511,7 @@ class JavascriptParser extends Parser {
|
|
1521
1511
|
});
|
1522
1512
|
this.hooks.evaluateCallExpressionMember
|
1523
1513
|
.for("replace")
|
1524
|
-
.tap(
|
1514
|
+
.tap(CLASS_NAME, (expr, param) => {
|
1525
1515
|
if (!param.isString()) return;
|
1526
1516
|
if (expr.arguments.length !== 2) return;
|
1527
1517
|
if (expr.arguments[0].type === "SpreadElement") return;
|
@@ -1544,7 +1534,7 @@ class JavascriptParser extends Parser {
|
|
1544
1534
|
for (const fn of ["substr", "substring", "slice"]) {
|
1545
1535
|
this.hooks.evaluateCallExpressionMember
|
1546
1536
|
.for(fn)
|
1547
|
-
.tap(
|
1537
|
+
.tap(CLASS_NAME, (expr, param) => {
|
1548
1538
|
if (!param.isString()) return;
|
1549
1539
|
let arg1;
|
1550
1540
|
let result;
|
@@ -1636,22 +1626,20 @@ class JavascriptParser extends Parser {
|
|
1636
1626
|
};
|
1637
1627
|
};
|
1638
1628
|
|
1639
|
-
this.hooks.evaluate
|
1640
|
-
|
1641
|
-
.tap("JavascriptParser", _node => {
|
1642
|
-
const node = /** @type {TemplateLiteral} */ (_node);
|
1629
|
+
this.hooks.evaluate.for("TemplateLiteral").tap(CLASS_NAME, _node => {
|
1630
|
+
const node = /** @type {TemplateLiteral} */ (_node);
|
1643
1631
|
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
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
|
+
});
|
1652
1640
|
this.hooks.evaluate
|
1653
1641
|
.for("TaggedTemplateExpression")
|
1654
|
-
.tap(
|
1642
|
+
.tap(CLASS_NAME, _node => {
|
1655
1643
|
const node = /** @type {TaggedTemplateExpression} */ (_node);
|
1656
1644
|
const tag = this.evaluateExpression(node.tag);
|
1657
1645
|
|
@@ -1668,7 +1656,7 @@ class JavascriptParser extends Parser {
|
|
1668
1656
|
|
1669
1657
|
this.hooks.evaluateCallExpressionMember
|
1670
1658
|
.for("concat")
|
1671
|
-
.tap(
|
1659
|
+
.tap(CLASS_NAME, (expr, param) => {
|
1672
1660
|
if (!param.isString() && !param.isWrapped()) return;
|
1673
1661
|
let stringSuffix = null;
|
1674
1662
|
let hasUnknownParams = false;
|
@@ -1738,7 +1726,7 @@ class JavascriptParser extends Parser {
|
|
1738
1726
|
});
|
1739
1727
|
this.hooks.evaluateCallExpressionMember
|
1740
1728
|
.for("split")
|
1741
|
-
.tap(
|
1729
|
+
.tap(CLASS_NAME, (expr, param) => {
|
1742
1730
|
if (!param.isString()) return;
|
1743
1731
|
if (expr.arguments.length !== 1) return;
|
1744
1732
|
if (expr.arguments[0].type === "SpreadElement") return;
|
@@ -1760,101 +1748,95 @@ class JavascriptParser extends Parser {
|
|
1760
1748
|
.setSideEffects(param.couldHaveSideEffects())
|
1761
1749
|
.setRange(/** @type {Range} */ (expr.range));
|
1762
1750
|
});
|
1763
|
-
this.hooks.evaluate
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
res
|
1775
|
-
|
1776
|
-
|
1777
|
-
/** @type {BasicEvaluatedExpression[]} */ (consequent.options)
|
1778
|
-
);
|
1779
|
-
} else {
|
1780
|
-
res.setOptions([consequent]);
|
1781
|
-
}
|
1782
|
-
if (alternate.isConditional()) {
|
1783
|
-
res.addOptions(
|
1784
|
-
/** @type {BasicEvaluatedExpression[]} */ (alternate.options)
|
1785
|
-
);
|
1786
|
-
} else {
|
1787
|
-
res.addOptions([alternate]);
|
1788
|
-
}
|
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
|
+
);
|
1789
1765
|
} else {
|
1790
|
-
res
|
1791
|
-
|
1766
|
+
res.setOptions([consequent]);
|
1767
|
+
}
|
1768
|
+
if (alternate.isConditional()) {
|
1769
|
+
res.addOptions(
|
1770
|
+
/** @type {BasicEvaluatedExpression[]} */ (alternate.options)
|
1792
1771
|
);
|
1793
|
-
|
1772
|
+
} else {
|
1773
|
+
res.addOptions([alternate]);
|
1794
1774
|
}
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
this.hooks.evaluate
|
1799
|
-
.for("ArrayExpression")
|
1800
|
-
.tap("JavascriptParser", _expr => {
|
1801
|
-
const expr = /** @type {ArrayExpression} */ (_expr);
|
1802
|
-
|
1803
|
-
const items = expr.elements.map(
|
1804
|
-
element =>
|
1805
|
-
element !== null &&
|
1806
|
-
element.type !== "SpreadElement" &&
|
1807
|
-
this.evaluateExpression(element)
|
1775
|
+
} else {
|
1776
|
+
res = this.evaluateExpression(
|
1777
|
+
conditionValue ? expr.consequent : expr.alternate
|
1808
1778
|
);
|
1809
|
-
if (
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
1814
|
-
this.hooks.evaluate
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
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
|
+
);
|
1843
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
|
+
);
|
1823
|
+
}
|
1824
|
+
next = next.callee;
|
1844
1825
|
}
|
1826
|
+
}
|
1845
1827
|
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1828
|
+
while (optionalExpressionsStack.length > 0) {
|
1829
|
+
const expression =
|
1830
|
+
/** @type {Expression} */
|
1831
|
+
(optionalExpressionsStack.pop());
|
1832
|
+
const evaluated = this.evaluateExpression(expression);
|
1851
1833
|
|
1852
|
-
|
1853
|
-
|
1854
|
-
}
|
1834
|
+
if (evaluated.asNullish()) {
|
1835
|
+
return evaluated.setRange(/** @type {Range} */ (_expr.range));
|
1855
1836
|
}
|
1856
|
-
|
1857
|
-
|
1837
|
+
}
|
1838
|
+
return this.evaluateExpression(expr.expression);
|
1839
|
+
});
|
1858
1840
|
}
|
1859
1841
|
|
1860
1842
|
/**
|
@@ -2171,7 +2153,7 @@ class JavascriptParser extends Parser {
|
|
2171
2153
|
this.blockPreWalkStatements(body);
|
2172
2154
|
this.prevStatement = prev;
|
2173
2155
|
this.walkStatements(body);
|
2174
|
-
},
|
2156
|
+
}, true);
|
2175
2157
|
}
|
2176
2158
|
|
2177
2159
|
/**
|
@@ -2211,20 +2193,12 @@ class JavascriptParser extends Parser {
|
|
2211
2193
|
|
2212
2194
|
this.scope.terminated =
|
2213
2195
|
consequentTerminated && alternateTerminated
|
2214
|
-
?
|
2196
|
+
? alternateTerminated
|
2215
2197
|
: undefined;
|
2216
|
-
} else {
|
2217
|
-
|
2218
|
-
|
2219
|
-
this.
|
2220
|
-
|
2221
|
-
if (result) {
|
2222
|
-
this.walkNestedStatement(statement.consequent);
|
2223
|
-
} else if (statement.alternate) {
|
2224
|
-
this.walkNestedStatement(statement.alternate);
|
2225
|
-
}
|
2226
|
-
|
2227
|
-
this.scope.inExecutedPath = oldState;
|
2198
|
+
} else if (result) {
|
2199
|
+
this.walkNestedStatement(statement.consequent);
|
2200
|
+
} else if (statement.alternate) {
|
2201
|
+
this.walkNestedStatement(statement.alternate);
|
2228
2202
|
}
|
2229
2203
|
}
|
2230
2204
|
|
@@ -2290,7 +2264,9 @@ class JavascriptParser extends Parser {
|
|
2290
2264
|
if (this.scope.topLevelScope === true) return;
|
2291
2265
|
if (this.hooks.terminate.call(statement)) {
|
2292
2266
|
this.scope.terminated =
|
2293
|
-
statement.type === "ReturnStatement"
|
2267
|
+
statement.type === "ReturnStatement"
|
2268
|
+
? SCOPE_INFO_TERMINATED_RETURN
|
2269
|
+
: SCOPE_INFO_TERMINATED_THROW;
|
2294
2270
|
}
|
2295
2271
|
}
|
2296
2272
|
|
@@ -2337,14 +2313,20 @@ class JavascriptParser extends Parser {
|
|
2337
2313
|
const handlerTerminated = this.scope.terminated;
|
2338
2314
|
this.scope.terminated = undefined;
|
2339
2315
|
|
2340
|
-
if (statement.finalizer)
|
2316
|
+
if (statement.finalizer) {
|
2317
|
+
this.walkStatement(statement.finalizer);
|
2318
|
+
}
|
2341
2319
|
|
2342
|
-
|
2343
|
-
|
2320
|
+
const finalizerTerminated = this.scope.terminated;
|
2321
|
+
this.scope.terminated = undefined;
|
2322
|
+
|
2323
|
+
if (finalizerTerminated) {
|
2324
|
+
this.scope.terminated = finalizerTerminated;
|
2325
|
+
} else if (
|
2344
2326
|
tryTerminated &&
|
2345
2327
|
(statement.handler ? handlerTerminated : true)
|
2346
2328
|
) {
|
2347
|
-
this.scope.terminated = tryTerminated;
|
2329
|
+
this.scope.terminated = handlerTerminated || tryTerminated;
|
2348
2330
|
}
|
2349
2331
|
}
|
2350
2332
|
|
@@ -2412,7 +2394,9 @@ class JavascriptParser extends Parser {
|
|
2412
2394
|
if (statement.update) {
|
2413
2395
|
this.walkExpression(statement.update);
|
2414
2396
|
}
|
2397
|
+
|
2415
2398
|
const body = statement.body;
|
2399
|
+
|
2416
2400
|
if (body.type === "BlockStatement") {
|
2417
2401
|
// no need to add additional scope
|
2418
2402
|
const prev = this.prevStatement;
|
@@ -2446,8 +2430,11 @@ class JavascriptParser extends Parser {
|
|
2446
2430
|
} else {
|
2447
2431
|
this.walkPattern(statement.left);
|
2448
2432
|
}
|
2433
|
+
|
2449
2434
|
this.walkExpression(statement.right);
|
2435
|
+
|
2450
2436
|
const body = statement.body;
|
2437
|
+
|
2451
2438
|
if (body.type === "BlockStatement") {
|
2452
2439
|
// no need to add additional scope
|
2453
2440
|
const prev = this.prevStatement;
|
@@ -2484,8 +2471,11 @@ class JavascriptParser extends Parser {
|
|
2484
2471
|
} else {
|
2485
2472
|
this.walkPattern(statement.left);
|
2486
2473
|
}
|
2474
|
+
|
2487
2475
|
this.walkExpression(statement.right);
|
2476
|
+
|
2488
2477
|
const body = statement.body;
|
2478
|
+
|
2489
2479
|
if (body.type === "BlockStatement") {
|
2490
2480
|
// no need to add additional scope
|
2491
2481
|
const prev = this.prevStatement;
|
@@ -4074,7 +4064,6 @@ class JavascriptParser extends Parser {
|
|
4074
4064
|
inTaggedTemplateTag: false,
|
4075
4065
|
isStrict: oldScope.isStrict,
|
4076
4066
|
isAsmJs: oldScope.isAsmJs,
|
4077
|
-
inExecutedPath: false,
|
4078
4067
|
terminated: undefined,
|
4079
4068
|
definitions: oldScope.definitions.createChild()
|
4080
4069
|
};
|
@@ -4103,7 +4092,6 @@ class JavascriptParser extends Parser {
|
|
4103
4092
|
inTry: false,
|
4104
4093
|
inShorthand: false,
|
4105
4094
|
inTaggedTemplateTag: false,
|
4106
|
-
inExecutedPath: true,
|
4107
4095
|
isStrict: oldScope.isStrict,
|
4108
4096
|
isAsmJs: oldScope.isAsmJs,
|
4109
4097
|
terminated: undefined,
|
@@ -4136,7 +4124,6 @@ class JavascriptParser extends Parser {
|
|
4136
4124
|
inTry: false,
|
4137
4125
|
inShorthand: false,
|
4138
4126
|
inTaggedTemplateTag: false,
|
4139
|
-
inExecutedPath: true,
|
4140
4127
|
isStrict: oldScope.isStrict,
|
4141
4128
|
isAsmJs: oldScope.isAsmJs,
|
4142
4129
|
terminated: undefined,
|
@@ -4168,7 +4155,6 @@ class JavascriptParser extends Parser {
|
|
4168
4155
|
inTry: oldScope.inTry,
|
4169
4156
|
inShorthand: false,
|
4170
4157
|
inTaggedTemplateTag: false,
|
4171
|
-
inExecutedPath,
|
4172
4158
|
isStrict: oldScope.isStrict,
|
4173
4159
|
isAsmJs: oldScope.isAsmJs,
|
4174
4160
|
terminated: oldScope.terminated,
|
@@ -4179,10 +4165,7 @@ class JavascriptParser extends Parser {
|
|
4179
4165
|
|
4180
4166
|
const terminated = this.scope.terminated;
|
4181
4167
|
|
4182
|
-
if (
|
4183
|
-
inExecutedPath &&
|
4184
|
-
((this.scope.inTry && terminated === "throw") || terminated === "return")
|
4185
|
-
) {
|
4168
|
+
if (inExecutedPath && terminated) {
|
4186
4169
|
oldScope.terminated = terminated;
|
4187
4170
|
}
|
4188
4171
|
|
@@ -4502,7 +4485,6 @@ class JavascriptParser extends Parser {
|
|
4502
4485
|
inTry: false,
|
4503
4486
|
inShorthand: false,
|
4504
4487
|
inTaggedTemplateTag: false,
|
4505
|
-
inExecutedPath: false,
|
4506
4488
|
isStrict: false,
|
4507
4489
|
isAsmJs: false,
|
4508
4490
|
terminated: undefined,
|