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.
- package/dist/{chunk-EJXGN76H.mjs → chunk-WMHY2C6D.mjs} +138 -85
- package/dist/chunk-WMHY2C6D.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +137 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/integrations/zustand.js +137 -84
- package/dist/integrations/zustand.js.map +1 -1
- package/dist/integrations/zustand.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-EJXGN76H.mjs.map +0 -1
|
@@ -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
|
|
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
|
-
|
|
31
|
-
const
|
|
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
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
44
|
-
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
108
|
+
return { kSync, kALeadsB, kBLeadsA, densityA, densityB };
|
|
45
109
|
};
|
|
46
|
-
var
|
|
47
|
-
|
|
48
|
-
|
|
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,
|
|
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 (
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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}
|
|
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
|
|
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
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
);
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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 (
|
|
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:
|
|
691
|
-
displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta,
|
|
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:
|
|
695
|
-
displayRedundancyAlert(entryB.label, entryB.meta, entryA.label, entryA.meta,
|
|
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:
|
|
700
|
-
pushViolation(violationMap, entryB.label, { type: "duplicate_state", target: entryA.label, similarity:
|
|
701
|
-
displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta,
|
|
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
|
-
|
|
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.
|
|
768
|
+
if (similarities.kALeadsB >= similarities.kBLeadsA) {
|
|
718
769
|
addLeak(entryA.label, entryB.label);
|
|
719
|
-
} else
|
|
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.
|
|
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 = (
|
|
1018
|
+
var printBasisHealthReport = () => {
|
|
966
1019
|
if (!instance.config.debug) return;
|
|
967
|
-
displayHealthReport(instance.history,
|
|
1020
|
+
displayHealthReport(instance.history, instance.violationMap);
|
|
968
1021
|
};
|
|
969
1022
|
var getBasisMetrics = () => ({
|
|
970
1023
|
engine: "v0.6.x",
|