eslint-plugin-react-hooks 7.1.0-canary-eb89912e-20251118 → 7.1.0-canary-40b4a5bf-20251120

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.
@@ -17816,6 +17816,22 @@ class CompilerErrorDetail {
17816
17816
  }
17817
17817
  }
17818
17818
  class CompilerError extends Error {
17819
+ static simpleInvariant(condition, options) {
17820
+ var _a;
17821
+ if (!condition) {
17822
+ const errors = new CompilerError();
17823
+ errors.pushDiagnostic(CompilerDiagnostic.create({
17824
+ reason: options.reason,
17825
+ description: (_a = options.description) !== null && _a !== void 0 ? _a : null,
17826
+ category: ErrorCategory.Invariant,
17827
+ }).withDetails({
17828
+ kind: 'error',
17829
+ loc: options.loc,
17830
+ message: options.reason,
17831
+ }));
17832
+ throw errors;
17833
+ }
17834
+ }
17819
17835
  static invariant(condition, options) {
17820
17836
  if (!condition) {
17821
17837
  const errors = new CompilerError();
@@ -18016,7 +18032,8 @@ function printErrorSummary(category, message) {
18016
18032
  case ErrorCategory.Suppression:
18017
18033
  case ErrorCategory.Syntax:
18018
18034
  case ErrorCategory.UseMemo:
18019
- case ErrorCategory.VoidUseMemo: {
18035
+ case ErrorCategory.VoidUseMemo:
18036
+ case ErrorCategory.MemoDependencies: {
18020
18037
  heading = 'Error';
18021
18038
  break;
18022
18039
  }
@@ -18050,6 +18067,7 @@ var ErrorCategory;
18050
18067
  ErrorCategory["VoidUseMemo"] = "VoidUseMemo";
18051
18068
  ErrorCategory["Factories"] = "Factories";
18052
18069
  ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
18070
+ ErrorCategory["MemoDependencies"] = "MemoDependencies";
18053
18071
  ErrorCategory["IncompatibleLibrary"] = "IncompatibleLibrary";
18054
18072
  ErrorCategory["Immutability"] = "Immutability";
18055
18073
  ErrorCategory["Globals"] = "Globals";
@@ -18323,6 +18341,15 @@ function getRuleForCategoryImpl(category) {
18323
18341
  preset: LintRulePreset.RecommendedLatest,
18324
18342
  };
18325
18343
  }
18344
+ case ErrorCategory.MemoDependencies: {
18345
+ return {
18346
+ category,
18347
+ severity: ErrorSeverity.Error,
18348
+ name: 'memo-dependencies',
18349
+ description: 'Validates that useMemo() and useCallback() specify comprehensive dependencies without extraneous values. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
18350
+ preset: LintRulePreset.RecommendedLatest,
18351
+ };
18352
+ }
18326
18353
  case ErrorCategory.IncompatibleLibrary: {
18327
18354
  return {
18328
18355
  category,
@@ -18831,6 +18858,11 @@ function areEqualPaths(a, b) {
18831
18858
  return (a.length === b.length &&
18832
18859
  a.every((item, ix) => item.property === b[ix].property && item.optional === b[ix].optional));
18833
18860
  }
18861
+ function isSubPath(subpath, path) {
18862
+ return (subpath.length <= path.length &&
18863
+ subpath.every((item, ix) => item.property === path[ix].property &&
18864
+ item.optional === path[ix].optional));
18865
+ }
18834
18866
  function getPlaceScope(id, place) {
18835
18867
  const scope = place.identifier.scope;
18836
18868
  if (scope !== null && isScopeActive(scope, id)) {
@@ -18922,6 +18954,9 @@ function isObjectMethodType(id) {
18922
18954
  function isPrimitiveType(id) {
18923
18955
  return id.type.kind === 'Primitive';
18924
18956
  }
18957
+ function isPlainObjectType(id) {
18958
+ return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInObject';
18959
+ }
18925
18960
  function isArrayType(id) {
18926
18961
  return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInArray';
18927
18962
  }
@@ -19599,7 +19634,7 @@ function printInstructionValue(instrValue) {
19599
19634
  break;
19600
19635
  }
19601
19636
  case 'StartMemoize': {
19602
- value = `StartMemoize deps=${(_e = (_d = instrValue.deps) === null || _d === void 0 ? void 0 : _d.map(dep => printManualMemoDependency(dep, false))) !== null && _e !== void 0 ? _e : '(none)'}`;
19637
+ value = `StartMemoize deps=${(_e = (_d = instrValue.deps) === null || _d === void 0 ? void 0 : _d.map(dep => printManualMemoDependency$1(dep, false))) !== null && _e !== void 0 ? _e : '(none)'}`;
19603
19638
  break;
19604
19639
  }
19605
19640
  case 'FinishMemoize': {
@@ -19687,7 +19722,7 @@ function printName(name) {
19687
19722
  function printScope(scope) {
19688
19723
  return `${scope !== null ? `_@${scope.id}` : ''}`;
19689
19724
  }
19690
- function printManualMemoDependency(val, nameOnly) {
19725
+ function printManualMemoDependency$1(val, nameOnly) {
19691
19726
  var _a;
19692
19727
  let rootStr;
19693
19728
  if (val.root.kind === 'Global') {
@@ -32163,6 +32198,7 @@ const EnvironmentConfigSchema = v4.z.object({
32163
32198
  enableResetCacheOnSourceFileChanges: v4.z.nullable(v4.z.boolean()).default(null),
32164
32199
  enablePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
32165
32200
  validatePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
32201
+ validateExhaustiveMemoizationDependencies: v4.z.boolean().default(false),
32166
32202
  enablePreserveExistingManualUseMemo: v4.z.boolean().default(false),
32167
32203
  enableForest: v4.z.boolean().default(false),
32168
32204
  enableUseTypeAnnotations: v4.z.boolean().default(false),
@@ -32217,7 +32253,7 @@ const EnvironmentConfigSchema = v4.z.object({
32217
32253
  enableInferEventHandlers: v4.z.boolean().default(false),
32218
32254
  });
32219
32255
  class Environment {
32220
- constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
32256
+ constructor(scope, fnType, outputMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
32221
32257
  _Environment_instances.add(this);
32222
32258
  _Environment_globals.set(this, void 0);
32223
32259
  _Environment_shapes.set(this, void 0);
@@ -32233,7 +32269,7 @@ class Environment {
32233
32269
  _Environment_flowTypeEnvironment.set(this, void 0);
32234
32270
  __classPrivateFieldSet(this, _Environment_scope, scope, "f");
32235
32271
  this.fnType = fnType;
32236
- this.compilerMode = compilerMode;
32272
+ this.outputMode = outputMode;
32237
32273
  this.config = config;
32238
32274
  this.filename = filename;
32239
32275
  this.code = code;
@@ -32317,8 +32353,52 @@ class Environment {
32317
32353
  });
32318
32354
  return __classPrivateFieldGet(this, _Environment_flowTypeEnvironment, "f");
32319
32355
  }
32320
- get isInferredMemoEnabled() {
32321
- return this.compilerMode !== 'no_inferred_memo';
32356
+ get enableDropManualMemoization() {
32357
+ switch (this.outputMode) {
32358
+ case 'lint': {
32359
+ return true;
32360
+ }
32361
+ case 'client':
32362
+ case 'ssr': {
32363
+ return true;
32364
+ }
32365
+ case 'client-no-memo': {
32366
+ return false;
32367
+ }
32368
+ default: {
32369
+ assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
32370
+ }
32371
+ }
32372
+ }
32373
+ get enableMemoization() {
32374
+ switch (this.outputMode) {
32375
+ case 'client':
32376
+ case 'lint': {
32377
+ return true;
32378
+ }
32379
+ case 'ssr':
32380
+ case 'client-no-memo': {
32381
+ return false;
32382
+ }
32383
+ default: {
32384
+ assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
32385
+ }
32386
+ }
32387
+ }
32388
+ get enableValidations() {
32389
+ switch (this.outputMode) {
32390
+ case 'client':
32391
+ case 'lint':
32392
+ case 'ssr': {
32393
+ return true;
32394
+ }
32395
+ case 'client-no-memo': {
32396
+ return false;
32397
+ }
32398
+ default: {
32399
+ assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
32400
+ }
32401
+ }
32322
32402
  }
32323
32403
  get nextIdentifierId() {
32324
32404
  var _a, _b;
@@ -34431,9 +34511,10 @@ function deadCodeElimination(fn) {
34431
34511
  retainWhere(fn.context, contextVar => state.isIdOrNameUsed(contextVar.identifier));
34432
34512
  }
34433
34513
  let State$2 = class State {
34434
- constructor() {
34514
+ constructor(env) {
34435
34515
  this.named = new Set();
34436
34516
  this.identifiers = new Set();
34517
+ this.env = env;
34437
34518
  }
34438
34519
  reference(identifier) {
34439
34520
  this.identifiers.add(identifier.id);
@@ -34455,7 +34536,7 @@ let State$2 = class State {
34455
34536
  function findReferencedIdentifiers(fn) {
34456
34537
  const hasLoop = hasBackEdge(fn);
34457
34538
  const reversedBlocks = [...fn.body.blocks.values()].reverse();
34458
- const state = new State$2();
34539
+ const state = new State$2(fn.env);
34459
34540
  let size = state.count;
34460
34541
  do {
34461
34542
  size = state.count;
@@ -34602,12 +34683,25 @@ function pruneableValue(value, state) {
34602
34683
  case 'Debugger': {
34603
34684
  return false;
34604
34685
  }
34605
- case 'Await':
34606
34686
  case 'CallExpression':
34687
+ case 'MethodCall': {
34688
+ if (state.env.outputMode === 'ssr') {
34689
+ const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
34690
+ const hookKind = getHookKind(state.env, calleee.identifier);
34691
+ switch (hookKind) {
34692
+ case 'useState':
34693
+ case 'useReducer':
34694
+ case 'useRef': {
34695
+ return true;
34696
+ }
34697
+ }
34698
+ }
34699
+ return false;
34700
+ }
34701
+ case 'Await':
34607
34702
  case 'ComputedDelete':
34608
34703
  case 'ComputedStore':
34609
34704
  case 'PropertyDelete':
34610
- case 'MethodCall':
34611
34705
  case 'PropertyStore':
34612
34706
  case 'StoreGlobal': {
34613
34707
  return false;
@@ -37402,7 +37496,7 @@ function codegenFunction(fn, { uniqueIdentifiers, fbtOperands, }) {
37402
37496
  }
37403
37497
  const compiled = compileResult.unwrap();
37404
37498
  const hookGuard = fn.env.config.enableEmitHookGuards;
37405
- if (hookGuard != null && fn.env.isInferredMemoEnabled) {
37499
+ if (hookGuard != null && fn.env.outputMode === 'client') {
37406
37500
  compiled.body = libExports$1.blockStatement([
37407
37501
  createHookGuard(hookGuard, fn.env.programContext, compiled.body.body, GuardKind.PushHookGuard, GuardKind.PopHookGuard),
37408
37502
  ]);
@@ -37432,7 +37526,7 @@ function codegenFunction(fn, { uniqueIdentifiers, fbtOperands, }) {
37432
37526
  const emitInstrumentForget = fn.env.config.enableEmitInstrumentForget;
37433
37527
  if (emitInstrumentForget != null &&
37434
37528
  fn.id != null &&
37435
- fn.env.isInferredMemoEnabled) {
37529
+ fn.env.outputMode === 'client') {
37436
37530
  const gating = emitInstrumentForget.gating != null
37437
37531
  ? libExports$1.identifier(fn.env.programContext.addImportSpecifier(emitInstrumentForget.gating).name)
37438
37532
  : null;
@@ -37670,7 +37764,8 @@ function codegenBlockNoReset(cx, block) {
37670
37764
  return libExports$1.blockStatement(statements);
37671
37765
  }
37672
37766
  function wrapCacheDep(cx, value) {
37673
- if (cx.env.config.enableEmitFreeze != null && cx.env.isInferredMemoEnabled) {
37767
+ if (cx.env.config.enableEmitFreeze != null &&
37768
+ cx.env.outputMode === 'client') {
37674
37769
  const emitFreezeIdentifier = cx.env.programContext.addImportSpecifier(cx.env.config.enableEmitFreeze).name;
37675
37770
  cx.env.programContext
37676
37771
  .assertGlobalBinding(EMIT_FREEZE_GLOBAL_GATING, cx.env.scope)
@@ -38516,7 +38611,7 @@ function createCallExpression(env, callee, args, loc, isHook) {
38516
38611
  callExpr.loc = loc;
38517
38612
  }
38518
38613
  const hookGuard = env.config.enableEmitHookGuards;
38519
- if (hookGuard != null && isHook && env.isInferredMemoEnabled) {
38614
+ if (hookGuard != null && isHook && env.outputMode === 'client') {
38520
38615
  const iife = libExports$1.functionExpression(null, [], libExports$1.blockStatement([
38521
38616
  createHookGuard(hookGuard, env.programContext, [libExports$1.returnStatement(callExpr)], GuardKind.AllowHook, GuardKind.DisallowHook),
38522
38617
  ]));
@@ -42214,7 +42309,7 @@ function computeEffectsForLegacySignature(state, signature, lvalue, receiver, ar
42214
42309
  }),
42215
42310
  });
42216
42311
  }
42217
- if (signature.knownIncompatible != null && state.env.isInferredMemoEnabled) {
42312
+ if (signature.knownIncompatible != null && state.env.enableValidations) {
42218
42313
  const errors = new CompilerError();
42219
42314
  errors.pushDiagnostic(CompilerDiagnostic.create({
42220
42315
  category: ErrorCategory.IncompatibleLibrary,
@@ -44583,7 +44678,10 @@ function collectTemporaries(instr, env, sidemap) {
44583
44678
  }
44584
44679
  case 'ArrayExpression': {
44585
44680
  if (value.elements.every(e => e.kind === 'Identifier')) {
44586
- sidemap.maybeDepsLists.set(instr.lvalue.identifier.id, value.elements);
44681
+ sidemap.maybeDepsLists.set(instr.lvalue.identifier.id, {
44682
+ loc: value.loc,
44683
+ deps: value.elements,
44684
+ });
44587
44685
  }
44588
44686
  break;
44589
44687
  }
@@ -44593,7 +44691,7 @@ function collectTemporaries(instr, env, sidemap) {
44593
44691
  sidemap.maybeDeps.set(lvalue.identifier.id, maybeDep);
44594
44692
  }
44595
44693
  }
44596
- function makeManualMemoizationMarkers(fnExpr, env, depsList, memoDecl, manualMemoId) {
44694
+ function makeManualMemoizationMarkers(fnExpr, env, depsList, depsLoc, memoDecl, manualMemoId) {
44597
44695
  return [
44598
44696
  {
44599
44697
  id: makeInstructionId(0),
@@ -44602,6 +44700,7 @@ function makeManualMemoizationMarkers(fnExpr, env, depsList, memoDecl, manualMem
44602
44700
  kind: 'StartMemoize',
44603
44701
  manualMemoId,
44604
44702
  deps: depsList,
44703
+ depsLoc,
44605
44704
  loc: fnExpr.loc,
44606
44705
  },
44607
44706
  effects: null,
@@ -44646,71 +44745,69 @@ function getManualMemoizationReplacement(fn, loc, kind) {
44646
44745
  }
44647
44746
  function extractManualMemoizationArgs(instr, kind, sidemap, errors) {
44648
44747
  const [fnPlace, depsListPlace] = instr.value.args;
44649
- if (fnPlace == null) {
44748
+ if (fnPlace == null || fnPlace.kind !== 'Identifier') {
44650
44749
  errors.pushDiagnostic(CompilerDiagnostic.create({
44651
44750
  category: ErrorCategory.UseMemo,
44652
44751
  reason: `Expected a callback function to be passed to ${kind}`,
44653
- description: `Expected a callback function to be passed to ${kind}`,
44752
+ description: kind === 'useCallback'
44753
+ ? 'The first argument to useCallback() must be a function to cache'
44754
+ : 'The first argument to useMemo() must be a function that calculates a result to cache',
44654
44755
  suggestions: null,
44655
44756
  }).withDetails({
44656
44757
  kind: 'error',
44657
44758
  loc: instr.value.loc,
44658
- message: `Expected a callback function to be passed to ${kind}`,
44759
+ message: kind === 'useCallback'
44760
+ ? `Expected a callback function`
44761
+ : `Expected a memoization function`,
44659
44762
  }));
44660
- return { fnPlace: null, depsList: null };
44763
+ return null;
44764
+ }
44765
+ if (depsListPlace == null) {
44766
+ return {
44767
+ fnPlace,
44768
+ depsList: null,
44769
+ depsLoc: null,
44770
+ };
44661
44771
  }
44662
- if (fnPlace.kind === 'Spread' || (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Spread') {
44772
+ const maybeDepsList = depsListPlace.kind === 'Identifier'
44773
+ ? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
44774
+ : null;
44775
+ if (maybeDepsList == null) {
44663
44776
  errors.pushDiagnostic(CompilerDiagnostic.create({
44664
44777
  category: ErrorCategory.UseMemo,
44665
- reason: `Unexpected spread argument to ${kind}`,
44666
- description: `Unexpected spread argument to ${kind}`,
44778
+ reason: `Expected the dependency list for ${kind} to be an array literal`,
44779
+ description: `Expected the dependency list for ${kind} to be an array literal`,
44667
44780
  suggestions: null,
44668
44781
  }).withDetails({
44669
44782
  kind: 'error',
44670
- loc: instr.value.loc,
44671
- message: `Unexpected spread argument to ${kind}`,
44783
+ loc: (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Identifier' ? depsListPlace.loc : instr.loc,
44784
+ message: `Expected the dependency list for ${kind} to be an array literal`,
44672
44785
  }));
44673
- return { fnPlace: null, depsList: null };
44786
+ return null;
44674
44787
  }
44675
- let depsList = null;
44676
- if (depsListPlace != null) {
44677
- const maybeDepsList = sidemap.maybeDepsLists.get(depsListPlace.identifier.id);
44678
- if (maybeDepsList == null) {
44788
+ const depsList = [];
44789
+ for (const dep of maybeDepsList.deps) {
44790
+ const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
44791
+ if (maybeDep == null) {
44679
44792
  errors.pushDiagnostic(CompilerDiagnostic.create({
44680
44793
  category: ErrorCategory.UseMemo,
44681
- reason: `Expected the dependency list for ${kind} to be an array literal`,
44682
- description: `Expected the dependency list for ${kind} to be an array literal`,
44794
+ reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
44795
+ description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
44683
44796
  suggestions: null,
44684
44797
  }).withDetails({
44685
44798
  kind: 'error',
44686
- loc: depsListPlace.loc,
44687
- message: `Expected the dependency list for ${kind} to be an array literal`,
44799
+ loc: dep.loc,
44800
+ message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
44688
44801
  }));
44689
- return { fnPlace, depsList: null };
44690
44802
  }
44691
- depsList = [];
44692
- for (const dep of maybeDepsList) {
44693
- const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
44694
- if (maybeDep == null) {
44695
- errors.pushDiagnostic(CompilerDiagnostic.create({
44696
- category: ErrorCategory.UseMemo,
44697
- reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
44698
- description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
44699
- suggestions: null,
44700
- }).withDetails({
44701
- kind: 'error',
44702
- loc: dep.loc,
44703
- message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
44704
- }));
44705
- }
44706
- else {
44707
- depsList.push(maybeDep);
44708
- }
44803
+ else {
44804
+ depsList.push(maybeDep);
44709
44805
  }
44710
44806
  }
44711
44807
  return {
44712
44808
  fnPlace,
44713
44809
  depsList,
44810
+ depsLoc: maybeDepsList.loc,
44714
44811
  };
44715
44812
  }
44716
44813
  function dropManualMemoization(func) {
@@ -44718,7 +44815,7 @@ function dropManualMemoization(func) {
44718
44815
  const isValidationEnabled = func.env.config.validatePreserveExistingMemoizationGuarantees ||
44719
44816
  func.env.config.validateNoSetStateInRender ||
44720
44817
  func.env.config.enablePreserveExistingMemoizationGuarantees;
44721
- const optionals = findOptionalPlaces(func);
44818
+ const optionals = findOptionalPlaces$1(func);
44722
44819
  const sidemap = {
44723
44820
  functions: new Map(),
44724
44821
  manualMemos: new Map(),
@@ -44739,10 +44836,11 @@ function dropManualMemoization(func) {
44739
44836
  : instr.value.property.identifier.id;
44740
44837
  const manualMemo = sidemap.manualMemos.get(id);
44741
44838
  if (manualMemo != null) {
44742
- const { fnPlace, depsList } = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, errors);
44743
- if (fnPlace == null) {
44839
+ const memoDetails = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, errors);
44840
+ if (memoDetails == null) {
44744
44841
  continue;
44745
44842
  }
44843
+ const { fnPlace, depsList, depsLoc } = memoDetails;
44746
44844
  instr.value = getManualMemoizationReplacement(fnPlace, instr.value.loc, manualMemo.kind);
44747
44845
  if (isValidationEnabled) {
44748
44846
  if (!sidemap.functions.has(fnPlace.identifier.id)) {
@@ -44767,7 +44865,7 @@ function dropManualMemoization(func) {
44767
44865
  reactive: false,
44768
44866
  loc: fnPlace.loc,
44769
44867
  };
44770
- const [startMarker, finishMarker] = makeManualMemoizationMarkers(fnPlace, func.env, depsList, memoDecl, nextManualMemoId++);
44868
+ const [startMarker, finishMarker] = makeManualMemoizationMarkers(fnPlace, func.env, depsList, depsLoc, memoDecl, nextManualMemoId++);
44771
44869
  queuedInserts.set(manualMemo.loadInstr.id, startMarker);
44772
44870
  queuedInserts.set(instr.id, finishMarker);
44773
44871
  }
@@ -44805,7 +44903,7 @@ function dropManualMemoization(func) {
44805
44903
  }
44806
44904
  return errors.asResult();
44807
44905
  }
44808
- function findOptionalPlaces(fn) {
44906
+ function findOptionalPlaces$1(fn) {
44809
44907
  const optionals = new Set();
44810
44908
  for (const [, block] of fn.body.blocks) {
44811
44909
  if (block.terminal.kind === 'optional' && block.terminal.optional) {
@@ -46178,7 +46276,7 @@ function propagateScopeDependenciesHIR(fn) {
46178
46276
  const temporaries = collectTemporariesSidemap$1(fn, usedOutsideDeclaringScope);
46179
46277
  const { temporariesReadInOptional, processedInstrsInOptional, hoistableObjects, } = collectOptionalChainSidemap(fn);
46180
46278
  const hoistablePropertyLoads = keyByScopeId(fn, collectHoistablePropertyLoads(fn, temporaries, hoistableObjects));
46181
- const scopeDeps = collectDependencies(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
46279
+ const scopeDeps = collectDependencies$1(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
46182
46280
  for (const [scope, deps] of scopeDeps) {
46183
46281
  if (deps.length === 0) {
46184
46282
  continue;
@@ -46529,7 +46627,7 @@ function handleInstruction(instr, context) {
46529
46627
  }
46530
46628
  }
46531
46629
  }
46532
- function collectDependencies(fn, usedOutsideDeclaringScope, temporaries, processedInstrsInOptional) {
46630
+ function collectDependencies$1(fn, usedOutsideDeclaringScope, temporaries, processedInstrsInOptional) {
46533
46631
  const context = new DependencyCollectionContext(usedOutsideDeclaringScope, temporaries, processedInstrsInOptional);
46534
46632
  for (const param of fn.params) {
46535
46633
  if (param.kind === 'Identifier') {
@@ -50141,7 +50239,7 @@ function validateInferredDep(dep, temporaries, declsWithinMemoBlock, validDepsIn
50141
50239
  'The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. ',
50142
50240
  (dep.identifier.name != null && dep.identifier.name.kind === 'named')
50143
50241
  ? `The inferred dependency was \`${prettyPrintScopeDependency(dep)}\`, but the source dependencies were [${validDepsInMemoBlock
50144
- .map(dep => printManualMemoDependency(dep, true))
50242
+ .map(dep => printManualMemoDependency$1(dep, true))
50145
50243
  .join(', ')}]. ${errorDiagnostic
50146
50244
  ? getCompareDependencyResultDescription(errorDiagnostic)
50147
50245
  : 'Inferred dependency not present in source'}`
@@ -52448,6 +52546,7 @@ function validateEffect$1(effectFunction, effectDeps, errors) {
52448
52546
  }
52449
52547
  }
52450
52548
 
52549
+ const MAX_FIXPOINT_ITERATIONS = 100;
52451
52550
  class DerivationCache {
52452
52551
  constructor() {
52453
52552
  this.hasChanges = false;
@@ -52567,6 +52666,7 @@ function validateNoDerivedComputationsInEffects_exp(fn) {
52567
52666
  });
52568
52667
  }
52569
52668
  }
52669
+ let iterationCount = 0;
52570
52670
  do {
52571
52671
  context.derivationCache.takeSnapshot();
52572
52672
  for (const block of fn.body.blocks.values()) {
@@ -52576,6 +52676,18 @@ function validateNoDerivedComputationsInEffects_exp(fn) {
52576
52676
  }
52577
52677
  }
52578
52678
  context.derivationCache.checkForChanges();
52679
+ iterationCount++;
52680
+ CompilerError.invariant(iterationCount < MAX_FIXPOINT_ITERATIONS, {
52681
+ reason: '[ValidateNoDerivedComputationsInEffects] Fixpoint iteration failed to converge.',
52682
+ description: `Fixpoint iteration exceeded ${MAX_FIXPOINT_ITERATIONS} iterations while tracking derivations. This suggests a cyclic dependency in the derivation cache.`,
52683
+ details: [
52684
+ {
52685
+ kind: 'error',
52686
+ loc: fn.loc,
52687
+ message: `Exceeded ${MAX_FIXPOINT_ITERATIONS} iterations in ValidateNoDerivedComputationsInEffects`,
52688
+ },
52689
+ ],
52690
+ });
52579
52691
  } while (context.derivationCache.snapshot());
52580
52692
  for (const [, effect] of effectsCache) {
52581
52693
  validateEffect(effect.effect, effect.dependencies, context);
@@ -52670,7 +52782,7 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
52670
52782
  });
52671
52783
  }
52672
52784
  }
52673
- else if (isUseStateType(lvalue.identifier) && value.args.length > 0) {
52785
+ else if (isUseStateType(lvalue.identifier)) {
52674
52786
  typeOfValue = 'fromState';
52675
52787
  context.derivationCache.addDerivationEntry(lvalue, new Set(), typeOfValue, true);
52676
52788
  return;
@@ -52699,6 +52811,9 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
52699
52811
  for (const lvalue of eachInstructionLValue(instr)) {
52700
52812
  context.derivationCache.addDerivationEntry(lvalue, sources, typeOfValue, isSource);
52701
52813
  }
52814
+ if (value.kind === 'FunctionExpression') {
52815
+ return;
52816
+ }
52702
52817
  for (const operand of eachInstructionOperand(instr)) {
52703
52818
  switch (operand.effect) {
52704
52819
  case Effect.Capture:
@@ -52760,6 +52875,17 @@ function buildTreeNode(sourceId, context, visited = new Set()) {
52760
52875
  const children = [];
52761
52876
  const namedSiblings = new Set();
52762
52877
  for (const childId of sourceMetadata.sourcesIds) {
52878
+ CompilerError.invariant(childId !== sourceId, {
52879
+ reason: 'Unexpected self-reference: a value should not have itself as a source',
52880
+ description: null,
52881
+ details: [
52882
+ {
52883
+ kind: 'error',
52884
+ loc: sourceMetadata.place.loc,
52885
+ message: null,
52886
+ },
52887
+ ],
52888
+ });
52763
52889
  const childNodes = buildTreeNode(childId, context, new Set([
52764
52890
  ...visited,
52765
52891
  ...(isNamedIdentifier(sourceMetadata.place)
@@ -53106,6 +53232,765 @@ function nameAnonymousFunctionsImpl(fn) {
53106
53232
  return nodes;
53107
53233
  }
53108
53234
 
53235
+ function optimizeForSSR(fn) {
53236
+ const inlinedState = new Map();
53237
+ for (const block of fn.body.blocks.values()) {
53238
+ for (const instr of block.instructions) {
53239
+ const { value } = instr;
53240
+ switch (value.kind) {
53241
+ case 'Destructure': {
53242
+ if (inlinedState.has(value.value.identifier.id) &&
53243
+ value.lvalue.pattern.kind === 'ArrayPattern' &&
53244
+ value.lvalue.pattern.items.length >= 1 &&
53245
+ value.lvalue.pattern.items[0].kind === 'Identifier') {
53246
+ continue;
53247
+ }
53248
+ break;
53249
+ }
53250
+ case 'MethodCall':
53251
+ case 'CallExpression': {
53252
+ const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
53253
+ const hookKind = getHookKind(fn.env, calleee.identifier);
53254
+ switch (hookKind) {
53255
+ case 'useReducer': {
53256
+ if (value.args.length === 2 &&
53257
+ value.args[1].kind === 'Identifier') {
53258
+ const arg = value.args[1];
53259
+ const replace = {
53260
+ kind: 'LoadLocal',
53261
+ place: arg,
53262
+ loc: arg.loc,
53263
+ };
53264
+ inlinedState.set(instr.lvalue.identifier.id, replace);
53265
+ }
53266
+ else if (value.args.length === 3 &&
53267
+ value.args[1].kind === 'Identifier' &&
53268
+ value.args[2].kind === 'Identifier') {
53269
+ const arg = value.args[1];
53270
+ const initializer = value.args[2];
53271
+ const replace = {
53272
+ kind: 'CallExpression',
53273
+ callee: initializer,
53274
+ args: [arg],
53275
+ loc: value.loc,
53276
+ };
53277
+ inlinedState.set(instr.lvalue.identifier.id, replace);
53278
+ }
53279
+ break;
53280
+ }
53281
+ case 'useState': {
53282
+ if (value.args.length === 1 &&
53283
+ value.args[0].kind === 'Identifier') {
53284
+ const arg = value.args[0];
53285
+ if (isPrimitiveType(arg.identifier) ||
53286
+ isPlainObjectType(arg.identifier) ||
53287
+ isArrayType(arg.identifier)) {
53288
+ const replace = {
53289
+ kind: 'LoadLocal',
53290
+ place: arg,
53291
+ loc: arg.loc,
53292
+ };
53293
+ inlinedState.set(instr.lvalue.identifier.id, replace);
53294
+ }
53295
+ }
53296
+ break;
53297
+ }
53298
+ }
53299
+ }
53300
+ }
53301
+ if (inlinedState.size !== 0) {
53302
+ for (const operand of eachInstructionValueOperand(value)) {
53303
+ inlinedState.delete(operand.identifier.id);
53304
+ }
53305
+ }
53306
+ }
53307
+ if (inlinedState.size !== 0) {
53308
+ for (const operand of eachTerminalOperand(block.terminal)) {
53309
+ inlinedState.delete(operand.identifier.id);
53310
+ }
53311
+ }
53312
+ }
53313
+ for (const block of fn.body.blocks.values()) {
53314
+ for (const instr of block.instructions) {
53315
+ const { value } = instr;
53316
+ switch (value.kind) {
53317
+ case 'FunctionExpression': {
53318
+ if (hasKnownNonRenderCall(value.loweredFunc.func)) {
53319
+ instr.value = {
53320
+ kind: 'Primitive',
53321
+ value: undefined,
53322
+ loc: value.loc,
53323
+ };
53324
+ }
53325
+ break;
53326
+ }
53327
+ case 'JsxExpression': {
53328
+ if (value.tag.kind === 'BuiltinTag' &&
53329
+ value.tag.name.indexOf('-') === -1) {
53330
+ const tag = value.tag.name;
53331
+ retainWhere(value.props, prop => {
53332
+ return (prop.kind === 'JsxSpreadAttribute' ||
53333
+ (!isKnownEventHandler(tag, prop.name) && prop.name !== 'ref'));
53334
+ });
53335
+ }
53336
+ break;
53337
+ }
53338
+ case 'Destructure': {
53339
+ if (inlinedState.has(value.value.identifier.id)) {
53340
+ CompilerError.invariant(value.lvalue.pattern.kind === 'ArrayPattern' &&
53341
+ value.lvalue.pattern.items.length >= 1 &&
53342
+ value.lvalue.pattern.items[0].kind === 'Identifier', {
53343
+ reason: 'Expected a valid destructuring pattern for inlined state',
53344
+ description: null,
53345
+ details: [
53346
+ {
53347
+ kind: 'error',
53348
+ message: 'Expected a valid destructuring pattern',
53349
+ loc: value.loc,
53350
+ },
53351
+ ],
53352
+ });
53353
+ const store = {
53354
+ kind: 'StoreLocal',
53355
+ loc: value.loc,
53356
+ type: null,
53357
+ lvalue: {
53358
+ kind: value.lvalue.kind,
53359
+ place: value.lvalue.pattern.items[0],
53360
+ },
53361
+ value: value.value,
53362
+ };
53363
+ instr.value = store;
53364
+ }
53365
+ break;
53366
+ }
53367
+ case 'MethodCall':
53368
+ case 'CallExpression': {
53369
+ const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
53370
+ const hookKind = getHookKind(fn.env, calleee.identifier);
53371
+ switch (hookKind) {
53372
+ case 'useEffectEvent': {
53373
+ if (value.args.length === 1 &&
53374
+ value.args[0].kind === 'Identifier') {
53375
+ const load = {
53376
+ kind: 'LoadLocal',
53377
+ place: value.args[0],
53378
+ loc: value.loc,
53379
+ };
53380
+ instr.value = load;
53381
+ }
53382
+ break;
53383
+ }
53384
+ case 'useEffect':
53385
+ case 'useLayoutEffect':
53386
+ case 'useInsertionEffect': {
53387
+ instr.value = {
53388
+ kind: 'Primitive',
53389
+ value: undefined,
53390
+ loc: value.loc,
53391
+ };
53392
+ break;
53393
+ }
53394
+ case 'useReducer':
53395
+ case 'useState': {
53396
+ const replace = inlinedState.get(instr.lvalue.identifier.id);
53397
+ if (replace != null) {
53398
+ instr.value = replace;
53399
+ }
53400
+ break;
53401
+ }
53402
+ }
53403
+ }
53404
+ }
53405
+ }
53406
+ }
53407
+ }
53408
+ function hasKnownNonRenderCall(fn) {
53409
+ for (const block of fn.body.blocks.values()) {
53410
+ for (const instr of block.instructions) {
53411
+ if (instr.value.kind === 'CallExpression' &&
53412
+ (isSetStateType(instr.value.callee.identifier) ||
53413
+ isStartTransitionType(instr.value.callee.identifier))) {
53414
+ return true;
53415
+ }
53416
+ }
53417
+ }
53418
+ return false;
53419
+ }
53420
+ const EVENT_HANDLER_PATTERN = /^on[A-Z]/;
53421
+ function isKnownEventHandler(_tag, prop) {
53422
+ return EVENT_HANDLER_PATTERN.test(prop);
53423
+ }
53424
+
53425
+ function validateExhaustiveDependencies(fn) {
53426
+ const reactive = collectReactiveIdentifiersHIR(fn);
53427
+ const temporaries = new Map();
53428
+ for (const param of fn.params) {
53429
+ const place = param.kind === 'Identifier' ? param : param.place;
53430
+ temporaries.set(place.identifier.id, {
53431
+ kind: 'Local',
53432
+ identifier: place.identifier,
53433
+ path: [],
53434
+ context: false,
53435
+ loc: place.loc,
53436
+ });
53437
+ }
53438
+ const error = new CompilerError();
53439
+ let startMemo = null;
53440
+ function onStartMemoize(value, dependencies, locals) {
53441
+ CompilerError.simpleInvariant(startMemo == null, {
53442
+ reason: 'Unexpected nested memo calls',
53443
+ loc: value.loc,
53444
+ });
53445
+ startMemo = value;
53446
+ dependencies.clear();
53447
+ locals.clear();
53448
+ }
53449
+ function onFinishMemoize(value, dependencies, locals) {
53450
+ var _b, _c, _d;
53451
+ CompilerError.simpleInvariant(startMemo != null && startMemo.manualMemoId === value.manualMemoId, {
53452
+ reason: 'Found FinishMemoize without corresponding StartMemoize',
53453
+ loc: value.loc,
53454
+ });
53455
+ visitCandidateDependency(value.decl, temporaries, dependencies, locals);
53456
+ const inferred = Array.from(dependencies);
53457
+ inferred.sort((a, b) => {
53458
+ var _a, _b;
53459
+ if (a.kind === 'Global' && b.kind == 'Global') {
53460
+ return a.binding.name.localeCompare(b.binding.name);
53461
+ }
53462
+ else if (a.kind == 'Local' && b.kind == 'Local') {
53463
+ CompilerError.simpleInvariant(a.identifier.name != null &&
53464
+ a.identifier.name.kind === 'named' &&
53465
+ b.identifier.name != null &&
53466
+ b.identifier.name.kind === 'named', {
53467
+ reason: 'Expected dependencies to be named variables',
53468
+ loc: a.loc,
53469
+ });
53470
+ if (a.identifier.id !== b.identifier.id) {
53471
+ return a.identifier.name.value.localeCompare(b.identifier.name.value);
53472
+ }
53473
+ if (a.path.length !== b.path.length) {
53474
+ return a.path.length - b.path.length;
53475
+ }
53476
+ for (let i = 0; i < a.path.length; i++) {
53477
+ const aProperty = a.path[i];
53478
+ const bProperty = b.path[i];
53479
+ const aOptional = aProperty.optional ? 0 : 1;
53480
+ const bOptional = bProperty.optional ? 0 : 1;
53481
+ if (aOptional !== bOptional) {
53482
+ return aOptional - bOptional;
53483
+ }
53484
+ else if (aProperty.property !== bProperty.property) {
53485
+ return String(aProperty.property).localeCompare(String(bProperty.property));
53486
+ }
53487
+ }
53488
+ return 0;
53489
+ }
53490
+ else {
53491
+ const aName = a.kind === 'Global' ? a.binding.name : (_a = a.identifier.name) === null || _a === void 0 ? void 0 : _a.value;
53492
+ const bName = b.kind === 'Global' ? b.binding.name : (_b = b.identifier.name) === null || _b === void 0 ? void 0 : _b.value;
53493
+ if (aName != null && bName != null) {
53494
+ return aName.localeCompare(bName);
53495
+ }
53496
+ return 0;
53497
+ }
53498
+ });
53499
+ retainWhere(inferred, (dep, ix) => {
53500
+ const match = inferred.findIndex(prevDep => {
53501
+ return (isEqualTemporary(prevDep, dep) ||
53502
+ (prevDep.kind === 'Local' &&
53503
+ dep.kind === 'Local' &&
53504
+ prevDep.identifier.id === dep.identifier.id &&
53505
+ isSubPath(prevDep.path, dep.path)));
53506
+ });
53507
+ return match === -1 || match >= ix;
53508
+ });
53509
+ const manualDependencies = (_b = startMemo.deps) !== null && _b !== void 0 ? _b : [];
53510
+ const matched = new Set();
53511
+ const missing = [];
53512
+ const extra = [];
53513
+ for (const inferredDependency of inferred) {
53514
+ if (inferredDependency.kind === 'Global') {
53515
+ for (const manualDependency of manualDependencies) {
53516
+ if (manualDependency.root.kind === 'Global' &&
53517
+ manualDependency.root.identifierName ===
53518
+ inferredDependency.binding.name) {
53519
+ matched.add(manualDependency);
53520
+ extra.push(manualDependency);
53521
+ }
53522
+ }
53523
+ continue;
53524
+ }
53525
+ CompilerError.simpleInvariant(inferredDependency.kind === 'Local', {
53526
+ reason: 'Unexpected function dependency',
53527
+ loc: value.loc,
53528
+ });
53529
+ const isRequiredDependency = reactive.has(inferredDependency.identifier.id) ||
53530
+ !isStableType(inferredDependency.identifier);
53531
+ let hasMatchingManualDependency = false;
53532
+ for (const manualDependency of manualDependencies) {
53533
+ if (manualDependency.root.kind === 'NamedLocal' &&
53534
+ manualDependency.root.value.identifier.id ===
53535
+ inferredDependency.identifier.id &&
53536
+ (areEqualPaths(manualDependency.path, inferredDependency.path) ||
53537
+ isSubPath(manualDependency.path, inferredDependency.path))) {
53538
+ hasMatchingManualDependency = true;
53539
+ matched.add(manualDependency);
53540
+ if (!isRequiredDependency) {
53541
+ extra.push(manualDependency);
53542
+ }
53543
+ }
53544
+ }
53545
+ if (isRequiredDependency && !hasMatchingManualDependency) {
53546
+ missing.push(inferredDependency);
53547
+ }
53548
+ }
53549
+ for (const dep of (_c = startMemo.deps) !== null && _c !== void 0 ? _c : []) {
53550
+ if (matched.has(dep)) {
53551
+ continue;
53552
+ }
53553
+ extra.push(dep);
53554
+ }
53555
+ if (missing.length !== 0 || extra.length !== 0) {
53556
+ let suggestions = null;
53557
+ if (startMemo.depsLoc != null && typeof startMemo.depsLoc !== 'symbol') {
53558
+ suggestions = [
53559
+ {
53560
+ description: 'Update dependencies',
53561
+ range: [startMemo.depsLoc.start.index, startMemo.depsLoc.end.index],
53562
+ op: CompilerSuggestionOperation.Replace,
53563
+ text: `[${inferred.map(printInferredDependency).join(', ')}]`,
53564
+ },
53565
+ ];
53566
+ }
53567
+ if (missing.length !== 0) {
53568
+ const diagnostic = CompilerDiagnostic.create({
53569
+ category: ErrorCategory.MemoDependencies,
53570
+ reason: 'Found non-exhaustive dependencies',
53571
+ description: 'Missing dependencies can cause a value not to update when those inputs change, ' +
53572
+ 'resulting in stale UI',
53573
+ suggestions,
53574
+ });
53575
+ for (const dep of missing) {
53576
+ let reactiveStableValueHint = '';
53577
+ if (isStableType(dep.identifier)) {
53578
+ reactiveStableValueHint =
53579
+ '. Refs, setState functions, and other "stable" values generally do not need to be added as dependencies, but this variable may change over time to point to different values';
53580
+ }
53581
+ diagnostic.withDetails({
53582
+ kind: 'error',
53583
+ message: `Missing dependency \`${printInferredDependency(dep)}\`${reactiveStableValueHint}`,
53584
+ loc: dep.loc,
53585
+ });
53586
+ }
53587
+ error.pushDiagnostic(diagnostic);
53588
+ }
53589
+ else if (extra.length !== 0) {
53590
+ const diagnostic = CompilerDiagnostic.create({
53591
+ category: ErrorCategory.MemoDependencies,
53592
+ reason: 'Found unnecessary memoization dependencies',
53593
+ description: 'Unnecessary dependencies can cause a value to update more often than necessary, ' +
53594
+ 'which can cause effects to run more than expected',
53595
+ });
53596
+ diagnostic.withDetails({
53597
+ kind: 'error',
53598
+ message: `Unnecessary dependencies ${extra.map(dep => `\`${printManualMemoDependency(dep)}\``).join(', ')}`,
53599
+ loc: (_d = startMemo.depsLoc) !== null && _d !== void 0 ? _d : value.loc,
53600
+ });
53601
+ error.pushDiagnostic(diagnostic);
53602
+ }
53603
+ }
53604
+ dependencies.clear();
53605
+ locals.clear();
53606
+ startMemo = null;
53607
+ }
53608
+ collectDependencies(fn, temporaries, {
53609
+ onStartMemoize,
53610
+ onFinishMemoize,
53611
+ }, false);
53612
+ return error.asResult();
53613
+ }
53614
+ function addDependency(dep, dependencies, locals) {
53615
+ if (dep.kind === 'Function') {
53616
+ for (const x of dep.dependencies) {
53617
+ addDependency(x, dependencies, locals);
53618
+ }
53619
+ }
53620
+ else if (dep.kind === 'Global') {
53621
+ dependencies.add(dep);
53622
+ }
53623
+ else if (!locals.has(dep.identifier.id)) {
53624
+ dependencies.add(dep);
53625
+ }
53626
+ }
53627
+ function visitCandidateDependency(place, temporaries, dependencies, locals) {
53628
+ const dep = temporaries.get(place.identifier.id);
53629
+ if (dep != null) {
53630
+ addDependency(dep, dependencies, locals);
53631
+ }
53632
+ }
53633
+ function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
53634
+ var _a;
53635
+ const optionals = findOptionalPlaces(fn);
53636
+ const locals = new Set();
53637
+ if (isFunctionExpression) {
53638
+ for (const param of fn.params) {
53639
+ const place = param.kind === 'Identifier' ? param : param.place;
53640
+ locals.add(place.identifier.id);
53641
+ }
53642
+ }
53643
+ const dependencies = new Set();
53644
+ function visit(place) {
53645
+ visitCandidateDependency(place, temporaries, dependencies, locals);
53646
+ }
53647
+ for (const block of fn.body.blocks.values()) {
53648
+ for (const phi of block.phis) {
53649
+ let deps = null;
53650
+ for (const operand of phi.operands.values()) {
53651
+ const dep = temporaries.get(operand.identifier.id);
53652
+ if (dep == null) {
53653
+ continue;
53654
+ }
53655
+ if (deps == null) {
53656
+ deps = [dep];
53657
+ }
53658
+ else {
53659
+ deps.push(dep);
53660
+ }
53661
+ }
53662
+ if (deps == null) {
53663
+ continue;
53664
+ }
53665
+ else if (deps.length === 1) {
53666
+ temporaries.set(phi.place.identifier.id, deps[0]);
53667
+ }
53668
+ else {
53669
+ temporaries.set(phi.place.identifier.id, {
53670
+ kind: 'Function',
53671
+ dependencies: new Set(deps),
53672
+ });
53673
+ }
53674
+ }
53675
+ for (const instr of block.instructions) {
53676
+ const { lvalue, value } = instr;
53677
+ switch (value.kind) {
53678
+ case 'LoadGlobal': {
53679
+ temporaries.set(lvalue.identifier.id, {
53680
+ kind: 'Global',
53681
+ binding: value.binding,
53682
+ });
53683
+ break;
53684
+ }
53685
+ case 'LoadContext':
53686
+ case 'LoadLocal': {
53687
+ if (locals.has(value.place.identifier.id)) {
53688
+ break;
53689
+ }
53690
+ const temp = temporaries.get(value.place.identifier.id);
53691
+ if (temp != null) {
53692
+ if (temp.kind === 'Local') {
53693
+ const local = Object.assign(Object.assign({}, temp), { loc: value.place.loc });
53694
+ temporaries.set(lvalue.identifier.id, local);
53695
+ }
53696
+ else {
53697
+ temporaries.set(lvalue.identifier.id, temp);
53698
+ }
53699
+ }
53700
+ break;
53701
+ }
53702
+ case 'DeclareLocal': {
53703
+ const local = {
53704
+ kind: 'Local',
53705
+ identifier: value.lvalue.place.identifier,
53706
+ path: [],
53707
+ context: false,
53708
+ loc: value.lvalue.place.loc,
53709
+ };
53710
+ temporaries.set(value.lvalue.place.identifier.id, local);
53711
+ locals.add(value.lvalue.place.identifier.id);
53712
+ break;
53713
+ }
53714
+ case 'StoreLocal': {
53715
+ if (value.lvalue.place.identifier.name == null) {
53716
+ const temp = temporaries.get(value.value.identifier.id);
53717
+ if (temp != null) {
53718
+ temporaries.set(value.lvalue.place.identifier.id, temp);
53719
+ }
53720
+ break;
53721
+ }
53722
+ visit(value.value);
53723
+ if (value.lvalue.kind !== InstructionKind.Reassign) {
53724
+ const local = {
53725
+ kind: 'Local',
53726
+ identifier: value.lvalue.place.identifier,
53727
+ path: [],
53728
+ context: false,
53729
+ loc: value.lvalue.place.loc,
53730
+ };
53731
+ temporaries.set(value.lvalue.place.identifier.id, local);
53732
+ locals.add(value.lvalue.place.identifier.id);
53733
+ }
53734
+ break;
53735
+ }
53736
+ case 'DeclareContext': {
53737
+ const local = {
53738
+ kind: 'Local',
53739
+ identifier: value.lvalue.place.identifier,
53740
+ path: [],
53741
+ context: true,
53742
+ loc: value.lvalue.place.loc,
53743
+ };
53744
+ temporaries.set(value.lvalue.place.identifier.id, local);
53745
+ break;
53746
+ }
53747
+ case 'StoreContext': {
53748
+ visit(value.value);
53749
+ if (value.lvalue.kind !== InstructionKind.Reassign) {
53750
+ const local = {
53751
+ kind: 'Local',
53752
+ identifier: value.lvalue.place.identifier,
53753
+ path: [],
53754
+ context: true,
53755
+ loc: value.lvalue.place.loc,
53756
+ };
53757
+ temporaries.set(value.lvalue.place.identifier.id, local);
53758
+ locals.add(value.lvalue.place.identifier.id);
53759
+ }
53760
+ break;
53761
+ }
53762
+ case 'Destructure': {
53763
+ visit(value.value);
53764
+ if (value.lvalue.kind !== InstructionKind.Reassign) {
53765
+ for (const lvalue of eachInstructionValueLValue(value)) {
53766
+ const local = {
53767
+ kind: 'Local',
53768
+ identifier: lvalue.identifier,
53769
+ path: [],
53770
+ context: false,
53771
+ loc: lvalue.loc,
53772
+ };
53773
+ temporaries.set(lvalue.identifier.id, local);
53774
+ locals.add(lvalue.identifier.id);
53775
+ }
53776
+ }
53777
+ break;
53778
+ }
53779
+ case 'PropertyLoad': {
53780
+ if (typeof value.property === 'number' ||
53781
+ (isUseRefType(value.object.identifier) &&
53782
+ value.property === 'current')) {
53783
+ visit(value.object);
53784
+ break;
53785
+ }
53786
+ const object = temporaries.get(value.object.identifier.id);
53787
+ if (object != null && object.kind === 'Local') {
53788
+ const optional = (_a = optionals.get(value.object.identifier.id)) !== null && _a !== void 0 ? _a : false;
53789
+ const local = {
53790
+ kind: 'Local',
53791
+ identifier: object.identifier,
53792
+ context: object.context,
53793
+ path: [
53794
+ ...object.path,
53795
+ {
53796
+ optional,
53797
+ property: value.property,
53798
+ },
53799
+ ],
53800
+ loc: value.loc,
53801
+ };
53802
+ temporaries.set(lvalue.identifier.id, local);
53803
+ }
53804
+ break;
53805
+ }
53806
+ case 'FunctionExpression':
53807
+ case 'ObjectMethod': {
53808
+ const functionDeps = collectDependencies(value.loweredFunc.func, temporaries, null, true);
53809
+ temporaries.set(lvalue.identifier.id, functionDeps);
53810
+ addDependency(functionDeps, dependencies, locals);
53811
+ break;
53812
+ }
53813
+ case 'StartMemoize': {
53814
+ const onStartMemoize = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onStartMemoize;
53815
+ if (onStartMemoize != null) {
53816
+ onStartMemoize(value, dependencies, locals);
53817
+ }
53818
+ break;
53819
+ }
53820
+ case 'FinishMemoize': {
53821
+ const onFinishMemoize = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onFinishMemoize;
53822
+ if (onFinishMemoize != null) {
53823
+ onFinishMemoize(value, dependencies, locals);
53824
+ }
53825
+ break;
53826
+ }
53827
+ case 'MethodCall': {
53828
+ for (const operand of eachInstructionValueOperand(value)) {
53829
+ if (operand.identifier.id === value.property.identifier.id) {
53830
+ continue;
53831
+ }
53832
+ visit(operand);
53833
+ }
53834
+ break;
53835
+ }
53836
+ default: {
53837
+ for (const operand of eachInstructionValueOperand(value)) {
53838
+ visit(operand);
53839
+ }
53840
+ for (const lvalue of eachInstructionLValue(instr)) {
53841
+ locals.add(lvalue.identifier.id);
53842
+ }
53843
+ }
53844
+ }
53845
+ }
53846
+ for (const operand of eachTerminalOperand(block.terminal)) {
53847
+ if (optionals.has(operand.identifier.id)) {
53848
+ continue;
53849
+ }
53850
+ visit(operand);
53851
+ }
53852
+ }
53853
+ return { kind: 'Function', dependencies };
53854
+ }
53855
+ function printInferredDependency(dep) {
53856
+ switch (dep.kind) {
53857
+ case 'Global': {
53858
+ return dep.binding.name;
53859
+ }
53860
+ case 'Local': {
53861
+ CompilerError.simpleInvariant(dep.identifier.name != null && dep.identifier.name.kind === 'named', {
53862
+ reason: 'Expected dependencies to be named variables',
53863
+ loc: dep.loc,
53864
+ });
53865
+ return `${dep.identifier.name.value}${dep.path.map(p => (p.optional ? '?' : '') + '.' + p.property).join('')}`;
53866
+ }
53867
+ }
53868
+ }
53869
+ function printManualMemoDependency(dep) {
53870
+ let identifierName;
53871
+ if (dep.root.kind === 'Global') {
53872
+ identifierName = dep.root.identifierName;
53873
+ }
53874
+ else {
53875
+ const name = dep.root.value.identifier.name;
53876
+ CompilerError.simpleInvariant(name != null && name.kind === 'named', {
53877
+ reason: 'Expected manual dependencies to be named variables',
53878
+ loc: dep.root.value.loc,
53879
+ });
53880
+ identifierName = name.value;
53881
+ }
53882
+ return `${identifierName}${dep.path.map(p => (p.optional ? '?' : '') + '.' + p.property).join('')}`;
53883
+ }
53884
+ function isEqualTemporary(a, b) {
53885
+ switch (a.kind) {
53886
+ case 'Function': {
53887
+ return false;
53888
+ }
53889
+ case 'Global': {
53890
+ return b.kind === 'Global' && a.binding.name === b.binding.name;
53891
+ }
53892
+ case 'Local': {
53893
+ return (b.kind === 'Local' &&
53894
+ a.identifier.id === b.identifier.id &&
53895
+ areEqualPaths(a.path, b.path));
53896
+ }
53897
+ }
53898
+ }
53899
+ function collectReactiveIdentifiersHIR(fn) {
53900
+ const reactive = new Set();
53901
+ for (const block of fn.body.blocks.values()) {
53902
+ for (const instr of block.instructions) {
53903
+ for (const lvalue of eachInstructionLValue(instr)) {
53904
+ if (lvalue.reactive) {
53905
+ reactive.add(lvalue.identifier.id);
53906
+ }
53907
+ }
53908
+ for (const operand of eachInstructionValueOperand(instr.value)) {
53909
+ if (operand.reactive) {
53910
+ reactive.add(operand.identifier.id);
53911
+ }
53912
+ }
53913
+ }
53914
+ for (const operand of eachTerminalOperand(block.terminal)) {
53915
+ if (operand.reactive) {
53916
+ reactive.add(operand.identifier.id);
53917
+ }
53918
+ }
53919
+ }
53920
+ return reactive;
53921
+ }
53922
+ function findOptionalPlaces(fn) {
53923
+ const optionals = new Map();
53924
+ const visited = new Set();
53925
+ for (const [, block] of fn.body.blocks) {
53926
+ if (visited.has(block.id)) {
53927
+ continue;
53928
+ }
53929
+ if (block.terminal.kind === 'optional') {
53930
+ visited.add(block.id);
53931
+ const optionalTerminal = block.terminal;
53932
+ let testBlock = fn.body.blocks.get(block.terminal.test);
53933
+ const queue = [block.terminal.optional];
53934
+ loop: while (true) {
53935
+ visited.add(testBlock.id);
53936
+ const terminal = testBlock.terminal;
53937
+ switch (terminal.kind) {
53938
+ case 'branch': {
53939
+ const isOptional = queue.pop();
53940
+ CompilerError.simpleInvariant(isOptional !== undefined, {
53941
+ reason: 'Expected an optional value for each optional test condition',
53942
+ loc: terminal.test.loc,
53943
+ });
53944
+ if (isOptional != null) {
53945
+ optionals.set(terminal.test.identifier.id, isOptional);
53946
+ }
53947
+ if (terminal.fallthrough === optionalTerminal.fallthrough) {
53948
+ const consequent = fn.body.blocks.get(terminal.consequent);
53949
+ const last = consequent.instructions.at(-1);
53950
+ if (last !== undefined && last.value.kind === 'StoreLocal') {
53951
+ if (isOptional != null) {
53952
+ optionals.set(last.value.value.identifier.id, isOptional);
53953
+ }
53954
+ }
53955
+ break loop;
53956
+ }
53957
+ else {
53958
+ testBlock = fn.body.blocks.get(terminal.fallthrough);
53959
+ }
53960
+ break;
53961
+ }
53962
+ case 'optional': {
53963
+ queue.push(terminal.optional);
53964
+ testBlock = fn.body.blocks.get(terminal.test);
53965
+ break;
53966
+ }
53967
+ case 'logical':
53968
+ case 'ternary': {
53969
+ queue.push(null);
53970
+ testBlock = fn.body.blocks.get(terminal.test);
53971
+ break;
53972
+ }
53973
+ case 'sequence': {
53974
+ testBlock = fn.body.blocks.get(terminal.block);
53975
+ break;
53976
+ }
53977
+ default: {
53978
+ CompilerError.simpleInvariant(false, {
53979
+ reason: `Unexpected terminal in optional`,
53980
+ loc: terminal.loc,
53981
+ });
53982
+ }
53983
+ }
53984
+ }
53985
+ CompilerError.simpleInvariant(queue.length === 0, {
53986
+ reason: 'Expected a matching number of conditional blocks and branch points',
53987
+ loc: block.terminal.loc,
53988
+ });
53989
+ }
53990
+ }
53991
+ return optionals;
53992
+ }
53993
+
53109
53994
  function run(func, config, fnType, mode, programContext, logger, filename, code) {
53110
53995
  var _a, _b;
53111
53996
  const contextIdentifiers = findContextIdentifiers(func);
@@ -53128,7 +54013,7 @@ function runWithEnvironment(func, env) {
53128
54013
  log({ kind: 'hir', name: 'PruneMaybeThrows', value: hir });
53129
54014
  validateContextVariableLValues(hir);
53130
54015
  validateUseMemo(hir).unwrap();
53131
- if (env.isInferredMemoEnabled &&
54016
+ if (env.enableDropManualMemoization &&
53132
54017
  !env.config.enablePreserveExistingManualUseMemo &&
53133
54018
  !env.config.disableMemoizationForDebugging &&
53134
54019
  !env.config.enableChangeDetectionForDebugging) {
@@ -53154,7 +54039,7 @@ function runWithEnvironment(func, env) {
53154
54039
  log({ kind: 'hir', name: 'ConstantPropagation', value: hir });
53155
54040
  inferTypes(hir);
53156
54041
  log({ kind: 'hir', name: 'InferTypes', value: hir });
53157
- if (env.isInferredMemoEnabled) {
54042
+ if (env.enableValidations) {
53158
54043
  if (env.config.validateHooksUsage) {
53159
54044
  validateHooksUsage(hir).unwrap();
53160
54045
  }
@@ -53175,11 +54060,15 @@ function runWithEnvironment(func, env) {
53175
54060
  log({ kind: 'hir', name: 'AnalyseFunctions', value: hir });
53176
54061
  const mutabilityAliasingErrors = inferMutationAliasingEffects(hir);
53177
54062
  log({ kind: 'hir', name: 'InferMutationAliasingEffects', value: hir });
53178
- if (env.isInferredMemoEnabled) {
54063
+ if (env.enableValidations) {
53179
54064
  if (mutabilityAliasingErrors.isErr()) {
53180
54065
  throw mutabilityAliasingErrors.unwrapErr();
53181
54066
  }
53182
54067
  }
54068
+ if (env.outputMode === 'ssr') {
54069
+ optimizeForSSR(hir);
54070
+ log({ kind: 'hir', name: 'OptimizeForSSR', value: hir });
54071
+ }
53183
54072
  deadCodeElimination(hir);
53184
54073
  log({ kind: 'hir', name: 'DeadCodeElimination', value: hir });
53185
54074
  if (env.config.enableInstructionReordering) {
@@ -53192,13 +54081,13 @@ function runWithEnvironment(func, env) {
53192
54081
  isFunctionExpression: false,
53193
54082
  });
53194
54083
  log({ kind: 'hir', name: 'InferMutationAliasingRanges', value: hir });
53195
- if (env.isInferredMemoEnabled) {
54084
+ if (env.enableValidations) {
53196
54085
  if (mutabilityAliasingRangeErrors.isErr()) {
53197
54086
  throw mutabilityAliasingRangeErrors.unwrapErr();
53198
54087
  }
53199
54088
  validateLocalsNotReassignedAfterRender(hir);
53200
54089
  }
53201
- if (env.isInferredMemoEnabled) {
54090
+ if (env.enableValidations) {
53202
54091
  if (env.config.assertValidMutableRanges) {
53203
54092
  assertValidMutableRanges(hir);
53204
54093
  }
@@ -53227,16 +54116,19 @@ function runWithEnvironment(func, env) {
53227
54116
  }
53228
54117
  inferReactivePlaces(hir);
53229
54118
  log({ kind: 'hir', name: 'InferReactivePlaces', value: hir });
54119
+ if (env.config.validateExhaustiveMemoizationDependencies) {
54120
+ validateExhaustiveDependencies(hir).unwrap();
54121
+ }
53230
54122
  rewriteInstructionKindsBasedOnReassignment(hir);
53231
54123
  log({
53232
54124
  kind: 'hir',
53233
54125
  name: 'RewriteInstructionKindsBasedOnReassignment',
53234
54126
  value: hir,
53235
54127
  });
53236
- if (env.isInferredMemoEnabled) {
53237
- if (env.config.validateStaticComponents) {
53238
- env.logErrors(validateStaticComponents(hir));
53239
- }
54128
+ if (env.enableValidations && env.config.validateStaticComponents) {
54129
+ env.logErrors(validateStaticComponents(hir));
54130
+ }
54131
+ if (env.enableMemoization) {
53240
54132
  inferReactiveScopeVariables(hir);
53241
54133
  log({ kind: 'hir', name: 'InferReactiveScopeVariables', value: hir });
53242
54134
  }
@@ -53816,7 +54708,7 @@ function isFilePartOfSources(sources, filename) {
53816
54708
  return false;
53817
54709
  }
53818
54710
  function compileProgram(program, pass) {
53819
- var _a;
54711
+ var _a, _b;
53820
54712
  if (shouldSkipCompilation(program, pass)) {
53821
54713
  return null;
53822
54714
  }
@@ -53837,9 +54729,10 @@ function compileProgram(program, pass) {
53837
54729
  });
53838
54730
  const queue = findFunctionsToCompile(program, pass, programContext);
53839
54731
  const compiledFns = [];
54732
+ const outputMode = (_b = pass.opts.outputMode) !== null && _b !== void 0 ? _b : (pass.opts.noEmit ? 'lint' : 'client');
53840
54733
  while (queue.length !== 0) {
53841
54734
  const current = queue.shift();
53842
- const compiled = processFn(current.fn, current.fnType, programContext);
54735
+ const compiled = processFn(current.fn, current.fnType, programContext, outputMode);
53843
54736
  if (compiled != null) {
53844
54737
  for (const outlined of compiled.outlined) {
53845
54738
  CompilerError.invariant(outlined.fn.outlined.length === 0, {
@@ -53921,7 +54814,7 @@ function findFunctionsToCompile(program, pass, programContext) {
53921
54814
  }, Object.assign(Object.assign({}, pass), { opts: Object.assign(Object.assign({}, pass.opts), pass.opts), filename: (_a = pass.filename) !== null && _a !== void 0 ? _a : null }));
53922
54815
  return queue;
53923
54816
  }
53924
- function processFn(fn, fnType, programContext) {
54817
+ function processFn(fn, fnType, programContext, outputMode) {
53925
54818
  var _a, _b, _c, _d, _e, _f, _g, _h;
53926
54819
  let directives;
53927
54820
  if (fn.node.body.type !== 'BlockStatement') {
@@ -53942,7 +54835,7 @@ function processFn(fn, fnType, programContext) {
53942
54835
  };
53943
54836
  }
53944
54837
  let compiledFn;
53945
- const compileResult = tryCompileFunction(fn, fnType, programContext);
54838
+ const compileResult = tryCompileFunction(fn, fnType, programContext, outputMode);
53946
54839
  if (compileResult.kind === 'error') {
53947
54840
  if (directives.optOut != null) {
53948
54841
  logError(compileResult.error, programContext, (_b = fn.node.loc) !== null && _b !== void 0 ? _b : null);
@@ -53950,11 +54843,16 @@ function processFn(fn, fnType, programContext) {
53950
54843
  else {
53951
54844
  handleError(compileResult.error, programContext, (_c = fn.node.loc) !== null && _c !== void 0 ? _c : null);
53952
54845
  }
53953
- const retryResult = retryCompileFunction(fn, fnType, programContext);
53954
- if (retryResult == null) {
54846
+ if (outputMode === 'client') {
54847
+ const retryResult = retryCompileFunction(fn, fnType, programContext);
54848
+ if (retryResult == null) {
54849
+ return null;
54850
+ }
54851
+ compiledFn = retryResult;
54852
+ }
54853
+ else {
53955
54854
  return null;
53956
54855
  }
53957
- compiledFn = retryResult;
53958
54856
  }
53959
54857
  else {
53960
54858
  compiledFn = compileResult.compiledFn;
@@ -53982,7 +54880,7 @@ function processFn(fn, fnType, programContext) {
53982
54880
  if (programContext.hasModuleScopeOptOut) {
53983
54881
  return null;
53984
54882
  }
53985
- else if (programContext.opts.noEmit) {
54883
+ else if (programContext.opts.outputMode === 'lint') {
53986
54884
  for (const loc of compiledFn.inferredEffectLocations) {
53987
54885
  if (loc !== GeneratedSource) {
53988
54886
  programContext.inferredEffectLocations.add(loc);
@@ -53998,7 +54896,7 @@ function processFn(fn, fnType, programContext) {
53998
54896
  return compiledFn;
53999
54897
  }
54000
54898
  }
54001
- function tryCompileFunction(fn, fnType, programContext) {
54899
+ function tryCompileFunction(fn, fnType, programContext, outputMode) {
54002
54900
  const suppressionsInFunction = filterSuppressionsThatAffectFunction(programContext.suppressions, fn);
54003
54901
  if (suppressionsInFunction.length > 0) {
54004
54902
  return {
@@ -54009,7 +54907,7 @@ function tryCompileFunction(fn, fnType, programContext) {
54009
54907
  try {
54010
54908
  return {
54011
54909
  kind: 'compile',
54012
- compiledFn: compileFn(fn, programContext.opts.environment, fnType, 'all_features', programContext, programContext.opts.logger, programContext.filename, programContext.code),
54910
+ compiledFn: compileFn(fn, programContext.opts.environment, fnType, outputMode, programContext, programContext.opts.logger, programContext.filename, programContext.code),
54013
54911
  };
54014
54912
  }
54015
54913
  catch (err) {
@@ -54022,7 +54920,7 @@ function retryCompileFunction(fn, fnType, programContext) {
54022
54920
  return null;
54023
54921
  }
54024
54922
  try {
54025
- const retryResult = compileFn(fn, environment, fnType, 'no_inferred_memo', programContext, programContext.opts.logger, programContext.filename, programContext.code);
54923
+ const retryResult = compileFn(fn, environment, fnType, 'client-no-memo', programContext, programContext.opts.logger, programContext.filename, programContext.code);
54026
54924
  if (!retryResult.hasFireRewrite && !retryResult.hasInferredEffect) {
54027
54925
  return null;
54028
54926
  }
@@ -54698,6 +55596,12 @@ v4.z.enum([
54698
55596
  'annotation',
54699
55597
  'all',
54700
55598
  ]);
55599
+ v4.z.enum([
55600
+ 'ssr',
55601
+ 'client',
55602
+ 'client-no-memo',
55603
+ 'lint',
55604
+ ]);
54701
55605
  const defaultOptions = {
54702
55606
  compilationMode: 'infer',
54703
55607
  panicThreshold: 'none',
@@ -54705,6 +55609,7 @@ const defaultOptions = {
54705
55609
  logger: null,
54706
55610
  gating: null,
54707
55611
  noEmit: false,
55612
+ outputMode: null,
54708
55613
  dynamicGating: null,
54709
55614
  eslintSuppressionRules: null,
54710
55615
  flowSuppressions: true,
@@ -55123,7 +56028,7 @@ function BabelPluginReactCompiler(_babel) {
55123
56028
 
55124
56029
  var _LRUCache_values, _LRUCache_headIdx;
55125
56030
  const COMPILER_OPTIONS = {
55126
- noEmit: true,
56031
+ outputMode: 'lint',
55127
56032
  panicThreshold: 'none',
55128
56033
  flowSuppressions: false,
55129
56034
  environment: {