react-state-basis 0.6.5 → 0.6.6

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.
@@ -24,33 +24,92 @@ __export(zustand_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(zustand_exports);
26
26
 
27
+ // src/core/constants.ts
28
+ var WINDOW_SIZE = 50;
29
+ var PAIR_RARITY_TARGET = 0.01;
30
+ var RELATIVE_OVERLAP_FLOOR = 0.65;
31
+ var LOOP_THRESHOLD = 150;
32
+ var VOLATILITY_THRESHOLD = 25;
33
+ var INSTANCE_SEP = "##";
34
+
27
35
  // src/core/math.ts
28
- var calculateSimilarityCircular = (bufferA, headA, bufferB, headB, offset) => {
36
+ var choose = (n, k) => {
37
+ if (k < 0 || k > n) return 0;
38
+ k = Math.min(k, n - k);
39
+ let result = 1;
40
+ for (let i = 0; i < k; i++) {
41
+ result = result * (n - i) / (i + 1);
42
+ }
43
+ return result;
44
+ };
45
+ var hypergeomPMF = (k, n1, m1, N) => {
46
+ const total = choose(N, n1);
47
+ if (total === 0) return 0;
48
+ return choose(m1, k) * choose(N - m1, n1 - k) / total;
49
+ };
50
+ var hypergeomUpperTailP = (kStart, n1, m1, N) => {
51
+ const kMax = Math.min(n1, m1);
52
+ let p = 0;
53
+ for (let k = Math.max(0, kStart); k <= kMax; k++) {
54
+ p += hypergeomPMF(k, n1, m1, N);
55
+ }
56
+ return p;
57
+ };
58
+ var minOverlapForRarity = (n1, m1, N, targetP) => {
59
+ const kMax = Math.min(n1, m1);
60
+ for (let k = 0; k <= kMax; k++) {
61
+ if (hypergeomUpperTailP(k, n1, m1, N) <= targetP) return k;
62
+ }
63
+ return kMax + 1;
64
+ };
65
+ var overlapThresholdCache = /* @__PURE__ */ new Map();
66
+ var getMinOverlap = (densityA, densityB, windowSize) => {
67
+ const lo = Math.min(densityA, densityB) | 0;
68
+ const hi = Math.max(densityA, densityB) | 0;
69
+ const key = `${lo}_${hi}_${windowSize}`;
70
+ let cached = overlapThresholdCache.get(key);
71
+ if (cached === void 0) {
72
+ const rare = minOverlapForRarity(lo, hi, windowSize, PAIR_RARITY_TARGET);
73
+ const floor = Math.ceil(RELATIVE_OVERLAP_FLOOR * lo);
74
+ cached = Math.max(rare, floor);
75
+ overlapThresholdCache.set(key, cached);
76
+ }
77
+ return cached;
78
+ };
79
+ var isSignificantOverlap = (overlap, densityA, densityB, windowSize) => {
80
+ if (densityA < 2 || densityB < 2) return false;
81
+ return overlap >= getMinOverlap(densityA, densityB, windowSize);
82
+ };
83
+ var countOverlapsCircular = (bufferA, headA, bufferB, headB) => {
29
84
  const L = bufferA.length;
30
- let dot = 0, magA = 0, magB = 0;
31
- const baseOffset = ((headB - headA + offset) % L + L) % L;
85
+ const offSync = ((headB - headA) % L + L) % L;
86
+ const offALeadsB = ((headB - headA + 1) % L + L) % L;
87
+ const offBLeadsA = ((headB - headA - 1) % L + L) % L;
88
+ let kSync = 0;
89
+ let kALeadsB = 0;
90
+ let kBLeadsA = 0;
91
+ let densityA = 0;
92
+ let densityB = 0;
32
93
  for (let i = 0; i < L; i++) {
33
- const valA = bufferA[i];
34
- let iB = i + baseOffset;
35
- if (iB >= L) {
36
- iB -= L;
37
- }
38
- const valB = bufferB[iB];
39
- dot += valA * valB;
40
- magA += valA * valA;
41
- magB += valB * valB;
94
+ const a = bufferA[i] ? 1 : 0;
95
+ const b = bufferB[i] ? 1 : 0;
96
+ densityA += a;
97
+ densityB += b;
98
+ let iSync = i + offSync;
99
+ if (iSync >= L) iSync -= L;
100
+ let iALeadsB = i + offALeadsB;
101
+ if (iALeadsB >= L) iALeadsB -= L;
102
+ let iBLeadsA = i + offBLeadsA;
103
+ if (iBLeadsA >= L) iBLeadsA -= L;
104
+ if (a && bufferB[iSync]) kSync++;
105
+ if (a && bufferB[iALeadsB]) kALeadsB++;
106
+ if (a && bufferB[iBLeadsA]) kBLeadsA++;
42
107
  }
43
- if (magA === 0 || magB === 0) return 0;
44
- return dot / (Math.sqrt(magA) * Math.sqrt(magB));
108
+ return { kSync, kALeadsB, kBLeadsA, densityA, densityB };
45
109
  };
46
- var calculateCosineSimilarity = (A, B) => {
47
- let dot = 0, magA = 0, magB = 0;
48
- for (let i = 0; i < A.length; i++) {
49
- dot += A[i] * B[i];
50
- magA += A[i] * A[i];
51
- magB += B[i] * B[i];
52
- }
53
- return magA === 0 || magB === 0 ? 0 : dot / (Math.sqrt(magA) * Math.sqrt(magB));
110
+ var cosineFromOverlap = (overlap, densityA, densityB) => {
111
+ if (densityA <= 0 || densityB <= 0) return 0;
112
+ return overlap / Math.sqrt(densityA * densityB);
54
113
  };
55
114
 
56
115
  // src/core/graph.ts
@@ -109,13 +168,6 @@ var groupEventSources = (nodes, edges) => {
109
168
  return groups.sort((a, b) => b.edges.length - a.edges.length || b.occurrences - a.occurrences);
110
169
  };
111
170
 
112
- // src/core/constants.ts
113
- var WINDOW_SIZE = 50;
114
- var SIMILARITY_THRESHOLD = 0.88;
115
- var LOOP_THRESHOLD = 150;
116
- var VOLATILITY_THRESHOLD = 25;
117
- var INSTANCE_SEP = "##";
118
-
119
171
  // src/core/label.ts
120
172
  var stripInstance = (label) => {
121
173
  const idx = label.indexOf(INSTANCE_SEP);
@@ -229,32 +281,22 @@ var LAST_LOG_TIMES = /* @__PURE__ */ new Map();
229
281
  var LOG_COOLDOWN = 3e3;
230
282
  var THEME = {
231
283
  identity: "#6C5CE7",
232
- // Purple (Brand)
233
284
  problem: "#D63031",
234
- // Red (Bugs)
235
285
  solution: "#FBC531",
236
- // Yellow (Fixes)
237
286
  context: "#0984E3",
238
- // Blue (Locations)
239
287
  muted: "#9AA0A6",
240
- // Gray (Metadata)
241
288
  border: "#2E2E35",
242
289
  success: "#00b894"
243
- // Green (Good Score)
244
290
  };
245
291
  var STYLES = {
246
- // Structure
247
292
  basis: `background: ${THEME.identity}; color: white; font-weight: bold; padding: 2px 6px; border-radius: 3px;`,
248
293
  headerIdentity: `background: ${THEME.identity}; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;`,
249
294
  headerProblem: `background: ${THEME.problem}; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;`,
250
295
  version: `background: #a29bfe; color: #2d3436; padding: 2px 6px; border-radius: 3px; margin-left: -4px;`,
251
- // Actions
252
296
  actionLabel: `color: ${THEME.solution}; font-weight: bold;`,
253
297
  actionPill: `color: ${THEME.solution}; font-weight: bold; border: 1px solid ${THEME.solution}; padding: 0 4px; border-radius: 3px;`,
254
- // Context
255
298
  impactLabel: `color: ${THEME.context}; font-weight: bold;`,
256
299
  location: `color: ${THEME.context}; font-family: monospace; font-weight: bold;`,
257
- // Text
258
300
  subText: `color: ${THEME.muted}; font-size: 11px;`,
259
301
  bold: "font-weight: bold;",
260
302
  label: "background: #dfe6e9; color: #2d3436; padding: 0 4px; border-radius: 3px; font-family: monospace; font-weight: bold; border: 1px solid #b2bec3;"
@@ -269,6 +311,15 @@ var shouldLog = (key) => {
269
311
  return false;
270
312
  };
271
313
  var isBooleanLike = (name) => /^(is|has|can|should|did|will|show|hide)(?=[A-Z_])/.test(name);
314
+ var areSyncSignificant = (metaA, metaB) => {
315
+ const { kSync, densityA, densityB } = countOverlapsCircular(
316
+ metaA.buffer,
317
+ metaA.head,
318
+ metaB.buffer,
319
+ metaB.head
320
+ );
321
+ return isSignificantOverlap(kSync, densityA, densityB, metaA.buffer.length);
322
+ };
272
323
  var getSuggestedFix = (issue, info) => {
273
324
  if (issue.label.includes("Global Event")) {
274
325
  return `These variables update together but live in different hooks/files. Consolidate them into a single %cuseReducer%c or atomic store update.`;
@@ -298,7 +349,7 @@ var getSuggestedFix = (issue, info) => {
298
349
  }
299
350
  return `Check the dependency chain of ${info.name}.`;
300
351
  };
301
- var displayHealthReport = (history2, threshold, violationMap) => {
352
+ var displayHealthReport = (history2, violationMap) => {
302
353
  if (!isWeb) return;
303
354
  const entries = Array.from(history2.entries());
304
355
  if (entries.length === 0) return;
@@ -374,11 +425,10 @@ var displayHealthReport = (history2, threshold, violationMap) => {
374
425
  processed.add(labelA);
375
426
  entries.forEach(([labelB, metaB]) => {
376
427
  if (labelA === labelB || processed.has(labelB)) return;
377
- if (calculateCosineSimilarity(metaA.buffer, metaB.buffer) > threshold) {
378
- if (metaA.role === "context" /* CONTEXT */ && metaB.role === "context" /* CONTEXT */) return;
379
- currentCluster.push(labelB);
380
- processed.add(labelB);
381
- }
428
+ if (!areSyncSignificant(metaA, metaB)) return;
429
+ if (metaA.role === "context" /* CONTEXT */ && metaB.role === "context" /* CONTEXT */) return;
430
+ currentCluster.push(labelB);
431
+ processed.add(labelB);
382
432
  });
383
433
  if (currentCluster.length > 1) clusters.push(currentCluster);
384
434
  else independentCount++;
@@ -454,7 +504,7 @@ var displayRedundancyAlert = (labelA, metaA, labelB, metaB, sim) => {
454
504
  const alertType = isContextMirror ? "CONTEXT MIRRORING" : isStoreMirror ? "STORE MIRRORING" : "DUPLICATE STATE";
455
505
  console.group(`%c \u264A BASIS | ${alertType} `, STYLES.headerProblem);
456
506
  console.log(`%c\u{1F4CD} Location: %c${infoA.file}`, STYLES.bold, STYLES.location);
457
- console.log(`%cIssue:%c ${infoA.name} and ${infoB.name} are synchronized (${(sim * 100).toFixed(0)}%).`, STYLES.bold, "");
507
+ console.log(`%cIssue:%c ${infoA.name} and ${infoB.name} overlapped on ${(sim * 100).toFixed(0)}% of aligned updates.`, STYLES.bold, "");
458
508
  if (isContextMirror || isStoreMirror) {
459
509
  const sourceType = isStoreMirror ? "External Store" : "Global Context";
460
510
  console.log(
@@ -628,7 +678,6 @@ Frequency: ${count} updates/sec`);
628
678
  };
629
679
 
630
680
  // src/core/analysis.ts
631
- var CAUSAL_MARGIN = 0.05;
632
681
  var isEventDriven = (label, graph) => {
633
682
  for (const [parent, targets] of graph.entries()) {
634
683
  if (parent.startsWith("Event_Tick_") && targets.has(label)) {
@@ -638,28 +687,33 @@ var isEventDriven = (label, graph) => {
638
687
  return false;
639
688
  };
640
689
  var calculateAllSimilarities = (entryA, entryB) => {
641
- const sync = calculateSimilarityCircular(
690
+ const { kSync, kALeadsB, kBLeadsA, densityA, densityB } = countOverlapsCircular(
642
691
  entryA.meta.buffer,
643
692
  entryA.meta.head,
644
693
  entryB.meta.buffer,
645
- entryB.meta.head,
646
- 0
694
+ entryB.meta.head
647
695
  );
648
- const bA = calculateSimilarityCircular(
649
- entryA.meta.buffer,
650
- entryA.meta.head,
651
- entryB.meta.buffer,
652
- entryB.meta.head,
653
- 1
654
- );
655
- const aB = calculateSimilarityCircular(
656
- entryA.meta.buffer,
657
- entryA.meta.head,
658
- entryB.meta.buffer,
659
- entryB.meta.head,
660
- -1
661
- );
662
- return { sync, bA, aB, max: Math.max(sync, bA, aB) };
696
+ const sync = cosineFromOverlap(kSync, densityA, densityB);
697
+ const bA = cosineFromOverlap(kALeadsB, densityA, densityB);
698
+ const aB = cosineFromOverlap(kBLeadsA, densityA, densityB);
699
+ const max = Math.max(sync, bA, aB);
700
+ const windowSize = entryA.meta.buffer.length;
701
+ const significantSync = isSignificantOverlap(kSync, densityA, densityB, windowSize);
702
+ const kLead = Math.max(kALeadsB, kBLeadsA);
703
+ const significantLead = isSignificantOverlap(kLead, densityA, densityB, windowSize) && kLead >= kSync + 1;
704
+ return {
705
+ sync,
706
+ bA,
707
+ aB,
708
+ max,
709
+ kSync,
710
+ kALeadsB,
711
+ kBLeadsA,
712
+ densityA,
713
+ densityB,
714
+ significantSync,
715
+ significantLead
716
+ };
663
717
  };
664
718
  var shouldSkipComparison = (entryA, entryB, dirtyLabels2) => {
665
719
  if (entryA.label === entryB.label) return true;
@@ -684,52 +738,51 @@ var detectRedundancy = (entryA, entryB, similarities, redundantSet, violationMap
684
738
  const roleA = entryA.meta.role;
685
739
  const roleB = entryB.meta.role;
686
740
  if (isGlobalSource(roleA) && isGlobalSource(roleB)) return;
687
- if (entryA.meta.density < 2 || entryB.meta.density < 2) return;
741
+ if (similarities.densityA < 2 || similarities.densityB < 2) return;
742
+ const score = similarities.sync;
688
743
  if (roleA === "local" /* LOCAL */ && isGlobalSource(roleB)) {
689
744
  redundantSet.add(entryA.label);
690
- pushViolation(violationMap, entryB.label, { type: "context_mirror", target: entryA.label, similarity: similarities.max });
691
- displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, similarities.max);
745
+ pushViolation(violationMap, entryB.label, { type: "context_mirror", target: entryA.label, similarity: score });
746
+ displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, score);
692
747
  } else if (isGlobalSource(roleA) && roleB === "local" /* LOCAL */) {
693
748
  redundantSet.add(entryB.label);
694
- pushViolation(violationMap, entryA.label, { type: "context_mirror", target: entryB.label, similarity: similarities.max });
695
- displayRedundancyAlert(entryB.label, entryB.meta, entryA.label, entryA.meta, similarities.max);
749
+ pushViolation(violationMap, entryA.label, { type: "context_mirror", target: entryB.label, similarity: score });
750
+ displayRedundancyAlert(entryB.label, entryB.meta, entryA.label, entryA.meta, score);
696
751
  } else if (roleA === "local" /* LOCAL */ && roleB === "local" /* LOCAL */) {
697
752
  redundantSet.add(entryA.label);
698
753
  redundantSet.add(entryB.label);
699
- pushViolation(violationMap, entryA.label, { type: "duplicate_state", target: entryB.label, similarity: similarities.max });
700
- pushViolation(violationMap, entryB.label, { type: "duplicate_state", target: entryA.label, similarity: similarities.max });
701
- displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, similarities.max);
754
+ pushViolation(violationMap, entryA.label, { type: "duplicate_state", target: entryB.label, similarity: score });
755
+ pushViolation(violationMap, entryB.label, { type: "duplicate_state", target: entryA.label, similarity: score });
756
+ displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, score);
702
757
  }
703
758
  };
704
759
  var detectCausalLeak = (entryA, entryB, similarities, violationMap, graph) => {
705
760
  if (entryA.isVolatile || entryB.isVolatile) return;
706
- if (similarities.max - similarities.sync < CAUSAL_MARGIN) return;
707
761
  const addLeak = (source, target) => {
708
762
  if (isEventDriven(target, graph)) return;
709
- if (!violationMap.has(source)) {
710
- violationMap.set(source, []);
711
- }
712
- violationMap.get(source).push({ type: "causal_leak", target });
763
+ pushViolation(violationMap, source, { type: "causal_leak", target });
713
764
  const sourceEntry = source === entryA.label ? entryA : entryB;
714
765
  const targetEntry = source === entryA.label ? entryB : entryA;
715
766
  displayCausalHint(target, targetEntry.meta, source, sourceEntry.meta);
716
767
  };
717
- if (similarities.bA === similarities.max) {
768
+ if (similarities.kALeadsB >= similarities.kBLeadsA) {
718
769
  addLeak(entryA.label, entryB.label);
719
- } else if (similarities.aB === similarities.max) {
770
+ } else {
720
771
  addLeak(entryB.label, entryA.label);
721
772
  }
722
773
  };
723
774
  var detectSubspaceOverlap = (dirtyEntries, allEntries, redundantSet, dirtyLabels2, graph) => {
724
- let compCount = 0;
725
775
  const violationMap = /* @__PURE__ */ new Map();
776
+ let compCount = 0;
726
777
  for (const entryA of dirtyEntries) {
727
778
  for (const entryB of allEntries) {
728
779
  if (shouldSkipComparison(entryA, entryB, dirtyLabels2)) continue;
729
780
  compCount++;
730
781
  const similarities = calculateAllSimilarities(entryA, entryB);
731
- if (similarities.max > SIMILARITY_THRESHOLD) {
782
+ if (similarities.significantSync) {
732
783
  detectRedundancy(entryA, entryB, similarities, redundantSet, violationMap);
784
+ }
785
+ if (similarities.significantLead) {
733
786
  detectCausalLeak(entryA, entryB, similarities, violationMap, graph);
734
787
  }
735
788
  }
@@ -962,9 +1015,9 @@ var registerVariable = (l, o = {}) => {
962
1015
  });
963
1016
  }
964
1017
  };
965
- var printBasisHealthReport = (threshold = 0.5) => {
1018
+ var printBasisHealthReport = () => {
966
1019
  if (!instance.config.debug) return;
967
- displayHealthReport(instance.history, threshold, instance.violationMap);
1020
+ displayHealthReport(instance.history, instance.violationMap);
968
1021
  };
969
1022
  var getBasisMetrics = () => ({
970
1023
  engine: "v0.6.x",