@violetflux/eslint-plugin-kerros 0.3.0 → 0.3.1
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/index.cjs +43 -23
- package/dist/index.mjs +43 -23
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -472,32 +472,51 @@ const setMutationMethods = /* @__PURE__ */ new Set([
|
|
|
472
472
|
"clear",
|
|
473
473
|
"delete"
|
|
474
474
|
]);
|
|
475
|
-
/** Build
|
|
476
|
-
function
|
|
475
|
+
/** Build a reusable index that streams dynamic call-site contexts without retaining every path. */
|
|
476
|
+
function createFunctionCallSiteContexts(edges) {
|
|
477
477
|
const incoming = /* @__PURE__ */ new Map();
|
|
478
478
|
for (const edge of edges) {
|
|
479
479
|
const existing = incoming.get(edge.callee) ?? [];
|
|
480
480
|
existing.push(edge);
|
|
481
481
|
incoming.set(edge.callee, existing);
|
|
482
482
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
483
|
+
/** Visit paths independently while retaining only the current DFS path. */
|
|
484
|
+
const some = (target, predicate) => {
|
|
485
|
+
const calls = /* @__PURE__ */ new Map();
|
|
486
|
+
const active = /* @__PURE__ */ new Set([target]);
|
|
487
|
+
const frames = [{
|
|
488
|
+
advanced: false,
|
|
489
|
+
edges: incoming.get(target) ?? [],
|
|
490
|
+
fn: target,
|
|
491
|
+
index: 0
|
|
492
|
+
}];
|
|
493
|
+
while (frames.length > 0) {
|
|
494
|
+
const frame = frames.at(-1);
|
|
495
|
+
if (!frame) break;
|
|
496
|
+
const edge = frame.edges[frame.index];
|
|
497
|
+
if (edge) {
|
|
498
|
+
frame.index += 1;
|
|
499
|
+
if (active.has(edge.caller)) continue;
|
|
500
|
+
frame.advanced = true;
|
|
501
|
+
calls.set(frame.fn, edge.site);
|
|
502
|
+
active.add(edge.caller);
|
|
503
|
+
frames.push({
|
|
504
|
+
advanced: false,
|
|
505
|
+
edges: incoming.get(edge.caller) ?? [],
|
|
506
|
+
fn: edge.caller,
|
|
507
|
+
index: 0,
|
|
508
|
+
parent: frame.fn
|
|
509
|
+
});
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
if (!frame.advanced && predicate(calls)) return true;
|
|
513
|
+
frames.pop();
|
|
514
|
+
active.delete(frame.fn);
|
|
515
|
+
if (frame.parent) calls.delete(frame.parent);
|
|
496
516
|
}
|
|
497
|
-
|
|
517
|
+
return false;
|
|
498
518
|
};
|
|
499
|
-
|
|
500
|
-
return contexts;
|
|
519
|
+
return { some };
|
|
501
520
|
}
|
|
502
521
|
/** Track assignment sources and resolve definitions that reach a concrete reference point. */
|
|
503
522
|
function createReferenceOriginTracker(program) {
|
|
@@ -1481,7 +1500,7 @@ const noRenderInstanceSnapshot = createRule({
|
|
|
1481
1500
|
changed = true;
|
|
1482
1501
|
}
|
|
1483
1502
|
}
|
|
1484
|
-
const
|
|
1503
|
+
const callContexts = createFunctionCallSiteContexts(localEdges.filter((edge) => rendered.has(edge.caller)));
|
|
1485
1504
|
/** Test whether an expression is a local alias of a Store instance Hook result. */
|
|
1486
1505
|
const isInstanceDerived = (input, calls, seen = /* @__PURE__ */ new Set()) => {
|
|
1487
1506
|
const node = unwrapExpression(input);
|
|
@@ -1514,7 +1533,7 @@ const noRenderInstanceSnapshot = createRule({
|
|
|
1514
1533
|
};
|
|
1515
1534
|
for (const snapshot of snapshots) {
|
|
1516
1535
|
if (!snapshot.owner || !rendered.has(snapshot.owner)) continue;
|
|
1517
|
-
if (
|
|
1536
|
+
if (callContexts.some(snapshot.owner, (calls) => {
|
|
1518
1537
|
return snapshot.kind === "instance" ? isInstanceDerived(snapshot.source, calls) : isSnapshotReaderDerived(snapshot.source, calls);
|
|
1519
1538
|
})) context.report({
|
|
1520
1539
|
node: snapshot.node,
|
|
@@ -1682,9 +1701,10 @@ const noStoreMutation = createRule({
|
|
|
1682
1701
|
site: node
|
|
1683
1702
|
});
|
|
1684
1703
|
}
|
|
1685
|
-
|
|
1704
|
+
const callContexts = createFunctionCallSiteContexts(localEdges);
|
|
1705
|
+
for (const candidate of candidates) if (candidate.owner ? callContexts.some(candidate.owner, (calls) => {
|
|
1686
1706
|
return isSnapshotDerived(candidate.expression, maxAliasDepth, /* @__PURE__ */ new Set(), calls);
|
|
1687
|
-
})) context.report({
|
|
1707
|
+
}) : isSnapshotDerived(candidate.expression, maxAliasDepth, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Map())) context.report({
|
|
1688
1708
|
node: candidate.node,
|
|
1689
1709
|
messageId: "mutation"
|
|
1690
1710
|
});
|
|
@@ -2451,7 +2471,7 @@ const rules = {
|
|
|
2451
2471
|
const plugin = {
|
|
2452
2472
|
meta: {
|
|
2453
2473
|
name: "@violetflux/eslint-plugin-kerros",
|
|
2454
|
-
version: "0.3.
|
|
2474
|
+
version: "0.3.1"
|
|
2455
2475
|
},
|
|
2456
2476
|
rules
|
|
2457
2477
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -444,32 +444,51 @@ const setMutationMethods = /* @__PURE__ */ new Set([
|
|
|
444
444
|
"clear",
|
|
445
445
|
"delete"
|
|
446
446
|
]);
|
|
447
|
-
/** Build
|
|
448
|
-
function
|
|
447
|
+
/** Build a reusable index that streams dynamic call-site contexts without retaining every path. */
|
|
448
|
+
function createFunctionCallSiteContexts(edges) {
|
|
449
449
|
const incoming = /* @__PURE__ */ new Map();
|
|
450
450
|
for (const edge of edges) {
|
|
451
451
|
const existing = incoming.get(edge.callee) ?? [];
|
|
452
452
|
existing.push(edge);
|
|
453
453
|
incoming.set(edge.callee, existing);
|
|
454
454
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
455
|
+
/** Visit paths independently while retaining only the current DFS path. */
|
|
456
|
+
const some = (target, predicate) => {
|
|
457
|
+
const calls = /* @__PURE__ */ new Map();
|
|
458
|
+
const active = /* @__PURE__ */ new Set([target]);
|
|
459
|
+
const frames = [{
|
|
460
|
+
advanced: false,
|
|
461
|
+
edges: incoming.get(target) ?? [],
|
|
462
|
+
fn: target,
|
|
463
|
+
index: 0
|
|
464
|
+
}];
|
|
465
|
+
while (frames.length > 0) {
|
|
466
|
+
const frame = frames.at(-1);
|
|
467
|
+
if (!frame) break;
|
|
468
|
+
const edge = frame.edges[frame.index];
|
|
469
|
+
if (edge) {
|
|
470
|
+
frame.index += 1;
|
|
471
|
+
if (active.has(edge.caller)) continue;
|
|
472
|
+
frame.advanced = true;
|
|
473
|
+
calls.set(frame.fn, edge.site);
|
|
474
|
+
active.add(edge.caller);
|
|
475
|
+
frames.push({
|
|
476
|
+
advanced: false,
|
|
477
|
+
edges: incoming.get(edge.caller) ?? [],
|
|
478
|
+
fn: edge.caller,
|
|
479
|
+
index: 0,
|
|
480
|
+
parent: frame.fn
|
|
481
|
+
});
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (!frame.advanced && predicate(calls)) return true;
|
|
485
|
+
frames.pop();
|
|
486
|
+
active.delete(frame.fn);
|
|
487
|
+
if (frame.parent) calls.delete(frame.parent);
|
|
468
488
|
}
|
|
469
|
-
|
|
489
|
+
return false;
|
|
470
490
|
};
|
|
471
|
-
|
|
472
|
-
return contexts;
|
|
491
|
+
return { some };
|
|
473
492
|
}
|
|
474
493
|
/** Track assignment sources and resolve definitions that reach a concrete reference point. */
|
|
475
494
|
function createReferenceOriginTracker(program) {
|
|
@@ -1453,7 +1472,7 @@ const noRenderInstanceSnapshot = createRule({
|
|
|
1453
1472
|
changed = true;
|
|
1454
1473
|
}
|
|
1455
1474
|
}
|
|
1456
|
-
const
|
|
1475
|
+
const callContexts = createFunctionCallSiteContexts(localEdges.filter((edge) => rendered.has(edge.caller)));
|
|
1457
1476
|
/** Test whether an expression is a local alias of a Store instance Hook result. */
|
|
1458
1477
|
const isInstanceDerived = (input, calls, seen = /* @__PURE__ */ new Set()) => {
|
|
1459
1478
|
const node = unwrapExpression(input);
|
|
@@ -1486,7 +1505,7 @@ const noRenderInstanceSnapshot = createRule({
|
|
|
1486
1505
|
};
|
|
1487
1506
|
for (const snapshot of snapshots) {
|
|
1488
1507
|
if (!snapshot.owner || !rendered.has(snapshot.owner)) continue;
|
|
1489
|
-
if (
|
|
1508
|
+
if (callContexts.some(snapshot.owner, (calls) => {
|
|
1490
1509
|
return snapshot.kind === "instance" ? isInstanceDerived(snapshot.source, calls) : isSnapshotReaderDerived(snapshot.source, calls);
|
|
1491
1510
|
})) context.report({
|
|
1492
1511
|
node: snapshot.node,
|
|
@@ -1654,9 +1673,10 @@ const noStoreMutation = createRule({
|
|
|
1654
1673
|
site: node
|
|
1655
1674
|
});
|
|
1656
1675
|
}
|
|
1657
|
-
|
|
1676
|
+
const callContexts = createFunctionCallSiteContexts(localEdges);
|
|
1677
|
+
for (const candidate of candidates) if (candidate.owner ? callContexts.some(candidate.owner, (calls) => {
|
|
1658
1678
|
return isSnapshotDerived(candidate.expression, maxAliasDepth, /* @__PURE__ */ new Set(), calls);
|
|
1659
|
-
})) context.report({
|
|
1679
|
+
}) : isSnapshotDerived(candidate.expression, maxAliasDepth, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Map())) context.report({
|
|
1660
1680
|
node: candidate.node,
|
|
1661
1681
|
messageId: "mutation"
|
|
1662
1682
|
});
|
|
@@ -2423,7 +2443,7 @@ const rules = {
|
|
|
2423
2443
|
const plugin = {
|
|
2424
2444
|
meta: {
|
|
2425
2445
|
name: "@violetflux/eslint-plugin-kerros",
|
|
2426
|
-
version: "0.3.
|
|
2446
|
+
version: "0.3.1"
|
|
2427
2447
|
},
|
|
2428
2448
|
rules
|
|
2429
2449
|
};
|