@vltpkg/graph 1.3.7 → 1.3.8

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/graph.d.ts CHANGED
@@ -100,9 +100,10 @@ export declare class Graph implements GraphLike {
100
100
  /**
101
101
  * Whether the lockfile on disk no longer matches this graph even
102
102
  * though no node changed, e.g. an importer edge spec was rewritten to
103
- * the value saved to `package.json`, or the config options the graph
104
- * was built with differ from the ones stored in the lockfile. Reify
105
- * saves the lockfiles from its no-diff early return when set.
103
+ * the value saved to `package.json`, a node dev/optional flag was
104
+ * re-derived, or the config options the graph was built with differ
105
+ * from the ones stored in the lockfile. Reify saves the lockfiles
106
+ * from its no-diff early return when set.
106
107
  */
107
108
  lockfileStale: boolean;
108
109
  /**
@@ -126,6 +127,13 @@ export declare class Graph implements GraphLike {
126
127
  * Get the next peer context index.
127
128
  */
128
129
  nextPeerContextIndex(): number;
130
+ /**
131
+ * Re-derive node `dev`/`optional` flags: a node is dev/optional only
132
+ * when every importer path crosses a dev/optional edge. Placement only
133
+ * ever lowers these flags, so removed or retyped edges leave them
134
+ * stale. Sets `lockfileStale` when any flag changes.
135
+ */
136
+ recomputeFlags(): void;
129
137
  /**
130
138
  * Delete all nodes and edges that are unreachable from the importers.
131
139
  * The collection of deleted nodes is returned.
package/dist/graph.js CHANGED
@@ -110,9 +110,10 @@ export class Graph {
110
110
  /**
111
111
  * Whether the lockfile on disk no longer matches this graph even
112
112
  * though no node changed, e.g. an importer edge spec was rewritten to
113
- * the value saved to `package.json`, or the config options the graph
114
- * was built with differ from the ones stored in the lockfile. Reify
115
- * saves the lockfiles from its no-diff early return when set.
113
+ * the value saved to `package.json`, a node dev/optional flag was
114
+ * re-derived, or the config options the graph was built with differ
115
+ * from the ones stored in the lockfile. Reify saves the lockfiles
116
+ * from its no-diff early return when set.
116
117
  */
117
118
  lockfileStale = false;
118
119
  /**
@@ -195,6 +196,35 @@ export class Graph {
195
196
  nextPeerContextIndex() {
196
197
  return ++this.currentPeerContextIndex;
197
198
  }
199
+ /**
200
+ * Re-derive node `dev`/`optional` flags: a node is dev/optional only
201
+ * when every importer path crosses a dev/optional edge. Placement only
202
+ * ever lowers these flags, so removed or retyped edges leave them
203
+ * stale. Sets `lockfileStale` when any flag changes.
204
+ */
205
+ recomputeFlags() {
206
+ const reach = (skip) => {
207
+ const seen = new Set(this.importers);
208
+ for (const node of seen) {
209
+ for (const edge of node.edgesOut.values()) {
210
+ if (edge.to && !skip(edge))
211
+ seen.add(edge.to);
212
+ }
213
+ }
214
+ return seen;
215
+ };
216
+ const nonDev = reach(edge => edge.dev);
217
+ const nonOptional = reach(edge => edge.optional);
218
+ for (const node of this.nodes.values()) {
219
+ const dev = !nonDev.has(node);
220
+ const optional = !nonOptional.has(node);
221
+ if (node.dev !== dev || node.optional !== optional) {
222
+ node.dev = dev;
223
+ node.optional = optional;
224
+ this.lockfileStale = true;
225
+ }
226
+ }
227
+ }
198
228
  /**
199
229
  * Delete all nodes and edges that are unreachable from the importers.
200
230
  * The collection of deleted nodes is returned.
@@ -93,5 +93,6 @@ export const buildIdealFromStartingGraph = async (options) => {
93
93
  hasProvisionalPeerIds(options.graph)) {
94
94
  await movePeerStoreDirs(canonicalizePeerIds(options.graph), options);
95
95
  }
96
+ options.graph.recomputeFlags();
96
97
  return options.graph;
97
98
  };
@@ -96,8 +96,9 @@ export const reify = async (options) => {
96
96
  // Even when there are no changes to reify, ensure lockfiles
97
97
  // exist on disk. This handles the case where a project has no
98
98
  // dependencies (or only workspace importers) but still needs
99
- // lockfiles written on the first install. A stale flag means an
100
- // edge spec was rewritten above, which the lockfiles have to carry.
99
+ // lockfiles written on the first install. A stale flag means
100
+ // lockfile data changed w/o a node diff (edge spec/type, options,
101
+ // dev/optional flags), which the lockfiles have to carry.
101
102
  if (!hasLockfiles || graph.lockfileStale) {
102
103
  // with no diff at all the ideal graph is the actual graph, so the
103
104
  // hidden lockfile can be written from it; an optional-only diff
package/dist/uninstall.js CHANGED
@@ -5,12 +5,18 @@ import { reify } from "./reify/index.js";
5
5
  import { lockfile } from "./index.js";
6
6
  import { updatePackageJson } from "./reify/update-importers-package-json.js";
7
7
  import { RollbackRemove } from '@vltpkg/rollback-remove';
8
+ import { Monorepo } from '@vltpkg/workspaces';
8
9
  import { existsSync, rmSync } from 'node:fs';
9
10
  import { resolve } from 'node:path';
10
11
  export const uninstall = async (options, remove) => {
11
12
  const mainManifest = options.packageJson.read(options.projectRoot);
12
13
  const modifiers = GraphModifier.maybeLoad(options);
13
14
  const remover = new RollbackRemove();
15
+ // graph spans every workspace; -w only picks the `remove` targets
16
+ const monorepo = Monorepo.maybeLoad(options.projectRoot, {
17
+ packageJson: options.packageJson,
18
+ scurry: options.scurry,
19
+ });
14
20
  try {
15
21
  // Load the actual graph before building the ideal graph so that
16
22
  // manifest data from installed packages can be used to hydrate
@@ -20,12 +26,14 @@ export const uninstall = async (options, remove) => {
20
26
  // due to throwOnMissingManifest and leaving stale entries behind.
21
27
  const act = actualLoad({
22
28
  ...options,
29
+ monorepo,
23
30
  modifiers: undefined,
24
31
  mainManifest,
25
32
  loadManifests: true,
26
33
  });
27
34
  const graph = await idealBuild({
28
35
  ...options,
36
+ monorepo,
29
37
  actual: act,
30
38
  remove,
31
39
  mainManifest,
package/dist/update.js CHANGED
@@ -5,10 +5,45 @@ import { GraphModifier } from "./modifiers.js";
5
5
  import { init } from '@vltpkg/init';
6
6
  import { asError } from '@vltpkg/types';
7
7
  import { Graph } from "./graph.js";
8
+ import { load as loadVirtual } from "./lockfile/load.js";
9
+ import { isPathSecurityError } from "./path-security-error.js";
8
10
  import { graphStep } from '@vltpkg/output';
9
11
  import { RollbackRemove } from '@vltpkg/rollback-remove';
12
+ import { Monorepo } from '@vltpkg/workspaces';
10
13
  import { existsSync, rmSync } from 'node:fs';
11
14
  import { resolve } from 'node:path';
15
+ /**
16
+ * Graph to update from. `-w` filtered: the lockfile (else installed)
17
+ * graph minus the selected workspaces' deps, so only those re-resolve
18
+ * (deps shared with other workspaces stay locked). Else: empty.
19
+ */
20
+ const startingGraph = (options, monorepo) => {
21
+ const fresh = () => new Graph({ ...options, monorepo });
22
+ if (!options.monorepo || !monorepo)
23
+ return fresh();
24
+ const selected = new Set([...options.monorepo.values()].map(ws => ws.id));
25
+ if (selected.size === monorepo.size)
26
+ return fresh();
27
+ let graph;
28
+ try {
29
+ graph = loadVirtual({ ...options, monorepo });
30
+ }
31
+ catch (err) {
32
+ if (isPathSecurityError(err))
33
+ throw err;
34
+ graph = actualLoad({ ...options, monorepo, loadManifests: true });
35
+ }
36
+ for (const importer of graph.importers) {
37
+ if (!selected.has(importer.id))
38
+ continue;
39
+ for (const edge of importer.edgesOut.values()) {
40
+ edge.to?.edgesIn.delete(edge);
41
+ }
42
+ importer.edgesOut.clear();
43
+ }
44
+ graph.gc();
45
+ return graph;
46
+ };
12
47
  export const update = async (options) => {
13
48
  let mainManifest = undefined;
14
49
  try {
@@ -27,6 +62,10 @@ export const update = async (options) => {
27
62
  }
28
63
  const modifiers = GraphModifier.maybeLoad(options);
29
64
  const remover = new RollbackRemove();
65
+ const monorepo = Monorepo.maybeLoad(options.projectRoot, {
66
+ packageJson: options.packageJson,
67
+ scurry: options.scurry,
68
+ });
30
69
  try {
31
70
  const done = graphStep('build');
32
71
  const graph = await buildIdealFromStartingGraph({
@@ -35,13 +74,14 @@ export const update = async (options) => {
35
74
  remove: Object.assign(new Map(), {
36
75
  modifiedDependencies: false,
37
76
  }),
38
- graph: new Graph({ ...options, mainManifest }),
77
+ graph: startingGraph({ ...options, mainManifest, modifiers }, monorepo),
39
78
  modifiers,
40
79
  remover,
41
80
  });
42
81
  done();
43
82
  const act = actualLoad({
44
83
  ...options,
84
+ monorepo,
45
85
  mainManifest,
46
86
  loadManifests: true,
47
87
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/graph",
3
3
  "description": "A library that helps understanding & expressing what happens on an install",
4
- "version": "1.3.7",
4
+ "version": "1.3.8",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -13,26 +13,26 @@
13
13
  "url": "http://vlt.sh"
14
14
  },
15
15
  "dependencies": {
16
- "@vltpkg/cmd-shim": "1.3.7",
17
- "@vltpkg/dep-id": "1.3.7",
18
- "@vltpkg/dss-breadcrumb": "1.3.7",
19
- "@vltpkg/error-cause": "1.3.7",
20
- "@vltpkg/fast-split": "1.3.7",
21
- "@vltpkg/graph-run": "1.3.7",
22
- "@vltpkg/init": "1.3.7",
23
- "@vltpkg/output": "1.3.7",
24
- "@vltpkg/package-info": "1.3.7",
25
- "@vltpkg/package-json": "1.3.7",
26
- "@vltpkg/pick-manifest": "1.3.7",
27
- "@vltpkg/query": "1.3.7",
28
- "@vltpkg/rollback-remove": "1.3.7",
29
- "@vltpkg/run": "1.3.7",
30
- "@vltpkg/satisfies": "1.3.7",
31
- "@vltpkg/security-archive": "1.3.7",
32
- "@vltpkg/spec": "1.3.7",
33
- "@vltpkg/types": "1.3.7",
34
- "@vltpkg/vlt-json": "1.3.7",
35
- "@vltpkg/workspaces": "1.3.7",
16
+ "@vltpkg/cmd-shim": "1.3.8",
17
+ "@vltpkg/dep-id": "1.3.8",
18
+ "@vltpkg/dss-breadcrumb": "1.3.8",
19
+ "@vltpkg/error-cause": "1.3.8",
20
+ "@vltpkg/fast-split": "1.3.8",
21
+ "@vltpkg/graph-run": "1.3.8",
22
+ "@vltpkg/init": "1.3.8",
23
+ "@vltpkg/output": "1.3.8",
24
+ "@vltpkg/package-info": "1.3.8",
25
+ "@vltpkg/package-json": "1.3.8",
26
+ "@vltpkg/pick-manifest": "1.3.8",
27
+ "@vltpkg/query": "1.3.8",
28
+ "@vltpkg/rollback-remove": "1.3.8",
29
+ "@vltpkg/run": "1.3.8",
30
+ "@vltpkg/satisfies": "1.3.8",
31
+ "@vltpkg/security-archive": "1.3.8",
32
+ "@vltpkg/spec": "1.3.8",
33
+ "@vltpkg/types": "1.3.8",
34
+ "@vltpkg/vlt-json": "1.3.8",
35
+ "@vltpkg/workspaces": "1.3.8",
36
36
  "path-scurry": "^2.0.1",
37
37
  "promise-call-limit": "^3.0.2"
38
38
  },