@antongolub/lockfile 0.0.0-snapshot.70 → 0.0.0-snapshot.71

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.js CHANGED
@@ -10609,6 +10609,12 @@ async function replaceVersion(graph, selector, toRange, context, options = {}) {
10609
10609
  currentGraph = currentGraph.mutate((m) => {
10610
10610
  for (const e of staleOut) m.removeEdge(targetId, e.dst, e.kind);
10611
10611
  }).graph;
10612
+ for (const e of staleOut) {
10613
+ const dst = currentGraph.getNode(e.dst);
10614
+ if (dst !== void 0 && dst.workspacePath === void 0 && currentGraph.in(e.dst).length === 0) {
10615
+ recentlyOrphaned.add(e.dst);
10616
+ }
10617
+ }
10612
10618
  }
10613
10619
  replaced.push({ from: node.id, to: targetId });
10614
10620
  recentlyAdded.add(targetId);
package/dist/modify.js CHANGED
@@ -628,6 +628,12 @@ async function replaceVersion(graph, selector, toRange, context, options = {}) {
628
628
  currentGraph = currentGraph.mutate((m) => {
629
629
  for (const e of staleOut) m.removeEdge(targetId, e.dst, e.kind);
630
630
  }).graph;
631
+ for (const e of staleOut) {
632
+ const dst = currentGraph.getNode(e.dst);
633
+ if (dst !== void 0 && dst.workspacePath === void 0 && currentGraph.in(e.dst).length === 0) {
634
+ recentlyOrphaned.add(e.dst);
635
+ }
636
+ }
631
637
  }
632
638
  replaced.push({ from: node.id, to: targetId });
633
639
  recentlyAdded.add(targetId);
@@ -9,9 +9,17 @@ interface PruneOrphansOptions {
9
9
  /**
10
10
  * Bound the sweep to a candidate set. When provided, ONLY these NodeIds (and
11
11
  * the closure they transitively strand) are removal candidates — any OTHER
12
- * pre-existing in-degree-0 node is left untouched. Pass the mutation's removed
13
- * / orphaned NodeIds (e.g. `replaceVersion`'s `recentlyOrphaned`) for a purely
14
- * differential GC. Omit for a whole-graph sweep.
12
+ * pre-existing in-degree-0 node is left untouched.
13
+ *
14
+ * **Seeded is the SAFE / recommended mode for post-mutation GC.** Pass the
15
+ * mutation's orphaned NodeIds (`replaceVersion`'s `recentlyOrphaned` — which
16
+ * now includes the targets whose last incoming edge a rebind's edge-refresh
17
+ * dropped). The sweep then retires exactly that delta and CANNOT touch a node
18
+ * the mutation never affected — including ones that only LOOK orphaned because
19
+ * an incoming edge is unresolved in the parse (e.g. berry `@patch:…!builtin`
20
+ * fsevents). Omit only for a whole-graph sweep on a graph whose edges you trust
21
+ * to be complete; the unseeded path over-prunes such unresolved-edge nodes and
22
+ * is guarded against wiping a rootless lock (PRUNE_NO_ROOTS).
15
23
  */
16
24
  seed?: ReadonlySet<NodeId>;
17
25
  }
@@ -42,7 +50,7 @@ interface OptimizeDiagnostic extends Diagnostic {
42
50
  * rationale — the NodeId alone may carry a long peerContext suffix.
43
51
  */
44
52
  declare function optimizeNodeRemoved(nodeId: NodeId): OptimizeDiagnostic;
45
- type PruneDiagnosticCode = 'PRUNE_NODE_REMOVED' | 'PRUNE_NOOP';
53
+ type PruneDiagnosticCode = 'PRUNE_NODE_REMOVED' | 'PRUNE_NOOP' | 'PRUNE_NO_ROOTS';
46
54
  interface PruneDiagnostic extends Diagnostic {
47
55
  code: PruneDiagnosticCode;
48
56
  }
@@ -50,6 +58,15 @@ interface PruneDiagnostic extends Diagnostic {
50
58
  declare function pruneNodeRemoved(nodeId: NodeId): PruneDiagnostic;
51
59
  /** Fires once per `pruneOrphans(graph)` call when nothing was removed. */
52
60
  declare function pruneNoop(): PruneDiagnostic;
61
+ /**
62
+ * Fires when an UNSEEDED pruneOrphans runs on a non-empty graph with no
63
+ * workspace anchor (e.g. a rootless yarn-classic lock). Without a workspace
64
+ * every top-level dependency is itself in-degree 0, so a whole-graph sweep would
65
+ * cascade and wipe the lock. We no-op instead — the caller bounds the sweep with
66
+ * an explicit `seed` (or `preserve`) to GC a rootless graph. Mirrors
67
+ * OPTIMIZE_NO_ROOTS.
68
+ */
69
+ declare function pruneNoRoots(): PruneDiagnostic;
53
70
  declare function optimizeWorkspaceUnreachable(nodeId: NodeId): OptimizeDiagnostic;
54
71
  /**
55
72
  * Fires once per `optimize(graph)` call when `removed.length === 0`. The
@@ -60,4 +77,4 @@ declare function optimizeWorkspaceUnreachable(nodeId: NodeId): OptimizeDiagnosti
60
77
  */
61
78
  declare function optimizeNoop(): OptimizeDiagnostic;
62
79
 
63
- export { type OptimizeDiagnostic, type OptimizeDiagnosticCode, type PruneDiagnostic, type PruneDiagnosticCode, type PruneOrphansOptions, type PruneOrphansResult, optimizeNodeRemoved, optimizeNoop, optimizeWorkspaceUnreachable, pruneNodeRemoved, pruneNoop, pruneOrphans };
80
+ export { type OptimizeDiagnostic, type OptimizeDiagnosticCode, type PruneDiagnostic, type PruneDiagnosticCode, type PruneOrphansOptions, type PruneOrphansResult, optimizeNodeRemoved, optimizeNoop, optimizeWorkspaceUnreachable, pruneNoRoots, pruneNodeRemoved, pruneNoop, pruneOrphans };
package/dist/optimize.js CHANGED
@@ -58,6 +58,14 @@ function pruneNoop() {
58
58
  message: "pruneOrphans: no unreferenced nodes to collect"
59
59
  };
60
60
  }
61
+ function pruneNoRoots() {
62
+ return {
63
+ code: "PRUNE_NO_ROOTS",
64
+ severity: "warning",
65
+ subject: "graph",
66
+ message: "pruneOrphans: no workspace anchor and no seed on a non-empty graph \u2014 kept all nodes to avoid wiping a rootless lock"
67
+ };
68
+ }
61
69
  function optimizeWorkspaceUnreachable(nodeId) {
62
70
  return {
63
71
  code: "OPTIMIZE_WORKSPACE_UNREACHABLE",
@@ -177,6 +185,25 @@ function pruneOrphans(graph, options = {}) {
177
185
  if (onDiagnostic !== void 0) onDiagnostic(d);
178
186
  };
179
187
  let current = graph;
188
+ if (options.seed === void 0) {
189
+ let hasNodes = false;
190
+ let hasWorkspace = false;
191
+ for (const node of current.nodes()) {
192
+ hasNodes = true;
193
+ if (node.workspacePath !== void 0) {
194
+ hasWorkspace = true;
195
+ break;
196
+ }
197
+ }
198
+ if (hasNodes && !hasWorkspace) {
199
+ const diag = pruneNoRoots();
200
+ const guarded = current.mutate((m) => {
201
+ m.diagnostic(diag);
202
+ }).graph;
203
+ emit(diag);
204
+ return { graph: guarded, removed, unresolved };
205
+ }
206
+ }
180
207
  const collectable = (id) => {
181
208
  const node = current.getNode(id);
182
209
  if (node === void 0) return false;
@@ -226,4 +253,4 @@ function tarballSharedByOther(graph, removingId, key) {
226
253
  return false;
227
254
  }
228
255
 
229
- export { optimize, optimizeNodeRemoved, optimizeNoop, optimizeWorkspaceUnreachable, pruneNodeRemoved, pruneNoop, pruneOrphans };
256
+ export { optimize, optimizeNodeRemoved, optimizeNoop, optimizeWorkspaceUnreachable, pruneNoRoots, pruneNodeRemoved, pruneNoop, pruneOrphans };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antongolub/lockfile",
3
- "version": "0.0.0-snapshot.70",
3
+ "version": "0.0.0-snapshot.71",
4
4
  "private": false,
5
5
  "description": "Universal lockfile model and converter for npm, yarn, pnpm, bun",
6
6
  "type": "module",